• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
JvstTypeChecker(CtClass cc, ClassPool cp, JvstCodeGen gen)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      */
addNullIfVoid()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      */
atMember(Member mem)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 
atFieldAssign(Expr expr, int op, ASTree left, ASTree right)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 
atCastExpr(CastExpr expr)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      */
atCastToRtype(CastExpr expr)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 
atCastToWrapper(CastExpr expr)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      */
atCallExpr(CallExpr expr)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      */
atCflow(ASTList cname)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      */
isParamListName(ASTList args)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 
getMethodArgsLength(ASTList args)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 
atMethodArgs(ASTList args, int[] types, int[] dims, String[] cnames)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      */
compileInvokeSpecial(ASTree target, String classname, String methodname, String descriptor, ASTList args)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 
compileUnwrapValue(CtClass type)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      */
setType(CtClass type)257     public void setType(CtClass type) throws CompileError {
258         setType(type, 0);
259     }
260 
setType(CtClass type, int dim)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