Browse Source

Display XML documentation in decompiler output.

pull/166/head
Daniel Grunwald 14 years ago
parent
commit
e552ae0fa1
  1. 15
      ICSharpCode.Decompiler/DecompilerSettings.cs
  2. 24
      ILSpy/CSharpLanguage.cs
  3. 1
      ILSpy/DecompilerSettingsPanel.xaml
  4. 2
      ILSpy/DecompilerSettingsPanel.xaml.cs
  5. 1
      ILSpy/ILSpy.csproj
  6. 6
      ILSpy/TextView/DecompilerTextView.cs
  7. 80
      ILSpy/XmlDoc/AddXmlDocTransform.cs

15
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -209,6 +209,21 @@ namespace ICSharpCode.Decompiler
} }
} }
bool showXmlDocumentation = true;
/// <summary>
/// Gets/Sets whether to include XML documentation comments in the decompiled code
/// </summary>
public bool ShowXmlDocumentation {
get { return showXmlDocumentation; }
set {
if (showXmlDocumentation != value) {
showXmlDocumentation = value;
OnPropertyChanged("ShowXmlDocumentation");
}
}
}
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) protected virtual void OnPropertyChanged(string propertyName)

24
ILSpy/CSharpLanguage.cs

@ -32,6 +32,7 @@ using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast; using ICSharpCode.Decompiler.Ast;
using ICSharpCode.Decompiler.Ast.Transforms; using ICSharpCode.Decompiler.Ast.Transforms;
using ICSharpCode.ILSpy.Baml; using ICSharpCode.ILSpy.Baml;
using ICSharpCode.ILSpy.XmlDoc;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil; using Mono.Cecil;
@ -89,8 +90,7 @@ namespace ICSharpCode.ILSpy
WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true)); WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: method.DeclaringType, isSingleMember: true); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: method.DeclaringType, isSingleMember: true);
codeDomBuilder.AddMethod(method); codeDomBuilder.AddMethod(method);
codeDomBuilder.RunTransformations(transformAbortCondition); RunTransformsAndGenerateCode(codeDomBuilder, output, options);
codeDomBuilder.GenerateCode(output);
} }
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options) public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
@ -98,8 +98,7 @@ namespace ICSharpCode.ILSpy
WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true)); WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: property.DeclaringType, isSingleMember: true); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: property.DeclaringType, isSingleMember: true);
codeDomBuilder.AddProperty(property); codeDomBuilder.AddProperty(property);
codeDomBuilder.RunTransformations(transformAbortCondition); RunTransformsAndGenerateCode(codeDomBuilder, output, options);
codeDomBuilder.GenerateCode(output);
} }
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options) public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
@ -107,8 +106,7 @@ namespace ICSharpCode.ILSpy
WriteCommentLine(output, TypeToString(field.DeclaringType, includeNamespace: true)); WriteCommentLine(output, TypeToString(field.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: field.DeclaringType, isSingleMember: true); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: field.DeclaringType, isSingleMember: true);
codeDomBuilder.AddField(field); codeDomBuilder.AddField(field);
codeDomBuilder.RunTransformations(transformAbortCondition); RunTransformsAndGenerateCode(codeDomBuilder, output, options);
codeDomBuilder.GenerateCode(output);
} }
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options) public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
@ -116,16 +114,22 @@ namespace ICSharpCode.ILSpy
WriteCommentLine(output, TypeToString(ev.DeclaringType, includeNamespace: true)); WriteCommentLine(output, TypeToString(ev.DeclaringType, includeNamespace: true));
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: ev.DeclaringType, isSingleMember: true); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: ev.DeclaringType, isSingleMember: true);
codeDomBuilder.AddEvent(ev); codeDomBuilder.AddEvent(ev);
codeDomBuilder.RunTransformations(transformAbortCondition); RunTransformsAndGenerateCode(codeDomBuilder, output, options);
codeDomBuilder.GenerateCode(output);
} }
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{ {
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: type); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: type);
codeDomBuilder.AddType(type); codeDomBuilder.AddType(type);
codeDomBuilder.RunTransformations(transformAbortCondition); RunTransformsAndGenerateCode(codeDomBuilder, output, options);
codeDomBuilder.GenerateCode(output); }
void RunTransformsAndGenerateCode(AstBuilder astBuilder, ITextOutput output, DecompilationOptions options)
{
astBuilder.RunTransformations(transformAbortCondition);
if (options.DecompilerSettings.ShowXmlDocumentation)
AddXmlDocTransform.Run(astBuilder.CompilationUnit);
astBuilder.GenerateCode(output);
} }
public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options) public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)

