1 | //////////////////////////////////////////////////////////////////////////////// | |
2 | // checkstyle: Checks Java source code for adherence to a set of rules. | |
3 | // Copyright (C) 2001-2020 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 | * Default value is {@code sun}. | |
51 | * </li> | |
52 | * <li> | |
53 | * Property {@code illegalClasses} - Specify class names to reject, if <b>regexp</b> | |
54 | * property is not set, checks if import equals class name. If <b>regexp</b> | |
55 | * property is set, then list of class names will be interpreted as regular expressions. | |
56 | * Note, all properties for match will be used. | |
57 | * Default value is {@code {}}. | |
58 | * </li> | |
59 | * <li> | |
60 | * Property {@code regexp} - Control whether the {@code illegalPkgs} and | |
61 | * {@code illegalClasses} should be interpreted as regular expressions. | |
62 | * Default value is {@code false}. | |
63 | * </li> | |
64 | * </ul> | |
65 | * <p> | |
66 | * To configure the check: | |
67 | * </p> | |
68 | * <pre> | |
69 | * <module name="IllegalImport"/> | |
70 | * </pre> | |
71 | * <p> | |
72 | * To configure the check so that it rejects packages {@code java.io.*} and {@code java.sql.*}: | |
73 | * </p> | |
74 | * <pre> | |
75 | * <module name="IllegalImport"> | |
76 | * <property name="illegalPkgs" value="java.io, java.sql"/> | |
77 | * </module> | |
78 | * </pre> | |
79 | * <p> | |
80 | * The following example shows class with no illegal imports | |
81 | * </p> | |
82 | * <pre> | |
83 | * import java.lang.ArithmeticException; | |
84 | * import java.util.List; | |
85 | * import java.util.Enumeration; | |
86 | * import java.util.Arrays; | |
87 | * import sun.applet.*; | |
88 | * | |
89 | * public class InputIllegalImport { } | |
90 | * </pre> | |
91 | * <p> | |
92 | * The following example shows class with two illegal imports | |
93 | * </p> | |
94 | * <ul> | |
95 | * <li> | |
96 | * <b>java.io.*</b>, illegalPkgs property contains this package | |
97 | * </li> | |
98 | * <li> | |
99 | * <b>java.sql.Connection</b> is inside java.sql package | |
100 | * </li> | |
101 | * </ul> | |
102 | * <pre> | |
103 | * import java.io.*; // violation | |
104 | * import java.lang.ArithmeticException; | |
105 | * import java.sql.Connection; // violation | |
106 | * import java.util.List; | |
107 | * import java.util.Enumeration; | |
108 | * import java.util.Arrays; | |
109 | * import sun.applet.*; | |
110 | * | |
111 | * public class InputIllegalImport { } | |
112 | * </pre> | |
113 | * <p> | |
114 | * To configure the check so that it rejects classes {@code java.util.Date} and | |
115 | * {@code java.sql.Connection}: | |
116 | * </p> | |
117 | * <pre> | |
118 | * <module name="IllegalImport"> | |
119 | * <property name="illegalClasses" | |
120 | * value="java.util.Date, java.sql.Connection"/> | |
121 | * </module> | |
122 | * </pre> | |
123 | * <p> | |
124 | * The following example shows class with no illegal imports | |
125 | * </p> | |
126 | * <pre> | |
127 | * import java.io.*; | |
128 | * import java.lang.ArithmeticException; | |
129 | * import java.util.List; | |
130 | * import java.util.Enumeration; | |
131 | * import java.util.Arrays; | |
132 | * import sun.applet.*; | |
133 | * | |
134 | * public class InputIllegalImport { } | |
135 | * </pre> | |
136 | * <p> | |
137 | * The following example shows class with two illegal imports | |
138 | * </p> | |
139 | * <ul> | |
140 | * <li> | |
141 | * <b>java.sql.Connection</b>, illegalClasses property contains this class | |
142 | * </li> | |
143 | * <li> | |
144 | * <b>java.util.Date</b>, illegalClasses property contains this class | |
145 | * </li> | |
146 | * </ul> | |
147 | * <pre> | |
148 | * import java.io.*; | |
149 | * import java.lang.ArithmeticException; | |
150 | * import java.sql.Connection; // violation | |
151 | * import java.util.List; | |
152 | * import java.util.Enumeration; | |
153 | * import java.util.Arrays; | |
154 | * import java.util.Date; // violation | |
155 | * import sun.applet.*; | |
156 | * | |
157 | * public class InputIllegalImport { } | |
158 | * </pre> | |
159 | * <p> | |
160 | * To configure the check so that it rejects packages not satisfying to regular | |
161 | * expression {@code java\.util}: | |
162 | * </p> | |
163 | * <pre> | |
164 | * <module name="IllegalImport"> | |
165 | * <property name="regexp" value="true"/> | |
166 | * <property name="illegalPkgs" value="java\.util"/> | |
167 | * </module> | |
168 | * </pre> | |
169 | * <p> | |
170 | * The following example shows class with no illegal imports | |
171 | * </p> | |
172 | * <pre> | |
173 | * import java.io.*; | |
174 | * import java.lang.ArithmeticException; | |
175 | * import java.sql.Connection; | |
176 | * import sun.applet.*; | |
177 | * | |
178 | * public class InputIllegalImport { } | |
179 | * </pre> | |
180 | * <p> | |
181 | * The following example shows class with four illegal imports | |
182 | * </p> | |
183 | * <ul> | |
184 | * <li> | |
185 | * <b>java.util.List</b> | |
186 | * </li> | |
187 | * <li> | |
188 | * <b>java.util.Enumeration</b> | |
189 | * </li> | |
190 | * <li> | |
191 | * <b>java.util.Arrays</b> | |
192 | * </li> | |
193 | * <li> | |
194 | * <b>java.util.Date</b> | |
195 | * </li> | |
196 | * </ul> | |
197 | * <p> | |
198 | * All four imports match "java\.util" regular expression | |
199 | * </p> | |
200 | * <pre> | |
201 | * import java.io.*; | |
202 | * import java.lang.ArithmeticException; | |
203 | * import java.sql.Connection; | |
204 | * import java.util.List; // violation | |
205 | * import java.util.Enumeration; // violation | |
206 | * import java.util.Arrays; // violation | |
207 | * import java.util.Date; // violation | |
208 | * import sun.applet.*; | |
209 | * | |
210 | * public class InputIllegalImport { } | |
211 | * </pre> | |
212 | * <p> | |
213 | * To configure the check so that it rejects class names not satisfying to regular | |
214 | * expression {@code ^java\.util\.(List|Arrays)} and {@code ^java\.sql\.Connection}: | |
215 | * </p> | |
216 | * <pre> | |
217 | * <module name="IllegalImport"> | |
218 | * <property name="regexp" value="true"/> | |
219 | * <property name="illegalClasses" | |
220 | * value="^java\.util\.(List|Arrays), ^java\.sql\.Connection"/> | |
221 | * </module> | |
222 | * </pre> | |
223 | * <p> | |
224 | * The following example shows class with no illegal imports | |
225 | * </p> | |
226 | * <pre> | |
227 | * import java.io.*; | |
228 | * import java.lang.ArithmeticException; | |
229 | * import java.util.Enumeration; | |
230 | * import java.util.Date; | |
231 | * import sun.applet.*; | |
232 | * | |
233 | * public class InputIllegalImport { } | |
234 | * </pre> | |
235 | * <p> | |
236 | * The following example shows class with three illegal imports | |
237 | * </p> | |
238 | * <ul> | |
239 | * <li> | |
240 | * <b>java.sql.Connection</b> matches "^java\.sql\.Connection" regular expression | |
241 | * </li> | |
242 | * <li> | |
243 | * <b>java.util.List</b> matches "^java\.util\.(List|Arrays)" regular expression | |
244 | * </li> | |
245 | * <li> | |
246 | * <b>java.util.Arrays</b> matches "^java\.util\.(List|Arrays)" regular expression | |
247 | * </li> | |
248 | * </ul> | |
249 | * <pre> | |
250 | * import java.io.*; | |
251 | * import java.lang.ArithmeticException; | |
252 | * import java.sql.Connection; // violation | |
253 | * import java.util.List; // violation | |
254 | * import java.util.Enumeration; | |
255 | * import java.util.Arrays; // violation | |
256 | * import java.util.Date; | |
257 | * import sun.applet.*; | |
258 | * | |
259 | * public class InputIllegalImport { } | |
260 | * </pre> | |
261 | * | |
262 | * @since 3.0 | |
263 | */ | |
264 | @StatelessCheck | |
265 | public class IllegalImportCheck | |
266 | extends AbstractCheck { | |
267 | ||
268 | /** | |
269 | * A key is pointing to the warning message text in "messages.properties" | |
270 | * file. | |
271 | */ | |
272 | public static final String MSG_KEY = "import.illegal"; | |
273 | ||
274 | /** The compiled regular expressions for packages. */ | |
275 |
1
1. |
private final List<Pattern> illegalPkgsRegexps = new ArrayList<>(); |
276 | ||
277 | /** The compiled regular expressions for classes. */ | |
278 |
1
1. |
private final List<Pattern> illegalClassesRegexps = new ArrayList<>(); |
279 | ||
280 | /** | |
281 | * Specify packages to reject, if <b>regexp</b> property is not set, checks | |
282 | * if import is the part of package. If <b>regexp</b> property is set, then | |
283 | * list of packages will be interpreted as regular expressions. | |
284 | * Note, all properties for match will be used. | |
285 | */ | |
286 | private String[] illegalPkgs; | |
287 | ||
288 | /** | |
289 | * Specify class names to reject, if <b>regexp</b> property is not set, | |
290 | * checks if import equals class name. If <b>regexp</b> property is set, | |
291 | * then list of class names will be interpreted as regular expressions. | |
292 | * Note, all properties for match will be used. | |
293 | */ | |
294 | private String[] illegalClasses; | |
295 | ||
296 | /** | |
297 | * Control whether the {@code illegalPkgs} and {@code illegalClasses} | |
298 | * should be interpreted as regular expressions. | |
299 | */ | |
300 | private boolean regexp; | |
301 | ||
302 | /** | |
303 | * Creates a new {@code IllegalImportCheck} instance. | |
304 | */ | |
305 | public IllegalImportCheck() { | |
306 |
1
1. |
setIllegalPkgs("sun"); |
307 | } | |
308 | ||
309 | /** | |
310 | * Setter to specify packages to reject, if <b>regexp</b> property is not set, | |
311 | * checks if import is the part of package. If <b>regexp</b> property is set, | |
312 | * then list of packages will be interpreted as regular expressions. | |
313 | * Note, all properties for match will be used. | |
314 | * | |
315 | * @param from array of illegal packages | |
316 | * @noinspection WeakerAccess | |
317 | */ | |
318 | public final void setIllegalPkgs(String... from) { | |
319 | illegalPkgs = from.clone(); | |
320 |
1
1. setIllegalPkgs : removed call to java/util/List::clear → KILLED |
illegalPkgsRegexps.clear(); |
321 | for (String illegalPkg : illegalPkgs) { | |
322 |
1
1. setIllegalPkgs : removed call to java/lang/StringBuilder::<init> → KILLED |
illegalPkgsRegexps.add(CommonUtil.createPattern("^" + illegalPkg + "\\..*")); |
323 | } | |
324 | } | |
325 | ||
326 | /** | |
327 | * Setter to specify class names to reject, if <b>regexp</b> property is not | |
328 | * set, checks if import equals class name. If <b>regexp</b> property is set, | |
329 | * then list of class names will be interpreted as regular expressions. | |
330 | * Note, all properties for match will be used. | |
331 | * | |
332 | * @param from array of illegal classes | |
333 | */ | |
334 | public void setIllegalClasses(String... from) { | |
335 | illegalClasses = from.clone(); | |
336 | for (String illegalClass : illegalClasses) { | |
337 | illegalClassesRegexps.add(CommonUtil.createPattern(illegalClass)); | |
338 | } | |
339 | } | |
340 | ||
341 | /** | |
342 | * Setter to control whether the {@code illegalPkgs} and {@code illegalClasses} | |
343 | * should be interpreted as regular expressions. | |
344 | * | |
345 | * @param regexp a {@code Boolean} value | |
346 | */ | |
347 | public void setRegexp(boolean regexp) { | |
348 | this.regexp = regexp; | |
349 | } | |
350 | ||
351 | @Override | |
352 | public int[] getDefaultTokens() { | |
353 |
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(); |
354 | } | |
355 | ||
356 | @Override | |
357 | public int[] getAcceptableTokens() { | |
358 |
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(); |
359 | } | |
360 | ||
361 | @Override | |
362 | public int[] getRequiredTokens() { | |
363 |
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}; |
364 | } | |
365 | ||
366 | @Override | |
367 | public void visitToken(DetailAST ast) { | |
368 | final FullIdent imp; | |
369 |
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) { |
370 | imp = FullIdent.createFullIdentBelow(ast); | |
371 | } | |
372 | else { | |
373 | imp = FullIdent.createFullIdent( | |
374 | ast.getFirstChild().getNextSibling()); | |
375 | } | |
376 |
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())) { |
377 |
1
1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck::log → KILLED |
log(ast, |
378 | MSG_KEY, | |
379 | imp.getText()); | |
380 | } | |
381 | } | |
382 | ||
383 | /** | |
384 | * Checks if an import matches one of the regular expressions | |
385 | * for illegal packages or illegal class names. | |
386 | * @param importText the argument of the import keyword | |
387 | * @return if {@code importText} matches one of the regular expressions | |
388 | * for illegal packages or illegal class names | |
389 | */ | |
390 | private boolean isIllegalImportByRegularExpressions(String importText) { | |
391 | boolean result = false; | |
392 | for (Pattern pattern : illegalPkgsRegexps) { | |
393 |
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()) { |
394 | result = true; | |
395 | break; | |
396 | } | |
397 | } | |
398 |
3
1. isIllegalImportByRegularExpressions : removed conditional - replaced equality check with true → SURVIVED 2. isIllegalImportByRegularExpressions : negated conditional → KILLED 3. isIllegalImportByRegularExpressions : removed conditional - replaced equality check with false → KILLED |
if (!result) { |
399 | for (Pattern pattern : illegalClassesRegexps) { | |
400 |
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()) { |
401 | result = true; | |
402 | break; | |
403 | } | |
404 | } | |
405 | } | |
406 |
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; |
407 | } | |
408 | ||
409 | /** | |
410 | * Checks if an import is from a package or class name that must not be used. | |
411 | * @param importText the argument of the import keyword | |
412 | * @return if {@code importText} contains an illegal package prefix or equals illegal class name | |
413 | */ | |
414 | private boolean isIllegalImportByPackagesAndClassNames(String importText) { | |
415 | boolean result = false; | |
416 | for (String element : illegalPkgs) { | |
417 |
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 + ".")) { |
418 | result = true; | |
419 | break; | |
420 | } | |
421 | } | |
422 |
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) { |
423 | for (String element : illegalClasses) { | |
424 |
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)) { |
425 | result = true; | |
426 | break; | |
427 | } | |
428 | } | |
429 | } | |
430 |
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; |
431 | } | |
432 | ||
433 | /** | |
434 | * Checks if an import is from a package or class name that must not be used. | |
435 | * @param importText the argument of the import keyword | |
436 | * @return if {@code importText} is illegal import | |
437 | */ | |
438 | private boolean isIllegalImport(String importText) { | |
439 | final boolean result; | |
440 |
3
1. isIllegalImport : removed conditional - replaced equality check with true → SURVIVED 2. isIllegalImport : negated conditional → KILLED 3. isIllegalImport : removed conditional - replaced equality check with false → KILLED |
if (regexp) { |
441 | result = isIllegalImportByRegularExpressions(importText); | |
442 | } | |
443 | else { | |
444 | result = isIllegalImportByPackagesAndClassNames(importText); | |
445 | } | |
446 |
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; |
447 | } | |
448 | ||
449 | } | |
Mutations | ||
275 |
1.1 |
|
278 |
1.1 |
|
306 |
1.1 |
|
320 |
1.1 |
|
322 |
1.1 |
|
353 |
1.1 |
|
358 |
1.1 |
|
363 |
1.1 |
|
369 |
1.1 2.2 3.3 |
|
376 |
1.1 2.2 3.3 |
|
377 |
1.1 |
|
393 |
1.1 2.2 3.3 |
|
398 |
1.1 2.2 3.3 |
|
400 |
1.1 2.2 3.3 |
|
406 |
1.1 2.2 3.3 |
|
417 |
1.1 2.2 3.3 4.4 |
|
422 |
1.1 2.2 3.3 |
|
424 |
1.1 2.2 3.3 |
|
430 |
1.1 2.2 3.3 |
|
440 |
1.1 2.2 3.3 |
|
446 |
1.1 2.2 3.3 |