ImportControlCheck.java

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.net.URI;
23
import java.util.Collections;
24
import java.util.Set;
25
import java.util.regex.Pattern;
26
27
import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
28
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
29
import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
30
import com.puppycrawl.tools.checkstyle.api.DetailAST;
31
import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder;
32
import com.puppycrawl.tools.checkstyle.api.FullIdent;
33
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
34
35
/**
36
 * <p>
37
 * Controls what can be imported in each package and file. Useful for ensuring
38
 * that application layering rules are not violated, especially on large projects.
39
 * </p>
40
 * <p>
41
 * You can control imports based on the a package name or based on the file name.
42
 * When controlling packages, all files and sub-packages in the declared package
43
 * will be controlled by this check. To specify differences between a main package
44
 * and a sub-package, you must define the sub-package inside the main package.
45
 * When controlling file, only the file name is considered and only files processed by
46
 * <a href="https://checkstyle.org/config.html#TreeWalker">TreeWalker</a>.
47
 * The file's extension is ignored.
48
 * </p>
49
 * <p>
50
 * Short description of the behaviour:
51
 * </p>
52
 * <ul>
53
 * <li>
54
 * Check starts checking from the longest matching subpackage (later 'current subpackage') or
55
 * the first file name match described inside import control file to package defined in class file.
56
 * <ul>
57
 * <li>
58
 * The longest matching subpackage is found by starting with the root package and
59
 * examining if the any of the sub-packages or file definitions match the current
60
 * class' package or file name.
61
 * </li>
62
 * <li>
63
 * If a file name is matched first, that is considered the longest match and becomes
64
 * the current file/subpackage.
65
 * </li>
66
 * <li>
67
 * If another subpackage is matched, then it's subpackages and file names are examined
68
 * for the next longest match and the process repeats recursively.
69
 * </li>
70
 * <li>
71
 * If no subpackages or file names are matched, the current subpackage is then used.
72
 * </li>
73
 * </ul>
74
 * </li>
75
 * <li>
76
 * Order of rules in the same subpackage/root are defined by the order of declaration
77
 * in the XML file, which is from top (first) to bottom (last).
78
 * </li>
79
 * <li>
80
 * If there is matching allow/disallow rule inside the current file/subpackage
81
 * then the Check returns the first "allowed" or "disallowed" message.
82
 * </li>
83
 * <li>
84
 * If there is no matching allow/disallow rule inside the current file/subpackage
85
 * then it continues checking in the parent subpackage.
86
 * </li>
87
 * <li>
88
 * If there is no matching allow/disallow rule in any of the files/subpackages,
89
 * including the root level (import-control), then the import is disallowed by default.
90
 * </li>
91
 * </ul>
92
 * <p>
93
 * The DTD for a import control XML document is at
94
 * <a href="https://checkstyle.org/dtds/import_control_1_4.dtd">
95
 * https://checkstyle.org/dtds/import_control_1_4.dtd</a>.
96
 * It contains documentation on each of the elements and attributes.
97
 * </p>
98
 * <p>
99
 * The check validates a XML document when it loads the document. To validate against
100
 * the above DTD, include the following document type declaration in your XML document:
101
 * </p>
102
 * <pre>
103
 * &lt;!DOCTYPE import-control PUBLIC
104
 *     "-//Checkstyle//DTD ImportControl Configuration 1.4//EN"
105
 *     "https://checkstyle.org/dtds/import_control_1_4.dtd"&gt;
106
 * </pre>
107
 * <ul>
108
 * <li>
109
 * Property {@code file} - Specify the location of the file containing the
110
 * import control configuration. It can be a regular file, URL or resource path.
111
 * It will try loading the path as a URL first, then as a file, and finally as a resource.
112
 * Type is {@code java.net.URI}.
113
 * Default value is {@code null}.
114
 * </li>
115
 * <li>
116
 * Property {@code path} - Specify the regular expression of file paths to which
117
 * this check should apply. Files that don't match the pattern will not be checked.
118
 * The pattern will be matched against the full absolute file path.
119
 * Type is {@code java.util.regex.Pattern}.
120
 * Default value is {@code ".*"}.
121
 * </li>
122
 * </ul>
123
 * <p>
124
 * To configure the check using an import control file called "config/import-control.xml",
125
 * then have the following:
126
 * </p>
127
 * <pre>
128
 * &lt;module name="ImportControl"&gt;
129
 *   &lt;property name="file" value="config/import-control.xml"/&gt;
130
 * &lt;/module&gt;
131
 * </pre>
132
 * <p>
133
 * To configure the check to only check the "src/main" directory using an import
134
 * control file called "config/import-control.xml", then have the following:
135
 * </p>
136
 * <pre>
137
 * &lt;module name="ImportControl"&gt;
138
 *   &lt;property name="file" value="config/import-control.xml"/&gt;
139
 *   &lt;property name="path" value="^.*[\\/]src[\\/]main[\\/].*$"/&gt;
140
 * &lt;/module&gt;
141
 * </pre>
142
 * <p>
143
 * In the example below access to package {@code com.puppycrawl.tools.checkstyle.checks}
144
 * and its subpackages is allowed from anywhere in {@code com.puppycrawl.tools.checkstyle}
145
 * except from the {@code filters} subpackage where access to all {@code check}'s
146
 * subpackages is disallowed. Two {@code java.lang.ref} classes are allowed by virtue
147
 * of one regular expression instead of listing them in two separate allow rules
148
 * (as it is done with the {@code Files} and {@code ClassPath} classes).
149
 * </p>
150
 * <pre>
151
 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle"&gt;
152
 *   &lt;disallow pkg="sun"/&gt;
153
 *   &lt;allow pkg="com.puppycrawl.tools.checkstyle.api"/&gt;
154
 *   &lt;allow pkg="com.puppycrawl.tools.checkstyle.checks"/&gt;
155
 *   &lt;allow class="com.google.common.io.Files"/&gt;
156
 *   &lt;allow class="com.google.common.reflect.ClassPath"/&gt;
157
 *   &lt;subpackage name="filters"&gt;
158
 *     &lt;allow class="java\.lang\.ref\.(Weak|Soft)Reference"
159
 *       regex="true"/&gt;
160
 *     &lt;disallow pkg="com\.puppycrawl\.tools\.checkstyle\.checks\.[^.]+"
161
 *       regex="true"/&gt;
162
 *     &lt;disallow pkg="com.puppycrawl.tools.checkstyle.ant"/&gt;
163
 *     &lt;disallow pkg="com.puppycrawl.tools.checkstyle.gui"/&gt;
164
 *   &lt;/subpackage&gt;
165
 *   &lt;subpackage name="dao"&gt;
166
 *     &lt;disallow pkg="javax.swing" exact-match="true"/&gt;
167
 *   &lt;/subpackage&gt;
168
 * &lt;/import-control&gt;
169
 * </pre>
170
 * <p>
171
 * In the next example regular expressions are used to enforce a layering rule:
172
 * In all {@code dao} packages it is not allowed to access UI layer code ({@code ui},
173
 * {@code awt}, and {@code swing}). On the other hand it is not allowed to directly
174
 * access {@code dao} and {@code service} layer from {@code ui} packages.
175
 * The root package is also a regular expression that is used to handle old and
176
 * new domain name with the same rules.
177
 * </p>
178
 * <pre>
179
 * &lt;import-control pkg="(de.olddomain|de.newdomain)\..*" regex="true"&gt;
180
 *   &lt;subpackage pkg="[^.]+\.dao" regex="true"&gt;
181
 *     &lt;disallow pkg=".*\.ui" regex="true"/&gt;
182
 *     &lt;disallow pkg=".*\.(awt|swing).\.*" regex="true"/&gt;
183
 *   &lt;/subpackage&gt;
184
 *   &lt;subpackage pkg="[^.]+\.ui" regex="true"&gt;
185
 *     &lt;disallow pkg=".*\.(dao|service)" regex="true"/&gt;
186
 *   &lt;/subpackage&gt;
187
 * &lt;/import-control&gt;
188
 * </pre>
189
 * <p>
190
 * In the next examples usage of {@code strategyOnMismatch} property is shown.
191
 * This property defines strategy in a case when no matching allow/disallow rule was found.
192
 * Property {@code strategyOnMismatch} is attribute of {@code import-control} and
193
 * {@code subpackage} tags. Property can have following values for {@code import-control} tag:
194
 * </p>
195
 * <ul>
196
 * <li>
197
 * disallowed (default value) - if there is no matching allow/disallow rule in any of
198
 * the subpackages, including the root level (import-control), then the import is disallowed.
199
 * </li>
200
 * <li>
201
 * allowed - if there is no matching allow/disallow rule in any of the subpackages,
202
 * including the root level, then the import is allowed.
203
 * </li>
204
 * </ul>
205
 * <p>
206
 * And following values for {@code subpackage} tags:
207
 * </p>
208
 * <ul>
209
 * <li>
210
 * delegateToParent (default value) - if there is no matching allow/disallow rule
211
 * inside the current subpackage, then it continues checking in the parent subpackage.
212
 * </li>
213
 * <li>
214
 * allowed - if there is no matching allow/disallow rule inside the current subpackage,
215
 * then the import is allowed.
216
 * </li>
217
 * <li>
218
 * disallowed - if there is no matching allow/disallow rule inside the current subpackage,
219
 * then the import is disallowed.
220
 * </li>
221
 * </ul>
222
 * <p>
223
 * The following example demonstrates usage of {@code strategyOnMismatch}
224
 * property for {@code import-control} tag. Here all imports are allowed except
225
 * {@code java.awt.Image} and {@code java.io.File} classes.
226
 * </p>
227
 * <pre>
228
 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle.checks"
229
 *   strategyOnMismatch="allowed"&gt;
230
 *   &lt;disallow class="java.awt.Image"/&gt;
231
 *   &lt;disallow class="java.io.File"/&gt;
232
 * &lt;/import-control&gt;
233
 * </pre>
234
 * <p>
235
 * In the example below, any import is disallowed inside
236
 * {@code com.puppycrawl.tools.checkstyle.checks.imports} package except imports
237
 * from package {@code javax.swing} and class {@code java.io.File}.
238
 * However, any import is allowed in the classes outside of
239
 * {@code com.puppycrawl.tools.checkstyle.checks.imports} package.
240
 * </p>
241
 * <pre>
242
 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle.checks"
243
 *   strategyOnMismatch="allowed"&gt;
244
 *   &lt;subpackage name="imports" strategyOnMismatch="disallowed"&gt;
245
 *     &lt;allow pkg="javax.swing"/&gt;
246
 *     &lt;allow class="java.io.File"/&gt;
247
 *   &lt;/subpackage&gt;
248
 * &lt;/import-control&gt;
249
 * </pre>
250
 * <p>
251
 * When {@code strategyOnMismatch} has {@code allowed} or {@code disallowed}
252
 * value for {@code subpackage} tag, it makes {@code subpackage} isolated from
253
 * parent rules. In the next example, if no matching rule was found inside
254
 * {@code com.puppycrawl.tools.checkstyle.checks.filters} then it continues
255
 * checking in the parent subpackage, while for
256
 * {@code com.puppycrawl.tools.checkstyle.checks.imports} import will be allowed by default.
257
 * </p>
258
 * <pre>
259
 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle.checks"&gt;
260
 *   &lt;allow class="java\.awt\.Image" regex="true"/&gt;
261
 *   &lt;allow class="java\..*\.File" local-only="true" regex="true"/&gt;
262
 *   &lt;subpackage name="imports" strategyOnMismatch="allowed"&gt;
263
 *     &lt;allow pkg="javax\.swing" regex="true"/&gt;
264
 *     &lt;allow pkg="java\.io" exact-match="true"
265
 *       local-only="true" regex="true"/&gt;
266
 *   &lt;/subpackage&gt;
267
 *   &lt;subpackage name="filters"&gt;
268
 *     &lt;allow class="javax.util.Date"/&gt;
269
 *   &lt;/subpackage&gt;
270
 * &lt;/import-control&gt;
271
 * </pre>
272
 * <p>
273
 * In the example below, only file names that end with "Panel", "View", or "Dialog"
274
 * in the package {@code gui} are disallowed to have imports from {@code com.mycompany.dao}
275
 * and any {@code jdbc} package. In addition, only the file name named "PresentationModel"
276
 * in the package {@code gui} are disallowed to have imports that match {@code javax.swing.J*}.
277
 * All other imports in the package are allowed.
278
 * </p>
279
 * <pre>
280
 * &lt;import-control pkg="com.mycompany.billing"&gt;
281
 *   &lt;subpackage name="gui" strategyOnMismatch="allowed"&gt;
282
 *     &lt;file name=".*(Panel|View|Dialog)" regex="true"&gt;
283
 *       &lt;disallow pkg="com.mycompany.dao"/&gt;
284
 *       &lt;disallow pkg=".*\.jdbc" regex="true"/&gt;
285
 *     &lt;/file&gt;
286
 *     &lt;file name="PresentationModel"&gt;
287
 *       &lt;disallow pkg="javax\.swing\.J.*" regex="true"/&gt;
288
 *     &lt;/file&gt;
289
 *   &lt;/subpackage&gt;
290
 * &lt;/import-control&gt;
291
 * </pre>
292
 * <p>
293
 * For a real-life import control file look at the file called
294
 * <a href="https://github.com/checkstyle/checkstyle/blob/master/config/import-control.xml">
295
 * import-control.xml</a> which is part of the Checkstyle distribution.
296
 * </p>
297
 * <p id="blacklist-example">Example of blacklist mode</p>
298
 * <p>
299
 * To have a <b>blacklist mode</b>, it is required to have disallows inside
300
 * subpackage and to have allow rule inside parent of the current subpackage
301
 * to catch classes and packages those are not in the blacklist.
302
 * </p>
303
 * <p>
304
 * In the example below any import from {@code java.util}({@code java.util.List},
305
 * {@code java.util.Date}) package is allowed except {@code java.util.Map}
306
 * inside subpackage {@code com.puppycrawl.tools.checkstyle.filters}.
307
 * </p>
308
 * <pre>
309
 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle"&gt;
310
 *   &lt;allow pkg="java.util"/&gt;
311
 *   &lt;subpackage name="filters" &gt;
312
 *     &lt;disallow class="java.util.Map"/&gt;
313
 *   &lt;/subpackage&gt;
314
 * &lt;/import-control&gt;
315
 * </pre>
316
 * <p>
317
 * In the next example imports {@code java.util.stream.Stream} and
318
 * {@code java.util.stream.Collectors} are disallowed inside
319
 * {@code com.puppycrawl.tools.checkstyle.checks.imports} package, but because of
320
 * {@code &lt;allow pkg="java.util.stream"/&gt;} every import from
321
 * {@code java.util.stream} is allowed except described ones.
322
 * </p>
323
 * <pre>
324
 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle.checks"&gt;
325
 *   &lt;allow pkg="java.util.stream"/&gt;
326
 *   &lt;subpackage name="imports"&gt;
327
 *     &lt;disallow class="java.util.stream.Stream"/&gt;
328
 *     &lt;disallow class="java.util.stream.Collectors"/&gt;
329
 *   &lt;/subpackage&gt;
330
 * &lt;/import-control&gt;
331
 * </pre>
332
 * <pre>
333
 * package com.puppycrawl.tools.checkstyle.checks.imports;
334
 *
335
 * import java.util.stream.Stream;     // violation here
336
 * import java.util.stream.Collectors; // violation here
337
 * import java.util.stream.IntStream;
338
 * </pre>
339
 * <p>
340
 * In the following example, all imports are allowed except the classes
341
 * {@code java.util.Date}, {@code java.util.List} and package {@code sun}.
342
 * </p>
343
 * <pre>
344
 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle.checks"&gt;
345
 *   &lt;allow pkg=".*" regex="true"/&gt;
346
 *   &lt;subpackage name="imports"&gt;
347
 *     &lt;disallow class="java.util.Date"/&gt;
348
 *     &lt;disallow class="java.util.List"/&gt;
349
 *     &lt;disallow pkg="sun"/&gt;
350
 *   &lt;/subpackage&gt;
351
 * &lt;/import-control&gt;
352
 * </pre>
353
 * <p>
354
 * In the following example, all imports of the {@code java.util} package are
355
 * allowed except the {@code java.util.Date} class.
356
 * </p>
357
 * <pre>
358
 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle.checks"&gt;
359
 *   &lt;disallow class="java.util.Date"/&gt;
360
 *
361
 *   &lt;allow pkg="java.util"/&gt;
362
 * &lt;/import-control&gt;
363
 * </pre>
364
 * <p id="regex-notes">Notes on regular expressions</p>
365
 * <p>
366
 * Regular expressions in import rules have to match either Java packages or classes.
367
 * The language rules for packages and class names can be described by the following
368
 * complicated regular expression that takes into account that Java names may contain
369
 * any unicode letter, numbers, underscores, and dollar signs (see section 3.8 in the
370
 * <a href="https://docs.oracle.com/javase/specs/">Java specs</a>):
371
 * </p>
372
 * <ul>
373
 * <li>
374
 * {@code [\p{Letter}_$][\p{Letter}\p{Number}_$]*} or short {@code [\p{L}_$][\p{L}\p{N}_$]*}
375
 * for a class name or package component.
376
 * </li>
377
 * <li>
378
 * {@code ([\p{L}_$][\p{L}\p{N}_$]*\.)*[\p{L}_$][\p{L}\p{N}_$]*} for a fully qualified name.
379
 * </li>
380
 * </ul>
381
 * <p>
382
 * But it is not necessary to use these complicated expressions since no validation is required.
383
 * Differentiating between package separator '.' and others is sufficient.
384
 * Unfortunately '.' has a special meaning in regular expressions so one has to write {@code \.}
385
 * to match an actual dot.
386
 * </p>
387
 * <ul>
388
 * <li>
389
 * Use {@code [^.]+}(one or more "not a dot" characters) for a class name or package component.
390
 * </li>
391
 * <li>
392
 * Use {@code com\.google\.common\.[^.]+} to match any subpackage of {@code com.google.common}.
393
 * </li>
394
 * <li>
395
 * When matching concrete packages like {@code com.google.common} omitting the backslash before
396
 * the dots may improve readability and may be just exact enough: {@code com.google.common\.[^.]+}
397
 * matches not only subpackages of {@code com.google.common} but e.g. also of
398
 * {@code com.googleecommon} but you may not care for that.
399
 * </li>
400
 * <li>
401
 * Do not use {@code .*} unless you really do not care for what is matched.
402
 * Often you want to match only a certain package level instead.
403
 * </li>
404
 * </ul><p id="static-import-notes">Notes on static imports</p>
405
 * <p>
406
 * Static members (including methods, constants and static inner classes)
407
 * have to be explicitly allowed when they are imported, they are not automatically
408
 * allowed along with their enclosing class.
409
 * </p>
410
 * <p>
411
 * For example, to allow importing both {@code java.util.Map} and {@code java.util.Map.Entry}
412
 * use the following configuration:
413
 * </p>
414
 * <pre>
415
 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle"&gt;
416
 *   &lt;allow class="java.util.Map"/&gt;
417
 *   &lt;allow class="java.util.Map.Entry"/&gt;
418
 * &lt;/import-control&gt;
419
 * </pre>
420
 * <p>
421
 * It is also possible to use a regex with a wildcard:
422
 * </p>
423
 * <pre>
424
 * &lt;import-control pkg="com.puppycrawl.tools.checkstyle"&gt;
425
 *   &lt;allow class="java.util.Map"/&gt;
426
 *   &lt;allow class="java.util.Map.*" regex="true" /&gt;
427
 * &lt;/import-control&gt;
428
 * </pre>
429
 * <p>
430
 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
431
 * </p>
432
 * <p>
433
 * Violation Message Keys:
434
 * </p>
435
 * <ul>
436
 * <li>
437
 * {@code import.control.disallowed}
438
 * </li>
439
 * <li>
440
 * {@code import.control.missing.file}
441
 * </li>
442
 * <li>
443
 * {@code import.control.unknown.pkg}
444
 * </li>
445
 * </ul>
446
 *
447
 * @since 4.0
448
 */
