KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > clirr > core > internal > bcel > BcelScopeHelper


1 package net.sf.clirr.core.internal.bcel;
2
3 import net.sf.clirr.core.CheckerException;
4 import net.sf.clirr.core.spi.Scope;
5
6 import org.apache.bcel.Constants;
7 import org.apache.bcel.classfile.Attribute;
8 import org.apache.bcel.classfile.ConstantClass;
9 import org.apache.bcel.classfile.ConstantPool;
10 import org.apache.bcel.classfile.ConstantUtf8;
11 import org.apache.bcel.classfile.InnerClass;
12 import org.apache.bcel.classfile.InnerClasses;
13 import org.apache.bcel.classfile.JavaClass;
14 import org.apache.bcel.util.Repository;
15
16 final class BcelScopeHelper
17 {
18     
19     /**
20      *
21      *
22      */

23     private BcelScopeHelper()
24     {
25     }
26
27     /**
28      * Get a Scope object representing the accessibility of the specified
29      * object.
30      * <p>
31      * Note that this method gives the wrong results for JavaClass objects
32      * which are nested classes. Use getClassScope(jclass) instead.
33      */

34     public static Scope getScope(int accessFlags)
35     {
36         if ((accessFlags & Constants.ACC_PUBLIC) > 0)
37         {
38             return Scope.PUBLIC;
39         }
40
41         if ((accessFlags & Constants.ACC_PROTECTED) > 0)
42         {
43             return Scope.PROTECTED;
44         }
45
46         if ((accessFlags & Constants.ACC_PRIVATE) > 0)
47         {
48             return Scope.PRIVATE;
49         }
50
51         return Scope.PACKAGE;
52     }
53
54     /**
55      * Java class files only ever contain scope specifiers of "public" or
56      * "package". For top-level classes, this is expected: it is not possible
57      * to have a top-level protected or private class.
58      * <p>
59      * However nested classes <i>can</i> be declared as protected or private. The
60      * way to tell the real scope of a nested class is to ignore the scope in
61      * the actual class file itself, and instead look in the "InnerClasses"
62      * attribute stored on the enclosing class. This is exactly what the java
63      * compiler does when compiling, and what the jvm does when verifying class
64      * linkage at runtime.
65      * <p>
66      * For a "top-level" class, this method just returns the access scope for
67      * the class itself. For nested classes, the enclosing class of the
68      * specified class is retrieved and its InnerClasses attribute checked to
69      * find the true scope for the specified class.
70      * <p>
71      * @throws CheckerException if the specified class is a nested class and
72      * the enclosing class could not be found, or if the supposedly enclosing
73      * class has no reference to the nested class. This exception is not
74      * expected to occur in practice, unless a truly screwed-up jar file is
75      * passed to clirr for inspection.
76      */

77     public static Scope getClassScope(JavaClass jclass) throws CheckerException
78     {
79         int dollarPos = jclass.getClassName().lastIndexOf('$');
80         if (dollarPos == -1)
81         {
82             // not a nested class
83
return getScope(jclass.getAccessFlags());
84         }
85
86         // ok this is a nested class
87
String JavaDoc jclassName = jclass.getClassName();
88         String JavaDoc enclosingClassName = jclassName.substring(0, dollarPos);
89         Repository repo = jclass.getRepository();
90         JavaClass enclosingClass = repo.findClass(enclosingClassName);
91
92         if (enclosingClass == null)
93         {
94             throw new CheckerException(
95                 "Unable to locate enclosing class " + enclosingClassName
96                 + " for nested class " + jclassName);
97         }
98
99         ConstantPool pool = enclosingClass.getConstantPool();
100         Attribute[] attrs = enclosingClass.getAttributes();
101         for (int i = 0; i < attrs.length; ++i)
102         {
103             if (attrs[i] instanceof InnerClasses)
104             {
105                 InnerClasses ics = (InnerClasses) attrs[i];
106                 InnerClass[] icarray = ics.getInnerClasses();
107                 for (int j = 0; j < icarray.length; ++j)
108                 {
109                     // in the code below, instanceof checks should not be necessary
110
// before casting Constants because the classfile format ensures
111
// that instanceof would always be true
112
InnerClass ic = icarray[j];
113                     int classIndex = ic.getInnerClassIndex();
114                     ConstantClass constClass = (ConstantClass) pool.getConstant(classIndex);
115                     int nameIndex = constClass.getNameIndex();
116                     ConstantUtf8 nameconst = (ConstantUtf8) pool.getConstant(nameIndex);
117                     String JavaDoc classname = nameconst.getBytes().replace('/', '.');
118                     if (jclassName.equals(classname))
119                     {
120                         return getScope(ic.getInnerAccessFlags());
121                     }
122                 }
123             }
124         }
125
126         // weird; no nested class info found
127
throw new CheckerException(
128             "Unable to find information in class " + enclosingClass.getClassName()
129             + " referring back to nested class " + jclassName);
130
131     }
132
133 }
134
Popular Tags