Browse Source

Refactored handling of debug mapping in the decompiler: we now avoid using a side-channel for the debug info and instead return it via the ITextOutput.

pull/205/merge
Daniel Grunwald 14 years ago
parent
commit
56c75e09b2
  1. 51
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 29
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 69
      ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
  4. 90
      ICSharpCode.Decompiler/CodeMappings.cs
  5. 8
      ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
  6. 12
      ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  7. 11
      ICSharpCode.Decompiler/ITextOutput.cs
  8. 27
      ICSharpCode.Decompiler/PlainTextOutput.cs
  9. 6
      ILSpy/Bookmarks/MemberBookmark.cs
  10. 6
      ILSpy/Languages/CSharpLanguage.cs
  11. 7
      ILSpy/Languages/ILLanguage.cs
  12. 43
      ILSpy/Languages/Language.cs
  13. 20
      ILSpy/TextView/AvalonEditTextOutput.cs
  14. 1
      ILSpy/VB/VBLanguage.cs

51
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.Ast
DoNotUsePrimitiveTypeNames = 4
}
public class AstBuilder : BaseCodeMappings
public class AstBuilder
{
DecompilerContext context;
CompilationUnit astCompileUnit = new CompilationUnit();
@ -62,10 +62,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -62,10 +62,6 @@ namespace ICSharpCode.Decompiler.Ast
throw new ArgumentNullException("context");
this.context = context;
this.DecompileMethodBodies = true;
this.LocalVariables = new ConcurrentDictionary<int, IEnumerable<ILVariable>>();
this.CodeMappings = new Dictionary<int, List<MemberMapping>>();
this.DecompiledMemberReferences = new Dictionary<int, MemberReference>();
}
public static bool MemberIsHidden(MemberReference member, DecompilerSettings settings)
@ -729,11 +725,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -729,11 +725,7 @@ namespace ICSharpCode.Decompiler.Ast
AttributedNode CreateMethod(MethodDefinition methodDef)
{
// Create mapping - used in debugger
CreateCodeMappings(methodDef.MetadataToken.ToInt32(), methodDef);
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[methodDef.MetadataToken.ToInt32()]);
MethodDeclaration astMethod = new MethodDeclaration().WithAnnotation(methodMapping);
MethodDeclaration astMethod = new MethodDeclaration();
astMethod.AddAnnotation(methodDef);
astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType);
astMethod.Name = CleanName(methodDef.Name);
@ -823,10 +815,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -823,10 +815,6 @@ namespace ICSharpCode.Decompiler.Ast
ConstructorDeclaration CreateConstructor(MethodDefinition methodDef)
{
// Create mapping - used in debugger
CreateCodeMappings(methodDef.MetadataToken.ToInt32(), methodDef);
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[methodDef.MetadataToken.ToInt32()]);
ConstructorDeclaration astMethod = new ConstructorDeclaration();
astMethod.AddAnnotation(methodDef);
astMethod.Modifiers = ConvertModifiers(methodDef);
@ -838,7 +826,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -838,7 +826,6 @@ namespace ICSharpCode.Decompiler.Ast
astMethod.Parameters.AddRange(MakeParameters(methodDef));
astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters);
ConvertAttributes(astMethod, methodDef);
astMethod.WithAnnotation(methodMapping);
if (methodDef.IsStatic && methodDef.DeclaringType.IsBeforeFieldInit && !astMethod.Body.IsNull) {
astMethod.Body.InsertChildAfter(null, new Comment(" Note: this type is marked as 'beforefieldinit'."), AstNode.Roles.Comment);
}
@ -891,10 +878,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -891,10 +878,6 @@ namespace ICSharpCode.Decompiler.Ast
astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
if (propDef.GetMethod != null) {
// Create mapping - used in debugger
CreateCodeMappings(propDef.GetMethod.MetadataToken.ToInt32(), propDef);
MemberMapping methodMapping = propDef.GetMethod.CreateCodeMapping(this.CodeMappings[propDef.GetMethod.MetadataToken.ToInt32()], propDef);
astProp.Getter = new Accessor();
astProp.Getter.Body = CreateMethodBody(propDef.GetMethod);
astProp.Getter.AddAnnotation(propDef.GetMethod);
@ -902,14 +885,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -902,14 +885,8 @@ namespace ICSharpCode.Decompiler.Ast
if ((getterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask))
astProp.Getter.Modifiers = getterModifiers & Modifiers.VisibilityMask;
astProp.Getter.WithAnnotation(methodMapping);
}
if (propDef.SetMethod != null) {
// Create mapping - used in debugger
CreateCodeMappings(propDef.SetMethod.MetadataToken.ToInt32(), propDef);
MemberMapping methodMapping = propDef.SetMethod.CreateCodeMapping(this.CodeMappings[propDef.SetMethod.MetadataToken.ToInt32()], propDef);
astProp.Setter = new Accessor();
astProp.Setter.Body = CreateMethodBody(propDef.SetMethod);
astProp.Setter.AddAnnotation(propDef.SetMethod);
@ -924,8 +901,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -924,8 +901,6 @@ namespace ICSharpCode.Decompiler.Ast
if ((setterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask))
astProp.Setter.Modifiers = setterModifiers & Modifiers.VisibilityMask;
astProp.Setter.WithAnnotation(methodMapping);
}
ConvertCustomAttributes(astProp, propDef);
@ -977,28 +952,16 @@ namespace ICSharpCode.Decompiler.Ast @@ -977,28 +952,16 @@ namespace ICSharpCode.Decompiler.Ast
astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType);
if (eventDef.AddMethod != null) {
// Create mapping - used in debugger
CreateCodeMappings(eventDef.AddMethod.MetadataToken.ToInt32(), eventDef);
MemberMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(this.CodeMappings[eventDef.AddMethod.MetadataToken.ToInt32()], eventDef);
astEvent.AddAccessor = new Accessor {
Body = CreateMethodBody(eventDef.AddMethod)
}.WithAnnotation(eventDef.AddMethod);
ConvertAttributes(astEvent.AddAccessor, eventDef.AddMethod);
astEvent.AddAccessor.WithAnnotation(methodMapping);
}
if (eventDef.RemoveMethod != null) {
// Create mapping - used in debugger
CreateCodeMappings(eventDef.RemoveMethod.MetadataToken.ToInt32(), eventDef);
MemberMapping methodMapping = eventDef.RemoveMethod.CreateCodeMapping(this.CodeMappings[eventDef.RemoveMethod.MetadataToken.ToInt32()], eventDef);
astEvent.RemoveAccessor = new Accessor {
Body = CreateMethodBody(eventDef.RemoveMethod)
}.WithAnnotation(eventDef.RemoveMethod);
ConvertAttributes(astEvent.RemoveAccessor, eventDef.RemoveMethod);
astEvent.RemoveAccessor.WithAnnotation(methodMapping);
}
MethodDefinition accessor = eventDef.AddMethod ?? eventDef.RemoveMethod;
if (accessor.IsVirtual == accessor.IsNewSlot) {
@ -1013,15 +976,13 @@ namespace ICSharpCode.Decompiler.Ast @@ -1013,15 +976,13 @@ namespace ICSharpCode.Decompiler.Ast
BlockStatement CreateMethodBody(MethodDefinition method, IEnumerable<ParameterDeclaration> parameters = null)
{
if (DecompileMethodBodies)
return AstMethodBodyBuilder.CreateMethodBody(method, context, parameters, LocalVariables);
return AstMethodBodyBuilder.CreateMethodBody(method, context, parameters);
else
return null;
}
FieldDeclaration CreateField(FieldDefinition fieldDef)
{
this.DecompiledMemberReferences.Add(fieldDef.MetadataToken.ToInt32(), fieldDef);
FieldDeclaration astField = new FieldDeclaration();
astField.AddAnnotation(fieldDef);
VariableInitializer initializer = new VariableInitializer(CleanName(fieldDef.Name));
@ -1673,11 +1634,5 @@ namespace ICSharpCode.Decompiler.Ast @@ -1673,11 +1634,5 @@ namespace ICSharpCode.Decompiler.Ast
&& (condition == null || condition(m))
&& TypesHierarchyHelpers.IsVisibleFromDerived(m, derived.DeclaringType));
}
/// <summary>
/// Gets the local variables for the current decompiled type, method, etc.
/// <remarks>The key is the metadata token.</remarks>
/// </summary>
public ConcurrentDictionary<int, IEnumerable<ILVariable>> LocalVariables { get; private set; }
}
}

