[java] UnnecessaryFullyQualifiedNameRule handles same file class conflicts
- This resolves [#1555](https://sourceforge.net/p/pmd/bugs/1555/) - If a class is defined in the same file that conflicts with an import, it's not considered a violation
This commit is contained in:

committed by
Andreas Dangel

parent
66b6b8df19
commit
54db0ffbd9
@@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.java.rule.imports;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
|
||||
@@ -14,12 +15,12 @@ import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPackageDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaNode;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
|
||||
import net.sourceforge.pmd.lang.java.symboltable.SourceFileScope;
|
||||
|
||||
public class UnnecessaryFullyQualifiedNameRule extends AbstractJavaRule {
|
||||
|
||||
private List<ASTImportDeclaration> imports = new ArrayList<>();
|
||||
private List<ASTImportDeclaration> matches = new ArrayList<>();
|
||||
private List<PotentialViolation> violations = new ArrayList<>();
|
||||
|
||||
public UnnecessaryFullyQualifiedNameRule() {
|
||||
super.addRuleChainVisit(ASTCompilationUnit.class);
|
||||
@@ -31,11 +32,6 @@ public class UnnecessaryFullyQualifiedNameRule extends AbstractJavaRule {
|
||||
@Override
|
||||
public Object visit(ASTCompilationUnit node, Object data) {
|
||||
imports.clear();
|
||||
violations.clear();
|
||||
|
||||
super.visit(node, data);
|
||||
|
||||
reportViolations(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -47,7 +43,7 @@ public class UnnecessaryFullyQualifiedNameRule extends AbstractJavaRule {
|
||||
|
||||
@Override
|
||||
public Object visit(ASTClassOrInterfaceType node, Object data) {
|
||||
checkImports(node);
|
||||
checkImports(node, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -55,12 +51,12 @@ public class UnnecessaryFullyQualifiedNameRule extends AbstractJavaRule {
|
||||
public Object visit(ASTName node, Object data) {
|
||||
if (!(node.jjtGetParent() instanceof ASTImportDeclaration)
|
||||
&& !(node.jjtGetParent() instanceof ASTPackageDeclaration)) {
|
||||
checkImports(node);
|
||||
checkImports(node, data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private void checkImports(JavaNode node) {
|
||||
private void checkImports(JavaNode node, Object data) {
|
||||
String name = node.getImage();
|
||||
matches.clear();
|
||||
|
||||
@@ -125,19 +121,20 @@ public class UnnecessaryFullyQualifiedNameRule extends AbstractJavaRule {
|
||||
ASTImportDeclaration firstMatch = matches.get(0);
|
||||
|
||||
// Could this done to avoid a conflict?
|
||||
if (!isAvoidingConflict(name, firstMatch)) {
|
||||
if (!isAvoidingConflict(node, name, firstMatch)) {
|
||||
String importStr = firstMatch.getImportedName() + (firstMatch.isImportOnDemand() ? ".*" : "");
|
||||
String type = firstMatch.isStatic() ? "static " : "";
|
||||
|
||||
PotentialViolation v = new PotentialViolation(node, importStr, type);
|
||||
violations.add(v);
|
||||
addViolation(data, node, new Object[] { node.getImage(), importStr, type });
|
||||
}
|
||||
}
|
||||
|
||||
matches.clear();
|
||||
}
|
||||
|
||||
private boolean isAvoidingConflict(final String name, final ASTImportDeclaration firstMatch) {
|
||||
private boolean isAvoidingConflict(final JavaNode node, final String name,
|
||||
final ASTImportDeclaration firstMatch) {
|
||||
// is it a conflict between different imports?
|
||||
if (firstMatch.isImportOnDemand() && firstMatch.isStatic() && name.indexOf('.') != -1) {
|
||||
final String methodCalled = name.substring(name.indexOf('.') + 1);
|
||||
|
||||
@@ -168,28 +165,19 @@ public class UnnecessaryFullyQualifiedNameRule extends AbstractJavaRule {
|
||||
}
|
||||
}
|
||||
|
||||
// Is it a conflict with a class in the same file?
|
||||
final String unqualifiedName = name.substring(name.lastIndexOf('.') + 1);
|
||||
final int unqualifiedNameLength = unqualifiedName.length();
|
||||
final Set<String> qualifiedTypes = node.getScope().getEnclosingScope(SourceFileScope.class)
|
||||
.getQualifiedTypeNames().keySet();
|
||||
for (final String qualified : qualifiedTypes) {
|
||||
int fullLength = qualified.length();
|
||||
if (qualified.endsWith(unqualifiedName)
|
||||
&& (fullLength == unqualifiedNameLength || qualified.charAt(fullLength - unqualifiedNameLength - 1) == '.')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class PotentialViolation {
|
||||
private JavaNode node;
|
||||
private String importStr;
|
||||
private String importType;
|
||||
|
||||
public PotentialViolation(JavaNode node, String importStr, String importType) {
|
||||
this.node = node;
|
||||
this.importStr = importStr;
|
||||
this.importType = importType;
|
||||
}
|
||||
|
||||
public void addViolation(UnnecessaryFullyQualifiedNameRule rule, Object data) {
|
||||
rule.addViolation(data, node, new Object[] { node.getImage(), importStr, importType });
|
||||
}
|
||||
}
|
||||
|
||||
private void reportViolations(Object data) {
|
||||
for (PotentialViolation v : violations) {
|
||||
v.addViolation(this, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -364,4 +364,27 @@ public class Foo {
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
</test-data>
|
||||
<test-code>
|
||||
<description>#1555 - UnnecessaryFullyQualifiedName for conflict resolution with inner class</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
import java.util.*;
|
||||
|
||||
final class Test {
|
||||
private Test() { }
|
||||
|
||||
private static class Locale {
|
||||
public final java.util.Locale locale; // Here we need to fully qualify
|
||||
public Locale(final String tag) {
|
||||
this.locale = java.util.Locale.forLanguageTag(tag);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
final Locale l = new Locale("fr-CA");
|
||||
System.out.println(l.toString());
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
</test-data>
|
||||
|
Reference in New Issue
Block a user