Browse Source

Store the code mappings when decompiling multiple member references (TypeDefinitions, MethodDefinitions, PropertyDefinitions, etc).

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
a2b35dbd60
  1. 5
      Debugger/Debugger.Core/Breakpoint.cs
  2. 35
      Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs
  3. 48
      Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs
  4. 12
      Debugger/ILSpy.Debugger/AvalonEdit/TextMarkerService.cs
  5. 4
      Debugger/ILSpy.Debugger/Bookmarks/BookmarkBase.cs
  6. 21
      Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs
  7. 2
      Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs
  8. 2
      Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs
  9. 28
      Debugger/ILSpy.Debugger/DebuggedData.cs
  10. 18
      Debugger/ILSpy.Debugger/DebuggerSettings.cs
  11. 2
      Debugger/ILSpy.Debugger/Services/Debugger/DebuggerService.cs
  12. 59
      Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs
  13. 69
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  14. 107
      ICSharpCode.Decompiler/CodeMappings.cs
  15. 90
      ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  16. 10
      ILSpy/CSharpLanguage.cs
  17. 4
      ILSpy/Commands/DebuggerCommands.cs
  18. 14
      ILSpy/ILLanguage.cs
  19. 7
      ILSpy/Language.cs
  20. 3
      ILSpy/Options/DebuggerSettingsPanel.xaml
  21. 16
      ILSpy/Options/DebuggerSettingsPanel.xaml.cs
  22. 34
      ILSpy/TextView/DecompilerTextView.cs

5
Debugger/Debugger.Core/Breakpoint.cs

@ -176,11 +176,12 @@ namespace Debugger
public class ILBreakpoint : Breakpoint public class ILBreakpoint : Breakpoint
{ {
public ILBreakpoint(NDebugger debugger, string typeName, int line, uint metadataToken, int offset, bool enabled) public ILBreakpoint(NDebugger debugger, string typeName, string memberReferenceName, int line, uint metadataToken, int offset, bool enabled)
{ {
this.Debugger = debugger; this.Debugger = debugger;
this.Line = line; this.Line = line;
this.TypeName = typeName; this.TypeName = typeName;
this.MemberReferenceName = memberReferenceName;
this.MetadataToken = metadataToken; this.MetadataToken = metadataToken;
this.ILOffset = offset; this.ILOffset = offset;
this.Enabled = enabled; this.Enabled = enabled;
@ -190,6 +191,8 @@ namespace Debugger
public int ILOffset { get; private set; } public int ILOffset { get; private set; }
public string MemberReferenceName { get; private set; }
public override bool SetBreakpoint(Module module) public override bool SetBreakpoint(Module module)
{ {
SourcecodeSegment segment = SourcecodeSegment.CreateForIL(module, this.Line, (int)MetadataToken, ILOffset); SourcecodeSegment segment = SourcecodeSegment.CreateForIL(module, this.Line, (int)MetadataToken, ILOffset);

35
Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs

@ -68,7 +68,7 @@ namespace Debugger.MetaData
sb.Append(this.ReturnType.Name); sb.Append(this.ReturnType.Name);
sb.Append(" "); sb.Append(" ");
} else { } else {
sb.Append("void "); sb.Append("System.Void ");
} }
sb.Append(this.DeclaringType.FullName); sb.Append(this.DeclaringType.FullName);
@ -80,7 +80,7 @@ namespace Debugger.MetaData
if (!first) if (!first)
sb.Append(", "); sb.Append(", ");
first = false; first = false;
sb.Append(p.ParameterType.Name); sb.Append(p.ParameterType.FullName);
sb.Append(" "); sb.Append(" ");
sb.Append(p.Name); sb.Append(p.Name);
} }
@ -89,6 +89,37 @@ namespace Debugger.MetaData
} }
} }
/// <summary> Name including the declaring type, return type without parameters names</summary>
public string FullNameWithoutParameterNames {
get {
StringBuilder sb = new StringBuilder();
if (this.IsStatic) {
sb.Append("static ");
}
if (this.ReturnType != null) {
sb.Append(this.ReturnType.Name);
sb.Append(" ");
} else {
sb.Append("System.Void ");
}
sb.Append(this.DeclaringType.FullName);
sb.Append(".");
sb.Append(this.Name);
sb.Append("(");
bool first = true;
foreach(DebugParameterInfo p in GetParameters()) {
if (!first)
sb.Append(", ");
first = false;
sb.Append(p.ParameterType.FullName);
}
sb.Append(")");
return sb.ToString();
}
}
/// <inheritdoc/> /// <inheritdoc/>
public override string Name { public override string Name {
get { return methodProps.Name; } get { return methodProps.Name; }

48
Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs

@ -4,10 +4,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using ICSharpCode.AvalonEdit.Editing; using ICSharpCode.AvalonEdit.Editing;
using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Utils; using ICSharpCode.AvalonEdit.Utils;
@ -59,7 +59,8 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
// create a dictionary line number => first bookmark // create a dictionary line number => first bookmark
Dictionary<int, BookmarkBase> bookmarkDict = new Dictionary<int, BookmarkBase>(); Dictionary<int, BookmarkBase> bookmarkDict = new Dictionary<int, BookmarkBase>();
foreach (var bm in BookmarkManager.Bookmarks) { foreach (var bm in BookmarkManager.Bookmarks) {
if (DebugData.CurrentMemberReference == null || bm.Member.FullName != DebugData.CurrentMemberReference.FullName) if (DebugData.DecompiledMemberReferences == null || DebugData.DecompiledMemberReferences.Count == 0 ||
!DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.FullName))
continue; continue;
if (bm is BreakpointBookmark && if (bm is BreakpointBookmark &&
((BreakpointBookmark)bm).Language != DebugData.Language) ((BreakpointBookmark)bm).Language != DebugData.Language)
@ -121,8 +122,7 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
BookmarkBase result = null; BookmarkBase result = null;
foreach (BookmarkBase bm in BookmarkManager.Bookmarks) { foreach (BookmarkBase bm in BookmarkManager.Bookmarks) {
if (bm.LineNumber == line && if (bm.LineNumber == line &&
DebugData.CurrentMemberReference != null && DebugData.DecompiledMemberReferences != null && DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.FullName)) {
bm.Member.FullName == DebugData.CurrentMemberReference.FullName) {
if (result == null || bm.ZOrder > result.ZOrder) if (result == null || bm.ZOrder > result.ZOrder)
result = bm; result = bm;
} }
@ -190,16 +190,6 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
dragStarted = true; dragStarted = true;
InvalidateVisual(); InvalidateVisual();
} }
if (DebugData.CurrentMemberReference == null)
return;
BreakpointBookmark bm = BookmarkManager.Bookmarks.Find(
b => b.Member.FullName == DebugData.CurrentMemberReference.FullName &&
b.LineNumber == GetLineFromMousePosition(e)
&& b is BreakpointBookmark) as BreakpointBookmark;
this.ToolTip = (bm != null) ? bm.Tooltip : null;
} }
protected override void OnMouseUp(MouseButtonEventArgs e) protected override void OnMouseUp(MouseButtonEventArgs e)
@ -228,24 +218,32 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
return; return;
} }
if (e.ChangedButton == MouseButton.Left) { if (e.ChangedButton == MouseButton.Left) {
if (DebugData.CurrentMemberReference != null) { if (DebugData.DecompiledMemberReferences != null && DebugData.DecompiledMemberReferences.Count > 0) {
// check if the codemappings exists for this line // check if the codemappings exists for this line
var storage = DebugData.CodeMappings; var storage = DebugData.CodeMappings;
uint token; uint token = 0;
var instruction = storage.GetInstructionByTypeAndLine(DebugData.CurrentMemberReference.FullName, line, out token); foreach (var member in DebugData.DecompiledMemberReferences.Values) {
string memberName = member.FullName;
var instruction = storage[memberName].GetInstructionByTypeAndLine(memberName, line, out token);
if (instruction == null) {
continue;
}
// no bookmark on the line: create a new breakpoint
DebuggerService.ToggleBreakpointAt(
member,
line,
DebugData.Language);
break;
}
if (instruction == null) { if (token == 0) {
MessageBox.Show(string.Format("Missing code mappings for {0} at line {1}", DebugData.CurrentMemberReference.FullName, line), MessageBox.Show(string.Format("Missing code mappings at line {0}.", line),
"Code mappings", MessageBoxButton.OK, MessageBoxImage.Information); "Code mappings", MessageBoxButton.OK, MessageBoxImage.Information);
return; return;
} }
// no bookmark on the line: create a new breakpoint
DebuggerService.ToggleBreakpointAt(
DebugData.CurrentMemberReference,
line,
DebugData.Language);
} }
} }
InvalidateVisual(); InvalidateVisual();

12
Debugger/ILSpy.Debugger/AvalonEdit/TextMarkerService.cs

