From 2d6bb094ee69a04c5e62f043c6b0297fc98d67ab Mon Sep 17 00:00:00 2001 From: tomasz-tylenda-sonarsource Date: Wed, 11 Dec 2024 14:15:29 +0100 Subject: [PATCH] SONARJAVA-4436 Fix FP on S2095 when using @lombok.Cleanup (#4957) Co-authored-by: Dorian Burihabwa <75226315+dorian-burihabwa-sonarsource@users.noreply.github.com> --- .../java/se/checks/UnclosedResourcesCheck.java | 12 +++++++++++- .../files/se/UnclosedResourcesLombokCheck.java | 18 ++++++++++++++++++ .../se/checks/UnclosedResourcesCheckTest.java | 18 ++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 java-symbolic-execution/java-symbolic-execution-plugin/src/test/files/se/UnclosedResourcesLombokCheck.java diff --git a/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/checks/UnclosedResourcesCheck.java b/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/checks/UnclosedResourcesCheck.java index bcebf96267a..4b261f1312f 100644 --- a/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/checks/UnclosedResourcesCheck.java +++ b/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/checks/UnclosedResourcesCheck.java @@ -474,11 +474,21 @@ private void closeResource(@Nullable final SymbolicValue target) { @Override public void visitIdentifier(IdentifierTree tree) { // close resource as soon as it is encountered in the resource declaration - if (isWithinTryHeader(tree)) { + // or if it is annotated with @lombok.Cleanup + if (isWithinTryHeader(tree) || isAnnotatedLombokCleanup(tree)) { Symbol symbol = tree.symbol(); closeResource(programState.getValue(symbol)); } } + + private static boolean isAnnotatedLombokCleanup(IdentifierTree tree) { + return tree + .symbol() + .metadata() + .annotations() + .stream() + .anyMatch(annotation -> annotation.symbol().type().fullyQualifiedName().endsWith("Cleanup")); + } } private class PostStatementVisitor extends CheckerTreeNodeVisitor { diff --git a/java-symbolic-execution/java-symbolic-execution-plugin/src/test/files/se/UnclosedResourcesLombokCheck.java b/java-symbolic-execution/java-symbolic-execution-plugin/src/test/files/se/UnclosedResourcesLombokCheck.java new file mode 100644 index 00000000000..473712b1dbb --- /dev/null +++ b/java-symbolic-execution/java-symbolic-execution-plugin/src/test/files/se/UnclosedResourcesLombokCheck.java @@ -0,0 +1,18 @@ +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import lombok.Cleanup; + +class UnclosedResourcesLombokCheck { + public void fullyQualified(String fileName) throws IOException { + @lombok.Cleanup + InputStream in = new FileInputStream(fileName); + in.read(); + } + + public void annotated(String fileName) throws IOException { + @Cleanup + InputStream in = new FileInputStream(fileName); + in.read(); + } +} diff --git a/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/checks/UnclosedResourcesCheckTest.java b/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/checks/UnclosedResourcesCheckTest.java index 3e180415940..a4d72863f92 100644 --- a/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/checks/UnclosedResourcesCheckTest.java +++ b/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/checks/UnclosedResourcesCheckTest.java @@ -33,6 +33,24 @@ void test() { .verifyIssues(); } + @Test + void doesNotRaiseOnLombokCleanupAnnotatedVariable() { + SECheckVerifier.newVerifier() + .onFile("src/test/files/se/UnclosedResourcesLombokCheck.java") + .withCheck(new UnclosedResourcesCheck()) + .withClassPath(SETestUtils.CLASS_PATH) + .verifyNoIssues(); + } + + @Test + void doesNotRaiseOnLombokCleanupAnnotatedVariableNoSemantic() { + SECheckVerifier.newVerifier() + .onFile("src/test/files/se/UnclosedResourcesLombokCheck.java") + .withCheck(new UnclosedResourcesCheck()) + .withoutSemantic() + .verifyNoIssues(); + } + @Test void jdbcTests() { SECheckVerifier.newVerifier()