449
@FileStatefulCheck
450
public class ImportControlCheck extends AbstractCheck implements ExternalResourceHolder {
451
452
    /**
453
     * A key is pointing to the warning message text in "messages.properties"
454
     * file.
455
     */
456
    public static final String MSG_MISSING_FILE = "import.control.missing.file";
457
458
    /**
459
     * A key is pointing to the warning message text in "messages.properties"
460
     * file.
461
     */
462
    public static final String MSG_UNKNOWN_PKG = "import.control.unknown.pkg";
463
464
    /**
465
     * A key is pointing to the warning message text in "messages.properties"
466
     * file.
467
     */
468
    public static final String MSG_DISALLOWED = "import.control.disallowed";
469
470
    /**
471
     * A part of message for exception.
472
     */
473
    private static final String UNABLE_TO_LOAD = "Unable to load ";
474
475
    /**
476
     * Specify the location of the file containing the import control configuration.
477
     * It can be a regular file, URL or resource path. It will try loading the path
478
     * as a URL first, then as a file, and finally as a resource.
479
     */
480
    private URI file;
481
482
    /**
483
     * Specify the regular expression of file paths to which this check should apply.
484
     * Files that don't match the pattern will not be checked. The pattern will
485
     * be matched against the full absolute file path.
486
     */
487
    private Pattern path = Pattern.compile(".*");
488
    /** Whether to process the current file. */
489
    private boolean processCurrentFile;
490
491
    /** The root package controller. */
492
    private PkgImportControl root;
493
    /** The package doing the import. */
494
    private String packageName;
495
    /** The file name doing the import. */
496
    private String fileName;
497
498
    /**
499
     * The package controller for the current file. Used for performance
500
     * optimisation.
501
     */
502
    private AbstractImportControl currentImportControl;
503
504
    @Override
505
    public int[] getDefaultTokens() {
506 1 1. getDefaultTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return getRequiredTokens();
507
    }
508
509
    @Override
510
    public int[] getAcceptableTokens() {
511 1 1. getAcceptableTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::getAcceptableTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return getRequiredTokens();
512
    }
513
514
    @Override
515
    public int[] getRequiredTokens() {
516 1 1. getRequiredTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return new int[] {TokenTypes.PACKAGE_DEF, TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT, };
517
    }
518
519
    @Override
520
    public void beginTree(DetailAST rootAST) {
521
        currentImportControl = null;
522
        processCurrentFile = path.matcher(getFileContents().getFileName()).find();
523
        fileName = getFileContents().getText().getFile().getName();
524
525
        final int period = fileName.lastIndexOf('.');
526
527 3 1. beginTree : negated conditional → KILLED
2. beginTree : removed conditional - replaced equality check with false → KILLED
3. beginTree : removed conditional - replaced equality check with true → KILLED
        if (period != -1) {
528
            fileName = fileName.substring(0, period);
529
        }
530
    }
531
532
    @Override
533
    public void visitToken(DetailAST ast) {
534 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 (processCurrentFile) {
535 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.PACKAGE_DEF) {
536 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 (root == null) {
537 1 1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::log → KILLED
                    log(ast, MSG_MISSING_FILE);
538
                }
539
                else {
540
                    packageName = getPackageText(ast);
541
                    currentImportControl = root.locateFinest(packageName, fileName);
542 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 (currentImportControl == null) {
543 1 1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::log → KILLED
                        log(ast, MSG_UNKNOWN_PKG);
544
                    }
545
                }
546
            }
547 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
            else if (currentImportControl != null) {
548
                final String importText = getImportText(ast);
549
                final AccessResult access = currentImportControl.checkAccess(packageName, fileName,
550
                        importText);
551 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 (access != AccessResult.ALLOWED) {
552 1 1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::log → KILLED
                    log(ast, MSG_DISALLOWED, importText);
553
                }
554
            }
555
        }
556
    }
