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 访问它,所以我假设还有另一种方法可以做到这一点。
问题:
当我尝试查找对变量的所有引用时,仅返回声明,但我没有找到任何其他引用我该如何解决这个问题?
一旦我有了参考,我如何确定它是否是一个作业?
我最初找不到任何参考资料,因为我的文档不在正确的解决方案中。分析器没有为您提供获得解决方案的方法,正如@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);
我正在尝试编写一个分析器,我需要找到使用 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 访问它,所以我假设还有另一种方法可以做到这一点。
问题:
当我尝试查找对变量的所有引用时,仅返回声明,但我没有找到任何其他引用我该如何解决这个问题?
一旦我有了参考,我如何确定它是否是一个作业?
我最初找不到任何参考资料,因为我的文档不在正确的解决方案中。分析器没有为您提供获得解决方案的方法,正如@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);