From 22136c67e9c83494e7aa977ffe7a79beee1b4175 Mon Sep 17 00:00:00 2001 From: Oliver Burn Date: Sun, 7 Sep 2008 11:28:48 +0000 Subject: [PATCH] Add new options to the ImportOrderCheck to make it more flexible. Thanks to David Didier for providing patch #1854213. --- .../checks/imports/ImportOrderCheck.java | 348 ++++++++++++------ .../checks/imports/ImportOrderOption.java | 106 ++++++ .../imports/InputImportOrder_Above.java | 20 + .../imports/InputImportOrder_Bottom.java | 24 ++ .../imports/InputImportOrder_InFlow.java | 22 ++ .../imports/InputImportOrder_Top.java | 23 ++ .../imports/InputImportOrder_Under.java | 20 + .../checks/imports/ImportOrderCheckTest.java | 79 ++++ src/xdocs/config_imports.xml | 39 +- src/xdocs/property_types.xml | 79 +++- src/xdocs/releasenotes.xml | 6 + 11 files changed, 636 insertions(+), 130 deletions(-) create mode 100644 src/checkstyle/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderOption.java create mode 100644 src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Above.java create mode 100644 src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Bottom.java create mode 100644 src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_InFlow.java create mode 100644 src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Top.java create mode 100644 src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Under.java diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheck.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheck.java index 15b882cc0..0c811d681 100644 --- a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheck.java +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheck.java @@ -19,55 +19,74 @@ package com.puppycrawl.tools.checkstyle.checks.imports; -import com.puppycrawl.tools.checkstyle.api.Check; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.checks.AbstractOptionCheck; /** - * Class to check the ordering/grouping of imports. Ensures that - * groups of imports come in a specific order (e.g., java. comes - * first, javax. comes second, then everything else) and imports - * within each group are in lexicographic order. Static imports must - * be at the end of a group and in lexicographic order amongst themselves. + * Class to check the ordering/grouping of imports. Features are: + * * *

* Example: + *

+ * *
- *  <module name="ImportOrder">
- *    <property name="groups" value="java,javax"/>
- *    <property name="ordered" value="true"/>
- *    <property name="caseSensitive" value="false"/>
- *  </module>
+ *  <module name="ImportOrder">
+ *    <property name="groups" value="java,javax"/>
+ *    <property name="ordered" value="true"/>
+ *    <property name="caseSensitive" value="false"/>
+ *    <property name="option" value="above"/>
+ *  </module>
  * 
* + *

* There is always an additional, implied "everything else" package - * group. If no "groups" property is supplied, all imports belong in - * this "everything else" group.

- * - *

- * ordered defaults to true. + * group. If no "groups" property is supplied, all imports belong in + * this "everything else" group. *

* *

- * separated defaults to false. + * Defaults: *

+ * * + *

* Compatible with Java 1.5 source. + *