557
558
    @Override
559
    public Set<String> getExternalResourceLocations() {
560 1 1. getExternalResourceLocations : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::getExternalResourceLocations to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return Collections.singleton(file.toString());
561
    }
562
563
    /**
564
     * Returns package text.
565
     *
566
     * @param ast PACKAGE_DEF ast node
567
     * @return String that represents full package name
568
     */
569
    private static String getPackageText(DetailAST ast) {
570
        final DetailAST nameAST = ast.getLastChild().getPreviousSibling();
571 1 1. getPackageText : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::getPackageText to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return FullIdent.createFullIdent(nameAST).getText();
572
    }
573
574
    /**
575
     * Returns import text.
576
     *
577
     * @param ast ast node that represents import
578
     * @return String that represents importing class
579
     */
580
    private static String getImportText(DetailAST ast) {
581
        final FullIdent imp;
582 3 1. getImportText : negated conditional → KILLED
2. getImportText : removed conditional - replaced equality check with false → KILLED
3. getImportText : removed conditional - replaced equality check with true → KILLED
        if (ast.getType() == TokenTypes.IMPORT) {
583
            imp = FullIdent.createFullIdentBelow(ast);
584
        }
585
        else {
586
            // know it is a static import
587
            imp = FullIdent.createFullIdent(ast
588
                    .getFirstChild().getNextSibling());
589
        }
590 1 1. getImportText : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::getImportText to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return imp.getText();
591
    }
