diff --git a/pom.xml b/pom.xml index dee1fc5e041..451514dfb95 100644 --- a/pom.xml +++ b/pom.xml @@ -3308,6 +3308,10 @@ com.puppycrawl.tools.checkstyle.checks.whitespace.SingleSpaceSeparatorCheckTest + + + com.puppycrawl.tools.checkstyle.checks.whitespace.SeparatorWrapCheckTest + com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocStyleCheckTest diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SeparatorWrapCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SeparatorWrapCheck.java index 9323971bc8b..6d675a391f7 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SeparatorWrapCheck.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SeparatorWrapCheck.java @@ -19,12 +19,14 @@ package com.puppycrawl.tools.checkstyle.checks.whitespace; +import java.util.Arrays; import java.util.Locale; import com.puppycrawl.tools.checkstyle.StatelessCheck; import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CodePointUtil; import com.puppycrawl.tools.checkstyle.utils.CommonUtil; /** @@ -220,18 +222,20 @@ public void visitToken(DetailAST ast) { final String text = ast.getText(); final int colNo = ast.getColumnNo(); final int lineNo = ast.getLineNo(); - final String currentLine = getLines()[lineNo - 1]; - final String substringAfterToken = - currentLine.substring(colNo + text.length()).trim(); - final String substringBeforeToken = - currentLine.substring(0, colNo).trim(); + final int[] currentLine = getLineCodePoints(lineNo - 1); + final int[] substringAfterToken = CodePointUtil.trim( + Arrays.copyOfRange(currentLine, colNo + text.length(), currentLine.length) + ); + final int[] substringBeforeToken = CodePointUtil.trim( + Arrays.copyOfRange(currentLine, 0, colNo) + ); if (option == WrapOption.EOL - && substringBeforeToken.isEmpty()) { + && substringBeforeToken.length == 0) { log(ast, MSG_LINE_PREVIOUS, text); } else if (option == WrapOption.NL - && substringAfterToken.isEmpty()) { + && substringAfterToken.length == 0) { log(ast, MSG_LINE_NEW, text); } } diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/utils/CodePointUtil.java b/src/main/java/com/puppycrawl/tools/checkstyle/utils/CodePointUtil.java index ef4ce47912b..4d3b6974ab2 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/utils/CodePointUtil.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/utils/CodePointUtil.java @@ -63,12 +63,38 @@ public static boolean hasWhitespaceBefore(int index, int... codePoints) { */ public static int[] stripTrailing(int... codePoints) { int lastIndex = codePoints.length; - while (CommonUtil.isCodePointWhitespace(codePoints, lastIndex - 1)) { + while (lastIndex > 0 && CommonUtil.isCodePointWhitespace(codePoints, lastIndex - 1)) { lastIndex--; } return Arrays.copyOfRange(codePoints, 0, lastIndex); } + /** + * Removes leading whitespaces. + * + * @param codePoints array of unicode code points + * @return unicode code points array with leading whitespaces removed + */ + public static int[] stripLeading(int... codePoints) { + int startIndex = 0; + while (startIndex < codePoints.length + && CommonUtil.isCodePointWhitespace(codePoints, startIndex)) { + startIndex++; + } + return Arrays.copyOfRange(codePoints, startIndex, codePoints.length); + } + + /** + * Removes leading and trailing whitespaces. + * + * @param codePoints array of unicode code points + * @return unicode code points array with leading and trailing whitespaces removed + */ + public static int[] trim(int... codePoints) { + final int[] strippedCodePoints = stripTrailing(codePoints); + return stripLeading(strippedCodePoints); + } + /** * Tests if the unicode code points array * ends with the specified suffix. diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SeparatorWrapCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SeparatorWrapCheckTest.java index ee10cfa8500..dcee84e7336 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SeparatorWrapCheckTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SeparatorWrapCheckTest.java @@ -117,4 +117,18 @@ public void testArrayDeclarator() throws Exception { getPath("InputSeparatorWrapForArrayDeclarator.java"), expected); } + @Test + public void testWithEmoji() throws Exception { + final String[] expected = { + "13:39: " + getCheckMessage(MSG_LINE_NEW, '['), + "16:57: " + getCheckMessage(MSG_LINE_NEW, '['), + "19:39: " + getCheckMessage(MSG_LINE_NEW, "..."), + "26:19: " + getCheckMessage(MSG_LINE_NEW, '.'), + "39:50: " + getCheckMessage(MSG_LINE_NEW, ','), + "41:50: " + getCheckMessage(MSG_LINE_NEW, "::"), + }; + verifyWithInlineConfigParser( + getPath("InputSeparatorWrapWithEmoji.java"), expected); + } + } diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/whitespace/separatorwrap/InputSeparatorWrapWithEmoji.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/whitespace/separatorwrap/InputSeparatorWrapWithEmoji.java new file mode 100644 index 00000000000..c07e6ba3bbb --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/whitespace/separatorwrap/InputSeparatorWrapWithEmoji.java @@ -0,0 +1,44 @@ +/* +SeparatorWrap +option = NL +tokens = DOT, COMMA,ELLIPSIS, ARRAY_DECLARATOR, METHOD_REF + +*/ + +package com.puppycrawl.tools.checkstyle.checks.whitespace.separatorwrap; + +import java.util.Arrays; + +public class InputSeparatorWrapWithEmoji { + protected String[] s1 = new String[ + /*πŸŽ„ with text */ ] {"aabπŸŽ„", "aπŸŽ„aπŸ‘ba"}; // violation above ''\[' should be on a new line' + + /* emojiπŸ‘array */ protected String[] s2 = new String[ + ] {"πŸ₯³", "😠", "😨"}; // violation above''\[' should be on a new line' + + /*πŸ‘†πŸ» πŸ‘‡πŸ»*/ public void test1(String... + parameters) { // violation above ''...' should be on a new line' + } + + public void test2(String + /* πŸ‘ŒπŸ»πŸ‘ŒπŸ» */ ...parameters) { // ok + String s = "ffffooooString"; + /* 🧐πŸ₯³ */ s. + isEmpty(); // violation above ''.' should be on a new line' + try { + test2("2", s); + } catch (Exception e) {} + + test1("1" + /*🧐 sda πŸ₯³ */ ,s); // ok + + } + void goodCase() { + String[] stringArray = + { + "🌏", "πŸŒ”πŸŒŸ", "QWERTY", "πŸ§›πŸ»", "John", + /*🀞🏻*/ }; // violation above '',' should be on a new line' + /*🀞🏻 🀞🏻*/ Arrays.sort(stringArray, String:: + compareToIgnoreCase); // violation above ''::' should be on a new line' + } +}