From a0bff8626e523283cdaa8cca62c1ed12cda97d46 Mon Sep 17 00:00:00 2001 From: Eusebiu Marcu Date: Fri, 29 Apr 2011 15:25:41 +0300 Subject: [PATCH] sync bookmarks : types/members and C#/IL(not working 100%). --- .../AvalonEdit/IconBarMargin.cs | 65 +++++++++++++++++-- .../Bookmarks/BookmarkManager.cs | 10 +-- .../Bookmarks/BreakpointBookmark.cs | 3 +- .../Bookmarks/CurrentLineBookmark.cs | 3 +- Debugger/ILSpy.Debugger/DebuggedData.cs | 5 -- .../Services/Debugger/WindowsDebugger.cs | 18 ++--- .../Services/ExtensionMethods.cs | 51 ++++++++++++++- ICSharpCode.Decompiler/CodeMappings.cs | 6 +- .../Disassembler/ReflectionDisassembler.cs | 6 +- ILSpy/Options/DebuggerSettingsPanel.xaml | 3 - ILSpy/Options/DebuggerSettingsPanel.xaml.cs | 6 +- ILSpy/TextView/DecompilerTextView.cs | 5 +- 12 files changed, 131 insertions(+), 50 deletions(-) diff --git a/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs b/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs index 0a0aac387..19220c1b2 100644 --- a/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs +++ b/Debugger/ILSpy.Debugger/AvalonEdit/IconBarMargin.cs @@ -8,12 +8,14 @@ using System.Linq; using System.Windows; using System.Windows.Input; using System.Windows.Media; + using ICSharpCode.AvalonEdit.Editing; using ICSharpCode.AvalonEdit.Rendering; using ICSharpCode.AvalonEdit.Utils; using ICSharpCode.Decompiler; using ICSharpCode.ILSpy.Debugger.Bookmarks; using ICSharpCode.ILSpy.Debugger.Services; +using ICSharpCode.NRefactory.CSharp; using Mono.Cecil; namespace ICSharpCode.ILSpy.Debugger.AvalonEdit @@ -62,9 +64,6 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit if (DebugData.DecompiledMemberReferences == null || DebugData.DecompiledMemberReferences.Count == 0 || !DebugData.DecompiledMemberReferences.ContainsKey(bm.MemberReference.FullName)) continue; - if (bm is BreakpointBookmark && - ((BreakpointBookmark)bm).Language != DebugData.Language) - continue; int line = bm.LineNumber; BookmarkBase existingBookmark; @@ -232,7 +231,7 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit uint token = 0; foreach (var member in DebugData.DecompiledMemberReferences.Values) { string memberName = member.FullName; - var instruction = storage[memberName].GetInstructionByTypeAndLine(memberName, line, out token); + var instruction = storage[memberName].GetInstructionByLineNumber(line, out token); if (instruction == null) { continue; @@ -257,5 +256,63 @@ namespace ICSharpCode.ILSpy.Debugger.AvalonEdit InvalidateVisual(); } } + + public void SyncBookmarks() + { + if (DebugData.CodeMappings == null || DebugData.CodeMappings.Count == 0) + return; + + //remove existing bookmarks and create new ones + List newBookmarks = new List(); + for (int i = BookmarkManager.Bookmarks.Count - 1; i >= 0; --i) { + var breakpoint = BookmarkManager.Bookmarks[i] as BreakpointBookmark; + if (breakpoint == null) + continue; + + foreach (var key in DebugData.CodeMappings.Keys) { + var member = DebugData.DecompiledMemberReferences[key]; + + uint token; + if (member is TypeDefinition) { + var m = member as TypeDefinition; + if (breakpoint.MemberReference is TypeDefinition) { + if (member != breakpoint.MemberReference) + continue; + token = (uint)member.MetadataToken.ToInt32(); + } else { + if (!m.ContainsMember(breakpoint.MemberReference)) + continue; + token = (uint)breakpoint.MemberReference.MetadataToken.ToInt32(); + } + } else { + if (breakpoint.MemberReference is TypeDefinition) { + if (!(breakpoint.MemberReference as TypeDefinition).ContainsMember(member)) + continue; + token = (uint)member.MetadataToken.ToInt32(); + } else { + if (breakpoint.MemberReference != member) + continue; + token = (uint)breakpoint.MemberReference.MetadataToken.ToInt32(); + } + } + + bool isMatch; + SourceCodeMapping map = DebugData.CodeMappings[key] + .GetInstructionByTokenAndOffset(token, breakpoint.ILRange.From, out isMatch); + + if (map != null) { + newBookmarks.Add(new BreakpointBookmark( + DebugData.DecompiledMemberReferences[key], + new AstLocation(map.SourceCodeLine, 0), + map.ILInstructionOffset, BreakpointAction.Break, DebugData.Language)); + + BookmarkManager.RemoveMark(breakpoint); + break; + } + } + } + + newBookmarks.ForEach(m => BookmarkManager.AddMark(m)); + } } } \ No newline at end of file diff --git a/Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs b/Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs index 997520f94..fea2a704c 100644 --- a/Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs +++ b/Debugger/ILSpy.Debugger/Bookmarks/BookmarkManager.cs @@ -128,7 +128,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks var newLanguage = e.NewLanguage; SyncCurrentLineBookmark(oldLanguage, newLanguage); - SyncBreakpointBookmarks(oldLanguage, newLanguage); + //SyncBreakpointBookmarks(oldLanguage, newLanguage); } /// @@ -152,7 +152,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks int line = CurrentLineBookmark.Instance.LineNumber; var markerType = CurrentLineBookmark.Instance.MemberReference; - if (!oldMappings.ContainsKey(markerType.FullName) || !oldMappings.ContainsKey(markerType.FullName)) + if (!oldMappings.ContainsKey(markerType.FullName) || !newMappings.ContainsKey(markerType.FullName)) return; // 2. Remove it @@ -160,7 +160,7 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks // 3. map the marker line uint token; - var instruction = oldMappings[markerType.FullName].GetInstructionByTypeAndLine(markerType.FullName, line, out token); + var instruction = oldMappings[markerType.FullName].GetInstructionByLineNumber(line, out token); if (instruction == null) return; @@ -195,10 +195,10 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks foreach (var bp in oldbps) { uint token; string name = bp.MemberReference.FullName; - if (!oldMappings.ContainsKey(name) || !oldMappings.ContainsKey(name)) + if (!oldMappings.ContainsKey(name) || !newMappings.ContainsKey(name)) continue; - var instruction = oldMappings[name].GetInstructionByTypeAndLine(bp.MemberReference.FullName, bp.LineNumber, out token); + var instruction = oldMappings[name].GetInstructionByLineNumber(bp.LineNumber, out token); if (instruction == null) continue; diff --git a/Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs b/Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs index 7929bb168..1254f910f 100644 --- a/Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs +++ b/Debugger/ILSpy.Debugger/Bookmarks/BreakpointBookmark.cs @@ -91,7 +91,8 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks ITextMarker marker = markerService.Create(offset, length); marker.BackgroundColor = Color.FromRgb(180, 38, 38); marker.ForegroundColor = Colors.White; - marker.IsVisible = b => b is MarkerBookmark && DebugData.DecompiledMemberReferences.ContainsKey(((MarkerBookmark)b).MemberReference.FullName); + marker.IsVisible = b => b is MarkerBookmark && DebugData.DecompiledMemberReferences != null && + DebugData.DecompiledMemberReferences.ContainsKey(((MarkerBookmark)b).MemberReference.FullName); marker.Bookmark = this; this.Marker = marker; diff --git a/Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs b/Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs index b83f1ca77..3472d1bd5 100644 --- a/Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs +++ b/Debugger/ILSpy.Debugger/Bookmarks/CurrentLineBookmark.cs @@ -81,7 +81,8 @@ namespace ICSharpCode.ILSpy.Debugger.Bookmarks ITextMarker marker = markerService.Create(offset + startColumn - 1, length + 1); marker.BackgroundColor = Colors.Yellow; marker.ForegroundColor = Colors.Blue; - marker.IsVisible = b => b is MarkerBookmark && DebugData.DecompiledMemberReferences.ContainsKey(((MarkerBookmark)b).MemberReference.FullName); + marker.IsVisible = b => b is MarkerBookmark && DebugData.DecompiledMemberReferences != null && + DebugData.DecompiledMemberReferences.ContainsKey(((MarkerBookmark)b).MemberReference.FullName); marker.Bookmark = this; this.Marker = marker; return marker; diff --git a/Debugger/ILSpy.Debugger/DebuggedData.cs b/Debugger/ILSpy.Debugger/DebuggedData.cs index 0b1473e04..6fdc436bc 100644 --- a/Debugger/ILSpy.Debugger/DebuggedData.cs +++ b/Debugger/ILSpy.Debugger/DebuggedData.cs @@ -57,11 +57,6 @@ namespace ICSharpCode.ILSpy.Debugger /// public static Dictionary DecompiledMemberReferences { get; set; } - /// - /// Gets or sets the debug type. - /// - public static bool DebugWholeTypesOnly { get; set; } - /// /// Occures when the language is changed. /// diff --git a/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs b/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs index 07c3275f4..10a1a4eb3 100644 --- a/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs +++ b/Debugger/ILSpy.Debugger/Services/Debugger/WindowsDebugger.cs @@ -289,10 +289,10 @@ namespace ICSharpCode.ILSpy.Debugger.Services isMatch = false; frame = debuggedProcess.SelectedThread.MostRecentStackFrame; var debugType = (DebugType)frame.MethodInfo.DeclaringType; - string nameKey = DebugData.DebugWholeTypesOnly ? debugType.FullNameWithoutGenericArguments : frame.MethodInfo.FullNameWithoutParameterNames; + string nameKey = debugType.FullNameWithoutGenericArguments; // get the mapped instruction from the current line marker or the next one - return DebugData.CodeMappings[nameKey].GetInstructionByTypeTokenAndOffset( + return DebugData.CodeMappings[nameKey].GetInstructionByTokenAndOffset( (uint)frame.MethodInfo.MetadataToken, frame.IP, out isMatch); } @@ -562,7 +562,7 @@ namespace ICSharpCode.ILSpy.Debugger.Services uint token; SourceCodeMapping map = DebugData.CodeMappings[bookmark.MemberReference.FullName] - .GetInstructionByTypeAndLine(bookmark.MemberReference.FullName, bookmark.LineNumber, out token); + .GetInstructionByLineNumber(bookmark.LineNumber, out token); if (map != null) { var declaringType = bookmark.MemberReference.DeclaringType; @@ -822,7 +822,7 @@ namespace ICSharpCode.ILSpy.Debugger.Services int ilOffset = frame.IP; int line; MemberReference memberReference; - string nameKey = DebugData.DebugWholeTypesOnly ? debugType.FullNameWithoutGenericArguments : frame.MethodInfo.FullNameWithoutParameterNames; + string nameKey = debugType.FullNameWithoutGenericArguments; foreach (var key in DebugData.CodeMappings.Keys) { if (key.CreateKey() == nameKey.CreateKey()) { @@ -883,15 +883,7 @@ namespace ICSharpCode.ILSpy.Debugger.Services if (!DebugData.CodeMappings.ContainsKey(member.FullName)) { if (DebugData.Language == DecompiledLanguages.IL) { var dis = new ReflectionDisassembler(new PlainTextOutput(), true, CancellationToken.None); - - 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); - + dis.DisassembleType(nestedTypeDef ?? typeDef); codeMappings = dis.CodeMappings; } else { AstBuilder builder = new AstBuilder(new DecompilerContext(typeDef.Module)); diff --git a/Debugger/ILSpy.Debugger/Services/ExtensionMethods.cs b/Debugger/ILSpy.Debugger/Services/ExtensionMethods.cs index 1c590717f..e7b531db8 100644 --- a/Debugger/ILSpy.Debugger/Services/ExtensionMethods.cs +++ b/Debugger/ILSpy.Debugger/Services/ExtensionMethods.cs @@ -14,6 +14,8 @@ using System.Windows.Media; using System.Xml; using System.Xml.Linq; +using Mono.Cecil; + namespace ICSharpCode.ILSpy.Debugger.Services { /// @@ -344,7 +346,7 @@ namespace ICSharpCode.ILSpy.Debugger.Services int bytes; while ((bytes = sourceStream.Read(buffer, 0, buffer.Length)) > 0) targetStream.Write(buffer, 0, bytes); - } + } } /// @@ -358,8 +360,8 @@ namespace ICSharpCode.ILSpy.Debugger.Services public static ScrollViewer GetScrollViewer(this DependencyObject o) { var scrollViewer = o as ScrollViewer; - if (scrollViewer != null) { - return scrollViewer; + if (scrollViewer != null) { + return scrollViewer; } for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++) @@ -398,5 +400,48 @@ namespace ICSharpCode.ILSpy.Debugger.Services { scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset); } + + /// + /// Verifies if the type contains the member. + /// + /// + /// + /// + public static bool ContainsMember(this TypeDefinition type, MemberReference member) + { + // check fields + if (member is FieldDefinition) { + foreach (var field in type.Fields) { + if (field == member) + return true; + } + } + + // check properties + if (member is PropertyDefinition) { + foreach (var field in type.Properties) { + if (field.Resolve() == member) + return true; + } + } + + // check methods + if (member is MethodDefinition) { + foreach (var field in type.Methods) { + if (field == member) + return true; + } + } + + // check events + if (member is EventDefinition) { + foreach (var field in type.Events) { + if (field == member) + return true; + } + } + + return false; + } } } diff --git a/ICSharpCode.Decompiler/CodeMappings.cs b/ICSharpCode.Decompiler/CodeMappings.cs index 277e50287..700b03d49 100644 --- a/ICSharpCode.Decompiler/CodeMappings.cs +++ b/ICSharpCode.Decompiler/CodeMappings.cs @@ -201,9 +201,8 @@ namespace ICSharpCode.Decompiler /// Line number. /// Metadata token. /// - public static SourceCodeMapping GetInstructionByTypeAndLine( + public static SourceCodeMapping GetInstructionByLineNumber( this List codeMappings, - string memberReferenceName, int lineNumber, out uint metadataToken) { @@ -226,12 +225,11 @@ namespace ICSharpCode.Decompiler /// Gets a mapping given a type, a token and an IL offset. /// /// Code mappings storage. - /// Member reference name. /// Token. /// IL offset. /// True, if perfect match. /// A code mapping. - public static SourceCodeMapping GetInstructionByTypeTokenAndOffset( + public static SourceCodeMapping GetInstructionByTokenAndOffset( this List codeMappings, uint token, int ilOffset, diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs index e898ac86f..c9b6ea23a 100644 --- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs @@ -347,10 +347,8 @@ namespace ICSharpCode.Decompiler.Disassembler public void DisassembleType(TypeDefinition type) { // create IL code mappings - used for debugger - if (this.CodeMappings == null) { - this.CodeMappings.Add(type.FullName, new List()); - this.DecompiledMemberReferences.Add(type.FullName, type); - } + this.CodeMappings.Add(type.FullName, new List()); + this.DecompiledMemberReferences.Add(type.FullName, type); // start writing IL output.WriteDefinition(".class ", type); diff --git a/ILSpy/Options/DebuggerSettingsPanel.xaml b/ILSpy/Options/DebuggerSettingsPanel.xaml index 9b130bb38..27c24d0b6 100644 --- a/ILSpy/Options/DebuggerSettingsPanel.xaml +++ b/ILSpy/Options/DebuggerSettingsPanel.xaml @@ -5,9 +5,6 @@ Show warning messages - Debug whole types only \ No newline at end of file diff --git a/ILSpy/Options/DebuggerSettingsPanel.xaml.cs b/ILSpy/Options/DebuggerSettingsPanel.xaml.cs index 24b6b3766..ecc0fcbd2 100644 --- a/ILSpy/Options/DebuggerSettingsPanel.xaml.cs +++ b/ILSpy/Options/DebuggerSettingsPanel.xaml.cs @@ -21,8 +21,7 @@ namespace ICSharpCode.ILSpy.Options { private const string DEBUGGER_SETTINGS = "DebuggerSettings"; private const string SHOW_WARNINGS = "showWarnings"; - private const string DEBUG_WHOLE_TYPES_ONLY = "debugWholeTypesOnly"; - + public DebuggerSettingsPanel() { InitializeComponent(); @@ -46,7 +45,7 @@ namespace ICSharpCode.ILSpy.Options XElement e = settings[DEBUGGER_SETTINGS]; DebuggerSettings s = new DebuggerSettings(); s.ShowWarnings = (bool?)e.Attribute(SHOW_WARNINGS) ?? s.ShowWarnings; - s.DebugWholeTypesOnly = (bool?)e.Attribute(DEBUG_WHOLE_TYPES_ONLY) ?? s.DebugWholeTypesOnly; + return s; } @@ -55,7 +54,6 @@ namespace ICSharpCode.ILSpy.Options var s = (DebuggerSettings)this.DataContext; XElement section = new XElement(DEBUGGER_SETTINGS); section.SetAttributeValue(SHOW_WARNINGS, s.ShowWarnings); - section.SetAttributeValue(DEBUG_WHOLE_TYPES_ONLY, s.DebugWholeTypesOnly); XElement existingElement = root.Element(DEBUGGER_SETTINGS); if (existingElement != null) diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 5175003c4..5c29c9e03 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -380,11 +380,10 @@ namespace ICSharpCode.ILSpy.TextView isDecompilationOk = false; } finally { - + // sync bookmarks + iconMargin.SyncBookmarks(); // set the language DebugData.Language = MainWindow.Instance.sessionSettings.FilterSettings.Language.Name.StartsWith("IL") ? DecompiledLanguages.IL : DecompiledLanguages.CSharp; - bool debugOnlyTypes = DebuggerSettingsPanel.CurrentDebuggerSettings.DebugWholeTypesOnly; - DebugData.DebugWholeTypesOnly = debugOnlyTypes; if (isDecompilationOk) { if (DebugData.DecompiledMemberReferences != null && DebugData.DecompiledMemberReferences.Count > 0) {