592
593
    /**
594
     * Setter to specify the location of the file containing the import control configuration.
595
     * It can be a regular file, URL or resource path. It will try loading the path
596
     * as a URL first, then as a file, and finally as a resource.
597
     *
598
     * @param uri the uri of the file to load.
599
     * @throws IllegalArgumentException on error loading the file.
600
     */
601
    public void setFile(URI uri) {
602
        // Handle empty param
603 3 1. setFile : negated conditional → KILLED
2. setFile : removed conditional - replaced equality check with false → KILLED
3. setFile : removed conditional - replaced equality check with true → KILLED
        if (uri != null) {
604
            try {
605
                root = ImportControlLoader.load(uri);
606
                file = uri;
607
            }
608
            catch (CheckstyleException ex) {
609 2 1. setFile : removed call to java/lang/StringBuilder::<init> → KILLED
2. setFile : removed call to java/lang/IllegalArgumentException::<init> → KILLED
                throw new IllegalArgumentException(UNABLE_TO_LOAD + uri, ex);
610
            }
611
        }
612
    }
613
614
    /**
615
     * Setter to specify the regular expression of file paths to which this check should apply.
616
     * Files that don't match the pattern will not be checked. The pattern will be matched
617
     * against the full absolute file path.
618
     *
619
     * @param pattern the file path regex this check should apply to.
620
     */
