镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Fix ldftn decompilation throwing an exception for instance accessors - #4297

Open
ds5678 wants to merge 2 commits into
icsharpcode:masterfrom
ds5678:fix-instance-accessor-ldftn
Open

ds5678 wants to merge 2 commits into
icsharpcode:masterfrom
ds5678:fix-instance-accessor-ldftn

Conversation

@ds5678

@ds5678 ds5678 commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Problem

Decompiling the class generated by this causes an error in the latest version of ILSpy, but did not in earlier versions.

// ILSpy could not decompile this member: Error decompiling @060000A1 UpdateEngineAutoGenerated.UpdateMain0: Value cannot be null. (Parameter 'source')
// Please report the exception below,
// along with the assembly it came from, at https://github.com/icsharpcode/ILSpy/issues/new
// Error decompiling @060000A1 UpdateEngineAutoGenerated.UpdateMain0
// in assembly "N:\StrideProjects\FirstPersonShooter\Bin\Windows\Debug\FirstPersonShooter.Game.dll"
//  ---> System.ArgumentNullException: Value cannot be null. (Parameter 'source')
//    at System.Linq.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument) in offset 11
//    at System.Linq.Enumerable.Take[TSource](IEnumerable`1 source, Int32 count) in offset 3
//    at ICSharpCode.Decompiler.CSharp.ArgumentList.GetArgumentResolveResultsDirect(Int32 skipCount) in CallBuilder.cs:line 128
//    at ICSharpCode.Decompiler.CSharp.Disambiguator.Probe() in Disambiguator.cs:line 493
//    at ICSharpCode.Decompiler.CSharp.Disambiguator.Run() in Disambiguator.cs:line 438
//    at ICSharpCode.Decompiler.CSharp.Disambiguator.ForMethodReference(ExpressionBuilder expressionBuilder, IMethod method, IType targetType, TranslatedExpression target, Boolean requireTarget, ExpectedTargetDetails expectedTargetDetails, Boolean isExtensionMethodReference, Boolean castTargetUpFront) in Disambiguator.cs:line 131
//    at ICSharpCode.Decompiler.CSharp.CallBuilder.DisambiguateDelegateReference(IMethod method, IMethod invokeMethod, ExpectedTargetDetails expectedTargetDetails, ILInstruction thisArg) in CallBuilder.cs:line 1825
//    at ICSharpCode.Decompiler.CSharp.CallBuilder.BuildDelegateReference(IMethod method, IMethod invokeMethod, ExpectedTargetDetails expectedTargetDetails, ILInstruction thisArg) in CallBuilder.cs:line 1755
//    at ICSharpCode.Decompiler.CSharp.CallBuilder.BuildMethodReference(IMethod method, Boolean isVirtual) in CallBuilder.cs:line 1746
//    at ICSharpCode.Decompiler.CSharp.ExpressionBuilder.VisitLdFtn(LdFtn inst, TranslationContext context) in ExpressionBuilder.cs:line 5084
//    at ICSharpCode.Decompiler.IL.LdFtn.AcceptVisitor[C,T](ILVisitor`2 visitor, C context) in Instructions.cs:line 3198
//    at ICSharpCode.Decompiler.CSharp.ExpressionBuilder.Translate(ILInstruction inst, IType typeHint) in ExpressionBuilder.cs:line 173
//    at ICSharpCode.Decompiler.CSharp.CallBuilder.BuildArgumentList(ExpectedTargetDetails expectedTargetDetails, ResolveResult target, IMethod method, Int32 firstParamIndex, IReadOnlyList`1 callArguments, IReadOnlyList`1 argumentToParameterMap, Boolean writtenAsAssignment) in CallBuilder.cs:line 1084
//    at ICSharpCode.Decompiler.CSharp.CallBuilder.Build(OpCode callOpCode, IMethod method, IReadOnlyList`1 callArguments, IReadOnlyList`1 argumentToParameterMap, IType constrainedTo) in CallBuilder.cs:line 464
//    at ICSharpCode.Decompiler.CSharp.CallBuilder.Build(CallInstruction inst, IType typeHint) in CallBuilder.cs:line 258
//    at ICSharpCode.Decompiler.CSharp.ExpressionBuilder.VisitNewObj(NewObj inst, TranslationContext context) in ExpressionBuilder.cs:line 540
//    at ICSharpCode.Decompiler.IL.NewObj.AcceptVisitor[C,T](ILVisitor`2 visitor, C context) in Instructions.cs:line 4612
//    at ICSharpCode.Decompiler.CSharp.ExpressionBuilder.Translate(ILInstruction inst, IType typeHint) in ExpressionBuilder.cs:line 173
//    at ICSharpCode.Decompiler.CSharp.CallBuilder.BuildArgumentList(ExpectedTargetDetails expectedTargetDetails, ResolveResult target, IMethod method, Int32 firstParamIndex, IReadOnlyList`1 callArguments, IReadOnlyList`1 argumentToParameterMap, Boolean writtenAsAssignment) in CallBuilder.cs:line 1084
//    at ICSharpCode.Decompiler.CSharp.CallBuilder.Build(OpCode callOpCode, IMethod method, IReadOnlyList`1 callArguments, IReadOnlyList`1 argumentToParameterMap, IType constrainedTo) in CallBuilder.cs:line 464
//    at ICSharpCode.Decompiler.CSharp.CallBuilder.Build(CallInstruction inst, IType typeHint) in CallBuilder.cs:line 258
//    at ICSharpCode.Decompiler.CSharp.ExpressionBuilder.VisitCall(Call inst, TranslationContext context) in ExpressionBuilder.cs:line 2548
//    at ICSharpCode.Decompiler.IL.Call.AcceptVisitor[C,T](ILVisitor`2 visitor, C context) in Instructions.cs:line 2213
//    at ICSharpCode.Decompiler.CSharp.ExpressionBuilder.Translate(ILInstruction inst, IType typeHint) in ExpressionBuilder.cs:line 173
//    at ICSharpCode.Decompiler.CSharp.StatementBuilder.Default(ILInstruction inst) in StatementBuilder.cs:line 93
//    at ICSharpCode.Decompiler.IL.ILVisitor`1.VisitCall(Call inst) in Instructions.cs:line 7717
//    at ICSharpCode.Decompiler.IL.Call.AcceptVisitor[T](ILVisitor`1 visitor) in Instructions.cs:line 2209
//    at ICSharpCode.Decompiler.CSharp.StatementBuilder.Convert(ILInstruction inst) in StatementBuilder.cs:line 82
//    at ICSharpCode.Decompiler.CSharp.StatementBuilder.ConvertBlockContainer(BlockStatement blockStatement, BlockContainer container, IEnumerable`1 blocks, Boolean isLoop) in StatementBuilder.cs:line 1581
//    at ICSharpCode.Decompiler.CSharp.StatementBuilder.ConvertBlockContainer(BlockContainer container, Boolean isLoop) in StatementBuilder.cs:line 1468
//    at ICSharpCode.Decompiler.CSharp.StatementBuilder.VisitBlockContainer(BlockContainer container) in StatementBuilder.cs:line 1354
//    at ICSharpCode.Decompiler.IL.BlockContainer.AcceptVisitor[T](ILVisitor`1 visitor) in Instructions.cs:line 863
//    at ICSharpCode.Decompiler.CSharp.StatementBuilder.Convert(ILInstruction inst) in StatementBuilder.cs:line 82
//    at ICSharpCode.Decompiler.CSharp.StatementBuilder.ConvertAsBlock(ILInstruction inst) in StatementBuilder.cs:line 87
//    at ICSharpCode.Decompiler.CSharp.CSharpDecompiler.DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun decompileRun, ITypeResolveContext decompilationContext, ExtensionInfo extensionInfo) in CSharpDecompiler.cs:line 2457
// -- continuing with outer exception (ICSharpCode.Decompiler.DecompilerException) --
// 

Solution

  • At least one test covering the code changed

The error occurs when IL references an accessor method directly—for example, using ldftn to create a delegate to a property getter.

Previously, Disambiguator.Probe() treated every accessor method as a property or event access, even when it was being used as a method reference. That path expects an argument list, but method references leave it uninitialized, so LINQ throws ArgumentNullException.

The fix distinguishes accessor syntax from accessor metadata. Actual property, indexer, and event accesses still use accessor resolution; method references use method-reference resolution instead. The regression fixture exercises a Func<int> targeting a property getter.

ds5678 and others added 2 commits October 28, 2026 01:55
Accessor metadata and source syntax are independent: property, indexer and event accesses need accessor resolution, while ldftn references need method-reference resolution. Reuse the existing syntax flag and cover both paths with the isolated regression fixture.

Assisted-by: OpenCode:openai/gpt-5.6-luna:OpenCode
@siegfriedpammer

Copy link
Copy Markdown
Member

Hey Jeremy, thank you for the bugfix... I removed the extra "accessorSyntax" variable since !invocationSyntax + IMethod.IsAccessor should already be enough information. I updated the documentation as well...

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants