EmptyLineSeparatorCheck #186. Exactly one blank line separates each section that is present.

This commit is contained in:
Max 2014-07-09 23:53:26 +04:00 committed by Roman Ivanov
parent 05211d164a
commit d9452c8d5e
6 changed files with 410 additions and 1 deletions

View File

@ -0,0 +1,171 @@
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2014 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.whitespace;
import com.puppycrawl.tools.checkstyle.api.Check;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
/**
*
* Checks for blank line separators after package, all import declarations,
* fields, constructors, methods, nested classes,
* static initializers and instance initializers.
*
* <p> By default the check will check the following statements:
* {@link TokenTypes#PACKAGE_DEF PACKAGE_DEF},
* {@link TokenTypes#IMPORT IMPORT},
* {@link TokenTypes#CLASS_DEF CLASS_DEF},
* {@link TokenTypes#INTERFACE_DEF INTERFACE_DEF},
* {@link TokenTypes#LSTATIC_INIT STATIC_INIT},
* {@link TokenTypes#INSTANCE_INIT INSTANCE_INIT},
* {@link TokenTypes#METHOD_DEF METHOD_DEF},
* {@link TokenTypes#CTOR_DEF CTOR_DEF},
* {@link TokenTypes#VARIABLE_DEF VARIABLE_DEF}.
* </p>
*
* <p>
* Example of declarations without blank line separator:
* </p>
*
* <pre>
* package com.puppycrawl.tools.checkstyle.whitespace;
* import java.io.Serializable;
* class Foo
* {
* public static final int FOO_CONST = 1;
* public void foo() {} //should be separated from previous statement.
* }
* </pre>
*
* <p> An example of how to configure the check with default parameters is:
* </p>
*
* <pre>
* &lt;module name="EmptyLineSeparator"/&gt;
* </pre>
*
* <p>
* Example of declarations with blank line separator
* that is expected by the Check by default:
* </p>
*
* <pre>
* package com.puppycrawl.tools.checkstyle.whitespace;
*
* import java.io.Serializable;
*
* class Foo
* {
* public static final int FOO_CONST = 1;
*
* public void foo() {}
* }
* </pre>
* <p> An example how to check blank line after
* {@link TokenTypes#VARIABLE_DEF VARIABLE_DEF} and
* {@link TokenTypes#METHOD_DEF METHOD_DEF}:
* </p>
*
* <pre>
* &lt;module name="EmptyLineSeparator"&gt;
* &lt;property name="tokens" value="VARIABLE_DEF, METHOD_DEF"/&gt;
* &lt;/module&gt;
* </pre>
*
* @author maxvetrenko
*
*/
public class EmptyLineSeparatorCheck extends Check
{
@Override
public int[] getDefaultTokens()
{
return new int[] {
TokenTypes.PACKAGE_DEF,
TokenTypes.IMPORT,
TokenTypes.CLASS_DEF,
TokenTypes.INTERFACE_DEF,
TokenTypes.ENUM_DEF,
TokenTypes.STATIC_INIT,
TokenTypes.INSTANCE_INIT,
TokenTypes.METHOD_DEF,
TokenTypes.CTOR_DEF,
TokenTypes.VARIABLE_DEF,
};
}
@Override
public void visitToken(DetailAST aAST)
{
final DetailAST nextToken = aAST.getNextSibling();
if (nextToken != null && nextToken.getType() != TokenTypes.RCURLY) {
final int astType = aAST.getType();
switch (astType) {
case TokenTypes.VARIABLE_DEF:
if (isTypeField(aAST) && !hasBlankLineAfter(aAST)) {
log(nextToken.getLineNo(),
"empty.line.separator", nextToken.getText());
}
break;
case TokenTypes.IMPORT:
if (astType != nextToken.getType()
&& !hasBlankLineAfter(aAST))
{
log(nextToken.getLineNo(),
"empty.line.separator", nextToken.getText());
}
break;
default:
if (!hasBlankLineAfter(aAST)) {
log(nextToken.getLineNo(),
"empty.line.separator", nextToken.getText());
}
}
}
}
/**
* Checks if token have blank line after.
* @param aToken token.
* @return if token have blank line after.
*/
private boolean hasBlankLineAfter(DetailAST aToken)
{
DetailAST lastToken = aToken.getLastChild().getLastChild();
if (null == lastToken) {
lastToken = aToken.getLastChild();
}
return aToken.getNextSibling().getLineNo() - lastToken.getLineNo() > 1;
}
/**
* If variable definition is a type field.
* @param aVariableDef variable definition.
* @return true variable definition is a type field.
*/
private boolean isTypeField(DetailAST aVariableDef)
{
final int parentType = aVariableDef.getParent().getParent().getType();
return parentType == TokenTypes.CLASS_DEF;
}
}

View File

@ -1,3 +1,5 @@
empty.line.separator=''{0}'' should be separated from previous statement.
containsTab=Line contains a tab character.
file.containsTab=File contains tab characters (this is the first instance).

View File

