1 | //////////////////////////////////////////////////////////////////////////////// | |
2 | // checkstyle: Checks Java source code for adherence to a set of rules. | |
3 | // Copyright (C) 2001-2021 the original author or authors. | |
4 | // | |
5 | // This library is free software; you can redistribute it and/or | |
6 | // modify it under the terms of the GNU Lesser General Public | |
7 | // License as published by the Free Software Foundation; either | |
8 | // version 2.1 of the License, or (at your option) any later version. | |
9 | // | |
10 | // This library is distributed in the hope that it will be useful, | |
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | // Lesser General Public License for more details. | |
14 | // | |
15 | // You should have received a copy of the GNU Lesser General Public | |
16 | // License along with this library; if not, write to the Free Software | |
17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | //////////////////////////////////////////////////////////////////////////////// | |
19 | ||
20 | package com.puppycrawl.tools.checkstyle.checks.imports; | |
21 | ||
22 | import java.util.ArrayList; | |
23 | import java.util.List; | |
24 | import java.util.regex.Pattern; | |
25 | ||
26 | import com.puppycrawl.tools.checkstyle.StatelessCheck; | |
27 | import com.puppycrawl.tools.checkstyle.api.AbstractCheck; | |
28 | import com.puppycrawl.tools.checkstyle.api.DetailAST; | |
29 | import com.puppycrawl.tools.checkstyle.api.FullIdent; | |
30 | import com.puppycrawl.tools.checkstyle.api.TokenTypes; | |
31 | import com.puppycrawl.tools.checkstyle.utils.CommonUtil; | |
32 | ||
33 | /** | |
34 | * <p> | |
35 | * Checks for imports from a set of illegal packages. | |
36 | * </p> | |
37 | * <p> | |
38 | * Note: By default, the check rejects all {@code sun.*} packages since programs | |
39 | * that contain direct calls to the {@code sun.*} packages are | |
40 | * <a href="https://www.oracle.com/java/technologies/faq-sun-packages.html"> | |
41 | * "not guaranteed to work on all Java-compatible platforms"</a>. To reject other | |
42 | * packages, set property {@code illegalPkgs} to a list of the illegal packages. | |
43 | * </p> | |
44 | * <ul> | |
45 | * <li> | |
46 | * Property {@code illegalPkgs} - Specify packages to reject, if <b>regexp</b> | |
47 | * property is not set, checks if import is the part of package. If <b>regexp</b> | |
48 | * property is set, then list of packages will be interpreted as regular expressions. | |
49 | * Note, all properties for match will be used. | |
50 | * Type is {@code java.lang.String[]}. | |
51 | * Default value is {@code sun}. | |
52 | * </li> | |
53 | * <li> | |
54 | * Property {@code illegalClasses} - Specify class names to reject, if <b>regexp</b> | |
55 | * property is not set, checks if import equals class name. If <b>regexp</b> | |
56 | * property is set, then list of class names will be interpreted as regular expressions. | |
57 | * Note, all properties for match will be used. | |
58 | * Type is {@code java.lang.String[]}. | |
59 | * Default value is {@code ""}. | |
60 | * </li> | |
61 | * <li> | |
62 | * Property {@code regexp} - Control whether the {@code illegalPkgs} and | |
63 | * {@code illegalClasses} should be interpreted as regular expressions. | |
64 | * Type is {@code boolean}. | |
65 | * Default value is {@code false}. | |
66 | * </li> | |
67 | * </ul> | |
68 | * <p> | |
69 | * To configure the check: | |
70 | * </p> | |
71 | * <pre> | |
72 | * <module name="IllegalImport"/> | |
73 | * </pre> | |
74 | * <p> | |
75 | * To configure the check so that it rejects packages {@code java.io.*} and {@code java.sql.*}: | |
76 | * </p> | |
77 | * <pre> | |
78 | * <module name="IllegalImport"> | |
79 | * <property name="illegalPkgs" value="java.io, java.sql"/> | |
80 | * </module> | |
81 | * </pre> | |
82 | * <p> | |
83 | * The following example shows class with no illegal imports | |
84 | * </p> | |
85 | * <pre> | |
86 | * import java.lang.ArithmeticException; | |
87 | * import java.util.List; | |
88 | * import java.util.Enumeration; | |
89 | * import java.util.Arrays; | |
90 | * import sun.applet.*; | |
91 | * | |
92 | * public class InputIllegalImport { } | |
93 | * </pre> | |
94 | * <p> | |
95 | * The following example shows class with two illegal imports | |
96 | * </p> | |
97 | * <ul> | |
98 | * <li> | |
99 | * <b>java.io.*</b>, illegalPkgs property contains this package | |
100 | * </li> | |
101 | * <li> | |
102 | * <b>java.sql.Connection</b> is inside java.sql package | |
103 | * </li> | |
104 | * </ul> | |
105 | * <pre> | |
106 | * import java.io.*; // violation | |
107 | * import java.lang.ArithmeticException; | |
108 | * import java.sql.Connection; // violation | |
109 | * import java.util.List; | |
110 | * import java.util.Enumeration; | |
111 | * import java.util.Arrays; | |
112 | * import sun.applet.*; | |
113 | * | |
114 | * public class InputIllegalImport { } | |
115 | * </pre> | |
116 | * <p> | |
117 | * To configure the check so that it rejects classes {@code java.util.Date} and | |
118 | * {@code java.sql.Connection}: | |
119 | * </p> | |
120 | * <pre> | |
121 | * <module name="IllegalImport"> | |
122 | * <property name="illegalClasses" | |
123 | * value="java.util.Date, java.sql.Connection"/> | |
124 | * </module> | |
125 | * </pre> | |
126 | * <p> | |
127 | * The following example shows class with no illegal imports | |
128 | * </p> | |
129 | * <pre> | |
130 | * import java.io.*; | |
131 | * import java.lang.ArithmeticException; | |
132 | * import java.util.List; | |
133 | * import java.util.Enumeration; | |
134 | * import java.util.Arrays; | |
135 | * import sun.applet.*; | |
136 | * | |
137 | * public class InputIllegalImport { } | |
138 | * </pre> | |
139 | * <p> | |
140 | * The following example shows class with two illegal imports | |
141 | * </p> | |
142 | * <ul> | |
143 | * <li> | |
144 | * <b>java.sql.Connection</b>, illegalClasses property contains this class | |
145 | * </li> | |
146 | * <li> | |
147 | * <b>java.util.Date</b>, illegalClasses property contains this class | |
148 | * </li> | |
149 | * </ul> | |
150 | * <pre> | |
151 | * import java.io.*; | |
152 | * import java.lang.ArithmeticException; | |
153 | * import java.sql.Connection; // violation | |
154 | * import java.util.List; | |
155 | * import java.util.Enumeration; | |
156 | * import java.util.Arrays; | |
157 | * import java.util.Date; // violation | |
158 | * import sun.applet.*; | |
159 | * | |
160 | * public class InputIllegalImport { } | |
161 | * </pre> | |
162 | * <p> | |
163 | * To configure the check so that it rejects packages not satisfying to regular | |
164 | * expression {@code java\.util}: | |
165 | * </p> | |
166 | * <pre> | |
167 | * <module name="IllegalImport"> | |
168 | * <property name="regexp" value="true"/> | |
169 | * <property name="illegalPkgs" value="java\.util"/> | |
170 | * </module> | |
171 | * </pre> | |
172 | * <p> | |
173 | * The following example shows class with no illegal imports | |
174 | * </p> | |
175 | * <pre> | |
176 | * import java.io.*; | |
177 | * import java.lang.ArithmeticException; | |
178 | * import java.sql.Connection; | |
179 | * import sun.applet.*; | |
180 | * | |
181 | * public class InputIllegalImport { } | |
182 | * </pre> | |
183 | * <p> | |
184 | * The following example shows class with four illegal imports | |
185 | * </p> | |
186 | * <ul> | |
187 | * <li> | |
188 | * <b>java.util.List</b> | |
189 | * </li> | |
190 | * <li> | |
191 | * <b>java.util.Enumeration</b> | |
192 | * </li> | |
193 | * <li> | |
194 | * <b>java.util.Arrays</b> | |
195 | * </li> | |
196 | * <li> | |
197 | * <b>java.util.Date</b> | |
198 | * </li> | |
199 | * </ul> | |
200 | * <p> | |
201 | * All four imports match "java\.util" regular expression | |
202 | * </p> | |
203 | * <pre> | |
204 | * import java.io.*; | |
205 | * import java.lang.ArithmeticException; | |
206 | * import java.sql.Connection; | |
207 | * import java.util.List; // violation | |
208 | * import java.util.Enumeration; // violation | |
209 | * import java.util.Arrays; // violation | |
210 | * import java.util.Date; // violation | |
211 | * import sun.applet.*; | |
212 | * | |
213 | * public class InputIllegalImport { } | |
214 | * </pre> | |
215 | * <p> | |
216 | * To configure the check so that it rejects class names not satisfying to regular | |
217 | * expression {@code ^java\.util\.(List|Arrays)} and {@code ^java\.sql\.Connection}: | |
218 | * </p> | |
219 | * <pre> | |
220 | * <module name="IllegalImport"> | |
221 | * <property name="regexp" value="true"/> | |
222 | * <property name="illegalClasses" | |
223 | * value="^java\.util\.(List|Arrays), ^java\.sql\.Connection"/> | |
224 | * </module> | |
225 | * </pre> | |
226 | * <p> | |
227 | * The following example shows class with no illegal imports | |
228 | * </p> | |
229 | * <pre> | |
230 | * import java.io.*; | |
231 | * import java.lang.ArithmeticException; | |
232 | * import java.util.Enumeration; | |
233 | * import java.util.Date; | |
234 | * import sun.applet.*; | |
235 | * | |
236 | * public class InputIllegalImport { } | |
237 | * </pre> | |
238 | * <p> | |
239 | * The following example shows class with three illegal imports | |
240 | * </p> | |
241 | * <ul> | |
242 | * <li> | |
243 | * <b>java.sql.Connection</b> matches "^java\.sql\.Connection" regular expression | |
244 | * </li> | |
245 | * <li> | |
246 | * <b>java.util.List</b> matches "^java\.util\.(List|Arrays)" regular expression | |
247 | * </li> | |
248 | * <li> | |
249 | * <b>java.util.Arrays</b> matches "^java\.util\.(List|Arrays)" regular expression | |
250 | * </li> | |
251 | * </ul> | |
252 | * <pre> | |
253 | * import java.io.*; | |
254 | * import java.lang.ArithmeticException; | |
255 | * import java.sql.Connection; // violation | |
256 | * import java.util.List; // violation | |
257 | * import java.util.Enumeration; | |
258 | * import java.util.Arrays; // violation | |
259 | * import java.util.Date; | |
260 | * import sun.applet.*; | |
261 | * | |
262 | * public class InputIllegalImport { } | |
263 | * </pre> | |
264 | * <p> | |
265 | * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} | |
266 | * </p> | |
267 | * <p> | |
268 | * Violation Message Keys: | |
269 | * </p> | |
270 | * <ul> | |
271 | * <li> | |
272 | * {@code import.illegal} | |
273 | * </li> | |
274 | * </ul> | |
275 | * | |
276 | * @since 3.0 | |
277 | */ | |
278 | @StatelessCheck | |
279 | public class IllegalImportCheck | |
280 | extends AbstractCheck { | |
281 | ||
282 | /** | |
283 | * A key is pointing to the warning message text in "messages.properties" | |
284 | * file. | |
285 | */ | |
286 | public static final String MSG_KEY = "import.illegal"; | |
287 | ||
288 | /** The compiled regular expressions for packages. */ | |
289 |
1
1. <init> : removed call to java/util/ArrayList::<init> → KILLED |
private final List<Pattern> illegalPkgsRegexps = new ArrayList<>(); |
290 | ||
291 | /** The compiled regular expressions for classes. */ | |
292 |
1
1. <init> : removed call to java/util/ArrayList::<init> → KILLED |
private final List<Pattern> illegalClassesRegexps = new ArrayList<>(); |
293 | ||
294 | /** | |
295 | * Specify packages to reject, if <b>regexp</b> property is not set, checks | |
296 | * if import is the part of package. If <b>regexp</b> property is set, then | |
297 | * list of packages will be interpreted as regular expressions. | |
298 | * Note, all properties for match will be used. | |
299 | */ | |
300 | private String[] illegalPkgs; | |
301 | ||
302 | /** | |
303 | * Specify class names to reject, if <b>regexp</b> property is not set, | |
304 | * checks if import equals class name. If <b>regexp</b> property is set, | |
305 | * then list of class names will be interpreted as regular expressions. | |
306 | * Note, all properties for match will be used. | |
307 | */ | |
308 | private String[] illegalClasses; | |
309 | ||
310 | /** | |
311 | * Control whether the {@code illegalPkgs} and {@code illegalClasses} | |
312 | * should be interpreted as regular expressions. | |
313 | */ | |
314 | private boolean regexp; | |
315 | ||
316 | /** | |
317 | * Creates a new {@code IllegalImportCheck} instance. | |
318 | */ | |
319 | public IllegalImportCheck() { | |
320 |
1
1. <init> : removed call to com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck::setIllegalPkgs → KILLED |
setIllegalPkgs("sun"); |
321 | } | |
322 | ||
323 | /** | |
324 | * Setter to specify packages to reject, if <b>regexp</b> property is not set, | |
325 | * checks if import is the part of package. If <b>regexp</b> property is set, | |
326 | * then list of packages will be interpreted as regular expressions. | |
327 | * Note, all properties for match will be used. | |
328 | * | |
329 | * @param from array of illegal packages | |
330 | * @noinspection WeakerAccess | |
331 | */ | |
332 | public final void setIllegalPkgs(String... from) { | |
333 | illegalPkgs = from.clone(); | |
334 |
1
1. setIllegalPkgs : removed call to java/util/List::clear → KILLED |
illegalPkgsRegexps.clear(); |
335 | for (String illegalPkg : illegalPkgs) { | |
336 |
1
1. setIllegalPkgs : removed call to java/lang/StringBuilder::<init> → KILLED |
illegalPkgsRegexps.add(CommonUtil.createPattern("^" + illegalPkg + "\\..*")); |
337 | } | |
338 | } | |
339 | ||
340 | /** | |
341 | * Setter to specify class names to reject, if <b>regexp</b> property is not | |
342 | * set, checks if import equals class name. If <b>regexp</b> property is set, | |
343 | * then list of class names will be interpreted as regular expressions. | |
344 | * Note, all properties for match will be used. | |
345 | * | |
346 | * @param from array of illegal classes | |
347 | */ | |
348 | public void setIllegalClasses(String... from) { | |
349 | illegalClasses = from.clone(); | |
350 | for (String illegalClass : illegalClasses) { | |
351 | illegalClassesRegexps.add(CommonUtil.createPattern(illegalClass)); | |
352 | } | |
353 | } | |
354 | ||
355 | /** | |
356 | * Setter to control whether the {@code illegalPkgs} and {@code illegalClasses} | |
357 | * should be interpreted as regular expressions. | |
358 | * | |
359 | * @param regexp a {@code Boolean} value | |
360 | */ | |
361 | public void setRegexp(boolean regexp) { | |
362 | this.regexp = regexp; | |
363 | } | |
364 | ||
365 | @Override | |
366 | public int[] getDefaultTokens() { | |
367 |
1
1. getDefaultTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return getRequiredTokens(); |
368 | } | |
369 | ||
370 | @Override | |
371 | public int[] getAcceptableTokens() { | |
372 |
1
1. getAcceptableTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck::getAcceptableTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return getRequiredTokens(); |
373 | } | |
374 | ||
375 | @Override | |
376 | public int[] getRequiredTokens() { | |
377 |
1
1. getRequiredTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return new int[] {TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT}; |
378 | } | |
379 | ||
380 | @Override | |
381 | public void visitToken(DetailAST ast) { | |
382 | final FullIdent imp; | |
383 |
3
1. visitToken : negated conditional → KILLED 2. visitToken : removed conditional - replaced equality check with false → KILLED 3. visitToken : removed conditional - replaced equality check with true → KILLED |
if (ast.getType() == TokenTypes.IMPORT) { |
384 | imp = FullIdent.createFullIdentBelow(ast); | |
385 | } | |
386 | else { | |
387 | imp = FullIdent.createFullIdent( | |
388 | ast.getFirstChild().getNextSibling()); | |
389 | } | |
390 |
3
1. visitToken : negated conditional → KILLED 2. visitToken : removed conditional - replaced equality check with false → KILLED 3. visitToken : removed conditional - replaced equality check with true → KILLED |
if (isIllegalImport(imp.getText())) { |
391 |
1
1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck::log → KILLED |
log(ast, |
392 | MSG_KEY, | |
393 | imp.getText()); | |
394 | } | |
395 | } | |
396 | ||
397 | /** | |
398 | * Checks if an import matches one of the regular expressions | |
399 | * for illegal packages or illegal class names. | |
400 | * | |
401 | * @param importText the argument of the import keyword | |
402 | * @return if {@code importText} matches one of the regular expressions | |
403 | * for illegal packages or illegal class names | |
404 | */ | |
405 | private boolean isIllegalImportByRegularExpressions(String importText) { | |
406 | boolean result = false; | |
407 | for (Pattern pattern : illegalPkgsRegexps) { | |
408 |
3
1. isIllegalImportByRegularExpressions : negated conditional → KILLED 2. isIllegalImportByRegularExpressions : removed conditional - replaced equality check with false → KILLED 3. isIllegalImportByRegularExpressions : removed conditional - replaced equality check with true → KILLED |
if (pattern.matcher(importText).matches()) { |
409 | result = true; | |
410 | break; | |
411 | } | |
412 | } | |
413 | for (Pattern pattern : illegalClassesRegexps) { | |
414 |
3
1. isIllegalImportByRegularExpressions : negated conditional → KILLED 2. isIllegalImportByRegularExpressions : removed conditional - replaced equality check with false → KILLED 3. isIllegalImportByRegularExpressions : removed conditional - replaced equality check with true → KILLED |
if (pattern.matcher(importText).matches()) { |
415 | result = true; | |
416 | break; | |
417 | } | |
418 | } | |
419 |
3
1. isIllegalImportByRegularExpressions : replaced boolean return with false for com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck::isIllegalImportByRegularExpressions → KILLED 2. isIllegalImportByRegularExpressions : replaced boolean return with true for com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck::isIllegalImportByRegularExpressions → KILLED 3. isIllegalImportByRegularExpressions : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return result; |
420 | } | |
421 | ||
422 | /** | |
423 | * Checks if an import is from a package or class name that must not be used. | |
424 | * | |
425 | * @param importText the argument of the import keyword | |
426 | * @return if {@code importText} contains an illegal package prefix or equals illegal class name | |
427 | */ | |
428 | private boolean isIllegalImportByPackagesAndClassNames(String importText) { | |
429 | boolean result = false; | |
430 | for (String element : illegalPkgs) { | |
431 |
4
1. isIllegalImportByPackagesAndClassNames : removed call to java/lang/StringBuilder::<init> → KILLED 2. isIllegalImportByPackagesAndClassNames : negated conditional → KILLED 3. isIllegalImportByPackagesAndClassNames : removed conditional - replaced equality check with false → KILLED 4. isIllegalImportByPackagesAndClassNames : removed conditional - replaced equality check with true → KILLED |
if (importText.startsWith(element + ".")) { |
432 | result = true; | |
433 | break; | |
434 | } | |
435 | } | |
436 |
3
1. isIllegalImportByPackagesAndClassNames : negated conditional → KILLED 2. isIllegalImportByPackagesAndClassNames : removed conditional - replaced equality check with false → KILLED 3. isIllegalImportByPackagesAndClassNames : removed conditional - replaced equality check with true → KILLED |
if (illegalClasses != null) { |
437 | for (String element : illegalClasses) { | |
438 |
3
1. isIllegalImportByPackagesAndClassNames : negated conditional → KILLED 2. isIllegalImportByPackagesAndClassNames : removed conditional - replaced equality check with false → KILLED 3. isIllegalImportByPackagesAndClassNames : removed conditional - replaced equality check with true → KILLED |
if (importText.equals(element)) { |
439 | result = true; | |
440 | break; | |
441 | } | |
442 | } | |
443 | } | |
444 |
3
1. isIllegalImportByPackagesAndClassNames : replaced boolean return with false for com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck::isIllegalImportByPackagesAndClassNames → KILLED 2. isIllegalImportByPackagesAndClassNames : replaced boolean return with true for com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck::isIllegalImportByPackagesAndClassNames → KILLED 3. isIllegalImportByPackagesAndClassNames : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return result; |
445 | } | |
446 | ||
447 | /** | |
448 | * Checks if an import is from a package or class name that must not be used. | |
449 | * | |
450 | * @param importText the argument of the import keyword | |
451 | * @return if {@code importText} is illegal import | |
452 | */ | |
453 | private boolean isIllegalImport(String importText) { | |
454 | final boolean result; | |
455 |
3
1. isIllegalImport : negated conditional → KILLED 2. isIllegalImport : removed conditional - replaced equality check with false → KILLED 3. isIllegalImport : removed conditional - replaced equality check with true → KILLED |
if (regexp) { |
456 | result = isIllegalImportByRegularExpressions(importText); | |
457 | } | |
458 | else { | |
459 | result = isIllegalImportByPackagesAndClassNames(importText); | |
460 | } | |
461 |
3
1. isIllegalImport : replaced boolean return with false for com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck::isIllegalImport → KILLED 2. isIllegalImport : replaced boolean return with true for com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck::isIllegalImport → KILLED 3. isIllegalImport : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return result; |
462 | } | |
463 | ||
464 | } | |
Mutations | ||
289 |
1.1 |
|
292 |
1.1 |
|
320 |
1.1 |
|
334 |
1.1 |
|
336 |
1.1 |
|
367 |
1.1 |
|
372 |
1.1 |
|
377 |
1.1 |
|
383 |
1.1 2.2 3.3 |
|
390 |
1.1 2.2 3.3 |
|
391 |
1.1 |
|
408 |
1.1 2.2 3.3 |
|
414 |
1.1 2.2 3.3 |
|
419 |
1.1 2.2 3.3 |
|
431 |
1.1 2.2 3.3 4.4 |
|
436 |
1.1 2.2 3.3 |
|
438 |
1.1 2.2 3.3 |
|
444 |
1.1 2.2 3.3 |
|
455 |
1.1 2.2 3.3 |
|
461 |
1.1 2.2 3.3 |