Issue #2603: add allowEmptyLambda parameter to WhitespaceAroundCheck

This commit is contained in:
liscju 2015-12-07 14:11:02 +01:00 committed by Roman Ivanov
parent 6127a44e20
commit 02bc165a36
4 changed files with 89 additions and 4 deletions

View File

@ -98,7 +98,7 @@ import com.puppycrawl.tools.checkstyle.api.TokenTypes;
* </pre>
*
* <p>In addition, this check can be configured to allow empty methods, types,
* for, while, do-while loops and constructor bodies.
* for, while, do-while loops, lambdas and constructor bodies.
* For example:
*
* <pre>{@code
@ -111,6 +111,7 @@ import com.puppycrawl.tools.checkstyle.api.TokenTypes;
* while (i = 1) {} // empty while loop
* for (int i = 1; i &gt; 1; i++) {} // empty for loop
* do {} while (i = 1); // empty do-while loop
* Runnable noop = () -> {}; // empty lambda
* public @interface Beta {} // empty annotation type
* }</pre>
*
@ -130,6 +131,10 @@ import com.puppycrawl.tools.checkstyle.api.TokenTypes;
*
* <pre> &lt;property name="allowEmptyLoops" value="true" /&gt;</pre>
*
* <p>To configure the check to allow empty lambdas blocks use
*
* <pre> &lt;property name="allowEmptyLambdas" value="true" /&gt;</pre>
*
* <p>Also, this check can be configured to ignore the colon in an enhanced for
* loop. The colon in an enhanced for loop is ignored by default
*
@ -163,6 +168,8 @@ public class WhitespaceAroundCheck extends Check {
private boolean allowEmptyTypes;
/** Whether or not empty loops are allowed. */
private boolean allowEmptyLoops;
/** Whether or not empty lambda blocks are allowed. */
private boolean allowEmptyLambdas;
/** Whether or not to ignore a colon in a enhanced for loop. */
private boolean ignoreEnhancedForColon = true;
@ -327,6 +334,14 @@ public class WhitespaceAroundCheck extends Check {
allowEmptyLoops = allow;
}
/**
* Sets whether or not empty lambdas bodies are allowed.
* @param allow {@code true} to allow empty lambda expressions.
*/
public void setAllowEmptyLambdas(boolean allow) {
allowEmptyLambdas = allow;
}
@Override
public void visitToken(DetailAST ast) {
final int currentType = ast.getType();
@ -408,7 +423,8 @@ public class WhitespaceAroundCheck extends Check {
private boolean isEmptyBlock(DetailAST ast, int parentType) {
return isEmptyMethodBlock(ast, parentType)
|| isEmptyCtorBlock(ast, parentType)
|| isEmptyLoop(ast, parentType);
|| isEmptyLoop(ast, parentType)
|| isEmptyLambda(ast, parentType);
}
/**
@ -429,8 +445,10 @@ public class WhitespaceAroundCheck extends Check {
private static boolean isEmptyBlock(DetailAST ast, int parentType, int match) {
final int type = ast.getType();
if (type == TokenTypes.RCURLY) {
final DetailAST parent = ast.getParent();
final DetailAST grandParent = ast.getParent().getParent();
return parentType == TokenTypes.SLIST
&& parent.getFirstChild().getType() == TokenTypes.RCURLY
&& grandParent.getType() == match;
}
@ -518,6 +536,18 @@ public class WhitespaceAroundCheck extends Check {
parentType, TokenTypes.LITERAL_DO));
}
/**
* Test if the given {@code DetailAST} is part of an allowed empty
* lambda block.
* @param ast the {@code DetailAST} to test.
* @param parentType the token type of {@code ast}'s parent.
* @return {@code true} if {@code ast} makes up part of an
* allowed empty lambda block.
*/
private boolean isEmptyLambda(DetailAST ast, int parentType) {
return allowEmptyLambdas && isEmptyBlock(ast, parentType, TokenTypes.LAMBDA);
}
/**
* Test if the given {@code DetailAST} is part of an empty block.
* An example empty block might look like the following

View File

@ -49,6 +49,12 @@ public class WhitespaceAroundCheckTest
+ "whitespace" + File.separator + filename);
}
@Override
protected String getNonCompilablePath(String filename) throws IOException {
return super.getNonCompilablePath("checks" + File.separator
+ "whitespace" + File.separator + filename);
}
@Test
public void testGetRequiredTokens() {
final WhitespaceAroundCheck checkObj = new WhitespaceAroundCheck();
@ -330,4 +336,31 @@ public class WhitespaceAroundCheckTest
verify(checkConfig, getPath("InputAllowEmptyTypesAndNonEmptyClasses.java"),
expected);
}
@Test
public void testNotAllowEmptyLambdaExpressionsByDefault() throws Exception {
final String[] expected = {
"7:28: " + getCheckMessage(WS_NOT_FOLLOWED, "{"),
"7:28: " + getCheckMessage(WS_NOT_PRECEDED, "}"),
"12:29: " + getCheckMessage(WS_NOT_FOLLOWED, "{"),
"12:30: " + getCheckMessage(WS_NOT_PRECEDED, "}"),
"13:29: " + getCheckMessage(WS_NOT_FOLLOWED, "{"),
"13:43: " + getCheckMessage(WS_NOT_PRECEDED, "}"),
};
verify(checkConfig, getNonCompilablePath("InputAllowEmptyLambdaExpressions.java"),
expected);
}
@Test
public void testAllowEmptyLambdaExpressionsWithAllowEmptyLambdaParameter() throws Exception {
checkConfig.addAttribute("allowEmptyLambdas", "true");
final String[] expected = {
"12:29: " + getCheckMessage(WS_NOT_FOLLOWED, "{"),
"12:30: " + getCheckMessage(WS_NOT_PRECEDED, "}"),
"13:29: " + getCheckMessage(WS_NOT_FOLLOWED, "{"),
"13:43: " + getCheckMessage(WS_NOT_PRECEDED, "}"),
};
verify(checkConfig, getNonCompilablePath("InputAllowEmptyLambdaExpressions.java"),
expected);
}
}

View File

@ -0,0 +1,14 @@
//Compilable with Java8
package com.puppycrawl.tools.checkstyle.checks.whitespace;
import java.util.function.*;
public class InputAllowEmptyLambdaExpressions {
Runnable noop = () -> {};
Runnable noop2 = () -> {
int x = 10;
};
BinaryOperator<Integer> sum = (x, y) -> x + y;
Runnable noop3 = () -> {;};
Runnable noop4 = () -> {new Integer();};
}

View File

@ -1545,7 +1545,7 @@ foo(i,
<subsection name="Description">
<p>
Checks that a token is surrounded by whitespace. Empty constructor,
method, class, enum, interface, loop bodies (blocks) of the form
method, class, enum, interface, loop bodies (blocks), lambdas of the form
</p>
<source>public MyClass() {} // empty constructor
@ -1557,13 +1557,15 @@ MyClass c = new MyClass() {}; // empty anonymous class
while (i = 1) {} // empty while loop
for (int i = 1; i > 1; i++) {} // empty for loop
do {} while (i = 1); // empty do-while loop
Runnable noop = () -> {}; // empty lambda
public @interface Beta {} // empty annotation type
</source>
<p>
may optionally be exempted from the policy using the <code>
allowEmptyMethods</code>, <code>allowEmptyConstructors
</code>, <code>allowEmptyTypes</code> and <code>allowEmptyLoops</code> properties.
</code>, <code>allowEmptyTypes</code>, <code>allowEmptyLoops</code> and
<code>allowEmptyLambdas</code> properties.
</p>
</subsection>
@ -1599,6 +1601,12 @@ public @interface Beta {} // empty annotation type
<td><a href="property_types.html#boolean">boolean</a></td>
<td><code>false</code></td>
</tr>
<tr>
<td>allowEmptyLambdas</td>
<td>allow empty lambda bodies</td>
<td><a href="property_types.html#boolean">boolean</a></td>
<td><code>false</code></td>
</tr>
<tr>
<td>ignoreEnhancedForColon</td>
<td>ignore whitespace around colon in for-each loops</td>