@ -0,0 +1,48 @@
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2014 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.whitespace;
import com.puppycrawl.tools.checkstyle.BaseCheckTestSupport;
import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
import org.junit.Before;
import org.junit.Test;
public class EmptyLineSeparatorCheckTest
extends BaseCheckTestSupport
{
private DefaultConfiguration mCheckConfig;
@Before
public void setUp()
{
mCheckConfig = createCheckConfig(EmptyLineSeparatorCheck.class);
}
@Test
public void testDefault() throws Exception
{
final String[] expected = {
"2: 'import' should be separated from previous statement.",
"16: 'CLASS_DEF' should be separated from previous statement.",
"19: 'VARIABLE_DEF' should be separated from previous statement.",
"58: 'INTERFACE_DEF' should be separated from previous statement.",
};
verify(mCheckConfig, getPath("whitespace/InputEmptyLineSeparatorCheck.java"), expected);
}
}

View File

@ -0,0 +1,80 @@
package com.puppycrawl.tools.checkstyle.whitespace;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.Collections;
import com.google.common.base.CharMatcher;
import com.google.common.io.CharSource;
import javax.swing.AbstractAction;
import org.apache.commons.beanutils.locale.converters.ByteLocaleConverter;
import org.apache.commons.io.FilenameUtils;
class InputEmptyLineSeparatorCheck
{
public static final double FOO_PI = 3.1415;
private boolean flag = true;
//separator blank line
static {
//empty static initializer
}
//separator blank line
{
//empty instance initializer
}
//separator blank line
/**
*
*
*/
private InputEmptyLineSeparatorCheck()
{
//empty
}
//separator blank line
public int compareTo(InputGenericWhitespaceCheck aObject)
{
int number = 0;
return 0;
}
/**
*
* @param task
* @param result
* @return
*/
public static <T> Callable<T> callable(Runnable task, T result)
{
return null;
}
//separator blank line
public int getBeastNumber()
{
return 666;
}
interface IntEnum {
}
//separator blank line
class InnerClass {
public static final double FOO_PI_INNER = 3.1415;
//separator blank line
private boolean flagInner = true;
//separator blank line
static {
//empty static initializer
}
//separator blank line
{
//empty instance initializer
}
//separator blank line
private InnerClass()
{
//empty
}
}
}

View File

@ -134,6 +134,10 @@
space is required at an empty for iterator, or such spaces are
forbidden.</td>
</tr>
<tr>
<td><a href="config_whitespace.html#EmptyLineSeparator">EmptyLineSeparator</a></td>
<td>Checks for blank line separators.</td>
</tr>
<tr>
<td><a href="config_coding.html#EmptyStatement">EmptyStatement</a></td>
<td>

View File

@ -1274,7 +1274,111 @@ import com.puppycrawl.tools.checkstyle.api.Check;
<subsection name="Package">
<p>
com.puppycrawl.tools.checkstyle.checks
com.puppycrawl.tools.checkstyle.checks.whitespace
</p>
</subsection>
<subsection name="Parent Module">
<p>
<a href="config.html#TreeWalker">TreeWalker</a>
</p>
</subsection>
</section>
<section name="EmptyLineSeparator">
<subsection name="Description">
<p>
Checks for blank line separators after package, all import declarations,
fields, constructors, methods, nested classes,
static initializers and instance initializers.
</p>
</subsection>
<subsection name="Properties">
<table>
<tr>
<th>name</th>
<th>description</th>
<th>type</th>
<th>default value</th>
</tr>
<tr>
<td>tokens</td>
<td>assignments to check</td>
<td>subset of tokens <a
href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#PACKAGE_DEF">PACKAGE_DEF</a>,
<a
href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#IMPORT">IMPORT</a>,
<a
href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF">CLASS_DEF</a>,
<a
href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_DEF">ENUM_DEF</a>
<a
href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF">INTERFACE_DEF</a>,
<a
href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CTOR_DEF">CTOR_DEF</a>,
<a
href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF">METHOD_DEF</a>,
<a
href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF">STATIC_INIT</a>,
<a
href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INSTANCE_INIT">INSTANCE_INIT</a>,
<a
href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#VARIABLE_DEF">VARIABLE_DEF</a>
</td>
<td>All subset of tokens</td>
</tr>
</table>
</subsection>
<subsection name="Examples">
<p>
Example of declarations without blank line separator:
</p>
<source>
package com.puppycrawl.tools.checkstyle.whitespace;
import java.io.Serializable;
class Foo
{
public static final int FOO_CONST = 1;
public void foo() {} //should be separated from previous statement.
}
</source>
<p>
An example of how to configure the check with default parameters is:
</p>
<source>
&lt;module name="EmptyLineSeparator"/&gt;
</source>
<p>
Example of declarations with blank line separator that is expected by the Check by default:
</p>
<source>
package com.puppycrawl.tools.checkstyle.whitespace;
import java.io.Serializable;
class Foo
{
public static final int FOO_CONST = 1;
public void foo() {} //should be separated from previous statement.
}
</source>
<p>
An example how to check blank line after <a
href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#VARIABLE_DEF">VARIABLE_DEF</a> and <a
href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF">METHOD_DEF</a>:
</p>
<source>
&lt;module name="EmptyLineSeparator"&gt;
&lt;property name="tokens" value="VARIABLE_DEF, METHOD_DEF"/&gt;
&lt;/module&gt;
</source>
</subsection>
<subsection name="Package">
<p>
com.puppycrawl.tools.checkstyle.checks.whitespace
</p>
</subsection>