diff --git a/docs/rules.md b/docs/rules.md index eadc7bdf..e9ed799f 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -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 diff --git a/lint/annotation-constants/src/main/java/dev/whosnickdoglio/lint/annotations/hilt/HiltAnnotations.kt b/lint/annotation-constants/src/main/java/dev/whosnickdoglio/lint/annotations/hilt/HiltAnnotations.kt index 719a6f57..16a6e94f 100644 --- a/lint/annotation-constants/src/main/java/dev/whosnickdoglio/lint/annotations/hilt/HiltAnnotations.kt +++ b/lint/annotation-constants/src/main/java/dev/whosnickdoglio/lint/annotations/hilt/HiltAnnotations.kt @@ -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" diff --git a/lint/annotation-constants/src/testFixtures/java/dev/whosnickdoglio/stubs/Hilt.kt b/lint/annotation-constants/src/testFixtures/java/dev/whosnickdoglio/stubs/Hilt.kt index 56aee334..6d6403ec 100644 --- a/lint/annotation-constants/src/testFixtures/java/dev/whosnickdoglio/stubs/Hilt.kt +++ b/lint/annotation-constants/src/testFixtures/java/dev/whosnickdoglio/stubs/Hilt.kt @@ -31,6 +31,7 @@ val hiltAnnotations = annotation class InstallIn annotation class EntryPoint + annotation class DefineComponent """ .trimIndent() ), diff --git a/lint/hilt/src/main/java/dev/whosnickdoglio/hilt/HiltRulesIssueRegistry.kt b/lint/hilt/src/main/java/dev/whosnickdoglio/hilt/HiltRulesIssueRegistry.kt index 3773f002..b3ed0e19 100644 --- a/lint/hilt/src/main/java/dev/whosnickdoglio/hilt/HiltRulesIssueRegistry.kt +++ b/lint/hilt/src/main/java/dev/whosnickdoglio/hilt/HiltRulesIssueRegistry.kt @@ -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 @@ -19,7 +19,7 @@ import dev.whosnickdoglio.hilt.detectors.MissingInstallInDetector public class HiltRulesIssueRegistry : IssueRegistry() { override val issues: List = listOf( - EntryPointMustBeAnInterfaceDetector.ISSUE, + HiltAnnotationMustBeInterface.ISSUE, MissingHiltAndroidAppAnnotationDetector.ISSUE, MissingAndroidEntryPointDetector.ISSUE, MissingHiltViewModelAnnotationDetector.ISSUE_MISSING_ANNOTATION, diff --git a/lint/hilt/src/main/java/dev/whosnickdoglio/hilt/detectors/EntryPointMustBeAnInterfaceDetector.kt b/lint/hilt/src/main/java/dev/whosnickdoglio/hilt/detectors/HiltAnnotationMustBeInterface.kt similarity index 81% rename from lint/hilt/src/main/java/dev/whosnickdoglio/hilt/detectors/EntryPointMustBeAnInterfaceDetector.kt rename to lint/hilt/src/main/java/dev/whosnickdoglio/hilt/detectors/HiltAnnotationMustBeInterface.kt index cb825a39..c0a63187 100644 --- a/lint/hilt/src/main/java/dev/whosnickdoglio/hilt/detectors/EntryPointMustBeAnInterfaceDetector.kt +++ b/lint/hilt/src/main/java/dev/whosnickdoglio/hilt/detectors/HiltAnnotationMustBeInterface.kt @@ -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)") @@ -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) { @@ -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. """, diff --git a/lint/hilt/src/test/java/dev/whosnickdoglio/hilt/detectors/EntryPointMustBeAnInterfaceDetectorTest.kt b/lint/hilt/src/test/java/dev/whosnickdoglio/hilt/detectors/HiltAnnotationMustBeInterfaceTest.kt similarity index 65% rename from lint/hilt/src/test/java/dev/whosnickdoglio/hilt/detectors/EntryPointMustBeAnInterfaceDetectorTest.kt rename to lint/hilt/src/test/java/dev/whosnickdoglio/hilt/detectors/HiltAnnotationMustBeInterfaceTest.kt index 7c031d53..3d0184e8 100644 --- a/lint/hilt/src/test/java/dev/whosnickdoglio/hilt/detectors/EntryPointMustBeAnInterfaceDetectorTest.kt +++ b/lint/hilt/src/test/java/dev/whosnickdoglio/hilt/detectors/HiltAnnotationMustBeInterfaceTest.kt @@ -6,76 +6,89 @@ package dev.whosnickdoglio.hilt.detectors import com.android.tools.lint.checks.infrastructure.TestFiles import com.android.tools.lint.checks.infrastructure.TestLintTask -import dev.whosnickdoglio.lint.annotations.hilt.ENTRY_POINT +import com.google.testing.junit.testparameterinjector.TestParameter +import com.google.testing.junit.testparameterinjector.TestParameterInjector +import com.google.testing.junit.testparameterinjector.TestParameterValuesProvider import dev.whosnickdoglio.stubs.hiltAnnotations import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(TestParameterInjector::class) +class HiltAnnotationMustBeInterfaceTest { + + private class MustBeInterfaceTestParameterValuesProvider : TestParameterValuesProvider() { + override fun provideValues(context: Context?): List<*> = + HiltAnnotationMustBeInterface.annotations.toList() + } + + @TestParameter(valuesProvider = MustBeInterfaceTestParameterValuesProvider::class) + lateinit var annotation: String -class EntryPointMustBeAnInterfaceDetectorTest { @Test - fun `kotlin @EntryPoint usage on an interface does not show an error`() { + fun `kotlin hilt annotation usage on an interface does not show an error`() { TestLintTask.lint() .files( *hiltAnnotations, TestFiles.kotlin( """ - import $ENTRY_POINT + import $annotation - @EntryPoint + @${annotation.substringAfterLast(".")} interface MyEntryPoint """ .trimIndent() ), ) - .issues(EntryPointMustBeAnInterfaceDetector.ISSUE) + .issues(HiltAnnotationMustBeInterface.ISSUE) .run() .expectClean() .expectErrorCount(0) } @Test - fun `java @EntryPoint usage on an interface does not show an error`() { + fun `java hilt annotation usage on an interface does not show an error`() { TestLintTask.lint() .files( *hiltAnnotations, TestFiles.java( """ - import $ENTRY_POINT; + import $annotation; - @EntryPoint + @${annotation.substringAfterLast(".")} interface MyEntryPoint {} """ .trimIndent() ), ) - .issues(EntryPointMustBeAnInterfaceDetector.ISSUE) + .issues(HiltAnnotationMustBeInterface.ISSUE) .run() .expectClean() .expectErrorCount(0) } @Test - fun `kotlin @EntryPoint usage on an abstract class shows an error`() { + fun `kotlin hilt annotation usage on an abstract class shows an error`() { TestLintTask.lint() .files( *hiltAnnotations, TestFiles.kotlin( """ - import $ENTRY_POINT + import $annotation - @EntryPoint + @${annotation.substringAfterLast(".")} abstract class MyEntryPoint """ .trimIndent() ), ) - .issues(EntryPointMustBeAnInterfaceDetector.ISSUE) + .issues(HiltAnnotationMustBeInterface.ISSUE) .run() .expect( """ - src/MyEntryPoint.kt:3: Error: The @EntryPoint annotation can only be applied to interfaces, trying to apply it to anything else will cause an error at compile time. + src/MyEntryPoint.kt:3: Error: 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. [EntryPointMustBeAnInterface] - @EntryPoint + See https://whosnickdoglio.dev/dagger-rules/rules/#the-entrypoint-annotation-can-only-be-applied-to-interfaces for more information. [HiltMustBeAnInterface] + @${annotation.substringAfterLast(".")} ^ 1 errors, 0 warnings """ @@ -95,28 +108,28 @@ class EntryPointMustBeAnInterfaceDetectorTest { } @Test - fun `java @EntryPoint usage on an abstract class shows an error`() { + fun `java hilt annotation usage on an abstract class shows an error`() { TestLintTask.lint() .files( *hiltAnnotations, TestFiles.java( """ - import $ENTRY_POINT; + import $annotation; - @EntryPoint + @${annotation.substringAfterLast(".")} abstract class MyEntryPoint {} """ .trimIndent() ), ) - .issues(EntryPointMustBeAnInterfaceDetector.ISSUE) + .issues(HiltAnnotationMustBeInterface.ISSUE) .run() .expect( """ - src/MyEntryPoint.java:3: Error: The @EntryPoint annotation can only be applied to interfaces, trying to apply it to anything else will cause an error at compile time. + src/MyEntryPoint.java:3: Error: 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. [EntryPointMustBeAnInterface] - @EntryPoint + See https://whosnickdoglio.dev/dagger-rules/rules/#the-entrypoint-annotation-can-only-be-applied-to-interfaces for more information. [HiltMustBeAnInterface] + @${annotation.substringAfterLast(".")} ^ 1 errors, 0 warnings """ @@ -136,28 +149,28 @@ class EntryPointMustBeAnInterfaceDetectorTest { } @Test - fun `kotlin @EntryPoint usage on an concrete class shows an error`() { + fun `kotlin hilt annotation usage on an concrete class shows an error`() { TestLintTask.lint() .files( *hiltAnnotations, TestFiles.kotlin( """ - import $ENTRY_POINT + import $annotation - @EntryPoint + @${annotation.substringAfterLast(".")} class MyEntryPoint """ .trimIndent() ), ) - .issues(EntryPointMustBeAnInterfaceDetector.ISSUE) + .issues(HiltAnnotationMustBeInterface.ISSUE) .run() .expect( """ - src/MyEntryPoint.kt:3: Error: The @EntryPoint annotation can only be applied to interfaces, trying to apply it to anything else will cause an error at compile time. + src/MyEntryPoint.kt:3: Error: 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. [EntryPointMustBeAnInterface] - @EntryPoint + See https://whosnickdoglio.dev/dagger-rules/rules/#the-entrypoint-annotation-can-only-be-applied-to-interfaces for more information. [HiltMustBeAnInterface] + @${annotation.substringAfterLast(".")} ^ 1 errors, 0 warnings """ @@ -177,28 +190,28 @@ class EntryPointMustBeAnInterfaceDetectorTest { } @Test - fun `java @EntryPoint usage on an concrete class shows an error`() { + fun `java hilt annotation usage on an concrete class shows an error`() { TestLintTask.lint() .files( *hiltAnnotations, TestFiles.java( """ - import $ENTRY_POINT; + import $annotation; - @EntryPoint + @${annotation.substringAfterLast(".")} class MyEntryPoint {} """ .trimIndent() ), ) - .issues(EntryPointMustBeAnInterfaceDetector.ISSUE) + .issues(HiltAnnotationMustBeInterface.ISSUE) .run() .expect( """ - src/MyEntryPoint.java:3: Error: The @EntryPoint annotation can only be applied to interfaces, trying to apply it to anything else will cause an error at compile time. + src/MyEntryPoint.java:3: Error: 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. [EntryPointMustBeAnInterface] - @EntryPoint + See https://whosnickdoglio.dev/dagger-rules/rules/#the-entrypoint-annotation-can-only-be-applied-to-interfaces for more information. [HiltMustBeAnInterface] + @${annotation.substringAfterLast(".")} ^ 1 errors, 0 warnings """ @@ -218,28 +231,28 @@ class EntryPointMustBeAnInterfaceDetectorTest { } @Test - fun `@EntryPoint usage on a kotlin object shows an error`() { + fun `hilt annotation usage on a kotlin object shows an error`() { TestLintTask.lint() .files( *hiltAnnotations, TestFiles.kotlin( """ - import $ENTRY_POINT + import $annotation - @EntryPoint + @${annotation.substringAfterLast(".")} object MyEntryPoint """ .trimIndent() ), ) - .issues(EntryPointMustBeAnInterfaceDetector.ISSUE) + .issues(HiltAnnotationMustBeInterface.ISSUE) .run() .expect( """ - src/MyEntryPoint.kt:3: Error: The @EntryPoint annotation can only be applied to interfaces, trying to apply it to anything else will cause an error at compile time. + src/MyEntryPoint.kt:3: Error: 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. [EntryPointMustBeAnInterface] - @EntryPoint + See https://whosnickdoglio.dev/dagger-rules/rules/#the-entrypoint-annotation-can-only-be-applied-to-interfaces for more information. [HiltMustBeAnInterface] + @${annotation.substringAfterLast(".")} ^ 1 errors, 0 warnings """ @@ -259,28 +272,28 @@ class EntryPointMustBeAnInterfaceDetectorTest { } @Test - fun `@EntryPoint usage on kotlin enum shows an error`() { + fun `hilt annotation usage on kotlin enum shows an error`() { TestLintTask.lint() .files( *hiltAnnotations, TestFiles.kotlin( """ - import $ENTRY_POINT + import $annotation - @EntryPoint + @${annotation.substringAfterLast(".")} enum class MyEntryPoint """ .trimIndent() ), ) - .issues(EntryPointMustBeAnInterfaceDetector.ISSUE) + .issues(HiltAnnotationMustBeInterface.ISSUE) .run() .expect( """ - src/MyEntryPoint.kt:3: Error: The @EntryPoint annotation can only be applied to interfaces, trying to apply it to anything else will cause an error at compile time. + src/MyEntryPoint.kt:3: Error: 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. [EntryPointMustBeAnInterface] - @EntryPoint + See https://whosnickdoglio.dev/dagger-rules/rules/#the-entrypoint-annotation-can-only-be-applied-to-interfaces for more information. [HiltMustBeAnInterface] + @${annotation.substringAfterLast(".")} ^ 1 errors, 0 warnings """ @@ -300,28 +313,28 @@ class EntryPointMustBeAnInterfaceDetectorTest { } @Test - fun `@EntryPoint usage on a java enum class shows an error`() { + fun `hilt annotation usage on a java enum class shows an error`() { TestLintTask.lint() .files( *hiltAnnotations, TestFiles.java( """ - import $ENTRY_POINT; + import $annotation; - @EntryPoint + @${annotation.substringAfterLast(".")} enum MyEntryPoint {} """ .trimIndent() ), ) - .issues(EntryPointMustBeAnInterfaceDetector.ISSUE) + .issues(HiltAnnotationMustBeInterface.ISSUE) .run() .expect( """ - src/MyEntryPoint.java:3: Error: The @EntryPoint annotation can only be applied to interfaces, trying to apply it to anything else will cause an error at compile time. + src/MyEntryPoint.java:3: Error: 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. [EntryPointMustBeAnInterface] - @EntryPoint + See https://whosnickdoglio.dev/dagger-rules/rules/#the-entrypoint-annotation-can-only-be-applied-to-interfaces for more information. [HiltMustBeAnInterface] + @${annotation.substringAfterLast(".")} ^ 1 errors, 0 warnings """ @@ -341,28 +354,28 @@ class EntryPointMustBeAnInterfaceDetectorTest { } @Test - fun `@EntryPoint usage on kotlin data shows an error`() { + fun `hilt annotation usage on kotlin data shows an error`() { TestLintTask.lint() .files( *hiltAnnotations, TestFiles.kotlin( """ - import $ENTRY_POINT + import $annotation - @EntryPoint + @${annotation.substringAfterLast(".")} data class MyEntryPoint """ .trimIndent() ), ) - .issues(EntryPointMustBeAnInterfaceDetector.ISSUE) + .issues(HiltAnnotationMustBeInterface.ISSUE) .run() .expect( """ - src/MyEntryPoint.kt:3: Error: The @EntryPoint annotation can only be applied to interfaces, trying to apply it to anything else will cause an error at compile time. + src/MyEntryPoint.kt:3: Error: 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. [EntryPointMustBeAnInterface] - @EntryPoint + See https://whosnickdoglio.dev/dagger-rules/rules/#the-entrypoint-annotation-can-only-be-applied-to-interfaces for more information. [HiltMustBeAnInterface] + @${annotation.substringAfterLast(".")} ^ 1 errors, 0 warnings """ @@ -382,28 +395,28 @@ class EntryPointMustBeAnInterfaceDetectorTest { } @Test - fun `@EntryPoint usage on kotlin sealed shows an error`() { + fun `hilt annotation usage on kotlin sealed shows an error`() { TestLintTask.lint() .files( *hiltAnnotations, TestFiles.kotlin( """ - import $ENTRY_POINT + import $annotation - @EntryPoint + @${annotation.substringAfterLast(".")} sealed class MyEntryPoint """ .trimIndent() ), ) - .issues(EntryPointMustBeAnInterfaceDetector.ISSUE) + .issues(HiltAnnotationMustBeInterface.ISSUE) .run() .expect( """ - src/MyEntryPoint.kt:3: Error: The @EntryPoint annotation can only be applied to interfaces, trying to apply it to anything else will cause an error at compile time. + src/MyEntryPoint.kt:3: Error: 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. [EntryPointMustBeAnInterface] - @EntryPoint + See https://whosnickdoglio.dev/dagger-rules/rules/#the-entrypoint-annotation-can-only-be-applied-to-interfaces for more information. [HiltMustBeAnInterface] + @${annotation.substringAfterLast(".")} ^ 1 errors, 0 warnings """ @@ -423,28 +436,28 @@ class EntryPointMustBeAnInterfaceDetectorTest { } @Test - fun `@EntryPoint usage on kotlin annotation shows an error`() { + fun `hilt annotation usage on kotlin annotation shows an error`() { TestLintTask.lint() .files( *hiltAnnotations, TestFiles.kotlin( """ - import $ENTRY_POINT + import $annotation - @EntryPoint + @${annotation.substringAfterLast(".")} annotation class MyEntryPoint """ .trimIndent() ), ) - .issues(EntryPointMustBeAnInterfaceDetector.ISSUE) + .issues(HiltAnnotationMustBeInterface.ISSUE) .run() .expect( """ - src/MyEntryPoint.kt:3: Error: The @EntryPoint annotation can only be applied to interfaces, trying to apply it to anything else will cause an error at compile time. + src/MyEntryPoint.kt:3: Error: 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. [EntryPointMustBeAnInterface] - @EntryPoint + See https://whosnickdoglio.dev/dagger-rules/rules/#the-entrypoint-annotation-can-only-be-applied-to-interfaces for more information. [HiltMustBeAnInterface] + @${annotation.substringAfterLast(".")} ^ 1 errors, 0 warnings """