Merge branch 'pr-2771' into master

[java] Fix #2756, NPE in TypeTestUtil #2771
This commit is contained in:
Andreas Dangel
2020-09-11 17:40:43 +02:00
4 changed files with 68 additions and 2 deletions

View File

@ -19,6 +19,7 @@ This is a {{ site.pmd.release_type }} release.
* pmd-java
* [#2708](https://github.com/pmd/pmd/issues/2708): \[java] False positive FinalFieldCouldBeStatic when using lombok Builder.Default
* [#2738](https://github.com/pmd/pmd/issues/2738): \[java] Custom rule with @ExhaustiveEnumSwitch throws NPE
* [#2756](https://github.com/pmd/pmd/issues/2756): \[java] TypeTestUtil fails with NPE for anonymous class
### API Changes

View File

@ -106,7 +106,11 @@ public final class TypeTestUtil {
final Class<?> clazz = loadClassWithNodeClassloader(node, canonicalName);
if (clazz != null) {
if (clazz.getCanonicalName() == null) {
return false; // no canonical name, give up: we shouldn't be able to access them
}
return clazz.isAssignableFrom(nodeType);
} else {
return fallbackIsA(node, canonicalName, true);
@ -174,8 +178,16 @@ public final class TypeTestUtil {
}
return node.getType() == null ? fallbackIsA(node, canonicalName, false)
: node.getType().getCanonicalName().equals(canonicalName);
if (node.getType() == null) {
return fallbackIsA(node, canonicalName, false);
}
String canoname = node.getType().getCanonicalName();
if (canoname == null) {
// anonymous/local class, or class nested within one of those
return false;
}
return canoname.equals(canonicalName);
}

View File

@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.java.types;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.concurrent.Callable;
import org.junit.Assert;
import org.junit.Rule;
@ -13,6 +14,7 @@ import org.junit.Test;
import org.junit.function.ThrowingRunnable;
import org.junit.rules.ExpectedException;
import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;
@ -20,6 +22,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.TypeNode;
import net.sourceforge.pmd.lang.java.symboltable.BaseNonParserTest;
import net.sourceforge.pmd.lang.java.types.testdata.SomeClassWithAnon;
public class TypeTestUtilTest extends BaseNonParserTest {
@ -74,6 +77,31 @@ public class TypeTestUtilTest extends BaseNonParserTest {
assertIsA(klass, Object.class);
}
@Test
public void testAnonClassTypeNPE() {
// #2756
ASTAllocationExpression anon =
java.parseClass(SomeClassWithAnon.class)
.getFirstDescendantOfType(ASTAllocationExpression.class);
Assert.assertNotNull("Type should be resolved", anon.getType());
Assert.assertTrue("Anon class", anon.isAnonymousClass());
Assert.assertTrue("Anon class", anon.getType().isAnonymousClass());
Assert.assertTrue("Should be a Runnable", TypeTestUtil.isA(Runnable.class, anon));
// This is not a canonical name, so we give up early
Assert.assertFalse(TypeTestUtil.isA(SomeClassWithAnon.class.getName() + "$1", anon));
Assert.assertFalse(TypeTestUtil.isExactlyA(SomeClassWithAnon.class.getName() + "$1", anon));
// this is the failure case: if the binary name doesn't match, we test the canoname, which was null
Assert.assertFalse(TypeTestUtil.isA(Callable.class, anon));
Assert.assertFalse(TypeTestUtil.isA(Callable.class.getCanonicalName(), anon));
Assert.assertFalse(TypeTestUtil.isExactlyA(Callable.class, anon));
Assert.assertFalse(TypeTestUtil.isExactlyA(Callable.class.getCanonicalName(), anon));
}
/**
* If we don't have the annotation on the classpath,
* we should resolve the full name via the import, if possible

View File

@ -0,0 +1,25 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.types.testdata;
/**
* #2756
*/
public class SomeClassWithAnon {
{
new Runnable() {
@Override
public void run() {
}
};
}
}