Add new options to the ImportOrderCheck to make it more flexible. Thanks to David Didier for providing patch #1854213.

This commit is contained in:
Oliver Burn 2008-09-07 11:28:48 +00:00
parent 94e8285d4c
commit 22136c67e9
11 changed files with 636 additions and 130 deletions

View File

@ -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:
* <ul>
* <li>groups imports: ensures that groups of imports come in a specific order
* (e.g., java. comes first, javax. comes second, then everything else)</li>
* <li>adds a separation between groups : ensures that a blank line sit between
* each group</li>
* <li>sorts imports inside each group: ensures that imports within each group
* are in lexicographic order</li>
* <li>sorts according to case: ensures that the comparison between import is
* case sensitive</li>
* <li>groups static imports: ensures that static imports are at the top (or the
* bottom) of all the imports, or above (or under) each group, or are treated
* like non static imports (@see {@link ImportOrderOption}</li>
* </ul>
*
* <p>
* Example:
* </p>
*
* <pre>
* &lt;module name=&quot;ImportOrder&quot;>
* &lt;property name=&quot;groups&quot; value=&quot;java,javax&quot;/>
* &lt;property name=&quot;ordered&quot; value=&quot;true&quot;/>
* &lt;property name=&quot;caseSensitive&quot; value=&quot;false&quot;/>
* &lt;/module>
* &lt;module name=&quot;ImportOrder&quot;&gt;
* &lt;property name=&quot;groups&quot; value=&quot;java,javax&quot;/&gt;
* &lt;property name=&quot;ordered&quot; value=&quot;true&quot;/&gt;
* &lt;property name=&quot;caseSensitive&quot; value=&quot;false&quot;/&gt;
* &lt;property name=&quot;option&quot; value=&quot;above&quot;/&gt;
* &lt;/module&gt;
* </pre>
*
* <p>
* There is always an additional, implied &quot;everything else&quot; package
* group. If no &quot;groups&quot; property is supplied, all imports belong in
* this &quot;everything else&quot; group. </p>
*
* <p>
* ordered defaults to true.
* group. If no &quot;groups&quot; property is supplied, all imports belong in
* this &quot;everything else&quot; group.
* </p>
*
* <p>
* separated defaults to false.
* Defaults:
* </p>
* <ul>
* <li>import groups: none</li>
* <li>separation: false</li>
* <li>ordered: true</li>
* <li>case sensitive: true</li>
* <li>static import: under</li>
* </ul>
*
* <p>
* Compatible with Java 1.5 source.
* </p>
*
* @author Bill Schneider
* @author o_sukhodolsky
* @author David DIDIER
*/
public class ImportOrderCheck extends Check
public class ImportOrderCheck
extends AbstractOptionCheck<ImportOrderOption>
{
/** 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 <code>0</code> if string1 is equal to string2; a value
* less than <code>0</code> if string1 is lexicographically less
* than the string2; and a value greater than <code>0</code> 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);
}
}

View File

@ -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:
*
* <pre>
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;
* </pre>
*/
TOP,
/**
* Represents the policy that static imports are above the local group.
* For example:
*
* <pre>
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;
* </pre>
*/
ABOVE,
/**
* Represents the policy that static imports are processed like non static
* imports. For example:
*
* <pre>
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;
* </pre>
*/
INFLOW,
/**
* Represents the policy that static imports are under the local group.
* For example:
*
* <pre>
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;
* </pre>
*/
UNDER,
/**
* Represents the policy that static imports are all at the bottom.
* For example:
*
* <pre>
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.*;
* </pre>
*/
BOTTOM;
}

View File

@ -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 {
}

View File

@ -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 {
}

View File

@ -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 {
}

View File

@ -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 {
}

View File

@ -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 {
}

View File

@ -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);
}
}

View File

