From 2c68fb0e7127b14e8139af913f6118ffe5f49e9c Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 4 May 2007 13:32:30 +0000 Subject: [PATCH] Fixed code-completion bugs. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2507 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Src/CodeCompletion/ResolveVisitor.cs | 2 +- .../Misc/UnitTesting/Test/Utils/MockMember.cs | 11 ++++++ .../Misc/UnitTesting/Test/Utils/MockMethod.cs | 11 ++++++ .../RefactoringService/RefactoringService.cs | 17 +++++++++ .../MethodInsightDataProvider.cs | 2 +- src/Main/Base/Test/MemberLookupHelperTests.cs | 33 +++++++++++------ src/Main/Base/Test/NRefactoryResolverTests.cs | 27 ++++++++++++++ src/Main/Base/Test/Utils/MockMethod.cs | 10 ++++++ src/Main/Base/Test/Utils/MockProperty.cs | 10 ++++++ .../Src/Implementations/AbstractMember.cs | 15 ++++++++ .../Implementations/ConstructedReturnType.cs | 8 ++--- .../Project/Src/Interfaces/IMember.cs | 19 +++++++++- .../Project/Src/MemberLookupHelper.cs | 35 +++++++++---------- .../Project/Src/ResolveResult.cs | 15 +------- 14 files changed, 166 insertions(+), 49 deletions(-) diff --git a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ResolveVisitor.cs b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ResolveVisitor.cs index 1c3730f64c..e101c0b717 100644 --- a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ResolveVisitor.cs +++ b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ResolveVisitor.cs @@ -490,7 +490,7 @@ namespace Grunwald.BooBinding.CodeCompletion ResolveResult.AddExtensions(callingClass.ProjectContent.Language, list, callingClass, containingType); foreach (IMethodOrProperty mp in list) { if (IsSameName(mp.Name, methodName) && mp is IMethod) { - IMethod m = (IMethod)mp.Clone(); + IMethod m = (IMethod)mp.CreateSpecializedMember(); m.Parameters.RemoveAt(0); methods.Add(m); } diff --git a/src/AddIns/Misc/UnitTesting/Test/Utils/MockMember.cs b/src/AddIns/Misc/UnitTesting/Test/Utils/MockMember.cs index 06c26e8e5b..98ed1123d7 100644 --- a/src/AddIns/Misc/UnitTesting/Test/Utils/MockMember.cs +++ b/src/AddIns/Misc/UnitTesting/Test/Utils/MockMember.cs @@ -232,5 +232,16 @@ namespace UnitTesting.Tests.Utils throw new NotImplementedException(); } } + + public IMember GenericMember { + get { + throw new NotImplementedException(); + } + } + + public IMember CreateSpecializedMember() + { + throw new NotImplementedException(); + } } } diff --git a/src/AddIns/Misc/UnitTesting/Test/Utils/MockMethod.cs b/src/AddIns/Misc/UnitTesting/Test/Utils/MockMethod.cs index 69981326be..5ea81f2940 100644 --- a/src/AddIns/Misc/UnitTesting/Test/Utils/MockMethod.cs +++ b/src/AddIns/Misc/UnitTesting/Test/Utils/MockMethod.cs @@ -277,5 +277,16 @@ namespace UnitTesting.Tests.Utils throw new NotImplementedException(); } } + + public IMember GenericMember { + get { + throw new NotImplementedException(); + } + } + + public IMember CreateSpecializedMember() + { + throw new NotImplementedException(); + } } } diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs b/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs index 71c28649aa..b3b020579c 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs @@ -463,6 +463,8 @@ namespace ICSharpCode.SharpDevelop.Refactoring /// public static bool IsSimilarMember(IMember member1, IMember member2) { + member1 = GetGenericMember(member1); + member2 = GetGenericMember(member2); do { if (IsSimilarMemberInternal(member1, member2)) return true; @@ -470,6 +472,21 @@ namespace ICSharpCode.SharpDevelop.Refactoring return false; } + /// + /// Gets the generic member from a specialized member. + /// Specialized members are the result of overload resolution with type substitution. + /// + static IMember GetGenericMember(IMember member) + { + // e.g. member = string[] ToArray(IEnumerable input) + // result = T[] ToArray(IEnumerable input) + if (member != null) { + while (member.GenericMember != null) + member = member.GenericMember; + } + return member; + } + static bool IsSimilarMemberInternal(IMember member1, IMember member2) { if (member1 == member2) diff --git a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/MethodInsightDataProvider.cs b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/MethodInsightDataProvider.cs index f628ccb783..2f95feb0a8 100644 --- a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/MethodInsightDataProvider.cs +++ b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/MethodInsightDataProvider.cs @@ -172,7 +172,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor ResolveResult.AddExtensions(language, list, result.CallingClass, result.ContainingType); foreach (IMethodOrProperty mp in list) { if (language.NameComparer.Equals(mp.Name, result.Name) && mp is IMethod) { - DefaultMethod m = (DefaultMethod)mp.Clone(); + DefaultMethod m = (DefaultMethod)mp.CreateSpecializedMember(); // for the insight window, remove first parameter and mark the // method as normal - this is required to show the list of // parameters the method expects. diff --git a/src/Main/Base/Test/MemberLookupHelperTests.cs b/src/Main/Base/Test/MemberLookupHelperTests.cs index 48788db66f..42843e05cf 100644 --- a/src/Main/Base/Test/MemberLookupHelperTests.cs +++ b/src/Main/Base/Test/MemberLookupHelperTests.cs @@ -310,30 +310,43 @@ namespace ICSharpCode.SharpDevelop.Tests } [Test] - public void ConversionExistsFromListOfStringToListOfT() + public void ListOfStringIsApplicableOnListOfT() { - Assert.IsTrue(MemberLookupHelper.ConversionExists(ListOf(msc.SystemTypes.String), - ListOf(CreateT()))); + Assert.IsTrue(MemberLookupHelper.IsApplicable(ListOf(msc.SystemTypes.String), + ListOf(CreateT()))); } [Test] - public void ConversionExistsFromListOfStringToIEnumerableOfT() + public void ListOfStringIsApplicableOnIEnumerableOfT() { - Assert.IsTrue(MemberLookupHelper.ConversionExists(ListOf(msc.SystemTypes.String), - EnumerableOf(CreateT()))); + Assert.IsTrue(MemberLookupHelper.IsApplicable(ListOf(msc.SystemTypes.String), + EnumerableOf(CreateT()))); } [Test] - public void ConversionExistsFromArrayOfStringToIListOfT() + public void ArrayOfStringIsApplicableOnIListOfT() { - Assert.IsTrue(MemberLookupHelper.ConversionExists(new ArrayReturnType(msc, msc.SystemTypes.String, 1), - IListOf(CreateT()))); + Assert.IsTrue(MemberLookupHelper.IsApplicable(new ArrayReturnType(msc, msc.SystemTypes.String, 1), + IListOf(CreateT()))); + + Assert.IsFalse(MemberLookupHelper.ConversionExists(new ArrayReturnType(msc, msc.SystemTypes.String, 1), + IListOf(CreateT()))); + } + + [Test] + public void ArrayOfStringIsApplicableOnArrayOfT() + { + Assert.IsTrue(MemberLookupHelper.IsApplicable(new ArrayReturnType(msc, msc.SystemTypes.String, 1), + new ArrayReturnType(msc, CreateT(), 1))); + + Assert.IsFalse(MemberLookupHelper.ConversionExists(new ArrayReturnType(msc, msc.SystemTypes.String, 1), + new ArrayReturnType(msc, CreateT(), 1))); } [Test] public void ConversionExistsFromAnonymousDelegateToSystemPredicate() { - Assert.IsTrue(MemberLookupHelper.ConversionExists( + Assert.IsTrue(MemberLookupHelper.IsApplicable( new AnonymousMethodReturnType(new DefaultCompilationUnit(msc)), new GetClassReturnType(msc, "System.Predicate", 1) )); diff --git a/src/Main/Base/Test/NRefactoryResolverTests.cs b/src/Main/Base/Test/NRefactoryResolverTests.cs index e43285a06a..c4eabdf20c 100644 --- a/src/Main/Base/Test/NRefactoryResolverTests.cs +++ b/src/Main/Base/Test/NRefactoryResolverTests.cs @@ -116,6 +116,33 @@ namespace ICSharpCode.SharpDevelop.Tests Assert.AreEqual(typeof(T), rr.GetType()); return (T)rr; } + + [Test] + public void GenericMethodInstanciation() + { + string program = @"using System; +using System.Collections.Generic; +class TestClass { + void Main() { + + } + static T First(IEnumerable input) { + foreach (T e in input) return e; + throw new EmptyCollectionException(); + } +} +"; + MemberResolveResult mrr = Resolve(program, "First(new string[0])", 5); + Assert.AreEqual("System.String", mrr.ResolvedType.FullyQualifiedName); + Assert.AreEqual("System.String", mrr.ResolvedMember.ReturnType.FullyQualifiedName); + + IMethod genericMethod = mrr.ResolvedMember.DeclaringType.Methods[1]; + Assert.AreEqual("T", genericMethod.ReturnType.FullyQualifiedName); + + // ensure that the reference pointing to the specialized method is seen as a reference + // to the generic method. + Assert.IsTrue(Refactoring.RefactoringService.IsReferenceToMember(genericMethod, mrr)); + } #endregion #region Test for old issues (Fidalgo) diff --git a/src/Main/Base/Test/Utils/MockMethod.cs b/src/Main/Base/Test/Utils/MockMethod.cs index 5cea0882bd..097b4befc4 100644 --- a/src/Main/Base/Test/Utils/MockMethod.cs +++ b/src/Main/Base/Test/Utils/MockMethod.cs @@ -272,5 +272,15 @@ namespace ICSharpCode.SharpDevelop.Tests.Utils throw new NotImplementedException(); } + public IMember GenericMember { + get { + throw new NotImplementedException(); + } + } + + public IMember CreateSpecializedMember() + { + throw new NotImplementedException(); + } } } diff --git a/src/Main/Base/Test/Utils/MockProperty.cs b/src/Main/Base/Test/Utils/MockProperty.cs index 37afcc370c..13b28785f0 100644 --- a/src/Main/Base/Test/Utils/MockProperty.cs +++ b/src/Main/Base/Test/Utils/MockProperty.cs @@ -290,5 +290,15 @@ namespace ICSharpCode.SharpDevelop.Tests.Utils throw new NotImplementedException(); } + public IMember GenericMember { + get { + throw new NotImplementedException(); + } + } + + public IMember CreateSpecializedMember() + { + throw new NotImplementedException(); + } } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractMember.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractMember.cs index 7b1f55805d..d02f7cf949 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractMember.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractMember.cs @@ -73,5 +73,20 @@ namespace ICSharpCode.SharpDevelop.Dom { return this.Clone(); } + + IMember genericMember; + + public virtual IMember GenericMember { + get { return genericMember; } + } + + public virtual IMember CreateSpecializedMember() + { + AbstractMember copy = Clone() as AbstractMember; + if (copy == null) + throw new Exception("Clone() must return an AbstractMember instance, or CreateSpecializedMember must also be overridden."); + copy.genericMember = this; + return copy; + } } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ConstructedReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ConstructedReturnType.cs index ff13f06f66..8310518819 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ConstructedReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ConstructedReturnType.cs @@ -174,7 +174,7 @@ namespace ICSharpCode.SharpDevelop.Dom List l = baseType.GetMethods(); for (int i = 0; i < l.Count; ++i) { if (CheckReturnType(l[i].ReturnType) || CheckParameters(l[i].Parameters)) { - l[i] = (IMethod)l[i].Clone(); + l[i] = (IMethod)l[i].CreateSpecializedMember(); if (l[i].DeclaringType == baseType.GetUnderlyingClass()) { l[i].DeclaringTypeReference = this; } @@ -192,7 +192,7 @@ namespace ICSharpCode.SharpDevelop.Dom List l = baseType.GetProperties(); for (int i = 0; i < l.Count; ++i) { if (CheckReturnType(l[i].ReturnType) || CheckParameters(l[i].Parameters)) { - l[i] = (IProperty)l[i].Clone(); + l[i] = (IProperty)l[i].CreateSpecializedMember(); if (l[i].DeclaringType == baseType.GetUnderlyingClass()) { l[i].DeclaringTypeReference = this; } @@ -210,7 +210,7 @@ namespace ICSharpCode.SharpDevelop.Dom List l = baseType.GetFields(); for (int i = 0; i < l.Count; ++i) { if (CheckReturnType(l[i].ReturnType)) { - l[i] = (IField)l[i].Clone(); + l[i] = (IField)l[i].CreateSpecializedMember(); if (l[i].DeclaringType == baseType.GetUnderlyingClass()) { l[i].DeclaringTypeReference = this; } @@ -225,7 +225,7 @@ namespace ICSharpCode.SharpDevelop.Dom List l = baseType.GetEvents(); for (int i = 0; i < l.Count; ++i) { if (CheckReturnType(l[i].ReturnType)) { - l[i] = (IEvent)l[i].Clone(); + l[i] = (IEvent)l[i].CreateSpecializedMember(); if (l[i].DeclaringType == baseType.GetUnderlyingClass()) { l[i].DeclaringTypeReference = this; } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IMember.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IMember.cs index e03a136afa..b1ccf3bf05 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IMember.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IMember.cs @@ -18,13 +18,30 @@ namespace ICSharpCode.SharpDevelop.Dom /// /// Gets/Sets the declaring type reference (declaring type incl. type arguments). - /// If set to null, the getter returns the default type reference to the . + /// Never returns null, if the property is set to null (e.g. when this is not a specialized member), + /// it should return the default type reference to the . /// IReturnType DeclaringTypeReference { get; set; } + /// + /// Gets the generic member this member is based on. + /// Returns null if this is not a specialized member. + /// Specialized members are the result of overload resolution with type substitution. + /// + IMember GenericMember { + get; + } + + /// + /// Creates a copy of this member with its GenericMember property set to this member. + /// Use this method to create copies of a member that should be regarded as the "same member" + /// for refactoring purposes. + /// + IMember CreateSpecializedMember(); + /// /// Declaration region of the member (without body!) /// diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs index 2336c096e8..2537f26634 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs @@ -104,7 +104,7 @@ namespace ICSharpCode.SharpDevelop.Dom for (int i = 0; i < list.Count; i++) { IMethod m = list[i]; if (m.TypeParameters.Count == typeParameters.Length) { - m = (IMethod)m.Clone(); + m = (IMethod)m.CreateSpecializedMember(); m.ReturnType = ConstructedReturnType.TranslateType(m.ReturnType, typeParameters, true); for (int j = 0; j < m.Parameters.Count; ++j) { m.Parameters[j].ReturnType = ConstructedReturnType.TranslateType(m.Parameters[j].ReturnType, typeParameters, true); @@ -144,7 +144,7 @@ namespace ICSharpCode.SharpDevelop.Dom for (int i = 0; i < list.Count; i++) { IReturnType[] inferred = inferredTypeParameters[i]; if (inferred != null && inferred.Length > 0) { - IMethod m = (IMethod)list[i].Clone(); + IMethod m = (IMethod)list[i].CreateSpecializedMember(); m.ReturnType = ConstructedReturnType.TranslateType(m.ReturnType, inferred, true); for (int j = 0; j < m.Parameters.Count; ++j) { m.Parameters[j].ReturnType = ConstructedReturnType.TranslateType(m.Parameters[j].ReturnType, inferred, true); @@ -524,16 +524,7 @@ namespace ICSharpCode.SharpDevelop.Dom { if (argument == null || argument == NullReturnType.Instance) return true; // "null" can be passed for any argument - if (expected.IsGenericReturnType) { - foreach (IReturnType constraint in expected.CastToGenericReturnType().TypeParameter.Constraints) { - if (!ConversionExists(argument, constraint)) { - return false; - } - } - return true; - } else { - return ConversionExists(argument, expected); - } + return ConversionExistsInternal(argument, expected, true); } #endregion @@ -542,6 +533,11 @@ namespace ICSharpCode.SharpDevelop.Dom /// Checks if an implicit conversion exists from to . /// public static bool ConversionExists(IReturnType from, IReturnType to) + { + return ConversionExistsInternal(from, to, false); + } + + static bool ConversionExistsInternal(IReturnType from, IReturnType to, bool allowGenericTarget) { // ECMA-334, ยง 13.1 Implicit conversions @@ -584,11 +580,11 @@ namespace ICSharpCode.SharpDevelop.Dom return true; // from any type to object } - if ((toIsDefault || to.IsConstructedReturnType) + if ((toIsDefault || to.IsConstructedReturnType || to.IsGenericReturnType) && (fromIsDefault || from.IsArrayReturnType || from.IsConstructedReturnType)) { foreach (IReturnType baseTypeOfFrom in GetTypeInheritanceTree(from)) { - if (IsConstructedConversionToGenericReturnType(baseTypeOfFrom, to)) + if (IsConstructedConversionToGenericReturnType(baseTypeOfFrom, to, allowGenericTarget)) return true; } } @@ -598,7 +594,7 @@ namespace ICSharpCode.SharpDevelop.Dom ArrayReturnType toArt = to.CastToArrayReturnType(); // from array to other array type if (fromArt.ArrayDimensions == toArt.ArrayDimensions) { - return ConversionExists(fromArt.ArrayElementType, toArt.ArrayElementType); + return ConversionExistsInternal(fromArt.ArrayElementType, toArt.ArrayElementType, allowGenericTarget); } } @@ -622,14 +618,17 @@ namespace ICSharpCode.SharpDevelop.Dom return false; } - static bool IsConstructedConversionToGenericReturnType(IReturnType from, IReturnType to) + static bool IsConstructedConversionToGenericReturnType(IReturnType from, IReturnType to, bool allowGenericTarget) { if (from.Equals(to)) return true; + if (!allowGenericTarget) + return false; + if (to.IsGenericReturnType) { foreach (IReturnType constraintType in to.CastToGenericReturnType().TypeParameter.Constraints) { - if (!ConversionExists(from, constraintType)) { + if (!ConversionExistsInternal(from, constraintType, allowGenericTarget)) { return false; } } @@ -642,7 +641,7 @@ namespace ICSharpCode.SharpDevelop.Dom if (cFrom != null && cTo != null) { if (cFrom.FullyQualifiedName == cTo.FullyQualifiedName && cFrom.TypeArguments.Count == cTo.TypeArguments.Count) { for (int i = 0; i < cFrom.TypeArguments.Count; i++) { - if (!IsConstructedConversionToGenericReturnType(cFrom.TypeArguments[i], cTo.TypeArguments[i])) + if (!IsConstructedConversionToGenericReturnType(cFrom.TypeArguments[i], cTo.TypeArguments[i], allowGenericTarget)) return false; } return true; diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs index 45798ae0e0..97cce37cc3 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs @@ -124,19 +124,6 @@ namespace ICSharpCode.SharpDevelop.Dom static void TryAddExtension(LanguageProperties language, ArrayList res, IMethodOrProperty ext, IReturnType resolvedType) { - // accept only extension methods - if (!ext.IsExtensionMethod) - return; - // don't add extension if method with that name already exists - // but allow overloading extension methods - foreach (IMember member in res) { - IMethodOrProperty p = member as IMethodOrProperty; - if (p != null && p.IsExtensionMethod) - continue; - if (language.NameComparer.Equals(member.Name, ext.Name)) { - return; - } - } // now add the extension method if it fits the type if (MemberLookupHelper.IsApplicable(resolvedType, ext.Parameters[0].ReturnType)) { IMethod method = ext as IMethod; @@ -145,7 +132,7 @@ namespace ICSharpCode.SharpDevelop.Dom MemberLookupHelper.InferTypeArgument(method.Parameters[0].ReturnType, resolvedType, typeArguments); for (int i = 0; i < typeArguments.Length; i++) { if (typeArguments[i] != null) { - ext = (IMethod)ext.Clone(); + ext = (IMethod)ext.CreateSpecializedMember(); ext.ReturnType = ConstructedReturnType.TranslateType(ext.ReturnType, typeArguments, true); for (int j = 0; j < ext.Parameters.Count; ++j) { ext.Parameters[j].ReturnType = ConstructedReturnType.TranslateType(ext.Parameters[j].ReturnType, typeArguments, true);