diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs index 77327f9aa..da34d08a7 100644 --- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs @@ -302,6 +302,8 @@ namespace ICSharpCode.Decompiler.Disassembler if (spaceAfter) { output.Write(' '); } + } else if (spaceBefore && spaceAfter) { + output.Write(' '); } } @@ -1112,42 +1114,11 @@ namespace ICSharpCode.Decompiler.Disassembler { FieldAttributes.NotSerialized, "notserialized" }, }; - public void DisassembleField(PEFile module, FieldDefinitionHandle field) + public void DisassembleField(PEFile module, FieldDefinitionHandle handle) { var metadata = module.Metadata; - var fieldDefinition = metadata.GetFieldDefinition(field); - output.WriteReference(module, field, ".field ", isDefinition: true); - int offset = fieldDefinition.GetOffset(); - if (offset > -1) { - output.Write("[" + offset + "] "); - } - WriteEnum(fieldDefinition.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility); - const FieldAttributes hasXAttributes = FieldAttributes.HasDefault | FieldAttributes.HasFieldMarshal | FieldAttributes.HasFieldRVA; - WriteFlags(fieldDefinition.Attributes & ~(FieldAttributes.FieldAccessMask | hasXAttributes), fieldAttributes); - - var signature = fieldDefinition.DecodeSignature(new DisassemblerSignatureTypeProvider(module, output), new GenericContext(fieldDefinition.GetDeclaringType(), module)); - - var marshallingDescriptor = fieldDefinition.GetMarshallingDescriptor(); - if (!marshallingDescriptor.IsNil) { - WriteMarshalInfo(metadata.GetBlobReader(marshallingDescriptor)); - } - - signature(ILNameSyntax.Signature); - output.Write(' '); - var fieldName = metadata.GetString(fieldDefinition.Name); - output.Write(DisassemblerHelpers.Escape(fieldName)); - char sectionPrefix = 'D'; - if (fieldDefinition.HasFlag(FieldAttributes.HasFieldRVA)) { - int rva = fieldDefinition.GetRelativeVirtualAddress(); - sectionPrefix = GetRVASectionPrefix(module.Reader.PEHeaders, rva); - output.Write(" at {1}_{0:X8}", rva, sectionPrefix); - } - - var defaultValue = fieldDefinition.GetDefaultValue(); - if (!defaultValue.IsNil) { - output.Write(" = "); - WriteConstant(metadata, metadata.GetConstant(defaultValue)); - } + var fieldDefinition = metadata.GetFieldDefinition(handle); + char sectionPrefix = DisassembleFieldHeaderInternal(module, handle, metadata, fieldDefinition); output.WriteLine(); var attributes = fieldDefinition.GetCustomAttributes(); if (attributes.Count > 0) { @@ -1187,6 +1158,53 @@ namespace ICSharpCode.Decompiler.Disassembler } } + public void DisassembleFieldHeader(PEFile module, FieldDefinitionHandle handle) + { + var metadata = module.Metadata; + var fieldDefinition = metadata.GetFieldDefinition(handle); + DisassembleFieldHeaderInternal(module, handle, metadata, fieldDefinition); + } + + private char DisassembleFieldHeaderInternal(PEFile module, FieldDefinitionHandle handle, MetadataReader metadata, FieldDefinition fieldDefinition) + { + output.WriteReference(module, handle, ".field", isDefinition: true); + WriteMetadataToken(output, module, handle, MetadataTokens.GetToken(handle), + spaceAfter: true, spaceBefore: true, ShowMetadataTokens, ShowMetadataTokensInBase10); + int offset = fieldDefinition.GetOffset(); + if (offset > -1) { + output.Write("[" + offset + "] "); + } + WriteEnum(fieldDefinition.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility); + const FieldAttributes hasXAttributes = FieldAttributes.HasDefault | FieldAttributes.HasFieldMarshal | FieldAttributes.HasFieldRVA; + WriteFlags(fieldDefinition.Attributes & ~(FieldAttributes.FieldAccessMask | hasXAttributes), fieldAttributes); + + var signature = fieldDefinition.DecodeSignature(new DisassemblerSignatureTypeProvider(module, output), new GenericContext(fieldDefinition.GetDeclaringType(), module)); + + var marshallingDescriptor = fieldDefinition.GetMarshallingDescriptor(); + if (!marshallingDescriptor.IsNil) { + WriteMarshalInfo(metadata.GetBlobReader(marshallingDescriptor)); + } + + signature(ILNameSyntax.Signature); + output.Write(' '); + var fieldName = metadata.GetString(fieldDefinition.Name); + output.Write(DisassemblerHelpers.Escape(fieldName)); + char sectionPrefix = 'D'; + if (fieldDefinition.HasFlag(FieldAttributes.HasFieldRVA)) { + int rva = fieldDefinition.GetRelativeVirtualAddress(); + sectionPrefix = GetRVASectionPrefix(module.Reader.PEHeaders, rva); + output.Write(" at {1}_{0:X8}", rva, sectionPrefix); + } + + var defaultValue = fieldDefinition.GetDefaultValue(); + if (!defaultValue.IsNil) { + output.Write(" = "); + WriteConstant(metadata, metadata.GetConstant(defaultValue)); + } + + return sectionPrefix; + } + char GetRVASectionPrefix(System.Reflection.PortableExecutable.PEHeaders headers, int rva) { int sectionIndex = headers.GetContainingSectionIndex(rva); @@ -1215,8 +1233,30 @@ namespace ICSharpCode.Decompiler.Disassembler { var metadata = module.Metadata; var propertyDefinition = metadata.GetPropertyDefinition(property); - output.WriteReference(module, property, ".property", isDefinition: true); - output.Write(" "); + PropertyAccessors accessors = DisassemblePropertyHeaderInternal(module, property, metadata, propertyDefinition); + + OpenBlock(false); + WriteAttributes(module, propertyDefinition.GetCustomAttributes()); + WriteNestedMethod(".get", module, accessors.Getter); + WriteNestedMethod(".set", module, accessors.Setter); + foreach (var method in accessors.Others) { + WriteNestedMethod(".other", module, method); + } + CloseBlock(); + } + + public void DisassemblePropertyHeader(PEFile module, PropertyDefinitionHandle property) + { + var metadata = module.Metadata; + var propertyDefinition = metadata.GetPropertyDefinition(property); + DisassemblePropertyHeaderInternal(module, property, metadata, propertyDefinition); + } + + private PropertyAccessors DisassemblePropertyHeaderInternal(PEFile module, PropertyDefinitionHandle handle, MetadataReader metadata, PropertyDefinition propertyDefinition) + { + output.WriteReference(module, handle, ".property", isDefinition: true); + WriteMetadataToken(output, module, handle, MetadataTokens.GetToken(handle), + spaceAfter: true, spaceBefore: true, ShowMetadataTokens, ShowMetadataTokensInBase10); WriteFlags(propertyDefinition.Attributes, propertyAttributes); var accessors = propertyDefinition.GetAccessors(); var declaringType = metadata.GetMethodDefinition(accessors.GetAny()).GetDeclaringType(); @@ -1239,15 +1279,7 @@ namespace ICSharpCode.Decompiler.Disassembler output.Unindent(); } output.Write(')'); - - OpenBlock(false); - WriteAttributes(module, propertyDefinition.GetCustomAttributes()); - WriteNestedMethod(".get", module, accessors.Getter); - WriteNestedMethod(".set", module, accessors.Setter); - foreach (var method in accessors.Others) { - WriteNestedMethod(".other", module, method); - } - CloseBlock(); + return accessors; } void WriteNestedMethod(string keyword, PEFile module, MethodDefinitionHandle method) @@ -1272,6 +1304,27 @@ namespace ICSharpCode.Decompiler.Disassembler { var eventDefinition = module.Metadata.GetEventDefinition(handle); var accessors = eventDefinition.GetAccessors(); + DisassembleEventHeaderInternal(module, handle, eventDefinition, accessors); + OpenBlock(false); + WriteAttributes(module, eventDefinition.GetCustomAttributes()); + WriteNestedMethod(".addon", module, accessors.Adder); + WriteNestedMethod(".removeon", module, accessors.Remover); + WriteNestedMethod(".fire", module, accessors.Raiser); + foreach (var method in accessors.Others) { + WriteNestedMethod(".other", module, method); + } + CloseBlock(); + } + + public void DisassembleEventHeader(PEFile module, EventDefinitionHandle handle) + { + var eventDefinition = module.Metadata.GetEventDefinition(handle); + var accessors = eventDefinition.GetAccessors(); + DisassembleEventHeaderInternal(module, handle, eventDefinition, accessors); + } + + private void DisassembleEventHeaderInternal(PEFile module, EventDefinitionHandle handle, EventDefinition eventDefinition, EventAccessors accessors) + { TypeDefinitionHandle declaringType; if (!accessors.Adder.IsNil) { declaringType = module.Metadata.GetMethodDefinition(accessors.Adder).GetDeclaringType(); @@ -1281,7 +1334,8 @@ namespace ICSharpCode.Decompiler.Disassembler declaringType = module.Metadata.GetMethodDefinition(accessors.Raiser).GetDeclaringType(); } output.WriteReference(module, handle, ".event", isDefinition: true); - output.Write(" "); + WriteMetadataToken(output, module, handle, MetadataTokens.GetToken(handle), + spaceAfter: true, spaceBefore: true, ShowMetadataTokens, ShowMetadataTokensInBase10); WriteFlags(eventDefinition.Attributes, eventAttributes); var provider = new DisassemblerSignatureTypeProvider(module, output); Action signature; @@ -1302,15 +1356,6 @@ namespace ICSharpCode.Decompiler.Disassembler signature(ILNameSyntax.TypeName); output.Write(' '); output.Write(DisassemblerHelpers.Escape(module.Metadata.GetString(eventDefinition.Name))); - OpenBlock(false); - WriteAttributes(module, eventDefinition.GetCustomAttributes()); - WriteNestedMethod(".addon", module, accessors.Adder); - WriteNestedMethod(".removeon", module, accessors.Remover); - WriteNestedMethod(".fire", module, accessors.Raiser); - foreach (var method in accessors.Others) { - WriteNestedMethod(".other", module, method); - } - CloseBlock(); } #endregion @@ -1352,30 +1397,9 @@ namespace ICSharpCode.Decompiler.Disassembler public void DisassembleType(PEFile module, TypeDefinitionHandle type) { var typeDefinition = module.Metadata.GetTypeDefinition(type); - output.WriteReference(module, type, ".class", isDefinition: true); - output.Write(" "); - if ((typeDefinition.Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface) - output.Write("interface "); - WriteEnum(typeDefinition.Attributes & TypeAttributes.VisibilityMask, typeVisibility); - WriteEnum(typeDefinition.Attributes & TypeAttributes.LayoutMask, typeLayout); - WriteEnum(typeDefinition.Attributes & TypeAttributes.StringFormatMask, typeStringFormat); - const TypeAttributes masks = TypeAttributes.ClassSemanticsMask | TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.StringFormatMask; - WriteFlags(typeDefinition.Attributes & ~masks, typeAttributes); - - 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(); - EntityHandle baseType = typeDefinition.GetBaseTypeOrNil(); - if (!baseType.IsNil) { - output.Indent(); - output.Write("extends "); - baseType.WriteTo(module, output, genericContext, ILNameSyntax.TypeName); - output.WriteLine(); - output.Unindent(); - } + DisassembleTypeHeaderInternal(module, type, typeDefinition, genericContext); var interfaces = typeDefinition.GetInterfaceImplementations(); if (interfaces.Count > 0) { @@ -1463,6 +1487,40 @@ namespace ICSharpCode.Decompiler.Disassembler isInType = oldIsInType; } + public void DisassembleTypeHeader(PEFile module, TypeDefinitionHandle type) + { + var typeDefinition = module.Metadata.GetTypeDefinition(type); + GenericContext genericContext = new GenericContext(type, module); + DisassembleTypeHeaderInternal(module, type, typeDefinition, genericContext); + } + + private void DisassembleTypeHeaderInternal(PEFile module, TypeDefinitionHandle handle, TypeDefinition typeDefinition, GenericContext genericContext) + { + output.WriteReference(module, handle, ".class", isDefinition: true); + WriteMetadataToken(output, module, handle, MetadataTokens.GetToken(handle), + spaceAfter: true, spaceBefore: true, ShowMetadataTokens, ShowMetadataTokensInBase10); if ((typeDefinition.Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface) + output.Write("interface "); + WriteEnum(typeDefinition.Attributes & TypeAttributes.VisibilityMask, typeVisibility); + WriteEnum(typeDefinition.Attributes & TypeAttributes.LayoutMask, typeLayout); + WriteEnum(typeDefinition.Attributes & TypeAttributes.StringFormatMask, typeStringFormat); + const TypeAttributes masks = TypeAttributes.ClassSemanticsMask | TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.StringFormatMask; + WriteFlags(typeDefinition.Attributes & ~masks, typeAttributes); + + output.Write(typeDefinition.GetDeclaringType().IsNil ? typeDefinition.GetFullTypeName(module.Metadata).ToILNameString() : DisassemblerHelpers.Escape(module.Metadata.GetString(typeDefinition.Name))); + WriteTypeParameters(output, module, genericContext, typeDefinition.GetGenericParameters()); + output.MarkFoldStart(defaultCollapsed: !ExpandMemberDefinitions && isInType); + output.WriteLine(); + + EntityHandle baseType = typeDefinition.GetBaseTypeOrNil(); + if (!baseType.IsNil) { + output.Indent(); + output.Write("extends "); + baseType.WriteTo(module, output, genericContext, ILNameSyntax.TypeName); + output.WriteLine(); + output.Unindent(); + } + } + void WriteTypeParameters(ITextOutput output, PEFile module, GenericContext context, GenericParameterHandleCollection p) { if (p.Count > 0) { diff --git a/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs b/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs index 6ae5f8e62..b49739bda 100644 --- a/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs +++ b/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs @@ -44,7 +44,7 @@ namespace ICSharpCode.Decompiler.IL output.Write(primitiveType.ToString().ToLowerInvariant()); } - public static void WriteTo(this IType type, ITextOutput output, ILNameSyntax nameSyntax = ILNameSyntax.ShortTypeName) + public static void WriteTo(this IType type, ITextOutput output) { output.WriteReference(type, type.ReflectionName); } diff --git a/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs index fec533c9e..72033be1a 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs @@ -135,7 +135,7 @@ namespace ICSharpCode.Decompiler.IL WriteILRange(output, options); if (ConstrainedTo != null) { output.Write("constrained["); - ConstrainedTo.WriteTo(output, ILNameSyntax.ShortTypeName); + ConstrainedTo.WriteTo(output); output.Write("]."); } if (IsTail) diff --git a/ILSpy.ReadyToRun/ReadyToRunLanguage.cs b/ILSpy.ReadyToRun/ReadyToRunLanguage.cs index 0158677aa..3bb34ee04 100644 --- a/ILSpy.ReadyToRun/ReadyToRunLanguage.cs +++ b/ILSpy.ReadyToRun/ReadyToRunLanguage.cs @@ -26,11 +26,14 @@ using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; using System.Runtime.CompilerServices; using Iced.Intel; + +using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.IL; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Solution; using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.ILSpy.TextView; using ILCompiler.Reflection.ReadyToRun; namespace ICSharpCode.ILSpy.ReadyToRun @@ -195,6 +198,11 @@ namespace ICSharpCode.ILSpy.ReadyToRun output.WriteLine(); } + public override RichText GetRichTextTooltip(IEntity entity) + { + return Languages.ILLanguage.GetRichTextTooltip(entity); + } + private ReadyToRunReaderCacheEntry GetReader(LoadedAssembly assembly, PEFile module) { ReadyToRunReaderCacheEntry result; diff --git a/ILSpy/Languages/CSharpILMixedLanguage.cs b/ILSpy/Languages/CSharpILMixedLanguage.cs index 20e058a76..6e986512a 100644 --- a/ILSpy/Languages/CSharpILMixedLanguage.cs +++ b/ILSpy/Languages/CSharpILMixedLanguage.cs @@ -47,12 +47,17 @@ namespace ICSharpCode.ILSpy protected override ReflectionDisassembler CreateDisassembler(ITextOutput output, DecompilationOptions options) { - return new ReflectionDisassembler(output, + return new ReflectionDisassembler(output, new MixedMethodBodyDisassembler(output, options) { DetectControlStructure = detectControlStructure, ShowSequencePoints = options.DecompilerSettings.ShowDebugInfo }, - options.CancellationToken); + options.CancellationToken) + { + ShowMetadataTokens = Options.DisplaySettingsPanel.CurrentDisplaySettings.ShowMetadataTokens, + ShowMetadataTokensInBase10 = Options.DisplaySettingsPanel.CurrentDisplaySettings.ShowMetadataTokensInBase10, + ExpandMemberDefinitions = options.DecompilerSettings.ExpandMemberDefinitions + }; } static CSharpDecompiler CreateDecompiler(PEFile module, DecompilationOptions options) diff --git a/ILSpy/Languages/ILLanguage.cs b/ILSpy/Languages/ILLanguage.cs index 4160e5597..7e8365a7d 100644 --- a/ILSpy/Languages/ILLanguage.cs +++ b/ILSpy/Languages/ILLanguage.cs @@ -20,15 +20,14 @@ using System.Collections.Generic; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Disassembler; using System.ComponentModel.Composition; -using System.Reflection.PortableExecutable; using System.Reflection.Metadata; -using System.IO; -using System.Reflection.Metadata.Ecma335; using System.Linq; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Solution; +using ICSharpCode.AvalonEdit.Highlighting; +using ICSharpCode.ILSpy.TextView; namespace ICSharpCode.ILSpy { @@ -178,5 +177,38 @@ namespace ICSharpCode.ILSpy } return null; } + + public override RichText GetRichTextTooltip(IEntity entity) + { + var output = new AvalonEditTextOutput() { IgnoreNewLineAndIndent = true }; + var disasm = CreateDisassembler(output, new DecompilationOptions()); + switch (entity.SymbolKind) { + case SymbolKind.TypeDefinition: + disasm.DisassembleTypeHeader(entity.ParentModule.PEFile, (TypeDefinitionHandle)entity.MetadataToken); + break; + case SymbolKind.Field: + disasm.DisassembleFieldHeader(entity.ParentModule.PEFile, (FieldDefinitionHandle)entity.MetadataToken); + break; + case SymbolKind.Property: + case SymbolKind.Indexer: + disasm.DisassemblePropertyHeader(entity.ParentModule.PEFile, (PropertyDefinitionHandle)entity.MetadataToken); + break; + case SymbolKind.Event: + disasm.DisassembleEventHeader(entity.ParentModule.PEFile, (EventDefinitionHandle)entity.MetadataToken); + break; + case SymbolKind.Method: + case SymbolKind.Operator: + case SymbolKind.Constructor: + case SymbolKind.Destructor: + case SymbolKind.Accessor: + disasm.DisassembleMethodHeader(entity.ParentModule.PEFile, (MethodDefinitionHandle)entity.MetadataToken); + break; + default: + output.Write(GetDisplayName(entity, true, true, true)); + break; + } + + return new DocumentHighlighter(output.GetDocument(), base.SyntaxHighlighting).HighlightLine(1).ToRichText(); + } } } diff --git a/ILSpy/Properties/AssemblyInfo.template.cs b/ILSpy/Properties/AssemblyInfo.template.cs index dd418e37e..5077cabf4 100644 --- a/ILSpy/Properties/AssemblyInfo.template.cs +++ b/ILSpy/Properties/AssemblyInfo.template.cs @@ -40,7 +40,7 @@ internal static class RevisionClass public const string Minor = "0"; public const string Build = "0"; public const string Revision = "$INSERTREVISION$"; - public const string VersionName = "preview3"; + public const string VersionName = "preview4"; public const string FullVersion = Major + "." + Minor + "." + Build + ".$INSERTREVISION$$INSERTBRANCHPOSTFIX$$INSERTVERSIONNAMEPOSTFIX$"; } diff --git a/ILSpy/TextView/AvalonEditTextOutput.cs b/ILSpy/TextView/AvalonEditTextOutput.cs index 3259ccf1b..fdaa23f19 100644 --- a/ILSpy/TextView/AvalonEditTextOutput.cs +++ b/ILSpy/TextView/AvalonEditTextOutput.cs @@ -82,6 +82,8 @@ namespace ICSharpCode.ILSpy.TextView public string IndentationString { get; set; } = "\t"; + internal bool IgnoreNewLineAndIndent { get; set; } + public string Title { get; set; } = Properties.Resources.NewTab; /// @@ -177,16 +179,22 @@ namespace ICSharpCode.ILSpy.TextView public void Indent() { + if (IgnoreNewLineAndIndent) + return; indent++; } public void Unindent() { + if (IgnoreNewLineAndIndent) + return; indent--; } void WriteIndent() { + if (IgnoreNewLineAndIndent) + return; Debug.Assert(textDocument == null); if (needsIndent) { needsIndent = false; @@ -211,10 +219,14 @@ namespace ICSharpCode.ILSpy.TextView public void WriteLine() { Debug.Assert(textDocument == null); - b.AppendLine(); - needsIndent = true; - lastLineStart = b.Length; - lineNumber++; + if (IgnoreNewLineAndIndent) { + b.Append(' '); + } else { + b.AppendLine(); + needsIndent = true; + lastLineStart = b.Length; + lineNumber++; + } if (this.TextLength > LengthLimit) { throw new OutputLengthExceededException(); }