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");