KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > puppycrawl > tools > checkstyle > checks > imports > ImportOrderCheck


1 ////////////////////////////////////////////////////////////////////////////////
2
// checkstyle: Checks Java source code for adherence to a set of rules.
3
// Copyright (C) 2001-2005 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 second, then everything else) and imports
31  * within each group are in lexicographic order. Static imports must
32  * be at the end of a group and in lexicographic order amongst themselves.
33  *
34  * <p>
35  * Example:
36  * <pre>
37  * &lt;module name=&quot;ImportOrder&quot;>
38  * &lt;property name=&quot;groups&quot; value=&quot;java,javax&quot;/>
39  * &lt;property name=&quot;ordered&quot; value=&quot;true&quot;/>
40  * &lt;property name=&quot;caseSensitive&quot; value=&quot;false&quot;/>
41  * &lt;/module>
42  * </pre>
43  *
44  * There is always an additional, implied &quot;everything else&quot; package
45  * group. If no &quot;groups&quot; property is supplied, all imports belong in
46  * this &quot;everything else&quot; group. </p>
47  *
48  * <p>
49  * ordered defaults to true.
50  * </p>
51  *
52  * <p>
53  * separated defaults to false.
54  * </p>
55  *
56  * Compatible with Java 1.5 source.
57  *
58  * @author Bill Schneider
59  * @author o_sukhodolsky
60  */

61 public class ImportOrderCheck extends Check
62 {
63     /** List of import groups specified by the user. */
64     private String JavaDoc[] mGroups = new String JavaDoc[0];
65
66     /** Require imports in group. */
67     private boolean mOrdered = true;
68
69     /** Require imports in group be separated. */
70     private boolean mSeparated;
71     /** Should comparison be case sensitive. */
72     private boolean mCaseSensitive = true;
73
74     /** Last imported group. */
75     private int mLastGroup;
76     /** Line number of last import. */
77     private int mLastImportLine;
78     /** Name of last import. */
79     private String JavaDoc mLastImport;
80     /** If last import was static. */
81     private boolean mLastImportStatic;
82     /** Whether there was any imports. */
83     private boolean mBeforeFirstImport;
84
85     /**
86      * Default constructor.
87      */

88     public ImportOrderCheck()
89     {
90     }
91
92     /**
93      * sets the list of package groups and the order they should
94      * occur in the file.
95      *
96      * @param aGroups a comma-separated list of package names/prefixes
97      */

98     public void setGroups(String JavaDoc[] aGroups)
99     {
100         mGroups = new String JavaDoc[ aGroups.length ];
101
102         for (int i = 0; i < aGroups.length; i++) {
103             String JavaDoc pkg = aGroups[i];
104
105             if (!pkg.endsWith(".")) {
106                 pkg = pkg + ".";
107             }
108
109             mGroups[i] = pkg;
110         }
111     }
112
113     /**
114      * Sets whether or not imports should be ordered within any one
115      * group of imports.
116      *
117      * @param aOrdered whether lexicographic ordering of imports within
118      * a group required or not.
119      */

120     public void setOrdered(boolean aOrdered)
121     {
122         mOrdered = aOrdered;
123     }
124
125     /**
126      * Sets whether or not groups of imports must be separated from
127      * one another by at least one blank line.
128      *
129      * @param aSeparated whehter groups should be separated by blank line.
130      */

131     public void setSeparated(boolean aSeparated)
132     {
133         mSeparated = aSeparated;
134     }
135
136     /**
137      * Sets whether string comparision should be case sensitive
138      * or not.
139      * @param aCaseSensitive whether string comparision should be
140      * case sensitive.
141      */

142     public void setCaseSensitive(boolean aCaseSensitive)
143     {
144         mCaseSensitive = aCaseSensitive;
145     }
146
147     /** {@inheritDoc} */
148     public int[] getDefaultTokens()
149     {
150         return new int[]{TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT};
151     }
152
153     /** {@inheritDoc} */
154     public int[] getRequiredTokens()
155     {
156         return getDefaultTokens();
157     }
158
159     /**
160      * @param aName import name to check.
161      * @return group number for given import name.
162      */

163     private int getGroupNumber(String JavaDoc aName)
164     {
165         int i = 0;
166
167         // find out what group this belongs in
168
// loop over mGroups and get index
169
for (; i < mGroups.length; i++) {
170             if (aName.startsWith(mGroups[i])) {
171                 break;
172             }
173         }
174
175         return i;
176     }
177
178     /** {@inheritDoc} */
179     public void beginTree(DetailAST aRootAST)
180     {
181         mLastGroup = Integer.MIN_VALUE;
182         mLastImportLine = Integer.MIN_VALUE;
183         mLastImport = "";
184         mLastImportStatic = false;
185         mBeforeFirstImport = true;
186     }
187
188     /** {@inheritDoc} */
189     public void visitToken(DetailAST aAST)
190     {
191         final FullIdent ident;
192         boolean isStatic;
193         if (aAST.getType() == TokenTypes.IMPORT) {
194             ident = FullIdent.createFullIdentBelow(aAST);
195             isStatic = false;
196         }
197         else {
198             ident = FullIdent.createFullIdent(
199                 (DetailAST) aAST.getFirstChild().getNextSibling());
200             isStatic = true;
201         }
202
203         if (ident != null) {
204             final String JavaDoc name = ident.getText();
205             final int groupIdx = getGroupNumber(name);
206             final int line = ident.getLineNo();
207
208             if (groupIdx > mLastGroup) {
209                 if (!mBeforeFirstImport && mSeparated) {
210                     // This check should be made more robust to handle
211
// comments and imports that span more than one line.
212
if (line - mLastImportLine < 2) {
213                         log(line, "import.separation", name);
214                     }
215                 }
216             }
217             else if (groupIdx == mLastGroup) {
218                 if (mOrdered) {
219                     boolean shouldFireError = false;
220                     if (mCaseSensitive) {
221                         shouldFireError =
222                             //current and previous static or current and
223
//previous non-static
224
(!(mLastImportStatic ^ isStatic)
225                             &&
226                             //and out of lexicographic order
227
(mLastImport.compareTo(name) >= 0))
228                             ||
229                             //previous static but current is non-static
230
(mLastImportStatic && !isStatic);
231                     }
232                     else {
233                         shouldFireError =
234                                 //current and previous static or current and
235
//previous non-static
236
(!(mLastImportStatic ^ isStatic)
237                                 &&
238                                 //and out of lexicographic order
239
(mLastImport.compareToIgnoreCase(name) >= 0))
240                                 ||
241                                 //previous static but current is non-static
242
(mLastImportStatic && !isStatic);
243                     }
244                     if (shouldFireError) {
245                         log(line, "import.ordering", name);
246                     }
247                 }
248             }
249             else {
250                 log(line, "import.ordering", name);
251             }
252
253             mLastGroup = groupIdx;
254             mLastImport = name;
255             mLastImportLine = aAST.findFirstToken(TokenTypes.SEMI).getLineNo();
256             mLastImportStatic = isStatic;
257             mBeforeFirstImport = false;
258         }
259     }
260 }
261
Popular Tags