From 12a1aec08012575b94c262d2b825a439bd69fde3 Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 13 Aug 2014 01:05:33 +0400 Subject: [PATCH] RightCurly. Force line break before '}' in case SAME option. #250 --- .../checks/blocks/RightCurlyCheck.java | 50 ++++++++++++-- .../checks/blocks/messages.properties | 3 +- .../checks/blocks/RightCurlyCheckTest.java | 40 +++++++++++ .../InputRightCurlyEmptyAbstractMethod.java | 8 +++ .../InputRightCurlyLineBreakBefore.java | 66 +++++++++++++++++++ src/xdocs/config_blocks.xml | 12 +++- 6 files changed, 172 insertions(+), 7 deletions(-) create mode 100644 src/test/resources/com/puppycrawl/tools/checkstyle/InputRightCurlyEmptyAbstractMethod.java create mode 100644 src/test/resources/com/puppycrawl/tools/checkstyle/InputRightCurlyLineBreakBefore.java 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 e56dc5d35..fdb0411c7 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,6 +40,11 @@ import com.puppycrawl.tools.checkstyle.checks.CheckUtils; * {@link TokenTypes#CLASS_DEF CLASS_DEF}, * {@link TokenTypes#METHOD_DEF METHOD_DEF}, * {@link TokenTypes#CTOR_DEF CTOR_DEF}. + * {@link TokenTypes#LITERAL_FOR LITERAL_FOR}. + * {@link TokenTypes#LITERAL_WHILE LITERAL_WHILE}. + * {@link TokenTypes#LITERAL_DO LITERAL_DO}. + * {@link TokenTypes#STATIC_INIT STATIC_INIT}. + * {@link TokenTypes#INSTANCE_INIT INSTANCE_INIT}. *

*

