Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheck.java


1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2003  Oliver Burn
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.api.Check;
23  import com.puppycrawl.tools.checkstyle.api.DetailAST;
24  import com.puppycrawl.tools.checkstyle.api.FullIdent;
25  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
26  
27  /**
28   * Class to check the ordering/grouping of imports.  Ensures that
29   * groups of imports come in a specific order (e.g., java. comes
30   * first, javax. comes first, then everything else) and imports
31   * within each group are in lexicographic order.
32   *
33   * <p>
34   * Example:
35   * <pre>
36   *  &lt;module name=&quot;ImportOrder&quot;>
37   *    &lt;property name=&quot;groups&quot; value=&quot;java,javax&quot;/>
38   *    &lt;property name=&quot;ordered&quot; value=&quot;true&quot;/>
39   *  &lt;/module>
40   * </pre>
41   *
42   * There is always an additional, implied &quot;everything else&quot; package
43   * group.  If no &quot;groups&quot; property is supplied, all imports belong in
44   * this &quot;everything else&quot; group.  </p>
45   *
46   * <p>
47   * ordered defaults to true.
48   * </p>
49   *
50   * <p>
51   * separated defaults to false.
52   * </p>
53   *
54   * @author Bill Schneider
55   * @author o_sukhodolsky
56   */
57  public class ImportOrderCheck extends Check
58  {
59      /** List of import groups specified by the user. */
60      private String[] mGroups = new String[0];
61  
62      /** Require imports in group. */
63      private boolean mOrdered = true;
64  
65      /** Require imports in group be separated. */
66      private boolean mSeparated;
67  
68      /** Last imported group. */
69      private int mLastGroup;
70      /** Line number of last import. */
71      private int mLastImportLine;
72      /** Name of last import. */
73      private String mLastImport;
74      /** Whether there was any imports. */
75      private boolean mBeforeFirstImport;
76  
77      /**
78       * Default constructor.
79       */
80      public ImportOrderCheck()
81      {
82      }
83  
84      /**
85       * sets the list of package groups and the order they should
86       * occur in the  file.
87       *
88       * @param aGroups a comma-separated list of package names/prefixes
89       */
90      public void setGroups(String[] aGroups)
91      {
92          mGroups = new String[ aGroups.length ];
93  
94          for (int i = 0; i < aGroups.length; i++) {
95              String pkg = aGroups[i];
96  
97              if (!pkg.endsWith(".")) {
98                  pkg = pkg + ".";
99              }
100 
101             mGroups[i] = pkg;
102         }
103     }
104 
105     /**
106      * Sets whether or not imports should be ordered within any one
107      * group of imports.
108      *
109      * @param aOrdered whether lexicographic ordering of imports within
110      *                 a group required or not.
111      */
112     public void setOrdered(boolean aOrdered)
113     {
114         mOrdered = aOrdered;
115     }
116 
117     /**
118      * Sets whether or not groups of imports must be separated from
119      * one another by at least one blank line.
120      *
121      * @param aSeparated whehter groups should be separated by blank line.
122      */
123     public void setSeparated(boolean aSeparated)
124     {
125         mSeparated = aSeparated;
126     }
127 
128     /** {@inheritDoc} */
129     public int[] getDefaultTokens()
130     {
131         return new int[]{TokenTypes.IMPORT};
132     }
133 
134     /** {@inheritDoc} */
135     public int[] getRequiredTokens()
136     {
137         return getDefaultTokens();
138     }
139 
140     /**
141      * @param aName import name to check.
142      * @return group number for given import name.
143      */
144     private int getGroupNumber(String aName)
145     {
146         int i = 0;
147 
148         // find out what group this belongs in
149         // loop over mGroups and get index
150         for (; i < mGroups.length; i++) {
151             if (aName.startsWith(mGroups[i])) {
152                 break;
153             }
154         }
155 
156         return i;
157     }
158 
159     /** {@inheritDoc} */
160     public void beginTree(DetailAST aRootAST)
161     {
162         mLastGroup = Integer.MIN_VALUE;
163         mLastImportLine = Integer.MIN_VALUE;
164         mLastImport = "";
165         mBeforeFirstImport = true;
166     }
167 
168     /** {@inheritDoc} */
169     public void visitToken(DetailAST aAST)
170     {
171         final FullIdent ident = FullIdent.createFullIdentBelow(aAST);
172 
173         if (ident != null) {
174             String name = ident.getText();
175             int groupIdx = getGroupNumber(name);
176             int line = ident.getLineNo();
177 
178             if (groupIdx > mLastGroup) {
179                 if (!mBeforeFirstImport && mSeparated) {
180                     // This check should be made more robust to handle
181                     // comments and imports that span more than one line.
182                     if (line - mLastImportLine < 2) {
183                         log(line, "import.separation", name);
184                     }
185                 }
186             }
187             else if (groupIdx == mLastGroup) {
188                 if (mOrdered) {
189                     if (mLastImport.compareTo(name) >= 0) {
190                         log(line, "import.ordering", name);
191                     }
192                 }
193             }
194             else {
195                 log(line, "import.ordering", name);
196             }
197 
198             mLastGroup = groupIdx;
199             mLastImport = name;
200             mLastImportLine = aAST.findFirstToken(TokenTypes.SEMI).getLineNo();
201             mBeforeFirstImport = false;
202         }
203     }
204 }