@ -27,7 +27,7 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
TextSegmentCollection<TextMarker> markers = new TextSegmentCollection<TextMarker>(); TextSegmentCollection<TextMarker> markers = new TextSegmentCollection<TextMarker>();
public TextMarkerService() public TextMarkerService()
{ {
BookmarkManager.Added += new BookmarkEventHandler(BookmarkManager_Added); BookmarkManager.Added += new BookmarkEventHandler(BookmarkManager_Added);
BookmarkManager.Removed += new BookmarkEventHandler(BookmarkManager_Removed); BookmarkManager.Removed += new BookmarkEventHandler(BookmarkManager_Removed);
} }
@ -53,11 +53,9 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
{ {
if (e.Bookmark is MarkerBookmark) { if (e.Bookmark is MarkerBookmark) {
var bm = (MarkerBookmark)e.Bookmark; var bm = (MarkerBookmark)e.Bookmark;
if (DebugData.CurrentMemberReference != null && DebugData.CurrentMemberReference == bm.Member) { // add bookmark for the current type
// add bookmark for the current type DocumentLine line = codeEditor.Document.GetLineByNumber(bm.LineNumber);
DocumentLine line = codeEditor.Document.GetLineByNumber(bm.LineNumber); bm.CreateMarker(this, line.Offset, line.Length);
bm.CreateMarker(this, line.Offset, line.Length);
}
} }
} }
@ -305,7 +303,7 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit
Redraw(); Redraw();
} }
} }
} }
/// <inheritdoc/> /// <inheritdoc/>
public object ToolTip { get; set; } public object ToolTip { get; set; }

4
Debugger/ILSpy.Debugger/Bookmarks/BookmarkBase.cs