29
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -50,16 +50,11 @@ namespace ICSharpCode.Decompiler.Ast @@ -50,16 +50,11 @@ namespace ICSharpCode.Decompiler.Ast
/// <param name="context">Decompilation context.</param>
/// <param name="parameters">Parameter declarations of the method being decompiled.
/// These are used to update the parameter names when the decompiler generates names for the parameters.</param>
/// <param name="localVariables">Local variables storage that will be filled/updated with the local variables.</param>
/// <returns>Block for the method body</returns>
public static BlockStatement CreateMethodBody(MethodDefinition methodDef,
DecompilerContext context,
IEnumerable<ParameterDeclaration> parameters = null,
ConcurrentDictionary<int, IEnumerable<ILVariable>> localVariables = null)
IEnumerable<ParameterDeclaration> parameters = null)
{
if (localVariables == null)
localVariables = new ConcurrentDictionary<int, IEnumerable<ILVariable>>();
MethodDefinition oldCurrentMethod = context.CurrentMethod;
Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef);
context.CurrentMethod = methodDef;
@ -69,10 +64,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -69,10 +64,10 @@ namespace ICSharpCode.Decompiler.Ast
builder.context = context;
builder.typeSystem = methodDef.Module.TypeSystem;
if (Debugger.IsAttached) {
return builder.CreateMethodBody(parameters, localVariables);
return builder.CreateMethodBody(parameters);
} else {
try {
return builder.CreateMethodBody(parameters, localVariables);
return builder.CreateMethodBody(parameters);
} catch (OperationCanceledException) {
throw;
} catch (Exception ex) {
@ -84,13 +79,11 @@ namespace ICSharpCode.Decompiler.Ast @@ -84,13 +79,11 @@ namespace ICSharpCode.Decompiler.Ast
}
}
public BlockStatement CreateMethodBody(IEnumerable<ParameterDeclaration> parameters,
ConcurrentDictionary<int, IEnumerable<ILVariable>> localVariables)
public BlockStatement CreateMethodBody(IEnumerable<ParameterDeclaration> parameters)
{
if (methodDef.Body == null) return null;
if (localVariables == null)
throw new ArgumentException("localVariables must be instantiated");
if (methodDef.Body == null) {
return null;
}
context.CancellationToken.ThrowIfCancellationRequested();
ILBlock ilMethod = new ILBlock();
@ -102,10 +95,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -102,10 +95,10 @@ namespace ICSharpCode.Decompiler.Ast
bodyGraph.Optimize(context, ilMethod);
context.CancellationToken.ThrowIfCancellationRequested();
var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable)
var localVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable)
.Where(v => v != null && !v.IsParameter).Distinct();
Debug.Assert(context.CurrentMethod == methodDef);
NameVariables.AssignNamesToVariables(context, astBuilder.Parameters, allVariables, ilMethod);
NameVariables.AssignNamesToVariables(context, astBuilder.Parameters, localVariables, ilMethod);
if (parameters != null) {
foreach (var pair in (from p in parameters
@ -132,9 +125,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -132,9 +125,7 @@ namespace ICSharpCode.Decompiler.Ast
astBlock.Statements.InsertBefore(insertionPoint, newVarDecl);
}
// store the variables - used for debugger
int token = methodDef.MetadataToken.ToInt32();
localVariables.AddOrUpdate(token, allVariables, (key, oldValue) => allVariables);
astBlock.AddAnnotation(new MemberMapping(methodDef));
return astBlock;
}

69
ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs

@ -19,9 +19,9 @@ @@ -19,9 +19,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
@ -198,48 +198,51 @@ namespace ICSharpCode.Decompiler.Ast @@ -198,48 +198,51 @@ namespace ICSharpCode.Decompiler.Ast
}
}
Stack<TextLocation> startLocations = new Stack<TextLocation>();
MemberMapping currentMemberMapping;
Stack<MemberMapping> parentMemberMappings = new Stack<MemberMapping>();
public void StartNode(AstNode node)
{
// code mappings
var ranges = node.Annotation<List<ILRange>>();
if (ranges != null && ranges.Count > 0) {
// find the ancestor that has method mapping as annotation
if (node.Parent != null)
{
var n = node.Ancestors.FirstOrDefault(a => a.Annotation<MemberMapping>() != null);
if (n != null) {
MemberMapping mapping = n.Annotation<MemberMapping>();
// add all ranges
foreach (var range in ranges) {
mapping.MemberCodeMappings.Add(new SourceCodeMapping {
ILInstructionOffset = range,
SourceCodeLine = output.Location.Line,
MemberMapping = mapping
});
}
}
}
}
// definitions of types and their members
Predicate<AstNode> predicate = n => n is AttributedNode;
nodeStack.Push(node);
startLocations.Push(output.Location);
if (predicate(node)) {
var n = node as AttributedNode;
int attributesCount = 0;
if (n != null)
attributesCount = n.Attributes.Count;
node.AddAnnotation(new TextOutputLocation { Line = output.Location.Line + attributesCount, Column = output.Location.Column});
MemberMapping mapping = node.Annotation<MemberMapping>();
if (mapping != null) {
parentMemberMappings.Push(currentMemberMapping);
currentMemberMapping = mapping;
}
nodeStack.Push(node);
}
public void EndNode(AstNode node)
{
if (nodeStack.Pop() != node)
throw new InvalidOperationException();
var startLocation = startLocations.Pop();
// code mappings
if (currentMemberMapping != null) {
var ranges = node.Annotation<List<ILRange>>();
if (ranges != null && ranges.Count > 0) {
// add all ranges
foreach (var range in ranges) {
currentMemberMapping.MemberCodeMappings.Add(
new SourceCodeMapping {
ILInstructionOffset = range,
StartLocation = startLocation,
EndLocation = output.Location,
MemberMapping = currentMemberMapping
});
}
}
}
if (node.Annotation<MemberMapping>() != null) {
output.AddDebuggerMemberMapping(currentMemberMapping);
currentMemberMapping = parentMemberMappings.Pop();
}
}
}
}

