From 24a815e00f21b257d247afdc741d541dfca4f5dd Mon Sep 17 00:00:00 2001 From: nicholasdoglio Date: Fri, 10 Feb 2023 17:12:05 -0500 Subject: [PATCH] Update ViewModelInjectionDetector to support a lint option --- .../compose/ViewModelInjectionDetector.kt | 21 +++++++++++++++++-- .../compose/ViewModelInjectionDetectorTest.kt | 11 ++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/compose-lint-checks/src/main/java/slack/lint/compose/ViewModelInjectionDetector.kt b/compose-lint-checks/src/main/java/slack/lint/compose/ViewModelInjectionDetector.kt index 0c8eb6dd..01b370ee 100644 --- a/compose-lint-checks/src/main/java/slack/lint/compose/ViewModelInjectionDetector.kt +++ b/compose-lint-checks/src/main/java/slack/lint/compose/ViewModelInjectionDetector.kt @@ -8,15 +8,28 @@ import com.android.tools.lint.detector.api.Issue import com.android.tools.lint.detector.api.JavaContext import com.android.tools.lint.detector.api.Severity import com.android.tools.lint.detector.api.SourceCodeScanner +import com.android.tools.lint.detector.api.StringOption import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtProperty import slack.lint.compose.util.* import slack.lint.compose.util.sourceImplementation -class ViewModelInjectionDetector : ComposableFunctionDetector(), SourceCodeScanner { +class ViewModelInjectionDetector +@JvmOverloads +constructor(private val allowedNames: StringSetLintOption = StringSetLintOption(ALLOW_LIST)) : + ComposableFunctionDetector(allowedNames), SourceCodeScanner { companion object { + + internal val ALLOW_LIST = + StringOption( + "allowed-viewmodel-injection", + "A comma-separated list of viewModel factories.", + null, + "This property should define comma-separated list of allowed viewModel factory names." + ) + private fun errorMessage(factoryName: String): String = """ Implicit dependencies of composables should be made explicit. @@ -35,6 +48,7 @@ class ViewModelInjectionDetector : ComposableFunctionDetector(), SourceCodeScann severity = Severity.ERROR, implementation = sourceImplementation() ) + .setOptions(listOf(ALLOW_LIST)) private val KnownViewModelFactories by lazy { setOf( @@ -57,7 +71,10 @@ class ViewModelInjectionDetector : ComposableFunctionDetector(), SourceCodeScann .flatMap { property -> property .findDirectChildrenByClass() - .filter { KnownViewModelFactories.contains(it.calleeExpression?.text) } + .filter { + KnownViewModelFactories.contains(it.calleeExpression?.text) || + allowedNames.value.contains(it.calleeExpression?.text) + } .map { property to it.calleeExpression!!.text } } .forEach { (property, viewModelFactoryName) -> diff --git a/compose-lint-checks/src/test/java/slack/lint/compose/ViewModelInjectionDetectorTest.kt b/compose-lint-checks/src/test/java/slack/lint/compose/ViewModelInjectionDetectorTest.kt index 2dae692f..80e9fe9d 100644 --- a/compose-lint-checks/src/test/java/slack/lint/compose/ViewModelInjectionDetectorTest.kt +++ b/compose-lint-checks/src/test/java/slack/lint/compose/ViewModelInjectionDetectorTest.kt @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 package slack.lint.compose +import com.android.tools.lint.checks.infrastructure.TestLintTask import com.android.tools.lint.checks.infrastructure.TestMode import com.android.tools.lint.detector.api.Detector import com.android.tools.lint.detector.api.Issue @@ -23,7 +24,8 @@ class ViewModelInjectionDetectorTest(private val viewModel: String) : BaseSlackL arrayOf("weaverViewModel"), arrayOf("hiltViewModel"), arrayOf("injectedViewModel"), - arrayOf("mavericksViewModel") + arrayOf("mavericksViewModel"), + arrayOf("tangleViewModel"), ) } } @@ -34,7 +36,12 @@ class ViewModelInjectionDetectorTest(private val viewModel: String) : BaseSlackL // This mode is irrelevant to our test and totally untestable with stringy outputs override val skipTestModes: Array = arrayOf(TestMode.SUPPRESSIBLE, TestMode.TYPE_ALIAS) - @Test + override fun lint(): TestLintTask { + return super.lint() + .configureOption(ViewModelInjectionDetector.ALLOW_LIST, "tangleViewModel") + } + + @Test fun `passes when a weaverViewModel is used as a default param`() { @Language("kotlin") val code =