Browse Source

Re-enabled "Open code in ILSpy" command in code editor, fixed several issues.

pull/1167/head
Andreas Weizel 7 years ago
parent
commit
84758dca5e
  1. 106
      ILSpy.AddIn/Commands/OpenCodeItemCommand.cs
  2. 13
      ILSpy.AddIn/Commands/OpenProjectOutputCommand.cs
  3. 38
      ILSpy.AddIn/Commands/ProjectItemForILSpy.cs
  4. 4
      ILSpy.AddIn/ILSpy.AddIn.csproj
  5. 8
      ILSpy.AddIn/ILSpyAddIn.vsct
  6. 2
      ILSpy.AddIn/ILSpyAddInPackage.cs
  7. 821
      ILSpy.AddIn/SyntaxNodeExtensions.cs
  8. 71
      ILSpy.AddIn/Utils.cs
  9. 2
      ILSpy.AddIn/source.extension.vsixmanifest

106
ILSpy.AddIn/Commands/OpenCodeItemCommand.cs

@ -3,7 +3,9 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Text;
namespace ICSharpCode.ILSpy.AddIn.Commands namespace ICSharpCode.ILSpy.AddIn.Commands
{ {
@ -18,10 +20,19 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
protected override void OnBeforeQueryStatus(object sender, EventArgs e) protected override void OnBeforeQueryStatus(object sender, EventArgs e)
{ {
OleMenuCommand menuItem = sender as OleMenuCommand; if (sender is OleMenuCommand menuItem) {
if (menuItem != null) { menuItem.Visible = false;
// Enable this item only if this is a .cs file!
if (Utils.GetCurrentViewHost(owner, f => f.EndsWith(".cs")) == null)
return;
// Enable this item only if this is a Roslyn document
if (GetRoslynDocument() == null)
return;
var document = owner.DTE.ActiveDocument; var document = owner.DTE.ActiveDocument;
menuItem.Enabled = menuItem.Visible =
(document != null) && (document != null) &&
(document.ProjectItem != null) && (document.ProjectItem != null) &&
(document.ProjectItem.ContainingProject != null) && (document.ProjectItem.ContainingProject != null) &&
@ -30,26 +41,99 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
} }
} }
protected override async void OnExecute(object sender, EventArgs e) Document GetRoslynDocument()
{ {
var document = owner.DTE.ActiveDocument; var document = owner.DTE.ActiveDocument;
var selection = (EnvDTE.TextPoint)((EnvDTE.TextSelection)document.Selection).ActivePoint; var selection = (EnvDTE.TextPoint)((EnvDTE.TextSelection)document.Selection).ActivePoint;
var id = owner.Workspace.CurrentSolution.GetDocumentIdsWithFilePath(document.FullName).FirstOrDefault(); var id = owner.Workspace.CurrentSolution.GetDocumentIdsWithFilePath(document.FullName).FirstOrDefault();
if (id == null)
return null;
if (id == null) return; return owner.Workspace.CurrentSolution.GetDocument(id);
var roslynDocument = owner.Workspace.CurrentSolution.GetDocument(id); }
EnvDTE.TextPoint GetEditorSelection()
{
var document = owner.DTE.ActiveDocument;
return ((EnvDTE.TextSelection)document.Selection).ActivePoint;
}
protected override async void OnExecute(object sender, EventArgs e)
{
var textView = Utils.GetCurrentViewHost(owner)?.TextView;
if (textView == null)
return;
SnapshotPoint caretPosition = textView.Caret.Position.BufferPosition;
var roslynDocument = GetRoslynDocument();
var ast = await roslynDocument.GetSyntaxRootAsync().ConfigureAwait(false); var ast = await roslynDocument.GetSyntaxRootAsync().ConfigureAwait(false);
var model = await roslynDocument.GetSemanticModelAsync().ConfigureAwait(false); var model = await roslynDocument.GetSemanticModelAsync().ConfigureAwait(false);
var node = ast.FindNode(new Microsoft.CodeAnalysis.Text.TextSpan(selection.AbsoluteCharOffset, 1)); var node = ast.FindNode(new TextSpan(caretPosition.Position, 0), false, true);
if (node == null) if (node == null) {
owner.ShowMessage("Can't show ILSpy for this code element!");
return; return;
var symbol = model.GetSymbolInfo(node).Symbol; }
if (symbol == null)
var symbol = GetSymbolResolvableByILSpy(model, node);
if (symbol == null) {
owner.ShowMessage("Can't show ILSpy for this code element!");
return; return;
var refs = GetReferences(roslynDocument.Project).Select(fn => fn.Value).Where(f => File.Exists(f)).ToArray(); }
var roslynProject = roslynDocument.Project;
var refsmap = GetReferences(roslynProject);
// Add our own project as well (not among references)
var project = owner.DTE.Solution.Projects.OfType<EnvDTE.Project>()
.FirstOrDefault(p => p.FileName == roslynProject.FilePath);
if (project != null) {
string projectOutputPath = GetProjectOutputPath(project, roslynProject);
refsmap.Add(roslynDocument.Project.AssemblyName, projectOutputPath);
}
var refs = refsmap.Select(fn => fn.Value).Where(f => File.Exists(f));
OpenAssembliesInILSpy(new ILSpyParameters(refs, "/navigateTo:" + symbol.GetDocumentationCommentId())); OpenAssembliesInILSpy(new ILSpyParameters(refs, "/navigateTo:" + symbol.GetDocumentationCommentId()));
} }
ISymbol GetSymbolResolvableByILSpy(SemanticModel model, SyntaxNode node)
{
var current = node;
while (current != null) {
var symbol = model.GetSymbolInfo(current).Symbol;
if (symbol == null) {
symbol = model.GetDeclaredSymbol(current);
}
// ILSpy can only resolve some symbol types, so allow them, discard everything else
if (symbol != null) {
switch (symbol.Kind) {
case SymbolKind.ArrayType:
case SymbolKind.Event:
case SymbolKind.Field:
case SymbolKind.Method:
case SymbolKind.NamedType:
case SymbolKind.Namespace:
case SymbolKind.PointerType:
case SymbolKind.Property:
break;
default:
symbol = null;
break;
}
}
if (symbol != null)
return symbol;
current = current is IStructuredTriviaSyntax
? ((IStructuredTriviaSyntax)current).ParentTrivia.Token.Parent
: current.Parent;
}
return null;
}
internal static void Register(ILSpyAddInPackage owner) internal static void Register(ILSpyAddInPackage owner)
{ {
instance = new OpenCodeItemCommand(owner); instance = new OpenCodeItemCommand(owner);

13
ILSpy.AddIn/Commands/OpenProjectOutputCommand.cs

@ -1,6 +1,7 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.VisualStudio.Shell;
namespace ICSharpCode.ILSpy.AddIn.Commands namespace ICSharpCode.ILSpy.AddIn.Commands
{ {
@ -13,11 +14,21 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
{ {
} }
protected override void OnBeforeQueryStatus(object sender, EventArgs e)
{
if (sender is OleMenuCommand menuItem) {
menuItem.Visible = false;
var selectedItem = owner.DTE.SelectedItems.Item(1);
menuItem.Visible = (ProjectItemForILSpy.Detect(owner, selectedItem) != null);
}
}
protected override void OnExecute(object sender, EventArgs e) protected override void OnExecute(object sender, EventArgs e)
{ {
if (owner.DTE.SelectedItems.Count != 1) if (owner.DTE.SelectedItems.Count != 1)
return; return;
var projectItemWrapper = ProjectItemForILSpy.Detect(owner.DTE.SelectedItems.Item(1)); var projectItemWrapper = ProjectItemForILSpy.Detect(owner, owner.DTE.SelectedItems.Item(1));
if (projectItemWrapper != null) { if (projectItemWrapper != null) {
OpenAssembliesInILSpy(projectItemWrapper.GetILSpyParameters(owner)); OpenAssembliesInILSpy(projectItemWrapper.GetILSpyParameters(owner));
} }

38
ILSpy.AddIn/Commands/ProjectItemForILSpy.cs

@ -1,9 +1,5 @@
using System; using System.IO;
using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EnvDTE; using EnvDTE;
namespace ICSharpCode.ILSpy.AddIn.Commands namespace ICSharpCode.ILSpy.AddIn.Commands
@ -14,9 +10,13 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
class ProjectItemForILSpy class ProjectItemForILSpy
{ {
SelectedItem item; SelectedItem item;
Project project;
Microsoft.CodeAnalysis.Project roslynProject;
ProjectItemForILSpy(SelectedItem item) ProjectItemForILSpy(Project project, Microsoft.CodeAnalysis.Project roslynProject, SelectedItem item)
{ {
this.project = project;
this.roslynProject = roslynProject;
this.item = item; this.item = item;
} }
@ -25,30 +25,24 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
/// </summary> /// </summary>
/// <param name="item">Selected item to check.</param> /// <param name="item">Selected item to check.</param>
/// <returns><see cref="ProjectItemForILSpy"/> instance or <c>null</c>, if item is not a supported project.</returns> /// <returns><see cref="ProjectItemForILSpy"/> instance or <c>null</c>, if item is not a supported project.</returns>
public static ProjectItemForILSpy Detect(SelectedItem item) public static ProjectItemForILSpy Detect(ILSpyAddInPackage package, SelectedItem item)
{ {
return new ProjectItemForILSpy(item); var project = item.Project;
var roslynProject = package.Workspace.CurrentSolution.Projects.FirstOrDefault(p => p.FilePath == project.FileName);
if (roslynProject == null)
return null;
return new ProjectItemForILSpy(project, roslynProject, item);
} }
/// <summary> /// <summary>
/// If possible retrieves parameters to use for launching ILSpy instance. /// If possible retrieves parameters to use for launching ILSpy instance.
/// </summary> /// </summary>
/// <param name="owner">Package instance.</param> /// <param name="package">Package instance.</param>
/// <returns>Parameters object or <c>null, if not applicable.</c></returns> /// <returns>Parameters object or <c>null, if not applicable.</c></returns>
public ILSpyParameters GetILSpyParameters(ILSpyAddInPackage owner) public ILSpyParameters GetILSpyParameters(ILSpyAddInPackage package)
{ {
var project = item.Project; return new ILSpyParameters(new[] { Utils.GetProjectOutputAssembly(project, roslynProject) });
var roslynProject = owner.Workspace.CurrentSolution.Projects.FirstOrDefault(p => p.FilePath == project.FileName);
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 new ILSpyParameters(new[] { Path.Combine(projectPath, projectOutputPath, outputFileName) });
} }
} }
} }

4
ILSpy.AddIn/ILSpy.AddIn.csproj

@ -49,8 +49,11 @@
<PackageReference Include="Microsoft.CodeAnalysis" Version="2.4.0" /> <PackageReference Include="Microsoft.CodeAnalysis" Version="2.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.4.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.4.0" />
<PackageReference Include="Microsoft.VisualStudio.ComponentModelHost" Version="15.6.27413" /> <PackageReference Include="Microsoft.VisualStudio.ComponentModelHost" Version="15.6.27413" />
<PackageReference Include="Microsoft.VisualStudio.Editor" Version="15.6.27740" />
<PackageReference Include="Microsoft.VisualStudio.LanguageServices" Version="2.4.0" /> <PackageReference Include="Microsoft.VisualStudio.LanguageServices" Version="2.4.0" />
<PackageReference Include="Microsoft.VisualStudio.Shell.14.0" Version="14.3.25407" /> <PackageReference Include="Microsoft.VisualStudio.Shell.14.0" Version="14.3.25407" />
<PackageReference Include="Microsoft.VisualStudio.Text.UI" Version="15.6.27740" />
<PackageReference Include="Microsoft.VisualStudio.Text.UI.Wpf" Version="15.6.27740" />
<PackageReference Include="Mono.Cecil" Version="0.10.0" /> <PackageReference Include="Mono.Cecil" Version="0.10.0" />
<PackageReference Include="VSLangProj" Version="7.0.3301" /> <PackageReference Include="VSLangProj" Version="7.0.3301" />
</ItemGroup> </ItemGroup>
@ -81,6 +84,7 @@
<Compile Include="ILSpyAddInPackage.cs" /> <Compile Include="ILSpyAddInPackage.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PkgCmdID.cs" /> <Compile Include="PkgCmdID.cs" />
<Compile Include="SyntaxNodeExtensions.cs" />
<Compile Include="Utils.cs" /> <Compile Include="Utils.cs" />
</ItemGroup> </ItemGroup>

8
ILSpy.AddIn/ILSpyAddIn.vsct

@ -82,18 +82,22 @@
<Button guid="guidILSpyAddInCmdSet" id="cmdidOpenProjectOutputInILSpy" priority="0x0600" type="Button"> <Button guid="guidILSpyAddInCmdSet" id="cmdidOpenProjectOutputInILSpy" priority="0x0600" type="Button">
<Parent guid="guidILSpyAddInCmdSet" id="OpenILSpyProjGroup" /> <Parent guid="guidILSpyAddInCmdSet" id="OpenILSpyProjGroup" />
<Icon guid="guidImages" id="bmpLogo" /> <Icon guid="guidImages" id="bmpLogo" />
<CommandFlag>DynamicVisibility</CommandFlag>
<CommandFlag>DefaultInvisible</CommandFlag>
<Strings> <Strings>
<ButtonText>Open output in ILSpy</ButtonText> <ButtonText>Open output in ILSpy</ButtonText>
</Strings> </Strings>
</Button> </Button>
<!--<Button guid="guidILSpyAddInCmdSet" id="cmdidOpenCodeItemInILSpy" priority="0x0600" type="Button"> <Button guid="guidILSpyAddInCmdSet" id="cmdidOpenCodeItemInILSpy" priority="0x0600" type="Button">
<Parent guid="guidILSpyAddInCmdSet" id="OpenILSpyCodeItemGroup" /> <Parent guid="guidILSpyAddInCmdSet" id="OpenILSpyCodeItemGroup" />
<Icon guid="guidImages" id="bmpLogo" /> <Icon guid="guidImages" id="bmpLogo" />
<CommandFlag>DynamicVisibility</CommandFlag>
<CommandFlag>DefaultInvisible</CommandFlag>
<Strings> <Strings>
<ButtonText>Open code in ILSpy</ButtonText> <ButtonText>Open code in ILSpy</ButtonText>
</Strings> </Strings>
</Button>--> </Button>
<Button guid="guidILSpyAddInCmdSet" id="cmdidOpenILSpy" priority="0x0600" type="Button"> <Button guid="guidILSpyAddInCmdSet" id="cmdidOpenILSpy" priority="0x0600" type="Button">
<Parent guid="guidILSpyAddInCmdSet" id="OpenILSpyGroup" /> <Parent guid="guidILSpyAddInCmdSet" id="OpenILSpyGroup" />

2
ILSpy.AddIn/ILSpyAddInPackage.cs

@ -85,7 +85,7 @@ namespace ICSharpCode.ILSpy.AddIn
OpenILSpyCommand.Register(this); OpenILSpyCommand.Register(this);
OpenProjectOutputCommand.Register(this); OpenProjectOutputCommand.Register(this);
OpenReferenceCommand.Register(this); OpenReferenceCommand.Register(this);
//OpenCodeItemCommand.Register(this); OpenCodeItemCommand.Register(this);
} }
#endregion #endregion

821
ILSpy.AddIn/SyntaxNodeExtensions.cs

@ -0,0 +1,821 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Threading.Tasks;
namespace ICSharpCode.ILSpy.AddIn
{
static class SyntaxNodeExtensions
{
public static IEnumerable<SyntaxNode> GetAncestors(this SyntaxNode node)
{
var current = node.Parent;
while (current != null)
{
yield return current;
current = current is IStructuredTriviaSyntax
? ((IStructuredTriviaSyntax)current).ParentTrivia.Token.Parent
: current.Parent;
}
}
public static IEnumerable<TNode> GetAncestors<TNode>(this SyntaxNode node)
where TNode : SyntaxNode
{
var current = node.Parent;
while (current != null)
{
if (current is TNode)
{
yield return (TNode)current;
}
current = current is IStructuredTriviaSyntax
? ((IStructuredTriviaSyntax)current).ParentTrivia.Token.Parent
: current.Parent;
}
}
public static TNode GetAncestor<TNode>(this SyntaxNode node)
where TNode : SyntaxNode
{
if (node == null)
{
return default(TNode);
}
return node.GetAncestors<TNode>().FirstOrDefault();
}
public static TNode GetAncestorOrThis<TNode>(this SyntaxNode node)
where TNode : SyntaxNode
{
if (node == null)
{
return default(TNode);
}
return node.GetAncestorsOrThis<TNode>().FirstOrDefault();
}
public static IEnumerable<TNode> GetAncestorsOrThis<TNode>(this SyntaxNode node)
where TNode : SyntaxNode
{
var current = node;
while (current != null)
{
if (current is TNode)
{
yield return (TNode)current;
}
current = current is IStructuredTriviaSyntax
? ((IStructuredTriviaSyntax)current).ParentTrivia.Token.Parent
: current.Parent;
}
}
public static bool HasAncestor<TNode>(this SyntaxNode node)
where TNode : SyntaxNode
{
return node.GetAncestors<TNode>().Any();
}
public static bool CheckParent<T>(this SyntaxNode node, Func<T, bool> valueChecker) where T : SyntaxNode
{
if (node == null)
{
return false;
}
var parentNode = node.Parent as T;
if (parentNode == null)
{
return false;
}
return valueChecker(parentNode);
}
/// <summary>
/// Returns true if is a given token is a child token of of a certain type of parent node.
/// </summary>
/// <typeparam name="TParent">The type of the parent node.</typeparam>
/// <param name="node">The node that we are testing.</param>
/// <param name="childGetter">A function that, when given the parent node, returns the child token we are interested in.</param>
public static bool IsChildNode<TParent>(this SyntaxNode node, Func<TParent, SyntaxNode> childGetter)
where TParent : SyntaxNode
{
var ancestor = node.GetAncestor<TParent>();
if (ancestor == null)
{
return false;
}
var ancestorNode = childGetter(ancestor);
return node == ancestorNode;
}
/// <summary>
/// Returns true if this node is found underneath the specified child in the given parent.
/// </summary>
public static bool IsFoundUnder<TParent>(this SyntaxNode node, Func<TParent, SyntaxNode> childGetter)
where TParent : SyntaxNode
{
var ancestor = node.GetAncestor<TParent>();
if (ancestor == null)
{
return false;
}
var child = childGetter(ancestor);
// See if node passes through child on the way up to ancestor.
return node.GetAncestorsOrThis<SyntaxNode>().Contains(child);
}
public static SyntaxNode GetCommonRoot(this SyntaxNode node1, SyntaxNode node2)
{
//Contract.ThrowIfTrue(node1.RawKind == 0 || node2.RawKind == 0);
// find common starting node from two nodes.
// as long as two nodes belong to same tree, there must be at least one common root (Ex, compilation unit)
var ancestors = node1.GetAncestorsOrThis<SyntaxNode>();
var set = new HashSet<SyntaxNode>(node2.GetAncestorsOrThis<SyntaxNode>());
return ancestors.First(set.Contains);
}
public static int Width(this SyntaxNode node)
{
return node.Span.Length;
}
public static int FullWidth(this SyntaxNode node)
{
return node.FullSpan.Length;
}
public static SyntaxNode FindInnermostCommonNode(
this IEnumerable<SyntaxNode> nodes,
Func<SyntaxNode, bool> predicate)
{
IEnumerable<SyntaxNode> blocks = null;
foreach (var node in nodes)
{
blocks = blocks == null
? node.AncestorsAndSelf().Where(predicate)
: blocks.Intersect(node.AncestorsAndSelf().Where(predicate));
}
return blocks == null ? null : blocks.First();
}
public static TSyntaxNode FindInnermostCommonNode<TSyntaxNode>(this IEnumerable<SyntaxNode> nodes)
where TSyntaxNode : SyntaxNode
{
return (TSyntaxNode)nodes.FindInnermostCommonNode(n => n is TSyntaxNode);
}
/// <summary>
/// create a new root node from the given root after adding annotations to the tokens
///
/// tokens should belong to the given root
/// </summary>
public static SyntaxNode AddAnnotations(this SyntaxNode root, IEnumerable<Tuple<SyntaxToken, SyntaxAnnotation>> pairs)
{
// Contract.ThrowIfNull(root);
// Contract.ThrowIfNull(pairs);
var tokenMap = pairs.GroupBy(p => p.Item1, p => p.Item2).ToDictionary(g => g.Key, g => g.ToArray());
return root.ReplaceTokens(tokenMap.Keys, (o, n) => o.WithAdditionalAnnotations(tokenMap[o]));
}
/// <summary>
/// create a new root node from the given root after adding annotations to the nodes
///
/// nodes should belong to the given root
/// </summary>
public static SyntaxNode AddAnnotations(this SyntaxNode root, IEnumerable<Tuple<SyntaxNode, SyntaxAnnotation>> pairs)
{
// Contract.ThrowIfNull(root);
// Contract.ThrowIfNull(pairs);
var tokenMap = pairs.GroupBy(p => p.Item1, p => p.Item2).ToDictionary(g => g.Key, g => g.ToArray());
return root.ReplaceNodes(tokenMap.Keys, (o, n) => o.WithAdditionalAnnotations(tokenMap[o]));
}
public static TextSpan GetContainedSpan(this IEnumerable<SyntaxNode> nodes)
{
// Contract.ThrowIfNull(nodes);
// Contract.ThrowIfFalse(nodes.Any());
TextSpan fullSpan = nodes.First().Span;
foreach (var node in nodes)
{
fullSpan = TextSpan.FromBounds(
Math.Min(fullSpan.Start, node.SpanStart),
Math.Max(fullSpan.End, node.Span.End));
}
return fullSpan;
}
public static IEnumerable<TextSpan> GetContiguousSpans(
this IEnumerable<SyntaxNode> nodes, Func<SyntaxNode, SyntaxToken> getLastToken = null)
{
SyntaxNode lastNode = null;
TextSpan? textSpan = null;
foreach (var node in nodes)
{
if (lastNode == null)
{
textSpan = node.Span;
}
else
{
var lastToken = getLastToken == null
? lastNode.GetLastToken()
: getLastToken(lastNode);
if (lastToken.GetNextToken(includeDirectives: true) == node.GetFirstToken())
{
// Expand the span
textSpan = TextSpan.FromBounds(textSpan.Value.Start, node.Span.End);
}
else
{
// Return the last span, and start a new one
yield return textSpan.Value;
textSpan = node.Span;
}
}
lastNode = node;
}
if (textSpan.HasValue)
{
yield return textSpan.Value;
}
}
//public static bool OverlapsHiddenPosition(this SyntaxNode node, CancellationToken cancellationToken)
//{
// return node.OverlapsHiddenPosition(node.Span, cancellationToken);
//}
//public static bool OverlapsHiddenPosition(this SyntaxNode node, TextSpan span, CancellationToken cancellationToken)
//{
// return node.SyntaxTree.OverlapsHiddenPosition(span, cancellationToken);
//}
//public static bool OverlapsHiddenPosition(this SyntaxNode declaration, SyntaxNode startNode, SyntaxNode endNode, CancellationToken cancellationToken)
//{
// var start = startNode.Span.End;
// var end = endNode.SpanStart;
// var textSpan = TextSpan.FromBounds(start, end);
// return declaration.OverlapsHiddenPosition(textSpan, cancellationToken);
//}
public static IEnumerable<T> GetAnnotatedNodes<T>(this SyntaxNode node, SyntaxAnnotation syntaxAnnotation) where T : SyntaxNode
{
return node.GetAnnotatedNodesAndTokens(syntaxAnnotation).Select(n => n.AsNode()).OfType<T>();
}
public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2)
{
if (node == null)
{
return false;
}
var csharpKind = node.Kind();
return csharpKind == kind1 || csharpKind == kind2;
}
public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3)
{
if (node == null)
{
return false;
}
var csharpKind = node.Kind();
return csharpKind == kind1 || csharpKind == kind2 || csharpKind == kind3;
}
public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4)
{
if (node == null)
{
return false;
}
var csharpKind = node.Kind();
return csharpKind == kind1 || csharpKind == kind2 || csharpKind == kind3 || csharpKind == kind4;
}
public static bool IsKind(this SyntaxNode node, SyntaxKind kind1, SyntaxKind kind2, SyntaxKind kind3, SyntaxKind kind4, SyntaxKind kind5)
{
if (node == null)
{
return false;
}
var csharpKind = node.Kind();
return csharpKind == kind1 || csharpKind == kind2 || csharpKind == kind3 || csharpKind == kind4 || csharpKind == kind5;
}
/// <summary>
/// Returns the list of using directives that affect <paramref name="node"/>. The list will be returned in
/// top down order.
/// </summary>
public static IEnumerable<UsingDirectiveSyntax> GetEnclosingUsingDirectives(this SyntaxNode node)
{
return node.GetAncestorOrThis<CompilationUnitSyntax>().Usings
.Concat(node.GetAncestorsOrThis<NamespaceDeclarationSyntax>()
.Reverse()
.SelectMany(n => n.Usings));
}
public static bool IsUnsafeContext(this SyntaxNode node)
{
if (node.GetAncestor<UnsafeStatementSyntax>() != null)
{
return true;
}
return node.GetAncestors<MemberDeclarationSyntax>().Any(
m => m.GetModifiers().Any(SyntaxKind.UnsafeKeyword));
}
public static bool IsInStaticContext(this SyntaxNode node)
{
// this/base calls are always static.
if (node.FirstAncestorOrSelf<ConstructorInitializerSyntax>() != null)
{
return true;
}
var memberDeclaration = node.FirstAncestorOrSelf<MemberDeclarationSyntax>();
if (memberDeclaration == null)
{
return false;
}
switch (memberDeclaration.Kind())
{
case SyntaxKind.MethodDeclaration:
case SyntaxKind.ConstructorDeclaration:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.EventDeclaration:
case SyntaxKind.IndexerDeclaration:
return memberDeclaration.GetModifiers().Any(SyntaxKind.StaticKeyword);
case SyntaxKind.FieldDeclaration:
// Inside a field one can only access static members of a type.
return true;
case SyntaxKind.DestructorDeclaration:
return false;
}
// Global statements are not a static context.
if (node.FirstAncestorOrSelf<GlobalStatementSyntax>() != null)
{
return false;
}
// any other location is considered static
return true;
}
public static NamespaceDeclarationSyntax GetInnermostNamespaceDeclarationWithUsings(this SyntaxNode contextNode)
{
var usingDirectiveAncsestor = contextNode.GetAncestor<UsingDirectiveSyntax>();
if (usingDirectiveAncsestor == null)
{
return contextNode.GetAncestorsOrThis<NamespaceDeclarationSyntax>().FirstOrDefault(n => n.Usings.Count > 0);
}
else
{
// We are inside a using directive. In this case, we should find and return the first 'parent' namespace with usings.
var containingNamespace = usingDirectiveAncsestor.GetAncestor<NamespaceDeclarationSyntax>();
if (containingNamespace == null)
{
// We are inside a top level using directive (i.e. one that's directly in the compilation unit).
return null;
}
else
{
return containingNamespace.GetAncestors<NamespaceDeclarationSyntax>().FirstOrDefault(n => n.Usings.Count > 0);
}
}
}
/// <summary>
/// Returns all of the trivia to the left of this token up to the previous token (concatenates
/// the previous token's trailing trivia and this token's leading trivia).
/// </summary>
public static IEnumerable<SyntaxTrivia> GetAllPrecedingTriviaToPreviousToken(this SyntaxToken token)
{
var prevToken = token.GetPreviousToken(includeSkipped: true);
if (prevToken.Kind() == SyntaxKind.None)
{
return token.LeadingTrivia;
}
return prevToken.TrailingTrivia.Concat(token.LeadingTrivia);
}
public static bool IsBreakableConstruct(this SyntaxNode node)
{
switch (node.Kind())
{
case SyntaxKind.DoStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.SwitchStatement:
case SyntaxKind.ForStatement:
case SyntaxKind.ForEachStatement:
return true;
}
return false;
}
public static bool IsContinuableConstruct(this SyntaxNode node)
{
switch (node.Kind())
{
case SyntaxKind.DoStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.ForStatement:
case SyntaxKind.ForEachStatement:
return true;
}
return false;
}
public static bool IsReturnableConstruct(this SyntaxNode node)
{
switch (node.Kind())
{
case SyntaxKind.AnonymousMethodExpression:
case SyntaxKind.SimpleLambdaExpression:
case SyntaxKind.ParenthesizedLambdaExpression:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.ConstructorDeclaration:
case SyntaxKind.DestructorDeclaration:
case SyntaxKind.GetAccessorDeclaration:
case SyntaxKind.SetAccessorDeclaration:
case SyntaxKind.OperatorDeclaration:
case SyntaxKind.AddAccessorDeclaration:
case SyntaxKind.RemoveAccessorDeclaration:
return true;
}
return false;
}
public static bool IsAnyArgumentList(this SyntaxNode node)
{
return node.IsKind(SyntaxKind.ArgumentList) ||
node.IsKind(SyntaxKind.AttributeArgumentList) ||
node.IsKind(SyntaxKind.BracketedArgumentList) ||
node.IsKind(SyntaxKind.TypeArgumentList);
}
public static bool IsAnyLambda(this SyntaxNode node)
{
return
node.IsKind(SyntaxKind.ParenthesizedLambdaExpression) ||
node.IsKind(SyntaxKind.SimpleLambdaExpression);
}
public static bool IsAnyLambdaOrAnonymousMethod(this SyntaxNode node)
{
return node.IsAnyLambda() || node.IsKind(SyntaxKind.AnonymousMethodExpression);
}
public static bool IsAnyAssignExpression(this SyntaxNode node)
{
return SyntaxFacts.IsAssignmentExpression(node.Kind());
}
public static bool IsParentKind(this SyntaxNode node, SyntaxKind kind)
{
return node != null && node.Parent.IsKind(kind);
}
public static bool IsParentKind(this SyntaxToken node, SyntaxKind kind)
{
return node.Parent != null && node.Parent.IsKind(kind);
}
public static bool IsCompoundAssignExpression(this SyntaxNode node)
{
switch (node.Kind())
{
case SyntaxKind.AddAssignmentExpression:
case SyntaxKind.SubtractAssignmentExpression:
case SyntaxKind.MultiplyAssignmentExpression:
case SyntaxKind.DivideAssignmentExpression:
case SyntaxKind.ModuloAssignmentExpression:
case SyntaxKind.AndAssignmentExpression:
case SyntaxKind.ExclusiveOrAssignmentExpression:
case SyntaxKind.OrAssignmentExpression:
case SyntaxKind.LeftShiftAssignmentExpression:
case SyntaxKind.RightShiftAssignmentExpression:
return true;
}
return false;
}
public static bool IsLeftSideOfAssignExpression(this SyntaxNode node)
{
return node.IsParentKind(SyntaxKind.SimpleAssignmentExpression) &&
((AssignmentExpressionSyntax)node.Parent).Left == node;
}
public static bool IsLeftSideOfAnyAssignExpression(this SyntaxNode node)
{
return node.Parent.IsAnyAssignExpression() &&
((AssignmentExpressionSyntax)node.Parent).Left == node;
}
public static bool IsRightSideOfAnyAssignExpression(this SyntaxNode node)
{
return node.Parent.IsAnyAssignExpression() &&
((AssignmentExpressionSyntax)node.Parent).Right == node;
}
public static bool IsVariableDeclaratorValue(this SyntaxNode node)
{
return
node.IsParentKind(SyntaxKind.EqualsValueClause) &&
node.Parent.IsParentKind(SyntaxKind.VariableDeclarator) &&
((EqualsValueClauseSyntax)node.Parent).Value == node;
}
public static BlockSyntax FindInnermostCommonBlock(this IEnumerable<SyntaxNode> nodes)
{
return nodes.FindInnermostCommonNode<BlockSyntax>();
}
public static IEnumerable<SyntaxNode> GetAncestorsOrThis(this SyntaxNode node, Func<SyntaxNode, bool> predicate)
{
var current = node;
while (current != null)
{
if (predicate(current))
{
yield return current;
}
current = current.Parent;
}
}
public static SyntaxNode GetParent(this SyntaxNode node)
{
return node != null ? node.Parent : null;
}
public static ValueTuple<SyntaxToken, SyntaxToken> GetBraces(this SyntaxNode node)
{
var namespaceNode = node as NamespaceDeclarationSyntax;
if (namespaceNode != null)
{
return ValueTuple.Create(namespaceNode.OpenBraceToken, namespaceNode.CloseBraceToken);
}
var baseTypeNode = node as BaseTypeDeclarationSyntax;
if (baseTypeNode != null)
{
return ValueTuple.Create(baseTypeNode.OpenBraceToken, baseTypeNode.CloseBraceToken);
}
var accessorListNode = node as AccessorListSyntax;
if (accessorListNode != null)
{
return ValueTuple.Create(accessorListNode.OpenBraceToken, accessorListNode.CloseBraceToken);
}
var blockNode = node as BlockSyntax;
if (blockNode != null)
{
return ValueTuple.Create(blockNode.OpenBraceToken, blockNode.CloseBraceToken);
}
var switchStatementNode = node as SwitchStatementSyntax;
if (switchStatementNode != null)
{
return ValueTuple.Create(switchStatementNode.OpenBraceToken, switchStatementNode.CloseBraceToken);
}
var anonymousObjectCreationExpression = node as AnonymousObjectCreationExpressionSyntax;
if (anonymousObjectCreationExpression != null)
{
return ValueTuple.Create(anonymousObjectCreationExpression.OpenBraceToken, anonymousObjectCreationExpression.CloseBraceToken);
}
var initializeExpressionNode = node as InitializerExpressionSyntax;
if (initializeExpressionNode != null)
{
return ValueTuple.Create(initializeExpressionNode.OpenBraceToken, initializeExpressionNode.CloseBraceToken);
}
return new ValueTuple<SyntaxToken, SyntaxToken>();
}
public static SyntaxTokenList GetModifiers(this SyntaxNode member)
{
if (member != null)
{
switch (member.Kind())
{
case SyntaxKind.EnumDeclaration:
return ((EnumDeclarationSyntax)member).Modifiers;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.StructDeclaration:
return ((TypeDeclarationSyntax)member).Modifiers;
case SyntaxKind.DelegateDeclaration:
return ((DelegateDeclarationSyntax)member).Modifiers;
case SyntaxKind.FieldDeclaration:
return ((FieldDeclarationSyntax)member).Modifiers;
case SyntaxKind.EventFieldDeclaration:
return ((EventFieldDeclarationSyntax)member).Modifiers;
case SyntaxKind.ConstructorDeclaration:
return ((ConstructorDeclarationSyntax)member).Modifiers;
case SyntaxKind.DestructorDeclaration:
return ((DestructorDeclarationSyntax)member).Modifiers;
case SyntaxKind.PropertyDeclaration:
return ((PropertyDeclarationSyntax)member).Modifiers;
case SyntaxKind.EventDeclaration:
return ((EventDeclarationSyntax)member).Modifiers;
case SyntaxKind.IndexerDeclaration:
return ((IndexerDeclarationSyntax)member).Modifiers;
case SyntaxKind.OperatorDeclaration:
return ((OperatorDeclarationSyntax)member).Modifiers;
case SyntaxKind.ConversionOperatorDeclaration:
return ((ConversionOperatorDeclarationSyntax)member).Modifiers;
case SyntaxKind.MethodDeclaration:
return ((MethodDeclarationSyntax)member).Modifiers;
case SyntaxKind.GetAccessorDeclaration:
case SyntaxKind.SetAccessorDeclaration:
case SyntaxKind.AddAccessorDeclaration:
case SyntaxKind.RemoveAccessorDeclaration:
return ((AccessorDeclarationSyntax)member).Modifiers;
}
}
return default(SyntaxTokenList);
}
public static SyntaxNode WithModifiers(this SyntaxNode member, SyntaxTokenList modifiers)
{
if (member != null)
{
switch (member.Kind())
{
case SyntaxKind.EnumDeclaration:
return ((EnumDeclarationSyntax)member).WithModifiers(modifiers);
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.StructDeclaration:
return ((TypeDeclarationSyntax)member).WithModifiers(modifiers);
case SyntaxKind.DelegateDeclaration:
return ((DelegateDeclarationSyntax)member).WithModifiers(modifiers);
case SyntaxKind.FieldDeclaration:
return ((FieldDeclarationSyntax)member).WithModifiers(modifiers);
case SyntaxKind.EventFieldDeclaration:
return ((EventFieldDeclarationSyntax)member).WithModifiers(modifiers);
case SyntaxKind.ConstructorDeclaration:
return ((ConstructorDeclarationSyntax)member).WithModifiers(modifiers);
case SyntaxKind.DestructorDeclaration:
return ((DestructorDeclarationSyntax)member).WithModifiers(modifiers);
case SyntaxKind.PropertyDeclaration:
return ((PropertyDeclarationSyntax)member).WithModifiers(modifiers);
case SyntaxKind.EventDeclaration:
return ((EventDeclarationSyntax)member).WithModifiers(modifiers);
case SyntaxKind.IndexerDeclaration:
return ((IndexerDeclarationSyntax)member).WithModifiers(modifiers);
case SyntaxKind.OperatorDeclaration:
return ((OperatorDeclarationSyntax)member).WithModifiers(modifiers);
case SyntaxKind.ConversionOperatorDeclaration:
return ((ConversionOperatorDeclarationSyntax)member).WithModifiers(modifiers);
case SyntaxKind.MethodDeclaration:
return ((MethodDeclarationSyntax)member).WithModifiers(modifiers);
case SyntaxKind.GetAccessorDeclaration:
case SyntaxKind.SetAccessorDeclaration:
case SyntaxKind.AddAccessorDeclaration:
case SyntaxKind.RemoveAccessorDeclaration:
return ((AccessorDeclarationSyntax)member).WithModifiers(modifiers);
}
}
return null;
}
public static TypeDeclarationSyntax WithModifiers(
this TypeDeclarationSyntax node, SyntaxTokenList modifiers)
{
switch (node.Kind())
{
case SyntaxKind.ClassDeclaration:
return ((ClassDeclarationSyntax)node).WithModifiers(modifiers);
case SyntaxKind.InterfaceDeclaration:
return ((InterfaceDeclarationSyntax)node).WithModifiers(modifiers);
case SyntaxKind.StructDeclaration:
return ((StructDeclarationSyntax)node).WithModifiers(modifiers);
}
throw new InvalidOperationException();
}
public static bool CheckTopLevel(this SyntaxNode node, TextSpan span)
{
var block = node as BlockSyntax;
if (block != null)
{
return block.ContainsInBlockBody(span);
}
var field = node as FieldDeclarationSyntax;
if (field != null)
{
foreach (var variable in field.Declaration.Variables)
{
if (variable.Initializer != null && variable.Initializer.Span.Contains(span))
{
return true;
}
}
}
var global = node as GlobalStatementSyntax;
if (global != null)
{
return true;
}
var constructorInitializer = node as ConstructorInitializerSyntax;
if (constructorInitializer != null)
{
return constructorInitializer.ContainsInArgument(span);
}
return false;
}
public static bool ContainsInArgument(this ConstructorInitializerSyntax initializer, TextSpan textSpan)
{
if (initializer == null)
{
return false;
}
return initializer.ArgumentList.Arguments.Any(a => a.Span.Contains(textSpan));
}
public static bool ContainsInBlockBody(this BlockSyntax block, TextSpan textSpan)
{
if (block == null)
{
return false;
}
var blockSpan = TextSpan.FromBounds(block.OpenBraceToken.Span.End, block.CloseBraceToken.SpanStart);
return blockSpan.Contains(textSpan);
}
public static bool IsDelegateOrConstructorOrMethodParameterList(this SyntaxNode node)
{
if (!node.IsKind(SyntaxKind.ParameterList))
{
return false;
}
return
node.IsParentKind(SyntaxKind.MethodDeclaration) ||
node.IsParentKind(SyntaxKind.ConstructorDeclaration) ||
node.IsParentKind(SyntaxKind.DelegateDeclaration);
}
}
}

71
ILSpy.AddIn/Utils.cs

@ -1,10 +1,16 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using EnvDTE; using EnvDTE;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.LanguageServices;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.TextManager.Interop;
namespace ICSharpCode.ILSpy.AddIn namespace ICSharpCode.ILSpy.AddIn
{ {
@ -161,5 +167,70 @@ namespace ICSharpCode.ILSpy.AddIn
return result; return result;
} }
public static ITextSelection GetSelectionInCurrentView(IServiceProvider serviceProvider, Func<string, bool> predicate)
{
IWpfTextViewHost viewHost = GetCurrentViewHost(serviceProvider, predicate);
if (viewHost == null)
return null;
return viewHost.TextView.Selection;
}
public static IWpfTextViewHost GetCurrentViewHost(IServiceProvider serviceProvider, Func<string, bool> predicate)
{
IWpfTextViewHost viewHost = GetCurrentViewHost(serviceProvider);
if (viewHost == null)
return null;
ITextDocument textDocument = viewHost.GetTextDocument();
if (textDocument == null || !predicate(textDocument.FilePath))
return null;
return viewHost;
}
public static IWpfTextViewHost GetCurrentViewHost(IServiceProvider serviceProvider)
{
IVsTextManager txtMgr = (IVsTextManager)serviceProvider.GetService(typeof(SVsTextManager));
IVsTextView vTextView = null;
int mustHaveFocus = 1;
txtMgr.GetActiveView(mustHaveFocus, null, out vTextView);
IVsUserData userData = vTextView as IVsUserData;
if (userData == null)
return null;
object holder;
Guid guidViewHost = DefGuidList.guidIWpfTextViewHost;
userData.GetData(ref guidViewHost, out holder);
return holder as IWpfTextViewHost;
}
public static ITextDocument GetTextDocument(this IWpfTextViewHost viewHost)
{
ITextDocument textDocument = null;
viewHost.TextView.TextDataModel.DocumentBuffer.Properties.TryGetProperty(typeof(ITextDocument), out textDocument);
return textDocument;
}
public static VisualStudioWorkspace GetWorkspace(IServiceProvider serviceProvider)
{
return (VisualStudioWorkspace)serviceProvider.GetService(typeof(VisualStudioWorkspace));
}
public static string GetProjectOutputAssembly(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);
}
} }
} }

2
ILSpy.AddIn/source.extension.vsixmanifest

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011"> <PackageManifest Version="2.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata> <Metadata>
<Identity Id="a9120dbe-164a-4891-842f-fb7829273838" Version="3.2.0.3721" Language="en-US" Publisher="ic#code" /> <Identity Id="a9120dbe-164a-4891-842f-fb7829273838" Version="3.2.0.3724" Language="en-US" Publisher="ic#code" />
<DisplayName>ILSpy</DisplayName> <DisplayName>ILSpy</DisplayName>
<Description xml:space="preserve">Integrates the ILSpy decompiler into Visual Studio.</Description> <Description xml:space="preserve">Integrates the ILSpy decompiler into Visual Studio.</Description>
<MoreInfo>http://www.ilspy.net</MoreInfo> <MoreInfo>http://www.ilspy.net</MoreInfo>

Loading…
Cancel
Save