@ -323,12 +323,21 @@ class FooBar {
<section name="ImportOrder">
<subsection name="Description">
<p>
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:
<ul>
<li>groups imports: ensures that groups of imports come in a
specific order (e.g., java. comes first, javax. comes second,
then everything else)</li>
<li>adds a separation between groups : ensures that a blank
line sit between each group</li>
<li>sorts imports inside each group: ensures that imports
within each group are in lexicographic order</li>
<li>sorts according to case: ensures that the comparison
between imports is case sensitive</li>
<li>groups static imports: ensures the relative order between
regular imports and static imports (see
<a href="property_types.html#importOrder">import orders</a>)</li>
</ul>
</p>
</subsection>
@ -340,6 +349,12 @@ class FooBar {
<th>type</th>
<th>default value</th>
</tr>
<tr>
<td>option</td>
<td>policy on the relative order between regular imports and static imports</td>
<td><a href="property_types.html#importOrder">import order</a></td>
<td><span class="default">under</span></td>
</tr>
<tr>
<td>groups</td>
<td>
@ -375,10 +390,13 @@ class FooBar {
<subsection name="Example">
<p>
To configure the check so that it requires &quot;java&quot; packages
first, than &quot;javax&quot; 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:
<ul>
<li>&quot;java&quot; packages first, then &quot;javax&quot; and then all other imports</li>
<li>imports will be sorted in the groups</li>
<li>groups are separated by, at least, on blank line</li>
<li>static imports are above each local groups</li>
</ul>
</p>
<source>
@ -386,6 +404,7 @@ class FooBar {
&lt;property name=&quot;groups&quot; value=&quot;java,javax&quot;/>
&lt;property name=&quot;ordered&quot; value=&quot;true&quot;/>
&lt;property name=&quot;separated&quot; value=&quot;true&quot;/>
&lt;property name=&quot;option&quot; value=&quot;above&quot;/>
&lt;/module>
</source>
</subsection>

View File

@ -65,7 +65,7 @@
This property represents a regular expression. The string
representation is parsed using <a
href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/package-summary.html">java.util.regex
package</a>.
package</a>.
</p>
</section>
@ -178,7 +178,7 @@
<td>Option</td>
<td>Definition</td>
</tr>
<tr>
<td><span class="code">eol</span></td>
<td>
@ -330,5 +330,80 @@
</tr>
</table>
</section>
<section name="importOrder">
<p>
This property represents the policy for checking imports order.
The following table describes the valid options:
</p>
<table summary="import order options">
<tr>
<td>Option</td>
<td>Definition</td>
</tr>
<tr>
<td><span class="code">top</span></td>
<td>All static imports are at the top. For example:
<pre>
import static a.b.C.*;
import static x.y.Z.*;
import a.b.D;
import x.y.Z;</pre>
</td>
</tr>
<tr>
<td><span class="code">above</span></td>
<td>All static imports are above the local group.. For example:
<pre>
import static a.b.C.*;
import a.b.D;
import static x.y.Z.*;
import x.y.Z;</pre>
</td>
</tr>
<tr>
<td><span class="code">inflow</span></td>
<td>All static imports are processed like non static
imports. For example:
<pre>
import static a.b.C.*;
import a.b.D;
import x.y.Z;
import static x.y.Z.*;</pre>
</td>
</tr>
<tr>
<td><span class="code">under</span></td>
<td>All static imports are under the local group. For example:
<pre>
import a.b.D;
import static a.b.C.*;
import x.y.Z;
import static x.y.Z.*;</pre>
</td>
</tr>
<tr>
<td><span class="code">bottom</span></td>
<td>All static imports are at the bottom. For example:
<pre>
import a.b.D;
import x.y.Z;
import static a.b.C.*;
import static x.y.Z.*;</pre>
</td>
</tr>
</table>
</section>
</body>
</document>

View File

@ -18,6 +18,12 @@
for enforcing the maximum number of outer types per file. Inspired
by patch #1145023 from Alexander Jesse.
</li>
<li>
Add new options to the <a
href="config_sizes.html#ImportOrderCheck">ImportOrderCheck</a>
to make it more flexible. Thanks to David Didier for providing
patch #1854213.
</li>
</ul>
<p>Fixed Bugs:</p>