Home | History | Annotate | Download | only in compiler
      1 /*
      2  * Javassist, a Java-bytecode translator toolkit.
      3  * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
      4  *
      5  * The contents of this file are subject to the Mozilla Public License Version
      6  * 1.1 (the "License"); you may not use this file except in compliance with
      7  * the License.  Alternatively, the contents of this file may be used under
      8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
      9  *
     10  * Software distributed under the License is distributed on an "AS IS" basis,
     11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     12  * for the specific language governing rights and limitations under the
     13  * License.
     14  */
     15 
     16 package javassist.compiler;
     17 
     18 import javassist.*;
     19 import javassist.compiler.ast.*;
     20 
     21 /* Type checker accepting extended Java syntax for Javassist.
     22  */
     23 
     24 public class JvstTypeChecker extends TypeChecker {
     25     private JvstCodeGen codeGen;
     26 
     27     public JvstTypeChecker(CtClass cc, ClassPool cp, JvstCodeGen gen) {
     28         super(cc, cp);
     29         codeGen = gen;
     30     }
     31 
     32     /* If the type of the expression compiled last is void,
     33      * add ACONST_NULL and change exprType, arrayDim, className.
     34      */
     35     public void addNullIfVoid() {
     36         if (exprType == VOID) {
     37             exprType = CLASS;
     38             arrayDim = 0;
     39             className = jvmJavaLangObject;
     40         }
     41     }
     42 
     43     /* To support $args, $sig, and $type.
     44      * $args is an array of parameter list.
     45      */
     46     public void atMember(Member mem) throws CompileError {
     47         String name = mem.get();
     48         if (name.equals(codeGen.paramArrayName)) {
     49             exprType = CLASS;
     50             arrayDim = 1;
     51             className = jvmJavaLangObject;
     52         }
     53         else if (name.equals(JvstCodeGen.sigName)) {
     54             exprType = CLASS;
     55             arrayDim = 1;
     56             className = "java/lang/Class";
     57         }
     58         else if (name.equals(JvstCodeGen.dollarTypeName)
     59                  || name.equals(JvstCodeGen.clazzName)) {
     60             exprType = CLASS;
     61             arrayDim = 0;
     62             className = "java/lang/Class";
     63         }
     64         else
     65             super.atMember(mem);
     66     }
     67 
     68     protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right)
     69         throws CompileError
     70     {
     71         if (left instanceof Member
     72             && ((Member)left).get().equals(codeGen.paramArrayName)) {
     73             right.accept(this);
     74             CtClass[] params = codeGen.paramTypeList;
     75             if (params == null)
     76                 return;
     77 
     78             int n = params.length;
     79             for (int i = 0; i < n; ++i)
     80                 compileUnwrapValue(params[i]);
     81         }
     82         else
     83             super.atFieldAssign(expr, op, left, right);
     84     }
     85 
     86     public void atCastExpr(CastExpr expr) throws CompileError {
     87         ASTList classname = expr.getClassName();
     88         if (classname != null && expr.getArrayDim() == 0) {
     89             ASTree p = classname.head();
     90             if (p instanceof Symbol && classname.tail() == null) {
     91                 String typename = ((Symbol)p).get();
     92                 if (typename.equals(codeGen.returnCastName)) {
     93                     atCastToRtype(expr);
     94                     return;
     95                 }
     96                 else if (typename.equals(JvstCodeGen.wrapperCastName)) {
     97                     atCastToWrapper(expr);
     98                     return;
     99                 }
    100             }
    101         }
    102 
    103         super.atCastExpr(expr);
    104     }
    105 
    106     /**
    107      * Inserts a cast operator to the return type.
    108      * If the return type is void, this does nothing.
    109      */
    110     protected void atCastToRtype(CastExpr expr) throws CompileError {
    111         CtClass returnType = codeGen.returnType;
    112         expr.getOprand().accept(this);
    113         if (exprType == VOID || CodeGen.isRefType(exprType) || arrayDim > 0)
    114             compileUnwrapValue(returnType);
    115         else if (returnType instanceof CtPrimitiveType) {
    116             CtPrimitiveType pt = (CtPrimitiveType)returnType;
    117             int destType = MemberResolver.descToType(pt.getDescriptor());
    118             exprType = destType;
    119             arrayDim = 0;
    120             className = null;
    121         }
    122     }
    123 
    124     protected void atCastToWrapper(CastExpr expr) throws CompileError {
    125         expr.getOprand().accept(this);
    126         if (CodeGen.isRefType(exprType) || arrayDim > 0)
    127             return;     // Object type.  do nothing.
    128 
    129         CtClass clazz = resolver.lookupClass(exprType, arrayDim, className);
    130         if (clazz instanceof CtPrimitiveType) {
    131             exprType = CLASS;
    132             arrayDim = 0;
    133             className = jvmJavaLangObject;
    134         }
    135     }
    136 
    137     /* Delegates to a ProcHandler object if the method call is
    138      * $proceed().  It may process $cflow().
    139      */
    140     public void atCallExpr(CallExpr expr) throws CompileError {
    141         ASTree method = expr.oprand1();
    142         if (method instanceof Member) {
    143             String name = ((Member)method).get();
    144             if (codeGen.procHandler != null
    145                 && name.equals(codeGen.proceedName)) {
    146                 codeGen.procHandler.setReturnType(this,
    147                                                   (ASTList)expr.oprand2());
    148                 return;
    149             }
    150             else if (name.equals(JvstCodeGen.cflowName)) {
    151                 atCflow((ASTList)expr.oprand2());
    152                 return;
    153             }
    154         }
    155 
    156         super.atCallExpr(expr);
    157     }
    158 
    159     /* To support $cflow().
    160      */
    161     protected void atCflow(ASTList cname) throws CompileError {
    162         exprType = INT;
    163         arrayDim = 0;
    164         className = null;
    165     }
    166 
    167     /* To support $$.  ($$) is equivalent to ($1, ..., $n).
    168      * It can be used only as a parameter list of method call.
    169      */
    170     public boolean isParamListName(ASTList args) {
    171         if (codeGen.paramTypeList != null
    172             && args != null && args.tail() == null) {
    173             ASTree left = args.head();
    174             return (left instanceof Member
    175                     && ((Member)left).get().equals(codeGen.paramListName));
    176         }
    177         else
    178             return false;
    179     }
    180 
    181     public int getMethodArgsLength(ASTList args) {
    182         String pname = codeGen.paramListName;
    183         int n = 0;
    184         while (args != null) {
    185             ASTree a = args.head();
    186             if (a instanceof Member && ((Member)a).get().equals(pname)) {
    187                 if (codeGen.paramTypeList != null)
    188                     n += codeGen.paramTypeList.length;
    189             }
    190             else
    191                 ++n;
    192 
    193             args = args.tail();
    194         }
    195 
    196         return n;
    197     }
    198 
    199     public void atMethodArgs(ASTList args, int[] types, int[] dims,
    200                                 String[] cnames) throws CompileError {
    201         CtClass[] params = codeGen.paramTypeList;
    202         String pname = codeGen.paramListName;
    203         int i = 0;
    204         while (args != null) {
    205             ASTree a = args.head();
    206             if (a instanceof Member && ((Member)a).get().equals(pname)) {
    207                 if (params != null) {
    208                     int n = params.length;
    209                     for (int k = 0; k < n; ++k) {
    210                         CtClass p = params[k];
    211                         setType(p);
    212                         types[i] = exprType;
    213                         dims[i] = arrayDim;
    214                         cnames[i] = className;
    215                         ++i;
    216                     }
    217                 }
    218             }
    219             else {
    220                 a.accept(this);
    221                 types[i] = exprType;
    222                 dims[i] = arrayDim;
    223                 cnames[i] = className;
    224                 ++i;
    225             }
    226 
    227             args = args.tail();
    228         }
    229     }
    230 
    231     /* called by Javac#recordSpecialProceed().
    232      */
    233     void compileInvokeSpecial(ASTree target, String classname,
    234                               String methodname, String descriptor,
    235                               ASTList args)
    236         throws CompileError
    237     {
    238         target.accept(this);
    239         int nargs = getMethodArgsLength(args);
    240         atMethodArgs(args, new int[nargs], new int[nargs],
    241                      new String[nargs]);
    242         setReturnType(descriptor);
    243         addNullIfVoid();
    244     }
    245 
    246     protected void compileUnwrapValue(CtClass type) throws CompileError
    247     {
    248         if (type == CtClass.voidType)
    249             addNullIfVoid();
    250         else
    251             setType(type);
    252     }
    253 
    254     /* Sets exprType, arrayDim, and className;
    255      * If type is void, then this method does nothing.
    256      */
    257     public void setType(CtClass type) throws CompileError {
    258         setType(type, 0);
    259     }
    260 
    261     private void setType(CtClass type, int dim) throws CompileError {
    262         if (type.isPrimitive()) {
    263             CtPrimitiveType pt = (CtPrimitiveType)type;
    264             exprType = MemberResolver.descToType(pt.getDescriptor());
    265             arrayDim = dim;
    266             className = null;
    267         }
    268         else if (type.isArray())
    269             try {
    270                 setType(type.getComponentType(), dim + 1);
    271             }
    272             catch (NotFoundException e) {
    273                 throw new CompileError("undefined type: " + type.getName());
    274             }
    275         else {
    276             exprType = CLASS;
    277             arrayDim = dim;
    278             className = MemberResolver.javaToJvmName(type.getName());
    279         }
    280     }
    281 }
    282