diff --git a/src/it/java/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/RightCurlyTest.java b/src/it/java/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/RightCurlyTest.java index 377bbef2eba0..f52d54849a55 100644 --- a/src/it/java/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/RightCurlyTest.java +++ b/src/it/java/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/RightCurlyTest.java @@ -121,4 +121,19 @@ public void testRightCurlyAloneSameAndLiteralDo() throws Exception { final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + + @Test + public void testRightCurlyAloneInLambda() throws Exception { + final String[] expected = { + "12:70: " + getCheckMessage(RightCurlyCheck.class, MSG_KEY_LINE_ALONE, "}", 70), + "15:46: " + getCheckMessage(RightCurlyCheck.class, MSG_KEY_LINE_ALONE, "}", 46), + "22:33: " + getCheckMessage(RightCurlyCheck.class, MSG_KEY_LINE_ALONE, "}", 33), + }; + + final Configuration checkConfig = getCheckConfig("RightCurly", "RightCurlyAlone"); + final String filePath = getPath("InputRightCurlyAloneLambda.java"); + + final Integer[] warnList = {12, 15, 22}; + verify(checkConfig, filePath, expected, warnList); + } } diff --git a/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyAloneLambda.java b/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyAloneLambda.java new file mode 100644 index 000000000000..821e60eb6e7c --- /dev/null +++ b/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyAloneLambda.java @@ -0,0 +1,30 @@ +package com.puppycrawl.tools.checkstyle.checks.blocks; + +/*Test lambda*/ +public class InputRightCurlyAloneLambda { + + static Runnable k1 = () -> { + String.valueOf("Test rightCurly 1!"); + }; + + static Runnable k2 = () -> String.valueOf("Test rightCurly 2!"); + + static Runnable k3 = () -> {String.valueOf("Test rightCurly 3!");}; // violation + + static Runnable k4 = () -> { + String.valueOf("Test rightCurly 4!");}; // violation + + static Runnable k5 = () -> + { + String.valueOf("Test rightCurly 5!"); + }; + + static Runnable k6 = () -> {}; // violation + + static Runnable k7 = () -> { + }; + + static Runnable k8 = () -> + { + }; +} diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyCheck.java index cf3cbb8cfb3e..1eba447696c3 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyCheck.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyCheck.java @@ -40,7 +40,8 @@ * {@link TokenTypes#LITERAL_CATCH LITERAL_CATCH}, * {@link TokenTypes#LITERAL_FINALLY LITERAL_FINALLY}, * {@link TokenTypes#LITERAL_IF LITERAL_IF}, - * {@link TokenTypes#LITERAL_ELSE LITERAL_ELSE}. + * {@link TokenTypes#LITERAL_ELSE LITERAL_ELSE}, + * {@link TokenTypes#LAMBDA LAMBDA}. * Other acceptable tokens are: * {@link TokenTypes#CLASS_DEF CLASS_DEF}, * {@link TokenTypes#METHOD_DEF METHOD_DEF}, @@ -50,6 +51,7 @@ * {@link TokenTypes#LITERAL_DO LITERAL_DO}. * {@link TokenTypes#STATIC_INIT STATIC_INIT}. * {@link TokenTypes#INSTANCE_INIT INSTANCE_INIT}. + * {@link TokenTypes#LAMBDA LAMBDA}. *
*
* shouldStartLine - does the check need to check
@@ -141,6 +143,7 @@ public int[] getDefaultTokens() {
TokenTypes.LITERAL_FINALLY,
TokenTypes.LITERAL_IF,
TokenTypes.LITERAL_ELSE,
+ TokenTypes.LAMBDA,
};
}
@@ -160,6 +163,7 @@ public int[] getAcceptableTokens() {
TokenTypes.LITERAL_DO,
TokenTypes.STATIC_INIT,
TokenTypes.INSTANCE_INIT,
+ TokenTypes.LAMBDA,
};
}
@@ -201,14 +205,11 @@ public void visitToken(DetailAST ast) {
private static String validate(Details details, RightCurlyOption bracePolicy,
boolean shouldStartLine, String targetSourceLine) {
final DetailAST rcurly = details.rcurly;
- final DetailAST lcurly = details.lcurly;
final DetailAST nextToken = details.nextToken;
final boolean shouldCheckLastRcurly = details.shouldCheckLastRcurly;
String violation = "";
- if (bracePolicy == RightCurlyOption.SAME
- && !hasLineBreakBefore(rcurly)
- && lcurly.getLineNo() != rcurly.getLineNo()) {
+ if (shouldHaveBeLineBreakBefore(bracePolicy, details)) {
violation = MSG_KEY_LINE_BREAK_BEFORE;
}
else if (shouldCheckLastRcurly) {
@@ -245,15 +246,22 @@ private static boolean shouldBeOnSameLine(RightCurlyOption bracePolicy, Details
* @param details Details for validation
* @return true if a right curly should be alone on a line.
*/
+ // -@cs[CyclomaticComplexity] keeping the logic in one place increases readability
+ // -@cs[BooleanExpressionComplexity] keeping the logic in one place increases readability
private static boolean shouldBeAloneOnLine(RightCurlyOption bracePolicy, Details details) {
+ final int tokenLambda = details.lcurly.getParent().getType();
return bracePolicy == RightCurlyOption.ALONE
- && !isAloneOnLine(details)
- && !isEmptyBody(details.lcurly)
+ && tokenLambda != TokenTypes.LAMBDA
+ && !isAloneOnLine(details)
+ && !isEmptyBody(details.lcurly)
|| bracePolicy == RightCurlyOption.ALONE_OR_SINGLELINE
- && !isAloneOnLine(details)
- && !isSingleLineBlock(details)
- && !isAnonInnerClassInit(details.lcurly)
- && !isEmptyBody(details.lcurly);
+ && !isAloneOnLine(details)
+ && !isSingleLineBlock(details)
+ && !isAnonInnerClassInit(details.lcurly)
+ && !isEmptyBody(details.lcurly)
+ || bracePolicy == RightCurlyOption.ALONE
+ && tokenLambda == TokenTypes.LAMBDA
+ && !isAloneLambda(details);
}
/**
@@ -293,6 +301,24 @@ private static boolean isSingleLineBlock(Details details) {
&& rcurly.getLineNo() != nextToken.getLineNo();
}
+ /**
+ * Checks if right curly is alone on line in token the lambda.
+ * @param details for validation.
+ * @return true, if right curly is alone on line.
+ */
+ private static boolean isAloneLambda(Details details) {
+ final DetailAST lcurly = details.lcurly;
+ final DetailAST rcurly = details.rcurly;
+ final int lcurlyNo = lcurly.getLineNo();
+ final int rcurlyNo = rcurly.getLineNo();
+ boolean result = false;
+ if (lcurlyNo != rcurlyNo) {
+ result = rcurly.getPreviousSibling() == null
+ || rcurlyNo != rcurly.getPreviousSibling().getLineNo();
+ }
+ return result;
+ }
+
/**
* Checks whether lcurly is in anonymous inner class initialization.
* @param lcurly left curly token.
@@ -310,7 +336,6 @@ private static boolean isAnonInnerClassInit(DetailAST lcurly) {
*/
// -@cs[JavaNCSS] getDetails() method is a huge SWITCH, it has to be monolithic
// -@cs[ExecutableStatementCount] getDetails() method is a huge SWITCH, it has to be monolithic
- // -@cs[NPathComplexity] getDetails() method is a huge SWITCH, it has to be monolithic
private static Details getDetails(DetailAST ast) {
// Attempt to locate the tokens to do the check
boolean shouldCheckLastRcurly = false;
@@ -320,19 +345,9 @@ private static Details getDetails(DetailAST ast) {
switch (ast.getType()) {
case TokenTypes.LITERAL_TRY:
- if (ast.getFirstChild().getType() == TokenTypes.RESOURCE_SPECIFICATION) {
- lcurly = ast.getFirstChild().getNextSibling();
- }
- else {
- lcurly = ast.getFirstChild();
- }
+ lcurly = ast.getFirstChild();
nextToken = lcurly.getNextSibling();
rcurly = lcurly.getLastChild();
-
- if (nextToken == null) {
- shouldCheckLastRcurly = true;
- nextToken = getNextToken(ast);
- }
break;
case TokenTypes.LITERAL_CATCH:
nextToken = ast.getNextSibling();
@@ -386,9 +401,16 @@ private static Details getDetails(DetailAST ast) {
rcurly = lcurly.getLastChild();
}
break;
+ case TokenTypes.LAMBDA:
+ lcurly = ast.findFirstToken(TokenTypes.SLIST);
+ nextToken = getNextToken(ast);
+ if (lcurly != null) {
+ rcurly = lcurly.getLastChild();
+ }
+ break;
default:
// ATTENTION! We have default here, but we expect case TokenTypes.METHOD_DEF,
- // TokenTypes.LITERAL_FOR, TokenTypes.LITERAL_WHILE, only.
+ // TokenTypes.LITERAL_FOR, TokenTypes.LITERAL_WHILE only.
// It has been done to improve coverage to 100%. I couldn't replace it with
// if-else-if block because code was ugly and didn't pass pmd check.
@@ -444,6 +466,21 @@ private static DetailAST getNextToken(DetailAST ast) {
return CheckUtils.getFirstNode(next);
}
+ /**
+ * Checks that before a right curly should be a linebreak.
+ * @param bracePolicy options for placing the right curly brace.
+ * @param details Details for validation
+ * @return true if before a right curly should be a linebreak.
+ */
+ private static boolean shouldHaveBeLineBreakBefore(RightCurlyOption bracePolicy,
+ Details details) {
+ final DetailAST rcurly = details.rcurly;
+ final DetailAST lcurly = details.lcurly;
+ return bracePolicy == RightCurlyOption.SAME
+ && !hasLineBreakBefore(rcurly)
+ && lcurly.getLineNo() != rcurly.getLineNo();
+ }
+
/**
* Checks if right curly has line break before.
* @param rightCurly right curly token.
diff --git a/src/main/resources/google_checks.xml b/src/main/resources/google_checks.xml
index a98447470545..19ca967f1e9c 100644
--- a/src/main/resources/google_checks.xml
+++ b/src/main/resources/google_checks.xml
@@ -61,7 +61,7 @@
LITERAL_TRY,
@@ -810,7 +812,9 @@ for(int i = 0; i < 10; value.incrementValue()); // OK
LITERAL_IF,
LITERAL_ELSE.
+ href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_ELSE">LITERAL_ELSE,
+ LAMBDA.