Repository: checkstyle/checkstyle

Problem statement:
EmptyCatchBlock check does not work properly with non-system line endings in files
```
/var/tmp $ javac Foo.java

/var/tmp $ cat config.xml
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
        "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
        "https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
    <module name="TreeWalker">
        <module name="EmptyCatchBlock">
            <property name="commentFormat" value="This is expected"/>
        </module>
    </module>
</module>

/var/tmp $ cat Foo.java
import java.io.IOException;

class Foo {
    private void foo() {
        try {
            throw new IOException();
        } catch (IOException e) {
            /*
             * some comment
             * This is expected
             */
        }
    }
}

/var/tmp $ xxd Foo.java
00000000: 696d 706f 7274 206a 6176 612e 696f 2e49  import java.io.I
00000010: 4f45 7863 6570 7469 6f6e 3b0a 0a63 6c61  OException;..cla
00000020: 7373 2046 6f6f 207b 0a20 2020 2070 7269  ss Foo {.    pri
00000030: 7661 7465 2076 6f69 6420 666f 6f28 2920  vate void foo()
00000040: 7b0a 2020 2020 2020 2020 7472 7920 7b0a  {.        try {.
00000050: 2020 2020 2020 2020 2020 2020 7468 726f              thro
00000060: 7720 6e65 7720 494f 4578 6365 7074 696f  w new IOExceptio
00000070: 6e28 293b 0a20 2020 2020 2020 207d 2063  n();.        } c
00000080: 6174 6368 2028 494f 4578 6365 7074 696f  atch (IOExceptio
00000090: 6e20 6529 207b 0a20 2020 2020 2020 2020  n e) {.
000000a0: 2020 202f 2a0a 2020 2020 2020 2020 2020     /*.
000000b0: 2020 202a 2073 6f6d 6520 636f 6d6d 656e     * some commen
000000c0: 740a 2020 2020 2020 2020 2020 2020 202a  t.             *
000000d0: 2054 6869 7320 6973 2065 7870 6563 7465   This is expecte
000000e0: 640a 2020 2020 2020 2020 2020 2020 202a  d.             *
000000f0: 2f0a 2020 2020 2020 2020 7d0a 2020 2020  /.        }.
00000100: 7d0a 7d0a                                }.}.

/var/tmp $ java -Duser.language=en -Duser.country=US -Dline.separator=$'\n' -jar checkstyle-8.18-all.jar -c config.xml Foo.java
Starting audit...
[ERROR] D:\Sourcecode\other\discord-logger\tmp\Foo.java:7: Empty catch block. [EmptyCatchBlock]
Audit done.
Checkstyle ends with 1 errors.

/var/tmp $ java -Duser.language=en -Duser.country=US -Dline.separator=$'\r\n' -jar checkstyle-8.18-all.jar -c config.xml Foo.java
Starting audit...
Audit done.
```

---------------

When having non-system line endings in files as is quite common for cross-platform projects, the `EmptyCatchBlock` check fails to properly extract the first line of a block comment with CS 8.18 to check it against the comment format pattern.
Instead for example the full comment will be used when a file has linux line endings on windows, or the comment to test has an extra carriage return character in the end when a file has windows line endings on linux.
This even happens in `EmptyCatchBlockCheckTest#testWithUserSetValues` when the `InputEmptyCatchBlockDefault.java` file has linux line endings and you run the test on a windows system.


Hints:

