diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java deleted file mode 100644 index f0b240238c..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.typeresolution; - -import net.sourceforge.pmd.annotation.DeprecatedUntil700; -import net.sourceforge.pmd.annotation.InternalApi; -import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter; -import net.sourceforge.pmd.lang.java.typeresolution.internal.NullableClassLoader; - - -// -// Helpful reading: -// http://www.janeg.ca/scjp/oper/promotions.html -// http://java.sun.com/docs/books/jls/second_edition/html/conversions.doc.html -// - -/** - * @deprecated Some rules still use this so we keep it around, but it's dysfunctional - */ -@Deprecated -@DeprecatedUntil700 -@InternalApi -public class ClassTypeResolver extends JavaParserVisitorAdapter implements NullableClassLoader { - - /** - * Check whether the supplied class name exists. - */ - public boolean classNameExists(String fullyQualifiedClassName) { - return false; - } - - @Override - public Class loadClassOrNull(String fullyQualifiedClassName) { - return null; - } - -} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/PMDASMClassLoader.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/PMDASMClassLoader.java deleted file mode 100644 index 3446631436..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/PMDASMClassLoader.java +++ /dev/null @@ -1,152 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.typeresolution; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.objectweb.asm.ClassReader; - -import net.sourceforge.pmd.annotation.InternalApi; -import net.sourceforge.pmd.lang.java.typeresolution.internal.NullableClassLoader; -import net.sourceforge.pmd.lang.java.typeresolution.visitors.PMDASMVisitor; - -/* - * I've refactored this class to not cache the results any more. This is a - * tradeoff in testing I've found the CPU tradeoff is negligeable. With the - * cache, large codebases consumed a lot of memory and slowed down greatly when - * approaching 3,000 classes. I'm adding this comment in case someone is looking - * at this code and thinks a cache may help. - * - * see: git show 9e7deee88f63870a1de2cd86458278a027deb6d6 - * - * However, there seems to be a big performance improvement by caching - * the negative cases only. The cache is shared between loadClass and getImportedClasses, - * as they are using the same (parent) class loader, e.g. if the class foo.Bar cannot be loaded, - * then the resource foo/Bar.class will not exist, too. - * - * Note: since git show 46ad3a4700b7a233a177fa77d08110127a85604c the cache is using - * a concurrent hash map to avoid synchronizing on the class loader instance. - */ -@InternalApi -@Deprecated -public final class PMDASMClassLoader extends ClassLoader implements NullableClassLoader { - - private static PMDASMClassLoader cachedPMDASMClassLoader; - private static ClassLoader cachedClassLoader; - private static final Object CACHE_LOCK = new Object(); - - /** - * Caches the names of the classes that we can't load or that don't exist. - */ - private final ConcurrentMap dontBother = new ConcurrentHashMap<>(); - - static { - registerAsParallelCapable(); - } - - private PMDASMClassLoader(ClassLoader parent) { - super(parent); - } - - /** - * A new PMDASMClassLoader is created for each compilation unit, this method - * allows to reuse the same PMDASMClassLoader across all the compilation - * units. - */ - public static PMDASMClassLoader getInstance(ClassLoader parent) { - if (parent instanceof PMDASMClassLoader) { - return (PMDASMClassLoader) parent; - } - synchronized (CACHE_LOCK) { - if (parent.equals(cachedClassLoader)) { - return cachedPMDASMClassLoader; - } - cachedClassLoader = parent; - cachedPMDASMClassLoader = new PMDASMClassLoader(parent); - - return cachedPMDASMClassLoader; - } - } - - @Override - public Class loadClass(String name) throws ClassNotFoundException { - Class aClass = loadClassOrNull(name); - if (aClass == null) { - throw new ClassNotFoundException(name); - } - return aClass; - } - - /** - * Not throwing CNFEs to represent failure makes a huge performance - * difference. Typeres as a whole is 2x faster. - */ - @Override - public Class loadClassOrNull(String name) { - if (dontBother.containsKey(name)) { - return null; - } - - try { - return super.loadClass(name); - } catch (ClassNotFoundException | LinkageError e) { - dontBother.put(name, Boolean.TRUE); - return null; - } - } - - /** - * Checks if the class loader could resolve a given class name (ie: it - * doesn't know for sure it will fail). Notice, that the ability to resolve - * a class does not imply that the class will actually be found and - * resolved. - * - * @param name - * the name of the class - * @return whether the class can be resolved - */ - public boolean couldResolve(String name) { - return !dontBother.containsKey(name); - } - - - /** - * FIXME what does this do? - */ - public synchronized Map getImportedClasses(String name) throws ClassNotFoundException { - if (dontBother.containsKey(name)) { - throw new ClassNotFoundException(name); - } - try (InputStream classResource = getResourceAsStream(name.replace('.', '/') + ".class")) { - ClassReader reader = new ClassReader(classResource); - PMDASMVisitor asmVisitor = new PMDASMVisitor(name); - reader.accept(asmVisitor, 0); - - List inner = asmVisitor.getInnerClasses(); - if (inner != null && !inner.isEmpty()) { - // to avoid ConcurrentModificationException - inner = new ArrayList<>(inner); - for (String str : inner) { - try (InputStream innerClassStream = getResourceAsStream(str.replace('.', '/') + ".class")) { - if (innerClassStream != null) { - reader = new ClassReader(innerClassStream); - reader.accept(asmVisitor, 0); - } - } - } - } - return asmVisitor.getPackages(); - } catch (IOException e) { - dontBother.put(name, Boolean.TRUE); - throw new ClassNotFoundException(name, e); - } - } -} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/internal/NullableClassLoader.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/internal/NullableClassLoader.java deleted file mode 100644 index 51a28bfd3f..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/internal/NullableClassLoader.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.typeresolution.internal; - -import net.sourceforge.pmd.lang.java.typeresolution.PMDASMClassLoader; - -/** - * A classloader that doesn't throw a {@link ClassNotFoundException} - * to report unresolved classes. This is a big performance improvement - * for {@link PMDASMClassLoader}, which caches negative cases. - * - *

