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.checks.infrastructure.TestMode 20 import com.android.tools.lint.detector.api.Detector 21 import com.android.tools.lint.detector.api.Issue 22 import org.junit.Test 23 import org.junit.runner.RunWith 24 import org.junit.runners.JUnit4 25 26 @Suppress("UnstableApiUsage") 27 @RunWith(JUnit4::class) 28 class DaggerKotlinIssueDetectorTest : LintDetectorTest() { 29 30 private companion object { 31 private val javaxInjectStubs = kotlin( 32 """ 33 package javax.inject 34 35 annotation class Inject 36 annotation class Qualifier 37 """ 38 ).indented() 39 40 private val daggerStubs = kotlin( 41 """ 42 package dagger 43 44 annotation class Provides 45 annotation class Module 46 """ 47 ).indented() 48 49 // For some reason in Bazel the stdlib dependency on the classpath isn't visible to the 50 // LintTestTask, so we just include it ourselves here for now. 51 private val jvmStaticStubs = kotlin( 52 """ 53 package kotlin.jvm 54 55 annotation class JvmStatic 56 """ 57 ).indented() 58 } 59 getDetectornull60 override fun getDetector(): Detector = DaggerKotlinIssueDetector() 61 62 override fun getIssues(): List<Issue> = DaggerKotlinIssueDetector.issues 63 64 @Test 65 fun simpleSmokeTestForQualifiersAndProviders() { 66 lint() 67 .allowMissingSdk() 68 .files( 69 javaxInjectStubs, 70 daggerStubs, 71 jvmStaticStubs, 72 kotlin( 73 """ 74 package foo 75 import javax.inject.Inject 76 import javax.inject.Qualifier 77 import kotlin.jvm.JvmStatic 78 import dagger.Provides 79 import dagger.Module 80 81 @Qualifier 82 annotation class MyQualifier 83 84 class InjectedTest { 85 // This should fail because of `:field` 86 @Inject 87 @field:MyQualifier 88 lateinit var prop: String 89 90 // This is fine! 91 @Inject 92 @MyQualifier 93 lateinit var prop2: String 94 } 95 96 @Module 97 object ObjectModule { 98 // This should fail because it uses `@JvmStatic` 99 @JvmStatic 100 @Provides 101 fun provideFoo(): String { 102 103 } 104 105 // This is fine! 106 @Provides 107 fun provideBar(): String { 108 109 } 110 } 111 112 @Module 113 class ClassModule { 114 companion object { 115 // This should fail because the companion object is part of ClassModule, so this is unnecessary. 116 @JvmStatic 117 @Provides 118 fun provideBaz(): String { 119 120 } 121 } 122 } 123 124 @Module 125 class ClassModuleQualified { 126 companion object { 127 // This should fail because the companion object is part of ClassModule, so this is unnecessary. 128 // This specifically tests a fully qualified annotation 129 @kotlin.jvm.JvmStatic 130 @Provides 131 fun provideBaz(): String { 132 133 } 134 } 135 } 136 137 @Module 138 class ClassModule2 { 139 // This should fail because the companion object is part of ClassModule 140 @Module 141 companion object { 142 @Provides 143 fun provideBaz(): String { 144 145 } 146 } 147 } 148 149 @Module 150 class ClassModule2Qualified { 151 // This should fail because the companion object is part of ClassModule 152 // This specifically tests a fully qualified annotation 153 @dagger.Module 154 companion object { 155 @Provides 156 fun provideBaz(): String { 157 158 } 159 } 160 } 161 162 // This is correct as of Dagger 2.26! 163 @Module 164 class ClassModule3 { 165 companion object { 166 @Provides 167 fun provideBaz(): String { 168 169 } 170 } 171 } 172 173 class ClassModule4 { 174 // This is should fail because this should be extracted to a standalone object. 175 @Module 176 companion object { 177 @Provides 178 fun provideBaz(): String { 179 180 } 181 } 182 } 183 """ 184 ).indented() 185 ) 186 .allowCompilationErrors(false) 187 // Unlikely that @JvmStatic would be aliased, so skipping these modes. 188 .skipTestModes(TestMode.TYPE_ALIAS, TestMode.IMPORT_ALIAS) 189 .run() 190 .expect( 191 """ 192 src/foo/MyQualifier.kt:14: Warning: Redundant 'field:' used for Dagger qualifier annotation. [FieldSiteTargetOnQualifierAnnotation] 193 @field:MyQualifier 194 ~~~~~~~~~~~~~~~~~~ 195 src/foo/MyQualifier.kt:26: Warning: @JvmStatic used for @Provides function in an object class [JvmStaticProvidesInObjectDetector] 196 @JvmStatic 197 ~~~~~~~~~~ 198 src/foo/MyQualifier.kt:43: Warning: @JvmStatic used for @Provides function in an object class [JvmStaticProvidesInObjectDetector] 199 @JvmStatic 200 ~~~~~~~~~~ 201 src/foo/MyQualifier.kt:56: Warning: @JvmStatic used for @Provides function in an object class [JvmStaticProvidesInObjectDetector] 202 @kotlin.jvm.JvmStatic 203 ~~~~~~~~~~~~~~~~~~~~~ 204 src/foo/MyQualifier.kt:66: 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:78: Warning: Module companion objects should not be annotated with @Module. [ModuleCompanionObjects] 208 // This should fail because the companion object is part of ClassModule 209 ^ 210 src/foo/MyQualifier.kt:101: Warning: Module companion objects should not be annotated with @Module. [ModuleCompanionObjects] 211 // This is should fail because this should be extracted to a standalone object. 212 ^ 213 0 errors, 7 warnings 214 """.trimIndent() 215 ) 216 .expectFixDiffs( 217 """ 218 Fix for src/foo/MyQualifier.kt line 14: Remove 'field:': 219 @@ -14 +14 220 - @field:MyQualifier 221 + @MyQualifier 222 Fix for src/foo/MyQualifier.kt line 26: Remove @JvmStatic: 223 @@ -26 +26 224 - @JvmStatic 225 + 226 Fix for src/foo/MyQualifier.kt line 43: Remove @JvmStatic: 227 @@ -43 +43 228 - @JvmStatic 229 + 230 Fix for src/foo/MyQualifier.kt line 56: Remove @JvmStatic: 231 @@ -56 +56 232 - @kotlin.jvm.JvmStatic 233 + 234 Fix for src/foo/MyQualifier.kt line 66: Remove @Module: 235 @@ -67 +67 236 - @Module 237 + 238 Fix for src/foo/MyQualifier.kt line 78: Remove @Module: 239 @@ -80 +80 240 - @dagger.Module 241 + 242 Fix for src/foo/MyQualifier.kt line 101: Remove @Module: 243 @@ -102 +102 244 - @Module 245 + 246 """.trimIndent() 247 ) 248 } 249 } 250