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.io.IOException; | |
23 | import java.io.InputStream; | |
24 | import java.net.MalformedURLException; | |
25 | import java.net.URI; | |
26 | import java.util.ArrayDeque; | |
27 | import java.util.Deque; | |
28 | import java.util.HashMap; | |
29 | import java.util.Map; | |
30 | ||
31 | import javax.xml.parsers.ParserConfigurationException; | |
32 | ||
33 | import org.xml.sax.Attributes; | |
34 | import org.xml.sax.InputSource; | |
35 | import org.xml.sax.SAXException; | |
36 | ||
37 | import com.puppycrawl.tools.checkstyle.api.AbstractLoader; | |
38 | import com.puppycrawl.tools.checkstyle.api.CheckstyleException; | |
39 | ||
40 | /** | |
41 | * Responsible for loading the contents of an import control configuration file. | |
42 | * @author Oliver Burn | |
43 | */ | |
44 | final class ImportControlLoader extends AbstractLoader { | |
45 | /** The public ID for the configuration dtd. */ | |
46 | private static final String DTD_PUBLIC_ID_1_0 = | |
47 | "-//Puppy Crawl//DTD Import Control 1.0//EN"; | |
48 | ||
49 | /** The public ID for the configuration dtd. */ | |
50 | private static final String DTD_PUBLIC_ID_1_1 = | |
51 | "-//Puppy Crawl//DTD Import Control 1.1//EN"; | |
52 | ||
53 | /** The public ID for the configuration dtd. */ | |
54 | private static final String DTD_PUBLIC_ID_1_2 = | |
55 | "-//Puppy Crawl//DTD Import Control 1.2//EN"; | |
56 | ||
57 | /** The public ID for the configuration dtd. */ | |
58 | private static final String DTD_PUBLIC_ID_1_3 = | |
59 | "-//Puppy Crawl//DTD Import Control 1.3//EN"; | |
60 | ||
61 | /** The resource for the configuration dtd. */ | |
62 | private static final String DTD_RESOURCE_NAME_1_0 = | |
63 | "com/puppycrawl/tools/checkstyle/checks/imports/import_control_1_0.dtd"; | |
64 | ||
65 | /** The resource for the configuration dtd. */ | |
66 | private static final String DTD_RESOURCE_NAME_1_1 = | |
67 | "com/puppycrawl/tools/checkstyle/checks/imports/import_control_1_1.dtd"; | |
68 | ||
69 | /** The resource for the configuration dtd. */ | |
70 | private static final String DTD_RESOURCE_NAME_1_2 = | |
71 | "com/puppycrawl/tools/checkstyle/checks/imports/import_control_1_2.dtd"; | |
72 | ||
73 | /** The resource for the configuration dtd. */ | |
74 | private static final String DTD_RESOURCE_NAME_1_3 = | |
75 | "com/puppycrawl/tools/checkstyle/checks/imports/import_control_1_3.dtd"; | |
76 | ||
77 | /** The map to lookup the resource name by the id. */ | |
78 | private static final Map<String, String> DTD_RESOURCE_BY_ID = new HashMap<>(); | |
79 | ||
80 | /** Name for attribute 'pkg'. */ | |
81 | private static final String PKG_ATTRIBUTE_NAME = "pkg"; | |
82 | ||
83 | /** Name for attribute 'strategyOnMismatch'. */ | |
84 | private static final String STRATEGY_ON_MISMATCH_ATTRIBUTE_NAME = "strategyOnMismatch"; | |
85 | ||
86 | /** Value "allowed" for attribute 'strategyOnMismatch'. */ | |
87 | private static final String STRATEGY_ON_MISMATCH_ALLOWED_VALUE = "allowed"; | |
88 | ||
89 | /** Value "disallowed" for attribute 'strategyOnMismatch'. */ | |
90 | private static final String STRATEGY_ON_MISMATCH_DISALLOWED_VALUE = "disallowed"; | |
91 | ||
92 | /** Qualified name for element 'subpackage'. */ | |
93 | private static final String SUBPACKAGE_ELEMENT_NAME = "subpackage"; | |
94 | ||
95 | /** Qualified name for element 'allow'. */ | |
96 | private static final String ALLOW_ELEMENT_NAME = "allow"; | |
97 | ||
98 | /** Used to hold the {@link ImportControl} objects. */ | |
99 | private final Deque<ImportControl> stack = new ArrayDeque<>(); | |
100 | ||
101 | static { | |
102 | DTD_RESOURCE_BY_ID.put(DTD_PUBLIC_ID_1_0, DTD_RESOURCE_NAME_1_0); | |
103 | DTD_RESOURCE_BY_ID.put(DTD_PUBLIC_ID_1_1, DTD_RESOURCE_NAME_1_1); | |
104 | DTD_RESOURCE_BY_ID.put(DTD_PUBLIC_ID_1_2, DTD_RESOURCE_NAME_1_2); | |
105 | DTD_RESOURCE_BY_ID.put(DTD_PUBLIC_ID_1_3, DTD_RESOURCE_NAME_1_3); | |
106 | } | |
107 | ||
108 | /** | |
109 | * Constructs an instance. | |
110 | * @throws ParserConfigurationException if an error occurs. | |
111 | * @throws SAXException if an error occurs. | |
112 | */ | |
113 | private ImportControlLoader() throws ParserConfigurationException, | |
114 | SAXException { | |
115 | super(DTD_RESOURCE_BY_ID); | |
116 | } | |
117 | ||
118 | @Override | |
119 | public void startElement(String namespaceUri, | |
120 | String localName, | |
121 | String qName, | |
122 | Attributes attributes) | |
123 | throws SAXException { | |
124 |
1
1. startElement : negated conditional → KILLED |
if ("import-control".equals(qName)) { |
125 | final String pkg = safeGet(attributes, PKG_ATTRIBUTE_NAME); | |
126 | final MismatchStrategy strategyOnMismatch = getStrategyForImportControl(attributes); | |
127 | final boolean regex = containsRegexAttribute(attributes); | |
128 |
1
1. startElement : removed call to java/util/Deque::push → KILLED |
stack.push(new ImportControl(pkg, regex, strategyOnMismatch)); |
129 | } | |
130 |
1
1. startElement : negated conditional → KILLED |
else if (SUBPACKAGE_ELEMENT_NAME.equals(qName)) { |
131 | final String name = safeGet(attributes, "name"); | |
132 | final MismatchStrategy strategyOnMismatch = getStrategyForSubpackage(attributes); | |
133 | final boolean regex = containsRegexAttribute(attributes); | |
134 | final ImportControl parentImportControl = stack.peek(); | |
135 | final ImportControl importControl = new ImportControl(parentImportControl, name, | |
136 | regex, strategyOnMismatch); | |
137 |
1
1. startElement : removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControl::addChild → KILLED |
parentImportControl.addChild(importControl); |
138 |
1
1. startElement : removed call to java/util/Deque::push → KILLED |
stack.push(importControl); |
139 | } | |
140 |
2
1. startElement : negated conditional → KILLED 2. startElement : negated conditional → KILLED |
else if (ALLOW_ELEMENT_NAME.equals(qName) || "disallow".equals(qName)) { |
141 | // Need to handle either "pkg" or "class" attribute. | |
142 | // May have "exact-match" for "pkg" | |
143 | // May have "local-only" | |
144 | final boolean isAllow = ALLOW_ELEMENT_NAME.equals(qName); | |
145 |
1
1. startElement : negated conditional → KILLED |
final boolean isLocalOnly = attributes.getValue("local-only") != null; |
146 | final String pkg = attributes.getValue(PKG_ATTRIBUTE_NAME); | |
147 | final boolean regex = containsRegexAttribute(attributes); | |
148 | final AbstractImportRule rule; | |
149 |
1
1. startElement : negated conditional → KILLED |
if (pkg == null) { |
150 | // handle class names which can be normal class names or regular | |
151 | // expressions | |
152 | final String clazz = safeGet(attributes, "class"); | |
153 | rule = new ClassImportRule(isAllow, isLocalOnly, clazz, regex); | |
154 | } | |
155 | else { | |
156 | final boolean exactMatch = | |
157 |
1
1. startElement : negated conditional → KILLED |
attributes.getValue("exact-match") != null; |
158 | rule = new PkgImportRule(isAllow, isLocalOnly, pkg, exactMatch, regex); | |
159 | } | |
160 |
1
1. startElement : removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControl::addImportRule → KILLED |
stack.peek().addImportRule(rule); |
161 | } | |
162 | } | |
163 | ||
164 | /** | |
165 | * Check if the given attributes contain the regex attribute. | |
166 | * @param attributes the attributes. | |
167 | * @return if the regex attribute is contained. | |
168 | */ | |
169 | private static boolean containsRegexAttribute(Attributes attributes) { | |
170 |
2
1. containsRegexAttribute : negated conditional → KILLED 2. containsRegexAttribute : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED |
return attributes.getValue("regex") != null; |
171 | } | |
172 | ||
173 | @Override | |
174 | public void endElement(String namespaceUri, String localName, | |
175 | String qName) { | |
176 |
1
1. endElement : negated conditional → KILLED |
if (SUBPACKAGE_ELEMENT_NAME.equals(qName)) { |
177 | stack.pop(); | |
178 | } | |
179 | } | |
180 | ||
181 | /** | |
182 | * Loads the import control file from a file. | |
183 | * @param uri the uri of the file to load. | |
184 | * @return the root {@link ImportControl} object. | |
185 | * @throws CheckstyleException if an error occurs. | |
186 | */ | |
187 | public static ImportControl load(URI uri) throws CheckstyleException { | |
188 | ||
189 | InputStream inputStream = null; | |
190 | try { | |
191 | inputStream = uri.toURL().openStream(); | |
192 | final InputSource source = new InputSource(inputStream); | |
193 |
1
1. load : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoader::load to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return load(source, uri); |
194 | } | |
195 | catch (MalformedURLException ex) { | |
196 | throw new CheckstyleException("syntax error in url " + uri, ex); | |
197 | } | |
198 | catch (IOException ex) { | |
199 | throw new CheckstyleException("unable to find " + uri, ex); | |
200 | } | |
201 | finally { | |
202 |
1
1. load : removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoader::closeStream → KILLED |
closeStream(inputStream); |
203 | } | |
204 | } | |
205 | ||
206 | /** | |
207 | * Loads the import control file from a {@link InputSource}. | |
208 | * @param source the source to load from. | |
209 | * @param uri uri of the source being loaded. | |
210 | * @return the root {@link ImportControl} object. | |
211 | * @throws CheckstyleException if an error occurs. | |
212 | */ | |
213 | private static ImportControl load(InputSource source, | |
214 | URI uri) throws CheckstyleException { | |
215 | try { | |
216 | final ImportControlLoader loader = new ImportControlLoader(); | |
217 |
1
1. load : removed call to com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoader::parseInputSource → KILLED |
loader.parseInputSource(source); |
218 |
1
1. load : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoader::load to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return loader.getRoot(); |
219 | } | |
220 | catch (ParserConfigurationException | SAXException ex) { | |
221 | throw new CheckstyleException("unable to parse " + uri | |
222 | + " - " + ex.getMessage(), ex); | |
223 | } | |
224 | catch (IOException ex) { | |
225 | throw new CheckstyleException("unable to read " + uri, ex); | |
226 | } | |
227 | } | |
228 | ||
229 | /** | |
230 | * This method exists only due to bug in cobertura library | |
231 | * https://github.com/cobertura/cobertura/issues/170 | |
232 | * @param inputStream the InputStream to close | |
233 | * @throws CheckstyleException if an error occurs. | |
234 | */ | |
235 | private static void closeStream(InputStream inputStream) throws CheckstyleException { | |
236 |
1
1. closeStream : negated conditional → KILLED |
if (inputStream != null) { |
237 | try { | |
238 |
1
1. closeStream : removed call to java/io/InputStream::close → KILLED |
inputStream.close(); |
239 | } | |
240 | catch (IOException ex) { | |
241 | throw new CheckstyleException("unable to close input stream", ex); | |
242 | } | |
243 | } | |
244 | } | |
245 | ||
246 | /** | |
247 | * Returns root ImportControl. | |
248 | * @return the root {@link ImportControl} object loaded. | |
249 | */ | |
250 | private ImportControl getRoot() { | |
251 |
1
1. getRoot : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoader::getRoot to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return stack.peek(); |
252 | } | |
253 | ||
254 | /** | |
255 | * Utility to get a strategyOnMismatch property for "import-control" tag. | |
256 | * @param attributes collect to get attribute from. | |
257 | * @return the value of the attribute. | |
258 | */ | |
259 | private static MismatchStrategy getStrategyForImportControl(Attributes attributes) { | |
260 | final String returnValue = attributes.getValue(STRATEGY_ON_MISMATCH_ATTRIBUTE_NAME); | |
261 | MismatchStrategy strategyOnMismatch = MismatchStrategy.DISALLOWED; | |
262 |
1
1. getStrategyForImportControl : negated conditional → KILLED |
if (STRATEGY_ON_MISMATCH_ALLOWED_VALUE.equals(returnValue)) { |
263 | strategyOnMismatch = MismatchStrategy.ALLOWED; | |
264 | } | |
265 |
1
1. getStrategyForImportControl : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoader::getStrategyForImportControl to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return strategyOnMismatch; |
266 | } | |
267 | ||
268 | /** | |
269 | * Utility to get a strategyOnMismatch property for "subpackage" tag. | |
270 | * @param attributes collect to get attribute from. | |
271 | * @return the value of the attribute. | |
272 | */ | |
273 | private static MismatchStrategy getStrategyForSubpackage(Attributes attributes) { | |
274 | final String returnValue = attributes.getValue(STRATEGY_ON_MISMATCH_ATTRIBUTE_NAME); | |
275 | MismatchStrategy strategyOnMismatch = MismatchStrategy.DELEGATE_TO_PARENT; | |
276 |
1
1. getStrategyForSubpackage : negated conditional → KILLED |
if (STRATEGY_ON_MISMATCH_ALLOWED_VALUE.equals(returnValue)) { |
277 | strategyOnMismatch = MismatchStrategy.ALLOWED; | |
278 | } | |
279 |
1
1. getStrategyForSubpackage : negated conditional → KILLED |
else if (STRATEGY_ON_MISMATCH_DISALLOWED_VALUE.equals(returnValue)) { |
280 | strategyOnMismatch = MismatchStrategy.DISALLOWED; | |
281 | } | |
282 |
1
1. getStrategyForSubpackage : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoader::getStrategyForSubpackage to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return strategyOnMismatch; |
283 | } | |
284 | ||
285 | /** | |
286 | * Utility to safely get an attribute. If it does not exist an exception | |
287 | * is thrown. | |
288 | * @param attributes collect to get attribute from. | |
289 | * @param name name of the attribute to get. | |
290 | * @return the value of the attribute. | |
291 | * @throws SAXException if the attribute does not exist. | |
292 | */ | |
293 | private static String safeGet(Attributes attributes, String name) | |
294 | throws SAXException { | |
295 | final String returnValue = attributes.getValue(name); | |
296 |
1
1. safeGet : negated conditional → KILLED |
if (returnValue == null) { |
297 | // -@cs[IllegalInstantiation] SAXException is in the overridden method signature | |
298 | // of the only method which calls the current one | |
299 | throw new SAXException("missing attribute " + name); | |
300 | } | |
301 |
1
1. safeGet : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoader::safeGet to ( if (x != null) null else throw new RuntimeException ) → KILLED |
return returnValue; |
302 | } | |
303 | } | |
Mutations | ||
124 |
1.1 |
|
128 |
1.1 |
|
130 |
1.1 |
|
137 |
1.1 |
|
138 |
1.1 |
|
140 |
1.1 2.2 |
|
145 |
1.1 |
|
149 |
1.1 |
|
157 |
1.1 |
|
160 |
1.1 |
|
170 |
1.1 2.2 |
|
176 |
1.1 |
|
193 |
1.1 |
|
202 |
1.1 |
|
217 |
1.1 |
|
218 |
1.1 |
|
236 |
1.1 |
|
238 |
1.1 |
|
251 |
1.1 |
|
262 |
1.1 |
|
265 |
1.1 |
|
276 |
1.1 |
|
279 |
1.1 |
|
282 |
1.1 |
|
296 |
1.1 |
|
301 |
1.1 |