NPE with lambdas in S4738

  • SonarQube Developer v7.4, sonar-java v5.9.1 build 16423 (from Marketplace)

Error:

Caused by: org.sonar.java.AnalysisException: SonarQube is unable to analyze file : '/Users/jschroeder/git/crash_repo/src/main/java/hello/HelloWorld.java'
        at org.sonar.java.ast.JavaAstScanner.simpleScan(JavaAstScanner.java:105)
        at org.sonar.java.ast.JavaAstScanner.scan(JavaAstScanner.java:68)
        at org.sonar.java.JavaSquid.scanSources(JavaSquid.java:116)
        at org.sonar.java.JavaSquid.scan(JavaSquid.java:110)
        at org.sonar.plugins.java.JavaSquidSensor.execute(JavaSquidSensor.java:93)
        at org.sonar.scanner.sensor.SensorWrapper.analyse(SensorWrapper.java:45)
        at org.sonar.scanner.phases.SensorsExecutor.execute(SensorsExecutor.java:88)
        at org.sonar.scanner.phases.SensorsExecutor.execute(SensorsExecutor.java:62)
        at org.sonar.scanner.phases.AbstractPhaseExecutor.execute(AbstractPhaseExecutor.java:74)
        at org.sonar.scanner.scan.ModuleScanContainer.doAfterStart(ModuleScanContainer.java:164)
        at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:136)
        at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:122)
        at org.sonar.scanner.scan.ProjectScanContainer.scan(ProjectScanContainer.java:319)
        at org.sonar.scanner.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:314)
        at org.sonar.scanner.scan.ProjectScanContainer.doAfterStart(ProjectScanContainer.java:288)
        at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:136)
        at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:122)
        at org.sonar.scanner.task.ScanTask.execute(ScanTask.java:48)
        at org.sonar.scanner.task.TaskContainer.doAfterStart(TaskContainer.java:82)
        at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:136)
        at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:122)
        at org.sonar.scanner.bootstrap.GlobalContainer.executeTask(GlobalContainer.java:131)
        at org.sonar.batch.bootstrapper.Batch.doExecuteTask(Batch.java:116)
        at org.sonar.batch.bootstrapper.Batch.executeTask(Batch.java:111)
        at org.sonarsource.scanner.api.internal.batch.BatchIsolatedLauncher.execute(BatchIsolatedLauncher.java:63)
        at org.sonarsource.scanner.api.internal.IsolatedLauncherProxy.invoke(IsolatedLauncherProxy.java:60)
        at com.sun.proxy.$Proxy535.execute(Unknown Source)
        at org.sonarsource.scanner.api.EmbeddedScanner.doExecute(EmbeddedScanner.java:233)
        at org.sonarsource.scanner.api.EmbeddedScanner.runAnalysis(EmbeddedScanner.java:151)
        at org.sonarqube.gradle.SonarQubeTask.run(SonarQubeTask.java:99)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:46)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:39)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:26)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:801)
        at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:768)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.run(ExecuteActionsTaskExecuter.java:131)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:300)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:292)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:174)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:90)
        at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:120)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:99)
        ... 31 more
Caused by: java.lang.NullPointerException
        at org.sonar.java.AnalyzerMessage.textSpanBetween(AnalyzerMessage.java:134)
        at org.sonar.java.AnalyzerMessage.textSpanFor(AnalyzerMessage.java:123)
        at org.sonar.java.model.DefaultJavaFileScannerContext.createAnalyzerMessage(DefaultJavaFileScannerContext.java:163)
        at org.sonar.java.model.DefaultJavaFileScannerContext.reportIssueWithFlow(DefaultJavaFileScannerContext.java:127)
        at org.sonar.java.model.DefaultJavaFileScannerContext.reportIssue(DefaultJavaFileScannerContext.java:120)
        at org.sonar.java.model.DefaultJavaFileScannerContext.reportIssue(DefaultJavaFileScannerContext.java:114)
        at org.sonar.plugins.java.api.IssuableSubscriptionVisitor.reportIssue(IssuableSubscriptionVisitor.java:62)
        at org.sonar.java.checks.ReplaceGuavaWithJava8Check.checkTypeToReplace(ReplaceGuavaWithJava8Check.java:99)
        at org.sonar.java.checks.ReplaceGuavaWithJava8Check.visitNode(ReplaceGuavaWithJava8Check.java:90)
        at org.sonar.java.model.VisitorsBridge$ScannerRunner.lambda$visit$7(VisitorsBridge.java:293)
        at org.sonar.java.model.VisitorsBridge$ScannerRunner.visit(VisitorsBridge.java:296)
        at org.sonar.java.model.VisitorsBridge$ScannerRunner.visitChildren(VisitorsBridge.java:278)
        at org.sonar.java.model.VisitorsBridge$ScannerRunner.visit(VisitorsBridge.java:300)

At org.sonar.java.AnalyzerMessage.textSpanFor(AnalyzerMessage.java:123) : both firstSyntaxToken and lastSyntaxToken are null, causing an NPE.

Reproducible test case:

package hello;

import com.google.common.base.Optional;
import io.reactivex.Observable;

public class HelloWorld {

    private static Observable<Optional<String>> getImageForNetworkResource() {
        return Observable.create(subscriber -> {
            // do something
        });
    }

    public static void main(String[] args) {
        System.out.println("hello, world");
        getImageForNetworkResource().filter(
                optionalStr -> { ////// << Sonar-java doesn't like this lambda
                    return optionalStr.isPresent();
                });
    }

}

build.gradle:


plugins {
    id "org.sonarqube" version "2.6"
}

apply plugin: 'application'
mainClassName = 'hello.HelloWorld'
group = 'sampleapp'


repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.google.guava:guava:20.0'
    implementation "io.reactivex.rxjava2:rxjava:2.2.2"
}

Possible workarounds: for me to refactor my lambda into a method reference, if possible! (my test case is a bit simplified)

Hello Jason,

Thanks a lot for the feedback. I reduced your case to the following slightly smaller code reproducing the issue (I get rid of the ReactiveX dependency, which is not required to reproduce the NPE):

abstract class A<X> {

  public void bar(A<com.google.common.base.Optional<String>> a) {
    a.foo(o -> { // << lambda causing NPE
      return o.isPresent();
    });
  }

  abstract A<X> foo(java.util.function.Predicate<X> predicate);
}

I consequently create the following JIRA ticket to handle it: SONARJAVA-2967

On top of the workaround your mention (using method references), note that there is also 2 other temporary workarounds you can put in place while we are working on the fix:

  • Disabling rule squid:S4738 [and losing all the other valid issues from the rule in your project]
  • excluding the file from your analysis [and losing all the other valid issues from other rules on the same file]

These are not ideal solutions, but it would allow you to continue with your analysis. I’m fully with you on the fact that it’s not always easily possible to rewrite lambdas with method references, so I won’t advise you to do so. :slight_smile:

Cheers,
Michael