FALSE NEGATIVE: `java:S2159` loses the covariant return type after a local upcast

Hi, I found a false negative in SonarQube 26.7.0 with sonar-java 8.41 when a local upcast hides a covariant return type from java:S2159.

Affected tool

SonarQube 26.7.0.124771; sonar-java 8.41 (build 47177)

Affected checker

SonarQube java:S2159

Minimal reproducer

class SpotBugsSonarQubeS2159Upcast {
  static class Base {
    Base value() { return this; }
  }

  static class Left extends Base {
    @Override
    Left value() { return this; }
  }

  static class Right extends Base {}

  boolean direct(Left left, Right right) {
    return left.value().equals(right);
  }

  boolean afterUpcast(Left left, Right right) {
    Base base = left;
    return base.value().equals(right);
  }
}

Reproduction command

sonar-scanner --version
sonar-scanner -Dsonar.projectKey=spotbugs-sonarqube-reproducer -Dsonar.sources=spotbugs-sonarqube-s2159-fn-upcast-covariant-return.java -Dsonar.host.url="$SONAR_HOST_URL" -Dsonar.token="$SONAR_TOKEN"

Current behavior

SonarQube reports java:S2159 for direct() at line 14, but produces no java:S2159 diagnostic for the equivalent comparison after the local upcast at line 19. SpotBugs reports EC_UNRELATED_TYPES for both comparisons.

Expected behavior

SonarQube should also report line 19 because base is initialized directly from left; dynamic dispatch still selects Left.value(), whose covariant return type is Left, and Left is unrelated to Right.

Hello @marktiwnzhao,

Thank you for reporting this issue. I’m agree that it’s FN, but proper resolving of such cases requires using symbolic execution mechanisms. I’ll create a ticket to investigate this, but real fix will take some time, and we’re not sure for now when it’ll be fixed.