Reputation: 2292
I can get a list from the solution of all calls to a particuliar method using the following code:
var createCommandList = new List<MethodSymbol>();
INamedTypeSymbol interfaceSymbol =
(from p
in solution.Projects
select p.GetCompilation().GetTypeByMetadataName(
"BuySeasons.BsiServices.DataResource.IBsiDataConnection")
).FirstOrDefault();
foreach (ISymbol symbol in interfaceSymbol.GetMembers("CreateCommand"))
{
if (symbol.Kind == CommonSymbolKind.Method
&& symbol is MethodSymbol)
{
createCommandList.Add(symbol as MethodSymbol);
}
}
foreach (MethodSymbol methodSymbol in createCommandList)
{
foreach (ReferencedSymbol referenceSymbol
in methodSymbol.FindReferences(solution))
{
foreach (ReferenceLocation referenceLocation
in from l
in referenceSymbol.Locations
orderby l.Document.FilePath
select l)
{
if (referenceLocation.Location.GetLineSpan(false)
.StartLinePosition.Line ==
referenceLocation.Location.GetLineSpan(false)
.EndLinePosition.Line)
{
Debug.WriteLine("{0} {1} at {2} {3}/{4} - {5}",
methodSymbol.Name,
"(" + String.Join(",",
(from p
in methodSymbol.Parameters
select p.Type.Name + " " + p.Name).ToArray()
) + ")",
Path.GetFileName(referenceLocation.Location.GetLineSpan(false)
.Path),
referenceLocation.Location.GetLineSpan(false)
.StartLinePosition.Line,
referenceLocation.Location.GetLineSpan(false)
.StartLinePosition.Character,
referenceLocation.Location.GetLineSpan(false)
.EndLinePosition.Character));
}
else
{
throw new ApplicationException("Call spans multiple lines");
}
}
}
}
But this gives me a list of ReferencedSymbol
. Although this gives me the file and line number that the method is called from I would also like to get the specific arguments that the method is called with. How can I either convert what I have or get the same information with Roslyn? (notice the I first load the solution with the Solution.Load
method and then loop through to find out where the method is defined/declared (createCommandList
)).
Upvotes: 14
Views: 6187
Reputation: 2972
I have discovered another way of getting the Parameter list from a method that might work for others as well.
Say I have the following method that has two parameters:
public string DebugPage(string enabled, string show){
//do stuff
}
Then you get your nodes however you wish. For example this gives me a list of public methods:
IEnumerable<MethodDeclarationSyntax> methods = from m in root.DescendantNodes().OfType<MethodDeclarationSyntax>() where m.Modifiers.ToString().Contains("public") select m;
Then I can iterate through that list of methods to get at the method's ParameterList property which is exposed to make this operation really easy. By the end of this loop the list parameters
will hold the names of each parameter in the method (in the example of the Debug
method above it will hold the values enabled
and show
as expected):
var parameters = new List<string>();
foreach (var method in methods)
{
foreach (var n in method.ParameterList.Parameters)
{
var parameterName = n.Identifier.Text;
parameters.Add(parameterName);
}
}
Upvotes: 1
Reputation: 6902
You are already using Roslyn here. When you have a referenceSymbol
, you can get at the Method Declaration Syntax and then look down into the tree to get the Parameter list.
I've inserted a arguments
variable that uses your referenceSymbol
:
// Snip start
foreach (MethodSymbol methodSymbol in createCommandList)
{
foreach (ReferencedSymbol referenceSymbol
in methodSymbol.FindReferences(solution))
{
var arguments = referenceSymbol.Definition.DeclaringSyntaxNodes.First()
.DescendantNodes().OfType<ParameterSyntax>().ToList();
foreach (ReferenceLocation referenceLocation in
from l
in referenceSymbol.Locations
orderby l.Document.FilePath
select l)
{
// Snip end
When you perform a Debug output, you can then use that list of arguments to get the names.
My solution requires getting the First()
of the DeclaringSyntaxNodes
, which I don't like very much but cannot find another way to get at the Descendant Nodes of the Syntax Tree.
Upvotes: 2
Reputation: 2016
You can search the syntax tree of the reference at the specific source location it occurs to find the node you are looking for. You'll need to use a call like DescendentNodes from the tree's root node and you'll probably need to request the language specific node type you are looking for. Once you have the node in the referecing tree you can then use that tree's semantic model to tell you other information about the arguments.
Upvotes: 0