Browse Source

Fix #2741: CallBuilder produces invalid invocation target when disambiguating calls to protected methods.

pull/2747/head
Siegfried Pammer 3 years ago
parent
commit
fbafc0289b
  1. 59
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs
  2. 14
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  3. 5
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

59
ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs

@ -37,6 +37,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
CallAmbiguousOutParam(); CallAmbiguousOutParam();
CallWithInParam(); CallWithInParam();
Issue2444.M2(); Issue2444.M2();
Issue2741.B.Test(new Issue2741.C());
} }
#region ConstructorTest #region ConstructorTest
@ -366,6 +367,64 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Console.WriteLine("#2444: after M1"); Console.WriteLine("#2444: after M1");
} }
} }
public class Issue2741
{
public class B
{
private void M()
{
Console.WriteLine("B::M");
}
protected void M2()
{
Console.WriteLine("B::M2");
}
protected void M3()
{
Console.WriteLine("B::M3");
}
protected void M4()
{
Console.WriteLine("B::M4");
}
public static void Test(C c)
{
((B)c).M();
((B)c).M2();
c.Test();
}
}
public class C : B
{
public void M()
{
Console.WriteLine("C::M");
}
public new void M2()
{
Console.WriteLine("C::M2");
}
public new void M3()
{
Console.WriteLine("C::M3");
}
public void Test()
{
M3();
base.M3();
M4();
}
}
}
#endregion #endregion
} }

14
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -917,7 +917,7 @@ namespace ICSharpCode.Decompiler.CSharp
else if (target.Expression is BaseReferenceExpression) else if (target.Expression is BaseReferenceExpression)
requireTarget = (expectedTargetDetails.CallOpCode != OpCode.CallVirt && method.IsVirtual); requireTarget = (expectedTargetDetails.CallOpCode != OpCode.CallVirt && method.IsVirtual);
else else
requireTarget = !(target.Expression is ThisReferenceExpression); requireTarget = target.Expression is not ThisReferenceExpression;
} }
targetResolveResult = requireTarget ? target.ResolveResult : null; targetResolveResult = requireTarget ? target.ResolveResult : null;
} }
@ -962,6 +962,8 @@ namespace ICSharpCode.Decompiler.CSharp
bool targetCasted = false; bool targetCasted = false;
bool argumentsCasted = false; bool argumentsCasted = false;
bool originalRequireTarget = requireTarget;
bool skipTargetCast = method.Accessibility <= Accessibility.Protected && expressionBuilder.IsBaseTypeOfCurrentType(method.DeclaringTypeDefinition);
OverloadResolutionErrors errors; OverloadResolutionErrors errors;
while ((errors = IsUnambiguousCall(expectedTargetDetails, method, targetResolveResult, typeArguments, while ((errors = IsUnambiguousCall(expectedTargetDetails, method, targetResolveResult, typeArguments,
argumentList.GetArgumentResolveResults().ToArray(), argumentList.ArgumentNames, argumentList.FirstOptionalArgumentIndex, out foundMethod, argumentList.GetArgumentResolveResults().ToArray(), argumentList.ArgumentNames, argumentList.FirstOptionalArgumentIndex, out foundMethod,
@ -1014,11 +1016,21 @@ namespace ICSharpCode.Decompiler.CSharp
targetResolveResult = target.ResolveResult; targetResolveResult = target.ResolveResult;
} }
else if ((allowedTransforms & CallTransformation.RequireTarget) != 0 && !targetCasted) else if ((allowedTransforms & CallTransformation.RequireTarget) != 0 && !targetCasted)
{
if (skipTargetCast && requireTarget != originalRequireTarget)
{
requireTarget = originalRequireTarget;
if (!originalRequireTarget)
targetResolveResult = null;
allowedTransforms &= ~CallTransformation.RequireTarget;
}
else
{ {
targetCasted = true; targetCasted = true;
target = target.ConvertTo(method.DeclaringType, expressionBuilder); target = target.ConvertTo(method.DeclaringType, expressionBuilder);
targetResolveResult = target.ResolveResult; targetResolveResult = target.ResolveResult;
} }
}
else if ((allowedTransforms & CallTransformation.RequireTypeArguments) != 0 && !requireTypeArguments) else if ((allowedTransforms & CallTransformation.RequireTypeArguments) != 0 && !requireTypeArguments)
{ {
requireTypeArguments = true; requireTypeArguments = true;

5
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -2272,6 +2272,11 @@ namespace ICSharpCode.Decompiler.CSharp
return false; return false;
} }
internal bool IsBaseTypeOfCurrentType(ITypeDefinition type)
{
return decompilationContext.CurrentTypeDefinition.GetAllBaseTypeDefinitions().Any(t => t == type);
}
internal ExpressionWithResolveResult TranslateFunction(IType delegateType, ILFunction function) internal ExpressionWithResolveResult TranslateFunction(IType delegateType, ILFunction function)
{ {
var method = function.Method?.MemberDefinition as IMethod; var method = function.Method?.MemberDefinition as IMethod;

Loading…
Cancel
Save