621
    public void setPath(Pattern pattern) {
622
        path = pattern;
623
    }
624
625
}

Mutations

506

1.1
Location : getDefaultTokens
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testMissing()]
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED

511

1.1
Location : getAcceptableTokens
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testGetAcceptableTokens()]
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::getAcceptableTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED

516

1.1
Location : getRequiredTokens
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testGetAcceptableTokens()]
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED

527

1.1
Location : beginTree
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testFileName()]
negated conditional → KILLED

2.2
Location : beginTree
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testFileName()]
removed conditional - replaced equality check with false → KILLED

3.3
Location : beginTree
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testFileNameNoExtension()]
removed conditional - replaced equality check with true → KILLED

534

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testMissing()]
negated conditional → KILLED

2.2
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testMissing()]
removed conditional - replaced equality check with false → KILLED

3.3
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testPathRegexDoesntMatch()]
removed conditional - replaced equality check with true → KILLED

535

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testMissing()]
negated conditional → KILLED

2.2
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testMissing()]
removed conditional - replaced equality check with false → KILLED

3.3
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testMissing()]
removed conditional - replaced equality check with true → KILLED

536

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testMissing()]
negated conditional → KILLED

2.2
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testMissing()]
removed conditional - replaced equality check with false → KILLED

3.3
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testWrong()]
removed conditional - replaced equality check with true → KILLED

