Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@t-kameyama
Copy link
Contributor

Fixes #2901

@codecov
Copy link

codecov bot commented Jul 28, 2020

Codecov Report

Merging #2903 into master will increase coverage by 0.01%.
The diff coverage is 75.75%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #2903      +/-   ##
============================================
+ Coverage     80.24%   80.26%   +0.01%     
- Complexity     2455     2467      +12     
============================================
  Files           422      423       +1     
  Lines          7420     7452      +32     
  Branches       1357     1367      +10     
============================================
+ Hits           5954     5981      +27     
+ Misses          762      759       -3     
- Partials        704      712       +8     
Impacted Files Coverage Δ Complexity Δ
...turbosch/detekt/rules/bugs/NullableToStringCall.kt 74.19% <74.19%> (ø) 10.00 <10.00> (?)
...turbosch/detekt/rules/bugs/PotentialBugProvider.kt 100.00% <100.00%> (ø) 2.00 <0.00> (ø)
.../gitlab/arturbosch/detekt/api/internal/BaseRule.kt 100.00% <0.00%> (+6.25%) 6.00% <0.00%> (ø%)
...rturbosch/detekt/api/internal/CompilerResources.kt 100.00% <0.00%> (+66.66%) 3.00% <0.00%> (+2.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 fc769b5...beb3028. Read the comment docs.

Copy link
Member

@cortinico cortinico left a comment

Choose a reason for hiding this comment

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

Thanks for your contribution @t-kameyama 🙏
There are several things that need to be addressed. Moreover, I advice for splitting this PR in maybe two.

Ideally, the rule should be simplified:

  • A simpler rule should just check if you're invoking kotlin.Any?.toString(). If so, report to the user that you can potentially return a "null".
  • Ideally the string template handling should be added afterwards. Potentially this can also be a separate rule as the name NullableToStringCall becomes confusing. Something like NullableStringInTemplate or something along this line.


open val ruleId: RuleId = javaClass.simpleName
var bindingContext: BindingContext = BindingContext.EMPTY
var languageVersionSettings: LanguageVersionSettings? = null
Copy link
Member

Choose a reason for hiding this comment

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

I'm unsure we want to have a LanguageVersionSettings stored in the baserule + extending to API to always pass it around just for a single rule.

If possible, let's come up with a simpler version of this rule that doesn't need a LanguageVersionSettings explicitly. We can still update BaseRule if it brings value, but it should probably be discussed with the other maintainers first.

val descriptor = expression.descriptor() ?: return
val originalType = descriptor.returnType ?.takeIf { it.isNullable() } ?: return
@Suppress("DEPRECATION")
val dataFlowValueFactory = DataFlowValueFactoryImpl(languageVersionSettings)
Copy link
Member

Choose a reason for hiding this comment

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

This class is deprecated and has a clear deprecation message on top:
https://github.com/JetBrains/kotlin/blob/687d13a320b4a5697aedca3ed31f6568a40deafa/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueFactoryImpl.kt#L28

I don't think we want to directly depend on this class.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can get a container with the following function and get an instance of DataFlowValueFactory from it.
https://github.com/JetBrains/kotlin/blob/017f640f26e29f1b1d0909d89e812aca9173691c/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/TopDownAnalyzerFacadeForJVM.kt#L130

However, I'm not using a container here because we only need an instance of DataFlowValueFactory.

*
* <compliant>
* fun foo(a: Any?): String {
* return a?.toString ?: "-"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* return a?.toString ?: "-"
* return a?.toString() ?: "-"

"""
val actual = subject.compileAndLintWithContext(env, code)
Assertions.assertThat(actual).hasSize(1)
Assertions.assertThat(actual.first().issue.id).isEqualTo("NullableToStringCall")
Copy link
Member

Choose a reason for hiding this comment

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

You can remove all the Assertions.assertThat(actual.first().issue.id)... as your subject contains only NullableToStringCall

it("reports when a nullable toString is implicitly called in a raw string template") {
val code = """
fun test(a: Any?) {
println(${'"'}${'"'}${'"'}${'$'}a${'"'}${'"'}${'"'})
Copy link
Member

Choose a reason for hiding this comment

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

It feels like this test is a bit too complicated. I'm having a hard time finding a real-world scenario where such code would be used.

Copy link
Member

Choose a reason for hiding this comment

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

This code just test println("""$a""") so ${'"'}""${'$'}a""${'"'} should be enought.

@BraisGabin
Copy link
Member

Why do you need LanguageVersionSettings? If you want to extend the detekt API we will need to move it to another PR and add some explanation for the change.

Ideally the string template handling should be added afterwards. Potentially this can also be a separate rule as the name NullableToStringCall becomes confusing. Something like NullableStringInTemplate or something along this line.

Why do you think that this should be two different rules? I mean, it's the same error. When you do this: "hello $any" you are doing an implicit call of toString(). NullableToStringCall doesn't seem a bad name thinking of this fact.

@cortinico
Copy link
Member

cortinico commented Jul 29, 2020

Why do you think that this should be two different rules? I mean, it's the same error. When you do this: "hello $any" you are doing an implicit call of toString(). NullableToStringCall doesn't seem a bad name thinking of this fact.

I don't have a strong opinion on having two separate rules here. On the other hand I do believe the explicit/implicit toString() call should be distinguished (if is not through a separate rule, a config option will also work).

@t-kameyama
Copy link
Contributor Author

t-kameyama commented Aug 4, 2020

Why do you need LanguageVersionSettings?

We don't want the following cases to be false positives.

fun test(a: Any?) {
    if (a != null) {
        println("$a") // 'a' is cast to 'String'
    }
}

To do so, we need to know if the variables have been smart cast. To know if it has been cast, we need the languageVersionSettings as follows.
https://github.com/t-kameyama/detekt/blob/16d7dd4dfbecfbc2b3ae0bb15cb1f3f1714cb7d5/detekt-rules-errorprone/src/main/kotlin/io/gitlab/arturbosch/detekt/rules/bugs/NullableToStringCall.kt#L69-L75

@t-kameyama
Copy link
Contributor Author

Ideally the string template handling should be added afterwards. Potentially this can also be a separate rule as the name NullableToStringCall becomes confusing. Something like NullableStringInTemplate or something along this line.

I don't think it's necessary to separate the two because I think it's the same error.

@cortinico
Copy link
Member

If you want to extend the detekt API we will need to move it to another PR and add some explanation for the change.

@t-kameyama please follow what @BraisGabin already suggested.

@arturbosch
Copy link
Member

arturbosch commented Aug 5, 2020

@t-kameyama thanks for the rule!
I agree with @cortinico that we should prefer a simpler version of this rule without handling string templates for now as we want to go into a different direction with the rule api (I wrote a longer comment in #2929 (comment)).

@BraisGabin
Copy link
Member

@t-kameyama please refactor this PR so we can merge it :). And thanks again for this great contribution!

@arturbosch arturbosch modified the milestones: 1.11.0, 1.11.0-RC2 Aug 9, 2020
@t-kameyama
Copy link
Contributor Author

PTAL

@arturbosch arturbosch merged commit 3bfec16 into detekt:master Aug 11, 2020
@t-kameyama t-kameyama deleted the issue_2901 branch August 11, 2020 10:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New rule: toString over a nullable value

4 participants