From 7ef5994b3138354ad2c3777cbf3301bc30f2d1d4 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 6 Sep 2026 10:51:56 +0200 Subject: [PATCH] Look methods up the same way whether or not they come from metadata Resolving a method reference and resolving one by name and signature differed in three ways that had no reason to differ: only the metadata path found a static constructor, only it restricted the candidates to the declared members, and only it matched a vararg signature against its required parameters plus __arglist. Assisted-by: Claude:claude-opus-5:Claude Code --- .../TypeSystem/MetadataModule.cs | 89 ++++++++----------- 1 file changed, 37 insertions(+), 52 deletions(-) diff --git a/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs b/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs index a48bc1631..4144a32fc 100644 --- a/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs +++ b/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs @@ -537,43 +537,7 @@ namespace ICSharpCode.Decompiler.TypeSystem string name = metadata.GetString(memberRef.Name); signature = memberRef.DecodeMethodSignature(TypeProvider, new GenericContext(declaringTypeDefinition?.TypeParameters)); - if (declaringTypeDefinition != null) - { - // Find the set of overloads to search: - IEnumerable methods; - if (name == ".ctor") - { - methods = declaringTypeDefinition.GetConstructors(); - } - else if (name == ".cctor") - { - methods = declaringTypeDefinition.Methods.Where(m => m.IsConstructor && m.IsStatic); - } - else - { - methods = declaringTypeDefinition.GetMethods(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers) - .Concat(declaringTypeDefinition.GetAccessors(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers)); - } - // Determine the expected parameters from the signature: - ImmutableArray parameterTypes; - if (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs) - { - parameterTypes = signature.ParameterTypes - .Take(signature.RequiredParameterCount) - .Concat(new[] { SpecialType.ArgList }) - .ToImmutableArray(); - } - else - { - parameterTypes = signature.ParameterTypes; - } - // Search for the matching method: - method = FindMethod(methods, signature, parameterTypes); - } - else - { - method = null; - } + method = declaringTypeDefinition != null ? FindMethod(declaringTypeDefinition, name, signature) : null; if (method == null) { method = CreateFakeMethod(declaringType, name, signature); @@ -609,27 +573,48 @@ namespace ICSharpCode.Decompiler.TypeSystem throw new ArgumentNullException(nameof(declaringType)); if (name == null) throw new ArgumentNullException(nameof(name)); - IEnumerable methods; - if (name == ".ctor") - { - methods = declaringType.GetConstructors(); - } - else - { - methods = declaringType.GetMethods(m => m.Name == name) - .Concat(declaringType.GetAccessors(m => m.Name == name)); - } - return FindMethod(methods, signature, signature.ParameterTypes) + return FindMethod(declaringType, name, signature) ?? CreateFakeMethod(declaringType, name, signature); } /// - /// The single method among that matches the signature, or - /// null. is passed separately because a vararg - /// signature is matched against its required parameters plus __arglist. + /// The single method on that matches the name and the + /// signature, or null. Only the methods the type itself declares are candidates, because + /// a signature always names the type that declares the method. /// - static IMethod FindMethod(IEnumerable candidates, MethodSignature signature, ImmutableArray parameterTypes) + static IMethod FindMethod(IType declaringType, string name, MethodSignature signature) { + // Find the set of overloads to search: + IEnumerable candidates; + if (name == ".ctor") + { + candidates = declaringType.GetConstructors(); + } + else if (name == ".cctor") + { + // GetConstructors() only returns instance constructors. + candidates = declaringType.GetDefinition()?.Methods.Where(m => m.IsConstructor && m.IsStatic) ?? []; + } + else + { + candidates = declaringType.GetMethods(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers) + .Concat(declaringType.GetAccessors(m => m.Name == name, GetMemberOptions.IgnoreInheritedMembers)); + } + // Determine the expected parameters from the signature: a vararg signature is matched + // against its required parameters plus __arglist. + ImmutableArray parameterTypes; + if (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs) + { + parameterTypes = signature.ParameterTypes + .Take(signature.RequiredParameterCount) + .Concat(new[] { SpecialType.ArgList }) + .ToImmutableArray(); + } + else + { + parameterTypes = signature.ParameterTypes; + } + // Search for the matching method: foreach (var method in candidates) { if (method.TypeParameters.Count != signature.GenericParameterCount)