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