Skip to content

Commit

Permalink
Use ILSpyHelper_AsRefReadOnly to ensure that overload resolution can …
Browse files Browse the repository at this point in the history
…pick the correct overload using 'in'.
  • Loading branch information
siegfriedpammer committed Jul 20, 2024
1 parent 03a20f3 commit 9548a11
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 1 deletion.
37 changes: 36 additions & 1 deletion ICSharpCode.Decompiler/CSharp/CallBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -971,7 +971,11 @@ enum CallTransformation
RequireTarget = 1,
RequireTypeArguments = 2,
NoOptionalArgumentAllowed = 4,
All = 7
/// <summary>
/// Add calls to AsRefReadOnly for in parameters that did not have an explicit DirectionExpression yet.
/// </summary>
EnforceExplicitIn = 8,
All = 0xf,
}

private CallTransformation GetRequiredTransformationsForCall(ExpectedTargetDetails expectedTargetDetails, IMethod method,
Expand Down Expand Up @@ -1122,6 +1126,11 @@ private CallTransformation GetRequiredTransformationsForCall(ExpectedTargetDetai
requireTypeArguments = true;
typeArguments = method.TypeArguments.ToArray();
}
else if ((allowedTransforms & CallTransformation.EnforceExplicitIn) != 0)
{
EnforceExplicitIn(argumentList.Arguments, argumentList.ExpectedParameters);
allowedTransforms &= ~CallTransformation.EnforceExplicitIn;
}
else
{
break;
Expand All @@ -1141,6 +1150,32 @@ private CallTransformation GetRequiredTransformationsForCall(ExpectedTargetDetai
return transform;
}

private void EnforceExplicitIn(TranslatedExpression[] arguments, IParameter[] expectedParameters)
{
for (int i = 0; i < arguments.Length; i++)
{
if (expectedParameters[i].ReferenceKind != ReferenceKind.In)
continue;
if (arguments[i].Expression is DirectionExpression)
continue;

arguments[i] = WrapInAsRefReadOnly(arguments[i]);
expressionBuilder.statementBuilder.EmitAsRefReadOnly = true;
}
}

private TranslatedExpression WrapInAsRefReadOnly(TranslatedExpression arg)
{
return new DirectionExpression(
FieldDirection.In,
new InvocationExpression {
Target = new IdentifierExpression("ILSpyHelper_AsRefReadOnly"),
Arguments = { arg.Expression }
}
).WithRR(new ByReferenceResolveResult(arg.Type, ReferenceKind.In))
.WithoutILInstruction();
}

private bool IsPossibleExtensionMethodCallOnNull(IMethod method, IList<TranslatedExpression> arguments)
{
return method.IsExtensionMethod && arguments.Count > 0 && arguments[0].Expression is NullReferenceExpression;
Expand Down
28 changes: 28 additions & 0 deletions ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ sealed class StatementBuilder : ILVisitor<TranslatedStatement>
internal IType currentResultType;
internal bool currentIsIterator;

internal bool EmitAsRefReadOnly;

public StatementBuilder(IDecompilerTypeSystem typeSystem, ITypeResolveContext decompilationContext,
ILFunction currentFunction, DecompilerSettings settings, DecompileRun decompileRun,
CancellationToken cancellationToken)
Expand Down Expand Up @@ -1367,6 +1369,32 @@ BlockStatement ConvertBlockContainer(BlockContainer container, bool isLoop)
{
var blockStatement = ConvertBlockContainer(new BlockStatement(), container, container.Blocks, isLoop);
DeclareLocalFunctions(currentFunction, container, blockStatement);
if (currentFunction.Body == container)
{
if (EmitAsRefReadOnly)
{
var methodDecl = new MethodDeclaration();
if (settings.StaticLocalFunctions)
{
methodDecl.Modifiers = Modifiers.Static;
}

methodDecl.ReturnType = new ComposedType() { HasReadOnlySpecifier = true, HasRefSpecifier = true, BaseType = new SimpleType("T") };
methodDecl.Name = "ILSpyHelper_AsRefReadOnly";
methodDecl.TypeParameters.Add(new TypeParameterDeclaration("T"));
methodDecl.Parameters.Add(new ParameterDeclaration { ParameterModifier = ReferenceKind.In, Type = new SimpleType("T"), Name = "temp" });

methodDecl.Body = new BlockStatement();
methodDecl.Body.AddChild(new Comment(
"ILSpy generated this function to help ensure overload resolution can pick the overload using 'in'"),
Roles.Comment);
methodDecl.Body.Add(new ReturnStatement(new DirectionExpression(FieldDirection.Ref, new IdentifierExpression("temp"))));

blockStatement.Statements.Add(
new LocalFunctionDeclarationStatement(methodDecl)
);
}
}
return blockStatement;
}

Expand Down

0 comments on commit 9548a11

Please sign in to comment.