90
ICSharpCode.Decompiler/CodeMappings.cs

@ -20,15 +20,16 @@ using System; @@ -20,15 +20,16 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace ICSharpCode.Decompiler
{
[Obsolete]
public enum DecompiledLanguages
{
IL,
@ -36,57 +37,36 @@ namespace ICSharpCode.Decompiler @@ -36,57 +37,36 @@ namespace ICSharpCode.Decompiler
}
/// <summary>
/// Base class for decompliler classes : AstBuilder & ReflectionDisassembler.
/// Maps the source code to IL.
/// </summary>
public abstract class BaseCodeMappings
public sealed class SourceCodeMapping
{
/// <summary>
/// Gets the code mappings.
/// <remarks>Key is the metadata token.</remarks>
/// </summary>
public Dictionary<int, List<MemberMapping>> CodeMappings { get; protected set; }
[Obsolete("Use StartLocation instead - there might be multiple statements per line (e.g. for loops)")]
public int SourceCodeLine {
get {
return this.StartLocation.Line;
}
}
/// <summary>
/// Gets the MembeReference that is decompiled (a MethodDefinition, PropertyDefinition etc.)
/// <remarks>Key is the metadata token.</remarks>
/// Gets or sets the start location of the instruction.
/// </summary>
public Dictionary<int, MemberReference> DecompiledMemberReferences { get; protected set; }
public TextLocation StartLocation { get; set; }
/// <summary>
/// Create data in the CodeMappings and DecompiledMemberReferences.
/// Gets or sets the end location of the instruction.
/// </summary>
/// <param name="token">Token of the current method.</param>
/// <param name="member">Current member (MethodDefinition, PropertyDefinition, EventDefinition).</param>
/// <remarks>The token is used in CodeMappings; member (and its token) is used in DecompiledMemberReferences.</remarks>
protected virtual void CreateCodeMappings(int token, MemberReference member)
{
this.CodeMappings.Add(token, new List<MemberMapping>());
int t = member.MetadataToken.ToInt32();
if (!this.DecompiledMemberReferences.ContainsKey(t))
this.DecompiledMemberReferences.Add(t, member);
}
}
/// <summary>
/// Maps the source code to IL.
/// </summary>
public sealed class SourceCodeMapping
{
/// <summary>
/// Gets or sets the source code line number in the output.
/// </summary>
public int SourceCodeLine { get; internal set; }
public TextLocation EndLocation { get; set; }
/// <summary>
/// Gets or sets IL Range offset for the source code line. E.g.: 13-19 &lt;-&gt; 135.
/// </summary>
public ILRange ILInstructionOffset { get; internal set; }
public ILRange ILInstructionOffset { get; set; }
/// <summary>
/// Gets or sets the member mapping this source code mapping belongs to.
/// </summary>
public MemberMapping MemberMapping { get; internal set; }
public MemberMapping MemberMapping { get; set; }
/// <summary>
/// Retrieves the array that contains the IL range and the missing gaps between ranges.
@ -129,6 +109,18 @@ namespace ICSharpCode.Decompiler @@ -129,6 +109,18 @@ namespace ICSharpCode.Decompiler
{
IEnumerable<ILRange> invertedList;
internal MemberMapping()
{
}
public MemberMapping(MethodDefinition method)
{
this.MetadataToken = method.MetadataToken.ToInt32();
this.MemberCodeMappings = new List<SourceCodeMapping>();
this.MemberReference = method;
this.CodeSize = method.Body.CodeSize;
}
/// <summary>
/// Gets or sets the type of the mapping.
/// </summary>
@ -317,30 +309,4 @@ namespace ICSharpCode.Decompiler @@ -317,30 +309,4 @@ namespace ICSharpCode.Decompiler
return true;
}
}
/// <summary>
/// Decompilation data. Can be used by other applications to store the decompilation data.
/// </summary>
public class DecompileInformation
{
/// <summary>
/// Gets ot sets the code mappings
/// </summary>
public Dictionary<int, List<MemberMapping>> CodeMappings { get; set; }
/// <summary>
/// Gets or sets the local variables.
/// </summary>
public ConcurrentDictionary<int, IEnumerable<ILVariable>> LocalVariables { get; set; }
/// <summary>
/// Gets the list of MembeReferences that are decompiled (TypeDefinitions, MethodDefinitions, etc)
/// </summary>
public Dictionary<int, MemberReference> DecompiledMemberReferences { get; set; }
/// <summary>
/// Gets (or internal sets) the AST nodes.
/// </summary>
public IEnumerable<AstNode> AstNodes { get; set; }
}
}

