diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/CodeGenerator.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/CodeGenerator.cs index 1e33a0bb47..6110152a19 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/CodeGenerator.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Refactoring/CodeGenerator.cs @@ -43,26 +43,66 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring if (returnType == null) return TypeReference.Null; if (returnType is NullReturnType) return TypeReference.Null; - TypeReference typeRef; - if (IsPrimitiveType(returnType)) - typeRef = new TypeReference(returnType.FullyQualifiedName, true); - else if (context != null && CanUseShortTypeName(returnType, context)) - typeRef = new TypeReference(returnType.Name); - else - typeRef = new TypeReference(returnType.FullyQualifiedName); - while (returnType.IsArrayReturnType) { + ArrayReturnType arrayReturnType = returnType.CastToArrayReturnType(); + if (arrayReturnType != null) { + TypeReference typeRef = ConvertType(arrayReturnType.ArrayElementType, context); int[] rank = typeRef.RankSpecifier ?? new int[0]; Array.Resize(ref rank, rank.Length + 1); - rank[rank.Length - 1] = returnType.CastToArrayReturnType().ArrayDimensions - 1; + rank[rank.Length - 1] = arrayReturnType.ArrayDimensions - 1; typeRef.RankSpecifier = rank; - returnType = returnType.CastToArrayReturnType().ArrayElementType; + return typeRef; + } + PointerReturnType pointerReturnType = returnType.CastToDecoratingReturnType(); + if (pointerReturnType != null) { + TypeReference typeRef = ConvertType(pointerReturnType.BaseType, context); + typeRef.PointerNestingLevel++; + return typeRef; } + + IList typeArguments = EmptyList.Instance; if (returnType.IsConstructedReturnType) { - foreach (IReturnType typeArgument in returnType.CastToConstructedReturnType().TypeArguments) { + typeArguments = returnType.CastToConstructedReturnType().TypeArguments; + } + IClass c = returnType.GetUnderlyingClass(); + if (c != null) { + return CreateTypeReference(c, typeArguments, context); + } else { + TypeReference typeRef; + if (IsPrimitiveType(returnType)) + typeRef = new TypeReference(returnType.FullyQualifiedName, true); + else if (context != null && CanUseShortTypeName(returnType, context)) + typeRef = new TypeReference(returnType.Name); + else + typeRef = new TypeReference(returnType.FullyQualifiedName); + foreach (IReturnType typeArgument in typeArguments) { typeRef.GenericTypes.Add(ConvertType(typeArgument, context)); } + return typeRef; + } + } + + static TypeReference CreateTypeReference(IClass c, IList typeArguments, ClassFinder context) + { + if (c.DeclaringType != null) { + TypeReference outerClass = CreateTypeReference(c.DeclaringType, typeArguments, context); + List args = new List(); + for (int i = c.DeclaringType.TypeParameters.Count; i < Math.Min(c.TypeParameters.Count, typeArguments.Count); i++) { + args.Add(ConvertType(typeArguments[i], context)); + } + return new InnerClassTypeReference(outerClass, c.Name, args); + } else { + TypeReference typeRef; + if (IsPrimitiveType(c.DefaultReturnType)) + typeRef = new TypeReference(c.FullyQualifiedName, true); + else if (context != null && CanUseShortTypeName(c.DefaultReturnType, context)) + typeRef = new TypeReference(c.Name); + else + typeRef = new TypeReference(c.FullyQualifiedName); + for (int i = 0; i < Math.Min(c.TypeParameters.Count, typeArguments.Count); i++) { + typeRef.GenericTypes.Add(ConvertType(typeArguments[i], context)); + } + return typeRef; } - return typeRef; } static bool IsPrimitiveType(IReturnType returnType) @@ -78,9 +118,12 @@ namespace ICSharpCode.SharpDevelop.Dom.Refactoring /// public static bool CanUseShortTypeName(IReturnType returnType, ClassFinder context) { - int typeArgumentCount = (returnType.IsConstructedReturnType) ? returnType.CastToConstructedReturnType().TypeArguments.Count : 0; - IReturnType typeInTargetContext = context.SearchType(returnType.Name, typeArgumentCount); - return typeInTargetContext != null && typeInTargetContext.FullyQualifiedName == returnType.FullyQualifiedName; + if (returnType == null || context == null) + return false; + IReturnType typeInTargetContext = context.SearchType(returnType.Name, returnType.TypeArgumentCount); + return typeInTargetContext != null + && typeInTargetContext.FullyQualifiedName == returnType.FullyQualifiedName + && typeInTargetContext.TypeArgumentCount == returnType.TypeArgumentCount; } public static Modifiers ConvertModifier(ModifierEnum modifiers, ClassFinder targetContext) diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Tests/ICSharpCode.SharpDevelop.Dom.Tests/ICSharpCode.SharpDevelop.Dom.Tests.csproj b/src/Main/ICSharpCode.SharpDevelop.Dom/Tests/ICSharpCode.SharpDevelop.Dom.Tests/ICSharpCode.SharpDevelop.Dom.Tests.csproj index 01b6c38175..4f301408b8 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Tests/ICSharpCode.SharpDevelop.Dom.Tests/ICSharpCode.SharpDevelop.Dom.Tests.csproj +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Tests/ICSharpCode.SharpDevelop.Dom.Tests/ICSharpCode.SharpDevelop.Dom.Tests.csproj @@ -1,4 +1,5 @@ - + + {7DB80259-24D4-46C3-A024-53FF1987733D} Debug @@ -50,6 +51,7 @@ + diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Tests/ICSharpCode.SharpDevelop.Dom.Tests/ImplementInterfaceTests.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Tests/ICSharpCode.SharpDevelop.Dom.Tests/ImplementInterfaceTests.cs new file mode 100644 index 0000000000..62259e718d --- /dev/null +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Tests/ICSharpCode.SharpDevelop.Dom.Tests/ImplementInterfaceTests.cs @@ -0,0 +1,59 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.PrettyPrinter; +using ICSharpCode.SharpDevelop.Dom.Refactoring; +using NUnit.Framework; + +namespace ICSharpCode.SharpDevelop.Dom.Tests +{ + [TestFixture] + public class ImplementInterfaceTests + { + [Test] + public void NestedInterfaceInGenericClass() + { + // See SD2-1626 + DefaultProjectContent pc = new DefaultProjectContent(); + pc.ReferencedContents.Add(SharedProjectContentRegistryForTests.Instance.Mscorlib); + + DefaultCompilationUnit cu = new DefaultCompilationUnit(pc); + DefaultClass container = new DefaultClass(cu, "TestClass"); + container.TypeParameters.Add(new DefaultTypeParameter(container, "T", 0)); + + DefaultClass innerClass = new DefaultClass(cu, container); + innerClass.FullyQualifiedName = "TestClass.INestedInterface"; + innerClass.ClassType = ClassType.Interface; + innerClass.TypeParameters.Add(new DefaultTypeParameter(innerClass, "T", 0)); + innerClass.Properties.Add(new DefaultProperty(innerClass, "P") { + ReturnType = new GenericReturnType(innerClass.TypeParameters[0]), + CanGet = true + }); + container.InnerClasses.Add(innerClass); + pc.AddClassToNamespaceList(container); + + DefaultClass targetClass = new DefaultClass(cu, "TargetClass"); + List nodes = new List(); + + IReturnType interf = new SearchClassReturnType(pc, targetClass, 0, 0, "TestClass.INestedInterface", 1); + interf = new ConstructedReturnType(interf, new IReturnType[] { SharedProjectContentRegistryForTests.Instance.Mscorlib.GetClass("System.String", 0).DefaultReturnType }); + + CSharpCodeGenerator codeGen = new CSharpCodeGenerator(); + codeGen.ImplementInterface(nodes, interf, true, targetClass); + + Assert.AreEqual(1, nodes.Count); + CSharpOutputVisitor output = new CSharpOutputVisitor(); + output.Options.IndentationChar = ' '; + output.Options.IndentSize = 2; + nodes[0].AcceptVisitor(output, null); + Assert.AreEqual("string TestClass.INestedInterface.P {\n get {\n throw new NotImplementedException();\n }\n}", output.Text.Replace("\r", "").Trim()); + } + } +}