This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch GROOVY-12353
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY-12353 by this push:
     new a843fc47d9 GROOVY-12353: fix some issues found by Sonar
a843fc47d9 is described below

commit a843fc47d930d9d5e2bc563991893fec8266a15a
Author: Daniel Sun <[email protected]>
AuthorDate: Sun Sep 6 19:53:13 2026 +0900

    GROOVY-12353: fix some issues found by Sonar
---
 .../apache/groovy/parser/antlr4/AbstractLexer.java | 70 +++++++++++-----------
 .../groovy/parser/antlr4/AbstractLexerTest.java    | 53 +++++++---------
 2 files changed, 55 insertions(+), 68 deletions(-)

diff --git a/src/main/java/org/apache/groovy/parser/antlr4/AbstractLexer.java 
b/src/main/java/org/apache/groovy/parser/antlr4/AbstractLexer.java
index 9d2c7fb1d0..f755682cf2 100644
--- a/src/main/java/org/apache/groovy/parser/antlr4/AbstractLexer.java
+++ b/src/main/java/org/apache/groovy/parser/antlr4/AbstractLexer.java
@@ -158,44 +158,42 @@ public abstract class AbstractLexer extends Lexer 
implements SyntaxErrorReportab
         if (n == IntStream.EOF) {
             return -1;
         }
-        switch (n) {
-            case 'b':
-            case 't':
-            case 'n':
-            case 'f':
-            case 'r':
-            case 's':
-            case '"':
-            case '\'':
-            case '\\':
-            case '$':
-            case '\n':
-                return 2;
-            case '\r':
-                return input.LA(i + 2) == '\n' ? 3 : 2;
-            case 'u':
-                for (int h = 2; h <= 5; h++) {
-                    int d = input.LA(i + h);
-                    if (d == IntStream.EOF || !isAsciiHexDigit(d)) {
-                        return -1;
-                    }
-                }
-                return 6;
-            default:
-                if (n >= '0' && n <= '7') {
-                    int len = 2;
-                    int n2 = input.LA(i + 2);
-                    if (n2 >= '0' && n2 <= '7') {
-                        len = 3;
-                        int n3 = input.LA(i + 3);
-                        if (n <= '3' && n3 >= '0' && n3 <= '7') {
-                            len = 4;
-                        }
-                    }
-                    return len;
-                }
+        return switch (n) {
+            case 'b', 't', 'n', 'f', 'r', 's', '"', '\'', '\\', '$', '\n' -> 2;
+            case '\r' -> input.LA(i + 2) == '\n' ? 3 : 2;
+            case 'u' -> unicodeEscapeLength(input, i);
+            default -> octalEscapeLength(n, input, i);
+        };
+    }
+
+    /** {@code UnicodeEscape}: backslash-u plus four ASCII hex digits, else 
{@code -1}. */
+    private static int unicodeEscapeLength(final CharStream input, final int 
backslashAt) {
+        for (int h = 2; h <= 5; h++) {
+            int d = input.LA(backslashAt + h);
+            if (d == IntStream.EOF || !isAsciiHexDigit(d)) {
                 return -1;
+            }
+        }
+        return 6;
+    }
+
+    /**
+     * {@code OctalEscape}: one to three octal digits; three only when the 
first
+     * is {@code 0-3}.
+     */
+    private static int octalEscapeLength(final int firstDigit, final 
CharStream input, final int backslashAt) {
+        if (firstDigit < '0' || firstDigit > '7') {
+            return -1;
+        }
+        int n2 = input.LA(backslashAt + 2);
+        if (n2 < '0' || n2 > '7') {
+            return 2;
+        }
+        int n3 = input.LA(backslashAt + 3);
+        if (firstDigit > '3' || n3 < '0' || n3 > '7') {
+            return 3;
         }
+        return 4;
     }
 
     /** Matches {@code HexDigit} in {@code GroovyLexer.g4}: {@code 
[0-9a-fA-F]}. */
diff --git 
a/src/test/java/org/apache/groovy/parser/antlr4/AbstractLexerTest.java 
b/src/test/java/org/apache/groovy/parser/antlr4/AbstractLexerTest.java
index 230ad1ddc0..00f7e88a93 100644
--- a/src/test/java/org/apache/groovy/parser/antlr4/AbstractLexerTest.java
+++ b/src/test/java/org/apache/groovy/parser/antlr4/AbstractLexerTest.java
@@ -21,10 +21,14 @@ package org.apache.groovy.parser.antlr4;
 import org.antlr.v4.runtime.CharStreams;
 import org.antlr.v4.runtime.Token;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Stream;
 
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -121,13 +125,24 @@ final class AbstractLexerTest {
                 AbstractLexer.illegalEscapeMessage(rest, 3));
     }
 