537

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testMissing()]
removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::log → KILLED

542

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testWrong()]
negated conditional → KILLED

2.2
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testWrong()]
removed conditional - replaced equality check with false → KILLED

3.3
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testDisallowClassOfAllowPackage()]
removed conditional - replaced equality check with true → KILLED

543

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testWrong()]
removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::log → KILLED

547

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testMissing()]
negated conditional → KILLED

2.2
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testDisallowClassOfAllowPackage()]
removed conditional - replaced equality check with false → KILLED

3.3
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testMissing()]
removed conditional - replaced equality check with true → KILLED

551

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testDisallowClassOfAllowPackage()]
negated conditional → KILLED

2.2
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testDisallowClassOfAllowPackage()]
removed conditional - replaced equality check with false → KILLED

3.3
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testDisallowClassOfAllowPackage()]
removed conditional - replaced equality check with true → KILLED

552

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testDisallowClassOfAllowPackage()]
removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::log → KILLED

560

1.1
Location : getExternalResourceLocations
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testCacheWhenFileExternalResourceContentDoesNotChange()]
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::getExternalResourceLocations to ( if (x != null) null else throw new RuntimeException ) → KILLED

571

1.1
Location : getPackageText
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testWrong()]
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::getPackageText to ( if (x != null) null else throw new RuntimeException ) → KILLED

