diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/BreakPointsPad.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/BreakPointsPad.cs index 2cb6ce9279..c93bc25bfb 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/BreakPointsPad.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/BreakPointsPad.cs @@ -1,8 +1,10 @@ // Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) +using System; using System.Windows; using System.Windows.Controls; + using Debugger; using Debugger.AddIn.Pads.Controls; using ICSharpCode.Core; @@ -26,7 +28,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads CreateColumns(); } - + void InitializeComponents() { debugger = (WindowsDebugger)DebuggerService.CurrentDebugger; @@ -52,7 +54,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads return toolbar; } - protected override void CreateColumns() + protected override void CreateColumns() { string conditionHeader = StringParser.Parse("${res:MainWindow.Windows.Debug.Conditional.Breakpoints.ConditionalColumnHeader}"); @@ -66,5 +68,29 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads { return mark.IsVisibleInBookmarkPad && mark is BreakpointBookmark; } + + protected override void OnItemActivated(object sender, EventArgs e) + { + var node = CurrentItem; + if (node == null) + return; + SDBookmark mark = node.Mark as SDBookmark; + if (mark == null) + return; + + string fileName = mark.FileName; + if (mark is DecompiledBreakpointBookmark) { + // get information from breakpoint and navigate to the decompiled type + string assemblyFile, typeName; + if (DecompiledBreakpointBookmark.GetAssemblyAndType(fileName, out assemblyFile, out typeName)) { + NavigationService.NavigateTo(assemblyFile, typeName, string.Empty, mark.LineNumber, false); + } + } else { + // jump to normal breakpoint + FileService.JumpToFilePosition(fileName, mark.LineNumber, 1); + + // TODO: if other types of breakpoint bookmarks are available, one should do jumping/navigation here + } + } } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs index 3fc040a62d..cacfef1084 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs @@ -2,7 +2,6 @@ // This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) using System; -using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.IO; @@ -583,7 +582,7 @@ namespace ICSharpCode.SharpDevelop.Services var stackFrame = !debuggedProcess.IsInExternalCode ? debuggedProcess.SelectedStackFrame : debuggedProcess.SelectedThread.MostRecentStackFrame; try { - object data = debuggerDecompilerService.GetLocalVariableIndex(stackFrame.MethodInfo.DeclaringType.MetadataToken, + object data = debuggerDecompilerService.GetLocalVariableIndex(stackFrame.MethodInfo.DeclaringType.MetadataToken, stackFrame.MethodInfo.MetadataToken, variableName); // evaluate expression @@ -723,7 +722,7 @@ namespace ICSharpCode.SharpDevelop.Services // init NDebugger debugger = new NDebugger(); - debugger.Options = DebuggingOptions.Instance; + debugger.Options = DebuggingOptions.Instance; debugger.DebuggerTraceMessage += debugger_TraceMessage; debugger.Processes.Added += debugger_ProcessStarted; debugger.Processes.Removed += debugger_ProcessExited; @@ -755,29 +754,42 @@ namespace ICSharpCode.SharpDevelop.Services Breakpoint breakpoint = null; if (bookmark is DecompiledBreakpointBookmark) { - var dbb = (DecompiledBreakpointBookmark)bookmark; - var memberReference = dbb.MemberReference; - int token = memberReference.MetadataToken.ToInt32(); - - if (!debuggerDecompilerService.CheckMappings(token)) - debuggerDecompilerService.DecompileOnDemand(memberReference as TypeDefinition); - - int[] ilRanges; - int methodToken; - if (debuggerDecompilerService.GetILAndTokenByLineNumber(token, dbb.LineNumber, out ilRanges, out methodToken)) { - dbb.ILFrom = ilRanges[0]; - dbb.ILTo = ilRanges[1]; - // create BP - breakpoint = new ILBreakpoint( - debugger, - dbb.MemberReference.FullName, - dbb.LineNumber, - memberReference.MetadataToken.ToInt32(), - methodToken, - dbb.ILFrom, - dbb.IsEnabled); + try { + if (debuggerDecompilerService == null) { + LoggingService.Warn("No IDebuggerDecompilerService found!"); + return; + } + var dbb = (DecompiledBreakpointBookmark)bookmark; + MemberReference memberReference = null; - debugger.Breakpoints.Add(breakpoint); + string assemblyFile, typeName; + if (DecompiledBreakpointBookmark.GetAssemblyAndType(dbb.FileName, out assemblyFile, out typeName)) { + memberReference = dbb.GetMemberReference(debuggerDecompilerService.GetAssemblyResolver(assemblyFile)); + } + + int token = memberReference.MetadataToken.ToInt32(); + if (!debuggerDecompilerService.CheckMappings(token)) + debuggerDecompilerService.DecompileOnDemand(memberReference as TypeDefinition); + + int[] ilRanges; + int methodToken; + if (debuggerDecompilerService.GetILAndTokenByLineNumber(token, dbb.LineNumber, out ilRanges, out methodToken)) { + dbb.ILFrom = ilRanges[0]; + dbb.ILTo = ilRanges[1]; + // create BP + breakpoint = new ILBreakpoint( + debugger, + memberReference.FullName, + dbb.LineNumber, + memberReference.MetadataToken.ToInt32(), + methodToken, + dbb.ILFrom, + dbb.IsEnabled); + + debugger.Breakpoints.Add(breakpoint); + } + } catch (System.Exception ex) { + LoggingService.Error("Error on DecompiledBreakpointBookmark: " + ex.Message); } } else { breakpoint = debugger.Breakpoints.Add(bookmark.FileName, null, bookmark.LineNumber, 0, bookmark.IsEnabled); @@ -1038,56 +1050,49 @@ namespace ICSharpCode.SharpDevelop.Services DebuggerService.JumpToCurrentLine(nextStatement.Filename, nextStatement.StartLine, nextStatement.StartColumn, nextStatement.EndLine, nextStatement.EndColumn); } } else { - if (debuggerDecompilerService == null) { - LoggingService.Warn("No IDebuggerDecompilerService found!"); - return; - } - // use most recent stack frame because we don't have the symbols - var frame = debuggedProcess.SelectedThread.MostRecentStackFrame; - if (frame == null) - return; - int typeToken = frame.MethodInfo.DeclaringType.MetadataToken; - - // get external data - int methodToken = frame.MethodInfo.MetadataToken; - int ilOffset = frame.IP; - - int[] ilRanges = null; - int line = -1; - bool isMatch = false; - if (debuggerDecompilerService.GetILAndLineNumber(typeToken, methodToken, ilOffset, out ilRanges, out line, out isMatch)) { - debuggerDecompilerService.DebugStepInformation = null; // we do not need to step into/out - - // update marker - var debugType = (DebugType)frame.MethodInfo.DeclaringType; - - foreach (dynamic vc in WorkbenchSingleton.Workbench.ViewContentCollection.OfType()) { - if (vc == null || vc.MemberReference == null) - continue; - - if (vc.MemberReference.MetadataToken.ToInt32() == debugType.MetadataToken) { - CurrentLineBookmark.SetPosition(vc, line, 0, line, 0); - var wbw = vc.WorkbenchWindow as IWorkbenchWindow; - if (wbw != null) - wbw.SelectWindow(); - return; - } - } - // the decompiled content was closed so we have to recreate it - StepIntoUnknownFrame(frame, methodToken, ilOffset); - } else { - StepIntoUnknownFrame(frame, methodToken, ilOffset); - } - + JumpToDecompiledCode(); } } - - void StepIntoUnknownFrame(Debugger.StackFrame frame, int token, int ilOffset) + + void JumpToDecompiledCode() { + if (debuggerDecompilerService == null) { + LoggingService.Warn("No IDebuggerDecompilerService found!"); + return; + } + + // check for options - if these options are enabled, debugging decompiled code should not continue + if (debuggedProcess.Options.EnableJustMyCode || debuggedProcess.Options.StepOverNoSymbols) { + LoggingService.Info("Decompiled code debugging is disabled!"); + return; + } + + // use most recent stack frame because we don't have the symbols + var frame = debuggedProcess.SelectedThread.MostRecentStackFrame; + Debug.Assert(frame != null); + + // get external data + int typeToken = frame.MethodInfo.DeclaringType.MetadataToken; + int methodToken = frame.MethodInfo.MetadataToken; + int ilOffset = frame.IP; + int[] ilRanges = null; + int line = -1; + bool isMatch = false; var debugType = (DebugType)frame.MethodInfo.DeclaringType; - string fullName = debugType.FullNameWithoutGenericArguments; - debuggerDecompilerService.DebugStepInformation = Tuple.Create(token, ilOffset); - NavigationService.NavigateTo(debugType.DebugModule.FullPath, debugType.FullNameWithoutGenericArguments, string.Empty); + debuggerDecompilerService.DebugStepInformation = Tuple.Create(methodToken, ilOffset); + + if (debuggerDecompilerService.GetILAndLineNumber(typeToken, methodToken, ilOffset, out ilRanges, out line, out isMatch)) { + // update marker & navigate to line + NavigationService.NavigateTo(debugType.DebugModule.FullPath, + debugType.FullNameWithoutGenericArguments, + string.Empty, + line); + } else { + // no line => do decompilation + NavigationService.NavigateTo(debugType.DebugModule.FullPath, + debugType.FullNameWithoutGenericArguments, + string.Empty); + } } StopAttachedProcessDialogResult ShowStopAttachedProcessDialog() diff --git a/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs index e7ff56f130..84c701c218 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs @@ -105,8 +105,7 @@ namespace Debugger.AddIn.Tooltips if (provider != null) { editor = provider.TextEditor; } else { - dynamic codeView = viewContent.Control; - editor = codeView.TextEditor as ITextEditor; + editor = viewContent.GetService(typeof(ITextEditor)) as ITextEditor; } if (editor != null) { diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/IconBarMargin.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/IconBarMargin.cs index 417fe4e2c2..69ebc08bb2 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/IconBarMargin.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/IconBarMargin.cs @@ -238,14 +238,16 @@ namespace ICSharpCode.AvalonEdit.AddIn DebuggerService.ToggleBreakpointAt(textEditor, line); return; } - // create breakpoint for the decompiled content - dynamic viewContent = WorkbenchSingleton.Workbench.ActiveContent; - if (viewContent is AbstractViewContentWithoutFile) { - dynamic codeView = ((AbstractViewContentWithoutFile)viewContent).Control; - var editor = codeView.TextEditor as ITextEditor; - var memberReference = viewContent.MemberReference as MemberReference; - if (editor != null && !string.IsNullOrEmpty(editor.FileName)) - DebuggerService.ToggleBreakpointAt(memberReference, editor, line); + + // create breakpoint for the other posible active contents + var viewContent = WorkbenchSingleton.Workbench.ActiveContent as AbstractViewContentWithoutFile; + if (viewContent != null && viewContent.Tag is MemberReference) { + var memberReference = (MemberReference)viewContent.Tag; + textEditor = viewContent.Services.GetService(typeof(ITextEditor)) as ITextEditor; + if (textEditor != null) { + DebuggerService.ToggleBreakpointAt(memberReference, textEditor, line); + return; + } } } } diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerDecompilerService.cs b/src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerDecompilerService.cs index 5ca6f051e8..970c71efc3 100644 --- a/src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerDecompilerService.cs +++ b/src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerDecompilerService.cs @@ -3,10 +3,12 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.IO; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Ast; using ICSharpCode.Decompiler.ILAst; +using ICSharpCode.ILSpyAddIn.LaunchILSpy; using ICSharpCode.SharpDevelop.Debugging; using Mono.Cecil; @@ -17,6 +19,8 @@ namespace ICSharpCode.ILSpyAddIn /// public class DebuggerDecompilerService : IDebuggerDecompilerService { + ILSpyAssemblyResolver resolver; + static DebuggerDecompilerService() { DebugInformation = new ConcurrentDictionary(); @@ -166,5 +170,20 @@ namespace ICSharpCode.ILSpyAddIn return null; } + + public IAssemblyResolver GetAssemblyResolver(string assemblyFile) + { + if (string.IsNullOrEmpty(assemblyFile)) + throw new ArgumentException("assemblyFile is null or empty"); + + string folderPath = Path.GetDirectoryName(assemblyFile); + if (resolver == null) + return (resolver = new ILSpyAssemblyResolver(folderPath)); + + if (string.Compare(folderPath, resolver.FolderPath, StringComparison.OrdinalIgnoreCase) != 0) + return (resolver = new ILSpyAssemblyResolver(folderPath)); + + return resolver; + } } } diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/LaunchILSpy/ILSpyAssemblyResolver.cs b/src/AddIns/DisplayBindings/ILSpyAddIn/LaunchILSpy/ILSpyAssemblyResolver.cs index ce08da724b..6de60e61eb 100644 --- a/src/AddIns/DisplayBindings/ILSpyAddIn/LaunchILSpy/ILSpyAssemblyResolver.cs +++ b/src/AddIns/DisplayBindings/ILSpyAddIn/LaunchILSpy/ILSpyAssemblyResolver.cs @@ -22,10 +22,15 @@ namespace ICSharpCode.ILSpyAddIn.LaunchILSpy if (string.IsNullOrEmpty(decompiledAssemblyFolder)) throw new ArgumentException("Invalid working folder"); + FolderPath = decompiledAssemblyFolder; this.directoryInfo = new DirectoryInfo(decompiledAssemblyFolder); this.cache = new Dictionary (); } + public string FolderPath { + get; private set; + } + public AssemblyDefinition Resolve(AssemblyNameReference name) { return this.Resolve(name, new ReaderParameters()); diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/NavigateToDecompiledEntityService.cs b/src/AddIns/DisplayBindings/ILSpyAddIn/NavigateToDecompiledEntityService.cs index 86ab9d5fbd..b83afcbf6e 100644 --- a/src/AddIns/DisplayBindings/ILSpyAddIn/NavigateToDecompiledEntityService.cs +++ b/src/AddIns/DisplayBindings/ILSpyAddIn/NavigateToDecompiledEntityService.cs @@ -48,29 +48,45 @@ namespace ICSharpCode.ILSpyAddIn if (string.IsNullOrEmpty(typeName)) throw new ArgumentException("typeName is null or empty"); - foreach (var vc in WorkbenchSingleton.Workbench.ViewContentCollection.OfType()) { - if (string.Equals(vc.AssemblyFile, assemblyFile, StringComparison.OrdinalIgnoreCase) && typeName == vc.FullTypeName) { - vc.WorkbenchWindow.SelectWindow(); - vc.JumpToEntity(entityTag); + foreach (var viewContent in WorkbenchSingleton.Workbench.ViewContentCollection.OfType()) { + if (string.Equals(viewContent.AssemblyFile, assemblyFile, StringComparison.OrdinalIgnoreCase) && typeName == viewContent.FullTypeName) { + viewContent.WorkbenchWindow.SelectWindow(); + viewContent.JumpToEntity(entityTag); return; } } WorkbenchSingleton.Workbench.ShowView(new DecompiledViewContent(assemblyFile, typeName, entityTag)); } - public bool NavigateToMember(string assemblyFile, string typeName, string entityTag, int lineNumber) + public bool NavigateToMember(string assemblyFile, string typeName, string entityTag, int lineNumber, bool updateMarker) { - //close the window if exists - this is a workaround - foreach (var vc in WorkbenchSingleton.Workbench.ViewContentCollection.OfType()) { - if (string.Equals(vc.AssemblyFile, assemblyFile, StringComparison.OrdinalIgnoreCase) && typeName == vc.FullTypeName) { - vc.WorkbenchWindow.CloseWindow(true); - break; + if (string.IsNullOrEmpty(assemblyFile)) + throw new ArgumentException("assemblyFile is null or empty"); + + if (string.IsNullOrEmpty(typeName)) + throw new ArgumentException("typeName is null or empty"); + + // jump to line number if the decompiled view content exits - no need for a new decompilation + foreach (var viewContent in WorkbenchSingleton.Workbench.ViewContentCollection.OfType()) { + if (string.Equals(viewContent.AssemblyFile, assemblyFile, StringComparison.OrdinalIgnoreCase) && typeName == viewContent.FullTypeName) { + if (updateMarker) { + viewContent.UpdateDebuggingUI(); + } + viewContent.JumpToLineNumber(lineNumber); + viewContent.WorkbenchWindow.SelectWindow(); + return true; } } - var view = new DecompiledViewContent(assemblyFile, typeName, entityTag); - view.DecompilationFinished += delegate { view.JumpTo(lineNumber); }; - WorkbenchSingleton.Workbench.ShowView(view); + // create a new decompiled view + var decompiledView = new DecompiledViewContent(assemblyFile, typeName, entityTag); + decompiledView.DecompilationFinished += delegate { + if (updateMarker) { + decompiledView.UpdateDebuggingUI(); + } + decompiledView.JumpToLineNumber(lineNumber); + }; + WorkbenchSingleton.Workbench.ShowView(decompiledView); return true; } } diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/CodeView.cs b/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/CodeView.cs index ed0b494bb0..bb1498f052 100644 --- a/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/CodeView.cs +++ b/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/CodeView.cs @@ -25,17 +25,17 @@ namespace ICSharpCode.ILSpyAddIn.ViewContent public DecompiledTextEditorAdapter(TextEditor textEditor) : base(textEditor) {} - public string DecompiledFullTypeName { get; set; } + public string DecompiledFileName { get; set; } public override ICSharpCode.Core.FileName FileName { - get { return ICSharpCode.Core.FileName.Create(DecompiledFullTypeName); } + get { return ICSharpCode.Core.FileName.Create(DecompiledFileName); } } } /// /// Equivalent to AE.AddIn CodeEditor, but without editing capabilities. /// - public class CodeView : Grid, IDisposable, ICodeEditor + class CodeView : Grid, IDisposable, ICodeEditor { public event EventHandler DocumentChanged; @@ -44,11 +44,10 @@ namespace ICSharpCode.ILSpyAddIn.ViewContent readonly IconBarMargin iconMargin; readonly TextMarkerService textMarkerService; - public CodeView(string decompiledFullTypeName) + public CodeView(string decompiledFileName) { - DecompiledFullTypeName = decompiledFullTypeName; this.adapter = new DecompiledTextEditorAdapter(new SharpDevelopTextEditor { IsReadOnly = true }) { - DecompiledFullTypeName = decompiledFullTypeName + DecompiledFileName = decompiledFileName }; this.Children.Add(adapter.TextEditor); adapter.TextEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#"); @@ -64,6 +63,7 @@ namespace ICSharpCode.ILSpyAddIn.ViewContent this.adapter.TextEditor.TextArea.TextView.LineTransformers.Add(textMarkerService); this.adapter.TextEditor.TextArea.TextView.Services.AddService(typeof(ITextMarkerService), textMarkerService); this.adapter.TextEditor.TextArea.TextView.Services.AddService(typeof(IBookmarkMargin), iconBarManager); + // DON'T add the editor in textview ervices - will mess the setting of breakpoints // add events this.adapter.TextEditor.MouseHover += TextEditorMouseHover; @@ -230,16 +230,6 @@ namespace ICSharpCode.ILSpyAddIn.ViewContent get { return iconBarManager; } } - public AvalonEditTextEditorAdapter Adapter { - get { - return adapter; - } - } - - public string DecompiledFullTypeName { - get; private set; - } - public void Dispose() { } @@ -249,9 +239,9 @@ namespace ICSharpCode.ILSpyAddIn.ViewContent if (lineNumber <= 0 || lineNumber > adapter.Document.TotalNumberOfLines) return; - //var line = adapter.TextEditor.Document.GetLineByNumber(lineNumber); +// var line = adapter.TextEditor.Document.GetLineByNumber(lineNumber); - // unfold +// // unfold // var foldings = foldingManager.GetFoldingsContaining(line.Offset); // if (foldings != null) { // foreach (var folding in foldings) { @@ -260,6 +250,7 @@ namespace ICSharpCode.ILSpyAddIn.ViewContent // } // } // } + // scroll to adapter.TextEditor.ScrollTo(lineNumber, 0); } diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs b/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs index b3b38cfc88..75b2faa3d1 100644 --- a/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs +++ b/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs @@ -16,6 +16,7 @@ using ICSharpCode.NRefactory.Utils; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Bookmarks; using ICSharpCode.SharpDevelop.Debugging; +using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Gui; using Mono.Cecil; @@ -24,7 +25,7 @@ namespace ICSharpCode.ILSpyAddIn /// /// Hosts a decompiled type. /// - public class DecompiledViewContent : AbstractViewContentWithoutFile + class DecompiledViewContent : AbstractViewContentWithoutFile { readonly string assemblyFile; readonly string fullTypeName; @@ -43,14 +44,17 @@ namespace ICSharpCode.ILSpyAddIn #region Constructor public DecompiledViewContent(string assemblyFile, string fullTypeName, string entityTag) { - codeView = new CodeView(string.Format("{0},{1}", assemblyFile, fullTypeName)); + // TODO: create options for decompiling in a specific language + this.tempFileName = string.Format("{0}{1}{2}.cs", assemblyFile, DecompiledBreakpointBookmark.SEPARATOR, fullTypeName); + this.codeView = new CodeView(tempFileName); + this.assemblyFile = assemblyFile; this.fullTypeName = fullTypeName; this.jumpToEntityTagWhenDecompilationFinished = entityTag; string shortTypeName = fullTypeName.Substring(fullTypeName.LastIndexOf('.') + 1); this.TitleName = "[" + shortTypeName + "]"; - tempFileName = string.Format("decompiled/{0}.cs", fullTypeName); + this.InfoTip = tempFileName; Thread thread = new Thread(DecompilationThread); @@ -59,6 +63,9 @@ namespace ICSharpCode.ILSpyAddIn BookmarkManager.Removed += BookmarkManager_Removed; BookmarkManager.Added += BookmarkManager_Added; + + // add services + this.Services.AddService(typeof(ITextEditor), this.codeView.TextEditor); } #endregion @@ -83,6 +90,10 @@ namespace ICSharpCode.ILSpyAddIn get; private set; } + public override object Tag { + get { return MemberReference; } + } + #endregion #region Dispose @@ -194,9 +205,8 @@ namespace ICSharpCode.ILSpyAddIn // update UI UpdateIconMargin(output.ToString()); - UpdateDebuggingUI(); - // fire event + // fire events OnDecompilationFinished(EventArgs.Empty); } #endregion @@ -207,56 +217,73 @@ namespace ICSharpCode.ILSpyAddIn codeView.IconBarManager.UpdateClassMemberBookmarks(ParserService.ParseFile(tempFileName, new StringTextBuffer(text))); // load bookmarks - foreach (SDBookmark bookmark in BookmarkManager.GetBookmarks(codeView.Adapter.FileName)) { - bookmark.Document = codeView.Adapter.Document; + foreach (SDBookmark bookmark in BookmarkManager.GetBookmarks(this.codeView.TextEditor.FileName)) { + bookmark.Document = this.codeView.TextEditor.Document; codeView.IconBarManager.Bookmarks.Add(bookmark); } } - void UpdateDebuggingUI() + public void UpdateDebuggingUI() { if (!DebuggerService.IsDebuggerStarted) return; if (MemberReference == null || MemberReference.MetadataToken == null) return; - int typeToken = MemberReference.MetadataToken.ToInt32(); + int typeToken = MemberReference.MetadataToken.ToInt32(); if (!DebuggerDecompilerService.DebugInformation.ContainsKey(typeToken)) return; - if (DebuggerDecompilerService.Instance == null || DebuggerDecompilerService.Instance.DebugStepInformation == null) + var decompilerService = DebuggerDecompilerService.Instance; + if (decompilerService == null || decompilerService.DebugStepInformation == null) return; // get debugging information DecompileInformation debugInformation = (DecompileInformation)DebuggerDecompilerService.DebugInformation[typeToken]; - int token = DebuggerDecompilerService.Instance.DebugStepInformation.Item1; - int ilOffset = DebuggerDecompilerService.Instance.DebugStepInformation.Item2; + int methodToken = decompilerService.DebugStepInformation.Item1; + int ilOffset = decompilerService.DebugStepInformation.Item2; int line; MemberReference member; - if (debugInformation.CodeMappings == null || !debugInformation.CodeMappings.ContainsKey(token)) + if (debugInformation.CodeMappings == null || !debugInformation.CodeMappings.ContainsKey(methodToken)) return; - debugInformation.CodeMappings[token].GetInstructionByTokenAndOffset(token, ilOffset, out member, out line); + debugInformation.CodeMappings[methodToken].GetInstructionByTokenAndOffset(methodToken, ilOffset, out member, out line); - // HACK : if the codemappings are not built + // if the codemappings are not built if (line <= 0) { DebuggerService.CurrentDebugger.StepOver(); return; } - // update bookmark & marker - codeView.UnfoldAndScroll(line); - CurrentLineBookmark.SetPosition(this, line, 0, line, 0); + + // jump to line - scoll and unfold + this.UpdateCurrentLineBookmark(line); + this.JumpToLineNumber(line); } - public void JumpTo(int lineNumber) - { - if (codeView == null) + public void JumpToLineNumber(int lineNumber) + { + if (codeView == null || codeView.Document == null) return; if (lineNumber <= 0 || lineNumber > codeView.Document.LineCount) return; - + codeView.UnfoldAndScroll(lineNumber); } + + void UpdateCurrentLineBookmark(int lineNumber) + { + if (lineNumber <= 0) + return; + + CurrentLineBookmark.SetPosition(codeView.TextEditor.FileName, codeView.TextEditor.Document, lineNumber, 0, lineNumber, 0); + var currentLineBookmark = BookmarkManager.Bookmarks.OfType().FirstOrDefault(); + if (currentLineBookmark != null) { + // update bookmark & marker + codeView.IconBarManager.Bookmarks.Add(currentLineBookmark); + currentLineBookmark.Document = this.codeView.TextEditor.Document; + } + } + #endregion #region Bookmarks @@ -272,14 +299,15 @@ namespace ICSharpCode.ILSpyAddIn void BookmarkManager_Added(object sender, BookmarkEventArgs e) { var mark = e.Bookmark; - if (mark != null && mark is BreakpointBookmark && mark.FileName == codeView.DecompiledFullTypeName) { + if (mark != null && mark is BreakpointBookmark && mark.FileName == this.codeView.TextEditor.FileName) { codeView.IconBarManager.Bookmarks.Add(mark); - mark.Document = codeView.Adapter.Document; + mark.Document = this.codeView.TextEditor.Document; } } #endregion #region Events + public event EventHandler DecompilationFinished; protected virtual void OnDecompilationFinished(EventArgs e) @@ -288,6 +316,7 @@ namespace ICSharpCode.ILSpyAddIn DecompilationFinished(this, e); } } + #endregion } } diff --git a/src/Main/Base/Project/Src/Bookmarks/Pad/BookmarkPad.cs b/src/Main/Base/Project/Src/Bookmarks/Pad/BookmarkPad.cs index 9aa41fc6c7..099fcb56da 100644 --- a/src/Main/Base/Project/Src/Bookmarks/Pad/BookmarkPad.cs +++ b/src/Main/Base/Project/Src/Bookmarks/Pad/BookmarkPad.cs @@ -72,14 +72,14 @@ namespace ICSharpCode.SharpDevelop.Bookmarks listView.SetValue(Grid.RowProperty, 1); myPanel.Children.Add(listView); - BookmarkManager.Added += new BookmarkEventHandler(BookmarkManagerAdded); - BookmarkManager.Removed += new BookmarkEventHandler(BookmarkManagerRemoved); + BookmarkManager.Added += BookmarkManagerAdded; + BookmarkManager.Removed += BookmarkManagerRemoved; foreach (SDBookmark mark in BookmarkManager.Bookmarks) { AddMark(mark); } - listView.ItemActivated += new EventHandler(listView_ItemActivated); + listView.ItemActivated += new EventHandler(OnItemActivated); } public IEnumerable AllItems { @@ -120,6 +120,12 @@ namespace ICSharpCode.SharpDevelop.Bookmarks listView.CurrentItem = model; } + public override void Dispose() + { + BookmarkManager.Added -= BookmarkManagerAdded; + BookmarkManager.Removed -= BookmarkManagerRemoved; + } + void AddMark(SDBookmark mark) { if (!ShowBookmarkInThisPad(mark)) @@ -133,6 +139,17 @@ namespace ICSharpCode.SharpDevelop.Bookmarks return mark.IsVisibleInBookmarkPad && !(mark is BreakpointBookmark); } + protected virtual void OnItemActivated(object sender, EventArgs e) + { + var node = CurrentItem; + if (node != null) { + SDBookmark mark = node.Mark as SDBookmark; + if (mark != null) { + FileService.JumpToFilePosition(mark.FileName, mark.LineNumber, 1); + } + } + } + void BookmarkManagerAdded(object sender, BookmarkEventArgs e) { AddMark((SDBookmark)e.Bookmark); @@ -143,16 +160,5 @@ namespace ICSharpCode.SharpDevelop.Bookmarks if (ShowBookmarkInThisPad(e.Bookmark)) listView.Remove(new ListViewPadItemModel(e.Bookmark)); } - - void listView_ItemActivated(object sender, EventArgs e) - { - var node = CurrentItem; - if (node != null) { - SDBookmark mark = node.Mark as SDBookmark; - if (mark != null) { - FileService.JumpToFilePosition(mark.FileName, mark.LineNumber, 1); - } - } - } } } diff --git a/src/Main/Base/Project/Src/Gui/AbstractViewContentWithoutFile.cs b/src/Main/Base/Project/Src/Gui/AbstractViewContentWithoutFile.cs index c7e7340f2c..274e5d58f9 100644 --- a/src/Main/Base/Project/Src/Gui/AbstractViewContentWithoutFile.cs +++ b/src/Main/Base/Project/Src/Gui/AbstractViewContentWithoutFile.cs @@ -16,6 +16,13 @@ namespace ICSharpCode.SharpDevelop.Gui /// public abstract class AbstractViewContentWithoutFile : AbstractViewContent, ICustomizedCommands { + /// + /// Gets specific information (from implementations) regarding this view content. + /// + public virtual object Tag { + get { return null; } + } + public override bool IsViewOnly { get { return false; } } diff --git a/src/Main/Base/Project/Src/Services/Debugger/CurrentLineBookmark.cs b/src/Main/Base/Project/Src/Services/Debugger/CurrentLineBookmark.cs index 6a34d81c38..fbfd2a379f 100644 --- a/src/Main/Base/Project/Src/Services/Debugger/CurrentLineBookmark.cs +++ b/src/Main/Base/Project/Src/Services/Debugger/CurrentLineBookmark.cs @@ -22,24 +22,11 @@ namespace ICSharpCode.SharpDevelop.Debugging static int endLine; static int endColumn; - public static void SetPosition(IViewContent viewContent, int markerStartLine, int markerStartColumn, int markerEndLine, int markerEndColumn) + public static void SetPosition(IViewContent viewContent, int markerStartLine, int markerStartColumn, int markerEndLine, int markerEndColumn) { ITextEditorProvider tecp = viewContent as ITextEditorProvider; if (tecp != null) { SetPosition(tecp.TextEditor.FileName, tecp.TextEditor.Document, markerStartLine, markerStartColumn, markerEndLine, markerEndColumn); - } else { - lock (syncObject) { - // get the decompiled view if exists - if (viewContent != null && viewContent.Control != null) { - dynamic codeView = viewContent.Control; - var document = codeView.TextEditor.Document as IDocument; - SetPosition(codeView.Adapter.FileName, document, markerStartLine, markerStartColumn, markerEndLine, markerEndColumn); - codeView.IconBarManager.Bookmarks.Add(CurrentLineBookmark.instance); - codeView.UnfoldAndScroll(markerStartLine); - if (document != null) - CurrentLineBookmark.instance.Document = document; - } - } } } diff --git a/src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs b/src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs index 55a3670e7c..b6cbc79038 100644 --- a/src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs +++ b/src/Main/Base/Project/Src/Services/Debugger/DebuggerService.cs @@ -479,5 +479,12 @@ namespace ICSharpCode.SharpDevelop.Debugging /// Gets the local variable index. /// object GetLocalVariableIndex(int typeToken, int memberToken, string name); + + /// + /// Gets an implementation of an assembly resolver. + /// + /// Assembly file path. + /// An . + IAssemblyResolver GetAssemblyResolver(string assemblyFile); } } diff --git a/src/Main/Base/Project/Src/Services/Debugger/DecompiledBreakpointBookmark.cs b/src/Main/Base/Project/Src/Services/Debugger/DecompiledBreakpointBookmark.cs index d67f99b952..72a6273c10 100644 --- a/src/Main/Base/Project/Src/Services/Debugger/DecompiledBreakpointBookmark.cs +++ b/src/Main/Base/Project/Src/Services/Debugger/DecompiledBreakpointBookmark.cs @@ -10,9 +10,14 @@ namespace ICSharpCode.SharpDevelop.Bookmarks { public class DecompiledBreakpointBookmark : BreakpointBookmark { + public const string SEPARATOR = ","; // don't use '.' + + MemberReference memberReference; + string assemblyFile; + public DecompiledBreakpointBookmark(MemberReference member, int ilFrom, int ilTo, FileName fileName, Location location, BreakpointAction action, string scriptLanguage, string script) : base(fileName, location, action, scriptLanguage, script) { - this.MemberReference = member; + this.memberReference = member; this.ILFrom = ilFrom; this.ILTo = ILTo; } @@ -25,32 +30,52 @@ namespace ICSharpCode.SharpDevelop.Bookmarks get; set; } - MemberReference memberReference; - public MemberReference MemberReference { - get { - if (memberReference != null) - return memberReference; - - // reload from filename - ReaderParameters readerParameters = new ReaderParameters(); - // Use new assembly resolver instance so that the AssemblyDefinitions can be garbage-collected - // once the code is decompiled. - readerParameters.AssemblyResolver = new DefaultAssemblyResolver(); - - string fileName = FileName.ToString(); - int index = fileName.IndexOf(","); - string assemblyFile = fileName.Substring(0, index); - string fullTypeName = fileName.Substring(index + 1, fileName.Length - index - 1); - + get { return memberReference; } + } + + public MemberReference GetMemberReference(IAssemblyResolver resolver) + { + if (resolver == null) + throw new ArgumentNullException("resolver"); + + if (memberReference != null) + return memberReference; + + // reload from filename + ReaderParameters readerParameters = new ReaderParameters(); + // Use new assembly resolver instance so that the AssemblyDefinitions can be garbage-collected + // once the code is decompiled. + readerParameters.AssemblyResolver = resolver; + + string typeName; + if (GetAssemblyAndType(FileName.ToString(), out assemblyFile, out typeName)) { ModuleDefinition module = ModuleDefinition.ReadModule(assemblyFile, readerParameters); - TypeDefinition typeDefinition = module.GetType(fullTypeName); + TypeDefinition typeDefinition = module.GetType(typeName); if (typeDefinition == null) throw new InvalidOperationException("Could not find type"); memberReference = typeDefinition; - return memberReference; } - private set { memberReference = value; } + + return memberReference; + } + + /// + /// Gets the assembly file and the type from the file name. + /// + /// true, if the operation succeded; false, otherwise. + public static bool GetAssemblyAndType(string fileName, out string assemblyFile, out string typeName) + { + if (string.IsNullOrEmpty(fileName) || !fileName.Contains(",")) { + assemblyFile = null; + typeName = null; + return false; + } + + int index = fileName.IndexOf(SEPARATOR); + assemblyFile = fileName.Substring(0, index); + typeName = fileName.Substring(index + 1, fileName.Length - index - 4); + return true; } } } diff --git a/src/Main/Base/Project/Src/Services/File/FileService.cs b/src/Main/Base/Project/Src/Services/File/FileService.cs index 17529f3103..a073d950b8 100644 --- a/src/Main/Base/Project/Src/Services/File/FileService.cs +++ b/src/Main/Base/Project/Src/Services/File/FileService.cs @@ -533,15 +533,6 @@ namespace ICSharpCode.SharpDevelop bool loggingResumed = false; try { - // jump to decompiled type from filename - if (fileName.Contains(",")) { - int index = fileName.IndexOf(","); - string assemblyName = fileName.Substring(0, index); - string typeName = fileName.Substring(index + 1, fileName.Length - index - 1); - NavigationService.NavigateTo(assemblyName, typeName, string.Empty, line); - return null; - } - IViewContent content = OpenFile(fileName); if (content is IPositionable) { // TODO: enable jumping to a particular view diff --git a/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs b/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs index 0712af2204..e41a1c43ce 100644 --- a/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs +++ b/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Project; -using Mono.Cecil; namespace ICSharpCode.SharpDevelop { @@ -475,7 +474,7 @@ namespace ICSharpCode.SharpDevelop #region Navigate to Member - public static bool NavigateTo(string assemblyFile, string typeName, string entityTag, int lineNumber = 0) + public static bool NavigateTo(string assemblyFile, string typeName, string entityTag, int lineNumber = 0, bool updateMarker = true) { if (string.IsNullOrEmpty(assemblyFile)) throw new ArgumentException("assemblyFile is null or empty"); @@ -484,7 +483,7 @@ namespace ICSharpCode.SharpDevelop throw new ArgumentException("typeName is null or empty"); foreach (var item in AddInTree.BuildItems("/SharpDevelop/Services/NavigateToEntityService", null, false)) { - if (item.NavigateToMember(assemblyFile, typeName, entityTag, lineNumber)) + if (item.NavigateToMember(assemblyFile, typeName, entityTag, lineNumber, updateMarker)) return true; } return false; @@ -512,6 +511,6 @@ namespace ICSharpCode.SharpDevelop /// public interface INavigateToMemberService { - bool NavigateToMember(string assemblyFile, string typeName, string entityTag, int lineNumber); + bool NavigateToMember(string assemblyFile, string typeName, string entityTag, int lineNumber, bool updateMarker); } }