Найти значение параметров конкретного метода с Roslyn - PullRequest
0 голосов
/ 08 февраля 2019

Мне нужно найти все вхождения вызова метода.

Пример: у меня есть такой класс:

public class Foo
{
   public string Bar(string firstParam, string secondParam){}
}

Что мне нужно сделать, это открыть решениеи найдите все способы использования метода Bar в классе Foo.Теперь для каждого использования я хочу получить значение первого параметра, когда он был передан в виде строки.

Так что, если у меня есть эта строка где-то в моем коде:

foo.Bar("some value", "something else")

ТогдаЯ должен получить «некоторое значение».

Теперь, если у меня есть:

foo.Bar(someProperty, "something else")

Тогда я должен игнорировать это.

Я нашел много источников во время своих исследований, ноКажется, я не могу найти способ, который действительно работает.

1 Ответ

0 голосов
/ 12 февраля 2019

Я нашел ответ сам.

Решение основано на шаблоне проекта «Автономный инструмент анализа кода» из Visual Studio.

Поскольку этот шаблон поставляется с открытием решения и созданием рабочей области, я пропущу эту часть.

private static async Task<List<INamedTypeSymbol>> GetDeclarationOfType(string typeName, Solution solution)
{
     var symbols = await SymbolFinder.FindSourceDeclarationsAsync(solution, x => x.Equals(typeName));
     return symbols.Where(x => x.Kind == SymbolKind.NamedType).Cast<INamedTypeSymbol>().ToList();
}

Здесь я просто использую SymbolFinder, чтобы найти объявления типа, которым я являюсьищу.

Для каждого из возвращенных символов я затем получаю членов (методы), имя которых является именем моего класса:

var members = symbol.GetMembers().Where(x => x.Name.Equals("MyMethod"));

Для каждого из соответствующих членов,Затем я получаю все ссылки:

var references = await SymbolFinder.FindReferencesAsync(member, solution);

Решение частично основано на этом , но я изменил его в соответствии со своими потребностями.

Так что для каждой ссылки,Я буду перемещаться по исходному дереву, пока не найду вызов.Когда я найду один, я получу искомый параметр (на основе его индекса здесь), и если он 'kind' - SyntaxKind.StringLiteralExpression, тогда все, что мне нужно, это:

foreach (var referencedSymbol in references)
{
    foreach (var location in referencedSymbol.Locations)
    {
        var theToken = location.Location.SourceTree.GetRoot().FindToken(location.Location.SourceSpan.Start);
        var theNode = theToken.Parent;
        while (!theNode.IsKind(SyntaxKind.InvocationExpression))
        {
            theNode = theNode.Parent;
            if (theNode == null) break; // There isn't an InvocationExpression in this branch of the tree
        }

        if (theNode != null)
        {
            var argument = ((InvocationExpressionSyntax) theNode).ArgumentList.Arguments[searchPattern.ArgumentIndex];
            if (argument.Expression.IsKind(SyntaxKind.StringLiteralExpression))
            {
                textToTranslate.Add(argument.ToString());
            }
        }
    }
}

Вызов ToString() для самого аргумента возвращает фактическое значение аргумента, следовательно, строковое значение аргумента, переданного методу.

Для справки, мой вариант использования заключается в извлечении всех переводимых строк из моего решения,Это очень большое решение (более 170 проектов), которое использует 5 различных способов перевода строк, и мне нужен был способ найти их все в коде автоматически, в инструменте, который можно автоматизировать.

Это можетне будет лучшим решением, но я сделаю по крайней мере сейчас.

...