ImportControlCheck.java

1
////////////////////////////////////////////////////////////////////////////////
2
// checkstyle: Checks Java source code for adherence to a set of rules.
3
// Copyright (C) 2001-2017 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.api.AbstractCheck;
28
import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
29
import com.puppycrawl.tools.checkstyle.api.DetailAST;
30
import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder;
31
import com.puppycrawl.tools.checkstyle.api.FullIdent;
32
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
33
34
/**
35
 * Check that controls what packages can be imported in each package. Useful
36
 * for ensuring that application layering is not violated. Ideas on how the
37
 * check can be improved include support for:
38
 * <ul>
39
 * <li>
40
 * Change the default policy that if a package being checked does not
41
 * match any guards, then it is allowed. Currently defaults to disallowed.
42
 * </li>
43
 * </ul>
44
 *
45
 * @author Oliver Burn
46
 */
47
public class ImportControlCheck extends AbstractCheck implements ExternalResourceHolder {
48
49
    /**
50
     * A key is pointing to the warning message text in "messages.properties"
51
     * file.
52
     */
53
    public static final String MSG_MISSING_FILE = "import.control.missing.file";
54
55
    /**
56
     * A key is pointing to the warning message text in "messages.properties"
57
     * file.
58
     */
59
    public static final String MSG_UNKNOWN_PKG = "import.control.unknown.pkg";
60
61
    /**
62
     * A key is pointing to the warning message text in "messages.properties"
63
     * file.
64
     */
65
    public static final String MSG_DISALLOWED = "import.control.disallowed";
66
67
    /**
68
     * A part of message for exception.
69
     */
70
    private static final String UNABLE_TO_LOAD = "Unable to load ";
71
72
    /** Location of import control file. */
73
    private String fileLocation;
74
75
    /** The filepath pattern this check applies to. */
76
    private Pattern path = Pattern.compile(".*");
77
    /** Whether to process the current file. */
78
    private boolean processCurrentFile;
79
80
    /** The root package controller. */
81
    private ImportControl root;
82
    /** The package doing the import. */
83
    private String packageName;
84
85
    /**
86
     * The package controller for the current file. Used for performance
87
     * optimisation.
88
     */
89
    private ImportControl currentImportControl;
90
91
    @Override
92
    public int[] getDefaultTokens() {
93 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 getAcceptableTokens();
94
    }
95
96
    @Override
97
    public int[] getAcceptableTokens() {
98 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 new int[] {TokenTypes.PACKAGE_DEF, TokenTypes.IMPORT,
99
                          TokenTypes.STATIC_IMPORT, };
100
    }
101
102
    @Override
103
    public int[] getRequiredTokens() {
104 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 getAcceptableTokens();
105
    }
106
107
    @Override
108
    public void beginTree(DetailAST rootAST) {
109
        currentImportControl = null;
110
        processCurrentFile = path.matcher(getFileContents().getFileName()).find();
111
    }
112
113
    @Override
114
    public void visitToken(DetailAST ast) {
115 1 1. visitToken : negated conditional → KILLED
        if (processCurrentFile) {
116 1 1. visitToken : negated conditional → KILLED
            if (ast.getType() == TokenTypes.PACKAGE_DEF) {
117 1 1. visitToken : negated conditional → KILLED
                if (root == null) {
118 1 1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::log → KILLED
                    log(ast, MSG_MISSING_FILE);
119
                }
120
                else {
121
                    packageName = getPackageText(ast);
122
                    currentImportControl = root.locateFinest(packageName);
123 1 1. visitToken : negated conditional → KILLED
                    if (currentImportControl == null) {
124 1 1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::log → KILLED
                        log(ast, MSG_UNKNOWN_PKG);
125
                    }
126
                }
127
            }
128 1 1. visitToken : negated conditional → KILLED
            else if (currentImportControl != null) {
129
                final String importText = getImportText(ast);
130
                final AccessResult access =
131
                        currentImportControl.checkAccess(packageName, importText);
132 1 1. visitToken : negated conditional → KILLED
                if (access != AccessResult.ALLOWED) {
133 1 1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::log → KILLED
                    log(ast, MSG_DISALLOWED, importText);
134
                }
135
            }
136
        }
137
    }
138
139
    @Override
140
    public Set<String> getExternalResourceLocations() {
141 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(fileLocation);
142
    }
143
144
    /**
145
     * Returns package text.
146
     * @param ast PACKAGE_DEF ast node
147
     * @return String that represents full package name
148
     */
149
    private static String getPackageText(DetailAST ast) {
150
        final DetailAST nameAST = ast.getLastChild().getPreviousSibling();
151 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();
152
    }
153
154
    /**
155
     * Returns import text.
156
     * @param ast ast node that represents import
157
     * @return String that represents importing class
158
     */
159
    private static String getImportText(DetailAST ast) {
160
        final FullIdent imp;
161 1 1. getImportText : negated conditional → KILLED
        if (ast.getType() == TokenTypes.IMPORT) {
162
            imp = FullIdent.createFullIdentBelow(ast);
163
        }
164
        else {
165
            // know it is a static import
166
            imp = FullIdent.createFullIdent(ast
167
                    .getFirstChild().getNextSibling());
168
        }
169 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();
170
    }
171
172
    /**
173
     * Set the name for the file containing the import control
174
     * configuration. It can also be a URL or resource in the classpath.
175
     * It will cause the file to be loaded.
176
     * @param uri the uri of the file to load.
177
     * @throws IllegalArgumentException on error loading the file.
178
     */
179
    public void setFile(URI uri) {
180
        // Handle empty param
181 1 1. setFile : negated conditional → KILLED
        if (uri != null) {
182
            try {
183
                root = ImportControlLoader.load(uri);
184
                fileLocation = uri.toString();
185
            }
186
            catch (CheckstyleException ex) {
187
                throw new IllegalArgumentException(UNABLE_TO_LOAD + uri, ex);
188
            }
189
        }
190
    }
191
192
    /**
193
     * Set the file path pattern that this check applies to.
194
     * @param pattern the file path regex this check should apply to.
195
     */
196
    public void setPath(Pattern pattern) {
197
        path = pattern;
198
    }
199
}

Mutations

93

1.1
Location : getDefaultTokens
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.testWrong(com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest)
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED

98

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

104

1.1
Location : getRequiredTokens
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.testGetRequiredTokens(com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest)
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED

115

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.testWrong(com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest)
negated conditional → KILLED

116

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.testWrong(com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest)
negated conditional → KILLED

117

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.testWrong(com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest)
negated conditional → KILLED

118

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.testEmpty(com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest)
removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::log → KILLED

123

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.testWrong(com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest)
negated conditional → KILLED

124

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.testWrong(com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest)
removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::log → KILLED

128

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.testWrong(com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest)
negated conditional → KILLED

132

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.testStrategyOnMismatchOne(com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest)
negated conditional → KILLED

133

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.testStrategyOnMismatchOne(com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest)
removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::log → KILLED

141

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

151

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

161

1.1
Location : getImportText
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.testStrategyOnMismatchOne(com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest)
negated conditional → KILLED

169

1.1
Location : getImportText
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.testStrategyOnMismatchOne(com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest)
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck::getImportText to ( if (x != null) null else throw new RuntimeException ) → KILLED

181

1.1
Location : setFile
Killed by : com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest.testWrong(com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest)
negated conditional → KILLED

Active mutators

Tests examined


Report generated by PIT 1.2.2