582

1.1
Location : getImportText
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testDisallowClassOfAllowPackage()]
negated conditional → KILLED

2.2
Location : getImportText
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testDisallowClassOfAllowPackage()]
removed conditional - replaced equality check with false → KILLED

3.3
Location : getImportText
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testOne()]
removed conditional - replaced equality check with true → KILLED

590

1.1
Location : getImportText
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testDisallowClassOfAllowPackage()]
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::getImportText to ( if (x != null) null else throw new RuntimeException ) → KILLED

603

1.1
Location : setFile
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testUrlInFilePropertyUnableToLoad()]
negated conditional → KILLED

2.2
Location : setFile
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testUrlInFilePropertyUnableToLoad()]
removed conditional - replaced equality check with false → KILLED

3.3
Location : setFile
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testEmpty()]
removed conditional - replaced equality check with true → KILLED

609

1.1
Location : setFile
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testUrlInFilePropertyUnableToLoad()]
removed call to java/lang/StringBuilder::<init> → KILLED

2.2
Location : setFile
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.[engine:junit-jupiter]/[class:com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest]/[method:testUrlInFilePropertyUnableToLoad()]
removed call to java/lang/IllegalArgumentException::<init> → KILLED

Active mutators

Tests examined


Report generated by PIT 1.6.3