From: akuznetsov Date: Tue, 26 Sep 2023 11:57:53 +0000 (+0400) Subject: add line numbers and test X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=d5a7881381080fa4953b24c069675ca435598b95;p=javassist.git add line numbers and test --- diff --git a/src/main/javassist/bytecode/CodeAttribute.java b/src/main/javassist/bytecode/CodeAttribute.java index 4c8ea2f2..98479b21 100644 --- a/src/main/javassist/bytecode/CodeAttribute.java +++ b/src/main/javassist/bytecode/CodeAttribute.java @@ -347,6 +347,20 @@ public class CodeAttribute extends AttributeInfo implements Opcode { attributes.add(sm); } + /** + * Adds a line number table. If another copy of line number table + * is already contained, the old one is removed. + * + * @param lnt the line number table added to this code attribute. + * If it is null, a new line number is not added. + * Only the old line number is removed. + */ + public void setAttribute(LineNumberAttribute lnt) { + AttributeInfo.remove(attributes, LineNumberAttribute.tag); + if (lnt != null) + attributes.add(lnt); + } + /** * Copies code. */ diff --git a/src/main/javassist/bytecode/LineNumberAttribute.java b/src/main/javassist/bytecode/LineNumberAttribute.java index cead96e0..16b37377 100644 --- a/src/main/javassist/bytecode/LineNumberAttribute.java +++ b/src/main/javassist/bytecode/LineNumberAttribute.java @@ -35,7 +35,7 @@ public class LineNumberAttribute extends AttributeInfo { super(cp, n, in); } - private LineNumberAttribute(ConstPool cp, byte[] i) { + LineNumberAttribute(ConstPool cp, byte[] i) { super(cp, tag, i); } diff --git a/src/main/javassist/bytecode/LineNumberAttributeBuilder.java b/src/main/javassist/bytecode/LineNumberAttributeBuilder.java new file mode 100644 index 00000000..52d9d0c8 --- /dev/null +++ b/src/main/javassist/bytecode/LineNumberAttributeBuilder.java @@ -0,0 +1,40 @@ +package javassist.bytecode; + +import javassist.compiler.ast.ASTree; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class LineNumberAttributeBuilder { + private final HashMap map = new HashMap<>(); + + public void put(int newPc, ASTree tree) { + if (tree != null) + put(newPc, tree.getLineNumber()); + } + + private void put(int newPc, int lineNum) { + Integer pc = map.get(lineNum); + if (pc == null || newPc < pc) { + map.put(lineNum, newPc); + } + } + + public LineNumberAttribute build(ConstPool cp) { + int size = map.size(); + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(size * 4 + 2); + DataOutputStream dos = new DataOutputStream(bos)) { + dos.writeShort(size); + for (Map.Entry entry : map.entrySet()) { + dos.writeShort(entry.getValue()); + dos.writeShort(entry.getKey()); + } + return new LineNumberAttribute(cp, bos.toByteArray()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/javassist/compiler/CodeGen.java b/src/main/javassist/compiler/CodeGen.java index e3115617..1f028f2b 100644 --- a/src/main/javassist/compiler/CodeGen.java +++ b/src/main/javassist/compiler/CodeGen.java @@ -121,8 +121,8 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { typeChecker = checker; } - protected static void fatal() throws CompileError { - throw new CompileError("fatal"); + protected static void fatal(int lineNumber) throws CompileError { + throw new CompileError("fatal", lineNumber); } public static boolean is2word(int type, int dim) { @@ -267,13 +267,13 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { } @Override - public void atASTList(ASTList n) throws CompileError { fatal(); } + public void atASTList(ASTList n) throws CompileError { fatal(n.getLineNumber()); } @Override - public void atPair(Pair n) throws CompileError { fatal(); } + public void atPair(Pair n) throws CompileError { fatal(n.getLineNumber()); } @Override - public void atSymbol(Symbol n) throws CompileError { fatal(); } + public void atSymbol(Symbol n) throws CompileError { fatal(n.getLineNumber()); } @Override public void atFieldDecl(FieldDecl field) throws CompileError { @@ -325,7 +325,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { hasReturned = true; } else - throw new CompileError("no return statement"); + throw new CompileError("no return statement", s.getLineNumber()); } private boolean needsSuperCall(Stmnt body) throws CompileError { @@ -403,7 +403,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { // LABEL, SWITCH label stament might be null?. hasReturned = false; throw new CompileError( - "sorry, not supported statement: TokenId " + op); + "sorry, not supported statement: TokenId " + op, st.getLineNumber()); } } @@ -590,7 +590,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { if (op == DEFAULT) defaultPc = bytecode.currentPc(); else if (op != CASE) - fatal(); + fatal(st.getLineNumber()); else { int curPos = bytecode.currentPc(); long caseLabel; @@ -638,7 +638,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { expr = TypeChecker.stripPlusExpr(expr); if (expr instanceof IntConst) return (int)((IntConst)expr).get(); - throw new CompileError("bad case label"); + throw new CompileError("bad case label", expr.getLineNumber()); } private int computeStringLabel(ASTree expr, int tmpVar, List gotoDefaults) @@ -658,7 +658,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { gotoDefaults.add(pc); return (int)label.hashCode(); } - throw new CompileError("bad case label"); + throw new CompileError("bad case label", expr.getLineNumber()); } private void atBreakStmnt(Stmnt st, boolean notCont) @@ -666,7 +666,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { { if (st.head() != null) throw new CompileError( - "sorry, not support labeled break or continue"); + "sorry, not support labeled break or continue", st.getLineNumber()); bytecode.addOpcode(Opcode.GOTO); Integer pc = Integer.valueOf(bytecode.currentPc()); @@ -718,7 +718,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { ASTree e = st.getLeft(); compileExpr(e); if (exprType != CLASS || arrayDim > 0) - throw new CompileError("bad throw statement"); + throw new CompileError("bad throw statement", st.getLineNumber()); bytecode.addOpcode(ATHROW); hasReturned = true; @@ -736,7 +736,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { compileExpr(st.head()); if (exprType != CLASS && arrayDim == 0) - throw new CompileError("bad type expr for synchronized block"); + throw new CompileError("bad type expr for synchronized block", st.getLineNumber()); Bytecode bc = bytecode; final int var = bc.getMaxLocals(); @@ -783,7 +783,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { if (getListSize(breakList) != nbreaks || getListSize(continueList) != ncontinues) throw new CompileError( - "sorry, cannot break/continue in synchronized block"); + "sorry, cannot break/continue in synchronized block", st.getLineNumber()); } private static int getListSize(List list) { @@ -863,7 +863,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { else msg = "incompatible type for " + expr.getName(); - throw new CompileError(msg); + throw new CompileError(msg, expr.getLineNumber()); } /* op is either =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, or >>>=. @@ -962,7 +962,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { int token = assignOps[op - MOD_E]; int k = lookupBinOp(token); if (k < 0) - fatal(); + fatal(right.getLineNumber()); atArithBinExpr(expr, token, k, type); } @@ -981,9 +981,9 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { if (!jvmJavaLangString.equals(cname)) badAssign(expr); - convToString(type, dim); // the value might be null. + convToString(type, dim, expr.getLineNumber()); // the value might be null. right.accept(this); - convToString(exprType, arrayDim); + convToString(exprType, arrayDim, expr.getLineNumber()); bytecode.addInvokevirtual(javaLangString, "concat", "(Ljava/lang/String;)Ljava/lang/String;"); exprType = CLASS; @@ -1025,7 +1025,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { bytecode.write16bit(pc, bytecode.currentPc() - pc + 1); expr.elseExpr().accept(this); if (dim1 != arrayDim) - throw new CompileError("type mismatch in ?:"); + throw new CompileError("type mismatch in ?:", expr.getLineNumber()); bytecode.write16bit(pc2, bytecode.currentPc() - pc2 + 1); } @@ -1072,7 +1072,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { String cname1 = className; right.accept(this); if (dim1 != arrayDim) - throw new CompileError("incompatible array types"); + throw new CompileError("incompatible array types", expr.getLineNumber()); if (token == '+' && dim1 == 0 && (type1 == CLASS || exprType == CLASS)) @@ -1139,7 +1139,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { = (type2 == CLASS && jvmJavaLangString.equals(className)); if (type2Is2) - convToString(type2, dim2); + convToString(type2, dim2, expr.getLineNumber()); if (is2word(type1, dim1)) { bytecode.addOpcode(DUP_X2); @@ -1149,11 +1149,11 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { bytecode.addOpcode(SWAP); // even if type1 is String, the left operand might be null. - convToString(type1, dim1); + convToString(type1, dim1, expr.getLineNumber()); bytecode.addOpcode(SWAP); if (!type2Is2 && !type2IsString) - convToString(type2, dim2); + convToString(type2, dim2, expr.getLineNumber()); bytecode.addInvokevirtual(javaLangString, "concat", "(Ljava/lang/String;)Ljava/lang/String;"); @@ -1162,7 +1162,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { className = jvmJavaLangString; } - private void convToString(int type, int dim) throws CompileError { + private void convToString(int type, int dim, int lineNumber) throws CompileError { final String method = "valueOf"; if (isRefType(type) || dim > 0) @@ -1184,7 +1184,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { bytecode.addInvokestatic(javaLangString, method, "(C)Ljava/lang/String;"); else if (type == VOID) - throw new CompileError("void type expression"); + throw new CompileError("void type expression", lineNumber); else /* INT, BYTE, SHORT */ bytecode.addInvokestatic(javaLangString, method, "(I)Ljava/lang/String;"); @@ -1237,7 +1237,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { else { // others expr.accept(this); if (exprType != BOOLEAN || arrayDim != 0) - throw new CompileError("boolean expr is required"); + throw new CompileError("boolean expr is required", expr.getLineNumber()); bytecode.addOpcode(branchIf ? IFNE : IFEQ); } @@ -1280,7 +1280,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { expr.oprand2().accept(this); if (dim1 != arrayDim) if (type1 != NULL && exprType != NULL) - throw new CompileError("incompatible array types"); + throw new CompileError("incompatible array types", expr.getLineNumber()); else if (exprType == NULL) arrayDim = dim1; @@ -1348,7 +1348,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { else if (p == P_LONG) bytecode.addOpcode(LCMP); // 1: >, 0: =, -1: < else - fatal(); + fatal(expr.getLineNumber()); int[] op = ifOp2; for (int i = 0; i < op.length; i += 3) @@ -1362,7 +1362,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { } protected static void badTypes(Expr expr) throws CompileError { - throw new CompileError("invalid types for " + expr.getName()); + throw new CompileError("invalid types for " + expr.getName(), expr.getLineNumber()); } private static final int P_DOUBLE = 0; @@ -1462,7 +1462,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { bytecode.addOpcode(SWAP); } else - fatal(); + fatal(expr.getLineNumber()); } else if (op != NOP) bytecode.addOpcode(op); @@ -1503,11 +1503,11 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { int srcDim = arrayDim; if (invalidDim(srcType, arrayDim, className, type, dim, name, true) || srcType == VOID || type == VOID) - throw new CompileError(msg); + throw new CompileError(msg, expr.getLineNumber()); if (type == CLASS) { if (!isRefType(srcType) && srcDim == 0) - throw new CompileError(msg); + throw new CompileError(msg, expr.getLineNumber()); return toJvmArrayName(name, dim); } @@ -1591,7 +1591,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { bytecode.addIconst(0); } else if (token == CALL) // method call - fatal(); + fatal(expr.getLineNumber()); else { expr.oprand1().accept(this); int type = typePrecedence(exprType); @@ -1633,12 +1633,12 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { // do nothing. ignore. } else - fatal(); + fatal(expr.getLineNumber()); } } protected static void badType(Expr expr) throws CompileError { - throw new CompileError("invalid type for " + expr.getName()); + throw new CompileError("invalid type for " + expr.getName(), expr.getLineNumber()); } @Override @@ -1649,7 +1649,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { public void atClassObject(Expr expr) throws CompileError { ASTree op1 = expr.oprand1(); if (!(op1 instanceof Symbol)) - throw new CompileError("fatal error: badly parsed .class expr"); + throw new CompileError("fatal error: badly parsed .class expr", expr.getLineNumber()); String cname = ((Symbol)op1).get(); if (cname.startsWith("[")) { @@ -1736,13 +1736,13 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { int type = exprType; int dim = arrayDim; if (dim == 0) - throw new CompileError("bad array access"); + throw new CompileError("bad array access", array.getLineNumber()); String cname = className; index.accept(this); if (typePrecedence(exprType) != P_INT || arrayDim > 0) - throw new CompileError("bad array index"); + throw new CompileError("bad array index", array.getLineNumber()); exprType = type; arrayDim = dim - 1; @@ -1992,7 +1992,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { case SUPER : if (inStaticMethod) throw new CompileError("not-available: " - + (token == THIS ? "this" : "super")); + + (token == THIS ? "this" : "super"), k.getLineNumber()); bytecode.addAload(0); exprType = CLASS; @@ -2002,7 +2002,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { className = getSuperName(); break; default : - fatal(); + fatal(k.getLineNumber()); } } diff --git a/src/main/javassist/compiler/CompileError.java b/src/main/javassist/compiler/CompileError.java index 5b857cf2..8bb12cba 100644 --- a/src/main/javassist/compiler/CompileError.java +++ b/src/main/javassist/compiler/CompileError.java @@ -25,11 +25,18 @@ public class CompileError extends Exception { private Lex lex; private String reason; + private int lineNumber = -1; + public CompileError(String s, Lex l) { - reason = s; + this(s, l.getLineNumber()); lex = l; } + public CompileError(String s, int lineNumber) { + this.lineNumber = lineNumber; + reason = String.format("line %d: %s", lineNumber, s); + } + public CompileError(String s) { reason = s; lex = null; @@ -45,6 +52,10 @@ public class CompileError extends Exception { public Lex getLex() { return lex; } + public int getLineNumber() { + return lineNumber; + } + @Override public String getMessage() { return reason; diff --git a/src/main/javassist/compiler/Javac.java b/src/main/javassist/compiler/Javac.java index 084487b4..6e67ab66 100644 --- a/src/main/javassist/compiler/Javac.java +++ b/src/main/javassist/compiler/Javac.java @@ -43,7 +43,7 @@ import javassist.compiler.ast.Stmnt; import javassist.compiler.ast.Symbol; public class Javac { - JvstCodeGen gen; + JvstCodeGenWitlLineNumber gen; SymbolTable stable; private Bytecode bytecode; @@ -71,7 +71,7 @@ public class Javac { * belongs to. */ public Javac(Bytecode b, CtClass thisClass) { - gen = new JvstCodeGen(b, thisClass, thisClass.getClassPool()); + gen = new JvstCodeGenWitlLineNumber(b, thisClass, thisClass.getClassPool()); stable = new SymbolTable(); bytecode = b; } @@ -160,8 +160,9 @@ public class Javac { gen.getThisClass()); cons.setModifiers(mod); md.accept(gen); - cons.getMethodInfo().setCodeAttribute( - bytecode.toCodeAttribute()); + CodeAttribute cattr = bytecode.toCodeAttribute(); + cattr.setAttribute(gen.toLineNumberAttribute()); + cons.getMethodInfo().setCodeAttribute(cattr); cons.setExceptionTypes(tlist); return cons; } @@ -173,10 +174,11 @@ public class Javac { method.setModifiers(mod); gen.setThisMethod(method); md.accept(gen); - if (md.getBody() != null) - method.getMethodInfo().setCodeAttribute( - bytecode.toCodeAttribute()); - else + if (md.getBody() != null) { + CodeAttribute cattr = bytecode.toCodeAttribute(); + cattr.setAttribute(gen.toLineNumberAttribute()); + method.getMethodInfo().setCodeAttribute(cattr); + } else method.setModifiers(mod | Modifier.ABSTRACT); method.setExceptionTypes(tlist); @@ -446,11 +448,11 @@ public class Javac { public void doit(JvstCodeGen gen, Bytecode b, ASTList args) throws CompileError { - ASTree expr = new Member(m); + ASTree expr = new Member(m, texpr.getLineNumber()); if (texpr != null) - expr = Expr.make('.', texpr, expr); + expr = Expr.make('.', texpr, expr, texpr.getLineNumber()); - expr = CallExpr.makeCall(expr, args); + expr = CallExpr.makeCall(expr, args, texpr.getLineNumber()); gen.compileExpr(expr); gen.addNullIfVoid(); } @@ -459,11 +461,11 @@ public class Javac { public void setReturnType(JvstTypeChecker check, ASTList args) throws CompileError { - ASTree expr = new Member(m); + ASTree expr = new Member(m, texpr.getLineNumber()); if (texpr != null) - expr = Expr.make('.', texpr, expr); + expr = Expr.make('.', texpr, expr, texpr.getLineNumber()); - expr = CallExpr.makeCall(expr, args); + expr = CallExpr.makeCall(expr, args, texpr.getLineNumber()); expr.accept(check); check.addNullIfVoid(); } @@ -493,8 +495,8 @@ public class Javac { throws CompileError { Expr expr = Expr.make(TokenId.MEMBER, - new Symbol(c), new Member(m)); - expr = CallExpr.makeCall(expr, args); + new Symbol(c, args.getLineNumber()), new Member(m, args.getLineNumber()), args.getLineNumber()); + expr = CallExpr.makeCall(expr, args, args.getLineNumber()); gen.compileExpr(expr); gen.addNullIfVoid(); } @@ -504,8 +506,8 @@ public class Javac { throws CompileError { Expr expr = Expr.make(TokenId.MEMBER, - new Symbol(c), new Member(m)); - expr = CallExpr.makeCall(expr, args); + new Symbol(c, args.getLineNumber()), new Member(m, args.getLineNumber()), args.getLineNumber()); + expr = CallExpr.makeCall(expr, args, args.getLineNumber()); expr.accept(check); check.addNullIfVoid(); } diff --git a/src/main/javassist/compiler/JvstCodeGen.java b/src/main/javassist/compiler/JvstCodeGen.java index 714b9699..4f251924 100644 --- a/src/main/javassist/compiler/JvstCodeGen.java +++ b/src/main/javassist/compiler/JvstCodeGen.java @@ -110,14 +110,14 @@ public class JvstCodeGen extends MemberCodeGen { } else if (name.equals(dollarTypeName)) { if (dollarType == null) - throw new CompileError(dollarTypeName + " is not available"); + throw new CompileError(dollarTypeName + " is not available", mem.getLineNumber()); bytecode.addLdc(Descriptor.of(dollarType)); callGetType("getType"); } else if (name.equals(clazzName)) { if (param0Type == null) - throw new CompileError(clazzName + " is not available"); + throw new CompileError(clazzName + " is not available", mem.getLineNumber()); bytecode.addLdc(param0Type); callGetType("getClazz"); @@ -141,11 +141,11 @@ public class JvstCodeGen extends MemberCodeGen { if (left instanceof Member && ((Member)left).get().equals(paramArrayName)) { if (op != '=') - throw new CompileError("bad operator for " + paramArrayName); + throw new CompileError("bad operator for " + paramArrayName, expr.getLineNumber()); right.accept(this); if (arrayDim != 1 || exprType != CLASS) - throw new CompileError("invalid type for " + paramArrayName); + throw new CompileError("invalid type for " + paramArrayName, expr.getLineNumber()); atAssignParamList(paramTypeList, bytecode); if (!doDup) @@ -211,7 +211,7 @@ public class JvstCodeGen extends MemberCodeGen { className = null; } else - throw new CompileError("invalid cast"); + throw new CompileError("invalid cast", expr.getLineNumber()); } protected void atCastToWrapper(CastExpr expr) throws CompileError { @@ -253,7 +253,7 @@ public class JvstCodeGen extends MemberCodeGen { return; } else if (name.equals(cflowName)) { - atCflow((ASTList)expr.oprand2()); + atCflow((ASTList)expr.oprand2(), expr.getLineNumber()); return; } } @@ -263,16 +263,16 @@ public class JvstCodeGen extends MemberCodeGen { /* To support $cflow(). */ - protected void atCflow(ASTList cname) throws CompileError { + protected void atCflow(ASTList cname, int lineNumber) throws CompileError { StringBuilder sbuf = new StringBuilder(); if (cname == null || cname.tail() != null) - throw new CompileError("bad " + cflowName); + throw new CompileError("bad " + cflowName, lineNumber); makeCflowName(sbuf, cname.head()); String name = sbuf.toString(); Object[] names = resolver.getClassPool().lookupCflow(name); if (names == null) - throw new CompileError("no such " + cflowName + ": " + name); + throw new CompileError("no such " + cflowName + ": " + name, lineNumber); bytecode.addGetstatic((String)names[0], (String)names[1], "Ljavassist/runtime/Cflow;"); @@ -305,7 +305,7 @@ public class JvstCodeGen extends MemberCodeGen { } } - throw new CompileError("bad " + cflowName); + throw new CompileError("bad " + cflowName, name.getLineNumber()); } /* To support $$. ($$) is equivalent to ($1, ..., $n). @@ -530,7 +530,7 @@ public class JvstCodeGen extends MemberCodeGen { String varName = prefix + "0"; Declarator decl = new Declarator(CLASS, MemberResolver.javaToJvmName(target), - 0, varNo++, new Symbol(varName)); + 0, varNo++, new Symbol(varName, 0), 0); tbl.append(varName, decl); } @@ -573,7 +573,7 @@ public class JvstCodeGen extends MemberCodeGen { Declarator decl = new Declarator(exprType, className, arrayDim, - varNo, new Symbol(varName)); + varNo, new Symbol(varName, 0), 0); tbl.append(varName, decl); return is2word(exprType, arrayDim) ? 2 : 1; } @@ -603,7 +603,7 @@ public class JvstCodeGen extends MemberCodeGen { } Declarator decl - = new Declarator(type, cname, dim, varNo, new Symbol(varName)); + = new Declarator(type, cname, dim, varNo, new Symbol(varName, 0), 0); tbl.append(varName, decl); } diff --git a/src/main/javassist/compiler/JvstCodeGenWitlLineNumber.java b/src/main/javassist/compiler/JvstCodeGenWitlLineNumber.java new file mode 100644 index 00000000..969948c5 --- /dev/null +++ b/src/main/javassist/compiler/JvstCodeGenWitlLineNumber.java @@ -0,0 +1,265 @@ +package javassist.compiler; + +import javassist.ClassPool; +import javassist.CtClass; +import javassist.bytecode.Bytecode; +import javassist.bytecode.LineNumberAttribute; +import javassist.bytecode.LineNumberAttributeBuilder; +import javassist.compiler.ast.*; + +public class JvstCodeGenWitlLineNumber extends JvstCodeGen { + private final LineNumberAttributeBuilder lineNumberAttributeBuilder = new LineNumberAttributeBuilder(); + public JvstCodeGenWitlLineNumber(Bytecode b, CtClass cc, ClassPool cp) { + super(b, cc, cp); + } + + public LineNumberAttribute toLineNumberAttribute() { + return lineNumberAttributeBuilder.build(bytecode.getConstPool()); + } + + @Override + public void atASTList(ASTList n) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), n); + super.atASTList(n); + } + + @Override + public void atPair(Pair n) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), n); + super.atPair(n); + } + + @Override + public void atSymbol(Symbol n) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), n); + super.atSymbol(n); + } + + @Override + public void atFieldDecl(FieldDecl field) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), field); + super.atFieldDecl(field); + } + + @Override + public void atMethodDecl(MethodDecl method) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), method); + super.atMethodDecl(method); + } + + @Override + public void atMethodBody(Stmnt s, boolean isCons, boolean isVoid) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), s); + super.atMethodBody(s, isCons, isVoid); + } + + @Override + public void atStmnt(Stmnt st) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), st); + super.atStmnt(st); + } + + @Override + public void atDeclarator(Declarator d) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), d); + super.atDeclarator(d); + } + + @Override + public void atAssignExpr(AssignExpr expr) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atAssignExpr(expr); + } + + @Override + protected void atAssignExpr(AssignExpr expr, boolean doDup) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atAssignExpr(expr, doDup); + } + + @Override + protected void atAssignCore(Expr expr, int op, ASTree right, int type, int dim, String cname) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atAssignCore(expr, op, right, type, dim, cname); + } + + @Override + public void atCondExpr(CondExpr expr) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atCondExpr(expr); + } + + @Override + public void atBinExpr(BinExpr expr) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atBinExpr(expr); + } + + @Override + public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atInstanceOfExpr(expr); + } + + @Override + public void atExpr(Expr expr) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atExpr(expr); + } + + @Override + public void atClassObject(Expr expr) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atClassObject(expr); + } + + @Override + public void atArrayRead(ASTree array, ASTree index) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), array); + super.atArrayRead(array, index); + } + + @Override + protected void arrayAccess(ASTree array, ASTree index) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), array); + super.arrayAccess(array, index); + } + + @Override + public void atArrayPlusPlus(int token, boolean isPost, Expr expr, boolean doDup) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atArrayPlusPlus(token, isPost, expr, doDup); + } + + @Override + protected void atPlusPlusCore(int dup_code, boolean doDup, int token, boolean isPost, Expr expr) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atPlusPlusCore(dup_code, doDup, token, isPost, expr); + } + + @Override + public void atVariable(Variable v) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), v); + super.atVariable(v); + } + + @Override + public void atKeyword(Keyword k) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), k); + super.atKeyword(k); + } + + @Override + public void atStringL(javassist.compiler.ast.StringL s) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), s); + super.atStringL(s); + } + + @Override + public void atIntConst(IntConst i) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), i); + super.atIntConst(i); + } + + @Override + public void atDoubleConst(DoubleConst d) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), d); + super.atDoubleConst(d); + } + + @Override + public void atMember(Member mem) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), mem); + super.atMember(mem); + } + + @Override + protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right, boolean doDup) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atFieldAssign(expr, op, left, right, doDup); + } + + @Override + public void atCastExpr(CastExpr expr) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atCastExpr(expr); + } + + @Override + protected void atCastToRtype(CastExpr expr) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atCastToRtype(expr); + } + + @Override + protected void atCastToWrapper(CastExpr expr) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atCastToWrapper(expr); + } + + @Override + public void atCallExpr(CallExpr expr) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atCallExpr(expr); + } + + @Override + protected void atCflow(ASTList cname, int lineNumber) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), cname); + super.atCflow(cname, lineNumber); + } + + @Override + protected void atTryStmnt(Stmnt st) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), st); + super.atTryStmnt(st); + } + + @Override + public void atNewExpr(NewExpr expr) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atNewExpr(expr); + } + + @Override + public void atNewArrayExpr(NewExpr expr) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atNewArrayExpr(expr); + } + + @Override + protected void atArrayVariableAssign(ArrayInit init, int varType, int varArray, String varClass) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), init); + super.atArrayVariableAssign(init, varType, varArray, varClass); + } + + @Override + public void atArrayInit(ArrayInit init) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), init); + super.atArrayInit(init); + } + + @Override + protected void atMultiNewArray(int type, ASTList classname, ASTList size) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), classname); + super.atMultiNewArray(type, classname, size); + } + + @Override + public void atMethodCallCore(CtClass targetClass, String mname, ASTList args, boolean isStatic, boolean isSpecial, int aload0pos, MemberResolver.Method found) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), args); + super.atMethodCallCore(targetClass, mname, args, isStatic, isSpecial, aload0pos, found); + } + + @Override + protected void atFieldRead(ASTree expr) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atFieldRead(expr); + } + + @Override + protected void atFieldPlusPlus(int token, boolean isPost, ASTree oprand, Expr expr, boolean doDup) throws CompileError { + lineNumberAttributeBuilder.put(bytecode.currentPc(), expr); + super.atFieldPlusPlus(token, isPost, oprand, expr, doDup); + } +} diff --git a/src/main/javassist/compiler/JvstTypeChecker.java b/src/main/javassist/compiler/JvstTypeChecker.java index 13e47291..d25928a6 100644 --- a/src/main/javassist/compiler/JvstTypeChecker.java +++ b/src/main/javassist/compiler/JvstTypeChecker.java @@ -89,7 +89,7 @@ public class JvstTypeChecker extends TypeChecker { int n = params.length; for (int i = 0; i < n; ++i) - compileUnwrapValue(params[i]); + compileUnwrapValue(params[i], expr.getLineNumber()); } else super.atFieldAssign(expr, op, left, right); @@ -124,7 +124,7 @@ public class JvstTypeChecker extends TypeChecker { CtClass returnType = codeGen.returnType; expr.getOprand().accept(this); if (exprType == VOID || CodeGen.isRefType(exprType) || arrayDim > 0) - compileUnwrapValue(returnType); + compileUnwrapValue(returnType, expr.getLineNumber()); else if (returnType instanceof CtPrimitiveType) { CtPrimitiveType pt = (CtPrimitiveType)returnType; int destType = MemberResolver.descToType(pt.getDescriptor()); @@ -258,7 +258,7 @@ public class JvstTypeChecker extends TypeChecker { addNullIfVoid(); } - protected void compileUnwrapValue(CtClass type) throws CompileError + protected void compileUnwrapValue(CtClass type, int lineNumber) throws CompileError { if (type == CtClass.voidType) addNullIfVoid(); diff --git a/src/main/javassist/compiler/Lex.java b/src/main/javassist/compiler/Lex.java index b7c39a98..c2c8666c 100644 --- a/src/main/javassist/compiler/Lex.java +++ b/src/main/javassist/compiler/Lex.java @@ -163,7 +163,8 @@ public class Lex implements TokenId { ungetc(c); c = '/'; } - } + } else if (c == '\n') + ++lineNumber; } while(isBlank(c)); return c; } @@ -529,4 +530,8 @@ public class Lex implements TokenId { lastChar = -1; return c; } + + public int getLineNumber() { + return lineNumber + 1; + } } diff --git a/src/main/javassist/compiler/MemberCodeGen.java b/src/main/javassist/compiler/MemberCodeGen.java index e8e9912b..52e3aaea 100644 --- a/src/main/javassist/compiler/MemberCodeGen.java +++ b/src/main/javassist/compiler/MemberCodeGen.java @@ -234,7 +234,7 @@ public class MemberCodeGen extends CodeGen { body.accept(this); int end = bc.currentPc(); if (start == end) - throw new CompileError("empty try block"); + throw new CompileError("empty try block", st.getLineNumber()); boolean tryNotReturn = !hasReturned; if (tryNotReturn) { @@ -346,21 +346,21 @@ public class MemberCodeGen extends CodeGen { if (init != null) throw new CompileError( "sorry, multi-dimensional array initializer " + - "for new is not supported"); + "for new is not supported", expr.getLineNumber()); atMultiNewArray(type, classname, size); return; } ASTree sizeExpr = size.head(); - atNewArrayExpr2(type, sizeExpr, Declarator.astToClassName(classname, '/'), init); + atNewArrayExpr2(type, sizeExpr, Declarator.astToClassName(classname, '/'), init, expr.getLineNumber()); } private void atNewArrayExpr2(int type, ASTree sizeExpr, - String jvmClassname, ArrayInit init) throws CompileError { + String jvmClassname, ArrayInit init, int lineNumber) throws CompileError { if (init == null) if (sizeExpr == null) - throw new CompileError("no array size"); + throw new CompileError("no array size", lineNumber); else sizeExpr.accept(this); else @@ -369,7 +369,7 @@ public class MemberCodeGen extends CodeGen { bytecode.addIconst(s); } else - throw new CompileError("unnecessary array size specified for new"); + throw new CompileError("unnecessary array size specified for new", lineNumber); String elementClass; if (type == CLASS) { @@ -405,7 +405,7 @@ public class MemberCodeGen extends CodeGen { atype = T_LONG; break; default : - badNewExpr(); + badNewExpr(lineNumber); break; } @@ -433,19 +433,19 @@ public class MemberCodeGen extends CodeGen { className = elementClass; } - private static void badNewExpr() throws CompileError { - throw new CompileError("bad new expression"); + private static void badNewExpr(int lineNumber) throws CompileError { + throw new CompileError("bad new expression", lineNumber); } @Override protected void atArrayVariableAssign(ArrayInit init, int varType, int varArray, String varClass) throws CompileError { - atNewArrayExpr2(varType, null, varClass, init); + atNewArrayExpr2(varType, null, varClass, init, init.getLineNumber()); } @Override public void atArrayInit(ArrayInit init) throws CompileError { - throw new CompileError("array initializer is not supported"); + throw new CompileError("array initializer is not supported", init.getLineNumber()); } protected void atMultiNewArray(int type, ASTList classname, ASTList size) @@ -461,7 +461,7 @@ public class MemberCodeGen extends CodeGen { ++count; s.accept(this); if (exprType != INT) - throw new CompileError("bad type for array size"); + throw new CompileError("bad type for array size", classname.getLineNumber()); } String desc; @@ -503,7 +503,7 @@ public class MemberCodeGen extends CodeGen { mname = MethodInfo.nameInit; // targetClass = thisClass; if (inStaticMethod) - throw new CompileError("a constructor cannot be static"); + throw new CompileError("a constructor cannot be static", expr.getLineNumber()); bytecode.addAload(0); // this if (((Keyword)method).get() == SUPER) @@ -563,7 +563,7 @@ public class MemberCodeGen extends CodeGen { badMethod(); } else - fatal(); + fatal(expr.getLineNumber()); atMethodCallCore(targetClass, mname, args, isStatic, isSpecial, aload0pos, cached); @@ -612,7 +612,7 @@ public class MemberCodeGen extends CodeGen { msg = "Method " + mname + " not found in " + targetClass.getName(); - throw new CompileError(msg); + throw new CompileError(msg, args.getLineNumber()); } atMethodCallCore2(targetClass, mname, isStatic, isSpecial, @@ -844,14 +844,14 @@ public class MemberCodeGen extends CodeGen { if (op == '=') { FieldInfo finfo = f.getFieldInfo2(); setFieldType(finfo); - AccessorMaker maker = isAccessibleField(f, finfo); + AccessorMaker maker = isAccessibleField(f, finfo, expr.getLineNumber()); if (maker == null) fi = addFieldrefInfo(f, finfo); else fi = 0; } else - fi = atFieldRead(f, is_static); + fi = atFieldRead(f, is_static, expr.getLineNumber()); int fType = exprType; int fDim = arrayDim; @@ -921,9 +921,9 @@ public class MemberCodeGen extends CodeGen { } boolean is_static = resultStatic; - ASTree cexpr = TypeChecker.getConstantFieldValue(f); + ASTree cexpr = TypeChecker.getConstantFieldValue(f, expr.getLineNumber()); if (cexpr == null) - atFieldRead(f, is_static); + atFieldRead(f, is_static,expr.getLineNumber() ); else { cexpr.accept(this); setFieldType(f.getFieldInfo2()); @@ -932,7 +932,7 @@ public class MemberCodeGen extends CodeGen { private void atArrayLength(ASTree expr) throws CompileError { if (arrayDim == 0) - throw new CompileError(".length applied to a non array"); + throw new CompileError(".length applied to a non array", expr.getLineNumber()); bytecode.addOpcode(ARRAYLENGTH); exprType = INT; @@ -944,10 +944,10 @@ public class MemberCodeGen extends CodeGen { * It returns a fieldref_info index or zero if the field is a private * one declared in an enclosing class. */ - private int atFieldRead(CtField f, boolean isStatic) throws CompileError { + private int atFieldRead(CtField f, boolean isStatic, int lineNumber) throws CompileError { FieldInfo finfo = f.getFieldInfo2(); boolean is2byte = setFieldType(finfo); - AccessorMaker maker = isAccessibleField(f, finfo); + AccessorMaker maker = isAccessibleField(f, finfo, lineNumber); if (maker != null) { MethodInfo minfo = maker.getFieldGetter(finfo, isStatic); bytecode.addInvokestatic(f.getDeclaringClass(), minfo.getName(), @@ -973,7 +973,7 @@ public class MemberCodeGen extends CodeGen { * an exception or it returns AccessorMaker if the field is a private * one declared in an enclosing class. */ - private AccessorMaker isAccessibleField(CtField f, FieldInfo finfo) + private AccessorMaker isAccessibleField(CtField f, FieldInfo finfo, int lineNumber) throws CompileError { if (AccessFlag.isPrivate(finfo.getAccessFlags()) @@ -985,7 +985,7 @@ public class MemberCodeGen extends CodeGen { return maker; } throw new CompileError("Field " + f.getName() + " in " - + declClass.getName() + " is private."); + + declClass.getName() + " is private.", lineNumber); } return null; // accessible field @@ -1046,7 +1046,7 @@ public class MemberCodeGen extends CodeGen { if (!is_static) bytecode.addOpcode(DUP); - int fi = atFieldRead(f, is_static); + int fi = atFieldRead(f, is_static, oprand.getLineNumber()); int t = exprType; boolean is2w = is2word(t, arrayDim); @@ -1082,7 +1082,7 @@ public class MemberCodeGen extends CodeGen { if (!is_static) if (inStaticMethod) throw new CompileError( - "not available in a static method: " + name); + "not available in a static method: " + name, expr.getLineNumber()); else bytecode.addAload(0); // this @@ -1117,7 +1117,7 @@ public class MemberCodeGen extends CodeGen { && ((Symbol)e.oprand2()).get().equals("length")) return null; // expr is an array length. else - badLvalue(); + badLvalue(expr.getLineNumber()); boolean is_static = Modifier.isStatic(f.getModifiers()); if (is_static) @@ -1142,17 +1142,17 @@ public class MemberCodeGen extends CodeGen { } } else - badLvalue(); + badLvalue(expr.getLineNumber()); } else - badLvalue(); + badLvalue(expr.getLineNumber()); resultStatic = false; return null; // never reach } - private static void badLvalue() throws CompileError { - throw new CompileError("bad l-value"); + private static void badLvalue(int lineNumber) throws CompileError { + throw new CompileError("bad l-value", lineNumber); } public CtClass[] makeParamList(MethodDecl md) throws CompileError { diff --git a/src/main/javassist/compiler/NoFieldException.java b/src/main/javassist/compiler/NoFieldException.java index dd878590..898998d1 100644 --- a/src/main/javassist/compiler/NoFieldException.java +++ b/src/main/javassist/compiler/NoFieldException.java @@ -27,7 +27,7 @@ public class NoFieldException extends CompileError { /* NAME must be JVM-internal representation. */ public NoFieldException(String name, ASTree e) { - super("no such field: " + name); + super("no such field: " + name, e.getLineNumber()); fieldName = name; expr = e; } diff --git a/src/main/javassist/compiler/Parser.java b/src/main/javassist/compiler/Parser.java index 2b0dfd69..43e8a3ec 100644 --- a/src/main/javassist/compiler/Parser.java +++ b/src/main/javassist/compiler/Parser.java @@ -66,7 +66,7 @@ public final class Parser implements TokenId { Declarator d; boolean isConstructor = false; if (lex.lookAhead() == Identifier && lex.lookAhead(1) == '(') { - d = new Declarator(VOID, 0); + d = new Declarator(VOID, 0, lex.getLineNumber()); isConstructor = true; } else @@ -81,7 +81,7 @@ public final class Parser implements TokenId { else name = lex.getString(); - d.setVariable(new Symbol(name)); + d.setVariable(new Symbol(name, lex.getLineNumber())); if (isConstructor || lex.lookAhead() == '(') return parseMethod1(tbl, isConstructor, mods, d); return parseField(tbl, mods, d); @@ -103,7 +103,7 @@ public final class Parser implements TokenId { int c = lex.get(); if (c == ';') - return new FieldDecl(mods, new ASTList(d, new ASTList(expr))); + return new FieldDecl(mods, new ASTList(d, new ASTList(expr, lex.getLineNumber()), lex.getLineNumber()), lex.getLineNumber()); else if (c == ',') throw new CompileError( "only one field can be declared in one declaration", lex); @@ -131,7 +131,7 @@ public final class Parser implements TokenId { ASTList parms = null; if (lex.lookAhead() != ')') while (true) { - parms = ASTList.append(parms, parseFormalParam(tbl)); + parms = ASTList.append(parms, parseFormalParam(tbl), lex.getLineNumber()); int t = lex.lookAhead(); if (t == ',') lex.get(); @@ -148,7 +148,7 @@ public final class Parser implements TokenId { if (lex.lookAhead() == THROWS) { lex.get(); while (true) { - throwsList = ASTList.append(throwsList, parseClassType(tbl)); + throwsList = ASTList.append(throwsList, parseClassType(tbl), lex.getLineNumber()); if (lex.lookAhead() == ',') lex.get(); else @@ -157,7 +157,7 @@ public final class Parser implements TokenId { } return new MethodDecl(mods, new ASTList(d, - ASTList.make(parms, throwsList, null))); + ASTList.make(parms, throwsList, null, lex.getLineNumber()), lex.getLineNumber()), lex.getLineNumber()); } /* Parses a method body. @@ -171,7 +171,7 @@ public final class Parser implements TokenId { else { body = parseBlock(tbl); if (body == null) - body = new Stmnt(BLOCK); + body = new Stmnt(BLOCK, lex.getLineNumber()); } md.sublist(4).setHead(body); @@ -191,7 +191,7 @@ public final class Parser implements TokenId { if (t == ABSTRACT || t == FINAL || t == PUBLIC || t == PROTECTED || t == PRIVATE || t == SYNCHRONIZED || t == STATIC || t == VOLATILE || t == TRANSIENT || t == STRICT) - list = new ASTList(new Keyword(lex.get()), list); + list = new ASTList(new Keyword(lex.get(), lex.getLineNumber()), list, lex.getLineNumber()); else break; } @@ -206,11 +206,11 @@ public final class Parser implements TokenId { if (isBuiltinType(t) || t == VOID) { lex.get(); // primitive type int dim = parseArrayDimension(); - return new Declarator(t, dim); + return new Declarator(t, dim, lex.getLineNumber()); } ASTList name = parseClassType(tbl); int dim = parseArrayDimension(); - return new Declarator(name, dim); + return new Declarator(name, dim, lex.getLineNumber()); } private static boolean isBuiltinType(int t) { @@ -228,7 +228,7 @@ public final class Parser implements TokenId { throw new SyntaxError(lex); String name = lex.getString(); - d.setVariable(new Symbol(name)); + d.setVariable(new Symbol(name, lex.getLineNumber())); d.addArrayDim(parseArrayDimension()); tbl.append(name, d); return d; @@ -261,13 +261,13 @@ public final class Parser implements TokenId { return parseBlock(tbl); else if (t == ';') { lex.get(); - return new Stmnt(BLOCK); // empty statement + return new Stmnt(BLOCK, lex.getLineNumber()); // empty statement } else if (t == Identifier && lex.lookAhead(1) == ':') { lex.get(); // Identifier String label = lex.getString(); lex.get(); // ':' - return Stmnt.make(LABEL, new Symbol(label), parseStatement(tbl)); + return Stmnt.make(LABEL, new Symbol(label, lex.getLineNumber()), parseStatement(tbl), lex.getLineNumber()); } else if (t == IF) return parseIf(tbl); @@ -306,12 +306,12 @@ public final class Parser implements TokenId { while (lex.lookAhead() != '}') { Stmnt s = parseStatement(tbl2); if (s != null) - body = (Stmnt)ASTList.concat(body, new Stmnt(BLOCK, s)); + body = (Stmnt)ASTList.concat(body, new Stmnt(BLOCK, s, lex.getLineNumber())); } lex.get(); // '}' if (body == null) - return new Stmnt(BLOCK); // empty block + return new Stmnt(BLOCK, lex.getLineNumber()); // empty block return body; } @@ -330,7 +330,7 @@ public final class Parser implements TokenId { else elsep = null; - return new Stmnt(t, expr, new ASTList(thenp, new ASTList(elsep))); + return new Stmnt(t, expr, new ASTList(thenp, new ASTList(elsep, lex.getLineNumber()), lex.getLineNumber()), lex.getLineNumber()); } /* while.statement : WHILE "(" expression ")" statement @@ -341,7 +341,7 @@ public final class Parser implements TokenId { int t = lex.get(); // WHILE ASTree expr = parseParExpression(tbl); Stmnt body = parseStatement(tbl); - return new Stmnt(t, expr, body); + return new Stmnt(t, expr, body, lex.getLineNumber()); } /* do.statement : DO statement WHILE "(" expression ")" ";" @@ -356,7 +356,7 @@ public final class Parser implements TokenId { if (lex.get() != ')' || lex.get() != ';') throw new SyntaxError(lex); - return new Stmnt(t, expr, body); + return new Stmnt(t, expr, body, lex.getLineNumber()); } /* for.statement : FOR "(" decl.or.expr expression ";" expression ")" @@ -397,7 +397,7 @@ public final class Parser implements TokenId { Stmnt body = parseStatement(tbl2); return new Stmnt(t, expr1, new ASTList(expr2, - new ASTList(expr3, body))); + new ASTList(expr3, body, lex.getLineNumber()), lex.getLineNumber()), lex.getLineNumber()); } /* switch.statement : SWITCH "(" expression ")" "{" switch.block "}" @@ -411,7 +411,7 @@ public final class Parser implements TokenId { int t = lex.get(); // SWITCH ASTree expr = parseParExpression(tbl); Stmnt body = parseSwitchBlock(tbl); - return new Stmnt(t, expr, body); + return new Stmnt(t, expr, body, lex.getLineNumber()); } private Stmnt parseSwitchBlock(SymbolTable tbl) throws CompileError { @@ -428,17 +428,17 @@ public final class Parser implements TokenId { throw new CompileError("no case or default in a switch block", lex); - Stmnt body = new Stmnt(BLOCK, s); + Stmnt body = new Stmnt(BLOCK, s, lex.getLineNumber()); while (lex.lookAhead() != '}') { Stmnt s2 = parseStmntOrCase(tbl2); if (s2 != null) { int op2 = s2.getOperator(); if (op2 == CASE || op2 == DEFAULT) { - body = (Stmnt)ASTList.concat(body, new Stmnt(BLOCK, s2)); + body = (Stmnt)ASTList.concat(body, new Stmnt(BLOCK, s2, lex.getLineNumber())); s = s2; } else - s = (Stmnt)ASTList.concat(s, new Stmnt(BLOCK, s2)); + s = (Stmnt)ASTList.concat(s, new Stmnt(BLOCK, s2, lex.getLineNumber())); } } @@ -454,9 +454,9 @@ public final class Parser implements TokenId { lex.get(); Stmnt s; if (t == CASE) - s = new Stmnt(t, parseExpression(tbl)); + s = new Stmnt(t, parseExpression(tbl), lex.getLineNumber()); else - s = new Stmnt(DEFAULT); + s = new Stmnt(DEFAULT, lex.getLineNumber()); if (lex.get() != ':') throw new CompileError(": is missing", lex); @@ -477,7 +477,7 @@ public final class Parser implements TokenId { throw new SyntaxError(lex); Stmnt body = parseBlock(tbl); - return new Stmnt(t, expr, body); + return new Stmnt(t, expr, body, lex.getLineNumber()); } /* try.statement @@ -503,7 +503,7 @@ public final class Parser implements TokenId { throw new SyntaxError(lex); Stmnt b = parseBlock(tbl2); - catchList = ASTList.append(catchList, new Pair(d, b)); + catchList = ASTList.append(catchList, new Pair(d, b), lex.getLineNumber()); } Stmnt finallyBlock = null; @@ -512,14 +512,14 @@ public final class Parser implements TokenId { finallyBlock = parseBlock(tbl); } - return Stmnt.make(TRY, block, catchList, finallyBlock); + return Stmnt.make(TRY, block, catchList, finallyBlock, lex.getLineNumber()); } /* return.statement : RETURN [ expression ] ";" */ private Stmnt parseReturn(SymbolTable tbl) throws CompileError { int t = lex.get(); // RETURN - Stmnt s = new Stmnt(t); + Stmnt s = new Stmnt(t, lex.getLineNumber()); if (lex.lookAhead() != ';') s.setLeft(parseExpression(tbl)); @@ -537,7 +537,7 @@ public final class Parser implements TokenId { if (lex.get() != ';') throw new CompileError("; is missing", lex); - return new Stmnt(t, expr); + return new Stmnt(t, expr, lex.getLineNumber()); } /* break.statement : BREAK [ Identifier ] ";" @@ -554,10 +554,10 @@ public final class Parser implements TokenId { throws CompileError { int t = lex.get(); // CONTINUE - Stmnt s = new Stmnt(t); + Stmnt s = new Stmnt(t, lex.getLineNumber()); int t2 = lex.get(); if (t2 == Identifier) { - s.setLeft(new Symbol(lex.getString())); + s.setLeft(new Symbol(lex.getString(), lex.getLineNumber())); t2 = lex.get(); } @@ -589,7 +589,7 @@ public final class Parser implements TokenId { if (isBuiltinType(t)) { t = lex.get(); int dim = parseArrayDimension(); - return parseDeclarators(tbl, new Declarator(t, dim)); + return parseDeclarators(tbl, new Declarator(t, dim, lex.getLineNumber())); } else if (t == Identifier) { int i = nextIsClassType(0); @@ -597,7 +597,7 @@ public final class Parser implements TokenId { if (lex.lookAhead(i) == Identifier) { ASTList name = parseClassType(tbl); int dim = parseArrayDimension(); - return parseDeclarators(tbl, new Declarator(name, dim)); + return parseDeclarators(tbl, new Declarator(name, dim, lex.getLineNumber())); } } @@ -605,7 +605,7 @@ public final class Parser implements TokenId { if (exprList) expr = parseExprList(tbl); else - expr = new Stmnt(EXPR, parseExpression(tbl)); + expr = new Stmnt(EXPR, parseExpression(tbl), lex.getLineNumber()); if (lex.get() != ';') throw new CompileError("; is missing", lex); @@ -618,8 +618,8 @@ public final class Parser implements TokenId { private Stmnt parseExprList(SymbolTable tbl) throws CompileError { Stmnt expr = null; for (;;) { - Stmnt e = new Stmnt(EXPR, parseExpression(tbl)); - expr = (Stmnt)ASTList.concat(expr, new Stmnt(BLOCK, e)); + Stmnt e = new Stmnt(EXPR, parseExpression(tbl), lex.getLineNumber()); + expr = (Stmnt)ASTList.concat(expr, new Stmnt(BLOCK, e, lex.getLineNumber())); if (lex.lookAhead() == ',') lex.get(); else @@ -635,7 +635,7 @@ public final class Parser implements TokenId { Stmnt decl = null; for (;;) { decl = (Stmnt)ASTList.concat(decl, - new Stmnt(DECL, parseDeclarator(tbl, d))); + new Stmnt(DECL, parseDeclarator(tbl, d), lex.getLineNumber())); int t = lex.get(); if (t == ';') return decl; @@ -653,7 +653,7 @@ public final class Parser implements TokenId { throw new SyntaxError(lex); String name = lex.getString(); - Symbol symbol = new Symbol(name); + Symbol symbol = new Symbol(name, lex.getLineNumber()); int dim = parseArrayDimension(); ASTree init = null; if (lex.lookAhead() == '=') { @@ -661,7 +661,7 @@ public final class Parser implements TokenId { init = parseInitializer(tbl); } - Declarator decl = d.make(symbol, dim, init); + Declarator decl = d.make(symbol, dim, init, lex.getLineNumber()); tbl.append(name, decl); return decl; } @@ -683,14 +683,14 @@ public final class Parser implements TokenId { lex.get(); // '{' if(lex.lookAhead() == '}'){ lex.get(); - return new ArrayInit(null); + return new ArrayInit(null, lex.getLineNumber()); } ASTree expr = parseExpression(tbl); - ArrayInit init = new ArrayInit(expr); + ArrayInit init = new ArrayInit(expr, lex.getLineNumber()); while (lex.lookAhead() == ',') { lex.get(); expr = parseExpression(tbl); - ASTList.append(init, expr); + ASTList.append(init, expr, lex.getLineNumber()); } if (lex.get() != '}') @@ -722,7 +722,7 @@ public final class Parser implements TokenId { int t = lex.get(); ASTree right = parseExpression(tbl); - return AssignExpr.makeAssign(t, left, right); + return AssignExpr.makeAssign(t, left, right, lex.getLineNumber()); } private static boolean isAssignOp(int t) { @@ -744,7 +744,7 @@ public final class Parser implements TokenId { throw new CompileError(": is missing", lex); ASTree elseExpr = parseExpression(tbl); - return new CondExpr(cond, thenExpr, elseExpr); + return new CondExpr(cond, thenExpr, elseExpr, lex.getLineNumber()); } return cond; } @@ -808,11 +808,11 @@ public final class Parser implements TokenId { if (isBuiltinType(t)) { lex.get(); // primitive type int dim = parseArrayDimension(); - return new InstanceOfExpr(t, dim, expr); + return new InstanceOfExpr(t, dim, expr, lex.getLineNumber()); } ASTList name = parseClassType(tbl); int dim = parseArrayDimension(); - return new InstanceOfExpr(name, dim, expr); + return new InstanceOfExpr(name, dim, expr, lex.getLineNumber()); } private ASTree binaryExpr2(SymbolTable tbl, ASTree expr, int prec) @@ -829,7 +829,7 @@ public final class Parser implements TokenId { if (p2 != 0 && prec > p2) expr2 = binaryExpr2(tbl, expr2, p2); else - return BinExpr.makeBin(t, expr, expr2); + return BinExpr.makeBin(t, expr, expr2, lex.getLineNumber()); } } @@ -887,17 +887,17 @@ public final class Parser implements TokenId { case IntConstant : case CharConstant : lex.get(); - return new IntConst(-lex.getLong(), t2); + return new IntConst(-lex.getLong(), t2, lex.getLineNumber()); case DoubleConstant : case FloatConstant : lex.get(); - return new DoubleConst(-lex.getDouble(), t2); + return new DoubleConst(-lex.getDouble(), t2, lex.getLineNumber()); default : break; } } - return Expr.make(t, parseUnaryExpr(tbl)); + return Expr.make(t, parseUnaryExpr(tbl), lex.getLineNumber()); case '(' : return parseCast(tbl); default : @@ -922,7 +922,7 @@ public final class Parser implements TokenId { if (lex.get() != ')') throw new CompileError(") is missing", lex); - return new CastExpr(t, dim, parseUnaryExpr(tbl)); + return new CastExpr(t, dim, parseUnaryExpr(tbl), lex.getLineNumber()); } else if (t == Identifier && nextIsClassCast()) { lex.get(); // '(' @@ -931,7 +931,7 @@ public final class Parser implements TokenId { if (lex.get() != ')') throw new CompileError(") is missing", lex); - return new CastExpr(name, dim, parseUnaryExpr(tbl)); + return new CastExpr(name, dim, parseUnaryExpr(tbl), lex.getLineNumber()); } else return parsePostfix(tbl); @@ -1001,7 +1001,7 @@ public final class Parser implements TokenId { if (lex.get() != Identifier) throw new SyntaxError(lex); - list = ASTList.append(list, new Symbol(lex.getString())); + list = ASTList.append(list, new Symbol(lex.getString(), lex.getLineNumber()), lex.getLineNumber()); if (lex.lookAhead() == '.') lex.get(); else @@ -1035,11 +1035,11 @@ public final class Parser implements TokenId { case IntConstant : case CharConstant : lex.get(); - return new IntConst(lex.getLong(), token); + return new IntConst(lex.getLong(), token, lex.getLineNumber()); case DoubleConstant : case FloatConstant : lex.get(); - return new DoubleConst(lex.getDouble(), token); + return new DoubleConst(lex.getDouble(), token, lex.getLineNumber()); default : break; } @@ -1066,13 +1066,13 @@ public final class Parser implements TokenId { if (index == null) throw new SyntaxError(lex); - expr = Expr.make(ARRAY, expr, index); + expr = Expr.make(ARRAY, expr, index, lex.getLineNumber()); } break; case PLUSPLUS : case MINUSMINUS : t = lex.get(); - expr = Expr.make(t, null, expr); + expr = Expr.make(t, null, expr, lex.getLineNumber()); break; case '.' : lex.get(); @@ -1080,10 +1080,10 @@ public final class Parser implements TokenId { if (t == CLASS) expr = parseDotClass(expr, 0); else if (t == SUPER) - expr = Expr.make('.', new Symbol(toClassName(expr)), new Keyword(t)); + expr = Expr.make('.', new Symbol(toClassName(expr), lex.getLineNumber()), new Keyword(t, lex.getLineNumber()), lex.getLineNumber()); else if (t == Identifier) { str = lex.getString(); - expr = Expr.make('.', expr, new Member(str)); + expr = Expr.make('.', expr, new Member(str, lex.getLineNumber()), lex.getLineNumber()); } else throw new CompileError("missing member name", lex); @@ -1095,8 +1095,8 @@ public final class Parser implements TokenId { throw new CompileError("missing static member name", lex); str = lex.getString(); - expr = Expr.make(MEMBER, new Symbol(toClassName(expr)), - new Member(str)); + expr = Expr.make(MEMBER, new Symbol(toClassName(expr), lex.getLineNumber()), + new Member(str, lex.getLineNumber()), lex.getLineNumber()); break; default : return expr; @@ -1121,7 +1121,7 @@ public final class Parser implements TokenId { cname = sbuf.toString(); } - return Expr.make('.', new Symbol(cname), new Member("class")); + return Expr.make('.', new Symbol(cname, className.getLineNumber()), new Member("class", className.getLineNumber()), lex.getLineNumber()); } /* Parses a .class expression on a built-in type. For example, @@ -1133,7 +1133,7 @@ public final class Parser implements TokenId { { if (dim > 0) { String cname = CodeGen.toJvmTypeName(builtinType, dim); - return Expr.make('.', new Symbol(cname), new Member("class")); + return Expr.make('.', new Symbol(cname, lex.getLineNumber()), new Member("class", lex.getLineNumber()), lex.getLineNumber()); } String cname; switch(builtinType) { @@ -1166,10 +1166,10 @@ public final class Parser implements TokenId { break; default : throw new CompileError("invalid builtin type: " - + builtinType); + + builtinType, lex); } - return Expr.make(MEMBER, new Symbol(cname), new Member("TYPE")); + return Expr.make(MEMBER, new Symbol(cname, lex.getLineNumber()), new Member("TYPE", lex.getLineNumber()), lex.getLineNumber()); } /* method.call : method.expr "(" argument.list ")" @@ -1193,7 +1193,7 @@ public final class Parser implements TokenId { throw new SyntaxError(lex); } - return CallExpr.makeCall(expr, parseArgumentList(tbl)); + return CallExpr.makeCall(expr, parseArgumentList(tbl), lex.getLineNumber()); } private String toClassName(ASTree name) @@ -1246,15 +1246,15 @@ public final class Parser implements TokenId { case TRUE : case FALSE : case NULL : - return new Keyword(t); + return new Keyword(t, lex.getLineNumber()); case Identifier : name = lex.getString(); decl = tbl.lookup(name); if (decl == null) - return new Member(name); // this or static member - return new Variable(name, decl); // local variable + return new Member(name, lex.getLineNumber()); // this or static member + return new Variable(name, decl, lex.getLineNumber()); // local variable case StringL : - return new StringL(lex.getString()); + return new StringL(lex.getString(), lex.getLineNumber()); case NEW : return parseNew(tbl); case '(' : @@ -1286,21 +1286,21 @@ public final class Parser implements TokenId { if (lex.lookAhead() == '{') init = parseArrayInitializer(tbl); - return new NewExpr(t, size, init); + return new NewExpr(t, size, init, lex.getLineNumber()); } else if (t == Identifier) { ASTList name = parseClassType(tbl); t = lex.lookAhead(); if (t == '(') { ASTList args = parseArgumentList(tbl); - return new NewExpr(name, args); + return new NewExpr(name, args, lex.getLineNumber()); } else if (t == '[') { ASTList size = parseArraySize(tbl); if (lex.lookAhead() == '{') init = parseArrayInitializer(tbl); - return NewExpr.makeObjectArray(name, size, init); + return NewExpr.makeObjectArray(name, size, init, lex.getLineNumber()); } } @@ -1312,7 +1312,7 @@ public final class Parser implements TokenId { private ASTList parseArraySize(SymbolTable tbl) throws CompileError { ASTList list = null; while (lex.lookAhead() == '[') - list = ASTList.append(list, parseArrayIndex(tbl)); + list = ASTList.append(list, parseArrayIndex(tbl), lex.getLineNumber()); return list; } @@ -1341,7 +1341,7 @@ public final class Parser implements TokenId { ASTList list = null; if (lex.lookAhead() != ')') for (;;) { - list = ASTList.append(list, parseExpression(tbl)); + list = ASTList.append(list, parseExpression(tbl), lex.getLineNumber()); if (lex.lookAhead() == ',') lex.get(); else diff --git a/src/main/javassist/compiler/TypeChecker.java b/src/main/javassist/compiler/TypeChecker.java index bceba419..55c35507 100644 --- a/src/main/javassist/compiler/TypeChecker.java +++ b/src/main/javassist/compiler/TypeChecker.java @@ -125,8 +125,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { thisMethod = m; } - protected static void fatal() throws CompileError { - throw new CompileError("fatal"); + protected static void fatal(int lineLum) throws CompileError { + throw new CompileError("fatal", lineLum); } /** @@ -316,9 +316,9 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { if (dim1 == 0 && dim1 == arrayDim) if (CodeGen.rightIsStrong(type1, exprType)) - expr.setThen(new CastExpr(exprType, 0, expr.thenExpr())); + expr.setThen(new CastExpr(exprType, 0, expr.thenExpr(), expr.getLineNumber())); else if (CodeGen.rightIsStrong(exprType, type1)) { - expr.setElse(new CastExpr(type1, 0, expr.elseExpr())); + expr.setElse(new CastExpr(type1, 0, expr.elseExpr(), expr.getLineNumber())); exprType = type1; } } @@ -343,7 +343,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { * an expression using StringBuffer. */ e = CallExpr.makeCall(Expr.make('.', e, - new Member("toString")), null); + new Member("toString", expr.getLineNumber()), expr.getLineNumber()), null, expr.getLineNumber()); expr.setOprand1(e); expr.setOprand2(null); // <---- look at this! className = jvmJavaLangString; @@ -404,9 +404,10 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { if ((type1 == CLASS && dim1 == 0 && jvmJavaLangString.equals(cname)) || (exprType == CLASS && arrayDim == 0 && jvmJavaLangString.equals(className))) { - ASTList sbufClass = ASTList.make(new Symbol("java"), - new Symbol("lang"), new Symbol("StringBuffer")); - ASTree e = new NewExpr(sbufClass, null); + int lineNum = expr.getLineNumber(); + ASTList sbufClass = ASTList.make(new Symbol("java", lineNum), + new Symbol("lang", lineNum), new Symbol("StringBuffer", lineNum), lineNum); + ASTree e = new NewExpr(sbufClass, null, lineNum); exprType = CLASS; arrayDim = 0; className = "java/lang/StringBuffer"; @@ -424,7 +425,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { ASTree newExpr = null; if (left instanceof StringL && right instanceof StringL && op == '+') newExpr = new StringL(((StringL)left).get() - + ((StringL)right).get()); + + ((StringL)right).get(), left.getLineNumber()); else if (left instanceof IntConst) newExpr = ((IntConst)left).compute(op, right); else if (left instanceof DoubleConst) @@ -451,7 +452,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { Expr e = (Expr)expr; int op = e.getOperator(); if (op == MEMBER) { - ASTree cexpr = getConstantFieldValue((Member)e.oprand2()); + ASTree cexpr = getConstantFieldValue((Member)e.oprand2(), expr.getLineNumber()); if (cexpr != null) return cexpr; } @@ -459,7 +460,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { return e.getLeft(); } else if (expr instanceof Member) { - ASTree cexpr = getConstantFieldValue((Member)expr); + ASTree cexpr = getConstantFieldValue((Member)expr, expr.getLineNumber()); if (cexpr != null) return cexpr; } @@ -471,11 +472,11 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { * If MEM is a static final field, this method returns a constant * expression representing the value of that field. */ - private static ASTree getConstantFieldValue(Member mem) { - return getConstantFieldValue(mem.getField()); + private static ASTree getConstantFieldValue(Member mem, int lineNumber) { + return getConstantFieldValue(mem.getField(), lineNumber); } - public static ASTree getConstantFieldValue(CtField f) { + public static ASTree getConstantFieldValue(CtField f, int lineNumber) { if (f == null) return null; @@ -484,19 +485,19 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { return null; if (value instanceof String) - return new StringL((String)value); + return new StringL((String)value, lineNumber); else if (value instanceof Double || value instanceof Float) { int token = (value instanceof Double) ? DoubleConstant : FloatConstant; - return new DoubleConst(((Number)value).doubleValue(), token); + return new DoubleConst(((Number)value).doubleValue(), token, lineNumber); } else if (value instanceof Number) { int token = (value instanceof Long) ? LongConstant : IntConstant; - return new IntConst(((Number)value).longValue(), token); + return new IntConst(((Number)value).longValue(), token, lineNumber); } else if (value instanceof Boolean) return new Keyword(((Boolean)value).booleanValue() - ? TokenId.TRUE : TokenId.FALSE); + ? TokenId.TRUE : TokenId.FALSE, lineNumber); else return null; } @@ -512,8 +513,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { } private static Expr makeAppendCall(ASTree target, ASTree arg) { - return CallExpr.makeCall(Expr.make('.', target, new Member("append")), - new ASTList(arg)); + return CallExpr.makeCall(Expr.make('.', target, new Member("append", target.getLineNumber()), target.getLineNumber()), + new ASTList(arg, target.getLineNumber()), target.getLineNumber()); } private void computeBinExprType(BinExpr expr, int token, int type1) @@ -561,7 +562,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { throws CompileError { if (CodeGen.rightIsStrong(type1, type2)) - expr.setLeft(new CastExpr(type2, 0, expr.oprand1())); + expr.setLeft(new CastExpr(type2, 0, expr.oprand1(), expr.getLineNumber())); else exprType = type1; } @@ -618,7 +619,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { else if (token == '!') booleanExpr(expr); else if (token == CALL) // method call - fatal(); + fatal(expr.getLineNumber()); else { oprand.accept(this); if (!isConstant(expr, token, oprand)) @@ -702,7 +703,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { className = nfe.getField(); // JVM-internal e.setOperator(MEMBER); e.setOprand1(new Symbol(MemberResolver.jvmToJavaName( - className))); + className), e.getLineNumber())); } if (arrayDim > 0) @@ -717,7 +718,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { badMethod(); } else - fatal(); + fatal(expr.getLineNumber()); MemberResolver.Method minfo = atMethodCallCore(targetClass, mname, args); @@ -933,14 +934,14 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { } } - throw new CompileError("bad field access"); + throw new CompileError("bad field access", expr.getLineNumber()); } private CtField fieldAccess2(Expr e, String jvmClassName) throws CompileError { Member fname = (Member)e.oprand2(); CtField f = resolver.lookupFieldByJvmName2(jvmClassName, fname, e); e.setOperator(MEMBER); - e.setOprand1(new Symbol(MemberResolver.jvmToJavaName(jvmClassName))); + e.setOprand1(new Symbol(MemberResolver.jvmToJavaName(jvmClassName), e.getLineNumber())); fname.setField(f); return f; } @@ -1046,7 +1047,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { className = getSuperName(); break; default : - fatal(); + fatal(k.getLineNumber()); } } diff --git a/src/main/javassist/compiler/ast/ASTList.java b/src/main/javassist/compiler/ast/ASTList.java index d9232ca0..786957f5 100644 --- a/src/main/javassist/compiler/ast/ASTList.java +++ b/src/main/javassist/compiler/ast/ASTList.java @@ -28,18 +28,18 @@ public class ASTList extends ASTree { private ASTree left; private ASTList right; - public ASTList(ASTree _head, ASTList _tail) { + public ASTList(ASTree _head, ASTList _tail, int lineNumber) { + super(lineNumber); left = _head; right = _tail; } - public ASTList(ASTree _head) { - left = _head; - right = null; + public ASTList(ASTree _head, int lineNumber) { + this(_head, null, lineNumber); } - public static ASTList make(ASTree e1, ASTree e2, ASTree e3) { - return new ASTList(e1, new ASTList(e2, new ASTList(e3))); + public static ASTList make(ASTree e1, ASTree e2, ASTree e3 , int lineNumber) { + return new ASTList(e1, new ASTList(e2, new ASTList(e3, lineNumber), lineNumber), lineNumber); } @Override @@ -146,8 +146,8 @@ public class ASTList extends ASTree { /** * Appends an object to a list. */ - public static ASTList append(ASTList a, ASTree b) { - return concat(a, new ASTList(b)); + public static ASTList append(ASTList a, ASTree b, int lineNumber) { + return concat(a, new ASTList(b, lineNumber)); } /** diff --git a/src/main/javassist/compiler/ast/ASTree.java b/src/main/javassist/compiler/ast/ASTree.java index 3d4dd842..f155fa87 100644 --- a/src/main/javassist/compiler/ast/ASTree.java +++ b/src/main/javassist/compiler/ast/ASTree.java @@ -29,6 +29,12 @@ public abstract class ASTree implements Serializable { /** default serialVersionUID */ private static final long serialVersionUID = 1L; + private final int lineNumber; + + public ASTree(int lineNumber) { + this.lineNumber = lineNumber; + } + public ASTree getLeft() { return null; } public ASTree getRight() { return null; } @@ -61,4 +67,8 @@ public abstract class ASTree implements Serializable { String name = getClass().getName(); return name.substring(name.lastIndexOf('.') + 1); } + + public int getLineNumber() { + return lineNumber; + } } diff --git a/src/main/javassist/compiler/ast/ArrayInit.java b/src/main/javassist/compiler/ast/ArrayInit.java index 0b87200e..bc3f06ea 100644 --- a/src/main/javassist/compiler/ast/ArrayInit.java +++ b/src/main/javassist/compiler/ast/ArrayInit.java @@ -27,10 +27,12 @@ public class ArrayInit extends ASTList { /** * Constructs an object. - * @param firstElement maybe null when the initializer is {} (empty). + * + * @param firstElement maybe null when the initializer is {} (empty). + * @param lineNumber */ - public ArrayInit(ASTree firstElement) { - super(firstElement); + public ArrayInit(ASTree firstElement, int lineNumber) { + super(firstElement, lineNumber); } /** diff --git a/src/main/javassist/compiler/ast/AssignExpr.java b/src/main/javassist/compiler/ast/AssignExpr.java index a5e1857d..97dfc6e7 100644 --- a/src/main/javassist/compiler/ast/AssignExpr.java +++ b/src/main/javassist/compiler/ast/AssignExpr.java @@ -29,13 +29,13 @@ public class AssignExpr extends Expr { /** default serialVersionUID */ private static final long serialVersionUID = 1L; - private AssignExpr(int op, ASTree _head, ASTList _tail) { - super(op, _head, _tail); + private AssignExpr(int op, ASTree _head, ASTList _tail, int lineNumber) { + super(op, _head, _tail, lineNumber); } public static AssignExpr makeAssign(int op, ASTree oprand1, - ASTree oprand2) { - return new AssignExpr(op, oprand1, new ASTList(oprand2)); + ASTree oprand2, int lineNumber) { + return new AssignExpr(op, oprand1, new ASTList(oprand2, lineNumber), lineNumber); } @Override diff --git a/src/main/javassist/compiler/ast/BinExpr.java b/src/main/javassist/compiler/ast/BinExpr.java index 9630ada9..789312ec 100644 --- a/src/main/javassist/compiler/ast/BinExpr.java +++ b/src/main/javassist/compiler/ast/BinExpr.java @@ -33,12 +33,12 @@ public class BinExpr extends Expr { /** default serialVersionUID */ private static final long serialVersionUID = 1L; - private BinExpr(int op, ASTree _head, ASTList _tail) { - super(op, _head, _tail); + private BinExpr(int op, ASTree _head, ASTList _tail, int lineNumber) { + super(op, _head, _tail, lineNumber); } - public static BinExpr makeBin(int op, ASTree oprand1, ASTree oprand2) { - return new BinExpr(op, oprand1, new ASTList(oprand2)); + public static BinExpr makeBin(int op, ASTree oprand1, ASTree oprand2, int lineNumber) { + return new BinExpr(op, oprand1, new ASTList(oprand2, lineNumber), lineNumber); } @Override diff --git a/src/main/javassist/compiler/ast/CallExpr.java b/src/main/javassist/compiler/ast/CallExpr.java index 395915ed..72a3ca51 100644 --- a/src/main/javassist/compiler/ast/CallExpr.java +++ b/src/main/javassist/compiler/ast/CallExpr.java @@ -28,8 +28,8 @@ public class CallExpr extends Expr { private static final long serialVersionUID = 1L; private MemberResolver.Method method; // cached result of lookupMethod() - private CallExpr(ASTree _head, ASTList _tail) { - super(TokenId.CALL, _head, _tail); + private CallExpr(ASTree _head, ASTList _tail, int lineNumber) { + super(TokenId.CALL, _head, _tail, lineNumber); method = null; } @@ -41,8 +41,8 @@ public class CallExpr extends Expr { return method; } - public static CallExpr makeCall(ASTree target, ASTree args) { - return new CallExpr(target, new ASTList(args)); + public static CallExpr makeCall(ASTree target, ASTree args, int lineNumber) { + return new CallExpr(target, new ASTList(args, lineNumber), lineNumber); } @Override diff --git a/src/main/javassist/compiler/ast/CastExpr.java b/src/main/javassist/compiler/ast/CastExpr.java index 903e5bbd..d3938078 100644 --- a/src/main/javassist/compiler/ast/CastExpr.java +++ b/src/main/javassist/compiler/ast/CastExpr.java @@ -28,14 +28,14 @@ public class CastExpr extends ASTList implements TokenId { protected int castType; protected int arrayDim; - public CastExpr(ASTList className, int dim, ASTree expr) { - super(className, new ASTList(expr)); + public CastExpr(ASTList className, int dim, ASTree expr, int lineNumber) { + super(className, new ASTList(expr, lineNumber), lineNumber); castType = CLASS; arrayDim = dim; } - public CastExpr(int type, int dim, ASTree expr) { - super(null, new ASTList(expr)); + public CastExpr(int type, int dim, ASTree expr, int lineNumber) { + super(null, new ASTList(expr, lineNumber), lineNumber); castType = type; arrayDim = dim; } diff --git a/src/main/javassist/compiler/ast/CondExpr.java b/src/main/javassist/compiler/ast/CondExpr.java index 46435012..e4b6e07b 100644 --- a/src/main/javassist/compiler/ast/CondExpr.java +++ b/src/main/javassist/compiler/ast/CondExpr.java @@ -25,8 +25,8 @@ public class CondExpr extends ASTList { /** default serialVersionUID */ private static final long serialVersionUID = 1L; - public CondExpr(ASTree cond, ASTree thenp, ASTree elsep) { - super(cond, new ASTList(thenp, new ASTList(elsep))); + public CondExpr(ASTree cond, ASTree thenp, ASTree elsep, int lineNumber) { + super(cond, new ASTList(thenp, new ASTList(elsep, lineNumber), lineNumber), lineNumber); } public ASTree condExpr() { return head(); } diff --git a/src/main/javassist/compiler/ast/Declarator.java b/src/main/javassist/compiler/ast/Declarator.java index c29f6740..1713d908 100644 --- a/src/main/javassist/compiler/ast/Declarator.java +++ b/src/main/javassist/compiler/ast/Declarator.java @@ -30,16 +30,16 @@ public class Declarator extends ASTList implements TokenId { protected int localVar; protected String qualifiedClass; // JVM-internal representation - public Declarator(int type, int dim) { - super(null); + public Declarator(int type, int dim, int lineNumber) { + super(null, lineNumber); varType = type; arrayDim = dim; localVar = -1; qualifiedClass = null; } - public Declarator(ASTList className, int dim) { - super(null); + public Declarator(ASTList className, int dim, int lineNumber) { + super(null, lineNumber); varType = CLASS; arrayDim = dim; localVar = -1; @@ -49,21 +49,21 @@ public class Declarator extends ASTList implements TokenId { /* For declaring a pre-defined? local variable. */ public Declarator(int type, String jvmClassName, int dim, - int var, Symbol sym) { - super(null); + int var, Symbol sym, int lineNumber) { + super(null, lineNumber); varType = type; arrayDim = dim; localVar = var; qualifiedClass = jvmClassName; setLeft(sym); - append(this, null); // initializer + append(this, null, lineNumber); // initializer } - public Declarator make(Symbol sym, int dim, ASTree init) { - Declarator d = new Declarator(this.varType, this.arrayDim + dim); + public Declarator make(Symbol sym, int dim, ASTree init, int lineNumber) { + Declarator d = new Declarator(this.varType, this.arrayDim + dim, lineNumber); d.qualifiedClass = this.qualifiedClass; d.setLeft(sym); - append(d, init); + append(d, init, lineNumber); return d; } diff --git a/src/main/javassist/compiler/ast/DoubleConst.java b/src/main/javassist/compiler/ast/DoubleConst.java index f8d0afde..d55821f0 100644 --- a/src/main/javassist/compiler/ast/DoubleConst.java +++ b/src/main/javassist/compiler/ast/DoubleConst.java @@ -28,7 +28,11 @@ public class DoubleConst extends ASTree { protected double value; protected int type; - public DoubleConst(double v, int tokenId) { value = v; type = tokenId; } + public DoubleConst(double v, int tokenId, int lineNumber) { + super(lineNumber); + value = v; + type = tokenId; + } public double get() { return value; } @@ -63,15 +67,15 @@ public class DoubleConst extends ASTree { else newType = TokenId.FloatConstant; - return compute(op, this.value, right.value, newType); + return compute(op, this.value, right.value, newType, getLineNumber()); } private DoubleConst compute0(int op, IntConst right) { - return compute(op, this.value, right.value, this.type); + return compute(op, this.value, right.value, this.type, getLineNumber()); } private static DoubleConst compute(int op, double value1, double value2, - int newType) + int newType, int lineNumber) { double newValue; switch (op) { @@ -94,6 +98,6 @@ public class DoubleConst extends ASTree { return null; } - return new DoubleConst(newValue, newType); + return new DoubleConst(newValue, newType, lineNumber); } } diff --git a/src/main/javassist/compiler/ast/Expr.java b/src/main/javassist/compiler/ast/Expr.java index ed5cb60b..4d2ce1a0 100644 --- a/src/main/javassist/compiler/ast/Expr.java +++ b/src/main/javassist/compiler/ast/Expr.java @@ -33,22 +33,22 @@ public class Expr extends ASTList implements TokenId { private static final long serialVersionUID = 1L; protected int operatorId; - Expr(int op, ASTree _head, ASTList _tail) { - super(_head, _tail); + Expr(int op, ASTree _head, ASTList _tail, int lineNumber) { + super(_head, _tail, lineNumber); operatorId = op; } - Expr(int op, ASTree _head) { - super(_head); + Expr(int op, ASTree _head, int lineNumber) { + super(_head, lineNumber); operatorId = op; } - public static Expr make(int op, ASTree oprand1, ASTree oprand2) { - return new Expr(op, oprand1, new ASTList(oprand2)); + public static Expr make(int op, ASTree oprand1, ASTree oprand2, int lineNumber) { + return new Expr(op, oprand1, new ASTList(oprand2, lineNumber), lineNumber); } - public static Expr make(int op, ASTree oprand1) { - return new Expr(op, oprand1); + public static Expr make(int op, ASTree oprand1, int lineNumber) { + return new Expr(op, oprand1, lineNumber); } public int getOperator() { return operatorId; } diff --git a/src/main/javassist/compiler/ast/FieldDecl.java b/src/main/javassist/compiler/ast/FieldDecl.java index e2a066e9..44df192e 100644 --- a/src/main/javassist/compiler/ast/FieldDecl.java +++ b/src/main/javassist/compiler/ast/FieldDecl.java @@ -22,8 +22,8 @@ public class FieldDecl extends ASTList { /** default serialVersionUID */ private static final long serialVersionUID = 1L; - public FieldDecl(ASTree _head, ASTList _tail) { - super(_head, _tail); + public FieldDecl(ASTree _head, ASTList _tail, int lineNumber) { + super(_head, _tail, lineNumber); } public ASTList getModifiers() { return (ASTList)getLeft(); } diff --git a/src/main/javassist/compiler/ast/InstanceOfExpr.java b/src/main/javassist/compiler/ast/InstanceOfExpr.java index ddf07bd2..e012defe 100644 --- a/src/main/javassist/compiler/ast/InstanceOfExpr.java +++ b/src/main/javassist/compiler/ast/InstanceOfExpr.java @@ -25,12 +25,12 @@ public class InstanceOfExpr extends CastExpr { /** default serialVersionUID */ private static final long serialVersionUID = 1L; - public InstanceOfExpr(ASTList className, int dim, ASTree expr) { - super(className, dim, expr); + public InstanceOfExpr(ASTList className, int dim, ASTree expr, int lineNumber) { + super(className, dim, expr, lineNumber); } - public InstanceOfExpr(int type, int dim, ASTree expr) { - super(type, dim, expr); + public InstanceOfExpr(int type, int dim, ASTree expr, int lineNumber) { + super(type, dim, expr, lineNumber); } @Override diff --git a/src/main/javassist/compiler/ast/IntConst.java b/src/main/javassist/compiler/ast/IntConst.java index 7040b0c9..8ffce479 100644 --- a/src/main/javassist/compiler/ast/IntConst.java +++ b/src/main/javassist/compiler/ast/IntConst.java @@ -28,7 +28,11 @@ public class IntConst extends ASTree { protected long value; protected int type; - public IntConst(long v, int tokenId) { value = v; type = tokenId; } + public IntConst(long v, int tokenId, int lineNumber) { + super(lineNumber); + value = v; + type = tokenId; + } public long get() { return value; } @@ -111,7 +115,7 @@ public class IntConst extends ASTree { return null; } - return new IntConst(newValue, newType); + return new IntConst(newValue, newType, right.getLineNumber()); } private DoubleConst compute0(int op, DoubleConst right) { @@ -138,6 +142,6 @@ public class IntConst extends ASTree { return null; } - return new DoubleConst(newValue, right.type); + return new DoubleConst(newValue, right.type, right.getLineNumber()); } } diff --git a/src/main/javassist/compiler/ast/Keyword.java b/src/main/javassist/compiler/ast/Keyword.java index b509375c..858316d5 100644 --- a/src/main/javassist/compiler/ast/Keyword.java +++ b/src/main/javassist/compiler/ast/Keyword.java @@ -26,7 +26,8 @@ public class Keyword extends ASTree { private static final long serialVersionUID = 1L; protected int tokenId; - public Keyword(int token) { + public Keyword(int token, int lineNumber) { + super(lineNumber); tokenId = token; } diff --git a/src/main/javassist/compiler/ast/Member.java b/src/main/javassist/compiler/ast/Member.java index 192c9ef3..279e2516 100644 --- a/src/main/javassist/compiler/ast/Member.java +++ b/src/main/javassist/compiler/ast/Member.java @@ -29,8 +29,8 @@ public class Member extends Symbol { // this is used to obtain the value of a static final field. private CtField field; - public Member(String name) { - super(name); + public Member(String name, int lineNumber) { + super(name, lineNumber); field = null; } diff --git a/src/main/javassist/compiler/ast/MethodDecl.java b/src/main/javassist/compiler/ast/MethodDecl.java index d96e3d4d..263775b0 100644 --- a/src/main/javassist/compiler/ast/MethodDecl.java +++ b/src/main/javassist/compiler/ast/MethodDecl.java @@ -23,8 +23,8 @@ public class MethodDecl extends ASTList { private static final long serialVersionUID = 1L; public static final String initName = ""; - public MethodDecl(ASTree _head, ASTList _tail) { - super(_head, _tail); + public MethodDecl(ASTree _head, ASTList _tail, int lineNumber) { + super(_head, _tail, lineNumber); } public boolean isConstructor() { diff --git a/src/main/javassist/compiler/ast/NewExpr.java b/src/main/javassist/compiler/ast/NewExpr.java index 44b264c0..d4f7f475 100644 --- a/src/main/javassist/compiler/ast/NewExpr.java +++ b/src/main/javassist/compiler/ast/NewExpr.java @@ -28,26 +28,26 @@ public class NewExpr extends ASTList implements TokenId { protected boolean newArray; protected int arrayType; - public NewExpr(ASTList className, ASTList args) { - super(className, new ASTList(args)); + public NewExpr(ASTList className, ASTList args, int lineNumber) { + super(className, new ASTList(args, lineNumber), lineNumber); newArray = false; arrayType = CLASS; } - public NewExpr(int type, ASTList arraySize, ArrayInit init) { - super(null, new ASTList(arraySize)); + public NewExpr(int type, ASTList arraySize, ArrayInit init, int lineNumber) { + super(null, new ASTList(arraySize, lineNumber), lineNumber); newArray = true; arrayType = type; if (init != null) - append(this, init); + append(this, init, lineNumber); } public static NewExpr makeObjectArray(ASTList className, - ASTList arraySize, ArrayInit init) { - NewExpr e = new NewExpr(className, arraySize); + ASTList arraySize, ArrayInit init, int lineNumber) { + NewExpr e = new NewExpr(className, arraySize, lineNumber); e.newArray = true; if (init != null) - append(e, init); + append(e, init, lineNumber); return e; } diff --git a/src/main/javassist/compiler/ast/Pair.java b/src/main/javassist/compiler/ast/Pair.java index 949028a4..44411b8d 100644 --- a/src/main/javassist/compiler/ast/Pair.java +++ b/src/main/javassist/compiler/ast/Pair.java @@ -28,6 +28,7 @@ public class Pair extends ASTree { protected ASTree left, right; public Pair(ASTree _left, ASTree _right) { + super(_left.getLineNumber()); left = _left; right = _right; } diff --git a/src/main/javassist/compiler/ast/Stmnt.java b/src/main/javassist/compiler/ast/Stmnt.java index c5aa5df3..7333d026 100644 --- a/src/main/javassist/compiler/ast/Stmnt.java +++ b/src/main/javassist/compiler/ast/Stmnt.java @@ -27,26 +27,26 @@ public class Stmnt extends ASTList implements TokenId { private static final long serialVersionUID = 1L; protected int operatorId; - public Stmnt(int op, ASTree _head, ASTList _tail) { - super(_head, _tail); + public Stmnt(int op, ASTree _head, ASTList _tail, int lineNumber) { + super(_head, _tail, lineNumber); operatorId = op; } - public Stmnt(int op, ASTree _head) { - super(_head); + public Stmnt(int op, ASTree _head, int lineNumber) { + super(_head, lineNumber); operatorId = op; } - public Stmnt(int op) { - this(op, null); + public Stmnt(int op, int lineNumber) { + this(op, null, lineNumber); } - public static Stmnt make(int op, ASTree oprand1, ASTree oprand2) { - return new Stmnt(op, oprand1, new ASTList(oprand2)); + public static Stmnt make(int op, ASTree oprand1, ASTree oprand2, int lineNumber) { + return new Stmnt(op, oprand1, new ASTList(oprand2, lineNumber), lineNumber); } - public static Stmnt make(int op, ASTree op1, ASTree op2, ASTree op3) { - return new Stmnt(op, op1, new ASTList(op2, new ASTList(op3))); + public static Stmnt make(int op, ASTree op1, ASTree op2, ASTree op3, int lineNumber) { + return new Stmnt(op, op1, new ASTList(op2, new ASTList(op3, lineNumber), lineNumber), lineNumber); } @Override diff --git a/src/main/javassist/compiler/ast/StringL.java b/src/main/javassist/compiler/ast/StringL.java index 7c7e00c3..063bb5ed 100644 --- a/src/main/javassist/compiler/ast/StringL.java +++ b/src/main/javassist/compiler/ast/StringL.java @@ -26,7 +26,8 @@ public class StringL extends ASTree { private static final long serialVersionUID = 1L; protected String text; - public StringL(String t) { + public StringL(String t, int lineNumber) { + super(lineNumber); text = t; } diff --git a/src/main/javassist/compiler/ast/Symbol.java b/src/main/javassist/compiler/ast/Symbol.java index 2b66207a..64c598eb 100644 --- a/src/main/javassist/compiler/ast/Symbol.java +++ b/src/main/javassist/compiler/ast/Symbol.java @@ -26,7 +26,8 @@ public class Symbol extends ASTree { private static final long serialVersionUID = 1L; protected String identifier; - public Symbol(String sym) { + public Symbol(String sym, int lineNumber) { + super(lineNumber); identifier = sym; } diff --git a/src/main/javassist/compiler/ast/Variable.java b/src/main/javassist/compiler/ast/Variable.java index c9224a7a..2e186950 100644 --- a/src/main/javassist/compiler/ast/Variable.java +++ b/src/main/javassist/compiler/ast/Variable.java @@ -26,8 +26,8 @@ public class Variable extends Symbol { private static final long serialVersionUID = 1L; protected Declarator declarator; - public Variable(String sym, Declarator d) { - super(sym); + public Variable(String sym, Declarator d, int lineNumber) { + super(sym, lineNumber); declarator = d; } diff --git a/src/test/javassist/bytecode/BytecodeTest.java b/src/test/javassist/bytecode/BytecodeTest.java index eac420bc..b7ab1f33 100644 --- a/src/test/javassist/bytecode/BytecodeTest.java +++ b/src/test/javassist/bytecode/BytecodeTest.java @@ -302,6 +302,41 @@ public class BytecodeTest extends TestCase { 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 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");