Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix False Positive on UnnecessarySafeCall #3419

Merged

Conversation

cortinico
Copy link
Member

This is a fix for the various false positives on UnnecessarySafeCall.

After some debugging the problems seems to be with misconfigured class-paths (e.g. cph-cachet/carp.core-kotlin#223). If the classpath doesn't contain a third-party types, but still has a safe call operator, the Kotlin Compiler raises an Errors.UNNECESSARY_SAFE_CALL detection.

Inside the detection the compiler adds information on the non-nullable type that is the receiver of the safe call (in the .a field). In this patch I'm try to see if the compiler failed to resolve the type => If so, we can skip the report.

Fixes #3409
Fixes #3414

@cortinico cortinico changed the title Fix False Positive on UnnecessarySafeCall Fix False Positive on UnnecessarySafeCall Jan 27, 2021
@cortinico cortinico force-pushed the nc/unnecessary-safe-call-unknown-type branch from b4cf2ff to 179fe30 Compare January 27, 2021 20:35
@codecov
Copy link

codecov bot commented Jan 27, 2021

Codecov Report

Merging #3419 (8548e5c) into master (95a1220) will increase coverage by 0.00%.
The diff coverage is 66.66%.

Impacted file tree graph

@@            Coverage Diff            @@
##             master    #3419   +/-   ##
=========================================
  Coverage     80.37%   80.37%           
- Complexity     2748     2749    +1     
=========================================
  Files           449      449           
  Lines          8295     8301    +6     
  Branches       1587     1590    +3     
=========================================
+ Hits           6667     6672    +5     
  Misses          774      774           
- Partials        854      855    +1     
Impacted Files Coverage Δ Complexity Δ
...rturbosch/detekt/rules/bugs/UnnecessarySafeCall.kt 75.00% <66.66%> (ø) 5.00 <0.00> (+1.00)
...turbosch/detekt/rules/style/UnusedPrivateMember.kt 90.76% <0.00%> (+0.14%) 5.00% <0.00%> (ø%)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 95a1220...8548e5c. Read the comment docs.

Copy link
Member

@BraisGabin BraisGabin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way to create a unit test?

Comment on lines 60 to 66
if (compilerReport != null) {
// For external types, if they're not included in the classpath, we still get an Errors.UNNECESSARY_SAFE_CALL.
// This causes false positives if our users are misconfiguring detekt with Type Resolution.
// Here we try to check if the compiler reports failed to resolve the nullable type.
if (compilerReport is DiagnosticWithParameters1<*, *> && compilerReport.a is ErrorType) {
return
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me this is still strange. Why is this popping up only after updating to the newest compiler version?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be able to find the exact DiagnosticWithParameters1 definition of the errors being reported and add this to the documentation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me this is still strange. Why is this popping up only after updating to the newest compiler version?

I believe this is related to us enabling the rule by default:
#3419

val compilerReport = bindingContext
.diagnostics
.forElement(safeAccessElement)
.firstOrNull { it.factory == Errors.UNNECESSARY_SAFE_CALL }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we still keep any instead of firstOrNull? I think the code depends on the order for the diagnostics, which seems too fragile.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we still keep any instead of firstOrNull?

I could change it to a forEach as we need to get access to the compilerReport

@cortinico
Copy link
Member Author

Is there any way to create a unit test?

Found a test case for it 👌 The only drawback is that we can't compile the test snippet as the import will break the compilation.

@cortinico
Copy link
Member Author

Turns out the Kotlin compiler was actually wrong here. I've pushed a fix upstream JetBrains/kotlin#4072 so we can revert our patch as soon as Kotlin 1.5 is out 🥳

@BraisGabin
Copy link
Member

How can we be sure that we don't forget? Create the pr with a blocked label and merge it as soon as we move to kotlin 1.5?

@schalkms
Copy link
Member

schalkms commented Feb 2, 2021

Turns out the Kotlin compiler was actually wrong here. I've pushed a fix upstream JetBrains/kotlin#4072 so we can revert our patch as soon as Kotlin 1.5 is out 🥳

That's really interesting, so this suspicion was right.
#3409 (comment)

How can we be sure that we don't forget? Create the pr with a blocked label and merge it as soon as we move to kotlin 1.5?

I'd suggest this approach.

@cortinico
Copy link
Member Author

How can we be sure that we don't forget? Create the pr with a blocked label and merge it as soon as we move to kotlin 1.5?

Created here #3439

This was referenced Mar 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
4 participants