Etant donné une liste de MethodDeclarationSyntax
, j'aimerais collecter toutes les méthodes d'une solution appelant cette méthode de manière transitoire.
J'ai utilisé le code suivant:
var methods = new Stack<MethodDeclarationSyntax>();
... // fill methods with original method to start from
var visited = new HashSet<MethodDeclarationSyntax>();
while (methods.Count > 0)
{
var method = methods.Pop();
if (!visited.Add(method))
{
continue;
}
var methodSymbol = (await solution.GetDocument(method.SyntaxTree).GetSemanticModelAsync()).GetDeclaredSymbol(method);
foreach (var referencer in await SymbolFinder.FindCallersAsync(methodSymbol, solution))
{
var callingMethod = (MethodDeclarationSyntax) referencer.CallingSymbol.DeclaringSyntaxReferences[0].GetSyntax();
methods.Push(callingMethod);
}
}
Le problème est que MethodDeclarationSyntax
ne semble pas être un singleton, donc cette boucle est exécutée pour toujours, visitant les mêmes méthodes encore et encore.
Quelle est la manière appropriée d’identifier de manière unique une MethodDeclarationSyntax
dans un dictionnaire/hachage?
Modifier 1)
En guise de solution de contournement, j'utilise la MethodDeclarationSyntaxComparer
suivante pour initialiser ma HashSet
, mais elle semble très fragile:
private class MethodDeclarationSyntaxComparer: IEqualityComparer<MethodDeclarationSyntax>
{
public bool Equals(MethodDeclarationSyntax x, MethodDeclarationSyntax y)
{
var xloc = x.GetLocation();
var yloc = y.GetLocation();
return xloc.SourceTree.FilePath == yloc.SourceTree.FilePath &&
xloc.SourceSpan == yloc.SourceSpan;
}
public int GetHashCode(MethodDeclarationSyntax obj)
{
var loc = obj.GetLocation();
return (loc.SourceTree.FilePath.GetHashCode() * 307) ^ loc.SourceSpan.GetHashCode();
}
}
Je me demande si utiliser SyntaxNode
ici est la bonne façon de faire.
Puisque vous utilisez déjà SymbolFinder
et que vous utilisez le modèle sémantique, la meilleure façon de procéder consiste peut-être à utiliser ISymbol
s, plutôt que SyntaxNode
s.
ISymbol
contient déjà la SyntaxReference
s que vous utilisez, donc:
var methods = new Stack<IMethodSymbol>();
... // fill methods with original method to start from
... // convert methods to symbols via semanticModel.GetDeclaredSymbol (node);
var visited = new HashSet<IMethodSymbol>();
while (methods.Count > 0)
{
var method = methods.Pop();
if (!visited.Add(method))
{
continue;
}
foreach (var referencer in await SymbolFinder.FindCallersAsync(method, solution))
{
var callingMethod = (MethodDeclarationSyntax) referencer.CallingSymbol.DeclaringSyntaxReferences[0].GetSyntax();
methods.Push(callingMethod);
}
}
Vous pouvez éventuellement transformer le hashset visité en un Dictionary<IMethodSymbol, IEnumerable<Location>>
, concaténer tous les emplacements et reconstruire ainsi les syntaxes à partir de ce résultat.