diff --git a/ILSpy/TreeNodes/Analyzer/Helpers.cs b/ILSpy/TreeNodes/Analyzer/Helpers.cs index c6caa9422..55f10b4d8 100644 --- a/ILSpy/TreeNodes/Analyzer/Helpers.cs +++ b/ILSpy/TreeNodes/Analyzer/Helpers.cs @@ -68,11 +68,24 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return typeUsage ?? method; } + + /// + /// Given a compiler-generated type, returns the method where that type is used. + /// Used to detect the 'parent method' for a lambda/iterator/async state machine. + /// public static MethodDefinition GetOriginalCodeLocation(TypeDefinition type) { if (type != null && type.DeclaringType != null && type.IsCompilerGenerated()) { - MethodDefinition constructor = GetTypeConstructor(type); - return FindMethodUsageInType(type.DeclaringType, constructor); + if (type.IsValueType) { + // Value types might not have any constructor; but they must be stored in a local var + // because 'initobj' (or 'call .ctor') expects a managed ref. + return FindVariableOfTypeUsageInType(type.DeclaringType, type); + } else { + MethodDefinition constructor = GetTypeConstructor(type); + if (constructor == null) + return null; + return FindMethodUsageInType(type.DeclaringType, constructor); + } } return null; } @@ -106,5 +119,26 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer } return null; } + + private static MethodDefinition FindVariableOfTypeUsageInType(TypeDefinition type, TypeDefinition variableType) + { + foreach (MethodDefinition method in type.Methods) { + bool found = false; + if (!method.HasBody) + continue; + foreach (var v in method.Body.Variables) { + if (v.VariableType.ResolveWithinSameModule() == variableType) { + found = true; + break; + } + } + + method.Body = null; + + if (found) + return method; + } + return null; + } } }