Browse Source

Fixed forum-7497: Wrong generic overload resolution in tooltip (when a generic method was called from another generic method)

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2991 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 18 years ago
parent
commit
111e507419
  1. 1
      src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/SelectReferenceDialog.cs
  2. 24
      src/Main/Base/Test/GenericResolverTests.cs
  3. 51
      src/Main/Base/Test/MemberLookupHelperTests.cs
  4. 52
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs
  5. 2
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/DomPersistence.cs
  6. 2
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs

1
src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/SelectReferenceDialog.cs

@ -282,6 +282,7 @@ namespace ICSharpCode.SharpDevelop.Gui @@ -282,6 +282,7 @@ namespace ICSharpCode.SharpDevelop.Gui
this.okButton.Size = new System.Drawing.Size(75, 23);
this.okButton.TabIndex = 5;
this.okButton.Text = "${res:Global.OKButtonText}";
this.okButton.Click += new System.EventHandler(this.OkButtonClick);
//
// cancelButton
//

24
src/Main/Base/Test/GenericResolverTests.cs

@ -392,6 +392,30 @@ class D : Program { @@ -392,6 +392,30 @@ class D : Program {
Assert.IsNotNull(baseMember);
Assert.AreEqual("Program.T<A, B>", ambience.Convert((IMethod)baseMember));
}
[Test]
public void PassGenericArgumentOnToOtherGenericMethod()
{
string program = @"class T {
static void Test<ValueT>(ValueT v, int iKey) {
}
}
class TestClass<T> {
public static bool Equals(T a, T b) { return false; }
}";
MemberResolveResult mrr;
mrr = Resolve<MemberResolveResult>(program, "TestClass<ValueT>.Equals(v, default(ValueT))", 3);
Assert.AreEqual("TestClass.Equals", mrr.ResolvedMember.FullyQualifiedName);
mrr = Resolve<MemberResolveResult>(program, "TestClass<int>.Equals(v, default(ValueT))", 3);
Assert.AreEqual("System.Object.Equals", mrr.ResolvedMember.FullyQualifiedName);
mrr = Resolve<MemberResolveResult>(program, "TestClass<ValueT>.Equals(v, default(object))", 3);
Assert.AreEqual("System.Object.Equals", mrr.ResolvedMember.FullyQualifiedName);
}
#endregion
}
}

51
src/Main/Base/Test/MemberLookupHelperTests.cs

