1 /* 2 * Copyright (C) 2017 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("ALL") 18 19 package com.android.tools.metalava 20 21 import com.android.tools.lint.checks.infrastructure.TestFiles.base64gzip 22 import com.android.tools.metalava.cli.common.ARG_ERROR 23 import com.android.tools.metalava.cli.common.ARG_HIDE 24 import com.android.tools.metalava.lint.DefaultLintErrorMessage 25 import com.android.tools.metalava.model.provider.Capability 26 import com.android.tools.metalava.model.testing.RequiresCapabilities 27 import com.android.tools.metalava.model.text.FileFormat 28 import com.android.tools.metalava.model.text.FileFormat.OverloadedMethodOrder 29 import com.android.tools.metalava.reporter.Issues 30 import com.android.tools.metalava.testing.KnownJarFiles 31 import com.android.tools.metalava.testing.createAndroidModuleDescription 32 import com.android.tools.metalava.testing.createCommonModuleDescription 33 import com.android.tools.metalava.testing.createProjectDescription 34 import com.android.tools.metalava.testing.java 35 import com.android.tools.metalava.testing.kotlin 36 import org.junit.Test 37 38 class ApiFileTest : DriverTest() { 39 /* 40 Conditions to test: 41 - test all the error scenarios found in the notStrippable case! 42 - split up test into many individual test cases 43 - try referencing a class from an annotation! 44 - test having a throws list where some exceptions are hidden but extend 45 public exceptions: do we map over to the referenced ones? 46 47 - test type reference from all the possible places -- in type signatures - interfaces, 48 extends, throws, type bounds, etc. 49 - method which overrides @hide method: should appear in subclass (test chain 50 of two nested too) 51 - BluetoothGattCharacteristic.java#describeContents: Was marked @hide, 52 but is unhidden because it extends a public interface method 53 - package javadoc (also make sure merging both!, e.g. try having @hide in each) 54 - StopWatchMap -- inner class with @hide marks all top levels! 55 - Test field inlining: should I include fields from an interface, if that 56 interface was implemented by the parent class (and therefore appears there too?) 57 What if the superclass is abstract? 58 - Exposing package private classes. Test that I only do this for package private 59 classes, NOT Those marked @hide (is that, having @hide on a used type, illegal?) 60 - Test error handling (invalid @hide combinations)) 61 - Consider what happens if we promote a package private class (because it's 62 extended by a public class), and then we restore its public members; the 63 override logic there isn't quite right. We've duplicated the significant-override 64 code to not skip private members, but that could change semantics. This isn't 65 ideal; instead we should now mark this class as public, and re-run the analysis 66 again (with the new hidden state for this class). 67 - compilation unit sorting - top level classes out of order 68 - Massive classes such as android.R.java? Maybe do synthetic test. 69 - HttpResponseCache implemented a public OkHttp interface, but the sole implementation 70 method was marked @hide, so the method doesn't show up. Is that some other rule -- 71 that we skip interfaces if their implementation methods are marked @hide? 72 - Test recursive package filtering. 73 */ 74 75 @RequiresCapabilities(Capability.KOTLIN) 76 @Test Kotlin language levelnull77 fun `Kotlin language level`() { 78 // static method in interface is not overridable. 79 // See https://kotlinlang.org/docs/reference/whatsnew13.html 80 check( 81 format = FileFormat.V4, 82 sourceFiles = 83 arrayOf( 84 kotlin( 85 """ 86 package test.pkg 87 interface Foo { 88 companion object { 89 @JvmField 90 const val answer: Int = 42 91 @JvmStatic 92 fun sayHello() { 93 println("Hello, world!") 94 } 95 } 96 } 97 """ 98 ) 99 ), 100 api = 101 """ 102 package test.pkg { 103 public interface Foo { 104 method public static void sayHello(); 105 field public static final test.pkg.Foo.Companion Companion; 106 field public static final int answer = 42; // 0x2a 107 } 108 public static final class Foo.Companion { 109 method public void sayHello(); 110 property public static int answer; 111 } 112 } 113 """, 114 // The above source uses 1.3 features, though UAST currently 115 // seems to still treat it as 1.3 despite being passed 1.2 116 extraArguments = arrayOf(ARG_KOTLIN_SOURCE, "1.2") 117 ) 118 } 119 120 @Test Basic class signature extractionnull121 fun `Basic class signature extraction`() { 122 // Basic class; also checks that default constructor is made explicit 123 check( 124 sourceFiles = 125 arrayOf( 126 java( 127 """ 128 package test.pkg; 129 public class Foo { 130 } 131 """ 132 ) 133 ), 134 api = 135 """ 136 package test.pkg { 137 public class Foo { 138 ctor public Foo(); 139 } 140 } 141 """ 142 ) 143 } 144 145 @RequiresCapabilities(Capability.KOTLIN) 146 @Test Basic Kotlin classnull147 fun `Basic Kotlin class`() { 148 check( 149 format = FileFormat.V4, 150 sourceFiles = 151 arrayOf( 152 kotlin( 153 """ 154 package test.pkg 155 class Kotlin(val property1: String = "Default Value", arg2: Int) : Parent() { 156 override fun method() = "Hello World" 157 fun otherMethod(ok: Boolean, times: Int) { 158 } 159 160 var property2: String? = null 161 162 private var someField = 42 163 @JvmField 164 var someField2 = 42 165 166 internal var myHiddenVar = false 167 internal fun myHiddenMethod() { } 168 internal data class myHiddenClass(): Unit 169 170 companion object { 171 const val MY_CONST = 42 172 } 173 } 174 175 //@get:RequiresApi(26) 176 inline val @receiver:String Long.isSrgb get() = true 177 inline val /*@receiver:ColorInt*/ Int.red get() = 0 178 inline operator fun String.component1() = "" 179 180 open class Parent { 181 open fun method(): String? = null 182 open fun method2(value: Boolean, value: Boolean?): String? = null 183 open fun method3(value: Int?, value2: Int): Int = null 184 } 185 """ 186 ) 187 ), 188 api = 189 """ 190 package test.pkg { 191 public final class Kotlin extends test.pkg.Parent { 192 ctor public Kotlin(optional String property1, int arg2); 193 method public String getProperty1(); 194 method public String? getProperty2(); 195 method public void otherMethod(boolean ok, int times); 196 method public void setProperty2(String?); 197 property public String property1; 198 property public String? property2; 199 property public int someField2; 200 field public static final test.pkg.Kotlin.Companion Companion; 201 field public static final int MY_CONST = 42; // 0x2a 202 field public int someField2; 203 } 204 public static final class Kotlin.Companion { 205 property public static int MY_CONST; 206 } 207 public final class KotlinKt { 208 method public static inline operator String component1(String); 209 method public static inline int getRed(int); 210 method public static inline boolean isSrgb(long); 211 property public static inline boolean long.isSrgb; 212 property public static inline int int.red; 213 } 214 public class Parent { 215 ctor public Parent(); 216 method public String? method(); 217 method public String? method2(boolean value, Boolean? value); 218 method public int method3(Integer? value, int value2); 219 } 220 } 221 """ 222 ) 223 } 224 225 @RequiresCapabilities(Capability.KOTLIN) 226 @Test Kotlin Reified Methodsnull227 fun `Kotlin Reified Methods`() { 228 check( 229 format = FileFormat.V4, 230 sourceFiles = 231 arrayOf( 232 java( 233 """ 234 package test.pkg; 235 236 public class Context { 237 @SuppressWarnings("unchecked") 238 public final <T> T getSystemService(Class<T> serviceClass) { 239 return null; 240 } 241 } 242 """ 243 ), 244 kotlin( 245 """ 246 package test.pkg 247 248 inline fun <reified T> Context.systemService1() = getSystemService(T::class.java) 249 inline fun Context.systemService2() = getSystemService(String::class.java) 250 """ 251 ) 252 ), 253 api = 254 """ 255 package test.pkg { 256 public class Context { 257 ctor public Context(); 258 method public final <T> T! getSystemService(Class<T!>!); 259 } 260 public final class TestKt { 261 method public static inline <reified T> T! systemService1(test.pkg.Context); 262 method public static inline String! systemService2(test.pkg.Context); 263 } 264 } 265 """ 266 ) 267 } 268 269 @RequiresCapabilities(Capability.KOTLIN) 270 @Test Kotlin Reified Methods 2null271 fun `Kotlin Reified Methods 2`() { 272 check( 273 format = FileFormat.V4, 274 sourceFiles = 275 arrayOf( 276 kotlin( 277 """ 278 @file:Suppress("All", "RedundantVisibilityModifier") 279 280 package test.pkg 281 import kotlin.collections.List 282 283 inline fun <T> inlineNoReified(t: T): T { return t } 284 inline fun <reified T> inlineReified(t: T) { } 285 private inline fun <reified T> privateInlineReified(t: T) { } // hide 286 internal inline fun <reified T> internalInlineReified(t: T) { } // hide 287 public inline fun <reified T> publicInlineReified(t: T): T { return t } 288 inline fun <reified T> T.inlineReifiedExtension(t: T) { this } 289 public inline fun <reified T> inlineReifiedTakesAndReturnsArray(t: Array<T>): Array<T> { return t } 290 public inline fun <reified T> inlineReifiedTakesAndReturnsList(t: List<T>): List<T> { return t } 291 """ 292 ) 293 ), 294 api = 295 """ 296 package test.pkg { 297 public final class TestKt { 298 method public static inline <T> T inlineNoReified(T t); 299 method public static inline <reified T> void inlineReified(T t); 300 method public static inline <reified T> void inlineReifiedExtension(T, T t); 301 method public static inline <reified T> T[] inlineReifiedTakesAndReturnsArray(T[] t); 302 method public static inline <reified T> java.util.List<T> inlineReifiedTakesAndReturnsList(java.util.List<? extends T> t); 303 method public static inline <reified T> T publicInlineReified(T t); 304 } 305 } 306 """ 307 ) 308 } 309 310 @RequiresCapabilities(Capability.KOTLIN) 311 @Test Suspend functionsnull312 fun `Suspend functions`() { 313 check( 314 format = FileFormat.V4, 315 sourceFiles = 316 arrayOf( 317 kotlin( 318 """ 319 package test.pkg 320 suspend inline fun hello(foo: Int) { } 321 suspend fun String.hello(foo: Int = 0) { } 322 suspend fun helloTwoContinuations(myContinuation: kotlin.coroutines.Continuation<Any>) { } 323 internal suspend fun internalHello() { } 324 private suspend fun privateHello() { } 325 """ 326 ) 327 ), 328 api = 329 """ 330 package test.pkg { 331 public final class TestKt { 332 method public static suspend inline Object? hello(int foo, kotlin.coroutines.Continuation<? super kotlin.Unit>); 333 method public static suspend Object? hello(String, optional int foo, kotlin.coroutines.Continuation<? super kotlin.Unit>); 334 method public static suspend Object? helloTwoContinuations(kotlin.coroutines.Continuation<java.lang.Object> myContinuation, kotlin.coroutines.Continuation<? super kotlin.Unit>); 335 } 336 } 337 """ 338 ) 339 } 340 341 @RequiresCapabilities(Capability.KOTLIN) 342 @Test Var properties with private settersnull343 fun `Var properties with private setters`() { 344 check( 345 format = FileFormat.V4, 346 sourceFiles = 347 arrayOf( 348 kotlin( 349 """ 350 package test.pkg 351 class MyClass { 352 // This property should have no public setter 353 var readOnlyVar = false 354 internal set 355 // This property should have no public setter 356 public var readOnlyVarWithPublicModifier = false 357 internal set 358 } 359 """ 360 ) 361 ), 362 api = 363 """ 364 // Signature format: 4.0 365 package test.pkg { 366 public final class MyClass { 367 ctor public MyClass(); 368 method public boolean getReadOnlyVar(); 369 method public boolean getReadOnlyVarWithPublicModifier(); 370 property public boolean readOnlyVar; 371 property public boolean readOnlyVarWithPublicModifier; 372 } 373 } 374 """ 375 ) 376 } 377 378 @RequiresCapabilities(Capability.KOTLIN) 379 @Test Kotlin Genericsnull380 fun `Kotlin Generics`() { 381 check( 382 format = FileFormat.V4, 383 sourceFiles = 384 arrayOf( 385 kotlin( 386 """ 387 package test.pkg 388 class Bar 389 class Type<in T> { 390 fun foo(param: Type<Bar>) { 391 } 392 } 393 """ 394 ) 395 ), 396 api = 397 """ 398 // Signature format: 4.0 399 package test.pkg { 400 public final class Bar { 401 ctor public Bar(); 402 } 403 public final class Type<T> { 404 ctor public Type(); 405 method public void foo(test.pkg.Type<? super test.pkg.Bar> param); 406 } 407 } 408 """ 409 ) 410 } 411 412 @RequiresCapabilities(Capability.KOTLIN) 413 @Test Nullness in reified signaturesnull414 fun `Nullness in reified signatures`() { 415 check( 416 sourceFiles = 417 arrayOf( 418 kotlin( 419 "src/test/pkg/test.kt", 420 """ 421 package test.pkg 422 423 import androidx.annotation.UiThread 424 import test.pkg2.NavArgs 425 import test.pkg2.NavArgsLazy 426 import test.pkg2.Fragment 427 import test.pkg2.Bundle 428 429 @UiThread 430 inline fun <reified Args : NavArgs> Fragment.navArgs() = NavArgsLazy(Args::class) { 431 throw IllegalStateException("Fragment $this has null arguments") 432 } 433 """ 434 ), 435 java( 436 """ 437 /** @hide */ 438 package test.pkg2; 439 """ 440 ), 441 kotlin( 442 """ 443 package test.pkg2 444 445 import kotlin.reflect.KClass 446 447 interface NavArgs 448 class Fragment 449 class Bundle 450 class NavArgsLazy<Args : NavArgs>( 451 private val navArgsClass: KClass<Args>, 452 private val argumentProducer: () -> Bundle 453 ) 454 """ 455 ), 456 uiThreadSource, 457 ), 458 api = 459 """ 460 // Signature format: 4.0 461 package test.pkg { 462 public final class TestKt { 463 method @UiThread public static inline <reified Args extends test.pkg2.NavArgs> test.pkg2.NavArgsLazy<Args> navArgs(test.pkg2.Fragment); 464 } 465 } 466 """, 467 format = FileFormat.V4, 468 extraArguments = 469 arrayOf( 470 ARG_HIDE, 471 "ReferencesHidden", 472 ARG_HIDE, 473 "UnavailableSymbol", 474 ARG_HIDE, 475 "HiddenTypeParameter", 476 ARG_HIDE, 477 "HiddenSuperclass" 478 ) 479 ) 480 } 481 482 @RequiresCapabilities(Capability.KOTLIN) 483 @Test Nullness in varargsnull484 fun `Nullness in varargs`() { 485 check( 486 sourceFiles = 487 arrayOf( 488 java( 489 """ 490 package androidx.collection; 491 492 import java.util.Collection; 493 import java.util.HashMap; 494 import java.util.Map; 495 496 public class ArrayMap<K, V> extends HashMap<K, V> implements Map<K, V> { 497 public ArrayMap() { 498 } 499 } 500 """ 501 ), 502 java( 503 """ 504 package androidx.collection; 505 506 import java.util.Collection; 507 import java.util.HashSet; 508 import java.util.Set; 509 510 public class ArraySet<E> extends HashSet<E> implements Set<E> { 511 public ArraySet() { 512 } 513 } 514 """ 515 ), 516 java( 517 """ 518 package androidx.core.app; 519 520 import java.util.ArrayList; 521 import java.util.List; 522 523 import androidx.annotation.NonNull; 524 import androidx.annotation.Nullable; 525 526 public class ActivityOptionsCompat { 527 private ActivityOptionsCompat() { 528 } 529 @NonNull 530 public static List<String> javaListOf(String... sharedElements) { 531 return new ArrayList<String>(); 532 } 533 @Nullable 534 public static List<String> javaListOfNullable(String... sharedElements) { 535 return null; 536 } 537 538 } 539 """ 540 ), 541 kotlin( 542 "src/main/java/androidx/collection/ArrayMap.kt", 543 """ 544 package androidx.collection 545 546 inline fun <K, V> arrayMapOf(): ArrayMap<K, V> = ArrayMap() 547 548 fun <K, V> arrayMapOf(vararg pairs: Pair<K, V>): ArrayMap<K, V> { 549 val map = ArrayMap<K, V>(pairs.size) 550 for (pair in pairs) { 551 map[pair.first] = pair.second 552 } 553 return map 554 } 555 fun <K, V> arrayMapOfNullable(vararg pairs: Pair<K, V>?): ArrayMap<K, V>? { 556 return null 557 } 558 """ 559 ), 560 kotlin( 561 "src/main/java/androidx/collection/ArraySet.kt", 562 """ 563 package androidx.collection 564 565 inline fun <T> arraySetOf(): ArraySet<T> = ArraySet() 566 567 fun <T> arraySetOf(vararg values: T): ArraySet<T> { 568 val set = ArraySet<T>(values.size) 569 for (value in values) { 570 set.add(value) 571 } 572 return set 573 } 574 575 fun <T> arraySetOfNullable(vararg values: T?): ArraySet<T>? { 576 return null 577 } 578 """ 579 ), 580 androidxNonNullSource, 581 androidxNullableSource, 582 ), 583 api = 584 """ 585 // Signature format: 4.0 586 package androidx.collection { 587 public class ArrayMap<K, V> extends java.util.HashMap<K!,V!> implements java.util.Map<K!,V!> { 588 ctor public ArrayMap(); 589 } 590 public final class ArrayMapKt { 591 method public static inline <K, V> androidx.collection.ArrayMap<K,V> arrayMapOf(); 592 method public static <K, V> androidx.collection.ArrayMap<K,V> arrayMapOf(kotlin.Pair<? extends K,? extends V>... pairs); 593 method public static <K, V> androidx.collection.ArrayMap<K,V>? arrayMapOfNullable(kotlin.Pair<? extends K,? extends V>?... pairs); 594 } 595 public class ArraySet<E> extends java.util.HashSet<E!> implements java.util.Set<E!> { 596 ctor public ArraySet(); 597 } 598 public final class ArraySetKt { 599 method public static inline <T> androidx.collection.ArraySet<T> arraySetOf(); 600 method public static <T> androidx.collection.ArraySet<T> arraySetOf(T... values); 601 method public static <T> androidx.collection.ArraySet<T>? arraySetOfNullable(T?... values); 602 } 603 } 604 package androidx.core.app { 605 public class ActivityOptionsCompat { 606 method public static java.util.List<java.lang.String!> javaListOf(java.lang.String!...!); 607 method public static java.util.List<java.lang.String!>? javaListOfNullable(java.lang.String!...!); 608 } 609 } 610 """, 611 format = FileFormat.V4, 612 extraArguments = 613 arrayOf( 614 ARG_HIDE, 615 "ReferencesHidden", 616 ARG_HIDE, 617 "UnavailableSymbol", 618 ARG_HIDE, 619 "HiddenTypeParameter" 620 ) 621 ) 622 } 623 624 @RequiresCapabilities(Capability.KOTLIN) 625 @Test Nullness in type parametersnull626 fun `Nullness in type parameters`() { 627 check( 628 sourceFiles = 629 arrayOf( 630 kotlin( 631 """ 632 package test.pkg 633 class NonNullUpperBound<T : Any>(ctorParam: T) { 634 fun explicitNullable(e: T?): T? = e 635 fun inheritedNullability(i: T): T = i 636 } 637 638 class NullableUpperBound<T : Any?>(ctorParam: T) { 639 fun explicitNullable(e: T?): T? = e 640 fun inheritedNullability(i: T): T = i 641 } 642 643 class UnspecifiedUpperBound<T>(ctorParam: T) { 644 fun explicitNullable(e: T?): T? = e 645 fun inheritedNullability(i: T): T = i 646 } 647 648 fun <T : Any> topLevelNonNullUpperBoundExplicitNullable(t: T?) = t 649 fun <T : Any> topLevelNonNullUpperBoundInherited(t: T) = t 650 651 fun <T : Any?> topLevelNullableUpperBoundExplicitNullable(t: T?) = t 652 fun <T : Any?> topLevelNullableUpperBoundInherited(t: T) = t 653 654 fun <T> topLevelUnspecifiedUpperBoundExplicitNullable(t: T?) = t 655 fun <T> topLevelUnspecifiedUpperBoundInherited(t: T) = t 656 """ 657 ) 658 ), 659 api = 660 """ 661 package test.pkg { 662 public final class NonNullUpperBound<T> { 663 ctor public NonNullUpperBound(T ctorParam); 664 method public T? explicitNullable(T? e); 665 method public T inheritedNullability(T i); 666 } 667 public final class NonNullUpperBoundKt { 668 method public static <T> T? topLevelNonNullUpperBoundExplicitNullable(T? t); 669 method public static <T> T topLevelNonNullUpperBoundInherited(T t); 670 method public static <T> T? topLevelNullableUpperBoundExplicitNullable(T? t); 671 method public static <T> T topLevelNullableUpperBoundInherited(T t); 672 method public static <T> T? topLevelUnspecifiedUpperBoundExplicitNullable(T? t); 673 method public static <T> T topLevelUnspecifiedUpperBoundInherited(T t); 674 } 675 public final class NullableUpperBound<T> { 676 ctor public NullableUpperBound(T ctorParam); 677 method public T? explicitNullable(T? e); 678 method public T inheritedNullability(T i); 679 } 680 public final class UnspecifiedUpperBound<T> { 681 ctor public UnspecifiedUpperBound(T ctorParam); 682 method public T? explicitNullable(T? e); 683 method public T inheritedNullability(T i); 684 } 685 } 686 """ 687 ) 688 } 689 690 @RequiresCapabilities(Capability.KOTLIN) 691 @Test Nullness in type parameter -- suspend funnull692 fun `Nullness in type parameter -- suspend fun`() { 693 check( 694 sourceFiles = 695 arrayOf( 696 java( 697 """ 698 package test.util.concurrent; 699 700 public interface MyFuture<V extends @Nullable Object> { 701 } 702 """ 703 ), 704 kotlin( 705 """ 706 package test.pkg 707 708 import test.util.concurrent.MyFuture 709 710 suspend fun <T> MyFuture<T>.await(t: T): T = TODO() 711 """ 712 ) 713 ), 714 api = 715 """ 716 package test.pkg { 717 public final class TestKt { 718 method public static suspend <T> Object? await(test.util.concurrent.MyFuture<T>, T t, kotlin.coroutines.Continuation<? super T>); 719 } 720 } 721 package test.util.concurrent { 722 public interface MyFuture<V> { 723 } 724 } 725 """ 726 ) 727 } 728 729 @RequiresCapabilities(Capability.KOTLIN) 730 @Test Nullness in type parameter -- property and accessornull731 fun `Nullness in type parameter -- property and accessor`() { 732 check( 733 sourceFiles = 734 arrayOf( 735 kotlin( 736 """ 737 package test.pkg 738 739 class CircularArray<E> { 740 val first: E 741 get() = TODO() 742 743 var last: E 744 get() = TODO() 745 set(value) = TODO() 746 } 747 """ 748 ) 749 ), 750 api = 751 """ 752 package test.pkg { 753 public final class CircularArray<E> { 754 ctor public CircularArray(); 755 method public E getFirst(); 756 method public E getLast(); 757 method public void setLast(E); 758 property public E first; 759 property public E last; 760 } 761 } 762 """ 763 ) 764 } 765 766 @RequiresCapabilities(Capability.KOTLIN) 767 @Test Propagate Platform types in Kotlinnull768 fun `Propagate Platform types in Kotlin`() { 769 check( 770 format = FileFormat.V4, 771 sourceFiles = 772 arrayOf( 773 kotlin( 774 """ 775 // Nullable Pair in Kotlin 776 package androidx.util 777 778 class NullableKotlinPair<out F, out S>(val first: F?, val second: S?) 779 """ 780 ), 781 kotlin( 782 """ 783 // Non-nullable Pair in Kotlin 784 package androidx.util 785 class NonNullableKotlinPair<out F: Any, out S: Any>(val first: F, val second: S) 786 """ 787 ), 788 java( 789 """ 790 // Platform nullability Pair in Java 791 package androidx.util; 792 793 @SuppressWarnings("WeakerAccess") 794 public class PlatformJavaPair<F, S> { 795 public final F first; 796 public final S second; 797 798 public PlatformJavaPair(F first, S second) { 799 this.first = first; 800 this.second = second; 801 } 802 } 803 """ 804 ), 805 java( 806 """ 807 // Platform nullability Pair in Java 808 package androidx.util; 809 import androidx.annotation.NonNull; 810 import androidx.annotation.Nullable; 811 812 @SuppressWarnings("WeakerAccess") 813 public class NullableJavaPair<F, S> { 814 public final @Nullable F first; 815 public final @Nullable S second; 816 817 public NullableJavaPair(@Nullable F first, @Nullable S second) { 818 this.first = first; 819 this.second = second; 820 } 821 } 822 """ 823 ), 824 java( 825 """ 826 // Platform nullability Pair in Java 827 package androidx.util; 828 829 import androidx.annotation.NonNull; 830 831 @SuppressWarnings("WeakerAccess") 832 public class NonNullableJavaPair<F, S> { 833 public final @NonNull F first; 834 public final @NonNull S second; 835 836 public NonNullableJavaPair(@NonNull F first, @NonNull S second) { 837 this.first = first; 838 this.second = second; 839 } 840 } 841 """ 842 ), 843 kotlin( 844 """ 845 package androidx.util 846 847 @Suppress("HasPlatformType") // Intentionally propagating platform type with unknown nullability. 848 inline operator fun <F, S> PlatformJavaPair<F, S>.component1() = first 849 """ 850 ), 851 androidxNonNullSource, 852 androidxNullableSource, 853 ), 854 api = 855 """ 856 // Signature format: 4.0 857 package androidx.util { 858 public class NonNullableJavaPair<F, S> { 859 ctor public NonNullableJavaPair(F, S); 860 field public final F first; 861 field public final S second; 862 } 863 public final class NonNullableKotlinPair<F, S> { 864 ctor public NonNullableKotlinPair(F first, S second); 865 method public F getFirst(); 866 method public S getSecond(); 867 property public F first; 868 property public S second; 869 } 870 public class NullableJavaPair<F, S> { 871 ctor public NullableJavaPair(F?, S?); 872 field public final F? first; 873 field public final S? second; 874 } 875 public final class NullableKotlinPair<F, S> { 876 ctor public NullableKotlinPair(F? first, S? second); 877 method public F? getFirst(); 878 method public S? getSecond(); 879 property public F? first; 880 property public S? second; 881 } 882 public class PlatformJavaPair<F, S> { 883 ctor public PlatformJavaPair(F!, S!); 884 field public final F! first; 885 field public final S! second; 886 } 887 public final class TestKt { 888 method public static inline operator <F, S> F! component1(androidx.util.PlatformJavaPair<F,S>); 889 } 890 } 891 """, 892 ) 893 } 894 895 @RequiresCapabilities(Capability.KOTLIN) 896 @Test Known nullnessnull897 fun `Known nullness`() { 898 // Don't emit platform types for some unannotated elements that we know the 899 // nullness for: annotation type members, equals-parameters, initialized constants, etc. 900 check( 901 format = FileFormat.V4, 902 sourceFiles = 903 arrayOf( 904 java( 905 """ 906 // Platform nullability Pair in Java 907 package test; 908 909 import androidx.annotation.NonNull; 910 911 public class MyClass { 912 public static final String MY_CONSTANT1 = "constant"; // Not nullable 913 public final String MY_CONSTANT2 = "constant"; // Not nullable 914 public String MY_CONSTANT3 = "constant"; // Unknown 915 916 /** @deprecated */ 917 @Deprecated 918 @Override 919 public boolean equals( 920 Object parameter // nullable 921 ) { 922 return super.equals(parameter); 923 } 924 925 /** @deprecated */ 926 @Deprecated 927 @Override // Not nullable 928 public String toString() { 929 return super.toString(); 930 } 931 } 932 """ 933 ), 934 java( 935 """ 936 package test.pkg; 937 938 import static java.lang.annotation.ElementType.*; 939 import java.lang.annotation.*; 940 public @interface MyAnnotation { 941 String[] value(); // Not nullable 942 } 943 """ 944 ) 945 .indented(), 946 java( 947 """ 948 package test.pkg; 949 @SuppressWarnings("ALL") 950 public enum Foo { 951 A, B; 952 } 953 """ 954 ), 955 kotlin( 956 """ 957 package test.pkg 958 enum class Language { 959 KOTLIN, 960 JAVA 961 } 962 """ 963 ) 964 .indented(), 965 kotlin( 966 """ 967 package test.pkg 968 class Issue { 969 fun setAndroidSpecific(value: Boolean): Issue { return this } 970 companion object { 971 @JvmStatic 972 fun create( 973 id: String, 974 briefDescription: String, 975 explanation: String 976 ): Issue { 977 return Issue() 978 } 979 } 980 } 981 """ 982 ) 983 .indented(), 984 kotlin( 985 """ 986 package test.pkg 987 object MySingleton { 988 } 989 """ 990 ) 991 .indented(), 992 java( 993 """ 994 package test.pkg; 995 public class WrongCallDetector { 996 public static final Issue ISSUE = 997 Issue.create( 998 "WrongCall", 999 "Using wrong draw/layout method", 1000 "Custom views typically need to call `measure()`) 1001 .setAndroidSpecific(true)); 1002 } 1003 """ 1004 ) 1005 .indented(), 1006 androidxNonNullSource, 1007 androidxNullableSource, 1008 ), 1009 api = 1010 """ 1011 // Signature format: 4.0 1012 package test { 1013 public class MyClass { 1014 ctor public MyClass(); 1015 method @Deprecated public boolean equals(Object?); 1016 method @Deprecated public String toString(); 1017 field public static final String MY_CONSTANT1 = "constant"; 1018 field public final String MY_CONSTANT2 = "constant"; 1019 field public String! MY_CONSTANT3; 1020 } 1021 } 1022 package test.pkg { 1023 public enum Foo { 1024 enum_constant public static final test.pkg.Foo A; 1025 enum_constant public static final test.pkg.Foo B; 1026 } 1027 public final class Issue { 1028 ctor public Issue(); 1029 method public static test.pkg.Issue create(String id, String briefDescription, String explanation); 1030 method public test.pkg.Issue setAndroidSpecific(boolean value); 1031 field public static final test.pkg.Issue.Companion Companion; 1032 } 1033 public static final class Issue.Companion { 1034 method public test.pkg.Issue create(String id, String briefDescription, String explanation); 1035 } 1036 public enum Language { 1037 enum_constant public static final test.pkg.Language JAVA; 1038 enum_constant public static final test.pkg.Language KOTLIN; 1039 } 1040 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface MyAnnotation { 1041 method public abstract String[] value(); 1042 } 1043 public final class MySingleton { 1044 field public static final test.pkg.MySingleton INSTANCE; 1045 } 1046 public class WrongCallDetector { 1047 ctor public WrongCallDetector(); 1048 field public static final test.pkg.Issue ISSUE; 1049 } 1050 } 1051 """, 1052 extraArguments = arrayOf(ARG_KOTLIN_SOURCE, "1.8") 1053 ) 1054 } 1055 1056 @RequiresCapabilities(Capability.KOTLIN) 1057 @Test JvmOverloadsnull1058 fun JvmOverloads() { 1059 // Regression test for https://github.com/android/android-ktx/issues/366 1060 check( 1061 format = FileFormat.V4, 1062 sourceFiles = 1063 arrayOf( 1064 kotlin( 1065 """ 1066 package androidx.content 1067 1068 import android.annotation.SuppressLint 1069 import android.content.SharedPreferences 1070 1071 @SuppressLint("ApplySharedPref") 1072 @JvmOverloads 1073 inline fun SharedPreferences.edit( 1074 commit: Boolean = false, 1075 action: SharedPreferences.Editor.() -> Unit 1076 ) { 1077 val editor = edit() 1078 action(editor) 1079 if (commit) { 1080 editor.commit() 1081 } else { 1082 editor.apply() 1083 } 1084 } 1085 1086 @JvmOverloads 1087 fun String.blahblahblah(firstArg: String = "hello", secondArg: Int = 42, thirdArg: String = "world") { 1088 } 1089 """ 1090 ), 1091 ), 1092 api = 1093 """ 1094 // Signature format: 4.0 1095 package androidx.content { 1096 public final class TestKt { 1097 method public static void blahblahblah(String); 1098 method public static void blahblahblah(String, optional String firstArg); 1099 method public static void blahblahblah(String, optional String firstArg, optional int secondArg); 1100 method public static void blahblahblah(String, optional String firstArg, optional int secondArg, optional String thirdArg); 1101 method public static inline void edit(android.content.SharedPreferences, optional boolean commit, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action); 1102 method public static inline void edit(android.content.SharedPreferences, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action); 1103 } 1104 } 1105 """, 1106 ) 1107 } 1108 1109 @RequiresCapabilities(Capability.KOTLIN) 1110 @Test Test JvmStaticnull1111 fun `Test JvmStatic`() { 1112 check( 1113 sourceFiles = 1114 arrayOf( 1115 kotlin( 1116 """ 1117 package test.pkg 1118 1119 class SimpleClass { 1120 companion object { 1121 @JvmStatic 1122 fun jvmStaticMethod() {} 1123 fun nonJvmStaticMethod() {} 1124 } 1125 } 1126 """ 1127 ) 1128 ), 1129 format = FileFormat.V4, 1130 api = 1131 """ 1132 // Signature format: 4.0 1133 package test.pkg { 1134 public final class SimpleClass { 1135 ctor public SimpleClass(); 1136 method public static void jvmStaticMethod(); 1137 field public static final test.pkg.SimpleClass.Companion Companion; 1138 } 1139 public static final class SimpleClass.Companion { 1140 method public void jvmStaticMethod(); 1141 method public void nonJvmStaticMethod(); 1142 } 1143 } 1144 """ 1145 ) 1146 } 1147 1148 @RequiresCapabilities(Capability.KOTLIN) 1149 @Test Test JvmFieldnull1150 fun `Test JvmField`() { 1151 check( 1152 sourceFiles = 1153 arrayOf( 1154 kotlin( 1155 """ 1156 package test.pkg 1157 1158 class SimpleClass { 1159 @JvmField 1160 var jvmField = -1 1161 1162 var nonJvmField = -2 1163 } 1164 """ 1165 ) 1166 ), 1167 format = FileFormat.V4, 1168 api = 1169 """ 1170 // Signature format: 4.0 1171 package test.pkg { 1172 public final class SimpleClass { 1173 ctor public SimpleClass(); 1174 method public int getNonJvmField(); 1175 method public void setNonJvmField(int); 1176 property public int jvmField; 1177 property public int nonJvmField; 1178 field public int jvmField; 1179 } 1180 } 1181 """ 1182 ) 1183 } 1184 1185 @RequiresCapabilities(Capability.KOTLIN) 1186 @Test Test JvmNamenull1187 fun `Test JvmName`() { 1188 check( 1189 sourceFiles = 1190 arrayOf( 1191 kotlin( 1192 """ 1193 package test.pkg 1194 1195 class SimpleClass { 1196 @get:JvmName("myPropertyJvmGetter") 1197 var myProperty = -1 1198 1199 var anotherProperty = -1 1200 } 1201 """ 1202 ) 1203 ), 1204 format = FileFormat.V4, 1205 api = 1206 """ 1207 // Signature format: 4.0 1208 package test.pkg { 1209 public final class SimpleClass { 1210 ctor public SimpleClass(); 1211 method public int getAnotherProperty(); 1212 method public int myPropertyJvmGetter(); 1213 method public void setAnotherProperty(int); 1214 method public void setMyProperty(int); 1215 property public int anotherProperty; 1216 property public int myProperty; 1217 } 1218 } 1219 """ 1220 ) 1221 } 1222 1223 @RequiresCapabilities(Capability.KOTLIN) 1224 @Test Test RequiresOptIn and OptInnull1225 fun `Test RequiresOptIn and OptIn`() { 1226 check( 1227 sourceFiles = 1228 arrayOf( 1229 kotlin( 1230 """ 1231 package test.pkg 1232 1233 @RequiresOptIn 1234 @Retention(AnnotationRetention.BINARY) 1235 @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) 1236 annotation class ExperimentalBar 1237 1238 @ExperimentalBar 1239 class FancyBar 1240 1241 @OptIn(FancyBar::class) // @OptIn should not be tracked as it is not API 1242 class SimpleClass { 1243 fun methodUsingFancyBar() { 1244 val fancyBar = FancyBar() 1245 } 1246 } 1247 """ 1248 ) 1249 ), 1250 format = FileFormat.V4, 1251 api = 1252 """ 1253 // Signature format: 4.0 1254 package test.pkg { 1255 @SuppressCompatibility @kotlin.RequiresOptIn @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public @interface ExperimentalBar { 1256 } 1257 @SuppressCompatibility @test.pkg.ExperimentalBar public final class FancyBar { 1258 ctor public FancyBar(); 1259 } 1260 public final class SimpleClass { 1261 ctor public SimpleClass(); 1262 method public void methodUsingFancyBar(); 1263 } 1264 } 1265 """, 1266 suppressCompatibilityMetaAnnotations = arrayOf("kotlin.RequiresOptIn") 1267 ) 1268 } 1269 1270 @Test Extract class with genericsnull1271 fun `Extract class with generics`() { 1272 // Basic interface with generics; makes sure <T extends Object> is written as just <T> 1273 // Also include some more complex generics expressions to make sure they're serialized 1274 // correctly (in particular, using fully qualified names instead of what appears in 1275 // the source code.) 1276 check( 1277 format = FileFormat.V2, 1278 sourceFiles = 1279 arrayOf( 1280 java( 1281 """ 1282 package test.pkg; 1283 @SuppressWarnings("ALL") 1284 public interface MyInterface<T extends Object> 1285 extends MyBaseInterface { 1286 } 1287 """ 1288 ), 1289 java( 1290 """ 1291 package a.b.c; 1292 @SuppressWarnings("ALL") 1293 public interface MyStream<T, S extends MyStream<T, S>> extends test.pkg.AutoCloseable { 1294 } 1295 """ 1296 ), 1297 java( 1298 """ 1299 package test.pkg; 1300 @SuppressWarnings("ALL") 1301 public interface MyInterface2<T extends Number> 1302 extends MyBaseInterface { 1303 class TtsSpan<C extends MyInterface<?>> { } 1304 abstract class Range<T extends Comparable<? super T>> { 1305 protected String myString; 1306 } 1307 } 1308 """ 1309 ), 1310 java( 1311 """ 1312 package test.pkg; 1313 public interface MyBaseInterface { 1314 void fun(int a, String b); 1315 } 1316 """ 1317 ), 1318 java( 1319 """ 1320 package test.pkg; 1321 public interface MyOtherInterface extends MyBaseInterface, AutoCloseable { 1322 void fun(int a, String b); 1323 } 1324 """ 1325 ), 1326 java( 1327 """ 1328 package test.pkg; 1329 public interface AutoCloseable { 1330 } 1331 """ 1332 ) 1333 ), 1334 api = 1335 """ 1336 package a.b.c { 1337 public interface MyStream<T, S extends a.b.c.MyStream<T, S>> extends test.pkg.AutoCloseable { 1338 } 1339 } 1340 package test.pkg { 1341 public interface AutoCloseable { 1342 } 1343 public interface MyBaseInterface { 1344 method public void fun(int, String); 1345 } 1346 public interface MyInterface<T> extends test.pkg.MyBaseInterface { 1347 } 1348 public interface MyInterface2<T extends java.lang.Number> extends test.pkg.MyBaseInterface { 1349 } 1350 public abstract static class MyInterface2.Range<T extends java.lang.Comparable<? super T>> { 1351 ctor public MyInterface2.Range(); 1352 field protected String myString; 1353 } 1354 public static class MyInterface2.TtsSpan<C extends test.pkg.MyInterface<?>> { 1355 ctor public MyInterface2.TtsSpan(); 1356 } 1357 public interface MyOtherInterface extends test.pkg.MyBaseInterface test.pkg.AutoCloseable { 1358 } 1359 } 1360 """, 1361 extraArguments = arrayOf(ARG_HIDE, "KotlinKeyword") 1362 ) 1363 } 1364 1365 @Test Basic class without default constructor, has constructors with argsnull1366 fun `Basic class without default constructor, has constructors with args`() { 1367 // Class without private constructors (shouldn't insert default constructor) 1368 check( 1369 sourceFiles = 1370 arrayOf( 1371 java( 1372 """ 1373 package test.pkg; 1374 public class Foo { 1375 public Foo(int i) { 1376 1377 } 1378 public Foo(int i, int j) { 1379 } 1380 } 1381 """ 1382 ) 1383 ), 1384 api = 1385 """ 1386 package test.pkg { 1387 public class Foo { 1388 ctor public Foo(int); 1389 ctor public Foo(int, int); 1390 } 1391 } 1392 """ 1393 ) 1394 } 1395 1396 @Test Basic class without default constructor, has private constructornull1397 fun `Basic class without default constructor, has private constructor`() { 1398 // Class without private constructors; no default constructor should be inserted 1399 check( 1400 sourceFiles = 1401 arrayOf( 1402 java( 1403 """ 1404 package test.pkg; 1405 @SuppressWarnings("ALL") 1406 public class Foo { 1407 private Foo() { 1408 } 1409 } 1410 """ 1411 ) 1412 ), 1413 api = 1414 """ 1415 package test.pkg { 1416 public class Foo { 1417 } 1418 } 1419 """ 1420 ) 1421 } 1422 1423 @Test Interface class extractionnull1424 fun `Interface class extraction`() { 1425 // Interface: makes sure the right modifiers etc are shown (and that "package private" 1426 // methods 1427 // in the interface are taken to be public etc) 1428 check( 1429 format = FileFormat.V2, 1430 sourceFiles = 1431 arrayOf( 1432 java( 1433 """ 1434 package test.pkg; 1435 @SuppressWarnings("ALL") 1436 public interface Foo { 1437 void foo(); 1438 } 1439 """ 1440 ) 1441 ), 1442 api = 1443 """ 1444 package test.pkg { 1445 public interface Foo { 1446 method public void foo(); 1447 } 1448 } 1449 """ 1450 ) 1451 } 1452 1453 @Test Enum class extractionnull1454 fun `Enum class extraction`() { 1455 check( 1456 format = FileFormat.V2, 1457 sourceFiles = 1458 arrayOf( 1459 java( 1460 """ 1461 package test.pkg; 1462 @SuppressWarnings("ALL") 1463 public enum Foo { 1464 A, B; 1465 } 1466 """ 1467 ) 1468 ), 1469 api = 1470 """ 1471 package test.pkg { 1472 public enum Foo { 1473 enum_constant public static final test.pkg.Foo A; 1474 enum_constant public static final test.pkg.Foo B; 1475 } 1476 } 1477 """ 1478 ) 1479 } 1480 1481 @Test Enum class -- javanull1482 fun `Enum class -- java`() { 1483 check( 1484 sourceFiles = 1485 arrayOf( 1486 java( 1487 """ 1488 package test.pkg; 1489 @SuppressWarnings("ALL") 1490 public enum Foo { 1491 A, B; 1492 } 1493 """ 1494 ) 1495 ), 1496 api = 1497 """ 1498 package test.pkg { 1499 public enum Foo { 1500 enum_constant public static final test.pkg.Foo A; 1501 enum_constant public static final test.pkg.Foo B; 1502 } 1503 } 1504 """ 1505 ) 1506 } 1507 1508 @RequiresCapabilities(Capability.KOTLIN) 1509 @Test Enum class -- ktnull1510 fun `Enum class -- kt`() { 1511 check( 1512 sourceFiles = 1513 arrayOf( 1514 kotlin( 1515 """ 1516 package test.pkg 1517 enum class Foo { 1518 A, B; 1519 } 1520 """ 1521 ) 1522 ), 1523 api = 1524 """ 1525 package test.pkg { 1526 public enum Foo { 1527 enum_constant public static final test.pkg.Foo A; 1528 enum_constant public static final test.pkg.Foo B; 1529 } 1530 } 1531 """, 1532 extraArguments = arrayOf(ARG_KOTLIN_SOURCE, "1.8") 1533 ) 1534 } 1535 1536 @Test Annotation class extractionnull1537 fun `Annotation class extraction`() { 1538 // Interface: makes sure the right modifiers etc are shown (and that "package private" 1539 // methods 1540 // in the interface are taken to be public etc) 1541 check( 1542 sourceFiles = 1543 arrayOf( 1544 java( 1545 """ 1546 package test.pkg; 1547 @SuppressWarnings("ALL") 1548 public @interface Foo { 1549 String value(); 1550 } 1551 """ 1552 ), 1553 java( 1554 """ 1555 package android.annotation; 1556 import static java.lang.annotation.ElementType.*; 1557 import java.lang.annotation.*; 1558 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) 1559 @Retention(RetentionPolicy.CLASS) 1560 @SuppressWarnings("ALL") 1561 public @interface SuppressLint { 1562 String[] value(); 1563 } 1564 """ 1565 ) 1566 ), 1567 // Override default to emit android.annotation classes. 1568 skipEmitPackages = emptyList(), 1569 api = 1570 """ 1571 package android.annotation { 1572 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE}) public @interface SuppressLint { 1573 method public abstract String[] value(); 1574 } 1575 } 1576 package test.pkg { 1577 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface Foo { 1578 method public abstract String value(); 1579 } 1580 } 1581 """ 1582 ) 1583 } 1584 1585 @Test Skip inherited package private methods from private parentsnull1586 fun `Skip inherited package private methods from private parents`() { 1587 // Include public methods from hidden parents too. 1588 // Real life example: StringBuilder.setLength 1589 check( 1590 expectedIssues = 1591 """ 1592 src/test/pkg/PublicSuper.java:3: error: isContiguous cannot be hidden and abstract when PublicSuper has a visible constructor, in case a third-party attempts to subclass it. [HiddenAbstractMethod] 1593 """, 1594 expectedFail = DefaultLintErrorMessage, 1595 sourceFiles = 1596 arrayOf( 1597 java( 1598 """ 1599 package test.pkg; 1600 public class MyStringBuilder<A,B> extends AbstractMyStringBuilder<A,B> { 1601 } 1602 """ 1603 ), 1604 java( 1605 """ 1606 package test.pkg; 1607 class AbstractMyStringBuilder<C,D> extends PublicSuper<C,D> { 1608 public void setLength(int length) { 1609 } 1610 @Override boolean isContiguous() { 1611 return true; 1612 } 1613 @Override boolean concrete() { 1614 return false; 1615 } 1616 } 1617 """ 1618 ), 1619 java( 1620 """ 1621 package test.pkg; 1622 public class PublicSuper<E,F> { 1623 abstract boolean isContiguous(); 1624 boolean concrete() { 1625 return false; 1626 } 1627 } 1628 """ 1629 ) 1630 ), 1631 api = 1632 """ 1633 package test.pkg { 1634 public class MyStringBuilder<A, B> extends test.pkg.PublicSuper<A!,B!> { 1635 ctor public MyStringBuilder(); 1636 method public void setLength(int); 1637 } 1638 public class PublicSuper<E, F> { 1639 ctor public PublicSuper(); 1640 } 1641 } 1642 """ 1643 ) 1644 } 1645 1646 @Test Superclass signature extractionnull1647 fun `Superclass signature extraction`() { 1648 // Make sure superclass statement is correct; inherited method from parent that has same 1649 // signature isn't included in the child 1650 check( 1651 sourceFiles = 1652 arrayOf( 1653 java( 1654 """ 1655 package test.pkg; 1656 @SuppressWarnings("ALL") 1657 public class Foo extends Super { 1658 @Override public void base() { } 1659 public void child() { } 1660 } 1661 """ 1662 ), 1663 java( 1664 """ 1665 package test.pkg; 1666 @SuppressWarnings("ALL") 1667 public class Super { 1668 public void base() { } 1669 } 1670 """ 1671 ) 1672 ), 1673 api = 1674 """ 1675 package test.pkg { 1676 public class Foo extends test.pkg.Super { 1677 ctor public Foo(); 1678 method public void child(); 1679 } 1680 public class Super { 1681 ctor public Super(); 1682 method public void base(); 1683 } 1684 } 1685 """ 1686 ) 1687 } 1688 1689 @Test Extract fields with types and initial valuesnull1690 fun `Extract fields with types and initial values`() { 1691 check( 1692 format = FileFormat.V2, 1693 sourceFiles = 1694 arrayOf( 1695 java( 1696 """ 1697 package test.pkg; 1698 @SuppressWarnings("ALL") 1699 public class Foo { 1700 private int hidden = 1; 1701 int hidden2 = 2; 1702 /** @hide */ 1703 int hidden3 = 3; 1704 1705 protected int field00; // No value 1706 public static final boolean field01 = true; 1707 public static final int field02 = 42; 1708 public static final long field03 = 42L; 1709 public static final short field04 = 5; 1710 public static final byte field05 = 5; 1711 public static final char field06 = 'c'; 1712 public static final float field07 = 98.5f; 1713 public static final double field08 = 98.5; 1714 public static final String field09 = "String with \"escapes\" and \u00a9..."; 1715 public static final double field10 = Double.NaN; 1716 public static final double field11 = Double.POSITIVE_INFINITY; 1717 1718 public static final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef"; 1719 public static final char HEX_INPUT = 61184; 1720 } 1721 """ 1722 ) 1723 ), 1724 api = 1725 """ 1726 package test.pkg { 1727 public class Foo { 1728 ctor public Foo(); 1729 field public static final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef"; 1730 field public static final char HEX_INPUT = 61184; // 0xef00 '\uef00' 1731 field protected int field00; 1732 field public static final boolean field01 = true; 1733 field public static final int field02 = 42; // 0x2a 1734 field public static final long field03 = 42L; // 0x2aL 1735 field public static final short field04 = 5; // 0x5 1736 field public static final byte field05 = 5; // 0x5 1737 field public static final char field06 = 99; // 0x0063 'c' 1738 field public static final float field07 = 98.5f; 1739 field public static final double field08 = 98.5; 1740 field public static final String field09 = "String with \"escapes\" and \u00a9..."; 1741 field public static final double field10 = (0.0/0.0); 1742 field public static final double field11 = (1.0/0.0); 1743 } 1744 } 1745 """ 1746 ) 1747 } 1748 1749 @Test Check all modifiersnull1750 fun `Check all modifiers`() { 1751 // Include as many modifiers as possible to see which ones are included 1752 // in the signature files, and the expected sorting order. 1753 // Note that the signature files treat "deprecated" as a fake modifier. 1754 // Note also how the "protected" modifier on the interface method gets 1755 // promoted to public. 1756 check( 1757 format = FileFormat.V2, 1758 sourceFiles = 1759 arrayOf( 1760 java( 1761 """ 1762 package test.pkg; 1763 1764 @SuppressWarnings("ALL") 1765 public abstract class Foo { 1766 @Deprecated private static final long field1 = 5; 1767 @Deprecated private static volatile long field2 = 5; 1768 @Deprecated public static strictfp final synchronized void method1() { } 1769 @Deprecated public static final synchronized native void method2(); 1770 @Deprecated protected static final class Inner1 { } 1771 @Deprecated protected static abstract class Inner2 { } 1772 @Deprecated protected interface Inner3 { 1773 default void method3() { } 1774 static void method4(final int arg) { } 1775 } 1776 } 1777 """ 1778 ) 1779 ), 1780 expectedIssues = 1781 """ 1782 src/test/pkg/Foo.java:7: error: Method test.pkg.Foo.method1(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match [DeprecationMismatch] 1783 src/test/pkg/Foo.java:8: error: Method test.pkg.Foo.method2(): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match [DeprecationMismatch] 1784 src/test/pkg/Foo.java:9: error: Class test.pkg.Foo.Inner1: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match [DeprecationMismatch] 1785 src/test/pkg/Foo.java:10: error: Class test.pkg.Foo.Inner2: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match [DeprecationMismatch] 1786 src/test/pkg/Foo.java:11: error: Class test.pkg.Foo.Inner3: @Deprecated annotation (present) and @deprecated doc tag (not present) do not match [DeprecationMismatch] 1787 """, 1788 expectedFail = DefaultLintErrorMessage, 1789 api = 1790 """ 1791 package test.pkg { 1792 public abstract class Foo { 1793 ctor public Foo(); 1794 method @Deprecated public static final void method1(); 1795 method @Deprecated public static final void method2(); 1796 } 1797 @Deprecated protected static final class Foo.Inner1 { 1798 ctor @Deprecated protected Foo.Inner1(); 1799 } 1800 @Deprecated protected abstract static class Foo.Inner2 { 1801 ctor @Deprecated protected Foo.Inner2(); 1802 } 1803 @Deprecated protected static interface Foo.Inner3 { 1804 method @Deprecated public default void method3(); 1805 method @Deprecated public static void method4(int); 1806 } 1807 } 1808 """ 1809 ) 1810 } 1811 1812 @Test Package with only hidden classes should be removed from signature filesnull1813 fun `Package with only hidden classes should be removed from signature files`() { 1814 // Checks that if we have packages that are hidden, or contain only hidden or doconly 1815 // classes, the entire package is omitted from the signature file. Note how the 1816 // test.pkg1.sub 1817 // package is not marked @hide, but doclava now treats subpackages of a hidden package 1818 // as also hidden. 1819 check( 1820 sourceFiles = 1821 arrayOf( 1822 java( 1823 """ 1824 ${"/** @hide hidden package */" /* avoid dangling javadoc warning */} 1825 package test.pkg1; 1826 """ 1827 ), 1828 java( 1829 """ 1830 package test.pkg1; 1831 @SuppressWarnings("ALL") 1832 public class Foo { 1833 // Hidden by package hide 1834 } 1835 """ 1836 ), 1837 java( 1838 """ 1839 package test.pkg2; 1840 /** @hide hidden class in this package */ 1841 @SuppressWarnings("ALL") 1842 public class Bar { 1843 } 1844 """ 1845 ), 1846 java( 1847 """ 1848 package test.pkg2; 1849 /** @doconly hidden class in this package */ 1850 @SuppressWarnings("ALL") 1851 public class Baz { 1852 } 1853 """ 1854 ), 1855 java( 1856 """ 1857 package test.pkg1.sub; 1858 // Hidden by @hide in package above 1859 @SuppressWarnings("ALL") 1860 public class Test { 1861 } 1862 """ 1863 ), 1864 java( 1865 """ 1866 package test.pkg3; 1867 // The only really visible class 1868 @SuppressWarnings("ALL") 1869 public class Boo { 1870 } 1871 """ 1872 ) 1873 ), 1874 api = 1875 """ 1876 package test.pkg3 { 1877 public class Boo { 1878 ctor public Boo(); 1879 } 1880 } 1881 """ 1882 ) 1883 } 1884 1885 @Test Enums can be abstractnull1886 fun `Enums can be abstract`() { 1887 // As per https://bugs.openjdk.java.net/browse/JDK-6287639 1888 // abstract methods in enums should not be listed as abstract, 1889 // but doclava1 does, so replicate this. 1890 // Also checks that we handle both enum fields and regular fields 1891 // and that they are listed separately. 1892 1893 check( 1894 format = FileFormat.V2, 1895 sourceFiles = 1896 arrayOf( 1897 java( 1898 """ 1899 package test.pkg; 1900 1901 @SuppressWarnings("ALL") 1902 public enum FooBar { 1903 ABC { 1904 @Override 1905 protected void foo() { } 1906 }, DEF { 1907 @Override 1908 protected void foo() { } 1909 }; 1910 1911 protected abstract void foo(); 1912 public static int field1 = 1; 1913 public int field2 = 2; 1914 } 1915 """ 1916 ) 1917 ), 1918 api = 1919 """ 1920 package test.pkg { 1921 public enum FooBar { 1922 method protected abstract void foo(); 1923 enum_constant public static final test.pkg.FooBar ABC; 1924 enum_constant public static final test.pkg.FooBar DEF; 1925 field public static int field1; 1926 field public int field2; 1927 } 1928 } 1929 """ 1930 ) 1931 } 1932 1933 @Test Check correct throws list for genericsnull1934 fun `Check correct throws list for generics`() { 1935 check( 1936 format = FileFormat.V2, 1937 sourceFiles = 1938 arrayOf( 1939 java( 1940 """ 1941 package test.pkg; 1942 1943 import java.util.function.Supplier; 1944 1945 @SuppressWarnings("ALL") 1946 public final class Test<T> { 1947 public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { 1948 return null; 1949 } 1950 } 1951 """ 1952 ) 1953 ), 1954 api = 1955 """ 1956 package test.pkg { 1957 public final class Test<T> { 1958 ctor public Test(); 1959 method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws X; 1960 } 1961 } 1962 """ 1963 ) 1964 } 1965 1966 @Test Check various generics signature subtletiesnull1967 fun `Check various generics signature subtleties`() { 1968 // Some additional declarations where PSI default type handling diffs from doclava1 1969 check( 1970 format = FileFormat.V2, 1971 sourceFiles = 1972 arrayOf( 1973 java( 1974 """ 1975 package test.pkg; 1976 1977 @SuppressWarnings("ALL") 1978 public abstract class Collections { 1979 public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T> collection) { 1980 return null; 1981 } 1982 public abstract <T extends java.util.Collection<java.lang.String>> T addAllTo(T t); 1983 public final class Range<T extends java.lang.Comparable<? super T>> { } 1984 } 1985 """ 1986 ), 1987 java( 1988 """ 1989 package test.pkg; 1990 1991 import java.util.Set; 1992 1993 @SuppressWarnings("ALL") 1994 public class MoreAsserts { 1995 public static void assertEquals(String arg0, Set<? extends Object> arg1, Set<? extends Object> arg2) { } 1996 public static void assertEquals(Set<? extends Object> arg1, Set<? extends Object> arg2) { } 1997 } 1998 1999 """ 2000 ) 2001 ), 2002 api = 2003 """ 2004 package test.pkg { 2005 public abstract class Collections { 2006 ctor public Collections(); 2007 method public abstract <T extends java.util.Collection<java.lang.String>> T addAllTo(T); 2008 method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>); 2009 } 2010 public final class Collections.Range<T extends java.lang.Comparable<? super T>> { 2011 ctor public Collections.Range(); 2012 } 2013 public class MoreAsserts { 2014 ctor public MoreAsserts(); 2015 method public static void assertEquals(String, java.util.Set<?>, java.util.Set<?>); 2016 method public static void assertEquals(java.util.Set<?>, java.util.Set<?>); 2017 } 2018 } 2019 """ 2020 ) 2021 } 2022 2023 @Test Check instance methods in enumsnull2024 fun `Check instance methods in enums`() { 2025 // Make sure that when we have instance methods in an enum they're handled 2026 // correctly (there's some special casing around enums to insert extra methods 2027 // that was broken, as exposed by ChronoUnit#toString) 2028 check( 2029 format = FileFormat.V2, 2030 sourceFiles = 2031 arrayOf( 2032 java( 2033 """ 2034 package test.pkg; 2035 2036 @SuppressWarnings("ALL") 2037 public interface TempUnit { 2038 @Override 2039 String toString(); 2040 } 2041 """ 2042 ), 2043 java( 2044 """ 2045 package test.pkg; 2046 2047 @SuppressWarnings("ALL") 2048 public enum ChronUnit implements TempUnit { 2049 C, B, A; 2050 2051 public String valueOf(int x) { 2052 return Integer.toString(x + 5); 2053 } 2054 2055 public String values(String separator) { 2056 return null; 2057 } 2058 2059 @Override 2060 public String toString() { 2061 return name(); 2062 } 2063 } 2064 """ 2065 ) 2066 ), 2067 importedPackages = emptyList(), 2068 api = 2069 """ 2070 package test.pkg { 2071 public enum ChronUnit implements test.pkg.TempUnit { 2072 method public String valueOf(int); 2073 method public String values(String); 2074 enum_constant public static final test.pkg.ChronUnit A; 2075 enum_constant public static final test.pkg.ChronUnit B; 2076 enum_constant public static final test.pkg.ChronUnit C; 2077 } 2078 public interface TempUnit { 2079 method public String toString(); 2080 } 2081 } 2082 """ 2083 ) 2084 } 2085 2086 @Test Mixing enums and fieldsnull2087 fun `Mixing enums and fields`() { 2088 // Checks sorting order of enum constant values 2089 val source = 2090 """ 2091 package java.nio.file.attribute { 2092 public enum AclEntryPermission { 2093 enum_constant public static final java.nio.file.attribute.AclEntryPermission APPEND_DATA; 2094 enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE; 2095 enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE_CHILD; 2096 enum_constant public static final java.nio.file.attribute.AclEntryPermission EXECUTE; 2097 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_ACL; 2098 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_ATTRIBUTES; 2099 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_DATA; 2100 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_NAMED_ATTRS; 2101 enum_constant public static final java.nio.file.attribute.AclEntryPermission SYNCHRONIZE; 2102 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_ACL; 2103 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_ATTRIBUTES; 2104 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_DATA; 2105 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_NAMED_ATTRS; 2106 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_OWNER; 2107 field public static final java.nio.file.attribute.AclEntryPermission ADD_FILE; 2108 field public static final java.nio.file.attribute.AclEntryPermission ADD_SUBDIRECTORY; 2109 field public static final java.nio.file.attribute.AclEntryPermission LIST_DIRECTORY; 2110 } 2111 } 2112 """ 2113 check(format = FileFormat.V2, signatureSource = source, api = source) 2114 } 2115 2116 @Test Inheriting from package private classes, package private class should be includednull2117 fun `Inheriting from package private classes, package private class should be included`() { 2118 check( 2119 sourceFiles = 2120 arrayOf( 2121 java( 2122 """ 2123 package test.pkg; 2124 @SuppressWarnings("ALL") 2125 public class MyClass extends HiddenParent { 2126 public void method1() { } 2127 } 2128 """ 2129 ), 2130 java( 2131 """ 2132 package test.pkg; 2133 @SuppressWarnings("ALL") 2134 class HiddenParent { 2135 public static final String CONSTANT = "MyConstant"; 2136 protected int mContext; 2137 public void method2() { } 2138 } 2139 """ 2140 ) 2141 ), 2142 expectedIssues = "", 2143 api = 2144 """ 2145 package test.pkg { 2146 public class MyClass { 2147 ctor public MyClass(); 2148 method public void method1(); 2149 method public void method2(); 2150 field public static final String CONSTANT = "MyConstant"; 2151 } 2152 } 2153 """ 2154 ) 2155 } 2156 2157 @Test Inheriting generic method from package private classnull2158 fun `Inheriting generic method from package private class`() { 2159 check( 2160 format = FileFormat.V2, 2161 sourceFiles = 2162 arrayOf( 2163 java( 2164 """ 2165 package test.pkg; 2166 @SuppressWarnings("ALL") 2167 public class MyClass extends HiddenParent { 2168 public void method1() { } 2169 } 2170 """ 2171 ), 2172 java( 2173 """ 2174 package test.pkg; 2175 @SuppressWarnings("ALL") 2176 class HiddenParent { 2177 public <T> T method2(T t) { } 2178 public String method3(String s) { } 2179 } 2180 """ 2181 ) 2182 ), 2183 expectedIssues = "", 2184 api = 2185 """ 2186 package test.pkg { 2187 public class MyClass { 2188 ctor public MyClass(); 2189 method public void method1(); 2190 method public <T> T method2(T); 2191 method public String method3(String); 2192 } 2193 } 2194 """ 2195 ) 2196 } 2197 2198 @Test Type substitution for generic method referencing parent type parameternull2199 fun `Type substitution for generic method referencing parent type parameter`() { 2200 // Type parameters from parent classes need to be replaced with their bounds in the child. 2201 check( 2202 format = FileFormat.V2, 2203 sourceFiles = 2204 arrayOf( 2205 java( 2206 """ 2207 package test.pkg; 2208 @SuppressWarnings("ALL") 2209 public class MyClass extends HiddenParent<String> { 2210 public void method1() { } 2211 } 2212 """ 2213 ), 2214 java( 2215 """ 2216 package test.pkg; 2217 @SuppressWarnings("ALL") 2218 class HiddenParent<T> { 2219 public T method2(T t) { } 2220 } 2221 """ 2222 ) 2223 ), 2224 expectedIssues = "", 2225 api = 2226 """ 2227 package test.pkg { 2228 public class MyClass { 2229 ctor public MyClass(); 2230 method public void method1(); 2231 method public String method2(String); 2232 } 2233 } 2234 """, 2235 extraArguments = arrayOf(ARG_HIDE, Issues.INHERIT_CHANGES_SIGNATURE.name), 2236 ) 2237 } 2238 2239 @Test Check generic type signature insertionnull2240 fun `Check generic type signature insertion`() { 2241 check( 2242 format = FileFormat.V2, 2243 sourceFiles = 2244 arrayOf( 2245 java( 2246 """ 2247 package test.pkg; 2248 public class MyClass { 2249 public <T> MyClass(Class<T> klass) { } 2250 public <U> void method1(Function<U> func) { } 2251 } 2252 """ 2253 ) 2254 ), 2255 expectedIssues = "", 2256 api = 2257 """ 2258 package test.pkg { 2259 public class MyClass { 2260 ctor public <T> MyClass(Class<T>); 2261 method public <U> void method1(Function<U>); 2262 } 2263 } 2264 """ 2265 ) 2266 } 2267 2268 @Test When implementing rather than extending package private class, inline members insteadnull2269 fun `When implementing rather than extending package private class, inline members instead`() { 2270 // If you implement a package private interface, we just remove it and inline the members 2271 // into 2272 // the subclass 2273 check( 2274 sourceFiles = 2275 arrayOf( 2276 java( 2277 """ 2278 package test.pkg; 2279 public class MyClass implements HiddenInterface { 2280 @Override public void method() { } 2281 @Override public void other() { } 2282 } 2283 """ 2284 ), 2285 java( 2286 """ 2287 package test.pkg; 2288 public interface OtherInterface { 2289 void other(); 2290 } 2291 """ 2292 ), 2293 java( 2294 """ 2295 package test.pkg; 2296 interface HiddenInterface extends OtherInterface { 2297 void method() { } 2298 String CONSTANT = "MyConstant"; 2299 } 2300 """ 2301 ) 2302 ), 2303 api = 2304 """ 2305 package test.pkg { 2306 public class MyClass implements test.pkg.OtherInterface { 2307 ctor public MyClass(); 2308 method public void method(); 2309 method public void other(); 2310 field public static final String CONSTANT = "MyConstant"; 2311 } 2312 public interface OtherInterface { 2313 method public void other(); 2314 } 2315 } 2316 """ 2317 ) 2318 } 2319 2320 @Test Implementing package private classnull2321 fun `Implementing package private class`() { 2322 // Include all the non-hidden public interfaces into the signature 2323 2324 // BUG: Note that we need to implement the parent 2325 check( 2326 sourceFiles = 2327 arrayOf( 2328 java( 2329 """ 2330 package test.pkg; 2331 public class MyClass implements HiddenInterface { 2332 @Override public void method() { } 2333 @Override public void other() { } 2334 } 2335 """ 2336 ), 2337 java( 2338 """ 2339 package test.pkg; 2340 public interface OtherInterface { 2341 void other(); 2342 } 2343 """ 2344 ), 2345 java( 2346 """ 2347 package test.pkg; 2348 interface HiddenInterface extends OtherInterface { 2349 void method() { } 2350 String CONSTANT = "MyConstant"; 2351 } 2352 """ 2353 ) 2354 ), 2355 api = 2356 """ 2357 package test.pkg { 2358 public class MyClass implements test.pkg.OtherInterface { 2359 ctor public MyClass(); 2360 method public void method(); 2361 method public void other(); 2362 field public static final String CONSTANT = "MyConstant"; 2363 } 2364 public interface OtherInterface { 2365 method public void other(); 2366 } 2367 } 2368 """ 2369 ) 2370 } 2371 2372 @Test Default modifiers should be omittednull2373 fun `Default modifiers should be omitted`() { 2374 // If signatures vary only by the "default" modifier in the interface, don't show it on the 2375 // implementing 2376 // class 2377 check( 2378 format = FileFormat.V2, 2379 sourceFiles = 2380 arrayOf( 2381 java( 2382 """ 2383 package test.pkg; 2384 2385 public class MyClass implements SuperInterface { 2386 @Override public void method() { } 2387 @Override public void method2() { } 2388 } 2389 """ 2390 ), 2391 java( 2392 """ 2393 package test.pkg; 2394 2395 public interface SuperInterface { 2396 void method(); 2397 default void method2() { 2398 } 2399 } 2400 """ 2401 ) 2402 ), 2403 api = 2404 """ 2405 package test.pkg { 2406 public class MyClass implements test.pkg.SuperInterface { 2407 ctor public MyClass(); 2408 method public void method(); 2409 } 2410 public interface SuperInterface { 2411 method public void method(); 2412 method public default void method2(); 2413 } 2414 } 2415 """ 2416 ) 2417 } 2418 2419 @Test Override via different throws list should be includednull2420 fun `Override via different throws list should be included`() { 2421 // If a method overrides another but changes the throws list, the overriding 2422 // method must be listed in the subclass. This is observed for example in 2423 // AbstractCursor#finalize, which omits the throws clause from Object's finalize. 2424 check( 2425 sourceFiles = 2426 arrayOf( 2427 java( 2428 """ 2429 package test.pkg; 2430 2431 public abstract class AbstractCursor extends Parent { 2432 @Override protected void finalize2() { } // note: not throws Throwable! 2433 } 2434 """ 2435 ), 2436 java( 2437 """ 2438 package test.pkg; 2439 2440 @SuppressWarnings("RedundantThrows") 2441 public class Parent { 2442 protected void finalize2() throws Throwable { 2443 } 2444 } 2445 """ 2446 ) 2447 ), 2448 api = 2449 """ 2450 package test.pkg { 2451 public abstract class AbstractCursor extends test.pkg.Parent { 2452 ctor public AbstractCursor(); 2453 method protected void finalize2(); 2454 } 2455 public class Parent { 2456 ctor public Parent(); 2457 method protected void finalize2() throws java.lang.Throwable; 2458 } 2459 } 2460 """ 2461 ) 2462 } 2463 2464 @Test Implementing interface methodnull2465 fun `Implementing interface method`() { 2466 // If you have a public method that implements an interface method, 2467 // they'll vary in the "abstract" modifier, but it shouldn't be listed on the 2468 // class. This is an issue for example for the ZonedDateTime#getLong method 2469 // implementing the TemporalAccessor#getLong method 2470 check( 2471 format = FileFormat.V2, 2472 sourceFiles = 2473 arrayOf( 2474 java( 2475 """ 2476 package test.pkg; 2477 public interface SomeInterface2 { 2478 @Override default long getLong() { 2479 return 42; 2480 } 2481 } 2482 """ 2483 ), 2484 java( 2485 """ 2486 package test.pkg; 2487 public class Foo implements SomeInterface2 { 2488 @Override 2489 public long getLong() { return 0L; } 2490 } 2491 """ 2492 ) 2493 ), 2494 api = 2495 """ 2496 package test.pkg { 2497 public class Foo implements test.pkg.SomeInterface2 { 2498 ctor public Foo(); 2499 } 2500 public interface SomeInterface2 { 2501 method public default long getLong(); 2502 } 2503 } 2504 """ 2505 ) 2506 } 2507 2508 @Test Implementing interface method 2null2509 fun `Implementing interface method 2`() { 2510 check( 2511 format = FileFormat.V2, 2512 sourceFiles = 2513 arrayOf( 2514 java( 2515 """ 2516 package test.pkg; 2517 public interface SomeInterface { 2518 long getLong(); 2519 } 2520 """ 2521 ), 2522 java( 2523 """ 2524 package test.pkg; 2525 public interface SomeInterface2 { 2526 @Override default long getLong() { 2527 return 42; 2528 } 2529 } 2530 """ 2531 ), 2532 java( 2533 """ 2534 package test.pkg; 2535 public class Foo implements SomeInterface, SomeInterface2 { 2536 @Override 2537 public long getLong() { return 0L; } 2538 } 2539 """ 2540 ) 2541 ), 2542 api = 2543 """ 2544 package test.pkg { 2545 public class Foo implements test.pkg.SomeInterface test.pkg.SomeInterface2 { 2546 ctor public Foo(); 2547 } 2548 public interface SomeInterface { 2549 method public long getLong(); 2550 } 2551 public interface SomeInterface2 { 2552 method public default long getLong(); 2553 } 2554 } 2555 """ 2556 ) 2557 } 2558 2559 @Test Check basic @remove scenariosnull2560 fun `Check basic @remove scenarios`() { 2561 // Test basic @remove handling for methods and fields 2562 check( 2563 sourceFiles = 2564 arrayOf( 2565 java( 2566 """ 2567 package test.pkg; 2568 @SuppressWarnings("JavaDoc") 2569 public class Bar { 2570 /** @removed */ 2571 public Bar() { } 2572 public int field; 2573 public void test() { } 2574 /** @removed */ 2575 public int removedField; 2576 /** @removed */ 2577 public void removedMethod() { } 2578 /** @removed and @hide - should not be listed */ 2579 public int hiddenField; 2580 2581 /** @removed */ 2582 public class Inner { } 2583 2584 public class Inner2 { 2585 public class Inner3 { 2586 /** @removed */ 2587 public class Inner4 { } 2588 } 2589 } 2590 2591 public class Inner5 { 2592 public class Inner6 { 2593 public class Inner7 { 2594 /** @removed */ 2595 public int removed; 2596 } 2597 } 2598 } 2599 } 2600 """ 2601 ) 2602 ), 2603 removedApi = 2604 """ 2605 package test.pkg { 2606 public class Bar { 2607 ctor public Bar(); 2608 method public void removedMethod(); 2609 field public int removedField; 2610 } 2611 public class Bar.Inner { 2612 ctor public Bar.Inner(); 2613 } 2614 public class Bar.Inner2.Inner3.Inner4 { 2615 ctor public Bar.Inner2.Inner3.Inner4(); 2616 } 2617 public class Bar.Inner5.Inner6.Inner7 { 2618 field public int removed; 2619 } 2620 } 2621 """ 2622 ) 2623 } 2624 2625 @Test Check @remove classnull2626 fun `Check @remove class`() { 2627 // Test removing classes 2628 check( 2629 format = FileFormat.V2, 2630 sourceFiles = 2631 arrayOf( 2632 java( 2633 """ 2634 package test.pkg; 2635 /** @removed */ 2636 @SuppressWarnings("JavaDoc") 2637 public class Foo { 2638 public void foo() { } 2639 public class Inner { 2640 } 2641 } 2642 """ 2643 ), 2644 java( 2645 """ 2646 package test.pkg; 2647 @SuppressWarnings("JavaDoc") 2648 public class Bar implements Parcelable { 2649 public int field; 2650 public void method(); 2651 2652 /** @removed */ 2653 public int removedField; 2654 /** @removed */ 2655 public void removedMethod() { } 2656 2657 public class Inner1 { 2658 } 2659 /** @removed */ 2660 public class Inner2 { 2661 } 2662 } 2663 """ 2664 ), 2665 java( 2666 """ 2667 package test.pkg; 2668 @SuppressWarnings("ALL") 2669 public interface Parcelable { 2670 void method(); 2671 } 2672 """ 2673 ) 2674 ), 2675 /* 2676 I expected this: but doclava1 doesn't do that (and we now match its behavior) 2677 package test.pkg { 2678 public class Bar { 2679 method public void removedMethod(); 2680 field public int removedField; 2681 } 2682 public class Bar.Inner2 { 2683 } 2684 public class Foo { 2685 method public void foo(); 2686 } 2687 } 2688 */ 2689 removedApi = 2690 """ 2691 package test.pkg { 2692 public class Bar implements test.pkg.Parcelable { 2693 method public void removedMethod(); 2694 field public int removedField; 2695 } 2696 public class Bar.Inner2 { 2697 ctor public Bar.Inner2(); 2698 } 2699 public class Foo { 2700 ctor public Foo(); 2701 method public void foo(); 2702 } 2703 public class Foo.Inner { 2704 ctor public Foo.Inner(); 2705 } 2706 } 2707 """ 2708 ) 2709 } 2710 2711 @Test Test include overridden @Deprecated even if annotated with @hidenull2712 fun `Test include overridden @Deprecated even if annotated with @hide`() { 2713 check( 2714 format = FileFormat.V2, 2715 sourceFiles = 2716 arrayOf( 2717 java( 2718 """ 2719 package test.pkg; 2720 @SuppressWarnings("JavaDoc") 2721 public class Child extends Parent { 2722 /** 2723 * @deprecated 2724 * @hide 2725 */ 2726 @Deprecated @Override 2727 public String toString() { 2728 return "Child"; 2729 } 2730 2731 /** 2732 * @hide 2733 */ 2734 public void hiddenApi() { 2735 } 2736 } 2737 """ 2738 ), 2739 java( 2740 """ 2741 package test.pkg; 2742 public class Parent { 2743 public String toString() { 2744 return "Parent"; 2745 } 2746 } 2747 """ 2748 ) 2749 ), 2750 api = 2751 """ 2752 package test.pkg { 2753 public class Child extends test.pkg.Parent { 2754 ctor public Child(); 2755 method @Deprecated public String toString(); 2756 } 2757 public class Parent { 2758 ctor public Parent(); 2759 } 2760 } 2761 """, 2762 ) 2763 } 2764 2765 @RequiresCapabilities(Capability.KOTLIN) 2766 @Test Test invalid class namenull2767 fun `Test invalid class name`() { 2768 // Regression test for b/73018978 2769 check( 2770 format = FileFormat.V4, 2771 sourceFiles = 2772 arrayOf( 2773 kotlin( 2774 "src/test/pkg/Foo.kt", 2775 """ 2776 @file:JvmName("-Foo") 2777 2778 package test.pkg 2779 2780 @Suppress("unused") 2781 inline fun String.printHelloWorld() { println("Hello World") } 2782 """ 2783 ) 2784 ), 2785 api = 2786 """ 2787 package test.pkg { 2788 public final class -Foo { 2789 method public static inline void printHelloWorld(String); 2790 } 2791 } 2792 """ 2793 ) 2794 } 2795 2796 @Test Indirect Field Includes from Interfacesnull2797 fun `Indirect Field Includes from Interfaces`() { 2798 // Real-world example: include ZipConstants into ZipFile and JarFile 2799 check( 2800 sourceFiles = 2801 arrayOf( 2802 java( 2803 """ 2804 package test.pkg1; 2805 interface MyConstants { 2806 long CONSTANT1 = 12345; 2807 long CONSTANT2 = 67890; 2808 long CONSTANT3 = 42; 2809 } 2810 """ 2811 ), 2812 java( 2813 """ 2814 package test.pkg1; 2815 import java.io.Closeable; 2816 @SuppressWarnings("WeakerAccess") 2817 public class MyParent implements MyConstants, Closeable { 2818 } 2819 """ 2820 ), 2821 java( 2822 """ 2823 package test.pkg2; 2824 2825 import test.pkg1.MyParent; 2826 public class MyChild extends MyParent { 2827 } 2828 """ 2829 ) 2830 ), 2831 api = 2832 """ 2833 package test.pkg1 { 2834 public class MyParent implements java.io.Closeable { 2835 ctor public MyParent(); 2836 field public static final long CONSTANT1 = 12345L; // 0x3039L 2837 field public static final long CONSTANT2 = 67890L; // 0x10932L 2838 field public static final long CONSTANT3 = 42L; // 0x2aL 2839 } 2840 } 2841 package test.pkg2 { 2842 public class MyChild extends test.pkg1.MyParent { 2843 ctor public MyChild(); 2844 field public static final long CONSTANT1 = 12345L; // 0x3039L 2845 field public static final long CONSTANT2 = 67890L; // 0x10932L 2846 field public static final long CONSTANT3 = 42L; // 0x2aL 2847 } 2848 } 2849 """ 2850 ) 2851 } 2852 2853 @Test Skip interfaces from packages explicitly hidden via argumentsnull2854 fun `Skip interfaces from packages explicitly hidden via arguments`() { 2855 // Real-world example: HttpResponseCache implements OkCacheContainer but hides the only 2856 // inherited method 2857 check( 2858 sourceFiles = 2859 arrayOf( 2860 java( 2861 """ 2862 package android.net.http; 2863 import com.squareup.okhttp.Cache; 2864 import com.squareup.okhttp.OkCacheContainer; 2865 import java.io.Closeable; 2866 import java.net.ResponseCache; 2867 @SuppressWarnings("JavaDoc") 2868 public final class HttpResponseCache implements Closeable, OkCacheContainer { 2869 /** @hide Needed for OkHttp integration. */ 2870 @Override 2871 public Cache getCache() { 2872 return delegate.getCache(); 2873 } 2874 } 2875 """ 2876 ), 2877 java( 2878 """ 2879 package com.squareup.okhttp; 2880 /** @hide */ 2881 public interface OkCacheContainer { 2882 Cache getCache(); 2883 } 2884 """ 2885 ), 2886 java( 2887 """ 2888 package com.squareup.okhttp; 2889 /** @hide */ 2890 public class Cache { 2891 } 2892 """ 2893 ) 2894 ), 2895 expectedIssues = 2896 """ 2897 src/android/net/http/HttpResponseCache.java:7: warning: Public class android.net.http.HttpResponseCache stripped of unavailable superclass com.squareup.okhttp.OkCacheContainer [HiddenSuperclass] 2898 """, 2899 api = 2900 """ 2901 package android.net.http { 2902 public final class HttpResponseCache implements java.io.Closeable { 2903 ctor public HttpResponseCache(); 2904 } 2905 } 2906 """ 2907 ) 2908 } 2909 2910 @Test Test whether partial or total orderingnull2911 fun `Test whether partial or total ordering`() { 2912 check( 2913 format = FileFormat.V2, 2914 checkCompilation = true, 2915 sourceFiles = 2916 arrayOf( 2917 java( 2918 """ 2919 package mine; 2920 2921 public interface Bar { 2922 } 2923 """ 2924 ), 2925 java( 2926 """ 2927 package other; 2928 2929 public interface Bar { 2930 } 2931 """ 2932 ), 2933 java( 2934 """ 2935 package test.pkg; 2936 public interface FooMineFirst extends mine.Bar, other.Bar { 2937 } 2938 """ 2939 ), 2940 java( 2941 """ 2942 package test.pkg; 2943 public interface FooOtherFirst extends other.Bar, mine.Bar { 2944 } 2945 """ 2946 ), 2947 ), 2948 api = 2949 """ 2950 package mine { 2951 public interface Bar { 2952 } 2953 } 2954 package other { 2955 public interface Bar { 2956 } 2957 } 2958 package test.pkg { 2959 public interface FooMineFirst extends mine.Bar other.Bar { 2960 } 2961 public interface FooOtherFirst extends other.Bar mine.Bar { 2962 } 2963 } 2964 """, 2965 ) 2966 } 2967 2968 @Test Test whether partial or total ordering - sort-whole-extends-list=yesnull2969 fun `Test whether partial or total ordering - sort-whole-extends-list=yes`() { 2970 check( 2971 format = FileFormat.V2.copy(specifiedSortWholeExtendsList = true), 2972 checkCompilation = true, 2973 sourceFiles = 2974 arrayOf( 2975 java( 2976 """ 2977 package mine; 2978 2979 public interface Bar { 2980 } 2981 """ 2982 ), 2983 java( 2984 """ 2985 package other; 2986 2987 public interface Bar { 2988 } 2989 """ 2990 ), 2991 java( 2992 """ 2993 package test.pkg; 2994 public interface FooMineFirst extends mine.Bar, other.Bar { 2995 } 2996 """ 2997 ), 2998 java( 2999 """ 3000 package test.pkg; 3001 public interface FooOtherFirst extends other.Bar, mine.Bar { 3002 } 3003 """ 3004 ), 3005 ), 3006 api = 3007 """ 3008 package mine { 3009 public interface Bar { 3010 } 3011 } 3012 package other { 3013 public interface Bar { 3014 } 3015 } 3016 package test.pkg { 3017 public interface FooMineFirst extends mine.Bar other.Bar { 3018 } 3019 public interface FooOtherFirst extends mine.Bar other.Bar { 3020 } 3021 } 3022 """, 3023 ) 3024 } 3025 3026 @Test Extend from multiple interfacesnull3027 fun `Extend from multiple interfaces`() { 3028 // Real-world example: XmlResourceParser 3029 check( 3030 format = FileFormat.V2, 3031 checkCompilation = true, 3032 sourceFiles = 3033 arrayOf( 3034 java( 3035 """ 3036 package android.content.res; 3037 import android.util.AttributeSet; 3038 import org.xmlpull.v1.XmlPullParser; 3039 import my.AutoCloseable; 3040 3041 @SuppressWarnings("UnnecessaryInterfaceModifier") 3042 public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable { 3043 public void close(); 3044 } 3045 """ 3046 ), 3047 java( 3048 """ 3049 package android.util; 3050 @SuppressWarnings("WeakerAccess") 3051 public interface AttributeSet { 3052 } 3053 """ 3054 ), 3055 java( 3056 """ 3057 package my; 3058 public interface AutoCloseable { 3059 } 3060 """ 3061 ), 3062 java( 3063 """ 3064 package org.xmlpull.v1; 3065 @SuppressWarnings("WeakerAccess") 3066 public interface XmlPullParser { 3067 } 3068 """ 3069 ) 3070 ), 3071 api = 3072 """ 3073 package android.content.res { 3074 public interface XmlResourceParser extends org.xmlpull.v1.XmlPullParser android.util.AttributeSet my.AutoCloseable { 3075 method public void close(); 3076 } 3077 } 3078 package android.util { 3079 public interface AttributeSet { 3080 } 3081 } 3082 package my { 3083 public interface AutoCloseable { 3084 } 3085 } 3086 package org.xmlpull.v1 { 3087 public interface XmlPullParser { 3088 } 3089 } 3090 """ 3091 ) 3092 } 3093 3094 @Test Extend from multiple interfaces - sort-whole-extends-list=yesnull3095 fun `Extend from multiple interfaces - sort-whole-extends-list=yes`() { 3096 // Real-world example: XmlResourceParser 3097 check( 3098 format = FileFormat.V2.copy(specifiedSortWholeExtendsList = true), 3099 checkCompilation = true, 3100 sourceFiles = 3101 arrayOf( 3102 java( 3103 """ 3104 package android.content.res; 3105 import android.util.AttributeSet; 3106 import org.xmlpull.v1.XmlPullParser; 3107 import my.AutoCloseable; 3108 3109 @SuppressWarnings("UnnecessaryInterfaceModifier") 3110 public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable { 3111 public void close(); 3112 } 3113 """ 3114 ), 3115 java( 3116 """ 3117 package android.util; 3118 @SuppressWarnings("WeakerAccess") 3119 public interface AttributeSet { 3120 } 3121 """ 3122 ), 3123 java( 3124 """ 3125 package my; 3126 public interface AutoCloseable { 3127 } 3128 """ 3129 ), 3130 java( 3131 """ 3132 package org.xmlpull.v1; 3133 @SuppressWarnings("WeakerAccess") 3134 public interface XmlPullParser { 3135 } 3136 """ 3137 ) 3138 ), 3139 api = 3140 """ 3141 package android.content.res { 3142 public interface XmlResourceParser extends android.util.AttributeSet my.AutoCloseable org.xmlpull.v1.XmlPullParser { 3143 method public void close(); 3144 } 3145 } 3146 package android.util { 3147 public interface AttributeSet { 3148 } 3149 } 3150 package my { 3151 public interface AutoCloseable { 3152 } 3153 } 3154 package org.xmlpull.v1 { 3155 public interface XmlPullParser { 3156 } 3157 } 3158 """ 3159 ) 3160 } 3161 3162 @Test Test KDoc suppressnull3163 fun `Test KDoc suppress`() { 3164 // Basic class; also checks that default constructor is made explicit 3165 check( 3166 sourceFiles = 3167 arrayOf( 3168 java( 3169 """ 3170 package test.pkg; 3171 public class Foo { 3172 private Foo() { } 3173 /** @suppress */ 3174 public void hidden() { 3175 } 3176 } 3177 """ 3178 ), 3179 java( 3180 """ 3181 package test.pkg; 3182 /** 3183 * Some comment. 3184 * @suppress 3185 */ 3186 public class Hidden { 3187 private Hidden() { } 3188 public void hidden() { 3189 } 3190 public class Inner { 3191 } 3192 } 3193 """ 3194 ) 3195 ), 3196 api = 3197 """ 3198 package test.pkg { 3199 public class Foo { 3200 } 3201 } 3202 """ 3203 ) 3204 } 3205 3206 @Test Check skipping implicit final or deprecated overridenull3207 fun `Check skipping implicit final or deprecated override`() { 3208 // Regression test for 122358225 3209 check( 3210 sourceFiles = 3211 arrayOf( 3212 java( 3213 """ 3214 package test.pkg; 3215 3216 public class Parent { 3217 public void foo1() { } 3218 public void foo2() { } 3219 public void foo3() { } 3220 public void foo4() { } 3221 } 3222 """ 3223 ), 3224 java( 3225 """ 3226 package test.pkg; 3227 3228 public final class Child1 extends Parent { 3229 private Child1() { } 3230 public final void foo1() { } 3231 public void foo2() { } 3232 } 3233 """ 3234 ), 3235 java( 3236 """ 3237 package test.pkg; 3238 3239 /** @deprecated */ 3240 @Deprecated 3241 public final class Child2 extends Parent { 3242 private Child2() { } 3243 /** @deprecated */ 3244 @Deprecated 3245 public void foo3() { } 3246 public void foo4() { } 3247 } 3248 """ 3249 ), 3250 java( 3251 """ 3252 package test.pkg; 3253 3254 /** @deprecated */ 3255 @Deprecated 3256 public final class Child3 extends Parent { 3257 private Child3() { } 3258 public final void foo1() { } 3259 public void foo2() { } 3260 /** @deprecated */ 3261 @Deprecated 3262 public void foo3() { } 3263 /** @deprecated */ 3264 @Deprecated 3265 public final void foo4() { } 3266 } 3267 """ 3268 ) 3269 ), 3270 api = 3271 """ 3272 package test.pkg { 3273 public final class Child1 extends test.pkg.Parent { 3274 } 3275 @Deprecated public final class Child2 extends test.pkg.Parent { 3276 } 3277 @Deprecated public final class Child3 extends test.pkg.Parent { 3278 } 3279 public class Parent { 3280 ctor public Parent(); 3281 method public void foo1(); 3282 method public void foo2(); 3283 method public void foo3(); 3284 method public void foo4(); 3285 } 3286 } 3287 """ 3288 ) 3289 } 3290 3291 @Test Ignore synchronized differencesnull3292 fun `Ignore synchronized differences`() { 3293 check( 3294 sourceFiles = 3295 arrayOf( 3296 java( 3297 """ 3298 package test.pkg2; 3299 3300 public class Parent { 3301 public void foo1() { } 3302 public synchronized void foo2() { } 3303 } 3304 """ 3305 ), 3306 java( 3307 """ 3308 package test.pkg2; 3309 3310 public class Child1 extends Parent { 3311 private Child1() { } 3312 public synchronized void foo1() { } 3313 public void foo2() { } 3314 } 3315 """ 3316 ) 3317 ), 3318 api = 3319 """ 3320 package test.pkg2 { 3321 public class Child1 extends test.pkg2.Parent { 3322 } 3323 public class Parent { 3324 ctor public Parent(); 3325 method public void foo1(); 3326 method public void foo2(); 3327 } 3328 } 3329 """ 3330 ) 3331 } 3332 3333 @Test Skip incorrect inheritnull3334 fun `Skip incorrect inherit`() { 3335 check( 3336 // Simulate test-mock scenario for getIContentProvider 3337 extraArguments = arrayOf("--stub-packages", "android.test.mock"), 3338 expectedIssues = 3339 "src/android/test/mock/MockContentProvider.java:6: warning: Public class android.test.mock.MockContentProvider stripped of unavailable superclass android.content.ContentProvider [HiddenSuperclass]", 3340 sourceFiles = 3341 arrayOf( 3342 java( 3343 """ 3344 package android.test.mock; 3345 3346 import android.content.ContentProvider; 3347 import android.content.IContentProvider; 3348 3349 public abstract class MockContentProvider extends ContentProvider { 3350 /** 3351 * Returns IContentProvider which calls back same methods in this class. 3352 * By overriding this class, we avoid the mechanism hidden behind ContentProvider 3353 * (IPC, etc.) 3354 * 3355 * @hide 3356 */ 3357 @Override 3358 public final IContentProvider getIContentProvider() { 3359 return mIContentProvider; 3360 } 3361 } 3362 """ 3363 ), 3364 java( 3365 """ 3366 package android.content; 3367 3368 /** @hide */ 3369 public abstract class ContentProvider { 3370 protected boolean isTemporary() { 3371 return false; 3372 } 3373 3374 // This is supposed to be @hide, but in turbine-combined/framework.jar included 3375 // by java_sdk_library like test-mock, it's not; this is what the special 3376 // flag is used to test 3377 public IContentProvider getIContentProvider() { 3378 return null; 3379 } 3380 } 3381 """ 3382 ), 3383 java( 3384 """ 3385 package android.content; 3386 import android.os.IInterface; 3387 3388 /** 3389 * The ipc interface to talk to a content provider. 3390 * @hide 3391 */ 3392 public interface IContentProvider extends IInterface { 3393 } 3394 """ 3395 ), 3396 java( 3397 """ 3398 package android.content; 3399 3400 // Not hidden. Here to make sure that we respect stub-packages 3401 // and exclude it from everything, including signatures. 3402 public class ClipData { 3403 } 3404 """ 3405 ) 3406 ), 3407 api = 3408 """ 3409 package android.test.mock { 3410 public abstract class MockContentProvider { 3411 ctor public MockContentProvider(); 3412 } 3413 } 3414 """ 3415 ) 3416 } 3417 3418 @Test References Deprecatednull3419 fun `References Deprecated`() { 3420 check( 3421 extraArguments = 3422 arrayOf(ARG_ERROR, "ReferencesDeprecated", ARG_ERROR, "ExtendsDeprecated"), 3423 expectedIssues = 3424 """ 3425 src/test/pkg/MyClass.java:2: error: Extending deprecated super class class test.pkg.DeprecatedClass from test.pkg.MyClass: this class should also be deprecated [ExtendsDeprecated] 3426 src/test/pkg/MyClass.java:2: error: Implementing interface of deprecated type test.pkg.DeprecatedInterface in test.pkg.MyClass: this class should also be deprecated [ExtendsDeprecated] 3427 src/test/pkg/MyClass.java:3: error: Parameter references deprecated type test.pkg.DeprecatedClass in test.pkg.MyClass.method1(): this method should also be deprecated [ReferencesDeprecated] 3428 src/test/pkg/MyClass.java:4: error: Return type references deprecated type test.pkg.DeprecatedInterface in test.pkg.MyClass.method2(): this method should also be deprecated [ReferencesDeprecated] 3429 """, 3430 expectedFail = DefaultLintErrorMessage, 3431 sourceFiles = 3432 arrayOf( 3433 java( 3434 """ 3435 package test.pkg; 3436 /** @deprecated */ 3437 @Deprecated 3438 public class DeprecatedClass { 3439 } 3440 """ 3441 ), 3442 java( 3443 """ 3444 package test.pkg; 3445 /** @deprecated */ 3446 @Deprecated 3447 public interface DeprecatedInterface { 3448 } 3449 """ 3450 ), 3451 java( 3452 """ 3453 package test.pkg; 3454 public class MyClass extends DeprecatedClass implements DeprecatedInterface { 3455 public void method1(DeprecatedClass p, int i) { } 3456 public DeprecatedInterface method2(int i) { return null; } 3457 3458 /** @deprecated */ 3459 @Deprecated 3460 public void method3(DeprecatedClass p, int i) { } 3461 } 3462 """ 3463 ) 3464 ) 3465 ) 3466 } 3467 3468 @Test v4 format for qualified references in typesnull3469 fun `v4 format for qualified references in types`() { 3470 check( 3471 format = FileFormat.V4, 3472 sourceFiles = 3473 arrayOf( 3474 java( 3475 """ 3476 package androidx.appcompat.app; 3477 import android.view.View; 3478 import android.view.View.OnClickListener; 3479 3480 public class ActionBarDrawerToggle { 3481 private ActionBarDrawerToggle() { } 3482 public View.OnClickListener getToolbarNavigationClickListener1() { 3483 return null; 3484 } 3485 public OnClickListener getToolbarNavigationClickListener2() { 3486 return null; 3487 } 3488 public android.view.View.OnClickListener getToolbarNavigationClickListener3() { 3489 return null; 3490 } 3491 } 3492 """ 3493 ) 3494 ), 3495 api = 3496 """ 3497 // Signature format: 4.0 3498 package androidx.appcompat.app { 3499 public class ActionBarDrawerToggle { 3500 method public android.view.View.OnClickListener! getToolbarNavigationClickListener1(); 3501 method public android.view.View.OnClickListener! getToolbarNavigationClickListener2(); 3502 method public android.view.View.OnClickListener! getToolbarNavigationClickListener3(); 3503 } 3504 } 3505 """ 3506 ) 3507 } 3508 3509 @RequiresCapabilities(Capability.KOTLIN) 3510 @Test FooKt class constructors are not publicnull3511 fun `FooKt class constructors are not public`() { 3512 check( 3513 format = FileFormat.V4, 3514 sourceFiles = 3515 arrayOf( 3516 kotlin( 3517 "src/main/java/test/pkg/Foo.kt", 3518 """ 3519 package test.pkg 3520 fun myCall() : Boolean = false 3521 class Bar 3522 """ 3523 ) 3524 ), 3525 api = 3526 """ 3527 // Signature format: 4.0 3528 package test.pkg { 3529 public final class Bar { 3530 ctor public Bar(); 3531 } 3532 public final class FooKt { 3533 method public static boolean myCall(); 3534 } 3535 } 3536 """ 3537 ) 3538 } 3539 3540 @Test Test inherited hidden methods for descendant classes - Package privatenull3541 fun `Test inherited hidden methods for descendant classes - Package private`() { 3542 check( 3543 sourceFiles = 3544 arrayOf( 3545 java( 3546 """ 3547 package test.pkg; 3548 public class Class4 extends Class3 { 3549 public void method4() { } 3550 } 3551 """ 3552 ), 3553 java( 3554 """ 3555 package test.pkg; 3556 public class Class3 extends Class2 { 3557 public void method3() { } 3558 } 3559 """ 3560 ), 3561 java( 3562 """ 3563 package test.pkg; 3564 class Class2 extends Class1 { 3565 public void method2() { } 3566 } 3567 """ 3568 ), 3569 java( 3570 """ 3571 package test.pkg; 3572 public class Class1 { 3573 public void method1() { } 3574 } 3575 """ 3576 ) 3577 ), 3578 expectedIssues = "", 3579 api = 3580 """ 3581 package test.pkg { 3582 public class Class1 { 3583 ctor public Class1(); 3584 method public void method1(); 3585 } 3586 public class Class3 extends test.pkg.Class1 { 3587 ctor public Class3(); 3588 method public void method2(); 3589 method public void method3(); 3590 } 3591 public class Class4 extends test.pkg.Class3 { 3592 ctor public Class4(); 3593 method public void method4(); 3594 } 3595 } 3596 """ 3597 ) 3598 } 3599 3600 @Test Test inherited hidden methods for descendant classes - Hidden annotationnull3601 fun `Test inherited hidden methods for descendant classes - Hidden annotation`() { 3602 check( 3603 sourceFiles = 3604 arrayOf( 3605 java( 3606 """ 3607 package test.pkg; 3608 public class Class4 extends Class3 { 3609 public void method4() { } 3610 } 3611 """ 3612 ), 3613 java( 3614 """ 3615 package test.pkg; 3616 public class Class3 extends Class2 { 3617 public void method3() { } 3618 } 3619 """ 3620 ), 3621 java( 3622 """ 3623 package test.pkg; 3624 /** @hide */ 3625 public class Class2 extends Class1 { 3626 public void method2() { } 3627 } 3628 """ 3629 ), 3630 java( 3631 """ 3632 package test.pkg; 3633 public class Class1 { 3634 public void method1() { } 3635 } 3636 """ 3637 ) 3638 ), 3639 expectedIssues = 3640 "src/test/pkg/Class3.java:2: warning: Public class test.pkg.Class3 stripped of unavailable superclass test.pkg.Class2 [HiddenSuperclass]", 3641 api = 3642 """ 3643 package test.pkg { 3644 public class Class1 { 3645 ctor public Class1(); 3646 method public void method1(); 3647 } 3648 public class Class3 extends test.pkg.Class1 { 3649 ctor public Class3(); 3650 method public void method2(); 3651 method public void method3(); 3652 } 3653 public class Class4 extends test.pkg.Class3 { 3654 ctor public Class4(); 3655 method public void method4(); 3656 } 3657 } 3658 """ 3659 ) 3660 } 3661 3662 @Test Test inherited methods that use genericsnull3663 fun `Test inherited methods that use generics`() { 3664 check( 3665 format = FileFormat.V2, 3666 sourceFiles = 3667 arrayOf( 3668 java( 3669 """ 3670 package test.pkg; 3671 import androidx.annotation.NonNull; 3672 public class Class2 extends Class1<String> { 3673 @Override 3674 public void method1(String input) { } 3675 @Override 3676 public void method2(@NonNull String input) { } 3677 } 3678 """ 3679 ), 3680 java( 3681 """ 3682 package test.pkg; 3683 import androidx.annotation.NonNull; 3684 class Class1<T> { 3685 public void method1(T input) { } 3686 public void method2(T input) { } 3687 public void method3(T input) { } 3688 @NonNull 3689 public String method4(T input) { return ""; } 3690 public T method5(@NonNull String input) { return null; } 3691 } 3692 """ 3693 ), 3694 androidxNonNullSource, 3695 ), 3696 expectedIssues = "", 3697 api = 3698 """ 3699 package test.pkg { 3700 public class Class2 { 3701 ctor public Class2(); 3702 method public void method1(String); 3703 method public void method2(@NonNull String); 3704 method public void method3(String); 3705 method @NonNull public String method4(String); 3706 method public String method5(@NonNull String); 3707 } 3708 } 3709 """, 3710 extraArguments = arrayOf(ARG_HIDE, Issues.INHERIT_CHANGES_SIGNATURE.name), 3711 ) 3712 } 3713 3714 val MERGE_TEST_SOURCE_1 = 3715 """ 3716 package test.pkg { 3717 public final class BaseClass { 3718 method public void method1(); 3719 } 3720 } 3721 """ 3722 val MERGE_TEST_SOURCE_2 = 3723 """ 3724 package test.pkg { 3725 public final class SubClass extends test.pkg.BaseClass { 3726 } 3727 } 3728 """ 3729 val MERGE_TEST_EXPECTED = 3730 """ 3731 package test.pkg { 3732 public final class BaseClass { 3733 method public void method1(); 3734 } 3735 public final class SubClass extends test.pkg.BaseClass { 3736 } 3737 } 3738 """ 3739 3740 @Test Test can merge API signature files with duplicate classes with constructorsnull3741 fun `Test can merge API signature files with duplicate classes with constructors`() { 3742 val source1 = 3743 """ 3744 package Test.pkg { 3745 public class IpcDataCache<Query, Result> { 3746 ctor public IpcDataCache(int, @NonNull String, @NonNull String, @NonNull String, @NonNull android.os.IpcDataCache.QueryHandler<Query,Result>); 3747 method public void disableForCurrentProcess(); 3748 method public static void disableForCurrentProcess(@NonNull String); 3749 method public void invalidateCache(); 3750 method public static void invalidateCache(@NonNull String, @NonNull String); 3751 method @Nullable public Result query(@NonNull Query); 3752 field public static final String MODULE_BLUETOOTH = "bluetooth"; 3753 } 3754 } 3755 """ 3756 val source2 = 3757 """ 3758 package Test.pkg { 3759 public class IpcDataCache<Query, Result> extends android.app.PropertyInvalidatedCache<Query,Result> { 3760 ctor public IpcDataCache(int, @NonNull String, @NonNull String, @NonNull String, @NonNull android.os.IpcDataCache.QueryHandler<Query,Result>); 3761 method public static void disableForCurrentProcess(@NonNull String); 3762 method public static void invalidateCache(@NonNull String, @NonNull String); 3763 field public static final String MODULE_BLUETOOTH = "bluetooth"; 3764 field public static final String MODULE_SYSTEM = "system_server"; 3765 field public static final String MODULE_TEST = "test"; 3766 } 3767 } 3768 """ 3769 val expected = 3770 """ 3771 package Test.pkg { 3772 public class IpcDataCache<Query, Result> extends android.app.PropertyInvalidatedCache<Query!,Result!> { 3773 ctor public IpcDataCache(int, String, String, String, android.os.IpcDataCache.QueryHandler<Query!,Result!>); 3774 method public void disableForCurrentProcess(); 3775 method public static void disableForCurrentProcess(String); 3776 method public void invalidateCache(); 3777 method public static void invalidateCache(String, String); 3778 method public Result? query(Query); 3779 field public static final String MODULE_BLUETOOTH = "bluetooth"; 3780 field public static final String MODULE_SYSTEM = "system_server"; 3781 field public static final String MODULE_TEST = "test"; 3782 } 3783 } 3784 """ 3785 check( 3786 signatureSources = arrayOf(source1, source2), 3787 api = expected, 3788 ) 3789 } 3790 3791 @Test Test can merge API signature files with generic type classesnull3792 fun `Test can merge API signature files with generic type classes`() { 3793 val source1 = 3794 """ 3795 package Test.pkg { 3796 public class LinkedHashMap<K, V> extends java.util.HashMap<K,V> implements java.util.Map<K,V> { 3797 ctor public LinkedHashMap(int, float); 3798 ctor public LinkedHashMap(int); 3799 ctor public LinkedHashMap(); 3800 ctor public LinkedHashMap(java.util.Map<? extends K,? extends V>); 3801 ctor public LinkedHashMap(int, float, boolean); 3802 method protected boolean removeEldestEntry(java.util.Map.Entry<K,V>); 3803 } 3804 } 3805 """ 3806 val source2 = 3807 """ 3808 package Test.pkg { 3809 public class LinkedHashMap<K, V> extends java.util.HashMap<K,V> implements java.util.Map<K,V> { 3810 method public java.util.Map.Entry<K,V> eldest(); 3811 } 3812 } 3813 """ 3814 val expected = 3815 """ 3816 package Test.pkg { 3817 public class LinkedHashMap<K, V> extends java.util.HashMap<K,V> implements java.util.Map<K,V> { 3818 ctor public LinkedHashMap(int, float); 3819 ctor public LinkedHashMap(int); 3820 ctor public LinkedHashMap(); 3821 ctor public LinkedHashMap(java.util.Map<? extends K,? extends V>); 3822 ctor public LinkedHashMap(int, float, boolean); 3823 method public java.util.Map.Entry<K,V> eldest(); 3824 method protected boolean removeEldestEntry(java.util.Map.Entry<K,V>); 3825 } 3826 } 3827 """ 3828 check( 3829 signatureSources = arrayOf(source1, source2), 3830 api = expected, 3831 format = 3832 FileFormat.V2.copy( 3833 specifiedOverloadedMethodOrder = OverloadedMethodOrder.SOURCE, 3834 ), 3835 ) 3836 } 3837 3838 @RequiresCapabilities(Capability.KOTLIN) 3839 @Test Test tracking of @Composable annotation from classpathnull3840 fun `Test tracking of @Composable annotation from classpath`() { 3841 check( 3842 format = FileFormat.V4, 3843 classpath = 3844 arrayOf( 3845 /* The following source file, compiled, then ran 3846 assertEquals("", toBase64gzip(File("path/to/test.jar"))) 3847 3848 package test.pkg 3849 @MustBeDocumented 3850 @Retention(AnnotationRetention.BINARY) 3851 @Target( 3852 AnnotationTarget.CLASS, 3853 AnnotationTarget.FUNCTION, 3854 AnnotationTarget.TYPE, 3855 AnnotationTarget.TYPE_PARAMETER, 3856 AnnotationTarget.PROPERTY 3857 ) 3858 annotation class Composable 3859 */ 3860 base64gzip( 3861 "test.jar", 3862 "" + 3863 "H4sIAAAAAAAAAAvwZmbhYmDg4GBw7DIMYwACJgYI4ARiX9cQR11PPzd9ZoYA" + 3864 "uEKDDsOwTfVM76SBCiSBWARZoa+jn6eba3CInq/bZ98zp328dfUu8nrrap07" + 3865 "c35zkMEV4wdPHz1lQjJsQieqraxAXJJaXIJiIzangRUVZKdjKFxiZ7vqLyMD" + 3866 "wwJmiPPgCp3zcwvyixOTclL1knMSi4tbg07nXQ4QsL1eaSFxa5lu65alXxw9" + 3867 "Kz2WhLyJsMzUUnqaaKkXNJV1l+86JfM+2avXG99tSj4b/4FXJ+CKqnzrjNld" + 3868 "Fh7TNiwtPm6c/u6M5Pn19+3rmCrar/O8DmrZZCL1xXtqggWXU91LTtkexfqj" + 3869 "x/c8KdwfnxUb17nuysSkG71773xnPrlU+odqcd6rEwYy19gbv8TUT7zU4RQp" + 3870 "ttzRXIorvuteddtcllm6Kq0nF1WkndnrYSCj+uFRV7fkzaK1mbfEeaI5Nfn2" + 3871 "v+P2XJP6rvJg+sXdxS0n/x5jfVY50+tuznbJovTnZ7uCs00lL51rDV0qffXj" + 3872 "SaPczYGlq8wCdXanhua2R91cr973Zr7nG9VisaWi/503Mp1/e+/Mslkec1Zb" + 3873 "ePSF2y68VZjn5sQ7qaQmY+6kCTM3fTbrjPlrvbRtwp7jqurzzGSWZ0yewTS3" + 3874 "kffE16Oh8cdTvt6btOXlEYMtTWkZP3OTrU7erbvKdflkZ9mZU5dPvv2+ZlmF" + 3875 "Oo/01xbXJVwL5JSCNGwvJkd0JeezTTqYwX6xNHzOTrm3J5et7XD+eJE3VulI" + 3876 "vYFOkOCSl6t0rix++JQn/oHo3PsLLnM/0ajzP3Cg1kaheGVzzwGjMJEnomu0" + 3877 "IoI39LVP2VA4/QOHdsWaM3yXmFhdtROCD85q0s1RblaXXZJ1Y+VDTcUy0TdX" + 3878 "N/Q380V0pFssqeh4rtil2PcPLc2wWSkGCAPTigQQyyMn59K8ksySnNQUvez8" + 3879 "kpzMvPjc/JTSnNTkhISENCBmSSrTOLvgyIKjDEDzGJlEmHEnVwgQYHjryIBs" + 3880 "PrI2bPkKBpY0auLIZcgmYMtMMItfOJbBMgOxbn3hOBs5/6BrQ89oMLCg8Qi+" + 3881 "bIduDHrYI4z5wUQwJgK8WdlAitmAsBzoFg9mEA8ANX1OW9UEAAA=" 3882 ) 3883 ), 3884 sourceFiles = 3885 arrayOf( 3886 kotlin( 3887 """ 3888 package test.pkg 3889 class RadioGroupScope() { 3890 @Composable 3891 fun RadioGroupItem( 3892 selected: Boolean, 3893 onSelect: () -> Unit, 3894 content: @Composable () -> Unit 3895 ) { } 3896 } 3897 """ 3898 ) 3899 ), 3900 expectedIssues = "", 3901 api = 3902 """ 3903 // Signature format: 4.0 3904 package test.pkg { 3905 public final class RadioGroupScope { 3906 ctor public RadioGroupScope(); 3907 method @test.pkg.Composable public void RadioGroupItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onSelect, kotlin.jvm.functions.Function0<kotlin.Unit> content); 3908 } 3909 } 3910 """ 3911 ) 3912 } 3913 3914 @RequiresCapabilities(Capability.KOTLIN) 3915 @Test Test for experimental annotations from classpathnull3916 fun `Test for experimental annotations from classpath`() { 3917 check( 3918 format = FileFormat.V4, 3919 classpath = 3920 arrayOf( 3921 /* The following source file, compiled, then ran 3922 assertEquals("", toBase64gzip(File("path/to/test.jar"))) 3923 3924 package test.pkg 3925 @RequiresOptIn 3926 annotation class ExternalExperimentalAnnotation 3927 */ 3928 base64gzip( 3929 "test.jar", 3930 "" + 3931 "H4sIAAAAAAAAAAvwZmbhYmDg4GCY0GkYxgAETAwQwAnEvq4hjrqefm76zAwB" + 3932 "cIUGHYZhm+qZ3kkDFUgCsQiyQl9HP0831+AQPV+3z75nTvt46+pd5PXW1Tp3" + 3933 "5vzmIIMrxg+ePnrKhGQYuq2sQFySWlyCYiM2p4EVFWSnYyjcr3nzUgYjA0Mo" + 3934 "ULUuskLXipLUorzEHNeKgtSizNzUvJLEHMe8vPySxJLM/Dy95JzE4uLegN1+" + 3935 "TI4ituWCYtfF9zmaZC3eWHj1RqSEr8FNliMPFm+USkxya4tMYW+Snbv/kXmE" + 3936 "RNJLd8n3alpqUqVdxuXvLJ/bPXv69SPnAb1pHK/D3K7lX1v/1+n6qWmCuy7k" + 3937 "npqW5ZHcamegtuXQqgs7FJyeuZW0rG/d+e10uPmmrFgVjtPNa35c+R2/1vNQ" + 3938 "zEa5qLU98RO3516dFLgzk3mze4Tmv4z1HqeFC45MSnF/sU1lzV9FW86tq+5t" + 3939 "PLh2jvx81qVMiZ8W53pGBQqHGbw2seKMm59UwBnyPCT86HrdvqzbNsH7n1f6" + 3940 "Xfs4x+fe6++Xzn/323b/duG2FxvuV9d5WG7Ma98Q+Of5+8JwgUu5cpezIpXX" + 3941 "/Ft3f010U7nUtujQyiUm7+etPvKsbU/AxF2XihR6OX6W6xnMzX8j1d+lmDfP" + 3942 "qUYoIqFkgvO897V9l87weldIHNSYJLHbRelARQOnW0rSDB6D1pfeAS2SZ4zk" + 3943 "E/UO1bToiO306OLecUAaNcrYrBQDhIFRJQHE8sipqTSvJLMkJzVFLzu/JCcz" + 3944 "Lz43P6U0JzU5ISEhDYhZkso0zi44suAoAzAJMDKJMONOLRAgwPDWkQHZfGRt" + 3945 "2JI1DCxp1MSRyPFZzIpk8QvHMlhaJNatLxxnIydfdG3o6RwGFjQeITXVoxuN" + 3946 "Hh8Io8uZCMZOgDcrG0gxGxB2A913HOw3ALXssnFoBAAA" 3947 ) 3948 ), 3949 sourceFiles = 3950 arrayOf( 3951 kotlin( 3952 """ 3953 package test.pkg 3954 3955 @ExternalExperimentalAnnotation 3956 class ClassUsingExternalExperimentalApi 3957 3958 @InLibraryExperimentalAnnotation 3959 class ClassUsingInLibraryExperimentalApi 3960 """ 3961 ), 3962 kotlin( 3963 """ 3964 package test.pkg 3965 @RequiresOptIn 3966 annotation class InLibraryExperimentalAnnotation 3967 """ 3968 ) 3969 ), 3970 expectedIssues = "", 3971 api = 3972 """ 3973 // Signature format: 4.0 3974 package test.pkg { 3975 @SuppressCompatibility @test.pkg.ExternalExperimentalAnnotation public final class ClassUsingExternalExperimentalApi { 3976 ctor public ClassUsingExternalExperimentalApi(); 3977 } 3978 @SuppressCompatibility @test.pkg.InLibraryExperimentalAnnotation public final class ClassUsingInLibraryExperimentalApi { 3979 ctor public ClassUsingInLibraryExperimentalApi(); 3980 } 3981 @SuppressCompatibility @kotlin.RequiresOptIn public @interface InLibraryExperimentalAnnotation { 3982 } 3983 } 3984 """, 3985 extraArguments = 3986 arrayOf(ARG_SUPPRESS_COMPATIBILITY_META_ANNOTATION, "kotlin.RequiresOptIn") 3987 ) 3988 } 3989 3990 @RequiresCapabilities(Capability.KOTLIN) 3991 @Test Inline suppress compatibility metadata for experimental annotations from classpathnull3992 fun `Inline suppress compatibility metadata for experimental annotations from classpath`() { 3993 check( 3994 format = FileFormat.V4, 3995 classpath = 3996 arrayOf( 3997 /* The following source file, compiled, then ran 3998 assertEquals("", toBase64gzip(File("path/to/test.jar"))) 3999 4000 package test.pkg 4001 @RequiresOptIn 4002 annotation class ExternalExperimentalAnnotation 4003 */ 4004 base64gzip( 4005 "test.jar", 4006 "" + 4007 "H4sIAAAAAAAAAAvwZmbhYmDg4GCY0GkYxgAETAwQwAnEvq4hjrqefm76zAwB" + 4008 "cIUGHYZhm+qZ3kkDFUgCsQiyQl9HP0831+AQPV+3z75nTvt46+pd5PXW1Tp3" + 4009 "5vzmIIMrxg+ePnrKhGQYuq2sQFySWlyCYiM2p4EVFWSnYyjcr3nzUgYjA0Mo" + 4010 "ULUuskLXipLUorzEHNeKgtSizNzUvJLEHMe8vPySxJLM/Dy95JzE4uLegN1+" + 4011 "TI4ituWCYtfF9zmaZC3eWHj1RqSEr8FNliMPFm+USkxya4tMYW+Snbv/kXmE" + 4012 "RNJLd8n3alpqUqVdxuXvLJ/bPXv69SPnAb1pHK/D3K7lX1v/1+n6qWmCuy7k" + 4013 "npqW5ZHcamegtuXQqgs7FJyeuZW0rG/d+e10uPmmrFgVjtPNa35c+R2/1vNQ" + 4014 "zEa5qLU98RO3516dFLgzk3mze4Tmv4z1HqeFC45MSnF/sU1lzV9FW86tq+5t" + 4015 "PLh2jvx81qVMiZ8W53pGBQqHGbw2seKMm59UwBnyPCT86HrdvqzbNsH7n1f6" + 4016 "Xfs4x+fe6++Xzn/323b/duG2FxvuV9d5WG7Ma98Q+Of5+8JwgUu5cpezIpXX" + 4017 "/Ft3f010U7nUtujQyiUm7+etPvKsbU/AxF2XihR6OX6W6xnMzX8j1d+lmDfP" + 4018 "qUYoIqFkgvO897V9l87weldIHNSYJLHbRelARQOnW0rSDB6D1pfeAS2SZ4zk" + 4019 "E/UO1bToiO306OLecUAaNcrYrBQDhIFRJQHE8sipqTSvJLMkJzVFLzu/JCcz" + 4020 "Lz43P6U0JzU5ISEhDYhZkso0zi44suAoAzAJMDKJMONOLRAgwPDWkQHZfGRt" + 4021 "2JI1DCxp1MSRyPFZzIpk8QvHMlhaJNatLxxnIydfdG3o6RwGFjQeITXVoxuN" + 4022 "Hh8Io8uZCMZOgDcrG0gxGxB2A913HOw3ALXssnFoBAAA" 4023 ) 4024 ), 4025 sourceFiles = 4026 arrayOf( 4027 kotlin( 4028 """ 4029 package test.pkg 4030 4031 @ExternalExperimentalAnnotation 4032 class ClassUsingExternalExperimentalApi 4033 4034 @InLibraryExperimentalAnnotation 4035 class ClassUsingInLibraryExperimentalApi 4036 """ 4037 ), 4038 kotlin( 4039 """ 4040 package test.pkg 4041 @RequiresOptIn 4042 annotation class InLibraryExperimentalAnnotation 4043 """ 4044 ) 4045 ), 4046 expectedIssues = "", 4047 api = 4048 """ 4049 // Signature format: 4.0 4050 package test.pkg { 4051 @SuppressCompatibility @test.pkg.ExternalExperimentalAnnotation public final class ClassUsingExternalExperimentalApi { 4052 ctor public ClassUsingExternalExperimentalApi(); 4053 } 4054 @SuppressCompatibility @test.pkg.InLibraryExperimentalAnnotation public final class ClassUsingInLibraryExperimentalApi { 4055 ctor public ClassUsingInLibraryExperimentalApi(); 4056 } 4057 @SuppressCompatibility @kotlin.RequiresOptIn public @interface InLibraryExperimentalAnnotation { 4058 } 4059 } 4060 """, 4061 suppressCompatibilityMetaAnnotations = arrayOf("kotlin.RequiresOptIn") 4062 ) 4063 } 4064 4065 @RequiresCapabilities(Capability.KOTLIN) 4066 @Test @IntRange value in kotlinnull4067 fun `@IntRange value in kotlin`() { 4068 check( 4069 format = FileFormat.V4, 4070 sourceFiles = 4071 arrayOf( 4072 kotlin( 4073 """ 4074 package test.pkg 4075 4076 import androidx.annotation.IntRange 4077 4078 class KotlinClass(@IntRange(from = 1) val param: Int) { 4079 constructor(@IntRange(from = 2) val differentParam: Int) 4080 fun myMethod(@IntRange(from = 3) val methodParam: Int) {} 4081 } 4082 """ 4083 ), 4084 ), 4085 // Access androidx.annotation.IntRange 4086 classpath = arrayOf(KnownJarFiles.stubAnnotationsTestFile), 4087 api = 4088 """ 4089 // Signature format: 4.0 4090 package test.pkg { 4091 public final class KotlinClass { 4092 ctor public KotlinClass(@IntRange(from=1L) int param); 4093 ctor public KotlinClass(@IntRange(from=2L) int differentParam); 4094 method public int getParam(); 4095 method public void myMethod(@IntRange(from=3L) int methodParam); 4096 property @IntRange(from=1L) public int param; 4097 } 4098 } 4099 """ 4100 ) 4101 } 4102 4103 @Test Annotation value visibilitynull4104 fun `Annotation value visibility`() { 4105 check( 4106 format = FileFormat.V2, 4107 sourceFiles = 4108 arrayOf( 4109 java( 4110 """ 4111 package test.pkg; 4112 4113 import androidx.annotation.IntRange; 4114 4115 public final class ApiClass { 4116 private int hiddenConstant = 1; 4117 public ApiClass(@IntRange(from=1) int x) {} 4118 public void method(@IntRange(from = hiddenConstant) int x) {} 4119 } 4120 """ 4121 ), 4122 ), 4123 // Access androidx.annotation.IntRange 4124 classpath = arrayOf(KnownJarFiles.stubAnnotationsTestFile), 4125 api = 4126 """ 4127 // Signature format: 2.0 4128 package test.pkg { 4129 public final class ApiClass { 4130 ctor public ApiClass(@IntRange(from=1) int); 4131 method public void method(@IntRange(from=0x1) int); 4132 } 4133 } 4134 """ 4135 ) 4136 } 4137 4138 @RequiresCapabilities(Capability.KOTLIN) 4139 @Test Kotlin properties with overriding getnull4140 fun `Kotlin properties with overriding get`() { 4141 check( 4142 format = FileFormat.V4, 4143 sourceFiles = 4144 arrayOf( 4145 kotlin( 4146 """ 4147 package test.pkg 4148 4149 import androidx.annotation.IntRange 4150 4151 class KotlinClass() { 4152 val propertyWithGetter: Boolean get() = true 4153 val propertyWithNoGetter: Boolean = true 4154 } 4155 """ 4156 ), 4157 ), 4158 // Access androidx.annotation.IntRange 4159 classpath = arrayOf(KnownJarFiles.stubAnnotationsTestFile), 4160 api = 4161 """ 4162 // Signature format: 4.0 4163 package test.pkg { 4164 public final class KotlinClass { 4165 ctor public KotlinClass(); 4166 method public boolean getPropertyWithGetter(); 4167 method public boolean getPropertyWithNoGetter(); 4168 property public boolean propertyWithGetter; 4169 property public boolean propertyWithNoGetter; 4170 } 4171 } 4172 """ 4173 ) 4174 } 4175 4176 @RequiresCapabilities(Capability.KOTLIN) 4177 @Test Constructor property trackingnull4178 fun `Constructor property tracking`() { 4179 check( 4180 format = FileFormat.V4, 4181 sourceFiles = 4182 arrayOf( 4183 kotlin( 4184 """ 4185 package test.pkg 4186 sealed class MyClass( 4187 val firstConstructorProperty: Int, 4188 val secondConstructorProperty: Boolean 4189 ) { 4190 val nonConstructorProperty: String = "PROP" 4191 } 4192 """ 4193 ), 4194 kotlin( 4195 """ 4196 package test.pkg 4197 data class MyDataClass( 4198 val constructorProperty: String, 4199 internal val internalConstructorProperty: String 4200 ) 4201 """ 4202 ) 4203 ), 4204 api = 4205 """ 4206 // Signature format: 4.0 4207 package test.pkg { 4208 public abstract sealed class MyClass { 4209 method public final int getFirstConstructorProperty(); 4210 method public final String getNonConstructorProperty(); 4211 method public final boolean getSecondConstructorProperty(); 4212 property public final int firstConstructorProperty; 4213 property public final String nonConstructorProperty; 4214 property public final boolean secondConstructorProperty; 4215 } 4216 public final class MyDataClass { 4217 ctor public MyDataClass(String constructorProperty, String internalConstructorProperty); 4218 method public String component1(); 4219 method public test.pkg.MyDataClass copy(String constructorProperty, String internalConstructorProperty); 4220 method public String getConstructorProperty(); 4221 property public String constructorProperty; 4222 } 4223 } 4224 """ 4225 ) 4226 } 4227 4228 @RequiresCapabilities(Capability.KOTLIN) 4229 @Test Default Values and Names in Kotlinnull4230 fun `Default Values and Names in Kotlin`() { 4231 // Kotlin code which explicitly specifies parameter names 4232 check( 4233 format = FileFormat.V4, 4234 sourceFiles = 4235 arrayOf( 4236 kotlin( 4237 """ 4238 package test.pkg 4239 import some.other.pkg.Constants.Misc.SIZE 4240 import android.graphics.Bitmap 4241 import android.view.View 4242 4243 class Foo(a: String = "1", b: String = "2") { 4244 fun method1(myInt: Int = 42, 4245 myInt2: Int? = null, 4246 myByte: Int = 2 * 21, 4247 str: String = "hello " + "world", 4248 vararg args: String) { } 4249 4250 fun method2(myInt: Int, myInt2: Int = (2*myInt) * SIZE) { } 4251 4252 fun method3(str: String, myInt: Int, myInt2: Int = double(myInt) + str.length) { } 4253 4254 fun emptyLambda(sizeOf: () -> Unit = { }) {} 4255 4256 fun View.drawToBitmap(config: Bitmap.Config = Bitmap.Config.ARGB_8888): Bitmap? = null 4257 4258 companion object { 4259 fun double(myInt: Int) = 2 * myInt 4260 fun print(foo: Foo = Foo()) { println(foo) } 4261 } 4262 } 4263 """ 4264 ), 4265 java( 4266 """ 4267 package some.other.pkg; 4268 /** @hide */ 4269 public class Constants { 4270 public static class Misc { 4271 public static final int SIZE = 5; 4272 } 4273 } 4274 """ 4275 ), 4276 ), 4277 api = 4278 """ 4279 // Signature format: 4.0 4280 package test.pkg { 4281 public final class Foo { 4282 ctor public Foo(); 4283 ctor public Foo(optional String a, optional String b); 4284 method public android.graphics.Bitmap? drawToBitmap(android.view.View, optional android.graphics.Bitmap.Config config); 4285 method public void emptyLambda(optional kotlin.jvm.functions.Function0<kotlin.Unit> sizeOf); 4286 method public void method1(optional int myInt, optional Integer? myInt2, optional int myByte, optional String str, java.lang.String... args); 4287 method public void method2(int myInt, optional int myInt2); 4288 method public void method3(String str, int myInt, optional int myInt2); 4289 field public static final test.pkg.Foo.Companion Companion; 4290 } 4291 public static final class Foo.Companion { 4292 method public int double(int myInt); 4293 method public void print(optional test.pkg.Foo foo); 4294 } 4295 } 4296 """, 4297 ) 4298 } 4299 4300 @RequiresCapabilities(Capability.KOTLIN) 4301 @Test Default Values in Kotlin for expressionsnull4302 fun `Default Values in Kotlin for expressions`() { 4303 // Testing trickier default values; regression test for problem 4304 // observed in androidx.core.util with LruCache 4305 check( 4306 format = FileFormat.V4, 4307 sourceFiles = 4308 arrayOf( 4309 kotlin( 4310 """ 4311 package androidx.core.util 4312 4313 import android.util.LruCache 4314 4315 inline fun <K : Any, V : Any> lruCache( 4316 maxSize: Int, 4317 crossinline sizeOf: (key: K, value: V) -> Int = { _, _ -> 1 }, 4318 @Suppress("USELESS_CAST") // https://youtrack.jetbrains.com/issue/KT-21946 4319 crossinline create: (key: K) -> V? = { null as V? }, 4320 crossinline onEntryRemoved: (evicted: Boolean, key: K, oldValue: V, newValue: V?) -> Unit = 4321 { _, _, _, _ -> } 4322 ): LruCache<K, V> { 4323 return object : LruCache<K, V>(maxSize) { 4324 override fun sizeOf(key: K, value: V) = sizeOf(key, value) 4325 override fun create(key: K) = create(key) 4326 override fun entryRemoved(evicted: Boolean, key: K, oldValue: V, newValue: V?) { 4327 onEntryRemoved(evicted, key, oldValue, newValue) 4328 } 4329 } 4330 } 4331 """ 4332 ), 4333 java( 4334 """ 4335 package androidx.collection; 4336 4337 import androidx.annotation.NonNull; 4338 import androidx.annotation.Nullable; 4339 4340 import java.util.LinkedHashMap; 4341 import java.util.Locale; 4342 import java.util.Map; 4343 4344 /** @hide */ 4345 public class LruCache<K, V> { 4346 @Nullable 4347 protected V create(@NonNull K key) { 4348 return null; 4349 } 4350 4351 protected int sizeOf(@NonNull K key, @NonNull V value) { 4352 return 1; 4353 } 4354 4355 protected void entryRemoved(boolean evicted, @NonNull K key, @NonNull V oldValue, 4356 @Nullable V newValue) { 4357 } 4358 } 4359 """ 4360 ), 4361 androidxNullableSource, 4362 androidxNonNullSource, 4363 ), 4364 api = 4365 """ 4366 // Signature format: 4.0 4367 package androidx.core.util { 4368 public final class TestKt { 4369 method public static inline <K, V> android.util.LruCache<K,V> lruCache(int maxSize, optional kotlin.jvm.functions.Function2<? super K,? super V,java.lang.Integer> sizeOf, optional kotlin.jvm.functions.Function1<? super K,? extends V?> create, optional kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V?,kotlin.Unit> onEntryRemoved); 4370 } 4371 } 4372 """, 4373 ) 4374 } 4375 4376 @RequiresCapabilities(Capability.KOTLIN) 4377 @Test Functional interface in signaturenull4378 fun `Functional interface in signature`() { 4379 check( 4380 format = FileFormat.V4, 4381 sourceFiles = 4382 arrayOf( 4383 kotlin( 4384 """ 4385 package test.pkg 4386 4387 fun interface FunctionalInterface { 4388 fun methodOne(number: Int): Boolean 4389 } 4390 4391 fun userOfFunctionalInterface(parameter: FunctionalInterface) { } 4392 """ 4393 ) 4394 ), 4395 api = 4396 """ 4397 // Signature format: 4.0 4398 package test.pkg { 4399 public fun interface FunctionalInterface { 4400 method public boolean methodOne(int number); 4401 } 4402 public final class FunctionalInterfaceKt { 4403 method public static void userOfFunctionalInterface(test.pkg.FunctionalInterface parameter); 4404 } 4405 } 4406 """ 4407 ) 4408 } 4409 4410 @RequiresCapabilities(Capability.KOTLIN) 4411 @Test Inline classnull4412 fun `Inline class`() { 4413 check( 4414 format = FileFormat.V4, 4415 sourceFiles = 4416 arrayOf( 4417 kotlin( 4418 """ 4419 package test.pkg 4420 4421 inline class Dp(val value: Float) : Comparable<Dp> { 4422 inline operator fun plus(other: Dp) = Dp(value = this.value + other.value) 4423 inline operator fun minus(other: Dp) = Dp(value = this.value - other.value) 4424 val someBits 4425 // Not tracked due to https://youtrack.jetbrains.com/issue/KTIJ-11559 4426 get() = value.toInt() and 0x00ff 4427 fun doSomething() {} 4428 } 4429 """ 4430 ) 4431 ), 4432 api = 4433 """ 4434 // Signature format: 4.0 4435 package test.pkg { 4436 public final inline class Dp implements java.lang.Comparable<test.pkg.Dp> { 4437 ctor public Dp(); 4438 method public void doSomething(); 4439 method public float getValue(); 4440 method public inline operator float minus(float other); 4441 method public inline operator float plus(float other); 4442 property public int someBits; 4443 property public float value; 4444 } 4445 } 4446 """ 4447 ) 4448 } 4449 4450 @RequiresCapabilities(Capability.KOTLIN) 4451 @Test Value classnull4452 fun `Value class`() { 4453 check( 4454 format = FileFormat.V4, 4455 sourceFiles = 4456 arrayOf( 4457 kotlin( 4458 """ 4459 package test.pkg 4460 @JvmInline 4461 value class Dp(val value: Float) : Comparable<Dp> { 4462 inline operator fun plus(other: Dp) = Dp(value = this.value + other.value) 4463 inline operator fun minus(other: Dp) = Dp(value = this.value - other.value) 4464 val someBits 4465 get() = value.toInt() and 0x00ff 4466 fun doSomething() {} 4467 override fun compareTo(other: Dp): Int = value.compareTo(other.value) 4468 } 4469 4470 fun box(p : Dp) { 4471 println(p) 4472 } 4473 """ 4474 ) 4475 ), 4476 api = 4477 """ 4478 // Signature format: 4.0 4479 package test.pkg { 4480 @kotlin.jvm.JvmInline public final value class Dp implements java.lang.Comparable<test.pkg.Dp> { 4481 ctor public Dp(float value); 4482 method public int compareTo(float other); 4483 method public void doSomething(); 4484 method public float getValue(); 4485 method public inline operator float minus(float other); 4486 method public inline operator float plus(float other); 4487 property public int someBits; 4488 property public float value; 4489 } 4490 public final class DpKt { 4491 method public static void box(float p); 4492 } 4493 } 4494 """ 4495 ) 4496 } 4497 4498 @RequiresCapabilities(Capability.KOTLIN) 4499 @Test Kotlin doesn't expand java named constantsnull4500 fun `Kotlin doesn't expand java named constants`() { 4501 check( 4502 format = FileFormat.V4, 4503 sourceFiles = 4504 arrayOf( 4505 kotlin( 4506 """ 4507 package test.pkg 4508 annotation class Foo(val bar: Long = java.lang.Long.MIN_VALUE) 4509 """ 4510 ) 4511 ), 4512 api = 4513 """ 4514 // Signature format: 4.0 4515 package test.pkg { 4516 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public @interface Foo { 4517 method public abstract long bar() default java.lang.Long.MIN_VALUE; 4518 property public abstract long bar; 4519 } 4520 } 4521 """ 4522 ) 4523 } 4524 4525 @RequiresCapabilities(Capability.KOTLIN) 4526 @Test 4527 fun `Kotlin constructors with JvmOverloads`() { 4528 check( 4529 format = FileFormat.V4, 4530 sourceFiles = 4531 arrayOf( 4532 kotlin( 4533 """ 4534 package test.pkg 4535 4536 class AllOptionalJvmOverloads @JvmOverloads constructor( 4537 private val foo: Int = 0, 4538 private val bar: Int = 0 4539 ) 4540 4541 // When all args are optional, the compiler generates a no-arg constructor 4542 // even when @JvmOverloads is not used: 4543 // https://kotlinlang.org/docs/java-to-kotlin-interop.html#overloads-generation 4544 class AllOptionalNoJvmOverloads( 4545 private val foo: Int = 0, 4546 private val bar: Int = 0 4547 ) 4548 4549 class SomeOptionalJvmOverloads @JvmOverloads constructor( 4550 private val p1: Int, 4551 private val p2: Int = 0, 4552 private val p3: Int, 4553 private val p4: Int = 0, 4554 private val p5: Int 4555 ) 4556 4557 class SomeOptionalNoJvmOverloads( 4558 private val foo: Int, 4559 private val bar: Int = 0 4560 ) 4561 """ 4562 ) 4563 ), 4564 api = 4565 """ 4566 // Signature format: 4.0 4567 package test.pkg { 4568 public final class AllOptionalJvmOverloads { 4569 ctor public AllOptionalJvmOverloads(); 4570 ctor public AllOptionalJvmOverloads(optional int foo); 4571 ctor public AllOptionalJvmOverloads(optional int foo, optional int bar); 4572 } 4573 public final class AllOptionalNoJvmOverloads { 4574 ctor public AllOptionalNoJvmOverloads(); 4575 ctor public AllOptionalNoJvmOverloads(optional int foo, optional int bar); 4576 } 4577 public final class SomeOptionalJvmOverloads { 4578 ctor public SomeOptionalJvmOverloads(int p1, int p3, int p5); 4579 ctor public SomeOptionalJvmOverloads(int p1, optional int p2, int p3, int p5); 4580 ctor public SomeOptionalJvmOverloads(int p1, optional int p2, int p3, optional int p4, int p5); 4581 } 4582 public final class SomeOptionalNoJvmOverloads { 4583 ctor public SomeOptionalNoJvmOverloads(int foo, optional int bar); 4584 } 4585 } 4586 """ 4587 ) 4588 } 4589 4590 @RequiresCapabilities(Capability.KOTLIN) 4591 @Test 4592 fun `Kotlin expect-actual with JvmOverloads constructors`() { 4593 check( 4594 format = FileFormat.V4, 4595 sourceFiles = 4596 arrayOf( 4597 kotlin( 4598 "src/commonMain/test/pkg/Expect.kt", 4599 """ 4600 package test.pkg 4601 4602 expect class AllOptionalJvmOverloads @JvmOverloads constructor( 4603 private val foo: Int = 0, 4604 private val bar: Int = 0 4605 ) 4606 4607 expect class SomeOptionalJvmOverloads @JvmOverloads constructor( 4608 private val p1: Int, 4609 private val p2: Int = 0, 4610 private val p3: Int, 4611 private val p4: Int = 0, 4612 private val p5: Int 4613 ) 4614 4615 expect class AllOptionalJvmOverloadsBothSides @JvmOverloads constructor( 4616 private val foo: Int = 0, 4617 private val bar: Int = 0 4618 ) 4619 """ 4620 ), 4621 kotlin( 4622 "src/jvmMain/test/pkg/Actual.kt", 4623 """ 4624 package test.pkg 4625 4626 actual class AllOptionalJvmOverloads @JvmOverloads actual constructor( 4627 private val foo: Int, 4628 private val bar: Int 4629 ) 4630 4631 actual class SomeOptionalJvmOverloads @JvmOverloads actual constructor( 4632 private val p1: Int, 4633 private val p2: Int, 4634 private val p3: Int, 4635 private val p4: Int, 4636 private val p5: Int 4637 ) 4638 4639 actual class AllOptionalJvmOverloadsBothSides @JvmOverloads actual constructor( 4640 private val foo: Int = 0, 4641 private val bar: Int = 0 4642 ) 4643 """ 4644 ) 4645 ), 4646 api = 4647 """ 4648 // Signature format: 4.0 4649 package test.pkg { 4650 public final class AllOptionalJvmOverloads { 4651 ctor public AllOptionalJvmOverloads(); 4652 ctor public AllOptionalJvmOverloads(optional int foo); 4653 ctor public AllOptionalJvmOverloads(optional int foo, optional int bar); 4654 } 4655 public final class AllOptionalJvmOverloadsBothSides { 4656 ctor public AllOptionalJvmOverloadsBothSides(); 4657 ctor public AllOptionalJvmOverloadsBothSides(optional int foo); 4658 ctor public AllOptionalJvmOverloadsBothSides(optional int foo, optional int bar); 4659 } 4660 public final class SomeOptionalJvmOverloads { 4661 ctor public SomeOptionalJvmOverloads(int p1, int p3, int p5); 4662 ctor public SomeOptionalJvmOverloads(int p1, optional int p2, int p3, int p5); 4663 ctor public SomeOptionalJvmOverloads(int p1, optional int p2, int p3, optional int p4, int p5); 4664 } 4665 } 4666 """ 4667 ) 4668 } 4669 4670 @RequiresCapabilities(Capability.KOTLIN) 4671 @Test 4672 fun `Kotlin expect-actual with JvmOverloads methods`() { 4673 val commonSource = 4674 kotlin( 4675 "commonMain/src/test/pkg/Foo.kt", 4676 """ 4677 package test.pkg 4678 import kotlin.jvm.JvmOverloads 4679 expect class Foo { 4680 @JvmOverloads 4681 fun allOptionalJvmOverloads(p1: Int = 0, p2: Int = 0, p3: Int = 0) 4682 4683 @JvmOverloads 4684 fun someOptionalJvmOverloads(p1: Int, p2: Int = 0, p3: Int, p4: Int = 0, p5: Int) 4685 } 4686 """ 4687 ) 4688 // @JvmOverloads needs to be annotated on the actual fun too, but the default values can't 4689 // be present on actuals 4690 val androidSource = 4691 kotlin( 4692 "androidMain/src/test/pkg/Foo.kt", 4693 """ 4694 package test.pkg 4695 actual class Foo { 4696 @JvmOverloads 4697 actual fun allOptionalJvmOverloads(p1: Int, p2: Int, p3: Int) = Unit 4698 4699 @JvmOverloads 4700 actual fun someOptionalJvmOverloads(p1: Int, p2: Int, p3: Int, p4: Int, p5: Int) = Unit 4701 } 4702 """ 4703 ) 4704 check( 4705 sourceFiles = arrayOf(androidSource, commonSource), 4706 projectDescription = 4707 createProjectDescription( 4708 createAndroidModuleDescription(arrayOf(androidSource)), 4709 createCommonModuleDescription(arrayOf(commonSource)), 4710 ), 4711 api = 4712 """ 4713 package test.pkg { 4714 public final class Foo { 4715 ctor public Foo(); 4716 method public void allOptionalJvmOverloads(); 4717 method public void allOptionalJvmOverloads(optional int p1); 4718 method public void allOptionalJvmOverloads(optional int p1, optional int p2); 4719 method public void allOptionalJvmOverloads(optional int p1, optional int p2, optional int p3); 4720 method public void someOptionalJvmOverloads(int p1, int p3, int p5); 4721 method public void someOptionalJvmOverloads(int p1, optional int p2, int p3, int p5); 4722 method public void someOptionalJvmOverloads(int p1, optional int p2, int p3, optional int p4, int p5); 4723 } 4724 } 4725 """ 4726 ) 4727 } 4728 4729 @RequiresCapabilities(Capability.KOTLIN) 4730 @Test 4731 fun `Kotlin public methods with DeprecationLevel HIDDEN are public API`() { 4732 check( 4733 format = FileFormat.V4, 4734 sourceFiles = 4735 arrayOf( 4736 kotlin( 4737 """ 4738 package test.pkg 4739 @Deprecated( 4740 message = "So much regret", 4741 level = DeprecationLevel.HIDDEN 4742 ) 4743 fun myMethod() { TODO() } 4744 @Deprecated( 4745 message = "So much regret", 4746 level = DeprecationLevel.HIDDEN 4747 ) 4748 internal fun myInternalMethod() { TODO() } 4749 @Deprecated( 4750 message = "So much regret", 4751 level = DeprecationLevel.HIDDEN 4752 ) 4753 private fun myPrivateMethod() { TODO() } 4754 @Deprecated( 4755 message = "So much regret", 4756 level = DeprecationLevel.WARNING 4757 ) 4758 fun myNormalDeprecatedMethod() { TODO() } 4759 """ 4760 ) 4761 ), 4762 api = 4763 """ 4764 // Signature format: 4.0 4765 package test.pkg { 4766 public final class TestKt { 4767 method @Deprecated public static void myMethod(); 4768 method @Deprecated public static void myNormalDeprecatedMethod(); 4769 } 4770 } 4771 """ 4772 ) 4773 } 4774 4775 @RequiresCapabilities(Capability.KOTLIN) 4776 @Test Annotations aren't dropped when DeprecationLevel is HIDDENnull4777 fun `Annotations aren't dropped when DeprecationLevel is HIDDEN`() { 4778 // Regression test for http://b/219792969 4779 check( 4780 format = FileFormat.V4, 4781 sourceFiles = 4782 arrayOf( 4783 kotlin( 4784 """ 4785 package test.pkg 4786 import androidx.annotation.IntRange 4787 @Deprecated( 4788 message = "So much regret", 4789 level = DeprecationLevel.HIDDEN 4790 ) 4791 @IntRange(from=0) 4792 fun myMethod() { TODO() } 4793 4794 @Deprecated( 4795 message = "Not supported anymore", 4796 level = DeprecationLevel.HIDDEN 4797 ) 4798 fun returnsNonNull(): String = "42" 4799 4800 @Deprecated( 4801 message = "Not supported anymore", 4802 level = DeprecationLevel.HIDDEN 4803 ) 4804 fun returnsNonNullImplicitly() = "42" 4805 """ 4806 ), 4807 ), 4808 // Access androidx.annotation.IntRange 4809 classpath = arrayOf(KnownJarFiles.stubAnnotationsTestFile), 4810 api = 4811 """ 4812 package test.pkg { 4813 public final class TestKt { 4814 method @Deprecated @IntRange(from=0L) public static void myMethod(); 4815 method @Deprecated public static String returnsNonNull(); 4816 method @Deprecated public static String returnsNonNullImplicitly(); 4817 } 4818 } 4819 """ 4820 ) 4821 } 4822 4823 @RequiresCapabilities(Capability.KOTLIN) 4824 @Test 4825 fun `Constants in a file scope annotation`() { 4826 check( 4827 sourceFiles = 4828 arrayOf( 4829 kotlin( 4830 """ 4831 @file:RestrictTo(RestrictTo.Scope.LIBRARY) 4832 package test.pkg 4833 import androidx.annotation.RestrictTo 4834 private fun veryFun(): Boolean = true 4835 const val CONST = "Hello" 4836 fun bar() 4837 """ 4838 ), 4839 restrictToSource, 4840 ), 4841 format = FileFormat.V4, 4842 api = 4843 """ 4844 // Signature format: 4.0 4845 package test.pkg { 4846 @RestrictTo({androidx.annotation.RestrictTo.Scope.LIBRARY}) public final class TestKt { 4847 method public static void bar(); 4848 property public static String CONST; 4849 field public static final String CONST = "Hello"; 4850 } 4851 } 4852 """ 4853 ) 4854 } 4855 4856 @RequiresCapabilities(Capability.KOTLIN) 4857 @Test 4858 fun `RestrictTo on a file hiding it`() { 4859 check( 4860 format = FileFormat.V4, 4861 sourceFiles = 4862 arrayOf( 4863 kotlin( 4864 """ 4865 @file:RestrictTo(RestrictTo.Scope.LIBRARY) 4866 package test.pkg 4867 import androidx.annotation.RestrictTo 4868 private fun veryFun(): Boolean = true 4869 """ 4870 ), 4871 restrictToSource, 4872 ), 4873 extraArguments = arrayOf("--show-unannotated"), 4874 hideAnnotations = 4875 arrayOf( 4876 "androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)" 4877 ), 4878 api = """ 4879 // Signature format: 4.0 4880 """ 4881 ) 4882 } 4883 4884 /** Regression test for b/202968090 */ 4885 @RequiresCapabilities(Capability.KOTLIN) 4886 @Test 4887 fun `annotation arrays should be non-null`() { 4888 check( 4889 format = FileFormat.V4, 4890 sourceFiles = 4891 arrayOf( 4892 kotlin( 4893 """ 4894 package test.pkg 4895 annotation class Foo ( 4896 val bar: Array<String>, 4897 vararg val baz: String 4898 ) 4899 """ 4900 ) 4901 ), 4902 api = 4903 """ 4904 // Signature format: 4.0 4905 package test.pkg { 4906 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public @interface Foo { 4907 method public abstract String[] bar(); 4908 method public abstract String[] baz(); 4909 property public abstract String[] bar; 4910 property public abstract String[] baz; 4911 } 4912 } 4913 """ 4914 ) 4915 } 4916 4917 @RequiresCapabilities(Capability.KOTLIN) 4918 @Test 4919 fun `property setter parameters are unnamed`() { 4920 check( 4921 sourceFiles = 4922 arrayOf( 4923 kotlin( 4924 """ 4925 package test.pkg 4926 class Foo(var bar: Int) 4927 """ 4928 ) 4929 ), 4930 api = 4931 """ 4932 package test.pkg { 4933 public final class Foo { 4934 ctor public Foo(int bar); 4935 method public int getBar(); 4936 method public void setBar(int); 4937 property public int bar; 4938 } 4939 } 4940 """ 4941 ) 4942 } 4943 4944 @RequiresCapabilities(Capability.KOTLIN) 4945 @Test 4946 fun `implements kotlin collection`() { 4947 check( 4948 sourceFiles = 4949 arrayOf( 4950 kotlin( 4951 """ 4952 package test.pkg 4953 class MyList : List<String> { 4954 override operator fun get(index: Int): String {} 4955 } 4956 """ 4957 ) 4958 ), 4959 api = 4960 """ 4961 package test.pkg { 4962 public final class MyList implements kotlin.jvm.internal.markers.KMappedMarker java.util.List<java.lang.String> { 4963 ctor public MyList(); 4964 method public operator String get(int index); 4965 } 4966 } 4967 """ 4968 ) 4969 } 4970 4971 @RequiresCapabilities(Capability.KOTLIN) 4972 @Test 4973 fun `companion object in annotation`() { 4974 check( 4975 sourceFiles = 4976 arrayOf( 4977 kotlin( 4978 """ 4979 package test.pkg 4980 annotation class Dimension(val unit: Int = PX) { 4981 companion object { 4982 const val DP: Int = 0 4983 const val PX: Int = 1 4984 const val SP: Int = 2 4985 } 4986 } 4987 """ 4988 ) 4989 ), 4990 api = 4991 """ 4992 package test.pkg { 4993 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public @interface Dimension { 4994 method public abstract int unit() default test.pkg.Dimension.PX; 4995 property public abstract int unit; 4996 field public static final test.pkg.Dimension.Companion Companion; 4997 field public static final int DP = 0; // 0x0 4998 field public static final int PX = 1; // 0x1 4999 field public static final int SP = 2; // 0x2 5000 } 5001 public static final class Dimension.Companion { 5002 property public static int DP; 5003 property public static int PX; 5004 property public static int SP; 5005 field public static final int DP = 0; // 0x0 5006 field public static final int PX = 1; // 0x1 5007 field public static final int SP = 2; // 0x2 5008 } 5009 } 5010 """ 5011 ) 5012 } 5013 5014 @RequiresCapabilities(Capability.KOTLIN) 5015 @Test 5016 fun `APIs before and after @Deprecated(HIDDEN)`() { 5017 val sameModifiersAndReturnType = "public static test.pkg.State<java.lang.String>" 5018 val sameParameters = "(Integer? i, String? s, java.lang.Object... vs);" 5019 check( 5020 sourceFiles = 5021 arrayOf( 5022 kotlin( 5023 """ 5024 package test.pkg 5025 interface State<out T> { 5026 val value: T 5027 } 5028 5029 @Deprecated(level = DeprecationLevel.HIDDEN, message="no longer supported") 5030 fun before( 5031 i : Int?, 5032 s : String?, 5033 vararg vs : Any, 5034 ): State<String> { 5035 return object : State<String> { 5036 override val value: String = i?.toString() ?: s ?: "42" 5037 } 5038 } 5039 5040 fun after( 5041 i : Int?, 5042 s : String?, 5043 vararg vs : Any, 5044 ): State<String> { 5045 return object : State<String> { 5046 override val value: String = i?.toString() ?: s ?: "42" 5047 } 5048 } 5049 """ 5050 ) 5051 ), 5052 api = 5053 """ 5054 package test.pkg { 5055 public interface State<T> { 5056 method public T getValue(); 5057 property public abstract T value; 5058 } 5059 public final class StateKt { 5060 method $sameModifiersAndReturnType after$sameParameters 5061 method @Deprecated $sameModifiersAndReturnType before$sameParameters 5062 } 5063 } 5064 """ 5065 ) 5066 } 5067 5068 @RequiresCapabilities(Capability.KOTLIN) 5069 @Test 5070 fun `APIs before and after @Deprecated(HIDDEN) on constructors`() { 5071 check( 5072 sourceFiles = 5073 arrayOf( 5074 kotlin( 5075 """ 5076 package test.pkg 5077 interface State<out T> { 5078 val value: T 5079 } 5080 5081 class AsyncPagingDataDiffer<T : Any> 5082 @JvmOverloads 5083 constructor( 5084 private val initState: State<T>, 5085 private val nextState: State<T>, 5086 private val updateCallback: Runnable, 5087 ) { 5088 @Deprecated(level = DeprecationLevel.HIDDEN, message="no longer supported") 5089 constructor( 5090 state: State<T>, 5091 ) : this( 5092 initState = state, 5093 nextState = state, 5094 updateCallback = { } 5095 ) 5096 5097 constructor( 5098 initState: State<T>, 5099 nextState: State<T>, 5100 ) : this( 5101 initState = initState, 5102 nextState = nextState, 5103 updateCallback = { } 5104 ) 5105 } 5106 """ 5107 ) 5108 ), 5109 api = 5110 """ 5111 package test.pkg { 5112 public final class AsyncPagingDataDiffer<T> { 5113 ctor @Deprecated public AsyncPagingDataDiffer(test.pkg.State<? extends T> state); 5114 ctor public AsyncPagingDataDiffer(test.pkg.State<? extends T> initState, test.pkg.State<? extends T> nextState); 5115 ctor public AsyncPagingDataDiffer(test.pkg.State<? extends T> initState, test.pkg.State<? extends T> nextState, Runnable updateCallback); 5116 } 5117 public interface State<T> { 5118 method public T getValue(); 5119 property public abstract T value; 5120 } 5121 } 5122 """ 5123 ) 5124 } 5125 5126 @RequiresCapabilities(Capability.KOTLIN) 5127 @Test 5128 fun `@Deprecated sealed interface and its members`() { 5129 check( 5130 sourceFiles = 5131 arrayOf( 5132 kotlin( 5133 """ 5134 package test.pkg 5135 5136 @Deprecated("moved to somewhere else") 5137 sealed interface LazyInfo { 5138 val index : Int 5139 val key: Int 5140 } 5141 """ 5142 ) 5143 ), 5144 api = 5145 """ 5146 package test.pkg { 5147 @Deprecated public sealed interface LazyInfo { 5148 method @Deprecated public int getIndex(); 5149 method @Deprecated public int getKey(); 5150 property @Deprecated public abstract int index; 5151 property @Deprecated public abstract int key; 5152 } 5153 } 5154 """ 5155 ) 5156 } 5157 5158 @RequiresCapabilities(Capability.KOTLIN) 5159 @Test 5160 fun `@Repeatable annotation`() { 5161 check( 5162 sourceFiles = 5163 arrayOf( 5164 kotlin( 5165 """ 5166 package test.pkg 5167 5168 import androidx.annotation.IntRange 5169 5170 @Repeatable 5171 annotation class RequiresExtension( 5172 @IntRange(from = 1) val extension: Int, 5173 @IntRange(from = 1) val version: Int 5174 ) 5175 """ 5176 ), 5177 ), 5178 // Access androidx.annotation.IntRange 5179 classpath = arrayOf(KnownJarFiles.stubAnnotationsTestFile), 5180 api = 5181 """ 5182 package test.pkg { 5183 @kotlin.annotation.Repeatable public @interface RequiresExtension { 5184 method public abstract int extension(); 5185 method public abstract int version(); 5186 property @IntRange(from=1L) public abstract int extension; 5187 property @IntRange(from=1L) public abstract int version; 5188 } 5189 @kotlin.annotation.Repeatable public static @interface RequiresExtension.Container { 5190 method public abstract test.pkg.RequiresExtension[] value(); 5191 property @IntRange(from=1L) public abstract int extension; 5192 property @IntRange(from=1L) public abstract int version; 5193 } 5194 } 5195 """ 5196 ) 5197 } 5198 5199 @RequiresCapabilities(Capability.KOTLIN) 5200 @Test 5201 fun `Don't print empty facade classes`() { 5202 check( 5203 sourceFiles = 5204 arrayOf( 5205 kotlin( 5206 "test/pkg/Toast.kt", 5207 """ 5208 package test.pkg 5209 internal fun bar() {} 5210 5211 private val baz 5212 5213 class Toast { 5214 val foo: Int = 0 5215 } 5216 """ 5217 ), 5218 kotlin( 5219 "test/pkg/Bar.kt", 5220 """ 5221 package test.pkg 5222 class Bar 5223 """ 5224 ), 5225 kotlin( 5226 "test/pkg/test.kt", 5227 """ 5228 package test.pkg 5229 5230 /** 5231 * @suppress 5232 */ 5233 @PublishedApi 5234 internal fun internalYetPublished() {} 5235 5236 private val buzz 5237 """ 5238 ), 5239 kotlin( 5240 "test/pkg/ConfigurationError.kt", 5241 """ 5242 package test.pkg 5243 import androidx.annotation.RestrictTo 5244 5245 /** 5246 * @hide 5247 */ 5248 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 5249 data class ConfigurationError(val id: String) 5250 5251 /** 5252 * @hide 5253 */ 5254 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 5255 fun conditionalError(): ConfigurationError? = null 5256 """ 5257 ), 5258 kotlin( 5259 "test/pkg/test2.kt", 5260 """ 5261 package test.pkg 5262 import androidx.annotation.VisibleForTesting 5263 5264 @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) 5265 fun shouldBePackagePrivate() {} 5266 5267 private fun shouldBePrivate() {} 5268 """ 5269 ), 5270 kotlin( 5271 "test/pkg/Path1.kt", 5272 """ 5273 package test.pkg 5274 5275 expect fun Path1(): Path1 5276 5277 interface Path1 { 5278 infix fun xor(path: Path1): Path1 5279 } 5280 """ 5281 ), 5282 kotlin( 5283 "test/pkg/Path2.kt", 5284 """ 5285 package test.pkg 5286 5287 expect fun Path2(): Path2 5288 5289 fun Path2.copy(): Path2 = TODO() 5290 5291 interface Path2 { 5292 infix fun xor(path: Path2): Path2 5293 } 5294 """ 5295 ), 5296 kotlin( 5297 "test/pkg/LazyLayoutItemProvider.kt", 5298 """ 5299 package test.pkg 5300 5301 interface LazyLayoutItemProvider { 5302 val itemCount: Int 5303 fun getIndex(): Int = -1 5304 } 5305 5306 internal fun LazyLayoutItemProvider.findIndexByKey( 5307 key: Any?, 5308 lastKnownIndex: Int, 5309 ): Int = TODO() 5310 5311 expect fun getDefaultLazyLayoutKey(index: Int): Any 5312 """ 5313 ), 5314 restrictToSource, 5315 visibleForTestingSource, 5316 ), 5317 extraArguments = 5318 arrayOf( 5319 ARG_SHOW_UNANNOTATED, 5320 ARG_SHOW_ANNOTATION, 5321 "kotlin.PublishedApi", 5322 ARG_HIDE_ANNOTATION, 5323 "androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP)", 5324 ), 5325 format = FileFormat.V4, 5326 api = 5327 """ 5328 // Signature format: 4.0 5329 package test.pkg { 5330 public final class Bar { 5331 ctor public Bar(); 5332 } 5333 public interface LazyLayoutItemProvider { 5334 method public default int getIndex(); 5335 method public int getItemCount(); 5336 property public abstract int itemCount; 5337 } 5338 public interface Path1 { 5339 method public infix test.pkg.Path1 xor(test.pkg.Path1 path); 5340 } 5341 public interface Path2 { 5342 method public infix test.pkg.Path2 xor(test.pkg.Path2 path); 5343 } 5344 public final class Path2Kt { 5345 method public static test.pkg.Path2 copy(test.pkg.Path2); 5346 } 5347 public final class TestKt { 5348 method @kotlin.PublishedApi internal static void internalYetPublished(); 5349 } 5350 public final class Toast { 5351 ctor public Toast(); 5352 method public int getFoo(); 5353 property public int foo; 5354 } 5355 } 5356 """ 5357 ) 5358 } 5359 5360 @RequiresCapabilities(Capability.KOTLIN) 5361 @Test Test @JvmMultifileClass appears only oncenull5362 fun `Test @JvmMultifileClass appears only once`() { 5363 check( 5364 sourceFiles = 5365 arrayOf( 5366 kotlin( 5367 "test/pkg/A.kt", 5368 """ 5369 @file:JvmMultifileClass 5370 @file:JvmName("Foo") 5371 5372 package test.pkg 5373 5374 fun String.bar(): Unit {} 5375 5376 val nonConstVal = 3 5377 """ 5378 ), 5379 kotlin( 5380 "test/pkg/B.kt", 5381 """ 5382 @file:JvmMultifileClass 5383 @file:JvmName("Foo") 5384 5385 package test.pkg 5386 5387 fun String.baz(): Unit {} 5388 5389 const val constVal = 4 5390 """ 5391 ) 5392 ), 5393 format = FileFormat.V4, 5394 api = 5395 """ 5396 // Signature format: 4.0 5397 package test.pkg { 5398 public final class Foo { 5399 method public static void bar(String); 5400 method public static void baz(String); 5401 method public static int getNonConstVal(); 5402 property public static int constVal; 5403 property public static int nonConstVal; 5404 field public static final int constVal = 4; // 0x4 5405 } 5406 } 5407 """ 5408 ) 5409 } 5410 5411 @RequiresCapabilities(Capability.KOTLIN) 5412 @Test @JvmName on @Deprecated hiddennull5413 fun `@JvmName on @Deprecated hidden`() { 5414 check( 5415 sourceFiles = 5416 arrayOf( 5417 kotlin( 5418 """ 5419 package test.pkg 5420 class Foo { 5421 @JvmName("newNameForRenamed") 5422 fun renamed() = Unit 5423 5424 @Deprecated(level = DeprecationLevel.HIDDEN) 5425 fun deprecatedHidden() = Unit 5426 5427 @JvmName("newNameForRenamedAndDeprecatedError") 5428 @Deprecated(level = DeprecationLevel.ERROR) 5429 fun renamedAndDeprecatedError() = Unit 5430 5431 @JvmName("newNameForRenamedAndDeprecatedHidden") 5432 @Deprecated(level = DeprecationLevel.HIDDEN) 5433 fun renamedAndDeprecatedHidden() = Unit 5434 } 5435 """ 5436 ) 5437 ), 5438 api = 5439 """ 5440 package test.pkg { 5441 public final class Foo { 5442 ctor public Foo(); 5443 method @Deprecated public void deprecatedHidden(); 5444 method public void newNameForRenamed(); 5445 method @Deprecated public void newNameForRenamedAndDeprecatedError(); 5446 method @Deprecated public void newNameForRenamedAndDeprecatedHidden(); 5447 } 5448 } 5449 """ 5450 ) 5451 } 5452 5453 @RequiresCapabilities(Capability.KOTLIN) 5454 @Test Ordering of methodsnull5455 fun `Ordering of methods`() { 5456 check( 5457 sourceFiles = 5458 arrayOf( 5459 kotlin( 5460 """ 5461 package test.pkg 5462 5463 class Foo { 5464 fun foo(s: String) {} 5465 fun foo(i: Int) {} 5466 } 5467 5468 class Bar { 5469 fun bar(i: Int) {} 5470 fun bar(s: String) {} 5471 } 5472 """ 5473 ) 5474 ), 5475 api = 5476 """ 5477 package test.pkg { 5478 public final class Bar { 5479 ctor public Bar(); 5480 method public void bar(int i); 5481 method public void bar(String s); 5482 } 5483 public final class Foo { 5484 ctor public Foo(); 5485 method public void foo(int i); 5486 method public void foo(String s); 5487 } 5488 } 5489 """ 5490 ) 5491 } 5492 5493 @Test Partial signature files include affected subclass definitionsnull5494 fun `Partial signature files include affected subclass definitions`() { 5495 check( 5496 format = FileFormat.V2, 5497 sourceFiles = 5498 arrayOf( 5499 java( 5500 """ 5501 package test.pkg; 5502 5503 public class SomePublicClass { 5504 } 5505 """ 5506 ), 5507 java( 5508 """ 5509 package test.pkg; 5510 5511 import android.annotation.SystemApi; 5512 5513 /** @hide */ 5514 @SystemApi 5515 public class SystemSubClass extends SomePublicClass { 5516 } 5517 """ 5518 ), 5519 java( 5520 """ 5521 package test.pkg; 5522 5523 public class AnotherPublicClass extends SystemSubClass { 5524 } 5525 """ 5526 ), 5527 systemApiSource, 5528 ), 5529 api = 5530 """ 5531 // Signature format: 2.0 5532 package test.pkg { 5533 public class AnotherPublicClass extends test.pkg.SystemSubClass { 5534 } 5535 public class SystemSubClass extends test.pkg.SomePublicClass { 5536 ctor public SystemSubClass(); 5537 } 5538 } 5539 """, 5540 extraArguments = 5541 arrayOf( 5542 ARG_SHOW_ANNOTATION, 5543 "android.annotation.SystemApi", 5544 ) 5545 ) 5546 } 5547 5548 @Test Partial signature files include affected subclass definitions in complex class hierarchynull5549 fun `Partial signature files include affected subclass definitions in complex class hierarchy`() { 5550 check( 5551 format = FileFormat.V2, 5552 sourceFiles = 5553 arrayOf( 5554 java( 5555 """ 5556 package test.pkg; 5557 5558 public class SomePublicClass { 5559 } 5560 """ 5561 ), 5562 java( 5563 """ 5564 package test.pkg; 5565 5566 import android.annotation.SystemApi; 5567 5568 /** @hide */ 5569 @SystemApi 5570 public class SystemSubClass extends SomePublicClass { 5571 } 5572 """ 5573 ), 5574 java( 5575 """ 5576 package test.pkg; 5577 5578 import android.annotation.TestApi; 5579 5580 /** @hide */ 5581 @TestApi 5582 public class TestSubClass extends SystemSubClass { 5583 } 5584 """ 5585 ), 5586 java( 5587 """ 5588 package test.pkg; 5589 5590 import android.annotation.SystemApi; 5591 5592 /** @hide */ 5593 @SystemApi 5594 public class AnotherSystemSubClass extends TestSubClass { 5595 } 5596 """ 5597 ), 5598 java( 5599 """ 5600 package test.pkg; 5601 5602 import android.annotation.TestApi; 5603 5604 /** @hide */ 5605 @TestApi 5606 public class AnotherTestSubClass extends AnotherSystemSubClass { 5607 } 5608 """ 5609 ), 5610 java( 5611 """ 5612 package test.pkg; 5613 5614 public class AnotherPublicClass extends AnotherTestSubClass { 5615 } 5616 """ 5617 ), 5618 systemApiSource, 5619 testApiSource, 5620 ), 5621 api = 5622 """ 5623 // Signature format: 2.0 5624 package test.pkg { 5625 public class AnotherPublicClass extends test.pkg.AnotherTestSubClass { 5626 } 5627 public class AnotherTestSubClass extends test.pkg.AnotherSystemSubClass { 5628 ctor public AnotherTestSubClass(); 5629 } 5630 public class TestSubClass extends test.pkg.SystemSubClass { 5631 ctor public TestSubClass(); 5632 } 5633 } 5634 """, 5635 extraArguments = 5636 arrayOf( 5637 ARG_SHOW_ANNOTATION, 5638 "android.annotation.TestApi", 5639 ARG_SHOW_FOR_STUB_PURPOSES_ANNOTATION, 5640 "android.annotation.SystemApi", 5641 ) 5642 ) 5643 } 5644 5645 @Test Subclass definition is not included in removed api filenull5646 fun `Subclass definition is not included in removed api file`() { 5647 check( 5648 format = FileFormat.V2, 5649 expectedIssues = 5650 """ 5651 src/test/pkg/AnotherPublicClass.java:3: warning: Public class test.pkg.AnotherPublicClass stripped of unavailable superclass test.pkg.SystemSubClass [HiddenSuperclass] 5652 """, 5653 sourceFiles = 5654 arrayOf( 5655 java( 5656 """ 5657 package test.pkg; 5658 5659 public class SomePublicClass { 5660 } 5661 """ 5662 ), 5663 java( 5664 """ 5665 package test.pkg; 5666 5667 import android.annotation.SystemApi; 5668 5669 /** 5670 * @hide 5671 * @removed 5672 */ 5673 @SystemApi 5674 public class SystemSubClass extends SomePublicClass { 5675 } 5676 """ 5677 ), 5678 java( 5679 """ 5680 package test.pkg; 5681 5682 public class AnotherPublicClass extends SystemSubClass { 5683 } 5684 """ 5685 ), 5686 systemApiSource, 5687 ), 5688 removedApi = 5689 """ 5690 // Signature format: 2.0 5691 package test.pkg { 5692 public class SystemSubClass extends test.pkg.SomePublicClass { 5693 ctor public SystemSubClass(); 5694 } 5695 } 5696 """, 5697 extraArguments = 5698 arrayOf( 5699 ARG_SHOW_ANNOTATION, 5700 "android.annotation.SystemApi", 5701 ) 5702 ) 5703 } 5704 5705 @Test Type-use annotations can be included in signature filesnull5706 fun `Type-use annotations can be included in signature files`() { 5707 check( 5708 sourceFiles = 5709 arrayOf( 5710 java( 5711 """ 5712 package test.pkg; 5713 @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE_USE) 5714 public @interface TypeAnnotation {} 5715 """ 5716 ), 5717 java( 5718 """ 5719 package test.pkg; 5720 @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) 5721 public @interface MethodAnnotation {} 5722 """ 5723 ), 5724 java( 5725 """ 5726 package test.pkg; 5727 @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE_USE}) 5728 public @interface MethodAndTypeAnnotation {} 5729 """ 5730 ), 5731 java( 5732 """ 5733 package test.pkg; 5734 import java.util.List; 5735 public class Foo { 5736 @MethodAnnotation 5737 @MethodAndTypeAnnotation 5738 public @TypeAnnotation List<@TypeAnnotation String> foo() {} 5739 } 5740 """ 5741 ) 5742 ), 5743 format = 5744 FileFormat.V5.copy(kotlinNameTypeOrder = true, includeTypeUseAnnotations = true), 5745 api = 5746 """ 5747 package test.pkg { 5748 public class Foo { 5749 ctor public Foo(); 5750 method @test.pkg.MethodAndTypeAnnotation @test.pkg.MethodAnnotation public foo(): java.util.@test.pkg.MethodAndTypeAnnotation @test.pkg.TypeAnnotation List<java.lang.@test.pkg.TypeAnnotation String!>!; 5751 } 5752 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE_USE}) public @interface MethodAndTypeAnnotation { 5753 } 5754 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface MethodAnnotation { 5755 } 5756 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE_USE) public @interface TypeAnnotation { 5757 } 5758 } 5759 """ 5760 ) 5761 } 5762 5763 @RequiresCapabilities(Capability.KOTLIN) 5764 @Test Test signature including parameterized converted typenull5765 fun `Test signature including parameterized converted type`() { 5766 check( 5767 sourceFiles = 5768 arrayOf( 5769 java( 5770 """ 5771 package test.pkg; 5772 public interface VisibleInterface<V> {} 5773 """ 5774 ), 5775 java( 5776 """ 5777 package test.pkg; 5778 import androidx.annotation.RestrictTo; 5779 @RestrictTo(RestrictTo.Scope.LIBRARY) 5780 public interface HiddenInterface<H> extends VisibleInterface<H> {} 5781 """ 5782 ), 5783 java( 5784 """ 5785 package test.pkg; 5786 import java.util.List; 5787 public class Foo<F> implements HiddenInterface<List<F>> {} 5788 """ 5789 ), 5790 restrictToSource 5791 ), 5792 // When `HiddenInterface` is hidden, the implements clause for `Foo` is converted to 5793 // `VisibleInterface` using [ClassItem.mapTypeVariables]. It really should become 5794 // `implements test.pkg.VisibleInterface<java.util.List<F>>`, but the `F` is erased from 5795 // `List` for legacy reasons. 5796 api = 5797 """ 5798 // Signature format: 5.0 5799 package test.pkg { 5800 public class Foo<F> implements test.pkg.VisibleInterface<java.util.List!> { 5801 ctor public Foo(); 5802 } 5803 public interface VisibleInterface<V> { 5804 } 5805 } 5806 """, 5807 skipEmitPackages = listOf("androidx.annotation"), 5808 hideAnnotations = arrayOf("androidx.annotation.RestrictTo"), 5809 expectedIssues = 5810 "src/test/pkg/Foo.java:3: warning: Public class test.pkg.Foo stripped of unavailable superclass test.pkg.HiddenInterface [HiddenSuperclass]" 5811 ) 5812 } 5813 5814 @RequiresCapabilities(Capability.KOTLIN) 5815 @Test sealed class with internal setternull5816 fun `sealed class with internal setter`() { 5817 check( 5818 sourceFiles = 5819 arrayOf( 5820 kotlin( 5821 """ 5822 package test.pkg 5823 5824 sealed class TransitionState<S> { 5825 abstract var currentState: S 5826 internal set 5827 } 5828 5829 class SeekableTransitionState<S>( 5830 initialState: S 5831 ) : TransitionState<S>() { 5832 override var currentState: S = initialState 5833 internal set 5834 } 5835 """ 5836 ) 5837 ), 5838 api = 5839 """ 5840 // Signature format: 5.0 5841 package test.pkg { 5842 public final class SeekableTransitionState<S> extends test.pkg.TransitionState<S> { 5843 ctor public SeekableTransitionState(S initialState); 5844 method public S getCurrentState(); 5845 property public S currentState; 5846 } 5847 public abstract sealed class TransitionState<S> { 5848 method public abstract S getCurrentState(); 5849 property public abstract S currentState; 5850 } 5851 } 5852 """ 5853 ) 5854 } 5855 5856 @RequiresCapabilities(Capability.KOTLIN) 5857 @Test Usage of NullableType annotationnull5858 fun `Usage of NullableType annotation`() { 5859 check( 5860 sourceFiles = 5861 arrayOf( 5862 java( 5863 """ 5864 package test.pkg; 5865 import java.util.List; 5866 public class Foo { 5867 public List<@NullableType String> foo(@NullableType Number nullableNumber, Number otherNumber) { return null; } 5868 } 5869 """ 5870 ), 5871 kotlin( 5872 """ 5873 package test.pkg 5874 @Target(AnnotationTarget.TYPE) 5875 annotation class NullableType 5876 """ 5877 ) 5878 ), 5879 api = 5880 """ 5881 package test.pkg { 5882 public class Foo { 5883 ctor public Foo(); 5884 method public java.util.List<java.lang.String?>! foo(Number?, Number!); 5885 } 5886 @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.TYPE) public @interface NullableType { 5887 } 5888 } 5889 """ 5890 ) 5891 } 5892 } 5893