[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:
Juan Martín Sotuyo Dodero
2016-12-10 20:21:58 -03:00
committed by Andreas Dangel
parent 66b6b8df19
commit 54db0ffbd9
2 changed files with 47 additions and 36 deletions

View File

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

View File

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