* * @author Bill Schneider * @author o_sukhodolsky + * @author David DIDIER */ -public class ImportOrderCheck extends Check +public class ImportOrderCheck + extends AbstractOptionCheck { /** List of import groups specified by the user. */ private String[] mGroups = new String[0]; - - /** Require imports in group. */ - private boolean mOrdered = true; - /** Require imports in group be separated. */ private boolean mSeparated; + /** Require imports in group. */ + private boolean mOrdered = true; /** Should comparison be case sensitive. */ private boolean mCaseSensitive = true; @@ -83,21 +102,23 @@ public class ImportOrderCheck extends Check private boolean mBeforeFirstImport; /** - * Default constructor. + * Groups static imports under each group. */ public ImportOrderCheck() { + super(ImportOrderOption.UNDER, ImportOrderOption.class); } /** - * sets the list of package groups and the order they should - * occur in the file. + * Sets the list of package groups and the order they should occur in the + * file. * - * @param aGroups a comma-separated list of package names/prefixes + * @param aGroups + * a comma-separated list of package names/prefixes. */ public void setGroups(String[] aGroups) { - mGroups = new String[ aGroups.length ]; + mGroups = new String[aGroups.length]; for (int i = 0; i < aGroups.length; i++) { String pkg = aGroups[i]; @@ -111,11 +132,12 @@ public class ImportOrderCheck extends Check } /** - * Sets whether or not imports should be ordered within any one - * group of imports. + * Sets whether or not imports should be ordered within any one group of + * imports. * - * @param aOrdered whether lexicographic ordering of imports within - * a group required or not. + * @param aOrdered + * whether lexicographic ordering of imports within a group + * required or not. */ public void setOrdered(boolean aOrdered) { @@ -123,10 +145,11 @@ public class ImportOrderCheck extends Check } /** - * Sets whether or not groups of imports must be separated from - * one another by at least one blank line. + * Sets whether or not groups of imports must be separated from one another + * by at least one blank line. * - * @param aSeparated whehter groups should be separated by blank line. + * @param aSeparated + * whether groups should be separated by oen blank line. */ public void setSeparated(boolean aSeparated) { @@ -134,10 +157,10 @@ public class ImportOrderCheck extends Check } /** - * Sets whether string comparision should be case sensitive - * or not. - * @param aCaseSensitive whether string comparision should be - * case sensitive. + * Sets whether string comparison should be case sensitive or not. + * + * @param aCaseSensitive + * whether string comparison should be case sensitive. */ public void setCaseSensitive(boolean aCaseSensitive) { @@ -147,7 +170,7 @@ public class ImportOrderCheck extends Check @Override public int[] getDefaultTokens() { - return new int[]{TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT}; + return new int[] {TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT}; } @Override @@ -156,8 +179,156 @@ public class ImportOrderCheck extends Check return getDefaultTokens(); } + @Override + public void beginTree(DetailAST aRootAST) + { + mLastGroup = Integer.MIN_VALUE; + mLastImportLine = Integer.MIN_VALUE; + mLastImport = ""; + mLastImportStatic = false; + mBeforeFirstImport = true; + } + + @Override + public void visitToken(DetailAST aAST) + { + final FullIdent ident; + final boolean isStatic; + + if (aAST.getType() == TokenTypes.IMPORT) { + ident = FullIdent.createFullIdentBelow(aAST); + isStatic = false; + } + else { + ident = FullIdent.createFullIdent((DetailAST) aAST.getFirstChild() + .getNextSibling()); + isStatic = true; + } + + switch (getAbstractOption()) { + case TOP: + if (!isStatic && mLastImportStatic) { + mLastGroup = Integer.MIN_VALUE; + mLastImport = ""; + } + // no break; + + case ABOVE: + // previous non-static but current is static + doVisitToken(ident, isStatic, (!mLastImportStatic && isStatic)); + break; + + case INFLOW: + // previous argument is useless here + doVisitToken(ident, isStatic, true); + break; + + case BOTTOM: + if (isStatic && !mLastImportStatic) { + mLastGroup = Integer.MIN_VALUE; + mLastImport = ""; + } + // no break; + + case UNDER: + // previous static but current is non-static + doVisitToken(ident, isStatic, (mLastImportStatic && !isStatic)); + break; + + default: + break; + } + + mLastImportLine = aAST.findFirstToken(TokenTypes.SEMI).getLineNo(); + mLastImportStatic = isStatic; + mBeforeFirstImport = false; + } + /** - * @param aName import name to check. + * Shares processing... + * + * @param aIdent the import to process. + * @param aIsStatic whether the token is static or not. + * @param aPrevious previous non-static but current is static (above), or + * previous static but current is non-static (under). + */ + private void doVisitToken(FullIdent aIdent, boolean aIsStatic, + boolean aPrevious) + { + if (aIdent != null) { + final String name = aIdent.getText(); + final int groupIdx = getGroupNumber(name); + final int line = aIdent.getLineNo(); + + if (groupIdx > mLastGroup) { + if (!mBeforeFirstImport && mSeparated) { + // This check should be made more robust to handle + // comments and imports that span more than one line. + if ((line - mLastImportLine) < 2) { + log(line, "import.separation", name); + } + } + } + else if (groupIdx == mLastGroup) { + doVisitTokenInSameGroup(aIdent, aIsStatic, aPrevious, name, + line); + } + else { + log(line, "import.ordering", name); + } + + mLastGroup = groupIdx; + mLastImport = name; + } + } + + /** + * Shares processing... + * + * @param aIdent the import to process. + * @param aIsStatic whether the token is static or not. + * @param aPrevious previous non-static but current is static (above), or + * previous static but current is non-static (under). + * @param aName the name of the current import. + * @param aLine the line of the current import. + */ + private void doVisitTokenInSameGroup(FullIdent aIdent, boolean aIsStatic, + boolean aPrevious, String aName, int aLine) + { + if (!mOrdered) { + return; + } + + if (getAbstractOption().equals(ImportOrderOption.INFLOW)) { + // out of lexicographic order + if (compare(mLastImport, aName, mCaseSensitive) >= 0) { + log(aLine, "import.ordering", aName); + } + } + else { + final boolean shouldFireError = + // current and previous static or current and + // previous non-static + (!(mLastImportStatic ^ aIsStatic) + && + // and out of lexicographic order + (compare(mLastImport, aName, mCaseSensitive) >= 0)) + || + // previous non-static but current is static (above) + // or + // previous static but current is non-static (under) + aPrevious; + + if (shouldFireError) { + log(aLine, "import.ordering", aName); + } + } + } + + /** + * Finds out what group the specified import belongs to. + * + * @param aName the import name to find. * @return group number for given import name. */ private int getGroupNumber(String aName) @@ -175,86 +346,27 @@ public class ImportOrderCheck extends Check return i; } - @Override - public void beginTree(DetailAST aRootAST) + /** + * Compares two strings. + * + * @param aString1 + * the first string. + * @param aString2 + * the second string. + * @param aCaseSensitive + * whether the comparison is case sensitive. + * @return the value 0 if string1 is equal to string2; a value + * less than 0 if string1 is lexicographically less + * than the string2; and a value greater than 0 if + * string1 is lexicographically greater than string2. + */ + private int compare(String aString1, String aString2, + boolean aCaseSensitive) { - mLastGroup = Integer.MIN_VALUE; - mLastImportLine = Integer.MIN_VALUE; - mLastImport = ""; - mLastImportStatic = false; - mBeforeFirstImport = true; - } - - @Override - public void visitToken(DetailAST aAST) - { - final FullIdent ident; - boolean isStatic; - if (aAST.getType() == TokenTypes.IMPORT) { - ident = FullIdent.createFullIdentBelow(aAST); - isStatic = false; - } - else { - ident = FullIdent.createFullIdent( - (DetailAST) aAST.getFirstChild().getNextSibling()); - isStatic = true; + if (aCaseSensitive) { + return aString1.compareTo(aString2); } - if (ident != null) { - final String name = ident.getText(); - final int groupIdx = getGroupNumber(name); - final int line = ident.getLineNo(); - - if (groupIdx > mLastGroup) { - if (!mBeforeFirstImport && mSeparated) { - // This check should be made more robust to handle - // comments and imports that span more than one line. - if (line - mLastImportLine < 2) { - log(line, "import.separation", name); - } - } - } - else if (groupIdx == mLastGroup) { - if (mOrdered) { - boolean shouldFireError = false; - if (mCaseSensitive) { - shouldFireError = - //current and previous static or current and - //previous non-static - (!(mLastImportStatic ^ isStatic) - && - //and out of lexicographic order - (mLastImport.compareTo(name) >= 0)) - || - //previous static but current is non-static - (mLastImportStatic && !isStatic); - } - else { - shouldFireError = - //current and previous static or current and - //previous non-static - (!(mLastImportStatic ^ isStatic) - && - //and out of lexicographic order - (mLastImport.compareToIgnoreCase(name) >= 0)) - || - //previous static but current is non-static - (mLastImportStatic && !isStatic); - } - if (shouldFireError) { - log(line, "import.ordering", name); - } - } - } - else { - log(line, "import.ordering", name); - } - - mLastGroup = groupIdx; - mLastImport = name; - mLastImportLine = aAST.findFirstToken(TokenTypes.SEMI).getLineNo(); - mLastImportStatic = isStatic; - mBeforeFirstImport = false; - } + return aString1.compareToIgnoreCase(aString2); } } diff --git a/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderOption.java b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderOption.java new file mode 100644 index 000000000..0d79bf319 --- /dev/null +++ b/src/checkstyle/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderOption.java @@ -0,0 +1,106 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2008 Oliver Burn +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// +package com.puppycrawl.tools.checkstyle.checks.imports; + +/** + * Represents the policy for checking import order statements. + * @see com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck + * @author David DIDIER + */ +public enum ImportOrderOption +{ + /** + * Represents the policy that static imports are all at the top. + * For example: + * + *
+        import static java.awt.Button.ABORT;
+        import static java.io.File.createTempFile;
+        import static javax.swing.WindowConstants.*;
+
+        import java.awt.Button;
+        import java.awt.event.ActionEvent;
+     * 
+ */ + TOP, + + /** + * Represents the policy that static imports are above the local group. + * For example: + * + *
+        import static java.awt.Button.A;
+        import static javax.swing.WindowConstants.*;
+        import java.awt.Dialog;
+        import javax.swing.JComponent;
+
+        import static java.io.File.createTempFile;
+        import java.io.File;
+        import java.io.IOException;
+     * 
+ */ + ABOVE, + + /** + * Represents the policy that static imports are processed like non static + * imports. For example: + * + *
+        import java.awt.Button;
+        import static java.awt.Button.ABORT;
+        import java.awt.Dialog;
+
+        import static javax.swing.WindowConstants.HIDE_ON_CLOSE;
+        import javax.swing.JComponent;
+     * 
+ */ + INFLOW, + + /** + * Represents the policy that static imports are under the local group. + * For example: + * + *
+        import java.awt.Dialog;
+        import javax.swing.JComponent;
+        import static java.awt.Button.A;
+        import static javax.swing.WindowConstants.*;
+
+        import java.io.File;
+        import java.io.IOException;
+        import static java.io.File.createTempFile;
+     * 
+ */ + UNDER, + + /** + * Represents the policy that static imports are all at the bottom. + * For example: + * + *
+        import java.awt.Button;
+        import java.awt.event.ActionEvent;
+
+        import static java.awt.Button.ABORT;
+        import static java.io.File.createTempFile;
+        import static javax.swing.WindowConstants.*;
+     * 
+ */ + BOTTOM; +} diff --git a/src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Above.java b/src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Above.java new file mode 100644 index 000000000..6d8ee6c6b --- /dev/null +++ b/src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Above.java @@ -0,0 +1,20 @@ +package com.puppycrawl.tools.checkstyle.imports; + +import static java.awt.Button.ABORT; +import static javax.swing.WindowConstants.*; +import static java.awt.Button.ABORT; +import java.awt.Button; +import java.awt.Frame; +import java.awt.Dialog; +import java.awt.event.ActionEvent; +import javax.swing.JComponent; +import javax.swing.JTable; + +import java.io.File; +import static java.io.File.createTempFile; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; + +public class InputImportOrder_Above { +} \ No newline at end of file diff --git a/src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Bottom.java b/src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Bottom.java new file mode 100644 index 000000000..b9e1133c2 --- /dev/null +++ b/src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Bottom.java @@ -0,0 +1,24 @@ +package com.puppycrawl.tools.checkstyle.imports; + +import java.awt.Button; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.event.ActionEvent; + +import java.io.IOException; +import java.io.InputStream; + +import javax.swing.JComponent; +import javax.swing.JTable; + +import static java.io.File.*; +import java.io.File; + +import static java.io.File.createTempFile; +import static java.awt.Button.ABORT; +import static javax.swing.WindowConstants.*; + +import java.io.Reader; + +public class InputImportOrder_Bottom { +} \ No newline at end of file diff --git a/src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_InFlow.java b/src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_InFlow.java new file mode 100644 index 000000000..8a0b5556d --- /dev/null +++ b/src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_InFlow.java @@ -0,0 +1,22 @@ +package com.puppycrawl.tools.checkstyle.imports; + +import java.awt.Button; +import static java.awt.Button.ABORT; +import java.awt.Frame; +import java.awt.Dialog; +import java.awt.event.ActionEvent; + +import javax.swing.JComponent; +import static javax.swing.WindowConstants.HIDE_ON_CLOSE; +import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE; +import static javax.swing.WindowConstants.*; +import javax.swing.JTable; + +import static java.io.File.createTempFile; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; + +public class InputImportOrder_InFlow { +} \ No newline at end of file diff --git a/src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Top.java b/src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Top.java new file mode 100644 index 000000000..a27124d9d --- /dev/null +++ b/src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Top.java @@ -0,0 +1,23 @@ +package com.puppycrawl.tools.checkstyle.imports; + +import static java.io.File.createTempFile; +import static java.awt.Button.ABORT; +import static javax.swing.WindowConstants.*; + +import java.awt.Button; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.event.ActionEvent; + +import java.io.IOException; +import java.io.InputStream; + +import javax.swing.JComponent; +import javax.swing.JTable; + +import static java.io.File.*; +import java.io.File; +import java.io.Reader; + +public class InputImportOrder_Top { +} \ No newline at end of file diff --git a/src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Under.java b/src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Under.java new file mode 100644 index 000000000..258695115 --- /dev/null +++ b/src/testinputs/com/puppycrawl/tools/checkstyle/imports/InputImportOrder_Under.java @@ -0,0 +1,20 @@ +package com.puppycrawl.tools.checkstyle.imports; + +import java.awt.Button; +import java.awt.Frame; +import java.awt.Dialog; +import java.awt.event.ActionEvent; +import javax.swing.JComponent; +import javax.swing.JTable; +import static java.awt.Button.ABORT; +import static javax.swing.WindowConstants.*; +import static java.awt.Button.ABORT; + +import static java.io.File.createTempFile; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; + +public class InputImportOrder_Under { +} \ No newline at end of file diff --git a/src/tests/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheckTest.java b/src/tests/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheckTest.java index cb9692db9..30c8eb9cd 100644 --- a/src/tests/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheckTest.java +++ b/src/tests/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheckTest.java @@ -62,4 +62,83 @@ public class ImportOrderCheckTest extends BaseCheckTestSupport verify(checkConfig, getPath("imports" + File.separator + "InputImportOrderCaseInsensitive.java"), expected); } + + @Test + public void testTop() throws Exception + { + final DefaultConfiguration checkConfig = + createCheckConfig(ImportOrderCheck.class); + checkConfig.addAttribute("option", "top"); + final String[] expected = { + "4: Wrong order for 'java.awt.Button.ABORT' import.", + "18: Wrong order for 'java.io.File.*' import." + }; + + verify(checkConfig, getPath("imports" + File.separator + "InputImportOrder_Top.java"), expected); + } + + @Test + public void testAbove() throws Exception + { + final DefaultConfiguration checkConfig = + createCheckConfig(ImportOrderCheck.class); + checkConfig.addAttribute("option", "above"); + final String[] expected = { + "5: Wrong order for 'java.awt.Button.ABORT' import.", + "8: Wrong order for 'java.awt.Dialog' import.", + "13: Wrong order for 'java.io.File' import.", + "14: Wrong order for 'java.io.File.createTempFile' import." + }; + + verify(checkConfig, getPath("imports" + File.separator + "InputImportOrder_Above.java"), expected); + } + + @Test + public void testInFlow() throws Exception + { + final DefaultConfiguration checkConfig = + createCheckConfig(ImportOrderCheck.class); + checkConfig.addAttribute("option", "inflow"); + final String[] expected = { + "6: Wrong order for 'java.awt.Dialog' import.", + "11: Wrong order for 'javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE' import.", + "12: Wrong order for 'javax.swing.WindowConstants.*' import.", + "13: Wrong order for 'javax.swing.JTable' import.", + "15: Wrong order for 'java.io.File.createTempFile' import.", + "16: Wrong order for 'java.io.File' import." + }; + + verify(checkConfig, getPath("imports" + File.separator + "InputImportOrder_InFlow.java"), expected); + } + + @Test + public void testUnder() throws Exception + { + // is default (testDefault) + final DefaultConfiguration checkConfig = + createCheckConfig(ImportOrderCheck.class); + checkConfig.addAttribute("option", "under"); + final String[] expected = { + "5: Wrong order for 'java.awt.Dialog' import.", + "11: Wrong order for 'java.awt.Button.ABORT' import.", + "14: Wrong order for 'java.io.File' import." + }; + + verify(checkConfig, getPath("imports" + File.separator + "InputImportOrder_Under.java"), expected); + } + + @Test + public void testBottom() throws Exception + { + final DefaultConfiguration checkConfig = + createCheckConfig(ImportOrderCheck.class); + checkConfig.addAttribute("option", "bottom"); + final String[] expected = { + "15: Wrong order for 'java.io.File' import.", + "18: Wrong order for 'java.awt.Button.ABORT' import.", + "21: Wrong order for 'java.io.Reader' import." + }; + + verify(checkConfig, getPath("imports" + File.separator + "InputImportOrder_Bottom.java"), expected); + } } diff --git a/src/xdocs/config_imports.xml b/src/xdocs/config_imports.xml index d5edbf06f..7137aa65a 100755 --- a/src/xdocs/config_imports.xml +++ b/src/xdocs/config_imports.xml @@ -323,12 +323,21 @@ class FooBar {

- Checks the ordering/grouping of imports. Ensures that groups of - imports come in a specific order (e.g., java. comes first, - javax. comes first, then everything else) and imports within each - group are in lexicographic order. - Static imports must be at the end of a group and in lexicographic - order amongst themselves. + Checks the ordering/grouping of imports. Features are: +

    +
  • groups imports: ensures that groups of imports come in a + specific order (e.g., java. comes first, javax. comes second, + then everything else)
  • +
  • adds a separation between groups : ensures that a blank + line sit between each group
  • +
  • sorts imports inside each group: ensures that imports + within each group are in lexicographic order
  • +
  • sorts according to case: ensures that the comparison + between imports is case sensitive
  • +
  • groups static imports: ensures the relative order between + regular imports and static imports (see + import orders)
  • +

@@ -340,6 +349,12 @@ class FooBar { type default value + + option + policy on the relative order between regular imports and static imports + import order + under + groups @@ -375,10 +390,13 @@ class FooBar {

- To configure the check so that it requires "java" packages - first, than "javax" and than all other imports, imports - will be sorted in the groups and groups are separated by, at least, - on blank line: + To configure the check so that it requires that: +

    +
  • "java" packages first, then "javax" and then all other imports
  • +
  • imports will be sorted in the groups
  • +
  • groups are separated by, at least, on blank line
  • +
  • static imports are above each local groups
  • +

@@ -386,6 +404,7 @@ class FooBar { <property name="groups" value="java,javax"/> <property name="ordered" value="true"/> <property name="separated" value="true"/> + <property name="option" value="above"/> </module>
diff --git a/src/xdocs/property_types.xml b/src/xdocs/property_types.xml index 263ccd221..45a659dcd 100755 --- a/src/xdocs/property_types.xml +++ b/src/xdocs/property_types.xml @@ -65,7 +65,7 @@ This property represents a regular expression. The string representation is parsed using java.util.regex - package. + package.

@@ -178,7 +178,7 @@ Option Definition - + eol @@ -330,5 +330,80 @@ + +
+

+ This property represents the policy for checking imports order. + The following table describes the valid options: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OptionDefinition
topAll static imports are at the top. For example: +
+    import static a.b.C.*;
+    import static x.y.Z.*;
+
+    import a.b.D;
+    import x.y.Z;
+
aboveAll static imports are above the local group.. For example: +
+    import static a.b.C.*;
+    import a.b.D;
+
+    import static x.y.Z.*;
+    import x.y.Z;
+
inflowAll static imports are processed like non static + imports. For example: +
+    import static a.b.C.*;
+    import a.b.D;
+
+    import x.y.Z;
+    import static x.y.Z.*;
+
underAll static imports are under the local group. For example: +
+    import a.b.D;
+    import static a.b.C.*;
+
+    import x.y.Z;
+    import static x.y.Z.*;
+
bottomAll static imports are at the bottom. For example: +
+    import a.b.D;
+    import x.y.Z;
+
+    import static a.b.C.*;
+    import static x.y.Z.*;
+
+
diff --git a/src/xdocs/releasenotes.xml b/src/xdocs/releasenotes.xml index ad0a43a7c..cd2c13892 100755 --- a/src/xdocs/releasenotes.xml +++ b/src/xdocs/releasenotes.xml @@ -18,6 +18,12 @@ for enforcing the maximum number of outer types per file. Inspired by patch #1145023 from Alexander Jesse. +
  • + Add new options to the ImportOrderCheck + to make it more flexible. Thanks to David Didier for providing + patch #1854213. +
  • Fixed Bugs: