From 7bf0ed79d4a54fd8b7bcf895c2c3d13ea6f5f713 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 27 Aug 2017 23:00:29 +0200 Subject: [PATCH] Fix hyperlinks in decompiled output. --- .../CSharp/CSharpDecompiler.cs | 2 + .../ICSharpCode.Decompiler.csproj | 1 + .../Output}/TextTokenWriter.cs | 79 +++++++++++-------- .../TypeSystem/DecompilerTypeSystem.cs | 9 +-- ILSpy/ILSpy.csproj | 1 - ILSpy/Languages/CSharpLanguage.cs | 13 +-- 6 files changed, 61 insertions(+), 44 deletions(-) rename {ILSpy/Languages => ICSharpCode.Decompiler/Output}/TextTokenWriter.cs (80%) diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 73bdfe398..f1ce4d74e 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -137,6 +137,8 @@ namespace ICSharpCode.Decompiler.CSharp public CancellationToken CancellationToken { get; set; } + public IDecompilerTypeSystem TypeSystem => typeSystem; + /// /// IL transforms. /// diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 29a7a9858..0d427c545 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -291,6 +291,7 @@ + diff --git a/ILSpy/Languages/TextTokenWriter.cs b/ICSharpCode.Decompiler/Output/TextTokenWriter.cs similarity index 80% rename from ILSpy/Languages/TextTokenWriter.cs rename to ICSharpCode.Decompiler/Output/TextTokenWriter.cs index df7260407..2920d15c2 100644 --- a/ILSpy/Languages/TextTokenWriter.cs +++ b/ICSharpCode.Decompiler/Output/TextTokenWriter.cs @@ -24,14 +24,16 @@ using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp.OutputVisitor; using ICSharpCode.Decompiler.CSharp.Syntax; using ICSharpCode.Decompiler.IL; +using ICSharpCode.Decompiler.TypeSystem; using Mono.Cecil; -namespace ICSharpCode.ILSpy +namespace ICSharpCode.Decompiler { public class TextTokenWriter : TokenWriter { readonly ITextOutput output; readonly DecompilerSettings settings; + readonly IDecompilerTypeSystem typeSystem; readonly Stack nodeStack = new Stack(); int braceLevelWithinType = -1; bool inDocumentationComment = false; @@ -42,14 +44,17 @@ namespace ICSharpCode.ILSpy public bool FoldBraces = false; - public TextTokenWriter(ITextOutput output, DecompilerSettings settings) + public TextTokenWriter(ITextOutput output, DecompilerSettings settings, IDecompilerTypeSystem typeSystem) { if (output == null) throw new ArgumentNullException(nameof(output)); if (settings == null) throw new ArgumentNullException(nameof(settings)); + if (typeSystem == null) + throw new ArgumentNullException(nameof(typeSystem)); this.output = output; this.settings = settings; + this.typeSystem = typeSystem; } public override void WriteIdentifier(Identifier identifier) @@ -64,11 +69,21 @@ namespace ICSharpCode.ILSpy return; } - object memberRef = GetCurrentMemberReference(); + var member = GetCurrentMemberReference(); - if (memberRef != null) { - output.WriteReference(identifier.Name, memberRef); - return; + if (member != null) { + MemberReference cecil; + if (member is IType type) { + cecil = typeSystem.GetCecil(type.GetDefinition()); + } else if (member is IMember) { + cecil = typeSystem.GetCecil((IMember)member); + } else { + cecil = null; + } + if (cecil != null) { + output.WriteReference(identifier.Name, cecil); + return; + } } definition = GetCurrentLocalDefinition(); @@ -77,7 +92,7 @@ namespace ICSharpCode.ILSpy return; } - memberRef = GetCurrentLocalReference(); + var memberRef = GetCurrentLocalReference(); if (memberRef != null) { output.WriteReference(identifier.Name, memberRef, true); return; @@ -91,32 +106,32 @@ namespace ICSharpCode.ILSpy output.Write(identifier.Name); } - MemberReference GetCurrentMemberReference() + ISymbol GetCurrentMemberReference() { AstNode node = nodeStack.Peek(); - MemberReference memberRef = node.Annotation(); - if (memberRef == null && node.Role == Roles.TargetExpression && (node.Parent is InvocationExpression || node.Parent is ObjectCreateExpression)) { - memberRef = node.Parent.Annotation(); + var symbol = node.GetSymbol(); + if (symbol == null && node.Role == Roles.TargetExpression && (node.Parent is InvocationExpression || node.Parent is ObjectCreateExpression)) { + symbol = node.Parent.GetSymbol(); } - if (node is IdentifierExpression && node.Role == Roles.TargetExpression && node.Parent is InvocationExpression && memberRef != null) { - var declaringType = memberRef.DeclaringType.Resolve(); - if (declaringType != null && declaringType.IsDelegate()) + if (node is IdentifierExpression && node.Role == Roles.TargetExpression && node.Parent is InvocationExpression && symbol is IMember member) { + var declaringType = member.DeclaringType; + if (declaringType != null && declaringType.Kind == TypeKind.Delegate) return null; } - return FilterMemberReference(memberRef); + return FilterMember(symbol); } - MemberReference FilterMemberReference(MemberReference memberRef) + ISymbol FilterMember(ISymbol symbol) { - if (memberRef == null) + if (symbol == null) return null; - if (settings.AutomaticEvents && memberRef is FieldDefinition) { - var field = (FieldDefinition)memberRef; - return field.DeclaringType.Events.FirstOrDefault(ev => ev.Name == field.Name) ?? memberRef; - } + //if (settings.AutomaticEvents && member is FieldDefinition) { + // var field = (FieldDefinition)member; + // return field.DeclaringType.Events.FirstOrDefault(ev => ev.Name == field.Name) ?? member; + //} - return memberRef; + return symbol; } object GetCurrentLocalReference() @@ -129,9 +144,9 @@ namespace ICSharpCode.ILSpy var gotoStatement = node as GotoStatement; if (gotoStatement != null) { - var method = nodeStack.Select(nd => nd.Annotation()).FirstOrDefault(mr => mr != null); + var method = nodeStack.Select(nd => nd.GetSymbol() as IMethod).FirstOrDefault(mr => mr != null); if (method != null) - return method.ToString() + gotoStatement.Label; + return method + gotoStatement.Label; } return null; @@ -151,9 +166,9 @@ namespace ICSharpCode.ILSpy var label = node as LabelStatement; if (label != null) { - var method = nodeStack.Select(nd => nd.Annotation()).FirstOrDefault(mr => mr != null); + var method = nodeStack.Select(nd => nd.GetSymbol() as IMethod).FirstOrDefault(mr => mr != null); if (method != null) - return method.ToString() + label.Label; + return method + label.Label; } return null; @@ -168,7 +183,7 @@ namespace ICSharpCode.ILSpy if (node is Identifier) node = node.Parent; if (IsDefinition(node)) - return node.Annotation(); + return node.GetSymbol(); return null; } @@ -181,10 +196,10 @@ namespace ICSharpCode.ILSpy public override void WriteToken(Role role, string token) { // Attach member reference to token only if there's no identifier in the current node. - MemberReference memberRef = GetCurrentMemberReference(); + var member = GetCurrentMemberReference(); var node = nodeStack.Peek(); - if (memberRef != null && node.GetChildByRole(Roles.Identifier).IsNull) - output.WriteReference(token, memberRef); + if (member != null && node.GetChildByRole(Roles.Identifier).IsNull) + output.WriteReference(token, member); else output.Write(token); } @@ -310,8 +325,8 @@ namespace ICSharpCode.ILSpy nodeStack.Push(node); // startLocations.Push(output.Location); - if (node is EntityDeclaration && node.Annotation() != null && node.GetChildByRole(Roles.Identifier).IsNull) - output.WriteDefinition("", node.Annotation(), false); +// if (node is EntityDeclaration && node.GetSymbol() != null && node.GetChildByRole(Roles.Identifier).IsNull) +// output.WriteDefinition("", node.GetSymbol(), false); // if (node.Annotation() != null) { // symbolsStack.Push(node.Annotation()); diff --git a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs index 71fe17c8c..f04e1dd8d 100644 --- a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs +++ b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs @@ -26,7 +26,7 @@ namespace ICSharpCode.Decompiler.TypeSystem readonly CecilLoader typeReferenceCecilLoader = new CecilLoader(); /// - /// Dictionary for NRefactory->Cecil lookup. Only contains entities from the main module. + /// Dictionary for NRefactory->Cecil lookup. /// May only be accessed within lock(entityDict) /// Dictionary entityDict = new Dictionary(); @@ -41,15 +41,14 @@ namespace ICSharpCode.Decompiler.TypeSystem if (moduleDefinition == null) throw new ArgumentNullException(nameof(moduleDefinition)); this.moduleDefinition = moduleDefinition; - CecilLoader mainAssemblyCecilLoader = new CecilLoader { IncludeInternalMembers = true, LazyLoad = true, OnEntityLoaded = StoreMemberReference, ShortenInterfaceImplNames = false }; - CecilLoader referencedAssemblyCecilLoader = new CecilLoader { IncludeInternalMembers = true, LazyLoad = true, ShortenInterfaceImplNames = false }; + CecilLoader cecilLoader = new CecilLoader { IncludeInternalMembers = true, LazyLoad = true, OnEntityLoaded = StoreMemberReference, ShortenInterfaceImplNames = false }; typeReferenceCecilLoader.SetCurrentModule(moduleDefinition); - IUnresolvedAssembly mainAssembly = mainAssemblyCecilLoader.LoadModule(moduleDefinition); + IUnresolvedAssembly mainAssembly = cecilLoader.LoadModule(moduleDefinition); var referencedAssemblies = new List(); foreach (var asmRef in moduleDefinition.AssemblyReferences) { var asm = moduleDefinition.AssemblyResolver.Resolve(asmRef); if (asm != null) - referencedAssemblies.Add(referencedAssemblyCecilLoader.LoadAssembly(asm)); + referencedAssemblies.Add(cecilLoader.LoadAssembly(asm)); } compilation = new SimpleCompilation(mainAssembly, referencedAssemblies); context = new SimpleTypeResolveContext(compilation.MainAssembly); diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index c104676ac..ea199d97d 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -173,7 +173,6 @@ - diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index da5a0a1df..e35cabf77 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -30,6 +30,7 @@ using Mono.Cecil; using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp.OutputVisitor; using ICSharpCode.Decompiler.CSharp.Syntax; +using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.ILSpy { @@ -93,10 +94,10 @@ namespace ICSharpCode.ILSpy return decompiler; } - void WriteCode(ITextOutput output, DecompilerSettings settings, SyntaxTree syntaxTree) + void WriteCode(ITextOutput output, DecompilerSettings settings, SyntaxTree syntaxTree, IDecompilerTypeSystem typeSystem) { syntaxTree.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }); - var outputFormatter = new TextTokenWriter(output, settings) { FoldBraces = settings.FoldBraces }; + var outputFormatter = new TextTokenWriter(output, settings, typeSystem) { FoldBraces = settings.FoldBraces }; var formattingPolicy = settings.CSharpFormattingOptions; syntaxTree.AcceptVisitor(new CSharpOutputVisitor(outputFormatter, formattingPolicy)); } @@ -105,7 +106,7 @@ namespace ICSharpCode.ILSpy { WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true)); CSharpDecompiler decompiler = CreateDecompiler(method.Module, options); - WriteCode(output, options.DecompilerSettings, decompiler.Decompile(method)); + WriteCode(output, options.DecompilerSettings, decompiler.Decompile(method), decompiler.TypeSystem); /* AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: method.DeclaringType, isSingleMember: true); if (method.IsConstructor && !method.IsStatic && !method.DeclaringType.IsValueType) { @@ -160,7 +161,7 @@ namespace ICSharpCode.ILSpy { WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true)); CSharpDecompiler decompiler = CreateDecompiler(property.Module, options); - WriteCode(output, options.DecompilerSettings, decompiler.Decompile(property)); + WriteCode(output, options.DecompilerSettings, decompiler.Decompile(property), decompiler.TypeSystem); } /* public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options) @@ -215,14 +216,14 @@ namespace ICSharpCode.ILSpy { WriteCommentLine(output, TypeToString(ev.DeclaringType, includeNamespace: true)); CSharpDecompiler decompiler = CreateDecompiler(ev.Module, options); - WriteCode(output, options.DecompilerSettings, decompiler.Decompile(ev)); + WriteCode(output, options.DecompilerSettings, decompiler.Decompile(ev), decompiler.TypeSystem); } public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) { WriteCommentLine(output, TypeToString(type, includeNamespace: true)); CSharpDecompiler decompiler = CreateDecompiler(type.Module, options); - WriteCode(output, options.DecompilerSettings, decompiler.Decompile(type)); + WriteCode(output, options.DecompilerSettings, decompiler.Decompile(type), decompiler.TypeSystem); } /*