From 02bc165a36f90bbcb638ffba74d9b3139a65d89f Mon Sep 17 00:00:00 2001 From: liscju Date: Mon, 7 Dec 2015 14:11:02 +0100 Subject: [PATCH] Issue #2603: add allowEmptyLambda parameter to WhitespaceAroundCheck --- .../whitespace/WhitespaceAroundCheck.java | 34 +++++++++++++++++-- .../whitespace/WhitespaceAroundCheckTest.java | 33 ++++++++++++++++++ .../InputAllowEmptyLambdaExpressions.java | 14 ++++++++ src/xdocs/config_whitespace.xml | 12 +++++-- 4 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/whitespace/InputAllowEmptyLambdaExpressions.java diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAroundCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAroundCheck.java index 972d97541..a332b6421 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAroundCheck.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAroundCheck.java @@ -98,7 +98,7 @@ import com.puppycrawl.tools.checkstyle.api.TokenTypes; * * *

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: * *

{@code
@@ -111,6 +111,7 @@ import com.puppycrawl.tools.checkstyle.api.TokenTypes;
  * 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
  * }
* @@ -130,6 +131,10 @@ import com.puppycrawl.tools.checkstyle.api.TokenTypes; * *
   <property name="allowEmptyLoops" value="true" />
* + *

To configure the check to allow empty lambdas blocks use + * + *

   <property name="allowEmptyLambdas" value="true" />
+ * *

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 diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAroundCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAroundCheckTest.java index 89d57b7c6..ead3993d2 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAroundCheckTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAroundCheckTest.java @@ -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); + } } diff --git a/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/whitespace/InputAllowEmptyLambdaExpressions.java b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/whitespace/InputAllowEmptyLambdaExpressions.java new file mode 100644 index 000000000..853942000 --- /dev/null +++ b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/whitespace/InputAllowEmptyLambdaExpressions.java @@ -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 sum = (x, y) -> x + y; + Runnable noop3 = () -> {;}; + Runnable noop4 = () -> {new Integer();}; +} diff --git a/src/xdocs/config_whitespace.xml b/src/xdocs/config_whitespace.xml index 1654dea99..8131481ab 100644 --- a/src/xdocs/config_whitespace.xml +++ b/src/xdocs/config_whitespace.xml @@ -1545,7 +1545,7 @@ foo(i,

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

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

may optionally be exempted from the policy using the allowEmptyMethods, allowEmptyConstructors - , allowEmptyTypes and allowEmptyLoops properties. + , allowEmptyTypes, allowEmptyLoops and + allowEmptyLambdas properties.

@@ -1599,6 +1601,12 @@ public @interface Beta {} // empty annotation type boolean false + + allowEmptyLambdas + allow empty lambda bodies + boolean + false + ignoreEnhancedForColon ignore whitespace around colon in for-each loops