8
ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

@ -85,13 +85,15 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -85,13 +85,15 @@ namespace ICSharpCode.Decompiler.Disassembler
WriteStructureBody(new ILStructure(body), branchTargets, ref inst, methodMapping, method.Body.CodeSize);
} else {
foreach (var inst in method.Body.Instructions) {
var startLocation = output.Location;
inst.WriteTo(output);
if (methodMapping != null) {
// add IL code mappings - used in debugger
methodMapping.MemberCodeMappings.Add(
new SourceCodeMapping() {
SourceCodeLine = output.Location.Line,
StartLocation = output.Location,
EndLocation = output.Location,
ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? method.Body.CodeSize : inst.Next.Offset },
MemberMapping = methodMapping
});
@ -188,13 +190,15 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -188,13 +190,15 @@ namespace ICSharpCode.Decompiler.Disassembler
if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset))) {
output.WriteLine(); // put an empty line after branches, and in front of branch targets
}
var startLocation = output.Location;
inst.WriteTo(output);
// add IL code mappings - used in debugger
if (currentMethodMapping != null) {
currentMethodMapping.MemberCodeMappings.Add(
new SourceCodeMapping() {
SourceCodeLine = output.Location.Line,
StartLocation = startLocation,
EndLocation = output.Location,
ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? codeSize : inst.Next.Offset },
MemberMapping = currentMethodMapping
});

