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 @@ -61,7 +61,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
if (service != null && !service.IsValidName(resolveResult.Identifier, AffectedEntity.Class)) {
yield break;
}
ClassType classType = GuessClassType (context, node);
ClassType classType = GuessClassTypeByName(context, node);
ModifyClassTypeBasedOnTypeGuessing(context, node, ref classType);
string message;
switch (classType) {
case ClassType.Struct:
@ -89,6 +91,18 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -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)
{
var service = (NamingConventionService)context.GetService (typeof (NamingConventionService));
@ -102,7 +116,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -102,7 +116,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return ClassType.Class;
}
static ClassType GuessClassType(RefactoringContext context, AstNode node)
static ClassType GuessClassTypeByName(RefactoringContext context, AstNode node)
{
if (node is SimpleType)
return GuessClassTypeByName (context, ((SimpleType)node).Identifier);
@ -148,10 +162,30 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -148,10 +162,30 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
var entity = simpleType.GetParent<EntityDeclaration>();
if (entity != null)
result.Modifiers |= entity.Modifiers & Modifiers.Public;
var guessedType = CreateFieldAction.GuessType (context, simpleType);
if (guessedType.Kind == TypeKind.TypeParameter)
ImplementConstraints (context, result, (ITypeParameter)guessedType);
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)
{
TypeDeclaration result;

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

@ -174,7 +174,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -174,7 +174,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
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) {
var parent = expr.Parent.Parent;
@ -279,7 +279,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -279,7 +279,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
return Enumerable.Empty<IType>();
}
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 typeInference = new TypeInference(context.Compilation);
@ -290,8 +290,20 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -290,8 +290,20 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
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 typeInference = new TypeInference(context.Compilation);
typeInference.Algorithm = TypeInferenceAlgorithm.Improved;

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

@ -391,7 +391,99 @@ class TestClass @@ -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