Merge pull request #4158 from icsharpcode/ldmembertoken

Invent a syntax for `ldtoken`.
This commit is contained in:
Daniel Grunwald
2026-09-21 23:41:49 +02:00
committed by GitHub
3 changed files with 35 additions and 3 deletions
@@ -1,4 +1,3 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -19,7 +18,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly
public int[] LiteralArray()
{
int[] array = new int[3];
RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
RuntimeHelpers.InitializeArray(array, __ldtoken(_003CPrivateImplementationDetails_003E._4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D));
return array;
}
@@ -5132,6 +5132,36 @@ namespace ICSharpCode.Decompiler.CSharp
.WithILInstruction(inst);
}
protected internal override TranslatedExpression VisitLdMemberToken(LdMemberToken inst, TranslationContext context)
{
// C# does not have syntax for obtaining a member token; so we emit pseudo-syntax:
// fields: __ldtoken(DeclaringType.Member)
// methods: __ldtoken(DeclaringType.Member(parameter-types))
var classType = astBuilder.ConvertType(inst.Member.DeclaringType);
var mre = new MemberReferenceExpression(
new TypeReferenceExpression(classType),
inst.Member.Name
);
Expression memberExpr = mre.WithRR(new MemberResolveResult(null, inst.Member));
if (inst.Member is IMethod method)
{
foreach (var t in method.TypeArguments)
{
mre.TypeArguments.Add(astBuilder.ConvertType(t));
}
var inv = new InvocationExpression(memberExpr);
foreach (var param in method.Parameters)
{
inv.Arguments.Add(new TypeReferenceExpression(astBuilder.ConvertType(param.Type)));
}
memberExpr = inv;
}
var tokenType = inst.Member is IField ? KnownTypeCode.RuntimeFieldHandle : KnownTypeCode.RuntimeMethodHandle;
return new InvocationExpression(new IdentifierExpression("__ldtoken"), memberExpr)
.WithRR(new ResolveResult(compilation.FindType(tokenType)))
.WithILInstruction(inst);
}
protected internal override TranslatedExpression VisitCallIndirect(CallIndirect inst, TranslationContext context)
{
if (inst.IsInstance)
@@ -152,7 +152,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
// and using the main assembly can cause a stack overflow if there
// are internal assembly attributes.
}
anyTypeDef = typeDef;
// If there's multiple possible matches prefer the first one -- we most likely are
// in the context of the assembly being decompiled, which usually is the first in the list,
// so this increases the odds of picking the correct type.
anyTypeDef ??= typeDef;
}
}
return anyTypeDef;