1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2019 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.util.Locale;
23  import java.util.regex.Matcher;
24  import java.util.regex.Pattern;
25  
26  import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
27  import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
28  import com.puppycrawl.tools.checkstyle.api.DetailAST;
29  import com.puppycrawl.tools.checkstyle.api.FullIdent;
30  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
31  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
32  
33  /**
34   * <p>
35   * Checks the ordering/grouping of imports. Features are:
36   * </p>
37   * <ul>
38   * <li>
39   * groups type/static imports: ensures that groups of imports come in a specific order
40   * (e.g., java. comes first, javax. comes second, then everything else)
41   * </li>
42   * <li>
43   * adds a separation between type import groups : ensures that a blank line sit between each group
44   * </li>
45   * <li>
46   * type/static import groups aren't separated internally: ensures that each group aren't separated
47   * internally by blank line or comment
48   * </li>
49   * <li>
50   * sorts type/static imports inside each group: ensures that imports within each group are in
51   * lexicographic order
52   * </li>
53   * <li>
54   * sorts according to case: ensures that the comparison between imports is case sensitive, in
55   * <a href="https://en.wikipedia.org/wiki/ASCII#Order">ASCII sort order</a>
56   * </li>
57   * <li>
58   * arrange static imports: ensures the relative order between type imports and static imports
59   * (see <a href="property_types.html#importOrder">import orders</a>)
60   * </li>
61   * </ul>
62   * <ul>
63   * <li>
64   * Property {@code option} - specify policy on the relative order between type imports and static
65   * imports.
66   * Default value is {@code under}.
67   * </li>
68   * <li>
69   * Property {@code groups} - specify list of <b>type import</b> groups (every group identified
70   * either by a common prefix string, or by a regular expression enclosed in forward slashes
71   * (e.g. {@code /regexp/}). All type imports, which does not match any group, falls into an
72   * additional group, located at the end.
73   * Thus, the empty list of type groups (the default value) means one group for all type imports.
74   * Default value is {@code {}}.
75   * </li>
76   * <li>
77   * Property {@code ordered} - control whether type imports within each group should be
78   * sorted.
79   * It doesn't affect sorting for static imports.
80   * Default value is true.
81   * </li>
82   * <li>
83   * Property {@code separated} - control whether type import groups should be separated
84   * by, at least, one blank line or comment and aren't separated internally.
85   * It doesn't affect separations for static imports.
86   * Default value is false.
87   * </li>
88   * <li>
89   * Property {@code separatedStaticGroups} - control whether static import groups should
90   * be separated by, at least, one blank line or comment and aren't separated internally.
91   * This property has effect only when the property {@code option} is is set to {@code top}
92   * or {@code bottom}.
93   * Default value is false.
94   * </li>
95   * <li>
96   * Property {@code caseSensitive} - control whether string comparison should be case
97   * sensitive or not. Case sensitive sorting is in
98   * <a href="https://en.wikipedia.org/wiki/ASCII#Order">ASCII sort order</a>.
99   * It affects both type imports and static imports.
100  * Default value is true.
101  * </li>
102  * <li>
103  * Property {@code staticGroups} - specify list of <b>static</b> import groups (every group
104  * identified either by a common prefix string, or by a regular expression enclosed in forward
105  * slashes (e.g. {@code /regexp/}). All static imports, which does not match any group, falls into
106  * an additional group, located at the end. Thus, the empty list of static groups (the default
107  * value) means one group for all static imports. This property has effect only when the property
108  * {@code option} is set to {@code top} or {@code bottom}.
109  * Default value is {@code {}}.
110  * </li>
111  * <li>
112  * Property {@code sortStaticImportsAlphabetically} - control whether
113  * <b>static imports</b> located at <b>top</b> or <b>bottom</b> are sorted within the group.
114  * Default value is false.
115  * </li>
116  * <li>
117  * Property {@code useContainerOrderingForStatic} - control whether to use container
118  * ordering (Eclipse IDE term) for static imports or not.
119  * Default value is false.
120  * </li>
121  * <li>
122  * Property {@code tokens} - tokens to check
123  * Default value is:
124  * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#STATIC_IMPORT">
125  * STATIC_IMPORT</a>.
126  * </li>
127  * </ul>
128  * <p>
129  * To configure the check so that it matches default Eclipse formatter configuration
130  * (tested on Kepler and Luna releases):
131  * </p>
132  * <ul>
133  * <li>
134  * group of static imports is on the top
135  * </li>
136  * <li>
137  * groups of type imports: "java" and "javax" packages first, then "org" and then all other imports
138  * </li>
139  * <li>
140  * imports will be sorted in the groups
141  * </li>
142  * <li>
143  * groups are separated by, at least, one blank line and aren't separated internally
144  * </li>
145  * </ul>
146  * <p>
147  * Notes:
148  * </p>
149  * <ul>
150  * <li>
151  * "com" package is not mentioned on configuration, because it is ignored by Eclipse Kepler and Luna
152  * (looks like Eclipse defect)
153  * </li>
154  * <li>
155  * configuration below doesn't work in all 100% cases due to inconsistent behavior prior to
156  * Mars release, but covers most scenarios
157  * </li>
158  * </ul>
159  * <pre>
160  * &lt;module name=&quot;ImportOrder&quot;&gt;
161  *   &lt;property name=&quot;groups&quot; value=&quot;/^java\./,javax,org&quot;/&gt;
162  *   &lt;property name=&quot;ordered&quot; value=&quot;true&quot;/&gt;
163  *   &lt;property name=&quot;separated&quot; value=&quot;true&quot;/&gt;
164  *   &lt;property name=&quot;option&quot; value=&quot;above&quot;/&gt;
165  *   &lt;property name=&quot;sortStaticImportsAlphabetically&quot; value=&quot;true&quot;/&gt;
166  * &lt;/module&gt;
167  * </pre>
168  * <p>
169  * To configure the check so that it matches default Eclipse formatter configuration
170  * (tested on Mars release):
171  * </p>
172  * <ul>
173  * <li>
174  * group of static imports is on the top
175  * </li>
176  * <li>
177  * groups of type imports: "java" and "javax" packages first, then "org" and "com",
178  * then all other imports as one group
179  * </li>
180  * <li>
181  * imports will be sorted in the groups
182  * </li>
183  * <li>
184  * groups are separated by, at least, one blank line and aren't separated internally
185  * </li>
186  * </ul>
187  * <pre>
188  * &lt;module name=&quot;ImportOrder&quot;&gt;
189  *   &lt;property name=&quot;groups&quot; value=&quot;/^java\./,javax,org,com&quot;/&gt;
190  *   &lt;property name=&quot;ordered&quot; value=&quot;true&quot;/&gt;
191  *   &lt;property name=&quot;separated&quot; value=&quot;true&quot;/&gt;
192  *   &lt;property name=&quot;option&quot; value=&quot;above&quot;/&gt;
193  *   &lt;property name=&quot;sortStaticImportsAlphabetically&quot; value=&quot;true&quot;/&gt;
194  * &lt;/module&gt;
195  * </pre>
196  * <p>
197  * To configure the check so that it matches default IntelliJ IDEA formatter configuration
198  * (tested on v2018.2):
199  * </p>
200  * <ul>
201  * <li>
202  * group of static imports is on the bottom
203  * </li>
204  * <li>
205  * groups of type imports: all imports except of "javax" and "java", then "javax" and "java"
206  * </li>
207  * <li>
208  * imports will be sorted in the groups
209  * </li>
210  * <li>
211  * groups are separated by, at least, one blank line and aren't separated internally
212  * </li>
213  * </ul>
214  * <p>
215  * Note: a <a href="config_filters.html#SuppressionXpathSingleFilter">
216  * suppression xpath single filter</a> is needed because
217  * IDEA has no blank line between "javax" and "java".
218  * ImportOrder has a limitation by design to enforce an empty line between groups ("java", "javax").
219  * There is no flexibility to enforce empty lines between some groups and no empty lines between
220  * other groups.
221  * </p>
222  * <p>
223  * Note: "separated" option is disabled because IDEA default has blank line between "java" and
224  * static imports, and no blank line between "javax" and "java".
225  * </p>
226  * <pre>
227  * &lt;module name=&quot;ImportOrder&quot;&gt;
228  *   &lt;property name=&quot;groups&quot; value=&quot;*,javax,java&quot;/&gt;
229  *   &lt;property name=&quot;ordered&quot; value=&quot;true&quot;/&gt;
230  *   &lt;property name=&quot;separated&quot; value=&quot;false&quot;/&gt;
231  *   &lt;property name=&quot;option&quot; value=&quot;bottom&quot;/&gt;
232  *   &lt;property name=&quot;sortStaticImportsAlphabetically&quot; value=&quot;true&quot;/&gt;
233  * &lt;/module&gt;
234  * &lt;module name="SuppressionXpathSingleFilter"&gt;
235  *   &lt;property name="checks" value="ImportOrder"/&gt;
236  *   &lt;property name="message" value="^'java\..*'.*"/&gt;
237  * &lt;/module&gt;
238  * </pre>
239  * <p>
240  * To configure the check so that it matches default NetBeans formatter configuration
241  * (tested on v8):
242  * </p>
243  * <ul>
244  * <li>
245  * groups of type imports are not defined, all imports will be sorted as a one group
246  * </li>
247  * <li>
248  * static imports are not separated, they will be sorted along with other imports
249  * </li>
250  * </ul>
251  * <pre>
252  * &lt;module name=&quot;ImportOrder&quot;&gt;
253  *   &lt;property name=&quot;option&quot; value=&quot;inflow&quot;/&gt;
254  * &lt;/module&gt;
255  * </pre>
256  * <p>
257  * Group descriptions enclosed in slashes are interpreted as regular expressions.
258  * If multiple groups match, the one matching a longer substring of the imported name
259  * will take precedence, with ties broken first in favor of earlier matches and finally
260  * in favor of the first matching group.
261  * </p>
262  * <p>
263  * There is always a wildcard group to which everything not in a named group belongs.
264  * If an import does not match a named group, the group belongs to this wildcard group.
265  * The wildcard group position can be specified using the {@code *} character.
266  * </p>
267  * <p>
268  * Check also has on option making it more flexible: <b>sortStaticImportsAlphabetically</b>
269  * - sets whether static imports grouped by <b>top</b> or <b>bottom</b> option should be sorted
270  * alphabetically or not, default value is <b>false</b>. It is applied to static imports grouped
271  * with <b>top</b> or <b>bottom</b> options. This option is helping in reconciling of this
272  * Check and other tools like Eclipse's Organize Imports feature.
273  * </p>
274  * <p>
275  * To configure the Check allows static imports grouped to the <b>top</b> being sorted
276  * alphabetically:
277  * </p>
278  * <pre>
279  * &lt;module name=&quot;ImportOrder&quot;&gt;
280  *   &lt;property name=&quot;sortStaticImportsAlphabetically&quot; value=&quot;true&quot;/&gt;
281  *   &lt;property name=&quot;option&quot; value=&quot;top&quot;/&gt;
282  * &lt;/module&gt;
283  * </pre>
284  * <pre>
285  * import static java.lang.Math.PI;
286  * import static java.lang.Math.abs; // OK, alphabetical case sensitive ASCII order, 'P' &lt; 'a'
287  * import static org.abego.treelayout.Configuration.AlignmentInLevel; // OK, alphabetical order
288  *
289  * import org.abego.*;
290  *
291  * import java.util.Set; //  Wrong order for 'java.util.Set' import.
292  *
293  * public class SomeClass { ... }
294  * </pre>
295  * <p>
296  * To configure the Check with groups of static imports:
297  * </p>
298  * <pre>
299  * &lt;module name=&quot;ImportOrder&quot;&gt;
300  *   &lt;property name=&quot;staticGroups&quot; value=&quot;org,java&quot;/&gt;
301  *   &lt;property name=&quot;sortStaticImportsAlphabetically&quot; value=&quot;true&quot;/&gt;
302  * &lt;/module&gt;
303  * </pre>
304  * <pre>
305  * import static org.abego.treelayout.Configuration.AlignmentInLevel; // Group 1
306  * import static java.lang.Math.abs; // Group 2
307  * import static java.lang.String.format; // Group 2
308  * import static com.google.common.primitives.Doubles.BYTES; // Group "everything else"
309  *
310  * public class SomeClass { ... }
311  * </pre>
312  * <p>
313  * The following example shows the idea of 'useContainerOrderingForStatic' option that is
314  * useful for Eclipse IDE users to match ordering validation.
315  * This is how the import comparison works for static imports: we first compare
316  * the container of the static import, container is the type enclosing the static element
317  * being imported. When the result of the comparison is 0 (containers are equal),
318  * we compare the fully qualified import names.
319  * For e.g. this is what is considered to be container names for the given example:
320  *
321  * import static HttpConstants.COLON     =&gt; HttpConstants
322  * import static HttpHeaders.addHeader   =&gt; HttpHeaders
323  * import static HttpHeaders.setHeader   =&gt; HttpHeaders
324  * import static HttpHeaders.Names.DATE  =&gt; HttpHeaders.Names
325  *
326  * According to this logic, HttpHeaders.Names should come after HttpHeaders.
327  * </p>
328  * <p>
329  * Example for {@code useContainerOrderingForStatic=true}
330  * </p>
331  * <pre>
332  * &lt;module name=&quot;ImportOrder&quot;&gt;
333  *   &lt;property name=&quot;useContainerOrderingForStatic&quot; value=&quot;true&quot;/&gt;
334  *   &lt;property name=&quot;ordered&quot; value=&quot;true&quot;/&gt;
335  *   &lt;property name=&quot;option&quot; value=&quot;top&quot;/&gt;
336  *   &lt;property name=&quot;caseSensitive&quot; value=&quot;false&quot;/&gt;
337  *   &lt;property name=&quot;sortStaticImportsAlphabetically&quot; value=&quot;true&quot;/&gt;
338  * &lt;/module&gt;
339  * </pre>
340  * <pre>
341  * import static io.netty.handler.codec.http.HttpConstants.COLON;
342  * import static io.netty.handler.codec.http.HttpHeaders.addHeader;
343  * import static io.netty.handler.codec.http.HttpHeaders.setHeader;
344  * import static io.netty.handler.codec.http.HttpHeaders.Names.DATE;
345  *
346  * public class InputEclipseStaticImportsOrder { }
347  * </pre>
348  * <p>
349  * Example for {@code useContainerOrderingForStatic=false}
350  * </p>
351  * <pre>
352  * &lt;module name=&quot;ImportOrder&quot;&gt;
353  *   &lt;property name=&quot;useContainerOrderingForStatic&quot; value=&quot;false&quot;/&gt;
354  *   &lt;property name=&quot;ordered&quot; value=&quot;true&quot;/&gt;
355  *   &lt;property name=&quot;option&quot; value=&quot;top&quot;/&gt;
356  *   &lt;property name=&quot;caseSensitive&quot; value=&quot;false&quot;/&gt;
357  *   &lt;property name=&quot;sortStaticImportsAlphabetically&quot; value=&quot;true&quot;/&gt;
358  * &lt;/module&gt;
359  * </pre>
360  * <pre>
361  * import static io.netty.handler.codec.http.HttpConstants.COLON;
362  * import static io.netty.handler.codec.http.HttpHeaders.addHeader;
363  * import static io.netty.handler.codec.http.HttpHeaders.setHeader;
364  * import static io.netty.handler.codec.http.HttpHeaders.Names.DATE; // violation
365  *
366  * public class InputEclipseStaticImportsOrder { }
367  * </pre>
368  *
369  * @since 3.2
370  */
371 @FileStatefulCheck
372 public class ImportOrderCheck
373     extends AbstractCheck {
374 
375     /**
376      * A key is pointing to the warning message text in "messages.properties"
377      * file.
378      */
379     public static final String MSG_SEPARATION = "import.separation";
380 
381     /**
382      * A key is pointing to the warning message text in "messages.properties"
383      * file.
384      */
385     public static final String MSG_ORDERING = "import.ordering";
386 
387     /**
388      * A key is pointing to the warning message text in "messages.properties"
389      * file.
390      */
391     public static final String MSG_SEPARATED_IN_GROUP = "import.groups.separated.internally";
392 
393     /** The special wildcard that catches all remaining groups. */
394     private static final String WILDCARD_GROUP_NAME = "*";
395 
396     /** Empty array of pattern type needed to initialize check. */
397     private static final Pattern[] EMPTY_PATTERN_ARRAY = new Pattern[0];
398 
399     /**
400      * Specify list of <b>type import</b> groups (every group identified either by a common prefix
401      * string, or by a regular expression enclosed in forward slashes (e.g. {@code /regexp/}).
402      * All type imports, which does not match any group, falls into an additional group,
403      * located at the end. Thus, the empty list of type groups (the default value) means one group
404      * for all type imports.
405      */
406     private Pattern[] groups = EMPTY_PATTERN_ARRAY;
407 
408     /**
409      * Specify list of <b>static</b> import groups (every group identified either by a common prefix
410      * string, or by a regular expression enclosed in forward slashes (e.g. {@code /regexp/}).
411      * All static imports, which does not match any group, falls into an additional group, located
412      * at the end. Thus, the empty list of static groups (the default value) means one group for all
413      * static imports. This property has effect only when the property {@code option} is set to
414      * {@code top} or {@code bottom}.
415      */
416     private Pattern[] staticGroups = EMPTY_PATTERN_ARRAY;
417 
418     /**
419      * Control whether type import groups should be separated by, at least, one blank
420      * line or comment and aren't separated internally. It doesn't affect separations for static
421      * imports.
422      */
423     private boolean separated;
424 
425     /**
426      * Control whether static import groups should be separated by, at least, one blank
427      * line or comment and aren't separated internally. This property has effect only when the
428      * property {@code option} is is set to {@code top} or {@code bottom}.
429      */
430     private boolean separatedStaticGroups;
431 
432     /**
433      * Control whether type imports within each group should be sorted.
434      * It doesn't affect sorting for static imports.
435      */
436     private boolean ordered = true;
437 
438     /**
439      * Control whether string comparison should be case sensitive or not. Case sensitive
440      * sorting is in <a href="https://en.wikipedia.org/wiki/ASCII#Order">ASCII sort order</a>.
441      * It affects both type imports and static imports.
442      */
443     private boolean caseSensitive = true;
444 
445     /** Last imported group. */
446     private int lastGroup;
447     /** Line number of last import. */
448     private int lastImportLine;
449     /** Name of last import. */
450     private String lastImport;
451     /** If last import was static. */
452     private boolean lastImportStatic;
453     /** Whether there was any imports. */
454     private boolean beforeFirstImport;
455     /** Whether static and type import groups should be split apart.
456      * When the {@code option} property is set to {@code INFLOW}, {@code BELOW} or {@code UNDER},
457      * both the type and static imports use the properties {@code groups} and {@code separated}.
458      * When the {@code option} property is set to {@code TOP} or {@code BOTTOM}, static imports
459      * uses the properties {@code staticGroups} and {@code separatedStaticGroups}.
460      **/
461     private boolean staticImportsApart;
462 
463     /**
464      * Control whether <b>static imports</b> located at <b>top</b> or <b>bottom</b> are
465      * sorted within the group.
466      */
467     private boolean sortStaticImportsAlphabetically;
468 
469     /**
470      * Control whether to use container ordering (Eclipse IDE term) for static imports
471      * or not.
472      */
473     private boolean useContainerOrderingForStatic;
474 
475     /**
476      * Specify policy on the relative order between type imports and static imports.
477      */
478     private ImportOrderOption option = ImportOrderOption.UNDER;
479 
480     /**
481      * Setter to specify policy on the relative order between type imports and static imports.
482      * @param optionStr string to decode option from
483      * @throws IllegalArgumentException if unable to decode
484      */
485     public void setOption(String optionStr) {
486         option = ImportOrderOption.valueOf(optionStr.trim().toUpperCase(Locale.ENGLISH));
487     }
488 
489     /**
490      * Setter to specify list of <b>type import</b> groups (every group identified either by a
491      * common prefix string, or by a regular expression enclosed in forward slashes
492      * (e.g. {@code /regexp/}). All type imports, which does not match any group, falls into an
493      * additional group, located at the end. Thus, the empty list of type groups (the default value)
494      * means one group for all type imports.
495      *
496      * @param packageGroups a comma-separated list of package names/prefixes.
497      */
498     public void setGroups(String... packageGroups) {
499         groups = compilePatterns(packageGroups);
500     }
501 
502     /**
503      * Setter to specify list of <b>static</b> import groups (every group identified either by a
504      * common prefix string, or by a regular expression enclosed in forward slashes
505      * (e.g. {@code /regexp/}). All static imports, which does not match any group, falls into an
506      * additional group, located at the end. Thus, the empty list of static groups (the default
507      * value) means one group for all static imports. This property has effect only when
508      * the property {@code option} is set to {@code top} or {@code bottom}.
509      *
510      * @param packageGroups a comma-separated list of package names/prefixes.
511      */
512     public void setStaticGroups(String... packageGroups) {
513         staticGroups = compilePatterns(packageGroups);
514     }
515 
516     /**
517      * Setter to control whether type imports within each group should be sorted.
518      * It doesn't affect sorting for static imports.
519      *
520      * @param ordered
521      *            whether lexicographic ordering of imports within a group
522      *            required or not.
523      */
524     public void setOrdered(boolean ordered) {
525         this.ordered = ordered;
526     }
527 
528     /**
529      * Setter to control whether type import groups should be separated by, at least,
530      * one blank line or comment and aren't separated internally.
531      * It doesn't affect separations for static imports.
532      *
533      * @param separated
534      *            whether groups should be separated by one blank line or comment.
535      */
536     public void setSeparated(boolean separated) {
537         this.separated = separated;
538     }
539 
540     /**
541      * Setter to control whether static import groups should be separated by, at least,
542      * one blank line or comment and aren't separated internally.
543      * This property has effect only when the property
544      * {@code option} is is set to {@code top} or {@code bottom}.
545      *
546      * @param separatedStaticGroups
547      *            whether groups should be separated by one blank line or comment.
548      */
549     public void setSeparatedStaticGroups(boolean separatedStaticGroups) {
550         this.separatedStaticGroups = separatedStaticGroups;
551     }
552 
553     /**
554      * Setter to control whether string comparison should be case sensitive or not.
555      * Case sensitive sorting is in
556      * <a href="https://en.wikipedia.org/wiki/ASCII#Order">ASCII sort order</a>.
557      * It affects both type imports and static imports.
558      * @param caseSensitive
559      *            whether string comparison should be case sensitive.
560      */
561     public void setCaseSensitive(boolean caseSensitive) {
562         this.caseSensitive = caseSensitive;
563     }
564 
565     /**
566      * Setter to control whether <b>static imports</b> located at <b>top</b> or
567      * <b>bottom</b> are sorted within the group.
568      * @param sortAlphabetically true or false.
569      */
570     public void setSortStaticImportsAlphabetically(boolean sortAlphabetically) {
571         sortStaticImportsAlphabetically = sortAlphabetically;
572     }
573 
574     /**
575      * Setter to control whether to use container ordering (Eclipse IDE term) for static
576      * imports or not.
577      * @param useContainerOrdering whether to use container ordering for static imports or not.
578      */
579     public void setUseContainerOrderingForStatic(boolean useContainerOrdering) {
580         useContainerOrderingForStatic = useContainerOrdering;
581     }
582 
583     @Override
584     public int[] getDefaultTokens() {
585         return getAcceptableTokens();
586     }
587 
588     @Override
589     public int[] getAcceptableTokens() {
590         return new int[] {TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT};
591     }
592 
593     @Override
594     public int[] getRequiredTokens() {
595         return new int[] {TokenTypes.IMPORT};
596     }
597 
598     @Override
599     public void beginTree(DetailAST rootAST) {
600         lastGroup = Integer.MIN_VALUE;
601         lastImportLine = Integer.MIN_VALUE;
602         lastImport = "";
603         lastImportStatic = false;
604         beforeFirstImport = true;
605         staticImportsApart =
606             option == ImportOrderOption.TOP || option == ImportOrderOption.BOTTOM;
607     }
608 
609     // -@cs[CyclomaticComplexity] SWITCH was transformed into IF-ELSE.
610     @Override
611     public void visitToken(DetailAST ast) {
612         final int line = ast.getLineNo();
613         final FullIdent ident;
614         final boolean isStatic;
615 
616         if (ast.getType() == TokenTypes.IMPORT) {
617             ident = FullIdent.createFullIdentBelow(ast);
618             isStatic = false;
619         }
620         else {
621             ident = FullIdent.createFullIdent(ast.getFirstChild()
622                     .getNextSibling());
623             isStatic = true;
624         }
625 
626         // using set of IF instead of SWITCH to analyze Enum options to satisfy coverage.
627         // https://github.com/checkstyle/checkstyle/issues/1387
628         if (option == ImportOrderOption.TOP || option == ImportOrderOption.ABOVE) {
629             final boolean isStaticAndNotLastImport = isStatic && !lastImportStatic;
630             doVisitToken(ident, isStatic, isStaticAndNotLastImport, line);
631         }
632         else if (option == ImportOrderOption.BOTTOM || option == ImportOrderOption.UNDER) {
633             final boolean isLastImportAndNonStatic = lastImportStatic && !isStatic;
634             doVisitToken(ident, isStatic, isLastImportAndNonStatic, line);
635         }
636         else if (option == ImportOrderOption.INFLOW) {
637             // "previous" argument is useless here
638             doVisitToken(ident, isStatic, true, line);
639         }
640         else {
641             throw new IllegalStateException(
642                     "Unexpected option for static imports: " + option);
643         }
644 
645         lastImportLine = ast.findFirstToken(TokenTypes.SEMI).getLineNo();
646         lastImportStatic = isStatic;
647         beforeFirstImport = false;
648     }
649 
650     /**
651      * Shares processing...
652      *
653      * @param ident the import to process.
654      * @param isStatic whether the token is static or not.
655      * @param previous previous non-static but current is static (above), or
656      *                  previous static but current is non-static (under).
657      * @param line the line of the current import.
658      */
659     private void doVisitToken(FullIdent ident, boolean isStatic, boolean previous, int line) {
660         final String name = ident.getText();
661         final int groupIdx = getGroupNumber(isStatic && staticImportsApart, name);
662 
663         if (groupIdx > lastGroup) {
664             if (!beforeFirstImport && line - lastImportLine < 2 && needSeparator(isStatic)) {
665                 log(line, MSG_SEPARATION, name);
666             }
667         }
668         else if (groupIdx == lastGroup) {
669             doVisitTokenInSameGroup(isStatic, previous, name, line);
670         }
671         else {
672             log(line, MSG_ORDERING, name);
673         }
674         if (isSeparatorInGroup(groupIdx, isStatic, line)) {
675             log(line, MSG_SEPARATED_IN_GROUP, name);
676         }
677 
678         lastGroup = groupIdx;
679         lastImport = name;
680     }
681 
682     /**
683      * Checks whether import groups should be separated.
684      * @param isStatic whether the token is static or not.
685      * @return true if imports groups should be separated.
686      */
687     private boolean needSeparator(boolean isStatic) {
688         final boolean typeImportSeparator = !isStatic && separated;
689         final boolean staticImportSeparator;
690         if (staticImportsApart) {
691             staticImportSeparator = isStatic && separatedStaticGroups;
692         }
693         else {
694             staticImportSeparator = isStatic && separated;
695         }
696         final boolean separatorBetween = isStatic != lastImportStatic
697             && (separated || separatedStaticGroups) && staticImportsApart;
698 
699         return typeImportSeparator || staticImportSeparator || separatorBetween;
700     }
701 
702     /**
703      * Checks whether imports group separated internally.
704      * @param groupIdx group number.
705      * @param isStatic whether the token is static or not.
706      * @param line the line of the current import.
707      * @return true if imports group are separated internally.
708      */
709     private boolean isSeparatorInGroup(int groupIdx, boolean isStatic, int line) {
710         final boolean inSameGroup = groupIdx == lastGroup;
711         return (inSameGroup || !needSeparator(isStatic)) && isSeparatorBeforeImport(line);
712     }
713 
714     /**
715      * Checks whether there is any separator before current import.
716      * @param line the line of the current import.
717      * @return true if there is separator before current import which isn't the first import.
718      */
719     private boolean isSeparatorBeforeImport(int line) {
720         return !beforeFirstImport && line - lastImportLine > 1;
721     }
722 
723     /**
724      * Shares processing...
725      *
726      * @param isStatic whether the token is static or not.
727      * @param previous previous non-static but current is static (above), or
728      *     previous static but current is non-static (under).
729      * @param name the name of the current import.
730      * @param line the line of the current import.
731      */
732     private void doVisitTokenInSameGroup(boolean isStatic,
733             boolean previous, String name, int line) {
734         if (ordered) {
735             if (option == ImportOrderOption.INFLOW) {
736                 if (isWrongOrder(name, isStatic)) {
737                     log(line, MSG_ORDERING, name);
738                 }
739             }
740             else {
741                 final boolean shouldFireError =
742                     // previous non-static but current is static (above)
743                     // or
744                     // previous static but current is non-static (under)
745                     previous
746                         ||
747                         // current and previous static or current and
748                         // previous non-static
749                         lastImportStatic == isStatic
750                     && isWrongOrder(name, isStatic);
751 
752                 if (shouldFireError) {
753                     log(line, MSG_ORDERING, name);
754                 }
755             }
756         }
757     }
758 
759     /**
760      * Checks whether import name is in wrong order.
761      * @param name import name.
762      * @param isStatic whether it is a static import name.
763      * @return true if import name is in wrong order.
764      */
765     private boolean isWrongOrder(String name, boolean isStatic) {
766         final boolean result;
767         if (isStatic) {
768             if (useContainerOrderingForStatic) {
769                 result = compareContainerOrder(lastImport, name, caseSensitive) > 0;
770             }
771             else if (staticImportsApart) {
772                 result = sortStaticImportsAlphabetically
773                     && compare(lastImport, name, caseSensitive) > 0;
774             }
775             else {
776                 result = compare(lastImport, name, caseSensitive) > 0;
777             }
778         }
779         else {
780             // out of lexicographic order
781             result = compare(lastImport, name, caseSensitive) > 0;
782         }
783         return result;
784     }
785 
786     /**
787      * Compares two import strings.
788      * We first compare the container of the static import, container being the type enclosing
789      * the static element being imported. When this returns 0, we compare the qualified
790      * import name. For e.g. this is what is considered to be container names:
791      * <p>
792      * import static HttpConstants.COLON     => HttpConstants
793      * import static HttpHeaders.addHeader   => HttpHeaders
794      * import static HttpHeaders.setHeader   => HttpHeaders
795      * import static HttpHeaders.Names.DATE  => HttpHeaders.Names
796      * </p>
797      * <p>
798      * According to this logic, HttpHeaders.Names would come after HttpHeaders.
799      *
800      * For more details, see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=473629#c3">
801      * static imports comparison method</a> in Eclipse.
802      * </p>
803      *
804      * @param importName1 first import name.
805      * @param importName2 second import name.
806      * @param caseSensitive whether the comparison of fully qualified import names is case
807      *                      sensitive.
808      * @return the value {@code 0} if str1 is equal to str2; a value
809      *         less than {@code 0} if str is less than the str2 (container order
810      *         or lexicographical); and a value greater than {@code 0} if str1 is greater than str2
811      *         (container order or lexicographically).
812      */
813     private static int compareContainerOrder(String importName1, String importName2,
814                                              boolean caseSensitive) {
815         final String container1 = getImportContainer(importName1);
816         final String container2 = getImportContainer(importName2);
817         final int compareContainersOrderResult;
818         if (caseSensitive) {
819             compareContainersOrderResult = container1.compareTo(container2);
820         }
821         else {
822             compareContainersOrderResult = container1.compareToIgnoreCase(container2);
823         }
824         final int result;
825         if (compareContainersOrderResult == 0) {
826             result = compare(importName1, importName2, caseSensitive);
827         }
828         else {
829             result = compareContainersOrderResult;
830         }
831         return result;
832     }
833 
834     /**
835      * Extracts import container name from fully qualified import name.
836      * An import container name is the type which encloses the static element being imported.
837      * For example, HttpConstants, HttpHeaders, HttpHeaders.Names are import container names:
838      * <p>
839      * import static HttpConstants.COLON     => HttpConstants
840      * import static HttpHeaders.addHeader   => HttpHeaders
841      * import static HttpHeaders.setHeader   => HttpHeaders
842      * import static HttpHeaders.Names.DATE  => HttpHeaders.Names
843      * </p>
844      * @param qualifiedImportName fully qualified import name.
845      * @return import container name.
846      */
847     private static String getImportContainer(String qualifiedImportName) {
848         final int lastDotIndex = qualifiedImportName.lastIndexOf('.');
849         return qualifiedImportName.substring(0, lastDotIndex);
850     }
851 
852     /**
853      * Finds out what group the specified import belongs to.
854      *
855      * @param isStatic whether the token is static or not.
856      * @param name the import name to find.
857      * @return group number for given import name.
858      */
859     private int getGroupNumber(boolean isStatic, String name) {
860         final Pattern[] patterns;
861         if (isStatic) {
862             patterns = staticGroups;
863         }
864         else {
865             patterns = groups;
866         }
867 
868         int number = getGroupNumber(patterns, name);
869 
870         if (isStatic && option == ImportOrderOption.BOTTOM) {
871             number += groups.length + 1;
872         }
873         else if (!isStatic && option == ImportOrderOption.TOP) {
874             number += staticGroups.length + 1;
875         }
876         return number;
877     }
878 
879     /**
880      * Finds out what group the specified import belongs to.
881      *
882      * @param patterns groups to check.
883      * @param name the import name to find.
884      * @return group number for given import name.
885      */
886     private static int getGroupNumber(Pattern[] patterns, String name) {
887         int bestIndex = patterns.length;
888         int bestEnd = -1;
889         int bestPos = Integer.MAX_VALUE;
890 
891         // find out what group this belongs in
892         // loop over patterns and get index
893         for (int i = 0; i < patterns.length; i++) {
894             final Matcher matcher = patterns[i].matcher(name);
895             if (matcher.find()) {
896                 if (matcher.start() < bestPos) {
897                     bestIndex = i;
898                     bestEnd = matcher.end();
899                     bestPos = matcher.start();
900                 }
901                 else if (matcher.start() == bestPos && matcher.end() > bestEnd) {
902                     bestIndex = i;
903                     bestEnd = matcher.end();
904                 }
905             }
906         }
907         return bestIndex;
908     }
909 
910     /**
911      * Compares two strings.
912      *
913      * @param string1
914      *            the first string.
915      * @param string2
916      *            the second string.
917      * @param caseSensitive
918      *            whether the comparison is case sensitive.
919      * @return the value {@code 0} if string1 is equal to string2; a value
920      *         less than {@code 0} if string1 is lexicographically less
921      *         than the string2; and a value greater than {@code 0} if
922      *         string1 is lexicographically greater than string2.
923      */
924     private static int compare(String string1, String string2,
925             boolean caseSensitive) {
926         final int result;
927         if (caseSensitive) {
928             result = string1.compareTo(string2);
929         }
930         else {
931             result = string1.compareToIgnoreCase(string2);
932         }
933 
934         return result;
935     }
936 
937     /**
938      * Compiles the list of package groups and the order they should occur in the file.
939      *
940      * @param packageGroups a comma-separated list of package names/prefixes.
941      * @return array of compiled patterns.
942      */
943     private static Pattern[] compilePatterns(String... packageGroups) {
944         final Pattern[] patterns = new Pattern[packageGroups.length];
945 
946         for (int i = 0; i < packageGroups.length; i++) {
947             String pkg = packageGroups[i];
948             final Pattern grp;
949 
950             // if the pkg name is the wildcard, make it match zero chars
951             // from any name, so it will always be used as last resort.
952             if (WILDCARD_GROUP_NAME.equals(pkg)) {
953                 // matches any package
954                 grp = Pattern.compile("");
955             }
956             else if (CommonUtil.startsWithChar(pkg, '/')) {
957                 if (!CommonUtil.endsWithChar(pkg, '/')) {
958                     throw new IllegalArgumentException("Invalid group: " + pkg);
959                 }
960                 pkg = pkg.substring(1, pkg.length() - 1);
961                 grp = Pattern.compile(pkg);
962             }
963             else {
964                 final StringBuilder pkgBuilder = new StringBuilder(pkg);
965                 if (!CommonUtil.endsWithChar(pkg, '.')) {
966                     pkgBuilder.append('.');
967                 }
968                 grp = Pattern.compile("^" + Pattern.quote(pkgBuilder.toString()));
969             }
970 
971             patterns[i] = grp;
972         }
973         return patterns;
974     }
975 
976 }