From 9777bae93cc84249fe08a7e81b2101c415bd55e5 Mon Sep 17 00:00:00 2001 From: akuznetsov Date: Fri, 29 Dec 2023 17:29:28 +0400 Subject: [PATCH] line numbers for undefined ids & more --- src/main/javassist/compiler/CodeGen.java | 8 +-- src/main/javassist/compiler/CompileError.java | 2 +- src/main/javassist/compiler/Javac.java | 28 ++++---- src/main/javassist/compiler/JvstCodeGen.java | 46 ++++++------ .../javassist/compiler/JvstTypeChecker.java | 24 +++---- .../javassist/compiler/MemberCodeGen.java | 50 ++++++------- .../javassist/compiler/MemberResolver.java | 72 ++++++++++--------- .../javassist/compiler/ProceedHandler.java | 4 +- src/main/javassist/compiler/TypeChecker.java | 56 +++++++-------- src/main/javassist/expr/Cast.java | 10 +-- src/main/javassist/expr/FieldAccess.java | 20 +++--- src/main/javassist/expr/Instanceof.java | 10 +-- src/main/javassist/expr/NewArray.java | 10 +-- src/main/javassist/expr/NewExpr.java | 10 +-- src/test/javassist/LineNumberTest.java | 14 ++++ src/test/javassist/compiler/CompTest.java | 4 +- 16 files changed, 191 insertions(+), 177 deletions(-) diff --git a/src/main/javassist/compiler/CodeGen.java b/src/main/javassist/compiler/CodeGen.java index 1f028f2b..e7e274b9 100644 --- a/src/main/javassist/compiler/CodeGen.java +++ b/src/main/javassist/compiler/CodeGen.java @@ -184,7 +184,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { /* Expands a simple class name to java.lang.*. * For example, this converts Object into java/lang/Object. */ - protected abstract String resolveClassName(String jvmClassName) + protected abstract String resolveClassName(String jvmClassName, int lineNumber) throws CompileError; /** @@ -802,7 +802,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { @Override public void atDeclarator(Declarator d) throws CompileError { d.setLocalVar(getMaxLocals()); - d.setClassName(resolveClassName(d.getClassName())); + d.setClassName(resolveClassName(d.getClassName(), d.getLineNumber())); int size; if (is2word(d.getType(), d.getArrayDim())) @@ -1656,7 +1656,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { int i = cname.indexOf("[L"); if (i >= 0) { String name = cname.substring(i + 2, cname.length() - 1); - String name2 = resolveClassName(name); + String name2 = resolveClassName(name, expr.getLineNumber()); if (!name.equals(name2)) { /* For example, to obtain String[].class, * "[Ljava.lang.String;" (not "[Ljava/lang/String"!) @@ -1673,7 +1673,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId { } } else { - cname = resolveClassName(MemberResolver.javaToJvmName(cname)); + cname = resolveClassName(MemberResolver.javaToJvmName(cname), expr.getLineNumber()); cname = MemberResolver.jvmToJavaName(cname); } diff --git a/src/main/javassist/compiler/CompileError.java b/src/main/javassist/compiler/CompileError.java index 8bb12cba..3a41779c 100644 --- a/src/main/javassist/compiler/CompileError.java +++ b/src/main/javassist/compiler/CompileError.java @@ -37,7 +37,7 @@ public class CompileError extends Exception { reason = String.format("line %d: %s", lineNumber, s); } - public CompileError(String s) { + private CompileError(String s) { reason = s; lex = null; } diff --git a/src/main/javassist/compiler/Javac.java b/src/main/javassist/compiler/Javac.java index 63da50a6..8d1a04f3 100644 --- a/src/main/javassist/compiler/Javac.java +++ b/src/main/javassist/compiler/Javac.java @@ -95,7 +95,8 @@ public class Javac { */ public CtMember compile(String src) throws CompileError { int startLine = gen.thisClass.getLinesCount(); - Parser p = new Parser(new Lex(src, startLine)); + Lex lex = new Lex(src, startLine); + Parser p = new Parser(lex); ASTList mem = p.parseMember1(stable); try { if (mem instanceof FieldDecl) @@ -107,11 +108,8 @@ public class Javac { decl.getClassFile2()); return cb; } - catch (BadBytecode bb) { - throw new CompileError(bb.getMessage()); - } - catch (CannotCompileException e) { - throw new CompileError(e.getMessage()); + catch (BadBytecode | CannotCompileException bb) { + throw new CompileError(bb.getMessage(), lex.getLineNumber()); } } @@ -186,7 +184,7 @@ public class Javac { return method; } catch (NotFoundException e) { - throw new CompileError(e.toString()); + throw new CompileError(e.toString(), md.getLineNumber()); } } @@ -222,7 +220,7 @@ public class Javac { Stmnt s = p.parseStatement(stb); if (p.hasMore()) throw new CompileError( - "the method/constructor body must be surrounded by {}"); + "the method/constructor body must be surrounded by {}", s.getLineNumber()); boolean callSuper = false; if (method instanceof CtConstructor) @@ -234,7 +232,7 @@ public class Javac { return bytecode; } catch (NotFoundException e) { - throw new CompileError(e.toString()); + throw new CompileError(e.toString(), -1); } } @@ -446,7 +444,7 @@ public class Javac { ProceedHandler h = new ProceedHandler() { @Override - public void doit(JvstCodeGen gen, Bytecode b, ASTList args) + public void doit(JvstCodeGen gen, Bytecode b, ASTList args, int lineNumber) throws CompileError { ASTree expr = new Member(m, texpr.getLineNumber()); @@ -459,7 +457,7 @@ public class Javac { } @Override - public void setReturnType(JvstTypeChecker check, ASTList args) + public void setReturnType(JvstTypeChecker check, ASTList args, int lineNumber) throws CompileError { ASTree expr = new Member(m, texpr.getLineNumber()); @@ -492,7 +490,7 @@ public class Javac { ProceedHandler h = new ProceedHandler() { @Override - public void doit(JvstCodeGen gen, Bytecode b, ASTList args) + public void doit(JvstCodeGen gen, Bytecode b, ASTList args, int lineNumber) throws CompileError { Expr expr = Expr.make(TokenId.MEMBER, @@ -503,7 +501,7 @@ public class Javac { } @Override - public void setReturnType(JvstTypeChecker check, ASTList args) + public void setReturnType(JvstTypeChecker check, ASTList args, int lineNumber) throws CompileError { Expr expr = Expr.make(TokenId.MEMBER, @@ -538,14 +536,14 @@ public class Javac { ProceedHandler h = new ProceedHandler() { @Override - public void doit(JvstCodeGen gen, Bytecode b, ASTList args) + public void doit(JvstCodeGen gen, Bytecode b, ASTList args, int lineNumber) throws CompileError { gen.compileInvokeSpecial(texpr, methodIndex, descriptor, args); } @Override - public void setReturnType(JvstTypeChecker c, ASTList args) + public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) throws CompileError { c.compileInvokeSpecial(texpr, classname, methodname, descriptor, args); diff --git a/src/main/javassist/compiler/JvstCodeGen.java b/src/main/javassist/compiler/JvstCodeGen.java index 4f251924..6a372018 100644 --- a/src/main/javassist/compiler/JvstCodeGen.java +++ b/src/main/javassist/compiler/JvstCodeGen.java @@ -147,7 +147,7 @@ public class JvstCodeGen extends MemberCodeGen { if (arrayDim != 1 || exprType != CLASS) throw new CompileError("invalid type for " + paramArrayName, expr.getLineNumber()); - atAssignParamList(paramTypeList, bytecode); + atAssignParamList(paramTypeList, bytecode, expr.getLineNumber()); if (!doDup) bytecode.addOpcode(POP); } @@ -155,7 +155,7 @@ public class JvstCodeGen extends MemberCodeGen { super.atFieldAssign(expr, op, left, right, doDup); } - protected void atAssignParamList(CtClass[] params, Bytecode code) + protected void atAssignParamList(CtClass[] params, Bytecode code, int lineNumber) throws CompileError { if (params == null) @@ -167,7 +167,7 @@ public class JvstCodeGen extends MemberCodeGen { code.addOpcode(DUP); code.addIconst(i); code.addOpcode(AALOAD); - compileUnwrapValue(params[i], code); + compileUnwrapValue(params[i], code, lineNumber); code.addStore(varNo, params[i]); varNo += is2word(exprType, arrayDim) ? 2 : 1; } @@ -201,10 +201,10 @@ public class JvstCodeGen extends MemberCodeGen { protected void atCastToRtype(CastExpr expr) throws CompileError { expr.getOprand().accept(this); if (exprType == VOID || isRefType(exprType) || arrayDim > 0) - compileUnwrapValue(returnType, bytecode); + compileUnwrapValue(returnType, bytecode, expr.getLineNumber()); else if (returnType instanceof CtPrimitiveType) { CtPrimitiveType pt = (CtPrimitiveType)returnType; - int destType = MemberResolver.descToType(pt.getDescriptor()); + int destType = MemberResolver.descToType(pt.getDescriptor(), expr.getLineNumber()); atNumCastExpr(exprType, destType); exprType = destType; arrayDim = 0; @@ -219,7 +219,7 @@ public class JvstCodeGen extends MemberCodeGen { if (isRefType(exprType) || arrayDim > 0) return; // Object type. do nothing. - CtClass clazz = resolver.lookupClass(exprType, arrayDim, className); + CtClass clazz = resolver.lookupClass(exprType, arrayDim, className, expr.getLineNumber()); if (clazz instanceof CtPrimitiveType) { CtPrimitiveType pt = (CtPrimitiveType)clazz; String wrapper = pt.getWrapperName(); @@ -249,7 +249,7 @@ public class JvstCodeGen extends MemberCodeGen { if (method instanceof Member) { String name = ((Member)method).get(); if (procHandler != null && name.equals(proceedName)) { - procHandler.doit(this, bytecode, (ASTList)expr.oprand2()); + procHandler.doit(this, bytecode, (ASTList)expr.oprand2(), expr.getLineNumber()); return; } else if (name.equals(cflowName)) { @@ -364,7 +364,7 @@ public class JvstCodeGen extends MemberCodeGen { for (int k = 0; k < n; ++k) { CtClass p = params[k]; regno += bytecode.addLoad(regno, p); - setType(p); + setType(p, a.getLineNumber()); types[i] = exprType; dims[i] = arrayDim; cnames[i] = className; @@ -420,7 +420,7 @@ public class JvstCodeGen extends MemberCodeGen { atMethodArgs(args, new int[nargs], new int[nargs], new String[nargs]); bytecode.addInvokespecial(methodIndex, descriptor); - setReturnType(descriptor, false, false); + setReturnType(descriptor, false, false, target.getLineNumber()); addNullIfVoid(); } @@ -569,7 +569,7 @@ public class JvstCodeGen extends MemberCodeGen { className = jvmJavaLangObject; } else - setType(cc); + setType(cc, cc.getLinesCount()); Declarator decl = new Declarator(exprType, className, arrayDim, @@ -593,7 +593,7 @@ public class JvstCodeGen extends MemberCodeGen { while ((c = typeDesc.charAt(dim)) == '[') ++dim; - int type = MemberResolver.descToType(c); + int type = MemberResolver.descToType(c, -1); String cname = null; if (type == CLASS) { if (dim == 0) @@ -653,7 +653,7 @@ public class JvstCodeGen extends MemberCodeGen { return 8; } - protected void compileUnwrapValue(CtClass type, Bytecode code) + protected void compileUnwrapValue(CtClass type, Bytecode code, int lineNumber) throws CompileError { if (type == CtClass.voidType) { @@ -662,7 +662,7 @@ public class JvstCodeGen extends MemberCodeGen { } if (exprType == VOID) - throw new CompileError("invalid type for " + returnCastName); + throw new CompileError("invalid type for " + returnCastName, lineNumber); if (type instanceof CtPrimitiveType) { CtPrimitiveType pt = (CtPrimitiveType)type; @@ -671,34 +671,34 @@ public class JvstCodeGen extends MemberCodeGen { code.addCheckcast(wrapper); code.addInvokevirtual(wrapper, pt.getGetMethodName(), pt.getGetMethodDescriptor()); - setType(type); + setType(type, lineNumber); } else { code.addCheckcast(type); - setType(type); + setType(type, lineNumber); } } /* Sets exprType, arrayDim, and className; * If type is void, then this method does nothing. */ - public void setType(CtClass type) throws CompileError { - setType(type, 0); + public void setType(CtClass type, int lineNumber) throws CompileError { + setType(type, 0, lineNumber); } - private void setType(CtClass type, int dim) throws CompileError { + private void setType(CtClass type, int dim, int lineNumber) throws CompileError { if (type.isPrimitive()) { CtPrimitiveType pt = (CtPrimitiveType)type; - exprType = MemberResolver.descToType(pt.getDescriptor()); + exprType = MemberResolver.descToType(pt.getDescriptor(), lineNumber); arrayDim = dim; className = null; } else if (type.isArray()) try { - setType(type.getComponentType(), dim + 1); + setType(type.getComponentType(), dim + 1, lineNumber); } catch (NotFoundException e) { - throw new CompileError("undefined type: " + type.getName()); + throw new CompileError("undefined type: " + type.getName(), lineNumber); } else { exprType = CLASS; @@ -714,9 +714,9 @@ public class JvstCodeGen extends MemberCodeGen { if (type instanceof CtPrimitiveType) { CtPrimitiveType pt = (CtPrimitiveType)type; atNumCastExpr(exprType, - MemberResolver.descToType(pt.getDescriptor())); + MemberResolver.descToType(pt.getDescriptor(), type.getLinesCount() - 1)); } else - throw new CompileError("type mismatch"); + throw new CompileError("type mismatch", type.getLinesCount() - 1); } } diff --git a/src/main/javassist/compiler/JvstTypeChecker.java b/src/main/javassist/compiler/JvstTypeChecker.java index d25928a6..dbd1b358 100644 --- a/src/main/javassist/compiler/JvstTypeChecker.java +++ b/src/main/javassist/compiler/JvstTypeChecker.java @@ -127,7 +127,7 @@ public class JvstTypeChecker extends TypeChecker { compileUnwrapValue(returnType, expr.getLineNumber()); else if (returnType instanceof CtPrimitiveType) { CtPrimitiveType pt = (CtPrimitiveType)returnType; - int destType = MemberResolver.descToType(pt.getDescriptor()); + int destType = MemberResolver.descToType(pt.getDescriptor(), expr.getLineNumber()); exprType = destType; arrayDim = 0; className = null; @@ -139,7 +139,7 @@ public class JvstTypeChecker extends TypeChecker { if (CodeGen.isRefType(exprType) || arrayDim > 0) return; // Object type. do nothing. - CtClass clazz = resolver.lookupClass(exprType, arrayDim, className); + CtClass clazz = resolver.lookupClass(exprType, arrayDim, className, expr.getLineNumber()); if (clazz instanceof CtPrimitiveType) { exprType = CLASS; arrayDim = 0; @@ -158,7 +158,7 @@ public class JvstTypeChecker extends TypeChecker { if (codeGen.procHandler != null && name.equals(codeGen.proceedName)) { codeGen.procHandler.setReturnType(this, - (ASTList)expr.oprand2()); + (ASTList)expr.oprand2(), expr.getLineNumber()); return; } else if (name.equals(JvstCodeGen.cflowName)) { @@ -223,7 +223,7 @@ public class JvstTypeChecker extends TypeChecker { int n = params.length; for (int k = 0; k < n; ++k) { CtClass p = params[k]; - setType(p); + setType(p, a.getLineNumber()); types[i] = exprType; dims[i] = arrayDim; cnames[i] = className; @@ -254,7 +254,7 @@ public class JvstTypeChecker extends TypeChecker { int nargs = getMethodArgsLength(args); atMethodArgs(args, new int[nargs], new int[nargs], new String[nargs]); - setReturnType(descriptor); + setReturnType(descriptor, target.getLineNumber()); addNullIfVoid(); } @@ -263,29 +263,29 @@ public class JvstTypeChecker extends TypeChecker { if (type == CtClass.voidType) addNullIfVoid(); else - setType(type); + setType(type, lineNumber); } /* Sets exprType, arrayDim, and className; * If type is void, then this method does nothing. */ - public void setType(CtClass type) throws CompileError { - setType(type, 0); + public void setType(CtClass type, int lineNumber) throws CompileError { + setType(type, 0, lineNumber); } - private void setType(CtClass type, int dim) throws CompileError { + private void setType(CtClass type, int dim, int lineNumber) throws CompileError { if (type.isPrimitive()) { CtPrimitiveType pt = (CtPrimitiveType)type; - exprType = MemberResolver.descToType(pt.getDescriptor()); + exprType = MemberResolver.descToType(pt.getDescriptor(), lineNumber); arrayDim = dim; className = null; } else if (type.isArray()) try { - setType(type.getComponentType(), dim + 1); + setType(type.getComponentType(), dim + 1, lineNumber); } catch (NotFoundException e) { - throw new CompileError("undefined type: " + type.getName()); + throw new CompileError("undefined type: " + type.getName(), lineNumber); } else { exprType = CLASS; diff --git a/src/main/javassist/compiler/MemberCodeGen.java b/src/main/javassist/compiler/MemberCodeGen.java index 52e3aaea..884b39df 100644 --- a/src/main/javassist/compiler/MemberCodeGen.java +++ b/src/main/javassist/compiler/MemberCodeGen.java @@ -254,7 +254,7 @@ public class MemberCodeGen extends CodeGen { decl.setLocalVar(var); - CtClass type = resolver.lookupClassByJvmName(decl.getClassName()); + CtClass type = resolver.lookupClassByJvmName(decl.getClassName(), st.getLineNumber()); decl.setClassName(MemberResolver.javaToJvmName(type.getName())); bc.addExceptionHandler(start, end, bc.currentPc(), type); bc.growStack(1); @@ -373,7 +373,7 @@ public class MemberCodeGen extends CodeGen { String elementClass; if (type == CLASS) { - elementClass = resolveClassName(jvmClassname); + elementClass = resolveClassName(jvmClassname, lineNumber); bytecode.addAnewarray(MemberResolver.jvmToJavaName(elementClass)); } else { @@ -515,7 +515,7 @@ public class MemberCodeGen extends CodeGen { int op = e.getOperator(); if (op == MEMBER) { // static method targetClass - = resolver.lookupClass(((Symbol)e.oprand1()).get(), false); + = resolver.lookupClass(((Symbol)e.oprand1()).get(), false, expr.getLineNumber()); isStatic = true; } else if (op == '.') { @@ -552,15 +552,15 @@ public class MemberCodeGen extends CodeGen { } if (arrayDim > 0) - targetClass = resolver.lookupClass(javaLangObject, true); + targetClass = resolver.lookupClass(javaLangObject, true, expr.getLineNumber()); else if (exprType == CLASS /* && arrayDim == 0 */) - targetClass = resolver.lookupClassByJvmName(className); + targetClass = resolver.lookupClassByJvmName(className, expr.getLineNumber()); else - badMethod(); + badMethod(e.getLineNumber()); } } else - badMethod(); + badMethod(expr.getLineNumber()); } else fatal(expr.getLineNumber()); @@ -569,8 +569,8 @@ public class MemberCodeGen extends CodeGen { aload0pos, cached); } - private static void badMethod() throws CompileError { - throw new CompileError("bad method"); + private static void badMethod(int lineNumber) throws CompileError { + throw new CompileError("bad method", lineNumber); } /* @@ -645,7 +645,7 @@ public class MemberCodeGen extends CodeGen { if (mname.equals(MethodInfo.nameInit)) { isSpecial = true; if (declClass != targetClass) - throw new CompileError("no such constructor: " + targetClass.getName()); + throw new CompileError("no such constructor: " + targetClass.getName(), targetClass.getLinesCount() - 1); if (declClass != thisClass && AccessFlag.isPrivate(acc)) { if (declClass.getClassFile().getMajorVersion() < ClassFile.JAVA_8 @@ -701,12 +701,12 @@ public class MemberCodeGen extends CodeGen { } else if (isStatic) - throw new CompileError(mname + " is not static"); + throw new CompileError(mname + " is not static", targetClass.getLinesCount() - 1); else bytecode.addInvokevirtual(declClass, mname, desc); } - setReturnType(desc, isStatic, popTarget); + setReturnType(desc, isStatic, popTarget, targetClass.getLinesCount() - 1); } /* @@ -729,7 +729,7 @@ public class MemberCodeGen extends CodeGen { } throw new CompileError("Method " + methodName - + " is private"); + + " is private", declClass.getLinesCount() - 1); } /* @@ -752,7 +752,7 @@ public class MemberCodeGen extends CodeGen { } throw new CompileError("the called constructor is private in " - + declClass.getName()); + + declClass.getName(), declClass.getLinesCount() - 1); } private boolean isEnclosing(CtClass outer, CtClass inner) { @@ -785,12 +785,12 @@ public class MemberCodeGen extends CodeGen { } } - void setReturnType(String desc, boolean isStatic, boolean popTarget) + void setReturnType(String desc, boolean isStatic, boolean popTarget, int lineNumber) throws CompileError { int i = desc.indexOf(')'); if (i < 0) - badMethod(); + badMethod(lineNumber); char c = desc.charAt(++i); int dim = 0; @@ -803,13 +803,13 @@ public class MemberCodeGen extends CodeGen { if (c == 'L') { int j = desc.indexOf(';', i + 1); if (j < 0) - badMethod(); + badMethod(lineNumber); exprType = CLASS; className = desc.substring(i + 1, j); } else { - exprType = MemberResolver.descToType(c); + exprType = MemberResolver.descToType(c, lineNumber); className = null; } @@ -843,7 +843,7 @@ public class MemberCodeGen extends CodeGen { int fi; if (op == '=') { FieldInfo finfo = f.getFieldInfo2(); - setFieldType(finfo); + setFieldType(finfo, expr.getLineNumber()); AccessorMaker maker = isAccessibleField(f, finfo, expr.getLineNumber()); if (maker == null) fi = addFieldrefInfo(f, finfo); @@ -926,7 +926,7 @@ public class MemberCodeGen extends CodeGen { atFieldRead(f, is_static,expr.getLineNumber() ); else { cexpr.accept(this); - setFieldType(f.getFieldInfo2()); + setFieldType(f.getFieldInfo2(), expr.getLineNumber()); } } @@ -946,7 +946,7 @@ public class MemberCodeGen extends CodeGen { */ private int atFieldRead(CtField f, boolean isStatic, int lineNumber) throws CompileError { FieldInfo finfo = f.getFieldInfo2(); - boolean is2byte = setFieldType(finfo); + boolean is2byte = setFieldType(finfo, lineNumber); AccessorMaker maker = isAccessibleField(f, finfo, lineNumber); if (maker != null) { MethodInfo minfo = maker.getFieldGetter(finfo, isStatic); @@ -996,7 +996,7 @@ public class MemberCodeGen extends CodeGen { * * @return true if the field type is long or double. */ - private boolean setFieldType(FieldInfo finfo) throws CompileError { + private boolean setFieldType(FieldInfo finfo, int lineNumber) throws CompileError { String type = finfo.getDescriptor(); int i = 0; @@ -1008,7 +1008,7 @@ public class MemberCodeGen extends CodeGen { } arrayDim = dim; - exprType = MemberResolver.descToType(c); + exprType = MemberResolver.descToType(c, lineNumber); if (c == 'L') className = type.substring(i + 1, type.indexOf(';', i + 1)); @@ -1201,7 +1201,7 @@ public class MemberCodeGen extends CodeGen { * For example, this converts Object into java/lang/Object. */ @Override - protected String resolveClassName(String jvmName) throws CompileError { - return resolver.resolveJvmClassName(jvmName); + protected String resolveClassName(String jvmName, int lineNumber) throws CompileError { + return resolver.resolveJvmClassName(jvmName, lineNumber); } } diff --git a/src/main/javassist/compiler/MemberResolver.java b/src/main/javassist/compiler/MemberResolver.java index c01974df..2ccb0ff7 100644 --- a/src/main/javassist/compiler/MemberResolver.java +++ b/src/main/javassist/compiler/MemberResolver.java @@ -50,8 +50,8 @@ public class MemberResolver implements TokenId { public ClassPool getClassPool() { return classPool; } - private static void fatal() throws CompileError { - throw new CompileError("fatal"); + private static void fatal(int lineNumber) throws CompileError { + throw new CompileError("fatal", lineNumber); } public static class Method { @@ -85,7 +85,7 @@ public class MemberResolver implements TokenId { if (current != null && clazz == currentClass) if (current.getName().equals(methodName)) { int res = compareSignature(current.getDescriptor(), - argTypes, argDims, argClassNames); + argTypes, argDims, argClassNames, currentClass.getLinesCount() - 1); if (res != NO) { Method r = new Method(clazz, current, res); if (res == YES) @@ -116,7 +116,7 @@ public class MemberResolver implements TokenId { if (minfo.getName().equals(methodName) && (minfo.getAccessFlags() & AccessFlag.BRIDGE) == 0) { int res = compareSignature(minfo.getDescriptor(), - argTypes, argDims, argClassNames); + argTypes, argDims, argClassNames, clazz.getLinesCount() - 1); if (res != NO) { Method r = new Method(clazz, minfo, res); if (res == YES) @@ -192,7 +192,7 @@ public class MemberResolver implements TokenId { * of parameter types that do not exactly match. */ private int compareSignature(String desc, int[] argTypes, - int[] argDims, String[] argClassNames) + int[] argDims, String[] argClassNames, int lineNumber) throws CompileError { int result = YES; @@ -240,9 +240,9 @@ public class MemberResolver implements TokenId { String cname = desc.substring(i, j); if (!cname.equals(argClassNames[n])) { - CtClass clazz = lookupClassByJvmName(argClassNames[n]); + CtClass clazz = lookupClassByJvmName(argClassNames[n], lineNumber); try { - if (clazz.subtypeOf(lookupClassByJvmName(cname))) + if (clazz.subtypeOf(lookupClassByJvmName(cname, lineNumber))) result++; else return NO; @@ -255,7 +255,7 @@ public class MemberResolver implements TokenId { i = j + 1; } else { - int t = descToType(c); + int t = descToType(c, lineNumber); int at = argTypes[n]; if (t != at) if (t == INT @@ -273,7 +273,7 @@ public class MemberResolver implements TokenId { * Only used by fieldAccess() in MemberCodeGen and TypeChecker. * * @param jvmClassName a JVM class name. e.g. java/lang/String - * @see #lookupClass(String, boolean) + * @see #lookupClass(String, boolean, int) */ public CtField lookupFieldByJvmName2(String jvmClassName, Symbol fieldSym, ASTree expr) throws NoFieldException @@ -281,7 +281,7 @@ public class MemberResolver implements TokenId { String field = fieldSym.get(); CtClass cc = null; try { - cc = lookupClass(jvmToJavaName(jvmClassName), true); + cc = lookupClass(jvmToJavaName(jvmClassName), true, expr.getLineNumber()); } catch (CompileError e) { // EXPR might be part of a qualified class name. @@ -313,55 +313,56 @@ public class MemberResolver implements TokenId { public CtField lookupField(String className, Symbol fieldName) throws CompileError { - CtClass cc = lookupClass(className, false); + CtClass cc = lookupClass(className, false, fieldName.getLineNumber()); try { return cc.getField(fieldName.get()); } catch (NotFoundException e) {} - throw new CompileError("no such field: " + fieldName.get()); + throw new CompileError("no such field: " + fieldName.get(), fieldName.getLineNumber()); } public CtClass lookupClassByName(ASTList name) throws CompileError { - return lookupClass(Declarator.astToClassName(name, '.'), false); + return lookupClass(Declarator.astToClassName(name, '.'), false, name.getLineNumber()); } - public CtClass lookupClassByJvmName(String jvmName) throws CompileError { - return lookupClass(jvmToJavaName(jvmName), false); + public CtClass lookupClassByJvmName(String jvmName, int lineNumber) throws CompileError { + return lookupClass(jvmToJavaName(jvmName), false, lineNumber); } public CtClass lookupClass(Declarator decl) throws CompileError { return lookupClass(decl.getType(), decl.getArrayDim(), - decl.getClassName()); + decl.getClassName(), decl.getLineNumber()); } /** - * @param classname jvm class name. + * @param classname jvm class name. + * @param lineNumber */ - public CtClass lookupClass(int type, int dim, String classname) + public CtClass lookupClass(int type, int dim, String classname, int lineNumber) throws CompileError { String cname = ""; CtClass clazz; if (type == CLASS) { - clazz = lookupClassByJvmName(classname); + clazz = lookupClassByJvmName(classname, lineNumber); if (dim > 0) cname = clazz.getName(); else return clazz; } else - cname = getTypeName(type); + cname = getTypeName(type, lineNumber); while (dim-- > 0) cname += "[]"; - return lookupClass(cname, false); + return lookupClass(cname, false, lineNumber); } /* * type cannot be CLASS */ - static String getTypeName(int type) throws CompileError { + static String getTypeName(int type, int lineNumber) throws CompileError { String cname = ""; switch (type) { case BOOLEAN : @@ -392,22 +393,23 @@ public class MemberResolver implements TokenId { cname = "void"; break; default : - fatal(); + fatal(lineNumber); } return cname; } /** - * @param name a qualified class name. e.g. java.lang.String + * @param name a qualified class name. e.g. java.lang.String + * @param lineNumber */ - public CtClass lookupClass(String name, boolean notCheckInner) + public CtClass lookupClass(String name, boolean notCheckInner, int lineNumber) throws CompileError { Map cache = getInvalidNames(); String found = cache.get(name); if (found == INVALID) - throw new CompileError("no such class: " + name); + throw new CompileError("no such class: " + name, lineNumber); else if (found != null) try { return classPool.get(found); @@ -419,7 +421,7 @@ public class MemberResolver implements TokenId { cc = lookupClass0(name, notCheckInner); } catch (NotFoundException e) { - cc = searchImports(name); + cc = searchImports(name, lineNumber); } cache.put(name, cc.getName()); @@ -454,7 +456,7 @@ public class MemberResolver implements TokenId { return ht; } - private CtClass searchImports(String orgName) + private CtClass searchImports(String orgName, int lineNumber) throws CompileError { if (orgName.indexOf('.') < 0) { @@ -476,7 +478,7 @@ public class MemberResolver implements TokenId { } getInvalidNames().put(orgName, INVALID); - throw new CompileError("no such class: " + orgName); + throw new CompileError("no such class: " + orgName, lineNumber); } private CtClass lookupClass0(String classname, boolean notCheckInner) @@ -513,10 +515,10 @@ public class MemberResolver implements TokenId { /* Expands a simple class name to java.lang.*. * For example, this converts Object into java/lang/Object. */ - public String resolveJvmClassName(String jvmName) throws CompileError { + public String resolveJvmClassName(String jvmName, int lineNumber) throws CompileError { if (jvmName == null) return null; - return javaToJvmName(lookupClassByJvmName(jvmName).getName()); + return javaToJvmName(lookupClassByJvmName(jvmName, lineNumber).getName()); } public static CtClass getSuperclass(CtClass c) throws CompileError { @@ -527,7 +529,7 @@ public class MemberResolver implements TokenId { } catch (NotFoundException e) {} throw new CompileError("cannot find the super class of " - + c.getName()); + + c.getName(), c.getLinesCount() - 1); } public static CtClass getSuperInterface(CtClass c, String interfaceName) @@ -540,7 +542,7 @@ public class MemberResolver implements TokenId { return intfs[i]; } catch (NotFoundException e) {} throw new CompileError("cannot find the super interface " + interfaceName - + " of " + c.getName()); + + " of " + c.getName(), c.getLinesCount() - 1); } public static String javaToJvmName(String classname) { @@ -551,7 +553,7 @@ public class MemberResolver implements TokenId { return classname.replace('/', '.'); } - public static int descToType(char c) throws CompileError { + public static int descToType(char c, int lineNumber) throws CompileError { switch (c) { case 'Z' : return BOOLEAN; @@ -575,7 +577,7 @@ public class MemberResolver implements TokenId { case '[' : return CLASS; default : - fatal(); + fatal(lineNumber); return VOID; // never reach here } } diff --git a/src/main/javassist/compiler/ProceedHandler.java b/src/main/javassist/compiler/ProceedHandler.java index 1c3cd47a..04023717 100644 --- a/src/main/javassist/compiler/ProceedHandler.java +++ b/src/main/javassist/compiler/ProceedHandler.java @@ -25,6 +25,6 @@ import javassist.compiler.ast.ASTList; * @see javassist.compiler.JvstCodeGen#setProceedHandler(ProceedHandler, String) */ public interface ProceedHandler { - void doit(JvstCodeGen gen, Bytecode b, ASTList args) throws CompileError; - void setReturnType(JvstTypeChecker c, ASTList args) throws CompileError; + void doit(JvstCodeGen gen, Bytecode b, ASTList args, int lineNumber) throws CompileError; + void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) throws CompileError; } diff --git a/src/main/javassist/compiler/TypeChecker.java b/src/main/javassist/compiler/TypeChecker.java index 55c35507..0d7c8e92 100644 --- a/src/main/javassist/compiler/TypeChecker.java +++ b/src/main/javassist/compiler/TypeChecker.java @@ -73,14 +73,14 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { * into a String object. */ protected static String argTypesToString(int[] types, int[] dims, - String[] cnames) { + String[] cnames, int lineNumber) { StringBuilder sbuf = new StringBuilder(); sbuf.append('('); int n = types.length; if (n > 0) { int i = 0; while (true) { - typeToString(sbuf, types[i], dims[i], cnames[i]); + typeToString(sbuf, types[i], dims[i], cnames[i], lineNumber); if (++i < n) sbuf.append(','); else @@ -97,7 +97,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { * into a String object. */ protected static StringBuilder typeToString(StringBuilder sbuf, - int type, int dim, String cname) { + int type, int dim, String cname, int lineNumber) { String s; if (type == CLASS) s = MemberResolver.jvmToJavaName(cname); @@ -105,7 +105,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { s = "Object"; else try { - s = MemberResolver.getTypeName(type); + s = MemberResolver.getTypeName(type, lineNumber); } catch (CompileError e) { s = "?"; @@ -156,8 +156,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { /* Expands a simple class name to java.lang.*. * For example, this converts Object into java/lang/Object. */ - protected String resolveClassName(String jvmName) throws CompileError { - return resolver.resolveJvmClassName(jvmName); + protected String resolveClassName(String jvmName, int lineNumber) throws CompileError { + return resolver.resolveJvmClassName(jvmName, lineNumber); } @Override @@ -168,7 +168,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { CtClass clazz = resolver.lookupClassByName(expr.getClassName()); String cname = clazz.getName(); ASTList args = expr.getArguments(); - atMethodCallCore(clazz, MethodInfo.nameInit, args); + atMethodCallCore(clazz, MethodInfo.nameInit, args, expr.getLineNumber()); exprType = CLASS; arrayDim = 0; className = MemberResolver.javaToJvmName(cname); @@ -294,7 +294,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { throws CompileError { CtField f = fieldAccess(left); - atFieldRead(f); + atFieldRead(f, expr.getLineNumber()); int fType = exprType; int fDim = arrayDim; String cname = className; @@ -682,7 +682,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { if (op == MEMBER) // static method targetClass = resolver.lookupClass(((Symbol)e.oprand1()).get(), - false); + false, e.getLineNumber()); else if (op == '.') { ASTree target = e.oprand1(); String classFollowedByDotSuper = isDotSuper(target); @@ -707,26 +707,26 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { } if (arrayDim > 0) - targetClass = resolver.lookupClass(javaLangObject, true); + targetClass = resolver.lookupClass(javaLangObject, true, e.getLineNumber()); else if (exprType == CLASS /* && arrayDim == 0 */) - targetClass = resolver.lookupClassByJvmName(className); + targetClass = resolver.lookupClassByJvmName(className, e.getLineNumber()); else - badMethod(); + badMethod(e.getLineNumber()); } } else - badMethod(); + badMethod(expr.getLineNumber()); } else fatal(expr.getLineNumber()); MemberResolver.Method minfo - = atMethodCallCore(targetClass, mname, args); + = atMethodCallCore(targetClass, mname, args, expr.getLineNumber()); expr.setMethod(minfo); } - private static void badMethod() throws CompileError { - throw new CompileError("bad method"); + private static void badMethod(int lineNumber) throws CompileError { + throw new CompileError("bad method", lineNumber); } /** @@ -754,7 +754,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { * and the MethodInfo of that method. Never null. */ public MemberResolver.Method atMethodCallCore(CtClass targetClass, - String mname, ASTList args) + String mname, ASTList args, int lineNumber) throws CompileError { int nargs = getMethodArgsLength(args); @@ -768,18 +768,18 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { mname, types, dims, cnames); if (found == null) { String clazz = targetClass.getName(); - String signature = argTypesToString(types, dims, cnames); + String signature = argTypesToString(types, dims, cnames, lineNumber); String msg; if (mname.equals(MethodInfo.nameInit)) msg = "cannot find constructor " + clazz + signature; else msg = mname + signature + " not found in " + clazz; - throw new CompileError(msg); + throw new CompileError(msg, lineNumber); } String desc = found.info.getDescriptor(); - setReturnType(desc); + setReturnType(desc, lineNumber); return found; } @@ -801,10 +801,10 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { } } - void setReturnType(String desc) throws CompileError { + void setReturnType(String desc, int lineNumber) throws CompileError { int i = desc.indexOf(')'); if (i < 0) - badMethod(); + badMethod(lineNumber); char c = desc.charAt(++i); int dim = 0; @@ -817,22 +817,22 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { if (c == 'L') { int j = desc.indexOf(';', i + 1); if (j < 0) - badMethod(); + badMethod(lineNumber); exprType = CLASS; className = desc.substring(i + 1, j); } else { - exprType = MemberResolver.descToType(c); + exprType = MemberResolver.descToType(c, lineNumber); className = null; } } private void atFieldRead(ASTree expr) throws CompileError { - atFieldRead(fieldAccess(expr)); + atFieldRead(fieldAccess(expr), expr.getLineNumber()); } - private void atFieldRead(CtField f) throws CompileError { + private void atFieldRead(CtField f, int lineNumber) throws CompileError { FieldInfo finfo = f.getFieldInfo2(); String type = finfo.getDescriptor(); @@ -845,7 +845,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { } arrayDim = dim; - exprType = MemberResolver.descToType(c); + exprType = MemberResolver.descToType(c, lineNumber); if (c == 'L') className = type.substring(i + 1, type.indexOf(';', i + 1)); @@ -1007,7 +1007,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId { protected void atFieldPlusPlus(ASTree oprand) throws CompileError { CtField f = fieldAccess(oprand); - atFieldRead(f); + atFieldRead(f, oprand.getLineNumber()); int t = exprType; if (t == INT || t == BYTE || t == CHAR || t == SHORT) exprType = INT; diff --git a/src/main/javassist/expr/Cast.java b/src/main/javassist/expr/Cast.java index 31522e5a..29f91f3e 100644 --- a/src/main/javassist/expr/Cast.java +++ b/src/main/javassist/expr/Cast.java @@ -163,26 +163,26 @@ public class Cast extends Expr { } @Override - public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) + public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber) throws CompileError { if (gen.getMethodArgsLength(args) != 1) throw new CompileError(Javac.proceedName + "() cannot take more than one parameter " - + "for cast"); + + "for cast", lineNumber); gen.atMethodArgs(args, new int[1], new int[1], new String[1]); bytecode.addOpcode(Opcode.CHECKCAST); bytecode.addIndex(index); - gen.setType(retType); + gen.setType(retType, lineNumber); } @Override - public void setReturnType(JvstTypeChecker c, ASTList args) + public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) throws CompileError { c.atMethodArgs(args, new int[1], new int[1], new String[1]); - c.setType(retType); + c.setType(retType, lineNumber); } } } diff --git a/src/main/javassist/expr/FieldAccess.java b/src/main/javassist/expr/FieldAccess.java index 335314a5..9075e5fa 100644 --- a/src/main/javassist/expr/FieldAccess.java +++ b/src/main/javassist/expr/FieldAccess.java @@ -259,12 +259,12 @@ public class FieldAccess extends Expr { } @Override - public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) + public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber) throws CompileError { if (args != null && !gen.isParamListName(args)) throw new CompileError(Javac.proceedName - + "() cannot take a parameter for field reading"); + + "() cannot take a parameter for field reading", lineNumber); int stack; if (isStatic(opcode)) @@ -282,14 +282,14 @@ public class FieldAccess extends Expr { bytecode.add(opcode); bytecode.addIndex(index); bytecode.growStack(stack); - gen.setType(fieldType); + gen.setType(fieldType, lineNumber); } @Override - public void setReturnType(JvstTypeChecker c, ASTList args) + public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) throws CompileError { - c.setType(fieldType); + c.setType(fieldType, lineNumber); } } @@ -309,13 +309,13 @@ public class FieldAccess extends Expr { } @Override - public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) + public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber) throws CompileError { if (gen.getMethodArgsLength(args) != 1) throw new CompileError(Javac.proceedName + "() cannot take more than one parameter " - + "for field writing"); + + "for field writing", lineNumber); int stack; if (isStatic(opcode)) @@ -335,16 +335,16 @@ public class FieldAccess extends Expr { bytecode.add(opcode); bytecode.addIndex(index); bytecode.growStack(stack); - gen.setType(CtClass.voidType); + gen.setType(CtClass.voidType, lineNumber); gen.addNullIfVoid(); } @Override - public void setReturnType(JvstTypeChecker c, ASTList args) + public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) throws CompileError { c.atMethodArgs(args, new int[1], new int[1], new String[1]); - c.setType(CtClass.voidType); + c.setType(CtClass.voidType, lineNumber); c.addNullIfVoid(); } } diff --git a/src/main/javassist/expr/Instanceof.java b/src/main/javassist/expr/Instanceof.java index a046ddbc..e56a3819 100644 --- a/src/main/javassist/expr/Instanceof.java +++ b/src/main/javassist/expr/Instanceof.java @@ -167,26 +167,26 @@ public class Instanceof extends Expr { } @Override - public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) + public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber) throws CompileError { if (gen.getMethodArgsLength(args) != 1) throw new CompileError(Javac.proceedName + "() cannot take more than one parameter " - + "for instanceof"); + + "for instanceof", lineNumber); gen.atMethodArgs(args, new int[1], new int[1], new String[1]); bytecode.addOpcode(Opcode.INSTANCEOF); bytecode.addIndex(index); - gen.setType(CtClass.booleanType); + gen.setType(CtClass.booleanType, lineNumber); } @Override - public void setReturnType(JvstTypeChecker c, ASTList args) + public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) throws CompileError { c.atMethodArgs(args, new int[1], new int[1], new String[1]); - c.setType(CtClass.booleanType); + c.setType(CtClass.booleanType, lineNumber); } } } diff --git a/src/main/javassist/expr/NewArray.java b/src/main/javassist/expr/NewArray.java index df30e26f..33dc417f 100644 --- a/src/main/javassist/expr/NewArray.java +++ b/src/main/javassist/expr/NewArray.java @@ -270,13 +270,13 @@ public class NewArray extends Expr { } @Override - public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) + public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber) throws CompileError { int num = gen.getMethodArgsLength(args); if (num != dimension) throw new CompileError(Javac.proceedName - + "() with a wrong number of parameters"); + + "() with a wrong number of parameters", lineNumber); gen.atMethodArgs(args, new int[num], new int[num], new String[num]); @@ -291,14 +291,14 @@ public class NewArray extends Expr { bytecode.growStack(1 - dimension); } - gen.setType(arrayType); + gen.setType(arrayType, lineNumber); } @Override - public void setReturnType(JvstTypeChecker c, ASTList args) + public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) throws CompileError { - c.setType(arrayType); + c.setType(arrayType, lineNumber); } } } diff --git a/src/main/javassist/expr/NewExpr.java b/src/main/javassist/expr/NewExpr.java index 3171fc3f..863f4db5 100644 --- a/src/main/javassist/expr/NewExpr.java +++ b/src/main/javassist/expr/NewExpr.java @@ -250,7 +250,7 @@ public class NewExpr extends Expr { } @Override - public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) + public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args, int lineNumber) throws CompileError { bytecode.addOpcode(NEW); @@ -258,15 +258,15 @@ public class NewExpr extends Expr { bytecode.addOpcode(DUP); gen.atMethodCallCore(newType, MethodInfo.nameInit, args, false, true, -1, null); - gen.setType(newType); + gen.setType(newType, lineNumber); } @Override - public void setReturnType(JvstTypeChecker c, ASTList args) + public void setReturnType(JvstTypeChecker c, ASTList args, int lineNumber) throws CompileError { - c.atMethodCallCore(newType, MethodInfo.nameInit, args); - c.setType(newType); + c.atMethodCallCore(newType, MethodInfo.nameInit, args, lineNumber); + c.setType(newType, lineNumber); } } } diff --git a/src/test/javassist/LineNumberTest.java b/src/test/javassist/LineNumberTest.java index 158efd01..7e9fbd2f 100644 --- a/src/test/javassist/LineNumberTest.java +++ b/src/test/javassist/LineNumberTest.java @@ -13,6 +13,20 @@ public class LineNumberTest extends TestCase { "}"), "line 3: syntax error near \" return\n}\""); } + public void testUndevField() { + doTestCompile(String.join("\n", + "public void run() {", + " foo = 5;", + "}"), "line 2: no such field: foo"); + } + + public void testUndevMethod() { + doTestCompile(String.join("\n", + "public void run() {", + " foo();", + "}"), "line 2: foo() not found in javassist.LineNumberCompileTest2"); + } + public void testException() { doTestRuntime(String.join("\n", "public void run() {", diff --git a/src/test/javassist/compiler/CompTest.java b/src/test/javassist/compiler/CompTest.java index 4154935f..5774f7aa 100644 --- a/src/test/javassist/compiler/CompTest.java +++ b/src/test/javassist/compiler/CompTest.java @@ -105,11 +105,11 @@ public class CompTest extends TestCase { public void testArgTypesToString() { String s; - s = TypeChecker.argTypesToString(new int[0], new int[0], new String[0]); + s = TypeChecker.argTypesToString(new int[0], new int[0], new String[0], 0); assertEquals("()", s); s = TypeChecker.argTypesToString(new int[] { TokenId.INT, TokenId.CHAR, TokenId.CLASS }, new int[] { 0, 1, 0 }, - new String[] { null, null, "String" }); + new String[] { null, null, "String" }, 0); assertEquals("(int,char[],String)", s); } -- 2.39.5