|
|
|
@ -58,12 +58,15 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
public bool AddNamesToPrimitiveValues; |
|
|
|
public bool AddNamesToPrimitiveValues; |
|
|
|
public bool UseImplicitlyTypedOut; |
|
|
|
public bool UseImplicitlyTypedOut; |
|
|
|
public bool IsExpandedForm; |
|
|
|
public bool IsExpandedForm; |
|
|
|
|
|
|
|
public bool IsSetter; |
|
|
|
public int Length => Arguments.Length; |
|
|
|
public int Length => Arguments.Length; |
|
|
|
|
|
|
|
|
|
|
|
private int GetActualArgumentCount() |
|
|
|
public int GetActualArgumentCount() |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
int count = IsSetter ? Arguments.Length - 1 : Arguments.Length; |
|
|
|
if (FirstOptionalArgumentIndex < 0) |
|
|
|
if (FirstOptionalArgumentIndex < 0) |
|
|
|
return Arguments.Length; |
|
|
|
return count; |
|
|
|
|
|
|
|
Debug.Assert(FirstOptionalArgumentIndex <= count); |
|
|
|
return FirstOptionalArgumentIndex; |
|
|
|
return FirstOptionalArgumentIndex; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -74,10 +77,11 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
&& !ParameterNames.Any(string.IsNullOrEmpty)) |
|
|
|
&& !ParameterNames.Any(string.IsNullOrEmpty)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
Debug.Assert(skipCount == 0); |
|
|
|
Debug.Assert(skipCount == 0); |
|
|
|
if (argumentNames == null) |
|
|
|
// On a copy: giving these names up again must leave the ones that order the
|
|
|
|
{ |
|
|
|
// arguments untouched.
|
|
|
|
argumentNames = new string[Arguments.Length]; |
|
|
|
argumentNames = argumentNames == null |
|
|
|
} |
|
|
|
? new string[Arguments.Length] |
|
|
|
|
|
|
|
: (string[])argumentNames.Clone(); |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < Arguments.Length; i++) |
|
|
|
for (int i = 0; i < Arguments.Length; i++) |
|
|
|
{ |
|
|
|
{ |
|
|
|
@ -88,10 +92,19 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The names cover the full parameter list and have to stop where the arguments do.
|
|
|
|
|
|
|
|
int argumentCount = GetActualArgumentCount(); |
|
|
|
|
|
|
|
if (argumentNames != null && argumentNames.Length > argumentCount) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var writtenNames = new string[argumentCount]; |
|
|
|
|
|
|
|
Array.Copy(argumentNames, writtenNames, argumentCount); |
|
|
|
|
|
|
|
argumentNames = writtenNames; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return argumentNames; |
|
|
|
return argumentNames; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public IList<ResolveResult> GetArgumentResolveResults(int skipCount = 0) |
|
|
|
public ResolveResult[] GetArgumentResolveResults(int skipCount = 0) |
|
|
|
{ |
|
|
|
{ |
|
|
|
var expectedParameters = ExpectedParameters; |
|
|
|
var expectedParameters = ExpectedParameters; |
|
|
|
var useImplicitlyTypedOut = UseImplicitlyTypedOut; |
|
|
|
var useImplicitlyTypedOut = UseImplicitlyTypedOut; |
|
|
|
@ -111,7 +124,7 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public IList<ResolveResult> GetArgumentResolveResultsDirect(int skipCount = 0) |
|
|
|
public ResolveResult[] GetArgumentResolveResultsDirect(int skipCount = 0) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return Arguments |
|
|
|
return Arguments |
|
|
|
.Skip(skipCount) |
|
|
|
.Skip(skipCount) |
|
|
|
@ -132,7 +145,7 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
else |
|
|
|
else |
|
|
|
{ |
|
|
|
{ |
|
|
|
Debug.Assert(skipCount == 0); |
|
|
|
Debug.Assert(skipCount == 0); |
|
|
|
return Arguments.Take(argumentCount).Zip(argumentNames.Take(argumentCount), |
|
|
|
return Arguments.Take(argumentCount).Zip(argumentNames, |
|
|
|
(arg, name) => { |
|
|
|
(arg, name) => { |
|
|
|
if (name == null) |
|
|
|
if (name == null) |
|
|
|
return AddAnnotations(arg.Expression); |
|
|
|
return AddAnnotations(arg.Expression); |
|
|
|
@ -500,11 +513,17 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int allowedParamCount = (method.ReturnType.IsKnownType(KnownTypeCode.Void) ? 1 : 0); |
|
|
|
// IsSetter carries the answer for an accessor that takes the assigned value, including
|
|
|
|
if (method.IsAccessor && (method.AccessorOwner.SymbolKind == SymbolKind.Indexer || argumentList.ExpectedParameters.Length == allowedParamCount)) |
|
|
|
// the argument order that keeps it last.
|
|
|
|
|
|
|
|
if (argumentList.IsSetter || (!TakesAssignedValueLast(method) && IsWrittenAsMemberAccess(method))) |
|
|
|
{ |
|
|
|
{ |
|
|
|
argumentList.CheckNoNamedOrOptionalArguments(); |
|
|
|
// Only an indexer access has an argument list to carry names or leave arguments out of.
|
|
|
|
return HandleAccessorCall(expectedTargetDetails, method, target, argumentList.Arguments.ToList(), argumentList.ArgumentNames); |
|
|
|
if (method.AccessorOwner!.SymbolKind != SymbolKind.Indexer) |
|
|
|
|
|
|
|
argumentList.CheckNoNamedOrOptionalArguments(); |
|
|
|
|
|
|
|
// An access spells its index out anyway, and the ladder answers a name the member
|
|
|
|
|
|
|
|
// does not have with a cast of the target rather than by giving the name up.
|
|
|
|
|
|
|
|
argumentList.AddNamesToPrimitiveValues = false; |
|
|
|
|
|
|
|
return HandleAccessorCall(expectedTargetDetails, method, target, argumentList); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (IsDelegateEqualityComparison(method, argumentList.Arguments)) |
|
|
|
if (IsDelegateEqualityComparison(method, argumentList.Arguments)) |
|
|
|
@ -793,10 +812,15 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
callArguments.Add(value ?? new Nop()); |
|
|
|
callArguments.Add(value ?? new Nop()); |
|
|
|
|
|
|
|
|
|
|
|
var argumentList = BuildArgumentList(expectedTargetDetails, target, method, 1, callArguments, null); |
|
|
|
var argumentList = BuildArgumentList(expectedTargetDetails, target, method, 1, callArguments, null); |
|
|
|
|
|
|
|
// An index initializer is an assignment whatever the accessor looks like, even for a
|
|
|
|
|
|
|
|
// parameterized property, which has no access syntax of its own.
|
|
|
|
|
|
|
|
argumentList.IsSetter = true; |
|
|
|
|
|
|
|
// The cast the ladder would answer an unresolvable name with is removed again below,
|
|
|
|
|
|
|
|
// together with the target.
|
|
|
|
|
|
|
|
argumentList.AddNamesToPrimitiveValues = false; |
|
|
|
var unused = new IdentifierExpression("initializedObject").WithRR(target).WithoutILInstruction(); |
|
|
|
var unused = new IdentifierExpression("initializedObject").WithRR(target).WithoutILInstruction(); |
|
|
|
|
|
|
|
|
|
|
|
var assignment = HandleAccessorCall(expectedTargetDetails, method, unused, |
|
|
|
var assignment = HandleAccessorCall(expectedTargetDetails, method, unused, argumentList); |
|
|
|
argumentList.Arguments.ToList(), argumentList.ArgumentNames); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (((AssignmentExpression)assignment).Left is IndexerExpression indexer && indexer.Target is not null) |
|
|
|
if (((AssignmentExpression)assignment).Left is IndexerExpression indexer && indexer.Target is not null) |
|
|
|
indexer.Target.Remove(); |
|
|
|
indexer.Target.Remove(); |
|
|
|
@ -1013,6 +1037,22 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
// >= 0 - the index of the first argument that can be removed, because it is optional
|
|
|
|
// >= 0 - the index of the first argument that can be removed, because it is optional
|
|
|
|
// and is the default value of the parameter.
|
|
|
|
// and is the default value of the parameter.
|
|
|
|
int firstOptionalArgumentIndex = expressionBuilder.settings.OptionalArguments ? -2 : -1; |
|
|
|
int firstOptionalArgumentIndex = expressionBuilder.settings.OptionalArguments ? -2 : -1; |
|
|
|
|
|
|
|
// Only an access takes the assigned value out of the argument list; an accessor
|
|
|
|
|
|
|
|
// written as a call passes it like any other argument.
|
|
|
|
|
|
|
|
bool writtenAsMemberAccess = IsWrittenAsMemberAccess(method); |
|
|
|
|
|
|
|
if (writtenAsMemberAccess && TakesAssignedValueLast(method) && argumentToParameterMap != null |
|
|
|
|
|
|
|
&& argumentToParameterMap[callArguments.Count - 1] != method.Parameters.Count - 1) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// An access writes the value from the last argument; in any other order there is
|
|
|
|
|
|
|
|
// no access syntax for it.
|
|
|
|
|
|
|
|
writtenAsMemberAccess = false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
bool isSetter = writtenAsMemberAccess && TakesAssignedValueLast(method); |
|
|
|
|
|
|
|
// A name in an element access names a parameter of the indexer, which the type system
|
|
|
|
|
|
|
|
// takes from the getter; the accessor being called may name them differently.
|
|
|
|
|
|
|
|
IReadOnlyList<IParameter> namedParameters = method.AccessorOwner is IProperty { IsIndexer: true } indexer |
|
|
|
|
|
|
|
? indexer.Parameters |
|
|
|
|
|
|
|
: method.Parameters; |
|
|
|
for (int i = firstParamIndex; i < callArguments.Count; i++) |
|
|
|
for (int i = firstParamIndex; i < callArguments.Count; i++) |
|
|
|
{ |
|
|
|
{ |
|
|
|
IParameter parameter; |
|
|
|
IParameter parameter; |
|
|
|
@ -1024,10 +1064,13 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
// assign names to that argument and all following arguments:
|
|
|
|
// assign names to that argument and all following arguments:
|
|
|
|
argumentNames = new string[method.Parameters.Count]; |
|
|
|
argumentNames = new string[method.Parameters.Count]; |
|
|
|
} |
|
|
|
} |
|
|
|
parameter = method.Parameters[argumentToParameterMap[i]]; |
|
|
|
int parameterIndex = argumentToParameterMap[i]; |
|
|
|
if (argumentNames != null && AssignVariableNames.IsValidName(parameter.Name)) |
|
|
|
parameter = method.Parameters[parameterIndex]; |
|
|
|
|
|
|
|
// The assigned value is past the end of the indexer's parameters.
|
|
|
|
|
|
|
|
if (argumentNames != null && parameterIndex < namedParameters.Count |
|
|
|
|
|
|
|
&& AssignVariableNames.IsValidName(namedParameters[parameterIndex].Name)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
argumentNames[arguments.Count] = parameter.Name; |
|
|
|
argumentNames[arguments.Count] = namedParameters[parameterIndex].Name; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
else |
|
|
|
@ -1039,17 +1082,24 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
{ |
|
|
|
{ |
|
|
|
isPrimitiveValue.Set(arguments.Count); |
|
|
|
isPrimitiveValue.Set(arguments.Count); |
|
|
|
} |
|
|
|
} |
|
|
|
if (IsOptionalArgument(parameter, arg)) |
|
|
|
// The assigned value of a setter is not part of the argument list, so it does not
|
|
|
|
|
|
|
|
// end the run of optional arguments either.
|
|
|
|
|
|
|
|
if (!(isSetter && i + 1 == callArguments.Count)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (firstOptionalArgumentIndex == -2) |
|
|
|
if (IsOptionalArgument(parameter, arg)) |
|
|
|
firstOptionalArgumentIndex = i - firstParamIndex; |
|
|
|
{ |
|
|
|
} |
|
|
|
if (firstOptionalArgumentIndex == -2) |
|
|
|
else |
|
|
|
firstOptionalArgumentIndex = i - firstParamIndex; |
|
|
|
{ |
|
|
|
} |
|
|
|
if (firstOptionalArgumentIndex != -1) |
|
|
|
else if (firstOptionalArgumentIndex != -1) |
|
|
|
|
|
|
|
{ |
|
|
|
firstOptionalArgumentIndex = -2; |
|
|
|
firstOptionalArgumentIndex = -2; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (expressionBuilder.settings.ExpandParamsArguments && parameter.IsParams && i + 1 == callArguments.Count && argumentToParameterMap == null) |
|
|
|
// An assignment has no argument list to spread a parameter array over, and C#
|
|
|
|
|
|
|
|
// cannot declare a property whose value is one.
|
|
|
|
|
|
|
|
if (expressionBuilder.settings.ExpandParamsArguments && parameter.IsParams && !isSetter |
|
|
|
|
|
|
|
&& i + 1 == callArguments.Count && argumentToParameterMap == null) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// Parameter is marked params
|
|
|
|
// Parameter is marked params
|
|
|
|
// If the argument is an array creation, inline all elements into the call and add missing default values.
|
|
|
|
// If the argument is an array creation, inline all elements into the call and add missing default values.
|
|
|
|
@ -1111,6 +1161,7 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
list.IsExpandedForm = isExpandedForm; |
|
|
|
list.IsExpandedForm = isExpandedForm; |
|
|
|
list.IsPrimitiveValue = isPrimitiveValue; |
|
|
|
list.IsPrimitiveValue = isPrimitiveValue; |
|
|
|
list.FirstOptionalArgumentIndex = firstOptionalArgumentIndex; |
|
|
|
list.FirstOptionalArgumentIndex = firstOptionalArgumentIndex; |
|
|
|
|
|
|
|
list.IsSetter = isSetter; |
|
|
|
list.UseImplicitlyTypedOut = true; |
|
|
|
list.UseImplicitlyTypedOut = true; |
|
|
|
list.AddNamesToPrimitiveValues = expressionBuilder.settings.NamedArguments && expressionBuilder.settings.NonTrailingNamedArguments; |
|
|
|
list.AddNamesToPrimitiveValues = expressionBuilder.settings.NamedArguments && expressionBuilder.settings.NonTrailingNamedArguments; |
|
|
|
return list; |
|
|
|
return list; |
|
|
|
@ -1133,8 +1184,7 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
expandedParameters.InsertRange(0, expectedParameters); |
|
|
|
expandedParameters.InsertRange(0, expectedParameters); |
|
|
|
expandedArguments.InsertRange(0, arguments); |
|
|
|
expandedArguments.InsertRange(0, arguments); |
|
|
|
if (IsUnambiguousCall(expectedTargetDetails, method, targetResolveResult, Empty<IType>.Array, |
|
|
|
if (IsUnambiguousCall(expectedTargetDetails, method, targetResolveResult, Empty<IType>.Array, |
|
|
|
expandedArguments.SelectArray(a => a.ResolveResult), argumentNames: null, |
|
|
|
expandedArguments.SelectArray(a => a.ResolveResult), argumentNames: null, out _, |
|
|
|
firstOptionalArgumentIndex: -1, out _, |
|
|
|
|
|
|
|
out var bestCandidateIsExpandedForm) == OverloadResolutionErrors.None && bestCandidateIsExpandedForm) |
|
|
|
out var bestCandidateIsExpandedForm) == OverloadResolutionErrors.None && bestCandidateIsExpandedForm) |
|
|
|
{ |
|
|
|
{ |
|
|
|
expectedParameters = expandedParameters; |
|
|
|
expectedParameters = expandedParameters; |
|
|
|
@ -1214,6 +1264,35 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Whether the omitted arguments are the defaults of the member the shortened call resolves
|
|
|
|
|
|
|
|
/// to. They were compared against the method the call instruction names, which for a virtual
|
|
|
|
|
|
|
|
/// call is the base declaration, and an override may redeclare a different default.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
bool OmittedArgumentsAreDefaultsOf(ArgumentList argumentList, IMember? foundMember) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int argumentCount = argumentList.IsSetter ? argumentList.Length - 1 : argumentList.Length; |
|
|
|
|
|
|
|
int omittedFrom = argumentList.GetActualArgumentCount(); |
|
|
|
|
|
|
|
if (omittedFrom >= argumentCount) |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
if (foundMember is not IParameterizedMember foundParameterizedMember) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
var parameters = foundParameterizedMember.Parameters; |
|
|
|
|
|
|
|
// Names may leave out a parameter in the middle, so what was dropped is found through
|
|
|
|
|
|
|
|
// the map rather than by position. Its first entries are the target's.
|
|
|
|
|
|
|
|
var map = argumentList.ArgumentToParameterMap; |
|
|
|
|
|
|
|
int firstParamIndex = map != null ? map.Count - argumentList.Length : 0; |
|
|
|
|
|
|
|
for (int i = omittedFrom; i < argumentCount; i++) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int parameterIndex = map != null ? map[i + firstParamIndex] : i; |
|
|
|
|
|
|
|
if (parameterIndex < 0 || parameterIndex >= parameters.Count) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
if (!IsOptionalArgument(parameters[parameterIndex], argumentList.Arguments[i])) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool IsOptionalArgument(IParameter parameter, TranslatedExpression arg) |
|
|
|
bool IsOptionalArgument(IParameter parameter, TranslatedExpression arg) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!parameter.IsOptional) |
|
|
|
if (!parameter.IsOptional) |
|
|
|
@ -1245,13 +1324,46 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
|
|
|
|
|
|
|
|
private CallTransformation GetRequiredTransformationsForCall(ExpectedTargetDetails expectedTargetDetails, IMethod method, |
|
|
|
private CallTransformation GetRequiredTransformationsForCall(ExpectedTargetDetails expectedTargetDetails, IMethod method, |
|
|
|
ref TranslatedExpression target, ref ArgumentList argumentList, CallTransformation allowedTransforms, out IParameterizedMember? foundMethod) |
|
|
|
ref TranslatedExpression target, ref ArgumentList argumentList, CallTransformation allowedTransforms, out IParameterizedMember? foundMethod) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
var transform = GetRequiredTransformations(expectedTargetDetails, method, ref target, ref argumentList, |
|
|
|
|
|
|
|
allowedTransforms, writtenAsMemberAccess: false, out var foundMember); |
|
|
|
|
|
|
|
foundMethod = (IParameterizedMember?)foundMember; |
|
|
|
|
|
|
|
return transform; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Finds the transformations an expression needs to bind back to the member the IL names,
|
|
|
|
|
|
|
|
/// cheapest first. With <paramref name="writtenAsMemberAccess"/> the expression is a
|
|
|
|
|
|
|
|
/// property, indexer or event access, which resolves against the accessor's owner.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
private CallTransformation GetRequiredTransformations(ExpectedTargetDetails expectedTargetDetails, IMethod method, |
|
|
|
|
|
|
|
ref TranslatedExpression target, ref ArgumentList argumentList, CallTransformation allowedTransforms, |
|
|
|
|
|
|
|
bool writtenAsMemberAccess, out IMember? foundMember) |
|
|
|
{ |
|
|
|
{ |
|
|
|
CallTransformation transform = CallTransformation.None; |
|
|
|
CallTransformation transform = CallTransformation.None; |
|
|
|
|
|
|
|
IMember boundMember = writtenAsMemberAccess ? method.AccessorOwner! : method; |
|
|
|
|
|
|
|
|
|
|
|
// initialize requireTarget flag
|
|
|
|
// initialize requireTarget flag
|
|
|
|
bool requireTarget; |
|
|
|
bool requireTarget; |
|
|
|
ResolveResult? targetResolveResult; |
|
|
|
ResolveResult? targetResolveResult; |
|
|
|
if ((allowedTransforms & CallTransformation.RequireTarget) != 0) |
|
|
|
if (writtenAsMemberAccess) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (settings.AlwaysQualifyMemberReferences || boundMember.SymbolKind == SymbolKind.Indexer |
|
|
|
|
|
|
|
|| expressionBuilder.HidesVariableWithName(boundMember.Name)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
requireTarget = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (method.IsStatic) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
requireTarget = !expressionBuilder.IsCurrentOrContainingType(method.DeclaringTypeDefinition); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
requireTarget = target.Expression is not ThisReferenceExpression; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
targetResolveResult = requireTarget ? target.ResolveResult : null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if ((allowedTransforms & CallTransformation.RequireTarget) != 0) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (settings.AlwaysQualifyMemberReferences || expressionBuilder.HidesVariableWithName(method.Name)) |
|
|
|
if (settings.AlwaysQualifyMemberReferences || expressionBuilder.HidesVariableWithName(method.Name)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
@ -1325,14 +1437,38 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool targetCasted = false; |
|
|
|
bool targetCasted = false; |
|
|
|
bool argumentsCasted = false; |
|
|
|
bool argumentsCasted = writtenAsMemberAccess && argumentList.GetActualArgumentCount() == 0; |
|
|
|
bool originalRequireTarget = requireTarget; |
|
|
|
bool originalRequireTarget = requireTarget; |
|
|
|
bool skipTargetCast = method.Accessibility <= Accessibility.Protected && expressionBuilder.IsBaseTypeOfCurrentType(method.DeclaringTypeDefinition); |
|
|
|
bool skipTargetCast = !writtenAsMemberAccess |
|
|
|
|
|
|
|
&& method.Accessibility <= Accessibility.Protected && expressionBuilder.IsBaseTypeOfCurrentType(method.DeclaringTypeDefinition); |
|
|
|
OverloadResolutionErrors errors; |
|
|
|
OverloadResolutionErrors errors; |
|
|
|
while ((errors = IsUnambiguousCall(expectedTargetDetails, method, targetResolveResult, typeArguments, |
|
|
|
while (true) |
|
|
|
argumentList.GetArgumentResolveResults().ToArray(), argumentList.GetArgumentNames(), argumentList.FirstOptionalArgumentIndex, out foundMethod, |
|
|
|
|
|
|
|
out var bestCandidateIsExpandedForm)) != OverloadResolutionErrors.None || bestCandidateIsExpandedForm != argumentList.IsExpandedForm) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
bool expandedFormMismatch = false; |
|
|
|
|
|
|
|
if (writtenAsMemberAccess) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
errors = IsUnambiguousAccess(expectedTargetDetails, targetResolveResult, method, |
|
|
|
|
|
|
|
argumentList.GetArgumentResolveResults(), argumentList.GetArgumentNames(), out foundMember); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
errors = IsUnambiguousCall(expectedTargetDetails, method, targetResolveResult, typeArguments, |
|
|
|
|
|
|
|
argumentList.GetArgumentResolveResults(), argumentList.GetArgumentNames(), |
|
|
|
|
|
|
|
out var foundMethod, out bool bestCandidateIsExpandedForm); |
|
|
|
|
|
|
|
foundMember = foundMethod; |
|
|
|
|
|
|
|
expandedFormMismatch = bestCandidateIsExpandedForm != argumentList.IsExpandedForm; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (errors == OverloadResolutionErrors.None && !expandedFormMismatch |
|
|
|
|
|
|
|
&& OmittedArgumentsAreDefaultsOf(argumentList, foundMember)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (errors == OverloadResolutionErrors.None && argumentList.FirstOptionalArgumentIndex >= 0) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// The omitted arguments are not the defaults of the member found.
|
|
|
|
|
|
|
|
argumentList.FirstOptionalArgumentIndex = -1; |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
switch (errors) |
|
|
|
switch (errors) |
|
|
|
{ |
|
|
|
{ |
|
|
|
case OverloadResolutionErrors.OutVarTypeMismatch: |
|
|
|
case OverloadResolutionErrors.OutVarTypeMismatch: |
|
|
|
@ -1380,7 +1516,8 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
} |
|
|
|
} |
|
|
|
argumentsCasted = true; |
|
|
|
argumentsCasted = true; |
|
|
|
argumentList.UseImplicitlyTypedOut = false; |
|
|
|
argumentList.UseImplicitlyTypedOut = false; |
|
|
|
CastArguments(argumentList.Arguments, argumentList.ExpectedParameters); |
|
|
|
CastArguments(argumentList.Arguments, argumentList.GetActualArgumentCount(), |
|
|
|
|
|
|
|
argumentList.ExpectedParameters); |
|
|
|
} |
|
|
|
} |
|
|
|
else if ((allowedTransforms & CallTransformation.RequireTarget) != 0 && !requireTarget) |
|
|
|
else if ((allowedTransforms & CallTransformation.RequireTarget) != 0 && !requireTarget) |
|
|
|
{ |
|
|
|
{ |
|
|
|
@ -1399,7 +1536,7 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
else |
|
|
|
else |
|
|
|
{ |
|
|
|
{ |
|
|
|
targetCasted = true; |
|
|
|
targetCasted = true; |
|
|
|
target = target.ConvertTo(method.DeclaringType, expressionBuilder); |
|
|
|
target = target.ConvertTo(boundMember.DeclaringType, expressionBuilder); |
|
|
|
targetResolveResult = target.ResolveResult; |
|
|
|
targetResolveResult = target.ResolveResult; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -1420,7 +1557,7 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
// We've given up.
|
|
|
|
// We've given up.
|
|
|
|
foundMethod = method; |
|
|
|
foundMember = boundMember; |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
if ((allowedTransforms & CallTransformation.RequireTarget) != 0 && requireTarget) |
|
|
|
if ((allowedTransforms & CallTransformation.RequireTarget) != 0 && requireTarget) |
|
|
|
@ -1537,9 +1674,13 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
return newObj; |
|
|
|
return newObj; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void CastArguments(IList<TranslatedExpression> arguments, IList<IParameter> expectedParameters) |
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Casts the first <paramref name="count"/> arguments in place - the retry loop reads them
|
|
|
|
|
|
|
|
/// back from the array on its next attempt. A setter's assigned value is past the count.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
private void CastArguments(TranslatedExpression[] arguments, int count, IParameter[] expectedParameters) |
|
|
|
{ |
|
|
|
{ |
|
|
|
for (int i = 0; i < arguments.Count; i++) |
|
|
|
for (int i = 0; i < count; i++) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (settings.AnonymousTypes && expectedParameters[i].Type.ContainsAnonymousType()) |
|
|
|
if (settings.AnonymousTypes && expectedParameters[i].Type.ContainsAnonymousType()) |
|
|
|
{ |
|
|
|
{ |
|
|
|
@ -1655,7 +1796,7 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
|
|
|
|
|
|
|
|
OverloadResolutionErrors IsUnambiguousCall(ExpectedTargetDetails expectedTargetDetails, IMethod method, |
|
|
|
OverloadResolutionErrors IsUnambiguousCall(ExpectedTargetDetails expectedTargetDetails, IMethod method, |
|
|
|
ResolveResult? target, IType[] typeArguments, ResolveResult[] arguments, |
|
|
|
ResolveResult? target, IType[] typeArguments, ResolveResult[] arguments, |
|
|
|
string[]? argumentNames, int firstOptionalArgumentIndex, |
|
|
|
string[]? argumentNames, |
|
|
|
out IParameterizedMember? foundMember, out bool bestCandidateIsExpandedForm) |
|
|
|
out IParameterizedMember? foundMember, out bool bestCandidateIsExpandedForm) |
|
|
|
{ |
|
|
|
{ |
|
|
|
foundMember = null; |
|
|
|
foundMember = null; |
|
|
|
@ -1666,10 +1807,6 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
Log.WriteLine("IsUnambiguousCall: Performing overload resolution for " + method); |
|
|
|
Log.WriteLine("IsUnambiguousCall: Performing overload resolution for " + method); |
|
|
|
Log.WriteCollection(" Arguments: ", arguments); |
|
|
|
Log.WriteCollection(" Arguments: ", arguments); |
|
|
|
|
|
|
|
|
|
|
|
argumentNames = firstOptionalArgumentIndex < 0 || argumentNames == null |
|
|
|
|
|
|
|
? argumentNames |
|
|
|
|
|
|
|
: argumentNames.Take(firstOptionalArgumentIndex).ToArray(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var or = new OverloadResolution(resolver.Compilation, |
|
|
|
var or = new OverloadResolution(resolver.Compilation, |
|
|
|
arguments, argumentNames, typeArguments, |
|
|
|
arguments, argumentNames, typeArguments, |
|
|
|
conversions: expressionBuilder.resolver.conversions); |
|
|
|
conversions: expressionBuilder.resolver.conversions); |
|
|
|
@ -1771,11 +1908,15 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
return OverloadResolutionErrors.None; |
|
|
|
return OverloadResolutionErrors.None; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool IsUnambiguousAccess(ExpectedTargetDetails expectedTargetDetails, ResolveResult? target, IMethod method, |
|
|
|
/// <summary>
|
|
|
|
IList<TranslatedExpression> arguments, string[]? argumentNames, [NotNullWhen(true)] out IMember? foundMember) |
|
|
|
/// Resolves an access the way a call is resolved, so that the ladder can tell one that binds
|
|
|
|
|
|
|
|
/// to nothing from one that is merely missing an argument.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
OverloadResolutionErrors IsUnambiguousAccess(ExpectedTargetDetails expectedTargetDetails, ResolveResult? target, IMethod method, |
|
|
|
|
|
|
|
ResolveResult[] arguments, string[]? argumentNames, out IMember? foundMember) |
|
|
|
{ |
|
|
|
{ |
|
|
|
Log.WriteLine("IsUnambiguousAccess: Performing overload resolution for " + method); |
|
|
|
Log.WriteLine("IsUnambiguousAccess: Performing overload resolution for " + method); |
|
|
|
Log.WriteCollection(" Arguments: ", arguments.Select(a => a.ResolveResult)); |
|
|
|
Log.WriteCollection(" Arguments: ", arguments); |
|
|
|
|
|
|
|
|
|
|
|
foundMember = null; |
|
|
|
foundMember = null; |
|
|
|
if (target == null) |
|
|
|
if (target == null) |
|
|
|
@ -1784,7 +1925,7 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
EmptyList<IType>.Instance, |
|
|
|
EmptyList<IType>.Instance, |
|
|
|
isInvocationTarget: false) as MemberResolveResult; |
|
|
|
isInvocationTarget: false) as MemberResolveResult; |
|
|
|
if (result == null || result.IsError) |
|
|
|
if (result == null || result.IsError) |
|
|
|
return false; |
|
|
|
return OverloadResolutionErrors.AmbiguousMatch; |
|
|
|
foundMember = result.Member; |
|
|
|
foundMember = result.Member; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
else |
|
|
|
@ -1793,15 +1934,15 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
if (method.AccessorOwner!.SymbolKind == SymbolKind.Indexer) |
|
|
|
if (method.AccessorOwner!.SymbolKind == SymbolKind.Indexer) |
|
|
|
{ |
|
|
|
{ |
|
|
|
var or = new OverloadResolution(resolver.Compilation, |
|
|
|
var or = new OverloadResolution(resolver.Compilation, |
|
|
|
arguments.SelectArray(a => a.ResolveResult), |
|
|
|
arguments, |
|
|
|
argumentNames: argumentNames, |
|
|
|
argumentNames: argumentNames, |
|
|
|
typeArguments: Empty<IType>.Array, |
|
|
|
typeArguments: Empty<IType>.Array, |
|
|
|
conversions: expressionBuilder.resolver.conversions); |
|
|
|
conversions: expressionBuilder.resolver.conversions); |
|
|
|
or.AddMethodLists(lookup.LookupIndexers(target)); |
|
|
|
or.AddMethodLists(lookup.LookupIndexers(target)); |
|
|
|
if (or.BestCandidateErrors != OverloadResolutionErrors.None) |
|
|
|
if (or.BestCandidateErrors != OverloadResolutionErrors.None) |
|
|
|
return false; |
|
|
|
return or.BestCandidateErrors; |
|
|
|
if (or.IsAmbiguous) |
|
|
|
if (or.IsAmbiguous) |
|
|
|
return false; |
|
|
|
return OverloadResolutionErrors.AmbiguousMatch; |
|
|
|
foundMember = or.GetBestCandidateWithSubstitutedTypeArguments(); |
|
|
|
foundMember = or.GetBestCandidateWithSubstitutedTypeArguments(); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
else |
|
|
|
@ -1811,61 +1952,61 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
EmptyList<IType>.Instance, |
|
|
|
EmptyList<IType>.Instance, |
|
|
|
isInvocation: false) as MemberResolveResult; |
|
|
|
isInvocation: false) as MemberResolveResult; |
|
|
|
if (result == null || result.IsError) |
|
|
|
if (result == null || result.IsError) |
|
|
|
return false; |
|
|
|
return OverloadResolutionErrors.AmbiguousMatch; |
|
|
|
foundMember = result.Member; |
|
|
|
foundMember = result.Member; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return foundMember != null && IsAppropriateCallTarget(expectedTargetDetails, method.AccessorOwner, foundMember); |
|
|
|
if (foundMember == null || !IsAppropriateCallTarget(expectedTargetDetails, method.AccessorOwner!, foundMember)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
foundMember = null; |
|
|
|
|
|
|
|
return OverloadResolutionErrors.AmbiguousMatch; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return OverloadResolutionErrors.None; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Whether the accessor's last parameter is the assigned value: a setter takes it, and so do
|
|
|
|
|
|
|
|
/// the two event accessors, written as += and -=.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
static bool TakesAssignedValueLast(IMethod method) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return method.AccessorKind is System.Reflection.MethodSemanticsAttributes.Setter |
|
|
|
|
|
|
|
or System.Reflection.MethodSemanticsAttributes.Adder |
|
|
|
|
|
|
|
or System.Reflection.MethodSemanticsAttributes.Remover; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Whether the accessor is written as a property or indexer access. One with more parameters
|
|
|
|
|
|
|
|
/// than the access syntax has room for is written as a call, assigned value and all.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
static bool IsWrittenAsMemberAccess(IMethod method) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!method.IsAccessor) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
if (method.AccessorOwner!.SymbolKind == SymbolKind.Indexer) |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
return method.Parameters.Count == (TakesAssignedValueLast(method) ? 1 : 0); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ExpressionWithResolveResult HandleAccessorCall(ExpectedTargetDetails expectedTargetDetails, IMethod method, |
|
|
|
ExpressionWithResolveResult HandleAccessorCall(ExpectedTargetDetails expectedTargetDetails, IMethod method, |
|
|
|
TranslatedExpression target, List<TranslatedExpression> arguments, string[]? argumentNames) |
|
|
|
TranslatedExpression target, ArgumentList argumentList) |
|
|
|
{ |
|
|
|
{ |
|
|
|
bool requireTarget; |
|
|
|
bool isSetter = argumentList.IsSetter; |
|
|
|
if (settings.AlwaysQualifyMemberReferences || method.AccessorOwner!.SymbolKind == SymbolKind.Indexer || expressionBuilder.HidesVariableWithName(method.AccessorOwner.Name)) |
|
|
|
|
|
|
|
requireTarget = true; |
|
|
|
|
|
|
|
else if (method.IsStatic) |
|
|
|
|
|
|
|
requireTarget = !expressionBuilder.IsCurrentOrContainingType(method.DeclaringTypeDefinition); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
requireTarget = !(target.Expression is ThisReferenceExpression); |
|
|
|
|
|
|
|
bool targetCasted = false; |
|
|
|
|
|
|
|
bool isSetter = method.ReturnType.IsKnownType(KnownTypeCode.Void); |
|
|
|
|
|
|
|
bool argumentsCasted = (isSetter && method.Parameters.Count == 1) || (!isSetter && method.Parameters.Count == 0); |
|
|
|
|
|
|
|
var targetResolveResult = requireTarget ? target.ResolveResult : null; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TranslatedExpression value = default(TranslatedExpression); |
|
|
|
// Dropping every argument would turn an indexer access into a property access.
|
|
|
|
if (isSetter) |
|
|
|
if (argumentList.FirstOptionalArgumentIndex == 0 && method.AccessorOwner!.SymbolKind == SymbolKind.Indexer) |
|
|
|
{ |
|
|
|
{ |
|
|
|
value = arguments.Last(); |
|
|
|
argumentList.FirstOptionalArgumentIndex = 1; |
|
|
|
arguments.Remove(value); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
IMember? foundMember; |
|
|
|
var transform = GetRequiredTransformations(expectedTargetDetails, method, ref target, ref argumentList, |
|
|
|
while (!IsUnambiguousAccess(expectedTargetDetails, targetResolveResult, method, arguments, argumentNames, out foundMember)) |
|
|
|
CallTransformation.RequireTarget, writtenAsMemberAccess: true, out var foundMember); |
|
|
|
{ |
|
|
|
Debug.Assert(foundMember != null); |
|
|
|
if (!argumentsCasted) |
|
|
|
bool requireTarget = (transform & CallTransformation.RequireTarget) != 0; |
|
|
|
{ |
|
|
|
|
|
|
|
argumentsCasted = true; |
|
|
|
|
|
|
|
CastArguments(arguments, method.Parameters.ToList()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (!requireTarget) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
requireTarget = true; |
|
|
|
|
|
|
|
targetResolveResult = target.ResolveResult; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (!targetCasted) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
targetCasted = true; |
|
|
|
|
|
|
|
target = target.ConvertTo(method.AccessorOwner!.DeclaringType, expressionBuilder); |
|
|
|
|
|
|
|
targetResolveResult = target.ResolveResult; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
foundMember = method.AccessorOwner!; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var arguments = argumentList.GetArgumentExpressions().ToList(); |
|
|
|
|
|
|
|
// Not one of the arguments the ladder casts.
|
|
|
|
|
|
|
|
TranslatedExpression value = isSetter ? argumentList.Arguments[argumentList.Length - 1] : default; |
|
|
|
var rr = new MemberResolveResult(target.ResolveResult, foundMember); |
|
|
|
var rr = new MemberResolveResult(target.ResolveResult, foundMember); |
|
|
|
|
|
|
|
|
|
|
|
if (isSetter) |
|
|
|
if (isSetter) |
|
|
|
@ -1874,7 +2015,7 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
|
|
|
|
|
|
|
|
if (arguments.Count != 0) |
|
|
|
if (arguments.Count != 0) |
|
|
|
{ |
|
|
|
{ |
|
|
|
expr = new IndexerExpression(target.ResolveResult is InitializedObjectResolveResult ? null : target.Expression, arguments.Select(a => a.Expression)) |
|
|
|
expr = new IndexerExpression(target.ResolveResult is InitializedObjectResolveResult ? null : target.Expression, arguments) |
|
|
|
.WithoutILInstruction().WithRR(rr); |
|
|
|
.WithoutILInstruction().WithRR(rr); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (requireTarget) |
|
|
|
else if (requireTarget) |
|
|
|
@ -1906,7 +2047,7 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (arguments.Count != 0) |
|
|
|
if (arguments.Count != 0) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return new IndexerExpression(target.Expression, arguments.Select(a => a.Expression)) |
|
|
|
return new IndexerExpression(target.Expression, arguments) |
|
|
|
.WithoutILInstruction().WithRR(rr); |
|
|
|
.WithoutILInstruction().WithRR(rr); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (requireTarget) |
|
|
|
else if (requireTarget) |
|
|
|
@ -1986,24 +2127,10 @@ namespace ICSharpCode.Decompiler.CSharp |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
else |
|
|
|
{ |
|
|
|
{ |
|
|
|
while (IsUnambiguousCall(expectedTargetDetails, method, null, Empty<IType>.Array, |
|
|
|
// A constructor names its type, so neither qualification nor type arguments apply.
|
|
|
|
argumentList.GetArgumentResolveResults().ToArray(), |
|
|
|
TranslatedExpression noTarget = default; |
|
|
|
argumentList.GetArgumentNames(), argumentList.FirstOptionalArgumentIndex, out _, |
|
|
|
GetRequiredTransformations(expectedTargetDetails, method, ref noTarget, ref argumentList, |
|
|
|
out var bestCandidateIsExpandedForm) != OverloadResolutionErrors.None || bestCandidateIsExpandedForm != argumentList.IsExpandedForm) |
|
|
|
CallTransformation.None, writtenAsMemberAccess: false, out _); |
|
|
|
{ |
|
|
|
|
|
|
|
if (argumentList.AddNamesToPrimitiveValues) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
argumentList.AddNamesToPrimitiveValues = false; |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (argumentList.FirstOptionalArgumentIndex >= 0) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
argumentList.FirstOptionalArgumentIndex = -1; |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
CastArguments(argumentList.Arguments, argumentList.ExpectedParameters); |
|
|
|
|
|
|
|
break; // make sure that we don't not end up in an infinite loop
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
IType? returnTypeOverride = null; |
|
|
|
IType? returnTypeOverride = null; |
|
|
|
if (typeSystem.MainModule.TypeSystemOptions.HasFlag(TypeSystemOptions.NativeIntegersWithoutAttribute)) |
|
|
|
if (typeSystem.MainModule.TypeSystemOptions.HasFlag(TypeSystemOptions.NativeIntegersWithoutAttribute)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|