View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 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.CommonUtil;
28  
29  /**
30   * <p>
31   * Checks that there are no static import statements.
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 in (without looking
37   * at the import statement).
38   * </p>
39   * <p>
40   * If you exclude a starred import on a class this automatically excludes
41   * each member individually.
42   * </p>
43   * <p>
44   * For example: Excluding {@code java.lang.Math.*}. will allow the import
45   * of each static member in the Math class individually like
46   * {@code java.lang.Math.PI, java.lang.Math.cos, ...}.
47   * </p>
48   * <ul>
49   * <li>
50   * Property {@code excludes} - Control whether to allow for certain classes via
51   * a star notation to be excluded such as {@code java.lang.Math.*} or specific
52   * static members to be excluded like {@code java.lang.System.out} for a variable
53   * or {@code java.lang.Math.random} for a method. See notes section for details.
54   * Type is {@code java.lang.String[]}.
55   * Default value is {@code ""}.
56   * </li>
57   * </ul>
58   * <p>
59   * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
60   * </p>
61   * <p>
62   * Violation Message Keys:
63   * </p>
64   * <ul>
65   * <li>
66   * {@code import.avoidStatic}
67   * </li>
68   * </ul>
69   *
70   * @since 5.0
71   */
72  @StatelessCheck
73  public class AvoidStaticImportCheck
74      extends AbstractCheck {
75  
76      /**
77       * A key is pointing to the warning message text in "messages.properties"
78       * file.
79       */
80      public static final String MSG_KEY = "import.avoidStatic";
81  
82      /**
83       * Control whether to allow for certain classes via a star notation to be
84       * excluded such as {@code java.lang.Math.*} or specific static members
85       * to be excluded like {@code java.lang.System.out} for a variable or
86       * {@code java.lang.Math.random} for a method. See notes section for details.
87       */
88      private String[] excludes = CommonUtil.EMPTY_STRING_ARRAY;
89  
90      @Override
91      public int[] getDefaultTokens() {
92          return getRequiredTokens();
93      }
94  
95      @Override
96      public int[] getAcceptableTokens() {
97          return getRequiredTokens();
98      }
99  
100     @Override
101     public int[] getRequiredTokens() {
102         return new int[] {TokenTypes.STATIC_IMPORT};
103     }
104 
105     /**
106      * Setter to control whether to allow for certain classes via a star notation
107      * to be excluded such as {@code java.lang.Math.*} or specific static members
108      * to be excluded like {@code java.lang.System.out} for a variable or
109      * {@code java.lang.Math.random} for a method. See notes section for details.
110      *
111      * @param excludes fully-qualified class names/specific
112      *     static members where static imports are ok
113      * @since 5.0
114      */
115     public void setExcludes(String... excludes) {
116         this.excludes = excludes.clone();
117     }
118 
119     @Override
120     public void visitToken(final DetailAST ast) {
121         final DetailAST startingDot =
122             ast.getFirstChild().getNextSibling();
123         final FullIdent name = FullIdent.createFullIdent(startingDot);
124 
125         final String nameText = name.getText();
126         if (!isExempt(nameText)) {
127             log(startingDot, MSG_KEY, nameText);
128         }
129     }
130 
131     /**
132      * Checks if a class or static member is exempt from known excludes.
133      *
134      * @param classOrStaticMember
135      *                the class or static member
136      * @return true if except false if not
137      */
138     private boolean isExempt(String classOrStaticMember) {
139         boolean exempt = false;
140 
141         for (String exclude : excludes) {
142             if (classOrStaticMember.equals(exclude)
143                     || isStarImportOfPackage(classOrStaticMember, exclude)) {
144                 exempt = true;
145                 break;
146             }
147         }
148         return exempt;
149     }
150 
151     /**
152      * Returns true if classOrStaticMember is a starred name of package,
153      *  not just member name.
154      *
155      * @param classOrStaticMember - full name of member
156      * @param exclude - current exclusion
157      * @return true if member in exclusion list
158      */
159     private static boolean isStarImportOfPackage(String classOrStaticMember, String exclude) {
160         boolean result = false;
161         if (exclude.endsWith(".*")) {
162             // this section allows explicit imports
163             // to be exempt when configured using
164             // a starred import
165             final String excludeMinusDotStar =
166                 exclude.substring(0, exclude.length() - 2);
167             if (classOrStaticMember.startsWith(excludeMinusDotStar)
168                     && !classOrStaticMember.equals(excludeMinusDotStar)) {
169                 final String member = classOrStaticMember.substring(
170                         excludeMinusDotStar.length() + 1);
171                 // if it contains a dot then it is not a member but a package
172                 if (member.indexOf('.') == -1) {
173                     result = true;
174                 }
175             }
176         }
177         return result;
178     }
179 
180 }