JavaParser: анализ и генерация кода Java - PullRequest
1 голос
/ 29 октября 2019

Я прочитал руководство по JavaParser и начал создавать свои собственные примеры. То, что я намерен достичь, это прочитать код Java и вставить в него новые строки кода. В частности, я хочу инициализировать счетчик перед каждым оператором if и while, а также внутри тела оператора, чтобы увеличить счетчик. Моя цель для этого состоит в том, чтобы запустить новый код для указанного набора прогонов и наблюдать, сколько раз выполняется каждая ветвь. Я использую JavaParser для анализа и добавления кода, потому что я хочу сгенерировать и запустить все автоматически.

Например, у нас есть следующий простой фрагмент кода:

if (x>4) { 
   x=4; 
} 
else { 
   x=4; 
} 
while (i<x) {
   i++;
} 

И послеЯ хотел бы иметь что-то вроде следующего:

int countA=0; 
int countB=0;            
if (x>4) { 
   x=4; 
   countA++;
} 
else { 
   x=4; 
   countB++;
} 
int countC=0;
while (i<x) {
   i++;
   countC++;
} 

Мой код до сих пор:

public static void main (String[] args) throws Exception {          
              CompilationUnit cu = StaticJavaParser.parse("class X{void x(){" +
              "    if (x>4) {  " +
              "      x=4;  " +
              "    }  " +
              "    else {  " +
              "        x=4;  " +
              "    }  " +
              "    while (i<x) {  " +
              "        i++;  " +
              "    }  " +
              "    }}");

              cu.findAll(Statement.class).forEach(statement -> {             
                  if (statement.isIfStmt()) {
                      //System.out.println(statement.getChildNodes().get(0));
                     // System.out.println(statement.getParentNodeForChildren().toString());
                     // statement.getChildNodes().add(statement.getChildNodes().get(0));

                     // System.out.println(statement.toString());
                  }
                  if (statement.isWhileStmt()) {
                     // System.out.println();
                  }
              });
              System.out.println(cu);
            }
}

Я пробовал некоторые вещи (зарекомендовавшие себя строки), но безуспешно. Моя главная проблема заключается в том, что я не могу найти способ ввести какую-либо строку кода в конце childNodes данного statement, который предположительно будет увеличивать счетчик или в конце parentNode, чтобыть инициализацией. Есть ли способ достичь того, что я описываю?

1 Ответ

1 голос
/ 29 октября 2019

Проблема в вашем коде заключается в следующем:

if (statement.isIfStmt()) {

Условие четко указывает на то, что вы имеете дело с оператором if, и, следовательно, вы не можете добавить инструкцию. Вам нужно получить элемент n + 1 (где n - индекс оператора if), а затем использовать:

cu.findAll(Statement.class).get(2).asBlockStmt().addStatement("countA++;")

Есть несколько способов определить выражение, которое нужно добавить, здесьЯ использую простую строку для ясности, но проверяю рабочий пример на предмет реального синтаксиса.

Пока вы можете использовать ту же технику, но она будет более сложной. Для простоты объявления ваших счетчиков будут добавлены в начале метода с использованием следующего подхода:

((BlockStmt)cu.findAll(Statement.class).get(6).getParentNode().get()).addStatement(0, new StringLiteralExpr("int b = 1;"));

Exaplanation

  • шестая инструкциясписок всех операторов - это цикл while
  • родительский узел этого оператора является основным блоком метода и там, где выхотите добавить свои инструкции
  • Этот объект должен быть класс, приведенный к BlockStm t, чтобы иметь возможность использовать метод addStatement
  • StringLiteralExpr являетсяподкласс Expression, и здесь он используется для создания экземпляра из строки. Существует множество других реализаций, которые вы можете исследовать.

Я воспроизвел ваш код, создав рабочий JUnit 5, и вот результат, который я получил

открытый класс ParserTest {

String counterName = "count";
Integer counterIndex = 1;

@Test
public void main() {

    CompilationUnit cu = StaticJavaParser.parse("class X{void x(){" + "    if (x>4) {  " + "      x=4;  "
            + "    }  " + "    else {  " + "        x=4;  " + "    }  " + "    while (i<x) {  " + "        i++;  "
            + "    }  " + "    }}");

    cu.findAll(Statement.class).forEach(statement -> {
        if (statement.isIfStmt()) {

            // Add counter declaration in main block for the if
            String counterNameAndIndexIf = counterName + counterIndex++;
            // Create expression using StaticJavaParser
            Expression ifCounterExpression = StaticJavaParser
                    .parseVariableDeclarationExpr(" int " + counterNameAndIndexIf + " = 0");
            ((BlockStmt) statement.getParentNode().get()).addStatement(0, ifCounterExpression);

            // Add counter declaration in main block for the else
            String counterNameAndIndexElse = counterName + counterIndex++;
            // Create expression using StaticJavaParser
            Expression elseCounterExpression = StaticJavaParser
                    .parseVariableDeclarationExpr("int " + counterNameAndIndexElse + " = 0");
            ((BlockStmt) statement.getParentNode().get()).addStatement(0, elseCounterExpression);

            // Add if increment
            Expression ifIncrementExpression = StaticJavaParser.parseExpression(counterNameAndIndexIf + "++");
            ((BlockStmt) statement.getChildNodes().get(1)).addStatement(ifIncrementExpression);

            // Add else increment
            Expression elseIncrementExpression = StaticJavaParser.parseExpression(counterNameAndIndexElse + "++");
            ((BlockStmt) statement.getChildNodes().get(2)).addStatement(elseIncrementExpression);
        }
        if (statement.isWhileStmt()) {
            String counterNameAndIndexWhile = counterName + counterIndex++;
            Expression whileCounterExpression = StaticJavaParser
                    .parseVariableDeclarationExpr(" int " + counterNameAndIndexWhile + " = 0");
            ((BlockStmt) statement.getParentNode().get()).addStatement(0, whileCounterExpression);

            // Add while increment
            Expression whileIncrementExpression = StaticJavaParser.parseExpression(counterNameAndIndexWhile + "++");
            ((BlockStmt) statement.getChildNodes().get(1)).addStatement(whileIncrementExpression);

        }
    });
    System.out.println(cu);
}

И результат

class X {

void x() {
    int count3 = 0;
    int count2 = 0;
    int count1 = 0;
    if (x > 4) {
        x = 4;
        count1++;
    } else {
        x = 4;
        count2++;
    }
    while (i < x) {
        i++;
        count3++;
    }
}

Надеюсь, это поможет. Дайте мне знать, если вам нужны разъяснения о том, как построить любой из этих объектов. Конечно, есть более разумные способы, и код может быть реорганизован, но я хотел, чтобы он был максимально понятным для вас.

Cheers

РЕДАКТИРОВАТЬ: для поддержки вложения операторов и объявления всехПеременные счетчика в главном блоке метода могут быть использованы следующим образом

statement.findRootNode().getChildNodes().get(0).getChildNodes().get(1).getChildNodes().get(2)

Этот подход будет начинаться сверху вниз от корня и всегда будет указывать на основной блок. Используйте его для добавления переменных счетчика.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...