简体   繁体   中英

Get all method calls

Let's say I have simple project

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) { }
}

How can I extract AddItem(new Item()); using VSSDK? I want to know what parameters are passed to it and at what line it is in the text editor.

I tried looking for CodeElement.Kind , but unfortunately vsCMElement.vsCMElementFunctionInvokeStmt doesn't return anything. Is there any other way of extracting this information?

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

With modern version of Visual Studio, if you're interested in the languages services, then you don't have to use DTE and the old FileCodeModel stuff, but you can leverage The .NET Compiler Platform SDK (aka Roslyn) which is the parsing backbone now.

So, first thing to do is add the latest Microsoft.CodeAnalysis.CSharp.Workspaces nuget package (roslyn for C#) and the Microsoft.VisualStudio.LanguageServices nuget (Visual Studio Roslyn workspace) to your package project. Note you may have to fix the now-usual nuget mess...

Once this is done, you can write this kind of code instead of yours:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM