1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078 |
- /*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later,
- * or the Apache License Version 2.0.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
- package javassist.compiler;
-
- import javassist.ClassPool;
- import javassist.CtClass;
- import javassist.CtField;
- import javassist.Modifier;
- import javassist.NotFoundException;
- import javassist.bytecode.FieldInfo;
- import javassist.bytecode.MethodInfo;
- import javassist.bytecode.Opcode;
- import javassist.compiler.ast.ASTList;
- import javassist.compiler.ast.ASTree;
- import javassist.compiler.ast.ArrayInit;
- import javassist.compiler.ast.AssignExpr;
- import javassist.compiler.ast.BinExpr;
- import javassist.compiler.ast.CallExpr;
- import javassist.compiler.ast.CastExpr;
- import javassist.compiler.ast.CondExpr;
- import javassist.compiler.ast.Declarator;
- import javassist.compiler.ast.DoubleConst;
- import javassist.compiler.ast.Expr;
- import javassist.compiler.ast.InstanceOfExpr;
- import javassist.compiler.ast.IntConst;
- import javassist.compiler.ast.Keyword;
- import javassist.compiler.ast.Member;
- import javassist.compiler.ast.NewExpr;
- import javassist.compiler.ast.StringL;
- import javassist.compiler.ast.Symbol;
- import javassist.compiler.ast.Variable;
- import javassist.compiler.ast.Visitor;
-
- public class TypeChecker extends Visitor implements Opcode, TokenId {
- static final String javaLangObject = "java.lang.Object";
- static final String jvmJavaLangObject = "java/lang/Object";
- static final String jvmJavaLangString = "java/lang/String";
- static final String jvmJavaLangClass = "java/lang/Class";
-
- /* The following fields are used by atXXX() methods
- * for returning the type of the compiled expression.
- */
- protected int exprType; // VOID, NULL, CLASS, BOOLEAN, INT, ...
- protected int arrayDim;
- protected String className; // JVM-internal representation
-
- protected MemberResolver resolver;
- protected CtClass thisClass;
- protected MethodInfo thisMethod;
-
- public TypeChecker(CtClass cc, ClassPool cp) {
- resolver = new MemberResolver(cp);
- thisClass = cc;
- thisMethod = null;
- }
-
- /*
- * Converts an array of tuples of exprType, arrayDim, and className
- * into a String object.
- */
- protected static String argTypesToString(int[] types, int[] dims,
- String[] cnames) {
- StringBuffer sbuf = new StringBuffer();
- sbuf.append('(');
- int n = types.length;
- if (n > 0) {
- int i = 0;
- while (true) {
- typeToString(sbuf, types[i], dims[i], cnames[i]);
- if (++i < n)
- sbuf.append(',');
- else
- break;
- }
- }
-
- sbuf.append(')');
- return sbuf.toString();
- }
-
- /*
- * Converts a tuple of exprType, arrayDim, and className
- * into a String object.
- */
- protected static StringBuffer typeToString(StringBuffer sbuf,
- int type, int dim, String cname) {
- String s;
- if (type == CLASS)
- s = MemberResolver.jvmToJavaName(cname);
- else if (type == NULL)
- s = "Object";
- else
- try {
- s = MemberResolver.getTypeName(type);
- }
- catch (CompileError e) {
- s = "?";
- }
-
- sbuf.append(s);
- while (dim-- > 0)
- sbuf.append("[]");
-
- return sbuf;
- }
-
- /**
- * Records the currently compiled method.
- */
- public void setThisMethod(MethodInfo m) {
- thisMethod = m;
- }
-
- protected static void fatal() throws CompileError {
- throw new CompileError("fatal");
- }
-
- /**
- * Returns the JVM-internal representation of this class name.
- */
- protected String getThisName() {
- return MemberResolver.javaToJvmName(thisClass.getName());
- }
-
- /**
- * Returns the JVM-internal representation of this super class name.
- */
- protected String getSuperName() throws CompileError {
- return MemberResolver.javaToJvmName(
- MemberResolver.getSuperclass(thisClass).getName());
- }
-
- /* Converts a class name into a JVM-internal representation.
- *
- * It may also expand a simple class name to java.lang.*.
- * For example, this converts Object into java/lang/Object.
- */
- protected String resolveClassName(ASTList name) throws CompileError {
- return resolver.resolveClassName(name);
- }
-
- /* 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);
- }
-
- @Override
- public void atNewExpr(NewExpr expr) throws CompileError {
- if (expr.isArray())
- atNewArrayExpr(expr);
- else {
- CtClass clazz = resolver.lookupClassByName(expr.getClassName());
- String cname = clazz.getName();
- ASTList args = expr.getArguments();
- atMethodCallCore(clazz, MethodInfo.nameInit, args);
- exprType = CLASS;
- arrayDim = 0;
- className = MemberResolver.javaToJvmName(cname);
- }
- }
-
- public void atNewArrayExpr(NewExpr expr) throws CompileError {
- int type = expr.getArrayType();
- ASTList size = expr.getArraySize();
- ASTList classname = expr.getClassName();
- ASTree init = expr.getInitializer();
- if (init != null)
- init.accept(this);
-
- if (size.length() > 1)
- atMultiNewArray(type, classname, size);
- else {
- ASTree sizeExpr = size.head();
- if (sizeExpr != null)
- sizeExpr.accept(this);
-
- exprType = type;
- arrayDim = 1;
- if (type == CLASS)
- className = resolveClassName(classname);
- else
- className = null;
- }
- }
-
- @Override
- public void atArrayInit(ArrayInit init) throws CompileError {
- ASTList list = init;
- while (list != null) {
- ASTree h = list.head();
- list = list.tail();
- if (h != null)
- h.accept(this);
- }
- }
-
- protected void atMultiNewArray(int type, ASTList classname, ASTList size)
- throws CompileError
- {
- @SuppressWarnings("unused")
- int count, dim;
- dim = size.length();
- for (count = 0; size != null; size = size.tail()) {
- ASTree s = size.head();
- if (s == null)
- break; // int[][][] a = new int[3][4][];
-
- ++count;
- s.accept(this);
- }
-
- exprType = type;
- arrayDim = dim;
- if (type == CLASS)
- className = resolveClassName(classname);
- else
- className = null;
- }
-
- @Override
- public void atAssignExpr(AssignExpr expr) throws CompileError {
- // =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, >>>=
- int op = expr.getOperator();
- ASTree left = expr.oprand1();
- ASTree right = expr.oprand2();
- if (left instanceof Variable)
- atVariableAssign(expr, op, (Variable)left,
- ((Variable)left).getDeclarator(),
- right);
- else {
- if (left instanceof Expr) {
- Expr e = (Expr)left;
- if (e.getOperator() == ARRAY) {
- atArrayAssign(expr, op, (Expr)left, right);
- return;
- }
- }
-
- atFieldAssign(expr, op, left, right);
- }
- }
-
- /* op is either =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, or >>>=.
- *
- * expr and var can be null.
- */
- private void atVariableAssign(Expr expr, int op, Variable var,
- Declarator d, ASTree right)
- throws CompileError
- {
- int varType = d.getType();
- int varArray = d.getArrayDim();
- String varClass = d.getClassName();
-
- if (op != '=')
- atVariable(var);
-
- right.accept(this);
- exprType = varType;
- arrayDim = varArray;
- className = varClass;
- }
-
- private void atArrayAssign(Expr expr, int op, Expr array,
- ASTree right) throws CompileError
- {
- atArrayRead(array.oprand1(), array.oprand2());
- int aType = exprType;
- int aDim = arrayDim;
- String cname = className;
- right.accept(this);
- exprType = aType;
- arrayDim = aDim;
- className = cname;
- }
-
- protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right)
- throws CompileError
- {
- CtField f = fieldAccess(left);
- atFieldRead(f);
- int fType = exprType;
- int fDim = arrayDim;
- String cname = className;
- right.accept(this);
- exprType = fType;
- arrayDim = fDim;
- className = cname;
- }
-
- @Override
- public void atCondExpr(CondExpr expr) throws CompileError {
- booleanExpr(expr.condExpr());
- expr.thenExpr().accept(this);
- int type1 = exprType;
- int dim1 = arrayDim;
- @SuppressWarnings("unused")
- String cname1 = className;
- expr.elseExpr().accept(this);
-
- if (dim1 == 0 && dim1 == arrayDim)
- if (CodeGen.rightIsStrong(type1, exprType))
- expr.setThen(new CastExpr(exprType, 0, expr.thenExpr()));
- else if (CodeGen.rightIsStrong(exprType, type1)) {
- expr.setElse(new CastExpr(type1, 0, expr.elseExpr()));
- exprType = type1;
- }
- }
-
- /*
- * If atBinExpr() substitutes a new expression for the original
- * binary-operator expression, it changes the operator name to '+'
- * (if the original is not '+') and sets the new expression to the
- * left-hand-side expression and null to the right-hand-side expression.
- */
- @Override
- public void atBinExpr(BinExpr expr) throws CompileError {
- int token = expr.getOperator();
- int k = CodeGen.lookupBinOp(token);
- if (k >= 0) {
- /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>>
- */
- if (token == '+') {
- Expr e = atPlusExpr(expr);
- if (e != null) {
- /* String concatenation has been translated into
- * an expression using StringBuffer.
- */
- e = CallExpr.makeCall(Expr.make('.', e,
- new Member("toString")), null);
- expr.setOprand1(e);
- expr.setOprand2(null); // <---- look at this!
- className = jvmJavaLangString;
- }
- }
- else {
- ASTree left = expr.oprand1();
- ASTree right = expr.oprand2();
- left.accept(this);
- int type1 = exprType;
- right.accept(this);
- if (!isConstant(expr, token, left, right))
- computeBinExprType(expr, token, type1);
- }
- }
- else {
- /* equation: &&, ||, ==, !=, <=, >=, <, >
- */
- booleanExpr(expr);
- }
- }
-
- /* EXPR must be a + expression.
- * atPlusExpr() returns non-null if the given expression is string
- * concatenation. The returned value is "new StringBuffer().append..".
- */
- private Expr atPlusExpr(BinExpr expr) throws CompileError {
- ASTree left = expr.oprand1();
- ASTree right = expr.oprand2();
- if (right == null) {
- // this expression has been already type-checked.
- // see atBinExpr() above.
- left.accept(this);
- return null;
- }
-
- if (isPlusExpr(left)) {
- Expr newExpr = atPlusExpr((BinExpr)left);
- if (newExpr != null) {
- right.accept(this);
- exprType = CLASS;
- arrayDim = 0;
- className = "java/lang/StringBuffer";
- return makeAppendCall(newExpr, right);
- }
- }
- else
- left.accept(this);
-
- int type1 = exprType;
- int dim1 = arrayDim;
- String cname = className;
- right.accept(this);
-
- if (isConstant(expr, '+', left, right))
- return null;
-
- 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);
- exprType = CLASS;
- arrayDim = 0;
- className = "java/lang/StringBuffer";
- return makeAppendCall(makeAppendCall(e, left), right);
- }
- computeBinExprType(expr, '+', type1);
- return null;
- }
-
- private boolean isConstant(BinExpr expr, int op, ASTree left,
- ASTree right) throws CompileError
- {
- left = stripPlusExpr(left);
- right = stripPlusExpr(right);
- ASTree newExpr = null;
- if (left instanceof StringL && right instanceof StringL && op == '+')
- newExpr = new StringL(((StringL)left).get()
- + ((StringL)right).get());
- else if (left instanceof IntConst)
- newExpr = ((IntConst)left).compute(op, right);
- else if (left instanceof DoubleConst)
- newExpr = ((DoubleConst)left).compute(op, right);
-
- if (newExpr == null)
- return false; // not a constant expression
- expr.setOperator('+');
- expr.setOprand1(newExpr);
- expr.setOprand2(null);
- newExpr.accept(this); // for setting exprType, arrayDim, ...
- return true;
- }
-
- /* CodeGen.atSwitchStmnt() also calls stripPlusExpr().
- */
- static ASTree stripPlusExpr(ASTree expr) {
- if (expr instanceof BinExpr) {
- BinExpr e = (BinExpr)expr;
- if (e.getOperator() == '+' && e.oprand2() == null)
- return e.getLeft();
- }
- else if (expr instanceof Expr) { // note: BinExpr extends Expr.
- Expr e = (Expr)expr;
- int op = e.getOperator();
- if (op == MEMBER) {
- ASTree cexpr = getConstantFieldValue((Member)e.oprand2());
- if (cexpr != null)
- return cexpr;
- }
- else if (op == '+' && e.getRight() == null)
- return e.getLeft();
- }
- else if (expr instanceof Member) {
- ASTree cexpr = getConstantFieldValue((Member)expr);
- if (cexpr != null)
- return cexpr;
- }
-
- return expr;
- }
-
- /**
- * 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());
- }
-
- public static ASTree getConstantFieldValue(CtField f) {
- if (f == null)
- return null;
-
- Object value = f.getConstantValue();
- if (value == null)
- return null;
-
- if (value instanceof String)
- return new StringL((String)value);
- else if (value instanceof Double || value instanceof Float) {
- int token = (value instanceof Double)
- ? DoubleConstant : FloatConstant;
- return new DoubleConst(((Number)value).doubleValue(), token);
- }
- else if (value instanceof Number) {
- int token = (value instanceof Long) ? LongConstant : IntConstant;
- return new IntConst(((Number)value).longValue(), token);
- }
- else if (value instanceof Boolean)
- return new Keyword(((Boolean)value).booleanValue()
- ? TokenId.TRUE : TokenId.FALSE);
- else
- return null;
- }
-
- private static boolean isPlusExpr(ASTree expr) {
- if (expr instanceof BinExpr) {
- BinExpr bexpr = (BinExpr)expr;
- int token = bexpr.getOperator();
- return token == '+';
- }
-
- return false;
- }
-
- private static Expr makeAppendCall(ASTree target, ASTree arg) {
- return CallExpr.makeCall(Expr.make('.', target, new Member("append")),
- new ASTList(arg));
- }
-
- private void computeBinExprType(BinExpr expr, int token, int type1)
- throws CompileError
- {
- // arrayDim should be 0.
- int type2 = exprType;
- if (token == LSHIFT || token == RSHIFT || token == ARSHIFT)
- exprType = type1;
- else
- insertCast(expr, type1, type2);
-
- if (CodeGen.isP_INT(exprType) && exprType != BOOLEAN)
- exprType = INT; // type1 may be BYTE, ...
- }
-
- private void booleanExpr(ASTree expr)
- throws CompileError
- {
- int op = CodeGen.getCompOperator(expr);
- if (op == EQ) { // ==, !=, ...
- BinExpr bexpr = (BinExpr)expr;
- bexpr.oprand1().accept(this);
- int type1 = exprType;
- int dim1 = arrayDim;
- bexpr.oprand2().accept(this);
- if (dim1 == 0 && arrayDim == 0)
- insertCast(bexpr, type1, exprType);
- }
- else if (op == '!')
- ((Expr)expr).oprand1().accept(this);
- else if (op == ANDAND || op == OROR) {
- BinExpr bexpr = (BinExpr)expr;
- bexpr.oprand1().accept(this);
- bexpr.oprand2().accept(this);
- }
- else // others
- expr.accept(this);
-
- exprType = BOOLEAN;
- arrayDim = 0;
- }
-
- private void insertCast(BinExpr expr, int type1, int type2)
- throws CompileError
- {
- if (CodeGen.rightIsStrong(type1, type2))
- expr.setLeft(new CastExpr(type2, 0, expr.oprand1()));
- else
- exprType = type1;
- }
-
- @Override
- public void atCastExpr(CastExpr expr) throws CompileError {
- String cname = resolveClassName(expr.getClassName());
- expr.getOprand().accept(this);
- exprType = expr.getType();
- arrayDim = expr.getArrayDim();
- className = cname;
- }
-
- @Override
- public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError {
- expr.getOprand().accept(this);
- exprType = BOOLEAN;
- arrayDim = 0;
- }
-
- @Override
- public void atExpr(Expr expr) throws CompileError {
- // array access, member access,
- // (unary) +, (unary) -, ++, --, !, ~
-
- int token = expr.getOperator();
- ASTree oprand = expr.oprand1();
- if (token == '.') {
- String member = ((Symbol)expr.oprand2()).get();
- if (member.equals("length"))
- try {
- atArrayLength(expr);
- }
- catch (NoFieldException nfe) {
- // length might be a class or package name.
- atFieldRead(expr);
- }
- else if (member.equals("class"))
- atClassObject(expr); // .class
- else
- atFieldRead(expr);
- }
- else if (token == MEMBER) { // field read
- String member = ((Symbol)expr.oprand2()).get();
- if (member.equals("class"))
- atClassObject(expr); // .class
- else
- atFieldRead(expr);
- }
- else if (token == ARRAY)
- atArrayRead(oprand, expr.oprand2());
- else if (token == PLUSPLUS || token == MINUSMINUS)
- atPlusPlus(token, oprand, expr);
- else if (token == '!')
- booleanExpr(expr);
- else if (token == CALL) // method call
- fatal();
- else {
- oprand.accept(this);
- if (!isConstant(expr, token, oprand))
- if (token == '-' || token == '~')
- if (CodeGen.isP_INT(exprType))
- exprType = INT; // type may be BYTE, ...
- }
- }
-
- private boolean isConstant(Expr expr, int op, ASTree oprand) {
- oprand = stripPlusExpr(oprand);
- if (oprand instanceof IntConst) {
- IntConst c = (IntConst)oprand;
- long v = c.get();
- if (op == '-')
- v = -v;
- else if (op == '~')
- v = ~v;
- else
- return false;
-
- c.set(v);
- }
- else if (oprand instanceof DoubleConst) {
- DoubleConst c = (DoubleConst)oprand;
- if (op == '-')
- c.set(-c.get());
- else
- return false;
- }
- else
- return false;
-
- expr.setOperator('+');
- return true;
- }
-
- @Override
- public void atCallExpr(CallExpr expr) throws CompileError {
- String mname = null;
- CtClass targetClass = null;
- ASTree method = expr.oprand1();
- ASTList args = (ASTList)expr.oprand2();
-
- if (method instanceof Member) {
- mname = ((Member)method).get();
- targetClass = thisClass;
- }
- else if (method instanceof Keyword) { // constructor
- mname = MethodInfo.nameInit; // <init>
- if (((Keyword)method).get() == SUPER)
- targetClass = MemberResolver.getSuperclass(thisClass);
- else
- targetClass = thisClass;
- }
- else if (method instanceof Expr) {
- Expr e = (Expr)method;
- mname = ((Symbol)e.oprand2()).get();
- int op = e.getOperator();
- if (op == MEMBER) // static method
- targetClass
- = resolver.lookupClass(((Symbol)e.oprand1()).get(),
- false);
- else if (op == '.') {
- ASTree target = e.oprand1();
- String classFollowedByDotSuper = isDotSuper(target);
- if (classFollowedByDotSuper != null)
- targetClass = MemberResolver.getSuperInterface(thisClass,
- classFollowedByDotSuper);
- else {
- try {
- target.accept(this);
- }
- catch (NoFieldException nfe) {
- if (nfe.getExpr() != target)
- throw nfe;
-
- // it should be a static method.
- exprType = CLASS;
- arrayDim = 0;
- className = nfe.getField(); // JVM-internal
- e.setOperator(MEMBER);
- e.setOprand1(new Symbol(MemberResolver.jvmToJavaName(
- className)));
- }
-
- if (arrayDim > 0)
- targetClass = resolver.lookupClass(javaLangObject, true);
- else if (exprType == CLASS /* && arrayDim == 0 */)
- targetClass = resolver.lookupClassByJvmName(className);
- else
- badMethod();
- }
- }
- else
- badMethod();
- }
- else
- fatal();
-
- MemberResolver.Method minfo
- = atMethodCallCore(targetClass, mname, args);
- expr.setMethod(minfo);
- }
-
- private static void badMethod() throws CompileError {
- throw new CompileError("bad method");
- }
-
- /**
- * Returns non-null if target is something like Foo.super
- * for accessing the default method in an interface.
- * Otherwise, null.
- *
- * @return the class name followed by {@code .super} or null.
- */
- static String isDotSuper(ASTree target) {
- if (target instanceof Expr) {
- Expr e = (Expr)target;
- if (e.getOperator() == '.') {
- ASTree right = e.oprand2();
- if (right instanceof Keyword && ((Keyword)right).get() == SUPER)
- return ((Symbol)e.oprand1()).get();
- }
- }
-
- return null;
- }
-
- /**
- * @return a pair of the class declaring the invoked method
- * and the MethodInfo of that method. Never null.
- */
- public MemberResolver.Method atMethodCallCore(CtClass targetClass,
- String mname, ASTList args)
- throws CompileError
- {
- int nargs = getMethodArgsLength(args);
- int[] types = new int[nargs];
- int[] dims = new int[nargs];
- String[] cnames = new String[nargs];
- atMethodArgs(args, types, dims, cnames);
-
- MemberResolver.Method found
- = resolver.lookupMethod(targetClass, thisClass, thisMethod,
- mname, types, dims, cnames);
- if (found == null) {
- String clazz = targetClass.getName();
- String signature = argTypesToString(types, dims, cnames);
- 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);
- }
-
- String desc = found.info.getDescriptor();
- setReturnType(desc);
- return found;
- }
-
- public int getMethodArgsLength(ASTList args) {
- return ASTList.length(args);
- }
-
- public void atMethodArgs(ASTList args, int[] types, int[] dims,
- String[] cnames) throws CompileError {
- int i = 0;
- while (args != null) {
- ASTree a = args.head();
- a.accept(this);
- types[i] = exprType;
- dims[i] = arrayDim;
- cnames[i] = className;
- ++i;
- args = args.tail();
- }
- }
-
- void setReturnType(String desc) throws CompileError {
- int i = desc.indexOf(')');
- if (i < 0)
- badMethod();
-
- char c = desc.charAt(++i);
- int dim = 0;
- while (c == '[') {
- ++dim;
- c = desc.charAt(++i);
- }
-
- arrayDim = dim;
- if (c == 'L') {
- int j = desc.indexOf(';', i + 1);
- if (j < 0)
- badMethod();
-
- exprType = CLASS;
- className = desc.substring(i + 1, j);
- }
- else {
- exprType = MemberResolver.descToType(c);
- className = null;
- }
- }
-
- private void atFieldRead(ASTree expr) throws CompileError {
- atFieldRead(fieldAccess(expr));
- }
-
- private void atFieldRead(CtField f) throws CompileError {
- FieldInfo finfo = f.getFieldInfo2();
- String type = finfo.getDescriptor();
-
- int i = 0;
- int dim = 0;
- char c = type.charAt(i);
- while (c == '[') {
- ++dim;
- c = type.charAt(++i);
- }
-
- arrayDim = dim;
- exprType = MemberResolver.descToType(c);
-
- if (c == 'L')
- className = type.substring(i + 1, type.indexOf(';', i + 1));
- else
- className = null;
- }
-
- /* if EXPR is to access a static field, fieldAccess() translates EXPR
- * into an expression using '#' (MEMBER). For example, it translates
- * java.lang.Integer.TYPE into java.lang.Integer#TYPE. This translation
- * speeds up type resolution by MemberCodeGen.
- */
- protected CtField fieldAccess(ASTree expr) throws CompileError {
- if (expr instanceof Member) {
- Member mem = (Member)expr;
- String name = mem.get();
- try {
- CtField f = thisClass.getField(name);
- if (Modifier.isStatic(f.getModifiers()))
- mem.setField(f);
-
- return f;
- }
- catch (NotFoundException e) {
- // EXPR might be part of a static member access?
- throw new NoFieldException(name, expr);
- }
- }
- else if (expr instanceof Expr) {
- Expr e = (Expr)expr;
- int op = e.getOperator();
- if (op == MEMBER) {
- Member mem = (Member)e.oprand2();
- CtField f
- = resolver.lookupField(((Symbol)e.oprand1()).get(), mem);
- mem.setField(f);
- return f;
- }
- else if (op == '.') {
- try {
- e.oprand1().accept(this);
- }
- catch (NoFieldException nfe) {
- if (nfe.getExpr() != e.oprand1())
- throw nfe;
-
- /* EXPR should be a static field.
- * If EXPR might be part of a qualified class name,
- * lookupFieldByJvmName2() throws NoFieldException.
- */
- return fieldAccess2(e, nfe.getField());
- }
-
- CompileError err = null;
- try {
- if (exprType == CLASS && arrayDim == 0)
- return resolver.lookupFieldByJvmName(className,
- (Symbol)e.oprand2());
- }
- catch (CompileError ce) {
- err = ce;
- }
-
- /* If a filed name is the same name as a package's,
- * a static member of a class in that package is not
- * visible. For example,
- *
- * class Foo {
- * int javassist;
- * }
- *
- * It is impossible to add the following method:
- *
- * String m() { return javassist.CtClass.intType.toString(); }
- *
- * because javassist is a field name. However, this is
- * often inconvenient, this compiler allows it. The following
- * code is for that.
- */
- ASTree oprnd1 = e.oprand1();
- if (oprnd1 instanceof Symbol)
- return fieldAccess2(e, ((Symbol)oprnd1).get());
-
- if (err != null)
- throw err;
- }
- }
-
- throw new CompileError("bad field access");
- }
-
- 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)));
- fname.setField(f);
- return f;
- }
-
- public void atClassObject(Expr expr) throws CompileError {
- exprType = CLASS;
- arrayDim = 0;
- className =jvmJavaLangClass;
- }
-
- public void atArrayLength(Expr expr) throws CompileError {
- expr.oprand1().accept(this);
- if (arrayDim == 0)
- throw new NoFieldException("length", expr);
-
- exprType = INT;
- arrayDim = 0;
- }
-
- public void atArrayRead(ASTree array, ASTree index)
- throws CompileError
- {
- array.accept(this);
- int type = exprType;
- int dim = arrayDim;
- String cname = className;
- index.accept(this);
- exprType = type;
- arrayDim = dim - 1;
- className = cname;
- }
-
- private void atPlusPlus(int token, ASTree oprand, Expr expr)
- throws CompileError
- {
- boolean isPost = oprand == null; // ++i or i++?
- if (isPost)
- oprand = expr.oprand2();
-
- if (oprand instanceof Variable) {
- Declarator d = ((Variable)oprand).getDeclarator();
- exprType = d.getType();
- arrayDim = d.getArrayDim();
- }
- else {
- if (oprand instanceof Expr) {
- Expr e = (Expr)oprand;
- if (e.getOperator() == ARRAY) {
- atArrayRead(e.oprand1(), e.oprand2());
- // arrayDim should be 0.
- int t = exprType;
- if (t == INT || t == BYTE || t == CHAR || t == SHORT)
- exprType = INT;
-
- return;
- }
- }
-
- atFieldPlusPlus(oprand);
- }
- }
-
- protected void atFieldPlusPlus(ASTree oprand) throws CompileError
- {
- CtField f = fieldAccess(oprand);
- atFieldRead(f);
- int t = exprType;
- if (t == INT || t == BYTE || t == CHAR || t == SHORT)
- exprType = INT;
- }
-
- @Override
- public void atMember(Member mem) throws CompileError {
- atFieldRead(mem);
- }
-
- @Override
- public void atVariable(Variable v) throws CompileError {
- Declarator d = v.getDeclarator();
- exprType = d.getType();
- arrayDim = d.getArrayDim();
- className = d.getClassName();
- }
-
- @Override
- public void atKeyword(Keyword k) throws CompileError {
- arrayDim = 0;
- int token = k.get();
- switch (token) {
- case TRUE :
- case FALSE :
- exprType = BOOLEAN;
- break;
- case NULL :
- exprType = NULL;
- break;
- case THIS :
- case SUPER :
- exprType = CLASS;
- if (token == THIS)
- className = getThisName();
- else
- className = getSuperName();
- break;
- default :
- fatal();
- }
- }
-
- @Override
- public void atStringL(StringL s) throws CompileError {
- exprType = CLASS;
- arrayDim = 0;
- className = jvmJavaLangString;
- }
-
- @Override
- public void atIntConst(IntConst i) throws CompileError {
- arrayDim = 0;
- int type = i.getType();
- if (type == IntConstant || type == CharConstant)
- exprType = (type == IntConstant ? INT : CHAR);
- else
- exprType = LONG;
- }
-
- @Override
- public void atDoubleConst(DoubleConst d) throws CompileError {
- arrayDim = 0;
- if (d.getType() == DoubleConstant)
- exprType = DOUBLE;
- else
- exprType = FLOAT;
- }
- }
|