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