Roslyn 查找对字段所做的所有分配

Roslyn Find All assignments made to a Field

我正在尝试编写一个分析器,我需要找到使用 Roslyn 对字段所做的所有分配。

private async static Task<bool> VariableDoesNotMutate(SyntaxNodeAnalysisContext context, VariableDeclaratorSyntax firstVariable)
{
    var variableSymbol = context.SemanticModel.GetDeclaredSymbol(firstVariable);
    var references = await SymbolFinder.FindReferencesAsync(variableSymbol, context.GetSolution());

    foreach (var reference in references)
    {
        //How do I check for assignment?
    }

    //need to filter by assignments
    return references.Count() > 1;
}

我听说使用 symbolFinder 是正确的,但我不知道该怎么做。
符号查找器需要一个解决方案,我只能通过 hack 访问它,所以我假设还有另一种方法可以做到这一点。

问题:

  1. 当我尝试查找对变量的所有引用时,仅返回声明,但我没有找到任何其他引用我该如何解决这个问题?

  2. 一旦我有了参考,我如何确定它是否是一个作业?

我最初找不到任何参考资料,因为我的文档不在正确的解决方案中。分析器没有为您提供获得解决方案的方法,正如@SLaks 所说,出于性能原因,您不应该这样做:

要获得解决方案您需要反映到 AnalyzerOptions 我已经写了一个答案如何这样做 here

但是,如果需要,您可以执行此操作获取解决方案中的等效符号并解决该问题。这有潜在危险

static async Task<ISymbol> GetEquivalentSymbol(SyntaxNodeAnalysisContext context, FieldDeclarationSyntax field, CancellationToken cancellationToken)
{
    var solution = context.GetSolution();
    var classDeclaration = field.Ancestors().OfType<ClassDeclarationSyntax>().FirstOrDefault();
    var namespaceDeclaration = field.Ancestors().OfType<NamespaceDeclarationSyntax>().FirstOrDefault();

    var className = classDeclaration?.Identifier.ValueText;

    var initialVariable = field.Declaration.Variables.FirstOrDefault();

    foreach (var project in solution.Projects)
    {
        foreach (var document in project.Documents)
        {
            var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
            var root = await document.GetSyntaxRootAsync(cancellationToken);
            if (null != namespaceDeclaration)
            {
                var namespaceNode = root.DescendantNodes().OfType<NamespaceDeclarationSyntax>()
                    .FirstOrDefault(node => node.Name.ToString() == namespaceDeclaration.Name.ToString());
                if (null == namespaceNode)
                {
                    continue;
                }
            }

            var classNode = root.DescendantNodes()
                .OfType<ClassDeclarationSyntax>()
                .FirstOrDefault(node => node.Identifier.ValueText == className);

            var desiredField = classNode?.DescendantNodes().OfType<FieldDeclarationSyntax>()
                .FirstOrDefault(x => x.Declaration.Variables.First().Identifier.ValueText == initialVariable.Identifier.ValueText);

            if (desiredField == null)
            {
                continue;
            }

            var symbol = semanticModel.GetDeclaredSymbol(desiredField.Declaration.Variables.FirstOrDefault());
            return symbol;
        }
    }

    return null;
}

然后你可以像这样获取参考文献:

var equivalentSymbol = await GetEquivalentSymbol(context, field, cancellationToken);

var references = await SymbolFinder.FindReferencesAsync(equivalentSymbol, context.GetSolution(), cancellationToken);