Merge branch 'pr-2269'

[java] Improve TypeHelper resilience
This commit is contained in:
Andreas Dangel
2020-02-10 19:17:24 +01:00
3 changed files with 120 additions and 2 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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));
}
}