1
ILSpy/DecompilerSettingsPanel.xaml

@ -7,5 +7,6 @@
<CheckBox IsChecked="{Binding YieldReturn}">Decompile enumerators (yield return)</CheckBox> <CheckBox IsChecked="{Binding YieldReturn}">Decompile enumerators (yield return)</CheckBox>
<CheckBox IsChecked="{Binding QueryExpressions}" IsEnabled="{Binding AnonymousMethods}">Decompile query expressions</CheckBox> <CheckBox IsChecked="{Binding QueryExpressions}" IsEnabled="{Binding AnonymousMethods}">Decompile query expressions</CheckBox>
<CheckBox IsChecked="{Binding UseDebugSymbols}">Use variable names from debug symbols, if available</CheckBox> <CheckBox IsChecked="{Binding UseDebugSymbols}">Use variable names from debug symbols, if available</CheckBox>
<CheckBox IsChecked="{Binding ShowXmlDocumentation}">Show XML documentation in decompiled code</CheckBox>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

2
ILSpy/DecompilerSettingsPanel.xaml.cs

@ -62,6 +62,7 @@ namespace ICSharpCode.ILSpy
s.YieldReturn = (bool?)e.Attribute("yieldReturn") ?? s.YieldReturn; s.YieldReturn = (bool?)e.Attribute("yieldReturn") ?? s.YieldReturn;
s.QueryExpressions = (bool?)e.Attribute("queryExpressions") ?? s.QueryExpressions; s.QueryExpressions = (bool?)e.Attribute("queryExpressions") ?? s.QueryExpressions;
s.UseDebugSymbols = (bool?)e.Attribute("useDebugSymbols") ?? s.UseDebugSymbols; s.UseDebugSymbols = (bool?)e.Attribute("useDebugSymbols") ?? s.UseDebugSymbols;
s.ShowXmlDocumentation = (bool?)e.Attribute("xmlDoc") ?? s.ShowXmlDocumentation;
return s; return s;
} }
@ -73,6 +74,7 @@ namespace ICSharpCode.ILSpy
section.SetAttributeValue("yieldReturn", s.YieldReturn); section.SetAttributeValue("yieldReturn", s.YieldReturn);
section.SetAttributeValue("queryExpressions", s.QueryExpressions); section.SetAttributeValue("queryExpressions", s.QueryExpressions);
section.SetAttributeValue("useDebugSymbols", s.UseDebugSymbols); section.SetAttributeValue("useDebugSymbols", s.UseDebugSymbols);
section.SetAttributeValue("xmlDoc", s.ShowXmlDocumentation);
XElement existingElement = root.Element("DecompilerSettings"); XElement existingElement = root.Element("DecompilerSettings");
if (existingElement != null) if (existingElement != null)

1
ILSpy/ILSpy.csproj

@ -156,6 +156,7 @@
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyAccessorsTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedPropertyAccessorsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyOverridesTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedPropertyOverridesTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedPropertyTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedPropertyTreeNode.cs" />
<Compile Include="XmlDoc\AddXmlDocTransform.cs" />
<Compile Include="XmlDoc\XmlDocKeyProvider.cs" /> <Compile Include="XmlDoc\XmlDocKeyProvider.cs" />
<Compile Include="XmlDoc\XmlDocLoader.cs" /> <Compile Include="XmlDoc\XmlDocLoader.cs" />
<Compile Include="XmlDoc\XmlDocRenderer.cs" /> <Compile Include="XmlDoc\XmlDocRenderer.cs" />

