Browse Source

Create class declaration takes now constraints into account.

pull/32/merge
Mike Krüger 13 years ago
parent
commit
24a9d7f342
  1. 40
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateClassDeclarationAction.cs
  2. 18
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateFieldAction.cs
  3. 92
      ICSharpCode.NRefactory.Tests/CSharp/CodeActions/CreateClassDeclarationTests.cs

40
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateClassDeclarationAction.cs

@ -61,7 +61,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (service != null && !service.IsValidName(resolveResult.Identifier, AffectedEntity.Class)) { if (service != null && !service.IsValidName(resolveResult.Identifier, AffectedEntity.Class)) {
yield break; yield break;
} }
ClassType classType = GuessClassType (context, node); ClassType classType = GuessClassTypeByName(context, node);
ModifyClassTypeBasedOnTypeGuessing(context, node, ref classType);
string message; string message;
switch (classType) { switch (classType) {
case ClassType.Struct: case ClassType.Struct:
@ -89,6 +91,18 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
}); });
} }
static void ModifyClassTypeBasedOnTypeGuessing(RefactoringContext context, AstNode node, ref ClassType classType)
{
var guessedType = CreateFieldAction.GuessType(context, node);
if (guessedType.Kind == TypeKind.TypeParameter) {
var tp = (ITypeParameter)guessedType;
if (tp.HasValueTypeConstraint)
classType = ClassType.Struct;
if (tp.HasReferenceTypeConstraint)
classType = ClassType.Class;
}
}
static ClassType GuessClassTypeByName(RefactoringContext context, string identifier) static ClassType GuessClassTypeByName(RefactoringContext context, string identifier)
{ {
var service = (NamingConventionService)context.GetService (typeof (NamingConventionService)); var service = (NamingConventionService)context.GetService (typeof (NamingConventionService));
@ -102,7 +116,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return ClassType.Class; return ClassType.Class;
} }
static ClassType GuessClassType(RefactoringContext context, AstNode node) static ClassType GuessClassTypeByName(RefactoringContext context, AstNode node)
{ {
if (node is SimpleType) if (node is SimpleType)
return GuessClassTypeByName (context, ((SimpleType)node).Identifier); return GuessClassTypeByName (context, ((SimpleType)node).Identifier);
@ -148,10 +162,30 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var entity = simpleType.GetParent<EntityDeclaration>(); var entity = simpleType.GetParent<EntityDeclaration>();
if (entity != null) if (entity != null)
result.Modifiers |= entity.Modifiers & Modifiers.Public; result.Modifiers |= entity.Modifiers & Modifiers.Public;
var guessedType = CreateFieldAction.GuessType (context, simpleType);
if (guessedType.Kind == TypeKind.TypeParameter)
ImplementConstraints (context, result, (ITypeParameter)guessedType);
return result; return result;
} }
static void ImplementConstraints(RefactoringContext context, TypeDeclaration result, ITypeParameter tp)
{
if (tp.HasValueTypeConstraint)
result.ClassType = ClassType.Struct;
if (tp.HasReferenceTypeConstraint)
result.ClassType = ClassType.Class;
if (tp.HasDefaultConstructorConstraint)
result.AddChild (new ConstructorDeclaration { Modifiers = Modifiers.Public, Body = new BlockStatement () }, Roles.TypeMemberRole);
foreach (var baseType in tp.DirectBaseTypes) {
if (baseType.Namespace == "System") {
if (baseType.Name == "Object" || baseType.Name == "ValueType")
continue;
}
result.BaseTypes.Add (context.CreateShortType (baseType));
}
}
static TypeDeclaration CreateClassFromObjectCreation(RefactoringContext context, ObjectCreateExpression createExpression) static TypeDeclaration CreateClassFromObjectCreation(RefactoringContext context, ObjectCreateExpression createExpression)
{ {
TypeDeclaration result; TypeDeclaration result;

18
ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateFieldAction.cs

@ -174,7 +174,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return resolver.Compilation.FindType(KnownTypeCode.Object); return resolver.Compilation.FindType(KnownTypeCode.Object);
} }
internal static IEnumerable<IType> GetValidTypes(CSharpAstResolver resolver, Expression expr) internal static IEnumerable<IType> GetValidTypes(CSharpAstResolver resolver, AstNode expr)
{ {
if (expr.Parent is DirectionExpression) { if (expr.Parent is DirectionExpression) {
var parent = expr.Parent.Parent; var parent = expr.Parent.Parent;
@ -279,7 +279,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return Enumerable.Empty<IType>(); return Enumerable.Empty<IType>();
} }
static readonly IType[] emptyTypes = new IType[0]; static readonly IType[] emptyTypes = new IType[0];
public static AstType GuessAstType(RefactoringContext context, Expression expr) public static AstType GuessAstType(RefactoringContext context, AstNode expr)
{ {
var type = GetValidTypes(context.Resolver, expr).ToArray(); var type = GetValidTypes(context.Resolver, expr).ToArray();
var typeInference = new TypeInference(context.Compilation); var typeInference = new TypeInference(context.Compilation);
@ -290,8 +290,20 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return context.CreateShortType(inferedType); return context.CreateShortType(inferedType);
} }
public static IType GuessType(RefactoringContext context, Expression expr) public static IType GuessType(RefactoringContext context, AstNode expr)
{ {
if (expr is SimpleType && expr.Role == Roles.TypeArgument && (expr.Parent is MemberReferenceExpression || expr.Parent is IdentifierExpression)) {
var rr = context.Resolve (expr.Parent);
var argumentNumber = expr.Parent.GetChildrenByRole (Roles.TypeArgument).TakeWhile (c => c != expr).Count ();
var mgrr = rr as MethodGroupResolveResult;
Console.WriteLine (argumentNumber);
Console.WriteLine (mgrr.Methods.First ().TypeArguments.Count);
if (mgrr != null && mgrr.Methods.Any () && mgrr.Methods.First ().TypeArguments.Count > argumentNumber) {
return mgrr.Methods.First ().TypeParameters[argumentNumber];
}
}
var type = GetValidTypes(context.Resolver, expr).ToArray(); var type = GetValidTypes(context.Resolver, expr).ToArray();
var typeInference = new TypeInference(context.Compilation); var typeInference = new TypeInference(context.Compilation);
typeInference.Algorithm = TypeInferenceAlgorithm.Improved; typeInference.Algorithm = TypeInferenceAlgorithm.Improved;

92
ICSharpCode.NRefactory.Tests/CSharp/CodeActions/CreateClassDeclarationTests.cs

@ -391,7 +391,99 @@ class TestClass
"); ");
} }
/// <summary>
/// Bug 10672 - Auto-Fix of Generate Class to fill Generic params does not take in account constraints
/// </summary>
[Test]
public void TestBug10672 ()
{
Test<CreateClassDeclarationAction> (
@"
namespace TestConsole
{
public interface IBase
{
}
public class Test
{
public void Generate<S, T>() where T:IBase, new()
{
}
}
class MainClass
{
public static void Main (string[] args)
{
var testConsole = new Test ();
testConsole.Generate<int, $Data> ();
}
}
}
", @"
public class Data : IBase
{
public Data ()
{
}
}
namespace TestConsole
{
public interface IBase
{
}
public class Test
{
public void Generate<S, T>() where T:IBase, new()
{
}
}
class MainClass
{
public static void Main (string[] args)
{
var testConsole = new Test ();
testConsole.Generate<int, Data> ();
}
}
}
");
}
[Test]
public void TestStructConstraint ()
{
Test<CreateClassDeclarationAction> (
@"
public class Test
{
public void Generate<T> () where T : struct
{
}
public void FooBar ()
{
Generate<$Data> ();
}
}
", @"
public struct Data
{
}
public class Test
{
public void Generate<T> () where T : struct
{
}
public void FooBar ()
{
Generate<Data> ();
}
}
");
}
} }
} }

Loading…
Cancel
Save