Patch:
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyCatchBlockCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyCatchBlockCheck.java
--- a/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyCatchBlockCheck.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyCatchBlockCheck.java
@@ -159,6 +159,11 @@ public class EmptyCatchBlockCheck extends AbstractCheck {
      */
     public static final String MSG_KEY_CATCH_BLOCK_EMPTY = "catch.block.empty";
 
+    /**
+     * A pattern to split on line ends.
+     */
+    private static final Pattern LINE_END_PATTERN = Pattern.compile("\\r?+\\n|\\r");
+
     /**
      * Specify the RegExp for the name of the variable associated with exception.
      * If check meets variable name matching specified value - empty block is suppressed.
@@ -250,7 +255,7 @@ private static String getCommentFirstLine(DetailAST catchAst) {
         }
         else if (firstElementInBlock.getType() == TokenTypes.BLOCK_COMMENT_BEGIN) {
             commentContent = firstElementInBlock.getFirstChild().getText();
-            final String[] lines = commentContent.split(System.getProperty("line.separator"));
+            final String[] lines = LINE_END_PATTERN.split(commentContent);
             for (String line : lines) {
                 if (!line.isEmpty()) {
                     commentContent = line;


Test patch:
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyCatchBlockCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyCatchBlockCheckTest.java
--- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyCatchBlockCheckTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyCatchBlockCheckTest.java
@@ -73,6 +73,32 @@ public void testWithUserSetValues() throws Exception {
         verify(checkConfig, getPath("InputEmptyCatchBlockDefault.java"), expected);
     }
 
+    @Test
+    public void testLinesAreProperlySplitSystemIndependently() throws Exception {
+        final DefaultConfiguration checkConfig =
+            createModuleConfig(EmptyCatchBlockCheck.class);
+        checkConfig.addAttribute("exceptionVariableName", "expected|ignore|myException");
+        checkConfig.addAttribute("commentFormat", "This is expected");
+        final String[] expected = {
+            "35: " + getCheckMessage(MSG_KEY_CATCH_BLOCK_EMPTY),
+            "63: " + getCheckMessage(MSG_KEY_CATCH_BLOCK_EMPTY),
+            "97: " + getCheckMessage(MSG_KEY_CATCH_BLOCK_EMPTY),
+            "186: " + getCheckMessage(MSG_KEY_CATCH_BLOCK_EMPTY),
+            "195: " + getCheckMessage(MSG_KEY_CATCH_BLOCK_EMPTY),
+            "214: " + getCheckMessage(MSG_KEY_CATCH_BLOCK_EMPTY),
+            "230: " + getCheckMessage(MSG_KEY_CATCH_BLOCK_EMPTY),
+            "239: " + getCheckMessage(MSG_KEY_CATCH_BLOCK_EMPTY),
+        };
+        final String originalLineSeparator = System.getProperty("line.separator");
+        try {
+            System.setProperty("line.separator", "\r\n");
+            verify(checkConfig, getPath("InputEmptyCatchBlockDefaultLF.java"), expected);
+        }
+        finally {
+            System.setProperty("line.separator", originalLineSeparator);
+        }
+    }
+
     @Test
     public void testGetAcceptableTokens() {
         final EmptyCatchBlockCheck constantNameCheckObj = new EmptyCatchBlockCheck();
diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/blocks/emptycatchblock/InputEmptyCatchBlockDefaultLF.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/blocks/emptycatchblock/InputEmptyCatchBlockDefaultLF.java
new file mode 100644
--- /dev/null
+++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/blocks/emptycatchblock/InputEmptyCatchBlockDefaultLF.java
@@ -0,0 +1,244 @@
+////////////////////////////////////////////////////////////////////////////////
+// checkstyle: Checks Java source code for adherence to a set of rules.
+// Copyright (C) 2001-2019 the original author or authors.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+////////////////////////////////////////////////////////////////////////////////
+package com.puppycrawl.tools.checkstyle.checks.blocks.emptycatchblock;
+import java.io.IOException;
+public class InputEmptyCatchBlockDefaultLF
+{
+
+    private void foo() {
+        try {
+            throw new RuntimeException();
+        } catch (Exception expected) {
+            //Expected
+        }
+    }
+
+    private void foo1() {
+        try {
+            throw new RuntimeException();
+        } catch (Exception e) {}
+
+    }
+
+    private void foo2() {
+        try {
+            throw new IOException();
+        } catch (IOException | NullPointerException | ArithmeticException ignore) {
+        }
+    }
+
+    private void foo3() { // comment
+        try {
+            throw new IOException();
+        } catch (IOException | NullPointerException | ArithmeticException e) { //This is expected
+        }
+    }
+
+    private void foo4() {
+        try {
+            throw new IOException();
+        } catch (IOException | NullPointerException | ArithmeticException e) { /* This is expected*/
+        }
+    }
+
+    private void foo5() {
+        try {
+            throw new IOException();
+        } catch (IOException | NullPointerException | ArithmeticException e) { // Some singleline comment
+        }
+    }
+
+    private void foo6() {
+        try {
+            throw new IOException();
+        } catch (IOException expected) { // This is expected
+            int k = 0;
+        }
+    }
+
+    public void testTryCatch()
+    {
+        try {
+            int y=0;
+            int u=8;
+            int e=u-y;
+            return;
+        }
+        catch (Exception e) {
+            System.identityHashCode(e);
+            return;
+        }
+        finally
+        {
+            return;
+        }
+    }
+
+    public void testTryCatch2()
+    {
+        try {
+        }
+        catch (Exception e) { //OK
+            //This is expected
+            /* This is expected */
+            /**This is expected */
+        }
+        finally
+        {
+        }
+    }
+
+    public void testTryCatch3()
+    {
+        try {
+            int y=0;
+            int u=8;
+            int e=u-y;
+        }
+        catch (IllegalArgumentException e) {
+            System.identityHashCode(e); //some comment
+            return;
+        }
+        catch (IllegalStateException ex) {
+                System.identityHashCode(ex);
+                return;
+        }
+    }
+
+    public void testTryCatch4()
+    {
+        int y=0;
+        int u=8;
+        try {
+            int e=u-y;
+        }
+        catch (IllegalArgumentException e) {
+            System.identityHashCode(e);
+            return;
+        }
+    }
+    public void setFormats() {
+        try {
+            int k = 4;
+        } catch (Exception e) {
+            Object k = null;
+            if (k != null)
+                k = "ss";
+            else {
+                return;
+            }
+        }
+    }
+    public void setFormats1() {
+        try {
+            int k = 4;
+        } catch (Exception e) {
+            Object k = null;
+            if (k != null) {
+                k = "ss";
+            } else {
+                return;
+            }
+        }
+    }
+    public void setFormats2() {
+        try {
+            int k = 4;
+        } catch (Exception e) {
+            Object k = null;
+            if (k != null) {
+                k = "ss";
+                return;
+            }
+        }
+    }
+    public void setFormats3() {
+        try {
+            int k = 4;
+        } catch (Exception e) {
+            Object k = null;
+            if (k != null) {
+                k = "ss";
+
+            }
+        }
+    }
+
+    private void some() {
+        try {
+            throw new IOException();
+        } catch (IOException e) {
+            /* ololo
+             * blalba
+             */
+        }
+    }
+    private void some1() {
+        try {
+            throw new IOException();
+        } catch (IOException e) {
+            /* lalala
+             * This is expected
+             */
+        }
+    }
+    private void some2() {
+        try {
+            throw new IOException();
+        } catch (IOException e) {
+            /*
+             * This is expected
+             * lalala
+             */
+        }
+    }
+    private void some3() {
+        try {
+            throw new IOException();
+        } catch (IOException e) {
+            // some comment
+            //This is expected
+        }
+    }
+    private void some4() {
+        try {
+            throw new IOException();
+        } catch (IOException e) {
+            //This is expected
+            // some comment
+        }
+    }
+    private void some5() {
+        try {
+            throw new IOException();
+        } catch (IOException e) {
+            /* some comment */
+            //This is expected
+        }
+    }
+
+    private void emptyMultilineComment() {
+        try {
+            throw new IOException();
+        } catch (IOException e) {
+            /*
+*/
+        }
+    }
+}