/* block.statement : "{" statement* "}"
*/
private Stmnt parseBlock(SymbolTable tbl) throws CompileError {
+ int blockLineNumber = lex.getLineNumber();
if (lex.get() != '{')
throw new SyntaxError(lex);
Stmnt body = null;
SymbolTable tbl2 = new SymbolTable(tbl);
while (lex.lookAhead() != '}') {
+ int lineNumber = lex.getLineNumber();
Stmnt s = parseStatement(tbl2);
if (s != null)
- body = (Stmnt)ASTList.concat(body, new Stmnt(BLOCK, s, lex.getLineNumber()));
+ body = (Stmnt)ASTList.concat(body, new Stmnt(BLOCK, s, lineNumber));
}
lex.get(); // '}'
if (body == null)
- return new Stmnt(BLOCK, lex.getLineNumber()); // empty block
+ return new Stmnt(BLOCK, blockLineNumber); // empty block
return body;
}
private Stmnt parseIf(SymbolTable tbl) throws CompileError {
int t = lex.get(); // IF
ASTree expr = parseParExpression(tbl);
+ int exprLineNum = lex.getLineNumber();
Stmnt thenp = parseStatement(tbl);
+ int thenLineNum = lex.getLineNumber();
Stmnt elsep;
if (lex.lookAhead() == ELSE) {
lex.get();
else
elsep = null;
- return new Stmnt(t, expr, new ASTList(thenp, new ASTList(elsep, lex.getLineNumber()), lex.getLineNumber()), lex.getLineNumber());
+ return new Stmnt(t, expr, new ASTList(thenp, new ASTList(elsep, lex.getLineNumber()), thenLineNum), exprLineNum);
}
/* while.statement : WHILE "(" expression ")" statement
{
int t = lex.get(); // WHILE
ASTree expr = parseParExpression(tbl);
+ int lineNumber = lex.getLineNumber();
Stmnt body = parseStatement(tbl);
- return new Stmnt(t, expr, body, lex.getLineNumber());
+ return new Stmnt(t, expr, body, lineNumber);
}
/* do.statement : DO statement WHILE "(" expression ")" ";"
if (lex.get() != '(')
throw new SyntaxError(lex);
+ int expr1LineNumber = lex.getLineNumber();
if (lex.lookAhead() == ';') {
lex.get();
expr1 = null;
else
expr1 = parseDeclarationOrExpression(tbl2, true);
+ int expr2LineNumber = lex.getLineNumber();
if (lex.lookAhead() == ';')
expr2 = null;
else
if (lex.get() != ';')
throw new CompileError("; is missing", lex);
+ int expr3LineNumber = lex.getLineNumber();
if (lex.lookAhead() == ')')
expr3 = null;
else
Stmnt body = parseStatement(tbl2);
return new Stmnt(t, expr1, new ASTList(expr2,
- new ASTList(expr3, body, lex.getLineNumber()), lex.getLineNumber()), lex.getLineNumber());
+ new ASTList(expr3, body, expr3LineNumber), expr2LineNumber), expr1LineNumber);
}
/* switch.statement : SWITCH "(" expression ")" "{" switch.block "}"
--- /dev/null
+package javassist;
+
+import junit.framework.TestCase;
+
+public class LineNumberTest extends TestCase {
+ private final ClassPool loader = ClassPool.getDefault();
+ private static int classNumber = 0;
+
+ public void testComma() {
+ doTestCompile(String.join("\n",
+ "public void run() {",
+ " return",
+ "}"), "line 3: syntax error near \" return\n}\"");
+ }
+
+ public void testException() {
+ doTestRuntime(String.join("\n",
+ "public void run() {",
+ " throw new java.lang.RuntimeException();",
+ "}"), 0, 5);
+ }
+
+ public void testIf() {
+ doTestRuntime(String.join("\n",
+ "public void run() {",
+ " if (throwException()) {",
+ " }",
+ "}"), 1, 5);
+ }
+
+ public void testWhile() {
+ doTestRuntime(String.join("\n",
+ "public void run() {",
+ " while (throwException()) {",
+ " }",
+ "}"), 1, 5);
+ }
+
+ public void testFor() {
+ doTestRuntime(String.join("\n",
+ "public void run() {",
+ " for (; throwException(); ) {",
+ " ",
+ " }",
+ "}"), 1, 5);
+ }
+
+ private void doTestCompile(String src, String msg) {
+ CtClass testClass = loader.makeClass("javassist.LineNumberCompileTest" + classNumber++);
+ try {
+ testClass.addMethod(CtMethod.make(src, testClass));
+ } catch (CannotCompileException e) {
+ assertEquals(msg, e.getCause().getMessage());
+ return;
+ }
+ fail("should not happen");
+ }
+
+ private void doTestRuntime(String src, int stackOffset, int lineNumber) {
+ CtClass testClass = loader.makeClass("javassist.LineNumberRuntimeTest" + classNumber++);
+ String test = String.join("\n",
+ "private boolean throwException() {",
+ " throw new java.lang.RuntimeException();",
+ "}");
+ try {
+ testClass.addInterface(loader.get("java.lang.Runnable"));
+ testClass.addMethod(CtMethod.make(test, testClass));
+ testClass.addMethod(CtMethod.make(src, testClass));
+ Class cls = testClass.toClass(LineNumberTest.class);
+ var runnable = (Runnable) cls.getConstructor().newInstance();
+ runnable.run();
+ } catch (Exception e) {
+ var lineNum = e.getStackTrace()[stackOffset].getLineNumber();
+ assertEquals("Line number should be right", lineNumber, lineNum);
+ return;
+ }
+ fail("should not happen");
+ }
+}
assertEquals(20, pc.line);
}
- public void testLineNumberCompiler() {
- CtClass testClass = loader.makeClass("javassist.bytecode.LineNumberCompilerClass");
- String run = String.join("\n",
- "public void run() {",
- " return",
- "}");
- try {
- testClass.addMethod(CtMethod.make(run, testClass));
- } catch (CannotCompileException e) {
- assertEquals("line 3: syntax error near \" return\n}\"", e.getCause().getMessage());
- return;
- }
- fail("should not happen");
- }
-
- public void testLineNumberCompiler2() {
- CtClass testClass = loader.makeClass("javassist.bytecode.LineNumberCompilerClass2");
- String ctor = String.join("\n",
- "public LineNumberCompilerClass2() {",
- " super();",
- "}");
- String run = String.join("\n",
- "public void run() {",
- " return;",
- "}");
- String run2 = String.join("\n",
- "public void run2() {",
- " run()",
- "}");
- try {
- testClass.addConstructor(CtNewConstructor.make(ctor, testClass));
- testClass.addMethod(CtMethod.make(run, testClass));
- testClass.addMethod(CtMethod.make(run2, testClass));
- } catch (CannotCompileException e) {
- assertEquals("line 9: ; is missing", e.getCause().getMessage());
- return;
- }
- fail("should not happen");
- }
-
- public void testLineNumberException() {
- CtClass testClass = loader.makeClass("javassist.bytecode.LineNumberExceptionClass");
- String run = String.join("\n",
- "public void run() {",
- " throw new java.lang.RuntimeException();",
- "}");
- try {
- testClass.addInterface(loader.get("java.lang.Runnable"));
- testClass.addMethod(CtMethod.make(run, testClass));
- Class cls = testClass.toClass(BytecodeTest.class);
- var runnable = (Runnable) cls.getConstructor().newInstance();
- runnable.run();
- } catch (Exception e) {
- var lineNum = e.getStackTrace()[0].getLineNumber();
- assertEquals("Line number should be right", 2, lineNum);
- return;
- }
- fail("should not happen");
- }
-
public void testRenameClass() throws Exception {
CtClass cc = loader.get("test1.RenameClass");
cc.replaceClassName("test1.RenameClass2", "java.lang.String");