Coverage Report - com.puppycrawl.tools.checkstyle.checks.imports.AvoidStaticImportCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
AvoidStaticImportCheck
100%
31/31
100%
16/16
2.143
 
 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 com.puppycrawl.tools.checkstyle.StatelessCheck;
 23  
 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
 24  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 25  
 import com.puppycrawl.tools.checkstyle.api.FullIdent;
 26  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 27  
 import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
 28  
 
 29  
 /**
 30  
  * <p>
 31  
  * Check that finds static imports.
 32  
  * </p>
 33  
  * <p>
 34  
  * Rationale: Importing static members can lead to naming conflicts
 35  
  * between class' members. It may lead to poor code readability since it
 36  
  * may no longer be clear what class a member resides (without looking
 37  
  * at the import statement).
 38  
  * </p>
 39  
  * <p>
 40  
  * An example of how to configure the check is:
 41  
  * </p>
 42  
  * <pre>
 43  
  * &lt;module name="AvoidStaticImport"&gt;
 44  
  *   &lt;property name="excludes"
 45  
  *       value="java.lang.System.out,java.lang.Math.*"/&gt;
 46  
  * &lt;/module&gt;
 47  
  * </pre>
 48  
  * The optional "excludes" property allows for certain classes via a star
 49  
  * notation to be excluded such as java.lang.Math.* or specific
 50  
  * static members to be excluded like java.lang.System.out for a variable
 51  
  * or java.lang.Math.random for a method.
 52  
  *
 53  
  * <p>
 54  
  * If you exclude a starred import on a class this automatically
 55  
  * excludes each member individually.
 56  
  * </p>
 57  
  *
 58  
  * <p>
 59  
  * For example:
 60  
  * Excluding java.lang.Math.* will allow the import of
 61  
  * each static member in the Math class individually like
 62  
  * java.lang.Math.PI
 63  
  * </p>
 64  
  * @author Travis Schneeberger
 65  
  */
 66  
 @StatelessCheck
 67  14
 public class AvoidStaticImportCheck
 68  
     extends AbstractCheck {
 69  
 
 70  
     /**
 71  
      * A key is pointing to the warning message text in "messages.properties"
 72  
      * file.
 73  
      */
 74  
     public static final String MSG_KEY = "import.avoidStatic";
 75  
 
 76  
     /** The classes/static members to exempt from this check. */
 77  14
     private String[] excludes = CommonUtils.EMPTY_STRING_ARRAY;
 78  
 
 79  
     @Override
 80  
     public int[] getDefaultTokens() {
 81  18
         return getRequiredTokens();
 82  
     }
 83  
 
 84  
     @Override
 85  
     public int[] getAcceptableTokens() {
 86  5
         return getRequiredTokens();
 87  
     }
 88  
 
 89  
     @Override
 90  
     public int[] getRequiredTokens() {
 91  42
         return new int[] {TokenTypes.STATIC_IMPORT};
 92  
     }
 93  
 
 94  
     /**
 95  
      * Sets the list of classes or static members to be exempt from the check.
 96  
      * @param excludes a list of fully-qualified class names/specific
 97  
      *     static members where static imports are ok
 98  
      */
 99  
     public void setExcludes(String... excludes) {
 100  5
         this.excludes = excludes.clone();
 101  5
     }
 102  
 
 103  
     @Override
 104  
     public void visitToken(final DetailAST ast) {
 105  35
         final DetailAST startingDot =
 106  35
             ast.getFirstChild().getNextSibling();
 107  35
         final FullIdent name = FullIdent.createFullIdent(startingDot);
 108  
 
 109  35
         if (!isExempt(name.getText())) {
 110  30
             log(startingDot.getLineNo(), MSG_KEY, name.getText());
 111  
         }
 112  35
     }
 113  
 
 114  
     /**
 115  
      * Checks if a class or static member is exempt from known excludes.
 116  
      *
 117  
      * @param classOrStaticMember
 118  
      *                the class or static member
 119  
      * @return true if except false if not
 120  
      */
 121  
     private boolean isExempt(String classOrStaticMember) {
 122  35
         boolean exempt = false;
 123  
 
 124  97
         for (String exclude : excludes) {
 125  67
             if (classOrStaticMember.equals(exclude)
 126  66
                     || isStarImportOfPackage(classOrStaticMember, exclude)) {
 127  5
                 exempt = true;
 128  5
                 break;
 129  
             }
 130  
         }
 131  35
         return exempt;
 132  
     }
 133  
 
 134  
     /**
 135  
      * Returns true if classOrStaticMember is a starred name of package,
 136  
      *  not just member name.
 137  
      * @param classOrStaticMember - full name of member
 138  
      * @param exclude - current exclusion
 139  
      * @return true if member in exclusion list
 140  
      */
 141  
     private static boolean isStarImportOfPackage(String classOrStaticMember, String exclude) {
 142  66
         boolean result = false;
 143  66
         if (exclude.endsWith(".*")) {
 144  
             //this section allows explicit imports
 145  
             //to be exempt when configured using
 146  
             //a starred import
 147  25
             final String excludeMinusDotStar =
 148  25
                 exclude.substring(0, exclude.length() - 2);
 149  25
             if (classOrStaticMember.startsWith(excludeMinusDotStar)
 150  7
                     && !classOrStaticMember.equals(excludeMinusDotStar)) {
 151  12
                 final String member = classOrStaticMember.substring(
 152  6
                         excludeMinusDotStar.length() + 1);
 153  
                 //if it contains a dot then it is not a member but a package
 154  6
                 if (member.indexOf('.') == -1) {
 155  4
                     result = true;
 156  
                 }
 157  
             }
 158  
         }
 159  66
         return result;
 160  
     }
 161  
 }