Browse Source

Store debugger member mappings in a simple list in the text output; copy the entries into the DebugInformation only when the output gets displayed.

MemberBookmark: Re-use the GetIcon methods from the TreeNodes.
pull/285/head
Daniel Grunwald 14 years ago
parent
commit
c542648d87
  1. 71
      ICSharpCode.Decompiler/PlainTextOutput.cs
  2. 2
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  3. 111
      ILSpy/Bookmarks/MemberBookmark.cs
  4. 43
      ILSpy/TextView/AvalonEditTextOutput.cs
  5. 35
      ILSpy/TextView/DecompilerTextView.cs

71
ICSharpCode.Decompiler/PlainTextOutput.cs

@ -17,57 +17,12 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using ICSharpCode.NRefactory; using ICSharpCode.NRefactory;
using Mono.Cecil;
namespace ICSharpCode.Decompiler namespace ICSharpCode.Decompiler
{ {
/// <summary> public sealed class PlainTextOutput : ITextOutput
/// Base text output.
/// <remarks>Provides access to code mappings.</remarks>
/// </summary>
public abstract class BaseTextOutput : ITextOutput
{
#region Code mappings
Dictionary<int, MemberMapping> codeMappings = new Dictionary<int, MemberMapping>();
public Dictionary<int, MemberMapping> CodeMappings {
get { return codeMappings; }
}
public virtual void AddDebuggerMemberMapping(MemberMapping memberMapping)
{
if (memberMapping == null)
throw new ArgumentNullException("memberMapping");
int token = memberMapping.MetadataToken;
codeMappings.Add(token, memberMapping);
}
#endregion
#region ITextOutput members
public abstract TextLocation Location { get; }
public abstract void Indent();
public abstract void Unindent();
public abstract void Write(char ch);
public abstract void Write(string text);
public abstract void WriteLine();
public abstract void WriteDefinition(string text, object definition, bool isLocal);
public abstract void WriteReference(string text, object reference, bool isLocal);
public abstract void MarkFoldStart(string collapsedText, bool defaultCollapsed);
public abstract void MarkFoldEnd();
#endregion
}
/// <summary>
/// Plain text output.
/// <remarks>Can be used when there's no UI.</remarks>
/// </summary>
public sealed class PlainTextOutput : BaseTextOutput
{ {
readonly TextWriter writer; readonly TextWriter writer;
int indent; int indent;
@ -88,7 +43,7 @@ namespace ICSharpCode.Decompiler
this.writer = new StringWriter(); this.writer = new StringWriter();
} }
public override TextLocation Location { public TextLocation Location {
get { get {
return new TextLocation(line, column + (needsIndent ? indent : 0)); return new TextLocation(line, column + (needsIndent ? indent : 0));
} }
@ -99,12 +54,12 @@ namespace ICSharpCode.Decompiler
return writer.ToString(); return writer.ToString();
} }
public override void Indent() public void Indent()
{ {
indent++; indent++;
} }
public override void Unindent() public void Unindent()
{ {
indent--; indent--;
} }
@ -120,21 +75,21 @@ namespace ICSharpCode.Decompiler
} }
} }
public override void Write(char ch) public void Write(char ch)
{ {
WriteIndent(); WriteIndent();
writer.Write(ch); writer.Write(ch);
column++; column++;
} }
public override void Write(string text) public void Write(string text)
{ {
WriteIndent(); WriteIndent();
writer.Write(text); writer.Write(text);
column += text.Length; column += text.Length;
} }
public override void WriteLine() public void WriteLine()
{ {
writer.WriteLine(); writer.WriteLine();
needsIndent = true; needsIndent = true;
@ -142,21 +97,25 @@ namespace ICSharpCode.Decompiler
column = 1; column = 1;
} }
public override void WriteDefinition(string text, object definition, bool isLocal) public void WriteDefinition(string text, object definition, bool isLocal)
{ {
Write(text); Write(text);
} }
public override void WriteReference(string text, object reference, bool isLocal) public void WriteReference(string text, object reference, bool isLocal)
{ {
Write(text); Write(text);
} }
public override void MarkFoldStart(string collapsedText, bool defaultCollapsed) void ITextOutput.MarkFoldStart(string collapsedText, bool defaultCollapsed)
{
}
void ITextOutput.MarkFoldEnd()
{ {
} }
public override void MarkFoldEnd() void ITextOutput.AddDebuggerMemberMapping(MemberMapping memberMapping)
{ {
} }
} }

2
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -14,7 +14,7 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors> <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<NoWarn>67,169,1058,728,1720</NoWarn> <NoWarn>67,169,1058,728,1720,649</NoWarn>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'x86' "> <PropertyGroup Condition=" '$(Platform)' == 'x86' ">
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>

