Merge branch 'pr-2771' into master
[java] Fix #2756, NPE in TypeTestUtil #2771
This commit is contained in:
@ -19,6 +19,7 @@ This is a {{ site.pmd.release_type }} release.
|
|||||||
* pmd-java
|
* pmd-java
|
||||||
* [#2708](https://github.com/pmd/pmd/issues/2708): \[java] False positive FinalFieldCouldBeStatic when using lombok Builder.Default
|
* [#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
|
* [#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
|
### API Changes
|
||||||
|
@ -106,7 +106,11 @@ public final class TypeTestUtil {
|
|||||||
|
|
||||||
final Class<?> clazz = loadClassWithNodeClassloader(node, canonicalName);
|
final Class<?> clazz = loadClassWithNodeClassloader(node, canonicalName);
|
||||||
|
|
||||||
|
|
||||||
if (clazz != null) {
|
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);
|
return clazz.isAssignableFrom(nodeType);
|
||||||
} else {
|
} else {
|
||||||
return fallbackIsA(node, canonicalName, true);
|
return fallbackIsA(node, canonicalName, true);
|
||||||
@ -174,8 +178,16 @@ public final class TypeTestUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return node.getType() == null ? fallbackIsA(node, canonicalName, false)
|
if (node.getType() == null) {
|
||||||
: node.getType().getCanonicalName().equals(canonicalName);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.java.types;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
@ -13,6 +14,7 @@ import org.junit.Test;
|
|||||||
import org.junit.function.ThrowingRunnable;
|
import org.junit.function.ThrowingRunnable;
|
||||||
import org.junit.rules.ExpectedException;
|
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.ASTAnnotationTypeDeclaration;
|
||||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
|
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
|
||||||
import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;
|
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.ASTName;
|
||||||
import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
||||||
import net.sourceforge.pmd.lang.java.symboltable.BaseNonParserTest;
|
import net.sourceforge.pmd.lang.java.symboltable.BaseNonParserTest;
|
||||||
|
import net.sourceforge.pmd.lang.java.types.testdata.SomeClassWithAnon;
|
||||||
|
|
||||||
public class TypeTestUtilTest extends BaseNonParserTest {
|
public class TypeTestUtilTest extends BaseNonParserTest {
|
||||||
|
|
||||||
@ -74,6 +77,31 @@ public class TypeTestUtilTest extends BaseNonParserTest {
|
|||||||
assertIsA(klass, Object.class);
|
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,
|
* If we don't have the annotation on the classpath,
|
||||||
* we should resolve the full name via the import, if possible
|
* we should resolve the full name via the import, if possible
|
||||||
|
25
pmd-java/src/test/java/net/sourceforge/pmd/lang/java/types/testdata/SomeClassWithAnon.java
vendored
Normal file
25
pmd-java/src/test/java/net/sourceforge/pmd/lang/java/types/testdata/SomeClassWithAnon.java
vendored
Normal 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() {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user