12
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -30,7 +30,7 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -30,7 +30,7 @@ namespace ICSharpCode.Decompiler.Disassembler
/// <summary>
/// Disassembles type and member definitions.
/// </summary>
public sealed class ReflectionDisassembler : BaseCodeMappings
public sealed class ReflectionDisassembler
{
ITextOutput output;
CancellationToken cancellationToken;
@ -45,9 +45,6 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -45,9 +45,6 @@ namespace ICSharpCode.Decompiler.Disassembler
this.output = output;
this.cancellationToken = cancellationToken;
this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken);
this.CodeMappings = new Dictionary<int, List<MemberMapping>>();
this.DecompiledMemberReferences = new Dictionary<int, MemberReference>();
}
#region Disassemble Method
@ -220,9 +217,9 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -220,9 +217,9 @@ namespace ICSharpCode.Decompiler.Disassembler
if (method.HasBody) {
// create IL code mappings - used in debugger
CreateCodeMappings(method.MetadataToken.ToInt32(), currentMember);
MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings[method.MetadataToken.ToInt32()], currentMember);
MemberMapping methodMapping = new MemberMapping(method);
methodBodyDisassembler.Disassemble(method.Body, methodMapping);
output.AddDebuggerMemberMapping(methodMapping);
}
CloseBlock("end of method " + DisassemblerHelpers.Escape(method.DeclaringType.Name) + "::" + DisassemblerHelpers.Escape(method.Name));
@ -676,9 +673,6 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -676,9 +673,6 @@ namespace ICSharpCode.Decompiler.Disassembler
public void DisassembleField(FieldDefinition field)
{
// create mappings for decompiled fields only
this.DecompiledMemberReferences.Add(field.MetadataToken.ToInt32(), field);
output.WriteDefinition(".field ", field);
WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility);
const FieldAttributes hasXAttributes = FieldAttributes.HasDefault | FieldAttributes.HasFieldMarshal | FieldAttributes.HasFieldRVA;

