Browse Source

Fix #3626: Do not emit named arguments for bool constants, if it causes the call to become ambiguous.

pull/3620/head
Siegfried Pammer 1 month ago
parent
commit
d70a5e7fb2
  1. 28
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.cs
  2. 72
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs

28
ICSharpCode.Decompiler.Tests/TestCases/Pretty/NamedArguments.cs

@ -32,6 +32,34 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -32,6 +32,34 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
private class MustNotUseNamedArgsInCtor
{
public MustNotUseNamedArgsInCtor(string start = "", bool enable = false)
{
}
public MustNotUseNamedArgsInCtor(bool enable, string start = "")
{
}
public static MustNotUseNamedArgsInCtor Use()
{
// second overload
MustNotUseNamedArgsInCall(true);
// first overload
MustNotUseNamedArgsInCall();
return new MustNotUseNamedArgsInCtor(true);
}
public static void MustNotUseNamedArgsInCall(string start = "", bool enable = false)
{
}
public static void MustNotUseNamedArgsInCall(bool enable, string start = "")
{
}
}
public void Use(int a, int b, int c)
{
}

72
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -64,6 +64,30 @@ namespace ICSharpCode.Decompiler.CSharp @@ -64,6 +64,30 @@ namespace ICSharpCode.Decompiler.CSharp
return FirstOptionalArgumentIndex;
}
public string[] GetArgumentNames(int skipCount = 0)
{
string[] argumentNames = ArgumentNames;
if (AddNamesToPrimitiveValues && IsPrimitiveValue.Any() && !IsExpandedForm
&& !ParameterNames.Any(string.IsNullOrEmpty))
{
Debug.Assert(skipCount == 0);
if (argumentNames == null)
{
argumentNames = new string[Arguments.Length];
}
for (int i = 0; i < Arguments.Length; i++)
{
if (IsPrimitiveValue[i] && argumentNames[i] == null)
{
argumentNames[i] = ParameterNames[i];
}
}
}
return argumentNames;
}
public IList<ResolveResult> GetArgumentResolveResults(int skipCount = 0)
{
var expectedParameters = ExpectedParameters;
@ -95,33 +119,17 @@ namespace ICSharpCode.Decompiler.CSharp @@ -95,33 +119,17 @@ namespace ICSharpCode.Decompiler.CSharp
public IEnumerable<Expression> GetArgumentExpressions(int skipCount = 0)
{
if (AddNamesToPrimitiveValues && IsPrimitiveValue.Any() && !IsExpandedForm
&& !ParameterNames.Any(p => string.IsNullOrEmpty(p)))
{
Debug.Assert(skipCount == 0);
if (ArgumentNames == null)
{
ArgumentNames = new string[Arguments.Length];
}
for (int i = 0; i < Arguments.Length; i++)
{
if (IsPrimitiveValue[i] && ArgumentNames[i] == null)
{
ArgumentNames[i] = ParameterNames[i];
}
}
}
var argumentNames = GetArgumentNames(skipCount);
int argumentCount = GetActualArgumentCount();
var useImplicitlyTypedOut = UseImplicitlyTypedOut;
if (ArgumentNames == null)
if (argumentNames == null)
{
return Arguments.Skip(skipCount).Take(argumentCount).Select(arg => AddAnnotations(arg.Expression));
}
else
{
Debug.Assert(skipCount == 0);
return Arguments.Take(argumentCount).Zip(ArgumentNames.Take(argumentCount),
return Arguments.Take(argumentCount).Zip(argumentNames.Take(argumentCount),
(arg, name) => {
if (name == null)
return AddAnnotations(arg.Expression);
@ -531,6 +539,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -531,6 +539,10 @@ namespace ICSharpCode.Decompiler.CSharp
Expression targetExpr;
string methodName = method.Name;
AstNodeCollection<AstType> typeArgumentList;
if ((transform & CallTransformation.NoNamedArgsForPrettiness) != 0)
{
argumentList.AddNamesToPrimitiveValues = false;
}
if ((transform & CallTransformation.NoOptionalArgumentAllowed) != 0)
{
argumentList.FirstOptionalArgumentIndex = -1;
@ -674,7 +686,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -674,7 +686,7 @@ namespace ICSharpCode.Decompiler.CSharp
argumentList.UseImplicitlyTypedOut = false;
var transform = GetRequiredTransformationsForCall(expectedTargetDetails, method, ref unused,
ref argumentList, CallTransformation.None, out _);
Debug.Assert(transform == CallTransformation.None || transform == CallTransformation.NoOptionalArgumentAllowed);
Debug.Assert((transform & ~(CallTransformation.NoOptionalArgumentAllowed | CallTransformation.NoNamedArgsForPrettiness)) == 0);
// Calls with only one argument do not need an array initializer expression to wrap them.
// Any special cases are handled by the caller (i.e., ExpressionBuilder.TranslateObjectAndCollectionInitializer)
@ -1121,7 +1133,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1121,7 +1133,8 @@ namespace ICSharpCode.Decompiler.CSharp
/// Add calls to AsRefReadOnly for in parameters that did not have an explicit DirectionExpression yet.
/// </summary>
EnforceExplicitIn = 8,
All = 0xf,
NoNamedArgsForPrettiness = 0x10,
All = 0x1f,
}
private CallTransformation GetRequiredTransformationsForCall(ExpectedTargetDetails expectedTargetDetails, IMethod method,
@ -1198,7 +1211,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1198,7 +1211,7 @@ namespace ICSharpCode.Decompiler.CSharp
bool skipTargetCast = method.Accessibility <= Accessibility.Protected && expressionBuilder.IsBaseTypeOfCurrentType(method.DeclaringTypeDefinition);
OverloadResolutionErrors errors;
while ((errors = IsUnambiguousCall(expectedTargetDetails, method, targetResolveResult, typeArguments,
argumentList.GetArgumentResolveResults().ToArray(), argumentList.ArgumentNames, argumentList.FirstOptionalArgumentIndex, out foundMethod,
argumentList.GetArgumentResolveResults().ToArray(), argumentList.GetArgumentNames(), argumentList.FirstOptionalArgumentIndex, out foundMethod,
out var bestCandidateIsExpandedForm)) != OverloadResolutionErrors.None || bestCandidateIsExpandedForm != argumentList.IsExpandedForm)
{
switch (errors)
@ -1228,7 +1241,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1228,7 +1241,11 @@ namespace ICSharpCode.Decompiler.CSharp
default:
// TODO : implement some more intelligent algorithm that decides which of these fixes (cast args, add target, cast target, add type args)
// is best in this case. Additionally we should not cast all arguments at once, but step-by-step try to add only a minimal number of casts.
if (argumentList.FirstOptionalArgumentIndex >= 0)
if (argumentList.AddNamesToPrimitiveValues)
{
argumentList.AddNamesToPrimitiveValues = false;
}
else if (argumentList.FirstOptionalArgumentIndex >= 0)
{
argumentList.FirstOptionalArgumentIndex = -1;
}
@ -1293,6 +1310,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1293,6 +1310,8 @@ namespace ICSharpCode.Decompiler.CSharp
transform |= CallTransformation.RequireTypeArguments;
if (argumentList.FirstOptionalArgumentIndex < 0)
transform |= CallTransformation.NoOptionalArgumentAllowed;
if (!argumentList.AddNamesToPrimitiveValues)
transform |= CallTransformation.NoNamedArgsForPrettiness;
return transform;
}
@ -1766,9 +1785,14 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1766,9 +1785,14 @@ namespace ICSharpCode.Decompiler.CSharp
{
while (IsUnambiguousCall(expectedTargetDetails, method, null, Empty<IType>.Array,
argumentList.GetArgumentResolveResults().ToArray(),
argumentList.ArgumentNames, argumentList.FirstOptionalArgumentIndex, out _,
argumentList.GetArgumentNames(), argumentList.FirstOptionalArgumentIndex, out _,
out var bestCandidateIsExpandedForm) != OverloadResolutionErrors.None || bestCandidateIsExpandedForm != argumentList.IsExpandedForm)
{
if (argumentList.AddNamesToPrimitiveValues)
{
argumentList.AddNamesToPrimitiveValues = false;
continue;
}
if (argumentList.FirstOptionalArgumentIndex >= 0)
{
argumentList.FirstOptionalArgumentIndex = -1;

Loading…
Cancel
Save