Merge branch 'pr-2269'
[java] Improve TypeHelper resilience
This commit is contained in:
@@ -21,6 +21,8 @@ For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designe
|
||||
|
||||
### Fixed Issues
|
||||
|
||||
* java
|
||||
* [#2268](https://github.com/pmd/pmd/issues/2268): \[java] Improve TypeHelper resilience
|
||||
* java-errorprone
|
||||
* [#2250](https://github.com/pmd/pmd/issues/2250): \[java] InvalidLogMessageFormat flags logging calls using a slf4j-Marker
|
||||
* java-performance
|
||||
|
@@ -6,6 +6,11 @@ package net.sourceforge.pmd.lang.java.typeresolution;
|
||||
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTImplementsList;
|
||||
import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
||||
import net.sourceforge.pmd.lang.java.symboltable.TypedNameDeclaration;
|
||||
|
||||
@@ -35,7 +40,45 @@ public final class TypeHelper {
|
||||
return isA(n, clazz);
|
||||
}
|
||||
|
||||
return clazzName.equals(n.getImage()) || clazzName.endsWith("." + n.getImage());
|
||||
return fallbackIsA(n, clazzName);
|
||||
}
|
||||
|
||||
private static boolean fallbackIsA(TypeNode n, String clazzName) {
|
||||
if (clazzName.equals(n.getImage()) || clazzName.endsWith("." + n.getImage())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (n instanceof ASTClassOrInterfaceDeclaration) {
|
||||
ASTClassOrInterfaceType superClass = ((ASTClassOrInterfaceDeclaration) n).getSuperClassTypeNode();
|
||||
if (superClass != null) {
|
||||
return isA(superClass, clazzName);
|
||||
}
|
||||
|
||||
for (ASTClassOrInterfaceType itf : ((ASTClassOrInterfaceDeclaration) n).getSuperInterfacesTypeNodes()) {
|
||||
if (isA(itf, clazzName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (n instanceof ASTEnumDeclaration) {
|
||||
|
||||
ASTImplementsList implemented = n.getFirstChildOfType(ASTImplementsList.class);
|
||||
if (implemented != null) {
|
||||
for (ASTClassOrInterfaceType itf : implemented) {
|
||||
if (isA(itf, clazzName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "java.lang.Enum".equals(clazzName)
|
||||
// supertypes of Enum
|
||||
|| "java.lang.Comparable".equals(clazzName)
|
||||
|| "java.io.Serializable".equals(clazzName);
|
||||
} else if (n instanceof ASTAnnotationTypeDeclaration) {
|
||||
return "java.lang.annotation.Annotation".equals(clazzName);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,8 +180,10 @@ public final class TypeHelper {
|
||||
|
||||
public static boolean subclasses(TypeNode n, Class<?> clazz) {
|
||||
Class<?> type = n.getType();
|
||||
if (type == null || clazz == null) {
|
||||
if (clazz == null) {
|
||||
return false; // If in auxclasspath, both should be resolvable, or are not the same
|
||||
} else if (type == null) {
|
||||
return fallbackIsA(n, clazz.getName());
|
||||
}
|
||||
|
||||
return clazz.isAssignableFrom(type);
|
||||
|
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.typeresolution;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.symboltable.BaseNonParserTest;
|
||||
|
||||
public class TypeHelperTest extends BaseNonParserTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void testIsAFallback() {
|
||||
|
||||
ASTClassOrInterfaceDeclaration klass =
|
||||
java.parse("package org; import java.io.Serializable; "
|
||||
+ "class FooBar implements Serializable {}")
|
||||
.getFirstDescendantOfType(ASTClassOrInterfaceDeclaration.class);
|
||||
|
||||
|
||||
Assert.assertNull(klass.getType());
|
||||
Assert.assertTrue(TypeHelper.isA(klass, "org.FooBar"));
|
||||
Assert.assertTrue(TypeHelper.isA(klass, "java.io.Serializable"));
|
||||
Assert.assertTrue(TypeHelper.isA(klass, Serializable.class));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testIsAFallbackEnum() {
|
||||
|
||||
ASTEnumDeclaration klass =
|
||||
java.parse("package org; "
|
||||
+ "enum FooBar implements Iterable {}")
|
||||
.getFirstDescendantOfType(ASTEnumDeclaration.class);
|
||||
|
||||
|
||||
Assert.assertNull(klass.getType());
|
||||
Assert.assertTrue(TypeHelper.isA(klass, "org.FooBar"));
|
||||
Assert.assertTrue(TypeHelper.isA(klass, "java.lang.Iterable"));
|
||||
Assert.assertTrue(TypeHelper.isA(klass, Iterable.class));
|
||||
Assert.assertTrue(TypeHelper.isA(klass, Enum.class));
|
||||
Assert.assertTrue(TypeHelper.isA(klass, Serializable.class));
|
||||
Assert.assertTrue(TypeHelper.isA(klass, Comparable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAFallbackAnnotation() {
|
||||
|
||||
ASTAnnotationTypeDeclaration klass =
|
||||
java.parse("package org; import foo.Stuff;"
|
||||
+ "public @interface FooBar {}")
|
||||
.getFirstDescendantOfType(ASTAnnotationTypeDeclaration.class);
|
||||
|
||||
|
||||
Assert.assertNull(klass.getType());
|
||||
Assert.assertTrue(TypeHelper.isA(klass, "org.FooBar"));
|
||||
Assert.assertTrue(TypeHelper.isA(klass, Annotation.class));
|
||||
}
|
||||
|
||||
|
||||
}
|
Reference in New Issue
Block a user