C# -> Roslyn -> 将参数语法和变量声明符语法更改为调用表达式



我在下面编写了程序,该程序可以识别方法的变量和参数中的字符串。我想做的是将这些字符串替换为对我添加到程序中的新方法的方法调用。

前任:

我现在将此 metod 添加到代码中:

public static string StringManipulation(string test)
{
    return test + " new value";
}

然后我想替换:

var test = ""test var"";

自:

var test = StringManipulation(""test var"");

和:

Test(""Testing"");

自:

Test(StringManipulation(""Testing""));

我已经找到了很多关于如何添加或替换整个节点的答案,但在这种情况下,我不想重用一些值,我还没有找到一个好的答案。

法典:

class Program
{
    static void Main(string[] args)
    {
        var workspace = new AdhocWorkspace();
        var projectId = ProjectId.CreateNewId();
        var versionStamp = VersionStamp.Create();
        var projectInfo = ProjectInfo.Create(projectId, versionStamp, "NewProject", "projName", LanguageNames.CSharp);
        var newProject = workspace.AddProject(projectInfo);
        var sourceText = SourceText.From(
            @"using System;
              using System.Collections;
              using System.Linq;
              using System.Text;
              namespace HelloWorld
              {
                  class Program
                  {
                      static void Main(string[] args)
                      {
                          var test = ""test var"";
                          string test1 = ""test string"";
                          String test2 = ""test String"";
                          const string test3 = ""test const""; 
                          readonly string test4 = ""test readonly""; 
                          int i = 0;
                          var i2 = 0;
                          Test(""Testing"");
                          Test(""Testing"", ""Testing 2"", 1);
                      }
                      public static string Test(string test)
                      {
                          return test;
                      }
                      public static string Test(string test, string test2, int test3)
                      {
                          return test + test2 + test3;
                      }
                  }
              }");
        var document = workspace.AddDocument(newProject.Id, "NewFile.cs", sourceText);
        var syntaxRoot = document.GetSyntaxRootAsync().Result;
        var root = (CompilationUnitSyntax)syntaxRoot;
        var invocationExpressions = root.DescendantNodes()
            .OfType<InvocationExpressionSyntax>();
        var mainNode = root.DescendantNodes()
            .OfType<MethodDeclarationSyntax>().FirstOrDefault(x => x.Identifier.ValueText == "Main"
                                                                   && x.ParameterList.Parameters.FirstOrDefault().Identifier.ValueText == "args");
        var editor = DocumentEditor.CreateAsync(document).Result;
        SeparatedSyntaxList<ParameterSyntax> parametersList = new SeparatedSyntaxList<ParameterSyntax>().AddRange
        (new ParameterSyntax[]
            {
                SyntaxFactory.Parameter(SyntaxFactory.Identifier("test")).WithType(SyntaxFactory.ParseTypeName("string")),
            }
        );
        var syntax = SyntaxFactory.ParseStatement("return test + " new value";");
        var newMethod = SyntaxFactory.MethodDeclaration(
            SyntaxFactory.List<AttributeListSyntax>(),
            SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)),
            SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.StringKeyword)),
            null,
            SyntaxFactory.Identifier("StringManipulation"),
            null,
            SyntaxFactory.ParameterList(parametersList),
            SyntaxFactory.List<TypeParameterConstraintClauseSyntax>(),
            SyntaxFactory.Block(syntax),
            null
        );
        newMethod = newMethod.NormalizeWhitespace();
        editor.InsertAfter(mainNode, newMethod);
        foreach (var invocationExpressionSyntax in invocationExpressions)
        {
            foreach (var argument in invocationExpressionSyntax.ArgumentList.Arguments)
            {
                if (argument.Expression.Kind() == SyntaxKind.StringLiteralExpression)
                {
                    Console.WriteLine($"Method: {invocationExpressionSyntax.Expression.GetFirstToken().Value} Parameter: {argument.Expression.GetFirstToken().Value}");
                }
            }
        }
        var localDeclaration = new LocalDeclarationVirtualizationVisitor();
        localDeclaration.Visit(root);
        var localDeclarations = localDeclaration.LocalDeclarations;
        foreach (var localDeclarationStatementSyntax in localDeclarations)
        {
            foreach (VariableDeclaratorSyntax variable in localDeclarationStatementSyntax.Declaration.Variables)
            {
                var stringKind = variable.Initializer.Value.Kind();
                if (stringKind == SyntaxKind.StringLiteralExpression)
                {
                    Console.WriteLine($"Key: {variable.Identifier.Value} Value:{variable.Initializer.Value}");
                }
            }
        }
        var newDocument = editor.GetChangedDocument();
    }
}
class LocalDeclarationVirtualizationVisitor : CSharpSyntaxRewriter
{
    public LocalDeclarationVirtualizationVisitor()
    {
        LocalDeclarations = new List<LocalDeclarationStatementSyntax>();
    }
    public List<LocalDeclarationStatementSyntax> LocalDeclarations { get; set; }
    public override SyntaxNode VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node)
    {
        node = (LocalDeclarationStatementSyntax)base.VisitLocalDeclarationStatement(node);
        LocalDeclarations.Add(node);
        return node;
    }
}