6
ILSpy/TextView/DecompilerTextView.cs

@ -138,17 +138,17 @@ namespace ICSharpCode.ILSpy.TextView
} else if (mr is MethodReference) { } else if (mr is MethodReference) {
mr = ((MethodReference)mr).Resolve() ?? mr; mr = ((MethodReference)mr).Resolve() ?? mr;
} }
XmlDocRenderer renderer = new XmlDocRenderer();
renderer.AppendText(MainWindow.Instance.CurrentLanguage.GetTooltip(mr));
XmlDocumentationProvider docProvider = XmlDocLoader.LoadDocumentation(mr.Module); XmlDocumentationProvider docProvider = XmlDocLoader.LoadDocumentation(mr.Module);
if (docProvider != null) { if (docProvider != null) {
XmlDocRenderer renderer = new XmlDocRenderer();
renderer.AppendText(MainWindow.Instance.CurrentLanguage.GetTooltip(mr));
string documentation = docProvider.GetDocumentation(XmlDocKeyProvider.GetKey(mr)); string documentation = docProvider.GetDocumentation(XmlDocKeyProvider.GetKey(mr));
if (documentation != null) { if (documentation != null) {
renderer.AppendText(Environment.NewLine); renderer.AppendText(Environment.NewLine);
renderer.AddXmlDocumentation(documentation); renderer.AddXmlDocumentation(documentation);
} }
return renderer.CreateTextBlock();
} }
return renderer.CreateTextBlock();
} }
return null; return null;
} }

80
ILSpy/XmlDoc/AddXmlDocTransform.cs

@ -0,0 +1,80 @@
// 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.IO;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.XmlDoc
{
/// <summary>
/// Adds XML documentation for member definitions.
/// </summary>
static class AddXmlDocTransform
{
public static void Run(AstNode node)
{
if (node is AttributedNode) {
MemberReference mr = node.Annotation<MemberReference>();
if (mr != null && mr.Module != null) {
var xmldoc = XmlDocLoader.LoadDocumentation(mr.Module);
if (xmldoc != null) {
string doc = xmldoc.GetDocumentation(XmlDocKeyProvider.GetKey(mr));
if (doc != null) {
InsertXmlDocumentation(node, new StringReader(doc));
}
}
}
if (!(node is TypeDeclaration))
return; // don't recurse into attributed nodes, except for type definitions
}
foreach (AstNode child in node.Children)
Run(child);
}
static void InsertXmlDocumentation(AstNode node, StringReader r)
{
// Find the first non-empty line:
string firstLine;
do {
firstLine = r.ReadLine();
if (firstLine == null)
return;
} while (string.IsNullOrWhiteSpace(firstLine));
string indentation = firstLine.Substring(0, firstLine.Length - firstLine.TrimStart().Length);
string line = firstLine;
int skippedWhitespaceLines = 0;
// Copy all lines from input to output, except for empty lines at the end.
while (line != null) {
if (string.IsNullOrWhiteSpace(line)) {
skippedWhitespaceLines++;
} else {
while (skippedWhitespaceLines > 0) {
node.Parent.InsertChildBefore(node, new Comment(string.Empty, CommentType.Documentation), AstNode.Roles.Comment);
skippedWhitespaceLines--;
}
if (line.StartsWith(indentation, StringComparison.Ordinal))
line = line.Substring(indentation.Length);
node.Parent.InsertChildBefore(node, new Comment(" " + line, CommentType.Documentation), AstNode.Roles.Comment);
}
line = r.ReadLine();
}
}
}
}
Loading…
Cancel
Save