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