slack.lint.InjectInJavaDetector.kt Maven / Gradle / Ivy
The newest version!
// Copyright (C) 2021 Slack Technologies, LLC
// SPDX-License-Identifier: Apache-2.0
package slack.lint
import com.android.tools.lint.client.api.UElementHandler
import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.Detector
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.TextFormat
import org.jetbrains.uast.UAnnotated
import org.jetbrains.uast.UAnnotation
import org.jetbrains.uast.UClass
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UField
import org.jetbrains.uast.UMethod
import org.jetbrains.uast.java.isJava
import slack.lint.util.sourceImplementation
/**
* A simple detector that ensures that `@Inject`, `@Module`, and `@AssistedInject` are not used in
* Java files in order to properly support Anvil factory generation.
*/
class InjectInJavaDetector : Detector(), SourceCodeScanner {
override fun getApplicableUastTypes(): List> {
return listOf(UClass::class.java, UField::class.java, UMethod::class.java)
}
override fun createUastHandler(context: JavaContext): UElementHandler? {
// Only applicable to Java files
if (!isJava(context.uastFile?.lang)) return null
return object : UElementHandler() {
private fun checkNode(node: UAnnotated) {
node.findInjectionAnnotation()?.let { annotation ->
context.report(
ISSUE,
context.getNameLocation(annotation),
ISSUE.getBriefDescription(TextFormat.TEXT),
quickfixData = null,
)
}
}
override fun visitClass(node: UClass) = checkNode(node)
override fun visitMethod(node: UMethod) = checkNode(node)
override fun visitField(node: UField) = checkNode(node)
}
}
companion object {
private const val FQCN_INJECT = "javax.inject.Inject"
private const val FQCN_MODULE = "dagger.Module"
private const val FQCN_ASSISTED_INJECT = "dagger.assisted.AssistedInject"
private const val FQCN_ASSISTED_FACTORY = "dagger.assisted.AssistedFactory"
val ISSUE: Issue =
Issue.create(
"InjectInJava",
"Only Kotlin classes should be injected in order for Anvil to work.",
"""
Only Kotlin classes should be injected in order for Anvil to work. If you \
cannot easily convert this to Kotlin, consider manually providing it via a Kotlin \
`@Module`-annotated object.
""",
Category.CORRECTNESS,
9,
Severity.ERROR,
sourceImplementation(),
)
private val ANNOTATIONS =
setOf(FQCN_INJECT, FQCN_ASSISTED_INJECT, FQCN_MODULE, FQCN_ASSISTED_FACTORY)
private fun UAnnotated.findInjectionAnnotation(): UAnnotation? {
for (annotation in ANNOTATIONS) {
return findAnnotation(annotation) ?: continue
}
return null
}
}
}