获取所有方法调用

时间:2019-07-19 18:58:08

标签: c# vssdk

假设我有一个简单的项目

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没有返回任何内容。还有其他提取信息的方法吗?

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;
}

1 个答案:

答案 0 :(得分:1)

使用Visual Studio的现代版本,如果您对语言服务感兴趣,则不必使用DTE和旧的FileCodeModel东西,但是可以利用The .NET Compiler Platform SDK(又名Roslyn)现在解析主干。

因此,首先要做的是将最新的Microsoft.CodeAnalysis.CSharp.Workspaces nuget包(对于C#为roslyn)和Microsoft.VisualStudio.LanguageServices nuget(Visual Studio Roslyn工作区)添加到您的包项目中。请注意,您可能必须修复现在常见的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;
                ...
            }
        }
    }
}