Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get all method calls

Tags:

c#

vssdk

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;
}
like image 382
FCin Avatar asked Jul 19 '19 18:07

FCin


People also ask

How do you call all methods in a class?

Write the callAll() method to actually call each method explicitly without reflection. This allows for flexibility in subclassing. It also allows you to deal with methods which have parameters. It also allows you to bypass methods which don't apply.

How to Find where a method is called in eclipse?

Select mymethod() and press ctrl + alt + h . To see some detailed Information about any method you can use this by selecting that particular Object or method and right click. you can see the "OpenCallHierarchy" ( Ctrl + Alt + H ).

How to define methods in C#?

Methods are declared in a class, struct, or interface by specifying the access level such as public or private , optional modifiers such as abstract or sealed , the return value, the name of the method, and any method parameters. These parts together are the signature of the method.

How can I see the call hierarchy code in Visual Studio?

To display the Call Hierarchy window, right-click in the code editor on the name of a method, property, or constructor call, and then select View Call Hierarchy.


1 Answers

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;
                ...
            }
        }
    }
}
like image 79
Simon Mourier Avatar answered Sep 20 '22 06:09

Simon Mourier