获取所有方法调用
Get all method calls
假设我有一个简单的项目
class Program : TestBase
{
static void Main(string[] args)
{
}
public void Test()
{
AddItem(new Item());
AddItem(new Item());
}
}
public class Item { }
public class TestBase
{
public virtual void AddItem(Item vertex) { }
}
如何使用 VSSDK 提取 AddItem(new Item());
?我想知道传递给它的参数是什么以及它在文本编辑器中的哪一行。
我尝试寻找 CodeElement.Kind
,但不幸的是 vsCMElement.vsCMElementFunctionInvokeStmt
没有 return 任何东西。有没有其他方法可以提取此信息?
public static async Task InitializeAsync(AsyncPackage package)
{
// ...
_dte = (await package.GetServiceAsync(typeof(DTE))) as DTE2;
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
var sandboxProject = _dte.Solution.Projects;
var codeItems = new List<string>();
if (!ThreadHelper.CheckAccess())
return;
foreach (Project project in sandboxProject)
{
var projectItems = GetProjectItemsRecursively(project.ProjectItems);
foreach (ProjectItem projectItem in projectItems)
{
foreach (CodeElement element in projectItem.FileCodeModel.CodeElements)
{
codeItems.AddRange(GetItems(element).Select(codeItem => $"{codeItem.FullName} : {codeItem.Kind.ToString()}"));
}
}
}
}
private static IEnumerable<CodeElement> GetItems(CodeElement items)
{
var ret = new List<CodeElement>();
if (items == null)
return ret;
foreach (CodeElement item in items.Children)
{
ret.Add(item);
ret.AddRange(GetItems(item));
}
return ret;
}
private static List<ProjectItem> GetProjectItemsRecursively(ProjectItems items)
{
var ret = new List<EnvDTE.ProjectItem>();
if (items == null) return ret;
foreach (ProjectItem item in items)
{
ret.Add(item);
ret.AddRange(GetProjectItemsRecursively(item.ProjectItems));
}
return ret;
}
对于 Visual Studio 的现代版本,如果您对语言服务感兴趣,那么您不必使用 DTE 和旧的 FileCodeModel 东西,但您可以利用 The .NET Compiler Platform SDK(又名 Roslyn)现在是解析 backbone。
因此,首先要做的是将最新的 Microsoft.CodeAnalysis.CSharp.Workspaces nuget package (roslyn for C#) and the Microsoft.VisualStudio.LanguageServices nuget(Visual Studio Roslyn 工作区)添加到您的包项目中。请注意,您可能需要修复 now-usual nuget 混乱...
完成后,您可以编写这种代码来代替您的代码:
// get component model & Visual Studio Roslyn workspace
var componentModel = await package.GetServiceAsync<SComponentModel, IComponentModel>();
var workspace = componentModel.GetService<VisualStudioWorkspace>(); // requires "Microsoft.VisualStudio.LanguageServices" nuget package
// enum all the projects
foreach (var project in workspace.CurrentSolution.Projects)
{
// enum all the documents in the project
foreach (var doc in project.Documents)
{
// get the semantic model & syntax tree root
var model = await doc.GetSemanticModelAsync();
var root = await model.SyntaxTree.GetRootAsync();
// find a class named "TestBase"
// ClassDeclarationSyntax etc. requires "Microsoft.CodeAnalysis.CSharp.Workspaces" nuget package
var myClass = root.DescendantNodes()
.OfType<ClassDeclarationSyntax>()
.FirstOrDefault(c => c.Identifier.Text == "TestBase");
if (myClass != null)
{
// find a method named "AddItem"
var myMethod = myClass.Members.Where(m => m.Kind() == SyntaxKind.MethodDeclaration)
.OfType<MethodDeclarationSyntax>()
.FirstOrDefault(m => m.Identifier.Text == "AddItem");
if (myMethod != null)
{
// get the list of method parameters
var parameters = myMethod.ParameterList.Parameters;
...
// get the start line for the method declaration
var lineSpan = model.SyntaxTree.GetLineSpan(myMethod.Span);
int startLine = lineSpan.StartLinePosition.Line;
...
}
}
}
}
假设我有一个简单的项目
class Program : TestBase
{
static void Main(string[] args)
{
}
public void Test()
{
AddItem(new Item());
AddItem(new Item());
}
}
public class Item { }
public class TestBase
{
public virtual void AddItem(Item vertex) { }
}
如何使用 VSSDK 提取 AddItem(new Item());
?我想知道传递给它的参数是什么以及它在文本编辑器中的哪一行。
我尝试寻找 CodeElement.Kind
,但不幸的是 vsCMElement.vsCMElementFunctionInvokeStmt
没有 return 任何东西。有没有其他方法可以提取此信息?
public static async Task InitializeAsync(AsyncPackage package)
{
// ...
_dte = (await package.GetServiceAsync(typeof(DTE))) as DTE2;
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
var sandboxProject = _dte.Solution.Projects;
var codeItems = new List<string>();
if (!ThreadHelper.CheckAccess())
return;
foreach (Project project in sandboxProject)
{
var projectItems = GetProjectItemsRecursively(project.ProjectItems);
foreach (ProjectItem projectItem in projectItems)
{
foreach (CodeElement element in projectItem.FileCodeModel.CodeElements)
{
codeItems.AddRange(GetItems(element).Select(codeItem => $"{codeItem.FullName} : {codeItem.Kind.ToString()}"));
}
}
}
}
private static IEnumerable<CodeElement> GetItems(CodeElement items)
{
var ret = new List<CodeElement>();
if (items == null)
return ret;
foreach (CodeElement item in items.Children)
{
ret.Add(item);
ret.AddRange(GetItems(item));
}
return ret;
}
private static List<ProjectItem> GetProjectItemsRecursively(ProjectItems items)
{
var ret = new List<EnvDTE.ProjectItem>();
if (items == null) return ret;
foreach (ProjectItem item in items)
{
ret.Add(item);
ret.AddRange(GetProjectItemsRecursively(item.ProjectItems));
}
return ret;
}
对于 Visual Studio 的现代版本,如果您对语言服务感兴趣,那么您不必使用 DTE 和旧的 FileCodeModel 东西,但您可以利用 The .NET Compiler Platform SDK(又名 Roslyn)现在是解析 backbone。
因此,首先要做的是将最新的 Microsoft.CodeAnalysis.CSharp.Workspaces nuget package (roslyn for C#) and the Microsoft.VisualStudio.LanguageServices nuget(Visual Studio Roslyn 工作区)添加到您的包项目中。请注意,您可能需要修复 now-usual nuget 混乱...
完成后,您可以编写这种代码来代替您的代码:
// get component model & Visual Studio Roslyn workspace
var componentModel = await package.GetServiceAsync<SComponentModel, IComponentModel>();
var workspace = componentModel.GetService<VisualStudioWorkspace>(); // requires "Microsoft.VisualStudio.LanguageServices" nuget package
// enum all the projects
foreach (var project in workspace.CurrentSolution.Projects)
{
// enum all the documents in the project
foreach (var doc in project.Documents)
{
// get the semantic model & syntax tree root
var model = await doc.GetSemanticModelAsync();
var root = await model.SyntaxTree.GetRootAsync();
// find a class named "TestBase"
// ClassDeclarationSyntax etc. requires "Microsoft.CodeAnalysis.CSharp.Workspaces" nuget package
var myClass = root.DescendantNodes()
.OfType<ClassDeclarationSyntax>()
.FirstOrDefault(c => c.Identifier.Text == "TestBase");
if (myClass != null)
{
// find a method named "AddItem"
var myMethod = myClass.Members.Where(m => m.Kind() == SyntaxKind.MethodDeclaration)
.OfType<MethodDeclarationSyntax>()
.FirstOrDefault(m => m.Identifier.Text == "AddItem");
if (myMethod != null)
{
// get the list of method parameters
var parameters = myMethod.ParameterList.Parameters;
...
// get the start line for the method declaration
var lineSpan = model.SyntaxTree.GetLineSpan(myMethod.Span);
int startLine = lineSpan.StartLinePosition.Line;
...
}
}
}
}