diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java new file mode 100644 index 00000000..d31d4534 --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.tools.ant.util.depend.bcel; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.StringTokenizer; + +import org.apache.bcel.classfile.ConstantClass; +import org.apache.bcel.classfile.ConstantNameAndType; +import org.apache.bcel.classfile.ConstantPool; +import org.apache.bcel.classfile.EmptyVisitor; +import org.apache.bcel.classfile.Field; +import org.apache.bcel.classfile.JavaClass; +import org.apache.bcel.classfile.Method; + +/** + * A BCEL visitor implementation to collect class dependency information + * + */ +public class DependencyVisitor extends EmptyVisitor { + /** The collected dependencies */ + private final Hashtable<String, String> dependencies = new Hashtable<String, String>(); + /** + * The current class's constant pool - used to determine class names + * from class references. + */ + private ConstantPool constantPool; + + /** + * Get the dependencies collected by this visitor + * + * @return a Enumeration of classnames, being the classes upon which the + * visited classes depend. + */ + public Enumeration<String> getDependencies() { + return dependencies.keys(); + } + + /** Clear the current set of collected dependencies. */ + public void clearDependencies() { + dependencies.clear(); + } + + /** + * Visit the constant pool of a class + * + * @param constantPool the constant pool of the class being visited. + */ + public void visitConstantPool(final ConstantPool constantPool) { + this.constantPool = constantPool; + } + + /** + * Visit a class reference + * + * @param constantClass the constantClass entry for the class reference + */ + public void visitConstantClass(final ConstantClass constantClass) { + final String classname + = constantClass.getConstantValue(constantPool).toString(); + addSlashClass(classname); + } + + /** + * Visit a name and type ref + * + * Look for class references in this + * + * @param obj the name and type reference being visited. + */ + public void visitConstantNameAndType(final ConstantNameAndType obj) { + final String name = obj.getName(constantPool); + if (obj.getSignature(constantPool).equals("Ljava/lang/Class;") + && name.startsWith("class$")) { + String classname + = name.substring("class$".length()).replace('$', '.'); + // does the class have a package structure + final int index = classname.lastIndexOf("."); + if (index > 0) { + char start; + // check if the package structure is more than 1 level deep + final int index2 = classname.lastIndexOf(".", index - 1); + if (index2 != -1) { + // class name has more than 1 package level 'com.company.Class' + start = classname.charAt(index2 + 1); + } else { + // class name has only 1 package level 'package.Class' + start = classname.charAt(0); + } + // Check to see if it's an inner class 'com.company.Class$Inner' + // CheckStyle:MagicNumber OFF + if ((start > 0x40) && (start < 0x5B)) { + // first letter of the previous segment of the class name 'Class' + // is upper case ascii. so according to the spec it's an inner class + classname = classname.substring(0, index) + "$" + + classname.substring(index + 1); + addClass(classname); + } else { + // Add the class in dotted notation 'com.company.Class' + addClass(classname); + } + // CheckStyle:MagicNumber ON + } else { + // Add a class with no package 'Class' + addClass(classname); + } + } + } + + /** + * Visit a field of the class. + * + * @param field the field being visited + */ + public void visitField(final Field field) { + addClasses(field.getSignature()); + } + + /** + * Visit a Java class + * + * @param javaClass the class being visited. + */ + public void visitJavaClass(final JavaClass javaClass) { + addClass(javaClass.getClassName()); + } + + /** + * Visit a method of the current class + * + * @param method the method being visited. + */ + public void visitMethod(final Method method) { + final String signature = method.getSignature(); + final int pos = signature.indexOf(")"); + addClasses(signature.substring(1, pos)); + addClasses(signature.substring(pos + 1)); + } + + /** + * Add a classname to the list of dependency classes + * + * @param classname the class to be added to the list of dependencies. + */ + void addClass(final String classname) { + dependencies.put(classname, classname); + } + + /** + * Add all the classes from a descriptor string. + * + * @param string the descriptor string, being descriptors separated by + * ';' characters. + */ + private void addClasses(final String string) { + final StringTokenizer tokens = new StringTokenizer(string, ";"); + while (tokens.hasMoreTokens()) { + final String descriptor = tokens.nextToken(); + final int pos = descriptor.indexOf('L'); + if (pos != -1) { + addSlashClass(descriptor.substring(pos + 1)); + } + } + } + + /** + * Adds a class name in slash format + * (for example org/apache/tools/ant/Main). + * + * @param classname the class name in slash format + */ + private void addSlashClass(final String classname) { + addClass(classname.replace('/', '.')); + } +} + |