Skip to content

Commit

Permalink
Document and test edge cases for ForbiddenMethodCall function signatu…
Browse files Browse the repository at this point in the history
…res (#5495)

I was stuck trying to match some function signatures (from Timber on Android)
for the ForbiddenMethodCall rule and had to test inside detekt to figure out how
to do it properly. To make this more clear in the future, I've expanded the
description of the methods configuration parameter and added more tests for
these cases. Some of this might be obvious to some but it was not to me at the
time so I think having some quick tips might be helpful; or perhaps a link to a
more comprehensive guide on Kotlin function signatures (if one exists).
  • Loading branch information
dzirbel committed Nov 3, 2022
1 parent f0b9b44 commit 621bcc9
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 2 deletions.
Expand Up @@ -58,10 +58,13 @@ class ForbiddenMethodCall(config: Config = Config.empty) : Rule(config) {
"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. If you want to forbid an extension function like" +
"with this concrete signature. If you want to forbid an extension function like " +
"`fun String.hello(a: Int)` you should add the receiver parameter as the first parameter like this: " +
"`hello(kotlin.String, kotlin.Int)`. To forbid constructor calls you need to define them with `<init>`, " +
" for example `java.util.Date.<init>`."
"for example `java.util.Date.<init>`. To forbid calls involving type parameters, omit them, for example " +
"`fun hello(args: Array<Any>)` is referred to as simply `hello(kotlin.Array)` (also the signature for " +
"vararg parameters). To forbid methods from the companion object reference the Companion class, for " +
"example as `TestClass.Companion.hello()` (even if it is marked `@JvmStatic`)."
)
private val methods: List<Forbidden> by config(
valuesWithReason(
Expand Down
Expand Up @@ -283,6 +283,100 @@ class ForbiddenMethodCallSpec(val env: KotlinCoreEnvironment) {
assertThat(findings).hasStartSourceLocation(6, 13)
}

@Test
fun `should report method with array argument`() {
val code = """
package io.gitlab.arturbosch.detekt.rules.style
fun arrayMethod(args: Array<Any>) = args.size
fun test() {
val s = arrayMethod(arrayOf("test"))
}
""".trimIndent()
val methodName = "io.gitlab.arturbosch.detekt.rules.style.arrayMethod(kotlin.Array)"
val findings = ForbiddenMethodCall(TestConfig(mapOf(METHODS to listOf(methodName))))
.compileAndLintWithContext(env, code)
assertThat(findings).hasSize(1).hasStartSourceLocation(6, 13)
}

@Test
fun `should report method with list argument`() {
val code = """
package io.gitlab.arturbosch.detekt.rules.style
fun listMethod(args: List<Any>) = args.size
fun test() {
val s = listMethod(listOf("test"))
}
""".trimIndent()
val methodName = "io.gitlab.arturbosch.detekt.rules.style.listMethod(kotlin.collections.List)"
val findings = ForbiddenMethodCall(TestConfig(mapOf(METHODS to listOf(methodName))))
.compileAndLintWithContext(env, code)
assertThat(findings).hasSize(1).hasStartSourceLocation(6, 13)
}

@Test
fun `should report method with vararg argument`() {
val code = """
package io.gitlab.arturbosch.detekt.rules.style
fun varargMethod(vararg args: Any) = args.size
fun test() {
val s = varargMethod(arrayOf("test"))
}
""".trimIndent()
val methodName = "io.gitlab.arturbosch.detekt.rules.style.varargMethod(kotlin.Array)"
val findings = ForbiddenMethodCall(TestConfig(mapOf(METHODS to listOf(methodName))))
.compileAndLintWithContext(env, code)
assertThat(findings).hasSize(1).hasStartSourceLocation(6, 13)
}

@Test
fun `should report companion object method`() {
val code = """
package io.gitlab.arturbosch.detekt.rules.style
class TestClass {
companion object {
fun staticMethod() {}
}
}
fun test() {
TestClass.staticMethod()
}
""".trimIndent()
val methodName = "io.gitlab.arturbosch.detekt.rules.style.TestClass.Companion.staticMethod()"
val findings = ForbiddenMethodCall(TestConfig(mapOf(METHODS to listOf(methodName))))
.compileAndLintWithContext(env, code)
assertThat(findings).hasSize(1).hasStartSourceLocation(10, 15)
}

@Test
fun `should report @JvmStatic method`() {
val code = """
package io.gitlab.arturbosch.detekt.rules.style
class TestClass {
companion object {
@JvmStatic
fun staticMethod() {}
}
}
fun test() {
TestClass.staticMethod()
}
""".trimIndent()
val methodName = "io.gitlab.arturbosch.detekt.rules.style.TestClass.Companion.staticMethod()"
val findings = ForbiddenMethodCall(TestConfig(mapOf(METHODS to listOf(methodName))))
.compileAndLintWithContext(env, code)
assertThat(findings).hasSize(1).hasStartSourceLocation(11, 15)
}

@Test
fun `should report overriding method calls`() {
val code = """
Expand Down

0 comments on commit 621bcc9

Please sign in to comment.