1 /* 2 * Copyright (C) 2020 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package dagger.lint 17 18 import com.android.tools.lint.checks.infrastructure.LintDetectorTest 19 import com.android.tools.lint.detector.api.Detector 20 import com.android.tools.lint.detector.api.Issue 21 import org.junit.Test 22 import org.junit.runner.RunWith 23 import org.junit.runners.JUnit4 24 25 @Suppress("UnstableApiUsage") 26 @RunWith(JUnit4::class) 27 class DaggerKotlinIssueDetectorTest : LintDetectorTest() { 28 29 private companion object { 30 private val javaxInjectStubs = kotlin( 31 """ 32 package javax.inject 33 34 annotation class Inject 35 annotation class Qualifier 36 """ 37 ).indented() 38 39 private val daggerStubs = kotlin( 40 """ 41 package dagger 42 43 annotation class Provides 44 annotation class Module 45 """ 46 ).indented() 47 48 // For some reason in Bazel the stdlib dependency on the classpath isn't visible to the 49 // LintTestTask, so we just include it ourselves here for now. 50 private val jvmStaticStubs = kotlin( 51 """ 52 package kotlin.jvm 53 54 annotation class JvmStatic 55 """ 56 ).indented() 57 } 58 getDetectornull59 override fun getDetector(): Detector = DaggerKotlinIssueDetector() 60 61 override fun getIssues(): List<Issue> = DaggerKotlinIssueDetector.issues 62 63 @Test 64 fun simpleSmokeTestForQualifiersAndProviders() { 65 lint() 66 .allowMissingSdk() 67 .files( 68 javaxInjectStubs, 69 daggerStubs, 70 jvmStaticStubs, 71 kotlin( 72 """ 73 package foo 74 import javax.inject.Inject 75 import javax.inject.Qualifier 76 import kotlin.jvm.JvmStatic 77 import dagger.Provides 78 import dagger.Module 79 80 @Qualifier 81 annotation class MyQualifier 82 83 class InjectedTest { 84 // This should fail because of `:field` 85 @Inject 86 @field:MyQualifier 87 lateinit var prop: String 88 89 // This is fine! 90 @Inject 91 @MyQualifier 92 lateinit var prop2: String 93 } 94 95 @Module 96 object ObjectModule { 97 // This should fail because it uses `@JvmStatic` 98 @JvmStatic 99 @Provides 100 fun provideFoo(): String { 101 102 } 103 104 // This is fine! 105 @Provides 106 fun provideBar(): String { 107 108 } 109 } 110 111 @Module 112 class ClassModule { 113 companion object { 114 // This should fail because the companion object is part of ClassModule, so this is unnecessary. 115 @JvmStatic 116 @Provides 117 fun provideBaz(): String { 118 119 } 120 } 121 } 122 123 @Module 124 class ClassModuleQualified { 125 companion object { 126 // This should fail because the companion object is part of ClassModule, so this is unnecessary. 127 // This specifically tests a fully qualified annotation 128 @kotlin.jvm.JvmStatic 129 @Provides 130 fun provideBaz(): String { 131 132 } 133 } 134 } 135 136 @Module 137 class ClassModule2 { 138 // This should fail because the companion object is part of ClassModule 139 @Module 140 companion object { 141 @Provides 142 fun provideBaz(): String { 143 144 } 145 } 146 } 147 148 @Module 149 class ClassModule2Qualified { 150 // This should fail because the companion object is part of ClassModule 151 // This specifically tests a fully qualified annotation 152 @dagger.Module 153 companion object { 154 @Provides 155 fun provideBaz(): String { 156 157 } 158 } 159 } 160 161 // This is correct as of Dagger 2.26! 162 @Module 163 class ClassModule3 { 164 companion object { 165 @Provides 166 fun provideBaz(): String { 167 168 } 169 } 170 } 171 172 class ClassModule4 { 173 // This is should fail because this should be extracted to a standalone object. 174 @Module 175 companion object { 176 @Provides 177 fun provideBaz(): String { 178 179 } 180 } 181 } 182 """ 183 ).indented() 184 ) 185 .allowCompilationErrors(false) 186 .run() 187 .expect( 188 """ 189 src/foo/MyQualifier.kt:14: Warning: Redundant 'field:' used for Dagger qualifier annotation. [FieldSiteTargetOnQualifierAnnotation] 190 @field:MyQualifier 191 ~~~~~~~~~~~~~~~~~~ 192 src/foo/MyQualifier.kt:26: Warning: @JvmStatic used for @Provides function in an object class [JvmStaticProvidesInObjectDetector] 193 @JvmStatic 194 ~~~~~~~~~~ 195 src/foo/MyQualifier.kt:43: Warning: @JvmStatic used for @Provides function in an object class [JvmStaticProvidesInObjectDetector] 196 @JvmStatic 197 ~~~~~~~~~~ 198 src/foo/MyQualifier.kt:56: Warning: @JvmStatic used for @Provides function in an object class [JvmStaticProvidesInObjectDetector] 199 @kotlin.jvm.JvmStatic 200 ~~~~~~~~~~~~~~~~~~~~~ 201 src/foo/MyQualifier.kt:66: Warning: Module companion objects should not be annotated with @Module. [ModuleCompanionObjects] 202 // This should fail because the companion object is part of ClassModule 203 ^ 204 src/foo/MyQualifier.kt:78: Warning: Module companion objects should not be annotated with @Module. [ModuleCompanionObjects] 205 // This should fail because the companion object is part of ClassModule 206 ^ 207 src/foo/MyQualifier.kt:101: Warning: Module companion objects should not be annotated with @Module. [ModuleCompanionObjects] 208 // This is should fail because this should be extracted to a standalone object. 209 ^ 210 0 errors, 7 warnings 211 """.trimIndent() 212 ) 213 .expectFixDiffs( 214 """ 215 Fix for src/foo/MyQualifier.kt line 14: Remove 'field:': 216 @@ -14 +14 217 - @field:MyQualifier 218 + @MyQualifier 219 Fix for src/foo/MyQualifier.kt line 26: Remove @JvmStatic: 220 @@ -26 +26 221 - @JvmStatic 222 + 223 Fix for src/foo/MyQualifier.kt line 43: Remove @JvmStatic: 224 @@ -43 +43 225 - @JvmStatic 226 + 227 Fix for src/foo/MyQualifier.kt line 56: Remove @JvmStatic: 228 @@ -56 +56 229 - @kotlin.jvm.JvmStatic 230 + 231 Fix for src/foo/MyQualifier.kt line 66: Remove @Module: 232 @@ -67 +67 233 - @Module 234 + 235 Fix for src/foo/MyQualifier.kt line 78: Remove @Module: 236 @@ -80 +80 237 - @dagger.Module 238 + 239 Fix for src/foo/MyQualifier.kt line 101: Remove @Module: 240 @@ -102 +102 241 - @Module 242 + 243 """.trimIndent() 244 ) 245 } 246 } 247