修改方法调用的代码:

foreach (var invocationExpressionSyntax in invocationExpressions)
{
    if (invocationExpressionSyntax.ArgumentList.Arguments.Any(x =>
        x.Expression.Kind() == SyntaxKind.StringLiteralExpression))
    {
        var stringList = new List<string>();
        for (int i = 0; i < invocationExpressionSyntax.ArgumentList.Arguments.Count(); i++)
        {
            if (invocationExpressionSyntax.ArgumentList.Arguments[i].Expression.Kind() == SyntaxKind.StringLiteralExpression)
            {
                stringList.Add("StringManipulation("" + invocationExpressionSyntax.ArgumentList.Arguments[i].Expression.GetFirstToken().ValueText + "")");
            }
            else
            {
                stringList.Add(invocationExpressionSyntax.ArgumentList.Arguments[i].Expression
                    .GetFirstToken().ValueText);
            }
        }
        SeparatedSyntaxList<ArgumentSyntax> arguments = new SeparatedSyntaxList<ArgumentSyntax>().AddRange
        (new ArgumentSyntax[]
            {
                SyntaxFactory.Argument(SyntaxFactory.ParseExpression($"{string.Join(",", stringList)}")),
            }
        );
        var newMethodWithStringObfuscation =
            SyntaxFactory
                .InvocationExpression(SyntaxFactory.IdentifierName(invocationExpressionSyntax.Expression
                    .GetFirstToken().ValueText))
                .WithArgumentList(
                    SyntaxFactory.ArgumentList()
                        .WithOpenParenToken(
                            SyntaxFactory.Token(
                                SyntaxKind.OpenParenToken))
                        .WithArguments(arguments)
                        .WithCloseParenToken(
                            SyntaxFactory.Token(
                                SyntaxKind.CloseParenToken)));
        Console.WriteLine($"Replacing values for method {invocationExpressionSyntax.Expression.GetFirstToken().ValueText}");
        editor.ReplaceNode(invocationExpressionSyntax, newMethodWithStringObfuscation);
    }
}

修改变量的代码:

foreach (var localDeclarationStatementSyntax in localDeclarations)
{
    foreach (VariableDeclaratorSyntax variable in localDeclarationStatementSyntax.Declaration.Variables)
    {
        var stringKind = variable.Initializer.Value.Kind();
        if (stringKind == SyntaxKind.StringLiteralExpression)
        {
            var newVariable = SyntaxFactory.ParseStatement($"string {variable.Identifier.ValueText} = StringManipulation({variable.Initializer.Value});");
            newVariable.NormalizeWhitespace();
            editor.ReplaceNode(variable, newVariable);
            Console.WriteLine($"Key: {variable.Identifier.Value} Value:{variable.Initializer.Value}");
        }
    }
}

最新更新