| 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 |