11
ICSharpCode.Decompiler/ITextOutput.cs

@ -18,12 +18,13 @@ @@ -18,12 +18,13 @@
using System;
using System.IO;
using ICSharpCode.NRefactory;
namespace ICSharpCode.Decompiler
{
public interface ITextOutput
{
TextOutputLocation Location { get; }
TextLocation Location { get; }
void Indent();
void Unindent();
@ -33,16 +34,12 @@ namespace ICSharpCode.Decompiler @@ -33,16 +34,12 @@ namespace ICSharpCode.Decompiler
void WriteDefinition(string text, object definition);
void WriteReference(string text, object reference, bool isLocal = false);
void AddDebuggerMemberMapping(MemberMapping memberMapping);
void MarkFoldStart(string collapsedText = "...", bool defaultCollapsed = false);
void MarkFoldEnd();
}
public sealed class TextOutputLocation
{
public int Line { get; set; }
public int Column { get; set; }
}
public static class TextOutputExtensions
{
public static void Write(this ITextOutput output, string format, params object[] args)

27
ICSharpCode.Decompiler/PlainTextOutput.cs

@ -18,17 +18,18 @@ @@ -18,17 +18,18 @@
using System;
using System.IO;
using ICSharpCode.NRefactory;
namespace ICSharpCode.Decompiler
{
public sealed class PlainTextOutput : ITextOutput
{
const int TAB_SIZE = 4;
readonly TextWriter writer;
int indent;
bool needsIndent;
TextOutputLocation location = new TextOutputLocation { Line = 1, Column = 1};
int line = 1;
int column = 1;
public PlainTextOutput(TextWriter writer)
{
@ -42,8 +43,10 @@ namespace ICSharpCode.Decompiler @@ -42,8 +43,10 @@ namespace ICSharpCode.Decompiler
this.writer = new StringWriter();
}
public TextOutputLocation Location {
get { return location; }
public TextLocation Location {
get {
return new TextLocation(line, column + (needsIndent ? indent : 0));
}
}
public override string ToString()
@ -67,8 +70,8 @@ namespace ICSharpCode.Decompiler @@ -67,8 +70,8 @@ namespace ICSharpCode.Decompiler
needsIndent = false;
for (int i = 0; i < indent; i++) {
writer.Write('\t');
location.Column += TAB_SIZE - 1;
}
column += indent;
}
}
@ -76,22 +79,22 @@ namespace ICSharpCode.Decompiler @@ -76,22 +79,22 @@ namespace ICSharpCode.Decompiler
{
WriteIndent();
writer.Write(ch);
location.Column++;
column++;
}
public void Write(string text)
{
WriteIndent();
writer.Write(text);
location.Column += text.Length;
column += text.Length;
}
public void WriteLine()
{
location.Line++;
writer.WriteLine();
needsIndent = true;
location.Column = TAB_SIZE * indent;
line++;
column = 1;
}
public void WriteDefinition(string text, object definition)
@ -111,5 +114,9 @@ namespace ICSharpCode.Decompiler @@ -111,5 +114,9 @@ namespace ICSharpCode.Decompiler
void ITextOutput.MarkFoldEnd()
{
}
void ITextOutput.AddDebuggerMemberMapping(MemberMapping memberMapping)
{
}
}
}

6
ILSpy/Bookmarks/MemberBookmark.cs

@ -92,9 +92,9 @@ namespace ICSharpCode.ILSpy.Bookmarks @@ -92,9 +92,9 @@ namespace ICSharpCode.ILSpy.Bookmarks
public int LineNumber {
get {
var t = node.Annotation<TextOutputLocation>();
if (t != null)
return t.Line;
//var t = node.Annotation<TextOutputLocation>();
//if (t != null)
// return t.Line;
return 0;
}
}

6
ILSpy/Languages/CSharpLanguage.cs

@ -100,7 +100,6 @@ namespace ICSharpCode.ILSpy @@ -100,7 +100,6 @@ namespace ICSharpCode.ILSpy
codeDomBuilder.AddMethod(method);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
}
NotifyDecompilationFinished(codeDomBuilder);
}
class SelectCtorTransform : IAstTransform
@ -145,7 +144,6 @@ namespace ICSharpCode.ILSpy @@ -145,7 +144,6 @@ namespace ICSharpCode.ILSpy
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: property.DeclaringType, isSingleMember: true);
codeDomBuilder.AddProperty(property);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
NotifyDecompilationFinished(codeDomBuilder);
}
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
@ -159,7 +157,6 @@ namespace ICSharpCode.ILSpy @@ -159,7 +157,6 @@ namespace ICSharpCode.ILSpy
AddFieldsAndCtors(codeDomBuilder, field.DeclaringType, field.IsStatic);
}
RunTransformsAndGenerateCode(codeDomBuilder, output, options, new SelectFieldTransform(field));
NotifyDecompilationFinished(codeDomBuilder);
}
/// <summary>
@ -203,7 +200,6 @@ namespace ICSharpCode.ILSpy @@ -203,7 +200,6 @@ namespace ICSharpCode.ILSpy
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: ev.DeclaringType, isSingleMember: true);
codeDomBuilder.AddEvent(ev);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
NotifyDecompilationFinished(codeDomBuilder);
}
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
@ -211,7 +207,6 @@ namespace ICSharpCode.ILSpy @@ -211,7 +207,6 @@ namespace ICSharpCode.ILSpy
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: type);
codeDomBuilder.AddType(type);
RunTransformsAndGenerateCode(codeDomBuilder, output, options);
NotifyDecompilationFinished(codeDomBuilder);
}
void RunTransformsAndGenerateCode(AstBuilder astBuilder, ITextOutput output, DecompilationOptions options, IAstTransform additionalTransform = null)
@ -283,7 +278,6 @@ namespace ICSharpCode.ILSpy @@ -283,7 +278,6 @@ namespace ICSharpCode.ILSpy
codeDomBuilder.GenerateCode(output);
}
}
OnDecompilationFinished(null);
}
#region WriteProjectFile

