I'm modifying my earlier code analyser in C# using Roslyn and again I'm stuck with some changes that I don't exactly know how to apply.
Basing on: https://github.com/dotnet/roslyn/wiki/Getting-Started-C%23-Syntax-Analysis I've created some base to work with in this question: Finding all not inheriting C# classes with Roslyn and changing to inheriting from base object (java-like)
I've parsed and traversed tree to find all method declarations, and their parameters. Basing on VS Syntax Visualiser I've constructed this:
foreach (var c in root1.DescendantNodesAndSelf())
{
var methodDeclaration = c as MethodDeclarationSyntax;
if (methodDeclaration == null)
continue;
if (methodDeclaration.ParameterList != null) //Have parameters
{
foreach (var p in methodDeclaration.ParameterList.Parameters)
{
var parameter = p as ParameterSyntax;
String name, type;
name = parameter.GetLastToken().Value.ToString();
type = parameter.GetFirstToken().Value.ToString();
if (parameter == null)
continue;
if (name == "caller" && type == "string")
{
AttributeSyntax ats = SyntaxFactory.Attribute(SyntaxFactory.QualifiedName(SyntaxFactory.IdentifierName("System.Runtime.CompilerServices"),SyntaxFactory.IdentifierName("CallerMemberName")));
SeparatedSyntaxList<AttributeSyntax> ssl = new SeparatedSyntaxList<AttributeSyntax>();
ssl = ssl.Add(ats);
AttributeListSyntax als = SyntaxFactory.AttributeList(ssl);
var par1 = parameter.AddAttributeLists(als);
//ExpressionSyntax es = SyntaxFactory.AssignmentExpression(SyntaxKind.EqualsValueClause,null,SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression))
//SyntaxFactory.EqualsValueClause(es);
par1 = par1.AddModifiers();
root2 = root2.ReplaceNode(parameter, par1);
}
}
}
else //Don't have parameters
continue;
}
I'm trying to convert method declared like this:
private void testM3(string caller)
into
private void testM3([System.Runtime.CompilerServices.CallerMemberName] string caller = "")
And this part:
//ExpressionSyntax es = SyntaxFactory.AssignmentExpression(SyntaxKind.EqualsValueClause,null,SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression))
//SyntaxFactory.EqualsValueClause(es);
is my failed attempt to achieve creation of equals node.
From what I understand, this part:
AttributeSyntax ats = SyntaxFactory.Attribute(SyntaxFactory.QualifiedName(SyntaxFactory.IdentifierName("System.Runtime.CompilerServices"),SyntaxFactory.IdentifierName("CallerMemberName")));
SeparatedSyntaxList<AttributeSyntax> ssl = new SeparatedSyntaxList<AttributeSyntax>();
ssl = ssl.Add(ats);
AttributeListSyntax als = SyntaxFactory.AttributeList(ssl);
var par1 = parameter.AddAttributeLists(als);
will give me new parameter node in var par1
that includes attribute already, so I need to add default value setting. Please correct me if I'm wrong about this attribute, and I'd like to know how to build this equals expression node properly.
You have a two mistakes:
System.Runtime.CompilerServices.CallerMemberName
is QualifiedName that contains System.Runtime.CompilerServices
as QualifiedName and CallerMemberName
as IdentifierName. System.Runtime.CompilerServices
contains System.Runtime
as QualifiedName and CompilerServices
as IdentifierName. And finally System.Runtime
contains two IdentifierName.
So you need to fix creation of AttributeSyntax
as are shown in the code below:
AttributeSyntax ats = SyntaxFactory.Attribute(
SyntaxFactory.QualifiedName(
SyntaxFactory.QualifiedName(
SyntaxFactory.QualifiedName(SyntaxFactory.IdentifierName("System"), SyntaxFactory.IdentifierName("Runtime")),
SyntaxFactory.IdentifierName("CompilerServices")),
SyntaxFactory.IdentifierName("CallerMemberName")));
EqualsValueClause
shouldn't contain AssignmentExpression
, but should contains a some kind of LiteralExpression
directly. In your case it's StringLiteralExpression
:
var par1 = parameter
.AddAttributeLists(als)
.WithDefault(SyntaxFactory.EqualsValueClause(SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(""))));
By the way, you can use a some helpful method of Nodes, as example ParameterSyntax.WithDefault
, to create a copy of Node (SyntaxTree is immutable in Roslyn) when you want to applay a small changes to existing node and then repace it.