001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.tools.ant.util.depend.bcel;
019:
020: import java.util.Enumeration;
021: import java.util.Hashtable;
022: import java.util.StringTokenizer;
023: import org.apache.bcel.classfile.ConstantClass;
024: import org.apache.bcel.classfile.ConstantPool;
025: import org.apache.bcel.classfile.EmptyVisitor;
026: import org.apache.bcel.classfile.Field;
027: import org.apache.bcel.classfile.JavaClass;
028: import org.apache.bcel.classfile.Method;
029: import org.apache.bcel.classfile.ConstantNameAndType;
030:
031: /**
032: * A BCEL visitor implementation to collect class dependency information
033: *
034: */
035: public class DependencyVisitor extends EmptyVisitor {
036: /** The collectd dependencies */
037: private Hashtable dependencies = new Hashtable();
038: /**
039: * The current class's constant pool - used to determine class names
040: * from class references.
041: */
042: private ConstantPool constantPool;
043:
044: /**
045: * Get the dependencies collected by this visitor
046: *
047: * @return a Enumeration of classnames, being the classes upon which the
048: * visited classes depend.
049: */
050: public Enumeration getDependencies() {
051: return dependencies.keys();
052: }
053:
054: /** Clear the curretn set of collected dependencies. */
055: public void clearDependencies() {
056: dependencies.clear();
057: }
058:
059: /**
060: * Visit the constant pool of a class
061: *
062: * @param constantPool the constant pool of the class being visited.
063: */
064: public void visitConstantPool(ConstantPool constantPool) {
065: this .constantPool = constantPool;
066: }
067:
068: /**
069: * Visit a class reference
070: *
071: * @param constantClass the constantClass entry for the class reference
072: */
073: public void visitConstantClass(ConstantClass constantClass) {
074: String classname = constantClass.getConstantValue(constantPool)
075: .toString();
076: addSlashClass(classname);
077: }
078:
079: /**
080: * Visit a name and type ref
081: *
082: * Look for class references in this
083: *
084: * @param obj the name and type reference being visited.
085: */
086: public void visitConstantNameAndType(ConstantNameAndType obj) {
087: String name = obj.getName(constantPool);
088: if (obj.getSignature(constantPool).equals("Ljava/lang/Class;")
089: && name.startsWith("class$")) {
090: String classname = name.substring(6).replace('$', '.');
091: // does the class have a package structure
092: int index = classname.lastIndexOf(".");
093: if (index > 0) {
094: char start;
095: // check if the package structure is more than 1 level deep
096: int index2 = classname.lastIndexOf(".", index - 1);
097: if (index2 != -1) {
098: // class name has more than 1 package level 'com.company.Class'
099: start = classname.charAt(index2 + 1);
100: } else {
101: // class name has only 1 package level 'package.Class'
102: start = classname.charAt(0);
103: }
104: // Check to see if it's an inner class 'com.company.Class$Inner'
105: if ((start > 0x40) && (start < 0x5B)) {
106: // first letter of the previous segment of the class name 'Class'
107: // is upper case ascii. so according to the spec it's an inner class
108: classname = classname.substring(0, index) + "$"
109: + classname.substring(index + 1);
110: addClass(classname);
111: } else {
112: // Add the class in dotted notation 'com.company.Class'
113: addClass(classname);
114: }
115: } else {
116: // Add a class with no package 'Class'
117: addClass(classname);
118: }
119: }
120: }
121:
122: /**
123: * Visit a field of the class.
124: *
125: * @param field the field being visited
126: */
127: public void visitField(Field field) {
128: addClasses(field.getSignature());
129: }
130:
131: /**
132: * Visit a Java class
133: *
134: * @param javaClass the class being visited.
135: */
136: public void visitJavaClass(JavaClass javaClass) {
137: addClass(javaClass.getClassName());
138: }
139:
140: /**
141: * Visit a method of the current class
142: *
143: * @param method the method being visited.
144: */
145: public void visitMethod(Method method) {
146: String signature = method.getSignature();
147: int pos = signature.indexOf(")");
148: addClasses(signature.substring(1, pos));
149: addClasses(signature.substring(pos + 1));
150: }
151:
152: /**
153: * Add a classname to the list of dependency classes
154: *
155: * @param classname the class to be added to the list of dependencies.
156: */
157: void addClass(String classname) {
158: dependencies.put(classname, classname);
159: }
160:
161: /**
162: * Add all the classes from a descriptor string.
163: *
164: * @param string the descriptor string, being descriptors separated by
165: * ';' characters.
166: */
167: private void addClasses(String string) {
168: StringTokenizer tokens = new StringTokenizer(string, ";");
169: while (tokens.hasMoreTokens()) {
170: String descriptor = tokens.nextToken();
171: int pos = descriptor.indexOf('L');
172: if (pos != -1) {
173: addSlashClass(descriptor.substring(pos + 1));
174: }
175: }
176: }
177:
178: /**
179: * Adds a class name in slash format
180: * (for example org/apache/tools/ant/Main).
181: *
182: * @param classname the class name in slash format
183: */
184: private void addSlashClass(String classname) {
185: addClass(classname.replace('/', '.'));
186: }
187: }
|