7
ILSpy/Languages/ILLanguage.cs

@ -52,14 +52,12 @@ namespace ICSharpCode.ILSpy @@ -52,14 +52,12 @@ namespace ICSharpCode.ILSpy
{
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
dis.DisassembleMethod(method);
NotifyDecompilationFinished(dis);
}
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
dis.DisassembleField(field);
NotifyDecompilationFinished(dis);
}
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
@ -78,7 +76,6 @@ namespace ICSharpCode.ILSpy @@ -78,7 +76,6 @@ namespace ICSharpCode.ILSpy
output.WriteLine();
rd.DisassembleMethod(m);
}
NotifyDecompilationFinished(rd);
}
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
@ -97,20 +94,17 @@ namespace ICSharpCode.ILSpy @@ -97,20 +94,17 @@ namespace ICSharpCode.ILSpy
output.WriteLine();
rd.DisassembleMethod(m);
}
NotifyDecompilationFinished(rd);
}
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
dis.DisassembleType(type);
NotifyDecompilationFinished(dis);
}
public override void DecompileNamespace(string nameSpace, IEnumerable<TypeDefinition> types, ITextOutput output, DecompilationOptions options)
{
new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).DisassembleNamespace(nameSpace, types);
OnDecompilationFinished(null);
}
public override void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
@ -129,7 +123,6 @@ namespace ICSharpCode.ILSpy @@ -129,7 +123,6 @@ namespace ICSharpCode.ILSpy
output.WriteLine();
rd.WriteModuleContents(assembly.AssemblyDefinition.MainModule);
}
OnDecompilationFinished(null);
}
public override string TypeToString(TypeReference t, bool includeNamespace, ICustomAttributeProvider attributeProvider)

43
ILSpy/Languages/Language.cs

