java:S3063 False negative when StringBuilder/StringBuffer declaration and assignment are split

Product: SonarQube Community Build 26.5.0.122743
sonar-java version: sonar-java 8.29 (build 43460)
sonar-java SE version: sonar-java-symbolic-execution 8.16.4 (build 1912)
Java source level: 21 (javac 21, source/target 21)

Rule

S3063 - “StringBuilder” data should be used

Description

The rule `S3063` is designed to detect `StringBuilder` and `StringBuffer` instances that are created but never consumed (e.g., via `.toString()`), as they needlessly clutter the code and impact performance.

However, the current implementation fails to trigger a warning if the variable declaration and its instantiation/assignment are split into two separate statements. When they are combined into a single statement (declaration with immediate initialization), the rule works perfectly.

This inconsistent behavior indicates a gap in the Symbolic Execution / Data Flow Analysis when tracking local variable re-assignments or split declarations.

Reproducer

public class S3063Reproducer {
    // Case 1: False Negative (No finding)
    public void withSplitDeclaration() {
        StringBuffer foo;
        foo = new StringBuffer("test"); // S3063 should fire here, but is missed.
    }

    // Case 2: Correct Behavior (S3063 fired)
    public void withImmediateInitialization() {
        StringBuffer bar = new StringBuffer("test"); // Noncompliant \[\[sc=24;ec=47\]\] {{S3063}}
    }
}

Expected behavior

Both withSplitDeclaration and withImmediateInitialization methods should raise an S3063 issue. In both cases, the StringBuffer instance is allocated but its data is never used or converted via toString(), which exactly matches the performance-wasting pattern this rule aims to prevent.

Actual behavior

  • withImmediateInitialization() correctly triggers the S3063 violation.

  • withSplitDeclaration() silently passes without any warning, resulting in a False Negative (FN).