Browse Source

Fix CSharpDecompiler.ReadCodeMappingInfo not taking generic lambdas into account.

pull/1612/head
Siegfried Pammer 6 years ago
parent
commit
01b8b83360
  1. 104
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

104
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -622,39 +622,7 @@ namespace ICSharpCode.Decompiler.CSharp
var memberRef = module.Metadata.GetMemberReference((MemberReferenceHandle)token); var memberRef = module.Metadata.GetMemberReference((MemberReferenceHandle)token);
if (memberRef.GetKind() != MemberReferenceKind.Field) if (memberRef.GetKind() != MemberReferenceKind.Field)
continue; continue;
switch (memberRef.Parent.Kind) { fsmTypeDef = ExtractDeclaringType(memberRef);
case HandleKind.TypeReference:
// This should never happen in normal code, because we are looking at nested types
// If it's not a nested type, it can't be a reference to the state machine anyway, and
// those should be either TypeDef or TypeSpec.
continue;
case HandleKind.TypeDefinition:
fsmTypeDef = (TypeDefinitionHandle)memberRef.Parent;
break;
case HandleKind.TypeSpecification:
var ts = module.Metadata.GetTypeSpecification((TypeSpecificationHandle)memberRef.Parent);
if (ts.Signature.IsNil)
continue;
// Do a quick scan using BlobReader
var signature = module.Metadata.GetBlobReader(ts.Signature);
// When dealing with FSM implementations, we can safely assume that if it's a type spec,
// it must be a generic type instance.
if (signature.ReadByte() != (byte)SignatureTypeCode.GenericTypeInstance)
continue;
// Skip over the rawTypeKind: value type or class
var rawTypeKind = signature.ReadCompressedInteger();
if (rawTypeKind < 17 || rawTypeKind > 18)
continue;
// Only read the generic type, ignore the type arguments
var genericType = signature.ReadTypeHandle();
// Again, we assume this is a type def, because we are only looking at nested types
if (genericType.Kind != HandleKind.TypeDefinition)
continue;
fsmTypeDef = (TypeDefinitionHandle)genericType;
break;
default:
continue;
}
break; break;
default: default:
continue; continue;
@ -664,10 +632,10 @@ namespace ICSharpCode.Decompiler.CSharp
// Must be a nested type of the containing type. // Must be a nested type of the containing type.
if (fsmType.GetDeclaringType() != declaringType) if (fsmType.GetDeclaringType() != declaringType)
break; break;
if (!processedNestedTypes.Add(fsmTypeDef))
break;
if (YieldReturnDecompiler.IsCompilerGeneratorEnumerator(fsmTypeDef, module.Metadata) if (YieldReturnDecompiler.IsCompilerGeneratorEnumerator(fsmTypeDef, module.Metadata)
|| AsyncAwaitDecompiler.IsCompilerGeneratedStateMachine(fsmTypeDef, module.Metadata)) { || AsyncAwaitDecompiler.IsCompilerGeneratedStateMachine(fsmTypeDef, module.Metadata)) {
if (!processedNestedTypes.Add(fsmTypeDef))
break;
foreach (var h in fsmType.GetMethods()) { foreach (var h in fsmType.GetMethods()) {
if (module.MethodSemanticsLookup.GetSemantics(h).Item2 != 0) if (module.MethodSemanticsLookup.GetSemantics(h).Item2 != 0)
continue; continue;
@ -682,9 +650,35 @@ namespace ICSharpCode.Decompiler.CSharp
case ILOpCode.Ldftn: case ILOpCode.Ldftn:
// deal with ldftn instructions, i.e., lambdas // deal with ldftn instructions, i.e., lambdas
token = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32()); token = MetadataTokenHelpers.EntityHandleOrNil(blob.ReadInt32());
if (!token.IsNil && token.Kind == HandleKind.MethodDefinition) { if (token.IsNil)
if (((MethodDefinitionHandle)token).IsCompilerGeneratedOrIsInCompilerGeneratedClass(module.Metadata)) continue;
connectedMethods.Enqueue((MethodDefinitionHandle)token); TypeDefinitionHandle closureTypeHandle;
switch (token.Kind) {
case HandleKind.MethodDefinition:
if (((MethodDefinitionHandle)token).IsCompilerGeneratedOrIsInCompilerGeneratedClass(module.Metadata)) {
connectedMethods.Enqueue((MethodDefinitionHandle)token);
}
continue;
case HandleKind.MemberReference:
var memberRef = module.Metadata.GetMemberReference((MemberReferenceHandle)token);
if (memberRef.GetKind() != MemberReferenceKind.Method)
continue;
closureTypeHandle = ExtractDeclaringType(memberRef);
if (!closureTypeHandle.IsNil) {
var closureType = module.Metadata.GetTypeDefinition(closureTypeHandle);
// Must be a nested type of the containing type.
if (closureType.GetDeclaringType() != declaringType)
break;
if (!processedNestedTypes.Add(closureTypeHandle))
break;
foreach (var m in closureType.GetMethods()) {
connectedMethods.Enqueue(m);
}
break;
}
break;
default:
continue;
} }
break; break;
case ILOpCode.Call: case ILOpCode.Call:
@ -716,6 +710,40 @@ namespace ICSharpCode.Decompiler.CSharp
} }
info.AddMapping(parent, part); info.AddMapping(parent, part);
TypeDefinitionHandle ExtractDeclaringType(MemberReference memberRef)
{
switch (memberRef.Parent.Kind) {
case HandleKind.TypeReference:
// This should never happen in normal code, because we are looking at nested types
// If it's not a nested type, it can't be a reference to the state machine or lambda anyway, and
// those should be either TypeDef or TypeSpec.
return default;
case HandleKind.TypeDefinition:
return (TypeDefinitionHandle)memberRef.Parent;
case HandleKind.TypeSpecification:
var ts = module.Metadata.GetTypeSpecification((TypeSpecificationHandle)memberRef.Parent);
if (ts.Signature.IsNil)
return default;
// Do a quick scan using BlobReader
var signature = module.Metadata.GetBlobReader(ts.Signature);
// When dealing with FSM implementations, we can safely assume that if it's a type spec,
// it must be a generic type instance.
if (signature.ReadByte() != (byte)SignatureTypeCode.GenericTypeInstance)
return default;
// Skip over the rawTypeKind: value type or class
var rawTypeKind = signature.ReadCompressedInteger();
if (rawTypeKind < 17 || rawTypeKind > 18)
return default;
// Only read the generic type, ignore the type arguments
var genericType = signature.ReadTypeHandle();
// Again, we assume this is a type def, because we are only looking at nested types
if (genericType.Kind != HandleKind.TypeDefinition)
return default;
return (TypeDefinitionHandle)genericType;
}
return default;
}
} }
/// <summary> /// <summary>

Loading…
Cancel
Save