111
ILSpy/Bookmarks/MemberBookmark.cs

@ -52,19 +52,19 @@ namespace ICSharpCode.ILSpy.Bookmarks
public virtual ImageSource Image { public virtual ImageSource Image {
get { get {
if (member is FieldDefinition) if (member is FieldDefinition)
return GetOverlayedImage(member as FieldDefinition, MemberIcon.Field); return TreeNodes.FieldTreeNode.GetIcon((FieldDefinition)member);
if (member is PropertyDefinition) if (member is PropertyDefinition)
return GetOverlayedImage(member as PropertyDefinition, MemberIcon.Property); return TreeNodes.PropertyTreeNode.GetIcon((PropertyDefinition)member);
if (member is EventDefinition) if (member is EventDefinition)
return GetOverlayedImage(member as EventDefinition, MemberIcon.Event); return TreeNodes.EventTreeNode.GetIcon((EventDefinition)member);
if (member is MethodDefinition) if (member is MethodDefinition)
return GetOverlayedImage(member as MethodDefinition, MemberIcon.Method); return TreeNodes.MethodTreeNode.GetIcon((MethodDefinition)member);
if (member is TypeDefinition) if (member is TypeDefinition)
return GetOverlayedImage(member as TypeDefinition); return TreeNodes.TypeTreeNode.GetIcon((TypeDefinition)member);
return null; return null;
} }
@ -94,105 +94,6 @@ namespace ICSharpCode.ILSpy.Bookmarks
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
#region Overlayed images
internal ImageSource GetOverlayedImage(TypeDefinition typeDef)
{
TypeIcon icon = TypeIcon.Class;
if (typeDef.IsEnum)
icon = TypeIcon.Enum;
if (typeDef.IsValueType)
icon = TypeIcon.Struct;
if (typeDef.IsInterface)
icon = TypeIcon.Interface;
if (typeDef.BaseType.FullName == "System.MulticastDelegate" || typeDef.BaseType.FullName == "System.Delegate")
icon = TypeIcon.Delegate;
bool isStatic = false;
AccessOverlayIcon overlayIcon = AccessOverlayIcon.Private;
if (typeDef.IsNestedPrivate)
overlayIcon = AccessOverlayIcon.Public;
else if (typeDef.IsNestedAssembly || typeDef.IsNestedFamilyAndAssembly || typeDef.IsNotPublic)
overlayIcon = AccessOverlayIcon.Internal;
else if (typeDef.IsNestedFamily)
overlayIcon = AccessOverlayIcon.Protected;
else if (typeDef.IsNestedFamilyOrAssembly)
overlayIcon = AccessOverlayIcon.ProtectedInternal;
else if (typeDef.IsPublic || typeDef.IsNestedPublic)
overlayIcon = AccessOverlayIcon.Public;
if (typeDef.IsAbstract && typeDef.IsSealed)
isStatic = true;
return Images.GetIcon(icon, overlayIcon, isStatic);
}
ImageSource GetOverlayedImage(FieldDefinition fieldDef, MemberIcon icon)
{
bool isStatic = false;
AccessOverlayIcon overlayIcon = AccessOverlayIcon.Public;
if (fieldDef.IsPrivate)
overlayIcon = AccessOverlayIcon.Private;
else if (fieldDef.IsAssembly || fieldDef.IsFamilyAndAssembly)
overlayIcon = AccessOverlayIcon.Internal;
else if (fieldDef.IsFamily)
overlayIcon = AccessOverlayIcon.Protected;
else if (fieldDef.IsFamilyOrAssembly)
overlayIcon = AccessOverlayIcon.ProtectedInternal;
else if (fieldDef.IsPublic)
overlayIcon = AccessOverlayIcon.Public;
if (fieldDef.IsStatic)
isStatic = true;
return Images.GetIcon(icon, overlayIcon, isStatic);
}
ImageSource GetOverlayedImage(MethodDefinition methodDef, MemberIcon icon)
{
bool isStatic = false;
AccessOverlayIcon overlayIcon = AccessOverlayIcon.Public;
if (methodDef == null)
return Images.GetIcon(icon, overlayIcon, isStatic);;
if (methodDef.IsPrivate)
overlayIcon = AccessOverlayIcon.Private;
else if (methodDef.IsAssembly || methodDef.IsFamilyAndAssembly)
overlayIcon = AccessOverlayIcon.Internal;
else if (methodDef.IsFamily)
overlayIcon = AccessOverlayIcon.Protected;
else if (methodDef.IsFamilyOrAssembly)
overlayIcon = AccessOverlayIcon.ProtectedInternal;
else if (methodDef.IsPublic)
overlayIcon = AccessOverlayIcon.Public;
if (methodDef.IsStatic)
isStatic = true;
return Images.GetIcon(icon, overlayIcon, isStatic);
}
ImageSource GetOverlayedImage(PropertyDefinition propDef, MemberIcon icon)
{
bool isStatic = false;
AccessOverlayIcon overlayIcon = AccessOverlayIcon.Public;
return Images.GetIcon(propDef.IsIndexer() ? MemberIcon.Indexer : icon, overlayIcon, isStatic);
}
ImageSource GetOverlayedImage(EventDefinition eventDef, MemberIcon icon)
{
bool isStatic = false;
AccessOverlayIcon overlayIcon = AccessOverlayIcon.Public;
return Images.GetIcon(icon, overlayIcon, isStatic);
}
#endregion
} }
public class TypeBookmark : MemberBookmark public class TypeBookmark : MemberBookmark
@ -204,7 +105,7 @@ namespace ICSharpCode.ILSpy.Bookmarks
public override ImageSource Image { public override ImageSource Image {
get { get {
if (Member is TypeDefinition) { if (Member is TypeDefinition) {
return GetOverlayedImage(Member as TypeDefinition); return TreeNodes.TypeTreeNode.GetIcon((TypeDefinition)Member);
} }
return null; return null;

43
ILSpy/TextView/AvalonEditTextOutput.cs

@ -67,7 +67,7 @@ namespace ICSharpCode.ILSpy.TextView
/// <summary> /// <summary>
/// Text output implementation for AvalonEdit. /// Text output implementation for AvalonEdit.
/// </summary> /// </summary>
public sealed class AvalonEditTextOutput : BaseTextOutput, ISmartTextOutput public sealed class AvalonEditTextOutput : ISmartTextOutput
{ {
int lastLineStart = 0; int lastLineStart = 0;
int lineNumber = 1; int lineNumber = 1;
@ -94,6 +94,8 @@ namespace ICSharpCode.ILSpy.TextView
/// <summary>Embedded UIElements, see <see cref="UIElementGenerator"/>.</summary> /// <summary>Embedded UIElements, see <see cref="UIElementGenerator"/>.</summary>
internal readonly List<KeyValuePair<int, Lazy<UIElement>>> UIElements = new List<KeyValuePair<int, Lazy<UIElement>>>(); internal readonly List<KeyValuePair<int, Lazy<UIElement>>> UIElements = new List<KeyValuePair<int, Lazy<UIElement>>>();
internal readonly List<MemberMapping> DebuggerMemberMappings = new List<MemberMapping>();
public AvalonEditTextOutput() public AvalonEditTextOutput()
{ {
} }
@ -121,7 +123,7 @@ namespace ICSharpCode.ILSpy.TextView
get { return b.Length; } get { return b.Length; }
} }
public override ICSharpCode.NRefactory.TextLocation Location { public ICSharpCode.NRefactory.TextLocation Location {
get { get {
return new ICSharpCode.NRefactory.TextLocation(lineNumber, b.Length - lastLineStart + 1 + (needsIndent ? indent : 0)); return new ICSharpCode.NRefactory.TextLocation(lineNumber, b.Length - lastLineStart + 1 + (needsIndent ? indent : 0));
} }
@ -159,12 +161,12 @@ namespace ICSharpCode.ILSpy.TextView
} }
#endregion #endregion
public override void Indent() public void Indent()
{ {
indent++; indent++;
} }
public override void Unindent() public void Unindent()
{ {
indent--; indent--;
} }
@ -180,19 +182,19 @@ namespace ICSharpCode.ILSpy.TextView
} }
} }
public override void Write(char ch) public void Write(char ch)
{ {
WriteIndent(); WriteIndent();
b.Append(ch); b.Append(ch);
} }
public override void Write(string text) public void Write(string text)
{ {
WriteIndent(); WriteIndent();
b.Append(text); b.Append(text);
} }
public override void WriteLine() public void WriteLine()
{ {
Debug.Assert(textDocument == null); Debug.Assert(textDocument == null);
b.AppendLine(); b.AppendLine();
@ -204,7 +206,7 @@ namespace ICSharpCode.ILSpy.TextView
} }
} }
public override void WriteDefinition(string text, object definition, bool isLocal) public void WriteDefinition(string text, object definition, bool isLocal)
{ {
WriteIndent(); WriteIndent();
int start = this.TextLength; int start = this.TextLength;
@ -214,7 +216,7 @@ namespace ICSharpCode.ILSpy.TextView
references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = definition, IsLocal = isLocal, IsLocalTarget = true }); references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = definition, IsLocal = isLocal, IsLocalTarget = true });
} }
public override void WriteReference(string text, object reference, bool isLocal) public void WriteReference(string text, object reference, bool isLocal)
{ {
WriteIndent(); WriteIndent();
int start = this.TextLength; int start = this.TextLength;
@ -223,7 +225,7 @@ namespace ICSharpCode.ILSpy.TextView
references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = reference, IsLocal = isLocal }); references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = reference, IsLocal = isLocal });
} }
public override void MarkFoldStart(string collapsedText, bool defaultCollapsed) public void MarkFoldStart(string collapsedText, bool defaultCollapsed)
{ {
WriteIndent(); WriteIndent();
openFoldings.Push( openFoldings.Push(
@ -234,7 +236,7 @@ namespace ICSharpCode.ILSpy.TextView
}); });
} }
public override void MarkFoldEnd() public void MarkFoldEnd()
{ {
NewFolding f = openFoldings.Pop(); NewFolding f = openFoldings.Pop();
f.EndOffset = this.TextLength; f.EndOffset = this.TextLength;
@ -249,25 +251,10 @@ namespace ICSharpCode.ILSpy.TextView
this.UIElements.Add(new KeyValuePair<int, Lazy<UIElement>>(this.TextLength, new Lazy<UIElement>(element))); this.UIElements.Add(new KeyValuePair<int, Lazy<UIElement>>(this.TextLength, new Lazy<UIElement>(element)));
} }
} }
}
internal static class Extentions public void AddDebuggerMemberMapping(MemberMapping memberMapping)
{
public static Dictionary<MemberReference, int> ToDictionary(this DefinitionLookup definitions, Func<int, int> lineNumber)
{ {
if (definitions == null) DebuggerMemberMappings.Add(memberMapping);
throw new ArgumentNullException("definitions");
var result = new Dictionary<MemberReference, int>();
foreach (var element in definitions.definitions) {
if (!(element.Key is MemberReference))
continue;
result.Add((MemberReference)element.Key, lineNumber(element.Value));
}
return result;
} }
} }
} }

