Kotlin S6531 False Positive unnecessary cast

We have at least one example of a false positive for useless cast in Kotlin.

  • What language is this for - Kotlin
  • Which rule? S6531 useless cast
  • Why do you believe it’s a false-positive/false-negative? The cast is needed to make IntelliJ happy
  • using Sonarcloud

Reproduction:
We have rewritten this part of this library into Kotlin:

in Kotlin our IntelliJ IDE suggests on that line that the type of matchingHandlers.get(0) is List<Command.Handler<*, *>> and that it needs to be cast to List<Command.Handler<C, R>

Of note would be that this is a scenario where we’re doing a cast that the compiler thinks is unchecked where it actually is fully validated. It’s possible then the sonar highlighter is being smarter than the compiler itself in knowing that the cast is unneeded and that the root fix is with the compiler, but until then I think this would still technically be a false positive?

Hello @TiKevin83 , thanks a lot for raising this issue.

Could you please point me to the Kotlin project that can reproduce this issue ?

Thanks for contributing to the community.

Hi Jonathan,
This is a proprietary/private repo so I can’t point directly to the codebase beyond my description of the issue above. With my understanding of Kotlin as a superset of Java it would be relatively trivial to reproduce on the described line with slight modifications to the Java repo to compile it under Kotlin

Hello Travis

I understand.

I tried to convert the class into Kotlin (in fact this is what we were expecting, not the full project).


And according to the resultant code, I see the warning from the IDE but not from SonarLint.
However, this may not be your exact context, as I don’t know how your class with types is really created.

In order to analyze properly the issue you are reporting we need the real piece of code in order to reproduce it and test it.

That’s exactly it, if you throw as Command.Handler<C, R> there on the matchingHandlers[0] and then @Suppress("UNCHECKED_CAST") above that should match our scenario exactly.

OK. Thanks for the clarification.

Just to better understand the issue.

  1. SonarLint is not complaining as it is now.
  2. Intellij is complaining
  3. You are doing the casting just to please Intellij
  4. Then is when SonarLint complains

Is that right ?

Yes though in #2 to clarify I also see a failure at compilation and not just the IDE warning, which is what leads me to see it as a false positive for sonar and not a false positive on the IntelliJ IDE, this is the compiler error:

Type mismatch: inferred type is Command.Handler<*, *> but Command.Handler<C, R> was expected

So, now adding the cast and suppress:

override fun <C : Command<R>?, R> route(command: C): Command.Handler<C, R> {
    val matchingHandlers =
            commandHandlers.supply().filter { handler: Command.Handler<*, *> -> handler.matches(command) }.collect(Collectors.toList())

    val noMatches = matchingHandlers.isEmpty()
    if (noMatches) {
        throw CommandHandlerNotFoundException(command)
    }

    val moreThanOneMatch = matchingHandlers.size > 1
    if (moreThanOneMatch) {
        throw CommandHasMultipleHandlersException(command, matchingHandlers)
    }

    @Suppress("UNCHECKED_CAST")
    return matchingHandlers[0] as Command.Handler<C, R>
}

I understand now that what you mean is that the compiler forces to do the cast and suppress the unchecked warning, but then SonarLint should not complain that it is a redundant cast.

  1. Am I right with what you mean ?
  2. I don’t see any complaints from SonarLint. Do you see them?

We’re seeing the complaint at the point of sonarcloud analysis, I think it’s possible that it doesn’t show up locally from SonarLint but it does in the cloud analysis? That’s about the end of my guesses though.