Java解析器:解析并生成Java代码
JavaParser: parsing and generating Java code
我已阅读 JavaParser manual 并开始构建我自己的示例。我打算实现的是阅读 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);
}
}
我尝试了一些事情(推荐的行)但没有成功。我的主要问题是我找不到在给定 statement
的 childNodes
末尾注入任何代码行的方法,这应该是计数器的增量或 parentNode
这将是初始化。有什么方法可以实现我所描述的吗?
您的代码中的问题如下:
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;"));
解释
- 所有语句列表的第六条语句是while循环
- 这条语句的父节点是方法的主块,也是您要添加指令的地方
- 此对象需要 class 转换为 BlockStmt 才能使用 addStatement 方法
- StringLiteralExpr 是 Expression 的子class,它在这里用于从字符串创建实例。您可以探索许多其他不同的实现方式。
我复制了您的代码,使 JUnit 5 可以正常工作,这就是我得到的结果
public class 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++;
}
}
希望这对您有所帮助。
如果您需要说明如何构建这些对象,请告诉我。
肯定有更聪明的方法和代码显然可以重构,但我想尽可能清楚地为您列出。
干杯
编辑:为了支持语句嵌套并在方法的主块中声明所有计数器变量,可以使用以下方法
statement.findRootNode().getChildNodes().get(0).getChildNodes().get(1).getChildNodes().get(2)
这种方法将从根开始自上而下,并始终指向主块。
用它来添加你的计数器变量。
我已阅读 JavaParser manual 并开始构建我自己的示例。我打算实现的是阅读 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);
}
}
我尝试了一些事情(推荐的行)但没有成功。我的主要问题是我找不到在给定 statement
的 childNodes
末尾注入任何代码行的方法,这应该是计数器的增量或 parentNode
这将是初始化。有什么方法可以实现我所描述的吗?
您的代码中的问题如下:
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;"));
解释
- 所有语句列表的第六条语句是while循环
- 这条语句的父节点是方法的主块,也是您要添加指令的地方
- 此对象需要 class 转换为 BlockStmt 才能使用 addStatement 方法
- StringLiteralExpr 是 Expression 的子class,它在这里用于从字符串创建实例。您可以探索许多其他不同的实现方式。
我复制了您的代码,使 JUnit 5 可以正常工作,这就是我得到的结果
public class 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++;
}
}
希望这对您有所帮助。 如果您需要说明如何构建这些对象,请告诉我。 肯定有更聪明的方法和代码显然可以重构,但我想尽可能清楚地为您列出。
干杯
编辑:为了支持语句嵌套并在方法的主块中声明所有计数器变量,可以使用以下方法
statement.findRootNode().getChildNodes().get(0).getChildNodes().get(1).getChildNodes().get(2)
这种方法将从根开始自上而下,并始终指向主块。 用它来添加你的计数器变量。