@ -41,7 +41,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
} }
public MemberReference Member { get; set; } public MemberReference MemberReference { get; set; }
public int LineNumber { public int LineNumber {
get { return location.Line; } get { return location.Line; }
@ -66,7 +66,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
public BookmarkBase(MemberReference member, AstLocation location) public BookmarkBase(MemberReference member, AstLocation location)
{ {
this.Member = member; this.MemberReference = member;
this.Location = location; this.Location = location;
} }

21
Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
List<BookmarkBase> marks = new List<BookmarkBase>(); List<BookmarkBase> marks = new List<BookmarkBase>();
foreach (BookmarkBase mark in bookmarks) { foreach (BookmarkBase mark in bookmarks) {
if (typeName == mark.Member.FullName) { if (typeName == mark.MemberReference.FullName) {
marks.Add(mark); marks.Add(mark);
} }
} }
@ -56,7 +56,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
return false; return false;
if (a.GetType() != b.GetType()) if (a.GetType() != b.GetType())
return false; return false;
if (a.Member.FullName != b.Member.FullName) if (a.MemberReference.FullName != b.MemberReference.FullName)
return false; return false;
return a.LineNumber == b.LineNumber; return a.LineNumber == b.LineNumber;
} }
@ -150,20 +150,23 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
// 1. Save it's data // 1. Save it's data
int line = CurrentLineBookmark.Instance.LineNumber; int line = CurrentLineBookmark.Instance.LineNumber;
var markerType = CurrentLineBookmark.Instance.Member; var markerType = CurrentLineBookmark.Instance.MemberReference;
if (!oldMappings.ContainsKey(markerType.FullName) || !oldMappings.ContainsKey(markerType.FullName))
return;
// 2. Remove it // 2. Remove it
CurrentLineBookmark.Remove(); CurrentLineBookmark.Remove();
// 3. map the marker line // 3. map the marker line
uint token; uint token;
var instruction = oldMappings.GetInstructionByTypeAndLine(markerType.FullName, line, out token); var instruction = oldMappings[markerType.FullName].GetInstructionByTypeAndLine(markerType.FullName, line, out token);
if (instruction == null) if (instruction == null)
return; return;
MemberReference memberReference; MemberReference memberReference;
int newline; int newline;
if (newMappings.GetSourceCodeFromMetadataTokenAndOffset(markerType.FullName, token, instruction.ILInstructionOffset.From, out memberReference, out newline)) { if (newMappings[markerType.FullName].GetSourceCodeFromMetadataTokenAndOffset(token, instruction.ILInstructionOffset.From, out memberReference, out newline)) {
// 4. create breakpoint for new languages // 4. create breakpoint for new languages
CurrentLineBookmark.SetPosition(memberReference, newline, 0, newline, 0); CurrentLineBookmark.SetPosition(memberReference, newline, 0, newline, 0);
} }
@ -191,13 +194,17 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
foreach (var bp in oldbps) { foreach (var bp in oldbps) {
uint token; uint token;
var instruction = oldMappings.GetInstructionByTypeAndLine(bp.Member.FullName, bp.LineNumber, out token); string name = bp.MemberReference.FullName;
if (!oldMappings.ContainsKey(name) || !oldMappings.ContainsKey(name))
continue;
var instruction = oldMappings[name].GetInstructionByTypeAndLine(bp.MemberReference.FullName, bp.LineNumber, out token);
if (instruction == null) if (instruction == null)
continue; continue;
MemberReference memberReference; MemberReference memberReference;
int line; int line;
if (newMappings.GetSourceCodeFromMetadataTokenAndOffset(bp.Member.FullName, token, instruction.ILInstructionOffset.From, out memberReference, out line)) { if (newMappings[name].GetSourceCodeFromMetadataTokenAndOffset(token, instruction.ILInstructionOffset.From, out memberReference, out line)) {
// 2. create breakpoint for new languages // 2. create breakpoint for new languages
var bookmark = new BreakpointBookmark(memberReference, new AstLocation(line, 0), BreakpointAction.Break, newLanguage); var bookmark = new BreakpointBookmark(memberReference, new AstLocation(line, 0), BreakpointAction.Break, newLanguage);
AddMark(bookmark); AddMark(bookmark);

2
Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs

@ -91,7 +91,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
ITextMarker marker = markerService.Create(offset, length); ITextMarker marker = markerService.Create(offset, length);
marker.BackgroundColor = Color.FromRgb(180, 38, 38); marker.BackgroundColor = Color.FromRgb(180, 38, 38);
marker.ForegroundColor = Colors.White; marker.ForegroundColor = Colors.White;
marker.IsVisible = b => b is MarkerBookmark && ((MarkerBookmark)b).Member == DebugData.CurrentMemberReference; marker.IsVisible = b => b is MarkerBookmark && DebugData.DecompiledMemberReferences.ContainsKey(((MarkerBookmark)b).MemberReference.FullName);
marker.Bookmark = this; marker.Bookmark = this;
this.Marker = marker; this.Marker = marker;

2
Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs

@ -81,7 +81,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks
ITextMarker marker = markerService.Create(offset + startColumn - 1, length + 1); ITextMarker marker = markerService.Create(offset + startColumn - 1, length + 1);
marker.BackgroundColor = Colors.Yellow; marker.BackgroundColor = Colors.Yellow;
marker.ForegroundColor = Colors.Blue; marker.ForegroundColor = Colors.Blue;
marker.IsVisible = b => b is MarkerBookmark && ((MarkerBookmark)b).Member == DebugData.CurrentMemberReference; marker.IsVisible = b => b is MarkerBookmark && DebugData.DecompiledMemberReferences.ContainsKey(((MarkerBookmark)b).MemberReference.FullName);
marker.Bookmark = this; marker.Bookmark = this;
this.Marker = marker; this.Marker = marker;
return marker; return marker;

28
Debugger/ILSpy.Debugger/DebuggedData.cs

@ -18,11 +18,6 @@ namespace ICSharpCode.ILSpy.Debugger
{ {
static DecompiledLanguages language; static DecompiledLanguages language;
/// <summary>
/// Gets or sets the current debugged member reference. Can be a type or a member of a type (method, property).
/// </summary>
public static MemberReference CurrentMemberReference { get; set; }
/// <summary> /// <summary>
/// Gets or sets the decompiled language. /// Gets or sets the decompiled language.
/// </summary> /// </summary>
@ -42,19 +37,10 @@ namespace ICSharpCode.ILSpy.Debugger
/// </summary> /// </summary>
public static IEnumerable<AssemblyDefinition> LoadedAssemblies { get; set; } public static IEnumerable<AssemblyDefinition> LoadedAssemblies { get; set; }
/// <summary>
/// Returns true if the CurrentMember is a type (TypeDefinition). Otherwise, returns false (is MethodDefinition or PropertyDefinition).
/// </summary>
public static bool IsCurrentMemberReferenceType {
get {
return CurrentMemberReference is TypeDefinition;
}
}
/// <summary> /// <summary>
/// Gets or sets the current code mappings. /// Gets or sets the current code mappings.
/// </summary> /// </summary>
public static Tuple<string, List<MemberMapping>> CodeMappings { get; set; } public static Dictionary<string, List<MemberMapping>> CodeMappings { get; set; }
/// <summary> /// <summary>
/// Gets or sets the local variables of the current decompiled type, method, etc. /// Gets or sets the local variables of the current decompiled type, method, etc.
@ -64,7 +50,17 @@ namespace ICSharpCode.ILSpy.Debugger
/// <summary> /// <summary>
/// Gets or sets the old code mappings. /// Gets or sets the old code mappings.
/// </summary> /// </summary>
public static Tuple<string, List<MemberMapping>> OldCodeMappings { get; set; } public static Dictionary<string, List<MemberMapping>> OldCodeMappings { get; set; }
/// <summary>
/// Gets or sets the MembeReference that was decompiled (a TypeDefinition, MethodDefinition, etc)
/// </summary>
public static Dictionary<string, MemberReference> DecompiledMemberReferences { get; set; }
/// <summary>
/// Gets or sets the debug type.
/// </summary>
public static bool DebugWholeTypesOnly { get; set; }
/// <summary> /// <summary>
/// Occures when the language is changed. /// Occures when the language is changed.

18
Debugger/ILSpy.Debugger/DebuggerSettings.cs

@ -9,10 +9,13 @@ namespace ICSharpCode.ILSpy.Debugger
public class DebuggerSettings : INotifyPropertyChanged public class DebuggerSettings : INotifyPropertyChanged
{ {
bool showWarnings = true; bool showWarnings = true;
bool debugWholeTypesOnly = false;
/// <summary> /// <summary>
/// Show warnings messages. /// Show warnings messages.
/// <remarks>Default value is true.</remarks>
/// </summary> /// </summary>
[DefaultValue(true)]
public bool ShowWarnings { public bool ShowWarnings {
get { return showWarnings; } get { return showWarnings; }
set { set {
@ -23,6 +26,21 @@ namespace ICSharpCode.ILSpy.Debugger
} }
} }
/// <summary>
/// True, if debug only whole types; otherwise false (debug only methods and properties).
/// <remarks>Default value is false.</remarks>
/// </summary>
[DefaultValue(false)]
public bool DebugWholeTypesOnly {
get { return debugWholeTypesOnly; }
set {
if (debugWholeTypesOnly != value) {
debugWholeTypesOnly = value;
OnPropertyChanged("DebugWholeTypesOnly");
}
}
}
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) protected virtual void OnPropertyChanged(string propertyName)

2
Debugger/ILSpy.Debugger/Services/Debugger/DebuggerService.cs

@ -166,7 +166,7 @@ namespace ICSharpCode.ILSpy.Debugger.Services
public static void ToggleBreakpointAt(MemberReference member, int lineNumber, DecompiledLanguages language) public static void ToggleBreakpointAt(MemberReference member, int lineNumber, DecompiledLanguages language)
{ {
BookmarkManager.ToggleBookmark( BookmarkManager.ToggleBookmark(
member.FullName, lineNumber, member.FullName.Replace("::", "."), lineNumber,
b => b.CanToggle && b is BreakpointBookmark, b => b.CanToggle && b is BreakpointBookmark,
location => new BreakpointBookmark(member, location, BreakpointAction.Break, language)); location => new BreakpointBookmark(member, location, BreakpointAction.Break, language));
} }

59
Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs

@ -288,10 +288,11 @@ namespace ICSharpCode.ILSpy.Debugger.Services
{ {
isMatch = false; isMatch = false;
frame = debuggedProcess.SelectedThread.MostRecentStackFrame; frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
var debugType = (DebugType)frame.MethodInfo.DeclaringType;
string nameKey = DebugData.DebugWholeTypesOnly ? debugType.FullNameWithoutGenericArguments : frame.MethodInfo.FullNameWithoutParameterNames;
// get the mapped instruction from the current line marker or the next one // get the mapped instruction from the current line marker or the next one
return DebugData.CodeMappings.GetInstructionByTypeTokenAndOffset( return DebugData.CodeMappings[nameKey].GetInstructionByTypeTokenAndOffset(
((DebugType)frame.MethodInfo.DeclaringType).FullNameWithoutGenericArguments,
(uint)frame.MethodInfo.MetadataToken, (uint)frame.MethodInfo.MetadataToken,
frame.IP, out isMatch); frame.IP, out isMatch);
} }
@ -560,13 +561,16 @@ namespace ICSharpCode.ILSpy.Debugger.Services
Breakpoint breakpoint = null; Breakpoint breakpoint = null;
uint token; uint token;
SourceCodeMapping map = DebugData.CodeMappings SourceCodeMapping map = DebugData.CodeMappings[bookmark.MemberReference.FullName]
.GetInstructionByTypeAndLine(bookmark.Member.FullName, bookmark.LineNumber, out token); .GetInstructionByTypeAndLine(bookmark.MemberReference.FullName, bookmark.LineNumber, out token);
if (map != null) { if (map != null) {
var declaringType = bookmark.MemberReference.DeclaringType;
breakpoint = new ILBreakpoint( breakpoint = new ILBreakpoint(
debugger, debugger,
bookmark.Member.FullName, (declaringType ?? bookmark.MemberReference).FullName,
bookmark.MemberReference.FullName,
bookmark.LineNumber, bookmark.LineNumber,
token, token,
map.ILInstructionOffset.From, map.ILInstructionOffset.From,
@ -745,7 +749,7 @@ namespace ICSharpCode.ILSpy.Debugger.Services
foreach (var bookmark in DebuggerService.Breakpoints) { foreach (var bookmark in DebuggerService.Breakpoints) {
var breakpoint = var breakpoint =
debugger.Breakpoints.FirstOrDefault( debugger.Breakpoints.FirstOrDefault(
b => b.Line == bookmark.LineNumber && b.TypeName == bookmark.Member.FullName); b => b.Line == bookmark.LineNumber && (b as ILBreakpoint).MemberReferenceName.CreateKey() == bookmark.MemberReference.FullName.CreateKey());
if (breakpoint == null) if (breakpoint == null)
continue; continue;
// set the breakpoint only if the module contains the type // set the breakpoint only if the module contains the type
@ -818,14 +822,18 @@ namespace ICSharpCode.ILSpy.Debugger.Services
int ilOffset = frame.IP; int ilOffset = frame.IP;
int line; int line;
MemberReference memberReference; MemberReference memberReference;
string nameKey = DebugData.DebugWholeTypesOnly ? debugType.FullNameWithoutGenericArguments : frame.MethodInfo.FullNameWithoutParameterNames;
if (DebugData.CodeMappings.GetSourceCodeFromMetadataTokenAndOffset(debugType.FullNameWithoutGenericArguments, token, ilOffset, out memberReference, out line) foreach (var key in DebugData.CodeMappings.Keys) {
&& memberReference.DeclaringType == null) { if (key.CreateKey() == nameKey.CreateKey()) {
DebuggerService.RemoveCurrentLineMarker(); if (DebugData.CodeMappings[key].GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out memberReference, out line)) {
DebuggerService.JumpToCurrentLine(memberReference, line, 0, line, 0); DebuggerService.RemoveCurrentLineMarker();
} else { DebuggerService.JumpToCurrentLine(memberReference, line, 0, line, 0);
// is possible that the type is not decompiled yet, so we must do a decompilation on demand } else {
DecompileOnDemand(frame); // is possible that the type is not decompiled yet, so we must do a decompilation on demand
DecompileOnDemand(frame);
}
}
} }
} }
} }
@ -837,7 +845,6 @@ namespace ICSharpCode.ILSpy.Debugger.Services
uint token = (uint)frame.MethodInfo.MetadataToken; uint token = (uint)frame.MethodInfo.MetadataToken;
int ilOffset = frame.IP; int ilOffset = frame.IP;
string fullName = debugType.FullNameWithoutGenericArguments; string fullName = debugType.FullNameWithoutGenericArguments;
fullName = fullName.Replace("+", "/");
if (DebugData.LoadedAssemblies == null) if (DebugData.LoadedAssemblies == null)
throw new NullReferenceException("No DebugData assemblies!"); throw new NullReferenceException("No DebugData assemblies!");
@ -845,6 +852,7 @@ namespace ICSharpCode.ILSpy.Debugger.Services
// search for type in the current assembly list // search for type in the current assembly list
TypeDefinition typeDef = null; TypeDefinition typeDef = null;
TypeDefinition nestedTypeDef = null; TypeDefinition nestedTypeDef = null;
MemberReference member = null;
foreach (var assembly in DebugData.LoadedAssemblies) { foreach (var assembly in DebugData.LoadedAssemblies) {
if ((assembly.FullName.StartsWith("System") || assembly.FullName.StartsWith("Microsoft") || assembly.FullName.StartsWith("mscorlib")) && if ((assembly.FullName.StartsWith("System") || assembly.FullName.StartsWith("Microsoft") || assembly.FullName.StartsWith("mscorlib")) &&
@ -854,9 +862,9 @@ namespace ICSharpCode.ILSpy.Debugger.Services
foreach (var module in assembly.Modules) { foreach (var module in assembly.Modules) {
var localType = module.GetType(fullName); var localType = module.GetType(fullName);
if (localType != null) { if (localType != null) {
if (localType.DeclaringType == null) if (localType.DeclaringType == null) {
typeDef = localType; typeDef = localType;
else { } else {
nestedTypeDef = localType; nestedTypeDef = localType;
typeDef = localType.DeclaringType; typeDef = localType.DeclaringType;
} }
@ -868,12 +876,22 @@ namespace ICSharpCode.ILSpy.Debugger.Services
} }
if (typeDef != null) { if (typeDef != null) {
// decompile on demand member = nestedTypeDef ?? typeDef;
Tuple<string, List<MemberMapping>> codeMappings = null;
if (DebugData.CodeMappings.Item1 != (nestedTypeDef ?? typeDef).FullName) { // decompile on demand if the type was not decompiled
Dictionary<string, List<MemberMapping>> codeMappings = null;
if (!DebugData.CodeMappings.ContainsKey(member.FullName)) {
if (DebugData.Language == DecompiledLanguages.IL) { if (DebugData.Language == DecompiledLanguages.IL) {
var dis = new ReflectionDisassembler(new PlainTextOutput(), true, CancellationToken.None); var dis = new ReflectionDisassembler(new PlainTextOutput(), true, CancellationToken.None);
dis.DisassembleType(nestedTypeDef ?? typeDef); dis.DisassembleType(nestedTypeDef ?? typeDef);
// else if (ICSharpCode.Decompiler.CodeMappings.DecompiledMember is MethodDefinition)
// dis.DisassembleMethod(ICSharpCode.Decompiler.CodeMappings.DecompiledMember as MethodDefinition);
// else if (ICSharpCode.Decompiler.CodeMappings.DecompiledMember is PropertyDefinition)
// dis.DisassembleProperty(ICSharpCode.Decompiler.CodeMappings.DecompiledMember as PropertyDefinition);
// else if (ICSharpCode.Decompiler.CodeMappings.DecompiledMember is EventDefinition)
// dis.DisassembleEvent(ICSharpCode.Decompiler.CodeMappings.DecompiledMember as EventDefinition);
codeMappings = dis.CodeMappings; codeMappings = dis.CodeMappings;
} else { } else {
AstBuilder builder = new AstBuilder(new DecompilerContext(typeDef.Module)); AstBuilder builder = new AstBuilder(new DecompilerContext(typeDef.Module));
@ -886,7 +904,8 @@ namespace ICSharpCode.ILSpy.Debugger.Services
int line; int line;
MemberReference memberReference; MemberReference memberReference;
codeMappings = codeMappings ?? DebugData.CodeMappings; codeMappings = codeMappings ?? DebugData.CodeMappings;
if (codeMappings.GetSourceCodeFromMetadataTokenAndOffset((nestedTypeDef ?? typeDef).FullName, token, ilOffset, out memberReference, out line)) { string name = (nestedTypeDef ?? typeDef).FullName;
if (codeMappings[name].GetSourceCodeFromMetadataTokenAndOffset(token, ilOffset, out memberReference, out line)) {
DebuggerService.RemoveCurrentLineMarker(); DebuggerService.RemoveCurrentLineMarker();
DebuggerService.JumpToCurrentLine(nestedTypeDef ?? typeDef, line, 0, line, 0); DebuggerService.JumpToCurrentLine(nestedTypeDef ?? typeDef, line, 0, line, 0);
} else { } else {

69
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -46,6 +46,8 @@ namespace ICSharpCode.Decompiler.Ast
this.DecompileMethodBodies = true; this.DecompileMethodBodies = true;
this.LocalVariables = new ConcurrentDictionary<int, IEnumerable<ILVariable>>(); this.LocalVariables = new ConcurrentDictionary<int, IEnumerable<ILVariable>>();
this.CodeMappings = new Dictionary<string, List<MemberMapping>>();
this.DecompiledMemberReferences = new Dictionary<string, MemberReference>();
} }
public static bool MemberIsHidden(MemberReference member, DecompilerSettings settings) public static bool MemberIsHidden(MemberReference member, DecompilerSettings settings)
@ -159,6 +161,10 @@ namespace ICSharpCode.Decompiler.Ast
public void AddType(TypeDefinition typeDef) public void AddType(TypeDefinition typeDef)
{ {
// add to mappings information
this.DecompiledMemberReferences.Add(typeDef.FullName, typeDef);
this.CodeMappings.Add(typeDef.FullName, new List<MemberMapping>());
var astType = CreateType(typeDef); var astType = CreateType(typeDef);
NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace); NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace);
if (astNS != null) { if (astNS != null) {
@ -170,22 +176,36 @@ namespace ICSharpCode.Decompiler.Ast
public void AddMethod(MethodDefinition method) public void AddMethod(MethodDefinition method)
{ {
// add to mappings information
this.CodeMappings.Add(method.FullName, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(method.FullName, method);
AstNode node = method.IsConstructor ? (AstNode)CreateConstructor(method) : CreateMethod(method); AstNode node = method.IsConstructor ? (AstNode)CreateConstructor(method) : CreateMethod(method);
astCompileUnit.AddChild(node, CompilationUnit.MemberRole); astCompileUnit.AddChild(node, CompilationUnit.MemberRole);
} }
public void AddProperty(PropertyDefinition property) public void AddProperty(PropertyDefinition property)
{ {
// add to mappings information
this.CodeMappings.Add(property.FullName, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(property.FullName, property);
astCompileUnit.AddChild(CreateProperty(property), CompilationUnit.MemberRole); astCompileUnit.AddChild(CreateProperty(property), CompilationUnit.MemberRole);
} }
public void AddField(FieldDefinition field) public void AddField(FieldDefinition field)
{ {
this.DecompiledMemberReferences.Add(field.FullName, field);
astCompileUnit.AddChild(CreateField(field), CompilationUnit.MemberRole); astCompileUnit.AddChild(CreateField(field), CompilationUnit.MemberRole);
} }
public void AddEvent(EventDefinition ev) public void AddEvent(EventDefinition ev)
{ {
// add to mappings information
this.DecompiledMemberReferences.Add(ev.FullName, ev);
this.CodeMappings.Add(ev.FullName, new List<MemberMapping>());
astCompileUnit.AddChild(CreateEvent(ev), CompilationUnit.MemberRole); astCompileUnit.AddChild(CreateEvent(ev), CompilationUnit.MemberRole);
} }
@ -195,11 +215,7 @@ namespace ICSharpCode.Decompiler.Ast
/// <param name="typeDef"></param> /// <param name="typeDef"></param>
/// <returns>TypeDeclaration or DelegateDeclaration.</returns> /// <returns>TypeDeclaration or DelegateDeclaration.</returns>
public AttributedNode CreateType(TypeDefinition typeDef) public AttributedNode CreateType(TypeDefinition typeDef)
{ {
// create CSharp code mappings - used for debugger
if (this.CodeMappings == null)
this.CodeMappings = new Tuple<string, List<MemberMapping>>(typeDef.FullName, new List<MemberMapping>());
// create type // create type
TypeDefinition oldCurrentType = context.CurrentType; TypeDefinition oldCurrentType = context.CurrentType;
context.CurrentType = typeDef; context.CurrentType = typeDef;
@ -603,12 +619,12 @@ namespace ICSharpCode.Decompiler.Ast
// Add events // Add events
foreach(EventDefinition eventDef in typeDef.Events) { foreach(EventDefinition eventDef in typeDef.Events) {
astType.AddChild(CreateEvent(eventDef), TypeDeclaration.MemberRole); astType.AddChild(CreateEvent(eventDef, true), TypeDeclaration.MemberRole);
} }
// Add properties // Add properties
foreach(PropertyDefinition propDef in typeDef.Properties) { foreach(PropertyDefinition propDef in typeDef.Properties) {
astType.Members.Add(CreateProperty(propDef)); astType.Members.Add(CreateProperty(propDef, true));
} }
// Add methods // Add methods
@ -616,16 +632,17 @@ namespace ICSharpCode.Decompiler.Ast
if (MemberIsHidden(methodDef, context.Settings)) continue; if (MemberIsHidden(methodDef, context.Settings)) continue;
if (methodDef.IsConstructor) if (methodDef.IsConstructor)
astType.Members.Add(CreateConstructor(methodDef)); astType.Members.Add(CreateConstructor(methodDef, true));
else else
astType.Members.Add(CreateMethod(methodDef)); astType.Members.Add(CreateMethod(methodDef, true));
} }
} }
AttributedNode CreateMethod(MethodDefinition methodDef) AttributedNode CreateMethod(MethodDefinition methodDef, bool isTypeDecompiled = false)
{ {
// Create mapping - used in debugger // Create mapping - used in debugger
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings); string name = isTypeDecompiled ? methodDef.DeclaringType.FullName : methodDef.FullName;
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled);
MethodDeclaration astMethod = new MethodDeclaration(); MethodDeclaration astMethod = new MethodDeclaration();
astMethod.AddAnnotation(methodDef); astMethod.AddAnnotation(methodDef);
@ -717,10 +734,11 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
ConstructorDeclaration CreateConstructor(MethodDefinition methodDef) ConstructorDeclaration CreateConstructor(MethodDefinition methodDef, bool isTypeDecompiled = false)
{ {
// Create mapping - used in debugger // Create mapping - used in debugger
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings); string name = isTypeDecompiled ? methodDef.DeclaringType.FullName : methodDef.FullName;
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled);
ConstructorDeclaration astMethod = new ConstructorDeclaration(); ConstructorDeclaration astMethod = new ConstructorDeclaration();
astMethod.AddAnnotation(methodDef); astMethod.AddAnnotation(methodDef);
@ -750,7 +768,7 @@ namespace ICSharpCode.Decompiler.Ast
return m & ~Modifiers.Private; return m & ~Modifiers.Private;
} }
MemberDeclaration CreateProperty(PropertyDefinition propDef) MemberDeclaration CreateProperty(PropertyDefinition propDef, bool isTypeDecompiled = false)
{ {
PropertyDeclaration astProp = new PropertyDeclaration(); PropertyDeclaration astProp = new PropertyDeclaration();
astProp.AddAnnotation(propDef); astProp.AddAnnotation(propDef);
@ -785,9 +803,12 @@ namespace ICSharpCode.Decompiler.Ast
} }
astProp.Name = CleanName(propDef.Name); astProp.Name = CleanName(propDef.Name);
astProp.ReturnType = ConvertType(propDef.PropertyType, propDef); astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
string name = isTypeDecompiled ? propDef.DeclaringType.FullName : propDef.FullName;
if (propDef.GetMethod != null) { if (propDef.GetMethod != null) {
// Create mapping - used in debugger // Create mapping - used in debugger
MemberMapping methodMapping = propDef.GetMethod.CreateCodeMapping(this.CodeMappings); MemberMapping methodMapping = propDef.GetMethod.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled);
astProp.Getter = new Accessor(); astProp.Getter = new Accessor();
astProp.Getter.Body = CreateMethodBody(propDef.GetMethod); astProp.Getter.Body = CreateMethodBody(propDef.GetMethod);
@ -801,7 +822,7 @@ namespace ICSharpCode.Decompiler.Ast
} }
if (propDef.SetMethod != null) { if (propDef.SetMethod != null) {
// Create mapping - used in debugger // Create mapping - used in debugger
MemberMapping methodMapping = propDef.SetMethod.CreateCodeMapping(this.CodeMappings); MemberMapping methodMapping = propDef.SetMethod.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled);
astProp.Setter = new Accessor(); astProp.Setter = new Accessor();
astProp.Setter.Body = CreateMethodBody(propDef.SetMethod); astProp.Setter.Body = CreateMethodBody(propDef.SetMethod);
@ -837,7 +858,7 @@ namespace ICSharpCode.Decompiler.Ast
return astIndexer; return astIndexer;
} }
AttributedNode CreateEvent(EventDefinition eventDef) AttributedNode CreateEvent(EventDefinition eventDef, bool isTypeDecompiled = false)
{ {
if (eventDef.AddMethod != null && eventDef.AddMethod.IsAbstract) { if (eventDef.AddMethod != null && eventDef.AddMethod.IsAbstract) {
// An abstract event cannot be custom // An abstract event cannot be custom
@ -859,9 +880,12 @@ namespace ICSharpCode.Decompiler.Ast
astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod); astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod);
else else
astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType); astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType);
string name = isTypeDecompiled ? eventDef.DeclaringType.FullName : eventDef.FullName;
if (eventDef.AddMethod != null) { if (eventDef.AddMethod != null) {
// Create mapping - used in debugger // Create mapping - used in debugger
MemberMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(this.CodeMappings); MemberMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled);
astEvent.AddAccessor = new Accessor { astEvent.AddAccessor = new Accessor {
Body = CreateMethodBody(eventDef.AddMethod) Body = CreateMethodBody(eventDef.AddMethod)
@ -872,7 +896,7 @@ namespace ICSharpCode.Decompiler.Ast
} }
if (eventDef.RemoveMethod != null) { if (eventDef.RemoveMethod != null) {
// Create mapping - used in debugger // Create mapping - used in debugger
MemberMapping methodMapping = eventDef.RemoveMethod.CreateCodeMapping(this.CodeMappings); MemberMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled);
astEvent.RemoveAccessor = new Accessor { astEvent.RemoveAccessor = new Accessor {
Body = CreateMethodBody(eventDef.RemoveMethod) Body = CreateMethodBody(eventDef.RemoveMethod)
@ -1371,12 +1395,17 @@ namespace ICSharpCode.Decompiler.Ast
/// <summary> /// <summary>
/// <inheritdoc/> /// <inheritdoc/>
/// </summary> /// </summary>
public Tuple<string, List<MemberMapping>> CodeMappings { get; private set; } public Dictionary<string, List<MemberMapping>> CodeMappings { get; private set; }
/// <summary> /// <summary>
/// Gets the local variables for the current decompiled type, method, etc. /// Gets the local variables for the current decompiled type, method, etc.
/// <remarks>The key is the metadata token.</remarks> /// <remarks>The key is the metadata token.</remarks>
/// </summary> /// </summary>
public ConcurrentDictionary<int, IEnumerable<ILVariable>> LocalVariables { get; private set; } public ConcurrentDictionary<int, IEnumerable<ILVariable>> LocalVariables { get; private set; }
/// <summary>
/// <inheritdoc/>
/// </summary>
public Dictionary<string, MemberReference> DecompiledMemberReferences { get; private set; }
} }
} }

107
ICSharpCode.Decompiler/CodeMappings.cs

@ -27,7 +27,12 @@ namespace ICSharpCode.Decompiler
/// <summary> /// <summary>
/// Gets the code mappings. /// Gets the code mappings.
/// </summary> /// </summary>
Tuple<string, List<MemberMapping>> CodeMappings { get; } Dictionary<string, List<MemberMapping>> CodeMappings { get; }
/// <summary>
/// Gets the MembeReference that is decompiled (a TypeDefinition, MethodDefinition, etc)
/// </summary>
Dictionary<string, MemberReference> DecompiledMemberReferences { get; }
} }
/// <summary> /// <summary>
@ -133,15 +138,17 @@ namespace ICSharpCode.Decompiler
/// Code mappings helper class. /// Code mappings helper class.
/// </summary> /// </summary>
public static class CodeMappings public static class CodeMappings
{ {
/// <summary> /// <summary>
/// Create code mapping for a method. /// Create code mapping for a method.
/// </summary> /// </summary>
/// <param name="method">Method to create the mapping for.</param> /// <param name="method">Method to create the mapping for.</param>
/// <param name="sourceCodeMappings">Source code mapping storage.</param> /// <param name="codeMappings">Source code mapping storage.</param>
/// <param name="isTypeDecompiled">True, if a full type was decompiled; false otherwise.</param>
internal static MemberMapping CreateCodeMapping( internal static MemberMapping CreateCodeMapping(
this MethodDefinition member, this MethodDefinition member,
Tuple<string, List<MemberMapping>> codeMappings) List<MemberMapping> codeMappings,
bool isTypeDecompiled)
{ {
if (member == null || !member.HasBody) if (member == null || !member.HasBody)
return null; return null;
@ -151,17 +158,21 @@ namespace ICSharpCode.Decompiler
// create IL/CSharp code mappings - used in debugger // create IL/CSharp code mappings - used in debugger
MemberMapping currentMemberMapping = null; MemberMapping currentMemberMapping = null;
if (codeMappings.Item1 == member.DeclaringType.FullName) { string key = isTypeDecompiled ? member.DeclaringType.FullName : member.FullName;
var mapping = codeMappings.Item2;
if (mapping.Find(map => (int)map.MetadataToken == member.MetadataToken.ToInt32()) == null) { if (codeMappings.Find(map => (int)map.MetadataToken == member.MetadataToken.ToInt32()) == null) {
currentMemberMapping = new MemberMapping() { currentMemberMapping = new MemberMapping() {
MetadataToken = (uint)member.MetadataToken.ToInt32(), MetadataToken = (uint)member.MetadataToken.ToInt32(),
MemberReference = member.DeclaringType.Resolve(), MemberCodeMappings = new List<SourceCodeMapping>(),
MemberCodeMappings = new List<SourceCodeMapping>(), CodeSize = member.Body.CodeSize
CodeSize = member.Body.CodeSize };
};
mapping.Add(currentMemberMapping); if (isTypeDecompiled)
} currentMemberMapping.MemberReference = member.DeclaringType.Resolve();
else
currentMemberMapping.MemberReference = member.Resolve();
codeMappings.Add(currentMemberMapping);
} }
return currentMemberMapping; return currentMemberMapping;
@ -171,31 +182,20 @@ namespace ICSharpCode.Decompiler
/// Gets source code mapping and metadata token based on type name and line number. /// Gets source code mapping and metadata token based on type name and line number.
/// </summary> /// </summary>
/// <param name="codeMappings">Code mappings storage.</param> /// <param name="codeMappings">Code mappings storage.</param>
/// <param name="typeName">Type name.</param> /// <param name="typeName">Member reference name.</param>
/// <param name="lineNumber">Line number.</param> /// <param name="lineNumber">Line number.</param>
/// <param name="metadataToken">Metadata token.</param> /// <param name="metadataToken">Metadata token.</param>
/// <returns></returns> /// <returns></returns>
public static SourceCodeMapping GetInstructionByTypeAndLine( public static SourceCodeMapping GetInstructionByTypeAndLine(
this Tuple<string, List<MemberMapping>> codeMappings, this List<MemberMapping> codeMappings,
string memberReferenceName, string memberReferenceName,
int lineNumber, int lineNumber,
out uint metadataToken) out uint metadataToken)
{ {
if (codeMappings == null) if (codeMappings == null)
throw new ArgumentNullException("CodeMappings storage must be valid!"); throw new ArgumentException("CodeMappings storage must be valid!");
if (codeMappings.Item1 != memberReferenceName) {
metadataToken = 0;
return null;
}
if (lineNumber <= 0) {
metadataToken = 0;
return null;
}
var methodMappings = codeMappings.Item2; foreach (var maping in codeMappings) {
foreach (var maping in methodMappings) {
var map = maping.MemberCodeMappings.Find(m => m.SourceCodeLine == lineNumber); var map = maping.MemberCodeMappings.Find(m => m.SourceCodeLine == lineNumber);
if (map != null) { if (map != null) {
metadataToken = maping.MetadataToken; metadataToken = maping.MetadataToken;
@ -211,33 +211,26 @@ namespace ICSharpCode.Decompiler
/// Gets a mapping given a type, a token and an IL offset. /// Gets a mapping given a type, a token and an IL offset.
/// </summary> /// </summary>
/// <param name="codeMappings">Code mappings storage.</param> /// <param name="codeMappings">Code mappings storage.</param>
/// <param name="typeName">Type name.</param> /// <param name="memberReferenceName">Member reference name.</param>
/// <param name="token">Token.</param> /// <param name="token">Token.</param>
/// <param name="ilOffset">IL offset.</param> /// <param name="ilOffset">IL offset.</param>
/// <param name="isMatch">True, if perfect match.</param> /// <param name="isMatch">True, if perfect match.</param>
/// <returns>A code mapping.</returns> /// <returns>A code mapping.</returns>
public static SourceCodeMapping GetInstructionByTypeTokenAndOffset( public static SourceCodeMapping GetInstructionByTypeTokenAndOffset(
this Tuple<string, List<MemberMapping>> codeMappings, this List<MemberMapping> codeMappings,
string memberReferenceName,
uint token, uint token,
int ilOffset, out bool isMatch) int ilOffset,
out bool isMatch)
{ {
isMatch = false; isMatch = false;
memberReferenceName = memberReferenceName.Replace("+", "/");
if (codeMappings == null) if (codeMappings == null)
throw new ArgumentNullException("CodeMappings storage must be valid!"); throw new ArgumentNullException("CodeMappings storage must be valid!");
if (codeMappings.Item1 != memberReferenceName) { var maping = codeMappings.Find(m => m.MetadataToken == token);
return null;
}
var methodMappings = codeMappings.Item2;
var maping = methodMappings.Find(m => m.MetadataToken == token);
if (maping == null) { if (maping == null)
return null; return null;
}
// try find an exact match // try find an exact match
var map = maping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From <= ilOffset && ilOffset < m.ILInstructionOffset.To); var map = maping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From <= ilOffset && ilOffset < m.ILInstructionOffset.To);
@ -260,31 +253,25 @@ namespace ICSharpCode.Decompiler
/// Gets the source code and type name from metadata token and offset. /// Gets the source code and type name from metadata token and offset.
/// </summary> /// </summary>
/// <param name="codeMappings">Code mappings storage.</param> /// <param name="codeMappings">Code mappings storage.</param>
/// <param name="typeName">Current type name.</param>
/// <param name="token">Metadata token.</param> /// <param name="token">Metadata token.</param>
/// <param name="ilOffset">IL offset.</param> /// <param name="ilOffset">IL offset.</param>
/// <param name="typeName">Type definition.</param> /// <param name="typeName">Type definition.</param>
/// <param name="line">Line number.</param> /// <param name="line">Line number.</param>
/// <remarks>It is possible to exist to different types from different assemblies with the same metadata token.</remarks> /// <remarks>It is possible to exist to different types from different assemblies with the same metadata token.</remarks>
public static bool GetSourceCodeFromMetadataTokenAndOffset( public static bool GetSourceCodeFromMetadataTokenAndOffset(
this Tuple<string, List<MemberMapping>> codeMappings, this List<MemberMapping> codeMappings,
string memberReferenceName,
uint token, uint token,
int ilOffset, int ilOffset,
out MemberReference type, out MemberReference member,
out int line) out int line)
{ {
type = null; member = null;
line = 0; line = 0;
if (codeMappings == null) if (codeMappings == null)
throw new ArgumentNullException("CodeMappings storage must be valid!"); throw new ArgumentException("CodeMappings storage must be valid!");
memberReferenceName = memberReferenceName.Replace("+", "/"); var mapping = codeMappings.Find(m => m.MetadataToken == token);
if (codeMappings.Item1 != memberReferenceName)
return false;
var mapping = codeMappings.Item2.Find(m => m.MetadataToken == token);
if (mapping == null) if (mapping == null)
return false; return false;
@ -299,9 +286,19 @@ namespace ICSharpCode.Decompiler
} }
} }
type = mapping.MemberReference; member = mapping.MemberReference;
line = codeMapping.SourceCodeLine; line = codeMapping.SourceCodeLine;
return true; return true;
} }
/// <summary>
/// Create a key by replacing "::" with ".", "+" with "/", " " with "";
/// </summary>
/// <param name="item">Item to convert.</param>
/// <returns></returns>
public static string CreateKey(this string item)
{
return item.Replace("+", "/").Replace("::", ".").Replace(" ", string.Empty);
}
} }
} }

90
ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -44,6 +44,9 @@ namespace ICSharpCode.Decompiler.Disassembler
this.cancellationToken = cancellationToken; this.cancellationToken = cancellationToken;
this.detectControlStructure = detectControlStructure; this.detectControlStructure = detectControlStructure;
this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken); this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken);
this.CodeMappings = new Dictionary<string, List<MemberMapping>>();
this.DecompiledMemberReferences = new Dictionary<string, MemberReference>();
} }
#region Disassemble Method #region Disassemble Method
@ -92,14 +95,21 @@ namespace ICSharpCode.Decompiler.Disassembler
{ MethodImplAttributes.NoOptimization, "nooptimization" }, { MethodImplAttributes.NoOptimization, "nooptimization" },
}; };
public void DisassembleMethod(MethodDefinition method) public void DisassembleMethod(MethodDefinition method, bool isTypeDecompiled = false)
{ {
// create mappings for decompiled methods only
string name = isTypeDecompiled ? method.DeclaringType.FullName : method.FullName;
if (!isTypeDecompiled) {
this.CodeMappings.Add(name, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(method.FullName, method);
}
// write method header // write method header
output.WriteDefinition(".method ", method); output.WriteDefinition(".method ", method);
DisassembleMethodInternal(method); DisassembleMethodInternal(method, isTypeDecompiled);
} }
void DisassembleMethodInternal(MethodDefinition method) void DisassembleMethodInternal(MethodDefinition method, bool isTypeDecompiled)
{ {
// .method public hidebysig specialname // .method public hidebysig specialname
// instance default class [mscorlib]System.IO.TextWriter get_BaseWriter () cil managed // instance default class [mscorlib]System.IO.TextWriter get_BaseWriter () cil managed
@ -118,7 +128,6 @@ namespace ICSharpCode.Decompiler.Disassembler
//call convention //call convention
WriteEnum(method.CallingConvention & (MethodCallingConvention)0x1f, callingConvention); WriteEnum(method.CallingConvention & (MethodCallingConvention)0x1f, callingConvention);
//return type //return type
method.ReturnType.WriteTo(output); method.ReturnType.WriteTo(output);
output.Write(' '); output.Write(' ');
@ -149,7 +158,9 @@ namespace ICSharpCode.Decompiler.Disassembler
if (method.HasBody) { if (method.HasBody) {
// create IL code mappings - used in debugger // create IL code mappings - used in debugger
MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings); string name = isTypeDecompiled ? method.DeclaringType.FullName : method.FullName;
MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings[name], isTypeDecompiled);
methodBodyDisassembler.Disassemble(method.Body, methodMapping); methodBodyDisassembler.Disassemble(method.Body, methodMapping);
} }
@ -192,8 +203,13 @@ namespace ICSharpCode.Decompiler.Disassembler
{ FieldAttributes.NotSerialized, "notserialized" }, { FieldAttributes.NotSerialized, "notserialized" },
}; };
public void DisassembleField(FieldDefinition field) public void DisassembleField(FieldDefinition field, bool isTypeDecompiled = false)
{ {
// create mappings for decompiled fields only
if (!isTypeDecompiled) {
this.DecompiledMemberReferences.Add(field.FullName, field);
}
output.WriteDefinition(".field ", field); output.WriteDefinition(".field ", field);
WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility); WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility);
WriteFlags(field.Attributes & ~(FieldAttributes.FieldAccessMask | FieldAttributes.HasDefault), fieldAttributes); WriteFlags(field.Attributes & ~(FieldAttributes.FieldAccessMask | FieldAttributes.HasDefault), fieldAttributes);
@ -221,8 +237,15 @@ namespace ICSharpCode.Decompiler.Disassembler
{ PropertyAttributes.HasDefault, "hasdefault" }, { PropertyAttributes.HasDefault, "hasdefault" },
}; };
public void DisassembleProperty(PropertyDefinition property) public void DisassembleProperty(PropertyDefinition property, bool isTypeDecompiled = false)
{ {
// create mappings for decompiled properties only
string name = isTypeDecompiled ? property.DeclaringType.FullName : property.FullName;
if (!isTypeDecompiled) {
this.CodeMappings.Add(name, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(property.FullName, property);
}
output.WriteDefinition(".property ", property); output.WriteDefinition(".property ", property);
WriteFlags(property.Attributes, propertyAttributes); WriteFlags(property.Attributes, propertyAttributes);
property.PropertyType.WriteTo(output); property.PropertyType.WriteTo(output);
@ -230,22 +253,22 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write(DisassemblerHelpers.Escape(property.Name)); output.Write(DisassemblerHelpers.Escape(property.Name));
OpenBlock(false); OpenBlock(false);
WriteAttributes(property.CustomAttributes); WriteAttributes(property.CustomAttributes);
WriteNestedMethod(".get", property.GetMethod); WriteNestedMethod(".get", property.GetMethod, isTypeDecompiled);
WriteNestedMethod(".set", property.SetMethod); WriteNestedMethod(".set", property.SetMethod, isTypeDecompiled);
foreach (var method in property.OtherMethods) { foreach (var method in property.OtherMethods) {
WriteNestedMethod(".method", method); WriteNestedMethod(".method", method, isTypeDecompiled);
} }
CloseBlock(); CloseBlock();
} }
void WriteNestedMethod(string keyword, MethodDefinition method) void WriteNestedMethod(string keyword, MethodDefinition method, bool isTypeDecompiled)
{ {
if (method == null) if (method == null)
return; return;
if (detectControlStructure) { if (detectControlStructure) {
output.WriteDefinition(keyword, method); output.WriteDefinition(keyword, method);
output.Write(' '); output.Write(' ');
DisassembleMethodInternal(method); DisassembleMethodInternal(method, isTypeDecompiled);
} else { } else {
output.Write(keyword); output.Write(keyword);
output.Write(' '); output.Write(' ');
@ -261,8 +284,15 @@ namespace ICSharpCode.Decompiler.Disassembler
{ EventAttributes.RTSpecialName, "rtspecialname" }, { EventAttributes.RTSpecialName, "rtspecialname" },
}; };
public void DisassembleEvent(EventDefinition ev) public void DisassembleEvent(EventDefinition ev, bool isTypeDecompiled = false)
{ {
// create mappings for decompiled events only
string name = isTypeDecompiled ? ev.DeclaringType.FullName : ev.FullName;
if (!isTypeDecompiled) {
this.CodeMappings.Add(name, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(ev.FullName, ev);
}
output.WriteDefinition(".event ", ev); output.WriteDefinition(".event ", ev);
WriteFlags(ev.Attributes, eventAttributes); WriteFlags(ev.Attributes, eventAttributes);
ev.EventType.WriteTo(output); ev.EventType.WriteTo(output);
@ -270,11 +300,11 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write(DisassemblerHelpers.Escape(ev.Name)); output.Write(DisassemblerHelpers.Escape(ev.Name));
OpenBlock(false); OpenBlock(false);
WriteAttributes(ev.CustomAttributes); WriteAttributes(ev.CustomAttributes);
WriteNestedMethod(".add", ev.AddMethod); WriteNestedMethod(".add", ev.AddMethod, isTypeDecompiled);
WriteNestedMethod(".remove", ev.RemoveMethod); WriteNestedMethod(".remove", ev.RemoveMethod, isTypeDecompiled);
WriteNestedMethod(".invoke", ev.InvokeMethod); WriteNestedMethod(".invoke", ev.InvokeMethod, isTypeDecompiled);
foreach (var method in ev.OtherMethods) { foreach (var method in ev.OtherMethods) {
WriteNestedMethod(".method", method); WriteNestedMethod(".method", method, isTypeDecompiled);
} }
CloseBlock(); CloseBlock();
} }
@ -317,8 +347,10 @@ namespace ICSharpCode.Decompiler.Disassembler
public void DisassembleType(TypeDefinition type) public void DisassembleType(TypeDefinition type)
{ {
// create IL code mappings - used for debugger // create IL code mappings - used for debugger
if (this.CodeMappings == null) if (this.CodeMappings == null) {
this.CodeMappings = new Tuple<string, List<MemberMapping>>(type.FullName, new List<MemberMapping>()); this.CodeMappings.Add(type.FullName, new List<MemberMapping>());
this.DecompiledMemberReferences.Add(type.FullName, type);
}
// start writing IL // start writing IL
output.WriteDefinition(".class ", type); output.WriteDefinition(".class ", type);
@ -383,7 +415,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine("// Fields"); output.WriteLine("// Fields");
foreach (var field in type.Fields) { foreach (var field in type.Fields) {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
DisassembleField(field); DisassembleField(field, true);
} }
output.WriteLine(); output.WriteLine();
} }
@ -391,7 +423,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine("// Properties"); output.WriteLine("// Properties");
foreach (var prop in type.Properties) { foreach (var prop in type.Properties) {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
DisassembleProperty(prop); DisassembleProperty(prop, true);
} }
output.WriteLine(); output.WriteLine();
} }
@ -399,7 +431,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine("// Events"); output.WriteLine("// Events");
foreach (var ev in type.Events) { foreach (var ev in type.Events) {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
DisassembleEvent(ev); DisassembleEvent(ev, true);
output.WriteLine(); output.WriteLine();
} }
output.WriteLine(); output.WriteLine();
@ -410,7 +442,7 @@ namespace ICSharpCode.Decompiler.Disassembler
foreach (var m in type.Methods) { foreach (var m in type.Methods) {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
if (!(detectControlStructure && accessorMethods.Contains(m))) { if (!(detectControlStructure && accessorMethods.Contains(m))) {
DisassembleMethod(m); DisassembleMethod(m, true);
output.WriteLine(); output.WriteLine();
} }
} }
@ -605,10 +637,14 @@ namespace ICSharpCode.Decompiler.Disassembler
CloseBlock(); CloseBlock();
} }
/// <summary>
/// <inheritdoc/> /// <inheritdoc/>
public Tuple<string, List<MemberMapping>> CodeMappings { /// </summary>
get; public Dictionary<string, List<MemberMapping>> CodeMappings { get; private set; }
private set;
} /// <summary>
/// <inheritdoc/>
/// </summary>
public Dictionary<string, MemberReference> DecompiledMemberReferences { get; private set; }
} }
} }

10
ILSpy/CSharpLanguage.cs

@ -92,7 +92,7 @@ namespace ICSharpCode.ILSpy
codeDomBuilder.AddMethod(method); codeDomBuilder.AddMethod(method);
codeDomBuilder.RunTransformations(transformAbortCondition); codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output); codeDomBuilder.GenerateCode(output);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables }); OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables, DecompiledMemberReferences = codeDomBuilder.DecompiledMemberReferences });
} }
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options) public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
@ -102,7 +102,7 @@ namespace ICSharpCode.ILSpy
codeDomBuilder.AddProperty(property); codeDomBuilder.AddProperty(property);
codeDomBuilder.RunTransformations(transformAbortCondition); codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output); codeDomBuilder.GenerateCode(output);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables }); OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables, DecompiledMemberReferences = codeDomBuilder.DecompiledMemberReferences });
} }
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options) public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
@ -112,7 +112,7 @@ namespace ICSharpCode.ILSpy
codeDomBuilder.AddField(field); codeDomBuilder.AddField(field);
codeDomBuilder.RunTransformations(transformAbortCondition); codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output); codeDomBuilder.GenerateCode(output);
OnDecompilationFinished(null); OnDecompilationFinished(new DecompileEventArgs { DecompiledMemberReferences = codeDomBuilder.DecompiledMemberReferences });
} }
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options) public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
@ -122,7 +122,7 @@ namespace ICSharpCode.ILSpy
codeDomBuilder.AddEvent(ev); codeDomBuilder.AddEvent(ev);
codeDomBuilder.RunTransformations(transformAbortCondition); codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output); codeDomBuilder.GenerateCode(output);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables }); OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables, DecompiledMemberReferences = codeDomBuilder.DecompiledMemberReferences });
} }
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
@ -131,7 +131,7 @@ namespace ICSharpCode.ILSpy
codeDomBuilder.AddType(type); codeDomBuilder.AddType(type);
codeDomBuilder.RunTransformations(transformAbortCondition); codeDomBuilder.RunTransformations(transformAbortCondition);
codeDomBuilder.GenerateCode(output); codeDomBuilder.GenerateCode(output);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables }); OnDecompilationFinished(new DecompileEventArgs { CodeMappings = codeDomBuilder.CodeMappings, LocalVariables = codeDomBuilder.LocalVariables, DecompiledMemberReferences = codeDomBuilder.DecompiledMemberReferences });
} }
public override void DecompileAssembly(AssemblyDefinition assembly, string fileName, ITextOutput output, DecompilationOptions options) public override void DecompileAssembly(AssemblyDefinition assembly, string fileName, ITextOutput output, DecompilationOptions options)