* An example of how to configure the check is: @@ -111,6 +116,11 @@ public class RightCurlyCheck extends AbstractOptionCheck TokenTypes.CLASS_DEF, TokenTypes.METHOD_DEF, TokenTypes.CTOR_DEF, + TokenTypes.LITERAL_FOR, + TokenTypes.LITERAL_WHILE, + TokenTypes.LITERAL_DO, + TokenTypes.STATIC_INIT, + TokenTypes.INSTANCE_INIT, }; } @@ -164,17 +174,27 @@ public class RightCurlyCheck extends AbstractOptionCheck rcurly = lcurly.getLastChild(); break; case TokenTypes.CLASS_DEF: - lcurly = aAST.getLastChild().getFirstChild(); - rcurly = aAST.getLastChild().getLastChild(); + final DetailAST child = aAST.getLastChild(); + lcurly = child.getFirstChild(); + rcurly = child.getLastChild(); nextToken = aAST; break; case TokenTypes.CTOR_DEF: - lcurly = aAST.getLastChild(); + case TokenTypes.STATIC_INIT: + case TokenTypes.INSTANCE_INIT: + lcurly = aAST.findFirstToken(TokenTypes.SLIST); rcurly = lcurly.getLastChild(); nextToken = aAST; break; case TokenTypes.METHOD_DEF: - lcurly = aAST.getLastChild(); + case TokenTypes.LITERAL_FOR: + case TokenTypes.LITERAL_WHILE: + case TokenTypes.LITERAL_DO: + lcurly = aAST.findFirstToken(TokenTypes.SLIST); + //SLIST could be absent if method is abstract, and code like "while(true);" + if (lcurly == null) { + return; + } rcurly = lcurly.getLastChild(); nextToken = aAST; break; @@ -188,6 +208,10 @@ public class RightCurlyCheck extends AbstractOptionCheck return; } + if (getAbstractOption() == RightCurlyOption.SAME && !hasLineBreakBefore(rcurly)) { + log(rcurly, "line.break.before"); + } + if (shouldCheckLastRcurly) { if (rcurly.getLineNo() == nextToken.getLineNo()) { log(rcurly, "line.alone", "}"); @@ -251,4 +275,22 @@ public class RightCurlyCheck extends AbstractOptionCheck } return CheckUtils.getFirstNode(next); } + + /** + * Checks if right curly has line break before. + * @param aRightCurly + * Right curly token. + * @return + * True, if right curly has line break before. + */ + private boolean hasLineBreakBefore(DetailAST aRightCurly) + { + if (aRightCurly != null) { + final DetailAST previousToken = aRightCurly.getPreviousSibling(); + if (previousToken != null && aRightCurly.getLineNo() == previousToken.getLineNo()) { + return false; + } + } + return true; + } } diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/blocks/messages.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/blocks/messages.properties index 42b68e3af..0abbcfbf5 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/blocks/messages.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/blocks/messages.properties @@ -10,5 +10,4 @@ line.same=''{0}'' should be on the same line. needBraces=''{0}'' construct must use '''{}'''s. line.break.after='''{''' should have line break after. - - +line.break.before='''}''' should have line break before. diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyCheckTest.java index 5da950bbc..89c448cd3 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyCheckTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyCheckTest.java @@ -44,6 +44,8 @@ public class RightCurlyCheckTest extends BaseCheckTestSupport "44:13: '}' should be on the same line.", "93:27: '}' should be alone on a line.", "93:27: '}' should be on a new line.", + "93:27: '}' should have line break before.", + "97:54: '}' should have line break before.", }; verify(mCheckConfig, getPath("InputLeftCurlyOther.java"), expected); } @@ -58,6 +60,8 @@ public class RightCurlyCheckTest extends BaseCheckTestSupport "44:13: '}' should be on the same line.", "93:27: '}' should be alone on a line.", "93:27: '}' should be on a new line.", + "93:27: '}' should have line break before.", + "97:54: '}' should have line break before.", }; verify(mCheckConfig, getPath("InputLeftCurlyOther.java"), expected); } @@ -107,4 +111,40 @@ public class RightCurlyCheckTest extends BaseCheckTestSupport }; verify(mCheckConfig, getPath("InputLeftCurlyOther.java"), expected); } + + @Test + public void testForceLineBreakBefore() throws Exception + { + mCheckConfig.addAttribute("option", RightCurlyOption.ALONE.toString()); + mCheckConfig.addAttribute("tokens", "LITERAL_FOR," + + "LITERAL_WHILE, LITERAL_DO, STATIC_INIT, INSTANCE_INIT"); + final String[] expected = { + "35:43: '}' should be alone on a line.", + "41:71: '}' should be alone on a line.", + "46:25: '}' should be alone on a line.", + }; + verify(mCheckConfig, getPath("InputRightCurlyLineBreakBefore.java"), expected); + } + + @Test + public void testForceLineBreakBefore2() throws Exception + { + final String[] expected = { + "24:33: '}' should have line break before.", + "32:44: '}' should have line break before.", + "32:63: '}' should have line break before.", + "50:48: '}' should have line break before.", + }; + verify(mCheckConfig, getPath("InputRightCurlyLineBreakBefore.java"), expected); + } + + @Test + public void testNPE() throws Exception + { + mCheckConfig.addAttribute("option", RightCurlyOption.ALONE.toString()); + mCheckConfig.addAttribute("tokens", "CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO, STATIC_INIT, INSTANCE_INIT"); + final String[] expected = { + }; + verify(mCheckConfig, getPath("InputRightCurlyEmptyAbstractMethod.java"), expected); + } } diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/InputRightCurlyEmptyAbstractMethod.java b/src/test/resources/com/puppycrawl/tools/checkstyle/InputRightCurlyEmptyAbstractMethod.java new file mode 100644 index 000000000..c581027b1 --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/InputRightCurlyEmptyAbstractMethod.java @@ -0,0 +1,8 @@ +abstract class CharSequenceReader{ + + abstract void moveTo(double deltaX, double deltaY); + + void foo() { + while (true); + } +} \ No newline at end of file diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/InputRightCurlyLineBreakBefore.java b/src/test/resources/com/puppycrawl/tools/checkstyle/InputRightCurlyLineBreakBefore.java new file mode 100644 index 000000000..96858fce8 --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/InputRightCurlyLineBreakBefore.java @@ -0,0 +1,66 @@ +package com.puppycrawl.tools.checkstyle; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; +import java.util.ArrayList; +import java.util.List; + +class InputLeftCurlyOther +{ + /** @see test method **/ + int foo() throws InterruptedException + { + int x = 1; + int a = 2; + while (true) + { + try + { + if (x > 0) + { + break; + } else if (x < 0) { + ; + } else { break; } + switch (a) + { + case 0: + break; + default: + break; + } + } catch (Exception e) { break; } finally { break; } + } + + synchronized (this) { do { x = 2; } while (x == 2); } + + synchronized (this) { + do {} while (x == 2); + } + + for (int k = 0; k < 1; k++) { String innerBlockVariable = ""; } + + for (int k = 0; k < 1; k++) {} + } + + static { int x = 1; } + + void method2() + { + if (flag) { System.err.println("foo"); } + } +} + +class Absent_CustomFieldSerializer { + + public static void serialize() {} +} + +class Absent_CustomFieldSerializer +{ + public Absent_CustomFieldSerializer() {} +} + +class EmptyClass {} + +interface EmptyInterface {} \ No newline at end of file diff --git a/src/xdocs/config_blocks.xml b/src/xdocs/config_blocks.xml index dc65783b2..6b14b6512 100644 --- a/src/xdocs/config_blocks.xml +++ b/src/xdocs/config_blocks.xml @@ -303,7 +303,17 @@ METHOD_DEF, CTOR_DEF. + href="apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CTOR_DEF">CTOR_DEF, + LITERAL_FOR, + LITERAL_WHILE, + LITERAL_DO, + STATIC_INIT, + INSTANCE_INIT. LITERAL_TRY,