1
2
3
4 package net.sourceforge.pmd.lang.java.rule.imports;
5
6 import java.util.ArrayList;
7 import java.util.List;
8
9 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
10 import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
11 import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
12 import net.sourceforge.pmd.lang.java.ast.ASTName;
13 import net.sourceforge.pmd.lang.java.ast.ASTPackageDeclaration;
14 import net.sourceforge.pmd.lang.java.ast.JavaNode;
15 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
16
17 public class UnnecessaryFullyQualifiedNameRule extends AbstractJavaRule {
18
19 private List<ASTImportDeclaration> imports = new ArrayList<ASTImportDeclaration>();
20 private List<ASTImportDeclaration> matches = new ArrayList<ASTImportDeclaration>();
21 private List<PotentialViolation> violations = new ArrayList<PotentialViolation>();
22 private List<PotentialViolation> enumViolations = new ArrayList<PotentialViolation>();
23
24 public UnnecessaryFullyQualifiedNameRule() {
25 super.addRuleChainVisit(ASTCompilationUnit.class);
26 super.addRuleChainVisit(ASTImportDeclaration.class);
27 super.addRuleChainVisit(ASTClassOrInterfaceType.class);
28 super.addRuleChainVisit(ASTName.class);
29 }
30
31 @Override
32 public Object visit(ASTCompilationUnit node, Object data) {
33 imports.clear();
34 violations.clear();
35 enumViolations.clear();
36
37 super.visit(node, data);
38
39 filterPotentialViolations();
40 reportViolations(data);
41 return data;
42 }
43
44 @Override
45 public Object visit(ASTImportDeclaration node, Object data) {
46 imports.add(node);
47 return data;
48 }
49
50 @Override
51 public Object visit(ASTClassOrInterfaceType node, Object data) {
52 checkImports(node, data, false);
53 return data;
54 }
55
56 @Override
57 public Object visit(ASTName node, Object data) {
58 if (!(node.jjtGetParent() instanceof ASTImportDeclaration)
59 && !(node.jjtGetParent() instanceof ASTPackageDeclaration)) {
60 checkImports(node, data, true);
61 }
62 return data;
63 }
64
65 private void checkImports(JavaNode node, Object data, boolean checkStatic) {
66 String name = node.getImage();
67 matches.clear();
68
69
70 for (ASTImportDeclaration importDeclaration : imports) {
71 if (importDeclaration.isImportOnDemand()) {
72
73 if (name.startsWith(importDeclaration.getImportedName())) {
74 if (name.lastIndexOf('.') == importDeclaration.getImportedName().length()) {
75 matches.add(importDeclaration);
76 continue;
77 }
78 }
79 } else {
80
81 if (name.equals(importDeclaration.getImportedName())) {
82 matches.add(importDeclaration);
83 continue;
84 }
85
86 if (name.startsWith(importDeclaration.getImportedName())) {
87 if (name.lastIndexOf('.') == importDeclaration.getImportedName().length()) {
88 matches.add(importDeclaration);
89 continue;
90 }
91 }
92 }
93 }
94
95
96
97
98
99
100
101
102
103
104
105 if (matches.isEmpty() && name.indexOf('.') >= 0) {
106 for (ASTImportDeclaration importDeclaration : imports) {
107 if (importDeclaration.isStatic()) {
108 String[] importParts = importDeclaration.getImportedName().split("\\.");
109 String[] nameParts = name.split("\\.");
110 if (importDeclaration.isImportOnDemand()) {
111
112 if (nameParts[nameParts.length - 2].equals(importParts[importParts.length - 1])) {
113 matches.add(importDeclaration);
114 }
115 } else {
116
117 if (nameParts[nameParts.length - 1].equals(importParts[importParts.length - 1])
118 && nameParts[nameParts.length - 2].equals(importParts[importParts.length - 2])) {
119 matches.add(importDeclaration);
120 }
121 }
122 }
123 }
124 }
125
126 if (!matches.isEmpty()) {
127 ASTImportDeclaration firstMatch = matches.get(0);
128 String importStr = firstMatch.getImportedName() + (matches.get(0).isImportOnDemand() ? ".*" : "");
129 String type = firstMatch.isStatic() ? "static " : "";
130
131 PotentialViolation v = new PotentialViolation(node, importStr, type);
132 violations.add(v);
133 if (isEnum(firstMatch.getType())) {
134 enumViolations.add(v);
135 }
136 }
137
138 matches.clear();
139 }
140
141 private static class PotentialViolation {
142 private JavaNode node;
143 private String importStr;
144 private String importType;
145
146 public PotentialViolation(JavaNode node, String importStr, String importType) {
147 this.node = node;
148 this.importStr = importStr;
149 this.importType = importType;
150 }
151
152 public void addViolation(UnnecessaryFullyQualifiedNameRule rule, Object data) {
153 rule.addViolation(data, node, new Object[] { node.getImage(), importStr, importType });
154 }
155 }
156
157 private void filterPotentialViolations() {
158 if (enumViolations.size() > 1) {
159 violations.removeAll(enumViolations);
160 }
161 }
162
163 private void reportViolations(Object data) {
164 for (PotentialViolation v : violations) {
165 v.addViolation(this, data);
166 }
167 }
168
169 private boolean isEnum(Class<?> type) {
170 if (type != null && Enum.class.isAssignableFrom(type)) {
171 return true;
172 }
173 return false;
174 }
175 }