[java] Fix typehelper fallback for simple class name

If there is no auxclasspath, then we still can use imports to
check the full name before we fallback to simple name only.

Also improve RuleTst to actually test without auxclasspath
This commit is contained in:
Andreas Dangel
2020-05-22 16:17:36 +02:00
parent a0e2558ca2
commit 5a6cb7be8b
4 changed files with 87 additions and 19 deletions

View File

@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.java.typeresolution;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
@ -16,6 +17,7 @@ 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.ASTImportDeclaration;
import net.sourceforge.pmd.lang.java.ast.TypeNode;
import net.sourceforge.pmd.lang.java.symboltable.TypedNameDeclaration;
import net.sourceforge.pmd.lang.java.typeresolution.internal.NullableClassLoader;
@ -85,6 +87,18 @@ public final class TypeHelper {
}
private static boolean fallbackIsA(TypeNode n, String clazzName) {
if (n.getImage() != null && !n.getImage().contains(".")) {
// simple name detected, check the imports to get the full name and use that for fallback
List<ASTImportDeclaration> imports = n.getRoot().findChildrenOfType(ASTImportDeclaration.class);
for (ASTImportDeclaration importDecl : imports) {
if (n.hasImageEqualTo(importDecl.getImportedSimpleName())) {
// found the import, compare the full names
return clazzName.equals(importDecl.getImportedName());
}
}
}
// fall back on using the simple name of the class only
if (clazzName.equals(n.getImage()) || clazzName.endsWith("." + n.getImage())) {
return true;
}

View File

@ -18,6 +18,8 @@ import org.junit.rules.ExpectedException;
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.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.typeresolution.internal.NullableClassLoader;
@ -78,6 +80,22 @@ public class TypeHelperTest extends BaseNonParserTest {
assertIsA(klass, Object.class);
}
/**
* If we don't have the annotation on the classpath,
* we should resolve the full name via the import, if possible
* and compare then. Only after that, we should compare the
* simple names.
*/
@Test
public void testIsAFallbackAnnotationSimpleNameImport() {
ASTName annotation = java.parse("package org; import foo.Stuff; @Stuff public class FooBar {}")
.getFirstDescendantOfType(ASTMarkerAnnotation.class).getFirstChildOfType(ASTName.class);
Assert.assertNull(annotation.getType());
Assert.assertTrue(TypeHelper.isA(annotation, "foo.Stuff"));
Assert.assertFalse(TypeHelper.isA(annotation, "other.Stuff"));
}
private void assertIsA(TypeNode node, Class<?> type) {
Assert.assertTrue("TypeHelper::isA with class arg: " + type.getCanonicalName(),
TypeHelper.isA(node, type));

View File

@ -150,41 +150,63 @@ public class MethodNamingConventions implements SomeInterface {
]]>
</code>
</test-code>
<test-code>
<description>JUnit 4 test detection</description>
<rule-property name="junit4TestPattern">[a-z][A-Za-z]*Test</rule-property>
<expected-problems>2</expected-problems>
<expected-linenumbers>12,16</expected-linenumbers>
<expected-linenumbers>8,12</expected-linenumbers>
<expected-messages>
<message>The JUnit 4 test method name 'testGetBestTeam' doesn't match '[a-z][A-Za-z]*Test'</message>
<message>The JUnit 4 test method name 'getBestTeam' doesn't match '[a-z][A-Za-z]*Test'</message>
</expected-messages>
<code><![CDATA[
import junit.framework.Assert;
import junit.framework.TestCase;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.Test;
public class TournamentTest extends TestCase {
Tournament tournament;
@Test // note that this is also a junit 3 test, but the junit4 rule applies
public void testGetBestTeam() {
}
public class TournamentTest extends TestCase {
Tournament tournament;
@Test // this is just a junit 4 test
public void getBestTeam() {
}
// this is ok
@Test
public void getBestTeamTest() {
}
}
]]></code>
</test-code>
@Test // note that this is also a junit 3 test, but the junit4 rule applies
public void testGetBestTeam() {
}
<test-code useAuxClasspath="false">
<description>JUnit 4 test detection without proper auxclasspath</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>8</expected-linenumbers>
<expected-messages>
<message>The JUnit 4 test method name 'get_best_team' doesn't match '[a-z][a-zA-Z0-9]*'</message>
</expected-messages>
<code><![CDATA[
import org.junit.Test; // note: test case uses "useAuxClasspath=false"!!
@Test // this is just a junit 4 test
public void getBestTeam() {
}
public class TournamentTest {
Tournament tournament;
// this is ok
@Test
public void getBestTeamTest() {
}
}
]]>
</code>
// wrong test name pattern
@Test
public void get_best_team() {
}
// this is ok
@Test
public void getBestTeam() {
}
}
]]></code>
</test-code>
<test-code>