4
ILSpy/Commands/DebuggerCommands.cs

@ -163,8 +163,8 @@ namespace ICSharpCode.ILSpy.Commands
// jump to type & expand folding // jump to type & expand folding
if (CurrentLineBookmark.Instance != null) { if (CurrentLineBookmark.Instance != null) {
if (CurrentLineBookmark.Instance.Member != DebugData.CurrentMemberReference) if (!DebugData.DecompiledMemberReferences.ContainsKey(CurrentLineBookmark.Instance.MemberReference.FullName))
MainWindow.Instance.JumpToReference(CurrentLineBookmark.Instance.Member); MainWindow.Instance.JumpToReference(CurrentLineBookmark.Instance.MemberReference);
MainWindow.Instance.TextView.UnfoldAndScroll(CurrentLineBookmark.Instance.LineNumber); MainWindow.Instance.TextView.UnfoldAndScroll(CurrentLineBookmark.Instance.LineNumber);
} }

14
ILSpy/ILLanguage.cs

@ -55,35 +55,35 @@ namespace ICSharpCode.ILSpy
{ {
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken); var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
dis.DisassembleMethod(method); dis.DisassembleMethod(method);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings }); OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings, DecompiledMemberReferences = dis.DecompiledMemberReferences });
} }
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options) public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{ {
new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken).DisassembleField(field); var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
OnDecompilationFinished(null); dis.DisassembleField(field);
OnDecompilationFinished(new DecompileEventArgs { DecompiledMemberReferences = dis.DecompiledMemberReferences });
} }
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options) public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{ {
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken); var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
dis.DisassembleProperty(property); dis.DisassembleProperty(property);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings }); OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings, DecompiledMemberReferences = dis.DecompiledMemberReferences });
} }
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options) public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{ {
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken); var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
dis.DisassembleEvent(ev); dis.DisassembleEvent(ev);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings }); OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings, DecompiledMemberReferences = dis.DecompiledMemberReferences });
} }
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{ {
var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken); var dis = new ReflectionDisassembler(output, detectControlStructure, options.CancellationToken);
dis.DisassembleType(type); dis.DisassembleType(type);
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings , DecompiledMemberReferences = dis.DecompiledMemberReferences});
OnDecompilationFinished(new DecompileEventArgs { CodeMappings = dis.CodeMappings });
} }
public override void DecompileNamespace(string nameSpace, IEnumerable<TypeDefinition> types, ITextOutput output, DecompilationOptions options) public override void DecompileNamespace(string nameSpace, IEnumerable<TypeDefinition> types, ITextOutput output, DecompilationOptions options)

