diff --git a/ILSpy.AddIn/Commands/AssemblyReferenceForILSpy.cs b/ILSpy.AddIn/Commands/AssemblyReferenceForILSpy.cs
index cde4f679a..e5aaa592a 100644
--- a/ILSpy.AddIn/Commands/AssemblyReferenceForILSpy.cs
+++ b/ILSpy.AddIn/Commands/AssemblyReferenceForILSpy.cs
@@ -34,10 +34,10 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
///
/// List of current project's references.
/// Parameters object or null, if not applicable.
- public ILSpyParameters GetILSpyParameters(Dictionary projectReferences)
+ public ILSpyParameters GetILSpyParameters(Dictionary projectReferences)
{
- if (projectReferences.TryGetValue(reference.Name, out var path))
- return new ILSpyParameters(new[] { path });
+ if (projectReferences.TryGetValue(reference.Name, out var refentry))
+ return new ILSpyParameters(new[] { refentry.AssemblyFile });
return null;
}
diff --git a/ILSpy.AddIn/Commands/OpenCodeItemCommand.cs b/ILSpy.AddIn/Commands/OpenCodeItemCommand.cs
index d8f14cc25..cd0b95f24 100644
--- a/ILSpy.AddIn/Commands/OpenCodeItemCommand.cs
+++ b/ILSpy.AddIn/Commands/OpenCodeItemCommand.cs
@@ -1,10 +1,12 @@
using System;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
namespace ICSharpCode.ILSpy.AddIn.Commands
@@ -70,33 +72,80 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
var model = await roslynDocument.GetSemanticModelAsync().ConfigureAwait(false);
var node = ast.FindNode(new TextSpan(caretPosition.Position, 0), false, true);
if (node == null) {
- owner.ShowMessage("Can't show ILSpy for this code element!");
+ owner.ShowMessage(OLEMSGICON.OLEMSGICON_WARNING, "Can't show ILSpy for this code element!");
return;
}
var symbol = GetSymbolResolvableByILSpy(model, node);
if (symbol == null) {
- owner.ShowMessage("Can't show ILSpy for this code element!");
+ owner.ShowMessage(OLEMSGICON.OLEMSGICON_WARNING, "Can't show ILSpy for this code element!");
return;
}
-
var roslynProject = roslynDocument.Project;
var refsmap = GetReferences(roslynProject);
+ var symbolAssemblyName = symbol.ContainingAssembly?.Identity?.Name;
// Add our own project as well (not among references)
var project = owner.DTE.Solution.Projects.OfType()
.FirstOrDefault(p => p.FileName == roslynProject.FilePath);
- if (project != null) {
- string projectOutputPath = GetProjectOutputPath(project, roslynProject);
- refsmap.Add(roslynDocument.Project.AssemblyName, projectOutputPath);
+ if (project == null) {
+ owner.ShowMessage(OLEMSGICON.OLEMSGICON_WARNING, "Can't show ILSpy for this code element!");
+ return;
+ }
+
+ string assemblyName = roslynDocument.Project.AssemblyName;
+ string projectOutputPath = Utils.GetProjectOutputAssembly(project, roslynProject);
+ refsmap.Add(assemblyName, new DetectedReference(assemblyName, projectOutputPath, true));
+
+ // Divide into valid and invalid (= not found) referenced assemblies
+ CheckAssemblies(refsmap, out var validRefs, out var invalidRefs);
+ var invalidSymbolReference = invalidRefs.FirstOrDefault(r => r.IsProjectReference && (r.Name == symbolAssemblyName));
+ if (invalidSymbolReference != null) {
+ if (string.IsNullOrEmpty(invalidSymbolReference.AssemblyFile)) {
+ // No assembly file given at all. This has been seen while project is still loading after opening...
+ owner.ShowMessage(OLEMSGICON.OLEMSGICON_WARNING,
+ "Symbol can't be opened. This might happen while project is loading.",
+ Environment.NewLine, invalidSymbolReference.AssemblyFile);
+ }
+ if (invalidSymbolReference.IsProjectReference) {
+ // Some project references don't have assemblies, maybe not compiled yet?
+ if (owner.ShowMessage(
+ OLEMSGBUTTON.OLEMSGBUTTON_YESNO, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, OLEMSGICON.OLEMSGICON_WARNING,
+ "The project output for '{0}' could not be found for analysis. Would you like to rebuild the solution?",
+ symbolAssemblyName) == (int)MessageButtonResult.IDYES) {
+ owner.DTE.ExecuteCommand("Build.BuildSolution");
+ }
+ } else {
+ // External assembly is missing, we should abort
+ owner.ShowMessage(OLEMSGICON.OLEMSGICON_WARNING,
+ "Referenced assembly{0}{0}'{1}'{0}{0} could not be found.",
+ Environment.NewLine, invalidSymbolReference.AssemblyFile);
+ }
+
+ return;
}
- var refs = refsmap.Select(fn => fn.Value).Where(f => File.Exists(f));
- OpenAssembliesInILSpy(new ILSpyParameters(refs, "/navigateTo:" +
+ OpenAssembliesInILSpy(new ILSpyParameters(validRefs.Select(r => r.AssemblyFile), "/navigateTo:" +
(symbol.OriginalDefinition ?? symbol).GetDocumentationCommentId()));
}
+ void CheckAssemblies(Dictionary inputReferenceList,
+ out List validRefs,
+ out List invalidRefs)
+ {
+ validRefs = new List();
+ invalidRefs = new List();
+
+ foreach (var reference in inputReferenceList.Select(r => r.Value)) {
+ if ((reference.AssemblyFile == null) || !File.Exists(reference.AssemblyFile)) {
+ invalidRefs.Add(reference);
+ } else {
+ validRefs.Add(reference);
+ }
+ }
+ }
+
ISymbol GetSymbolResolvableByILSpy(SemanticModel model, SyntaxNode node)
{
var current = node;
diff --git a/ILSpy.AddIn/Commands/OpenILSpyCommand.cs b/ILSpy.AddIn/Commands/OpenILSpyCommand.cs
index d3e1254f1..f7a431e08 100644
--- a/ILSpy.AddIn/Commands/OpenILSpyCommand.cs
+++ b/ILSpy.AddIn/Commands/OpenILSpyCommand.cs
@@ -23,6 +23,20 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
public string[] Arguments { get; private set; }
}
+ public class DetectedReference
+ {
+ public DetectedReference(string name, string assemblyFile, bool isProjectReference)
+ {
+ this.Name = name;
+ this.AssemblyFile = assemblyFile;
+ this.IsProjectReference = isProjectReference;
+ }
+
+ public string Name { get; private set; }
+ public string AssemblyFile { get; private set; }
+ public bool IsProjectReference { get; private set; }
+ }
+
abstract class ILSpyCommand
{
protected ILSpyAddInPackage owner;
@@ -68,26 +82,18 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
System.Diagnostics.Process.Start(GetILSpyPath(), commandLineArguments);
}
- protected string GetProjectOutputPath(EnvDTE.Project project, Microsoft.CodeAnalysis.Project roslynProject)
- {
- string outputFileName = Path.GetFileName(roslynProject.OutputFilePath);
- //get the directory path based on the project file.
- string projectPath = Path.GetDirectoryName(project.FullName);
- //get the output path based on the active configuration
- string projectOutputPath = project.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath").Value.ToString();
- //combine the project path and output path to get the bin path
- return Path.Combine(projectPath, projectOutputPath, outputFileName);
- }
-
- protected Dictionary GetReferences(Microsoft.CodeAnalysis.Project parentProject)
+ protected Dictionary GetReferences(Microsoft.CodeAnalysis.Project parentProject)
{
- var dict = new Dictionary();
+ var dict = new Dictionary();
foreach (var reference in parentProject.MetadataReferences) {
using (var assemblyDef = AssemblyDefinition.ReadAssembly(reference.Display)) {
+ string assemblyName = assemblyDef.Name.Name;
if (IsReferenceAssembly(assemblyDef)) {
- dict.Add(assemblyDef.Name.Name, GacInterop.FindAssemblyInNetGac(assemblyDef.Name));
+ dict.Add(assemblyName,
+ new DetectedReference(assemblyName, GacInterop.FindAssemblyInNetGac(assemblyDef.Name), false));
} else {
- dict.Add(assemblyDef.Name.Name, reference.Display);
+ dict.Add(assemblyName,
+ new DetectedReference(assemblyName, reference.Display, false));
}
}
}
@@ -95,7 +101,8 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
var roslynProject = owner.Workspace.CurrentSolution.GetProject(projectReference.ProjectId);
var project = owner.DTE.Solution.Projects.OfType().FirstOrDefault(p => p.FileName == roslynProject.FilePath);
if (roslynProject != null && project != null)
- dict.Add(roslynProject.AssemblyName, GetProjectOutputPath(project, roslynProject));
+ dict.Add(roslynProject.AssemblyName,
+ new DetectedReference(roslynProject.AssemblyName, Utils.GetProjectOutputAssembly(project, roslynProject), true));
}
return dict;
}
diff --git a/ILSpy.AddIn/Commands/OpenReferenceCommand.cs b/ILSpy.AddIn/Commands/OpenReferenceCommand.cs
index f3c2fcc00..7b5b346fb 100644
--- a/ILSpy.AddIn/Commands/OpenReferenceCommand.cs
+++ b/ILSpy.AddIn/Commands/OpenReferenceCommand.cs
@@ -73,7 +73,7 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
if (!string.IsNullOrEmpty(fileName)) {
var roslynProject = owner.Workspace.CurrentSolution.Projects.FirstOrDefault(p => p.FilePath == fileName);
var references = GetReferences(roslynProject);
- if (references.TryGetValue(projectItem.Name, out string path)) {
+ if (references.TryGetValue(projectItem.Name, out DetectedReference path)) {
OpenAssembliesInILSpy(projectRefItem.GetILSpyParameters(references));
return;
}
diff --git a/ILSpy.AddIn/Commands/ProjectReferenceForILSpy.cs b/ILSpy.AddIn/Commands/ProjectReferenceForILSpy.cs
index 1927e9852..8f48b2bd4 100644
--- a/ILSpy.AddIn/Commands/ProjectReferenceForILSpy.cs
+++ b/ILSpy.AddIn/Commands/ProjectReferenceForILSpy.cs
@@ -48,12 +48,12 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
///
/// List of current project's references.
/// Parameters object or null, if not applicable.
- public ILSpyParameters GetILSpyParameters(Dictionary projectReferences)
+ public ILSpyParameters GetILSpyParameters(Dictionary projectReferences)
{
string fileName = projectItem.ContainingProject?.FileName;
if (!string.IsNullOrEmpty(fileName)) {
- if (projectReferences.TryGetValue(projectItem.Name, out string path)) {
- return new ILSpyParameters(new[] { path });
+ if (projectReferences.TryGetValue(projectItem.Name, out DetectedReference path)) {
+ return new ILSpyParameters(new[] { path.AssemblyFile });
}
}
diff --git a/ILSpy.AddIn/ILSpyAddInPackage.cs b/ILSpy.AddIn/ILSpyAddInPackage.cs
index 7e4ec8388..cd2b937e4 100644
--- a/ILSpy.AddIn/ILSpyAddInPackage.cs
+++ b/ILSpy.AddIn/ILSpyAddInPackage.cs
@@ -90,6 +90,16 @@ namespace ICSharpCode.ILSpy.AddIn
#endregion
public void ShowMessage(string format, params object[] items)
+ {
+ ShowMessage(OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, OLEMSGICON.OLEMSGICON_INFO, format, items);
+ }
+
+ public void ShowMessage(OLEMSGICON icon, string format, params object[] items)
+ {
+ ShowMessage(OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, icon, format, items);
+ }
+
+ public int ShowMessage(OLEMSGBUTTON buttons, OLEMSGDEFBUTTON defaultButton, OLEMSGICON icon, string format, params object[] items)
{
IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell));
Guid clsid = Guid.Empty;
@@ -98,17 +108,19 @@ namespace ICSharpCode.ILSpy.AddIn
uiShell.ShowMessageBox(
0,
ref clsid,
- "ILSpy.AddIn",
+ "ILSpy AddIn",
string.Format(CultureInfo.CurrentCulture, format, items),
string.Empty,
0,
- OLEMSGBUTTON.OLEMSGBUTTON_OK,
- OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
- OLEMSGICON.OLEMSGICON_INFO,
+ buttons,
+ defaultButton,
+ icon,
0, // false
out result
)
);
+
+ return result;
}
public IEnumerable GetSelectedItemsData()
diff --git a/ILSpy.AddIn/Utils.cs b/ILSpy.AddIn/Utils.cs
index 54bdd8d69..ae5ee4bca 100644
--- a/ILSpy.AddIn/Utils.cs
+++ b/ILSpy.AddIn/Utils.cs
@@ -14,8 +14,22 @@ using Microsoft.VisualStudio.TextManager.Interop;
namespace ICSharpCode.ILSpy.AddIn
{
+ public enum MessageButtonResult : int
+ {
+ IDOK = 1,
+ IDCANCEL = 2,
+ IDABORT = 3,
+ IDRETRY = 4,
+ IDIGNORE = 5,
+ IDYES = 6,
+ IDNO = 7,
+ IDTRYAGAIN = 10,
+ IDCONTINUE = 11,
+ }
+
static class Utils
{
+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass")]
[DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern unsafe char** CommandLineToArgvW([MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine, out int pNumArgs);
@@ -230,7 +244,10 @@ namespace ICSharpCode.ILSpy.AddIn
string projectOutputPath = project.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath").Value.ToString();
// Combine the project path and output path to get the bin path
- return Path.Combine(projectPath, projectOutputPath, outputFileName);
+ if ((projectPath != null) && (projectOutputPath != null) && (outputFileName != null))
+ return Path.Combine(projectPath, projectOutputPath, outputFileName);
+
+ return null;
}
}
}