Skip to content

Commit

Permalink
Flag DefineComponent should be interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
WhosNickDoglio committed Oct 19, 2024
1 parent 7ffe8ee commit 4f977ac
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 89 deletions.
4 changes: 3 additions & 1 deletion docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,9 @@ You can, however, use Anvil in Kotlin files in modules with a mixed Java/Kotlin

## Hilt Rules

### The `@EntryPoint` annotation can only be applied to interfaces
### The `@EntryPoint` & `@DefineComponent` annotations can only be applied to interfaces

// TODO rewrite this

The [`@EntryPoint` annotation](https://dagger.dev/api/latest/dagger/hilt/EntryPoint.html) can be used
to define an interface that exposes a dependency on the DI graph to make it easier to consume in places where you
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package dev.whosnickdoglio.lint.annotations.hilt

public const val INSTALL_IN: String = "dagger.hilt.InstallIn"
public const val ENTRY_POINT: String = "dagger.hilt.EntryPoint"
public const val DEFINE_COMPONENT: String = "dagger.hilt.DefineComponent"
public const val ANDROID_ENTRY_POINT: String = "dagger.hilt.android.AndroidEntryPoint"
public const val HILT_ANDROID_APP: String = "dagger.hilt.android.HiltAndroidApp"
public const val HILT_VIEW_MODEL: String = "dagger.hilt.android.lifecycle.HiltViewModel"
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ val hiltAnnotations =
annotation class InstallIn
annotation class EntryPoint
annotation class DefineComponent
"""
.trimIndent()
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import com.android.tools.lint.client.api.Vendor
import com.android.tools.lint.detector.api.CURRENT_API
import com.android.tools.lint.detector.api.Issue
import com.google.auto.service.AutoService
import dev.whosnickdoglio.hilt.detectors.EntryPointMustBeAnInterfaceDetector
import dev.whosnickdoglio.hilt.detectors.HiltAnnotationMustBeInterface
import dev.whosnickdoglio.hilt.detectors.MissingAndroidEntryPointDetector
import dev.whosnickdoglio.hilt.detectors.MissingHiltAndroidAppAnnotationDetector
import dev.whosnickdoglio.hilt.detectors.MissingHiltViewModelAnnotationDetector
Expand All @@ -19,7 +19,7 @@ import dev.whosnickdoglio.hilt.detectors.MissingInstallInDetector
public class HiltRulesIssueRegistry : IssueRegistry() {
override val issues: List<Issue> =
listOf(
EntryPointMustBeAnInterfaceDetector.ISSUE,
HiltAnnotationMustBeInterface.ISSUE,

Check warning on line 22 in lint/hilt/src/main/java/dev/whosnickdoglio/hilt/HiltRulesIssueRegistry.kt

View check run for this annotation

Codecov / codecov/patch

lint/hilt/src/main/java/dev/whosnickdoglio/hilt/HiltRulesIssueRegistry.kt#L22

Added line #L22 was not covered by tests
MissingHiltAndroidAppAnnotationDetector.ISSUE,
MissingAndroidEntryPointDetector.ISSUE,
MissingHiltViewModelAnnotationDetector.ISSUE_MISSING_ANNOTATION,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ import com.android.tools.lint.detector.api.Scope
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 dev.whosnickdoglio.lint.annotations.hilt.DEFINE_COMPONENT
import dev.whosnickdoglio.lint.annotations.hilt.ENTRY_POINT
import org.jetbrains.uast.UAnnotation
import org.jetbrains.uast.UClass
import org.jetbrains.uast.UElement

internal class EntryPointMustBeAnInterfaceDetector : Detector(), SourceCodeScanner {
internal class HiltAnnotationMustBeInterface : Detector(), SourceCodeScanner {
private val oldClassPattern =
("(object|abstract\\s+class|enum\\s+class|annotation\\s+class|" +
"sealed\\s+class|data\\s+class|enum|class)")
Expand All @@ -33,7 +34,7 @@ internal class EntryPointMustBeAnInterfaceDetector : Detector(), SourceCodeScann
override fun createUastHandler(context: JavaContext): UElementHandler =
object : UElementHandler() {
override fun visitAnnotation(node: UAnnotation) {
if (node.qualifiedName == ENTRY_POINT) {
if (node.qualifiedName in annotations) {
val entryPoint = node.uastParent as? UClass ?: return

if (!entryPoint.isInterface || entryPoint.isAnnotationType) {
Expand All @@ -56,16 +57,18 @@ internal class EntryPointMustBeAnInterfaceDetector : Detector(), SourceCodeScann
}

companion object {
internal val annotations = setOf(ENTRY_POINT, DEFINE_COMPONENT)

private val implementation =
Implementation(EntryPointMustBeAnInterfaceDetector::class.java, Scope.JAVA_FILE_SCOPE)
Implementation(HiltAnnotationMustBeInterface::class.java, Scope.JAVA_FILE_SCOPE)

internal val ISSUE =
Issue.create(
id = "EntryPointMustBeAnInterface",
briefDescription = "Hilt entry points must be interfaces",
id = "HiltMustBeAnInterface",
briefDescription = "Must be interfaces",
explanation =
"""
The `@EntryPoint` annotation can only be applied to `interfaces`, trying to apply it to anything else will cause an error at compile time.
The `@EntryPoint` and `DefineComponent` annotations can only be applied to `interfaces`, trying to apply it to anything else will cause an error at compile time.
See https://whosnickdoglio.dev/dagger-rules/rules/#the-entrypoint-annotation-can-only-be-applied-to-interfaces for more information.
""",
Expand Down
Loading

0 comments on commit 4f977ac

Please sign in to comment.