False Positive on Java code in SonarLint for rule java:S1854

I guess SonarLint for IntelliJ 4.5.1.15617 is showing false positive warning:

Unused assignments should be removed java:S1854
‘Remove this useless assignment to local variable “!unknown!”.’

    static {
        final Function<Triple<CurrencyEnum, String, ImmutableMap.Builder<String, CurrencyEnum>>, Void> addCodeToBuilder
                = new Function<Triple<CurrencyEnum, String, ImmutableMap.Builder<String, CurrencyEnum>>, Void>() {

            void apply(final CurrencyEnum currency, final String currencyCode, final ImmutableMap.Builder<String, CurrencyEnum> mapBuilder) {
                mapBuilder.put(currencyCode, currency);
                final String currencyCodeUpper = currencyCode.toUpperCase(); <<<<<<<<<<<<<<<<<
                if (!currencyCode.equals(currencyCodeUpper)) {
                    mapBuilder.put(currencyCodeUpper, currency);
                }
            }
            ...

Hello @Petr_Nehez

Here are my first investigations:
I managed to build a smaller reproducer triggering a similar issue.

//import com.google.common.collect.ImmutableMap;
void apply(String param, ImmutableMap.Builder<String, Integer> anotherUnknownParam) {
  String paramToUpper = param.toUpperCase(); // FP: 'Remove this useless assignment to local variable "paramToUpper".
  if ("SOMETHING".equals(paramToUpper)) {
    System.out.println(paramToUpper);
  }
}

Note that the import is commented, if we uncomment it, the FP is not reported.
Then, concerning the strange !unknown!, I manage to reproduce it with similar code nested in an anonymous class.

//import com.google.common.collect.ImmutableMap;
class A {
  Function<ImmutableMap.Builder<String, Integer>, Integer> fun = new Function<ImmutableMap.Builder<String, Integer>, Integer>() {

    @Override
    public Integer apply(ImmutableMap.Builder<String, Integer> map) {
      return 1;
    }

    void apply(String param, ImmutableMap.Builder<String, Integer> anotherUnknownParam) {
      String paramToUpper = param.toUpperCase(); // FP: 'Remove this useless assignment to local variable "!unknown!".'
      if ("SOMETHING".equals(paramToUpper)) {
        System.out.println(paramToUpper);
      }
    }
  };
}

Once again, if we add the import back, everything works as expected.

So now, you might wonder what it has to do with your issue?

Bytecode of dependencies are required to get precise results, commenting an import “simulate” missing ones. I expect it to be a problem with classpath.

Hi @Petr_Nehez

Thanks @Quentin for the initial investigation. SonarLint for IntelliJ is supposed to provide the correct project classpath to the Java analyzer, so let’s investigate in this direction.

@Petr_Nehez could you please tell us if you are using connected mode with a SonarQube server (if yes, we will need the version of the Java analyzer installed on your SonarQube server)?
Then we will need a full analysis logs. Go to the SonarLint Tool Window, and enable verbose + analysis logs. Then reopen your offending file, and share the log with us. If you are concerned about privacy of paths and filenames, send it to me by private message.

This should look like this:

Trigger: EDITOR_OPEN
[Editor open] 1 file(s) submitted
Configuring analysis with org.sonarlint.intellij.analysis.JavaAnalysisConfigurator
Analysing 'SonarLintJob.java'...
Starting analysis with configuration:
[
  baseDir: /home/julien/Prog/Projects/sonar-intellij
  extraProperties: {sonar.java.target=1.8, sonar.java.libraries=/home/julien/.gradle/caches/modules-2/files-2.1/org.sonarsource.sonarlint.core/sonarlint-core/4.8.0.14729/f08fde1b1632c54876e578d147c4037e8c482099/sonarlint-core-4.8.0.14729.jar,/home/julien/.gradle/caches/modules-2/files-2.1/org.sonarsource.sonarlint.core/sonarlint-client-api/4.8.0.14729/65cd0d1ecfdc68c40e6d79bf2fe120971074467f/sonarlint-client-api-4.8.0.14729.jar,[...]}
  inputFiles: [
    file:///home/julien/Prog/Projects/sonar-intellij/src/main/java/org/sonarlint/intellij/analysis/SonarLintJob.java (UTF-8)
  ]
]

Available languages:
  * Java => "java"
[...]
Start analysis
Declared extensions of language Java were converted to java: **/*.java,**/*.jav
[...]
Index files
Language of file 'file:///home/julien/Prog/Projects/sonar-intellij/src/main/java/org/sonarlint/intellij/analysis/SonarLintJob.java' is detected to be 'java'
1 file indexed
Quality profiles:
  * java: 'Default - SonarSource conventions' (423 rules)
[...]
Execute Sensor: JavaSquidSensor
Configured Java source version (sonar.java.source): 8
JavaClasspath initialization
JavaClasspath initialization (done) | time=2ms
JavaTestClasspath initialization
JavaTestClasspath initialization (done) | time=3ms
----- Classpath analyzed by Squid:
/home/julien/Prog/Projects/sonar-intellij/out/production/classes
/home/julien/.gradle/caches/modules-2/files-2.1/org.sonarsource.sonarlint.core/sonarlint-core/4.8.0.14729/f08fde1b1632c54876e578d147c4037e8c482099/sonarlint-core-4.8.0.14729.jar
[...]
-----
----- Classpath analyzed by Squid:
/home/julien/Prog/Projects/sonar-intellij/out/production/classes
/home/julien/.gradle/caches/modules-2/files-2.1/org.sonarsource.sonarlint.core/sonarlint-core/4.8.0.14729/f08fde1b1632c54876e578d147c4037e8c482099/sonarlint-core-4.8.0.14729.jar
[...]
-----
Java Main Files AST scan
1 source files to be analyzed
Initializing metadata of file file:///home/julien/Prog/Projects/sonar-intellij/src/main/java/org/sonarlint/intellij/analysis/SonarLintJob.java
1/1 source files have been analyzed
Java Main Files AST scan (done) | time=394ms
[...]

Thanks

1 Like

Sorry for my layte reply, we are in hard times now :slight_smile:

@Quentin It has nothing to do with classpath, it is a problem in IntelliJ plugin.

@Julien_HENRY I enabled verbose log:

Trigger: ACTION
[Action] 1 file(s) submitted
Configuring analysis with org.sonarlint.intellij.analysis.JavaAnalysisConfigurator
Analysing 'CurrencyEnum.java'...
Starting analysis with configuration:
[
  baseDir: /home/petr/work/src/tipsport/tipsys2
  extraProperties: {sonar.java.target=8, sonar.java.source=6, sonar.java.binaries=/home/petr/work/src/tipsport/tipsys2/commons/bin, sonar.java.test.binaries=/home/petr/work/src/tipsport/tipsys2/commons/bin}
  excludedRules: [squid:S1220, squid:S3776, squid:S1135]
  includedRules: []
  inputFiles: [
    file:///home/petr/work/src/tipsport/tipsys2/commons/src/main/java/cz/tipsport/common/enums/CurrencyEnum.java (UTF-8)
  ]
]

Done in 151ms

Processed 3 issues in 0 ms
Found 3 issues

I don’t see anything suspicious there.

This is the full block which reproduces the issue:

    static {
        final Function<Triple<CurrencyEnum, String, ImmutableMap.Builder<String, CurrencyEnum>>, Void> addCodeToBuilder
                = new Function<Triple<CurrencyEnum, String, ImmutableMap.Builder<String, CurrencyEnum>>, Void>() {

            void apply(final CurrencyEnum currency, final String currencyCode, final ImmutableMap.Builder<String, CurrencyEnum> mapBuilder) {
                mapBuilder.put(currencyCode, currency);
                final String currencyCodeUpper = currencyCode.toUpperCase();
                if (!currencyCode.equals(currencyCodeUpper)) {
                    mapBuilder.put(currencyCodeUpper, currency);
                }
            }

            @Nullable
            @Override
            public Void apply(final Triple<CurrencyEnum, String, ImmutableMap.Builder<String, CurrencyEnum>> input) {
                apply(input.getKey1(), input.getKey2() != null ? input.getKey2() : input.getKey1().getCurrencyCode(), input.getKey3());
                return null;
            }
        };

        ImmutableMap.Builder<String, CurrencyEnum> currencyCodeMapBuilder = new ImmutableMap.Builder<String, CurrencyEnum>();
        ImmutableMap.Builder<String, CurrencyEnum> currencyCodeForPageMapBuilder = new ImmutableMap.Builder<String, CurrencyEnum>();
        for (CurrencyEnum currency : values()) {
            addCodeToBuilder.apply(Triple.of(currency, (String) null, currencyCodeMapBuilder));
            if (currency != GLD) {
                addCodeToBuilder.apply(Triple.of(currency, currency.getCurrencyCodeForPage(), currencyCodeForPageMapBuilder));
            }
        }

        currencyCodeMapBuilder.build();
    }

Hi @Petr_Nehez

No worries for the delay. I tried to reproduce without success, so I will need more details.

  1. What is your IntelliJ version, and what is the JRE used to run it (embedded JBR or a different one). You can check in the Help -> About menu. Here is what I have on my side:
    image

  2. What is the SDK configured for your project. Here is what I used in my attempt:
    image

@Julien_HENRY, I know the code looks weird :slight_smile:, but it was something for code review.

IntelliJ version is 2019.3.4
image

and this configuration for that project:
image

Can you share a bit more about your project dependencies?

  1. Can you confirm ImmutableMap comes from Guava?
  2. If yes, how is the dependency imported in your project? Are you using Maven or Gradle? Looking at the log you provided, it doesn’t seem so. Does the project compile in IntelliJ? Do you see something in project libraries?
    image

FYI, the issue I would like to investigate is why the property sonar.java.libraries only contains /home/petr/work/src/tipsport/tipsys2/commons/bin

This project is very old, it has been started 14 years ago.

  1. Yes, ImmutableMap comes from Guava.
  2. This specific project is Eclipse project with several modules and dependencies are imported from .classpath file(s).

The code was in a unit of module bo and that module has dependency to the module commons and that module has dependecy to the module where libraries are physically stored in repo.
The problematic code compiled fine in IntelliJ, there was no error at all, just that false report in SonarLint.

Feel free to ask for more details :slight_smile:.

This is it! I managed to reproduce. The classpath we are passing to our Java analyzer is incomplete (doesn’t contain transitive module dependencies), leading to your FP. I created a ticket, and we will fix it in the coming weeks:
https://jira.sonarsource.com/browse/SLI-393

Thanks again for sharing all those valuable informations!

1 Like

@Julien_HENRY Pleasure :wink: