diff --git a/MetadataProvider/AssemblyExtractor.cs b/MetadataProvider/AssemblyExtractor.cs index 66787d90..9a500c8c 100644 --- a/MetadataProvider/AssemblyExtractor.cs +++ b/MetadataProvider/AssemblyExtractor.cs @@ -971,8 +971,10 @@ private IInstruction ExtractInstruction(ILInstruction operation) break; case SRM.ILOpCode.Ldftn: + instruction = ProcessLoadMethodAddress(operation, false); + break; case SRM.ILOpCode.Ldvirtftn: - instruction = ProcessLoadMethodAddress(operation); + instruction = ProcessLoadMethodAddress(operation, true); break; case SRM.ILOpCode.Ldc_i4: @@ -1305,7 +1307,10 @@ private IMethodReference GetMethodReference(SRM.MethodSpecificationHandle handle CreateGenericParameterReferences(GenericParameterKind.Method, genericArguments.Length); var method = GetMethodReference(methodspec.Method); - method = method.Instantiate(genericArguments); + // method might have not been extracted yet so some fields might be missing (ex: returnType, isStatic, etc). + // a proxy is used instead so when the method is actually extracted, this instantiated one is updated as well. + // Otherwise the instantiated one would have some null fields. + method = new MethodInstantiationProxy(method, genericArguments); BindGenericParameterReferences(GenericParameterKind.Method, method); return method; @@ -1573,10 +1578,24 @@ private IInstruction ProcessLoadField(ILInstruction op) return instruction; } - private IInstruction ProcessLoadMethodAddress(ILInstruction op) + private IInstruction ProcessLoadMethodAddress(ILInstruction op, bool isVirtual) { var operation = OperationHelper.ToLoadMethodAddressOperation(op.Opcode); var method = GetOperand(op); + switch (method) + { + case MethodDefinition methodDefinition: + { + methodDefinition.IsVirtual = isVirtual; + break; + } + case MethodReference methodReference: + { + methodReference.IsVirtual = isVirtual; + break; + } + default: throw new Exception("case not handled"); + } var instruction = new LoadMethodAddressInstruction(op.Offset, operation, method); return instruction; diff --git a/Model/Types/TypeDefinitions.cs b/Model/Types/TypeDefinitions.cs index 27062ea7..e17d7a7e 100644 --- a/Model/Types/TypeDefinitions.cs +++ b/Model/Types/TypeDefinitions.cs @@ -286,6 +286,7 @@ public interface IMethodReference : ITypeMemberReference, IMetadataReference, IG IMethodReference GenericMethod { get; } MethodDefinition ResolvedMethod { get; } bool IsStatic { get; } + bool IsVirtual { get; } } public class MethodReference : IMethodReference @@ -302,6 +303,7 @@ public class MethodReference : IMethodReference public IList Parameters { get; private set; } public IMethodReference GenericMethod { get; set; } public bool IsStatic { get; set; } + public bool IsVirtual { get; set; } public MethodReference(string name, IType returnType) { @@ -585,6 +587,35 @@ public override string ToString() return result.ToString(); } } + + public class MethodInstantiationProxy : IMethodReference + { + public IBasicType ContainingType => method.ContainingType; + public ISet Attributes => method.Attributes; + public int GenericParameterCount => method.GenericParameterCount; + public IType ReturnType => method.ReturnType; + public string Name => method.Name; + public string GenericName => method.GenericName; + public IList Parameters => method.Parameters; + public IList GenericArguments => genericArguments; + public IMethodReference GenericMethod => method; + + public MethodDefinition ResolvedMethod => + throw new InvalidOperationException("Use Resolve method to bind this reference with some host."); + + public bool IsStatic => method.IsStatic; + public bool IsVirtual => method.IsVirtual; + + private readonly IMethodReference method; + private readonly IList genericArguments; + + public MethodInstantiationProxy(IMethodReference method, IEnumerable genericArguments) + { + this.method = method; + this.genericArguments = new List(); + this.genericArguments.AddRange(genericArguments); + } + } public enum TypeDefinitionKind {