35
ILSpy/TextView/DecompilerTextView.cs

@ -358,11 +358,23 @@ namespace ICSharpCode.ILSpy.TextView
Debug.WriteLine(" Updating folding: {0}", w.Elapsed); w.Restart(); Debug.WriteLine(" Updating folding: {0}", w.Elapsed); w.Restart();
} }
// update debugger info
DebugInformation.CodeMappings = textOutput.DebuggerMemberMappings.ToDictionary(m => m.MetadataToken);
// update class bookmarks // update class bookmarks
var document = textEditor.Document; var document = textEditor.Document;
manager.UpdateClassMemberBookmarks(textOutput.DefinitionLookup.ToDictionary(line => document.GetLineByOffset(line).LineNumber), manager.Bookmarks.Clear();
typeof(TypeBookmark), foreach (var pair in textOutput.DefinitionLookup.definitions) {
typeof(MemberBookmark)); MemberReference member = pair.Key as MemberReference;
int offset = pair.Value;
if (member != null) {
int line = document.GetLocation(offset).Line;
if (member is TypeDefinition)
manager.Bookmarks.Add(new TypeBookmark(member, line));
else
manager.Bookmarks.Add(new MemberBookmark(member, line));
}
}
} }
#endregion #endregion
@ -535,9 +547,6 @@ namespace ICSharpCode.ILSpy.TextView
void DecompileNodes(DecompilationContext context, ITextOutput textOutput) void DecompileNodes(DecompilationContext context, ITextOutput textOutput)
{ {
// reset debug information
DebugInformation.CodeMappings = null;
var nodes = context.TreeNodes; var nodes = context.TreeNodes;
for (int i = 0; i < nodes.Length; i++) { for (int i = 0; i < nodes.Length; i++) {
if (i > 0) if (i > 0)
@ -546,21 +555,7 @@ namespace ICSharpCode.ILSpy.TextView
context.Options.CancellationToken.ThrowIfCancellationRequested(); context.Options.CancellationToken.ThrowIfCancellationRequested();
nodes[i].Decompile(context.Language, textOutput, context.Options); nodes[i].Decompile(context.Language, textOutput, context.Options);
} }
OnDecompilationFinished(textOutput);
}
void OnDecompilationFinished(ITextOutput textOutput)
{
if (!(textOutput is AvalonEditTextOutput))
return;
var output = textOutput as AvalonEditTextOutput;
// update debug inforomation
DebugInformation.CodeMappings = output.CodeMappings;
} }
#endregion #endregion
#region WriteOutputLengthExceededMessage #region WriteOutputLengthExceededMessage

Loading…
Cancel
Save