将 ArgumentSyntax 和 VariableDeclaratorSyntax 更改为 InitationExpression

问题描述 投票:0回答:1

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

例如:

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

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;
    }
}
c# string compilation roslyn
1个回答
3
投票

修改方法调用的代码:

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}");
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.