From 9acc372a684e4cc2f506d751a9d7eec36e795177 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 1 Jul 2018 11:47:22 +0200 Subject: [PATCH 01/13] Use TypeSystem for ILSpy UI: Most important tree nodes and search ported, Currently only ILLanguage is active --- .../AddXmlDocumentationTransform.cs | 5 +- .../Disassembler/DomExtensions.cs | 15 +- .../Disassembler/ReflectionDisassembler.cs | 138 ++-- .../Documentation/XmlDocKeyProvider.cs | 591 +++++++++--------- .../ICSharpCode.Decompiler.csproj | 2 +- ICSharpCode.Decompiler/Metadata/Dom.cs | 402 ------------ .../Metadata/MetadataExtensions.cs | 36 -- .../Metadata/MetadataResolver.cs | 50 +- ICSharpCode.Decompiler/Metadata/PEFile.cs | 1 - .../Metadata/UniversalAssemblyResolver.cs | 3 +- ICSharpCode.Decompiler/Output/ITextOutput.cs | 25 + .../Output/PlainTextOutput.cs | 3 + .../Output/TextTokenWriter.cs | 82 +-- .../Implementation/MetadataTypeDefinition.cs | 3 +- .../TypeSystem/MetadataAssembly.cs | 2 +- ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs | 1 - .../ConnectMethodDecompiler.cs | 34 +- ILSpy/AnalyzerTreeView.cs | 4 +- ILSpy/Commands/DecompileAllCommand.cs | 2 +- ILSpy/DebugSteps.xaml.cs | 14 +- ILSpy/ILSpy.csproj | 14 - ILSpy/Languages/CodeMappingInfo.cs | 3 +- ILSpy/Languages/ILLanguage.cs | 46 +- ILSpy/Languages/Language.cs | 208 ++---- ILSpy/Languages/Languages.cs | 2 +- ILSpy/LoadedAssembly.cs | 20 +- ILSpy/MainWindow.xaml.cs | 34 +- ILSpy/SearchPane.cs | 9 +- ILSpy/SearchStrategies.cs | 157 ++--- ILSpy/TextView/DecompilerTextView.cs | 9 +- .../Analyzer/AnalyzeContextMenuEntry.cs | 13 +- ILSpy/TreeNodes/AssemblyListTreeNode.cs | 97 +-- ILSpy/TreeNodes/AssemblyTreeNode.cs | 16 +- ILSpy/TreeNodes/BaseTypesEntryNode.cs | 55 +- ILSpy/TreeNodes/BaseTypesTreeNode.cs | 33 +- .../CopyFullyQualifiedNameContextMenuEntry.cs | 52 +- ILSpy/TreeNodes/DerivedTypesEntryNode.cs | 11 +- ILSpy/TreeNodes/DerivedTypesTreeNode.cs | 6 +- ILSpy/TreeNodes/EventTreeNode.cs | 52 +- ILSpy/TreeNodes/FieldTreeNode.cs | 54 +- ILSpy/TreeNodes/IMemberTreeNode.cs | 6 +- ILSpy/TreeNodes/MethodTreeNode.cs | 35 +- ILSpy/TreeNodes/PropertyTreeNode.cs | 44 +- ILSpy/TreeNodes/TypeTreeNode.cs | 111 ++-- TestPlugin/CustomLanguage.cs | 9 +- 45 files changed, 953 insertions(+), 1556 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/AddXmlDocumentationTransform.cs b/ICSharpCode.Decompiler/CSharp/Transforms/AddXmlDocumentationTransform.cs index 84ecf1b28..07a7b822a 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/AddXmlDocumentationTransform.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/AddXmlDocumentationTransform.cs @@ -41,10 +41,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms if (xmldoc == null) return; foreach (var entity in rootNode.DescendantsAndSelf.OfType()) { - var handle = ((entity.GetSymbol() as IEntity)?.MetadataToken).Value; - if (handle.IsNil) + if (!(entity.GetSymbol() is IEntity symbolicEntity)) continue; - string doc = xmldoc.GetDocumentation(XmlDocKeyProvider.GetKey(context.TypeSystem.GetMetadata(), handle)); + string doc = xmldoc.GetDocumentation(XmlDocKeyProvider.GetKey(symbolicEntity)); if (doc != null) { InsertXmlDocumentation(entity, new StringReader(doc)); } diff --git a/ICSharpCode.Decompiler/Disassembler/DomExtensions.cs b/ICSharpCode.Decompiler/Disassembler/DomExtensions.cs index f4eb431b6..ecde19ff1 100644 --- a/ICSharpCode.Decompiler/Disassembler/DomExtensions.cs +++ b/ICSharpCode.Decompiler/Disassembler/DomExtensions.cs @@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.Disassembler switch (entity.Kind) { case HandleKind.TypeDefinition: { var td = metadata.GetTypeDefinition((TypeDefinitionHandle)entity); - output.WriteReference(td.GetFullTypeName(metadata).ToILNameString(), new Metadata.TypeDefinition(module, (TypeDefinitionHandle)entity)); + output.WriteReference(module, entity, td.GetFullTypeName(metadata).ToILNameString()); break; } case HandleKind.TypeReference: { @@ -68,7 +68,7 @@ namespace ICSharpCode.Decompiler.Disassembler } output.Write("]"); } - output.WriteReference(entity.GetFullTypeName(metadata).ToILNameString(), new Metadata.TypeReference(module, (TypeReferenceHandle)entity)); + output.WriteReference(module, entity, entity.GetFullTypeName(metadata).ToILNameString()); break; } case HandleKind.TypeSpecification: { @@ -84,7 +84,7 @@ namespace ICSharpCode.Decompiler.Disassembler output.Write(' '); ((EntityHandle)fd.GetDeclaringType()).WriteTo(module, output, GenericContext.Empty, ILNameSyntax.TypeName); output.Write("::"); - output.WriteReference(DisassemblerHelpers.Escape(metadata.GetString(fd.Name)), new Metadata.FieldDefinition(module, (FieldDefinitionHandle)entity)); + output.WriteReference(module, entity, DisassemblerHelpers.Escape(metadata.GetString(fd.Name))); break; } case HandleKind.MethodDefinition: { @@ -106,11 +106,10 @@ namespace ICSharpCode.Decompiler.Disassembler output.Write("::"); } bool isCompilerControlled = (md.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.PrivateScope; - var reference = new Metadata.MethodDefinition(module, (MethodDefinitionHandle)entity); if (isCompilerControlled) { - output.WriteReference(DisassemblerHelpers.Escape(metadata.GetString(md.Name) + "$PST" + MetadataTokens.GetToken(entity).ToString("X8")), reference); + output.WriteReference(module, entity, DisassemblerHelpers.Escape(metadata.GetString(md.Name) + "$PST" + MetadataTokens.GetToken(entity).ToString("X8"))); } else { - output.WriteReference(DisassemblerHelpers.Escape(metadata.GetString(md.Name)), reference); + output.WriteReference(module, entity, DisassemblerHelpers.Escape(metadata.GetString(md.Name))); } var genericParameters = md.GetGenericParameters(); if (genericParameters.Count > 0) { @@ -174,7 +173,7 @@ namespace ICSharpCode.Decompiler.Disassembler output.Write(' '); WriteParent(output, module, metadata, mr.Parent, genericContext, syntax); output.Write("::"); - output.WriteReference(DisassemblerHelpers.Escape(memberName), new Metadata.MemberReference(module, (MemberReferenceHandle)entity)); + output.WriteReference(module, entity, DisassemblerHelpers.Escape(memberName)); output.Write("("); for (int i = 0; i < methodSignature.ParameterTypes.Length; ++i) { if (i > 0) @@ -191,7 +190,7 @@ namespace ICSharpCode.Decompiler.Disassembler output.Write(' '); WriteParent(output, module, metadata, mr.Parent, genericContext, syntax); output.Write("::"); - output.WriteReference(DisassemblerHelpers.Escape(memberName), new Metadata.MemberReference(module, (MemberReferenceHandle)entity)); + output.WriteReference(module, entity, DisassemblerHelpers.Escape(memberName)); break; } break; diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs index f323f9a29..4d045e034 100644 --- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs @@ -125,25 +125,27 @@ namespace ICSharpCode.Decompiler.Disassembler public void DisassembleMethod(PEFile module, MethodDefinitionHandle handle) { - var metadata = module.Metadata; var genericContext = new GenericContext(handle, module); // write method header - output.WriteDefinition(".method ", new Metadata.MethodDefinition(module, handle)); - DisassembleMethodHeaderInternal(module, handle, metadata, genericContext); - DisassembleMethodBlock(module, handle, metadata, genericContext); + output.WriteReference(module, handle, ".method", isDefinition: true); + output.Write(" "); + DisassembleMethodHeaderInternal(module, handle, genericContext); + DisassembleMethodBlock(module, handle, genericContext); } public void DisassembleMethodHeader(PEFile module, MethodDefinitionHandle handle) { - var metadata = module.Metadata; var genericContext = new GenericContext(handle, module); // write method header - output.WriteDefinition(".method ", new Metadata.MethodDefinition(module, handle)); - DisassembleMethodHeaderInternal(module, handle, metadata, genericContext); + output.WriteReference(module, handle, ".method", isDefinition: true); + output.Write(" "); + DisassembleMethodHeaderInternal(module, handle, genericContext); } - void DisassembleMethodHeaderInternal(PEFile module, MethodDefinitionHandle handle, MetadataReader metadata, GenericContext genericContext) + void DisassembleMethodHeaderInternal(PEFile module, MethodDefinitionHandle handle, GenericContext genericContext) { + var metadata = module.Metadata; + WriteMetadataToken(handle, spaceAfter:true); var methodDefinition = metadata.GetMethodDefinition(handle); // .method public hidebysig specialname @@ -272,8 +274,9 @@ namespace ICSharpCode.Decompiler.Disassembler } } - void DisassembleMethodBlock(PEFile module, MethodDefinitionHandle handle, MetadataReader metadata, GenericContext genericContext) + void DisassembleMethodBlock(PEFile module, MethodDefinitionHandle handle, GenericContext genericContext) { + var metadata = module.Metadata; var methodDefinition = metadata.GetMethodDefinition(handle); OpenBlock(defaultCollapsed: isInType); @@ -481,7 +484,7 @@ namespace ICSharpCode.Decompiler.Disassembler } } - PrimitiveSerializationTypeCode ResolveEnumUnderlyingType(string typeName, PEFile module, out Metadata.TypeDefinition typeDefinition) + PrimitiveSerializationTypeCode ResolveEnumUnderlyingType(string typeName, PEFile module, out (PEFile Module, EntityHandle Handle) typeDefinition) { typeDefinition = default; @@ -529,7 +532,7 @@ namespace ICSharpCode.Decompiler.Disassembler var metadata = containingModule.Metadata; if (handle.IsNil || !handle.IsEnum(metadata, out var typeCode)) throw new NotSupportedException(); - typeDefinition = new Metadata.TypeDefinition(containingModule, handle); + typeDefinition = (containingModule, handle); return (PrimitiveSerializationTypeCode)typeCode; } else { // just fully-qualified name, try current assembly @@ -545,7 +548,7 @@ namespace ICSharpCode.Decompiler.Disassembler var metadata = module.Metadata; if (handle.IsNil || !handle.IsEnum(metadata, out var typeCode)) throw new NotSupportedException(); - typeDefinition = new Metadata.TypeDefinition(module, handle); + typeDefinition = (module, handle); return (PrimitiveSerializationTypeCode)typeCode; } } @@ -625,14 +628,14 @@ namespace ICSharpCode.Decompiler.Disassembler } var typeInfo = ReadArgumentType(ref blob); var typeCode = typeInfo.TypeCode; - var typeDefinition = default(Metadata.TypeDefinition); + var typeDefinition = default((PEFile Module, EntityHandle Handle)); if (typeInfo.Kind == TypeKind.Enum) { typeCode = ResolveEnumUnderlyingType(typeInfo.TypeName, module, out typeDefinition); } var name = blob.ReadSerializedString(); object value = ReadArgumentValue(ref blob, typeCode, typeInfo.Kind, typeInfo.IsArray, typeInfo.TypeName); - WriteTypeInfo(typeInfo.TypeCode, typeInfo.Kind, typeInfo.IsArray, typeInfo.TypeName, typeDefinition, module); + WriteTypeInfo(module, typeInfo.TypeCode, typeInfo.Kind, typeInfo.IsArray, typeInfo.TypeName, typeDefinition.Module, typeDefinition.Handle); output.Write(' '); output.Write(DisassemblerHelpers.Escape(name)); @@ -645,7 +648,7 @@ namespace ICSharpCode.Decompiler.Disassembler if (typeInfo.Kind == TypeKind.Enum || typeInfo.Kind == TypeKind.Primitive) { WritePrimitiveTypeCode(typeCode); } else { - WriteTypeInfo(typeCode, typeInfo.Kind, typeInfo.IsArray, typeInfo.TypeName, typeDefinition, module); + WriteTypeInfo(module, typeInfo.TypeCode, typeInfo.Kind, typeInfo.IsArray, typeInfo.TypeName, typeDefinition.Module, typeDefinition.Handle); } output.Write('('); DisassemblerHelpers.WriteOperand(output, value); @@ -653,7 +656,8 @@ namespace ICSharpCode.Decompiler.Disassembler } } - private void WriteTypeInfo(PrimitiveSerializationTypeCode typeCode, TypeKind kind, bool isArray, string typeName, Metadata.TypeDefinition type, PEFile currentModule) + private void WriteTypeInfo(PEFile currentModule, PrimitiveSerializationTypeCode typeCode, TypeKind kind, + bool isArray, string typeName, PEFile referencedModule, EntityHandle type) { switch (kind) { case TypeKind.Primitive: @@ -669,12 +673,11 @@ namespace ICSharpCode.Decompiler.Disassembler output.Write(DisassemblerHelpers.Escape(typeName)); break; } - var referencedModule = type.Module; if (referencedModule != currentModule) { output.Write('['); output.Write(referencedModule.Name); output.Write(']'); - output.WriteReference(type.Handle.GetFullTypeName(type.Module.Metadata).ToString(), type); + output.WriteReference(referencedModule, type, type.GetFullTypeName(referencedModule.Metadata).ToString()); } else { output.Write(DisassemblerHelpers.Escape(typeName)); } @@ -1019,10 +1022,10 @@ namespace ICSharpCode.Decompiler.Disassembler { FieldAttributes.NotSerialized, "notserialized" }, }; - public void DisassembleField(Metadata.FieldDefinition field) + public void DisassembleField(PEFile module, FieldDefinitionHandle field) { - var metadata = field.Module.Metadata; - var fieldDefinition = metadata.GetFieldDefinition(field.Handle); + var metadata = module.Metadata; + var fieldDefinition = metadata.GetFieldDefinition(field); output.WriteDefinition(".field ", field); int offset = fieldDefinition.GetOffset(); if (offset > -1) { @@ -1032,7 +1035,7 @@ namespace ICSharpCode.Decompiler.Disassembler const FieldAttributes hasXAttributes = FieldAttributes.HasDefault | FieldAttributes.HasFieldMarshal | FieldAttributes.HasFieldRVA; WriteFlags(fieldDefinition.Attributes & ~(FieldAttributes.FieldAccessMask | hasXAttributes), fieldAttributes); - var signature = fieldDefinition.DecodeSignature(new DisassemblerSignatureProvider(field.Module, output), new GenericContext(fieldDefinition.GetDeclaringType(), field.Module)); + var signature = fieldDefinition.DecodeSignature(new DisassemblerSignatureProvider(module, output), new GenericContext(fieldDefinition.GetDeclaringType(), module)); var marshallingDescriptor = fieldDefinition.GetMarshallingDescriptor(); if (!marshallingDescriptor.IsNil) { @@ -1056,7 +1059,7 @@ namespace ICSharpCode.Decompiler.Disassembler var attributes = fieldDefinition.GetCustomAttributes(); if (attributes.Count > 0) { output.MarkFoldStart(); - WriteAttributes(field.Module, fieldDefinition.GetCustomAttributes()); + WriteAttributes(module, fieldDefinition.GetCustomAttributes()); output.MarkFoldEnd(); } } @@ -1069,15 +1072,16 @@ namespace ICSharpCode.Decompiler.Disassembler { PropertyAttributes.HasDefault, "hasdefault" }, }; - public void DisassembleProperty(Metadata.PropertyDefinition property) + public void DisassembleProperty(PEFile module, PropertyDefinitionHandle property) { - var metadata = property.Module.Metadata; - var propertyDefinition = metadata.GetPropertyDefinition(property.Handle); - output.WriteDefinition(".property ", property); + var metadata = module.Metadata; + var propertyDefinition = metadata.GetPropertyDefinition(property); + output.WriteReference(module, property, ".property", true); + output.Write(" "); WriteFlags(propertyDefinition.Attributes, propertyAttributes); var accessors = propertyDefinition.GetAccessors(); var declaringType = metadata.GetMethodDefinition(accessors.GetAny()).GetDeclaringType(); - var signature = propertyDefinition.DecodeSignature(new DisassemblerSignatureProvider(property.Module, output), new GenericContext(declaringType, property.Module)); + var signature = propertyDefinition.DecodeSignature(new DisassemblerSignatureProvider(module, output), new GenericContext(declaringType, module)); if (signature.Header.IsInstance) output.Write("instance "); @@ -1098,23 +1102,23 @@ namespace ICSharpCode.Decompiler.Disassembler output.Write(')'); OpenBlock(false); - WriteAttributes(property.Module, propertyDefinition.GetCustomAttributes()); - WriteNestedMethod(".get", new Metadata.MethodDefinition(property.Module, accessors.Getter)); - WriteNestedMethod(".set", new Metadata.MethodDefinition(property.Module, accessors.Setter)); + WriteAttributes(module, propertyDefinition.GetCustomAttributes()); + WriteNestedMethod(".get", module, accessors.Getter); + WriteNestedMethod(".set", module, accessors.Setter); /*foreach (var method in property.OtherMethods) { WriteNestedMethod(".other", method); }*/ CloseBlock(); } - void WriteNestedMethod(string keyword, Metadata.MethodDefinition method) + void WriteNestedMethod(string keyword, PEFile module, MethodDefinitionHandle method) { if (method.IsNil) return; output.Write(keyword); output.Write(' '); - ((EntityHandle)method.Handle).WriteTo(method.Module, output, GenericContext.Empty); + ((EntityHandle)method).WriteTo(module, output, GenericContext.Empty); output.WriteLine(); } #endregion @@ -1127,28 +1131,28 @@ namespace ICSharpCode.Decompiler.Disassembler public void DisassembleEvent(PEFile module, EventDefinitionHandle handle) { - var metadata = module.Metadata; - var eventDefinition = metadata.GetEventDefinition(handle); + var eventDefinition = module.Metadata.GetEventDefinition(handle); var accessors = eventDefinition.GetAccessors(); TypeDefinitionHandle declaringType; if (!accessors.Adder.IsNil) { - declaringType = metadata.GetMethodDefinition(accessors.Adder).GetDeclaringType(); + declaringType = module.Metadata.GetMethodDefinition(accessors.Adder).GetDeclaringType(); } else if (!accessors.Remover.IsNil) { - declaringType = metadata.GetMethodDefinition(accessors.Remover).GetDeclaringType(); + declaringType = module.Metadata.GetMethodDefinition(accessors.Remover).GetDeclaringType(); } else { - declaringType = metadata.GetMethodDefinition(accessors.Raiser).GetDeclaringType(); + declaringType = module.Metadata.GetMethodDefinition(accessors.Raiser).GetDeclaringType(); } - output.WriteDefinition(".event ", new Metadata.EventDefinition(module, handle)); + output.WriteReference(module, handle, ".event", true); + output.Write(" "); WriteFlags(eventDefinition.Attributes, eventAttributes); - var signature = eventDefinition.DecodeSignature(metadata, new DisassemblerSignatureProvider(module, output), new GenericContext(declaringType, module)); + var signature = eventDefinition.DecodeSignature(module.Metadata, new DisassemblerSignatureProvider(module, output), new GenericContext(declaringType, module)); signature(ILNameSyntax.TypeName); output.Write(' '); - output.Write(DisassemblerHelpers.Escape(metadata.GetString(eventDefinition.Name))); + output.Write(DisassemblerHelpers.Escape(module.Metadata.GetString(eventDefinition.Name))); OpenBlock(false); WriteAttributes(module, eventDefinition.GetCustomAttributes()); - WriteNestedMethod(".addon", new Metadata.MethodDefinition(module, accessors.Adder)); - WriteNestedMethod(".removeon", new Metadata.MethodDefinition(module, accessors.Remover)); - WriteNestedMethod(".fire", new Metadata.MethodDefinition(module, accessors.Raiser)); + WriteNestedMethod(".addon", module, accessors.Adder); + WriteNestedMethod(".removeon", module, accessors.Remover); + WriteNestedMethod(".fire", module, accessors.Raiser); /*foreach (var method in ev.OtherMethods) { WriteNestedMethod(".other", method); }*/ @@ -1191,12 +1195,11 @@ namespace ICSharpCode.Decompiler.Disassembler { TypeAttributes.HasSecurity, null }, }; - public void DisassembleType(Metadata.TypeDefinition type) + public void DisassembleType(PEFile module, TypeDefinitionHandle type) { - var metadata = type.Module.Metadata; - var typeDefinition = metadata.GetTypeDefinition(type.Handle); - output.WriteDefinition(".class ", type); - + var typeDefinition = module.Metadata.GetTypeDefinition(type); + output.WriteReference(module, type, ".class", true); + output.Write(" "); if ((typeDefinition.Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface) output.Write("interface "); WriteEnum(typeDefinition.Attributes & TypeAttributes.VisibilityMask, typeVisibility); @@ -1205,15 +1208,16 @@ namespace ICSharpCode.Decompiler.Disassembler const TypeAttributes masks = TypeAttributes.ClassSemanticsMask | TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.StringFormatMask; WriteFlags(typeDefinition.Attributes & ~masks, typeAttributes); - output.Write(typeDefinition.GetDeclaringType().IsNil ? typeDefinition.GetFullTypeName(metadata).ToILNameString() : DisassemblerHelpers.Escape(metadata.GetString(typeDefinition.Name))); - WriteTypeParameters(output, type.Module, new GenericContext(type), typeDefinition.GetGenericParameters()); + output.Write(typeDefinition.GetDeclaringType().IsNil ? typeDefinition.GetFullTypeName(module.Metadata).ToILNameString() : DisassemblerHelpers.Escape(module.Metadata.GetString(typeDefinition.Name))); + GenericContext genericContext = new GenericContext(type, module); + WriteTypeParameters(output, module, genericContext, typeDefinition.GetGenericParameters()); output.MarkFoldStart(defaultCollapsed: !ExpandMemberDefinitions && isInType); output.WriteLine(); if (!typeDefinition.BaseType.IsNil) { output.Indent(); output.Write("extends "); - typeDefinition.BaseType.WriteTo(type.Module, output, new GenericContext(type), ILNameSyntax.TypeName); + typeDefinition.BaseType.WriteTo(module, output, genericContext, ILNameSyntax.TypeName); output.WriteLine(); output.Unindent(); } @@ -1229,9 +1233,9 @@ namespace ICSharpCode.Decompiler.Disassembler else output.Write(" "); first = false; - var iface = metadata.GetInterfaceImplementation(i); - WriteAttributes(type.Module, iface.GetCustomAttributes()); - iface.Interface.WriteTo(type.Module, output, new GenericContext(type), ILNameSyntax.TypeName); + var iface = module.Metadata.GetInterfaceImplementation(i); + WriteAttributes(module, iface.GetCustomAttributes()); + iface.Interface.WriteTo(module, output, genericContext, ILNameSyntax.TypeName); } output.WriteLine(); output.Unindent(); @@ -1241,8 +1245,8 @@ namespace ICSharpCode.Decompiler.Disassembler output.Indent(); bool oldIsInType = isInType; isInType = true; - WriteAttributes(type.Module, typeDefinition.GetCustomAttributes()); - WriteSecurityDeclarations(type.Module, typeDefinition.GetDeclarativeSecurityAttributes()); + WriteAttributes(module, typeDefinition.GetCustomAttributes()); + WriteSecurityDeclarations(module, typeDefinition.GetDeclarativeSecurityAttributes()); var layout = typeDefinition.GetLayout(); if (!layout.IsDefault) { output.WriteLine(".pack {0}", layout.PackingSize); @@ -1254,7 +1258,7 @@ namespace ICSharpCode.Decompiler.Disassembler output.WriteLine("// Nested Types"); foreach (var nestedType in nestedTypes) { cancellationToken.ThrowIfCancellationRequested(); - DisassembleType(new Metadata.TypeDefinition(type.Module, nestedType)); + DisassembleType(module, nestedType); output.WriteLine(); } output.WriteLine(); @@ -1264,7 +1268,7 @@ namespace ICSharpCode.Decompiler.Disassembler output.WriteLine("// Fields"); foreach (var field in fields) { cancellationToken.ThrowIfCancellationRequested(); - DisassembleField(new Metadata.FieldDefinition(type.Module, field)); + DisassembleField(module, field); } output.WriteLine(); } @@ -1273,7 +1277,7 @@ namespace ICSharpCode.Decompiler.Disassembler output.WriteLine("// Methods"); foreach (var m in methods) { cancellationToken.ThrowIfCancellationRequested(); - DisassembleMethod(type.Module, m); + DisassembleMethod(module, m); output.WriteLine(); } } @@ -1282,7 +1286,7 @@ namespace ICSharpCode.Decompiler.Disassembler output.WriteLine("// Events"); foreach (var ev in events) { cancellationToken.ThrowIfCancellationRequested(); - DisassembleEvent(type.Module, ev); + DisassembleEvent(module, ev); output.WriteLine(); } output.WriteLine(); @@ -1292,11 +1296,11 @@ namespace ICSharpCode.Decompiler.Disassembler output.WriteLine("// Properties"); foreach (var prop in properties) { cancellationToken.ThrowIfCancellationRequested(); - DisassembleProperty(new Metadata.PropertyDefinition(type.Module, prop)); + DisassembleProperty(module, prop); } output.WriteLine(); } - CloseBlock("end of class " + (!typeDefinition.GetDeclaringType().IsNil ? metadata.GetString(typeDefinition.Name) : typeDefinition.GetFullTypeName(metadata).ToString())); + CloseBlock("end of class " + (!typeDefinition.GetDeclaringType().IsNil ? module.Metadata.GetString(typeDefinition.Name) : typeDefinition.GetFullTypeName(module.Metadata).ToString())); isInType = oldIsInType; } @@ -1449,7 +1453,7 @@ namespace ICSharpCode.Decompiler.Disassembler } #endregion - public void DisassembleNamespace(string nameSpace, IEnumerable types) + public void DisassembleNamespace(string nameSpace, PEFile module, IEnumerable types) { if (!string.IsNullOrEmpty(nameSpace)) { output.Write(".namespace " + DisassemblerHelpers.Escape(nameSpace)); @@ -1459,7 +1463,7 @@ namespace ICSharpCode.Decompiler.Disassembler isInType = true; foreach (var td in types) { cancellationToken.ThrowIfCancellationRequested(); - DisassembleType(td); + DisassembleType(module, td); output.WriteLine(); } if (!string.IsNullOrEmpty(nameSpace)) { @@ -1590,8 +1594,8 @@ namespace ICSharpCode.Decompiler.Disassembler public void WriteModuleContents(PEFile module) { - foreach (var handle in module.TopLevelTypeDefinitions) { - DisassembleType(handle); + foreach (var handle in module.Metadata.GetTopLevelTypeDefinitions()) { + DisassembleType(module, handle); output.WriteLine(); } } diff --git a/ICSharpCode.Decompiler/Documentation/XmlDocKeyProvider.cs b/ICSharpCode.Decompiler/Documentation/XmlDocKeyProvider.cs index 51cc7c3c5..e98469560 100644 --- a/ICSharpCode.Decompiler/Documentation/XmlDocKeyProvider.cs +++ b/ICSharpCode.Decompiler/Documentation/XmlDocKeyProvider.cs @@ -18,14 +18,10 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Text; using ICSharpCode.Decompiler.TypeSystem; -using ICSharpCode.Decompiler.Metadata; -using SRM = System.Reflection.Metadata; -using ICSharpCode.Decompiler.Util; -using System.Collections.Immutable; +using ICSharpCode.Decompiler.TypeSystem.Implementation; namespace ICSharpCode.Decompiler.Documentation { @@ -35,324 +31,361 @@ namespace ICSharpCode.Decompiler.Documentation public static class XmlDocKeyProvider { #region GetKey - public static string GetKey(Entity entity) - { - return GetKey(entity.Module.Metadata, entity.Handle); - } - - public static string GetKey(SRM.MetadataReader metadata, SRM.EntityHandle member) + /// + /// Gets the ID string (C# 4.0 spec, §A.3.1) for the specified entity. + /// + public static string GetKey(IEntity entity) { StringBuilder b = new StringBuilder(); - - void AppendTypeName(SRM.EntityHandle type) - { - switch (type.Kind) { - case SRM.HandleKind.TypeDefinition: - b.Append("T:"); - b.Append(((SRM.TypeDefinitionHandle)type).GetFullTypeName(metadata)); - break; - case SRM.HandleKind.TypeReference: - b.Append("T:"); - b.Append(((SRM.TypeReferenceHandle)type).GetFullTypeName(metadata)); - break; - default: - throw new NotImplementedException(); - /*case SRM.HandleKind.TypeSpecification: - b.Append("T:"); - var typeSpec = metadata.GetTypeSpecification((SRM.TypeSpecificationHandle)type); - b.Append(typeSpec.DecodeSignature(new DocumentationKeySignatureTypeProvider(), default(Unit))); - break;*/ - } + switch (entity.SymbolKind) { + case SymbolKind.TypeDefinition: + b.Append("T:"); + AppendTypeName(b, (ITypeDefinition)entity, false); + return b.ToString(); + case SymbolKind.Field: + b.Append("F:"); + break; + case SymbolKind.Property: + case SymbolKind.Indexer: + b.Append("P:"); + break; + case SymbolKind.Event: + b.Append("E:"); + break; + default: + b.Append("M:"); + break; } - - void AppendSignature(SRM.MethodSignature signature, bool printExplicitReturnType = false) - { - if (signature.GenericParameterCount > 0) { - b.Append("``"); - b.Append(signature.GenericParameterCount); - } + IMember member = (IMember)entity; + if (member.DeclaringType != null) { + AppendTypeName(b, member.DeclaringType, false); + b.Append('.'); + } + if (member.IsExplicitInterfaceImplementation && member.Name.IndexOf('.') < 0 && member.ExplicitlyImplementedInterfaceMembers.Count() == 1) { + AppendTypeName(b, member.ExplicitlyImplementedInterfaceMembers.First().DeclaringType, true); + b.Append('#'); + } + b.Append(member.Name.Replace('.', '#')); + IMethod method = member as IMethod; + if (method != null && method.TypeParameters.Count > 0) { + b.Append("``"); + b.Append(method.TypeParameters.Count); + } + IParameterizedMember parameterizedMember = member as IParameterizedMember; + if (parameterizedMember != null && parameterizedMember.Parameters.Count > 0) { b.Append('('); - for (int i = 0; i < signature.ParameterTypes.Length; i++) { - if (i > 0) - b.Append(','); - b.Append(signature.ParameterTypes[i]); + var parameters = parameterizedMember.Parameters; + for (int i = 0; i < parameters.Count; i++) { + if (i > 0) b.Append(','); + AppendTypeName(b, parameters[i].Type, false); } b.Append(')'); - if (printExplicitReturnType) { - b.Append('~'); - b.Append(signature.ReturnType); - } } + if (member.SymbolKind == SymbolKind.Operator && (member.Name == "op_Implicit" || member.Name == "op_Explicit")) { + b.Append('~'); + AppendTypeName(b, member.ReturnType, false); + } + return b.ToString(); + } + #endregion - switch (member.Kind) { - case SRM.HandleKind.TypeDefinition: - case SRM.HandleKind.TypeReference: - case SRM.HandleKind.TypeSpecification: - b.Append("T:"); - AppendTypeName(member); - break; - case SRM.HandleKind.FieldDefinition: - b.Append("F:"); - var field = metadata.GetFieldDefinition((SRM.FieldDefinitionHandle)member); - AppendTypeName(field.GetDeclaringType()); - b.Append('.'); - b.Append(metadata.GetString(field.Name).Replace('.', '#')); + #region GetTypeName + public static string GetTypeName(IType type) + { + if (type == null) + throw new ArgumentNullException("type"); + StringBuilder b = new StringBuilder(); + AppendTypeName(b, type, false); + return b.ToString(); + } + + static void AppendTypeName(StringBuilder b, IType type, bool explicitInterfaceImpl) + { + switch (type.Kind) { + case TypeKind.Dynamic: + b.Append(explicitInterfaceImpl ? "System#Object" : "System.Object"); break; - case SRM.HandleKind.PropertyDefinition: { - b.Append("P:"); - var property = metadata.GetPropertyDefinition((SRM.PropertyDefinitionHandle)member); - var accessors = property.GetAccessors(); - SRM.TypeDefinitionHandle declaringType; - if (!accessors.Getter.IsNil) { - declaringType = metadata.GetMethodDefinition(accessors.Getter).GetDeclaringType(); + case TypeKind.TypeParameter: + ITypeParameter tp = (ITypeParameter)type; + if (explicitInterfaceImpl) { + b.Append(tp.Name); } else { - declaringType = metadata.GetMethodDefinition(accessors.Setter).GetDeclaringType(); + b.Append('`'); + if (tp.OwnerType == SymbolKind.Method) + b.Append('`'); + b.Append(tp.Index); } - AppendTypeName(declaringType); - b.Append('.'); - b.Append(metadata.GetString(property.Name).Replace('.', '#')); - AppendSignature(property.DecodeSignature(new DocumentationKeySignatureTypeProvider(), default(Unit))); break; - } - case SRM.HandleKind.MethodDefinition: - b.Append("M:"); - var method = metadata.GetMethodDefinition((SRM.MethodDefinitionHandle)member); - AppendTypeName(method.GetDeclaringType()); - b.Append('.'); - var methodName = metadata.GetString(method.Name); - b.Append(metadata.GetString(method.Name).Replace('.', '#')); - AppendSignature(method.DecodeSignature(new DocumentationKeySignatureTypeProvider(), default(Unit)), methodName == "op_Implicit" || methodName == "op_Explicit"); + case TypeKind.Array: + ArrayType array = (ArrayType)type; + AppendTypeName(b, array.ElementType, explicitInterfaceImpl); + b.Append('['); + if (array.Dimensions > 1) { + for (int i = 0; i < array.Dimensions; i++) { + if (i > 0) + b.Append(explicitInterfaceImpl ? '@' : ','); + if (!explicitInterfaceImpl) + b.Append("0:"); + } + } + b.Append(']'); break; - case SRM.HandleKind.EventDefinition: { - b.Append("E:"); - var @event = metadata.GetEventDefinition((SRM.EventDefinitionHandle)member); - var accessors = @event.GetAccessors(); - SRM.TypeDefinitionHandle declaringType; - if (!accessors.Adder.IsNil) { - declaringType = metadata.GetMethodDefinition(accessors.Adder).GetDeclaringType(); - } else if (!accessors.Remover.IsNil) { - declaringType = metadata.GetMethodDefinition(accessors.Remover).GetDeclaringType(); + case TypeKind.Pointer: + AppendTypeName(b, ((PointerType)type).ElementType, explicitInterfaceImpl); + b.Append('*'); + break; + case TypeKind.ByReference: + AppendTypeName(b, ((ByReferenceType)type).ElementType, explicitInterfaceImpl); + b.Append('@'); + break; + default: + IType declType = type.DeclaringType; + if (declType != null) { + AppendTypeName(b, declType, explicitInterfaceImpl); + b.Append(explicitInterfaceImpl ? '#' : '.'); + b.Append(type.Name); + AppendTypeParameters(b, type, declType.TypeParameterCount, explicitInterfaceImpl); } else { - declaringType = metadata.GetMethodDefinition(accessors.Raiser).GetDeclaringType(); + if (explicitInterfaceImpl) + b.Append(type.FullName.Replace('.', '#')); + else + b.Append(type.FullName); + AppendTypeParameters(b, type, 0, explicitInterfaceImpl); } - AppendTypeName(declaringType); - b.Append('.'); - b.Append(metadata.GetString(@event.Name).Replace('.', '#')); break; - } - default: - throw new NotImplementedException(); } - return b.ToString(); } - public sealed class DocumentationKeySignatureTypeProvider : SRM.ISignatureTypeProvider + static void AppendTypeParameters(StringBuilder b, IType type, int outerTypeParameterCount, bool explicitInterfaceImpl) { - public string GetArrayType(string elementType, SRM.ArrayShape shape) - { - string shapeString = ""; - for (int i = 0; i < shape.Rank; i++) { - if (i > 0) - shapeString += ','; - int? lowerBound = i < shape.LowerBounds.Length ? (int?)shape.LowerBounds[i] : null; - int? size = i < shape.Sizes.Length ? (int?)shape.Sizes[i] : null; - if (lowerBound != null || size != null) { - shapeString += lowerBound.ToString(); - shapeString += ':'; - shapeString += (lowerBound + size - 1).ToString(); + int tpc = type.TypeParameterCount - outerTypeParameterCount; + if (tpc > 0) { + ParameterizedType pt = type as ParameterizedType; + if (pt != null) { + b.Append('{'); + var ta = pt.TypeArguments; + for (int i = outerTypeParameterCount; i < ta.Count; i++) { + if (i > outerTypeParameterCount) + b.Append(explicitInterfaceImpl ? '@' : ','); + AppendTypeName(b, ta[i], explicitInterfaceImpl); } + b.Append('}'); + } else { + b.Append('`'); + b.Append(tpc); } - return elementType + "[" + shapeString + "]"; - } - - public string GetByReferenceType(string elementType) - { - return elementType + '@'; - } - - public string GetFunctionPointerType(SRM.MethodSignature signature) - { - return ""; - } - - public string GetGenericInstantiation(string genericType, ImmutableArray typeArguments) - { - string arguments = ""; - for (int i = 0; i < typeArguments.Length; i++) { - if (i > 0) - arguments += ','; - arguments += typeArguments[i]; - } - return genericType + "{" + arguments + "}"; - } - - public string GetGenericMethodParameter(Unit genericContext, int index) - { - return "``" + index; - } - - public string GetGenericTypeParameter(Unit genericContext, int index) - { - return "`" + index; - } - - public string GetModifiedType(string modifier, string unmodifiedType, bool isRequired) - { - return unmodifiedType; - } - - public string GetPinnedType(string elementType) - { - return elementType; - } - - public string GetPointerType(string elementType) - { - return elementType + '*'; - } - - public string GetPrimitiveType(SRM.PrimitiveTypeCode typeCode) - { - return $"System.{typeCode}"; - } - - public string GetSZArrayType(string elementType) - { - return elementType + "[]"; - } - - public string GetTypeFromDefinition(SRM.MetadataReader reader, SRM.TypeDefinitionHandle handle, byte rawTypeKind) - { - return handle.GetFullTypeName(reader).ToString(); - } - - public string GetTypeFromReference(SRM.MetadataReader reader, SRM.TypeReferenceHandle handle, byte rawTypeKind) - { - return handle.GetFullTypeName(reader).ToString(); } + } + #endregion - public string GetTypeFromSpecification(SRM.MetadataReader reader, Unit genericContext, SRM.TypeSpecificationHandle handle, byte rawTypeKind) - { - return handle.GetFullTypeName(reader).ToString(); - } + #region ParseMemberName + /// + /// Parse the ID string into a member reference. + /// + /// The ID string representing the member (with "M:", "F:", "P:" or "E:" prefix). + /// A member reference that represents the ID string. + /// The syntax of the ID string is invalid + /// + /// The member reference will look in first, + /// and if the member is not found there, + /// it will look in all other assemblies of the compilation. + /// + public static IMemberReference ParseMemberIdString(string memberIdString) + { + if (memberIdString == null) + throw new ArgumentNullException("memberIdString"); + if (memberIdString.Length < 2 || memberIdString[1] != ':') + throw new ReflectionNameParseException(0, "Missing type tag"); + char typeChar = memberIdString[0]; + int parenPos = memberIdString.IndexOf('('); + if (parenPos < 0) + parenPos = memberIdString.LastIndexOf('~'); + if (parenPos < 0) + parenPos = memberIdString.Length; + int dotPos = memberIdString.LastIndexOf('.', parenPos - 1); + if (dotPos < 0) + throw new ReflectionNameParseException(0, "Could not find '.' separating type name from member name"); + string typeName = memberIdString.Substring(0, dotPos); + int pos = 2; + ITypeReference typeReference = ParseTypeName(typeName, ref pos); + if (pos != typeName.Length) + throw new ReflectionNameParseException(pos, "Expected end of type name"); + // string memberName = memberIDString.Substring(dotPos + 1, parenPos - (dotPos + 1)); + // pos = memberName.LastIndexOf("``"); + // if (pos > 0) + // memberName = memberName.Substring(0, pos); + // memberName = memberName.Replace('#', '.'); + return new IdStringMemberReference(typeReference, typeChar, memberIdString); } #endregion - #region FindMemberByKey - public static Entity FindMemberByKey(PEFile module, string key) + #region ParseTypeName + /// + /// Parse the ID string type name into a type reference. + /// + /// The ID string representing the type (the "T:" prefix is optional). + /// A type reference that represents the ID string. + /// The syntax of the ID string is invalid + /// + /// + /// The type reference will look in first, + /// and if the type is not found there, + /// it will look in all other assemblies of the compilation. + /// + /// + /// If the type is open (contains type parameters '`0' or '``0'), + /// an with the appropriate CurrentTypeDefinition/CurrentMember is required + /// to resolve the reference to the ITypeParameter. + /// + /// + public static ITypeReference ParseTypeName(string typeName) { - if (module == null) - throw new ArgumentNullException(nameof(module)); - if (key == null || key.Length < 2 || key[1] != ':') - return default(Entity); - switch (key[0]) { - case 'T': - return FindType(module, key.Substring(2)); - case 'F': - return FindMember(module, key, type => module.Metadata.GetTypeDefinition(type.Handle).GetFields().Select(f => new Entity(module, f))); - case 'P': - return FindMember(module, key, type => module.Metadata.GetTypeDefinition(type.Handle).GetProperties().Select(p => new Entity(module, p))); - case 'E': - return FindMember(module, key, type => module.Metadata.GetTypeDefinition(type.Handle).GetEvents().Select(e => new Entity(module, e))); - case 'M': - return FindMember(module, key, type => module.Metadata.GetTypeDefinition(type.Handle).GetMethods().Select(m => new Entity(module, m))); + if (typeName == null) + throw new ArgumentNullException("typeName"); + int pos = 0; + if (typeName.StartsWith("T:", StringComparison.Ordinal)) + pos = 2; + ITypeReference r = ParseTypeName(typeName, ref pos); + if (pos < typeName.Length) + throw new ReflectionNameParseException(pos, "Expected end of type name"); + return r; + } + + static bool IsIDStringSpecialCharacter(char c) + { + switch (c) { + case ':': + case '{': + case '}': + case '[': + case ']': + case '(': + case ')': + case '`': + case '*': + case '@': + case ',': + return true; default: - return default(Entity); + return false; } } - - static Entity FindMember(PEFile module, string key, Func> memberSelector) + + static ITypeReference ParseTypeName(string typeName, ref int pos) { - Debug.WriteLine("Looking for member " + key); - int parenPos = key.IndexOf('('); - int dotPos; - if (parenPos > 0) { - dotPos = key.LastIndexOf('.', parenPos - 1, parenPos); - } else { - dotPos = key.LastIndexOf('.'); - } - if (dotPos < 0) - return default(Entity); - TypeDefinition type = FindType(module, key.Substring(2, dotPos - 2)); - if (type == null) - return default(Entity); - string shortName; - if (parenPos > 0) { - shortName = key.Substring(dotPos + 1, parenPos - (dotPos + 1)); + string reflectionTypeName = typeName; + if (pos == typeName.Length) + throw new ReflectionNameParseException(pos, "Unexpected end"); + ITypeReference result; + if (reflectionTypeName[pos] == '`') { + // type parameter reference + pos++; + if (pos == reflectionTypeName.Length) + throw new ReflectionNameParseException(pos, "Unexpected end"); + if (reflectionTypeName[pos] == '`') { + // method type parameter reference + pos++; + int index = ReflectionHelper.ReadTypeParameterCount(reflectionTypeName, ref pos); + result = TypeParameterReference.Create(SymbolKind.Method, index); + } else { + // class type parameter reference + int index = ReflectionHelper.ReadTypeParameterCount(reflectionTypeName, ref pos); + result = TypeParameterReference.Create(SymbolKind.TypeDefinition, index); + } } else { - shortName = key.Substring(dotPos + 1); + // not a type parameter reference: read the actual type name + List typeArguments = new List(); + int typeParameterCount; + string typeNameWithoutSuffix = ReadTypeName(typeName, ref pos, true, out typeParameterCount, typeArguments); + result = new GetPotentiallyNestedClassTypeReference(typeNameWithoutSuffix, typeParameterCount); + while (pos < typeName.Length && typeName[pos] == '.') { + pos++; + string nestedTypeName = ReadTypeName(typeName, ref pos, false, out typeParameterCount, typeArguments); + result = new NestedTypeReference(result, nestedTypeName, typeParameterCount); + } + if (typeArguments.Count > 0) { + result = new ParameterizedTypeReference(result, typeArguments); + } } - var metadata = module.Metadata; - Debug.WriteLine("Searching in type {0} for {1}", type.Handle.GetFullTypeName(metadata), shortName); - Entity shortNameMatch = default(Entity); - foreach (var member in memberSelector(type)) { - string memberKey = GetKey(member); - Debug.WriteLine(memberKey); - if (memberKey == key) - return member; - string name; - switch (member.Handle.Kind) { - case SRM.HandleKind.MethodDefinition: - name = metadata.GetString(metadata.GetMethodDefinition((SRM.MethodDefinitionHandle)member.Handle).Name); - break; - case SRM.HandleKind.FieldDefinition: - name = metadata.GetString(metadata.GetFieldDefinition((SRM.FieldDefinitionHandle)member.Handle).Name); + while (pos < typeName.Length) { + switch (typeName[pos]) { + case '[': + int dimensions = 1; + do { + pos++; + if (pos == typeName.Length) + throw new ReflectionNameParseException(pos, "Unexpected end"); + if (typeName[pos] == ',') + dimensions++; + } while (typeName[pos] != ']'); + result = new ArrayTypeReference(result, dimensions); break; - case SRM.HandleKind.PropertyDefinition: - name = metadata.GetString(metadata.GetPropertyDefinition((SRM.PropertyDefinitionHandle)member.Handle).Name); + case '*': + result = new PointerTypeReference(result); break; - case SRM.HandleKind.EventDefinition: - name = metadata.GetString(metadata.GetEventDefinition((SRM.EventDefinitionHandle)member.Handle).Name); + case '@': + result = new ByReferenceTypeReference(result); break; default: - throw new NotSupportedException(); + return result; } - if (shortName == name.Replace('.', '#')) - shortNameMatch = member; + pos++; } - // if there's no match by ID string (key), return the match by name. - return shortNameMatch; + return result; } - - static TypeDefinition FindType(PEFile module, string name) + + static string ReadTypeName(string typeName, ref int pos, bool allowDottedName, out int typeParameterCount, List typeArguments) { - var metadata = module.Metadata; - string[] segments = name.Split('.'); - var currentNamespace = metadata.GetNamespaceDefinitionRoot(); - int i = 0; - while (i < segments.Length) { - string part = segments[i]; - var next = currentNamespace.NamespaceDefinitions.FirstOrDefault(ns => metadata.GetString(metadata.GetNamespaceDefinition(ns).Name) == part); - if (next.IsNil) - break; - currentNamespace = metadata.GetNamespaceDefinition(next); - i++; + int startPos = pos; + // skip the simple name portion: + while (pos < typeName.Length && !IsIDStringSpecialCharacter(typeName[pos]) && (allowDottedName || typeName[pos] != '.')) + pos++; + if (pos == startPos) + throw new ReflectionNameParseException(pos, "Expected type name"); + string shortTypeName = typeName.Substring(startPos, pos - startPos); + // read type arguments: + typeParameterCount = 0; + if (pos < typeName.Length && typeName[pos] == '`') { + // unbound generic type + pos++; + typeParameterCount = ReflectionHelper.ReadTypeParameterCount(typeName, ref pos); + } else if (pos < typeName.Length && typeName[pos] == '{') { + // bound generic type + typeArguments = new List(); + do { + pos++; + typeArguments.Add(ParseTypeName(typeName, ref pos)); + typeParameterCount++; + if (pos == typeName.Length) + throw new ReflectionNameParseException(pos, "Unexpected end"); + } while (typeName[pos] == ','); + if (typeName[pos] != '}') + throw new ReflectionNameParseException(pos, "Expected '}'"); + pos++; } - if (i == segments.Length) - return default(TypeDefinition); - var typeDefinitions = currentNamespace.TypeDefinitions; - while (i < segments.Length) { - string part = segments[i]; - foreach (var t in typeDefinitions) { - var type = metadata.GetTypeDefinition(t); - if (metadata.GetString(type.Name) == part) { - if (i + 1 == segments.Length) - return new TypeDefinition(module, t); - typeDefinitions = type.GetNestedTypes(); - i++; - break; - } - } + return shortTypeName; + } + #endregion + + #region FindEntity + /// + /// Finds the entity in the given type resolve context. + /// + /// ID string of the entity. + /// Type resolve context + /// Returns the entity, or null if it is not found. + /// The syntax of the ID string is invalid + public static IEntity FindEntity(string idString, ITypeResolveContext context) + { + if (idString == null) + throw new ArgumentNullException("idString"); + if (context == null) + throw new ArgumentNullException("context"); + if (idString.StartsWith("T:", StringComparison.Ordinal)) { + return ParseTypeName(idString.Substring(2)).Resolve(context).GetDefinition(); + } else { + return ParseMemberIdString(idString).Resolve(context); } - // TODO : add support for type forwarders - //foreach (var h in metadata.ExportedTypes) { - // var exportedType = metadata.GetExportedType(h); - // if (metadata.StringComparer.Equals(exportedType.Name, name) && exportedType.Namespace == ns) { - // type = exportedType.Resolve(); - // break; - // } - //} - return default; } #endregion } diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index ccd715010..8198321d7 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -270,6 +270,7 @@ + @@ -283,7 +284,6 @@ - diff --git a/ICSharpCode.Decompiler/Metadata/Dom.cs b/ICSharpCode.Decompiler/Metadata/Dom.cs index ec9dd13a3..61a201a2c 100644 --- a/ICSharpCode.Decompiler/Metadata/Dom.cs +++ b/ICSharpCode.Decompiler/Metadata/Dom.cs @@ -15,31 +15,11 @@ using ICSharpCode.Decompiler.Util; namespace ICSharpCode.Decompiler.Metadata { - using SRMMemberRef = System.Reflection.Metadata.MemberReference; - using SRMMethod = System.Reflection.Metadata.MethodDefinition; - using SRMMethodSpec = System.Reflection.Metadata.MethodSpecification; - using SRMProperty = System.Reflection.Metadata.PropertyDefinition; - using SRMEvent = System.Reflection.Metadata.EventDefinition; - using SRMField = System.Reflection.Metadata.FieldDefinition; - using SRMTypeDef = System.Reflection.Metadata.TypeDefinition; - using SRMTypeRef = System.Reflection.Metadata.TypeReference; - using SRMTypeSpec = System.Reflection.Metadata.TypeSpecification; - using SRMAssemblyReference = System.Reflection.Metadata.AssemblyReference; - - - public interface IAssemblyDocumentationResolver { XmlDocumentationProvider GetProvider(); } - public interface IMetadataEntity - { - PEFile Module { get; } - EntityHandle Handle { get; } - bool IsNil { get; } - } - public struct Variable { public string Name { get; set; } @@ -136,378 +116,6 @@ namespace ICSharpCode.Decompiler.Metadata } } - public struct Entity : IEquatable, IMetadataEntity - { - public PEFile Module { get; } - public EntityHandle Handle { get; } - public bool IsNil => Handle.IsNil; - - public Entity(PEFile module, EntityHandle handle) : this() - { - this.Module = module ?? throw new ArgumentNullException(nameof(module)); - this.Handle = handle; - } - - public bool IsType() => Handle.Kind == HandleKind.TypeDefinition || Handle.Kind == HandleKind.TypeReference || Handle.Kind == HandleKind.TypeSpecification; - - public TypeDefinition ResolveAsType() - { - return MetadataResolver.ResolveType(Handle, new SimpleMetadataResolveContext(Module)); - } - - public FieldDefinition ResolveAsField() - { - return MetadataResolver.ResolveAsField(Handle, new SimpleMetadataResolveContext(Module)); - } - - public MethodDefinition ResolveAsMethod() - { - return MetadataResolver.ResolveAsMethod(Handle, new SimpleMetadataResolveContext(Module)); - } - - public bool Equals(Entity other) - { - return Module == other.Module && Handle == other.Handle; - } - - public override bool Equals(object obj) - { - if (obj is Entity entity) - return Equals(entity); - return false; - } - - public override int GetHashCode() - { - return unchecked(982451629 * Module.GetHashCode() + 982451653 * MetadataTokens.GetToken(Handle)); - } - - public static bool operator ==(Entity lhs, Entity rhs) => lhs.Equals(rhs); - public static bool operator !=(Entity lhs, Entity rhs) => !lhs.Equals(rhs); - - public static implicit operator Entity(MethodDefinition method) - { - return new Entity(method.Module, method.Handle); - } - - public static implicit operator Entity(PropertyDefinition property) - { - return new Entity(property.Module, property.Handle); - } - - public static implicit operator Entity(EventDefinition @event) - { - return new Entity(@event.Module, @event.Handle); - } - - public static implicit operator Entity(FieldDefinition field) - { - return new Entity(field.Module, field.Handle); - } - - public static implicit operator Entity(TypeDefinition type) - { - return new Entity(type.Module, type.Handle); - } - - public static implicit operator TypeDefinition(Entity entity) - { - return new TypeDefinition(entity.Module, (TypeDefinitionHandle)entity.Handle); - } - - public static implicit operator MethodDefinition(Entity entity) - { - return new MethodDefinition(entity.Module, (MethodDefinitionHandle)entity.Handle); - } - - public static implicit operator PropertyDefinition(Entity entity) - { - return new PropertyDefinition(entity.Module, (PropertyDefinitionHandle)entity.Handle); - } - - public static implicit operator EventDefinition(Entity entity) - { - return new EventDefinition(entity.Module, (EventDefinitionHandle)entity.Handle); - } - - public static implicit operator FieldDefinition(Entity entity) - { - return new FieldDefinition(entity.Module, (FieldDefinitionHandle)entity.Handle); - } - } - - public struct MethodDefinition : IEquatable, IMetadataEntity - { - public PEFile Module { get; } - public MethodDefinitionHandle Handle { get; } - public bool IsNil => Handle.IsNil; - EntityHandle IMetadataEntity.Handle => Handle; - - public MethodDefinition(PEFile module, MethodDefinitionHandle handle) : this() - { - this.Module = module ?? throw new ArgumentNullException(nameof(module)); - this.Handle = handle; - } - - public bool Equals(MethodDefinition other) - { - return Module == other.Module && Handle == other.Handle; - } - - public override bool Equals(object obj) - { - if (obj is MethodDefinition md) - return Equals(md); - return false; - } - - public override int GetHashCode() - { - return unchecked(982451629 * Module.GetHashCode() + 982451653 * MetadataTokens.GetToken(Handle)); - } - - public static bool operator ==(MethodDefinition lhs, MethodDefinition rhs) => lhs.Equals(rhs); - public static bool operator !=(MethodDefinition lhs, MethodDefinition rhs) => !lhs.Equals(rhs); - - public IList GetSequencePoints() - { - return Module.DebugInfo?.GetSequencePoints(Handle) ?? EmptyList.Instance; - } - - public IList GetVariables() - { - return Module.DebugInfo?.GetVariables(Handle) ?? EmptyList.Instance; - } - } - - public struct PropertyDefinition : IEquatable, IMetadataEntity - { - public PEFile Module { get; } - public PropertyDefinitionHandle Handle { get; } - public bool IsNil => Handle.IsNil; - EntityHandle IMetadataEntity.Handle => Handle; - - public PropertyDefinition(PEFile module, PropertyDefinitionHandle handle) : this() - { - this.Module = module ?? throw new ArgumentNullException(nameof(module)); - this.Handle = handle; - } - - public bool Equals(PropertyDefinition other) - { - return Module == other.Module && Handle == other.Handle; - } - - public override bool Equals(object obj) - { - if (obj is PropertyDefinition pd) - return Equals(pd); - return false; - } - - public override int GetHashCode() - { - return unchecked(982451629 * Module.GetHashCode() + 982451653 * MetadataTokens.GetToken(Handle)); - } - - public static bool operator ==(PropertyDefinition lhs, PropertyDefinition rhs) => lhs.Equals(rhs); - public static bool operator !=(PropertyDefinition lhs, PropertyDefinition rhs) => !lhs.Equals(rhs); - } - - public struct FieldDefinition : IEquatable, IMetadataEntity - { - public PEFile Module { get; } - public FieldDefinitionHandle Handle { get; } - public bool IsNil => Handle.IsNil; - EntityHandle IMetadataEntity.Handle => Handle; - - public FieldDefinition(PEFile module, FieldDefinitionHandle handle) : this() - { - this.Module = module ?? throw new ArgumentNullException(nameof(module)); - this.Handle = handle; - } - - public bool Equals(FieldDefinition other) - { - return Module == other.Module && Handle == other.Handle; - } - - public override bool Equals(object obj) - { - if (obj is FieldDefinition fd) - return Equals(fd); - return false; - } - - public override int GetHashCode() - { - return unchecked(982451629 * Module.GetHashCode() + 982451653 * MetadataTokens.GetToken(Handle)); - } - - public static bool operator ==(FieldDefinition lhs, FieldDefinition rhs) => lhs.Equals(rhs); - public static bool operator !=(FieldDefinition lhs, FieldDefinition rhs) => !lhs.Equals(rhs); - - public object DecodeConstant() - { - var metadata = Module.Metadata; - var constant = metadata.GetConstant(metadata.GetFieldDefinition(Handle).GetDefaultValue()); - var blob = metadata.GetBlobReader(constant.Value); - switch (constant.TypeCode) { - case ConstantTypeCode.Boolean: - return blob.ReadBoolean(); - case ConstantTypeCode.Char: - return blob.ReadChar(); - case ConstantTypeCode.SByte: - return blob.ReadSByte(); - case ConstantTypeCode.Byte: - return blob.ReadByte(); - case ConstantTypeCode.Int16: - return blob.ReadInt16(); - case ConstantTypeCode.UInt16: - return blob.ReadUInt16(); - case ConstantTypeCode.Int32: - return blob.ReadInt32(); - case ConstantTypeCode.UInt32: - return blob.ReadUInt32(); - case ConstantTypeCode.Int64: - return blob.ReadInt64(); - case ConstantTypeCode.UInt64: - return blob.ReadUInt64(); - case ConstantTypeCode.Single: - return blob.ReadSingle(); - case ConstantTypeCode.Double: - return blob.ReadDouble(); - case ConstantTypeCode.String: - return blob.ReadSerializedString(); - case ConstantTypeCode.NullReference: - return null; - default: - throw new NotSupportedException(); - } - } - } - - public struct EventDefinition : IEquatable, IMetadataEntity - { - public PEFile Module { get; } - public EventDefinitionHandle Handle { get; } - public bool IsNil => Handle.IsNil; - EntityHandle IMetadataEntity.Handle => Handle; - - public EventDefinition(PEFile module, EventDefinitionHandle handle) - { - this.Module = module ?? throw new ArgumentNullException(nameof(module)); - this.Handle = handle; - } - - public bool Equals(EventDefinition other) - { - return Module == other.Module && Handle == other.Handle; - } - - public override bool Equals(object obj) - { - if (obj is EventDefinition ed) - return Equals(ed); - return false; - } - - public override int GetHashCode() - { - return unchecked(982451629 * Module.GetHashCode() + 982451653 * MetadataTokens.GetToken(Handle)); - } - - public static bool operator ==(EventDefinition lhs, EventDefinition rhs) => lhs.Equals(rhs); - public static bool operator !=(EventDefinition lhs, EventDefinition rhs) => !lhs.Equals(rhs); - } - - public struct TypeDefinition : IEquatable, IMetadataEntity - { - public PEFile Module { get; } - public TypeDefinitionHandle Handle { get; } - public bool IsNil => Handle.IsNil; - - EntityHandle IMetadataEntity.Handle => Handle; - - public TypeDefinition(PEFile module, TypeDefinitionHandle handle) - { - this.Module = module ?? throw new ArgumentNullException(nameof(module)); - this.Handle = handle; - } - - public bool Equals(TypeDefinition other) - { - return Module == other.Module && Handle == other.Handle; - } - - public override bool Equals(object obj) - { - if (obj is TypeDefinition td) - return Equals(td); - return false; - } - - public override int GetHashCode() - { - return unchecked(982451629 * Module.GetHashCode() + 982451653 * MetadataTokens.GetToken(Handle)); - } - - public static bool operator ==(TypeDefinition lhs, TypeDefinition rhs) => lhs.Equals(rhs); - public static bool operator !=(TypeDefinition lhs, TypeDefinition rhs) => !lhs.Equals(rhs); - } - - public struct TypeReference - { - public PEFile Module { get; } - public TypeReferenceHandle Handle { get; } - public bool IsNil => Handle.IsNil; - - public TypeReference(PEFile module, TypeReferenceHandle handle) - { - this.Module = module ?? throw new ArgumentNullException(nameof(module)); - this.Handle = handle; - } - } - - public struct TypeSpecification - { - public PEFile Module { get; } - public TypeSpecificationHandle Handle { get; } - public bool IsNil => Handle.IsNil; - - public TypeSpecification(PEFile module, TypeSpecificationHandle handle) - { - this.Module = module ?? throw new ArgumentNullException(nameof(module)); - this.Handle = handle; - } - } - - public struct MethodSpecification - { - public PEFile Module { get; } - public MethodSpecificationHandle Handle { get; } - public bool IsNil => Handle.IsNil; - - public MethodSpecification(PEFile module, MethodSpecificationHandle handle) - { - this.Module = module ?? throw new ArgumentNullException(nameof(module)); - this.Handle = handle; - } - } - - public struct MemberReference - { - public PEFile Module { get; } - public MemberReferenceHandle Handle { get; } - public bool IsNil => Handle.IsNil; - - public MemberReference(PEFile module, MemberReferenceHandle handle) - { - this.Module = module ?? throw new ArgumentNullException(nameof(module)); - this.Handle = handle; - } - } - public sealed class FullTypeNameSignatureDecoder : ISignatureTypeProvider { readonly MetadataReader metadata; @@ -606,22 +214,12 @@ namespace ICSharpCode.Decompiler.Metadata this.declaringType = module.Metadata.GetMethodDefinition(method).GetDeclaringType(); } - public GenericContext(MethodDefinition method) - : this(method.Handle, method.Module) - { - } - public GenericContext(TypeDefinitionHandle declaringType, PEFile module) { this.module = module; this.declaringType = declaringType; } - public GenericContext(TypeDefinition declaringType) - : this(declaringType.Handle, declaringType.Module) - { - } - public string GetGenericTypeParameterName(int index) { GenericParameterHandle genericParameter = GetGenericTypeParameterHandleOrNull(index); diff --git a/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs b/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs index 1b2c07061..7c85c4a4f 100644 --- a/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs +++ b/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs @@ -104,42 +104,6 @@ namespace ICSharpCode.Decompiler.Metadata && (name == ".cctor" || name == ".ctor"); } - public static bool HasMatchingDefaultMemberAttribute(this PropertyDefinitionHandle handle, PEFile module, out CustomAttributeHandle defaultMemberAttribute) - { - defaultMemberAttribute = default(CustomAttributeHandle); - var metadata = module.Metadata; - var propertyDefinition = metadata.GetPropertyDefinition(handle); - var accessorHandle = propertyDefinition.GetAccessors().GetAny(); - var accessor = metadata.GetMethodDefinition(accessorHandle); - if (accessor.GetParameters().Count > 0) { - var basePropDef = propertyDefinition; - var firstOverrideHandle = accessorHandle.GetMethodImplementations(metadata).FirstOrDefault(); - if (!firstOverrideHandle.IsNil) { - // if the property is explicitly implementing an interface, look up the property in the interface: - var firstOverride = metadata.GetMethodImplementation(firstOverrideHandle); - var baseAccessor = new Metadata.Entity(module, firstOverride.MethodDeclaration).ResolveAsMethod(); - if (!baseAccessor.IsNil) { - var declaringType = metadata.GetTypeDefinition(metadata.GetMethodDefinition(baseAccessor.Handle).GetDeclaringType()); - foreach (var basePropHandle in declaringType.GetProperties()) { - var baseProp = metadata.GetPropertyDefinition(basePropHandle); - var accessors = baseProp.GetAccessors(); - if (accessors.Getter == baseAccessor.Handle || accessors.Setter == baseAccessor.Handle) { - basePropDef = baseProp; - break; - } - } - } else - return false; - } - var defaultMemberName = accessor.GetDeclaringType().GetDefaultMemberName(metadata, out var attr); - if (defaultMemberName == metadata.GetString(basePropDef.Name)) { - defaultMemberAttribute = attr; - return true; - } - } - return false; - } - public static string GetDefaultMemberName(this TypeDefinitionHandle type, MetadataReader reader) { return type.GetDefaultMemberName(reader, out var attr); diff --git a/ICSharpCode.Decompiler/Metadata/MetadataResolver.cs b/ICSharpCode.Decompiler/Metadata/MetadataResolver.cs index aa6f9c2cf..4c54ab314 100644 --- a/ICSharpCode.Decompiler/Metadata/MetadataResolver.cs +++ b/ICSharpCode.Decompiler/Metadata/MetadataResolver.cs @@ -68,13 +68,13 @@ namespace ICSharpCode.Decompiler.Metadata public static class MetadataResolver { - public static TypeDefinition ResolveType(EntityHandle handle, IMetadataResolveContext context) + public static (PEFile Module, TypeDefinitionHandle Handle) ResolveType(EntityHandle handle, IMetadataResolveContext context) { if (handle.IsNil) return default; switch (handle.Kind) { case HandleKind.TypeDefinition: - return new TypeDefinition(context.CurrentModule, (TypeDefinitionHandle)handle); + return (context.CurrentModule, (TypeDefinitionHandle)handle); case HandleKind.TypeReference: return Resolve((TypeReferenceHandle)handle, context); case HandleKind.TypeSpecification: @@ -84,39 +84,39 @@ namespace ICSharpCode.Decompiler.Metadata } } - public static MethodDefinition ResolveAsMethod(EntityHandle handle, IMetadataResolveContext context) + public static (PEFile Module, MethodDefinitionHandle Handle) ResolveAsMethod(EntityHandle handle, IMetadataResolveContext context) { if (handle.IsNil) return default; switch (handle.Kind) { case HandleKind.MethodDefinition: - return new MethodDefinition(context.CurrentModule, (MethodDefinitionHandle)handle); + return (context.CurrentModule, (MethodDefinitionHandle)handle); case HandleKind.MemberReference: var resolved = ((MemberReferenceHandle)handle).Resolve(context); - if (resolved is MethodDefinition m) - return m; + if (resolved.Handle.Kind == HandleKind.MethodDefinition) + return (resolved.Module, (MethodDefinitionHandle)resolved.Handle); return default; case HandleKind.MethodSpecification: resolved = ((MethodSpecificationHandle)handle).Resolve(context); - if (resolved is MethodDefinition m2) - return m2; + if (resolved.Handle.Kind == HandleKind.MethodDefinition) + return (resolved.Module, (MethodDefinitionHandle)resolved.Handle); return default; default: throw new NotSupportedException(); } } - public static FieldDefinition ResolveAsField(EntityHandle handle, IMetadataResolveContext context) + public static (PEFile Module, FieldDefinitionHandle Handle) ResolveAsField(EntityHandle handle, IMetadataResolveContext context) { if (handle.IsNil) return default; switch (handle.Kind) { case HandleKind.FieldDefinition: - return new FieldDefinition(context.CurrentModule, (FieldDefinitionHandle)handle); + return (context.CurrentModule, (FieldDefinitionHandle)handle); case HandleKind.MemberReference: var resolved = ((MemberReferenceHandle)handle).Resolve(context); - if (resolved is FieldDefinition m) - return m; + if (resolved.Handle.Kind == HandleKind.FieldDefinition) + return (resolved.Module, (FieldDefinitionHandle)resolved.Handle); return default; default: throw new NotSupportedException(); @@ -126,7 +126,7 @@ namespace ICSharpCode.Decompiler.Metadata /// /// Implements resolving of TypeReferences to TypeDefinitions as decribed in II.7.3 of ECMA-335 6th edition. /// - public static TypeDefinition Resolve(this TypeReferenceHandle handle, IMetadataResolveContext context) + public static (PEFile Module, TypeDefinitionHandle Handle) Resolve(this TypeReferenceHandle handle, IMetadataResolveContext context) { if (handle.IsNil) return default; @@ -150,14 +150,14 @@ namespace ICSharpCode.Decompiler.Metadata switch (tr.ResolutionScope.Kind) { case HandleKind.TypeReference: var outerType = Resolve((TypeReferenceHandle)tr.ResolutionScope, context); - if (outerType == null) + if (outerType.Module == null) throw new NotSupportedException(); var td = outerType.Module.Metadata.GetTypeDefinition(outerType.Handle); var name = metadata.GetString(tr.Name); foreach (var nestedType in td.GetNestedTypes()) { var nestedTypeDef = outerType.Module.Metadata.GetTypeDefinition(nestedType); if (outerType.Module.Metadata.GetString(nestedTypeDef.Name) == name) - return new TypeDefinition(outerType.Module, nestedType); + return (outerType.Module, nestedType); } break; case HandleKind.ModuleReference: @@ -167,7 +167,7 @@ namespace ICSharpCode.Decompiler.Metadata } throw new NotSupportedException(); - TypeDefinition ResolveTypeInOtherAssembly(AssemblyReferenceHandle asm, string ns, string typeName) + (PEFile Module, TypeDefinitionHandle Handle) ResolveTypeInOtherAssembly(AssemblyReferenceHandle asm, string ns, string typeName) { var module = context.ResolveAssembly(new AssemblyReference(context.CurrentModule, asm)); if (module == null) @@ -176,7 +176,7 @@ namespace ICSharpCode.Decompiler.Metadata Debug.Assert(@namespace != null); var type = FindTypeInNamespace(module.Metadata, @namespace.Value, typeName); Debug.Assert(!type.IsNil); - return new TypeDefinition(module, type); + return (module, type); } } @@ -210,7 +210,7 @@ namespace ICSharpCode.Decompiler.Metadata return default; } - public static IMetadataEntity Resolve(this MemberReferenceHandle handle, IMetadataResolveContext context) + static (PEFile Module, EntityHandle Handle) Resolve(this MemberReferenceHandle handle, IMetadataResolveContext context) { var metadata = context.CurrentModule.Metadata; var mr = metadata.GetMemberReference(handle); @@ -225,7 +225,7 @@ namespace ICSharpCode.Decompiler.Metadata break; case HandleKind.TypeReference: var resolvedTypeReference = Resolve((TypeReferenceHandle)mr.Parent, context); - if (resolvedTypeReference.IsNil) + if (resolvedTypeReference.Module == null) return default; targetModule = resolvedTypeReference.Module; targetMetadata = targetModule.Metadata; @@ -233,7 +233,7 @@ namespace ICSharpCode.Decompiler.Metadata break; case HandleKind.TypeSpecification: resolvedTypeReference = Resolve((TypeSpecificationHandle)mr.Parent, context); - if (resolvedTypeReference.IsNil) + if (resolvedTypeReference.Module == null) return default; targetModule = resolvedTypeReference.Module; targetMetadata = targetModule.Metadata; @@ -251,7 +251,7 @@ namespace ICSharpCode.Decompiler.Metadata foreach (var f in declaringType.GetFields()) { var fd = targetMetadata.GetFieldDefinition(f); if (targetMetadata.StringComparer.Equals(fd.Name, name)) - return new FieldDefinition(targetModule, f); + return (targetModule, f); } return default; case MemberReferenceKind.Method: @@ -263,7 +263,7 @@ namespace ICSharpCode.Decompiler.Metadata } foreach (var (method, signature) in candidates) { if (SignatureBlobComparer.EqualsMethodSignature(targetMetadata.GetBlobReader(signature), metadata.GetBlobReader(mr.Signature), targetMetadata, metadata)) - return new MethodDefinition(targetModule, method); + return (targetModule, method); } return default; default: @@ -271,7 +271,7 @@ namespace ICSharpCode.Decompiler.Metadata } } - public static TypeDefinition Resolve(this TypeSpecificationHandle handle, IMetadataResolveContext context) + public static (PEFile Module, TypeDefinitionHandle Handle) Resolve(this TypeSpecificationHandle handle, IMetadataResolveContext context) { var metadata = context.CurrentModule.Metadata; var ts = metadata.GetTypeSpecification(handle); @@ -280,7 +280,7 @@ namespace ICSharpCode.Decompiler.Metadata return default; switch (unspecialized.Kind) { case HandleKind.TypeDefinition: - return new TypeDefinition(context.CurrentModule, (TypeDefinitionHandle)unspecialized); + return (context.CurrentModule, (TypeDefinitionHandle)unspecialized); case HandleKind.TypeReference: return Resolve((TypeReferenceHandle)unspecialized, context); default: @@ -288,7 +288,7 @@ namespace ICSharpCode.Decompiler.Metadata } } - public static MethodDefinition Resolve(this MethodSpecificationHandle handle, IMetadataResolveContext context) + public static (PEFile Module, MethodDefinitionHandle Handle) Resolve(this MethodSpecificationHandle handle, IMetadataResolveContext context) { var metadata = context.CurrentModule.Metadata; var ms = metadata.GetMethodSpecification(handle); diff --git a/ICSharpCode.Decompiler/Metadata/PEFile.cs b/ICSharpCode.Decompiler/Metadata/PEFile.cs index 4c038eb3a..2a04b9149 100644 --- a/ICSharpCode.Decompiler/Metadata/PEFile.cs +++ b/ICSharpCode.Decompiler/Metadata/PEFile.cs @@ -85,7 +85,6 @@ namespace ICSharpCode.Decompiler.Metadata } public ImmutableArray AssemblyReferences => Metadata.AssemblyReferences.Select(r => new AssemblyReference(this, r)).ToImmutableArray(); - public ImmutableArray TopLevelTypeDefinitions => Metadata.GetTopLevelTypeDefinitions().Select(t => new TypeDefinition(this, t)).ToImmutableArray(); public ImmutableArray Resources => GetResources().ToImmutableArray(); IEnumerable GetResources() diff --git a/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs b/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs index 639ef2d17..735757173 100644 --- a/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs +++ b/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs @@ -69,7 +69,8 @@ namespace ICSharpCode.Decompiler.Metadata public string TargetFramework { get; } - public UniversalAssemblyResolver(string mainAssemblyFileName, bool throwOnError, string targetFramework, PEStreamOptions options) + public UniversalAssemblyResolver(string mainAssemblyFileName, bool throwOnError, string targetFramework, + PEStreamOptions options = PEStreamOptions.Default) { this.options = options; this.TargetFramework = targetFramework; diff --git a/ICSharpCode.Decompiler/Output/ITextOutput.cs b/ICSharpCode.Decompiler/Output/ITextOutput.cs index 9f8c0bcf9..f0ce1c3dd 100644 --- a/ICSharpCode.Decompiler/Output/ITextOutput.cs +++ b/ICSharpCode.Decompiler/Output/ITextOutput.cs @@ -17,6 +17,10 @@ // DEALINGS IN THE SOFTWARE. +using System.Reflection.Metadata; +using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; + namespace ICSharpCode.Decompiler { public interface ITextOutput @@ -50,5 +54,26 @@ namespace ICSharpCode.Decompiler { output.WriteLine(string.Format(format, args)); } + + public static void WriteReference(this ITextOutput output, PEFile module, EntityHandle handle, string text, bool isDefinition = false) + { + output.Write(text); + } + + public static void WriteReference(this ITextOutput output, IType type, string text, bool isDefinition = false) + { + output.Write(text); + } + + public static void WriteReference(this ITextOutput output, IMember member, string text, bool isDefinition = false) + { + output.Write(text); + + } + + public static void WriteLocalReference(this ITextOutput output, string text, object reference, bool isDefinition = false) + { + output.Write(text); + } } } diff --git a/ICSharpCode.Decompiler/Output/PlainTextOutput.cs b/ICSharpCode.Decompiler/Output/PlainTextOutput.cs index d598b4bd6..6ae3a7792 100644 --- a/ICSharpCode.Decompiler/Output/PlainTextOutput.cs +++ b/ICSharpCode.Decompiler/Output/PlainTextOutput.cs @@ -18,7 +18,10 @@ using System; using System.IO; +using System.Reflection.Metadata; using ICSharpCode.Decompiler.CSharp.Syntax; +using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.Decompiler { diff --git a/ICSharpCode.Decompiler/Output/TextTokenWriter.cs b/ICSharpCode.Decompiler/Output/TextTokenWriter.cs index d1970e274..1ea1b7aba 100644 --- a/ICSharpCode.Decompiler/Output/TextTokenWriter.cs +++ b/ICSharpCode.Decompiler/Output/TextTokenWriter.cs @@ -63,21 +63,23 @@ namespace ICSharpCode.Decompiler } var definition = GetCurrentDefinition(); - if (definition != null) { - IMetadataEntity entity = SymbolToMetadata(definition); - if (entity != null) { - output.WriteDefinition(identifier.Name, entity, false); + switch (definition) { + case IType t: + output.WriteReference(t, identifier.Name, true); + return; + case IMember m: + output.WriteReference(m, identifier.Name, true); return; - } } var member = GetCurrentMemberReference(); - if (member != null) { - IMetadataEntity entity = SymbolToMetadata(member); - if (entity != null) { - output.WriteReference(identifier.Name, entity); + switch (member) { + case IType t: + output.WriteReference(t, identifier.Name, false); + return; + case IMember m: + output.WriteReference(m, identifier.Name, false); return; - } } var localDefinition = GetCurrentLocalDefinition(); @@ -100,35 +102,6 @@ namespace ICSharpCode.Decompiler output.Write(identifier.Name); } - IMetadataEntity SymbolToMetadata(ISymbol symbol) - { - switch (symbol) { - case IType type: - var definition = type.GetDefinition(); - if (definition == null || definition.MetadataToken.IsNil) - return null; - return new TypeDefinition(typeSystem.GetModuleDefinition(definition.ParentAssembly), (SRM.TypeDefinitionHandle)definition.MetadataToken); - case IMethod method: - if (method.MetadataToken.IsNil) - return null; - return new MethodDefinition(typeSystem.GetModuleDefinition(method.ParentAssembly), (SRM.MethodDefinitionHandle)method.MetadataToken); - case IProperty property: - if (property.MetadataToken.IsNil) - return null; - return new PropertyDefinition(typeSystem.GetModuleDefinition(property.ParentAssembly), (SRM.PropertyDefinitionHandle)property.MetadataToken); - case IEvent @event: - if (@event.MetadataToken.IsNil) - return null; - return new EventDefinition(typeSystem.GetModuleDefinition(@event.ParentAssembly), (SRM.EventDefinitionHandle)@event.MetadataToken); - case IField field: - if (field.MetadataToken.IsNil) - return null; - return new FieldDefinition(typeSystem.GetModuleDefinition(field.ParentAssembly), (SRM.FieldDefinitionHandle)field.MetadataToken); - default: - return null; - } - } - ISymbol GetCurrentMemberReference() { AstNode node = nodeStack.Peek(); @@ -219,11 +192,8 @@ namespace ICSharpCode.Decompiler //To make reference for 'this' and 'base' keywords in the ClassName():this() expression if (role == ConstructorInitializer.ThisKeywordRole || role == ConstructorInitializer.BaseKeywordRole) { if (nodeStack.Peek() is ConstructorInitializer initializer && initializer.GetSymbol() is IMember member) { - var entity = SymbolToMetadata(member); - if (entity != null) { - output.WriteReference(keyword, entity); - return; - } + output.WriteReference(member, keyword); + return; } } output.Write(keyword); @@ -254,11 +224,18 @@ namespace ICSharpCode.Decompiler break; default: // Attach member reference to token only if there's no identifier in the current node. - var member = SymbolToMetadata(GetCurrentMemberReference()); + var member = GetCurrentMemberReference(); var node = nodeStack.Peek(); - if (member != null && node.GetChildByRole(Roles.Identifier).IsNull) - output.WriteReference(token, member); - else + if (member != null && node.GetChildByRole(Roles.Identifier).IsNull) { + switch (member) { + case IType t: + output.WriteReference(t, token, false); + return; + case IMember m: + output.WriteReference(m, token, false); + return; + } + } else output.Write(token); break; } @@ -368,7 +345,14 @@ namespace ICSharpCode.Decompiler symbol = nodeStack.Peek().GetSymbol(); } if (symbol == null) goto default; - output.WriteReference(type, SymbolToMetadata(symbol)); + switch (symbol) { + case IType t: + output.WriteReference(t, type, false); + return; + case IMember m: + output.WriteReference(m, type, false); + return; + } break; default: output.Write(type); diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs index 548efd109..950cef6c4 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataTypeDefinition.cs @@ -213,9 +213,10 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation var metadata = assembly.metadata; var methodsCollection = metadata.GetTypeDefinition(handle).GetMethods(); var methodsList = new List(methodsCollection.Count); + var methodSemantics = assembly.PEFile.MethodSemanticsLookup; foreach (MethodDefinitionHandle h in methodsCollection) { var md = metadata.GetMethodDefinition(h); - if (assembly.IsVisible(md.Attributes)) { + if (methodSemantics.GetSemantics(h).Item2 == 0 && assembly.IsVisible(md.Attributes)) { methodsList.Add(assembly.GetDefinition(h)); } } diff --git a/ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs b/ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs index fc38f4655..45b2f22f7 100644 --- a/ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs +++ b/ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs @@ -38,7 +38,7 @@ namespace ICSharpCode.Decompiler.TypeSystem public class MetadataAssembly : IAssembly { public ICompilation Compilation { get; } - internal readonly Metadata.PEFile PEFile; + public readonly Metadata.PEFile PEFile; internal readonly MetadataReader metadata; readonly TypeSystemOptions options; internal readonly TypeProvider TypeProvider; diff --git a/ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs b/ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs index 2f801dc99..927ec4920 100644 --- a/ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs +++ b/ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs @@ -123,7 +123,6 @@ namespace ILSpy.BamlDecompiler.Tests XDocument document = BamlResourceEntryNode.LoadIntoDocument(module, bamlStream, CancellationToken.None); XamlIsEqual(File.ReadAllText(sourcePath), document.ToString()); - } } diff --git a/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs b/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs index 7b0731837..10eb55937 100644 --- a/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs +++ b/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs @@ -3,16 +3,14 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using System.Reflection.Metadata; using System.Threading; -using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.CSharp; -using ICSharpCode.Decompiler.Documentation; using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.Util; using Metadata = ICSharpCode.Decompiler.Metadata; @@ -31,36 +29,34 @@ namespace ILSpy.BamlDecompiler /// sealed class ConnectMethodDecompiler { - public List<(LongSet, EventRegistration[])> DecompileEventMappings(Metadata.PEFile module, string fullTypeName, CancellationToken cancellationToken) + public List<(LongSet, EventRegistration[])> DecompileEventMappings(Metadata.PEFile module, + string fullTypeName, CancellationToken cancellationToken) { var result = new List<(LongSet, EventRegistration[])>(); + var typeSystem = new DecompilerTypeSystem(module); - var typeDefinition = (Metadata.TypeDefinition)XmlDocKeyProvider.FindMemberByKey(module, "T:" + fullTypeName); - if (typeDefinition.IsNil) + var typeDefinition = typeSystem.Compilation.FindType(new FullTypeName(fullTypeName)).GetDefinition(); + if (typeDefinition == null) return result; - - var metadata = module.Metadata; - TypeDefinition type = metadata.GetTypeDefinition(typeDefinition.Handle); - - MethodDefinition method = default; - MethodDefinitionHandle handle = default; + + IMethod method = null; + MethodDefinition metadataEntry = default; - foreach (var h in type.GetMethods()) { - var m = metadata.GetMethodDefinition(h); - if (metadata.GetString(m.Name) == "System.Windows.Markup.IComponentConnector.Connect") { - handle = h; + foreach (var m in typeDefinition.GetMethods()) { + if (m.Name == "System.Windows.Markup.IComponentConnector.Connect") { method = m; + metadataEntry = module.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken); break; } } - if (handle.IsNil) + if (method == null || metadataEntry.RelativeVirtualAddress <= 0) return result; // decompile method and optimize the switch - var typeSystem = new DecompilerTypeSystem(typeDefinition.Module); var ilReader = new ILReader(typeSystem); - var function = ilReader.ReadIL(typeDefinition.Module, handle, typeDefinition.Module.Reader.GetMethodBody(method.RelativeVirtualAddress), cancellationToken); + var function = ilReader.ReadIL(module, (MethodDefinitionHandle)method.MetadataToken, + module.Reader.GetMethodBody(metadataEntry.RelativeVirtualAddress), cancellationToken); var context = new ILTransformContext(function, typeSystem) { CancellationToken = cancellationToken diff --git a/ILSpy/AnalyzerTreeView.cs b/ILSpy/AnalyzerTreeView.cs index c0181b577..12e0aec54 100644 --- a/ILSpy/AnalyzerTreeView.cs +++ b/ILSpy/AnalyzerTreeView.cs @@ -86,7 +86,7 @@ namespace ICSharpCode.ILSpy public void ShowOrFocus(AnalyzerTreeNode node) { - if (node is AnalyzerEntityTreeNode) { + /*if (node is AnalyzerEntityTreeNode) { var an = node as AnalyzerEntityTreeNode; var found = this.Root.Children.OfType().FirstOrDefault(n => n.Member == an.Member); if (found != null) { @@ -98,7 +98,7 @@ namespace ICSharpCode.ILSpy return; } } - Show(node); + Show(node);*/ } void IPane.Closed() diff --git a/ILSpy/Commands/DecompileAllCommand.cs b/ILSpy/Commands/DecompileAllCommand.cs index e54d88877..38d89fd68 100644 --- a/ILSpy/Commands/DecompileAllCommand.cs +++ b/ILSpy/Commands/DecompileAllCommand.cs @@ -45,7 +45,7 @@ namespace ICSharpCode.ILSpy Exception exception = null; using (var writer = new System.IO.StreamWriter("c:\\temp\\decompiled\\" + asm.ShortName + ".cs")) { try { - new CSharpLanguage().DecompileAssembly(asm, new Decompiler.PlainTextOutput(writer), new DecompilationOptions() { FullDecompilation = true, CancellationToken = ct }); + //new CSharpLanguage().DecompileAssembly(asm, new Decompiler.PlainTextOutput(writer), new DecompilationOptions() { FullDecompilation = true, CancellationToken = ct }); } catch (Exception ex) { writer.WriteLine(ex.ToString()); diff --git a/ILSpy/DebugSteps.xaml.cs b/ILSpy/DebugSteps.xaml.cs index 0924282cf..d2e5ae0fa 100644 --- a/ILSpy/DebugSteps.xaml.cs +++ b/ILSpy/DebugSteps.xaml.cs @@ -7,10 +7,6 @@ using ICSharpCode.Decompiler.IL.Transforms; namespace ICSharpCode.ILSpy { - - /// - /// Interaktionslogik für DebugSteps.xaml - /// public partial class DebugSteps : UserControl, IPane { static readonly ILAstWritingOptions writingOptions = new ILAstWritingOptions { @@ -20,7 +16,7 @@ namespace ICSharpCode.ILSpy public static ILAstWritingOptions Options => writingOptions; -#if DEBUG +#if false ILAstLanguage language; #endif @@ -28,7 +24,7 @@ namespace ICSharpCode.ILSpy { InitializeComponent(); -#if DEBUG +#if false MainWindow.Instance.SessionSettings.FilterSettings.PropertyChanged += FilterSettings_PropertyChanged; MainWindow.Instance.SelectionChanged += SelectionChanged; writingOptions.PropertyChanged += WritingOptions_PropertyChanged; @@ -56,7 +52,7 @@ namespace ICSharpCode.ILSpy private void FilterSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { -#if DEBUG +#if false if (e.PropertyName == "Language") { if (language != null) { language.StepperUpdated -= ILAstStepperUpdated; @@ -72,7 +68,7 @@ namespace ICSharpCode.ILSpy private void ILAstStepperUpdated(object sender, EventArgs e) { -#if DEBUG +#if false if (language == null) return; Dispatcher.Invoke(() => { tree.ItemsSource = language.Stepper.Steps; @@ -88,7 +84,7 @@ namespace ICSharpCode.ILSpy void IPane.Closed() { -#if DEBUG +#if false MainWindow.Instance.SessionSettings.FilterSettings.PropertyChanged -= FilterSettings_PropertyChanged; MainWindow.Instance.SelectionChanged -= SelectionChanged; writingOptions.PropertyChanged -= WritingOptions_PropertyChanged; diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 29fa58be8..efd3f5741 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -113,8 +113,6 @@ - - @@ -124,7 +122,6 @@ - @@ -190,17 +187,6 @@ - - - - - - - - - - - diff --git a/ILSpy/Languages/CodeMappingInfo.cs b/ILSpy/Languages/CodeMappingInfo.cs index 60fba3a36..6e4723715 100644 --- a/ILSpy/Languages/CodeMappingInfo.cs +++ b/ILSpy/Languages/CodeMappingInfo.cs @@ -30,7 +30,8 @@ namespace ICSharpCode.ILSpy public bool ShowMember(EntityHandle entity) { - return Language.ShowMember(new Decompiler.Metadata.Entity(Module, entity)); + throw null; + //return Language.ShowMember(new Decompiler.Metadata.Entity(Module, entity)); } public IEnumerable GetMethodParts(MethodDefinitionHandle method) diff --git a/ILSpy/Languages/ILLanguage.cs b/ILSpy/Languages/ILLanguage.cs index aa6d52864..3b63b4d47 100644 --- a/ILSpy/Languages/ILLanguage.cs +++ b/ILSpy/Languages/ILLanguage.cs @@ -26,6 +26,7 @@ using System.IO; using System.Reflection.Metadata.Ecma335; using System.Linq; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.ILSpy { @@ -59,32 +60,33 @@ namespace ICSharpCode.ILSpy }; } - public override void DecompileMethod(Decompiler.Metadata.MethodDefinition method, ITextOutput output, DecompilationOptions options) + public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) { var dis = CreateDisassembler(output, options); - dis.DisassembleMethod(method.Module, method.Handle); + dis.DisassembleMethod(((MetadataAssembly)method.ParentAssembly).PEFile, (MethodDefinitionHandle)method.MetadataToken); } - public override void DecompileField(Decompiler.Metadata.FieldDefinition field, ITextOutput output, DecompilationOptions options) + public override void DecompileField(IField field, ITextOutput output, DecompilationOptions options) { var dis = CreateDisassembler(output, options); - dis.DisassembleField(field); + dis.DisassembleField(((MetadataAssembly)field.ParentAssembly).PEFile, (FieldDefinitionHandle)field.MetadataToken); } - public override void DecompileProperty(Decompiler.Metadata.PropertyDefinition property, ITextOutput output, DecompilationOptions options) + public override void DecompileProperty(IProperty property, ITextOutput output, DecompilationOptions options) { var dis = CreateDisassembler(output, options); - dis.DisassembleProperty(property); - var pd = property.Module.Metadata.GetPropertyDefinition(property.Handle); + PEFile module = ((MetadataAssembly)property.ParentAssembly).PEFile; + dis.DisassembleProperty(module, (PropertyDefinitionHandle)property.MetadataToken); + var pd = module.Metadata.GetPropertyDefinition((PropertyDefinitionHandle)property.MetadataToken); var accessors = pd.GetAccessors(); if (!accessors.Getter.IsNil) { output.WriteLine(); - dis.DisassembleMethod(property.Module, accessors.Getter); + dis.DisassembleMethod(module, accessors.Getter); } if (!accessors.Setter.IsNil) { output.WriteLine(); - dis.DisassembleMethod(property.Module, accessors.Setter); + dis.DisassembleMethod(module, accessors.Setter); } /*foreach (var m in property.OtherMethods) { output.WriteLine(); @@ -92,25 +94,25 @@ namespace ICSharpCode.ILSpy }*/ } - public override void DecompileEvent(Decompiler.Metadata.EventDefinition ev, ITextOutput output, DecompilationOptions options) + public override void DecompileEvent(IEvent ev, ITextOutput output, DecompilationOptions options) { var dis = CreateDisassembler(output, options); - var metadata = ev.Module.Metadata; - dis.DisassembleEvent(ev.Module, ev.Handle); + PEFile module = ((MetadataAssembly)ev.ParentAssembly).PEFile; + dis.DisassembleEvent(module, (EventDefinitionHandle)ev.MetadataToken); - var ed = metadata.GetEventDefinition(ev.Handle); + var ed = ((MetadataReader)module.Metadata).GetEventDefinition((EventDefinitionHandle)ev.MetadataToken); var accessors = ed.GetAccessors(); if (!accessors.Adder.IsNil) { output.WriteLine(); - dis.DisassembleMethod(ev.Module, accessors.Adder); + dis.DisassembleMethod(module, accessors.Adder); } if (!accessors.Remover.IsNil) { output.WriteLine(); - dis.DisassembleMethod(ev.Module, accessors.Remover); + dis.DisassembleMethod(module, accessors.Remover); } if (!accessors.Raiser.IsNil) { output.WriteLine(); - dis.DisassembleMethod(ev.Module, accessors.Raiser); + dis.DisassembleMethod(module, accessors.Raiser); } /*foreach (var m in ev.OtherMethods) { output.WriteLine(); @@ -118,16 +120,18 @@ namespace ICSharpCode.ILSpy }*/ } - public override void DecompileType(Decompiler.Metadata.TypeDefinition type, ITextOutput output, DecompilationOptions options) + public override void DecompileType(ITypeDefinition type, ITextOutput output, DecompilationOptions options) { var dis = CreateDisassembler(output, options); - dis.DisassembleType(type); + PEFile module = ((MetadataAssembly)type.ParentAssembly).PEFile; + dis.DisassembleType(module, (TypeDefinitionHandle)type.MetadataToken); } - - public override void DecompileNamespace(string nameSpace, IEnumerable types, ITextOutput output, DecompilationOptions options) + + public override void DecompileNamespace(string nameSpace, IEnumerable types, ITextOutput output, DecompilationOptions options) { var dis = CreateDisassembler(output, options); - dis.DisassembleNamespace(nameSpace, types); + PEFile module = ((MetadataAssembly)types.FirstOrDefault()?.ParentAssembly)?.PEFile; + dis.DisassembleNamespace(nameSpace, module, types.Select(t => (TypeDefinitionHandle)t.MetadataToken)); } public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options) diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs index e9b53b69b..76332e013 100644 --- a/ILSpy/Languages/Language.cs +++ b/ILSpy/Languages/Language.cs @@ -20,11 +20,10 @@ using System; using System.Collections.Generic; using System.Reflection.PortableExecutable; using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.Util; -using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.Util; -using static System.Reflection.Metadata.PEReaderExtensions; using SRM = System.Reflection.Metadata; namespace ICSharpCode.ILSpy @@ -96,42 +95,32 @@ namespace ICSharpCode.ILSpy } } - public virtual void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) + public virtual void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) { - var metadata = method.Module.Metadata; - var methodDefinition = metadata.GetMethodDefinition(method.Handle); - WriteCommentLine(output, TypeToString(new TypeDefinition(method.Module, methodDefinition.GetDeclaringType()), includeNamespace: true) + "." + metadata.GetString(methodDefinition.Name)); + WriteCommentLine(output, TypeToString(method.DeclaringTypeDefinition, includeNamespace: true) + "." + method.Name); } - public virtual void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options) + public virtual void DecompileProperty(IProperty property, ITextOutput output, DecompilationOptions options) { - var metadata = property.Module.Metadata; - var propertyDefinition = metadata.GetPropertyDefinition(property.Handle); - var declaringType = metadata.GetMethodDefinition(propertyDefinition.GetAccessors().GetAny()).GetDeclaringType(); - WriteCommentLine(output, TypeToString(new TypeDefinition(property.Module, declaringType), includeNamespace: true) + "." + metadata.GetString(propertyDefinition.Name)); + WriteCommentLine(output, TypeToString(property.DeclaringTypeDefinition, includeNamespace: true) + "." + property.Name); } - public virtual void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options) + public virtual void DecompileField(IField field, ITextOutput output, DecompilationOptions options) { - var metadata = field.Module.Metadata; - var fieldDefinition = metadata.GetFieldDefinition(field.Handle); - WriteCommentLine(output, TypeToString(new TypeDefinition(field.Module, fieldDefinition.GetDeclaringType()), includeNamespace: true) + "." + metadata.GetString(fieldDefinition.Name)); + WriteCommentLine(output, TypeToString(field.DeclaringTypeDefinition, includeNamespace: true) + "." + field.Name); } - public virtual void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options) + public virtual void DecompileEvent(IEvent @event, ITextOutput output, DecompilationOptions options) { - var metadata = ev.Module.Metadata; - var eventDefinition = metadata.GetEventDefinition(ev.Handle); - var declaringType = metadata.GetMethodDefinition(eventDefinition.GetAccessors().GetAny()).GetDeclaringType(); - WriteCommentLine(output, TypeToString(new TypeDefinition(ev.Module, declaringType), includeNamespace: true) + "." + metadata.GetString(eventDefinition.Name)); + WriteCommentLine(output, TypeToString(@event.DeclaringTypeDefinition, includeNamespace: true) + "." + @event.Name); } - public virtual void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) + public virtual void DecompileType(ITypeDefinition type, ITextOutput output, DecompilationOptions options) { WriteCommentLine(output, TypeToString(type, includeNamespace: true)); } - public virtual void DecompileNamespace(string nameSpace, IEnumerable types, ITextOutput output, DecompilationOptions options) + public virtual void DecompileNamespace(string nameSpace, IEnumerable types, ITextOutput output, DecompilationOptions options) { WriteCommentLine(output, nameSpace); } @@ -162,125 +151,52 @@ namespace ICSharpCode.ILSpy /// /// Converts a type definition, reference or specification into a string. This method is used by the type tree nodes and search results. /// - public virtual string TypeToString(Entity type, GenericContext genericContext = null, bool includeNamespace = true) + public virtual string TypeToString(IType type, bool includeNamespace) { - var provider = includeNamespace ? ILSignatureProvider.WithNamespace : ILSignatureProvider.WithoutNamespace; - var metadata = type.Module.Metadata; - switch (type.Handle.Kind) { - case SRM.HandleKind.TypeReference: - return provider.GetTypeFromReference(metadata, (SRM.TypeReferenceHandle)type.Handle, 0); - case SRM.HandleKind.TypeDefinition: - var td = metadata.GetTypeDefinition((SRM.TypeDefinitionHandle)type.Handle); - if (includeNamespace) { - var buffer = new System.Text.StringBuilder(); - if (!td.GetDeclaringType().IsNil) { - buffer.Append(TypeToString(new TypeDefinition(type.Module, td.GetDeclaringType()), genericContext, includeNamespace)); - buffer.Append('+'); - } else if (!td.Namespace.IsNil) { - buffer.Append(metadata.GetString(td.Namespace)); - buffer.Append('.'); - } - buffer.Append(metadata.GetString(td.Name)); - return buffer.ToString(); - } else { - return metadata.GetString(td.Name); - } - case SRM.HandleKind.TypeSpecification: - return provider.GetTypeFromSpecification(metadata, genericContext ?? GenericContext.Empty, (SRM.TypeSpecificationHandle)type.Handle, 0); - default: - throw new NotSupportedException(); - } + if (includeNamespace) + return type.FullName; + else + return type.Name; } /// /// Converts a member signature to a string. /// This is used for displaying the tooltip on a member reference. /// - public virtual string GetTooltip(Entity entity) + public virtual string GetTooltip(IEntity entity) { - var metadata = entity.Module.Metadata; - switch (entity.Handle.Kind) { - case SRM.HandleKind.TypeReference: - case SRM.HandleKind.TypeDefinition: - case SRM.HandleKind.TypeSpecification: - return entity.Handle.GetFullTypeName(metadata).ToString(); - case SRM.HandleKind.FieldDefinition: - var fieldDefinition = metadata.GetFieldDefinition((SRM.FieldDefinitionHandle)entity.Handle); - string fieldType = fieldDefinition.DecodeSignature(ILSignatureProvider.WithoutNamespace, new GenericContext(fieldDefinition.GetDeclaringType(), entity.Module)); - return fieldType + " " + fieldDefinition.GetDeclaringType().GetFullTypeName(metadata) + "." + metadata.GetString(fieldDefinition.Name); - case SRM.HandleKind.MethodDefinition: - return TreeNodes.MethodTreeNode.GetText(entity, this).ToString(); - case SRM.HandleKind.EventDefinition: - return TreeNodes.EventTreeNode.GetText(entity, this).ToString(); - case SRM.HandleKind.PropertyDefinition: - return TreeNodes.PropertyTreeNode.GetText(entity, this).ToString(); - default: - throw new NotSupportedException(); - } + return GetDisplayName(entity, true, true); } - public virtual string FieldToString(FieldDefinition field, bool includeTypeName, bool includeNamespace) + public virtual string FieldToString(IField field, bool includeTypeName, bool includeNamespace) { - if (field.Handle.IsNil) + if (field == null) throw new ArgumentNullException(nameof(field)); - var metadata = field.Module.Metadata; - var fd = metadata.GetFieldDefinition(field.Handle); - string fieldType = fd.DecodeSignature(ILSignatureProvider.WithoutNamespace, new GenericContext(fd.GetDeclaringType(), field.Module)); - string simple = metadata.GetString(fd.Name) + " : " + fieldType; - if (!includeTypeName) - return simple; - var typeName = fd.GetDeclaringType().GetFullTypeName(metadata); - if (!includeNamespace) - return typeName.Name + "." + simple; - return typeName + "." + simple; + return GetDisplayName(field, includeTypeName, includeNamespace) + " : " + TypeToString(field.ReturnType, includeNamespace); } - public virtual string PropertyToString(PropertyDefinition property, bool includeTypeName, bool includeNamespace, bool? isIndexer = null) + public virtual string PropertyToString(IProperty property, bool includeTypeName, bool includeNamespace, bool? isIndexer = null) { - if (property.Handle.IsNil) + if (property == null) throw new ArgumentNullException(nameof(property)); - var metadata = property.Module.Metadata; - var pd = metadata.GetPropertyDefinition(property.Handle); - var declaringType = metadata.GetMethodDefinition(pd.GetAccessors().GetAny()).GetDeclaringType(); - var signature = pd.DecodeSignature(!includeNamespace ? ILSignatureProvider.WithoutNamespace : ILSignatureProvider.WithNamespace, new GenericContext(declaringType, property.Module)); - string simple = metadata.GetString(metadata.GetPropertyDefinition(property.Handle).Name) + " : " + signature.ReturnType; - if (!includeTypeName) - return simple; - var typeName = declaringType.GetFullTypeName(metadata); - if (!includeNamespace) - return typeName.Name + "." + simple; - return typeName + "." + simple; + return GetDisplayName(property, includeTypeName, includeNamespace) + " : " + TypeToString(property.ReturnType, includeNamespace); } - public virtual string MethodToString(MethodDefinition method, bool includeTypeName, bool includeNamespace) + public virtual string MethodToString(IMethod method, bool includeTypeName, bool includeNamespace) { - if (method.IsNil) + if (method == null) throw new ArgumentNullException(nameof(method)); - var metadata = method.Module.Metadata; - var md = metadata.GetMethodDefinition(method.Handle); - string name; - if (includeTypeName) { - if (includeNamespace) { - name = md.GetDeclaringType().GetFullTypeName(metadata) + "."; - } else { - name = md.GetDeclaringType().GetFullTypeName(metadata).Name + "."; - } - name += metadata.GetString(md.Name); - } else { - name = metadata.GetString(md.Name); - } - var signature = md.DecodeSignature(includeNamespace ? ILSignatureProvider.WithNamespace : ILSignatureProvider.WithoutNamespace, new GenericContext(method)); int i = 0; - var buffer = new System.Text.StringBuilder(name); - var genericParams = md.GetGenericParameters(); - if (genericParams.Count > 0) { + var buffer = new System.Text.StringBuilder(); + buffer.Append(GetDisplayName(method, includeTypeName, includeNamespace)); + var typeParameters = method.TypeParameters; + if (typeParameters.Count > 0) { buffer.Append('<'); - foreach (var h in genericParams) { - var gp = metadata.GetGenericParameter(h); + foreach (var tp in typeParameters) { if (i > 0) buffer.Append(", "); - buffer.Append(metadata.GetString(gp.Name)); + buffer.Append(tp.Name); i++; } buffer.Append('>'); @@ -288,51 +204,45 @@ namespace ICSharpCode.ILSpy buffer.Append('('); i = 0; - var parameterHandles = md.GetParameters(); - if (signature.RequiredParameterCount > parameterHandles.Count) { - foreach (var type in signature.ParameterTypes) { - if (i > 0) - buffer.Append(", "); - buffer.Append(signature.ParameterTypes[i]); - i++; - } - } else { - foreach (var h in parameterHandles) { - var p = metadata.GetParameter(h); - if (p.SequenceNumber > 0 && i < signature.ParameterTypes.Length) { - if (i > 0) - buffer.Append(", "); - buffer.Append(signature.ParameterTypes[i]); - i++; - } - } - } - if (signature.Header.CallingConvention == SRM.SignatureCallingConvention.VarArgs) { - if (signature.ParameterTypes.Length > 0) + var parameters = method.Parameters; + foreach (var param in parameters) { + if (i > 0) buffer.Append(", "); - buffer.Append("..."); + buffer.Append(TypeToString(param.Type, includeNamespace)); + i++; } buffer.Append(')'); buffer.Append(" : "); - buffer.Append(signature.ReturnType); + buffer.Append(TypeToString(method.ReturnType, includeNamespace)); return buffer.ToString(); } - public virtual string EventToString(EventDefinition @event, bool includeTypeName, bool includeNamespace) + public virtual string EventToString(IEvent @event, bool includeTypeName, bool includeNamespace) { - if (@event.IsNil) + if (@event == null) throw new ArgumentNullException(nameof(@event)); - var metadata = @event.Module.Metadata; - var ed = metadata.GetEventDefinition(@event.Handle); - var accessorHandle = ed.GetAccessors().GetAny(); - var signature = ed.DecodeSignature(metadata, includeNamespace ? ILSignatureProvider.WithNamespace : ILSignatureProvider.WithoutNamespace, new GenericContext(accessorHandle, @event.Module)); var buffer = new System.Text.StringBuilder(); - buffer.Append(metadata.GetString(ed.Name)); + buffer.Append(GetDisplayName(@event, includeTypeName, includeNamespace)); buffer.Append(" : "); - buffer.Append(signature); + buffer.Append(TypeToString(@event.ReturnType, includeNamespace)); return buffer.ToString(); } + protected string GetDisplayName(IEntity entity, bool includeTypeName, bool includeNamespace) + { + if (includeTypeName) { + string name; + if (includeNamespace) { + name = entity.DeclaringTypeDefinition.FullName; + } else { + name = entity.DeclaringTypeDefinition.Name; + } + return name + "." + entity.Name; + } else { + return entity.Name; + } + } + /// /// Used for WPF keyboard navigation. /// @@ -341,7 +251,7 @@ namespace ICSharpCode.ILSpy return Name; } - public virtual bool ShowMember(IMetadataEntity member) + public virtual bool ShowMember(IEntity member) { return true; } diff --git a/ILSpy/Languages/Languages.cs b/ILSpy/Languages/Languages.cs index d8ef5b8ff..88bc29e16 100644 --- a/ILSpy/Languages/Languages.cs +++ b/ILSpy/Languages/Languages.cs @@ -45,7 +45,7 @@ namespace ICSharpCode.ILSpy List languages = new List(); languages.AddRange(ep.GetExportedValues()); languages.Sort((a, b) => a.Name.CompareTo(b.Name)); - #if DEBUG + #if false languages.AddRange(ILAstLanguage.GetDebugLanguages()); languages.AddRange(CSharpLanguage.GetDebugLanguages()); #endif diff --git a/ILSpy/LoadedAssembly.cs b/ILSpy/LoadedAssembly.cs index 5ea73d9fc..68c613ecd 100644 --- a/ILSpy/LoadedAssembly.cs +++ b/ILSpy/LoadedAssembly.cs @@ -25,6 +25,8 @@ using System.Threading; using System.Threading.Tasks; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.ILSpy.DebugInfo; using ICSharpCode.ILSpy.Options; @@ -85,6 +87,14 @@ namespace ICSharpCode.ILSpy } } + public ICompilation GetTypeSystem() + { + var module = GetPEFileOrNull(); + if (module == null) + return null; + return new SimpleCompilation(module, MinimalCorlib.Instance); + } + public AssemblyList AssemblyList => assemblyList; public string FileName => fileName; @@ -193,7 +203,7 @@ namespace ICSharpCode.ILSpy } } - sealed class MyAssemblyResolver : IAssemblyResolver + sealed class MyAssemblyResolver : Decompiler.Metadata.IAssemblyResolver { readonly LoadedAssembly parent; @@ -202,7 +212,7 @@ namespace ICSharpCode.ILSpy this.parent = parent; } - public PEFile Resolve(IAssemblyReference reference) + public PEFile Resolve(Decompiler.Metadata.IAssemblyReference reference) { return parent.LookupReferencedAssembly(reference)?.GetPEFileOrNull(); } @@ -213,7 +223,7 @@ namespace ICSharpCode.ILSpy return new MyAssemblyResolver(this); } - public LoadedAssembly LookupReferencedAssembly(IAssemblyReference reference) + public LoadedAssembly LookupReferencedAssembly(Decompiler.Metadata.IAssemblyReference reference) { if (reference == null) throw new ArgumentNullException(nameof(reference)); @@ -234,9 +244,9 @@ namespace ICSharpCode.ILSpy static Dictionary loadingAssemblies = new Dictionary(); - LoadedAssembly LookupReferencedAssemblyInternal(IAssemblyReference fullName, bool isWinRT) + LoadedAssembly LookupReferencedAssemblyInternal(Decompiler.Metadata.IAssemblyReference fullName, bool isWinRT) { - string GetName(IAssemblyReference name) => isWinRT ? name.Name : name.FullName; + string GetName(Decompiler.Metadata.IAssemblyReference name) => isWinRT ? name.Name : name.FullName; string file; LoadedAssembly asm; diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 9af504bcf..b906b5257 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -34,6 +34,8 @@ using System.Windows.Threading; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Documentation; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.TreeView; @@ -287,8 +289,8 @@ namespace ICSharpCode.ILSpy foreach (LoadedAssembly asm in commandLineLoadedAssemblies) { var def = asm.GetPEFileOrNull(); if (def != null) { - var mr = XmlDocKeyProvider.FindMemberByKey(def, args.NavigateTo); - if (!mr.IsNil) { + var mr = XmlDocKeyProvider.FindEntity(args.NavigateTo, new SimpleCompilation(def, MinimalCorlib.Instance).TypeResolveContext); + if (mr != null) { found = true; // Defer JumpToReference call to allow an assembly that was loaded while // resolving a type-forwarder in FindMemberByKey to appear in the assembly list. @@ -599,21 +601,17 @@ namespace ICSharpCode.ILSpy return assemblyListTreeNode.FindAssemblyNode(asm); case Resource res: return assemblyListTreeNode.FindResourceNode(res); - case IMetadataEntity entity: - switch (entity) { - case TypeDefinition td: - return assemblyListTreeNode.FindTypeNode(td); - case FieldDefinition fd: - return assemblyListTreeNode.FindFieldNode(fd); - case MethodDefinition md: - return assemblyListTreeNode.FindMethodNode(md); - case PropertyDefinition pd: - return assemblyListTreeNode.FindPropertyNode(pd); - case EventDefinition ed: - return assemblyListTreeNode.FindEventNode(ed); - default: - throw new NotSupportedException(); - } + case ITypeDefinition type: + return assemblyListTreeNode.FindTypeNode(type); + case IField fd: + return assemblyListTreeNode.FindFieldNode(fd); + case IMethod md: + return assemblyListTreeNode.FindMethodNode(md); + case IProperty pd: + return assemblyListTreeNode.FindPropertyNode(pd); + case IEvent ed: + return assemblyListTreeNode.FindEventNode(ed); + /* case TypeReference tr: var resolved = tr.Handle.Resolve(new SimpleMetadataResolveContext(tr.Module)); if (resolved != null && !resolved.IsNil) @@ -647,7 +645,7 @@ namespace ICSharpCode.ILSpy throw new NotSupportedException(); } } - return null; + return null;*/ default: return null; } diff --git a/ILSpy/SearchPane.cs b/ILSpy/SearchPane.cs index 167ebb835..f97b1273d 100644 --- a/ILSpy/SearchPane.cs +++ b/ILSpy/SearchPane.cs @@ -27,6 +27,7 @@ using System.Windows.Input; using System.Windows.Media; using System.Windows.Threading; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.TreeNodes; namespace ICSharpCode.ILSpy @@ -216,12 +217,12 @@ namespace ICSharpCode.ILSpy try { var searcher = GetSearchStrategy(searchMode, searchTerm); foreach (var loadedAssembly in assemblies) { - var module = loadedAssembly.GetPEFileOrNull(); - if (module == null) + var typeSystem = loadedAssembly.GetTypeSystem(); + if (typeSystem == null) continue; CancellationToken cancellationToken = cts.Token; - foreach (var type in module.TopLevelTypeDefinitions) { + foreach (var type in typeSystem.GetTopLevelTypeDefinitions()) { cancellationToken.ThrowIfCancellationRequested(); searcher.Search(type, language, AddResult); } @@ -333,7 +334,7 @@ namespace ICSharpCode.ILSpy { public static readonly System.Collections.Generic.IComparer Comparer = new SearchResultComparer(); - public IMetadataEntity Member { get; set; } + public IEntity Member { get; set; } public float Fitness { get; set; } public string Location { get; set; } diff --git a/ILSpy/SearchStrategies.cs b/ILSpy/SearchStrategies.cs index 79835636f..907d72145 100644 --- a/ILSpy/SearchStrategies.cs +++ b/ILSpy/SearchStrategies.cs @@ -14,6 +14,7 @@ using ILOpCode = System.Reflection.Metadata.ILOpCode; using ICSharpCode.Decompiler; using static System.Reflection.Metadata.PEReaderExtensions; +using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.ILSpy { @@ -43,29 +44,9 @@ namespace ICSharpCode.ILSpy searchTerm = terms; } - protected float CalculateFitness(IMetadataEntity member) + protected float CalculateFitness(IEntity member) { - var metadata = member.Module.Metadata; - string text; - switch (member) { - case TypeDefinition td: - text = metadata.GetString(metadata.GetTypeDefinition(td.Handle).Name); - break; - case FieldDefinition fd: - text = metadata.GetString(metadata.GetFieldDefinition(fd.Handle).Name); - break; - case MethodDefinition md: - text = metadata.GetString(metadata.GetMethodDefinition(md.Handle).Name); - break; - case PropertyDefinition pd: - text = metadata.GetString(metadata.GetPropertyDefinition(pd.Handle).Name); - break; - case EventDefinition ed: - text = metadata.GetString(metadata.GetEventDefinition(ed.Handle).Name); - break; - default: - throw new NotSupportedException(); - } + string text = member.Name; // Probably compiler generated types without meaningful names, show them last if (text.StartsWith("<")) { @@ -75,36 +56,36 @@ namespace ICSharpCode.ILSpy // Constructors always have the same name in IL: // Use type name instead if (text == ".cctor" || text == ".ctor") { - //text = member.DeclaringType.Name; + text = member.DeclaringType.Name; } // Ignore generic arguments, it not possible to search based on them either - text = Decompiler.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(text); + text = ReflectionHelper.SplitTypeParameterCountFromReflectionName(text); return 1.0f / text.Length; } - protected virtual bool IsMatch(FieldDefinition field, Language language) + protected virtual bool IsMatch(IField field, Language language) { return false; } - protected virtual bool IsMatch(PropertyDefinition property, Language language) + protected virtual bool IsMatch(IProperty property, Language language) { return false; } - protected virtual bool IsMatch(EventDefinition ev, Language language) + protected virtual bool IsMatch(IEvent ev, Language language) { return false; } - protected virtual bool IsMatch(MethodDefinition m, Language language) + protected virtual bool IsMatch(IMethod m, Language language) { return false; } - protected virtual bool MatchName(IMetadataEntity m, Language language) + protected virtual bool MatchName(IEntity m, Language language) { return IsMatch(t => GetLanguageSpecificName(language, m, regex != null ? fullNameSearch : t.Contains("."))); } @@ -178,26 +159,25 @@ namespace ICSharpCode.ILSpy return false; } - string GetLanguageSpecificName(Language language, IMetadataEntity member, bool fullName = false) + string GetLanguageSpecificName(Language language, IEntity member, bool fullName = false) { - var metadata = member.Module.Metadata; switch (member) { - case TypeDefinition t: + case ITypeDefinition t: return language.TypeToString(t, includeNamespace: fullName); - case FieldDefinition f: + case IField f: return language.FieldToString(f, fullName, fullName); - case PropertyDefinition p: - return language.PropertyToString(p, fullName, fullName, p.Handle.HasMatchingDefaultMemberAttribute(member.Module, out _)); - case MethodDefinition m: + case IProperty p: + return language.PropertyToString(p, fullName, fullName, p.IsIndexer); + case IMethod m: return language.MethodToString(m, fullName, fullName); - case EventDefinition e: + case IEvent e: return language.EventToString(e, fullName, fullName); default: throw new NotSupportedException(member?.GetType() + " not supported!"); } } - void Add(Func> itemsGetter, TypeDefinition type, Language language, Action addResult, Func matcher, Func image) where T : IMetadataEntity + void Add(Func> itemsGetter, ITypeDefinition type, Language language, Action addResult, Func matcher, Func image) where T : IEntity { IEnumerable items = Enumerable.Empty(); try { @@ -219,30 +199,18 @@ namespace ICSharpCode.ILSpy } } - public virtual void Search(TypeDefinition type, Language language, Action addResult) + public virtual void Search(ITypeDefinition type, Language language, Action addResult) { - var metadata = type.Module.Metadata; - var td = metadata.GetTypeDefinition(type.Handle); - Add(() => td.GetFields().Select(f => new FieldDefinition(type.Module, f)), type, language, addResult, IsMatch, FieldTreeNode.GetIcon); - Add(() => td.GetProperties().Select(p => new PropertyDefinition(type.Module, p)), type, language, addResult, IsMatch, p => PropertyTreeNode.GetIcon(p)); - Add(() => td.GetEvents().Select(e => new EventDefinition(type.Module, e)), type, language, addResult, IsMatch, EventTreeNode.GetIcon); - Add(() => td.GetMethods().Where(m => NotSpecialMethod(m, metadata)).Select(m => new MethodDefinition(type.Module, m)), type, language, addResult, IsMatch, MethodTreeNode.GetIcon); + Add(() => type.Fields, type, language, addResult, IsMatch, FieldTreeNode.GetIcon); + Add(() => type.Properties, type, language, addResult, IsMatch, p => PropertyTreeNode.GetIcon(p)); + Add(() => type.Events, type, language, addResult, IsMatch, EventTreeNode.GetIcon); + Add(() => type.Methods.Where(m => !m.IsAccessor), type, language, addResult, IsMatch, MethodTreeNode.GetIcon); - foreach (var nestedType in td.GetNestedTypes()) { - Search(new TypeDefinition(type.Module, nestedType), language, addResult); + foreach (var nestedType in type.NestedTypes) { + Search(nestedType, language, addResult); } } - bool NotSpecialMethod(SRM.MethodDefinitionHandle method, SRM.MetadataReader metadata) - { - return (method.GetMethodSemanticsAttributes(metadata) & ( - MethodSemanticsAttributes.Setter - | MethodSemanticsAttributes.Getter - | MethodSemanticsAttributes.Adder - | MethodSemanticsAttributes.Remover - | MethodSemanticsAttributes.Raiser)) == 0; - } - Regex SafeNewRegex(string unsafePattern) { try { @@ -265,9 +233,9 @@ namespace ICSharpCode.ILSpy } } - protected override bool MatchName(IMetadataEntity m, Language language) + protected override bool MatchName(IEntity m, Language language) { - return SRM.Ecma335.MetadataTokens.GetToken(m.Handle) == searchTermToken; + return SRM.Ecma335.MetadataTokens.GetToken(m.MetadataToken) == searchTermToken; } } @@ -308,26 +276,24 @@ namespace ICSharpCode.ILSpy } } - protected override bool IsMatch(FieldDefinition field, Language language) + protected override bool IsMatch(IField field, Language language) { - return IsLiteralMatch(field.DecodeConstant()); + return IsLiteralMatch(field.ConstantValue); } - protected override bool IsMatch(PropertyDefinition property, Language language) + protected override bool IsMatch(IProperty property, Language language) { - var accessors = property.Module.Metadata.GetPropertyDefinition(property.Handle).GetAccessors(); - return MethodIsLiteralMatch(accessors.Getter, property.Module) || MethodIsLiteralMatch(accessors.Setter, property.Module); + return MethodIsLiteralMatch(property.Getter) || MethodIsLiteralMatch(property.Setter); } - protected override bool IsMatch(EventDefinition ev, Language language) + protected override bool IsMatch(IEvent ev, Language language) { - var accessors = ev.Module.Metadata.GetEventDefinition(ev.Handle).GetAccessors(); - return MethodIsLiteralMatch(accessors.Adder, ev.Module) || MethodIsLiteralMatch(accessors.Remover, ev.Module) || MethodIsLiteralMatch(accessors.Raiser, ev.Module); + return MethodIsLiteralMatch(ev.AddAccessor) || MethodIsLiteralMatch(ev.RemoveAccessor) || MethodIsLiteralMatch(ev.InvokeAccessor); } - protected override bool IsMatch(MethodDefinition m, Language language) + protected override bool IsMatch(IMethod m, Language language) { - return MethodIsLiteralMatch(m.Handle, m.Module); + return MethodIsLiteralMatch(m); } bool IsLiteralMatch(object val) @@ -351,14 +317,15 @@ namespace ICSharpCode.ILSpy } } - bool MethodIsLiteralMatch(SRM.MethodDefinitionHandle m, PEFile module) + bool MethodIsLiteralMatch(IMethod method) { - if (module == null) + if (method == null) return false; - var metadata = module.Metadata; + var module = ((MetadataAssembly)method.ParentAssembly).PEFile; + var m = (SRM.MethodDefinitionHandle)method.MetadataToken; if (m.IsNil) return false; - var methodDefinition = metadata.GetMethodDefinition(m); + var methodDefinition = module.Metadata.GetMethodDefinition(m); if (!methodDefinition.HasBody()) return false; var blob = module.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress).GetILReader(); @@ -455,7 +422,7 @@ namespace ICSharpCode.ILSpy return true; break; case ILOpCode.Ldstr: - if ((string)searchTermLiteralValue == ILParser.DecodeUserString(ref blob, metadata)) + if ((string)searchTermLiteralValue == ILParser.DecodeUserString(ref blob, module.Metadata)) return true; break; } @@ -467,7 +434,7 @@ namespace ICSharpCode.ILSpy ILParser.SkipOperand(ref blob, code); continue; } - if (IsMatch(t => ILParser.DecodeUserString(ref blob, metadata))) + if (base.IsMatch(t => ILParser.DecodeUserString(ref blob, module.Metadata))) return true; } } @@ -499,22 +466,22 @@ namespace ICSharpCode.ILSpy this.searchKind = searchKind; } - protected override bool IsMatch(FieldDefinition field, Language language) + protected override bool IsMatch(IField field, Language language) { return (searchKind == MemberSearchKind.All || searchKind == MemberSearchKind.Field) && MatchName(field, language); } - protected override bool IsMatch(PropertyDefinition property, Language language) + protected override bool IsMatch(IProperty property, Language language) { return (searchKind == MemberSearchKind.All || searchKind == MemberSearchKind.Property) && MatchName(property, language); } - protected override bool IsMatch(EventDefinition ev, Language language) + protected override bool IsMatch(IEvent ev, Language language) { return (searchKind == MemberSearchKind.All || searchKind == MemberSearchKind.Event) && MatchName(ev, language); } - protected override bool IsMatch(MethodDefinition m, Language language) + protected override bool IsMatch(IMethod m, Language language) { return (searchKind == MemberSearchKind.All || searchKind == MemberSearchKind.Method) && MatchName(m, language); } @@ -527,26 +494,23 @@ namespace ICSharpCode.ILSpy { } - public override void Search(TypeDefinition type, Language language, Action addResult) + public override void Search(ITypeDefinition type, Language language, Action addResult) { - var metadata = type.Module.Metadata; - var td = metadata.GetTypeDefinition(type.Handle); - if (MatchName(type, language)) { string name = language.TypeToString(type, includeNamespace: false); - var declaringType = td.GetDeclaringType(); + var declaringType = type.DeclaringTypeDefinition; addResult(new SearchResult { Member = type, Fitness = CalculateFitness(type), Image = TypeTreeNode.GetIcon(type), Name = name, - LocationImage = !declaringType.IsNil ? TypeTreeNode.GetIcon(new TypeDefinition(type.Module, declaringType)) : Images.Namespace, - Location = !declaringType.IsNil ? language.TypeToString(new TypeDefinition(type.Module, declaringType), includeNamespace: true) : type.Handle.GetFullTypeName(metadata).TopLevelTypeName.Namespace + LocationImage = declaringType != null ? TypeTreeNode.GetIcon(declaringType) : Images.Namespace, + Location = declaringType != null ? language.TypeToString(declaringType, includeNamespace: true) : type.Namespace }); } - foreach (var nestedType in td.GetNestedTypes()) { - Search(new TypeDefinition(type.Module, nestedType), language, addResult); + foreach (var nestedType in type.NestedTypes) { + Search(nestedType, language, addResult); } } } @@ -558,42 +522,41 @@ namespace ICSharpCode.ILSpy { } - public override void Search(TypeDefinition type, Language language, Action addResult) + public override void Search(ITypeDefinition type, Language language, Action addResult) { if (MatchName(type, language)) { string name = language.TypeToString(type, includeNamespace: false); - var metadata = type.Module.Metadata; - var declaringType = metadata.GetTypeDefinition(type.Handle).GetDeclaringType(); + var declaringType = type.DeclaringTypeDefinition; addResult(new SearchResult { Member = type, Image = TypeTreeNode.GetIcon(type), Fitness = CalculateFitness(type), Name = name, - LocationImage = !declaringType.IsNil ? TypeTreeNode.GetIcon(new TypeDefinition(type.Module, declaringType)) : Images.Namespace, - Location = !declaringType.IsNil ? language.TypeToString(new TypeDefinition(type.Module, declaringType), includeNamespace: true) : type.Handle.GetFullTypeName(metadata).TopLevelTypeName.Namespace + LocationImage = declaringType != null ? TypeTreeNode.GetIcon(declaringType) : Images.Namespace, + Location = declaringType != null ? language.TypeToString(declaringType, includeNamespace: true) : type.Namespace }); } base.Search(type, language, addResult); } - protected override bool IsMatch(FieldDefinition field, Language language) + protected override bool IsMatch(IField field, Language language) { return MatchName(field, language); } - protected override bool IsMatch(PropertyDefinition property, Language language) + protected override bool IsMatch(IProperty property, Language language) { return MatchName(property, language); } - protected override bool IsMatch(EventDefinition ev, Language language) + protected override bool IsMatch(IEvent ev, Language language) { return MatchName(ev, language); } - protected override bool IsMatch(MethodDefinition m, Language language) + protected override bool IsMatch(IMethod m, Language language) { return MatchName(m, language); } diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 5e2bfebfa..9ac0ab660 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -46,6 +46,7 @@ using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.Documentation; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy.AvalonEdit; using ICSharpCode.ILSpy.Options; using ICSharpCode.ILSpy.TreeNodes; @@ -206,14 +207,14 @@ namespace ICSharpCode.ILSpy.TextView } } return $"{code.Name} (0x{code.Code:x})"; - } else if (segment.Reference is IMetadataEntity entity) { + } else if (segment.Reference is IEntity entity) { XmlDocRenderer renderer = new XmlDocRenderer(); - renderer.AppendText(MainWindow.Instance.CurrentLanguage.GetTooltip(new Entity(entity.Module, entity.Handle))); + renderer.AppendText(MainWindow.Instance.CurrentLanguage.GetTooltip(entity)); try { //var docProvider = entity.Module.DocumentationResolver.GetProvider(); // TODO implement proper API - var docProvider = XmlDocLoader.LoadDocumentation(entity.Module); + var docProvider = XmlDocLoader.LoadDocumentation(((MetadataAssembly)entity.ParentAssembly).PEFile); if (docProvider != null) { - string documentation = docProvider.GetDocumentation(XmlDocKeyProvider.GetKey(new Entity(entity.Module, entity.Handle))); + string documentation = docProvider.GetDocumentation(XmlDocKeyProvider.GetKey(entity)); if (documentation != null) { renderer.AppendText(Environment.NewLine); renderer.AddXmlDocumentation(documentation); diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs b/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs index 1422adfa8..bcd187dcc 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs @@ -18,7 +18,7 @@ using System; using System.Linq; -using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { @@ -37,7 +37,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer public bool IsEnabled(TextViewContext context) { if (context.SelectedTreeNodes == null) - return context.Reference != null && context.Reference.Reference is IMetadataEntity; + return context.Reference != null && context.Reference.Reference is IEntity; foreach (IMemberTreeNode node in context.SelectedTreeNodes) { if (!IsValidReference(node.Member)) return false; @@ -48,11 +48,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer bool IsValidReference(object reference) { - return reference is IMetadataEntity - || reference is MemberReference - || reference is MethodSpecification - || reference is TypeReference - || reference is TypeSpecification; + return reference is IEntity; } public void Execute(TextViewContext context) @@ -67,7 +63,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer } public static void Analyze(object member) - { + {/* switch (member) { case IMetadataEntity entity: switch (entity) { @@ -133,6 +129,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer } break; } + */ } } } diff --git a/ILSpy/TreeNodes/AssemblyListTreeNode.cs b/ILSpy/TreeNodes/AssemblyListTreeNode.cs index b48296b67..bfd4a3abf 100644 --- a/ILSpy/TreeNodes/AssemblyListTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyListTreeNode.cs @@ -26,6 +26,7 @@ using System.Reflection.PortableExecutable; using System.Windows; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.TreeView; namespace ICSharpCode.ILSpy.TreeNodes @@ -176,6 +177,13 @@ namespace ICSharpCode.ILSpy.TreeNodes return null; } + public AssemblyTreeNode FindAssemblyNode(IAssembly module) + { + if (!(module is MetadataAssembly assembly)) + return null; + return FindAssemblyNode(assembly.PEFile); + } + public AssemblyTreeNode FindAssemblyNode(PEFile module) { if (module == null) @@ -204,17 +212,17 @@ namespace ICSharpCode.ILSpy.TreeNodes /// Looks up the type node corresponding to the type definition. /// Returns null if no matching node is found. /// - public TypeTreeNode FindTypeNode(TypeDefinition def) + public TypeTreeNode FindTypeNode(ITypeDefinition def) { - var declaringType = def.Module.Metadata.GetTypeDefinition(def.Handle).GetDeclaringType(); - if (!declaringType.IsNil) { - TypeTreeNode decl = FindTypeNode(new TypeDefinition(def.Module, declaringType)); + var declaringType = def.DeclaringTypeDefinition; + if (declaringType != null) { + TypeTreeNode decl = FindTypeNode(declaringType); if (decl != null) { decl.EnsureLazyChildren(); - return decl.Children.OfType().FirstOrDefault(t => t.TypeDefinition == def && !t.IsHidden); + return decl.Children.OfType().FirstOrDefault(t => t.TypeDefinition.Equals(def) && !t.IsHidden); } } else { - AssemblyTreeNode asm = FindAssemblyNode(def.Module); + AssemblyTreeNode asm = FindAssemblyNode(def.ParentAssembly); if (asm != null) { return asm.FindTypeNode(def); } @@ -226,78 +234,79 @@ namespace ICSharpCode.ILSpy.TreeNodes /// Looks up the method node corresponding to the method definition. /// Returns null if no matching node is found. /// - public ILSpyTreeNode FindMethodNode(MethodDefinition def) + public ILSpyTreeNode FindMethodNode(IMethod def) { - TypeTreeNode typeNode = FindTypeNode(new TypeDefinition(def.Module, def.Module.Metadata.GetMethodDefinition(def.Handle).GetDeclaringType())); + TypeTreeNode typeNode = FindTypeNode(def.DeclaringTypeDefinition); if (typeNode == null) return null; - typeNode.EnsureLazyChildren(); - MethodTreeNode methodNode = typeNode.Children.OfType().FirstOrDefault(m => m.MethodDefinition == def && !m.IsHidden); - if (methodNode != null) - return methodNode; - foreach (var p in typeNode.Children.OfType()) { - if (p.IsHidden) - continue; - - // method might be a child of a property or event - if (p is PropertyTreeNode || p is EventTreeNode) { - p.EnsureLazyChildren(); - methodNode = p.Children.OfType().FirstOrDefault(m => m.MethodDefinition == def); - if (methodNode != null) { - // If the requested method is a property or event accessor, and accessors are - // hidden in the UI, then return the owning property or event. - if (methodNode.IsHidden) - return p; - else - return methodNode; - } - } + // method might be an accessor, must look for parent node + ILSpyTreeNode parentNode = typeNode; + MethodTreeNode methodNode; + parentNode.EnsureLazyChildren(); + switch (def.AccessorOwner) { + case IProperty p: + parentNode = parentNode.Children.OfType().FirstOrDefault(m => m.PropertyDefinition.Equals(p)); + if (parentNode == null) + return null; + parentNode.EnsureLazyChildren(); + methodNode = parentNode.Children.OfType().FirstOrDefault(m => m.MethodDefinition.Equals(def)); + if (methodNode == null || methodNode.IsHidden) + return parentNode; + return methodNode; + case IEvent e: + parentNode = parentNode.Children.OfType().FirstOrDefault(m => m.EventDefinition.Equals(e)); + if (parentNode == null) + return null; + parentNode.EnsureLazyChildren(); + methodNode = parentNode.Children.OfType().FirstOrDefault(m => m.MethodDefinition.Equals(def)); + if (methodNode == null || methodNode.IsHidden) + return parentNode; + return methodNode; + default: + methodNode = typeNode.Children.OfType().FirstOrDefault(m => m.MethodDefinition.Equals(def) && !m.IsHidden); + if (methodNode != null) + return methodNode; + return null; } - - return null; } /// /// Looks up the field node corresponding to the field definition. /// Returns null if no matching node is found. /// - public FieldTreeNode FindFieldNode(FieldDefinition def) + public FieldTreeNode FindFieldNode(IField def) { - TypeTreeNode typeNode = FindTypeNode(new TypeDefinition(def.Module, def.Module.Metadata.GetFieldDefinition(def.Handle).GetDeclaringType())); + TypeTreeNode typeNode = FindTypeNode(def.DeclaringTypeDefinition); if (typeNode == null) return null; typeNode.EnsureLazyChildren(); - return typeNode.Children.OfType().FirstOrDefault(m => m.FieldDefinition == def && !m.IsHidden); + return typeNode.Children.OfType().FirstOrDefault(m => m.FieldDefinition.Equals(def) && !m.IsHidden); } /// /// Looks up the property node corresponding to the property definition. /// Returns null if no matching node is found. /// - public PropertyTreeNode FindPropertyNode(PropertyDefinition def) + public PropertyTreeNode FindPropertyNode(IProperty def) { - var metadata = def.Module.Metadata; - var accessor = metadata.GetMethodDefinition(metadata.GetPropertyDefinition(def.Handle).GetAccessors().GetAny()); - TypeTreeNode typeNode = FindTypeNode(new TypeDefinition(def.Module, accessor.GetDeclaringType())); + TypeTreeNode typeNode = FindTypeNode(def.DeclaringTypeDefinition); if (typeNode == null) return null; typeNode.EnsureLazyChildren(); - return typeNode.Children.OfType().FirstOrDefault(m => m.PropertyDefinition == def && !m.IsHidden); + return typeNode.Children.OfType().FirstOrDefault(m => m.PropertyDefinition.Equals(def) && !m.IsHidden); } /// /// Looks up the event node corresponding to the event definition. /// Returns null if no matching node is found. /// - public EventTreeNode FindEventNode(EventDefinition def) + public EventTreeNode FindEventNode(IEvent def) { - var metadata = def.Module.Metadata; - var accessor = metadata.GetMethodDefinition(metadata.GetEventDefinition(def.Handle).GetAccessors().GetAny()); - TypeTreeNode typeNode = FindTypeNode(new TypeDefinition(def.Module, accessor.GetDeclaringType())); + TypeTreeNode typeNode = FindTypeNode(def.DeclaringTypeDefinition); if (typeNode == null) return null; typeNode.EnsureLazyChildren(); - return typeNode.Children.OfType().FirstOrDefault(m => m.EventDefinition == def && !m.IsHidden); + return typeNode.Children.OfType().FirstOrDefault(m => m.EventDefinition.Equals(def) && !m.IsHidden); } #endregion } diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs index 3847ba523..bb3cba6a4 100644 --- a/ILSpy/TreeNodes/AssemblyTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs @@ -41,7 +41,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public sealed class AssemblyTreeNode : ILSpyTreeNode { readonly Dictionary namespaces = new Dictionary(); - readonly Dictionary typeDict = new Dictionary(); + readonly Dictionary typeDict = new Dictionary(); ICompilation typeSystem; public AssemblyTreeNode(LoadedAssembly assembly) @@ -136,6 +136,7 @@ namespace ICSharpCode.ILSpy.TreeNodes return; } typeSystem = new SimpleCompilation(module, MinimalCorlib.Instance); + var assembly = (MetadataAssembly)typeSystem.MainAssembly; var metadata = module.Metadata; this.Children.Add(new ReferenceFolderTreeNode(module, this)); @@ -144,13 +145,10 @@ namespace ICSharpCode.ILSpy.TreeNodes foreach (NamespaceTreeNode ns in namespaces.Values) { ns.Children.Clear(); } - foreach (var typeHandle in metadata.GetTopLevelTypeDefinitions().OrderBy(t => t.GetFullTypeName(metadata).ToString(), NaturalStringComparer.Instance)) { - NamespaceTreeNode ns; - var type = new TypeDefinition(module, typeHandle); - var namespaceString = metadata.GetString(metadata.GetTypeDefinition(typeHandle).Namespace); - if (!namespaces.TryGetValue(namespaceString, out ns)) { - ns = new NamespaceTreeNode(namespaceString); - namespaces[namespaceString] = ns; + foreach (var type in assembly.TopLevelTypeDefinitions.OrderBy(t => t.FullName, NaturalStringComparer.Instance)) { + if (!namespaces.TryGetValue(type.Namespace, out NamespaceTreeNode ns)) { + ns = new NamespaceTreeNode(type.Namespace); + namespaces[type.Namespace] = ns; } TypeTreeNode node = new TypeTreeNode(type, this); typeDict[type] = node; @@ -167,7 +165,7 @@ namespace ICSharpCode.ILSpy.TreeNodes /// /// Finds the node for a top-level type. /// - public TypeTreeNode FindTypeNode(TypeDefinition def) + public TypeTreeNode FindTypeNode(ITypeDefinition def) { if (def == null) return null; diff --git a/ILSpy/TreeNodes/BaseTypesEntryNode.cs b/ILSpy/TreeNodes/BaseTypesEntryNode.cs index b125b4f1a..42eef9028 100644 --- a/ILSpy/TreeNodes/BaseTypesEntryNode.cs +++ b/ILSpy/TreeNodes/BaseTypesEntryNode.cs @@ -18,65 +18,70 @@ using System; using System.Linq; +using System.Reflection.Metadata; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.TreeView; namespace ICSharpCode.ILSpy.TreeNodes { sealed class BaseTypesEntryNode : ILSpyTreeNode, IMemberTreeNode { - readonly Entity tr; - readonly GenericContext context; + readonly PEFile module; + readonly EntityHandle handle; + readonly IType type; readonly bool isInterface; readonly bool showExpander; - readonly object icon; - public BaseTypesEntryNode(GenericContext context, Entity entity, bool isInterface) + public BaseTypesEntryNode(PEFile module, EntityHandle handle, IType type, bool isInterface) { - if (entity.IsNil) throw new ArgumentNullException(nameof(entity)); - this.tr = entity; - this.context = context; + if (handle.IsNil) + throw new ArgumentNullException(nameof(handle)); + this.module = module ?? throw new ArgumentNullException(nameof(module)); + this.handle = handle; + this.type = type; this.isInterface = isInterface; this.LazyLoading = true; + showExpander = true; - var td = tr.ResolveAsType(); + /*var td = tr.ResolveAsType(); if (!td.IsNil) { var typeDef = td.Module.Metadata.GetTypeDefinition(td.Handle); showExpander = !typeDef.BaseType.IsNil || typeDef.GetInterfaceImplementations().Any(); - icon = TypeTreeNode.GetIcon(td); } else { showExpander = false; - icon = isInterface ? Images.Interface : Images.Class; - } + }*/ } public override bool ShowExpander => showExpander; public override object Text { - get { return this.Language.TypeToString(tr, context, includeNamespace: true) + tr.Handle.ToSuffixString(); } + get { return this.Language.TypeToString(type, includeNamespace: true) + handle.ToSuffixString(); } } - public override object Icon => icon; + public override object Icon => isInterface ? Images.Interface : Images.Class; protected override void LoadChildren() { - var td = tr.ResolveAsType(); - if (!td.IsNil) { - BaseTypesTreeNode.AddBaseTypes(this.Children, td); + DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module); + var t = typeSystem.ResolveAsType(handle).GetDefinition(); + if (t != null) { + BaseTypesTreeNode.AddBaseTypes(this.Children, ((MetadataAssembly)t.ParentAssembly).PEFile, t); } } public override void ActivateItem(System.Windows.RoutedEventArgs e) { - var td = tr.ResolveAsType(); - e.Handled = ActivateItem(this, td); + DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module); + var t = typeSystem.ResolveAsType(handle).GetDefinition(); + e.Handled = ActivateItem(this, t); } - internal static bool ActivateItem(SharpTreeNode node, TypeDefinition def) + internal static bool ActivateItem(SharpTreeNode node, ITypeDefinition def) { - if (!def.IsNil) { + if (def != null) { var assemblyListNode = node.Ancestors().OfType().FirstOrDefault(); if (assemblyListNode != null) { assemblyListNode.Select(assemblyListNode.FindTypeNode(def)); @@ -88,9 +93,15 @@ namespace ICSharpCode.ILSpy.TreeNodes public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) { - language.WriteCommentLine(output, language.TypeToString(tr, context, includeNamespace: true)); + language.WriteCommentLine(output, language.TypeToString(type, includeNamespace: true)); } - IMetadataEntity IMemberTreeNode.Member => tr; + IEntity IMemberTreeNode.Member { + get { + DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module); + var t = typeSystem.ResolveAsType(handle).GetDefinition(); + return t; + } + } } } diff --git a/ILSpy/TreeNodes/BaseTypesTreeNode.cs b/ILSpy/TreeNodes/BaseTypesTreeNode.cs index 574caae93..7792520e3 100644 --- a/ILSpy/TreeNodes/BaseTypesTreeNode.cs +++ b/ILSpy/TreeNodes/BaseTypesTreeNode.cs @@ -17,9 +17,12 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Linq; +using System.Reflection.Metadata; using System.Windows.Threading; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.TreeView; namespace ICSharpCode.ILSpy.TreeNodes @@ -29,10 +32,12 @@ namespace ICSharpCode.ILSpy.TreeNodes /// sealed class BaseTypesTreeNode : ILSpyTreeNode { - readonly TypeDefinition type; + readonly PEFile module; + readonly ITypeDefinition type; - public BaseTypesTreeNode(TypeDefinition type) + public BaseTypesTreeNode(PEFile module, ITypeDefinition type) { + this.module = module; this.type = type; this.LazyLoading = true; } @@ -43,19 +48,23 @@ namespace ICSharpCode.ILSpy.TreeNodes protected override void LoadChildren() { - AddBaseTypes(this.Children, type); + AddBaseTypes(this.Children, module, type); } - internal static void AddBaseTypes(SharpTreeNodeCollection children, TypeDefinition type) + internal static void AddBaseTypes(SharpTreeNodeCollection children, PEFile module, ITypeDefinition typeDefinition) { - var metadata = type.Module.Metadata; - var def = metadata.GetTypeDefinition(type.Handle); - var context = new GenericContext(type); - if (!def.BaseType.IsNil) - children.Add(new BaseTypesEntryNode(context, new Entity(type.Module, def.BaseType), false)); - foreach (var i in def.GetInterfaceImplementations()) { - var interfaceImpl = metadata.GetInterfaceImplementation(i); - children.Add(new BaseTypesEntryNode(context, new Entity(type.Module, interfaceImpl.Interface), true)); + var typeDef = module.Metadata.GetTypeDefinition((TypeDefinitionHandle)typeDefinition.MetadataToken); + var baseTypes = typeDefinition.DirectBaseTypes.ToArray(); + int i = 0; + if (typeDefinition.Kind == TypeKind.Interface) { + i++; + } else if (!typeDef.BaseType.IsNil) { + children.Add(new BaseTypesEntryNode(module, typeDef.BaseType, baseTypes[i], false)); + i++; + } + foreach (var h in typeDef.GetInterfaceImplementations()) { + children.Add(new BaseTypesEntryNode(module, h, baseTypes[i], true)); + i++; } } diff --git a/ILSpy/TreeNodes/CopyFullyQualifiedNameContextMenuEntry.cs b/ILSpy/TreeNodes/CopyFullyQualifiedNameContextMenuEntry.cs index e2338966d..800bff262 100644 --- a/ILSpy/TreeNodes/CopyFullyQualifiedNameContextMenuEntry.cs +++ b/ILSpy/TreeNodes/CopyFullyQualifiedNameContextMenuEntry.cs @@ -2,6 +2,7 @@ using System.Windows; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.ILSpy.TreeNodes { @@ -18,60 +19,13 @@ namespace ICSharpCode.ILSpy.TreeNodes public void Execute(TextViewContext context) { var member = GetMemberNodeFromContext(context)?.Member; - if (member == null || member.IsNil) return; - Clipboard.SetText(GetFullyQualifiedName(member)); + if (member == null) return; + Clipboard.SetText(member.ReflectionName); } private IMemberTreeNode GetMemberNodeFromContext(TextViewContext context) { return context.SelectedTreeNodes?.Length == 1 ? context.SelectedTreeNodes[0] as IMemberTreeNode : null; } - - /// - /// Resolve full type name using .NET type representation for nested types. - /// - private string GetFullyQualifiedName(IMetadataEntity member) - { - string name; - System.Reflection.Metadata.TypeDefinitionHandle declaringType; - switch (member.Handle.Kind) { - case System.Reflection.Metadata.HandleKind.TypeDefinition: - return ((System.Reflection.Metadata.TypeDefinitionHandle)member.Handle).GetFullTypeName(member.Module.Metadata).ToString(); - case System.Reflection.Metadata.HandleKind.FieldDefinition: - name = ""; - declaringType = member.Handle.GetDeclaringType(member.Module.Metadata); - var fd = member.Module.Metadata.GetFieldDefinition((System.Reflection.Metadata.FieldDefinitionHandle)member.Handle); - if (!declaringType.IsNil) { - name = declaringType.GetFullTypeName(member.Module.Metadata) + "."; - } - return name + member.Module.Metadata.GetString(fd.Name); - case System.Reflection.Metadata.HandleKind.MethodDefinition: - name = ""; - declaringType = member.Handle.GetDeclaringType(member.Module.Metadata); - var md = member.Module.Metadata.GetMethodDefinition((System.Reflection.Metadata.MethodDefinitionHandle)member.Handle); - if (!declaringType.IsNil) { - name = declaringType.GetFullTypeName(member.Module.Metadata) + "."; - } - return name + member.Module.Metadata.GetString(md.Name); - case System.Reflection.Metadata.HandleKind.EventDefinition: - name = ""; - declaringType = member.Handle.GetDeclaringType(member.Module.Metadata); - var ed = member.Module.Metadata.GetEventDefinition((System.Reflection.Metadata.EventDefinitionHandle)member.Handle); - if (!declaringType.IsNil) { - name = declaringType.GetFullTypeName(member.Module.Metadata) + "."; - } - return name + member.Module.Metadata.GetString(ed.Name); - case System.Reflection.Metadata.HandleKind.PropertyDefinition: - name = ""; - declaringType = member.Handle.GetDeclaringType(member.Module.Metadata); - var pd = member.Module.Metadata.GetPropertyDefinition((System.Reflection.Metadata.PropertyDefinitionHandle)member.Handle); - if (!declaringType.IsNil) { - name = declaringType.GetFullTypeName(member.Module.Metadata) + "."; - } - return name + member.Module.Metadata.GetString(pd.Name); - default: - throw new ArgumentOutOfRangeException(); - } - } } } \ No newline at end of file diff --git a/ILSpy/TreeNodes/DerivedTypesEntryNode.cs b/ILSpy/TreeNodes/DerivedTypesEntryNode.cs index 04c8ba1e6..0263f99c8 100644 --- a/ILSpy/TreeNodes/DerivedTypesEntryNode.cs +++ b/ILSpy/TreeNodes/DerivedTypesEntryNode.cs @@ -22,18 +22,19 @@ using System.Reflection.PortableExecutable; using System.Threading; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; using SRM = System.Reflection.Metadata; namespace ICSharpCode.ILSpy.TreeNodes { class DerivedTypesEntryNode : ILSpyTreeNode, IMemberTreeNode { - private readonly TypeDefinition type; - private readonly PEFile[] assemblies; + private readonly ITypeDefinition type; + /* private readonly PEFile[] assemblies; private readonly ThreadingSupport threading; private readonly SRM.TypeDefinition td; - public DerivedTypesEntryNode(TypeDefinition type, PEFile[] assemblies) + public DerivedTypesEntryNode(ITypeDefinition type, PEFile[] assemblies) { this.type = type; this.td = type.Module.Metadata.GetTypeDefinition(type.Handle); @@ -100,13 +101,13 @@ namespace ICSharpCode.ILSpy.TreeNodes public override void ActivateItem(System.Windows.RoutedEventArgs e) { e.Handled = BaseTypesEntryNode.ActivateItem(this, type); - } + }*/ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) { language.WriteCommentLine(output, language.TypeToString(type, includeNamespace: true)); } - IMetadataEntity IMemberTreeNode.Member => type; + IEntity IMemberTreeNode.Member => type; } } diff --git a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs index 9aa49c139..88f444ece 100644 --- a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs +++ b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs @@ -26,9 +26,9 @@ using ICSharpCode.Decompiler.Util; using SRM = System.Reflection.Metadata; namespace ICSharpCode.ILSpy.TreeNodes -{ +{/* /// - /// Lists the super types of a class. + /// Lists the sub types of a class. /// sealed class DerivedTypesTreeNode : ILSpyTreeNode { @@ -97,5 +97,5 @@ namespace ICSharpCode.ILSpy.TreeNodes { threading.Decompile(language, output, options, EnsureLazyChildren); } - } + }*/ } \ No newline at end of file diff --git a/ILSpy/TreeNodes/EventTreeNode.cs b/ILSpy/TreeNodes/EventTreeNode.cs index 87cd73280..16b3c23e6 100644 --- a/ILSpy/TreeNodes/EventTreeNode.cs +++ b/ILSpy/TreeNodes/EventTreeNode.cs @@ -23,6 +23,8 @@ using SRM = System.Reflection.Metadata; using System.Windows.Media; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; +using System.Reflection.Metadata; namespace ICSharpCode.ILSpy.TreeNodes { @@ -31,39 +33,34 @@ namespace ICSharpCode.ILSpy.TreeNodes /// public sealed class EventTreeNode : ILSpyTreeNode, IMemberTreeNode { - public EventTreeNode(EventDefinition ev) + public EventTreeNode(IEvent @event) { - if (ev.IsNil) - throw new ArgumentNullException(nameof(ev)); - this.EventDefinition = ev; - var metadata = ev.Module.Metadata; - var eventDefinition = metadata.GetEventDefinition(ev.Handle); - var accessors = eventDefinition.GetAccessors(); - if (!accessors.Adder.IsNil) - this.Children.Add(new MethodTreeNode(new MethodDefinition(ev.Module, accessors.Adder))); - if (!accessors.Remover.IsNil) - this.Children.Add(new MethodTreeNode(new MethodDefinition(ev.Module, accessors.Remover))); - if (!accessors.Raiser.IsNil) - this.Children.Add(new MethodTreeNode(new MethodDefinition(ev.Module, accessors.Raiser))); + this.EventDefinition = @event ?? throw new ArgumentNullException(nameof(@event)); + if (@event.CanAdd) + this.Children.Add(new MethodTreeNode(@event.AddAccessor)); + if (@event.CanRemove) + this.Children.Add(new MethodTreeNode(@event.RemoveAccessor)); + if (@event.CanInvoke) + this.Children.Add(new MethodTreeNode(@event.InvokeAccessor)); //foreach (var m in ev.OtherMethods) // this.Children.Add(new MethodTreeNode(m)); } - public EventDefinition EventDefinition { get; } + public IEvent EventDefinition { get; } - public override object Text => GetText(EventDefinition, this.Language) + EventDefinition.Handle.ToSuffixString(); + public override object Text => GetText(EventDefinition, this.Language) + EventDefinition.MetadataToken.ToSuffixString(); - public static object GetText(EventDefinition ev, Language language) + public static object GetText(IEvent ev, Language language) { return language.EventToString(ev, false, false); } public override object Icon => GetIcon(EventDefinition); - public static ImageSource GetIcon(EventDefinition @event) + public static ImageSource GetIcon(IEvent @event) { - var metadata = @event.Module.Metadata; - var accessor = metadata.GetEventDefinition(@event.Handle).GetAccessors().GetAny(); + var metadata = ((MetadataAssembly)@event.ParentAssembly).PEFile.Metadata; + var accessor = metadata.GetEventDefinition((EventDefinitionHandle)@event.MetadataToken).GetAccessors().GetAny(); if (!accessor.IsNil) { var accessorMethod = metadata.GetMethodDefinition(accessor); return Images.GetIcon(MemberIcon.Event, GetOverlayIcon(accessorMethod.Attributes), accessorMethod.HasFlag(MethodAttributes.Static)); @@ -97,8 +94,7 @@ namespace ICSharpCode.ILSpy.TreeNodes { if (!settings.ShowInternalApi && !IsPublicAPI) return FilterResult.Hidden; - var metadata = EventDefinition.Module.Metadata; - if (settings.SearchTermMatches(metadata.GetString(metadata.GetEventDefinition(EventDefinition.Handle).Name)) && settings.Language.ShowMember(EventDefinition)) + if (settings.SearchTermMatches(EventDefinition.Name) && settings.Language.ShowMember(EventDefinition)) return FilterResult.Match; else return FilterResult.Hidden; @@ -111,14 +107,10 @@ namespace ICSharpCode.ILSpy.TreeNodes public override bool IsPublicAPI { get { - var metadata = EventDefinition.Module.Metadata; - var accessor = metadata.GetEventDefinition(EventDefinition.Handle).GetAccessors().GetAny(); - if (accessor.IsNil) return false; - var accessorMethod = metadata.GetMethodDefinition(accessor); - switch (accessorMethod.Attributes & MethodAttributes.MemberAccessMask) { - case MethodAttributes.Public: - case MethodAttributes.FamORAssem: - case MethodAttributes.Family: + switch (EventDefinition.Accessibility) { + case Accessibility.Public: + case Accessibility.ProtectedOrInternal: + case Accessibility.Protected: return true; default: return false; @@ -126,6 +118,6 @@ namespace ICSharpCode.ILSpy.TreeNodes } } - IMetadataEntity IMemberTreeNode.Member => EventDefinition; + IEntity IMemberTreeNode.Member => EventDefinition; } } diff --git a/ILSpy/TreeNodes/FieldTreeNode.cs b/ILSpy/TreeNodes/FieldTreeNode.cs index 047b8fc0e..bcd577bb8 100644 --- a/ILSpy/TreeNodes/FieldTreeNode.cs +++ b/ILSpy/TreeNodes/FieldTreeNode.cs @@ -18,9 +18,11 @@ using System; using System.Reflection; +using System.Reflection.Metadata; using System.Windows.Media; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.Util; namespace ICSharpCode.ILSpy.TreeNodes @@ -30,28 +32,26 @@ namespace ICSharpCode.ILSpy.TreeNodes /// public sealed class FieldTreeNode : ILSpyTreeNode, IMemberTreeNode { - public FieldDefinition FieldDefinition { get; } + public IField FieldDefinition { get; } - public FieldTreeNode(FieldDefinition field) + public FieldTreeNode(IField field) { - if (field.IsNil) - throw new ArgumentNullException(nameof(field)); - this.FieldDefinition = field; + this.FieldDefinition = field ?? throw new ArgumentNullException(nameof(field)); } - public override object Text => GetText(FieldDefinition, Language) + FieldDefinition.Handle.ToSuffixString(); + public override object Text => GetText(FieldDefinition, Language) + FieldDefinition.MetadataToken.ToSuffixString(); - public static object GetText(FieldDefinition field, Language language) + public static object GetText(IField field, Language language) { return language.FieldToString(field, includeTypeName: false, includeNamespace: false); } public override object Icon => GetIcon(FieldDefinition); - public static ImageSource GetIcon(FieldDefinition field) + public static ImageSource GetIcon(IField field) { - var metadata = field.Module.Metadata; - var fieldDefinition = metadata.GetFieldDefinition(field.Handle); + var metadata = ((MetadataAssembly)field.ParentAssembly).PEFile.Metadata; + var fieldDefinition = metadata.GetFieldDefinition((FieldDefinitionHandle)field.MetadataToken); if (fieldDefinition.GetDeclaringType().IsEnum(metadata) && !fieldDefinition.HasFlag(FieldAttributes.SpecialName)) return Images.GetIcon(MemberIcon.EnumValue, GetOverlayIcon(fieldDefinition.Attributes), false); @@ -66,22 +66,9 @@ namespace ICSharpCode.ILSpy.TreeNodes return Images.GetIcon(MemberIcon.Field, GetOverlayIcon(fieldDefinition.Attributes), fieldDefinition.HasFlag(FieldAttributes.Static)); } - private static bool IsDecimalConstant(FieldDefinition field) + private static bool IsDecimalConstant(IField field) { - var metadata = field.Module.Metadata; - var fieldDefinition = metadata.GetFieldDefinition(field.Handle); - - var fieldType = fieldDefinition.DecodeSignature(new FullTypeNameSignatureDecoder(metadata), default(Unit)); - if (fieldType.ToString() == "System.Decimal") { - var attrs = fieldDefinition.GetCustomAttributes(); - foreach (var h in attrs) { - var attr = metadata.GetCustomAttribute(h); - var attrType = attr.GetAttributeType(metadata).GetFullTypeName(metadata); - if (attrType.ToString() == "System.Runtime.CompilerServices.DecimalConstantAttribute") - return true; - } - } - return false; + return field.IsConst && field.Type.IsKnownType(KnownTypeCode.Decimal) && field.ConstantValue != null; } private static AccessOverlayIcon GetOverlayIcon(FieldAttributes fieldAttributes) @@ -110,9 +97,7 @@ namespace ICSharpCode.ILSpy.TreeNodes { if (!settings.ShowInternalApi && !IsPublicAPI) return FilterResult.Hidden; - var metadata = FieldDefinition.Module.Metadata; - var fieldDefinition = metadata.GetFieldDefinition(FieldDefinition.Handle); - if (settings.SearchTermMatches(metadata.GetString(fieldDefinition.Name)) && settings.Language.ShowMember(FieldDefinition)) + if (settings.SearchTermMatches(FieldDefinition.Name) && settings.Language.ShowMember(FieldDefinition)) return FilterResult.Match; else return FilterResult.Hidden; @@ -125,13 +110,10 @@ namespace ICSharpCode.ILSpy.TreeNodes public override bool IsPublicAPI { get { - var metadata = FieldDefinition.Module.Metadata; - var fieldDefinition = metadata.GetFieldDefinition(FieldDefinition.Handle); - - switch (fieldDefinition.Attributes & FieldAttributes.FieldAccessMask) { - case FieldAttributes.Public: - case FieldAttributes.FamORAssem: - case FieldAttributes.Family: + switch (FieldDefinition.Accessibility) { + case Accessibility.Public: + case Accessibility.Protected: + case Accessibility.ProtectedOrInternal: return true; default: return false; @@ -139,6 +121,6 @@ namespace ICSharpCode.ILSpy.TreeNodes } } - IMetadataEntity IMemberTreeNode.Member => FieldDefinition; + IEntity IMemberTreeNode.Member => FieldDefinition; } } diff --git a/ILSpy/TreeNodes/IMemberTreeNode.cs b/ILSpy/TreeNodes/IMemberTreeNode.cs index bce6aa376..dc012cbba 100644 --- a/ILSpy/TreeNodes/IMemberTreeNode.cs +++ b/ILSpy/TreeNodes/IMemberTreeNode.cs @@ -16,17 +16,17 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.ILSpy.TreeNodes { /// /// Interface implemented by all tree nodes /// (both in main tree view and in analyzer) - /// that represent Cecil members. + /// that represent TypeSystem members. /// public interface IMemberTreeNode { - IMetadataEntity Member { get; } + IEntity Member { get; } } } diff --git a/ILSpy/TreeNodes/MethodTreeNode.cs b/ILSpy/TreeNodes/MethodTreeNode.cs index 8660a6741..1f7f2018d 100644 --- a/ILSpy/TreeNodes/MethodTreeNode.cs +++ b/ILSpy/TreeNodes/MethodTreeNode.cs @@ -20,11 +20,13 @@ using System; using System.Collections.Immutable; using System.Linq; using System.Reflection; +using System.Reflection.Metadata; using System.Text; using System.Windows.Media; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; using SRM = System.Reflection.Metadata; namespace ICSharpCode.ILSpy.TreeNodes @@ -34,30 +36,26 @@ namespace ICSharpCode.ILSpy.TreeNodes /// public sealed class MethodTreeNode : ILSpyTreeNode, IMemberTreeNode { - public MethodDefinition MethodDefinition { get; } - SRM.MethodDefinition md; + public IMethod MethodDefinition { get; } - public MethodTreeNode(MethodDefinition method) + public MethodTreeNode(IMethod method) { - if (method.IsNil) - throw new ArgumentNullException(nameof(method)); - this.MethodDefinition = method; - this.md = method.Module.Metadata.GetMethodDefinition(method.Handle); + this.MethodDefinition = method ?? throw new ArgumentNullException(nameof(method)); } - public override object Text => GetText(MethodDefinition, Language) + MethodDefinition.Handle.ToSuffixString(); + public override object Text => GetText(MethodDefinition, Language) + MethodDefinition.MetadataToken.ToSuffixString(); - public static object GetText(MethodDefinition method, Language language) + public static object GetText(IMethod method, Language language) { return language.MethodToString(method, false, false); } public override object Icon => GetIcon(MethodDefinition); - public static ImageSource GetIcon(MethodDefinition method) + public static ImageSource GetIcon(IMethod method) { - var metadata = method.Module.Metadata; - var methodDefinition = metadata.GetMethodDefinition(method.Handle); + var metadata = ((MetadataAssembly)method.ParentAssembly).PEFile.Metadata; + var methodDefinition = metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken); var methodName = metadata.GetString(methodDefinition.Name); if (methodDefinition.HasFlag(MethodAttributes.SpecialName) && methodName.StartsWith("op_", StringComparison.Ordinal)) { return Images.GetIcon(MemberIcon.Operator, GetOverlayIcon(methodDefinition.Attributes), false); @@ -116,8 +114,7 @@ namespace ICSharpCode.ILSpy.TreeNodes { if (!settings.ShowInternalApi && !IsPublicAPI) return FilterResult.Hidden; - var metadata = MethodDefinition.Module.Metadata; - if (settings.SearchTermMatches(metadata.GetString(md.Name)) && settings.Language.ShowMember(MethodDefinition)) + if (settings.SearchTermMatches(MethodDefinition.Name) && settings.Language.ShowMember(MethodDefinition)) return FilterResult.Match; else return FilterResult.Hidden; @@ -125,10 +122,10 @@ namespace ICSharpCode.ILSpy.TreeNodes public override bool IsPublicAPI { get { - switch (md.Attributes & MethodAttributes.MemberAccessMask) { - case MethodAttributes.Public: - case MethodAttributes.Family: - case MethodAttributes.FamORAssem: + switch (MethodDefinition.Accessibility) { + case Accessibility.Public: + case Accessibility.Protected: + case Accessibility.ProtectedOrInternal: return true; default: return false; @@ -136,6 +133,6 @@ namespace ICSharpCode.ILSpy.TreeNodes } } - IMetadataEntity IMemberTreeNode.Member => MethodDefinition; + IEntity IMemberTreeNode.Member => MethodDefinition; } } diff --git a/ILSpy/TreeNodes/PropertyTreeNode.cs b/ILSpy/TreeNodes/PropertyTreeNode.cs index 9bbb35d2c..174769c85 100644 --- a/ILSpy/TreeNodes/PropertyTreeNode.cs +++ b/ILSpy/TreeNodes/PropertyTreeNode.cs @@ -18,10 +18,11 @@ using System; using System.Reflection; +using System.Reflection.Metadata; using System.Windows.Media; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; - +using ICSharpCode.Decompiler.TypeSystem; using SRM = System.Reflection.Metadata; namespace ICSharpCode.ILSpy.TreeNodes @@ -33,38 +34,31 @@ namespace ICSharpCode.ILSpy.TreeNodes { readonly bool isIndexer; - public PropertyTreeNode(PropertyDefinition property) + public PropertyTreeNode(IProperty property) { - if (property == null) - throw new ArgumentNullException(nameof(property)); - this.PropertyDefinition = property; - var metadata = property.Module.Metadata; - var propertyDefinition = metadata.GetPropertyDefinition(property.Handle); - var accessors = propertyDefinition.GetAccessors(); - using (LoadedAssembly.DisableAssemblyLoad()) { - this.isIndexer = property.Handle.HasMatchingDefaultMemberAttribute(property.Module, out _); - } + this.PropertyDefinition = property ?? throw new ArgumentNullException(nameof(property)); + this.isIndexer = property.IsIndexer; - if (!accessors.Getter.IsNil) - this.Children.Add(new MethodTreeNode(new MethodDefinition(property.Module, accessors.Getter))); - if (!accessors.Setter.IsNil) - this.Children.Add(new MethodTreeNode(new MethodDefinition(property.Module, accessors.Setter))); + if (property.CanGet) + this.Children.Add(new MethodTreeNode(property.Getter)); + if (property.CanSet) + this.Children.Add(new MethodTreeNode(property.Setter)); /*foreach (var m in property.OtherMethods) this.Children.Add(new MethodTreeNode(m));*/ } - public PropertyDefinition PropertyDefinition { get; } + public IProperty PropertyDefinition { get; } - public override object Text => GetText(PropertyDefinition, Language, isIndexer) + PropertyDefinition.Handle.ToSuffixString(); + public override object Text => GetText(PropertyDefinition, Language, isIndexer) + PropertyDefinition.MetadataToken.ToSuffixString(); - public static object GetText(PropertyDefinition property, Language language, bool? isIndexer = null) + public static object GetText(IProperty property, Language language, bool? isIndexer = null) { return language.PropertyToString(property, false, false, isIndexer); } public override object Icon => GetIcon(PropertyDefinition); - public static ImageSource GetIcon(PropertyDefinition property, bool isIndexer = false) + public static ImageSource GetIcon(IProperty property, bool isIndexer = false) { MemberIcon icon = isIndexer ? MemberIcon.Indexer : MemberIcon.Property; MethodAttributes attributesOfMostAccessibleMethod = GetAttributesOfMostAccessibleMethod(property); @@ -94,7 +88,7 @@ namespace ICSharpCode.ILSpy.TreeNodes } } - private static MethodAttributes GetAttributesOfMostAccessibleMethod(PropertyDefinition property) + private static MethodAttributes GetAttributesOfMostAccessibleMethod(IProperty property) { // There should always be at least one method from which to // obtain the result, but the compiler doesn't know this so @@ -105,8 +99,8 @@ namespace ICSharpCode.ILSpy.TreeNodes // in numeric order, so we can do an integer comparison of the masked attribute int accessLevel = 0; - var metadata = property.Module.Metadata; - var propertyDefinition = metadata.GetPropertyDefinition(property.Handle); + var metadata = ((MetadataAssembly)property.ParentAssembly).PEFile.Metadata; + var propertyDefinition = metadata.GetPropertyDefinition((PropertyDefinitionHandle)property.MetadataToken); var accessors = propertyDefinition.GetAccessors(); if (!accessors.Getter.IsNil) { @@ -142,9 +136,7 @@ namespace ICSharpCode.ILSpy.TreeNodes { if (!settings.ShowInternalApi && !IsPublicAPI) return FilterResult.Hidden; - var metadata = PropertyDefinition.Module.Metadata; - var propertyDefinition = metadata.GetPropertyDefinition(PropertyDefinition.Handle); - if (settings.SearchTermMatches(metadata.GetString(propertyDefinition.Name)) && settings.Language.ShowMember(PropertyDefinition)) + if (settings.SearchTermMatches(PropertyDefinition.Name) && settings.Language.ShowMember(PropertyDefinition)) return FilterResult.Match; else return FilterResult.Hidden; @@ -168,6 +160,6 @@ namespace ICSharpCode.ILSpy.TreeNodes } } - IMetadataEntity IMemberTreeNode.Member => PropertyDefinition; + IEntity IMemberTreeNode.Member => PropertyDefinition; } } diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs index 8ea0910f0..d4d6f95db 100644 --- a/ILSpy/TreeNodes/TypeTreeNode.cs +++ b/ILSpy/TreeNodes/TypeTreeNode.cs @@ -22,39 +22,32 @@ using System.Reflection; using System.Windows.Media; using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.Metadata; - +using ICSharpCode.Decompiler.TypeSystem; using SRM = System.Reflection.Metadata; namespace ICSharpCode.ILSpy.TreeNodes { public sealed class TypeTreeNode : ILSpyTreeNode, IMemberTreeNode { - readonly SRM.TypeDefinition td; - - public TypeTreeNode(TypeDefinition typeDefinition, AssemblyTreeNode parentAssemblyNode) + public TypeTreeNode(ITypeDefinition typeDefinition, AssemblyTreeNode parentAssemblyNode) { - if (typeDefinition.IsNil) - throw new ArgumentNullException(nameof(typeDefinition)); this.ParentAssemblyNode = parentAssemblyNode ?? throw new ArgumentNullException(nameof(parentAssemblyNode)); - this.TypeDefinition = typeDefinition; - this.td = typeDefinition.Module.Metadata.GetTypeDefinition(typeDefinition.Handle); + this.TypeDefinition = typeDefinition ?? throw new ArgumentNullException(nameof(typeDefinition)); this.LazyLoading = true; } - public TypeDefinition TypeDefinition { get; } + public ITypeDefinition TypeDefinition { get; } public AssemblyTreeNode ParentAssemblyNode { get; } - public override object Text => this.Language.TypeToString(TypeDefinition, includeNamespace: false) + TypeDefinition.Handle.ToSuffixString(); + public override object Text => this.Language.TypeToString(TypeDefinition, includeNamespace: false) + TypeDefinition.MetadataToken.ToSuffixString(); public override bool IsPublicAPI { get { - switch (td.Attributes & TypeAttributes.VisibilityMask) { - case TypeAttributes.Public: - case TypeAttributes.NestedPublic: - case TypeAttributes.NestedFamily: - case TypeAttributes.NestedFamORAssem: + switch (TypeDefinition.Accessibility) { + case Accessibility.Public: + case Accessibility.Protected: + case Accessibility.ProtectedOrInternal: return true; default: return false; @@ -66,7 +59,7 @@ namespace ICSharpCode.ILSpy.TreeNodes { if (!settings.ShowInternalApi && !IsPublicAPI) return FilterResult.Hidden; - if (settings.SearchTermMatches(TypeDefinition.Module.Metadata.GetString(td.Name))) { + if (settings.SearchTermMatches(TypeDefinition.Name)) { if (settings.Language.ShowMember(TypeDefinition)) return FilterResult.Match; else @@ -78,28 +71,25 @@ namespace ICSharpCode.ILSpy.TreeNodes protected override void LoadChildren() { - var metadata = TypeDefinition.Module.Metadata; - if (!td.BaseType.IsNil || td.GetInterfaceImplementations().Any()) - this.Children.Add(new BaseTypesTreeNode(TypeDefinition)); - if (!td.HasFlag(TypeAttributes.Sealed)) - this.Children.Add(new DerivedTypesTreeNode(ParentAssemblyNode.AssemblyList, TypeDefinition)); - foreach (var nestedType in td.GetNestedTypes().OrderBy(m => metadata.GetString(metadata.GetTypeDefinition(m).Name), NaturalStringComparer.Instance)) { - this.Children.Add(new TypeTreeNode(new TypeDefinition(TypeDefinition.Module, nestedType), ParentAssemblyNode)); + if (!TypeDefinition.DirectBaseTypes.Any()) + this.Children.Add(new BaseTypesTreeNode(ParentAssemblyNode.LoadedAssembly.GetPEFileOrNull(), TypeDefinition)); + /*if (!TypeDefinition.IsSealed) + this.Children.Add(new DerivedTypesTreeNode(ParentAssemblyNode.AssemblyList, TypeDefinition));*/ + foreach (var nestedType in TypeDefinition.NestedTypes.OrderBy(t => t.Name, NaturalStringComparer.Instance)) { + this.Children.Add(new TypeTreeNode(nestedType, ParentAssemblyNode)); } - foreach (var field in td.GetFields().OrderBy(m => metadata.GetString(metadata.GetFieldDefinition(m).Name), NaturalStringComparer.Instance)) { - this.Children.Add(new FieldTreeNode(new FieldDefinition(TypeDefinition.Module, field))); + foreach (var field in TypeDefinition.Fields.OrderBy(f => f.Name, NaturalStringComparer.Instance)) { + this.Children.Add(new FieldTreeNode(field)); } - foreach (var property in td.GetProperties().OrderBy(m => metadata.GetString(metadata.GetPropertyDefinition(m).Name), NaturalStringComparer.Instance)) { - this.Children.Add(new PropertyTreeNode(new PropertyDefinition(TypeDefinition.Module, property))); + foreach (var property in TypeDefinition.Properties.OrderBy(p => p.Name, NaturalStringComparer.Instance)) { + this.Children.Add(new PropertyTreeNode(property)); } - foreach (var ev in td.GetEvents().OrderBy(m => metadata.GetString(metadata.GetEventDefinition(m).Name), NaturalStringComparer.Instance)) { - this.Children.Add(new EventTreeNode(new EventDefinition(TypeDefinition.Module, ev))); + foreach (var ev in TypeDefinition.Events.OrderBy(e => e.Name, NaturalStringComparer.Instance)) { + this.Children.Add(new EventTreeNode(ev)); } - foreach (var method in td.GetMethods().OrderBy(m => metadata.GetString(metadata.GetMethodDefinition(m).Name), NaturalStringComparer.Instance)) { - if (method.GetMethodSemanticsAttributes(metadata) == 0) { - this.Children.Add(new MethodTreeNode(new MethodDefinition(TypeDefinition.Module, method))); - } + foreach (var method in TypeDefinition.Methods.OrderBy(m => m.Name, NaturalStringComparer.Instance)) { + this.Children.Add(new MethodTreeNode(method)); } } @@ -112,7 +102,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public override object Icon => GetIcon(TypeDefinition); - public static ImageSource GetIcon(TypeDefinition type) + public static ImageSource GetIcon(ITypeDefinition type) { TypeIcon typeIcon = GetTypeIcon(type); AccessOverlayIcon overlayIcon = GetOverlayIcon(type); @@ -120,48 +110,42 @@ namespace ICSharpCode.ILSpy.TreeNodes return Images.GetIcon(typeIcon, overlayIcon); } - static TypeIcon GetTypeIcon(TypeDefinition type) + internal static TypeIcon GetTypeIcon(IType type) { - var metadata = type.Module.Metadata; - var typeDefinition = metadata.GetTypeDefinition(type.Handle); - if (typeDefinition.IsValueType(metadata)) { - if (typeDefinition.IsEnum(metadata)) - return TypeIcon.Enum; - else - return TypeIcon.Struct; - } else { - if ((typeDefinition.Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface) + switch (type.Kind) { + case TypeKind.Interface: return TypeIcon.Interface; - else if (typeDefinition.IsDelegate(metadata)) + case TypeKind.Struct: + return TypeIcon.Struct; + case TypeKind.Delegate: return TypeIcon.Delegate; - else if (IsStaticClass(typeDefinition)) - return TypeIcon.StaticClass; - else + case TypeKind.Enum: + return TypeIcon.Enum; + default: + if (type.GetDefinition()?.IsStatic == true) + return TypeIcon.StaticClass; return TypeIcon.Class; } } - private static AccessOverlayIcon GetOverlayIcon(TypeDefinition type) + private static AccessOverlayIcon GetOverlayIcon(ITypeDefinition type) { - var def = type.Module.Metadata.GetTypeDefinition(type.Handle); AccessOverlayIcon overlay; - switch (def.Attributes & TypeAttributes.VisibilityMask) { - case TypeAttributes.Public: - case TypeAttributes.NestedPublic: + switch (type.Accessibility) { + case Accessibility.Public: overlay = AccessOverlayIcon.Public; break; - case TypeAttributes.NotPublic: - case TypeAttributes.NestedAssembly: + case Accessibility.Internal: overlay = AccessOverlayIcon.Internal; break; - case TypeAttributes.NestedFamANDAssem: + case Accessibility.ProtectedAndInternal: overlay = AccessOverlayIcon.PrivateProtected; break; - case TypeAttributes.NestedFamily: - case TypeAttributes.NestedFamORAssem: + case Accessibility.Protected: + case Accessibility.ProtectedOrInternal: overlay = AccessOverlayIcon.Protected; break; - case TypeAttributes.NestedPrivate: + case Accessibility.Private: overlay = AccessOverlayIcon.Private; break; default: @@ -170,11 +154,6 @@ namespace ICSharpCode.ILSpy.TreeNodes return overlay; } - static bool IsStaticClass(SRM.TypeDefinition type) - { - return type.HasFlag(TypeAttributes.Sealed) && type.HasFlag(TypeAttributes.Abstract); - } - - IMetadataEntity IMemberTreeNode.Member => TypeDefinition; + IEntity IMemberTreeNode.Member => TypeDefinition; } } diff --git a/TestPlugin/CustomLanguage.cs b/TestPlugin/CustomLanguage.cs index cf5e1bdf1..17b60319c 100644 --- a/TestPlugin/CustomLanguage.cs +++ b/TestPlugin/CustomLanguage.cs @@ -6,6 +6,7 @@ using System.Reflection.Metadata; using System.Windows.Controls; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpy; namespace TestPlugin @@ -30,12 +31,12 @@ namespace TestPlugin } // There are several methods available to override; in this sample, we deal with methods only - public override void DecompileMethod(ICSharpCode.Decompiler.Metadata.MethodDefinition method, ITextOutput output, DecompilationOptions options) + public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) { - var metadata = method.Module.Metadata; - var methodDef = metadata.GetMethodDefinition(method.Handle); + var module = ((MetadataAssembly)method.ParentAssembly).PEFile; + var methodDef = module.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken); if (methodDef.HasBody()) { - var methodBody = method.Module.Reader.GetMethodBody(methodDef.RelativeVirtualAddress); + var methodBody = module.Reader.GetMethodBody(methodDef.RelativeVirtualAddress); output.WriteLine("Size of method: {0} bytes", methodBody.GetCodeSize()); ISmartTextOutput smartOutput = output as ISmartTextOutput; From bcfb3742eb1844548fd12bc8d5666827d10427a0 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 7 Jul 2018 18:22:53 +0200 Subject: [PATCH 02/13] Clean up PEFile, move Pdb related types to DebugInfo namespace --- .../MonoCecilDebugInfoProvider.cs | 4 +- .../Helpers/Tester.cs | 13 +- .../RoundtripAssembly.cs | 5 +- .../CSharp/CSharpDecompiler.cs | 45 ++-- .../CSharp/SequencePointBuilder.cs | 16 +- .../CSharp/WholeProjectDecompiler.cs | 9 +- .../DebugInfo/IDebugInfoProvider.cs | 19 ++ .../{Pdb => DebugInfo}/PortablePdbWriter.cs | 6 +- .../{Metadata => DebugInfo}/SequencePoint.cs | 2 +- .../Disassembler/MethodBodyDisassembler.cs | 15 +- .../Disassembler/ReflectionDisassembler.cs | 125 +++++----- .../Documentation/XmlDocumentationProvider.cs | 20 +- .../ICSharpCode.Decompiler.csproj | 5 +- .../IL/ControlFlow/YieldReturnDecompiler.cs | 6 +- ICSharpCode.Decompiler/IL/ILReader.cs | 8 +- .../IL/Transforms/DelegateConstruction.cs | 5 +- .../IL/Transforms/IILTransform.cs | 16 +- .../IL/Transforms/ProxyCallReplacer.cs | 18 +- ICSharpCode.Decompiler/Metadata/Dom.cs | 17 -- .../Metadata/MetadataResolver.cs | 14 +- ICSharpCode.Decompiler/Metadata/PEFile.cs | 19 +- .../Metadata/UniversalAssemblyResolver.cs | 2 +- .../TypeSystem/DecompilerTypeSystem.cs | 12 +- .../TypeSystem/IAssembly.cs | 6 + .../DefaultUnresolvedAssembly.cs | 2 + .../TypeSystem/MetadataAssembly.cs | 3 +- ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs | 4 +- ILSpy.BamlDecompiler/BamlResourceEntryNode.cs | 14 +- .../BamlResourceNodeFactory.cs | 2 +- ILSpy.BamlDecompiler/CecilTypeResolver.cs | 7 +- .../ConnectMethodDecompiler.cs | 8 +- .../DiaSymNativeDebugInfoProvider.cs | 9 +- ILSpy/DebugInfo/PortableDebugInfoProvider.cs | 7 +- ILSpy/ILSpy.csproj | 2 + ILSpy/Languages/CSharpLanguage.cs | 215 ++++++------------ ILSpy/LoadedAssembly.cs | 39 +++- ILSpy/LoadedAssemblyExtensions.cs | 25 ++ ILSpy/SearchPane.cs | 2 +- .../Analyzer/ScopedWhereUsedAnalyzer.cs | 6 +- ILSpy/TreeNodes/AssemblyTreeNode.cs | 2 +- ILSpy/TreeNodes/BaseTypesEntryNode.cs | 8 +- .../TreeNodes/GeneratePdbContextMenuEntry.cs | 4 +- 42 files changed, 412 insertions(+), 354 deletions(-) create mode 100644 ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs rename ICSharpCode.Decompiler/{Pdb => DebugInfo}/PortablePdbWriter.cs (98%) rename ICSharpCode.Decompiler/{Metadata => DebugInfo}/SequencePoint.cs (97%) create mode 100644 ILSpy/LoadedAssemblyExtensions.cs diff --git a/ICSharpCode.Decompiler.PdbProvider.Cecil/MonoCecilDebugInfoProvider.cs b/ICSharpCode.Decompiler.PdbProvider.Cecil/MonoCecilDebugInfoProvider.cs index 3b8f324b6..7cdef4c9a 100644 --- a/ICSharpCode.Decompiler.PdbProvider.Cecil/MonoCecilDebugInfoProvider.cs +++ b/ICSharpCode.Decompiler.PdbProvider.Cecil/MonoCecilDebugInfoProvider.cs @@ -20,7 +20,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection.Metadata.Ecma335; -using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.Util; using Mono.Cecil; @@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.PdbProvider.Cecil var method = this.module.LookupToken(MetadataTokens.GetToken(handle)) as Mono.Cecil.MethodDefinition; if (method?.DebugInformation == null || !method.DebugInformation.HasSequencePoints) return EmptyList.Instance; - return method.DebugInformation.SequencePoints.Select(point => new Metadata.SequencePoint { + return method.DebugInformation.SequencePoints.Select(point => new SequencePoint { Offset = point.Offset, StartLine = point.StartLine, StartColumn = point.StartColumn, diff --git a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs index 567a8427b..72d329a5b 100644 --- a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs +++ b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs @@ -348,8 +348,9 @@ namespace ICSharpCode.Decompiler.Tests.Helpers var emitResult = compilation.Emit(peStream); peStream.Position = 0; - var moduleDefinition = new PEFile("TestAssembly.dll", peStream, false, PEStreamOptions.PrefetchEntireImage); - var decompiler = new CSharpDecompiler(moduleDefinition, new DecompilerSettings()); + var moduleDefinition = new PEFile("TestAssembly.dll", peStream, PEStreamOptions.PrefetchEntireImage); + var resolver = new UniversalAssemblyResolver("TestAssembly.dll", false, moduleDefinition.Reader.DetectTargetFrameworkId(), PEStreamOptions.PrefetchEntireImage); + var decompiler = new CSharpDecompiler(moduleDefinition, resolver, new DecompilerSettings()); return decompiler; } @@ -394,9 +395,11 @@ namespace ICSharpCode.Decompiler.Tests.Helpers public static string DecompileCSharp(string assemblyFileName, DecompilerSettings settings = null) { using (var file = new FileStream(assemblyFileName, FileMode.Open, FileAccess.Read)) { - var module = new PEFile(assemblyFileName, file, false, PEStreamOptions.PrefetchEntireImage); - var typeSystem = new DecompilerTypeSystem(module); - CSharpDecompiler decompiler = new CSharpDecompiler(typeSystem, settings ?? new DecompilerSettings()); + var module = new PEFile(assemblyFileName, file, PEStreamOptions.PrefetchEntireImage); + var resolver = new UniversalAssemblyResolver(assemblyFileName, false, + module.Reader.DetectTargetFrameworkId(), PEStreamOptions.PrefetchMetadata); + var typeSystem = new DecompilerTypeSystem(module, resolver); + CSharpDecompiler decompiler = new CSharpDecompiler(typeSystem, resolver, settings ?? new DecompilerSettings()); decompiler.AstTransforms.Insert(0, new RemoveEmbeddedAtttributes()); decompiler.AstTransforms.Insert(0, new RemoveCompilerAttribute()); decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers()); diff --git a/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs b/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs index c061e54d4..a56c40496 100644 --- a/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs +++ b/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs @@ -144,11 +144,12 @@ namespace ICSharpCode.Decompiler.Tests Console.WriteLine($"Decompiling {fileToRoundtrip}..."); Stopwatch w = Stopwatch.StartNew(); using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read)) { - PEFile module = new PEFile(file, fileStream, false, PEStreamOptions.PrefetchEntireImage); - UniversalAssemblyResolver resolver = (UniversalAssemblyResolver)module.AssemblyResolver; + PEFile module = new PEFile(file, fileStream, PEStreamOptions.PrefetchEntireImage); + UniversalAssemblyResolver resolver = new UniversalAssemblyResolver(file, false, module.Reader.DetectTargetFrameworkId(), PEStreamOptions.PrefetchMetadata); resolver.AddSearchDirectory(inputDir); resolver.RemoveSearchDirectory("."); var decompiler = new TestProjectDecompiler(inputDir); + decompiler.AssemblyResolver = resolver; // use a fixed GUID so that we can diff the output between different ILSpy runs without spurious changes decompiler.ProjectGuid = Guid.Parse("{127C83E4-4587-4CF9-ADCA-799875F3DFE6}"); decompiler.DecompileProject(module, decompiledDir); diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 24f460238..a3dfe539f 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -39,6 +39,8 @@ using System.Reflection.Metadata; using SRM = System.Reflection.Metadata; using ICSharpCode.Decompiler.Metadata; using System.Reflection.PortableExecutable; +using ICSharpCode.Decompiler.Documentation; +using ICSharpCode.Decompiler.DebugInfo; namespace ICSharpCode.Decompiler.CSharp { @@ -179,6 +181,18 @@ namespace ICSharpCode.Decompiler.CSharp public IDecompilerTypeSystem TypeSystem => typeSystem; + public IAssemblyResolver AssemblyResolver { get; } + + /// + /// Gets or sets the optional provider for debug info. + /// + public IDebugInfoProvider DebugInfoProvider { get; set; } + + /// + /// Gets or sets the optional provider for XML documentation strings. + /// + public IDocumentationProvider DocumentationProvider { get; set; } + /// /// IL transforms. /// @@ -193,21 +207,20 @@ namespace ICSharpCode.Decompiler.CSharp get { return astTransforms; } } - public CSharpDecompiler(string fileName, DecompilerSettings settings) - : this(LoadPEFile(fileName, settings), settings) + public CSharpDecompiler(string fileName, IAssemblyResolver assemblyResolver, DecompilerSettings settings) + : this(LoadPEFile(fileName, settings), assemblyResolver, settings) { } - public CSharpDecompiler(Metadata.PEFile module, DecompilerSettings settings) - : this(new DecompilerTypeSystem(module, settings), settings) + public CSharpDecompiler(PEFile module, IAssemblyResolver assemblyResolver, DecompilerSettings settings) + : this(new DecompilerTypeSystem(module, assemblyResolver, settings), assemblyResolver, settings) { } - public CSharpDecompiler(DecompilerTypeSystem typeSystem, DecompilerSettings settings) + public CSharpDecompiler(DecompilerTypeSystem typeSystem, IAssemblyResolver assemblyResolver, DecompilerSettings settings) { - if (typeSystem == null) - throw new ArgumentNullException(nameof(typeSystem)); - this.typeSystem = typeSystem; + this.typeSystem = typeSystem ?? throw new ArgumentNullException(nameof(typeSystem)); + this.AssemblyResolver = assemblyResolver ?? throw new ArgumentNullException(nameof(assemblyResolver)); this.settings = settings; } @@ -318,7 +331,6 @@ namespace ICSharpCode.Decompiler.CSharp return new PEFile( fileName, new FileStream(fileName, FileMode.Open, FileAccess.Read), - settings.ThrowOnAssemblyResolveErrors, options: settings.LoadInMemory ? PEStreamOptions.PrefetchEntireImage : PEStreamOptions.Default ); } @@ -436,7 +448,7 @@ namespace ICSharpCode.Decompiler.CSharp { var decompileRun = new DecompileRun(settings) { CancellationToken = CancellationToken }; RequiredNamespaceCollector.CollectNamespaces(function.Method, typeSystem, decompileRun.Namespaces); - return new ILTransformContext(function, typeSystem, settings) { + return new ILTransformContext(function, typeSystem, DebugInfoProvider, settings) { CancellationToken = CancellationToken, DecompileRun = decompileRun }; @@ -887,10 +899,13 @@ namespace ICSharpCode.Decompiler.CSharp { try { var specializingTypeSystem = typeSystem.GetSpecializingTypeSystem(decompilationContext); - var ilReader = new ILReader(specializingTypeSystem); - ilReader.UseDebugSymbols = settings.UseDebugSymbols; + var ilReader = new ILReader(specializingTypeSystem) { + UseDebugSymbols = settings.UseDebugSymbols, + DebugInfo = DebugInfoProvider + }; var methodDef = typeSystem.ModuleDefinition.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken); - var function = ilReader.ReadIL(typeSystem.ModuleDefinition, (MethodDefinitionHandle)method.MetadataToken, typeSystem.ModuleDefinition.Reader.GetMethodBody(methodDef.RelativeVirtualAddress), CancellationToken); + var methodBody = typeSystem.ModuleDefinition.Reader.GetMethodBody(methodDef.RelativeVirtualAddress); + var function = ilReader.ReadIL(typeSystem.ModuleDefinition, (MethodDefinitionHandle)method.MetadataToken, methodBody, CancellationToken); function.CheckInvariant(ILPhase.Normal); if (entityDecl != null) { @@ -911,7 +926,7 @@ namespace ICSharpCode.Decompiler.CSharp localSettings.AlwaysCastTargetsOfExplicitInterfaceImplementationCalls = true; } - var context = new ILTransformContext(function, specializingTypeSystem, localSettings) { + var context = new ILTransformContext(function, specializingTypeSystem, DebugInfoProvider, localSettings) { CancellationToken = CancellationToken, DecompileRun = decompileRun }; @@ -1126,7 +1141,7 @@ namespace ICSharpCode.Decompiler.CSharp /// /// This only works correctly when the nodes in the syntax tree have line/column information. /// - public Dictionary> CreateSequencePoints(SyntaxTree syntaxTree) + public Dictionary> CreateSequencePoints(SyntaxTree syntaxTree) { SequencePointBuilder spb = new SequencePointBuilder(); syntaxTree.AcceptVisitor(spb); diff --git a/ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs b/ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs index b036f7985..5ad23f4e3 100644 --- a/ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs @@ -56,7 +56,7 @@ namespace ICSharpCode.Decompiler.CSharp } } - readonly List<(ILFunction, Metadata.SequencePoint)> sequencePoints = new List<(ILFunction, Metadata.SequencePoint)>(); + readonly List<(ILFunction, DebugInfo.SequencePoint)> sequencePoints = new List<(ILFunction, DebugInfo.SequencePoint)>(); readonly HashSet mappedInstructions = new HashSet(); // Stack holding information for outer statements. @@ -219,7 +219,7 @@ namespace ICSharpCode.Decompiler.CSharp // use LongSet to deduplicate and merge the intervals var longSet = new LongSet(current.Intervals.Select(i => new LongInterval(i.Start, i.End))); Debug.Assert(!longSet.IsEmpty); - sequencePoints.Add((current.Function, new Metadata.SequencePoint { + sequencePoints.Add((current.Function, new DebugInfo.SequencePoint { Offset = (int)longSet.Intervals[0].Start, EndOffset = (int)longSet.Intervals[0].End, StartLine = startLocation.Line, @@ -277,18 +277,18 @@ namespace ICSharpCode.Decompiler.CSharp /// /// Called after the visitor is done to return the results. /// - internal Dictionary> GetSequencePoints() + internal Dictionary> GetSequencePoints() { - var dict = new Dictionary>(); + var dict = new Dictionary>(); foreach (var (function, sequencePoint) in this.sequencePoints) { if (!dict.TryGetValue(function, out var list)) { - dict.Add(function, list = new List()); + dict.Add(function, list = new List()); } list.Add(sequencePoint); } foreach (var (function, list) in dict.ToList()) { // For each function, sort sequence points and fix overlaps+gaps - var newList = new List(); + var newList = new List(); int pos = 0; foreach (var sequencePoint in list.OrderBy(sp => sp.Offset).ThenBy(sp => sp.EndOffset)) { if (sequencePoint.Offset < pos) { @@ -305,7 +305,7 @@ namespace ICSharpCode.Decompiler.CSharp } } else if (sequencePoint.Offset > pos) { // insert hidden sequence point in the gap. - var hidden = new Metadata.SequencePoint(); + var hidden = new DebugInfo.SequencePoint(); hidden.Offset = pos; hidden.EndOffset = sequencePoint.Offset; hidden.SetHidden(); @@ -315,7 +315,7 @@ namespace ICSharpCode.Decompiler.CSharp pos = sequencePoint.EndOffset; } if (pos < function.CodeSize) { - var hidden = new Metadata.SequencePoint(); + var hidden = new DebugInfo.SequencePoint(); hidden.Offset = pos; hidden.EndOffset = function.CodeSize; hidden.SetHidden(); diff --git a/ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs b/ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs index 74c639267..25c4aa3e6 100644 --- a/ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs @@ -34,6 +34,7 @@ using System.Reflection.PortableExecutable; using System.Reflection.Metadata; using static ICSharpCode.Decompiler.Metadata.DotNetCorePathFinderExtensions; using static ICSharpCode.Decompiler.Metadata.MetadataExtensions; +using ICSharpCode.Decompiler.Metadata; namespace ICSharpCode.Decompiler.CSharp { @@ -56,6 +57,8 @@ namespace ICSharpCode.Decompiler.CSharp } } + public IAssemblyResolver AssemblyResolver { get; set; } + /// /// The MSBuild ProjectGuid to use for the new project. /// null to automatically generate a new GUID. @@ -218,7 +221,7 @@ namespace ICSharpCode.Decompiler.CSharp if (r.Name != "mscorlib") { w.WriteStartElement("Reference"); w.WriteAttributeString("Include", r.Name); - var asm = module.AssemblyResolver.Resolve(r); + var asm = AssemblyResolver.Resolve(r); if (!IsGacAssembly(r, asm)) { if (asm != null) { w.WriteElementString("HintPath", asm.FileName); @@ -275,7 +278,7 @@ namespace ICSharpCode.Decompiler.CSharp CSharpDecompiler CreateDecompiler(DecompilerTypeSystem ts) { - var decompiler = new CSharpDecompiler(ts, settings); + var decompiler = new CSharpDecompiler(ts, AssemblyResolver, settings); decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers()); decompiler.AstTransforms.Add(new RemoveCLSCompliantAttribute()); return decompiler; @@ -314,7 +317,7 @@ namespace ICSharpCode.Decompiler.CSharp return Path.Combine(dir, file); } }, StringComparer.OrdinalIgnoreCase).ToList(); - DecompilerTypeSystem ts = new DecompilerTypeSystem(module); + DecompilerTypeSystem ts = new DecompilerTypeSystem(module, AssemblyResolver); Parallel.ForEach( files, new ParallelOptions { diff --git a/ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs b/ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs new file mode 100644 index 000000000..c35c47bf2 --- /dev/null +++ b/ICSharpCode.Decompiler/DebugInfo/IDebugInfoProvider.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Reflection.Metadata; +using System.Text; + +namespace ICSharpCode.Decompiler.DebugInfo +{ + public struct Variable + { + public string Name { get; set; } + } + + public interface IDebugInfoProvider + { + IList GetSequencePoints(MethodDefinitionHandle method); + IList GetVariables(MethodDefinitionHandle method); + bool TryGetName(MethodDefinitionHandle method, int index, out string name); + } +} diff --git a/ICSharpCode.Decompiler/Pdb/PortablePdbWriter.cs b/ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs similarity index 98% rename from ICSharpCode.Decompiler/Pdb/PortablePdbWriter.cs rename to ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs index dbd849374..0cf6fdb03 100644 --- a/ICSharpCode.Decompiler/Pdb/PortablePdbWriter.cs +++ b/ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs @@ -17,7 +17,7 @@ using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.Util; -namespace ICSharpCode.Decompiler.Pdb +namespace ICSharpCode.Decompiler.DebugInfo { public class PortablePdbWriter { @@ -39,7 +39,7 @@ namespace ICSharpCode.Decompiler.Pdb var hasher = SHA256.Create(); var sequencePointBlobs = new Dictionary(); var importScopeBlobs = new Dictionary(); - var emptyList = new List(); + var emptyList = new List(); foreach (var handle in reader.GetTopLevelTypeDefinitions()) { var type = reader.GetTypeDefinition(handle); @@ -156,7 +156,7 @@ namespace ICSharpCode.Decompiler.Pdb return metadata.GetOrAddBlob(writer); } - static BlobHandle EncodeSequencePoints(MetadataBuilder metadata, int localSignatureRowId, List sequencePoints) + static BlobHandle EncodeSequencePoints(MetadataBuilder metadata, int localSignatureRowId, List sequencePoints) { if (sequencePoints.Count == 0) return default; diff --git a/ICSharpCode.Decompiler/Metadata/SequencePoint.cs b/ICSharpCode.Decompiler/DebugInfo/SequencePoint.cs similarity index 97% rename from ICSharpCode.Decompiler/Metadata/SequencePoint.cs rename to ICSharpCode.Decompiler/DebugInfo/SequencePoint.cs index 5534b21fc..441731f72 100644 --- a/ICSharpCode.Decompiler/Metadata/SequencePoint.cs +++ b/ICSharpCode.Decompiler/DebugInfo/SequencePoint.cs @@ -18,7 +18,7 @@ using System; -namespace ICSharpCode.Decompiler.Metadata +namespace ICSharpCode.Decompiler.DebugInfo { /// /// A sequence point read from a PDB file or produced by the decompiler. diff --git a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs index 856640e80..638fa4dab 100644 --- a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs @@ -21,7 +21,7 @@ using System.Collections.Generic; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Threading; - +using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Util; @@ -51,7 +51,12 @@ namespace ICSharpCode.Decompiler.Disassembler /// public bool ShowMetadataTokens { get; set; } - IList sequencePoints; + /// + /// Optional provider for sequence points. + /// + public IDebugInfoProvider DebugInfo { get; set; } + + IList sequencePoints; int nextSequencePointIndex; // cache info @@ -68,7 +73,7 @@ namespace ICSharpCode.Decompiler.Disassembler public virtual void Disassemble(PEFile module, MethodDefinitionHandle handle) { - this.module = module; + this.module = module ?? throw new ArgumentNullException(nameof(module)); metadata = module.Metadata; genericContext = new GenericContext(handle, module); signatureDecoder = new DisassemblerSignatureProvider(module, output); @@ -94,7 +99,7 @@ namespace ICSharpCode.Decompiler.Disassembler DisassembleLocalsBlock(body); output.WriteLine(); - sequencePoints = module.DebugInfo?.GetSequencePoints(handle) ?? EmptyList.Instance; + sequencePoints = DebugInfo?.GetSequencePoints(handle) ?? EmptyList.Instance; nextSequencePointIndex = 0; if (DetectControlStructure && blob.Length > 0) { blob.Reset(); @@ -278,7 +283,7 @@ namespace ICSharpCode.Decompiler.Disassembler { int offset = blob.Offset; if (ShowSequencePoints && nextSequencePointIndex < sequencePoints?.Count) { - Metadata.SequencePoint sp = sequencePoints[nextSequencePointIndex]; + var sp = sequencePoints[nextSequencePointIndex]; if (sp.Offset <= offset) { output.Write("// sequence point: "); if (sp.Offset != offset) { diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs index 4d045e034..4514887b8 100644 --- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs @@ -27,6 +27,7 @@ using System.Threading; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.IL; +using ICSharpCode.Decompiler.DebugInfo; namespace ICSharpCode.Decompiler.Disassembler { @@ -55,8 +56,15 @@ namespace ICSharpCode.Decompiler.Disassembler set => methodBodyDisassembler.ShowMetadataTokens = value; } + public IDebugInfoProvider DebugInfo { + get => methodBodyDisassembler.DebugInfo; + set => methodBodyDisassembler.DebugInfo = value; + } + public bool ExpandMemberDefinitions { get; set; } = false; + public IAssemblyResolver AssemblyResolver { get; set; } + public ReflectionDisassembler(ITextOutput output, CancellationToken cancellationToken) : this(output, new MethodBodyDisassembler(output, cancellationToken), cancellationToken) { @@ -362,59 +370,61 @@ namespace ICSharpCode.Decompiler.Disassembler output.Write(secdecl.Action.ToString()); break; } - output.WriteLine(" = {"); - output.Indent(); - var blob = metadata.GetBlobReader(secdecl.PermissionSet); - if ((char)blob.ReadByte() != '.') { - blob.Reset(); - WriteXmlSecurityDeclaration(blob.ReadUTF8(blob.RemainingBytes)); + if (AssemblyResolver == null) { + output.Write(" = "); + WriteBlob(secdecl.PermissionSet, metadata); } else { - string currentAssemblyName = null; - string currentFullAssemblyName = null; - if (metadata.IsAssembly) { - currentAssemblyName = metadata.GetString(metadata.GetAssemblyDefinition().Name); - currentFullAssemblyName = metadata.GetFullAssemblyName(); - } - int count = blob.ReadCompressedInteger(); - for (int i = 0; i < count; i++) { - var typeName = blob.ReadSerializedString(); - string[] nameParts = typeName.Split(new[] { ", " }, StringSplitOptions.None); - if (nameParts.Length < 2 || nameParts[1] == currentAssemblyName) { - output.Write("class "); - output.Write(DisassemblerHelpers.Escape(typeName + ", " + currentFullAssemblyName)); - } else { - string[] typeNameParts = typeName.Split(new[] { ", " }, StringSplitOptions.None); - if (typeNameParts.Length < 2) - throw new NotImplementedException(); - output.Write('['); - output.Write(typeNameParts[1]); - output.Write(']'); - output.WriteReference(typeNameParts[0], null); // TODO : hyperlink! + output.WriteLine(" = {"); + output.Indent(); + var blob = metadata.GetBlobReader(secdecl.PermissionSet); + if ((char)blob.ReadByte() != '.') { + blob.Reset(); + WriteXmlSecurityDeclaration(blob.ReadUTF8(blob.RemainingBytes)); + } else { + string currentAssemblyName = null; + string currentFullAssemblyName = null; + if (metadata.IsAssembly) { + currentAssemblyName = metadata.GetString(metadata.GetAssemblyDefinition().Name); + currentFullAssemblyName = metadata.GetFullAssemblyName(); } - output.Write(" = {"); - blob.ReadCompressedInteger(); // ? - // The specification seems to be incorrect here, so I'm using the logic from Cecil instead. - int argCount = blob.ReadCompressedInteger(); - if (argCount > 0) { - output.WriteLine(); - output.Indent(); - - for (int j = 0; j < argCount; j++) { - WriteSecurityDeclarationArgument(module, ref blob); + int count = blob.ReadCompressedInteger(); + for (int i = 0; i < count; i++) { + var typeName = blob.ReadSerializedString(); + string[] nameParts = typeName.Split(new[] { ", " }, StringSplitOptions.None); + if (nameParts.Length < 2 || nameParts[1] == currentAssemblyName) { + output.Write("class "); + output.Write(DisassemblerHelpers.Escape(typeName + ", " + currentFullAssemblyName)); + } else { + output.Write('['); + output.Write(nameParts[1]); + output.Write(']'); + output.WriteReference(nameParts[0], null); // TODO : hyperlink! + } + output.Write(" = {"); + blob.ReadCompressedInteger(); // ? + // The specification seems to be incorrect here, so I'm using the logic from Cecil instead. + int argCount = blob.ReadCompressedInteger(); + if (argCount > 0) { output.WriteLine(); + output.Indent(); + + for (int j = 0; j < argCount; j++) { + WriteSecurityDeclarationArgument(module, ref blob); + output.WriteLine(); + } + + output.Unindent(); } + output.Write('}'); - output.Unindent(); + if (i + 1 < count) + output.Write(','); + output.WriteLine(); } - output.Write('}'); - - if (i + 1 < count) - output.Write(','); - output.WriteLine(); } + output.Unindent(); + output.WriteLine("}"); } - output.Unindent(); - output.WriteLine("}"); } } @@ -525,7 +535,7 @@ namespace ICSharpCode.Decompiler.Disassembler PEFile containingModule = null; // if we deal with an assembly-qualified name, resolve the assembly if (nameParts.Length == 2) - containingModule = module.AssemblyResolver.Resolve(AssemblyNameReference.Parse(nameParts[1])); + containingModule = AssemblyResolver.Resolve(AssemblyNameReference.Parse(nameParts[1])); if (containingModule != null) { // try to find the type in the assembly var handle = FindType(containingModule, typeNameParts); @@ -539,7 +549,7 @@ namespace ICSharpCode.Decompiler.Disassembler var handle = FindType(module, typeNameParts); if (handle.IsNil) { // otherwise try mscorlib - var mscorlib = module.AssemblyResolver.Resolve(AssemblyNameReference.Parse("mscorlib")); + var mscorlib = AssemblyResolver.Resolve(AssemblyNameReference.Parse("mscorlib")); handle = FindType(mscorlib, typeNameParts); if (handle.IsNil) throw new NotImplementedException(); @@ -1352,27 +1362,27 @@ namespace ICSharpCode.Decompiler.Disassembler output.Write(".custom "); var attr = metadata.GetCustomAttribute(a); attr.Constructor.WriteTo(module, output, GenericContext.Empty); - byte[] blob = metadata.GetBlobBytes(attr.Value); - if (blob.Length > 0) { + if (!attr.Value.IsNil) { output.Write(" = "); - WriteBlob(blob); + WriteBlob(attr.Value, metadata); } output.WriteLine(); } } - void WriteBlob(byte[] blob) + void WriteBlob(BlobHandle blob, MetadataReader metadata) { + var reader = metadata.GetBlobReader(blob); output.Write("("); output.Indent(); - for (int i = 0; i < blob.Length; i++) { - if (i % 16 == 0 && i < blob.Length - 1) { + for (int i = 0; i < reader.Length; i++) { + if (i % 16 == 0 && i < reader.Length - 1) { output.WriteLine(); } else { output.Write(' '); } - output.Write(blob[i].ToString("x2")); + output.Write(reader.ReadByte().ToString("x2")); } output.WriteLine(); @@ -1484,10 +1494,9 @@ namespace ICSharpCode.Decompiler.Disassembler OpenBlock(false); WriteAttributes(module, asm.GetCustomAttributes()); WriteSecurityDeclarations(module, asm.GetDeclarativeSecurityAttributes()); - var publicKey = metadata.GetBlobBytes(asm.PublicKey); - if (publicKey.Length > 0) { + if (!asm.PublicKey.IsNil) { output.Write(".publickey = "); - WriteBlob(publicKey); + WriteBlob(asm.PublicKey, metadata); output.WriteLine(); } if (asm.HashAlgorithm != AssemblyHashAlgorithm.None) { @@ -1518,7 +1527,7 @@ namespace ICSharpCode.Decompiler.Disassembler OpenBlock(false); if (!aref.PublicKeyOrToken.IsNil) { output.Write(".publickeytoken = "); - WriteBlob(metadata.GetBlobBytes(aref.PublicKeyOrToken)); + WriteBlob(aref.PublicKeyOrToken, metadata); output.WriteLine(); } if (aref.Version != null) { diff --git a/ICSharpCode.Decompiler/Documentation/XmlDocumentationProvider.cs b/ICSharpCode.Decompiler/Documentation/XmlDocumentationProvider.cs index 289138caa..f590fc6c5 100644 --- a/ICSharpCode.Decompiler/Documentation/XmlDocumentationProvider.cs +++ b/ICSharpCode.Decompiler/Documentation/XmlDocumentationProvider.cs @@ -23,9 +23,15 @@ using System.IO; using System.Runtime.Serialization; using System.Text; using System.Xml; +using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.Decompiler.Documentation { + public interface IDocumentationProvider + { + string GetDocumentation(IEntity entity); + } + /// /// Provides documentation from an .xml file (as generated by the Microsoft C# compiler). /// @@ -36,7 +42,7 @@ namespace ICSharpCode.Decompiler.Documentation /// If the .xml file is changed, the index will automatically be recreated. /// [Serializable] - public class XmlDocumentationProvider : IDeserializationCallback + public class XmlDocumentationProvider : IDeserializationCallback, IDocumentationProvider { #region Cache sealed class XmlDocumentationCache @@ -316,7 +322,17 @@ namespace ICSharpCode.Decompiler.Documentation throw new ArgumentNullException("key"); return GetDocumentation(key, true); } - + + /// + /// Get the documentation for the specified member. + /// + public string GetDocumentation(IEntity entity) + { + if (entity == null) + throw new ArgumentNullException(nameof(entity)); + return GetDocumentation(XmlDocKeyProvider.GetKey(entity)); + } + string GetDocumentation(string key, bool allowReload) { int hashcode = GetHashCode(key); diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 0cc240f7c..92a342f21 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -306,7 +306,7 @@ - + @@ -342,7 +342,8 @@ - + + diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs b/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs index 975769c3c..408844da6 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs @@ -384,9 +384,11 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow ) ); } - var il = new ILReader(typeSystem).ReadIL(typeSystem.ModuleDefinition, method, typeSystem.ModuleDefinition.Reader.GetMethodBody(methodDef.RelativeVirtualAddress), context.CancellationToken); + var body = typeSystem.ModuleDefinition.Reader.GetMethodBody(methodDef.RelativeVirtualAddress); + var il = context.CreateILReader(typeSystem) + .ReadIL(typeSystem.ModuleDefinition, method, body, context.CancellationToken); il.RunTransforms(CSharpDecompiler.EarlyILTransforms(true), - new ILTransformContext(il, typeSystem, context.Settings) { + new ILTransformContext(il, typeSystem, context.DebugInfo, context.Settings) { CancellationToken = context.CancellationToken, DecompileRun = context.DecompileRun }); diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index 90bfc182f..c442f3f3f 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -40,6 +40,7 @@ namespace ICSharpCode.Decompiler.IL readonly IDecompilerTypeSystem typeSystem; public bool UseDebugSymbols { get; set; } + public DebugInfo.IDebugInfoProvider DebugInfo { get; set; } public List Warnings { get; } = new List(); public ILReader(IDecompilerTypeSystem typeSystem) @@ -53,7 +54,6 @@ namespace ICSharpCode.Decompiler.IL MetadataReader metadata; IMethod method; MethodBodyBlock body; - Metadata.IDebugInfoProvider debugInfo; StackType methodReturnStackType; BlobReader reader; ImmutableStack currentStack; @@ -79,7 +79,6 @@ namespace ICSharpCode.Decompiler.IL var methodDefinition = metadata.GetMethodDefinition(methodDefinitionHandle); this.body = body; this.reader = body.GetILReader(); - this.debugInfo = module.DebugInfo; this.currentStack = ImmutableStack.Empty; this.unionFind = new UnionFind(); this.stackMismatchPairs = new List<(ILVariable, ILVariable)>(); @@ -177,7 +176,7 @@ namespace ICSharpCode.Decompiler.IL kind = VariableKind.Local; } ILVariable ilVar = new ILVariable(kind, type, index); - if (!UseDebugSymbols || debugInfo == null || !debugInfo.TryGetName((MethodDefinitionHandle)method.MetadataToken, index, out string name)) { + if (!UseDebugSymbols || DebugInfo == null || !DebugInfo.TryGetName((MethodDefinitionHandle)method.MetadataToken, index, out string name)) { ilVar.Name = "V_" + index; ilVar.HasGeneratedName = true; } else if (string.IsNullOrWhiteSpace(name)) { @@ -410,7 +409,8 @@ namespace ICSharpCode.Decompiler.IL /// /// Debugging helper: writes the decoded instruction stream interleaved with the inferred evaluation stack layout. /// - public void WriteTypedIL(Metadata.PEFile module, MethodDefinitionHandle method, MethodBodyBlock body, ITextOutput output, CancellationToken cancellationToken = default(CancellationToken)) + public void WriteTypedIL(Metadata.PEFile module, + MethodDefinitionHandle method, MethodBodyBlock body, ITextOutput output, CancellationToken cancellationToken = default) { Init(module, method, body); ReadInstructions(cancellationToken); diff --git a/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs index 20a7f0b2d..626c339cf 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs @@ -145,8 +145,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms if (!methodDefinition.HasBody()) return null; var localTypeSystem = context.TypeSystem.GetSpecializingTypeSystem(targetMethod.Substitution); - var ilReader = new ILReader(localTypeSystem); - ilReader.UseDebugSymbols = context.Settings.UseDebugSymbols; + var ilReader = context.CreateILReader(localTypeSystem); var function = ilReader.ReadIL(context.TypeSystem.ModuleDefinition, (MethodDefinitionHandle)targetMethod.MetadataToken, context.TypeSystem.ModuleDefinition.Reader.GetMethodBody(methodDefinition.RelativeVirtualAddress), context.CancellationToken); function.DelegateType = value.Method.DeclaringType; function.CheckInvariant(ILPhase.Normal); @@ -156,7 +155,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms v.Name = contextPrefix + v.Name; } - var nestedContext = new ILTransformContext(function, localTypeSystem, context.Settings) { + var nestedContext = new ILTransformContext(function, localTypeSystem, context.DebugInfo, context.Settings) { CancellationToken = context.CancellationToken, DecompileRun = context.DecompileRun }; diff --git a/ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs index 20cdead3c..a549f07c4 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs @@ -22,6 +22,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Threading; using ICSharpCode.Decompiler.CSharp.TypeSystem; +using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.Util; @@ -42,6 +43,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms { public ILFunction Function { get; } public IDecompilerTypeSystem TypeSystem { get; } + public IDebugInfoProvider DebugInfo { get; } public DecompilerSettings Settings { get; } public CancellationToken CancellationToken { get; set; } public Stepper Stepper { get; set; } @@ -49,11 +51,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms internal DecompileRun DecompileRun { get; set; } internal ResolvedUsingScope UsingScope => DecompileRun.UsingScope.Resolve(TypeSystem.Compilation); - public ILTransformContext(ILFunction function, IDecompilerTypeSystem typeSystem, DecompilerSettings settings = null) + public ILTransformContext(ILFunction function, IDecompilerTypeSystem typeSystem, IDebugInfoProvider debugInfo, DecompilerSettings settings = null) { this.Function = function ?? throw new ArgumentNullException(nameof(function)); this.TypeSystem = typeSystem ?? throw new ArgumentNullException(nameof(typeSystem)); this.Settings = settings ?? new DecompilerSettings(); + this.DebugInfo = debugInfo; Stepper = new Stepper(); } @@ -61,12 +64,23 @@ namespace ICSharpCode.Decompiler.IL.Transforms { this.Function = context.Function; this.TypeSystem = context.TypeSystem; + this.DebugInfo = context.DebugInfo; this.Settings = context.Settings; this.DecompileRun = context.DecompileRun; this.CancellationToken = context.CancellationToken; this.Stepper = context.Stepper; } + public ILReader CreateILReader(IDecompilerTypeSystem typeSystem = null) + { + if (typeSystem == null) + typeSystem = this.TypeSystem; + return new ILReader(typeSystem) { + UseDebugSymbols = Settings.UseDebugSymbols, + DebugInfo = DebugInfo + }; + } + /// /// Call this method immediately before performing a transform step. /// Unlike context.Stepper.Step(), calls to this method are only compiled in debug builds. diff --git a/ICSharpCode.Decompiler/IL/Transforms/ProxyCallReplacer.cs b/ICSharpCode.Decompiler/IL/Transforms/ProxyCallReplacer.cs index 5583144af..f2a3c84fb 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/ProxyCallReplacer.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/ProxyCallReplacer.cs @@ -31,20 +31,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms return; // partially copied from CSharpDecompiler var specializingTypeSystem = context.TypeSystem.GetSpecializingTypeSystem(inst.Method.Substitution); - var ilReader = new ILReader(specializingTypeSystem); - System.Threading.CancellationToken cancellationToken = new System.Threading.CancellationToken(); - var proxyFunction = ilReader.ReadIL(module, handle, module.Reader.GetMethodBody(methodDef.RelativeVirtualAddress), cancellationToken); - var transformContext = new ILTransformContext(proxyFunction, specializingTypeSystem, context.Settings) { - CancellationToken = cancellationToken, + var ilReader = context.CreateILReader(specializingTypeSystem); + var body = module.Reader.GetMethodBody(methodDef.RelativeVirtualAddress); + var proxyFunction = ilReader.ReadIL(module, handle, body, context.CancellationToken); + var transformContext = new ILTransformContext(proxyFunction, specializingTypeSystem, context.DebugInfo, context.Settings) { + CancellationToken = context.CancellationToken, DecompileRun = context.DecompileRun }; - foreach (var transform in CSharp.CSharpDecompiler.GetILTransforms()) { - if (transform.GetType() != typeof(ProxyCallReplacer)) { // don't call itself on itself - cancellationToken.ThrowIfCancellationRequested(); - transform.Run(proxyFunction, transformContext); - } - } - + proxyFunction.RunTransforms(CSharp.CSharpDecompiler.EarlyILTransforms(), transformContext); if (!(proxyFunction.Body is BlockContainer blockContainer)) return; if (blockContainer.Blocks.Count != 1) diff --git a/ICSharpCode.Decompiler/Metadata/Dom.cs b/ICSharpCode.Decompiler/Metadata/Dom.cs index 61a201a2c..ccca23987 100644 --- a/ICSharpCode.Decompiler/Metadata/Dom.cs +++ b/ICSharpCode.Decompiler/Metadata/Dom.cs @@ -15,23 +15,6 @@ using ICSharpCode.Decompiler.Util; namespace ICSharpCode.Decompiler.Metadata { - public interface IAssemblyDocumentationResolver - { - XmlDocumentationProvider GetProvider(); - } - - public struct Variable - { - public string Name { get; set; } - } - - public interface IDebugInfoProvider - { - IList GetSequencePoints(MethodDefinitionHandle method); - IList GetVariables(MethodDefinitionHandle method); - bool TryGetName(MethodDefinitionHandle method, int index, out string name); - } - public enum TargetRuntime { Unknown, diff --git a/ICSharpCode.Decompiler/Metadata/MetadataResolver.cs b/ICSharpCode.Decompiler/Metadata/MetadataResolver.cs index 4c54ab314..df2476683 100644 --- a/ICSharpCode.Decompiler/Metadata/MetadataResolver.cs +++ b/ICSharpCode.Decompiler/Metadata/MetadataResolver.cs @@ -40,18 +40,18 @@ namespace ICSharpCode.Decompiler.Metadata readonly IAssemblyResolver assemblyResolver; readonly Dictionary loadedModules; - public SimpleMetadataResolveContext(PEFile mainModule) + public SimpleMetadataResolveContext(PEFile mainModule, IAssemblyResolver assemblyResolver) { - this.mainModule = mainModule; - this.assemblyResolver = mainModule.AssemblyResolver; + this.mainModule = mainModule ?? throw new ArgumentNullException(nameof(mainModule)); + this.assemblyResolver = assemblyResolver ?? throw new ArgumentNullException(nameof(assemblyResolver)); this.loadedModules = new Dictionary(); } - public SimpleMetadataResolveContext(PEFile mainModule, IMetadataResolveContext parentContext) + public SimpleMetadataResolveContext(PEFile mainModule, SimpleMetadataResolveContext parentContext) { - this.mainModule = mainModule; - this.assemblyResolver = mainModule.AssemblyResolver; - this.loadedModules = parentContext is SimpleMetadataResolveContext simple ? simple.loadedModules : new Dictionary(); + this.mainModule = mainModule ?? throw new ArgumentNullException(nameof(mainModule)); + this.assemblyResolver = parentContext.assemblyResolver; + this.loadedModules = parentContext.loadedModules; } public PEFile CurrentModule => mainModule; diff --git a/ICSharpCode.Decompiler/Metadata/PEFile.cs b/ICSharpCode.Decompiler/Metadata/PEFile.cs index 2a04b9149..0d9190df7 100644 --- a/ICSharpCode.Decompiler/Metadata/PEFile.cs +++ b/ICSharpCode.Decompiler/Metadata/PEFile.cs @@ -33,24 +33,17 @@ namespace ICSharpCode.Decompiler.Metadata public string FileName { get; } public PEReader Reader { get; } public MetadataReader Metadata { get; } - public IAssemblyResolver AssemblyResolver { get; } - public IAssemblyDocumentationResolver DocumentationResolver { get; set; } - public IDebugInfoProvider DebugInfo { get; set; } - public PEFile(string fileName, Stream stream, bool throwOnResolveError = false, PEStreamOptions options = PEStreamOptions.Default) + public PEFile(string fileName, Stream stream, PEStreamOptions options = PEStreamOptions.Default) + : this(fileName, new PEReader(stream, options)) { - this.FileName = fileName; - this.Reader = new PEReader(stream, options); - this.Metadata = Reader.GetMetadataReader(); - this.AssemblyResolver = new UniversalAssemblyResolver(fileName, throwOnResolveError, Reader.DetectTargetFrameworkId(), options); } - public PEFile(string fileName, Stream stream, IAssemblyResolver assemblyResolver, PEStreamOptions options = PEStreamOptions.Default) + public PEFile(string fileName, PEReader reader) { - this.FileName = fileName; - this.Reader = new PEReader(stream, options); - this.Metadata = Reader.GetMetadataReader(); - this.AssemblyResolver = assemblyResolver; + this.FileName = fileName ?? throw new ArgumentNullException(nameof(fileName)); + this.Reader = reader ?? throw new ArgumentNullException(nameof(reader)); + this.Metadata = reader.GetMetadataReader(); } public bool IsAssembly => Metadata.IsAssembly; diff --git a/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs b/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs index 735757173..a735e70f2 100644 --- a/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs +++ b/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs @@ -90,7 +90,7 @@ namespace ICSharpCode.Decompiler.Metadata throw new AssemblyResolutionException(name); return null; } - return new PEFile(file, new FileStream(file, FileMode.Open, FileAccess.Read), this, options); + return new PEFile(file, new FileStream(file, FileMode.Open, FileAccess.Read), options); } public string FindAssemblyFile(IAssemblyReference name) diff --git a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs index f270e3d97..c4fde1556 100644 --- a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs +++ b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs @@ -26,6 +26,7 @@ using ICSharpCode.Decompiler.Util; using static ICSharpCode.Decompiler.Metadata.MetadataExtensions; using System.Diagnostics; using System.Collections.Immutable; +using ICSharpCode.Decompiler.Metadata; namespace ICSharpCode.Decompiler.TypeSystem { @@ -77,18 +78,21 @@ namespace ICSharpCode.Decompiler.TypeSystem { readonly Metadata.PEFile moduleDefinition; readonly ICompilation compilation; + readonly IAssemblyResolver assemblyResolver; readonly TypeSystemOptions typeSystemOptions; readonly MetadataAssembly mainAssembly; - public DecompilerTypeSystem(Metadata.PEFile moduleDefinition) : this(moduleDefinition, new DecompilerSettings()) + public DecompilerTypeSystem(Metadata.PEFile moduleDefinition, IAssemblyResolver assemblyResolver) + : this(moduleDefinition, assemblyResolver, new DecompilerSettings()) { } - public DecompilerTypeSystem(Metadata.PEFile moduleDefinition, DecompilerSettings settings) + public DecompilerTypeSystem(PEFile moduleDefinition, IAssemblyResolver assemblyResolver, DecompilerSettings settings) { if (settings == null) throw new ArgumentNullException(nameof(settings)); - this.moduleDefinition = moduleDefinition; + this.moduleDefinition = moduleDefinition ?? throw new ArgumentNullException(nameof(moduleDefinition)); + this.assemblyResolver = assemblyResolver ?? throw new ArgumentNullException(nameof(assemblyResolver)); typeSystemOptions = TypeSystemOptions.None; if (settings.Dynamic) typeSystemOptions |= TypeSystemOptions.Dynamic; @@ -106,7 +110,7 @@ namespace ICSharpCode.Decompiler.TypeSystem var asmRef = assemblyReferenceQueue.Dequeue(); if (!processedAssemblyReferences.Add(asmRef)) continue; - var asm = moduleDefinition.AssemblyResolver.Resolve(asmRef); + var asm = assemblyResolver.Resolve(asmRef); if (asm != null) { referencedAssemblies.Add(asm.WithOptions(typeSystemOptions)); var metadata = asm.Metadata; diff --git a/ICSharpCode.Decompiler/TypeSystem/IAssembly.cs b/ICSharpCode.Decompiler/TypeSystem/IAssembly.cs index 9aa7f7e48..e82032161 100644 --- a/ICSharpCode.Decompiler/TypeSystem/IAssembly.cs +++ b/ICSharpCode.Decompiler/TypeSystem/IAssembly.cs @@ -18,6 +18,7 @@ using System.Collections.Generic; using System.Reflection.Metadata; +using ICSharpCode.Decompiler.Metadata; namespace ICSharpCode.Decompiler.TypeSystem { @@ -65,6 +66,11 @@ namespace ICSharpCode.Decompiler.TypeSystem /// public interface IAssembly : ICompilationProvider { + /// + /// Gets the underlying metadata file. May return null, if the IAssembly was not created from a PE file. + /// + PEFile PEFile { get; } + /// /// Gets whether this assembly is the main assembly of the compilation. /// diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs index 218eefe31..33d485691 100644 --- a/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs +++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultUnresolvedAssembly.cs @@ -329,6 +329,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation this.AssemblyAttributes = unresolved.AssemblyAttributes.CreateResolvedAttributes(context); this.ModuleAttributes = unresolved.ModuleAttributes.CreateResolvedAttributes(context); } + + public Metadata.PEFile PEFile => null; public IUnresolvedAssembly UnresolvedAssembly { get { return unresolvedAssembly; } diff --git a/ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs b/ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs index 45b2f22f7..26eebcea7 100644 --- a/ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs +++ b/ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs @@ -38,7 +38,6 @@ namespace ICSharpCode.Decompiler.TypeSystem public class MetadataAssembly : IAssembly { public ICompilation Compilation { get; } - public readonly Metadata.PEFile PEFile; internal readonly MetadataReader metadata; readonly TypeSystemOptions options; internal readonly TypeProvider TypeProvider; @@ -86,6 +85,8 @@ namespace ICSharpCode.Decompiler.TypeSystem public TypeSystemOptions TypeSystemOptions => options; #region IAssembly interface + public PEFile PEFile { get; } + public bool IsMainAssembly => this == Compilation.MainAssembly; public string AssemblyName { get; } diff --git a/ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs b/ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs index 1e3b3b217..9eb758512 100644 --- a/ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs +++ b/ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs @@ -114,13 +114,13 @@ namespace ILSpy.BamlDecompiler.Tests { using (var fileStream = new FileStream(asmPath, FileMode.Open, FileAccess.Read)) { var module = new PEFile(asmPath, fileStream); - var resolver = (UniversalAssemblyResolver)module.AssemblyResolver; + var resolver = new UniversalAssemblyResolver(asmPath, false, module.Reader.DetectTargetFrameworkId()); resolver.RemoveSearchDirectory("."); resolver.AddSearchDirectory(Path.GetDirectoryName(asmPath)); var res = module.Resources.First(); Stream bamlStream = LoadBaml(res, name + ".baml"); Assert.IsNotNull(bamlStream); - XDocument document = BamlResourceEntryNode.LoadIntoDocument(module, bamlStream, CancellationToken.None); + XDocument document = BamlResourceEntryNode.LoadIntoDocument(module, resolver, bamlStream, CancellationToken.None); XamlIsEqual(File.ReadAllText(sourcePath), document.ToString()); } diff --git a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs index 61b26deb6..fd9ac282e 100644 --- a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs +++ b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs @@ -50,30 +50,32 @@ namespace ILSpy.BamlDecompiler { var asm = this.Ancestors().OfType().FirstOrDefault().LoadedAssembly; Data.Position = 0; - XDocument xamlDocument = LoadIntoDocument(asm.GetPEFileOrNull(), Data, cancellationToken); + XDocument xamlDocument = LoadIntoDocument(asm.GetPEFileOrNull(), asm.GetAssemblyResolver(), Data, cancellationToken); output.Write(xamlDocument.ToString()); return true; } - internal static XDocument LoadIntoDocument(PEFile module, Stream stream, CancellationToken cancellationToken) + internal static XDocument LoadIntoDocument(PEFile module, IAssemblyResolver assemblyResolver, + Stream stream, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); XDocument xamlDocument; - using (XmlBamlReader reader = new XmlBamlReader(stream, new NRTypeResolver(module))) { + using (XmlBamlReader reader = new XmlBamlReader(stream, new NRTypeResolver(module, assemblyResolver))) { xamlDocument = XDocument.Load(reader); - ConvertConnectionIds(xamlDocument, module, cancellationToken); + ConvertConnectionIds(xamlDocument, module, assemblyResolver, cancellationToken); ConvertToEmptyElements(xamlDocument.Root); MoveNamespacesToRoot(xamlDocument, reader.XmlnsDefinitions); return xamlDocument; } } - static void ConvertConnectionIds(XDocument xamlDocument, PEFile asm, CancellationToken cancellationToken) + static void ConvertConnectionIds(XDocument xamlDocument, PEFile asm, IAssemblyResolver assemblyResolver, + CancellationToken cancellationToken) { var attr = xamlDocument.Root.Attribute(XName.Get("Class", XmlBamlReader.XWPFNamespace)); if (attr != null) { string fullTypeName = attr.Value; - var mappings = new ConnectMethodDecompiler().DecompileEventMappings(asm, fullTypeName, cancellationToken); + var mappings = new ConnectMethodDecompiler().DecompileEventMappings(asm, assemblyResolver, fullTypeName, cancellationToken); RemoveConnectionIds(xamlDocument.Root, mappings); } } diff --git a/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs b/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs index 740611e07..f0c177b32 100644 --- a/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs +++ b/ILSpy.BamlDecompiler/BamlResourceNodeFactory.cs @@ -36,7 +36,7 @@ namespace ILSpy.BamlDecompiler public string WriteResourceToFile(LoadedAssembly assembly, string fileName, Stream stream, DecompilationOptions options) { - var document = BamlResourceEntryNode.LoadIntoDocument(assembly.GetPEFileOrNull(), stream, options.CancellationToken); + var document = BamlResourceEntryNode.LoadIntoDocument(assembly.GetPEFileOrNull(), assembly.GetAssemblyResolver(), stream, options.CancellationToken); fileName = Path.ChangeExtension(fileName, ".xaml"); document.Save(Path.Combine(options.SaveAsProjectDirectory, fileName)); return fileName; diff --git a/ILSpy.BamlDecompiler/CecilTypeResolver.cs b/ILSpy.BamlDecompiler/CecilTypeResolver.cs index 0164fe120..877ec778d 100644 --- a/ILSpy.BamlDecompiler/CecilTypeResolver.cs +++ b/ILSpy.BamlDecompiler/CecilTypeResolver.cs @@ -4,6 +4,7 @@ using System; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.ILSpy; using Ricciolo.StylesExplorer.MarkupReflection; namespace ILSpy.BamlDecompiler @@ -17,10 +18,10 @@ namespace ILSpy.BamlDecompiler readonly DecompilerTypeSystem typeSystem; readonly ICompilation compilation; - public NRTypeResolver(PEFile module) + public NRTypeResolver(PEFile module, IAssemblyResolver resolver) { - this.module = module; - this.typeSystem = new DecompilerTypeSystem(module); + this.module = module ?? throw new ArgumentNullException(nameof(module)); + this.typeSystem = new DecompilerTypeSystem(module, resolver); this.compilation = typeSystem.Compilation; } diff --git a/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs b/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs index 10eb55937..2dbd549f2 100644 --- a/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs +++ b/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs @@ -9,9 +9,11 @@ using System.Threading; using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.IL.Transforms; +using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.Util; +using ICSharpCode.ILSpy; using Metadata = ICSharpCode.Decompiler.Metadata; namespace ILSpy.BamlDecompiler @@ -29,11 +31,11 @@ namespace ILSpy.BamlDecompiler /// sealed class ConnectMethodDecompiler { - public List<(LongSet, EventRegistration[])> DecompileEventMappings(Metadata.PEFile module, + public List<(LongSet, EventRegistration[])> DecompileEventMappings(Metadata.PEFile module, IAssemblyResolver assemblyResolver, string fullTypeName, CancellationToken cancellationToken) { var result = new List<(LongSet, EventRegistration[])>(); - var typeSystem = new DecompilerTypeSystem(module); + var typeSystem = new DecompilerTypeSystem(module, assemblyResolver); var typeDefinition = typeSystem.Compilation.FindType(new FullTypeName(fullTypeName)).GetDefinition(); if (typeDefinition == null) @@ -58,7 +60,7 @@ namespace ILSpy.BamlDecompiler var function = ilReader.ReadIL(module, (MethodDefinitionHandle)method.MetadataToken, module.Reader.GetMethodBody(metadataEntry.RelativeVirtualAddress), cancellationToken); - var context = new ILTransformContext(function, typeSystem) { + var context = new ILTransformContext(function, typeSystem, null) { CancellationToken = cancellationToken }; function.RunTransforms(CSharpDecompiler.GetILTransforms(), context); diff --git a/ILSpy/DebugInfo/DiaSymNativeDebugInfoProvider.cs b/ILSpy/DebugInfo/DiaSymNativeDebugInfoProvider.cs index 069bee8ae..add40845d 100644 --- a/ILSpy/DebugInfo/DiaSymNativeDebugInfoProvider.cs +++ b/ILSpy/DebugInfo/DiaSymNativeDebugInfoProvider.cs @@ -25,6 +25,7 @@ using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Text; using System.Threading.Tasks; +using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Util; using Microsoft.DiaSymReader; @@ -48,12 +49,12 @@ namespace ICSharpCode.ILSpy.DebugInfo this.reader = SymUnmanagedReaderFactory.CreateReader(stream, this); } - public IList GetSequencePoints(MethodDefinitionHandle handle) + public IList GetSequencePoints(MethodDefinitionHandle handle) { var method = reader.GetMethod(MetadataTokens.GetToken(handle)); if (method == null || method.GetSequencePointCount(out int count) != 0) - return Empty.Array; - var sequencePoints = new Decompiler.Metadata.SequencePoint[count]; + return Empty.Array; + var sequencePoints = new Decompiler.DebugInfo.SequencePoint[count]; var points = method.GetSequencePoints(); int i = 0; var buffer = new char[1024]; @@ -64,7 +65,7 @@ namespace ICSharpCode.ILSpy.DebugInfo } else { url = ""; } - sequencePoints[i] = new Decompiler.Metadata.SequencePoint() { + sequencePoints[i] = new Decompiler.DebugInfo.SequencePoint() { Offset = point.Offset, StartLine = point.StartLine, StartColumn = point.StartColumn, diff --git a/ILSpy/DebugInfo/PortableDebugInfoProvider.cs b/ILSpy/DebugInfo/PortableDebugInfoProvider.cs index f50568a2e..6ff89db90 100644 --- a/ILSpy/DebugInfo/PortableDebugInfoProvider.cs +++ b/ILSpy/DebugInfo/PortableDebugInfoProvider.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Reflection.Metadata; +using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.Metadata; namespace ICSharpCode.ILSpy.DebugInfo @@ -34,11 +35,11 @@ namespace ICSharpCode.ILSpy.DebugInfo this.provider = provider; } - public IList GetSequencePoints(MethodDefinitionHandle method) + public IList GetSequencePoints(MethodDefinitionHandle method) { var metadata = provider.GetMetadataReader(); var debugInfo = metadata.GetMethodDebugInformation(method); - var sequencePoints = new List(); + var sequencePoints = new List(); foreach (var point in debugInfo.GetSequencePoints()) { string documentFileName; @@ -50,7 +51,7 @@ namespace ICSharpCode.ILSpy.DebugInfo documentFileName = ""; } - sequencePoints.Add(new Decompiler.Metadata.SequencePoint() { + sequencePoints.Add(new Decompiler.DebugInfo.SequencePoint() { Offset = point.Offset, StartLine = point.StartLine, StartColumn = point.StartColumn, diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index efd3f5741..b4420f480 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -120,6 +120,7 @@ + @@ -135,6 +136,7 @@ + diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index a75239b11..a4d7cdad3 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -110,9 +110,9 @@ namespace ICSharpCode.ILSpy } } - CSharpDecompiler CreateDecompiler(Decompiler.Metadata.PEFile module, DecompilationOptions options) + CSharpDecompiler CreateDecompiler(PEFile module, DecompilationOptions options) { - CSharpDecompiler decompiler = new CSharpDecompiler(module, options.DecompilerSettings); + CSharpDecompiler decompiler = new CSharpDecompiler(module, module.GetAssemblyResolver(), options.DecompilerSettings); decompiler.CancellationToken = options.CancellationToken; while (decompiler.AstTransforms.Count > transformCount) decompiler.AstTransforms.RemoveAt(decompiler.AstTransforms.Count - 1); @@ -129,19 +129,19 @@ namespace ICSharpCode.ILSpy syntaxTree.AcceptVisitor(new CSharpOutputVisitor(tokenWriter, settings.CSharpFormattingOptions)); } - public override void DecompileMethod(Decompiler.Metadata.MethodDefinition method, ITextOutput output, DecompilationOptions options) + public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) { - AddReferenceWarningMessage(method.Module, output); - var md = method.Module.Metadata.GetMethodDefinition(method.Handle); - WriteCommentLine(output, TypeToString(new Entity(method.Module, md.GetDeclaringType()), includeNamespace: true)); - CSharpDecompiler decompiler = CreateDecompiler(method.Module, options); - var methodDefinition = decompiler.TypeSystem.ResolveAsMethod(method.Handle); + PEFile assembly = method.ParentAssembly.PEFile; + AddReferenceWarningMessage(assembly, output); + WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true)); + CSharpDecompiler decompiler = CreateDecompiler(assembly, options); + var methodDefinition = decompiler.TypeSystem.ResolveAsMethod(method.MetadataToken); if (methodDefinition.IsConstructor && methodDefinition.DeclaringType.IsReferenceType != false) { var members = CollectFieldsAndCtors(methodDefinition.DeclaringTypeDefinition, methodDefinition.IsStatic); decompiler.AstTransforms.Add(new SelectCtorTransform(methodDefinition)); WriteCode(output, options.DecompilerSettings, decompiler.Decompile(members), decompiler.TypeSystem); } else { - WriteCode(output, options.DecompilerSettings, decompiler.Decompile(method.Handle), decompiler.TypeSystem); + WriteCode(output, options.DecompilerSettings, decompiler.Decompile(method.MetadataToken), decompiler.TypeSystem); } } @@ -196,28 +196,26 @@ namespace ICSharpCode.ILSpy } } - public override void DecompileProperty(Decompiler.Metadata.PropertyDefinition property, ITextOutput output, DecompilationOptions options) + public override void DecompileProperty(IProperty property, ITextOutput output, DecompilationOptions options) { - AddReferenceWarningMessage(property.Module, output); - CSharpDecompiler decompiler = CreateDecompiler(property.Module, options); - var metadata = property.Module.Metadata; - var accessorHandle = metadata.GetPropertyDefinition(property.Handle).GetAccessors().GetAny(); - WriteCommentLine(output, TypeToString(new Decompiler.Metadata.TypeDefinition(property.Module, metadata.GetMethodDefinition(accessorHandle).GetDeclaringType()), includeNamespace: true)); - WriteCode(output, options.DecompilerSettings, decompiler.Decompile(property.Handle), decompiler.TypeSystem); + PEFile assembly = property.ParentAssembly.PEFile; + AddReferenceWarningMessage(assembly, output); + CSharpDecompiler decompiler = CreateDecompiler(assembly, options); + WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true)); + WriteCode(output, options.DecompilerSettings, decompiler.Decompile(property.MetadataToken), decompiler.TypeSystem); } - public override void DecompileField(Decompiler.Metadata.FieldDefinition field, ITextOutput output, DecompilationOptions options) + public override void DecompileField(IField field, ITextOutput output, DecompilationOptions options) { - AddReferenceWarningMessage(field.Module, output); - var fd = field.Module.Metadata.GetFieldDefinition(field.Handle); - WriteCommentLine(output, TypeToString(new Decompiler.Metadata.TypeDefinition(field.Module, fd.GetDeclaringType()), includeNamespace: true)); - CSharpDecompiler decompiler = CreateDecompiler(field.Module, options); - var fieldDefinition = decompiler.TypeSystem.ResolveAsField(field.Handle); - if (fd.HasFlag(FieldAttributes.Literal)) { - WriteCode(output, options.DecompilerSettings, decompiler.Decompile(field.Handle), decompiler.TypeSystem); + PEFile assembly = field.ParentAssembly.PEFile; + AddReferenceWarningMessage(assembly, output); + WriteCommentLine(output, TypeToString(field.DeclaringType, includeNamespace: true)); + CSharpDecompiler decompiler = CreateDecompiler(assembly, options); + if (field.IsConst) { + WriteCode(output, options.DecompilerSettings, decompiler.Decompile(field.MetadataToken), decompiler.TypeSystem); } else { - var members = CollectFieldsAndCtors(fieldDefinition.DeclaringTypeDefinition, fieldDefinition.IsStatic); - decompiler.AstTransforms.Add(new SelectFieldTransform(fieldDefinition)); + var members = CollectFieldsAndCtors(field.DeclaringTypeDefinition, field.IsStatic); + decompiler.AstTransforms.Add(new SelectFieldTransform(field)); WriteCode(output, options.DecompilerSettings, decompiler.Decompile(members), decompiler.TypeSystem); } } @@ -266,25 +264,25 @@ namespace ICSharpCode.ILSpy } } - public override void DecompileEvent(Decompiler.Metadata.EventDefinition ev, ITextOutput output, DecompilationOptions options) + public override void DecompileEvent(IEvent @event, ITextOutput output, DecompilationOptions options) { - AddReferenceWarningMessage(ev.Module, output); - var metadata = ev.Module.Metadata; - var accessorHandle = metadata.GetEventDefinition(ev.Handle).GetAccessors().GetAny(); - base.WriteCommentLine(output, TypeToString(new Decompiler.Metadata.TypeDefinition(ev.Module, metadata.GetMethodDefinition(accessorHandle).GetDeclaringType()), includeNamespace: true)); - CSharpDecompiler decompiler = CreateDecompiler(ev.Module, options); - WriteCode(output, options.DecompilerSettings, decompiler.Decompile(ev.Handle), decompiler.TypeSystem); + PEFile assembly = @event.ParentAssembly.PEFile; + AddReferenceWarningMessage(assembly, output); + base.WriteCommentLine(output, TypeToString(@event.DeclaringType, includeNamespace: true)); + CSharpDecompiler decompiler = CreateDecompiler(assembly, options); + WriteCode(output, options.DecompilerSettings, decompiler.Decompile(@event.MetadataToken), decompiler.TypeSystem); } - public override void DecompileType(Decompiler.Metadata.TypeDefinition type, ITextOutput output, DecompilationOptions options) + public override void DecompileType(ITypeDefinition type, ITextOutput output, DecompilationOptions options) { - AddReferenceWarningMessage(type.Module, output); + PEFile assembly = type.ParentAssembly.PEFile; + AddReferenceWarningMessage(assembly, output); WriteCommentLine(output, TypeToString(type, includeNamespace: true)); - CSharpDecompiler decompiler = CreateDecompiler(type.Module, options); - WriteCode(output, options.DecompilerSettings, decompiler.Decompile(type.Handle), decompiler.TypeSystem); + CSharpDecompiler decompiler = CreateDecompiler(assembly, options); + WriteCode(output, options.DecompilerSettings, decompiler.Decompile(type.MetadataToken), decompiler.TypeSystem); } - void AddReferenceWarningMessage(Decompiler.Metadata.PEFile assembly, ITextOutput output) + void AddReferenceWarningMessage(PEFile assembly, ITextOutput output) { var loadedAssembly = MainWindow.Instance.CurrentAssemblyList.GetAssemblies().FirstOrDefault(la => la.GetPEFileOrNull() == assembly); if (loadedAssembly == null || !loadedAssembly.LoadedAssemblyReferencesInfo.HasErrors) @@ -320,7 +318,7 @@ namespace ICSharpCode.ILSpy public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options) { - var module = assembly.GetPEFileAsync().Result; + var module = assembly.GetPEFileOrNull(); if (options.FullDecompilation && options.SaveAsProjectDirectory != null) { var decompiler = new ILSpyWholeProjectDecompiler(assembly, options); decompiler.DecompileProject(module, options.SaveAsProjectDirectory, new TextOutputWriter(output), options.CancellationToken); @@ -328,23 +326,24 @@ namespace ICSharpCode.ILSpy AddReferenceWarningMessage(module, output); output.WriteLine(); base.DecompileAssembly(assembly, output, options); - var metadata = module.Metadata; - - if (metadata.TypeDefinitions.Count > 0) { + IAssemblyResolver assemblyResolver = assembly.GetAssemblyResolver(); + var typeSystem = new DecompilerTypeSystem(module, assemblyResolver, options.DecompilerSettings); + var globalType = typeSystem.MainAssembly.TypeDefinitions.FirstOrDefault(); + if (globalType != null) { output.Write("// Global type: "); - var globalType = metadata.TypeDefinitions.First(); - output.WriteReference(globalType.GetFullTypeName(metadata).ToString(), new Decompiler.Metadata.TypeDefinition(module, globalType)); + output.WriteReference(globalType.FullName, globalType); output.WriteLine(); } + var metadata = module.Metadata; var corHeader = module.Reader.PEHeaders.CorHeader; var entrypointHandle = MetadataTokenHelpers.EntityHandleOrNil(corHeader.EntryPointTokenOrRelativeVirtualAddress); if (!entrypointHandle.IsNil && entrypointHandle.Kind == HandleKind.MethodDefinition) { - var entrypoint = metadata.GetMethodDefinition((MethodDefinitionHandle)entrypointHandle); - output.Write("// Entry point: "); - string name = entrypoint.GetDeclaringType().GetFullTypeName(metadata) + "." + metadata.GetString(entrypoint.Name); - var entrypointEntity = new Decompiler.Metadata.MethodDefinition(module, (MethodDefinitionHandle)entrypointHandle); - output.WriteReference(name, entrypointEntity); - output.WriteLine(); + var entrypoint = typeSystem.ResolveAsMethod(entrypointHandle); + if (entrypoint != null) { + output.Write("// Entry point: "); + output.WriteReference(entrypoint.DeclaringType.FullName + "." + entrypoint.Name, entrypoint); + output.WriteLine(); + } } output.WriteLine("// Architecture: " + GetPlatformDisplayName(module)); if ((corHeader.Flags & System.Reflection.PortableExecutable.CorFlags.ILOnly) == 0) { @@ -358,7 +357,7 @@ namespace ICSharpCode.ILSpy // don't automatically load additional assemblies when an assembly node is selected in the tree view using (options.FullDecompilation ? null : LoadedAssembly.DisableAssemblyLoad()) { - CSharpDecompiler decompiler = new CSharpDecompiler(module, options.DecompilerSettings); + CSharpDecompiler decompiler = new CSharpDecompiler(typeSystem, assemblyResolver, options.DecompilerSettings); decompiler.CancellationToken = options.CancellationToken; SyntaxTree st; if (options.FullDecompilation) { @@ -405,82 +404,35 @@ namespace ICSharpCode.ILSpy } } - public override string TypeToString(Entity type, Decompiler.Metadata.GenericContext genericContext = null, bool includeNamespace = true) + public override string TypeToString(IType type, bool includeNamespace) { - if (type.Handle.IsNil) + if (type == null) throw new ArgumentNullException(nameof(type)); - var metadata = type.Module.Metadata; - ConvertTypeOptions convertTypeOptions = ConvertTypeOptions.IncludeTypeParameterDefinitions; - if (includeNamespace) - convertTypeOptions |= ConvertTypeOptions.IncludeNamespace; - //if (includeTypeName) - // convertTypeOptions |= ConvertTypeOptions.IncludeOuterTypeName; - var builder = new AstTypeBuilder(convertTypeOptions); - AstType astType; - switch (type.Handle.Kind) { - case HandleKind.TypeReference: - astType = builder.GetTypeFromReference(metadata, (TypeReferenceHandle)type.Handle, 0); - return TypeToString(astType, metadata, null); - case HandleKind.TypeDefinition: - var td = metadata.GetTypeDefinition((TypeDefinitionHandle)type.Handle); - var genericParams = td.GetGenericParameters(); - - var buffer = new System.Text.StringBuilder(); - - var name = td.GetFullTypeName(metadata); - - if (includeNamespace) - buffer.Append(name.ToString()); - else - buffer.Append(name.Name); - - if (genericParams.Count > 0) { - buffer.Append('<'); - int i = 0; - foreach (var h in genericParams) { - var gp = metadata.GetGenericParameter(h); - if (i > 0) - buffer.Append(", "); - buffer.Append(metadata.GetString(gp.Name)); - i++; - } - buffer.Append('>'); - } + TypeSystemAstBuilder builder = new TypeSystemAstBuilder(); + AstType astType = builder.ConvertType(type); + StringWriter w = new StringWriter(); - return buffer.ToString(); - case HandleKind.TypeSpecification: - var ts = metadata.GetTypeSpecification((TypeSpecificationHandle)type.Handle); - astType = builder.GetTypeFromSpecification(metadata, genericContext ?? GenericContext.Empty, (TypeSpecificationHandle)type.Handle, 0); - return TypeToString(astType, metadata, ts.GetCustomAttributes()); - default: - throw new NotSupportedException(); - } + astType.AcceptVisitor(new CSharpOutputVisitor(w, FormattingOptionsFactory.CreateAllman())); + return w.ToString(); } - public override string FieldToString(Decompiler.Metadata.FieldDefinition field, bool includeTypeName, bool includeNamespace) + public override string FieldToString(IField field, bool includeTypeName, bool includeNamespace) { - if (field.Handle.IsNil) + if (field == null) throw new ArgumentNullException(nameof(field)); - ConvertTypeOptions convertTypeOptions = ConvertTypeOptions.IncludeTypeParameterDefinitions; - if (includeNamespace) - convertTypeOptions |= ConvertTypeOptions.IncludeNamespace; - if (includeTypeName) - convertTypeOptions |= ConvertTypeOptions.IncludeOuterTypeName; - var metadata = field.Module.Metadata; - var fd = metadata.GetFieldDefinition(field.Handle); - AstType fieldType = fd.DecodeSignature(new AstTypeBuilder(convertTypeOptions), new GenericContext(fd.GetDeclaringType(), field.Module)); - string simple = metadata.GetString(fd.Name) + " : " + TypeToString(fieldType, metadata, fd.GetCustomAttributes()); + + string simple = field.Name + " : " + TypeToString(field.Type, includeNamespace); if (!includeTypeName) return simple; - var typeName = fd.GetDeclaringType().GetFullTypeName(metadata); + var typeName = field.DeclaringTypeDefinition.FullTypeName; if (!includeNamespace) return typeName.Name + "." + simple; return typeName + "." + simple; } - - public override string PropertyToString(Decompiler.Metadata.PropertyDefinition property, bool includeTypeName, bool includeNamespace, bool? isIndexer = null) + /* + public override string PropertyToString(IProperty property, bool includeTypeName, bool includeNamespace, bool? isIndexer = null) { - if (property.IsNil) + if (property == null) throw new ArgumentNullException(nameof(property)); ConvertTypeOptions convertTypeOptions = ConvertTypeOptions.IncludeTypeParameterDefinitions; if (includeNamespace) @@ -699,43 +651,18 @@ namespace ICSharpCode.ILSpy buffer.Append(" : "); buffer.Append(TypeToString(signature, metadata, returnTypeAttributes)); return buffer.ToString(); - } + }*/ - public override bool ShowMember(IMetadataEntity member) + public override bool ShowMember(IEntity member) { - return showAllMembers || !CSharpDecompiler.MemberIsHidden(member.Module, member.Handle, new DecompilationOptions().DecompilerSettings); + PEFile assembly = member.ParentAssembly.PEFile; + return showAllMembers || !CSharpDecompiler.MemberIsHidden(assembly, member.MetadataToken, new DecompilationOptions().DecompilerSettings); } - public override string GetTooltip(Entity entity) + public override string GetTooltip(IEntity entity) { - var decompilerTypeSystem = new DecompilerTypeSystem(entity.Module); - ISymbol symbol; - switch (entity.Handle.Kind) { - case HandleKind.MethodDefinition: - symbol = decompilerTypeSystem.ResolveAsMethod(entity.Handle); - if (symbol == null) return base.GetTooltip(entity); - break; - case HandleKind.PropertyDefinition: - symbol = decompilerTypeSystem.ResolveAsProperty(entity.Handle); - if (symbol == null) return base.GetTooltip(entity); - break; - case HandleKind.EventDefinition: - symbol = decompilerTypeSystem.ResolveAsEvent(entity.Handle); - if (symbol == null) return base.GetTooltip(entity); - break; - case HandleKind.FieldDefinition: - symbol = decompilerTypeSystem.ResolveAsField(entity.Handle); - if (symbol == null) return base.GetTooltip(entity); - break; - case HandleKind.TypeDefinition: - symbol = decompilerTypeSystem.ResolveAsType(entity.Handle).GetDefinition(); - if (symbol == null) return base.GetTooltip(entity); - break; - default: - return base.GetTooltip(entity); - } var flags = ConversionFlags.All & ~ConversionFlags.ShowBody; - return new CSharpAmbience() { ConversionFlags = flags }.ConvertSymbol(symbol); + return new CSharpAmbience() { ConversionFlags = flags }.ConvertSymbol(entity); } public override CodeMappingInfo GetCodeMappingInfo(PEFile module, EntityHandle member) diff --git a/ILSpy/LoadedAssembly.cs b/ILSpy/LoadedAssembly.cs index 68c613ecd..02503c124 100644 --- a/ILSpy/LoadedAssembly.cs +++ b/ILSpy/LoadedAssembly.cs @@ -21,9 +21,11 @@ using System.Collections.Generic; using System.IO; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem.Implementation; @@ -39,6 +41,8 @@ namespace ICSharpCode.ILSpy /// public sealed class LoadedAssembly { + internal static readonly ConditionalWeakTable loadedAssemblies = new ConditionalWeakTable(); + readonly Task assemblyTask; readonly AssemblyList assemblyList; readonly string fileName; @@ -65,6 +69,8 @@ namespace ICSharpCode.ILSpy public ReferenceLoadInfo LoadedAssemblyReferencesInfo { get; } = new ReferenceLoadInfo(); + IDebugInfoProvider debugInfoProvider; + /// /// Gets the Cecil ModuleDefinition. /// @@ -87,12 +93,20 @@ namespace ICSharpCode.ILSpy } } - public ICompilation GetTypeSystem() + ICompilation typeSystem; + + /// + /// Gets a type system containing all types from this assembly + primitve types from mscorlib. + /// Returns null in case of load errors. + /// + public ICompilation GetTypeSystemOrNull() { + if (typeSystem != null) + return typeSystem; var module = GetPEFileOrNull(); if (module == null) return null; - return new SimpleCompilation(module, MinimalCorlib.Instance); + return typeSystem = new SimpleCompilation(module, MinimalCorlib.Instance); } public AssemblyList AssemblyList => assemblyList; @@ -129,12 +143,12 @@ namespace ICSharpCode.ILSpy if (stream != null) { // Read the module from a precrafted stream - module = new PEFile(fileName, stream, new MyAssemblyResolver(this), PEStreamOptions.Default); + module = new PEFile(fileName, stream); } else { // Read the module from disk (by default) - module = new PEFile(fileName, new FileStream(fileName, FileMode.Open, FileAccess.Read), new MyAssemblyResolver(this), PEStreamOptions.PrefetchEntireImage); + module = new PEFile(fileName, new FileStream(fileName, FileMode.Open, FileAccess.Read), PEStreamOptions.PrefetchEntireImage); } if (DecompilerSettingsPanel.CurrentDecompilerSettings.UseDebugSymbols) { @@ -146,6 +160,9 @@ namespace ICSharpCode.ILSpy // ignore any errors during symbol loading } } + lock (loadedAssemblies) { + loadedAssemblies.Add(module, this); + } return module; } @@ -154,13 +171,13 @@ namespace ICSharpCode.ILSpy var reader = module.Reader; // try to open portable pdb file/embedded pdb info: if (reader.TryOpenAssociatedPortablePdb(fileName, OpenStream, out var provider, out var pdbFileName)) { - module.DebugInfo = new PortableDebugInfoProvider(pdbFileName, provider); + debugInfoProvider = new PortableDebugInfoProvider(pdbFileName, provider); } else { // search for pdb in same directory as dll string pdbDirectory = Path.GetDirectoryName(fileName); pdbFileName = Path.Combine(pdbDirectory, Path.GetFileNameWithoutExtension(fileName) + ".pdb"); if (File.Exists(pdbFileName)) { - module.DebugInfo = new DiaSymNativeDebugInfoProvider(module, pdbFileName, OpenStream(pdbFileName)); + debugInfoProvider = new DiaSymNativeDebugInfoProvider(module, pdbFileName, OpenStream(pdbFileName)); return; } @@ -222,6 +239,16 @@ namespace ICSharpCode.ILSpy { return new MyAssemblyResolver(this); } + + /// + /// Returns the debug info for this assembly. Returns null in case of load errors or no debug info is available. + /// + public IDebugInfoProvider GetDebugInfoOrNull() + { + if (GetPEFileOrNull() == null) + return null; + return debugInfoProvider; + } public LoadedAssembly LookupReferencedAssembly(Decompiler.Metadata.IAssemblyReference reference) { diff --git a/ILSpy/LoadedAssemblyExtensions.cs b/ILSpy/LoadedAssemblyExtensions.cs new file mode 100644 index 000000000..059b4e6ca --- /dev/null +++ b/ILSpy/LoadedAssemblyExtensions.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using ICSharpCode.Decompiler.Metadata; + +namespace ICSharpCode.ILSpy +{ + public static class LoadedAssemblyExtensions + { + public static IAssemblyResolver GetAssemblyResolver(this PEFile file) + { + if (file == null) + throw new ArgumentNullException(nameof(file)); + LoadedAssembly loadedAssembly; + lock (LoadedAssembly.loadedAssemblies) { + if (!LoadedAssembly.loadedAssemblies.TryGetValue(file, out loadedAssembly)) + throw new ArgumentException("The specified file is not associated with a LoadedAssembly!"); + } + return loadedAssembly.GetAssemblyResolver(); + } + } +} diff --git a/ILSpy/SearchPane.cs b/ILSpy/SearchPane.cs index f97b1273d..c55c72563 100644 --- a/ILSpy/SearchPane.cs +++ b/ILSpy/SearchPane.cs @@ -217,7 +217,7 @@ namespace ICSharpCode.ILSpy try { var searcher = GetSearchStrategy(searchMode, searchTerm); foreach (var loadedAssembly in assemblies) { - var typeSystem = loadedAssembly.GetTypeSystem(); + var typeSystem = loadedAssembly.GetTypeSystemOrNull(); if (typeSystem == null) continue; CancellationToken cancellationToken = cts.Token; diff --git a/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs b/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs index a257bfe62..7af0a700e 100644 --- a/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs +++ b/ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs @@ -233,7 +233,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer IEnumerable FindReferencesInAssembly(Decompiler.Metadata.PEFile module, CancellationToken ct) { - IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(module) : null; + IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(module, module.GetAssemblyResolver()) : null; var metadata = module.Metadata; foreach (var type in TreeTraversal.PreOrder(metadata.TypeDefinitions, t => metadata.GetTypeDefinition(t).GetNestedTypes())) { ct.ThrowIfCancellationRequested(); @@ -247,7 +247,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer IEnumerable FindReferencesInTypeScope(CancellationToken ct) { - IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(assemblyScope) : null; + IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(assemblyScope, assemblyScope.GetAssemblyResolver()) : null; foreach (var type in TreeTraversal.PreOrder(typeScopeHandle, t => assemblyScope.Metadata.GetTypeDefinition(t).GetNestedTypes())) { ct.ThrowIfCancellationRequested(); var codeMappingInfo = language.GetCodeMappingInfo(assemblyScope, type); @@ -260,7 +260,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer IEnumerable FindReferencesInEnclosingTypeScope(CancellationToken ct) { - IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(assemblyScope) : null; + IDecompilerTypeSystem ts = provideTypeSystem ? new DecompilerTypeSystem(assemblyScope, assemblyScope.GetAssemblyResolver()) : null; var codeMappingInfo = language.GetCodeMappingInfo(assemblyScope, typeScope.GetDeclaringType()); foreach (var type in TreeTraversal.PreOrder(typeScope.GetDeclaringType(), t => assemblyScope.Metadata.GetTypeDefinition(t).GetNestedTypes())) { ct.ThrowIfCancellationRequested(); diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs index bb3cba6a4..a56b324f9 100644 --- a/ILSpy/TreeNodes/AssemblyTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs @@ -135,7 +135,7 @@ namespace ICSharpCode.ILSpy.TreeNodes // if we crashed on loading, then we don't have any children return; } - typeSystem = new SimpleCompilation(module, MinimalCorlib.Instance); + typeSystem = LoadedAssembly.GetTypeSystemOrNull(); var assembly = (MetadataAssembly)typeSystem.MainAssembly; var metadata = module.Metadata; diff --git a/ILSpy/TreeNodes/BaseTypesEntryNode.cs b/ILSpy/TreeNodes/BaseTypesEntryNode.cs index 42eef9028..7c4362a58 100644 --- a/ILSpy/TreeNodes/BaseTypesEntryNode.cs +++ b/ILSpy/TreeNodes/BaseTypesEntryNode.cs @@ -65,16 +65,16 @@ namespace ICSharpCode.ILSpy.TreeNodes protected override void LoadChildren() { - DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module); + DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver()); var t = typeSystem.ResolveAsType(handle).GetDefinition(); if (t != null) { - BaseTypesTreeNode.AddBaseTypes(this.Children, ((MetadataAssembly)t.ParentAssembly).PEFile, t); + BaseTypesTreeNode.AddBaseTypes(this.Children, t.ParentAssembly.PEFile, t); } } public override void ActivateItem(System.Windows.RoutedEventArgs e) { - DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module); + DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver()); var t = typeSystem.ResolveAsType(handle).GetDefinition(); e.Handled = ActivateItem(this, t); } @@ -98,7 +98,7 @@ namespace ICSharpCode.ILSpy.TreeNodes IEntity IMemberTreeNode.Member { get { - DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module); + DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver()); var t = typeSystem.ResolveAsType(handle).GetDefinition(); return t; } diff --git a/ILSpy/TreeNodes/GeneratePdbContextMenuEntry.cs b/ILSpy/TreeNodes/GeneratePdbContextMenuEntry.cs index e8374e0ba..244a995ad 100644 --- a/ILSpy/TreeNodes/GeneratePdbContextMenuEntry.cs +++ b/ILSpy/TreeNodes/GeneratePdbContextMenuEntry.cs @@ -7,7 +7,7 @@ using System.Text; using System.Threading.Tasks; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.CSharp; -using ICSharpCode.Decompiler.Pdb; +using ICSharpCode.Decompiler.DebugInfo; using ICSharpCode.ILSpy.TextView; using Microsoft.Win32; @@ -33,7 +33,7 @@ namespace ICSharpCode.ILSpy.TreeNodes using (FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write)) { try { var file = assembly.GetPEFileOrNull(); - var decompiler = new CSharpDecompiler(file, options.DecompilerSettings); + var decompiler = new CSharpDecompiler(file, assembly.GetAssemblyResolver(), options.DecompilerSettings); PortablePdbWriter.WritePdb(file, decompiler, options.DecompilerSettings, stream); } catch (OperationCanceledException) { output.WriteLine(); From a4962e17cdc39bfeaa42048be8a68ce4d719afc6 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 7 Jul 2018 19:28:47 +0200 Subject: [PATCH 03/13] Fix ToString methods of CSharpLanguage --- ILSpy/Languages/CSharpLanguage.cs | 221 +++++++++--------------------- ILSpy/Languages/Language.cs | 13 +- ILSpy/TreeNodes/TypeTreeNode.cs | 3 +- 3 files changed, 77 insertions(+), 160 deletions(-) diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index a4d7cdad3..cb96b1cc6 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -403,19 +403,46 @@ namespace ICSharpCode.ILSpy return base.WriteResourceToFile(fileName, resourceName, entryStream); } } + static readonly CSharpFormattingOptions TypeToStringFormattingOptions = FormattingOptionsFactory.CreateEmpty(); + public override string TypeToString(IType type, bool includeNamespace) { if (type == null) throw new ArgumentNullException(nameof(type)); TypeSystemAstBuilder builder = new TypeSystemAstBuilder(); + builder.AlwaysUseShortTypeNames = !includeNamespace; AstType astType = builder.ConvertType(type); StringWriter w = new StringWriter(); - astType.AcceptVisitor(new CSharpOutputVisitor(w, FormattingOptionsFactory.CreateAllman())); + astType.AcceptVisitor(new CSharpOutputVisitor(w, TypeToStringFormattingOptions)); return w.ToString(); } + public override string TypeDefinitionToString(ITypeDefinition type, bool includeNamespace) + { + if (type == null) + throw new ArgumentNullException(nameof(type)); + var buffer = new System.Text.StringBuilder(); + if (includeNamespace) { + buffer.Append(type.FullName); + } else { + buffer.Append(type.Name); + } + if (type.TypeParameterCount > 0) { + buffer.Append('<'); + int i = 0; + foreach (var tp in type.TypeParameters) { + if (i > 0) + buffer.Append(", "); + buffer.Append(tp.Name); + i++; + } + buffer.Append('>'); + } + return buffer.ToString(); + } + public override string FieldToString(IField field, bool includeTypeName, bool includeNamespace) { if (field == null) @@ -429,7 +456,7 @@ namespace ICSharpCode.ILSpy return typeName.Name + "." + simple; return typeName + "." + simple; } - /* + public override string PropertyToString(IProperty property, bool includeTypeName, bool includeNamespace, bool? isIndexer = null) { if (property == null) @@ -439,147 +466,66 @@ namespace ICSharpCode.ILSpy convertTypeOptions |= ConvertTypeOptions.IncludeNamespace; if (includeTypeName) convertTypeOptions |= ConvertTypeOptions.IncludeOuterTypeName; - var metadata = property.Module.Metadata; - var pd = metadata.GetPropertyDefinition(property.Handle); - var accessors = pd.GetAccessors(); - var accessorHandle = accessors.GetAny(); - var accessor = metadata.GetMethodDefinition(accessorHandle); - var declaringType = metadata.GetTypeDefinition(accessor.GetDeclaringType()); - if (!isIndexer.HasValue) { - isIndexer = accessor.GetDeclaringType().GetDefaultMemberName(metadata) != null; - } var buffer = new System.Text.StringBuilder(); if (isIndexer.Value) { - var overrides = accessorHandle.GetMethodImplementations(metadata); - if (overrides.Any()) { - string name = metadata.GetString(pd.Name); + if (property.IsExplicitInterfaceImplementation) { + string name = property.Name; int index = name.LastIndexOf('.'); if (index > 0) { buffer.Append(name.Substring(0, index)); - buffer.Append(@"."); + buffer.Append('.'); } } buffer.Append(@"this["); - var signature = pd.DecodeSignature(new AstTypeBuilder(convertTypeOptions), new GenericContext(accessorHandle, property.Module)); - - var parameterHandles = accessor.GetParameters(); int i = 0; - CustomAttributeHandleCollection? returnTypeAttributes = null; - if (signature.RequiredParameterCount > parameterHandles.Count) { - foreach (var type in signature.ParameterTypes) { - if (i > 0) - buffer.Append(", "); - buffer.Append(TypeToString(signature.ParameterTypes[i], metadata, null)); - i++; - } - } else { - foreach (var h in parameterHandles) { - var p = metadata.GetParameter(h); - if (p.SequenceNumber > 0 && i < signature.ParameterTypes.Length) { - if (i > 0) - buffer.Append(", "); - buffer.Append(TypeToString(signature.ParameterTypes[i], metadata, p.GetCustomAttributes(), h)); - i++; - } - if (p.SequenceNumber == 0) { - returnTypeAttributes = p.GetCustomAttributes(); - } - } - } - if (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs) { - if (signature.ParameterTypes.Length > 0) + var parameters = property.Parameters; + foreach (var param in parameters) { + if (i > 0) buffer.Append(", "); - buffer.Append("..."); + buffer.Append(TypeToString(param.Type, includeNamespace)); + i++; } buffer.Append(@"]"); - buffer.Append(" : "); - buffer.Append(TypeToString(signature.ReturnType, metadata, returnTypeAttributes)); } else { - var signature = pd.DecodeSignature(new AstTypeBuilder(convertTypeOptions), new GenericContext(accessorHandle, property.Module)); - - var parameterHandles = accessor.GetParameters(); - - CustomAttributeHandleCollection? returnTypeAttributes = null; - if (parameterHandles.Count > 0) { - var p = metadata.GetParameter(parameterHandles.First()); - if (p.SequenceNumber == 0) { - returnTypeAttributes = p.GetCustomAttributes(); - } - } - buffer.Append(metadata.GetString(pd.Name)); - buffer.Append(" : "); - buffer.Append(TypeToString(signature.ReturnType, metadata, returnTypeAttributes)); + buffer.Append(property.Name); } + buffer.Append(" : "); + buffer.Append(TypeToString(property.ReturnType, includeNamespace)); return buffer.ToString(); } - static readonly CSharpFormattingOptions TypeToStringFormattingOptions = FormattingOptionsFactory.CreateEmpty(); - string TypeToString(AstType astType, MetadataReader metadata, CustomAttributeHandleCollection? customAttributes, ParameterHandle paramHandle = default) + public override string MethodToString(IMethod method, bool includeTypeName, bool includeNamespace) { - StringWriter w = new StringWriter(); - - if (astType is ComposedType ct && ct.HasRefSpecifier) { - if (!paramHandle.IsNil) { - var p = metadata.GetParameter(paramHandle); - if ((p.Attributes & ParameterAttributes.In) == 0 && (p.Attributes & ParameterAttributes.Out) != 0) { - w.Write("out "); - } else { - w.Write("ref "); - } - } else { - w.Write("ref "); - } - - astType = ct.BaseType; - astType.Remove(); - } - - var st = new SyntaxTree(); - st.AddChild(astType, Roles.Type); - //st.AcceptVisitor(new InsertDynamicTypeVisitor(metadata, customAttributes)); - // TODO: we should probably remove AstTypeBuilder and use TypeBuilder(with dummy compilation)+TSAstBuilder instead. - // Otherwise we'd need to duplicate a whole bunch of logic... - st.FirstChild.AcceptVisitor(new CSharpOutputVisitor(w, TypeToStringFormattingOptions)); - return w.ToString(); - } - - public override string MethodToString(Decompiler.Metadata.MethodDefinition method, bool includeTypeName, bool includeNamespace) - { - if (method.IsNil) - throw new ArgumentNullException("method"); + if (method == null) + throw new ArgumentNullException(nameof(method)); ConvertTypeOptions convertTypeOptions = ConvertTypeOptions.IncludeTypeParameterDefinitions; if (includeNamespace) convertTypeOptions |= ConvertTypeOptions.IncludeNamespace; if (includeTypeName) convertTypeOptions |= ConvertTypeOptions.IncludeOuterTypeName; - var metadata = method.Module.Metadata; - var md = metadata.GetMethodDefinition(method.Handle); string name; - if (md.IsConstructor(metadata)) { - name = TypeToString(new Decompiler.Metadata.TypeDefinition(method.Module, md.GetDeclaringType()), includeNamespace: includeNamespace); + if (method.IsConstructor) { + name = TypeDefinitionToString(method.DeclaringTypeDefinition, includeNamespace: includeNamespace); } else { if (includeTypeName) { - name = TypeToString(new Decompiler.Metadata.TypeDefinition(method.Module, md.GetDeclaringType()), includeNamespace: includeNamespace) + "."; + name = TypeDefinitionToString(method.DeclaringTypeDefinition, includeNamespace: includeNamespace) + "."; } else { name = ""; } - name += metadata.GetString(md.Name); + name += method.Name; } - var signature = md.DecodeSignature(new AstTypeBuilder(convertTypeOptions), new GenericContext(method)); - int i = 0; var buffer = new System.Text.StringBuilder(name); - var genericParams = md.GetGenericParameters(); - if (genericParams.Count > 0) { + + if (method.TypeParameters.Count > 0) { buffer.Append('<'); - foreach (var h in genericParams) { - var gp = metadata.GetGenericParameter(h); + foreach (var tp in method.TypeParameters) { if (i > 0) buffer.Append(", "); - buffer.Append(metadata.GetString(gp.Name)); + buffer.Append(tp.Name); i++; } buffer.Append('>'); @@ -587,71 +533,30 @@ namespace ICSharpCode.ILSpy buffer.Append('('); i = 0; - var parameterHandles = md.GetParameters(); - CustomAttributeHandleCollection? returnTypeAttributes = null; - if (signature.RequiredParameterCount > parameterHandles.Count) { - foreach (var type in signature.ParameterTypes) { - if (i > 0) - buffer.Append(", "); - buffer.Append(TypeToString(signature.ParameterTypes[i], metadata, null)); - i++; - } - } else { - foreach (var h in parameterHandles) { - var p = metadata.GetParameter(h); - if (p.SequenceNumber > 0 && i < signature.ParameterTypes.Length) { - if (i > 0) - buffer.Append(", "); - buffer.Append(TypeToString(signature.ParameterTypes[i], metadata, p.GetCustomAttributes(), h)); - i++; - } - if (p.SequenceNumber == 0) { - returnTypeAttributes = p.GetCustomAttributes(); - } - } - } - if (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs) { - if (signature.ParameterTypes.Length > 0) + var parameters = method.Parameters; + foreach (var param in parameters) { + if (i > 0) buffer.Append(", "); - buffer.Append("..."); + buffer.Append(TypeToString(param.Type, includeNamespace)); + i++; } + buffer.Append(')'); buffer.Append(" : "); - buffer.Append(TypeToString(signature.ReturnType, metadata, returnTypeAttributes)); + buffer.Append(TypeToString(method.ReturnType, includeNamespace)); return buffer.ToString(); } - public override string EventToString(Decompiler.Metadata.EventDefinition @event, bool includeTypeName, bool includeNamespace) + public override string EventToString(IEvent @event, bool includeTypeName, bool includeNamespace) { - if (@event.IsNil) + if (@event == null) throw new ArgumentNullException(nameof(@event)); - ConvertTypeOptions convertTypeOptions = ConvertTypeOptions.IncludeTypeParameterDefinitions; - if (includeNamespace) - convertTypeOptions |= ConvertTypeOptions.IncludeNamespace; - if (includeTypeName) - convertTypeOptions |= ConvertTypeOptions.IncludeOuterTypeName; - var metadata = @event.Module.Metadata; - var ed = metadata.GetEventDefinition(@event.Handle); - var accessors = ed.GetAccessors(); - var accessorHandle = accessors.GetAny(); - var accessor = metadata.GetMethodDefinition(accessorHandle); - var declaringType = metadata.GetTypeDefinition(accessor.GetDeclaringType()); - var signature = ed.DecodeSignature(metadata, new AstTypeBuilder(convertTypeOptions), new GenericContext(accessorHandle, @event.Module)); - - var parameterHandles = accessor.GetParameters(); - CustomAttributeHandleCollection? returnTypeAttributes = null; - if (parameterHandles.Count > 0) { - var p = metadata.GetParameter(parameterHandles.First()); - if (p.SequenceNumber == 0) { - returnTypeAttributes = p.GetCustomAttributes(); - } - } var buffer = new System.Text.StringBuilder(); - buffer.Append(metadata.GetString(ed.Name)); + buffer.Append(GetDisplayName(@event, includeTypeName, includeNamespace)); buffer.Append(" : "); - buffer.Append(TypeToString(signature, metadata, returnTypeAttributes)); + buffer.Append(TypeToString(@event.ReturnType, includeNamespace)); return buffer.ToString(); - }*/ + } public override bool ShowMember(IEntity member) { diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs index 76332e013..c719d3f30 100644 --- a/ILSpy/Languages/Language.cs +++ b/ILSpy/Languages/Language.cs @@ -149,7 +149,7 @@ namespace ICSharpCode.ILSpy } /// - /// Converts a type definition, reference or specification into a string. This method is used by the type tree nodes and search results. + /// Converts a type definition, reference or specification into a string. This method is used by tree nodes and search results. /// public virtual string TypeToString(IType type, bool includeNamespace) { @@ -159,6 +159,17 @@ namespace ICSharpCode.ILSpy return type.Name; } + /// + /// Converts a type definition into a string. This method is used by tree nodes and search results. + /// + public virtual string TypeDefinitionToString(ITypeDefinition type, bool includeNamespace) + { + if (includeNamespace) + return type.FullName; + else + return type.Name; + } + /// /// Converts a member signature to a string. /// This is used for displaying the tooltip on a member reference. diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs index d4d6f95db..15de00d12 100644 --- a/ILSpy/TreeNodes/TypeTreeNode.cs +++ b/ILSpy/TreeNodes/TypeTreeNode.cs @@ -40,7 +40,8 @@ namespace ICSharpCode.ILSpy.TreeNodes public AssemblyTreeNode ParentAssemblyNode { get; } - public override object Text => this.Language.TypeToString(TypeDefinition, includeNamespace: false) + TypeDefinition.MetadataToken.ToSuffixString(); + public override object Text => this.Language.TypeDefinitionToString(TypeDefinition, includeNamespace: false) + + TypeDefinition.MetadataToken.ToSuffixString(); public override bool IsPublicAPI { get { From e3e7ea5e6821e38ebd90120c680e81dde2c7ad49 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 7 Jul 2018 19:44:54 +0200 Subject: [PATCH 04/13] Reimplement CSharpILMixedLanguage, ILAstLanguage and DebugSteps --- ILSpy/DebugSteps.xaml.cs | 10 +- ILSpy/ILSpy.csproj | 3 +- ILSpy/Languages/CSharpILMixedLanguage.cs | 4 +- ILSpy/Languages/ILAstLanguage.cs | 36 ++--- ILSpy/Languages/ILLanguage.cs | 12 +- ILSpy/Languages/ILSignatureProvider.cs | 172 ----------------------- ILSpy/SearchStrategies.cs | 12 +- 7 files changed, 40 insertions(+), 209 deletions(-) delete mode 100644 ILSpy/Languages/ILSignatureProvider.cs diff --git a/ILSpy/DebugSteps.xaml.cs b/ILSpy/DebugSteps.xaml.cs index d2e5ae0fa..e5c1431e3 100644 --- a/ILSpy/DebugSteps.xaml.cs +++ b/ILSpy/DebugSteps.xaml.cs @@ -16,7 +16,7 @@ namespace ICSharpCode.ILSpy public static ILAstWritingOptions Options => writingOptions; -#if false +#if DEBUG ILAstLanguage language; #endif @@ -24,7 +24,7 @@ namespace ICSharpCode.ILSpy { InitializeComponent(); -#if false +#if DEBUG MainWindow.Instance.SessionSettings.FilterSettings.PropertyChanged += FilterSettings_PropertyChanged; MainWindow.Instance.SelectionChanged += SelectionChanged; writingOptions.PropertyChanged += WritingOptions_PropertyChanged; @@ -52,7 +52,7 @@ namespace ICSharpCode.ILSpy private void FilterSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { -#if false +#if DEBUG if (e.PropertyName == "Language") { if (language != null) { language.StepperUpdated -= ILAstStepperUpdated; @@ -68,7 +68,7 @@ namespace ICSharpCode.ILSpy private void ILAstStepperUpdated(object sender, EventArgs e) { -#if false +#if DEBUG if (language == null) return; Dispatcher.Invoke(() => { tree.ItemsSource = language.Stepper.Steps; @@ -84,7 +84,7 @@ namespace ICSharpCode.ILSpy void IPane.Closed() { -#if false +#if DEBUG MainWindow.Instance.SessionSettings.FilterSettings.PropertyChanged -= FilterSettings_PropertyChanged; MainWindow.Instance.SelectionChanged -= SelectionChanged; writingOptions.PropertyChanged -= WritingOptions_PropertyChanged; diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index b4420f480..71e249aa4 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -120,6 +120,7 @@ + @@ -130,8 +131,8 @@ + - diff --git a/ILSpy/Languages/CSharpILMixedLanguage.cs b/ILSpy/Languages/CSharpILMixedLanguage.cs index 9c11200c1..c5d37efe0 100644 --- a/ILSpy/Languages/CSharpILMixedLanguage.cs +++ b/ILSpy/Languages/CSharpILMixedLanguage.cs @@ -38,7 +38,7 @@ using ICSharpCode.Decompiler.Util; namespace ICSharpCode.ILSpy { - using SequencePoint = ICSharpCode.Decompiler.Metadata.SequencePoint; + using SequencePoint = ICSharpCode.Decompiler.DebugInfo.SequencePoint; [Export(typeof(Language))] class CSharpILMixedLanguage : ILLanguage @@ -57,7 +57,7 @@ namespace ICSharpCode.ILSpy static CSharpDecompiler CreateDecompiler(PEFile module, DecompilationOptions options) { - CSharpDecompiler decompiler = new CSharpDecompiler(module, options.DecompilerSettings); + CSharpDecompiler decompiler = new CSharpDecompiler(module, module.GetAssemblyResolver(), options.DecompilerSettings); decompiler.CancellationToken = options.CancellationToken; return decompiler; } diff --git a/ILSpy/Languages/ILAstLanguage.cs b/ILSpy/Languages/ILAstLanguage.cs index 6dd6bb1ae..a7c0e1509 100644 --- a/ILSpy/Languages/ILAstLanguage.cs +++ b/ILSpy/Languages/ILAstLanguage.cs @@ -70,11 +70,11 @@ namespace ICSharpCode.ILSpy } } - public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) + public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) { base.DecompileMethod(method, output, options); - var module = method.Module; - new ReflectionDisassembler(output, options.CancellationToken).DisassembleMethodHeader(module, method.Handle); + new ReflectionDisassembler(output, options.CancellationToken) + .DisassembleMethodHeader(method.ParentAssembly.PEFile, (SRM.MethodDefinitionHandle)method.MetadataToken); output.WriteLine(); output.WriteLine(); } @@ -83,17 +83,17 @@ namespace ICSharpCode.ILSpy { public TypedIL() : base("Typed IL") {} - public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) + public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) { base.DecompileMethod(method, output, options); - var metadata = method.Module.Metadata; - var methodDef = metadata.GetMethodDefinition(method.Handle); + var module = method.ParentAssembly.PEFile; + var methodDef = module.Metadata.GetMethodDefinition((SRM.MethodDefinitionHandle)method.MetadataToken); if (!methodDef.HasBody()) return; - var typeSystem = new DecompilerTypeSystem(method.Module); + var typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver()); ILReader reader = new ILReader(typeSystem); - var methodBody = method.Module.Reader.GetMethodBody(methodDef.RelativeVirtualAddress); - reader.WriteTypedIL(method.Module, method.Handle, methodBody, output, options.CancellationToken); + var methodBody = module.Reader.GetMethodBody(methodDef.RelativeVirtualAddress); + reader.WriteTypedIL(module, (SRM.MethodDefinitionHandle)method.MetadataToken, methodBody, output, options.CancellationToken); } } @@ -106,21 +106,23 @@ namespace ICSharpCode.ILSpy this.transforms = transforms; } - public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) + public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) { base.DecompileMethod(method, output, options); - var metadata = method.Module.Metadata; - var methodDef = metadata.GetMethodDefinition(method.Handle); + var module = method.ParentAssembly.PEFile; + var metadata = module.Metadata; + var methodDef = metadata.GetMethodDefinition((SRM.MethodDefinitionHandle)method.MetadataToken); if (!methodDef.HasBody()) return; - var typeSystem = new DecompilerTypeSystem(method.Module); - var specializingTypeSystem = typeSystem.GetSpecializingTypeSystem(new SimpleTypeResolveContext(typeSystem.ResolveAsMethod(method.Handle))); + IAssemblyResolver assemblyResolver = module.GetAssemblyResolver(); + var typeSystem = new DecompilerTypeSystem(module, assemblyResolver); + var specializingTypeSystem = typeSystem.GetSpecializingTypeSystem(new SimpleTypeResolveContext(typeSystem.ResolveAsMethod(method.MetadataToken))); var reader = new ILReader(specializingTypeSystem); reader.UseDebugSymbols = options.DecompilerSettings.UseDebugSymbols; - var methodBody = method.Module.Reader.GetMethodBody(methodDef.RelativeVirtualAddress); - ILFunction il = reader.ReadIL(method.Module, method.Handle, methodBody, options.CancellationToken); + var methodBody = module.Reader.GetMethodBody(methodDef.RelativeVirtualAddress); + ILFunction il = reader.ReadIL(module, (SRM.MethodDefinitionHandle)method.MetadataToken, methodBody, options.CancellationToken); var namespaces = new HashSet(); - var decompiler = new CSharpDecompiler(typeSystem, options.DecompilerSettings) { CancellationToken = options.CancellationToken }; + var decompiler = new CSharpDecompiler(typeSystem, assemblyResolver, options.DecompilerSettings) { CancellationToken = options.CancellationToken }; ILTransformContext context = decompiler.CreateILTransformContext(il); context.Stepper.StepLimit = options.StepLimit; context.Stepper.IsDebug = options.IsDebug; diff --git a/ILSpy/Languages/ILLanguage.cs b/ILSpy/Languages/ILLanguage.cs index 3b63b4d47..290a023d1 100644 --- a/ILSpy/Languages/ILLanguage.cs +++ b/ILSpy/Languages/ILLanguage.cs @@ -63,19 +63,19 @@ namespace ICSharpCode.ILSpy public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) { var dis = CreateDisassembler(output, options); - dis.DisassembleMethod(((MetadataAssembly)method.ParentAssembly).PEFile, (MethodDefinitionHandle)method.MetadataToken); + dis.DisassembleMethod(method.ParentAssembly.PEFile, (MethodDefinitionHandle)method.MetadataToken); } public override void DecompileField(IField field, ITextOutput output, DecompilationOptions options) { var dis = CreateDisassembler(output, options); - dis.DisassembleField(((MetadataAssembly)field.ParentAssembly).PEFile, (FieldDefinitionHandle)field.MetadataToken); + dis.DisassembleField(field.ParentAssembly.PEFile, (FieldDefinitionHandle)field.MetadataToken); } public override void DecompileProperty(IProperty property, ITextOutput output, DecompilationOptions options) { var dis = CreateDisassembler(output, options); - PEFile module = ((MetadataAssembly)property.ParentAssembly).PEFile; + PEFile module = property.ParentAssembly.PEFile; dis.DisassembleProperty(module, (PropertyDefinitionHandle)property.MetadataToken); var pd = module.Metadata.GetPropertyDefinition((PropertyDefinitionHandle)property.MetadataToken); var accessors = pd.GetAccessors(); @@ -97,7 +97,7 @@ namespace ICSharpCode.ILSpy public override void DecompileEvent(IEvent ev, ITextOutput output, DecompilationOptions options) { var dis = CreateDisassembler(output, options); - PEFile module = ((MetadataAssembly)ev.ParentAssembly).PEFile; + PEFile module = ev.ParentAssembly.PEFile; dis.DisassembleEvent(module, (EventDefinitionHandle)ev.MetadataToken); var ed = ((MetadataReader)module.Metadata).GetEventDefinition((EventDefinitionHandle)ev.MetadataToken); @@ -123,14 +123,14 @@ namespace ICSharpCode.ILSpy public override void DecompileType(ITypeDefinition type, ITextOutput output, DecompilationOptions options) { var dis = CreateDisassembler(output, options); - PEFile module = ((MetadataAssembly)type.ParentAssembly).PEFile; + PEFile module = type.ParentAssembly.PEFile; dis.DisassembleType(module, (TypeDefinitionHandle)type.MetadataToken); } public override void DecompileNamespace(string nameSpace, IEnumerable types, ITextOutput output, DecompilationOptions options) { var dis = CreateDisassembler(output, options); - PEFile module = ((MetadataAssembly)types.FirstOrDefault()?.ParentAssembly)?.PEFile; + PEFile module = types.FirstOrDefault()?.ParentAssembly.PEFile; dis.DisassembleNamespace(nameSpace, module, types.Select(t => (TypeDefinitionHandle)t.MetadataToken)); } diff --git a/ILSpy/Languages/ILSignatureProvider.cs b/ILSpy/Languages/ILSignatureProvider.cs deleted file mode 100644 index 3750461e8..000000000 --- a/ILSpy/Languages/ILSignatureProvider.cs +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Immutable; -using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.Metadata; -using SRM = System.Reflection.Metadata; - -namespace ICSharpCode.ILSpy -{ - class ILSignatureProvider : SRM.ISignatureTypeProvider - { - public static readonly ILSignatureProvider WithoutNamespace = new ILSignatureProvider(false); - public static readonly ILSignatureProvider WithNamespace = new ILSignatureProvider(true); - - bool includeNamespace; - - public ILSignatureProvider(bool includeNamespace) - { - this.includeNamespace = includeNamespace; - } - - public string GetArrayType(string elementType, SRM.ArrayShape shape) - { - string printedShape = ""; - for (int i = 0; i < shape.Rank; i++) { - if (i > 0) - printedShape += ", "; - if (i < shape.LowerBounds.Length || i < shape.Sizes.Length) { - int lower = 0; - if (i < shape.LowerBounds.Length) { - lower = shape.LowerBounds[i]; - printedShape += lower.ToString(); - } - printedShape += "..."; - if (i < shape.Sizes.Length) - printedShape += (lower + shape.Sizes[i] - 1).ToString(); - } - } - return $"{elementType}[{printedShape}]"; - } - - public string GetByReferenceType(string elementType) - { - return elementType + "&"; - } - - public string GetFunctionPointerType(SRM.MethodSignature signature) - { - return "method " + signature.ReturnType + " *(" + string.Join(", ", signature.ParameterTypes) + ")"; - } - - public string GetGenericInstantiation(string genericType, ImmutableArray typeArguments) - { - return genericType + "<" + string.Join(", ", typeArguments) + ">"; - } - - public string GetGenericMethodParameter(GenericContext genericContext, int index) - { - return "!!" + genericContext.GetGenericMethodTypeParameterName(index); - } - - public string GetGenericTypeParameter(GenericContext genericContext, int index) - { - return "!" + genericContext.GetGenericTypeParameterName(index); - } - - public string GetModifiedType(string modifier, string unmodifiedType, bool isRequired) - { - string modifierKeyword = isRequired ? "modreq" : "modopt"; - return $"{unmodifiedType} {modifierKeyword}({modifier})"; - } - - public string GetPinnedType(string elementType) - { - throw new NotImplementedException(); - } - - public string GetPointerType(string elementType) - { - return elementType + "*"; - } - - public string GetPrimitiveType(SRM.PrimitiveTypeCode typeCode) - { - switch (typeCode) { - case SRM.PrimitiveTypeCode.Boolean: - return "bool"; - case SRM.PrimitiveTypeCode.Byte: - return "uint8"; - case SRM.PrimitiveTypeCode.SByte: - return "int8"; - case SRM.PrimitiveTypeCode.Char: - return "char"; - case SRM.PrimitiveTypeCode.Int16: - return "int16"; - case SRM.PrimitiveTypeCode.UInt16: - return "uint16"; - case SRM.PrimitiveTypeCode.Int32: - return "int32"; - case SRM.PrimitiveTypeCode.UInt32: - return "uint32"; - case SRM.PrimitiveTypeCode.Int64: - return "int64"; - case SRM.PrimitiveTypeCode.UInt64: - return "uint64"; - case SRM.PrimitiveTypeCode.Single: - return "float32"; - case SRM.PrimitiveTypeCode.Double: - return "float64"; - case SRM.PrimitiveTypeCode.IntPtr: - return "native int"; - case SRM.PrimitiveTypeCode.UIntPtr: - return "native uint"; - case SRM.PrimitiveTypeCode.Object: - return "object"; - case SRM.PrimitiveTypeCode.String: - return "string"; - case SRM.PrimitiveTypeCode.TypedReference: - return "typedref"; - case SRM.PrimitiveTypeCode.Void: - return "void"; - default: - throw new ArgumentOutOfRangeException(); - } - } - - public string GetSZArrayType(string elementType) - { - return elementType + "[]"; - } - - public string GetTypeFromDefinition(SRM.MetadataReader reader, SRM.TypeDefinitionHandle handle, byte rawTypeKind) - { - if (!includeNamespace) { - return Decompiler.Disassembler.DisassemblerHelpers.Escape(handle.GetFullTypeName(reader).Name); - } - - return handle.GetFullTypeName(reader).ToILNameString(); - } - - public string GetTypeFromReference(SRM.MetadataReader reader, SRM.TypeReferenceHandle handle, byte rawTypeKind) - { - if (!includeNamespace) { - return Decompiler.Disassembler.DisassemblerHelpers.Escape(handle.GetFullTypeName(reader).Name); - } - - return handle.GetFullTypeName(reader).ToILNameString(); - } - - public string GetTypeFromSpecification(SRM.MetadataReader reader, GenericContext genericContext, SRM.TypeSpecificationHandle handle, byte rawTypeKind) - { - return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext); - } - } -} diff --git a/ILSpy/SearchStrategies.cs b/ILSpy/SearchStrategies.cs index 907d72145..df3926420 100644 --- a/ILSpy/SearchStrategies.cs +++ b/ILSpy/SearchStrategies.cs @@ -163,7 +163,7 @@ namespace ICSharpCode.ILSpy { switch (member) { case ITypeDefinition t: - return language.TypeToString(t, includeNamespace: fullName); + return language.TypeDefinitionToString(t, includeNamespace: fullName); case IField f: return language.FieldToString(f, fullName, fullName); case IProperty p: @@ -193,7 +193,7 @@ namespace ICSharpCode.ILSpy Image = image(item), Name = GetLanguageSpecificName(language, item), LocationImage = TypeTreeNode.GetIcon(type), - Location = language.TypeToString(type, includeNamespace: true) + Location = language.TypeDefinitionToString(type, includeNamespace: true) }); } } @@ -497,7 +497,7 @@ namespace ICSharpCode.ILSpy public override void Search(ITypeDefinition type, Language language, Action addResult) { if (MatchName(type, language)) { - string name = language.TypeToString(type, includeNamespace: false); + string name = language.TypeDefinitionToString(type, includeNamespace: false); var declaringType = type.DeclaringTypeDefinition; addResult(new SearchResult { Member = type, @@ -505,7 +505,7 @@ namespace ICSharpCode.ILSpy Image = TypeTreeNode.GetIcon(type), Name = name, LocationImage = declaringType != null ? TypeTreeNode.GetIcon(declaringType) : Images.Namespace, - Location = declaringType != null ? language.TypeToString(declaringType, includeNamespace: true) : type.Namespace + Location = declaringType != null ? language.TypeDefinitionToString(declaringType, includeNamespace: true) : type.Namespace }); } @@ -526,7 +526,7 @@ namespace ICSharpCode.ILSpy { if (MatchName(type, language)) { - string name = language.TypeToString(type, includeNamespace: false); + string name = language.TypeDefinitionToString(type, includeNamespace: false); var declaringType = type.DeclaringTypeDefinition; addResult(new SearchResult { Member = type, @@ -534,7 +534,7 @@ namespace ICSharpCode.ILSpy Fitness = CalculateFitness(type), Name = name, LocationImage = declaringType != null ? TypeTreeNode.GetIcon(declaringType) : Images.Namespace, - Location = declaringType != null ? language.TypeToString(declaringType, includeNamespace: true) : type.Namespace + Location = declaringType != null ? language.TypeDefinitionToString(declaringType, includeNamespace: true) : type.Namespace }); } From 3630edab818d37ac6bdd329d9c289d7d38856426 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 8 Jul 2018 17:10:22 +0200 Subject: [PATCH 05/13] Remove TypeDefinitionToString, add BaseTypesTreeNode --- ILSpy/Languages/CSharpLanguage.cs | 55 +++++-------------------- ILSpy/Languages/Language.cs | 18 ++++---- ILSpy/Languages/Languages.cs | 2 +- ILSpy/LoadedAssemblyExtensions.cs | 13 +++++- ILSpy/SearchStrategies.cs | 12 +++--- ILSpy/TreeNodes/BaseTypesEntryNode.cs | 44 +++++++++++--------- ILSpy/TreeNodes/BaseTypesTreeNode.cs | 3 +- ILSpy/TreeNodes/DerivedTypesTreeNode.cs | 35 +++++++--------- ILSpy/TreeNodes/IMemberTreeNode.cs | 4 ++ ILSpy/TreeNodes/TypeTreeNode.cs | 8 ++-- 10 files changed, 87 insertions(+), 107 deletions(-) diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index cb96b1cc6..b4460d496 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -403,8 +403,8 @@ namespace ICSharpCode.ILSpy return base.WriteResourceToFile(fileName, resourceName, entryStream); } } - static readonly CSharpFormattingOptions TypeToStringFormattingOptions = FormattingOptionsFactory.CreateEmpty(); + static readonly CSharpFormattingOptions TypeToStringFormattingOptions = FormattingOptionsFactory.CreateEmpty(); public override string TypeToString(IType type, bool includeNamespace) { @@ -419,30 +419,6 @@ namespace ICSharpCode.ILSpy return w.ToString(); } - public override string TypeDefinitionToString(ITypeDefinition type, bool includeNamespace) - { - if (type == null) - throw new ArgumentNullException(nameof(type)); - var buffer = new System.Text.StringBuilder(); - if (includeNamespace) { - buffer.Append(type.FullName); - } else { - buffer.Append(type.Name); - } - if (type.TypeParameterCount > 0) { - buffer.Append('<'); - int i = 0; - foreach (var tp in type.TypeParameters) { - if (i > 0) - buffer.Append(", "); - buffer.Append(tp.Name); - i++; - } - buffer.Append('>'); - } - return buffer.ToString(); - } - public override string FieldToString(IField field, bool includeTypeName, bool includeNamespace) { if (field == null) @@ -451,21 +427,13 @@ namespace ICSharpCode.ILSpy string simple = field.Name + " : " + TypeToString(field.Type, includeNamespace); if (!includeTypeName) return simple; - var typeName = field.DeclaringTypeDefinition.FullTypeName; - if (!includeNamespace) - return typeName.Name + "." + simple; - return typeName + "." + simple; + return TypeToString(MakeParameterizedType(field.DeclaringTypeDefinition), includeNamespace) + "." + simple; } public override string PropertyToString(IProperty property, bool includeTypeName, bool includeNamespace, bool? isIndexer = null) { if (property == null) throw new ArgumentNullException(nameof(property)); - ConvertTypeOptions convertTypeOptions = ConvertTypeOptions.IncludeTypeParameterDefinitions; - if (includeNamespace) - convertTypeOptions |= ConvertTypeOptions.IncludeNamespace; - if (includeTypeName) - convertTypeOptions |= ConvertTypeOptions.IncludeOuterTypeName; var buffer = new System.Text.StringBuilder(); if (isIndexer.Value) { if (property.IsExplicitInterfaceImplementation) { @@ -493,25 +461,21 @@ namespace ICSharpCode.ILSpy } buffer.Append(" : "); buffer.Append(TypeToString(property.ReturnType, includeNamespace)); - return buffer.ToString(); + if (!includeTypeName) + return buffer.ToString(); + return TypeToString(MakeParameterizedType(property.DeclaringTypeDefinition), includeNamespace) + "." + buffer.ToString(); } - public override string MethodToString(IMethod method, bool includeTypeName, bool includeNamespace) { if (method == null) throw new ArgumentNullException(nameof(method)); - ConvertTypeOptions convertTypeOptions = ConvertTypeOptions.IncludeTypeParameterDefinitions; - if (includeNamespace) - convertTypeOptions |= ConvertTypeOptions.IncludeNamespace; - if (includeTypeName) - convertTypeOptions |= ConvertTypeOptions.IncludeOuterTypeName; string name; if (method.IsConstructor) { - name = TypeDefinitionToString(method.DeclaringTypeDefinition, includeNamespace: includeNamespace); + name = TypeToString(MakeParameterizedType(method.DeclaringTypeDefinition), includeNamespace: includeNamespace); } else { if (includeTypeName) { - name = TypeDefinitionToString(method.DeclaringTypeDefinition, includeNamespace: includeNamespace) + "."; + name = TypeToString(MakeParameterizedType(method.DeclaringTypeDefinition), includeNamespace: includeNamespace) + "."; } else { name = ""; } @@ -552,7 +516,10 @@ namespace ICSharpCode.ILSpy if (@event == null) throw new ArgumentNullException(nameof(@event)); var buffer = new System.Text.StringBuilder(); - buffer.Append(GetDisplayName(@event, includeTypeName, includeNamespace)); + if (includeTypeName) { + buffer.Append(TypeToString(MakeParameterizedType(@event.DeclaringTypeDefinition), includeNamespace) + "."); + } + buffer.Append(@event.Name); buffer.Append(" : "); buffer.Append(TypeToString(@event.ReturnType, includeNamespace)); return buffer.ToString(); diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs index c719d3f30..9fbd9ff5c 100644 --- a/ILSpy/Languages/Language.cs +++ b/ILSpy/Languages/Language.cs @@ -159,17 +159,6 @@ namespace ICSharpCode.ILSpy return type.Name; } - /// - /// Converts a type definition into a string. This method is used by tree nodes and search results. - /// - public virtual string TypeDefinitionToString(ITypeDefinition type, bool includeNamespace) - { - if (includeNamespace) - return type.FullName; - else - return type.Name; - } - /// /// Converts a member signature to a string. /// This is used for displaying the tooltip on a member reference. @@ -254,6 +243,13 @@ namespace ICSharpCode.ILSpy } } + public static IType MakeParameterizedType(ITypeDefinition type) + { + if (type.TypeParameterCount == 0) + return type; + return new ParameterizedType(type, type.TypeParameters); + } + /// /// Used for WPF keyboard navigation. /// diff --git a/ILSpy/Languages/Languages.cs b/ILSpy/Languages/Languages.cs index 88bc29e16..d8ef5b8ff 100644 --- a/ILSpy/Languages/Languages.cs +++ b/ILSpy/Languages/Languages.cs @@ -45,7 +45,7 @@ namespace ICSharpCode.ILSpy List languages = new List(); languages.AddRange(ep.GetExportedValues()); languages.Sort((a, b) => a.Name.CompareTo(b.Name)); - #if false + #if DEBUG languages.AddRange(ILAstLanguage.GetDebugLanguages()); languages.AddRange(CSharpLanguage.GetDebugLanguages()); #endif diff --git a/ILSpy/LoadedAssemblyExtensions.cs b/ILSpy/LoadedAssemblyExtensions.cs index 059b4e6ca..7e101490a 100644 --- a/ILSpy/LoadedAssemblyExtensions.cs +++ b/ILSpy/LoadedAssemblyExtensions.cs @@ -5,12 +5,23 @@ using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.ILSpy { public static class LoadedAssemblyExtensions { public static IAssemblyResolver GetAssemblyResolver(this PEFile file) + { + return GetLoadedAssembly(file).GetAssemblyResolver(); + } + + public static ICompilation GetTypeSystemOrNull(this PEFile file) + { + return GetLoadedAssembly(file).GetTypeSystemOrNull(); + } + + static LoadedAssembly GetLoadedAssembly(PEFile file) { if (file == null) throw new ArgumentNullException(nameof(file)); @@ -19,7 +30,7 @@ namespace ICSharpCode.ILSpy if (!LoadedAssembly.loadedAssemblies.TryGetValue(file, out loadedAssembly)) throw new ArgumentException("The specified file is not associated with a LoadedAssembly!"); } - return loadedAssembly.GetAssemblyResolver(); + return loadedAssembly; } } } diff --git a/ILSpy/SearchStrategies.cs b/ILSpy/SearchStrategies.cs index df3926420..92aa1ee84 100644 --- a/ILSpy/SearchStrategies.cs +++ b/ILSpy/SearchStrategies.cs @@ -163,7 +163,7 @@ namespace ICSharpCode.ILSpy { switch (member) { case ITypeDefinition t: - return language.TypeDefinitionToString(t, includeNamespace: fullName); + return language.TypeToString(Language.MakeParameterizedType(t), includeNamespace: fullName); case IField f: return language.FieldToString(f, fullName, fullName); case IProperty p: @@ -193,7 +193,7 @@ namespace ICSharpCode.ILSpy Image = image(item), Name = GetLanguageSpecificName(language, item), LocationImage = TypeTreeNode.GetIcon(type), - Location = language.TypeDefinitionToString(type, includeNamespace: true) + Location = language.TypeToString(Language.MakeParameterizedType(type), includeNamespace: true) }); } } @@ -497,7 +497,7 @@ namespace ICSharpCode.ILSpy public override void Search(ITypeDefinition type, Language language, Action addResult) { if (MatchName(type, language)) { - string name = language.TypeDefinitionToString(type, includeNamespace: false); + string name = language.TypeToString(Language.MakeParameterizedType(type), includeNamespace: false); var declaringType = type.DeclaringTypeDefinition; addResult(new SearchResult { Member = type, @@ -505,7 +505,7 @@ namespace ICSharpCode.ILSpy Image = TypeTreeNode.GetIcon(type), Name = name, LocationImage = declaringType != null ? TypeTreeNode.GetIcon(declaringType) : Images.Namespace, - Location = declaringType != null ? language.TypeDefinitionToString(declaringType, includeNamespace: true) : type.Namespace + Location = declaringType != null ? language.TypeToString(Language.MakeParameterizedType(declaringType), includeNamespace: true) : type.Namespace }); } @@ -526,7 +526,7 @@ namespace ICSharpCode.ILSpy { if (MatchName(type, language)) { - string name = language.TypeDefinitionToString(type, includeNamespace: false); + string name = language.TypeToString(Language.MakeParameterizedType(type), includeNamespace: false); var declaringType = type.DeclaringTypeDefinition; addResult(new SearchResult { Member = type, @@ -534,7 +534,7 @@ namespace ICSharpCode.ILSpy Fitness = CalculateFitness(type), Name = name, LocationImage = declaringType != null ? TypeTreeNode.GetIcon(declaringType) : Images.Namespace, - Location = declaringType != null ? language.TypeDefinitionToString(declaringType, includeNamespace: true) : type.Namespace + Location = declaringType != null ? language.TypeToString(Language.MakeParameterizedType(declaringType), includeNamespace: true) : type.Namespace }); } diff --git a/ILSpy/TreeNodes/BaseTypesEntryNode.cs b/ILSpy/TreeNodes/BaseTypesEntryNode.cs index 7c4362a58..e87069ca3 100644 --- a/ILSpy/TreeNodes/BaseTypesEntryNode.cs +++ b/ILSpy/TreeNodes/BaseTypesEntryNode.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Diagnostics; using System.Linq; using System.Reflection.Metadata; using ICSharpCode.Decompiler; @@ -32,7 +33,8 @@ namespace ICSharpCode.ILSpy.TreeNodes readonly EntityHandle handle; readonly IType type; readonly bool isInterface; - readonly bool showExpander; + bool showExpander; + object text; public BaseTypesEntryNode(PEFile module, EntityHandle handle, IType type, bool isInterface) { @@ -43,30 +45,37 @@ namespace ICSharpCode.ILSpy.TreeNodes this.type = type; this.isInterface = isInterface; this.LazyLoading = true; - showExpander = true; + TryResolve(module, handle, type); + } - /*var td = tr.ResolveAsType(); - if (!td.IsNil) { - var typeDef = td.Module.Metadata.GetTypeDefinition(td.Handle); - showExpander = !typeDef.BaseType.IsNil || typeDef.GetInterfaceImplementations().Any(); + ITypeDefinition TryResolve(PEFile module, EntityHandle handle, IType type, bool mayRetry = true) + { + DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver()); + var t = typeSystem.ResolveAsType(handle).GetDefinition(); + if (t != null) { + showExpander = t.DirectBaseTypes.Any(); + var other = t.ParentAssembly.PEFile.GetTypeSystemOrNull(); + Debug.Assert(other != null); + t = other.FindType(t.FullTypeName).GetDefinition(); + text = this.Language.TypeToString(Language.MakeParameterizedType(t), includeNamespace: true) + handle.ToSuffixString(); } else { - showExpander = false; - }*/ + showExpander = mayRetry; + text = this.Language.TypeToString(type, includeNamespace: true) + handle.ToSuffixString(); + } + RaisePropertyChanged(nameof(Text)); + RaisePropertyChanged(nameof(ShowExpander)); + return t; } public override bool ShowExpander => showExpander; - public override object Text - { - get { return this.Language.TypeToString(type, includeNamespace: true) + handle.ToSuffixString(); } - } + public override object Text => text; public override object Icon => isInterface ? Images.Interface : Images.Class; protected override void LoadChildren() { - DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver()); - var t = typeSystem.ResolveAsType(handle).GetDefinition(); + var t = TryResolve(module, handle, type, false); if (t != null) { BaseTypesTreeNode.AddBaseTypes(this.Children, t.ParentAssembly.PEFile, t); } @@ -74,8 +83,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public override void ActivateItem(System.Windows.RoutedEventArgs e) { - DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver()); - var t = typeSystem.ResolveAsType(handle).GetDefinition(); + var t = TryResolve(module, handle, type, false); e.Handled = ActivateItem(this, t); } @@ -98,9 +106,7 @@ namespace ICSharpCode.ILSpy.TreeNodes IEntity IMemberTreeNode.Member { get { - DecompilerTypeSystem typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver()); - var t = typeSystem.ResolveAsType(handle).GetDefinition(); - return t; + return TryResolve(module, handle, type, false); } } } diff --git a/ILSpy/TreeNodes/BaseTypesTreeNode.cs b/ILSpy/TreeNodes/BaseTypesTreeNode.cs index 7792520e3..8cbdb2304 100644 --- a/ILSpy/TreeNodes/BaseTypesTreeNode.cs +++ b/ILSpy/TreeNodes/BaseTypesTreeNode.cs @@ -63,7 +63,8 @@ namespace ICSharpCode.ILSpy.TreeNodes i++; } foreach (var h in typeDef.GetInterfaceImplementations()) { - children.Add(new BaseTypesEntryNode(module, h, baseTypes[i], true)); + var impl = module.Metadata.GetInterfaceImplementation(h); + children.Add(new BaseTypesEntryNode(module, impl.Interface, baseTypes[i], true)); i++; } } diff --git a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs index 88f444ece..05a742c59 100644 --- a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs +++ b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs @@ -21,22 +21,23 @@ using System.Linq; using System.Threading; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.Util; using SRM = System.Reflection.Metadata; namespace ICSharpCode.ILSpy.TreeNodes -{/* +{ /// /// Lists the sub types of a class. /// sealed class DerivedTypesTreeNode : ILSpyTreeNode { readonly AssemblyList list; - readonly TypeDefinition type; + readonly ITypeDefinition type; readonly ThreadingSupport threading; - public DerivedTypesTreeNode(AssemblyList list, TypeDefinition type) + public DerivedTypesTreeNode(AssemblyList list, ITypeDefinition type) { this.list = list; this.type = type; @@ -44,15 +45,9 @@ namespace ICSharpCode.ILSpy.TreeNodes this.threading = new ThreadingSupport(); } - public override object Text - { - get { return "Derived Types"; } - } + public override object Text => "Derived Types"; - public override object Icon - { - get { return Images.SubTypes; } - } + public override object Icon => Images.SubTypes; protected override void LoadChildren() { @@ -66,11 +61,11 @@ namespace ICSharpCode.ILSpy.TreeNodes return FindDerivedTypes(type, assemblies, cancellationToken); } - internal static IEnumerable FindDerivedTypes(TypeDefinition type, PEFile[] assemblies, CancellationToken cancellationToken) + internal static IEnumerable FindDerivedTypes(ITypeDefinition type, PEFile[] assemblies, CancellationToken cancellationToken) { - foreach (var module in assemblies) { - var metadata = module.Metadata; - foreach (var h in TreeTraversal.PreOrder(metadata.GetTopLevelTypeDefinitions(), t => metadata.GetTypeDefinition(t).GetNestedTypes())) { + /*foreach (var module in assemblies) { + var typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver()); + foreach (var td in typeSystem.MainAssembly.TypeDefinitions) { cancellationToken.ThrowIfCancellationRequested(); var td = new TypeDefinition(module, h); var typeDefinition = metadata.GetTypeDefinition(h); @@ -83,19 +78,19 @@ namespace ICSharpCode.ILSpy.TreeNodes yield return new DerivedTypesEntryNode(td, assemblies); } } - } + }*/ yield break; } - - static bool IsSameType(SRM.MetadataReader referenceMetadata, SRM.EntityHandle typeRef, TypeDefinition type) + /* + static bool IsSameType(SRM.MetadataReader referenceMetadata, SRM.EntityHandle typeRef, ITypeDefinition type) { // FullName contains only namespace, name and type parameter count, therefore this should suffice. return typeRef.GetFullTypeName(referenceMetadata) == type.Handle.GetFullTypeName(type.Module.Metadata); - } + }*/ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) { threading.Decompile(language, output, options, EnsureLazyChildren); } - }*/ + } } \ No newline at end of file diff --git a/ILSpy/TreeNodes/IMemberTreeNode.cs b/ILSpy/TreeNodes/IMemberTreeNode.cs index dc012cbba..2aa0d8619 100644 --- a/ILSpy/TreeNodes/IMemberTreeNode.cs +++ b/ILSpy/TreeNodes/IMemberTreeNode.cs @@ -27,6 +27,10 @@ namespace ICSharpCode.ILSpy.TreeNodes /// public interface IMemberTreeNode { + /// + /// Returns the entity that is represented by this tree node. + /// May return null, if the member cannot be resolved. + /// IEntity Member { get; } } } diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs index 15de00d12..85ddb3790 100644 --- a/ILSpy/TreeNodes/TypeTreeNode.cs +++ b/ILSpy/TreeNodes/TypeTreeNode.cs @@ -40,7 +40,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public AssemblyTreeNode ParentAssemblyNode { get; } - public override object Text => this.Language.TypeDefinitionToString(TypeDefinition, includeNamespace: false) + public override object Text => this.Language.TypeToString(Language.MakeParameterizedType(TypeDefinition), includeNamespace: false) + TypeDefinition.MetadataToken.ToSuffixString(); public override bool IsPublicAPI { @@ -72,10 +72,10 @@ namespace ICSharpCode.ILSpy.TreeNodes protected override void LoadChildren() { - if (!TypeDefinition.DirectBaseTypes.Any()) + if (TypeDefinition.DirectBaseTypes.Any()) this.Children.Add(new BaseTypesTreeNode(ParentAssemblyNode.LoadedAssembly.GetPEFileOrNull(), TypeDefinition)); - /*if (!TypeDefinition.IsSealed) - this.Children.Add(new DerivedTypesTreeNode(ParentAssemblyNode.AssemblyList, TypeDefinition));*/ + if (!TypeDefinition.IsSealed) + this.Children.Add(new DerivedTypesTreeNode(ParentAssemblyNode.AssemblyList, TypeDefinition)); foreach (var nestedType in TypeDefinition.NestedTypes.OrderBy(t => t.Name, NaturalStringComparer.Instance)) { this.Children.Add(new TypeTreeNode(nestedType, ParentAssemblyNode)); } From 186619b0851e2a8878fc549d119dadb58c015f35 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 8 Jul 2018 18:46:29 +0200 Subject: [PATCH 06/13] Fix DerivedTypesTreeNode and BaseTypesTreeNode --- ILSpy/TreeNodes/BaseTypesEntryNode.cs | 7 +--- ILSpy/TreeNodes/DerivedTypesEntryNode.cs | 49 +++++++++--------------- ILSpy/TreeNodes/DerivedTypesTreeNode.cs | 39 ++++++++++--------- 3 files changed, 41 insertions(+), 54 deletions(-) diff --git a/ILSpy/TreeNodes/BaseTypesEntryNode.cs b/ILSpy/TreeNodes/BaseTypesEntryNode.cs index e87069ca3..5751e0177 100644 --- a/ILSpy/TreeNodes/BaseTypesEntryNode.cs +++ b/ILSpy/TreeNodes/BaseTypesEntryNode.cs @@ -34,7 +34,6 @@ namespace ICSharpCode.ILSpy.TreeNodes readonly IType type; readonly bool isInterface; bool showExpander; - object text; public BaseTypesEntryNode(PEFile module, EntityHandle handle, IType type, bool isInterface) { @@ -57,19 +56,17 @@ namespace ICSharpCode.ILSpy.TreeNodes var other = t.ParentAssembly.PEFile.GetTypeSystemOrNull(); Debug.Assert(other != null); t = other.FindType(t.FullTypeName).GetDefinition(); - text = this.Language.TypeToString(Language.MakeParameterizedType(t), includeNamespace: true) + handle.ToSuffixString(); } else { showExpander = mayRetry; - text = this.Language.TypeToString(type, includeNamespace: true) + handle.ToSuffixString(); } RaisePropertyChanged(nameof(Text)); RaisePropertyChanged(nameof(ShowExpander)); return t; } - public override bool ShowExpander => showExpander; + public override bool ShowExpander => showExpander && base.ShowExpander; - public override object Text => text; + public override object Text => this.Language.TypeToString(type, includeNamespace: true) + handle.ToSuffixString(); public override object Icon => isInterface ? Images.Interface : Images.Class; diff --git a/ILSpy/TreeNodes/DerivedTypesEntryNode.cs b/ILSpy/TreeNodes/DerivedTypesEntryNode.cs index 0263f99c8..cd6ed881a 100644 --- a/ILSpy/TreeNodes/DerivedTypesEntryNode.cs +++ b/ILSpy/TreeNodes/DerivedTypesEntryNode.cs @@ -17,55 +17,42 @@ // DEALINGS IN THE SOFTWARE. using System.Collections.Generic; -using System.Reflection; -using System.Reflection.PortableExecutable; +using System.Linq; using System.Threading; using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; -using SRM = System.Reflection.Metadata; namespace ICSharpCode.ILSpy.TreeNodes { class DerivedTypesEntryNode : ILSpyTreeNode, IMemberTreeNode { - private readonly ITypeDefinition type; - /* private readonly PEFile[] assemblies; - private readonly ThreadingSupport threading; - private readonly SRM.TypeDefinition td; + readonly AssemblyList list; + readonly ITypeDefinition type; + readonly ThreadingSupport threading; - public DerivedTypesEntryNode(ITypeDefinition type, PEFile[] assemblies) + public DerivedTypesEntryNode(AssemblyList list, ITypeDefinition type) { + this.list = list; this.type = type; - this.td = type.Module.Metadata.GetTypeDefinition(type.Handle); - this.assemblies = assemblies; this.LazyLoading = true; threading = new ThreadingSupport(); } - public override bool ShowExpander - { - get { return !type.Module.Metadata.GetTypeDefinition(type.Handle).HasFlag(TypeAttributes.Sealed) && base.ShowExpander; } - } + public override bool ShowExpander => !type.IsSealed && base.ShowExpander; public override object Text { - get { return type.Handle.GetFullTypeName(type.Module.Metadata) + type.Handle.ToSuffixString(); } + get { return type.FullName + type.MetadataToken.ToSuffixString(); } } - public override object Icon - { - get { return TypeTreeNode.GetIcon(type); } - } + public override object Icon => TypeTreeNode.GetIcon(type); public override FilterResult Filter(FilterSettings settings) { if (!settings.ShowInternalApi && !IsPublicAPI) return FilterResult.Hidden; - var metadata = type.Module.Metadata; - var typeDefinition = metadata.GetTypeDefinition(type.Handle); - if (settings.SearchTermMatches(metadata.GetString(typeDefinition.Name))) { - if (!typeDefinition.GetDeclaringType().IsNil && !settings.Language.ShowMember(type)) + if (settings.SearchTermMatches(type.Name)) { + if (type.DeclaringType != null && !settings.Language.ShowMember(type)) return FilterResult.Hidden; else return FilterResult.Match; @@ -75,11 +62,10 @@ namespace ICSharpCode.ILSpy.TreeNodes public override bool IsPublicAPI { get { - switch (td.Attributes & TypeAttributes.VisibilityMask) { - case TypeAttributes.Public: - case TypeAttributes.NestedPublic: - case TypeAttributes.NestedFamily: - case TypeAttributes.NestedFamORAssem: + switch (type.Accessibility) { + case Accessibility.Public: + case Accessibility.Internal: + case Accessibility.ProtectedOrInternal: return true; default: return false; @@ -95,13 +81,14 @@ namespace ICSharpCode.ILSpy.TreeNodes IEnumerable FetchChildren(CancellationToken ct) { // FetchChildren() runs on the main thread; but the enumerator will be consumed on a background thread - return DerivedTypesTreeNode.FindDerivedTypes(type, assemblies, ct); + var assemblies = list.GetAssemblies().Select(node => node.GetPEFileOrNull()).Where(asm => asm != null).ToArray(); + return DerivedTypesTreeNode.FindDerivedTypes(list, type, assemblies, ct); } public override void ActivateItem(System.Windows.RoutedEventArgs e) { e.Handled = BaseTypesEntryNode.ActivateItem(this, type); - }*/ + } public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) { diff --git a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs index 05a742c59..19b9c1827 100644 --- a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs +++ b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs @@ -22,7 +22,6 @@ using System.Threading; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; -using ICSharpCode.Decompiler.Util; using SRM = System.Reflection.Metadata; @@ -58,35 +57,39 @@ namespace ICSharpCode.ILSpy.TreeNodes { // FetchChildren() runs on the main thread; but the enumerator will be consumed on a background thread var assemblies = list.GetAssemblies().Select(node => node.GetPEFileOrNull()).Where(asm => asm != null).ToArray(); - return FindDerivedTypes(type, assemblies, cancellationToken); + return FindDerivedTypes(list, type, assemblies, cancellationToken); } - internal static IEnumerable FindDerivedTypes(ITypeDefinition type, PEFile[] assemblies, CancellationToken cancellationToken) + internal static IEnumerable FindDerivedTypes(AssemblyList list, ITypeDefinition type, + PEFile[] assemblies, CancellationToken cancellationToken) { - /*foreach (var module in assemblies) { - var typeSystem = new DecompilerTypeSystem(module, module.GetAssemblyResolver()); - foreach (var td in typeSystem.MainAssembly.TypeDefinitions) { + var definitionMetadata = type.ParentAssembly.PEFile.Metadata; + var metadataToken = (SRM.TypeDefinitionHandle)type.MetadataToken; + foreach (var module in assemblies) { + var metadata = module.Metadata; + var assembly = (MetadataAssembly)module.GetTypeSystemOrNull().MainAssembly; + foreach (var h in metadata.TypeDefinitions) { cancellationToken.ThrowIfCancellationRequested(); - var td = new TypeDefinition(module, h); - var typeDefinition = metadata.GetTypeDefinition(h); - foreach (var iface in typeDefinition.GetInterfaceImplementations()) { + var td = metadata.GetTypeDefinition(h); + foreach (var iface in td.GetInterfaceImplementations()) { var ifaceImpl = metadata.GetInterfaceImplementation(iface); - if (IsSameType(metadata, ifaceImpl.Interface, type)) - yield return new DerivedTypesEntryNode(td, assemblies); + if (IsSameType(metadata, ifaceImpl.Interface, definitionMetadata, metadataToken)) + yield return new DerivedTypesEntryNode(list, assembly.GetDefinition(h)); } - if (!typeDefinition.BaseType.IsNil && IsSameType(metadata, typeDefinition.BaseType, type)) { - yield return new DerivedTypesEntryNode(td, assemblies); + if (!td.BaseType.IsNil && IsSameType(metadata, td.BaseType, definitionMetadata, metadataToken)) { + yield return new DerivedTypesEntryNode(list, assembly.GetDefinition(h)); } } - }*/ + } yield break; } - /* - static bool IsSameType(SRM.MetadataReader referenceMetadata, SRM.EntityHandle typeRef, ITypeDefinition type) + + static bool IsSameType(SRM.MetadataReader referenceMetadata, SRM.EntityHandle typeRef, + SRM.MetadataReader definitionMetadata, SRM.TypeDefinitionHandle typeDef) { // FullName contains only namespace, name and type parameter count, therefore this should suffice. - return typeRef.GetFullTypeName(referenceMetadata) == type.Handle.GetFullTypeName(type.Module.Metadata); - }*/ + return typeRef.GetFullTypeName(referenceMetadata) == typeDef.GetFullTypeName(definitionMetadata); + } public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) { From 5b4870e588d6d480bdbc1d98f17905aeacb43657 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 8 Jul 2018 18:47:02 +0200 Subject: [PATCH 07/13] Add AlwaysUseBuiltinTypeNames option to TypeSystemAstBuilder --- .../CSharp/Syntax/TypeSystemAstBuilder.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs index 796864eb9..2017c37fa 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs @@ -64,6 +64,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax #region Properties void InitProperties() { + this.AlwaysUseBuiltinTypeNames = true; this.ShowAccessibility = true; this.ShowModifiers = true; this.ShowBaseTypes = true; @@ -135,13 +136,19 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax /// The default value is false. /// public bool ShowAttributes { get; set; } - + /// /// Controls whether to use fully-qualified type names or short type names. /// The default value is false. /// public bool AlwaysUseShortTypeNames { get; set; } - + + /// + /// Controls whether to use fully-qualified type names or short type names. + /// The default value is true. + /// + public bool AlwaysUseBuiltinTypeNames { get; set; } + /// /// Determines the name lookup mode for converting a type name. /// @@ -233,7 +240,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax } } if (type is ParameterizedType pt) { - if (pt.IsKnownType(KnownTypeCode.NullableOfT)) { + if (AlwaysUseBuiltinTypeNames && pt.IsKnownType(KnownTypeCode.NullableOfT)) { return ConvertType(pt.TypeArguments[0]).MakeNullableType(); } return ConvertTypeHelper(pt.GenericType, pt.TypeArguments); @@ -269,7 +276,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax Debug.Assert(genericType is ITypeDefinition || genericType.Kind == TypeKind.Unknown); ITypeDefinition typeDef = genericType as ITypeDefinition; - if (typeDef != null) { + if (AlwaysUseBuiltinTypeNames && typeDef != null) { string keyword = KnownTypeReference.GetCSharpNameByTypeCode(typeDef.KnownTypeCode); if (keyword != null) return new PrimitiveType(keyword); From 6653487f81ecd796da1c3fb270d1d817d7244883 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 8 Jul 2018 18:47:26 +0200 Subject: [PATCH 08/13] Refactor CSharpLanguage.TypeToString --- ILSpy/Languages/CSharpLanguage.cs | 32 ++++++++++++++++++++----------- ILSpy/Languages/Language.cs | 7 ------- ILSpy/SearchStrategies.cs | 12 ++++++------ ILSpy/TreeNodes/TypeTreeNode.cs | 2 +- 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index b4460d496..389a16eef 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -410,9 +410,19 @@ namespace ICSharpCode.ILSpy { if (type == null) throw new ArgumentNullException(nameof(type)); + if (type is ITypeDefinition definition && definition.TypeParameterCount > 0) { + return TypeToStringInternal(new ParameterizedType(definition, definition.TypeParameters), includeNamespace, false); + } + return TypeToStringInternal(type, includeNamespace, false); + } + + string TypeToStringInternal(IType t, bool includeNamespace, bool useBuiltinTypeNames = true) + { TypeSystemAstBuilder builder = new TypeSystemAstBuilder(); builder.AlwaysUseShortTypeNames = !includeNamespace; - AstType astType = builder.ConvertType(type); + builder.AlwaysUseBuiltinTypeNames = useBuiltinTypeNames; + + AstType astType = builder.ConvertType(t); StringWriter w = new StringWriter(); astType.AcceptVisitor(new CSharpOutputVisitor(w, TypeToStringFormattingOptions)); @@ -427,7 +437,7 @@ namespace ICSharpCode.ILSpy string simple = field.Name + " : " + TypeToString(field.Type, includeNamespace); if (!includeTypeName) return simple; - return TypeToString(MakeParameterizedType(field.DeclaringTypeDefinition), includeNamespace) + "." + simple; + return TypeToStringInternal(field.DeclaringTypeDefinition, includeNamespace) + "." + simple; } public override string PropertyToString(IProperty property, bool includeTypeName, bool includeNamespace, bool? isIndexer = null) @@ -451,7 +461,7 @@ namespace ICSharpCode.ILSpy foreach (var param in parameters) { if (i > 0) buffer.Append(", "); - buffer.Append(TypeToString(param.Type, includeNamespace)); + buffer.Append(TypeToStringInternal(param.Type, includeNamespace)); i++; } @@ -460,10 +470,10 @@ namespace ICSharpCode.ILSpy buffer.Append(property.Name); } buffer.Append(" : "); - buffer.Append(TypeToString(property.ReturnType, includeNamespace)); + buffer.Append(TypeToStringInternal(property.ReturnType, includeNamespace)); if (!includeTypeName) return buffer.ToString(); - return TypeToString(MakeParameterizedType(property.DeclaringTypeDefinition), includeNamespace) + "." + buffer.ToString(); + return TypeToString(property.DeclaringTypeDefinition, includeNamespace) + "." + buffer.ToString(); } public override string MethodToString(IMethod method, bool includeTypeName, bool includeNamespace) @@ -472,10 +482,10 @@ namespace ICSharpCode.ILSpy throw new ArgumentNullException(nameof(method)); string name; if (method.IsConstructor) { - name = TypeToString(MakeParameterizedType(method.DeclaringTypeDefinition), includeNamespace: includeNamespace); + name = TypeToString(method.DeclaringTypeDefinition, includeNamespace: includeNamespace); } else { if (includeTypeName) { - name = TypeToString(MakeParameterizedType(method.DeclaringTypeDefinition), includeNamespace: includeNamespace) + "."; + name = TypeToString(method.DeclaringTypeDefinition, includeNamespace: includeNamespace) + "."; } else { name = ""; } @@ -501,13 +511,13 @@ namespace ICSharpCode.ILSpy foreach (var param in parameters) { if (i > 0) buffer.Append(", "); - buffer.Append(TypeToString(param.Type, includeNamespace)); + buffer.Append(TypeToStringInternal(param.Type, includeNamespace)); i++; } buffer.Append(')'); buffer.Append(" : "); - buffer.Append(TypeToString(method.ReturnType, includeNamespace)); + buffer.Append(TypeToStringInternal(method.ReturnType, includeNamespace)); return buffer.ToString(); } @@ -517,11 +527,11 @@ namespace ICSharpCode.ILSpy throw new ArgumentNullException(nameof(@event)); var buffer = new System.Text.StringBuilder(); if (includeTypeName) { - buffer.Append(TypeToString(MakeParameterizedType(@event.DeclaringTypeDefinition), includeNamespace) + "."); + buffer.Append(TypeToString(@event.DeclaringTypeDefinition, includeNamespace) + "."); } buffer.Append(@event.Name); buffer.Append(" : "); - buffer.Append(TypeToString(@event.ReturnType, includeNamespace)); + buffer.Append(TypeToStringInternal(@event.ReturnType, includeNamespace)); return buffer.ToString(); } diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs index 9fbd9ff5c..26b851940 100644 --- a/ILSpy/Languages/Language.cs +++ b/ILSpy/Languages/Language.cs @@ -243,13 +243,6 @@ namespace ICSharpCode.ILSpy } } - public static IType MakeParameterizedType(ITypeDefinition type) - { - if (type.TypeParameterCount == 0) - return type; - return new ParameterizedType(type, type.TypeParameters); - } - /// /// Used for WPF keyboard navigation. /// diff --git a/ILSpy/SearchStrategies.cs b/ILSpy/SearchStrategies.cs index 92aa1ee84..907d72145 100644 --- a/ILSpy/SearchStrategies.cs +++ b/ILSpy/SearchStrategies.cs @@ -163,7 +163,7 @@ namespace ICSharpCode.ILSpy { switch (member) { case ITypeDefinition t: - return language.TypeToString(Language.MakeParameterizedType(t), includeNamespace: fullName); + return language.TypeToString(t, includeNamespace: fullName); case IField f: return language.FieldToString(f, fullName, fullName); case IProperty p: @@ -193,7 +193,7 @@ namespace ICSharpCode.ILSpy Image = image(item), Name = GetLanguageSpecificName(language, item), LocationImage = TypeTreeNode.GetIcon(type), - Location = language.TypeToString(Language.MakeParameterizedType(type), includeNamespace: true) + Location = language.TypeToString(type, includeNamespace: true) }); } } @@ -497,7 +497,7 @@ namespace ICSharpCode.ILSpy public override void Search(ITypeDefinition type, Language language, Action addResult) { if (MatchName(type, language)) { - string name = language.TypeToString(Language.MakeParameterizedType(type), includeNamespace: false); + string name = language.TypeToString(type, includeNamespace: false); var declaringType = type.DeclaringTypeDefinition; addResult(new SearchResult { Member = type, @@ -505,7 +505,7 @@ namespace ICSharpCode.ILSpy Image = TypeTreeNode.GetIcon(type), Name = name, LocationImage = declaringType != null ? TypeTreeNode.GetIcon(declaringType) : Images.Namespace, - Location = declaringType != null ? language.TypeToString(Language.MakeParameterizedType(declaringType), includeNamespace: true) : type.Namespace + Location = declaringType != null ? language.TypeToString(declaringType, includeNamespace: true) : type.Namespace }); } @@ -526,7 +526,7 @@ namespace ICSharpCode.ILSpy { if (MatchName(type, language)) { - string name = language.TypeToString(Language.MakeParameterizedType(type), includeNamespace: false); + string name = language.TypeToString(type, includeNamespace: false); var declaringType = type.DeclaringTypeDefinition; addResult(new SearchResult { Member = type, @@ -534,7 +534,7 @@ namespace ICSharpCode.ILSpy Fitness = CalculateFitness(type), Name = name, LocationImage = declaringType != null ? TypeTreeNode.GetIcon(declaringType) : Images.Namespace, - Location = declaringType != null ? language.TypeToString(Language.MakeParameterizedType(declaringType), includeNamespace: true) : type.Namespace + Location = declaringType != null ? language.TypeToString(declaringType, includeNamespace: true) : type.Namespace }); } diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs index 85ddb3790..2ef084718 100644 --- a/ILSpy/TreeNodes/TypeTreeNode.cs +++ b/ILSpy/TreeNodes/TypeTreeNode.cs @@ -40,7 +40,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public AssemblyTreeNode ParentAssemblyNode { get; } - public override object Text => this.Language.TypeToString(Language.MakeParameterizedType(TypeDefinition), includeNamespace: false) + public override object Text => this.Language.TypeToString(TypeDefinition, includeNamespace: false) + TypeDefinition.MetadataToken.ToSuffixString(); public override bool IsPublicAPI { From 4f8441e14262b87403a63e65925abbf505bdb63c Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 8 Jul 2018 22:14:25 +0200 Subject: [PATCH 09/13] Introduce several new WriteReference overloads --- .../Disassembler/DisassemblerHelpers.cs | 2 +- .../Disassembler/MethodBodyDisassembler.cs | 12 ++-- .../Disassembler/ReflectionDisassembler.cs | 6 +- ICSharpCode.Decompiler/IL/ILReader.cs | 4 +- ICSharpCode.Decompiler/IL/ILVariable.cs | 4 +- .../IL/InstructionOutputExtensions.cs | 10 +-- .../IL/Instructions/Block.cs | 2 +- .../IL/Instructions/BlockContainer.cs | 4 +- .../IL/Instructions/Branch.cs | 2 +- .../IL/Instructions/Leave.cs | 2 +- .../IL/Instructions/SwitchInstruction.cs | 2 +- .../IL/Instructions/TryInstruction.cs | 2 +- ICSharpCode.Decompiler/Output/ITextOutput.cs | 29 ++------- .../Output/PlainTextOutput.cs | 25 +++++-- .../Output/TextTokenWriter.cs | 4 +- ILSpy/Languages/CSharpLanguage.cs | 4 +- ILSpy/MainWindow.xaml.cs | 56 +++++----------- ILSpy/TextView/AvalonEditTextOutput.cs | 65 ++++++++++++++++--- 18 files changed, 129 insertions(+), 106 deletions(-) diff --git a/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs b/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs index 29bcc027e..6a9ed063b 100644 --- a/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs +++ b/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs @@ -64,7 +64,7 @@ namespace ICSharpCode.Decompiler.Disassembler if (offset == null) writer.Write("null"); else - writer.WriteReference(OffsetToString(offset.Value), offset); + writer.WriteLocalReference(OffsetToString(offset.Value), offset); } public static void WriteTo(this SRM.ExceptionRegion exceptionHandler, Metadata.PEFile module, GenericContext context, ITextOutput writer) diff --git a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs index 638fa4dab..2802d43da 100644 --- a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs @@ -138,7 +138,7 @@ namespace ICSharpCode.Decompiler.Disassembler output.Indent(); int index = 0; foreach (var v in signature) { - output.WriteDefinition("[" + index + "] ", v); + output.WriteLocalReference("[" + index + "] ", v, isDefinition: true); v(ILNameSyntax.TypeName); if (index + 1 < signature.Length) output.Write(','); @@ -298,16 +298,16 @@ namespace ICSharpCode.Decompiler.Disassembler } } ILOpCode opCode = ILParser.DecodeOpCode(ref blob); - output.WriteDefinition(DisassemblerHelpers.OffsetToString(offset), offset); + output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset), offset, isDefinition: true); output.Write(": "); if (opCode.IsDefined()) { - output.WriteReference(opCode.GetDisplayName(), new OpCodeInfo(opCode, opCode.GetDisplayName())); + output.WriteReference(new OpCodeInfo(opCode, opCode.GetDisplayName())); switch (opCode.GetOperandType()) { case OperandType.BrTarget: case OperandType.ShortBrTarget: output.Write(' '); int targetOffset = ILParser.DecodeBranchTarget(ref blob, opCode); - output.WriteReference($"IL_{targetOffset:x4}", targetOffset, true); + output.WriteLocalReference($"IL_{targetOffset:x4}", targetOffset); break; case OperandType.Field: case OperandType.Method: @@ -392,7 +392,7 @@ namespace ICSharpCode.Decompiler.Disassembler for (int i = 0; i < targets.Length; i++) { if (i > 0) output.Write(", "); - output.WriteReference($"IL_{targets[i]:x4}", targets[i], true); + output.WriteLocalReference($"IL_{targets[i]:x4}", targets[i]); } output.Write(")"); break; @@ -421,7 +421,7 @@ namespace ICSharpCode.Decompiler.Disassembler // split 16-bit value into two emitbyte directives output.WriteLine($".emitbyte 0x{(byte)(opCodeValue >> 8):x}"); // add label - output.WriteDefinition(DisassemblerHelpers.OffsetToString(offset + 1), offset + 1); + output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset + 1), offset + 1, isDefinition: true); output.Write(": "); output.Write($".emitbyte 0x{(byte)(opCodeValue & 0xFF):x}"); } else { diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs index 4514887b8..b7a149392 100644 --- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs @@ -398,7 +398,7 @@ namespace ICSharpCode.Decompiler.Disassembler output.Write('['); output.Write(nameParts[1]); output.Write(']'); - output.WriteReference(nameParts[0], null); // TODO : hyperlink! + output.Write(nameParts[0]); } output.Write(" = {"); blob.ReadCompressedInteger(); // ? @@ -945,7 +945,7 @@ namespace ICSharpCode.Decompiler.Disassembler if (!md.IsNil) { WriteMarshalInfo(metadata.GetBlobReader(md)); } - output.WriteDefinition(DisassemblerHelpers.Escape(metadata.GetString(p.Name)), p); + output.WriteLocalReference(DisassemblerHelpers.Escape(metadata.GetString(p.Name)), p, isDefinition: true); } else { signature.ParameterTypes[i](ILNameSyntax.Signature); output.Write(" ''"); @@ -1036,7 +1036,7 @@ namespace ICSharpCode.Decompiler.Disassembler { var metadata = module.Metadata; var fieldDefinition = metadata.GetFieldDefinition(field); - output.WriteDefinition(".field ", field); + output.WriteReference(module, field, ".field ", isDefinition: true); int offset = fieldDefinition.GetOffset(); if (offset > -1) { output.Write("[" + offset + "] "); diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index c442f3f3f..02541bcb4 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -428,7 +428,7 @@ namespace ICSharpCode.Decompiler.IL isFirstElement = false; else output.Write(", "); - output.WriteReference(element.Name, element, isLocal: true); + output.WriteLocalReference(element.Name, element); output.Write(":"); output.Write(element.StackType); } @@ -438,7 +438,7 @@ namespace ICSharpCode.Decompiler.IL output.Write('*'); else output.Write(' '); - output.WriteDefinition("IL_" + inst.ILRange.Start.ToString("x4"), inst.ILRange.Start); + output.WriteLocalReference("IL_" + inst.ILRange.Start.ToString("x4"), inst.ILRange.Start, isDefinition: true); output.Write(": "); inst.WriteTo(output, new ILAstWritingOptions()); output.WriteLine(); diff --git a/ICSharpCode.Decompiler/IL/ILVariable.cs b/ICSharpCode.Decompiler/IL/ILVariable.cs index d9ba63e83..a4b68ea8d 100644 --- a/ICSharpCode.Decompiler/IL/ILVariable.cs +++ b/ICSharpCode.Decompiler/IL/ILVariable.cs @@ -319,7 +319,7 @@ namespace ICSharpCode.Decompiler.IL default: throw new ArgumentOutOfRangeException(); } - output.WriteDefinition(this.Name, this, isLocal: true); + output.WriteLocalReference(this.Name, this, isDefinition: true); output.Write(" : "); Type.WriteTo(output); output.Write('('); @@ -340,7 +340,7 @@ namespace ICSharpCode.Decompiler.IL internal void WriteTo(ITextOutput output) { - output.WriteReference(this.Name, this, isLocal: true); + output.WriteLocalReference(this.Name, this); } /// diff --git a/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs b/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs index 33b5cbc88..04fa15161 100644 --- a/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs +++ b/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs @@ -41,15 +41,15 @@ namespace ICSharpCode.Decompiler.IL public static void WriteTo(this IType type, ITextOutput output, ILNameSyntax nameSyntax = ILNameSyntax.ShortTypeName) { - output.WriteReference(type.ReflectionName, type); + output.WriteReference(type, type.ReflectionName); } - public static void WriteTo(this ISymbol symbol, ITextOutput output) + public static void WriteTo(this IMember member, ITextOutput output) { - if (symbol is IMethod method && method.IsConstructor) - output.WriteReference(method.DeclaringType?.Name + "." + method.Name, symbol); + if (member is IMethod method && method.IsConstructor) + output.WriteReference(member, method.DeclaringType?.Name + "." + method.Name); else - output.WriteReference(symbol.Name, symbol); + output.WriteReference(member, member.Name); } public static void WriteTo(this Interval interval, ITextOutput output, ILAstWritingOptions options) diff --git a/ICSharpCode.Decompiler/IL/Instructions/Block.cs b/ICSharpCode.Decompiler/IL/Instructions/Block.cs index 894cc04c7..f26cbfb27 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Block.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Block.cs @@ -152,7 +152,7 @@ namespace ICSharpCode.Decompiler.IL { ILRange.WriteTo(output, options); output.Write("Block "); - output.WriteDefinition(Label, this); + output.WriteLocalReference(Label, this, isDefinition: true); if (Kind != BlockKind.ControlFlow) output.Write($" ({Kind})"); if (Parent is BlockContainer) diff --git a/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs b/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs index d5420dc0f..a716a6776 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs @@ -118,7 +118,7 @@ namespace ICSharpCode.Decompiler.IL public override void WriteTo(ITextOutput output, ILAstWritingOptions options) { ILRange.WriteTo(output, options); - output.WriteDefinition("BlockContainer", this); + output.WriteLocalReference("BlockContainer", this, isDefinition: true); output.Write(' '); switch (Kind) { case ContainerKind.Loop: @@ -145,7 +145,7 @@ namespace ICSharpCode.Decompiler.IL inst.WriteTo(output, options); } else { output.Write("stale reference to "); - output.WriteReference(inst.Label, inst, isLocal: true); + output.WriteLocalReference(inst.Label, inst); } output.WriteLine(); output.WriteLine(); diff --git a/ICSharpCode.Decompiler/IL/Instructions/Branch.cs b/ICSharpCode.Decompiler/IL/Instructions/Branch.cs index be2d0a315..a9e78b330 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Branch.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Branch.cs @@ -116,7 +116,7 @@ namespace ICSharpCode.Decompiler.IL ILRange.WriteTo(output, options); output.Write(OpCode); output.Write(' '); - output.WriteReference(TargetLabel, (object)targetBlock ?? TargetILOffset, isLocal: true); + output.WriteLocalReference(TargetLabel, (object)targetBlock ?? TargetILOffset); } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/Leave.cs b/ICSharpCode.Decompiler/IL/Instructions/Leave.cs index 38e60cbe1..387a90e86 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Leave.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Leave.cs @@ -115,7 +115,7 @@ namespace ICSharpCode.Decompiler.IL output.Write(OpCode); if (targetContainer != null) { output.Write(' '); - output.WriteReference(TargetLabel, targetContainer, isLocal: true); + output.WriteLocalReference(TargetLabel, targetContainer); output.Write(" ("); value.WriteTo(output, options); output.Write(')'); diff --git a/ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs index 8158ac8b2..ef60070c2 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs @@ -183,7 +183,7 @@ namespace ICSharpCode.Decompiler.IL public override void WriteTo(ITextOutput output, ILAstWritingOptions options) { ILRange.WriteTo(output, options); - output.WriteDefinition("case", this, isLocal: true); + output.WriteLocalReference("case", this, isDefinition: true); output.Write(' '); if (HasNullLabel) { output.Write("null"); diff --git a/ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs index b53611c42..93889bbbd 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs @@ -165,7 +165,7 @@ namespace ICSharpCode.Decompiler.IL ILRange.WriteTo(output, options); output.Write("catch "); if (variable != null) { - output.WriteDefinition(variable.Name, variable); + output.WriteLocalReference(variable.Name, variable, isDefinition: true); output.Write(" : "); Disassembler.DisassemblerHelpers.WriteOperand(output, variable.Type); } diff --git a/ICSharpCode.Decompiler/Output/ITextOutput.cs b/ICSharpCode.Decompiler/Output/ITextOutput.cs index f0ce1c3dd..bd22b9663 100644 --- a/ICSharpCode.Decompiler/Output/ITextOutput.cs +++ b/ICSharpCode.Decompiler/Output/ITextOutput.cs @@ -18,6 +18,7 @@ using System.Reflection.Metadata; +using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; @@ -30,8 +31,11 @@ namespace ICSharpCode.Decompiler void Write(char ch); void Write(string text); void WriteLine(); - void WriteDefinition(string text, object definition, bool isLocal = true); - void WriteReference(string text, object reference, bool isLocal = false); + void WriteReference(OpCodeInfo opCode); + void WriteReference(PEFile module, EntityHandle handle, string text, bool isDefinition = false); + void WriteReference(IType type, string text, bool isDefinition = false); + void WriteReference(IMember member, string text, bool isDefinition = false); + void WriteLocalReference(string text, object reference, bool isDefinition = false); void MarkFoldStart(string collapsedText = "...", bool defaultCollapsed = false); void MarkFoldEnd(); @@ -54,26 +58,5 @@ namespace ICSharpCode.Decompiler { output.WriteLine(string.Format(format, args)); } - - public static void WriteReference(this ITextOutput output, PEFile module, EntityHandle handle, string text, bool isDefinition = false) - { - output.Write(text); - } - - public static void WriteReference(this ITextOutput output, IType type, string text, bool isDefinition = false) - { - output.Write(text); - } - - public static void WriteReference(this ITextOutput output, IMember member, string text, bool isDefinition = false) - { - output.Write(text); - - } - - public static void WriteLocalReference(this ITextOutput output, string text, object reference, bool isDefinition = false) - { - output.Write(text); - } } } diff --git a/ICSharpCode.Decompiler/Output/PlainTextOutput.cs b/ICSharpCode.Decompiler/Output/PlainTextOutput.cs index 6ae3a7792..d71d6a996 100644 --- a/ICSharpCode.Decompiler/Output/PlainTextOutput.cs +++ b/ICSharpCode.Decompiler/Output/PlainTextOutput.cs @@ -99,17 +99,32 @@ namespace ICSharpCode.Decompiler line++; column = 1; } - - public void WriteDefinition(string text, object definition, bool isLocal = true) + + public void WriteReference(Disassembler.OpCodeInfo opCode) + { + Write(opCode.Name); + } + + public void WriteReference(PEFile module, EntityHandle handle, string text, bool isDefinition = false) { Write(text); } - - public void WriteReference(string text, object reference, bool isLocal = false) + + public void WriteReference(IType type, string text, bool isDefinition = false) { Write(text); } - + + public void WriteReference(IMember member, string text, bool isDefinition = false) + { + Write(text); + } + + public void WriteLocalReference(string text, object reference, bool isDefinition = false) + { + Write(text); + } + void ITextOutput.MarkFoldStart(string collapsedText, bool defaultCollapsed) { } diff --git a/ICSharpCode.Decompiler/Output/TextTokenWriter.cs b/ICSharpCode.Decompiler/Output/TextTokenWriter.cs index 1ea1b7aba..bd6bd9628 100644 --- a/ICSharpCode.Decompiler/Output/TextTokenWriter.cs +++ b/ICSharpCode.Decompiler/Output/TextTokenWriter.cs @@ -84,13 +84,13 @@ namespace ICSharpCode.Decompiler var localDefinition = GetCurrentLocalDefinition(); if (localDefinition != null) { - output.WriteDefinition(identifier.Name, localDefinition); + output.WriteLocalReference(identifier.Name, localDefinition, isDefinition: true); return; } var localRef = GetCurrentLocalReference(); if (localRef != null) { - output.WriteReference(identifier.Name, localRef, true); + output.WriteLocalReference(identifier.Name, localRef); return; } diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index 389a16eef..4503201b9 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -331,7 +331,7 @@ namespace ICSharpCode.ILSpy var globalType = typeSystem.MainAssembly.TypeDefinitions.FirstOrDefault(); if (globalType != null) { output.Write("// Global type: "); - output.WriteReference(globalType.FullName, globalType); + output.WriteReference(globalType, globalType.FullName); output.WriteLine(); } var metadata = module.Metadata; @@ -341,7 +341,7 @@ namespace ICSharpCode.ILSpy var entrypoint = typeSystem.ResolveAsMethod(entrypointHandle); if (entrypoint != null) { output.Write("// Entry point: "); - output.WriteReference(entrypoint.DeclaringType.FullName + "." + entrypoint.Name, entrypoint); + output.WriteReference(entrypoint, entrypoint.DeclaringType.FullName + "." + entrypoint.Name); output.WriteLine(); } } diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index b906b5257..73b8cb653 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -611,41 +611,6 @@ namespace ICSharpCode.ILSpy return assemblyListTreeNode.FindPropertyNode(pd); case IEvent ed: return assemblyListTreeNode.FindEventNode(ed); - /* - case TypeReference tr: - var resolved = tr.Handle.Resolve(new SimpleMetadataResolveContext(tr.Module)); - if (resolved != null && !resolved.IsNil) - return assemblyListTreeNode.FindTypeNode(resolved); - return null; - case TypeSpecification ts: - resolved = ts.Handle.Resolve(new SimpleMetadataResolveContext(ts.Module)); - if (!resolved.IsNil) - return assemblyListTreeNode.FindTypeNode(resolved); - return null; - case MemberReference mr: - var resolvedMember = mr.Handle.Resolve(new SimpleMetadataResolveContext(mr.Module)); - if (resolvedMember != null && !resolvedMember.IsNil) { - switch (resolvedMember) { - case FieldDefinition fd: - return assemblyListTreeNode.FindFieldNode(fd); - case MethodDefinition md: - return assemblyListTreeNode.FindMethodNode(md); - default: - throw new NotSupportedException(); - } - } - return null; - case MethodSpecification ms: - resolvedMember = ms.Handle.Resolve(new SimpleMetadataResolveContext(ms.Module)); - if (resolvedMember != null && !resolvedMember.IsNil) { - switch (resolvedMember) { - case MethodDefinition md: - return assemblyListTreeNode.FindMethodNode(md); - default: - throw new NotSupportedException(); - } - } - return null;*/ default: return null; } @@ -666,11 +631,22 @@ namespace ICSharpCode.ILSpy public Task JumpToReferenceAsync(object reference) { decompilationTask = TaskHelper.CompletedTask; - ILSpyTreeNode treeNode = FindTreeNode(reference); - if (treeNode != null) { - SelectNode(treeNode); - } else if (reference is Decompiler.Disassembler.OpCodeInfo opCode) { - OpenLink(opCode.Link); + switch (reference) { + case Decompiler.Disassembler.OpCodeInfo opCode: + OpenLink(opCode.Link); + break; + case ValueTuple unresolvedEntity: + var typeSystem = new DecompilerTypeSystem(unresolvedEntity.Item1, unresolvedEntity.Item1.GetAssemblyResolver()); + if (unresolvedEntity.Item2.Kind.IsTypeKind()) + reference = typeSystem.ResolveAsType(unresolvedEntity.Item2).GetDefinition(); + else + reference = typeSystem.ResolveAsMember(unresolvedEntity.Item2); + goto default; + default: + ILSpyTreeNode treeNode = FindTreeNode(reference); + if (treeNode != null) + SelectNode(treeNode); + break; } return decompilationTask; } diff --git a/ILSpy/TextView/AvalonEditTextOutput.cs b/ILSpy/TextView/AvalonEditTextOutput.cs index 21dc101b2..710d2c2c9 100644 --- a/ILSpy/TextView/AvalonEditTextOutput.cs +++ b/ILSpy/TextView/AvalonEditTextOutput.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Reflection.Metadata; using System.Text; using System.Windows; @@ -27,6 +28,8 @@ using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Folding; using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Rendering; +using ICSharpCode.Decompiler.Metadata; +using ICSharpCode.Decompiler.TypeSystem; using TextLocation = ICSharpCode.Decompiler.CSharp.Syntax.TextLocation; namespace ICSharpCode.ILSpy.TextView @@ -206,26 +209,72 @@ namespace ICSharpCode.ILSpy.TextView throw new OutputLengthExceededException(); } } - - public void WriteDefinition(string text, object definition, bool isLocal = true) + + public void WriteReference(Decompiler.Disassembler.OpCodeInfo opCode) + { + WriteIndent(); + int start = this.TextLength; + b.Append(opCode.Name); + int end = this.TextLength; + references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = opCode }); + } + + public void WriteReference(PEFile module, EntityHandle handle, string text, bool isDefinition = false) { WriteIndent(); int start = this.TextLength; b.Append(text); int end = this.TextLength; - this.DefinitionLookup.AddDefinition(definition, this.TextLength); - references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = definition, IsLocal = isLocal, IsLocalTarget = true }); + if (isDefinition) { + this.DefinitionLookup.AddDefinition((module, handle), this.TextLength); + references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = (module, handle) }); + } else { + references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = (module, handle) }); + } } - - public void WriteReference(string text, object reference, bool isLocal = false) + + public void WriteReference(IType type, string text, bool isDefinition = false) { WriteIndent(); int start = this.TextLength; b.Append(text); int end = this.TextLength; - references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = reference, IsLocal = isLocal }); + if (isDefinition) { + this.DefinitionLookup.AddDefinition(type, this.TextLength); + references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = type }); + } else { + references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = type }); + } } - + + public void WriteReference(IMember member, string text, bool isDefinition = false) + { + WriteIndent(); + int start = this.TextLength; + b.Append(text); + int end = this.TextLength; + if (isDefinition) { + this.DefinitionLookup.AddDefinition(member, this.TextLength); + references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = member }); + } else { + references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = member }); + } + } + + public void WriteLocalReference(string text, object reference, bool isDefinition = false) + { + WriteIndent(); + int start = this.TextLength; + b.Append(text); + int end = this.TextLength; + if (isDefinition) { + this.DefinitionLookup.AddDefinition(reference, this.TextLength); + references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = reference, IsLocal = true, IsLocalTarget = true }); + } else { + references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = reference, IsLocal = true }); + } + } + public void MarkFoldStart(string collapsedText = "...", bool defaultCollapsed = false) { WriteIndent(); From 7e5ef32878fed1ace6e0322f995432658e8fb265 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 8 Jul 2018 22:14:44 +0200 Subject: [PATCH 10/13] Fix NRE in MetadataAssembly --- ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs b/ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs index 26eebcea7..f5df63c8b 100644 --- a/ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs +++ b/ICSharpCode.Decompiler/TypeSystem/MetadataAssembly.cs @@ -560,8 +560,9 @@ namespace ICSharpCode.Decompiler.TypeSystem IType ResolveForwardedType(ExportedType forwarder) { IAssembly assembly = ResolveAssembly(forwarder); - Debug.Assert(assembly != null); var typeName = forwarder.GetFullTypeName(metadata); + if (assembly == null) + return new UnknownType(typeName); using (var busyLock = BusyManager.Enter(this)) { if (busyLock.Success) { var td = assembly.GetTypeDefinition(typeName); From a531dbde2f52e2a3772594056ed9ce81366165c7 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 8 Jul 2018 22:15:27 +0200 Subject: [PATCH 11/13] Remove legacy code from MethodTreeNode and TypeTreeNode --- ILSpy/TreeNodes/MethodTreeNode.cs | 53 +++++++++++-------------------- ILSpy/TreeNodes/TypeTreeNode.cs | 26 +++++---------- 2 files changed, 27 insertions(+), 52 deletions(-) diff --git a/ILSpy/TreeNodes/MethodTreeNode.cs b/ILSpy/TreeNodes/MethodTreeNode.cs index 1f7f2018d..33a6f4fe7 100644 --- a/ILSpy/TreeNodes/MethodTreeNode.cs +++ b/ILSpy/TreeNodes/MethodTreeNode.cs @@ -54,54 +54,39 @@ namespace ICSharpCode.ILSpy.TreeNodes public static ImageSource GetIcon(IMethod method) { - var metadata = ((MetadataAssembly)method.ParentAssembly).PEFile.Metadata; - var methodDefinition = metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken); - var methodName = metadata.GetString(methodDefinition.Name); - if (methodDefinition.HasFlag(MethodAttributes.SpecialName) && methodName.StartsWith("op_", StringComparison.Ordinal)) { - return Images.GetIcon(MemberIcon.Operator, GetOverlayIcon(methodDefinition.Attributes), false); - } - - if (methodDefinition.IsExtensionMethod(metadata)) { - return Images.GetIcon(MemberIcon.ExtensionMethod, GetOverlayIcon(methodDefinition.Attributes), false); - } + if (method.IsOperator) + return Images.GetIcon(MemberIcon.Operator, GetOverlayIcon(method), false); - if (methodDefinition.HasFlag(MethodAttributes.SpecialName) && - (methodName == ".ctor" || methodName == ".cctor")) { - return Images.GetIcon(MemberIcon.Constructor, GetOverlayIcon(methodDefinition.Attributes), methodDefinition.HasFlag(MethodAttributes.Static)); - } + if (method.IsExtensionMethod) + return Images.GetIcon(MemberIcon.ExtensionMethod, GetOverlayIcon(method), false); - if (methodDefinition.HasFlag(MethodAttributes.PinvokeImpl) && !methodDefinition.GetImport().Module.IsNil) - return Images.GetIcon(MemberIcon.PInvokeMethod, GetOverlayIcon(methodDefinition.Attributes), true); + if (method.IsConstructor) + return Images.GetIcon(MemberIcon.Constructor, GetOverlayIcon(method), method.IsStatic); - bool showAsVirtual = methodDefinition.HasFlag(MethodAttributes.Virtual) - && !(methodDefinition.HasFlag(MethodAttributes.NewSlot) && methodDefinition.HasFlag(MethodAttributes.Final)) - && (metadata.GetTypeDefinition(methodDefinition.GetDeclaringType()).Attributes & TypeAttributes.ClassSemanticsMask) != TypeAttributes.Interface; + if (!method.HasBody && method.HasAttribute(KnownAttribute.DllImport)) + return Images.GetIcon(MemberIcon.PInvokeMethod, GetOverlayIcon(method), true); - return Images.GetIcon( - showAsVirtual ? MemberIcon.VirtualMethod : MemberIcon.Method, - GetOverlayIcon(methodDefinition.Attributes), - methodDefinition.HasFlag(MethodAttributes.Static)); + return Images.GetIcon(method.IsVirtual ? MemberIcon.VirtualMethod : MemberIcon.Method, + GetOverlayIcon(method), method.IsStatic); } - private static AccessOverlayIcon GetOverlayIcon(MethodAttributes methodAttributes) + static AccessOverlayIcon GetOverlayIcon(IMethod method) { - switch (methodAttributes & MethodAttributes.MemberAccessMask) { - case MethodAttributes.Public: + switch (method.Accessibility) { + case Accessibility.Public: return AccessOverlayIcon.Public; - case MethodAttributes.Assembly: + case Accessibility.Internal: return AccessOverlayIcon.Internal; - case MethodAttributes.FamANDAssem: + case Accessibility.ProtectedAndInternal: return AccessOverlayIcon.PrivateProtected; - case MethodAttributes.Family: + case Accessibility.Protected: return AccessOverlayIcon.Protected; - case MethodAttributes.FamORAssem: + case Accessibility.ProtectedOrInternal: return AccessOverlayIcon.ProtectedInternal; - case MethodAttributes.Private: + case Accessibility.Private: return AccessOverlayIcon.Private; - case 0: - return AccessOverlayIcon.CompilerControlled; default: - throw new NotSupportedException(); + return AccessOverlayIcon.CompilerControlled; } } diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs index 2ef084718..115564d10 100644 --- a/ILSpy/TreeNodes/TypeTreeNode.cs +++ b/ILSpy/TreeNodes/TypeTreeNode.cs @@ -105,10 +105,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public static ImageSource GetIcon(ITypeDefinition type) { - TypeIcon typeIcon = GetTypeIcon(type); - AccessOverlayIcon overlayIcon = GetOverlayIcon(type); - - return Images.GetIcon(typeIcon, overlayIcon); + return Images.GetIcon(GetTypeIcon(type), GetOverlayIcon(type)); } internal static TypeIcon GetTypeIcon(IType type) @@ -129,30 +126,23 @@ namespace ICSharpCode.ILSpy.TreeNodes } } - private static AccessOverlayIcon GetOverlayIcon(ITypeDefinition type) + static AccessOverlayIcon GetOverlayIcon(ITypeDefinition type) { - AccessOverlayIcon overlay; switch (type.Accessibility) { case Accessibility.Public: - overlay = AccessOverlayIcon.Public; - break; + return AccessOverlayIcon.Public; case Accessibility.Internal: - overlay = AccessOverlayIcon.Internal; - break; + return AccessOverlayIcon.Internal; case Accessibility.ProtectedAndInternal: - overlay = AccessOverlayIcon.PrivateProtected; - break; + return AccessOverlayIcon.PrivateProtected; case Accessibility.Protected: case Accessibility.ProtectedOrInternal: - overlay = AccessOverlayIcon.Protected; - break; + return AccessOverlayIcon.Protected; case Accessibility.Private: - overlay = AccessOverlayIcon.Private; - break; + return AccessOverlayIcon.Private; default: - throw new NotSupportedException(); + return AccessOverlayIcon.CompilerControlled; } - return overlay; } IEntity IMemberTreeNode.Member => TypeDefinition; From 4961b33d2aed0a30ed300fad60e1b9653e038b67 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 8 Jul 2018 22:16:04 +0200 Subject: [PATCH 12/13] Fix JumpToReference and GetTooltip --- ILSpy/TextView/DecompilerTextView.cs | 31 +++++++++++++++++++++++-- ILSpy/TreeNodes/AssemblyListTreeNode.cs | 12 ++++++---- ILSpy/TreeNodes/AssemblyTreeNode.cs | 14 +++++------ 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 9ac0ab660..b82b94363 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -211,8 +211,9 @@ namespace ICSharpCode.ILSpy.TextView XmlDocRenderer renderer = new XmlDocRenderer(); renderer.AppendText(MainWindow.Instance.CurrentLanguage.GetTooltip(entity)); try { - //var docProvider = entity.Module.DocumentationResolver.GetProvider(); // TODO implement proper API - var docProvider = XmlDocLoader.LoadDocumentation(((MetadataAssembly)entity.ParentAssembly).PEFile); + if (entity.ParentAssembly == null || entity.ParentAssembly.PEFile == null) + return null; + var docProvider = XmlDocLoader.LoadDocumentation(entity.ParentAssembly.PEFile); if (docProvider != null) { string documentation = docProvider.GetDocumentation(XmlDocKeyProvider.GetKey(entity)); if (documentation != null) { @@ -224,6 +225,32 @@ namespace ICSharpCode.ILSpy.TextView // ignore } return renderer.CreateTextBlock(); + } else if (segment.Reference is ValueTuple unresolvedEntity) { + var typeSystem = new DecompilerTypeSystem(unresolvedEntity.Item1, unresolvedEntity.Item1.GetAssemblyResolver()); + IEntity resolved; + if (unresolvedEntity.Item2.Kind.IsTypeKind()) + resolved = typeSystem.ResolveAsType(unresolvedEntity.Item2).GetDefinition(); + else + resolved = typeSystem.ResolveAsMember(unresolvedEntity.Item2); + if (resolved == null) + return null; + XmlDocRenderer renderer = new XmlDocRenderer(); + renderer.AppendText(MainWindow.Instance.CurrentLanguage.GetTooltip(resolved)); + try { + if (resolved.ParentAssembly == null || resolved.ParentAssembly.PEFile == null) + return null; + var docProvider = XmlDocLoader.LoadDocumentation(resolved.ParentAssembly.PEFile); + if (docProvider != null) { + string documentation = docProvider.GetDocumentation(XmlDocKeyProvider.GetKey(resolved)); + if (documentation != null) { + renderer.AppendText(Environment.NewLine); + renderer.AddXmlDocumentation(documentation); + } + } + } catch (XmlException) { + // ignore + } + return renderer.CreateTextBlock(); } return null; } diff --git a/ILSpy/TreeNodes/AssemblyListTreeNode.cs b/ILSpy/TreeNodes/AssemblyListTreeNode.cs index bfd4a3abf..2aaec2c7c 100644 --- a/ILSpy/TreeNodes/AssemblyListTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyListTreeNode.cs @@ -214,6 +214,8 @@ namespace ICSharpCode.ILSpy.TreeNodes /// public TypeTreeNode FindTypeNode(ITypeDefinition def) { + if (def == null) + return null; var declaringType = def.DeclaringTypeDefinition; if (declaringType != null) { TypeTreeNode decl = FindTypeNode(declaringType); @@ -245,25 +247,25 @@ namespace ICSharpCode.ILSpy.TreeNodes parentNode.EnsureLazyChildren(); switch (def.AccessorOwner) { case IProperty p: - parentNode = parentNode.Children.OfType().FirstOrDefault(m => m.PropertyDefinition.Equals(p)); + parentNode = parentNode.Children.OfType().FirstOrDefault(m => m.PropertyDefinition.MetadataToken == p.MetadataToken && !m.IsHidden); if (parentNode == null) return null; parentNode.EnsureLazyChildren(); - methodNode = parentNode.Children.OfType().FirstOrDefault(m => m.MethodDefinition.Equals(def)); + methodNode = parentNode.Children.OfType().FirstOrDefault(m => m.MethodDefinition.MetadataToken == def.MetadataToken && !m.IsHidden); if (methodNode == null || methodNode.IsHidden) return parentNode; return methodNode; case IEvent e: - parentNode = parentNode.Children.OfType().FirstOrDefault(m => m.EventDefinition.Equals(e)); + parentNode = parentNode.Children.OfType().FirstOrDefault(m => m.EventDefinition.MetadataToken == e.MetadataToken && !m.IsHidden); if (parentNode == null) return null; parentNode.EnsureLazyChildren(); - methodNode = parentNode.Children.OfType().FirstOrDefault(m => m.MethodDefinition.Equals(def)); + methodNode = parentNode.Children.OfType().FirstOrDefault(m => m.MethodDefinition.MetadataToken == def.MetadataToken && !m.IsHidden); if (methodNode == null || methodNode.IsHidden) return parentNode; return methodNode; default: - methodNode = typeNode.Children.OfType().FirstOrDefault(m => m.MethodDefinition.Equals(def) && !m.IsHidden); + methodNode = typeNode.Children.OfType().FirstOrDefault(m => m.MethodDefinition.MetadataToken == def.MetadataToken && !m.IsHidden); if (methodNode != null) return methodNode; return null; diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs index a56b324f9..3325685f3 100644 --- a/ILSpy/TreeNodes/AssemblyTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs @@ -30,7 +30,7 @@ using ICSharpCode.ILSpy.TextView; using ICSharpCode.TreeView; using Microsoft.Win32; using ICSharpCode.Decompiler.TypeSystem; -using ICSharpCode.Decompiler.TypeSystem.Implementation; +using TypeDefinitionHandle = System.Reflection.Metadata.TypeDefinitionHandle; namespace ICSharpCode.ILSpy.TreeNodes { @@ -41,7 +41,7 @@ namespace ICSharpCode.ILSpy.TreeNodes public sealed class AssemblyTreeNode : ILSpyTreeNode { readonly Dictionary namespaces = new Dictionary(); - readonly Dictionary typeDict = new Dictionary(); + readonly Dictionary typeDict = new Dictionary(); ICompilation typeSystem; public AssemblyTreeNode(LoadedAssembly assembly) @@ -145,13 +145,13 @@ namespace ICSharpCode.ILSpy.TreeNodes foreach (NamespaceTreeNode ns in namespaces.Values) { ns.Children.Clear(); } - foreach (var type in assembly.TopLevelTypeDefinitions.OrderBy(t => t.FullName, NaturalStringComparer.Instance)) { + foreach (var type in assembly.TopLevelTypeDefinitions.OrderBy(t => t.ReflectionName, NaturalStringComparer.Instance)) { if (!namespaces.TryGetValue(type.Namespace, out NamespaceTreeNode ns)) { ns = new NamespaceTreeNode(type.Namespace); namespaces[type.Namespace] = ns; } TypeTreeNode node = new TypeTreeNode(type, this); - typeDict[type] = node; + typeDict[(TypeDefinitionHandle)type.MetadataToken] = node; ns.Children.Add(node); } foreach (NamespaceTreeNode ns in namespaces.Values.OrderBy(n => n.Name, NaturalStringComparer.Instance)) { @@ -165,13 +165,13 @@ namespace ICSharpCode.ILSpy.TreeNodes /// /// Finds the node for a top-level type. /// - public TypeTreeNode FindTypeNode(ITypeDefinition def) + public TypeTreeNode FindTypeNode(ITypeDefinition type) { - if (def == null) + if (type == null) return null; EnsureLazyChildren(); TypeTreeNode node; - if (typeDict.TryGetValue(def, out node)) + if (typeDict.TryGetValue((TypeDefinitionHandle)type.MetadataToken, out node)) return node; else return null; From 99718bd34660fe0885cef804dcc08699bcf30a3d Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 8 Jul 2018 22:16:41 +0200 Subject: [PATCH 13/13] Fix display of generic types in tree view when IL language is selected. --- ILSpy/Languages/Language.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs index 26b851940..3763abeff 100644 --- a/ILSpy/Languages/Language.cs +++ b/ILSpy/Languages/Language.cs @@ -154,9 +154,14 @@ namespace ICSharpCode.ILSpy public virtual string TypeToString(IType type, bool includeNamespace) { if (includeNamespace) - return type.FullName; - else - return type.Name; + return type.ReflectionName; + else { + int index = type.ReflectionName.LastIndexOf('.'); + if (index > 0) { + return type.ReflectionName.Substring(index + 1); + } + return type.ReflectionName; + } } /// @@ -230,7 +235,7 @@ namespace ICSharpCode.ILSpy protected string GetDisplayName(IEntity entity, bool includeTypeName, bool includeNamespace) { - if (includeTypeName) { + if (includeTypeName && entity.DeclaringTypeDefinition != null) { string name; if (includeNamespace) { name = entity.DeclaringTypeDefinition.FullName; @@ -239,6 +244,8 @@ namespace ICSharpCode.ILSpy } return name + "." + entity.Name; } else { + if (includeNamespace) + return entity.FullName; return entity.Name; } }