KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > compiler > MemberResolver


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 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 java.util.List JavaDoc;
19 import javassist.*;
20 import javassist.bytecode.*;
21 import javassist.compiler.ast.*;
22
23 /* Code generator methods depending on javassist.* classes.
24  */

25 public class MemberResolver implements TokenId {
26     private ClassPool classPool;
27
28     public MemberResolver(ClassPool cp) {
29         classPool = cp;
30     }
31
32     public ClassPool getClassPool() { return classPool; }
33
34     private static void fatal() throws CompileError {
35         throw new CompileError("fatal");
36     }
37
38     /**
39      * @param jvmClassName a class name. Not a package name.
40      */

41     public void recordPackage(String JavaDoc jvmClassName) {
42         String JavaDoc classname = jvmToJavaName(jvmClassName);
43         for (;;) {
44             int i = classname.lastIndexOf('.');
45             if (i > 0) {
46                 classname = classname.substring(0, i);
47                 classPool.recordInvalidClassName(classname);
48             }
49             else
50                 break;
51         }
52     }
53
54     public static class Method {
55         public CtClass declaring;
56         public MethodInfo info;
57
58         public Method(CtClass c, MethodInfo i) {
59             declaring = c;
60             info = i;
61         }
62
63         /**
64          * Returns true if the invoked method is static.
65          */

66         public boolean isStatic() {
67             int acc = info.getAccessFlags();
68             return (acc & AccessFlag.STATIC) != 0;
69         }
70     }
71
72     public Method lookupMethod(CtClass clazz, MethodInfo current,
73                                String JavaDoc methodName,
74                                int[] argTypes, int[] argDims,
75                                String JavaDoc[] argClassNames, boolean onlyExact)
76         throws CompileError
77     {
78         Method maybe = null;
79
80         // to enable the creation of a recursively called method
81
if (current != null)
82             if (current.getName().equals(methodName)) {
83                 int res = compareSignature(current.getDescriptor(),
84                                            argTypes, argDims, argClassNames);
85                 Method r = new Method(clazz, current);
86                 if (res == YES)
87                     return r;
88                 else if (res == MAYBE && maybe == null)
89                     maybe = r;
90             }
91
92         List JavaDoc list = clazz.getClassFile2().getMethods();
93         int n = list.size();
94         for (int i = 0; i < n; ++i) {
95             MethodInfo minfo = (MethodInfo)list.get(i);
96             if (minfo.getName().equals(methodName)) {
97                 int res = compareSignature(minfo.getDescriptor(),
98                                            argTypes, argDims, argClassNames);
99                 Method r = new Method(clazz, minfo);
100                 if (res == YES)
101                     return r;
102                 else if (res == MAYBE && maybe == null)
103                     maybe = r;
104             }
105         }
106
107         try {
108             CtClass pclazz = clazz.getSuperclass();
109             if (pclazz != null) {
110                 Method r = lookupMethod(pclazz, null, methodName, argTypes,
111                                         argDims, argClassNames,
112                                         (onlyExact || maybe != null));
113                 if (r != null)
114                     return r;
115             }
116         }
117         catch (NotFoundException e) {}
118
119         int mod = clazz.getModifiers();
120         if (Modifier.isAbstract(mod) || Modifier.isInterface(mod))
121             try {
122                 CtClass[] ifs = clazz.getInterfaces();
123                 int size = ifs.length;
124                 for (int i = 0; i < size; ++i) {
125                     Method r = lookupMethod(ifs[i], null, methodName,
126                                             argTypes, argDims, argClassNames,
127                                             (onlyExact || maybe != null));
128                     if (r != null)
129                         return r;
130                 }
131             }
132             catch (NotFoundException e) {}
133
134         if (onlyExact)
135             return null;
136         else
137             return maybe;
138     }
139
140     private static final int YES = 2;
141     private static final int MAYBE = 1;
142     private static final int NO = 0;
143
144     /*
145      * Returns YES if actual parameter types matches the given signature.
146      *
147      * argTypes, argDims, and argClassNames represent actual parameters.
148      *
149      * This method does not correctly implement the Java method dispatch
150      * algorithm.
151      */

152     private int compareSignature(String JavaDoc desc, int[] argTypes,
153                                  int[] argDims, String JavaDoc[] argClassNames)
154         throws CompileError
155     {
156         int result = YES;
157         int i = 1;
158         int nArgs = argTypes.length;
159         if (nArgs != Descriptor.numOfParameters(desc))
160             return NO;
161
162         int len = desc.length();
163         for (int n = 0; i < len; ++n) {
164             char c = desc.charAt(i++);
165             if (c == ')')
166                 return (n == nArgs ? result : NO);
167             else if (n >= nArgs)
168                 return NO;
169
170             int dim = 0;
171             while (c == '[') {
172                 ++dim;
173                 c = desc.charAt(i++);
174             }
175
176             if (argTypes[n] == NULL) {
177                 if (dim == 0 && c != 'L')
178                     return NO;
179
180                 if (c == 'L')
181                     i = desc.indexOf(';', i) + 1;
182             }
183             else if (argDims[n] != dim) {
184                 if (!(dim == 0 && c == 'L'
185                       && desc.startsWith("java/lang/Object;", i)))
186                     return NO;
187
188                 // if the thread reaches here, c must be 'L'.
189
i = desc.indexOf(';', i) + 1;
190                 result = MAYBE;
191                 if (i <= 0)
192                     return NO; // invalid descriptor?
193
}
194             else if (c == 'L') { // not compare
195
int j = desc.indexOf(';', i);
196                 if (j < 0 || argTypes[n] != CLASS)
197                     return NO;
198
199                 String JavaDoc cname = desc.substring(i, j);
200                 if (!cname.equals(argClassNames[n])) {
201                     CtClass clazz = lookupClassByJvmName(argClassNames[n]);
202                     try {
203                         if (clazz.subtypeOf(lookupClassByJvmName(cname)))
204                             result = MAYBE;
205                         else
206                             return NO;
207                     }
208                     catch (NotFoundException e) {
209                         result = MAYBE; // should be NO?
210
}
211                 }
212
213                 i = j + 1;
214             }
215             else {
216                 int t = descToType(c);
217                 int at = argTypes[n];
218                 if (t != at)
219                     if (t == INT
220                         && (at == SHORT || at == BYTE || at == CHAR))
221                         result = MAYBE;
222                     else
223                         return NO;
224             }
225         }
226
227         return NO;
228     }
229
230     /**
231      * Only used by fieldAccess() in MemberCodeGen and TypeChecker.
232      *
233      * @param jvmClassName a JVM class name. e.g. java/lang/String
234      */

235     public CtField lookupFieldByJvmName2(String JavaDoc jvmClassName, Symbol fieldSym,
236                                          ASTree expr) throws NoFieldException
237     {
238         String JavaDoc field = fieldSym.get();
239         CtClass cc = null;
240         try {
241             cc = lookupClass(jvmToJavaName(jvmClassName), true);
242         }
243         catch (CompileError e) {
244             // EXPR might be part of a qualified class name.
245
throw new NoFieldException(jvmClassName + "/" + field, expr);
246         }
247
248         try {
249             return cc.getField(field);
250         }
251         catch (NotFoundException e) {
252             // maybe an inner class.
253
jvmClassName = javaToJvmName(cc.getName());
254             throw new NoFieldException(jvmClassName + "$" + field, expr);
255         }
256     }
257
258     /**
259      * @param jvmClassName a JVM class name. e.g. java/lang/String
260      */

261     public CtField lookupFieldByJvmName(String JavaDoc jvmClassName, Symbol fieldName)
262         throws CompileError
263     {
264         return lookupField(jvmToJavaName(jvmClassName), fieldName);
265     }
266
267     /**
268      * @param name a qualified class name. e.g. java.lang.String
269      */

270     public CtField lookupField(String JavaDoc className, Symbol fieldName)
271         throws CompileError
272     {
273         CtClass cc = lookupClass(className, false);
274         try {
275             return cc.getField(fieldName.get());
276         }
277         catch (NotFoundException e) {}
278         throw new CompileError("no such field: " + fieldName.get());
279     }
280
281     public CtClass lookupClassByName(ASTList name) throws CompileError {
282         return lookupClass(Declarator.astToClassName(name, '.'), false);
283     }
284
285     public CtClass lookupClassByJvmName(String JavaDoc jvmName) throws CompileError {
286         return lookupClass(jvmToJavaName(jvmName), false);
287     }
288
289     public CtClass lookupClass(Declarator decl) throws CompileError {
290         return lookupClass(decl.getType(), decl.getArrayDim(),
291                            decl.getClassName());
292     }
293
294     /**
295      * @parma classname jvm class name.
296      */

297     public CtClass lookupClass(int type, int dim, String JavaDoc classname)
298         throws CompileError
299     {
300         String JavaDoc cname = "";
301         CtClass clazz;
302         switch (type) {
303         case CLASS :
304             clazz = lookupClassByJvmName(classname);
305             if (dim > 0)
306                 cname = clazz.getName();
307             else
308                 return clazz;
309
310             break;
311         case BOOLEAN :
312             cname = "boolean";
313             break;
314         case CHAR :
315             cname = "char";
316             break;
317         case BYTE :
318             cname = "byte";
319             break;
320         case SHORT :
321             cname = "short";
322             break;
323         case INT :
324             cname = "int";
325             break;
326         case LONG :
327             cname = "long";
328             break;
329         case FLOAT :
330             cname = "float";
331             break;
332         case DOUBLE :
333             cname = "double";
334             break;
335         case VOID :
336             cname = "void";
337             break;
338         default :
339             fatal();
340         }
341
342         while (dim-- > 0)
343             cname += "[]";
344
345         return lookupClass(cname, false);
346     }
347
348     /**
349      * @param name a qualified class name. e.g. java.lang.String
350      */

351     public CtClass lookupClass(String JavaDoc name, boolean notCheckInner)
352         throws CompileError
353     {
354         try {
355             return lookupClass0(name, notCheckInner);
356         }
357         catch (NotFoundException e) {}
358         if (name.indexOf('.') < 0) {
359             String JavaDoc jlangName = "java.lang." + name;
360             try {
361                 CtClass cc = classPool.get(jlangName);
362                 // if java.lang... is found, then
363
classPool.recordInvalidClassName(name);
364                 return cc;
365             }
366             catch (NotFoundException e) {
367                 classPool.recordInvalidClassName(jlangName);
368             }
369         }
370
371         throw new CompileError("no such class: " + name);
372     }
373
374     private CtClass lookupClass0(String JavaDoc classname, boolean notCheckInner)
375         throws NotFoundException
376     {
377         CtClass cc = null;
378         do {
379             try {
380                 cc = classPool.get(classname);
381             }
382             catch (NotFoundException e) {
383                 int i = classname.lastIndexOf('.');
384                 if (notCheckInner || i < 0)
385                     throw e;
386                 else {
387                     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc(classname);
388                     sbuf.setCharAt(i, '$');
389                     classname = sbuf.toString();
390                 }
391             }
392         } while (cc == null);
393         return cc;
394     }
395
396     /* Converts a class name into a JVM-internal representation.
397      *
398      * It may also expand a simple class name to java.lang.*.
399      * For example, this converts Object into java/lang/Object.
400      */

401     public String JavaDoc resolveClassName(ASTList name) throws CompileError {
402         if (name == null)
403             return null;
404         else
405             return javaToJvmName(lookupClassByName(name).getName());
406     }
407
408     /* Expands a simple class name to java.lang.*.
409      * For example, this converts Object into java/lang/Object.
410      */

411     public String JavaDoc resolveJvmClassName(String JavaDoc jvmName) throws CompileError {
412         if (jvmName == null)
413             return null;
414         else
415             return javaToJvmName(lookupClassByJvmName(jvmName).getName());
416     }
417
418     public static CtClass getSuperclass(CtClass c) throws CompileError {
419         try {
420             return c.getSuperclass();
421         }
422         catch (NotFoundException e) {
423             throw new CompileError("cannot find the super class of "
424                                    + c.getName());
425         }
426     }
427
428     public static String JavaDoc javaToJvmName(String JavaDoc classname) {
429         return classname.replace('.', '/');
430     }
431
432     public static String JavaDoc jvmToJavaName(String JavaDoc classname) {
433         return classname.replace('/', '.');
434     }
435
436     public static int descToType(char c) throws CompileError {
437         switch (c) {
438         case 'Z' :
439             return BOOLEAN;
440         case 'C' :
441             return CHAR;
442         case 'B' :
443             return BYTE;
444         case 'S' :
445             return SHORT;
446         case 'I' :
447             return INT;
448         case 'J' :
449             return LONG;
450         case 'F' :
451             return FLOAT;
452         case 'D' :
453             return DOUBLE;
454         case 'V' :
455             return VOID;
456         case 'L' :
457         case '[' :
458             return CLASS;
459         default :
460             fatal();
461             return VOID; // never reach here
462
}
463     }
464
465     public static int getModifiers(ASTList mods) {
466         int m = 0;
467         while (mods != null) {
468             Keyword k = (Keyword)mods.head();
469             mods = mods.tail();
470             switch (k.get()) {
471             case STATIC :
472                 m |= Modifier.STATIC;
473                 break;
474             case FINAL :
475                 m |= Modifier.FINAL;
476                 break;
477             case SYNCHRONIZED :
478                 m |= Modifier.SYNCHRONIZED;
479                 break;
480             case ABSTRACT :
481                 m |= Modifier.ABSTRACT;
482                 break;
483             case PUBLIC :
484                 m |= Modifier.PUBLIC;
485                 break;
486             case PROTECTED :
487                 m |= Modifier.PROTECTED;
488                 break;
489             case PRIVATE :
490                 m |= Modifier.PRIVATE;
491                 break;
492             case VOLATILE :
493                 m |= Modifier.VOLATILE;
494                 break;
495             case TRANSIENT :
496                 m |= Modifier.TRANSIENT;
497                 break;
498             case STRICT :
499                 m |= Modifier.STRICT;
500                 break;
501             }
502         }
503
504         return m;
505     }
506 }
507
Popular Tags