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 AbstractOptionCheck0 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: +
- 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: +
+ This property represents the policy for checking imports order. + The following table describes the valid options: +
+ +| Option | +Definition | +
| top | +All 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;+ |
+
| above | +All 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;+ |
+
| inflow | +All 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.*;+ |
+
| under | +All 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.*;+ |
+
| bottom | +All 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.*;+ |
+