1 /* 2 * Copyright 2021 The Android Open Source Project 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 17 @file:Suppress("UnstableApiUsage") 18 19 package androidx.build.lint 20 21 import com.android.tools.lint.checks.infrastructure.LintDetectorTest 22 import com.android.tools.lint.checks.infrastructure.TestFile 23 import com.android.tools.lint.checks.infrastructure.TestFiles 24 25 class Stubs { 26 27 companion object { 28 29 /** [TestFile] containing Keep.java from the annotation library. */ 30 val Keep = 31 TestFiles.java( 32 """ 33 package androidx.annotation; 34 35 public @interface Keep { 36 } 37 """ 38 ) 39 40 val RunWith = 41 TestFiles.kotlin( 42 """ 43 package org.junit.runner 44 45 annotation class RunWith(val value: KClass<*>) 46 """ 47 ) 48 49 val JUnit4Runner = 50 TestFiles.kotlin( 51 """ 52 package org.junit.runners 53 54 class JUnit4 55 """ 56 ) 57 58 val ParameterizedRunner = 59 TestFiles.kotlin( 60 """ 61 package org.junit.runners 62 63 class Parameterized 64 """ 65 ) 66 67 val TestParameterInjector = 68 TestFiles.kotlin( 69 """ 70 package com.google.testing.junit.testparameterinjector 71 72 class TestParameterInjector 73 """ 74 ) 75 .indented() 76 77 val AndroidJUnit4Runner = 78 TestFiles.kotlin( 79 """ 80 package androidx.test.ext.junit.runners 81 82 class AndroidJUnit4 83 """ 84 ) 85 86 val TestSizeAnnotations = 87 TestFiles.kotlin( 88 """ 89 package androidx.test.filters 90 91 annotation class SmallTest 92 annotation class MediumTest 93 annotation class LargeTest 94 """ 95 ) 96 97 val TestAnnotation = 98 TestFiles.kotlin( 99 """ 100 package org.junit 101 102 annotation class Test 103 """ 104 ) 105 106 /** 107 * [TestFile] containing OptIn.kt from the Kotlin standard library. 108 * 109 * This is a workaround for the Kotlin standard library used by the Lint test harness not 110 * including the Experimental annotation by default. 111 */ 112 val OptIn = 113 TestFiles.kotlin( 114 """ 115 package kotlin 116 117 import kotlin.annotation.AnnotationRetention.BINARY 118 import kotlin.annotation.AnnotationRetention.SOURCE 119 import kotlin.annotation.AnnotationTarget.* 120 import kotlin.internal.RequireKotlin 121 import kotlin.internal.RequireKotlinVersionKind 122 import kotlin.reflect.KClass 123 124 @Target(ANNOTATION_CLASS) 125 @Retention(BINARY) 126 @SinceKotlin("1.3") 127 @RequireKotlin("1.3.70", versionKind = RequireKotlinVersionKind.COMPILER_VERSION) 128 public annotation class RequiresOptIn( 129 val message: String = "", 130 val level: Level = Level.ERROR 131 ) { 132 public enum class Level { 133 WARNING, 134 ERROR, 135 } 136 } 137 138 @Target( 139 CLASS, PROPERTY, LOCAL_VARIABLE, VALUE_PARAMETER, CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, EXPRESSION, FILE, TYPEALIAS 140 ) 141 @Retention(SOURCE) 142 @SinceKotlin("1.3") 143 @RequireKotlin("1.3.70", versionKind = RequireKotlinVersionKind.COMPILER_VERSION) 144 public annotation class OptIn( 145 vararg val markerClass: KClass<out Annotation> 146 ) 147 """ 148 ) 149 150 /** [TestFile] containing ChecksSdkIntAtLeast.java from the annotation library. */ 151 val ChecksSdkIntAtLeast = 152 TestFiles.java( 153 """ 154 package androidx.annotation; 155 156 import static java.lang.annotation.ElementType.FIELD; 157 import static java.lang.annotation.ElementType.METHOD; 158 import static java.lang.annotation.RetentionPolicy.CLASS; 159 160 import java.lang.annotation.Documented; 161 import java.lang.annotation.Retention; 162 import java.lang.annotation.Target; 163 164 @Documented 165 @Retention(CLASS) 166 @Target({METHOD, FIELD}) 167 public @interface ChecksSdkIntAtLeast { 168 int api() default -1; 169 String codename() default ""; 170 int parameter() default -1; 171 int lambda() default -1; 172 } 173 """ 174 ) 175 176 val RequiresApi = 177 TestFiles.java( 178 """ 179 package androidx.annotation; 180 181 import static java.lang.annotation.ElementType.CONSTRUCTOR; 182 import static java.lang.annotation.ElementType.FIELD; 183 import static java.lang.annotation.ElementType.METHOD; 184 import static java.lang.annotation.ElementType.PACKAGE; 185 import static java.lang.annotation.ElementType.TYPE; 186 import static java.lang.annotation.RetentionPolicy.CLASS; 187 188 import java.lang.annotation.Documented; 189 import java.lang.annotation.Retention; 190 import java.lang.annotation.Target; 191 192 @Documented 193 @Retention(CLASS) 194 @Target({TYPE, METHOD, CONSTRUCTOR, FIELD, PACKAGE}) 195 public @interface RequiresApi { 196 @IntRange(from = 1) 197 int value() default 1; 198 @IntRange(from = 1) 199 int api() default 1; 200 } 201 """ 202 ) 203 204 val IntRange = 205 TestFiles.java( 206 """ 207 package androidx.annotation; 208 209 import static java.lang.annotation.ElementType.ANNOTATION_TYPE; 210 import static java.lang.annotation.ElementType.FIELD; 211 import static java.lang.annotation.ElementType.LOCAL_VARIABLE; 212 import static java.lang.annotation.ElementType.METHOD; 213 import static java.lang.annotation.ElementType.PARAMETER; 214 import static java.lang.annotation.RetentionPolicy.CLASS; 215 216 import java.lang.annotation.Documented; 217 import java.lang.annotation.Retention; 218 import java.lang.annotation.Target; 219 220 @Documented 221 @Retention(CLASS) 222 @Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE}) 223 public @interface IntRange { 224 long from() default Long.MIN_VALUE; 225 long to() default Long.MAX_VALUE; 226 } 227 """ 228 ) 229 230 val RestrictTo = 231 TestFiles.java( 232 """ 233 package androidx.annotation; 234 235 import static java.lang.annotation.ElementType.ANNOTATION_TYPE; 236 import static java.lang.annotation.ElementType.CONSTRUCTOR; 237 import static java.lang.annotation.ElementType.FIELD; 238 import static java.lang.annotation.ElementType.METHOD; 239 import static java.lang.annotation.ElementType.PACKAGE; 240 import static java.lang.annotation.ElementType.TYPE; 241 import static java.lang.annotation.RetentionPolicy.CLASS; 242 243 import java.lang.annotation.Documented; 244 import java.lang.annotation.Retention; 245 import java.lang.annotation.Target; 246 247 @Documented 248 @Retention(CLASS) 249 @Target({ANNOTATION_TYPE, TYPE, METHOD, CONSTRUCTOR, FIELD, PACKAGE}) 250 public @interface RestrictTo { 251 Scope[] value(); 252 enum Scope { 253 LIBRARY, 254 LIBRARY_GROUP, 255 LIBRARY_GROUP_PREFIX, 256 /** @deprecated Use {@link #LIBRARY_GROUP_PREFIX} instead */ 257 @Deprecated 258 GROUP_ID, 259 TESTS, 260 SUBCLASSES, 261 } 262 } 263 """ 264 ) 265 266 val JetBrainsAnnotations = 267 TestFiles.kotlin( 268 """ 269 package org.jetbrains.annotations 270 271 annotation class NotNull 272 annotation class Nullable 273 """ 274 ) 275 276 val IgnoreAnnotation = 277 TestFiles.kotlin( 278 """ 279 package org.junit 280 281 annotation class Ignore 282 """ 283 ) 284 285 val DoNotInline = 286 TestFiles.java( 287 """ 288 package androidx.annotation; 289 290 import static java.lang.annotation.ElementType.METHOD; 291 import static java.lang.annotation.RetentionPolicy.CLASS; 292 293 import java.lang.annotation.Retention; 294 import java.lang.annotation.Target; 295 296 @Retention(CLASS) 297 @Target({METHOD}) 298 public @interface DoNotInline { 299 } 300 """ 301 ) 302 303 val DeprecatedSinceApi = 304 TestFiles.kotlin( 305 """ 306 package androidx.annotation 307 308 import kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS 309 import kotlin.annotation.AnnotationTarget.CLASS 310 import kotlin.annotation.AnnotationTarget.CONSTRUCTOR 311 import kotlin.annotation.AnnotationTarget.FUNCTION 312 import kotlin.annotation.AnnotationTarget.PROPERTY_GETTER 313 import kotlin.annotation.AnnotationTarget.PROPERTY_SETTER 314 315 @MustBeDocumented 316 @Retention(AnnotationRetention.BINARY) 317 @Target(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, ANNOTATION_CLASS, CLASS, CONSTRUCTOR) 318 public annotation class DeprecatedSinceApi( 319 val api: Int, 320 val message: String = "" 321 ) 322 """ 323 ) 324 325 val JvmDefaultWithCompatibility = 326 TestFiles.kotlin( 327 """ 328 package kotlin.jvm 329 330 @Retention(AnnotationRetention.SOURCE) 331 @Target(AnnotationTarget.CLASS) 332 annotation class JvmDefaultWithCompatibility 333 """ 334 .trimIndent() 335 ) 336 337 /** [TestFile] containing OptIn.kt from the AndroidX experimental annotation library. */ 338 val JetpackOptIn: TestFile = 339 LintDetectorTest.kotlin( 340 """ 341 package androidx.annotation 342 343 import kotlin.annotation.Retention 344 import kotlin.annotation.Target 345 import kotlin.reflect.KClass 346 347 @Retention(AnnotationRetention.BINARY) 348 @Target( 349 AnnotationTarget.CLASS, 350 AnnotationTarget.PROPERTY, 351 AnnotationTarget.LOCAL_VARIABLE, 352 AnnotationTarget.VALUE_PARAMETER, 353 AnnotationTarget.CONSTRUCTOR, 354 AnnotationTarget.FUNCTION, 355 AnnotationTarget.PROPERTY_GETTER, 356 AnnotationTarget.PROPERTY_SETTER, 357 AnnotationTarget.FILE, 358 AnnotationTarget.TYPEALIAS 359 ) 360 annotation class OptIn( 361 @get:Suppress("ArrayReturn") 362 vararg val markerClass: KClass<out Annotation> 363 ) 364 """ 365 .trimIndent() 366 ) 367 368 /** 369 * [TestFile] containing RequiresOptIn.kt from the AndroidX experimental annotation library. 370 */ 371 val JetpackRequiresOptIn: TestFile = 372 LintDetectorTest.kotlin( 373 """ 374 package androidx.annotation 375 376 import kotlin.annotation.Retention 377 import kotlin.annotation.Target 378 379 @Retention(AnnotationRetention.BINARY) 380 @Target(AnnotationTarget.ANNOTATION_CLASS) 381 annotation class RequiresOptIn( 382 val level: Level = Level.ERROR 383 ) { 384 enum class Level { 385 WARNING, 386 ERROR 387 } 388 } 389 """ 390 .trimIndent() 391 ) 392 393 /** [TestFile] containing VisibleForTesting.kt from the AndroidX annotation library. */ 394 val VisibleForTesting: TestFile = 395 LintDetectorTest.kotlin( 396 """ 397 package androidx.annotation 398 399 @MustBeDocumented 400 @Retention(AnnotationRetention.BINARY) 401 public annotation class VisibleForTesting( 402 @ProductionVisibility val otherwise: Int = PRIVATE 403 ) { 404 public companion object { 405 public const val PRIVATE: Int = 2 406 public const val PACKAGE_PRIVATE: Int = 3 407 public const val PROTECTED: Int = 4 408 public const val NONE: Int = 5 409 } 410 } 411 """ 412 .trimIndent() 413 ) 414 415 /** Contains only a few of the isAtLeastX implementations from BuildCompat for testing */ 416 val BuildCompat: TestFile = 417 LintDetectorTest.java( 418 """ 419 package androidx.core.os; 420 421 import android.os.Build; 422 import android.os.Build.VERSION; 423 424 import androidx.annotation.ChecksSdkIntAtLeast; 425 import androidx.annotation.NonNull; 426 import androidx.annotation.RequiresOptIn; 427 import androidx.annotation.RestrictTo; 428 429 import java.util.Locale; 430 431 public class BuildCompat { 432 private BuildCompat() {} 433 434 @RestrictTo(RestrictTo.Scope.TESTS) 435 protected static boolean isAtLeastPreReleaseCodename(@NonNull String codename, @NonNull String buildCodename) { 436 if ("REL".equals(buildCodename)) { 437 return false; 438 } 439 final String buildCodenameUpper = buildCodename.toUpperCase(Locale.ROOT); 440 final String codenameUpper = codename.toUpperCase(Locale.ROOT); 441 return buildCodenameUpper.compareTo(codenameUpper) >= 0; 442 } 443 444 @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.N) 445 @Deprecated 446 public static boolean isAtLeastN() { 447 return VERSION.SDK_INT >= 24; 448 } 449 450 @PrereleaseSdkCheck 451 @ChecksSdkIntAtLeast(api = 32, codename = "Sv2") 452 @Deprecated 453 public static boolean isAtLeastSv2() { 454 return VERSION.SDK_INT >= 32 || (VERSION.SDK_INT >= 31 && isAtLeastPreReleaseCodename("Sv2", VERSION.CODENAME)); 455 } 456 457 @PrereleaseSdkCheck 458 @ChecksSdkIntAtLeast(codename = "UpsideDownCake") 459 public static boolean isAtLeastU() { 460 return VERSION.SDK_INT >= 33 && isAtLeastPreReleaseCodename("UpsideDownCake", VERSION.CODENAME); 461 } 462 463 @RequiresOptIn 464 public @interface PrereleaseSdkCheck { } 465 } 466 """ 467 .trimIndent() 468 ) 469 470 val FlaggedApi: TestFile = 471 TestFiles.java( 472 """ 473 package android.annotation; // HIDE-FROM-DOCUMENTATION 474 475 import static java.lang.annotation.ElementType.ANNOTATION_TYPE; 476 import static java.lang.annotation.ElementType.CONSTRUCTOR; 477 import static java.lang.annotation.ElementType.FIELD; 478 import static java.lang.annotation.ElementType.METHOD; 479 import static java.lang.annotation.ElementType.TYPE; 480 481 import java.lang.annotation.Retention; 482 import java.lang.annotation.RetentionPolicy; 483 import java.lang.annotation.Target; 484 485 @Target({TYPE, METHOD, CONSTRUCTOR, FIELD, ANNOTATION_TYPE}) 486 @Retention(RetentionPolicy.CLASS) 487 public @interface FlaggedApi { 488 String value(); 489 } 490 """ 491 ) 492 .indented() 493 494 val ChecksAconfigFlag: TestFile = 495 TestFiles.kotlin( 496 """ 497 package androidx.annotation 498 499 @MustBeDocumented 500 @Retention(AnnotationRetention.BINARY) 501 @Target( 502 AnnotationTarget.FUNCTION, 503 AnnotationTarget.PROPERTY_GETTER, 504 AnnotationTarget.PROPERTY_SETTER, 505 AnnotationTarget.FIELD 506 ) 507 public annotation class ChecksAconfigFlag ( 508 val flag: String 509 ) 510 """ 511 ) 512 .indented() 513 } 514 } 515