S1144 false positive for JUnit 5 implicit @MethodSource

Product: SonarQube Community 26.4.0.121862
sonar-java version: sonar-java 8.28.0.43176
sonar-java SE version: sonar-java-symbolic-execution 8.16.3.1589
Java source level: 21 (javac 21, source/target 17)

Rule

java:S1144 — Unused “private” methods should be removed

Description

SonarJava incorrectly reports a private static method as unused when it is used implicitly via JUnit 5 @MethodSource without an explicit value. In this case, JUnit resolves the method by matching the test method name and calls it reflectively at runtime, so the method is actually used. S1144 should treat this implicit resolution the same as the explicit @MethodSource("methodName") form.

Reproducer

// AFTER — S1144 false positive
package demo.after;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

public class MethodSourceTest {

    private enum Color { RED, GREEN, BLUE }

    @ParameterizedTest
    @MethodSource // implicit: resolves to a factory named "testColorProcessing"
    void testColorProcessing(Color color, boolean flag) {
        System.out.println(color);
        System.out.println(flag);
    }

    // S1144 flags this as unused, but JUnit 5 calls it reflectively
    private static Stream<Arguments> testColorProcessing() {
        return Stream.of(
            Arguments.of(Color.RED, true),
            Arguments.of(Color.RED, false),
            Arguments.of(Color.GREEN, true),
            Arguments.of(Color.GREEN, false),
            Arguments.of(Color.BLUE, true),
            Arguments.of(Color.BLUE, false)
        );
    }
}

For comparison, the equivalent explicit form does not trigger S1144:

// BEFORE — no S1144
@ParameterizedTest
@MethodSource("provideParameters")
void testColorProcessing(Color color, boolean flag) { ... }

private static Stream<Arguments> provideParameters() { ... }

Hi @Emilyaxe ,

Thank you for reporting this false positive!

After investigation, I found that this FP only occurs when the semantic information is incomplete (often due to a scanner misconfiguration where the classpath is not fully provided). When the analyzer has full semantic context, it resolves these implicit references correctly.

To help us investigate further:

  • Could you share which scanner you are using (Maven, Gradle, CLI)?

  • Would you mind checking if your classpath/libraries are correctly configured during the scan?

Regardless of the configuration, we will work on making the rule more robust so it doesn’t trigger even when semantics are incomplete.

Thank you again for the detailed reproducer!

Hi, @romain.birling

Thanks for the quick response, and you were right. After adding the JUnit path to the classpath, the issue no longer reproduces and the rule works correctly.

I will make sure to avoid this kind of classpath configuration issue in future scans.

Thanks again for the help and clarification.

Hi @Emilyaxe ,

Could you confirm if you are using the SonarScanner CLI?

I just want to ensure there isn’t a broader issue with one of our scanners.

Best regards,

Romain

I’m using the sonar-scanner CLI

Thank you for the confirmation!
This explains the missing context, as the CLI scanner requires manual classpath configuration, unlike the Maven or Gradle scanners.

Best,
Romain