7
ILSpy/Language.cs

@ -37,12 +37,17 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// Gets ot sets the code mappings /// Gets ot sets the code mappings
/// </summary> /// </summary>
public Tuple<string, List<MemberMapping>> CodeMappings { get; set; } public Dictionary<string, List<MemberMapping>> CodeMappings { get; set; }
/// <summary> /// <summary>
/// Gets or sets the local variables. /// Gets or sets the local variables.
/// </summary> /// </summary>
public ConcurrentDictionary<int, IEnumerable<ILVariable>> LocalVariables { get; set; } public ConcurrentDictionary<int, IEnumerable<ILVariable>> LocalVariables { get; set; }
/// <summary>
/// Gets the list of MembeReferences that are decompiled (TypeDefinitions, MethodDefinitions, etc)
/// </summary>
public Dictionary<string, MemberReference> DecompiledMemberReferences { get; set; }
} }
/// <summary> /// <summary>

3
ILSpy/Options/DebuggerSettingsPanel.xaml

@ -5,6 +5,9 @@
<Grid> <Grid>
<StackPanel Margin="10"> <StackPanel Margin="10">
<CheckBox IsChecked="{Binding ShowWarnings}">Show warning messages</CheckBox> <CheckBox IsChecked="{Binding ShowWarnings}">Show warning messages</CheckBox>
<CheckBox
ToolTip="If checked, debug only whole types; otherwise debug only methods or properties."
IsChecked="{Binding DebugWholeTypesOnly}">Debug whole types only</CheckBox>
</StackPanel> </StackPanel>
</Grid> </Grid>
</UserControl> </UserControl>