@ -19,6 +19,7 @@ namespace ICSharpCode.SharpDevelop.Tests @@ -19,6 +19,7 @@ namespace ICSharpCode.SharpDevelop.Tests
{
IProjectContent msc; // = ProjectContentRegistry.Mscorlib;
IProjectContent swf; // = ProjectContentRegistry.GetProjectContentForReference("System.Windows.Forms", "System.Windows.Forms");
IMethod methodForGenericCalls;
[TestFixtureSetUp]
public void FixtureSetup()
@ -26,6 +27,14 @@ namespace ICSharpCode.SharpDevelop.Tests @@ -26,6 +27,14 @@ namespace ICSharpCode.SharpDevelop.Tests
ProjectContentRegistry r = new ProjectContentRegistry();
msc = r.Mscorlib;
swf = r.GetProjectContentForReference("System.Windows.Forms", "System.Windows.Forms");
DefaultProjectContent dpc = new DefaultProjectContent();
dpc.ReferencedContents.Add(msc);
DefaultCompilationUnit cu = new DefaultCompilationUnit(dpc);
DefaultClass c = new DefaultClass(cu, "DummyClass");
cu.Classes.Add(c);
methodForGenericCalls = new DefaultMethod(c, "DummyMethod");
c.Methods.Add(methodForGenericCalls);
}
IReturnType DictionaryRT {
@ -275,17 +284,15 @@ namespace ICSharpCode.SharpDevelop.Tests @@ -275,17 +284,15 @@ namespace ICSharpCode.SharpDevelop.Tests
ListOf(msc.SystemTypes.String)));
}
bool IsApplicable(IReturnType argument, IReturnType expected)
{
return MemberLookupHelper.IsApplicable(argument, expected, methodForGenericCalls);
}
GenericReturnType CreateT()
{
DefaultProjectContent dpc = new DefaultProjectContent();
dpc.ReferencedContents.Add(msc);
DefaultCompilationUnit cu = new DefaultCompilationUnit(dpc);
DefaultClass c = new DefaultClass(cu, "DummyClass");
cu.Classes.Add(c);
DefaultMethod m = new DefaultMethod(c, "DummyMethod");
c.Methods.Add(m);
m.TypeParameters.Add(new DefaultTypeParameter(m, "T", 0));
return new GenericReturnType(m.TypeParameters[0]);
ITypeParameter tp = new DefaultTypeParameter(methodForGenericCalls, "T", 0);
return new GenericReturnType(tp);
}
GenericReturnType CreateTWithDisposableConstraint()
@ -303,14 +310,14 @@ namespace ICSharpCode.SharpDevelop.Tests @@ -303,14 +310,14 @@ namespace ICSharpCode.SharpDevelop.Tests
CreateT()));
// but it is applicable
Assert.IsTrue(MemberLookupHelper.IsApplicable(msc.SystemTypes.String,
Assert.IsTrue(IsApplicable(msc.SystemTypes.String,
CreateT()));
}
[Test]
public void NoConversionExistsFromStringToDisposableT()
{
Assert.IsFalse(MemberLookupHelper.IsApplicable(msc.SystemTypes.String,
Assert.IsFalse(IsApplicable(msc.SystemTypes.String,
CreateTWithDisposableConstraint()));
Assert.IsFalse(MemberLookupHelper.ConversionExists(msc.SystemTypes.String,
@ -323,29 +330,29 @@ namespace ICSharpCode.SharpDevelop.Tests @@ -323,29 +330,29 @@ namespace ICSharpCode.SharpDevelop.Tests
Assert.IsFalse(MemberLookupHelper.ConversionExists(msc.GetClass("System.CharEnumerator", 0).DefaultReturnType,
CreateTWithDisposableConstraint()));
Assert.IsTrue(MemberLookupHelper.IsApplicable(msc.GetClass("System.CharEnumerator", 0).DefaultReturnType,
CreateTWithDisposableConstraint()));
Assert.IsTrue(IsApplicable(msc.GetClass("System.CharEnumerator", 0).DefaultReturnType,
CreateTWithDisposableConstraint()));
}
[Test]
public void ListOfStringIsApplicableOnListOfT()
{
Assert.IsTrue(MemberLookupHelper.IsApplicable(ListOf(msc.SystemTypes.String),
ListOf(CreateT())));
Assert.IsTrue(IsApplicable(ListOf(msc.SystemTypes.String),
ListOf(CreateT())));
}
[Test]
public void ListOfStringIsApplicableOnIEnumerableOfT()
{
Assert.IsTrue(MemberLookupHelper.IsApplicable(ListOf(msc.SystemTypes.String),
EnumerableOf(CreateT())));
Assert.IsTrue(IsApplicable(ListOf(msc.SystemTypes.String),
EnumerableOf(CreateT())));
}
[Test]
public void ArrayOfStringIsApplicableOnIListOfT()
{
Assert.IsTrue(MemberLookupHelper.IsApplicable(new ArrayReturnType(msc, msc.SystemTypes.String, 1),
IListOf(CreateT())));
Assert.IsTrue(IsApplicable(new ArrayReturnType(msc, msc.SystemTypes.String, 1),
IListOf(CreateT())));
Assert.IsFalse(MemberLookupHelper.ConversionExists(new ArrayReturnType(msc, msc.SystemTypes.String, 1),
IListOf(CreateT())));
@ -354,8 +361,8 @@ namespace ICSharpCode.SharpDevelop.Tests @@ -354,8 +361,8 @@ namespace ICSharpCode.SharpDevelop.Tests
[Test]
public void ArrayOfStringIsApplicableOnArrayOfT()
{
Assert.IsTrue(MemberLookupHelper.IsApplicable(new ArrayReturnType(msc, msc.SystemTypes.String, 1),
new ArrayReturnType(msc, CreateT(), 1)));
Assert.IsTrue(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)));
@ -364,7 +371,7 @@ namespace ICSharpCode.SharpDevelop.Tests @@ -364,7 +371,7 @@ namespace ICSharpCode.SharpDevelop.Tests
[Test]
public void ConversionExistsFromAnonymousDelegateToSystemPredicate()
{
Assert.IsTrue(MemberLookupHelper.IsApplicable(
Assert.IsTrue(IsApplicable(
new AnonymousMethodReturnType(new DefaultCompilationUnit(msc)),
new GetClassReturnType(msc, "System.Predicate", 1)
));

52
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs

@ -335,7 +335,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -335,7 +335,7 @@ namespace ICSharpCode.SharpDevelop.Dom
int score;
bool expanded;
for (int i = 0; i < list.Count; i++) {
if (IsApplicable(list[i].Parameters, arguments, allowAdditionalArguments, out score, out expanded)) {
if (IsApplicable(list[i], arguments, allowAdditionalArguments, out score, out expanded)) {
acceptableMatch = true;
score = int.MaxValue;
} else {
@ -619,7 +619,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -619,7 +619,7 @@ namespace ICSharpCode.SharpDevelop.Dom
#endregion
#region IsApplicable
static bool IsApplicable(IList<IParameter> parameters,
static bool IsApplicable(IMethodOrProperty targetMethodOrProperty,
IReturnType[] arguments,
bool allowAdditionalArguments,
out int score,
@ -627,6 +627,8 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -627,6 +627,8 @@ namespace ICSharpCode.SharpDevelop.Dom
{
// see ECMA-334, § 14.4.2.1
IList<IParameter> parameters = targetMethodOrProperty.Parameters;
IMethod targetMethod = targetMethodOrProperty as IMethod;
expanded = false;
score = 0;
if (parameters.Count == 0)
@ -638,7 +640,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -638,7 +640,7 @@ namespace ICSharpCode.SharpDevelop.Dom
// check all arguments except the last
bool ok = true;
for (int i = 0; i < Math.Min(lastParameter, arguments.Length); i++) {
if (IsApplicable(arguments[i], parameters[i])) {
if (IsApplicable(arguments[i], parameters[i], targetMethod)) {
score++;
} else {
ok = false;
@ -649,7 +651,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -649,7 +651,7 @@ namespace ICSharpCode.SharpDevelop.Dom
}
if (parameters.Count == arguments.Length) {
// try if method is applicable in normal form by checking last argument
if (IsApplicable(arguments[lastParameter], parameters[lastParameter])) {
if (IsApplicable(arguments[lastParameter], parameters[lastParameter], targetMethod)) {
return true;
}
}
@ -667,7 +669,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -667,7 +669,7 @@ namespace ICSharpCode.SharpDevelop.Dom
return false;
}
for (int i = lastParameter; i < arguments.Length; i++) {
if (IsApplicable(arguments[i], rt.CastToArrayReturnType().ArrayElementType)) {
if (IsApplicable(arguments[i], rt.CastToArrayReturnType().ArrayElementType, targetMethod)) {
score++;
} else {
ok = false;
@ -676,7 +678,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -676,7 +678,7 @@ namespace ICSharpCode.SharpDevelop.Dom
return ok;
}
static bool IsApplicable(IReturnType argument, IParameter expected)
static bool IsApplicable(IReturnType argument, IParameter expected, IMethod targetMethod)
{
bool parameterIsRefOrOut = expected.IsRef || expected.IsOut;
bool argumentIsRefOrOut = argument != null && argument.IsDecoratingReturnType<ReferenceReturnType>();
@ -685,13 +687,19 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -685,13 +687,19 @@ namespace ICSharpCode.SharpDevelop.Dom
if (parameterIsRefOrOut) {
return object.Equals(argument, expected.ReturnType);
} else {
return IsApplicable(argument, expected.ReturnType);
return IsApplicable(argument, expected.ReturnType, targetMethod);
}
}
public static bool IsApplicable(IReturnType argument, IReturnType expected)
/// <summary>
/// Tests whether an argument of type "argument" is valid for a parameter of type "expected" for a call
/// to "targetMethod".
/// targetMethod may be null, it is only used when it is a generic method and expected is (or contains) one of
/// its type parameters.
/// </summary>
public static bool IsApplicable(IReturnType argument, IReturnType expected, IMethod targetMethod)
{
return ConversionExistsInternal(argument, expected, true);
return ConversionExistsInternal(argument, expected, targetMethod);
}
#endregion
@ -701,10 +709,15 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -701,10 +709,15 @@ namespace ICSharpCode.SharpDevelop.Dom
/// </summary>
public static bool ConversionExists(IReturnType from, IReturnType to)
{
return ConversionExistsInternal(from, to, false);
return ConversionExistsInternal(from, to, null);
}
static bool ConversionExistsInternal(IReturnType from, IReturnType to, bool allowGenericTarget)
/// <summary>
/// Tests if an implicit conversion exists from "from" to "to".
/// Conversions from concrete types to generic types are only allowed when the generic type belongs to the
/// method "allowGenericTargetsOnThisMethod".
/// </summary>
static bool ConversionExistsInternal(IReturnType from, IReturnType to, IMethod allowGenericTargetsOnThisMethod)
{
// ECMA-334, § 13.1 Implicit conversions
@ -765,7 +778,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -765,7 +778,7 @@ namespace ICSharpCode.SharpDevelop.Dom
&& (fromIsDefault || from.IsArrayReturnType || from.IsConstructedReturnType))
{
foreach (IReturnType baseTypeOfFrom in GetTypeInheritanceTree(from)) {
if (IsConstructedConversionToGenericReturnType(baseTypeOfFrom, to, allowGenericTarget))
if (IsConstructedConversionToGenericReturnType(baseTypeOfFrom, to, allowGenericTargetsOnThisMethod))
return true;
}
}
@ -775,7 +788,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -775,7 +788,7 @@ namespace ICSharpCode.SharpDevelop.Dom
ArrayReturnType toArt = to.CastToArrayReturnType();
// from array to other array type
if (fromArt.ArrayDimensions == toArt.ArrayDimensions) {
return ConversionExistsInternal(fromArt.ArrayElementType, toArt.ArrayElementType, allowGenericTarget);
return ConversionExistsInternal(fromArt.ArrayElementType, toArt.ArrayElementType, allowGenericTargetsOnThisMethod);
}
}
@ -799,7 +812,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -799,7 +812,7 @@ namespace ICSharpCode.SharpDevelop.Dom
return false;
}
static bool IsConstructedConversionToGenericReturnType(IReturnType from, IReturnType to, bool allowGenericTarget)
static bool IsConstructedConversionToGenericReturnType(IReturnType from, IReturnType to, IMethod allowGenericTargetsOnThisMethod)
{
// null could be passed when type arguments could not be resolved/inferred
if (from == null && to == null)
@ -810,12 +823,15 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -810,12 +823,15 @@ namespace ICSharpCode.SharpDevelop.Dom
if (from.Equals(to))
return true;
if (!allowGenericTarget)
if (allowGenericTargetsOnThisMethod == null)
return false;
if (to.IsGenericReturnType) {
foreach (IReturnType constraintType in to.CastToGenericReturnType().TypeParameter.Constraints) {
if (!ConversionExistsInternal(from, constraintType, allowGenericTarget)) {
ITypeParameter typeParameter = to.CastToGenericReturnType().TypeParameter;
if (typeParameter.Method != allowGenericTargetsOnThisMethod)
return false;
foreach (IReturnType constraintType in typeParameter.Constraints) {
if (!ConversionExistsInternal(from, constraintType, allowGenericTargetsOnThisMethod)) {
return false;
}
}
@ -828,7 +844,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -828,7 +844,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], allowGenericTarget))
if (!IsConstructedConversionToGenericReturnType(cFrom.TypeArguments[i], cTo.TypeArguments[i], allowGenericTargetsOnThisMethod))
return false;
}
return true;

2
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/DomPersistence.cs

@ -20,7 +20,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -20,7 +20,7 @@ namespace ICSharpCode.SharpDevelop.Dom
{
public const long FileMagic = 0x11635233ED2F428C;
public const long IndexFileMagic = 0x11635233ED2F427D;
public const short FileVersion = 14;
public const short FileVersion = 15;
ProjectContentRegistry registry;
string cacheDirectory;

2
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs

@ -117,7 +117,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -117,7 +117,7 @@ namespace ICSharpCode.SharpDevelop.Dom
static void TryAddExtension(LanguageProperties language, ArrayList res, IMethodOrProperty ext, IReturnType resolvedType)
{
// now add the extension method if it fits the type
if (MemberLookupHelper.IsApplicable(resolvedType, ext.Parameters[0].ReturnType)) {
if (MemberLookupHelper.IsApplicable(resolvedType, ext.Parameters[0].ReturnType, ext as IMethod)) {
IMethod method = ext as IMethod;
if (method != null && method.TypeParameters.Count > 0) {
IReturnType[] typeArguments = new IReturnType[method.TypeParameters.Count];

Loading…
Cancel
Save