From 4809d733192875ef3e475e40d36cb75c4782d00f Mon Sep 17 00:00:00 2001 From: Tomasz Tylenda Date: Thu, 22 Jan 2026 18:17:18 +0100 Subject: [PATCH] S106 Do not raise on Java 25 compact source files --- ...tOrErrUsageCheckCompactOnlyMainSample.java | 5 ++++ ...OrErrUsageCheckCompactWithClassSample.java | 21 ++++++++++++++++ .../java/checks/SystemOutOrErrUsageCheck.java | 24 +++++++++++++++---- .../checks/SystemOutOrErrUsageCheckTest.java | 16 +++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 java-checks-test-sources/default/src/main/java/checks/SystemOutOrErrUsageCheckCompactOnlyMainSample.java create mode 100644 java-checks-test-sources/default/src/main/java/checks/SystemOutOrErrUsageCheckCompactWithClassSample.java diff --git a/java-checks-test-sources/default/src/main/java/checks/SystemOutOrErrUsageCheckCompactOnlyMainSample.java b/java-checks-test-sources/default/src/main/java/checks/SystemOutOrErrUsageCheckCompactOnlyMainSample.java new file mode 100644 index 00000000000..1b7f921dead --- /dev/null +++ b/java-checks-test-sources/default/src/main/java/checks/SystemOutOrErrUsageCheckCompactOnlyMainSample.java @@ -0,0 +1,5 @@ +void main() { + String name = IO.readln("Enter your name: "); + IO.println("Hello " + name + "!"); + System.out.println("Goodbye " + name + "!"); +} diff --git a/java-checks-test-sources/default/src/main/java/checks/SystemOutOrErrUsageCheckCompactWithClassSample.java b/java-checks-test-sources/default/src/main/java/checks/SystemOutOrErrUsageCheckCompactWithClassSample.java new file mode 100644 index 00000000000..ebd7f65558a --- /dev/null +++ b/java-checks-test-sources/default/src/main/java/checks/SystemOutOrErrUsageCheckCompactWithClassSample.java @@ -0,0 +1,21 @@ +void main() { + String name = IO.readln("Enter your name: "); + IO.println("Hello " + name + "!"); + System.out.println("Goodbye " + name + "!"); + + System.out.println(f(6, 7)); + + RegularClass rc = new RegularClass(); + rc.log("This is a log message."); +} + +int f(int x, int y) { + System.err.println("Error: x=" + x + ", y=" + y); + return x + y; +} + +class RegularClass { + void log(String message) { + System.out.println(message); + } +} diff --git a/java-checks/src/main/java/org/sonar/java/checks/SystemOutOrErrUsageCheck.java b/java-checks/src/main/java/org/sonar/java/checks/SystemOutOrErrUsageCheck.java index 0ff0ca98f0f..dd716f87d66 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/SystemOutOrErrUsageCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/SystemOutOrErrUsageCheck.java @@ -29,20 +29,36 @@ @Rule(key = "S106") public class SystemOutOrErrUsageCheck extends IssuableSubscriptionVisitor { + private boolean isCompactSourceFile = false; + @Override public List nodesToVisit() { - return Collections.singletonList(Tree.Kind.MEMBER_SELECT); + return List.of( + Tree.Kind.COMPILATION_UNIT, + Tree.Kind.IMPLICIT_CLASS, + Tree.Kind.MEMBER_SELECT + ); } @Override public void visitNode(Tree tree) { - MemberSelectExpressionTree mset = (MemberSelectExpressionTree) tree; + if (tree.is(Tree.Kind.COMPILATION_UNIT)) { + isCompactSourceFile = false; + } else if (tree.is(Tree.Kind.IMPLICIT_CLASS)) { + // System.out or System.err is allowed in compact source files. + isCompactSourceFile = true; + } else if (!isCompactSourceFile && tree instanceof MemberSelectExpressionTree mset) { + visitMemberSelectExpression(mset); + } + } + + private void visitMemberSelectExpression(MemberSelectExpressionTree mset) { String name = mset.identifier().name(); if ("out".equals(name) && isSystem(mset.expression())) { - reportIssue(tree, "Replace this use of System.out by a logger."); + reportIssue(mset, "Replace this use of System.out by a logger."); } else if ("err".equals(name) && isSystem(mset.expression())) { - reportIssue(tree, "Replace this use of System.err by a logger."); + reportIssue(mset, "Replace this use of System.err by a logger."); } } diff --git a/java-checks/src/test/java/org/sonar/java/checks/SystemOutOrErrUsageCheckTest.java b/java-checks/src/test/java/org/sonar/java/checks/SystemOutOrErrUsageCheckTest.java index c09fed38453..81b19e26b60 100644 --- a/java-checks/src/test/java/org/sonar/java/checks/SystemOutOrErrUsageCheckTest.java +++ b/java-checks/src/test/java/org/sonar/java/checks/SystemOutOrErrUsageCheckTest.java @@ -29,4 +29,20 @@ void test() { .withCheck(new SystemOutOrErrUsageCheck()) .verifyIssues(); } + + @Test + void test_compact_source_file() { + CheckVerifier.newVerifier() + .onFile(mainCodeSourcesPath("checks/SystemOutOrErrUsageCheckCompactOnlyMainSample.java")) + .withCheck(new SystemOutOrErrUsageCheck()) + .verifyNoIssues(); + } + + @Test + void test_compact_source_file_with_regular_class() { + CheckVerifier.newVerifier() + .onFile(mainCodeSourcesPath("checks/SystemOutOrErrUsageCheckCompactWithClassSample.java")) + .withCheck(new SystemOutOrErrUsageCheck()) + .verifyNoIssues(); + } }