diff --git a/java-checks-test-sources/default/src/main/files/non-compiling/checks/IoPrintlnUsageCheckCompactSample.java b/java-checks-test-sources/default/src/main/files/non-compiling/checks/IoPrintlnUsageCheckCompactSample.java new file mode 100644 index 0000000000..974efeb49a --- /dev/null +++ b/java-checks-test-sources/default/src/main/files/non-compiling/checks/IoPrintlnUsageCheckCompactSample.java @@ -0,0 +1,20 @@ +import java.io.IO; + +void main() { + IO.println(""); // Compliant + IO.print(""); // Compliant + f(); + new A().f(); +} + +void f() { + IO.println(""); // Compliant + IO.print(""); // Compliant +} + +class A { + void f() { + IO.println(""); // Compliant + IO.print(""); // Compliant + } +} diff --git a/java-checks-test-sources/default/src/main/files/non-compiling/checks/IoPrintlnUsageCheckSample.java b/java-checks-test-sources/default/src/main/files/non-compiling/checks/IoPrintlnUsageCheckSample.java new file mode 100644 index 0000000000..275bc47a71 --- /dev/null +++ b/java-checks-test-sources/default/src/main/files/non-compiling/checks/IoPrintlnUsageCheckSample.java @@ -0,0 +1,14 @@ +package checks; + + +import java.io.IO; +import java.io.PrintStream; + +class IoPrintlnUsageCheckSample { + + void f() { + IO.println(""); // Noncompliant {{Replace this use of IO.println by a logger.}} + IO.print(""); // Noncompliant {{Replace this use of IO.print by a logger.}} + } + +} 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 db2a53d2bf..18aece244c 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 @@ -22,7 +22,6 @@ import org.sonar.plugins.java.api.tree.IdentifierTree; import org.sonar.plugins.java.api.tree.MemberSelectExpressionTree; import org.sonar.plugins.java.api.tree.Tree; - import java.util.List; @Rule(key = "S106") @@ -53,11 +52,12 @@ public void visitNode(Tree tree) { private void visitMemberSelectExpression(MemberSelectExpressionTree mset) { String name = mset.identifier().name(); - if ("out".equals(name) && isSystem(mset.expression())) { reportIssue(mset, "Replace this use of System.out by a logger."); } else if ("err".equals(name) && isSystem(mset.expression())) { reportIssue(mset, "Replace this use of System.err by a logger."); + } else if (isIoPrintFunction(mset)) { + reportIssue(mset, "Replace this use of IO." + mset.identifier().name() + " by a logger."); } } @@ -70,4 +70,12 @@ private static boolean isSystem(ExpressionTree expression) { } return identifierTree != null && "System".equals(identifierTree.name()); } + + private static boolean isIoPrintFunction(MemberSelectExpressionTree mset) { + boolean isIoFunction = mset.expression().parent() instanceof MemberSelectExpressionTree tree && + tree.expression() instanceof IdentifierTree identifierTree && + "IO".equals(identifierTree.name()); + // use contains to cover both print and println methods + return isIoFunction && mset.identifier().name().contains("print"); + } } 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 81b19e26b6..43e91a8cf5 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 @@ -20,10 +20,11 @@ import org.sonar.java.checks.verifier.CheckVerifier; import static org.sonar.java.checks.verifier.TestUtils.mainCodeSourcesPath; +import static org.sonar.java.checks.verifier.TestUtils.nonCompilingTestSourcesPath; class SystemOutOrErrUsageCheckTest { @Test - void test() { + void test_sout() { CheckVerifier.newVerifier() .onFile(mainCodeSourcesPath("checks/SystemOutOrErrUsageCheckSample.java")) .withCheck(new SystemOutOrErrUsageCheck()) @@ -31,13 +32,29 @@ void test() { } @Test - void test_compact_source_file() { + void test_sout_compact_source_file() { CheckVerifier.newVerifier() .onFile(mainCodeSourcesPath("checks/SystemOutOrErrUsageCheckCompactOnlyMainSample.java")) .withCheck(new SystemOutOrErrUsageCheck()) .verifyNoIssues(); } + @Test + void test_io() { + CheckVerifier.newVerifier() + .onFile(nonCompilingTestSourcesPath("checks/IoPrintlnUsageCheckSample.java")) + .withCheck(new SystemOutOrErrUsageCheck()) + .verifyIssues(); + } + + @Test + void test_io_compact_source_file() { + CheckVerifier.newVerifier() + .onFile(nonCompilingTestSourcesPath("checks/IoPrintlnUsageCheckCompactSample.java")) + .withCheck(new SystemOutOrErrUsageCheck()) + .verifyNoIssues(); + } + @Test void test_compact_source_file_with_regular_class() { CheckVerifier.newVerifier()