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);