1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package com.puppycrawl.tools.checkstyle.checks.coding;
20
21 import antlr.collections.AST;
22 import com.google.common.collect.Sets;
23 import com.puppycrawl.tools.checkstyle.api.Check;
24 import com.puppycrawl.tools.checkstyle.api.DetailAST;
25 import com.puppycrawl.tools.checkstyle.api.FullIdent;
26 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
27 import com.puppycrawl.tools.checkstyle.api.Utils;
28 import java.util.Set;
29 import java.util.StringTokenizer;
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 public class IllegalInstantiationCheck
63 extends Check
64 {
65
66 private final Set<String> illegalClasses = Sets.newHashSet();
67
68
69 private String pkgName;
70
71
72 private final Set<FullIdent> imports = Sets.newHashSet();
73
74
75 private final Set<String> classNames = Sets.newHashSet();
76
77
78 private final Set<DetailAST> instantiations = Sets.newHashSet();
79
80 @Override
81 public int[] getDefaultTokens()
82 {
83 return new int[] {
84 TokenTypes.IMPORT,
85 TokenTypes.LITERAL_NEW,
86 TokenTypes.PACKAGE_DEF,
87 TokenTypes.CLASS_DEF,
88 };
89 }
90
91 @Override
92 public int[] getAcceptableTokens()
93 {
94
95 return new int[] {};
96 }
97
98 @Override
99 public int[] getRequiredTokens()
100 {
101 return new int[] {
102 TokenTypes.IMPORT,
103 TokenTypes.LITERAL_NEW,
104 TokenTypes.PACKAGE_DEF,
105 };
106 }
107
108 @Override
109 public void beginTree(DetailAST rootAST)
110 {
111 super.beginTree(rootAST);
112 pkgName = null;
113 imports.clear();
114 instantiations.clear();
115 classNames.clear();
116 }
117
118 @Override
119 public void visitToken(DetailAST ast)
120 {
121 switch (ast.getType()) {
122 case TokenTypes.LITERAL_NEW:
123 processLiteralNew(ast);
124 break;
125 case TokenTypes.PACKAGE_DEF:
126 processPackageDef(ast);
127 break;
128 case TokenTypes.IMPORT:
129 processImport(ast);
130 break;
131 case TokenTypes.CLASS_DEF:
132 processClassDef(ast);
133 break;
134 default:
135 throw new IllegalArgumentException("Unknown type " + ast);
136 }
137 }
138
139 @Override
140 public void finishTree(DetailAST rootAST)
141 {
142 for (DetailAST literalNewAST : instantiations) {
143 postprocessLiteralNew(literalNewAST);
144 }
145 }
146
147
148
149
150
151
152
153 private void processClassDef(DetailAST ast)
154 {
155 final DetailAST identToken = ast.findFirstToken(TokenTypes.IDENT);
156 final String className = identToken.getText();
157 classNames.add(className);
158 }
159
160
161
162
163
164 private void processImport(DetailAST ast)
165 {
166 final FullIdent name = FullIdent.createFullIdentBelow(ast);
167 if (name != null) {
168
169
170 imports.add(name);
171 }
172 }
173
174
175
176
177
178 private void processPackageDef(DetailAST ast)
179 {
180 final DetailAST packageNameAST = ast.getLastChild()
181 .getPreviousSibling();
182 final FullIdent packageIdent =
183 FullIdent.createFullIdent(packageNameAST);
184 pkgName = packageIdent.getText();
185 }
186
187
188
189
190
191 private void processLiteralNew(DetailAST ast)
192 {
193 if (ast.getParent().getType() == TokenTypes.METHOD_REF) {
194 return;
195 }
196 instantiations.add(ast);
197 }
198
199
200
201
202
203
204 private void postprocessLiteralNew(DetailAST ast)
205 {
206 final DetailAST typeNameAST = ast.getFirstChild();
207 final AST nameSibling = typeNameAST.getNextSibling();
208 if ((nameSibling != null)
209 && (nameSibling.getType() == TokenTypes.ARRAY_DECLARATOR))
210 {
211
212 return;
213 }
214
215 final FullIdent typeIdent = FullIdent.createFullIdent(typeNameAST);
216 final String typeName = typeIdent.getText();
217 final int lineNo = ast.getLineNo();
218 final int colNo = ast.getColumnNo();
219 final String fqClassName = getIllegalInstantiation(typeName);
220 if (fqClassName != null) {
221 log(lineNo, colNo, "instantiation.avoid", fqClassName);
222 }
223 }
224
225
226
227
228
229
230
231 private String getIllegalInstantiation(String className)
232 {
233 final String javlang = "java.lang.";
234
235 if (illegalClasses.contains(className)) {
236 return className;
237 }
238
239 final int clsNameLen = className.length();
240 final int pkgNameLen = (pkgName == null) ? 0 : pkgName.length();
241
242 for (String illegal : illegalClasses) {
243 final int illegalLen = illegal.length();
244
245
246 if (((illegalLen - javlang.length()) == clsNameLen)
247 && illegal.endsWith(className)
248 && illegal.startsWith(javlang))
249 {
250
251
252
253
254
255
256 final boolean isSameFile = classNames.contains(className);
257
258 boolean isSamePackage = false;
259 try {
260 final ClassLoader classLoader = getClassLoader();
261 if (classLoader != null) {
262 final String fqName = pkgName + "." + className;
263 classLoader.loadClass(fqName);
264
265 isSamePackage = true;
266 }
267 }
268 catch (final ClassNotFoundException ex) {
269
270 isSamePackage = false;
271 }
272
273 if (!(isSameFile || isSamePackage)) {
274 return illegal;
275 }
276 }
277
278
279
280
281
282
283
284
285 if ((pkgName != null)
286 && (clsNameLen == illegalLen - pkgNameLen - 1)
287 && (illegal.charAt(pkgNameLen) == '.')
288 && illegal.endsWith(className)
289 && illegal.startsWith(pkgName))
290 {
291 return illegal;
292 }
293
294 for (FullIdent importLineText : imports) {
295 final String importArg = importLineText.getText();
296 if (importArg.endsWith(".*")) {
297 final String fqClass =
298 importArg.substring(0, importArg.length() - 1)
299 + className;
300
301
302 if (illegalClasses.contains(fqClass)) {
303 return fqClass;
304 }
305 }
306 else {
307 if (Utils.baseClassname(importArg).equals(className)
308 && illegalClasses.contains(importArg))
309 {
310 return importArg;
311 }
312 }
313 }
314 }
315 return null;
316 }
317
318
319
320
321
322 public void setClasses(String classNames)
323 {
324 illegalClasses.clear();
325 final StringTokenizer tok = new StringTokenizer(classNames, ",");
326 while (tok.hasMoreTokens()) {
327 illegalClasses.add(tok.nextToken());
328 }
329 }
330 }