-    @Test
-    void requireUnexpectedCharacterPointsAtIllegalBackslash() {
-        GroovyLangLexer lexer = new 
GroovyLangLexer(CharStreams.fromString("\"C:\\Users\\me\""));
+    @ParameterizedTest
+    @MethodSource("requirePositionCases")
+    void requirePositionsTheDiagnostic(final String src, final String message, 
final int line, final int column) {
+        GroovyLangLexer lexer = new 
GroovyLangLexer(CharStreams.fromString(src));
         GroovySyntaxError err = assertThrows(GroovySyntaxError.class, () -> 
drain(lexer));
-        assertEquals("Illegal escape character: '\\U'", err.getMessage());
-        assertEquals(1, err.getLine());
-        assertEquals(4, err.getColumn()); // 1-based: " C : \
+        assertEquals(message, err.getMessage());
+        assertEquals(line, err.getLine());
+        assertEquals(column, err.getColumn());
+    }
+
+    private static Stream<Arguments> requirePositionCases() {
+        return Stream.of(
+                // 1-based: " C : \   — caret on the illegal backslash
+                Arguments.of("\"C:\\Users\\me\"", "Illegal escape character: 
'\\U'", 1, 4),
+                Arguments.of("\"C:\\Users", "Illegal escape character: '\\U'", 
1, 4),
+                Arguments.of("/* comment", "Unclosed comment", 1, 1),
+                Arguments.of("    /* comment", "Unclosed comment", 1, 5)
+        );
     }
 
     @Test
@@ -239,14 +254,6 @@ final class AbstractLexerTest {
         assertEquals(Token.EOF, tokens.get(tokens.size() - 1).getType());
     }
 
-    @Test
-    void unclosedQuoteWithIllegalEscapeReportsTheEscape() {
-        GroovyLangLexer lexer = new 
GroovyLangLexer(CharStreams.fromString("\"C:\\Users"));
-        GroovySyntaxError err = assertThrows(GroovySyntaxError.class, () -> 
drain(lexer));
-        assertEquals("Illegal escape character: '\\U'", err.getMessage());
-        assertEquals(4, err.getColumn());
-    }
-
     @Test
     void errorIgnoredIllegalEscapeTokenizesWithoutThrowing() {
         GroovyLangLexer lexer = new 
GroovyLangLexer(CharStreams.fromString("\"\\q\""));
@@ -349,15 +356,6 @@ final class AbstractLexerTest {
         assertEquals("Unclosed string literal", err.getMessage());
     }
 
-    @Test
-    void requireUnclosedCommentPointsAtOpener() {
-        GroovyLangLexer lexer = new GroovyLangLexer(CharStreams.fromString("/* 
comment"));
-        GroovySyntaxError err = assertThrows(GroovySyntaxError.class, () -> 
drain(lexer));
-        assertEquals("Unclosed comment", err.getMessage());
-        assertEquals(1, err.getLine());
-        assertEquals(1, err.getColumn());
-    }
-
     @Test
     void errorIgnoredUnclosedCommentTokenizesWithoutThrowing() {
         GroovyLangLexer lexer = new GroovyLangLexer(CharStreams.fromString("/* 
comment"));
@@ -367,15 +365,6 @@ final class AbstractLexerTest {
         assertTrue(tokens.size() >= 2, tokens.toString());
     }
 
-    @Test
-    void requireUnclosedCommentPointsAtIndentedOpener() {
-        GroovyLangLexer lexer = new GroovyLangLexer(CharStreams.fromString("   
 /* comment"));
-        GroovySyntaxError err = assertThrows(GroovySyntaxError.class, () -> 
drain(lexer));
-        assertEquals("Unclosed comment", err.getMessage());
-        assertEquals(1, err.getLine());
-        assertEquals(5, err.getColumn());
-    }
-
     @Test
     void closedBlockCommentDoesNotConsumeTrailingSource() {
         List<Token> tokens = collect("/* ok */\ndef x = 1\n");

Reply via email to