See https://github.com/pmd/pmd/pull/2236 - */ -public interface NullableClassLoader { - - /** - * Load a class from its binary name. Returns null if not found. - */ - Class loadClassOrNull(String binaryName); - - - final class ClassLoaderWrapper implements NullableClassLoader { - - private final ClassLoader classLoader; - - private ClassLoaderWrapper(ClassLoader classLoader) { - assert classLoader != null : "Null classloader"; - this.classLoader = classLoader; - } - - @Override - public Class loadClassOrNull(String binaryName) { - try { - return classLoader.loadClass(binaryName); - } catch (ClassNotFoundException e) { - return null; - } - } - - public static ClassLoaderWrapper wrapNullable(ClassLoader classLoader) { - if (classLoader == null) { - classLoader = ClassLoader.getSystemClassLoader(); - } - return new ClassLoaderWrapper(classLoader); - } - } -} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/visitors/PMDASMVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/visitors/PMDASMVisitor.java deleted file mode 100644 index b1c0b2dcf2..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/visitors/PMDASMVisitor.java +++ /dev/null @@ -1,369 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.typeresolution.visitors; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.signature.SignatureReader; -import org.objectweb.asm.signature.SignatureVisitor; - -import net.sourceforge.pmd.annotation.InternalApi; - -@Deprecated -@InternalApi -public class PMDASMVisitor extends ClassVisitor { - private static final int ASM_API = Opcodes.ASM9; // latest, non-experimental API version - - private String outerName; - - private Map packages = new HashMap<>(); - - private AnnotationVisitor annotationVisitor = new PMDAnnotationVisitor(this); - - private FieldVisitor fieldVisitor = new PMDFieldVisitor(this); - - private SignatureVisitor sigVisitor = new PMDSignatureVisitor(this); - - private MethodVisitor methodVisitor = new PMDMethodVisitor(this); - - public List innerClasses; - - public PMDASMVisitor(String outerName) { - super(ASM_API); - this.outerName = outerName; - } - - public Map getPackages() { - return packages; - } - - public List getInnerClasses() { - return innerClasses; - } - - private String parseClassName(String name) { - if (name == null) { - return null; - } - - String className = name; - int n = name.lastIndexOf('/'); - if (n > -1) { - className = name.substring(n + 1); - } - name = name.replace('/', '.'); - packages.put(className, name); - n = className.indexOf('$'); - if (n > -1) { - // TODO I don't think the first one, with Class$Inner is needed - - // come back and check - packages.put(className.substring(n + 1), name); - packages.put(className.replace('$', '.'), name); - } - - return name; - } - - private void parseClassName(String[] names) { - if (names != null) { - for (String s : names) { - parseClassName(s); - } - } - } - - private void extractSignature(String sig) { - if (sig != null) { - new SignatureReader(sig).accept(sigVisitor); - } - } - - /* Start ClassVisitor implementations */ - - @Override - public void visit(int version, int access, String name, String sig, String superName, String[] interfaces) { - parseClassName(name); - parseClassName(interfaces); - if (sig != null) { - extractSignature(sig); - } - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - addType(Type.getType(desc)); - return annotationVisitor; - } - - @Override - public FieldVisitor visitField(int access, String name, String desc, String sig, Object value) { - if (sig != null) { - extractSignature(sig); - } - - addType(Type.getType(desc)); - if (value instanceof Type) { - addType((Type) value); - } - return fieldVisitor; - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String sig, String[] exceptions) { - if (sig != null) { - extractSignature(sig); - } - addMethodDesc(desc); - parseClassName(exceptions); - return methodVisitor; - } - - @Override - public void visitInnerClass(String name, String outerName, String innerName, int access) { - if (!this.outerName.replace('.', '/').equals(outerName)) { - // do not consider the inner class if it is not a member of our - // outer class - return; - } - - if (innerClasses == null) { - innerClasses = new ArrayList<>(); - } - if (!innerClasses.contains(name.replace('/', '.'))) { - innerClasses.add(name.replace('/', '.')); - } - packages.put(innerName, name.replace('/', '.')); - } - - private void addMethodDesc(String desc) { - addTypes(desc); - addType(Type.getReturnType(desc)); - } - - private void addTypes(String desc) { - Type[] types = Type.getArgumentTypes(desc); - for (Type type : types) { - addType(type); - } - } - - private void addType(Type t) { - switch (t.getSort()) { - case Type.ARRAY: - addType(t.getElementType()); - break; - case Type.OBJECT: - parseClassName(t.getClassName().replace('.', '/')); - break; - default: - // Do nothing - break; - } - } - - /* - * Start visitors - */ - - private static class PMDFieldVisitor extends FieldVisitor { - - private PMDASMVisitor parent; - - PMDFieldVisitor(PMDASMVisitor visitor) { - super(ASM_API); - parent = visitor; - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - parent.addType(Type.getType(desc)); - return parent.annotationVisitor; - } - } - - private static class PMDAnnotationVisitor extends AnnotationVisitor { - private PMDASMVisitor parent; - - PMDAnnotationVisitor(PMDASMVisitor visitor) { - super(ASM_API); - parent = visitor; - } - - @Override - public AnnotationVisitor visitAnnotation(String name, String desc) { - parent.addType(Type.getType(desc)); - return this; - } - - @Override - public void visitEnum(String name, String desc, String value) { - parent.addType(Type.getType(desc)); - } - - @Override - public AnnotationVisitor visitArray(String name) { - return this; - } - - @Override - public void visit(String name, Object value) { - if (value instanceof Type) { - parent.addType((Type) value); - } - } - } - - private static class PMDSignatureVisitor extends SignatureVisitor { - private PMDASMVisitor parent; - - PMDSignatureVisitor(PMDASMVisitor visitor) { - super(ASM_API); - this.parent = visitor; - } - - @Override - public SignatureVisitor visitClassBound() { - return this; - } - - @Override - public SignatureVisitor visitInterfaceBound() { - return this; - } - - @Override - public SignatureVisitor visitSuperclass() { - return this; - } - - @Override - public SignatureVisitor visitInterface() { - return this; - } - - @Override - public SignatureVisitor visitParameterType() { - return this; - } - - @Override - public SignatureVisitor visitReturnType() { - return this; - } - - @Override - public SignatureVisitor visitExceptionType() { - return this; - } - - @Override - public SignatureVisitor visitArrayType() { - return this; - } - - @Override - public void visitClassType(String name) { - parent.parseClassName(name); - } - - @Override - public void visitInnerClassType(String name) { - // parent.parseClassName(name); - } - - @Override - public SignatureVisitor visitTypeArgument(char wildcard) { - return this; - } - } - - private static class PMDMethodVisitor extends MethodVisitor { - private PMDASMVisitor parent; - - PMDMethodVisitor(PMDASMVisitor visitor) { - super(ASM_API); - parent = visitor; - } - - @Override - public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { - parent.addType(Type.getType(desc)); - return parent.annotationVisitor; - } - - @Override - public void visitTypeInsn(int opcode, String desc) { - if (desc.charAt(0) == '[') { - parent.addType(Type.getType(desc)); - } else { - parent.parseClassName(desc); - } - } - - @Override - public void visitFieldInsn(int opcode, String owner, String name, String desc) { - parent.parseClassName(owner); - parent.addType(Type.getType(desc)); - } - - @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { - parent.parseClassName(owner); - parent.addMethodDesc(desc); - } - - /** - * the constant to be loaded on the stack. This parameter must be a non - * null Integer, a Float, a Long, a Double a String (or a Type for - * .class constants, for classes whose version is 49.0 or more). - * - * @see org.objectweb.asm.MethodVisitor#visitLdcInsn(java.lang.Object) - */ - @Override - public void visitLdcInsn(Object cst) { - if (cst instanceof Type) { - parent.addType((Type) cst); - } else if (cst instanceof String) { - parent.parseClassName((String) cst); - } - } - - @Override - public void visitMultiANewArrayInsn(String desc, int dims) { - parent.addType(Type.getType(desc)); - } - - @Override - public void visitLocalVariable(String name, String desc, String sig, Label start, Label end, int index) { - parent.extractSignature(sig); - } - - @Override - public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { - parent.parseClassName(type); - } - - @Override - public AnnotationVisitor visitAnnotationDefault() { - return parent.annotationVisitor; - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - parent.addType(Type.getType(desc)); - return parent.annotationVisitor; - } - } -}