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

Add list of functions to skip in IgnoredReturnValue rule #4434

Merged
merged 9 commits into from Jan 28, 2022
1 change: 1 addition & 0 deletions detekt-core/src/main/resources/default-detekt-config.yml
Expand Up @@ -552,6 +552,7 @@ potential-bugs:
- '*.CheckReturnValue'
ignoreReturnValueAnnotations:
- '*.CanIgnoreReturnValue'
skipFunctions: []
ImplicitDefaultLocale:
active: true
ImplicitUnitReturnType:
Expand Down
Expand Up @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.typeUtil.isUnit

/**
Expand Down Expand Up @@ -58,6 +59,12 @@ class IgnoredReturnValue(config: Config = Config.empty) : Rule(config) {
it.map(String::simplePatternToRegex)
}

@Configuration(
"List of fully-qualified function names that should be skipped by this check. " +
"Example: 'package.class.fun1'"
)
private val skipFunctions: List<String> by config(emptyList())
Copy link
Member

Choose a reason for hiding this comment

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

I think that you should use FunctionMatcher. It provides more porwerful matching (you can match only by name or name + param types. Here a rule using it:

@Configuration(
"List of fully qualified method signatures which are forbidden. " +
"Methods can be defined without full signature (i.e. `java.time.LocalDate.now`) which will report " +
"calls of all methods with this name or with full signature " +
"(i.e. `java.time.LocalDate(java.time.Clock)`) which would report only call " +
"with this concrete signature."
)
private val methods: List<FunctionMatcher> by config(
listOf(
"kotlin.io.print",
"kotlin.io.println",
)
) { it.map(FunctionMatcher::fromFunctionSignature) }


@Suppress("ReturnCount")
override fun visitCallExpression(expression: KtCallExpression) {
super.visitCallExpression(expression)
Expand All @@ -68,6 +75,8 @@ class IgnoredReturnValue(config: Config = Config.empty) : Rule(config) {
val resultingDescriptor = expression.getResolvedCall(bindingContext)?.resultingDescriptor ?: return
if (resultingDescriptor.returnType?.isUnit() == true) return

if (resultingDescriptor.fqNameSafe.asString() in skipFunctions) return

val annotations = resultingDescriptor.annotations
if (annotations.any { it in ignoreReturnValueAnnotations }) return
if (restrictToAnnotatedMethods &&
Expand Down
Expand Up @@ -813,5 +813,28 @@ object IgnoredReturnValueSpec : Spek({
val findings = rule.compileAndLintWithContext(env, code)
assertThat(findings).isEmpty()
}

it("does not report when a function is in skip list") {
val code = """
package foo

fun listOfChecked(value: String) = listOf(value)

fun foo() : Int {
listOfChecked("hello")
return 42
}
"""
val rule = IgnoredReturnValue(
TestConfig(
mapOf(
"skipFunctions" to listOf("foo.listOfChecked"),
"restrictToAnnotatedMethods" to false
)
)
)
val findings = rule.compileAndLintWithContext(env, code)
assertThat(findings).isEmpty()
}
}
})