16
ILSpy/Options/DebuggerSettingsPanel.xaml.cs

@ -19,6 +19,10 @@ namespace ICSharpCode.ILSpy.Options
[ExportOptionPage(Title = "Debugger", Order = 1)] [ExportOptionPage(Title = "Debugger", Order = 1)]
partial class DebuggerSettingsPanel : UserControl, IOptionPage partial class DebuggerSettingsPanel : UserControl, IOptionPage
{ {
private const string DEBUGGER_SETTINGS = "DebuggerSettings";
private const string SHOW_WARNINGS = "showWarnings";
private const string DEBUG_WHOLE_TYPES_ONLY = "debugWholeTypesOnly";
public DebuggerSettingsPanel() public DebuggerSettingsPanel()
{ {
InitializeComponent(); InitializeComponent();
@ -39,19 +43,21 @@ namespace ICSharpCode.ILSpy.Options
public static DebuggerSettings LoadDebuggerSettings(ILSpySettings settings) public static DebuggerSettings LoadDebuggerSettings(ILSpySettings settings)
{ {
XElement e = settings["DebuggerSettings"]; XElement e = settings[DEBUGGER_SETTINGS];
DebuggerSettings s = new DebuggerSettings(); DebuggerSettings s = new DebuggerSettings();
s.ShowWarnings = (bool?)e.Attribute("showWarnings") ?? s.ShowWarnings; s.ShowWarnings = (bool?)e.Attribute(SHOW_WARNINGS) ?? s.ShowWarnings;
s.DebugWholeTypesOnly = (bool?)e.Attribute(DEBUG_WHOLE_TYPES_ONLY) ?? s.DebugWholeTypesOnly;
return s; return s;
} }
public void Save(XElement root) public void Save(XElement root)
{ {
var s = (DebuggerSettings)this.DataContext; var s = (DebuggerSettings)this.DataContext;
XElement section = new XElement("DebuggerSettings"); XElement section = new XElement(DEBUGGER_SETTINGS);
section.SetAttributeValue("showWarnings", s.ShowWarnings); section.SetAttributeValue(SHOW_WARNINGS, s.ShowWarnings);
section.SetAttributeValue(DEBUG_WHOLE_TYPES_ONLY, s.DebugWholeTypesOnly);
XElement existingElement = root.Element("DebuggerSettings"); XElement existingElement = root.Element(DEBUGGER_SETTINGS);
if (existingElement != null) if (existingElement != null)
existingElement.ReplaceWith(section); existingElement.ReplaceWith(section);
else else

34
ILSpy/TextView/DecompilerTextView.cs

@ -44,6 +44,7 @@ using ICSharpCode.ILSpy.Debugger;
using ICSharpCode.ILSpy.Debugger.AvalonEdit; using ICSharpCode.ILSpy.Debugger.AvalonEdit;
using ICSharpCode.ILSpy.Debugger.Bookmarks; using ICSharpCode.ILSpy.Debugger.Bookmarks;
using ICSharpCode.ILSpy.Debugger.Tooltips; using ICSharpCode.ILSpy.Debugger.Tooltips;
using ICSharpCode.ILSpy.Options;
using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.XmlDoc; using ICSharpCode.ILSpy.XmlDoc;
using ICSharpCode.NRefactory.Documentation; using ICSharpCode.NRefactory.Documentation;
@ -335,9 +336,9 @@ namespace ICSharpCode.ILSpy.TextView
void DoDecompile(DecompilationContext context, int outputLengthLimit) void DoDecompile(DecompilationContext context, int outputLengthLimit)
{ {
// reset type // reset type
DebugData.CurrentMemberReference = null;
DebugData.OldCodeMappings = DebugData.CodeMappings; DebugData.OldCodeMappings = DebugData.CodeMappings;
TextEditorListener.Instance.ClosePopup(); TextEditorListener.Instance.ClosePopup();
bool isDecompilationOk = true;
RunWithCancellation( RunWithCancellation(
delegate (CancellationToken ct) { // creation of the background task delegate (CancellationToken ct) { // creation of the background task
@ -363,39 +364,34 @@ namespace ICSharpCode.ILSpy.TextView
output.WriteLine(ex.ToString()); output.WriteLine(ex.ToString());
} }
ShowOutput(output); ShowOutput(output);
isDecompilationOk = false;
// reset type
DebugData.CurrentMemberReference = null;
} }
finally { finally {
// set the language // set the language
DebugData.Language = MainWindow.Instance.sessionSettings.FilterSettings.Language.Name.StartsWith("IL") ? DecompiledLanguages.IL : DecompiledLanguages.CSharp; DebugData.Language = MainWindow.Instance.sessionSettings.FilterSettings.Language.Name.StartsWith("IL") ? DecompiledLanguages.IL : DecompiledLanguages.CSharp;
bool debugOnlyTypes = DebuggerSettingsPanel.CurrentDebuggerSettings.DebugWholeTypesOnly;
DebugData.DebugWholeTypesOnly = debugOnlyTypes;
if (DebugData.CurrentMemberReference != null) { if (isDecompilationOk) {
// TODO: show margin for single methods and properties if (DebugData.DecompiledMemberReferences != null && DebugData.DecompiledMemberReferences.Count > 0) {
if (context.TreeNodes.Count() == 1 && DebugData.IsCurrentMemberReferenceType) {
iconMargin.Visibility = Visibility.Visible;
// repaint bookmarks // repaint bookmarks
iconMargin.InvalidateVisual(); iconMargin.InvalidateVisual();
// show the currentline marker // show the currentline marker
var bm = CurrentLineBookmark.Instance; var bm = CurrentLineBookmark.Instance;
if (bm != null && DebugData.CurrentMemberReference != null) { if (bm != null) {
if (DebugData.CurrentMemberReference == bm.Member) { if (DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.FullName)) {
DocumentLine line = textEditor.Document.GetLineByNumber(bm.LineNumber); DocumentLine line = textEditor.Document.GetLineByNumber(bm.LineNumber);
bm.Marker = bm.CreateMarker(textMarkerService, line.Offset, line.Length); bm.Marker = bm.CreateMarker(textMarkerService, line.Offset, line.Length);
} }
UnfoldAndScroll(bm.LineNumber); UnfoldAndScroll(bm.LineNumber);
} }
} else {
// hide the margin
iconMargin.Visibility = Visibility.Collapsed;
} }
} else { } else {
// remove currentline marker // remove currentline marker
CurrentLineBookmark.Remove(); CurrentLineBookmark.Remove();
iconMargin.Visibility = Visibility.Collapsed;
} }
} }
}); });
@ -454,9 +450,6 @@ namespace ICSharpCode.ILSpy.TextView
if (i > 0) if (i > 0)
textOutput.WriteLine(); textOutput.WriteLine();
if (nodes[i] is IMemberTreeNode) {
DebugData.CurrentMemberReference = (nodes[i] as IMemberTreeNode).Member;
}
context.Options.CancellationToken.ThrowIfCancellationRequested(); context.Options.CancellationToken.ThrowIfCancellationRequested();
nodes[i].Decompile(context.Language, textOutput, context.Options); nodes[i].Decompile(context.Language, textOutput, context.Options);
} }
@ -466,8 +459,13 @@ namespace ICSharpCode.ILSpy.TextView
static void Language_DecompileFinished(object sender, DecompileEventArgs e) static void Language_DecompileFinished(object sender, DecompileEventArgs e)
{ {
if (e != null) { if (e != null) {
DebugData.CodeMappings = e.CodeMappings; DebugData.CodeMappings = e.CodeMappings;
DebugData.LocalVariables = e.LocalVariables; DebugData.LocalVariables = e.LocalVariables;
DebugData.DecompiledMemberReferences = e.DecompiledMemberReferences;
} else {
DebugData.CodeMappings = null;
DebugData.LocalVariables = null;
DebugData.DecompiledMemberReferences = null;
} }
} }
#endregion #endregion

Loading…
Cancel
Save