1
2
3
4 package net.sourceforge.pmd.lang.java.rule.imports;
5
6 import java.lang.reflect.Method;
7 import java.lang.reflect.Modifier;
8 import java.util.HashSet;
9 import java.util.Set;
10
11 import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
12 import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
13 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
14 import net.sourceforge.pmd.lang.rule.ImportWrapper;
15
16 public class DuplicateImportsRule extends AbstractJavaRule {
17
18 private Set<ImportWrapper> singleTypeImports;
19 private Set<ImportWrapper> importOnDemandImports;
20
21 public Object visit(ASTCompilationUnit node, Object data) {
22 singleTypeImports = new HashSet<ImportWrapper>();
23 importOnDemandImports = new HashSet<ImportWrapper>();
24 super.visit(node, data);
25
26
27
28
29 for (ImportWrapper thisImportOnDemand : importOnDemandImports) {
30 for (ImportWrapper thisSingleTypeImport : singleTypeImports) {
31 String singleTypeFullName = thisSingleTypeImport.getName();
32
33 int lastDot = singleTypeFullName.lastIndexOf('.');
34 String singleTypePkg = singleTypeFullName.substring(0, lastDot);
35 String singleTypeName = singleTypeFullName.substring(lastDot + 1);
36
37 if (thisImportOnDemand.getName().equals(singleTypePkg) &&
38 !isDisambiguationImport(node, singleTypePkg, singleTypeName)) {
39 addViolation(data, thisSingleTypeImport.getNode(), singleTypeFullName);
40 }
41 }
42 }
43 singleTypeImports.clear();
44 importOnDemandImports.clear();
45 return data;
46 }
47
48
49
50
51
52
53
54
55
56 private boolean isDisambiguationImport(ASTCompilationUnit node, String singleTypePkg, String singleTypeName) {
57 for (ImportWrapper thisImportOnDemand : importOnDemandImports) {
58 if (!thisImportOnDemand.getName().equals(singleTypePkg)) {
59 if (!thisImportOnDemand.isStaticOnDemand()) {
60 String fullyQualifiedClassName = thisImportOnDemand.getName() + "." + singleTypeName;
61 if (node.getClassTypeResolver().classNameExists(fullyQualifiedClassName)) {
62 return true;
63 }
64 } else {
65 Class<?> importClass = node.getClassTypeResolver().loadClass(thisImportOnDemand.getName());
66 if (importClass != null) {
67 for (Method m : importClass.getMethods()) {
68 if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(singleTypeName)) {
69 return true;
70 }
71 }
72 }
73 }
74 }
75 }
76
77 String fullyQualifiedClassName = "java.lang." + singleTypeName;
78 if (node.getClassTypeResolver().classNameExists(fullyQualifiedClassName)) {
79 return true;
80 }
81
82 return false;
83 }
84
85 public Object visit(ASTImportDeclaration node, Object data) {
86 ImportWrapper wrapper = new ImportWrapper(node.getImportedName(), node.getImportedName(), node.getImportedNameNode(),
87 node.isStatic() && node.isImportOnDemand());
88
89
90 if (node.isImportOnDemand()) {
91 if (importOnDemandImports.contains(wrapper)) {
92 addViolation(data, node.getImportedNameNode(), node.getImportedNameNode().getImage());
93 } else {
94 importOnDemandImports.add(wrapper);
95 }
96 } else {
97 if (singleTypeImports.contains(wrapper)) {
98 addViolation(data, node.getImportedNameNode(), node.getImportedNameNode().getImage());
99 } else {
100 singleTypeImports.add(wrapper);
101 }
102 }
103 return data;
104 }
105
106 }