diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.addin b/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.addin
index 486a48a727..19a2adb926 100644
--- a/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.addin
+++ b/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.addin
@@ -12,7 +12,11 @@
-
+
+
+
+
+
diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.csproj b/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.csproj
index 51a0e4026e..e2d4ae0e46 100644
--- a/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.csproj
+++ b/src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.csproj
@@ -40,17 +40,30 @@
+
+ 3.0
+
+
+ 3.0
+
3.5
+
+ 4.0
+
+
+ 3.0
+
Properties\GlobalAssemblyInfo.cs
+
@@ -58,6 +71,8 @@
SetILSpyPathDialog.cs
+
+
SetILSpyPathDialog.cs
@@ -66,6 +81,11 @@
+
+ {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}
+ ICSharpCode.AvalonEdit
+ False
+
{984CC812-9470-4A13-AFF9-CC44068D666C}
ICSharpCode.Decompiler
@@ -94,8 +114,14 @@
ICSharpCode.SharpDevelop.Dom
False
+
+ {0162E499-42D0-409B-AA25-EED21F75336B}
+ AvalonEdit.AddIn
+ False
+
+
\ No newline at end of file
diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/LaunchILSpy/ILSpyController.cs b/src/AddIns/DisplayBindings/ILSpyAddIn/LaunchILSpy/ILSpyController.cs
index 50e3ee303f..7bc3e20acb 100644
--- a/src/AddIns/DisplayBindings/ILSpyAddIn/LaunchILSpy/ILSpyController.cs
+++ b/src/AddIns/DisplayBindings/ILSpyAddIn/LaunchILSpy/ILSpyController.cs
@@ -32,12 +32,7 @@ namespace ICSharpCode.ILSpyAddIn
ReflectionProjectContent rpc = pc as ReflectionProjectContent;
string assemblyLocation = null;
if (rpc != null) {
- // prefer GAC assemblies over reference assemblies:
- assemblyLocation = FindAssemblyInNetGac(new DomAssemblyName(rpc.AssemblyFullName));
- if (string.IsNullOrEmpty(assemblyLocation)) {
- // use file only if assembly isn't in GAC:
- assemblyLocation = rpc.AssemblyLocation;
- }
+ assemblyLocation = GetAssemblyLocation(rpc);
} else {
IProject project = pc.Project as IProject;
if (project != null) {
@@ -59,6 +54,19 @@ namespace ICSharpCode.ILSpyAddIn
Process.Start(ilspyPath, commandLine);
}
+ public static string GetAssemblyLocation(ReflectionProjectContent rpc)
+ {
+ if (rpc == null)
+ throw new ArgumentNullException("rpc");
+ // prefer GAC assemblies over reference assemblies:
+ string assemblyLocation = FindAssemblyInNetGac(new DomAssemblyName(rpc.AssemblyFullName));
+ if (string.IsNullOrEmpty(assemblyLocation)) {
+ // use file only if assembly isn't in GAC:
+ assemblyLocation = rpc.AssemblyLocation;
+ }
+ return assemblyLocation;
+ }
+
#region Find ILSpy
internal const string ILSpyExePathPropertyName = "ILSpyAddIn.ILSpyExePath";
diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/NavigateToDecompiledEntityService.cs b/src/AddIns/DisplayBindings/ILSpyAddIn/NavigateToDecompiledEntityService.cs
new file mode 100644
index 0000000000..e4a0f88884
--- /dev/null
+++ b/src/AddIns/DisplayBindings/ILSpyAddIn/NavigateToDecompiledEntityService.cs
@@ -0,0 +1,54 @@
+// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
+
+using System;
+using System.IO;
+using System.Linq;
+using ICSharpCode.SharpDevelop;
+using ICSharpCode.SharpDevelop.Dom;
+using ICSharpCode.SharpDevelop.Gui;
+
+namespace ICSharpCode.ILSpyAddIn
+{
+ public class NavigateToDecompiledEntityService : INavigateToEntityService
+ {
+ public bool NavigateTo(IEntity entity)
+ {
+ if (entity == null)
+ throw new ArgumentNullException("entity");
+
+ // Get the underlying entity for generic instance members
+ while ((entity is IMember) && ((IMember)entity).GenericMember != null)
+ entity = ((IMember)entity).GenericMember;
+
+ IClass declaringType = (entity as IClass) ?? entity.DeclaringType;
+ if (declaringType == null)
+ return false;
+ // get the top-level type
+ while (declaringType.DeclaringType != null)
+ declaringType = declaringType.DeclaringType;
+
+ ReflectionProjectContent rpc = entity.ProjectContent as ReflectionProjectContent;
+ if (rpc != null) {
+ string assemblyLocation = ILSpyController.GetAssemblyLocation(rpc);
+ if (!string.IsNullOrEmpty(assemblyLocation) && File.Exists(assemblyLocation)) {
+ NavigateTo(assemblyLocation, declaringType.FullyQualifiedName, ((AbstractEntity)entity).DocumentationTag);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static void NavigateTo(string assemblyFile, string typeName, string entityTag)
+ {
+ 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);
+ return;
+ }
+ }
+ WorkbenchSingleton.Workbench.ShowView(new DecompiledViewContent(assemblyFile, typeName, entityTag));
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/Properties/AssemblyInfo.cs b/src/AddIns/DisplayBindings/ILSpyAddIn/Properties/AssemblyInfo.cs
index b804da8885..9d32b6fb8a 100644
--- a/src/AddIns/DisplayBindings/ILSpyAddIn/Properties/AssemblyInfo.cs
+++ b/src/AddIns/DisplayBindings/ILSpyAddIn/Properties/AssemblyInfo.cs
@@ -20,5 +20,3 @@ using System.Reflection;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-
-[assembly: System.CLSCompliant(true)]
diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/CodeView.cs b/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/CodeView.cs
new file mode 100644
index 0000000000..1ff758072a
--- /dev/null
+++ b/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/CodeView.cs
@@ -0,0 +1,34 @@
+// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
+
+using System;
+using System.Windows.Controls;
+using ICSharpCode.AvalonEdit.AddIn;
+using ICSharpCode.AvalonEdit.Document;
+using ICSharpCode.AvalonEdit.Highlighting;
+
+namespace ICSharpCode.ILSpyAddIn.ViewContent
+{
+ ///
+ /// Equivalent to AE.AddIn CodeEditor, but without editing capabilities.
+ ///
+ public class CodeView : Grid, IDisposable
+ {
+ readonly SharpDevelopTextEditor textEditor = new SharpDevelopTextEditor();
+
+ public CodeView()
+ {
+ this.Children.Add(textEditor);
+ textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#");
+ }
+
+ public TextDocument Document {
+ get { return textEditor.Document; }
+ set { textEditor.Document = value; }
+ }
+
+ public void Dispose()
+ {
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs b/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs
new file mode 100644
index 0000000000..304bffa655
--- /dev/null
+++ b/src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs
@@ -0,0 +1,156 @@
+// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
+
+using System;
+using System.IO;
+using System.Threading;
+using ICSharpCode.AvalonEdit.Document;
+using ICSharpCode.Core;
+using ICSharpCode.Decompiler;
+using ICSharpCode.Decompiler.Ast;
+using ICSharpCode.ILSpyAddIn.ViewContent;
+using ICSharpCode.NRefactory.TypeSystem;
+using ICSharpCode.SharpDevelop.Gui;
+using Mono.Cecil;
+
+namespace ICSharpCode.ILSpyAddIn
+{
+ ///
+ /// Hosts a decompiled type.
+ ///
+ public class DecompiledViewContent : AbstractViewContentWithoutFile
+ {
+ readonly string assemblyFile;
+ readonly string fullTypeName;
+
+ ///
+ /// Entity to jump to once decompilation has finished.
+ ///
+ string jumpToEntityTagWhenDecompilationFinished;
+
+ bool decompilationFinished;
+
+ readonly CodeView codeView = new CodeView();
+ readonly CancellationTokenSource cancellation = new CancellationTokenSource();
+
+ #region Constructor
+ public DecompiledViewContent(string assemblyFile, string fullTypeName, string entityTag)
+ {
+ this.assemblyFile = assemblyFile;
+ this.fullTypeName = fullTypeName;
+ this.jumpToEntityTagWhenDecompilationFinished = entityTag;
+
+ string shortTypeName = fullTypeName.Substring(fullTypeName.LastIndexOf('.') + 1);
+ this.TitleName = "[" + ReflectionHelper.SplitTypeParameterCountFromReflectionName(shortTypeName) + "]";
+
+ Thread thread = new Thread(DecompilationThread);
+ thread.Name = "Decompiler (" + shortTypeName + ")";
+ thread.Start();
+ }
+ #endregion
+
+ #region Properties
+ public string AssemblyFile {
+ get { return assemblyFile; }
+ }
+
+ public string FullTypeName {
+ get { return fullTypeName; }
+ }
+
+ public override object Control {
+ get { return codeView; }
+ }
+ #endregion
+
+ #region Dispose
+ public override void Dispose()
+ {
+ cancellation.Cancel();
+ codeView.Dispose();
+ base.Dispose();
+ }
+ #endregion
+
+ #region Load/Save
+ public override void Load()
+ {
+ // nothing to do...
+ }
+
+ public override void Save()
+ {
+ if (!decompilationFinished)
+ return;
+ // TODO: show Save As dialog to allow the user to save the decompiled file
+ }
+ #endregion
+
+ #region JumpToEntity
+ public void JumpToEntity(string entityTag)
+ {
+ if (!decompilationFinished) {
+ this.jumpToEntityTagWhenDecompilationFinished = entityTag;
+ return;
+ }
+ // TODO: implement this
+ }
+ #endregion
+
+ #region Decompilation
+ void DecompilationThread()
+ {
+ try {
+ StringWriter writer = new StringWriter();
+ RunDecompiler(assemblyFile, fullTypeName, new PlainTextOutput(writer), cancellation.Token);
+ if (!cancellation.IsCancellationRequested) {
+ WorkbenchSingleton.SafeThreadAsyncCall(OnDecompilationFinished, writer);
+ }
+ } catch (OperationCanceledException) {
+ // ignore cancellation
+ } catch (Exception ex) {
+ if (cancellation.IsCancellationRequested) {
+ MessageService.ShowException(ex);
+ return;
+ }
+ AnalyticsMonitorService.TrackException(ex);
+
+ StringWriter writer = new StringWriter();
+ writer.WriteLine("Exception while decompiling " + fullTypeName);
+ writer.WriteLine();
+ writer.WriteLine(ex.ToString());
+ WorkbenchSingleton.SafeThreadAsyncCall(OnDecompilationFinished, writer);
+ }
+ }
+
+ static void RunDecompiler(string assemblyFile, string fullTypeName, ITextOutput textOutput, CancellationToken cancellationToken)
+ {
+ 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();
+
+ ModuleDefinition module = ModuleDefinition.ReadModule(assemblyFile, readerParameters);
+ TypeDefinition typeDefinition = module.GetType(fullTypeName);
+ if (typeDefinition == null)
+ throw new InvalidOperationException("Could not find type");
+ DecompilerContext context = new DecompilerContext(module);
+ context.CancellationToken = cancellationToken;
+ AstBuilder astBuilder = new AstBuilder(context);
+ astBuilder.AddType(typeDefinition);
+ astBuilder.GenerateCode(textOutput);
+ }
+
+ void OnDecompilationFinished(StringWriter output)
+ {
+ if (cancellation.IsCancellationRequested)
+ return;
+ codeView.Document.Text = output.ToString();
+ codeView.Document.UndoStack.ClearAll();
+
+ this.decompilationFinished = true;
+ JumpToEntity(this.jumpToEntityTagWhenDecompilationFinished);
+ }
+ #endregion
+ }
+}
diff --git a/src/Main/Base/Project/Src/Editor/Commands/GoToDefinition.cs b/src/Main/Base/Project/Src/Editor/Commands/GoToDefinition.cs
index 8f7794f90c..7a2649e14d 100644
--- a/src/Main/Base/Project/Src/Editor/Commands/GoToDefinition.cs
+++ b/src/Main/Base/Project/Src/Editor/Commands/GoToDefinition.cs
@@ -15,11 +15,19 @@ namespace ICSharpCode.SharpDevelop.Editor.Commands
{
protected override void RunImpl(ITextEditor editor, int offset, ResolveResult symbol)
{
- if (symbol == null)
- return;
FilePosition pos = symbol.GetDefinitionPosition();
if (pos.IsEmpty) {
- //new GoToDecompiledDefinition().Run(symbol);
+ IEntity entity;
+ if (symbol is MemberResolveResult) {
+ entity = ((MemberResolveResult)symbol).ResolvedMember;
+ } else if (symbol is TypeResolveResult) {
+ entity = ((TypeResolveResult)symbol).ResolvedClass;
+ } else {
+ entity = null;
+ }
+ if (entity != null) {
+ NavigationService.NavigateTo(entity);
+ }
} else {
try {
if (pos.Position.IsEmpty)
diff --git a/src/Main/Base/Project/Src/Gui/Pads/ClassBrowser/Nodes/ClassNode.cs b/src/Main/Base/Project/Src/Gui/Pads/ClassBrowser/Nodes/ClassNode.cs
index 3a8b3d5743..52031f035c 100644
--- a/src/Main/Base/Project/Src/Gui/Pads/ClassBrowser/Nodes/ClassNode.cs
+++ b/src/Main/Base/Project/Src/Gui/Pads/ClassBrowser/Nodes/ClassNode.cs
@@ -55,9 +55,7 @@ namespace ICSharpCode.SharpDevelop.Gui.ClassBrowser
public override void ActivateItem()
{
- if (c.CompilationUnit != null) {
- FileService.JumpToFilePosition(c.CompilationUnit.FileName, c.Region.BeginLine, c.Region.BeginColumn);
- }
+ NavigationService.NavigateTo(c);
}
protected override void Initialize()
diff --git a/src/Main/Base/Project/Src/Gui/Pads/ClassBrowser/Nodes/MemberNode.cs b/src/Main/Base/Project/Src/Gui/Pads/ClassBrowser/Nodes/MemberNode.cs
index a1b18e8d34..632133607b 100644
--- a/src/Main/Base/Project/Src/Gui/Pads/ClassBrowser/Nodes/MemberNode.cs
+++ b/src/Main/Base/Project/Src/Gui/Pads/ClassBrowser/Nodes/MemberNode.cs
@@ -8,19 +8,9 @@ namespace ICSharpCode.SharpDevelop.Gui.ClassBrowser
{
public class MemberNode : ExtTreeNode
{
- int line;
- int column;
ModifierEnum modifiers;
IClass declaringType;
- string FileName {
- get {
- if (declaringType == null || declaringType.CompilationUnit == null) {
- return null;
- }
- return declaringType.CompilationUnit.FileName;
- }
- }
public override bool Visible {
get {
ClassBrowserFilter filter = ClassBrowserPad.Instance.Filter;
@@ -51,8 +41,6 @@ namespace ICSharpCode.SharpDevelop.Gui.ClassBrowser
this.ContextmenuAddinTreePath = "/SharpDevelop/Pads/ClassBrowser/MemberContextMenu";
declaringType = member.DeclaringType;
modifiers = member.Modifiers;
- line = member.Region.BeginLine;
- column = member.Region.BeginColumn;
}
public static string GetText(IMember member)
@@ -123,9 +111,7 @@ namespace ICSharpCode.SharpDevelop.Gui.ClassBrowser
public override void ActivateItem()
{
- if (FileName != null) {
- FileService.JumpToFilePosition(FileName, line, column);
- }
+ NavigationService.NavigateTo(member);
}
}
}
diff --git a/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs b/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs
index 6043ba911b..91ad361845 100644
--- a/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs
+++ b/src/Main/Base/Project/Src/Services/NavigationService/NavigationService.cs
@@ -445,5 +445,42 @@ namespace ICSharpCode.SharpDevelop
}
}
#endregion
+
+ #region Navigate To Entity
+ public static bool NavigateTo(Dom.IEntity entity)
+ {
+ if (entity == null)
+ throw new ArgumentNullException("entity");
+ var cu = entity.CompilationUnit;
+ Dom.DomRegion region;
+ if (entity is Dom.IClass)
+ region = ((Dom.IClass)entity).Region;
+ else if (entity is Dom.IMember)
+ region = ((Dom.IMember)entity).Region;
+ else
+ region = Dom.DomRegion.Empty;
+
+ if (cu == null || string.IsNullOrEmpty(cu.FileName) || region.IsEmpty) {
+ foreach (var item in AddInTree.BuildItems("/SharpDevelop/Services/NavigateToEntityService", null, false)) {
+ if (item.NavigateTo(entity))
+ return true;
+ }
+ return false;
+ } else {
+ return FileService.JumpToFilePosition(cu.FileName, region.BeginLine, region.BeginColumn) != null;
+ }
+ }
+ #endregion
+ }
+
+ ///
+ /// Called by when the entity is not defined in source code.
+ ///
+ ///
+ /// Loaded from addin tree path "/SharpDevelop/Services/NavigateToEntityService"
+ ///
+ public interface INavigateToEntityService
+ {
+ bool NavigateTo(Dom.IEntity entity);
}
}
diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/GoToClassAction.cs b/src/Main/Base/Project/Src/Services/RefactoringService/GoToClassAction.cs
index afda99db15..176261b3a0 100644
--- a/src/Main/Base/Project/Src/Services/RefactoringService/GoToClassAction.cs
+++ b/src/Main/Base/Project/Src/Services/RefactoringService/GoToClassAction.cs
@@ -26,11 +26,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
public void Execute()
{
- var cu = this.Class.CompilationUnit;
- var region = this.Class.Region;
- if (cu == null || cu.FileName == null || region == null || region.IsEmpty)
- return;
- FileService.JumpToFilePosition(cu.FileName, region.BeginLine, region.BeginColumn);
+ NavigationService.NavigateTo(this.Class);
}
}
}
diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/GoToMemberAction.cs b/src/Main/Base/Project/Src/Services/RefactoringService/GoToMemberAction.cs
index c2ba735569..51168ff6fc 100644
--- a/src/Main/Base/Project/Src/Services/RefactoringService/GoToMemberAction.cs
+++ b/src/Main/Base/Project/Src/Services/RefactoringService/GoToMemberAction.cs
@@ -26,11 +26,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring
public void Execute()
{
- var cu = this.Member.CompilationUnit;
- var region = this.Member.Region;
- if (cu == null || cu.FileName == null || region == null || region.IsEmpty)
- return;
- FileService.JumpToFilePosition(cu.FileName, region.BeginLine, region.BeginColumn);
+ NavigationService.NavigateTo(this.Member);
}
}
}