From 24a9d7f3420bb0eb3eaf4d3f7d5773fa4e41c582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Tue, 26 Feb 2013 11:23:39 +0100 Subject: [PATCH] Create class declaration takes now constraints into account. --- .../CreateClassDeclarationAction.cs | 40 +++++++- .../CodeActions/CreateFieldAction.cs | 18 +++- .../CreateClassDeclarationTests.cs | 92 +++++++++++++++++++ 3 files changed, 144 insertions(+), 6 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateClassDeclarationAction.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateClassDeclarationAction.cs index eb3a9a9a89..f63e0ee212 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateClassDeclarationAction.cs +++ b/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)) { 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 }); } + 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 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 var entity = simpleType.GetParent(); 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; diff --git a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateFieldAction.cs b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateFieldAction.cs index 2956fe2eae..6152953e6f 100644 --- a/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateFieldAction.cs +++ b/ICSharpCode.NRefactory.CSharp/Refactoring/CodeActions/CreateFieldAction.cs @@ -174,7 +174,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring return resolver.Compilation.FindType(KnownTypeCode.Object); } - internal static IEnumerable GetValidTypes(CSharpAstResolver resolver, Expression expr) + internal static IEnumerable GetValidTypes(CSharpAstResolver resolver, AstNode expr) { if (expr.Parent is DirectionExpression) { var parent = expr.Parent.Parent; @@ -279,7 +279,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring return Enumerable.Empty(); } 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 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; diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/CreateClassDeclarationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/CreateClassDeclarationTests.cs index 2b2ab2d0ed..fe8db36855 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/CreateClassDeclarationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeActions/CreateClassDeclarationTests.cs @@ -391,7 +391,99 @@ class TestClass "); } + /// + /// Bug 10672 - Auto-Fix of Generate Class to fill Generic params does not take in account constraints + /// + [Test] + public void TestBug10672 () + { + Test ( + @" +namespace TestConsole +{ + public interface IBase + { + } + public class Test + { + public void Generate() where T:IBase, new() + { + + } + } + class MainClass + { + public static void Main (string[] args) + { + var testConsole = new Test (); + testConsole.Generate (); + } + } +} +", @" +public class Data : IBase +{ + public Data () + { + } +} +namespace TestConsole +{ + public interface IBase + { + } + public class Test + { + public void Generate() where T:IBase, new() + { + + } + } + class MainClass + { + public static void Main (string[] args) + { + var testConsole = new Test (); + testConsole.Generate (); + } + } +} +"); + } + + [Test] + public void TestStructConstraint () + { + Test ( + @" +public class Test +{ + public void Generate () where T : struct + { + } + + public void FooBar () + { + Generate<$Data> (); + } +} +", @" +public struct Data +{ +} +public class Test +{ + public void Generate () where T : struct + { + } + public void FooBar () + { + Generate (); + } +} +"); + } } }