Замените trivia на node в Roslyn
например, у меня есть следующий комментарий к документации в моем файле кода C#:
/// add k+5
Я хочу заменить это с узлом
_tst.AddElement(k+5);
как я могу это сделать с помощью C# / Roslyn? Я нашел как добавить эту строку, но не нашел как заменить. Мой код, который добавляет узел:
public static MethodDeclarationSyntax getChangedNode(MethodDeclarationSyntax method)
{
var newmethod = method;
var TestEntryArgName = "_tst";
/* Adding _tst.AddElement(i); */
foreach (var s in newmethod.Body.DescendantNodes())
{
SyntaxTrivia st = SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, " ");
bool fl = false;
bool before = true;
var lt = s.GetLeadingTrivia();
foreach (var triviaEntry in lt)
{
if (triviaEntry.Kind() == SyntaxKind.SingleLineDocumentationCommentTrivia)
{
fl = true;
st = triviaEntry;
break;
}
}
if (!fl)
{
lt = s.GetTrailingTrivia();
before = false;
foreach (var triviaEntry in lt)
{
if (triviaEntry.Kind() == SyntaxKind.SingleLineDocumentationCommentTrivia)
{
fl = true;
st = triviaEntry;
break;
}
}
if (!fl) continue;
}
var commentContents = st.ToString();
char[] delim = { ' ', 'n', 't', 'r' };
var ar = commentContents.Split(delim, StringSplitOptions.RemoveEmptyEntries);
if (ar.Length != 2 || ar[0] != "add") continue;
var lineToAdd = TestEntryArgName + ".AddElement(" + ar[1] + ")";
var linelist = new List<ExpressionStatementSyntax>();
linelist.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression(lineToAdd)));
var childlist = s.Parent.ChildNodes();
foreach (var si in childlist)
{
if (s != si) continue;
if (before) newmethod = newmethod.InsertNodesBefore(si, linelist);
else newmethod = newmethod.InsertNodesAfter(si, linelist);
break;
}
break;
}
return newmethod;
}
мне нужно заменить все такие комментарии в моем методе. Эта функция только вставляет узел, и делает это только один раз.
правка. On в этот момент у меня есть следующее решение, но оно кажется слишком сложным и не очевидным...
public static MethodDeclarationSyntax getChangedNode(MethodDeclarationSyntax method)
{
var TestEntryArgName = "__tst";
/* Adding last param */
var parlist = method.ChildNodes().OfType<ParameterListSyntax>().First();
var newparlist = parlist.AddParameters(SyntaxFactory.Parameter(
SyntaxFactory.Identifier(TestEntryArgName))
.WithType(SyntaxFactory.ParseTypeName("Heap ")));
var newmethod = method.ReplaceNode(parlist, newparlist);
/* Adding __tst.AddElement(i); */
while (true) {
IEnumerable<SyntaxNode> desc;
bool triviaFound;
desc = newmethod.Body.DescendantNodes();
triviaFound = false;
foreach (var s in desc)
{
SyntaxTrivia st = SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, " ");
bool fl = false;
bool before = true;
var lt = s.GetLeadingTrivia();
foreach (var triviaEntry in lt)
{
if (triviaEntry.Kind() == SyntaxKind.SingleLineDocumentationCommentTrivia)
{
fl = true;
st = triviaEntry;
break;
}
}
if (!fl)
{
lt = s.GetTrailingTrivia();
before = false;
foreach (var triviaEntry in lt)
{
if (triviaEntry.Kind() == SyntaxKind.SingleLineDocumentationCommentTrivia)
{
fl = true;
st = triviaEntry;
break;
}
}
if (!fl) continue;
}
var commentContents = st.ToString();
char[] delim = { ' ', 'n', 't', 'r' };
var ar = commentContents.Split(delim, StringSplitOptions.RemoveEmptyEntries);
if (ar.Length != 2 || ar[0] != "add") continue;
var lineToAdd = TestEntryArgName + ".AddElement(" + ar[1] + ")";
var linelist = new List<ExpressionStatementSyntax>();
linelist.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression(lineToAdd)));
var childlist = s.Parent.ChildNodes();
foreach (var si in childlist)
{
if (s != si) continue;
if (before) newmethod = newmethod.InsertNodesBefore(si, linelist);
else newmethod = newmethod.InsertNodesAfter(si, linelist);
break;
}
var newTrvias = newmethod.DescendantTrivia().Where((t) =>
{
if (t.Kind() != SyntaxKind.SingleLineDocumentationCommentTrivia)
return false;
var arr = t.ToString().Split(delim, StringSplitOptions.RemoveEmptyEntries);
return arr.Length == 2 && arr[0] == "add";
});
newmethod = newmethod.ReplaceTrivia(newTrvias.First(), SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, " "));
triviaFound = true;
break;
}
if (!triviaFound) break;
}
return newmethod;
}
2 ответов
то, что вы ищете, вероятно, CSharpSyntaxRewriter.Это класс в roslyn, который посещает каждый узел, токен и мелочи в синтаксической модели вашего кода. Вы можете сделать свой собственный рерайтером, который переопределяет VisitTrivia и возвращает выражение, которое вы хотите получить.Например:
public class MyRewriter : CSharpSyntaxRewriter
{
public MyRewriter(): base(true)
{
}
public override SyntaxTrivia VisitTrivia(SyntaxTrivia trivia)
{
if(trivia.Kind() == SyntaxKind.SingleLineDocumentationCommentTrivia)
{
string xml = trivia.ToFullString();
var TestEntryArgName = "__tst";
char[] delim = { ' ', '\n', '\t', '\r' };
var ar = xml.Split(delim, StringSplitOptions.RemoveEmptyEntries);
if (ar.Length != 3 || ar[1] != "add")
{
return base.VisitTrivia(trivia);
}
var lineToAdd = TestEntryArgName + ".AddElement(" + ar[2] + ")";
var expression = SyntaxFactory.SyntaxTrivia(SyntaxKind.SingleLineCommentTrivia, lineToAdd);
return expression;
}
return base.VisitTrivia(trivia);
}
}
пример использования:
var myRewriter = new MyRewriter();
string code = "";
using (StreamReader sr = new StreamReader("Program.cs"))
{
code = sr.ReadToEnd();
}
var tree = CSharpSyntaxTree.ParseText(code);
var node = tree.GetRoot();
using(StreamWriter sw = new StreamWriter("Program.cs"))
{
sw.Write(myRewriter.Visit(node));
}
Я нашел простое решение, и я думаю, оно мне подходит, но, я знаю, его нельзя назвать "правильным" решением, потому что он имеет дело с исходным кодом. Во всяком случае:
public static MethodDeclarationSyntax getChangedNode(MethodDeclarationSyntax newmethod)
{
/* Adding __tst.AddElement(i); */
while (true)
{
var desc = newmethod.Body.DescendantTrivia().Where((t) => t.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia));
var triviaFound = false;
foreach (var s in desc)
{
var commentContents = s.ToString();
char[] delim = { ' ', '\n', '\t', '\r' };
var ar = commentContents.Split(delim, StringSplitOptions.RemoveEmptyEntries);
if (ar.Length != 2 || ar[0] != "add") continue;
var lineToAdd = "\r\n__tst.AddElement(" + ar[1] + ");\r\n";
newmethod = CSharpSyntaxTree.ParseText(newmethod.GetText().Replace(s.FullSpan, lineToAdd))
.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().First();
triviaFound = true;
break;
}
if (!triviaFound) break;
}
return newmethod;
}