@ -19,14 +19,10 @@ @@ -19,14 +19,10 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Utils;
using Mono.Cecil;
namespace ICSharpCode.ILSpy
@ -34,6 +30,7 @@ namespace ICSharpCode.ILSpy @@ -34,6 +30,7 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Decompilation event arguments.
/// </summary>
[Obsolete]
public sealed class DecompileEventArgs : EventArgs
{
/// <summary>
@ -65,7 +62,8 @@ namespace ICSharpCode.ILSpy @@ -65,7 +62,8 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Decompile finished event.
/// </summary>
public event EventHandler<DecompileEventArgs> DecompileFinished;
[Obsolete]
public event EventHandler<DecompileEventArgs> DecompileFinished { add {} remove {} }
/// <summary>
/// Gets the name of the language (as shown in the UI)
@ -121,7 +119,6 @@ namespace ICSharpCode.ILSpy @@ -121,7 +119,6 @@ namespace ICSharpCode.ILSpy
public virtual void DecompileNamespace(string nameSpace, IEnumerable<TypeDefinition> types, ITextOutput output, DecompilationOptions options)
{
WriteCommentLine(output, nameSpace);
OnDecompilationFinished(null);
}
public virtual void DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options)
@ -197,39 +194,5 @@ namespace ICSharpCode.ILSpy @@ -197,39 +194,5 @@ namespace ICSharpCode.ILSpy
{
return member;
}
protected virtual void OnDecompilationFinished(DecompileEventArgs e)
{
if (DecompileFinished != null) {
DecompileFinished(this, e);
}
}
protected void NotifyDecompilationFinished(BaseCodeMappings b)
{
if (b is AstBuilder) {
var builder = b as AstBuilder;
var nodes = TreeTraversal
.PreOrder((AstNode)builder.CompilationUnit, n => n.Children)
.Where(n => n is AttributedNode && n.Annotation<TextOutputLocation>() != null);
OnDecompilationFinished(new DecompileEventArgs {
CodeMappings = builder.CodeMappings,
LocalVariables = builder.LocalVariables,
DecompiledMemberReferences = builder.DecompiledMemberReferences,
AstNodes = nodes
});
}
if (b is ReflectionDisassembler) {
var dis = b as ReflectionDisassembler;
OnDecompilationFinished(new DecompileEventArgs {
CodeMappings = dis.CodeMappings,
DecompiledMemberReferences = dis.DecompiledMemberReferences,
AstNodes = null // TODO: how can I find the nodes with line numbers from dis?
});
}
}
}
}

20
ILSpy/TextView/AvalonEditTextOutput.cs

@ -67,8 +67,8 @@ namespace ICSharpCode.ILSpy.TextView @@ -67,8 +67,8 @@ namespace ICSharpCode.ILSpy.TextView
/// </summary>
public sealed class AvalonEditTextOutput : ISmartTextOutput
{
TextOutputLocation location = new TextOutputLocation { Line = 1, Column = 1 };
int lastLineStart = 0;
int lineNumber = 1;
readonly StringBuilder b = new StringBuilder();
/// <summary>Current indentation level</summary>
@ -92,6 +92,8 @@ namespace ICSharpCode.ILSpy.TextView @@ -92,6 +92,8 @@ namespace ICSharpCode.ILSpy.TextView
/// <summary>Embedded UIElements, see <see cref="UIElementGenerator"/>.</summary>
internal readonly List<KeyValuePair<int, Lazy<UIElement>>> UIElements = new List<KeyValuePair<int, Lazy<UIElement>>>();
List<MemberMapping> memberMappings = new List<MemberMapping>();
public AvalonEditTextOutput()
{
}
@ -119,13 +121,16 @@ namespace ICSharpCode.ILSpy.TextView @@ -119,13 +121,16 @@ namespace ICSharpCode.ILSpy.TextView
get { return b.Length; }
}
public TextOutputLocation Location {
public ICSharpCode.NRefactory.TextLocation Location {
get {
location.Column = b.Length - lastLineStart + 1;
return location;
return new ICSharpCode.NRefactory.TextLocation(lineNumber, b.Length - lastLineStart + 1 + (needsIndent ? indent : 0));
}
}
public IList<MemberMapping> MemberMappings {
get { return memberMappings; }
}
#region Text Document
TextDocument textDocument;
@ -197,7 +202,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -197,7 +202,7 @@ namespace ICSharpCode.ILSpy.TextView
b.AppendLine();
needsIndent = true;
lastLineStart = b.Length;
location.Line++;
lineNumber++;
if (this.TextLength > LengthLimit) {
throw new OutputLengthExceededException();
}
@ -248,5 +253,10 @@ namespace ICSharpCode.ILSpy.TextView @@ -248,5 +253,10 @@ namespace ICSharpCode.ILSpy.TextView
this.UIElements.Add(new KeyValuePair<int, Lazy<UIElement>>(this.TextLength, new Lazy<UIElement>(element)));
}
}
public void AddDebuggerMemberMapping(MemberMapping memberMapping)
{
memberMappings.Add(memberMapping);
}
}
}

1
ILSpy/VB/VBLanguage.cs

@ -125,7 +125,6 @@ namespace ICSharpCode.ILSpy.VB @@ -125,7 +125,6 @@ namespace ICSharpCode.ILSpy.VB
RunTransformsAndGenerateCode(codeDomBuilder, output, options, assembly.AssemblyDefinition.MainModule);
}
}
OnDecompilationFinished(null);
}
static readonly string[] projectImports = new[] {

Loading…
Cancel
Save