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 org.junit.Test 23 24 class ApiFileTest : DriverTest() { 25 /* 26 Conditions to test: 27 - test all the error scenarios found in the notStrippable case! 28 - split up test into many individual test cases 29 - try referencing a class from an annotation! 30 - test having a throws list where some exceptions are hidden but extend 31 public exceptions: do we map over to the referenced ones? 32 33 - test type reference from all the possible places -- in type signatures - interfaces, 34 extends, throws, type bounds, etc. 35 - method which overrides @hide method: should appear in subclass (test chain 36 of two nested too) 37 - BluetoothGattCharacteristic.java#describeContents: Was marked @hide, 38 but is unhidden because it extends a public interface method 39 - package javadoc (also make sure merging both!, e.g. try having @hide in each) 40 - StopWatchMap -- inner class with @hide marks allh top levels! 41 - Test field inlining: should I include fields from an interface, if that 42 inteface was implemented by the parent class (and therefore appears there too?) 43 What if the superclass is abstract? 44 - Exposing package private classes. Test that I only do this for package private 45 classes, NOT Those marked @hide (is that, having @hide on a used type, illegal?) 46 - Test error handling (invalid @hide combinations)) 47 - Consider what happens if we promote a package private class (because it's 48 extended by a public class), and then we restore its public members; the 49 override logic there isn't quite right. We've duplicated the significant-override 50 code to not skip private members, but that could change semantics. This isn't 51 ideal; instead we should now mark this class as public, and re-run the analysis 52 again (with the new hidden state for this class). 53 - compilation unit sorting - top level classes out of order 54 - Massive classes such as android.R.java? Maybe do synthetic test. 55 - HttpResponseCache implemented a public OkHttp interface, but the sole implementation 56 method was marked @hide, so the method doesn't show up. Is that some other rule -- 57 that we skip interfaces if their implementation methods are marked @hide? 58 - Test recursive package filtering. 59 */ 60 61 @Test Basic class signature extractionnull62 fun `Basic class signature extraction`() { 63 // Basic class; also checks that default constructor is made explicit 64 check( 65 sourceFiles = arrayOf( 66 java( 67 """ 68 package test.pkg; 69 public class Foo { 70 } 71 """ 72 ) 73 ), 74 api = """ 75 package test.pkg { 76 public class Foo { 77 ctor public Foo(); 78 } 79 } 80 """ 81 ) 82 } 83 84 @Test Parameter Names in Javanull85 fun `Parameter Names in Java`() { 86 // Java code which explicitly specifies parameter names 87 check( 88 sourceFiles = arrayOf( 89 java( 90 """ 91 package test.pkg; 92 import androidx.annotation.ParameterName; 93 94 public class Foo { 95 public void foo(int javaParameter1, @ParameterName("publicParameterName") int javaParameter2) { 96 } 97 } 98 """ 99 ), 100 supportParameterName 101 ), 102 api = """ 103 package test.pkg { 104 public class Foo { 105 ctor public Foo(); 106 method public void foo(int, int publicParameterName); 107 } 108 } 109 """, 110 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation") 111 ) 112 } 113 114 @Test Default Values Names in Javanull115 fun `Default Values Names in Java`() { 116 // Java code which explicitly specifies parameter names 117 check( 118 format = FileFormat.V3, 119 sourceFiles = arrayOf( 120 java( 121 """ 122 package test.pkg; 123 import androidx.annotation.DefaultValue; 124 125 public class Foo { 126 public void foo( 127 @DefaultValue("null") String prefix, 128 @DefaultValue("\"Hello World\"") String greeting, 129 @DefaultValue("42") int meaning) { 130 } 131 } 132 """ 133 ), 134 supportDefaultValue 135 ), 136 api = """ 137 // Signature format: 3.0 138 package test.pkg { 139 public class Foo { 140 ctor public Foo(); 141 method public void foo(String! = null, String! = "Hello World", int = 42); 142 } 143 } 144 """, 145 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation") 146 ) 147 } 148 149 @Test Default Values and Names in Kotlinnull150 fun `Default Values and Names in Kotlin`() { 151 // Kotlin code which explicitly specifies parameter names 152 check( 153 format = FileFormat.V3, 154 sourceFiles = arrayOf( 155 kotlin( 156 """ 157 package test.pkg 158 import some.other.pkg.Constants.Misc.SIZE 159 import android.graphics.Bitmap 160 import android.view.View 161 162 class Foo { 163 fun method1(myInt: Int = 42, 164 myInt2: Int? = null, 165 myByte: Int = 2 * 21, 166 str: String = "hello " + "world", 167 vararg args: String) { } 168 169 fun method2(myInt: Int, myInt2: Int = (2*int) * SIZE) { } 170 171 fun method3(str: String, myInt: Int, myInt2: Int = double(int) + str.length) { } 172 173 fun emptyLambda(sizeOf: () -> Unit = { }) {} 174 175 fun View.drawToBitmap(config: Bitmap.Config = Bitmap.Config.ARGB_8888): Bitmap? = null 176 177 companion object { 178 fun double(myInt: Int) = 2 * myInt 179 fun print(foo: Foo = Foo()) { println(foo) } 180 } 181 } 182 """ 183 ), 184 java( 185 """ 186 package some.other.pkg; 187 public class Constants { 188 public static class Misc { 189 public static final int SIZE = 5; 190 } 191 } 192 """ 193 ) 194 ), 195 api = """ 196 // Signature format: 3.0 197 package test.pkg { 198 public final class Foo { 199 ctor public Foo(); 200 method public android.graphics.Bitmap? drawToBitmap(android.view.View, android.graphics.Bitmap.Config config = android.graphics.Bitmap.Config.ARGB_8888); 201 method public void emptyLambda(kotlin.jvm.functions.Function0<kotlin.Unit> sizeOf = {}); 202 method public void method1(int myInt = 42, Integer? myInt2 = null, int myByte = 42, String str = "hello world", java.lang.String... args); 203 method public void method2(int myInt, int myInt2 = (2 * int) * some.other.pkg.Constants.Misc.SIZE); 204 method public void method3(String str, int myInt, int myInt2 = double(int) + str.length); 205 field public static final test.pkg.Foo.Companion Companion; 206 } 207 public static final class Foo.Companion { 208 method public int double(int myInt); 209 method public void print(test.pkg.Foo foo = test.pkg.Foo()); 210 } 211 } 212 """, 213 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation", ARG_HIDE_PACKAGE, "some.other.pkg"), 214 includeSignatureVersion = true 215 ) 216 } 217 218 @Test Default Values in Kotlin for expressionsnull219 fun `Default Values in Kotlin for expressions`() { 220 // Testing trickier default values; regression test for problem 221 // observed in androidx.core.util with LruCache 222 check( 223 format = FileFormat.V3, 224 sourceFiles = arrayOf( 225 kotlin( 226 """ 227 package androidx.core.util 228 229 import android.util.LruCache 230 231 inline fun <K : Any, V : Any> lruCache( 232 maxSize: Int, 233 crossinline sizeOf: (key: K, value: V) -> Int = { _, _ -> 1 }, 234 @Suppress("USELESS_CAST") // https://youtrack.jetbrains.com/issue/KT-21946 235 crossinline create: (key: K) -> V? = { null as V? }, 236 crossinline onEntryRemoved: (evicted: Boolean, key: K, oldValue: V, newValue: V?) -> Unit = 237 { _, _, _, _ -> } 238 ): LruCache<K, V> { 239 return object : LruCache<K, V>(maxSize) { 240 override fun sizeOf(key: K, value: V) = sizeOf(key, value) 241 override fun create(key: K) = create(key) 242 override fun entryRemoved(evicted: Boolean, key: K, oldValue: V, newValue: V?) { 243 onEntryRemoved(evicted, key, oldValue, newValue) 244 } 245 } 246 } 247 """ 248 ), 249 java( 250 """ 251 package androidx.collection; 252 253 import androidx.annotation.NonNull; 254 import androidx.annotation.Nullable; 255 256 import java.util.LinkedHashMap; 257 import java.util.Locale; 258 import java.util.Map; 259 260 public class LruCache<K, V> { 261 @Nullable 262 protected V create(@NonNull K key) { 263 return null; 264 } 265 266 protected int sizeOf(@NonNull K key, @NonNull V value) { 267 return 1; 268 } 269 270 protected void entryRemoved(boolean evicted, @NonNull K key, @NonNull V oldValue, 271 @Nullable V newValue) { 272 } 273 } 274 """ 275 ), 276 androidxNullableSource, 277 androidxNonNullSource 278 ), 279 api = """ 280 // Signature format: 3.0 281 package androidx.core.util { 282 public final class TestKt { 283 method public static inline <K, V> android.util.LruCache<K,V> lruCache(int maxSize, kotlin.jvm.functions.Function2<? super K,? super V,java.lang.Integer> sizeOf = { _, _ -> return 1 }, kotlin.jvm.functions.Function1<? super K,? extends V> create = { it -> return null as V }, kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved = { _, _, _, _ -> }); 284 } 285 } 286 """, 287 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation", ARG_HIDE_PACKAGE, "androidx.collection"), 288 includeSignatureVersion = true 289 ) 290 } 291 292 @Test Basic Kotlin classnull293 fun `Basic Kotlin class`() { 294 check( 295 format = FileFormat.V1, 296 sourceFiles = arrayOf( 297 kotlin( 298 """ 299 package test.pkg 300 class Kotlin(val property1: String = "Default Value", arg2: Int) : Parent() { 301 override fun method() = "Hello World" 302 fun otherMethod(ok: Boolean, times: Int) { 303 } 304 305 var property2: String? = null 306 307 private var someField = 42 308 @JvmField 309 var someField2 = 42 310 311 internal var myHiddenVar = false 312 internal fun myHiddenMethod() { } 313 internal data class myHiddenClass(): Unit 314 315 companion object { 316 const val MY_CONST = 42 317 } 318 } 319 320 //@get:RequiresApi(26) 321 inline val @receiver:String Long.isSrgb get() = true 322 inline val /*@receiver:ColorInt*/ Int.red get() = 0 323 inline operator fun String.component1() = "" 324 325 open class Parent { 326 open fun method(): String? = null 327 open fun method2(value: Boolean, value: Boolean?): String? = null 328 open fun method3(value: Int?, value2: Int): Int = null 329 } 330 """ 331 ) 332 ), 333 api = """ 334 package test.pkg { 335 public final class Kotlin extends test.pkg.Parent { 336 ctor public Kotlin(@NonNull String property1, int arg2); 337 method @NonNull public String getProperty1(); 338 method @Nullable public String getProperty2(); 339 method public void otherMethod(boolean ok, int times); 340 method public void setProperty2(@Nullable String); 341 property @NonNull public final String property1; 342 property @Nullable public final String property2; 343 field @NonNull public static final test.pkg.Kotlin.Companion Companion; 344 field public static final int MY_CONST = 42; // 0x2a 345 field public int someField2; 346 } 347 public static final class Kotlin.Companion { 348 } 349 public final class KotlinKt { 350 method @NonNull public static inline operator String component1(@NonNull String); 351 method public static inline int getRed(int); 352 method public static inline boolean isSrgb(long); 353 } 354 public class Parent { 355 ctor public Parent(); 356 method @Nullable public String method(); 357 method @Nullable public String method2(boolean value, @Nullable Boolean value); 358 method public int method3(@Nullable Integer value, int value2); 359 } 360 } 361 """ 362 ) 363 } 364 365 @Test Kotlin Reified Methodsnull366 fun `Kotlin Reified Methods`() { 367 check( 368 format = FileFormat.V1, 369 sourceFiles = arrayOf( 370 java( 371 """ 372 package test.pkg; 373 374 public class Context { 375 @SuppressWarnings("unchecked") 376 public final <T> T getSystemService(Class<T> serviceClass) { 377 return null; 378 } 379 } 380 """ 381 ), 382 kotlin( 383 """ 384 package test.pkg 385 386 inline fun <reified T> Context.systemService1() = getSystemService(T::class.java) 387 inline fun Context.systemService2() = getSystemService(String::class.java) 388 """ 389 ) 390 ), 391 api = """ 392 package test.pkg { 393 public class Context { 394 ctor public Context(); 395 method public final <T> T getSystemService(Class<T>); 396 } 397 public final class TestKt { 398 method public static inline <reified T> T systemService1(@NonNull test.pkg.Context); 399 method public static inline String systemService2(@NonNull test.pkg.Context); 400 } 401 } 402 """ 403 ) 404 } 405 406 @Test Kotlin Reified Methods 2null407 fun `Kotlin Reified Methods 2`() { 408 check( 409 format = FileFormat.V2, 410 sourceFiles = arrayOf( 411 kotlin( 412 """ 413 @file:Suppress("NOTHING_TO_INLINE", "RedundantVisibilityModifier", "unused") 414 415 package test.pkg 416 417 inline fun <T> a(t: T) { } 418 inline fun <reified T> b(t: T) { } 419 private inline fun <reified T> c(t: T) { } // hide 420 internal inline fun <reified T> d(t: T) { } // hide 421 public inline fun <reified T> e(t: T) { } 422 inline fun <reified T> T.f(t: T) { } 423 """ 424 ) 425 ), 426 api = """ 427 package test.pkg { 428 public final class TestKt { 429 method public static inline <T> void a(@Nullable T t); 430 method public static inline <reified T> void b(@Nullable T t); 431 method public static inline <reified T> void e(@Nullable T t); 432 method public static inline <reified T> void f(@Nullable T, @Nullable T t); 433 } 434 } 435 """ 436 ) 437 } 438 439 @Test Suspend functionsnull440 fun `Suspend functions`() { 441 check( 442 format = FileFormat.V2, 443 sourceFiles = arrayOf( 444 kotlin( 445 """ 446 package test.pkg 447 suspend inline fun hello(foo: Int) { } 448 suspend fun helloTwoContinuations(myContinuation: kotlin.coroutines.Continuation<Any>) { } 449 internal suspend fun internalHello() { } 450 private suspend fun privateHello() { } 451 """ 452 ) 453 ), 454 api = """ 455 package test.pkg { 456 public final class TestKt { 457 method @Nullable public static suspend inline Object hello(int foo, @NonNull kotlin.coroutines.Continuation<? super kotlin.Unit>); 458 method @Nullable public static suspend Object helloTwoContinuations(@NonNull kotlin.coroutines.Continuation<java.lang.Object> myContinuation, @NonNull kotlin.coroutines.Continuation<? super kotlin.Unit>); 459 } 460 } 461 """ 462 ) 463 } 464 465 @Test Var properties with private settersnull466 fun `Var properties with private setters`() { 467 check( 468 format = FileFormat.V3, 469 sourceFiles = arrayOf( 470 kotlin( 471 """ 472 package test.pkg 473 class MyClass { 474 // This property should have no public setter 475 var readOnlyVar = false 476 internal set 477 // This property should have no public setter 478 public var readOnlyVarWithPublicModifer = false 479 internal set 480 } 481 """ 482 ) 483 ), 484 api = """ 485 // Signature format: 3.0 486 package test.pkg { 487 public final class MyClass { 488 ctor public MyClass(); 489 method public boolean getReadOnlyVar(); 490 method public boolean getReadOnlyVarWithPublicModifer(); 491 property public final boolean readOnlyVar; 492 property public final boolean readOnlyVarWithPublicModifer; 493 } 494 } 495 """ 496 ) 497 } 498 499 @Test Kotlin Genericsnull500 fun `Kotlin Generics`() { 501 check( 502 format = FileFormat.V3, 503 sourceFiles = arrayOf( 504 kotlin( 505 """ 506 package test.pkg 507 class Bar 508 class Type<in T> { 509 fun foo(param: Type<Bar>) { 510 } 511 } 512 """ 513 ) 514 ), 515 api = """ 516 // Signature format: 3.0 517 package test.pkg { 518 public final class Bar { 519 ctor public Bar(); 520 } 521 public final class Type<T> { 522 ctor public Type(); 523 method public void foo(test.pkg.Type<? super test.pkg.Bar> param); 524 } 525 } 526 """ 527 ) 528 } 529 530 @Test Nullness in reified signaturesnull531 fun `Nullness in reified signatures`() { 532 check( 533 sourceFiles = arrayOf( 534 kotlin( 535 "src/test/pkg/test.kt", 536 """ 537 package test.pkg 538 539 import androidx.annotation.UiThread 540 import test.pkg2.NavArgs 541 import test.pkg2.NavArgsLazy 542 import test.pkg2.Fragment 543 import test.pkg2.Bundle 544 545 @UiThread 546 inline fun <reified Args : NavArgs> Fragment.navArgs() = NavArgsLazy(Args::class) { 547 throw IllegalStateException("Fragment $this has null arguments") 548 } 549 """ 550 ), 551 kotlin( 552 """ 553 package test.pkg2 554 555 import kotlin.reflect.KClass 556 557 interface NavArgs 558 class Fragment 559 class Bundle 560 class NavArgsLazy<Args : NavArgs>( 561 private val navArgsClass: KClass<Args>, 562 private val argumentProducer: () -> Bundle 563 ) 564 """ 565 ), 566 uiThreadSource 567 ), 568 api = """ 569 // Signature format: 3.0 570 package test.pkg { 571 public final class TestKt { 572 method @UiThread public static inline <reified Args extends test.pkg2.NavArgs> test.pkg2.NavArgsLazy<Args>! navArgs(test.pkg2.Fragment); 573 } 574 } 575 """, 576 // Actual expected API is below. However, due to KT-39209 the nullability information is 577 // missing 578 // api = """ 579 // // Signature format: 3.0 580 // package test.pkg { 581 // public final class TestKt { 582 // method @UiThread public static inline <reified Args extends test.pkg2.NavArgs> test.pkg2.NavArgsLazy<Args> navArgs(test.pkg2.Fragment); 583 // } 584 // } 585 // """, 586 format = FileFormat.V3, 587 extraArguments = arrayOf( 588 ARG_HIDE_PACKAGE, "androidx.annotation", 589 ARG_HIDE_PACKAGE, "test.pkg2", 590 ARG_HIDE, "ReferencesHidden", 591 ARG_HIDE, "UnavailableSymbol", 592 ARG_HIDE, "HiddenTypeParameter", 593 ARG_HIDE, "HiddenSuperclass" 594 ) 595 ) 596 } 597 598 @Test Nullness in varargsnull599 fun `Nullness in varargs`() { 600 check( 601 sourceFiles = arrayOf( 602 java( 603 """ 604 package androidx.collection; 605 606 import java.util.Collection; 607 import java.util.HashMap; 608 import java.util.Map; 609 610 public class ArrayMap<K, V> extends HashMap<K, V> implements Map<K, V> { 611 public ArrayMap() { 612 } 613 } 614 """ 615 ), 616 java( 617 """ 618 package androidx.core.app; 619 620 import java.util.ArrayList; 621 import java.util.List; 622 623 import androidx.annotation.NonNull; 624 import androidx.annotation.Nullable; 625 626 public class ActivityOptionsCompat { 627 private ActivityOptionsCompat() { 628 } 629 @NonNull 630 public static List<String> javaListOf(String... sharedElements) { 631 return new ArrayList<String>(); 632 } 633 @Nullable 634 public static List<String> javaListOfNullable(String... sharedElements) { 635 return null; 636 } 637 638 } 639 """ 640 ), 641 kotlin( 642 "src/main/java/androidx/collection/ArrayMap.kt", 643 """ 644 package androidx.collection 645 646 inline fun <K, V> arrayMapOf(): ArrayMap<K, V> = ArrayMap() 647 648 fun <K, V> arrayMapOf(vararg pairs: Pair<K, V>): ArrayMap<K, V> { 649 val map = ArrayMap<K, V>(pairs.size) 650 for (pair in pairs) { 651 map[pair.first] = pair.second 652 } 653 return map 654 } 655 fun <K, V> arrayMapOfNullable(vararg pairs: Pair<K, V>?): ArrayMap<K, V>? { 656 return null 657 } 658 """ 659 ), 660 androidxNonNullSource, 661 androidxNullableSource 662 ), 663 api = """ 664 // Signature format: 3.0 665 package androidx.collection { 666 public class ArrayMap<K, V> extends java.util.HashMap<K,V> implements java.util.Map<K,V> { 667 ctor public ArrayMap(); 668 } 669 public final class ArrayMapKt { 670 method public static inline <K, V> androidx.collection.ArrayMap<K,V> arrayMapOf(); 671 method public static <K, V> androidx.collection.ArrayMap<K,V> arrayMapOf(kotlin.Pair<? extends K,? extends V>... pairs); 672 method public static <K, V> androidx.collection.ArrayMap<K,V>? arrayMapOfNullable(kotlin.Pair<? extends K,? extends V>?... pairs); 673 } 674 } 675 package androidx.core.app { 676 public class ActivityOptionsCompat { 677 method public static java.util.List<java.lang.String!> javaListOf(java.lang.String!...); 678 method public static java.util.List<java.lang.String!>? javaListOfNullable(java.lang.String!...); 679 } 680 } 681 """, 682 format = FileFormat.V3, 683 extraArguments = arrayOf( 684 ARG_HIDE_PACKAGE, "androidx.annotation", 685 ARG_HIDE, "ReferencesHidden", 686 ARG_HIDE, "UnavailableSymbol", 687 ARG_HIDE, "HiddenTypeParameter" 688 ) 689 ) 690 } 691 692 @Test Propagate Platform types in Kotlinnull693 fun `Propagate Platform types in Kotlin`() { 694 check( 695 format = FileFormat.V3, 696 sourceFiles = arrayOf( 697 kotlin( 698 """ 699 // Nullable Pair in Kotlin 700 package androidx.util 701 702 class NullableKotlinPair<out F, out S>(val first: F?, val second: S?) 703 """ 704 ), 705 kotlin( 706 """ 707 // Non-nullable Pair in Kotlin 708 package androidx.util 709 class NonNullableKotlinPair<out F: Any, out S: Any>(val first: F, val second: S) 710 """ 711 ), 712 java( 713 """ 714 // Platform nullability Pair in Java 715 package androidx.util; 716 717 @SuppressWarnings("WeakerAccess") 718 public class PlatformJavaPair<F, S> { 719 public final F first; 720 public final S second; 721 722 public PlatformJavaPair(F first, S second) { 723 this.first = first; 724 this.second = second; 725 } 726 } 727 """ 728 ), 729 java( 730 """ 731 // Platform nullability Pair in Java 732 package androidx.util; 733 import androidx.annotation.NonNull; 734 import androidx.annotation.Nullable; 735 736 @SuppressWarnings("WeakerAccess") 737 public class NullableJavaPair<F, S> { 738 public final @Nullable F first; 739 public final @Nullable S second; 740 741 public NullableJavaPair(@Nullable F first, @Nullable S second) { 742 this.first = first; 743 this.second = second; 744 } 745 } 746 """ 747 ), 748 java( 749 """ 750 // Platform nullability Pair in Java 751 package androidx.util; 752 753 import androidx.annotation.NonNull; 754 755 @SuppressWarnings("WeakerAccess") 756 public class NonNullableJavaPair<F, S> { 757 public final @NonNull F first; 758 public final @NonNull S second; 759 760 public NonNullableJavaPair(@NonNull F first, @NonNull S second) { 761 this.first = first; 762 this.second = second; 763 } 764 } 765 """ 766 ), 767 kotlin( 768 """ 769 package androidx.util 770 771 @Suppress("HasPlatformType") // Intentionally propagating platform type with unknown nullability. 772 inline operator fun <F, S> PlatformJavaPair<F, S>.component1() = first 773 """ 774 ), 775 androidxNonNullSource, 776 androidxNullableSource 777 ), 778 api = """ 779 // Signature format: 3.0 780 package androidx.util { 781 public class NonNullableJavaPair<F, S> { 782 ctor public NonNullableJavaPair(F, S); 783 field public final F first; 784 field public final S second; 785 } 786 public final class NonNullableKotlinPair<F, S> { 787 ctor public NonNullableKotlinPair(F first, S second); 788 method public F getFirst(); 789 method public S getSecond(); 790 property public final F first; 791 property public final S second; 792 } 793 public class NullableJavaPair<F, S> { 794 ctor public NullableJavaPair(F?, S?); 795 field public final F? first; 796 field public final S? second; 797 } 798 public final class NullableKotlinPair<F, S> { 799 ctor public NullableKotlinPair(F? first, S? second); 800 method public F? getFirst(); 801 method public S? getSecond(); 802 property public final F? first; 803 property public final S? second; 804 } 805 public class PlatformJavaPair<F, S> { 806 ctor public PlatformJavaPair(F!, S!); 807 field public final F! first; 808 field public final S! second; 809 } 810 public final class TestKt { 811 method public static inline operator <F, S> F! component1(androidx.util.PlatformJavaPair<F,S>); 812 } 813 } 814 """, 815 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation") 816 ) 817 } 818 819 @Test Known nullnessnull820 fun `Known nullness`() { 821 // Don't emit platform types for some unannotated elements that we know the 822 // nullness for: annotation type members, equals-parameters, initialized constants, etc. 823 check( 824 format = FileFormat.V3, 825 outputKotlinStyleNulls = true, 826 sourceFiles = arrayOf( 827 java( 828 """ 829 // Platform nullability Pair in Java 830 package test; 831 832 import androidx.annotation.NonNull; 833 834 public class MyClass { 835 public static final String MY_CONSTANT1 = "constant"; // Not nullable 836 public final String MY_CONSTANT2 = "constant"; // Not nullable 837 public String MY_CONSTANT3 = "constant"; // Unknown 838 839 /** @deprecated */ 840 @Deprecated 841 @Override 842 public boolean equals( 843 Object parameter // nullable 844 ) { 845 return super.equals(parameter); 846 } 847 848 /** @deprecated */ 849 @Deprecated 850 @Override // Not nullable 851 public String toString() { 852 return super.toString(); 853 } 854 } 855 """ 856 ), 857 java( 858 """ 859 package test.pkg; 860 861 import static java.lang.annotation.ElementType.*; 862 import java.lang.annotation.*; 863 public @interface MyAnnotation { 864 String[] value(); // Not nullable 865 } 866 """ 867 ).indented(), 868 java( 869 """ 870 package test.pkg; 871 @SuppressWarnings("ALL") 872 public enum Foo { 873 A, B; 874 } 875 """ 876 ), 877 kotlin( 878 """ 879 package test.pkg 880 enum class Language { 881 KOTLIN, 882 JAVA 883 } 884 """ 885 ).indented(), 886 kotlin( 887 """ 888 package test.pkg 889 class Issue { 890 fun setAndroidSpecific(value: Boolean): Issue { return this } 891 companion object { 892 @JvmStatic 893 fun create( 894 id: String, 895 briefDescription: String, 896 explanation: String 897 ): Issue { 898 return Issue() 899 } 900 } 901 } 902 """ 903 ).indented(), 904 kotlin( 905 """ 906 package test.pkg 907 object MySingleton { 908 } 909 """ 910 ).indented(), 911 java( 912 """ 913 package test.pkg; 914 public class WrongCallDetector { 915 public static final Issue ISSUE = 916 Issue.create( 917 "WrongCall", 918 "Using wrong draw/layout method", 919 "Custom views typically need to call `measure()`) 920 .setAndroidSpecific(true)); 921 } 922 """ 923 ).indented(), 924 androidxNonNullSource, 925 androidxNullableSource 926 ), 927 api = """ 928 // Signature format: 3.0 929 package test { 930 public class MyClass { 931 ctor public MyClass(); 932 method @Deprecated public boolean equals(Object?); 933 method @Deprecated public String toString(); 934 field public static final String MY_CONSTANT1 = "constant"; 935 field public final String MY_CONSTANT2 = "constant"; 936 field public String! MY_CONSTANT3; 937 } 938 } 939 package test.pkg { 940 public enum Foo { 941 enum_constant public static final test.pkg.Foo A; 942 enum_constant public static final test.pkg.Foo B; 943 } 944 public final class Issue { 945 ctor public Issue(); 946 method public static test.pkg.Issue create(String id, String briefDescription, String explanation); 947 method public test.pkg.Issue setAndroidSpecific(boolean value); 948 field public static final test.pkg.Issue.Companion Companion; 949 } 950 public static final class Issue.Companion { 951 method public test.pkg.Issue create(String id, String briefDescription, String explanation); 952 } 953 public enum Language { 954 enum_constant public static final test.pkg.Language JAVA; 955 enum_constant public static final test.pkg.Language KOTLIN; 956 } 957 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface MyAnnotation { 958 method public abstract String[] value(); 959 } 960 public final class MySingleton { 961 field public static final test.pkg.MySingleton INSTANCE; 962 } 963 public class WrongCallDetector { 964 ctor public WrongCallDetector(); 965 field public static final test.pkg.Issue ISSUE; 966 } 967 } 968 """, 969 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation") 970 ) 971 } 972 973 @Test JvmOverloadsnull974 fun JvmOverloads() { 975 // Regression test for https://github.com/android/android-ktx/issues/366 976 check( 977 format = FileFormat.V3, 978 sourceFiles = arrayOf( 979 kotlin( 980 """ 981 package androidx.content 982 983 import android.annotation.SuppressLint 984 import android.content.SharedPreferences 985 986 @SuppressLint("ApplySharedPref") 987 @JvmOverloads 988 inline fun SharedPreferences.edit( 989 commit: Boolean = false, 990 action: SharedPreferences.Editor.() -> Unit 991 ) { 992 val editor = edit() 993 action(editor) 994 if (commit) { 995 editor.commit() 996 } else { 997 editor.apply() 998 } 999 } 1000 1001 @JvmOverloads 1002 fun String.blahblahblah(firstArg: String = "hello", secondArg: Int = 42, thirdArg: String = "world") { 1003 } 1004 """ 1005 ) 1006 ), 1007 api = """ 1008 // Signature format: 3.0 1009 package androidx.content { 1010 public final class TestKt { 1011 method public static void blahblahblah(String, String firstArg = "hello", int secondArg = 42, String thirdArg = "world"); 1012 method public static void blahblahblah(String, String firstArg = "hello", int secondArg = 42); 1013 method public static void blahblahblah(String, String firstArg = "hello"); 1014 method public static void blahblahblah(String); 1015 method public static inline void edit(android.content.SharedPreferences, boolean commit = false, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action); 1016 method public static inline void edit(android.content.SharedPreferences, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action); 1017 } 1018 } 1019 """, 1020 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation") 1021 ) 1022 } 1023 1024 @Test Test JvmStaticnull1025 fun `Test JvmStatic`() { 1026 check( 1027 sourceFiles = arrayOf( 1028 kotlin( 1029 """ 1030 package test.pkg 1031 1032 class SimpleClass { 1033 companion object { 1034 @JvmStatic 1035 fun jvmStaticMethod() {} 1036 fun nonJvmStaticMethod() {} 1037 } 1038 } 1039 """ 1040 ) 1041 ), 1042 format = FileFormat.V3, 1043 api = """ 1044 // Signature format: 3.0 1045 package test.pkg { 1046 public final class SimpleClass { 1047 ctor public SimpleClass(); 1048 method public static void jvmStaticMethod(); 1049 field public static final test.pkg.SimpleClass.Companion Companion; 1050 } 1051 public static final class SimpleClass.Companion { 1052 method public void jvmStaticMethod(); 1053 method public void nonJvmStaticMethod(); 1054 } 1055 } 1056 """ 1057 ) 1058 } 1059 1060 @Test Test JvmFieldnull1061 fun `Test JvmField`() { 1062 check( 1063 sourceFiles = arrayOf( 1064 kotlin( 1065 """ 1066 package test.pkg 1067 1068 class SimpleClass { 1069 @JvmField 1070 var jvmField = -1 1071 1072 var nonJvmField = -2 1073 } 1074 """ 1075 ) 1076 ), 1077 format = FileFormat.V3, 1078 api = """ 1079 // Signature format: 3.0 1080 package test.pkg { 1081 public final class SimpleClass { 1082 ctor public SimpleClass(); 1083 method public int getNonJvmField(); 1084 method public void setNonJvmField(int); 1085 property public final int nonJvmField; 1086 field public int jvmField; 1087 } 1088 } 1089 """ 1090 ) 1091 } 1092 1093 @Test Test JvmNamenull1094 fun `Test JvmName`() { 1095 check( 1096 sourceFiles = arrayOf( 1097 kotlin( 1098 """ 1099 package test.pkg 1100 1101 class SimpleClass { 1102 @get:JvmName("myPropertyJvmGetter") 1103 var myProperty = -1 1104 1105 var anotherProperty = -1 1106 } 1107 """ 1108 ) 1109 ), 1110 format = FileFormat.V3, 1111 api = """ 1112 // Signature format: 3.0 1113 package test.pkg { 1114 public final class SimpleClass { 1115 ctor public SimpleClass(); 1116 method public int getAnotherProperty(); 1117 method public int myPropertyJvmGetter(); 1118 method public void setAnotherProperty(int); 1119 method public void setMyProperty(int); 1120 property public final int anotherProperty; 1121 property public final int myProperty; 1122 } 1123 } 1124 """ 1125 ) 1126 } 1127 1128 @Test Test RequiresOptIn and OptInnull1129 fun `Test RequiresOptIn and OptIn`() { 1130 check( 1131 sourceFiles = arrayOf( 1132 kotlin( 1133 """ 1134 package test.pkg 1135 1136 @RequiresOptIn 1137 @Retention(AnnotationRetention.BINARY) 1138 @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) 1139 annotation class ExperimentalBar 1140 1141 @ExperimentalBar 1142 class FancyBar 1143 1144 @OptIn(FancyBar::class) // @OptIn should not be tracked as it is not API 1145 class SimpleClass { 1146 fun methodUsingFancyBar() { 1147 val fancyBar = FancyBar() 1148 } 1149 } 1150 """ 1151 ) 1152 ), 1153 format = FileFormat.V3, 1154 api = """ 1155 // Signature format: 3.0 1156 package test.pkg { 1157 @kotlin.RequiresOptIn @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public @interface ExperimentalBar { 1158 } 1159 @test.pkg.ExperimentalBar public final class FancyBar { 1160 ctor public FancyBar(); 1161 } 1162 public final class SimpleClass { 1163 ctor public SimpleClass(); 1164 method public void methodUsingFancyBar(); 1165 } 1166 } 1167 """ 1168 ) 1169 } 1170 1171 @Test Test Experimental and UseExperimentalnull1172 fun `Test Experimental and UseExperimental`() { 1173 check( 1174 sourceFiles = arrayOf( 1175 kotlin( 1176 """ 1177 package test.pkg 1178 1179 @Experimental 1180 @Retention(AnnotationRetention.BINARY) 1181 @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) 1182 annotation class ExperimentalBar 1183 1184 @ExperimentalBar 1185 class FancyBar 1186 1187 @UseExperimental(FancyBar::class) // @UseExperimental should not be tracked as it is not API 1188 class SimpleClass { 1189 fun methodUsingFancyBar() { 1190 val fancyBar = FancyBar() 1191 } 1192 } 1193 1194 @androidx.annotation.experimental.UseExperimental(FancyBar::class) // @UseExperimental should not be tracked as it is not API 1195 class AnotherSimpleClass { 1196 fun methodUsingFancyBar() { 1197 val fancyBar = FancyBar() 1198 } 1199 } 1200 """ 1201 ), 1202 kotlin( 1203 """ 1204 package androidx.annotation.experimental 1205 1206 import kotlin.annotation.Retention 1207 import kotlin.annotation.Target 1208 import kotlin.reflect.KClass 1209 1210 @Retention(AnnotationRetention.BINARY) 1211 @Target( 1212 AnnotationTarget.CLASS, 1213 AnnotationTarget.PROPERTY, 1214 AnnotationTarget.LOCAL_VARIABLE, 1215 AnnotationTarget.VALUE_PARAMETER, 1216 AnnotationTarget.CONSTRUCTOR, 1217 AnnotationTarget.FUNCTION, 1218 AnnotationTarget.PROPERTY_GETTER, 1219 AnnotationTarget.PROPERTY_SETTER, 1220 AnnotationTarget.FILE, 1221 AnnotationTarget.TYPEALIAS 1222 ) 1223 annotation class UseExperimental( 1224 /** 1225 * Defines the experimental API(s) whose usage this annotation allows. 1226 */ 1227 vararg val markerClass: KClass<out Annotation> 1228 ) 1229 """ 1230 ) 1231 ), 1232 format = FileFormat.V3, 1233 api = """ 1234 // Signature format: 3.0 1235 package androidx.annotation.experimental { 1236 @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.FILE, kotlin.annotation.AnnotationTarget.TYPEALIAS}) public @interface UseExperimental { 1237 method public abstract kotlin.reflect.KClass<? extends java.lang.annotation.Annotation>[] markerClass(); 1238 property public abstract kotlin.reflect.KClass<? extends java.lang.annotation.Annotation>[] markerClass; 1239 } 1240 } 1241 package test.pkg { 1242 public final class AnotherSimpleClass { 1243 ctor public AnotherSimpleClass(); 1244 method public void methodUsingFancyBar(); 1245 } 1246 @kotlin.Experimental @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public @interface ExperimentalBar { 1247 } 1248 @test.pkg.ExperimentalBar public final class FancyBar { 1249 ctor public FancyBar(); 1250 } 1251 public final class SimpleClass { 1252 ctor public SimpleClass(); 1253 method public void methodUsingFancyBar(); 1254 } 1255 } 1256 """ 1257 ) 1258 } 1259 1260 @Test Extract class with genericsnull1261 fun `Extract class with generics`() { 1262 // Basic interface with generics; makes sure <T extends Object> is written as just <T> 1263 // Also include some more complex generics expressions to make sure they're serialized 1264 // correctly (in particular, using fully qualified names instead of what appears in 1265 // the source code.) 1266 check( 1267 format = FileFormat.V1, 1268 sourceFiles = arrayOf( 1269 java( 1270 """ 1271 package test.pkg; 1272 @SuppressWarnings("ALL") 1273 public interface MyInterface<T extends Object> 1274 extends MyBaseInterface { 1275 } 1276 """ 1277 ), 1278 java( 1279 """ 1280 package a.b.c; 1281 @SuppressWarnings("ALL") 1282 public interface MyStream<T, S extends MyStream<T, S>> extends test.pkg.AutoCloseable { 1283 } 1284 """ 1285 ), 1286 java( 1287 """ 1288 package test.pkg; 1289 @SuppressWarnings("ALL") 1290 public interface MyInterface2<T extends Number> 1291 extends MyBaseInterface { 1292 class TtsSpan<C extends MyInterface<?>> { } 1293 abstract class Range<T extends Comparable<? super T>> { 1294 protected String myString; 1295 } 1296 } 1297 """ 1298 ), 1299 java( 1300 """ 1301 package test.pkg; 1302 public interface MyBaseInterface { 1303 void fun(int a, String b); 1304 } 1305 """ 1306 ), 1307 java( 1308 """ 1309 package test.pkg; 1310 public interface MyOtherInterface extends MyBaseInterface, AutoCloseable { 1311 void fun(int a, String b); 1312 } 1313 """ 1314 ), 1315 java( 1316 """ 1317 package test.pkg; 1318 public interface AutoCloseable { 1319 } 1320 """ 1321 ) 1322 ), 1323 api = """ 1324 package a.b.c { 1325 public interface MyStream<T, S extends a.b.c.MyStream<T, S>> extends test.pkg.AutoCloseable { 1326 } 1327 } 1328 package test.pkg { 1329 public interface AutoCloseable { 1330 } 1331 public interface MyBaseInterface { 1332 method public void fun(int, String); 1333 } 1334 public interface MyInterface<T> extends test.pkg.MyBaseInterface { 1335 } 1336 public interface MyInterface2<T extends java.lang.Number> extends test.pkg.MyBaseInterface { 1337 } 1338 public abstract static class MyInterface2.Range<T extends java.lang.Comparable<? super T>> { 1339 ctor public MyInterface2.Range(); 1340 field protected String myString; 1341 } 1342 public static class MyInterface2.TtsSpan<C extends test.pkg.MyInterface<?>> { 1343 ctor public MyInterface2.TtsSpan(); 1344 } 1345 public interface MyOtherInterface extends test.pkg.MyBaseInterface test.pkg.AutoCloseable { 1346 } 1347 } 1348 """, 1349 extraArguments = arrayOf(ARG_HIDE, "KotlinKeyword") 1350 ) 1351 } 1352 1353 @Test Basic class without default constructor, has constructors with argsnull1354 fun `Basic class without default constructor, has constructors with args`() { 1355 // Class without private constructors (shouldn't insert default constructor) 1356 check( 1357 sourceFiles = arrayOf( 1358 java( 1359 """ 1360 package test.pkg; 1361 public class Foo { 1362 public Foo(int i) { 1363 1364 } 1365 public Foo(int i, int j) { 1366 } 1367 } 1368 """ 1369 ) 1370 ), 1371 api = """ 1372 package test.pkg { 1373 public class Foo { 1374 ctor public Foo(int); 1375 ctor public Foo(int, int); 1376 } 1377 } 1378 """ 1379 ) 1380 } 1381 1382 @Test Basic class without default constructor, has private constructornull1383 fun `Basic class without default constructor, has private constructor`() { 1384 // Class without private constructors; no default constructor should be inserted 1385 check( 1386 sourceFiles = arrayOf( 1387 java( 1388 """ 1389 package test.pkg; 1390 @SuppressWarnings("ALL") 1391 public class Foo { 1392 private Foo() { 1393 } 1394 } 1395 """ 1396 ) 1397 ), 1398 api = """ 1399 package test.pkg { 1400 public class Foo { 1401 } 1402 } 1403 """ 1404 ) 1405 } 1406 1407 @Test Interface class extractionnull1408 fun `Interface class extraction`() { 1409 // Interface: makes sure the right modifiers etc are shown (and that "package private" methods 1410 // in the interface are taken to be public etc) 1411 check( 1412 format = FileFormat.V1, 1413 sourceFiles = arrayOf( 1414 java( 1415 """ 1416 package test.pkg; 1417 @SuppressWarnings("ALL") 1418 public interface Foo { 1419 void foo(); 1420 } 1421 """ 1422 ) 1423 ), 1424 api = """ 1425 package test.pkg { 1426 public interface Foo { 1427 method public void foo(); 1428 } 1429 } 1430 """ 1431 ) 1432 } 1433 1434 @Test Enum class extractionnull1435 fun `Enum class extraction`() { 1436 check( 1437 format = FileFormat.V1, 1438 sourceFiles = arrayOf( 1439 java( 1440 """ 1441 package test.pkg; 1442 @SuppressWarnings("ALL") 1443 public enum Foo { 1444 A, B; 1445 } 1446 """ 1447 ) 1448 ), 1449 api = """ 1450 package test.pkg { 1451 public enum Foo { 1452 enum_constant public static final test.pkg.Foo A; 1453 enum_constant public static final test.pkg.Foo B; 1454 } 1455 } 1456 """ 1457 ) 1458 } 1459 1460 @Test Enum classnull1461 fun `Enum class`() { 1462 check( 1463 sourceFiles = arrayOf( 1464 java( 1465 """ 1466 package test.pkg; 1467 @SuppressWarnings("ALL") 1468 public enum Foo { 1469 A, B; 1470 } 1471 """ 1472 ) 1473 ), 1474 api = """ 1475 package test.pkg { 1476 public enum Foo { 1477 enum_constant public static final test.pkg.Foo A; 1478 enum_constant public static final test.pkg.Foo B; 1479 } 1480 } 1481 """ 1482 ) 1483 } 1484 1485 @Test Annotation class extractionnull1486 fun `Annotation class extraction`() { 1487 // Interface: makes sure the right modifiers etc are shown (and that "package private" methods 1488 // in the interface are taken to be public etc) 1489 check( 1490 sourceFiles = arrayOf( 1491 java( 1492 """ 1493 package test.pkg; 1494 @SuppressWarnings("ALL") 1495 public @interface Foo { 1496 String value(); 1497 } 1498 """ 1499 ), 1500 java( 1501 """ 1502 package android.annotation; 1503 import static java.lang.annotation.ElementType.*; 1504 import java.lang.annotation.*; 1505 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) 1506 @Retention(RetentionPolicy.CLASS) 1507 @SuppressWarnings("ALL") 1508 public @interface SuppressLint { 1509 String[] value(); 1510 } 1511 """ 1512 ) 1513 ), 1514 api = """ 1515 package android.annotation { 1516 @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 { 1517 method public abstract String[] value(); 1518 } 1519 } 1520 package test.pkg { 1521 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface Foo { 1522 method public abstract String value(); 1523 } 1524 } 1525 """ 1526 ) 1527 } 1528 1529 @Test Skip inherited package private methods from private parentsnull1530 fun `Skip inherited package private methods from private parents`() { 1531 // Include public methods from hidden parents too. 1532 // Real life example: StringBuilder.setLength 1533 check( 1534 expectedIssues = """ 1535 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] 1536 """, 1537 sourceFiles = arrayOf( 1538 java( 1539 """ 1540 package test.pkg; 1541 public class MyStringBuilder<A,B> extends AbstractMyStringBuilder<A,B> { 1542 } 1543 """ 1544 ), 1545 java( 1546 """ 1547 package test.pkg; 1548 class AbstractMyStringBuilder<C,D> extends PublicSuper<C,D> { 1549 public void setLength(int length) { 1550 } 1551 @Override boolean isContiguous() { 1552 return true; 1553 } 1554 @Override boolean concrete() { 1555 return false; 1556 } 1557 } 1558 """ 1559 ), 1560 java( 1561 """ 1562 package test.pkg; 1563 public class PublicSuper<E,F> { 1564 abstract boolean isContiguous(); 1565 boolean concrete() { 1566 return false; 1567 } 1568 } 1569 """ 1570 ) 1571 ), 1572 api = """ 1573 package test.pkg { 1574 public class MyStringBuilder<A, B> extends test.pkg.PublicSuper<A,B> { 1575 ctor public MyStringBuilder(); 1576 method public void setLength(int); 1577 } 1578 public class PublicSuper<E, F> { 1579 ctor public PublicSuper(); 1580 } 1581 } 1582 """ 1583 ) 1584 } 1585 1586 @Test Annotation retentionnull1587 fun `Annotation retention`() { 1588 // For annotations where the java.lang.annotation classes themselves are not 1589 // part of the source tree, ensure that we compute the right retention (runtime, meaning 1590 // it should show up in the stubs file.). 1591 check( 1592 format = FileFormat.V3, 1593 extraArguments = arrayOf(ARG_EXCLUDE_ALL_ANNOTATIONS), 1594 sourceFiles = arrayOf( 1595 java( 1596 """ 1597 package test.pkg; 1598 public @interface Foo { 1599 String value(); 1600 } 1601 """ 1602 ), 1603 java( 1604 """ 1605 package android.annotation; 1606 import static java.lang.annotation.ElementType.*; 1607 import java.lang.annotation.*; 1608 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) 1609 @Retention(RetentionPolicy.CLASS) 1610 @SuppressWarnings("ALL") 1611 public @interface SuppressLint { 1612 String[] value(); 1613 } 1614 """ 1615 ), 1616 kotlin( 1617 """ 1618 package test.pkg 1619 1620 @DslMarker 1621 annotation class ImplicitRuntimeRetention 1622 1623 @Retention(AnnotationRetention.RUNTIME) 1624 annotation class ExplicitRuntimeRetention { 1625 } 1626 """.trimIndent() 1627 ) 1628 ), 1629 api = """ 1630 // Signature format: 3.0 1631 package android.annotation { 1632 @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 { 1633 method public abstract String[] value(); 1634 } 1635 } 1636 package test.pkg { 1637 @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.RUNTIME) public @interface ExplicitRuntimeRetention { 1638 } 1639 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface Foo { 1640 method public abstract String value(); 1641 } 1642 @kotlin.DslMarker public @interface ImplicitRuntimeRetention { 1643 } 1644 } 1645 """.trimIndent(), 1646 stubFiles = arrayOf( 1647 // For annotations where the java.lang.annotation classes themselves are not 1648 // part of the source tree, ensure that we compute the right retention (runtime, meaning 1649 // it should show up in the stubs file.). 1650 java( 1651 """ 1652 package test.pkg; 1653 @SuppressWarnings({"unchecked", "deprecation", "all"}) 1654 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) 1655 public @interface Foo { 1656 public java.lang.String value(); 1657 } 1658 """ 1659 ), 1660 java( 1661 """ 1662 package android.annotation; 1663 @SuppressWarnings({"unchecked", "deprecation", "all"}) 1664 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) 1665 @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}) 1666 public @interface SuppressLint { 1667 public java.lang.String[] value(); 1668 } 1669 """ 1670 ) 1671 ) 1672 ) 1673 } 1674 1675 @Test Superclass signature extractionnull1676 fun `Superclass signature extraction`() { 1677 // Make sure superclass statement is correct; inherited method from parent that has same 1678 // signature isn't included in the child 1679 check( 1680 sourceFiles = arrayOf( 1681 java( 1682 """ 1683 package test.pkg; 1684 @SuppressWarnings("ALL") 1685 public class Foo extends Super { 1686 @Override public void base() { } 1687 public void child() { } 1688 } 1689 """ 1690 ), 1691 java( 1692 """ 1693 package test.pkg; 1694 @SuppressWarnings("ALL") 1695 public class Super { 1696 public void base() { } 1697 } 1698 """ 1699 ) 1700 ), 1701 api = """ 1702 package test.pkg { 1703 public class Foo extends test.pkg.Super { 1704 ctor public Foo(); 1705 method public void child(); 1706 } 1707 public class Super { 1708 ctor public Super(); 1709 method public void base(); 1710 } 1711 } 1712 """ 1713 ) 1714 } 1715 1716 @Test Extract fields with types and initial valuesnull1717 fun `Extract fields with types and initial values`() { 1718 check( 1719 format = FileFormat.V1, 1720 sourceFiles = arrayOf( 1721 java( 1722 """ 1723 package test.pkg; 1724 @SuppressWarnings("ALL") 1725 public class Foo { 1726 private int hidden = 1; 1727 int hidden2 = 2; 1728 /** @hide */ 1729 int hidden3 = 3; 1730 1731 protected int field00; // No value 1732 public static final boolean field01 = true; 1733 public static final int field02 = 42; 1734 public static final long field03 = 42L; 1735 public static final short field04 = 5; 1736 public static final byte field05 = 5; 1737 public static final char field06 = 'c'; 1738 public static final float field07 = 98.5f; 1739 public static final double field08 = 98.5; 1740 public static final String field09 = "String with \"escapes\" and \u00a9..."; 1741 public static final double field10 = Double.NaN; 1742 public static final double field11 = Double.POSITIVE_INFINITY; 1743 1744 public static final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef"; 1745 public static final char HEX_INPUT = 61184; 1746 } 1747 """ 1748 ) 1749 ), 1750 api = """ 1751 package test.pkg { 1752 public class Foo { 1753 ctor public Foo(); 1754 field public static final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef"; 1755 field public static final char HEX_INPUT = 61184; // 0xef00 '\uef00' 1756 field protected int field00; 1757 field public static final boolean field01 = true; 1758 field public static final int field02 = 42; // 0x2a 1759 field public static final long field03 = 42L; // 0x2aL 1760 field public static final short field04 = 5; // 0x5 1761 field public static final byte field05 = 5; // 0x5 1762 field public static final char field06 = 99; // 0x0063 'c' 1763 field public static final float field07 = 98.5f; 1764 field public static final double field08 = 98.5; 1765 field public static final String field09 = "String with \"escapes\" and \u00a9..."; 1766 field public static final double field10 = (0.0/0.0); 1767 field public static final double field11 = (1.0/0.0); 1768 } 1769 } 1770 """ 1771 ) 1772 } 1773 1774 @Test Check all modifiersnull1775 fun `Check all modifiers`() { 1776 // Include as many modifiers as possible to see which ones are included 1777 // in the signature files, and the expected sorting order. 1778 // Note that the signature files treat "deprecated" as a fake modifier. 1779 // Note also how the "protected" modifier on the interface method gets 1780 // promoted to public. 1781 check( 1782 format = FileFormat.V1, 1783 sourceFiles = arrayOf( 1784 java( 1785 """ 1786 package test.pkg; 1787 1788 @SuppressWarnings("ALL") 1789 public abstract class Foo { 1790 @Deprecated private static final long field1 = 5; 1791 @Deprecated private static volatile long field2 = 5; 1792 @Deprecated public static strictfp final synchronized void method1() { } 1793 @Deprecated public static final synchronized native void method2(); 1794 @Deprecated protected static final class Inner1 { } 1795 @Deprecated protected static abstract class Inner2 { } 1796 @Deprecated protected interface Inner3 { 1797 default void method3() { } 1798 static void method4(final int arg) { } 1799 } 1800 } 1801 """ 1802 ) 1803 ), 1804 1805 expectedIssues = """ 1806 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] 1807 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] 1808 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] 1809 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] 1810 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] 1811 """, 1812 1813 api = """ 1814 package test.pkg { 1815 public abstract class Foo { 1816 ctor public Foo(); 1817 method @Deprecated public static final void method1(); 1818 method @Deprecated public static final void method2(); 1819 } 1820 @Deprecated protected static final class Foo.Inner1 { 1821 ctor @Deprecated protected Foo.Inner1(); 1822 } 1823 @Deprecated protected abstract static class Foo.Inner2 { 1824 ctor @Deprecated protected Foo.Inner2(); 1825 } 1826 @Deprecated protected static interface Foo.Inner3 { 1827 method @Deprecated public default void method3(); 1828 method @Deprecated public static void method4(int); 1829 } 1830 } 1831 """ 1832 ) 1833 } 1834 1835 @Test Warn about findViewByIdnull1836 fun `Warn about findViewById`() { 1837 // Include as many modifiers as possible to see which ones are included 1838 // in the signature files, and the expected sorting order. 1839 // Note that the signature files treat "deprecated" as a fake modifier. 1840 // Note also how the "protected" modifier on the interface method gets 1841 // promoted to public. 1842 check( 1843 format = FileFormat.V2, 1844 outputKotlinStyleNulls = false, 1845 sourceFiles = arrayOf( 1846 java( 1847 """ 1848 package test.pkg; 1849 import android.annotation.Nullable; 1850 1851 @SuppressWarnings("ALL") 1852 public abstract class Foo { 1853 @Nullable public String findViewById(int id) { return ""; } 1854 } 1855 """ 1856 ), 1857 nullableSource 1858 ), 1859 1860 expectedIssues = """ 1861 src/test/pkg/Foo.java:6: warning: method test.pkg.Foo.findViewById(int) should not be annotated @Nullable; it should be left unspecified to make it a platform type [ExpectedPlatformType] 1862 """, 1863 extraArguments = arrayOf(ARG_WARNING, "ExpectedPlatformType"), 1864 api = """ 1865 package test.pkg { 1866 public abstract class Foo { 1867 ctor public Foo(); 1868 method public String findViewById(int); 1869 } 1870 } 1871 """ 1872 ) 1873 } 1874 1875 @Test Package with only hidden classes should be removed from signature filesnull1876 fun `Package with only hidden classes should be removed from signature files`() { 1877 // Checks that if we have packages that are hidden, or contain only hidden or doconly 1878 // classes, the entire package is omitted from the signature file. Note how the test.pkg1.sub 1879 // package is not marked @hide, but doclava now treats subpackages of a hidden package 1880 // as also hidden. 1881 check( 1882 sourceFiles = arrayOf( 1883 java( 1884 """ 1885 ${"/** @hide hidden package */" /* avoid dangling javadoc warning */} 1886 package test.pkg1; 1887 """ 1888 ), 1889 java( 1890 """ 1891 package test.pkg1; 1892 @SuppressWarnings("ALL") 1893 public class Foo { 1894 // Hidden by package hide 1895 } 1896 """ 1897 ), 1898 java( 1899 """ 1900 package test.pkg2; 1901 /** @hide hidden class in this package */ 1902 @SuppressWarnings("ALL") 1903 public class Bar { 1904 } 1905 """ 1906 ), 1907 java( 1908 """ 1909 package test.pkg2; 1910 /** @doconly hidden class in this package */ 1911 @SuppressWarnings("ALL") 1912 public class Baz { 1913 } 1914 """ 1915 ), 1916 java( 1917 """ 1918 package test.pkg1.sub; 1919 // Hidden by @hide in package above 1920 @SuppressWarnings("ALL") 1921 public class Test { 1922 } 1923 """ 1924 ), 1925 java( 1926 """ 1927 package test.pkg3; 1928 // The only really visible class 1929 @SuppressWarnings("ALL") 1930 public class Boo { 1931 } 1932 """ 1933 ) 1934 ), 1935 api = """ 1936 package test.pkg3 { 1937 public class Boo { 1938 ctor public Boo(); 1939 } 1940 } 1941 """ 1942 ) 1943 } 1944 1945 @Test Enums can be abstractnull1946 fun `Enums can be abstract`() { 1947 // As per https://bugs.openjdk.java.net/browse/JDK-6287639 1948 // abstract methods in enums should not be listed as abstract, 1949 // but doclava1 does, so replicate this. 1950 // Also checks that we handle both enum fields and regular fields 1951 // and that they are listed separately. 1952 1953 check( 1954 format = FileFormat.V1, 1955 sourceFiles = arrayOf( 1956 java( 1957 """ 1958 package test.pkg; 1959 1960 @SuppressWarnings("ALL") 1961 public enum FooBar { 1962 ABC { 1963 @Override 1964 protected void foo() { } 1965 }, DEF { 1966 @Override 1967 protected void foo() { } 1968 }; 1969 1970 protected abstract void foo(); 1971 public static int field1 = 1; 1972 public int field2 = 2; 1973 } 1974 """ 1975 ) 1976 ), 1977 api = """ 1978 package test.pkg { 1979 public enum FooBar { 1980 method protected abstract void foo(); 1981 enum_constant public static final test.pkg.FooBar ABC; 1982 enum_constant public static final test.pkg.FooBar DEF; 1983 field public static int field1; 1984 field public int field2; 1985 } 1986 } 1987 """ 1988 ) 1989 } 1990 1991 @Test Check correct throws list for genericsnull1992 fun `Check correct throws list for generics`() { 1993 check( 1994 format = FileFormat.V2, 1995 sourceFiles = arrayOf( 1996 java( 1997 """ 1998 package test.pkg; 1999 2000 import java.util.function.Supplier; 2001 2002 @SuppressWarnings("ALL") 2003 public final class Test<T> { 2004 public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { 2005 return null; 2006 } 2007 } 2008 """ 2009 ) 2010 ), 2011 api = """ 2012 package test.pkg { 2013 public final class Test<T> { 2014 ctor public Test(); 2015 method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws X; 2016 } 2017 } 2018 """ 2019 ) 2020 } 2021 2022 @Test Check various generics signature subtletiesnull2023 fun `Check various generics signature subtleties`() { 2024 // Some additional declarations where PSI default type handling diffs from doclava1 2025 check( 2026 format = FileFormat.V1, 2027 sourceFiles = arrayOf( 2028 java( 2029 """ 2030 package test.pkg; 2031 2032 @SuppressWarnings("ALL") 2033 public abstract class Collections { 2034 public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T> collection) { 2035 return null; 2036 } 2037 public abstract <T extends java.util.Collection<java.lang.String>> T addAllTo(T t); 2038 public final class Range<T extends java.lang.Comparable<? super T>> { } 2039 } 2040 """ 2041 ), 2042 java( 2043 """ 2044 package test.pkg; 2045 2046 import java.util.Set; 2047 2048 @SuppressWarnings("ALL") 2049 public class MoreAsserts { 2050 public static void assertEquals(String arg0, Set<? extends Object> arg1, Set<? extends Object> arg2) { } 2051 public static void assertEquals(Set<? extends Object> arg1, Set<? extends Object> arg2) { } 2052 } 2053 2054 """ 2055 ) 2056 ), 2057 api = """ 2058 package test.pkg { 2059 public abstract class Collections { 2060 ctor public Collections(); 2061 method public abstract <T extends java.util.Collection<java.lang.String>> T addAllTo(T); 2062 method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>); 2063 } 2064 public final class Collections.Range<T extends java.lang.Comparable<? super T>> { 2065 ctor public Collections.Range(); 2066 } 2067 public class MoreAsserts { 2068 ctor public MoreAsserts(); 2069 method public static void assertEquals(String, java.util.Set<?>, java.util.Set<?>); 2070 method public static void assertEquals(java.util.Set<?>, java.util.Set<?>); 2071 } 2072 } 2073 """ 2074 ) 2075 } 2076 2077 @Test Check instance methods in enumsnull2078 fun `Check instance methods in enums`() { 2079 // Make sure that when we have instance methods in an enum they're handled 2080 // correctly (there's some special casing around enums to insert extra methods 2081 // that was broken, as exposed by ChronoUnit#toString) 2082 check( 2083 format = FileFormat.V1, 2084 sourceFiles = arrayOf( 2085 java( 2086 """ 2087 package test.pkg; 2088 2089 @SuppressWarnings("ALL") 2090 public interface TempUnit { 2091 @Override 2092 String toString(); 2093 } 2094 """ 2095 ), 2096 java( 2097 """ 2098 package test.pkg; 2099 2100 @SuppressWarnings("ALL") 2101 public enum ChronUnit implements TempUnit { 2102 C, B, A; 2103 2104 public String valueOf(int x) { 2105 return Integer.toString(x + 5); 2106 } 2107 2108 public String values(String separator) { 2109 return null; 2110 } 2111 2112 @Override 2113 public String toString() { 2114 return name(); 2115 } 2116 } 2117 """ 2118 ) 2119 ), 2120 importedPackages = emptyList(), 2121 api = """ 2122 package test.pkg { 2123 public enum ChronUnit implements test.pkg.TempUnit { 2124 method public String valueOf(int); 2125 method public String values(String); 2126 enum_constant public static final test.pkg.ChronUnit A; 2127 enum_constant public static final test.pkg.ChronUnit B; 2128 enum_constant public static final test.pkg.ChronUnit C; 2129 } 2130 public interface TempUnit { 2131 method public String toString(); 2132 } 2133 } 2134 """ 2135 ) 2136 } 2137 2138 @Test Mixing enums and fieldsnull2139 fun `Mixing enums and fields`() { 2140 // Checks sorting order of enum constant values 2141 val source = """ 2142 package java.nio.file.attribute { 2143 public enum AclEntryPermission { 2144 method public static java.nio.file.attribute.AclEntryPermission valueOf(String); 2145 method public static final java.nio.file.attribute.AclEntryPermission[] values(); 2146 enum_constant public static final java.nio.file.attribute.AclEntryPermission APPEND_DATA; 2147 enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE; 2148 enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE_CHILD; 2149 enum_constant public static final java.nio.file.attribute.AclEntryPermission EXECUTE; 2150 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_ACL; 2151 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_ATTRIBUTES; 2152 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_DATA; 2153 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_NAMED_ATTRS; 2154 enum_constant public static final java.nio.file.attribute.AclEntryPermission SYNCHRONIZE; 2155 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_ACL; 2156 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_ATTRIBUTES; 2157 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_DATA; 2158 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_NAMED_ATTRS; 2159 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_OWNER; 2160 field public static final java.nio.file.attribute.AclEntryPermission ADD_FILE; 2161 field public static final java.nio.file.attribute.AclEntryPermission ADD_SUBDIRECTORY; 2162 field public static final java.nio.file.attribute.AclEntryPermission LIST_DIRECTORY; 2163 } 2164 } 2165 """ 2166 check( 2167 format = FileFormat.V1, 2168 signatureSource = source, 2169 api = source 2170 ) 2171 } 2172 2173 @Test Inheriting from package private classes, package private class should be includednull2174 fun `Inheriting from package private classes, package private class should be included`() { 2175 check( 2176 sourceFiles = arrayOf( 2177 java( 2178 """ 2179 package test.pkg; 2180 @SuppressWarnings("ALL") 2181 public class MyClass extends HiddenParent { 2182 public void method1() { } 2183 } 2184 """ 2185 ), 2186 java( 2187 """ 2188 package test.pkg; 2189 @SuppressWarnings("ALL") 2190 class HiddenParent { 2191 public static final String CONSTANT = "MyConstant"; 2192 protected int mContext; 2193 public void method2() { } 2194 } 2195 """ 2196 ) 2197 ), 2198 expectedIssues = "", 2199 api = """ 2200 package test.pkg { 2201 public class MyClass { 2202 ctor public MyClass(); 2203 method public void method1(); 2204 method public void method2(); 2205 field public static final String CONSTANT = "MyConstant"; 2206 } 2207 } 2208 """ 2209 ) 2210 } 2211 2212 @Test Inheriting generic method from package private classnull2213 fun `Inheriting generic method from package private class`() { 2214 check( 2215 format = FileFormat.V2, 2216 sourceFiles = arrayOf( 2217 java( 2218 """ 2219 package test.pkg; 2220 @SuppressWarnings("ALL") 2221 public class MyClass extends HiddenParent { 2222 public void method1() { } 2223 } 2224 """ 2225 ), 2226 java( 2227 """ 2228 package test.pkg; 2229 @SuppressWarnings("ALL") 2230 class HiddenParent { 2231 public <T> T method2(T t) { } 2232 public String method3(String s) { } 2233 } 2234 """ 2235 ) 2236 ), 2237 expectedIssues = "", 2238 api = """ 2239 package test.pkg { 2240 public class MyClass { 2241 ctor public MyClass(); 2242 method public void method1(); 2243 method public <T> T method2(T); 2244 method public String method3(String); 2245 } 2246 } 2247 """ 2248 ) 2249 } 2250 2251 @Test Type substitution for generic method referencing parent type parameternull2252 fun `Type substitution for generic method referencing parent type parameter`() { 2253 // Type parameters from parent classes need to be replaced with their bounds in the child. 2254 check( 2255 format = FileFormat.V2, 2256 sourceFiles = arrayOf( 2257 java( 2258 """ 2259 package test.pkg; 2260 @SuppressWarnings("ALL") 2261 public class MyClass extends HiddenParent<String> { 2262 public void method1() { } 2263 } 2264 """ 2265 ), 2266 java( 2267 """ 2268 package test.pkg; 2269 @SuppressWarnings("ALL") 2270 class HiddenParent<T> { 2271 public T method2(T t) { } 2272 } 2273 """ 2274 ) 2275 ), 2276 expectedIssues = "", 2277 api = """ 2278 package test.pkg { 2279 public class MyClass { 2280 ctor public MyClass(); 2281 method public void method1(); 2282 method public String method2(String); 2283 } 2284 } 2285 """ 2286 ) 2287 } 2288 2289 @Test When implementing rather than extending package private class, inline members insteadnull2290 fun `When implementing rather than extending package private class, inline members instead`() { 2291 // If you implement a package private interface, we just remove it and inline the members into 2292 // the subclass 2293 check( 2294 sourceFiles = arrayOf( 2295 java( 2296 """ 2297 package test.pkg; 2298 public class MyClass implements HiddenInterface { 2299 @Override public void method() { } 2300 @Override public void other() { } 2301 } 2302 """ 2303 ), 2304 java( 2305 """ 2306 package test.pkg; 2307 public interface OtherInterface { 2308 void other(); 2309 } 2310 """ 2311 ), 2312 java( 2313 """ 2314 package test.pkg; 2315 interface HiddenInterface extends OtherInterface { 2316 void method() { } 2317 String CONSTANT = "MyConstant"; 2318 } 2319 """ 2320 ) 2321 ), 2322 api = """ 2323 package test.pkg { 2324 public class MyClass implements test.pkg.OtherInterface { 2325 ctor public MyClass(); 2326 method public void method(); 2327 method public void other(); 2328 field public static final String CONSTANT = "MyConstant"; 2329 } 2330 public interface OtherInterface { 2331 method public void other(); 2332 } 2333 } 2334 """ 2335 ) 2336 } 2337 2338 @Test Implementing package private classnull2339 fun `Implementing package private class`() { 2340 // Include all the non-hidden public interfaces into the signature 2341 2342 // BUG: Note that we need to implement the parent 2343 check( 2344 sourceFiles = arrayOf( 2345 java( 2346 """ 2347 package test.pkg; 2348 public class MyClass implements HiddenInterface { 2349 @Override public void method() { } 2350 @Override public void other() { } 2351 } 2352 """ 2353 ), 2354 java( 2355 """ 2356 package test.pkg; 2357 public interface OtherInterface { 2358 void other(); 2359 } 2360 """ 2361 ), 2362 java( 2363 """ 2364 package test.pkg; 2365 interface HiddenInterface extends OtherInterface { 2366 void method() { } 2367 String CONSTANT = "MyConstant"; 2368 } 2369 """ 2370 ) 2371 ), 2372 api = """ 2373 package test.pkg { 2374 public class MyClass implements test.pkg.OtherInterface { 2375 ctor public MyClass(); 2376 method public void method(); 2377 method public void other(); 2378 field public static final String CONSTANT = "MyConstant"; 2379 } 2380 public interface OtherInterface { 2381 method public void other(); 2382 } 2383 } 2384 """ 2385 ) 2386 } 2387 2388 @Test Default modifiers should be omittednull2389 fun `Default modifiers should be omitted`() { 2390 // If signatures vary only by the "default" modifier in the interface, don't show it on the implementing 2391 // class 2392 check( 2393 format = FileFormat.V1, 2394 sourceFiles = arrayOf( 2395 java( 2396 """ 2397 package test.pkg; 2398 2399 public class MyClass implements SuperInterface { 2400 @Override public void method() { } 2401 @Override public void method2() { } 2402 } 2403 """ 2404 ), 2405 java( 2406 """ 2407 package test.pkg; 2408 2409 public interface SuperInterface { 2410 void method(); 2411 default void method2() { 2412 } 2413 } 2414 """ 2415 ) 2416 ), 2417 api = """ 2418 package test.pkg { 2419 public class MyClass implements test.pkg.SuperInterface { 2420 ctor public MyClass(); 2421 method public void method(); 2422 } 2423 public interface SuperInterface { 2424 method public void method(); 2425 method public default void method2(); 2426 } 2427 } 2428 """ 2429 ) 2430 } 2431 2432 @Test Override via different throws list should be includednull2433 fun `Override via different throws list should be included`() { 2434 // If a method overrides another but changes the throws list, the overriding 2435 // method must be listed in the subclass. This is observed for example in 2436 // AbstractCursor#finalize, which omits the throws clause from Object's finalize. 2437 check( 2438 sourceFiles = arrayOf( 2439 java( 2440 """ 2441 package test.pkg; 2442 2443 public abstract class AbstractCursor extends Parent { 2444 @Override protected void finalize2() { } // note: not throws Throwable! 2445 } 2446 """ 2447 ), 2448 java( 2449 """ 2450 package test.pkg; 2451 2452 @SuppressWarnings("RedundantThrows") 2453 public class Parent { 2454 protected void finalize2() throws Throwable { 2455 } 2456 } 2457 """ 2458 ) 2459 ), 2460 api = """ 2461 package test.pkg { 2462 public abstract class AbstractCursor extends test.pkg.Parent { 2463 ctor public AbstractCursor(); 2464 method protected void finalize2(); 2465 } 2466 public class Parent { 2467 ctor public Parent(); 2468 method protected void finalize2() throws java.lang.Throwable; 2469 } 2470 } 2471 """ 2472 ) 2473 } 2474 2475 @Test Implementing interface methodnull2476 fun `Implementing interface method`() { 2477 // If you have a public method that implements an interface method, 2478 // they'll vary in the "abstract" modifier, but it shouldn't be listed on the 2479 // class. This is an issue for example for the ZonedDateTime#getLong method 2480 // implementing the TemporalAccessor#getLong method 2481 check( 2482 format = FileFormat.V1, 2483 sourceFiles = arrayOf( 2484 java( 2485 """ 2486 package test.pkg; 2487 public interface SomeInterface2 { 2488 @Override default long getLong() { 2489 return 42; 2490 } 2491 } 2492 """ 2493 ), 2494 java( 2495 """ 2496 package test.pkg; 2497 public class Foo implements SomeInterface2 { 2498 @Override 2499 public long getLong() { return 0L; } 2500 } 2501 """ 2502 ) 2503 ), 2504 api = """ 2505 package test.pkg { 2506 public class Foo implements test.pkg.SomeInterface2 { 2507 ctor public Foo(); 2508 } 2509 public interface SomeInterface2 { 2510 method public default long getLong(); 2511 } 2512 } 2513 """ 2514 ) 2515 } 2516 2517 @Test Implementing interface method 2null2518 fun `Implementing interface method 2`() { 2519 check( 2520 format = FileFormat.V1, 2521 sourceFiles = arrayOf( 2522 java( 2523 """ 2524 package test.pkg; 2525 public interface SomeInterface { 2526 long getLong(); 2527 } 2528 """ 2529 ), 2530 java( 2531 """ 2532 package test.pkg; 2533 public interface SomeInterface2 { 2534 @Override default long getLong() { 2535 return 42; 2536 } 2537 } 2538 """ 2539 ), 2540 java( 2541 """ 2542 package test.pkg; 2543 public class Foo implements SomeInterface, SomeInterface2 { 2544 @Override 2545 public long getLong() { return 0L; } 2546 } 2547 """ 2548 ) 2549 ), 2550 api = """ 2551 package test.pkg { 2552 public class Foo implements test.pkg.SomeInterface test.pkg.SomeInterface2 { 2553 ctor public Foo(); 2554 } 2555 public interface SomeInterface { 2556 method public long getLong(); 2557 } 2558 public interface SomeInterface2 { 2559 method public default long getLong(); 2560 } 2561 } 2562 """ 2563 ) 2564 } 2565 2566 @Test Check basic @remove scenariosnull2567 fun `Check basic @remove scenarios`() { 2568 // Test basic @remove handling for methods and fields 2569 check( 2570 sourceFiles = arrayOf( 2571 java( 2572 """ 2573 package test.pkg; 2574 @SuppressWarnings("JavaDoc") 2575 public class Bar { 2576 /** @removed */ 2577 public Bar() { } 2578 public int field; 2579 public void test() { } 2580 /** @removed */ 2581 public int removedField; 2582 /** @removed */ 2583 public void removedMethod() { } 2584 /** @removed and @hide - should not be listed */ 2585 public int hiddenField; 2586 2587 /** @removed */ 2588 public class Inner { } 2589 2590 public class Inner2 { 2591 public class Inner3 { 2592 /** @removed */ 2593 public class Inner4 { } 2594 } 2595 } 2596 2597 public class Inner5 { 2598 public class Inner6 { 2599 public class Inner7 { 2600 /** @removed */ 2601 public int removed; 2602 } 2603 } 2604 } 2605 } 2606 """ 2607 ) 2608 ), 2609 removedApi = """ 2610 package test.pkg { 2611 public class Bar { 2612 ctor public Bar(); 2613 method public void removedMethod(); 2614 field public int removedField; 2615 } 2616 public class Bar.Inner { 2617 ctor public Bar.Inner(); 2618 } 2619 public class Bar.Inner2.Inner3.Inner4 { 2620 ctor public Bar.Inner2.Inner3.Inner4(); 2621 } 2622 public class Bar.Inner5.Inner6.Inner7 { 2623 field public int removed; 2624 } 2625 } 2626 """ 2627 ) 2628 } 2629 2630 @Test Check @remove classnull2631 fun `Check @remove class`() { 2632 // Test removing classes 2633 check( 2634 format = FileFormat.V2, 2635 sourceFiles = arrayOf( 2636 java( 2637 """ 2638 package test.pkg; 2639 /** @removed */ 2640 @SuppressWarnings("JavaDoc") 2641 public class Foo { 2642 public void foo() { } 2643 public class Inner { 2644 } 2645 } 2646 """ 2647 ), 2648 java( 2649 """ 2650 package test.pkg; 2651 @SuppressWarnings("JavaDoc") 2652 public class Bar implements Parcelable { 2653 public int field; 2654 public void method(); 2655 2656 /** @removed */ 2657 public int removedField; 2658 /** @removed */ 2659 public void removedMethod() { } 2660 2661 public class Inner1 { 2662 } 2663 /** @removed */ 2664 public class Inner2 { 2665 } 2666 } 2667 """ 2668 ), 2669 java( 2670 """ 2671 package test.pkg; 2672 @SuppressWarnings("ALL") 2673 public interface Parcelable { 2674 void method(); 2675 } 2676 """ 2677 ) 2678 ), 2679 /* 2680 I expected this: but doclava1 doesn't do that (and we now match its behavior) 2681 package test.pkg { 2682 public class Bar { 2683 method public void removedMethod(); 2684 field public int removedField; 2685 } 2686 public class Bar.Inner2 { 2687 } 2688 public class Foo { 2689 method public void foo(); 2690 } 2691 } 2692 */ 2693 removedApi = """ 2694 package test.pkg { 2695 public class Bar implements test.pkg.Parcelable { 2696 method public void removedMethod(); 2697 field public int removedField; 2698 } 2699 public class Bar.Inner2 { 2700 ctor public Bar.Inner2(); 2701 } 2702 public class Foo { 2703 ctor public Foo(); 2704 method public void foo(); 2705 } 2706 public class Foo.Inner { 2707 ctor public Foo.Inner(); 2708 } 2709 } 2710 """ 2711 ) 2712 } 2713 2714 @Test Test include overridden @Deprecated even if annotated with @hidenull2715 fun `Test include overridden @Deprecated even if annotated with @hide`() { 2716 check( 2717 format = FileFormat.V1, 2718 sourceFiles = arrayOf( 2719 java( 2720 """ 2721 package test.pkg; 2722 @SuppressWarnings("JavaDoc") 2723 public class Child extends Parent { 2724 /** 2725 * @deprecated 2726 * @hide 2727 */ 2728 @Deprecated @Override 2729 public String toString() { 2730 return "Child"; 2731 } 2732 2733 /** 2734 * @hide 2735 */ 2736 public void hiddenApi() { 2737 } 2738 } 2739 """ 2740 ), 2741 java( 2742 """ 2743 package test.pkg; 2744 public class Parent { 2745 public String toString() { 2746 return "Parent"; 2747 } 2748 } 2749 """ 2750 ) 2751 ), 2752 api = """ 2753 package test.pkg { 2754 public class Child extends test.pkg.Parent { 2755 ctor public Child(); 2756 method @Deprecated public String toString(); 2757 } 2758 public class Parent { 2759 ctor public Parent(); 2760 } 2761 } 2762 """, 2763 dexApi = """ 2764 Ltest/pkg/Child; 2765 Ltest/pkg/Child;-><init>()V 2766 Ltest/pkg/Child;->toString()Ljava/lang/String; 2767 Ltest/pkg/Parent; 2768 Ltest/pkg/Parent;-><init>()V 2769 Ltest/pkg/Parent;->toString()Ljava/lang/String; 2770 """ 2771 ) 2772 } 2773 2774 @Test Test invalid class namenull2775 fun `Test invalid class name`() { 2776 // Regression test for b/73018978 2777 check( 2778 format = FileFormat.V1, 2779 sourceFiles = arrayOf( 2780 kotlin( 2781 "src/test/pkg/Foo.kt", 2782 """ 2783 @file:JvmName("-Foo") 2784 2785 package test.pkg 2786 2787 @Suppress("unused") 2788 inline fun String.printHelloWorld() { println("Hello World") } 2789 """ 2790 ) 2791 ), 2792 api = """ 2793 package test.pkg { 2794 public final class -Foo { 2795 method public static inline void printHelloWorld(@NonNull String); 2796 } 2797 } 2798 """ 2799 ) 2800 } 2801 2802 @Test Indirect Field Includes from Interfacesnull2803 fun `Indirect Field Includes from Interfaces`() { 2804 // Real-world example: include ZipConstants into ZipFile and JarFile 2805 check( 2806 sourceFiles = arrayOf( 2807 java( 2808 """ 2809 package test.pkg1; 2810 interface MyConstants { 2811 long CONSTANT1 = 12345; 2812 long CONSTANT2 = 67890; 2813 long CONSTANT3 = 42; 2814 } 2815 """ 2816 ), 2817 java( 2818 """ 2819 package test.pkg1; 2820 import java.io.Closeable; 2821 @SuppressWarnings("WeakerAccess") 2822 public class MyParent implements MyConstants, Closeable { 2823 } 2824 """ 2825 ), 2826 java( 2827 """ 2828 package test.pkg2; 2829 2830 import test.pkg1.MyParent; 2831 public class MyChild extends MyParent { 2832 } 2833 """ 2834 ) 2835 2836 ), 2837 api = """ 2838 package test.pkg1 { 2839 public class MyParent implements java.io.Closeable { 2840 ctor public MyParent(); 2841 field public static final long CONSTANT1 = 12345L; // 0x3039L 2842 field public static final long CONSTANT2 = 67890L; // 0x10932L 2843 field public static final long CONSTANT3 = 42L; // 0x2aL 2844 } 2845 } 2846 package test.pkg2 { 2847 public class MyChild extends test.pkg1.MyParent { 2848 ctor public MyChild(); 2849 field public static final long CONSTANT1 = 12345L; // 0x3039L 2850 field public static final long CONSTANT2 = 67890L; // 0x10932L 2851 field public static final long CONSTANT3 = 42L; // 0x2aL 2852 } 2853 } 2854 """ 2855 ) 2856 } 2857 2858 @Test Skip interfaces from packages explicitly hidden via argumentsnull2859 fun `Skip interfaces from packages explicitly hidden via arguments`() { 2860 // Real-world example: HttpResponseCache implements OkCacheContainer but hides the only inherited method 2861 check( 2862 extraArguments = arrayOf( 2863 ARG_HIDE_PACKAGE, "com.squareup.okhttp" 2864 ), 2865 sourceFiles = arrayOf( 2866 java( 2867 """ 2868 package android.net.http; 2869 import com.squareup.okhttp.Cache; 2870 import com.squareup.okhttp.OkCacheContainer; 2871 import java.io.Closeable; 2872 import java.net.ResponseCache; 2873 @SuppressWarnings("JavaDoc") 2874 public final class HttpResponseCache implements Closeable, OkCacheContainer { 2875 /** @hide Needed for OkHttp integration. */ 2876 @Override 2877 public Cache getCache() { 2878 return delegate.getCache(); 2879 } 2880 } 2881 """ 2882 ), 2883 java( 2884 """ 2885 package com.squareup.okhttp; 2886 public interface OkCacheContainer { 2887 Cache getCache(); 2888 } 2889 """ 2890 ), 2891 java( 2892 """ 2893 package com.squareup.okhttp; 2894 public class Cache { 2895 } 2896 """ 2897 ) 2898 ), 2899 expectedIssues = """ 2900 src/android/net/http/HttpResponseCache.java:7: warning: Public class android.net.http.HttpResponseCache stripped of unavailable superclass com.squareup.okhttp.OkCacheContainer [HiddenSuperclass] 2901 """, 2902 api = """ 2903 package android.net.http { 2904 public final class HttpResponseCache implements java.io.Closeable { 2905 ctor public HttpResponseCache(); 2906 } 2907 } 2908 """ 2909 ) 2910 } 2911 2912 @Test Extend from multiple interfacesnull2913 fun `Extend from multiple interfaces`() { 2914 // Real-world example: XmlResourceParser 2915 check( 2916 format = FileFormat.V1, 2917 checkCompilation = true, 2918 sourceFiles = arrayOf( 2919 java( 2920 """ 2921 package android.content.res; 2922 import android.util.AttributeSet; 2923 import org.xmlpull.v1.XmlPullParser; 2924 import my.AutoCloseable; 2925 2926 @SuppressWarnings("UnnecessaryInterfaceModifier") 2927 public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable { 2928 public void close(); 2929 } 2930 """ 2931 ), 2932 java( 2933 """ 2934 package android.util; 2935 @SuppressWarnings("WeakerAccess") 2936 public interface AttributeSet { 2937 } 2938 """ 2939 ), 2940 java( 2941 """ 2942 package my; 2943 public interface AutoCloseable { 2944 } 2945 """ 2946 ), 2947 java( 2948 """ 2949 package org.xmlpull.v1; 2950 @SuppressWarnings("WeakerAccess") 2951 public interface XmlPullParser { 2952 } 2953 """ 2954 ) 2955 ), 2956 api = """ 2957 package android.content.res { 2958 public interface XmlResourceParser extends org.xmlpull.v1.XmlPullParser android.util.AttributeSet my.AutoCloseable { 2959 method public void close(); 2960 } 2961 } 2962 package android.util { 2963 public interface AttributeSet { 2964 } 2965 } 2966 package my { 2967 public interface AutoCloseable { 2968 } 2969 } 2970 package org.xmlpull.v1 { 2971 public interface XmlPullParser { 2972 } 2973 } 2974 """ 2975 ) 2976 } 2977 2978 @Test Test KDoc suppressnull2979 fun `Test KDoc suppress`() { 2980 // Basic class; also checks that default constructor is made explicit 2981 check( 2982 sourceFiles = arrayOf( 2983 java( 2984 """ 2985 package test.pkg; 2986 public class Foo { 2987 private Foo() { } 2988 /** @suppress */ 2989 public void hidden() { 2990 } 2991 } 2992 """ 2993 ), 2994 java( 2995 """ 2996 package test.pkg; 2997 /** 2998 * Some comment. 2999 * @suppress 3000 */ 3001 public class Hidden { 3002 private Hidden() { } 3003 public void hidden() { 3004 } 3005 public class Inner { 3006 } 3007 } 3008 """ 3009 ) 3010 ), 3011 api = """ 3012 package test.pkg { 3013 public class Foo { 3014 } 3015 } 3016 """ 3017 ) 3018 } 3019 3020 @Test Check skipping implicit final or deprecated overridenull3021 fun `Check skipping implicit final or deprecated override`() { 3022 // Regression test for 122358225 3023 check( 3024 sourceFiles = arrayOf( 3025 java( 3026 """ 3027 package test.pkg; 3028 3029 public class Parent { 3030 public void foo1() { } 3031 public void foo2() { } 3032 public void foo3() { } 3033 public void foo4() { } 3034 } 3035 """ 3036 ), 3037 java( 3038 """ 3039 package test.pkg; 3040 3041 public final class Child1 extends Parent { 3042 private Child1() { } 3043 public final void foo1() { } 3044 public void foo2() { } 3045 } 3046 """ 3047 ), 3048 java( 3049 """ 3050 package test.pkg; 3051 3052 /** @deprecated */ 3053 @Deprecated 3054 public final class Child2 extends Parent { 3055 private Child2() { } 3056 /** @deprecated */ 3057 @Deprecated 3058 public void foo3() { } 3059 public void foo4() { } 3060 } 3061 """ 3062 ), 3063 java( 3064 """ 3065 package test.pkg; 3066 3067 /** @deprecated */ 3068 @Deprecated 3069 public final class Child3 extends Parent { 3070 private Child3() { } 3071 public final void foo1() { } 3072 public void foo2() { } 3073 /** @deprecated */ 3074 @Deprecated 3075 public void foo3() { } 3076 /** @deprecated */ 3077 @Deprecated 3078 public final void foo4() { } 3079 } 3080 """ 3081 ) 3082 ), 3083 api = """ 3084 package test.pkg { 3085 public final class Child1 extends test.pkg.Parent { 3086 } 3087 @Deprecated public final class Child2 extends test.pkg.Parent { 3088 } 3089 @Deprecated public final class Child3 extends test.pkg.Parent { 3090 } 3091 public class Parent { 3092 ctor public Parent(); 3093 method public void foo1(); 3094 method public void foo2(); 3095 method public void foo3(); 3096 method public void foo4(); 3097 } 3098 } 3099 """ 3100 ) 3101 } 3102 3103 @Test Ignore synchronized differencesnull3104 fun `Ignore synchronized differences`() { 3105 check( 3106 sourceFiles = arrayOf( 3107 java( 3108 """ 3109 package test.pkg2; 3110 3111 public class Parent { 3112 public void foo1() { } 3113 public synchronized void foo2() { } 3114 } 3115 """ 3116 ), 3117 java( 3118 """ 3119 package test.pkg2; 3120 3121 public class Child1 extends Parent { 3122 private Child1() { } 3123 public synchronized void foo1() { } 3124 public void foo2() { } 3125 } 3126 """ 3127 ) 3128 ), 3129 api = """ 3130 package test.pkg2 { 3131 public class Child1 extends test.pkg2.Parent { 3132 } 3133 public class Parent { 3134 ctor public Parent(); 3135 method public void foo1(); 3136 method public void foo2(); 3137 } 3138 } 3139 """ 3140 ) 3141 } 3142 3143 @Test Skip incorrect inheritnull3144 fun `Skip incorrect inherit`() { 3145 check( 3146 // Simulate test-mock scenario for getIContentProvider 3147 extraArguments = arrayOf("--stub-packages", "android.test.mock"), 3148 expectedIssues = "src/android/test/mock/MockContentProvider.java:6: warning: Public class android.test.mock.MockContentProvider stripped of unavailable superclass android.content.ContentProvider [HiddenSuperclass]", 3149 sourceFiles = arrayOf( 3150 java( 3151 """ 3152 package android.test.mock; 3153 3154 import android.content.ContentProvider; 3155 import android.content.IContentProvider; 3156 3157 public abstract class MockContentProvider extends ContentProvider { 3158 /** 3159 * Returns IContentProvider which calls back same methods in this class. 3160 * By overriding this class, we avoid the mechanism hidden behind ContentProvider 3161 * (IPC, etc.) 3162 * 3163 * @hide 3164 */ 3165 @Override 3166 public final IContentProvider getIContentProvider() { 3167 return mIContentProvider; 3168 } 3169 } 3170 """ 3171 ), 3172 java( 3173 """ 3174 package android.content; 3175 3176 /** @hide */ 3177 public abstract class ContentProvider { 3178 protected boolean isTemporary() { 3179 return false; 3180 } 3181 3182 // This is supposed to be @hide, but in turbine-combined/framework.jar included 3183 // by java_sdk_library like test-mock, it's not; this is what the special 3184 // flag is used to test 3185 public IContentProvider getIContentProvider() { 3186 return null; 3187 } 3188 } 3189 """ 3190 ), 3191 java( 3192 """ 3193 package android.content; 3194 import android.os.IInterface; 3195 3196 /** 3197 * The ipc interface to talk to a content provider. 3198 * @hide 3199 */ 3200 public interface IContentProvider extends IInterface { 3201 } 3202 """ 3203 ), 3204 java( 3205 """ 3206 package android.content; 3207 3208 // Not hidden. Here to make sure that we respect stub-packages 3209 // and exclude it from everything, including signatures. 3210 public class ClipData { 3211 } 3212 """ 3213 ) 3214 ), 3215 api = """ 3216 package android.test.mock { 3217 public abstract class MockContentProvider { 3218 ctor public MockContentProvider(); 3219 } 3220 } 3221 """ 3222 ) 3223 } 3224 3225 @Test Test Visible For Testingnull3226 fun `Test Visible For Testing`() { 3227 // Use the otherwise= visibility in signatures 3228 // Regression test for issue 118763806 3229 check( 3230 format = FileFormat.V1, 3231 sourceFiles = arrayOf( 3232 java( 3233 """ 3234 package test.pkg; 3235 import androidx.annotation.VisibleForTesting; 3236 3237 @SuppressWarnings({"ClassNameDiffersFromFileName", "WeakerAccess"}) 3238 public class ProductionCodeJava { 3239 private ProductionCodeJava() { } 3240 3241 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 3242 public void shouldBeProtected() { 3243 } 3244 3245 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 3246 protected void shouldBePrivate1() { 3247 } 3248 3249 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 3250 public void shouldBePrivate2() { 3251 } 3252 3253 @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) 3254 public void shouldBePackagePrivate() { 3255 } 3256 3257 @VisibleForTesting(otherwise = VisibleForTesting.NONE) 3258 public void shouldBeHidden() { 3259 } 3260 } 3261 """ 3262 ).indented(), 3263 kotlin( 3264 """ 3265 package test.pkg 3266 import androidx.annotation.VisibleForTesting 3267 3268 open class ProductionCodeKotlin private constructor() { 3269 3270 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 3271 fun shouldBeProtected() { 3272 } 3273 3274 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 3275 protected fun shouldBePrivate1() { 3276 } 3277 3278 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 3279 fun shouldBePrivate2() { 3280 } 3281 3282 @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) 3283 fun shouldBePackagePrivate() { 3284 } 3285 3286 @VisibleForTesting(otherwise = VisibleForTesting.NONE) 3287 fun shouldBeHidden() { 3288 } 3289 } 3290 """ 3291 ).indented(), 3292 visibleForTestingSource 3293 ), 3294 api = """ 3295 package test.pkg { 3296 public class ProductionCodeJava { 3297 method @VisibleForTesting(otherwise=androidx.annotation.VisibleForTesting.PROTECTED) protected void shouldBeProtected(); 3298 } 3299 public class ProductionCodeKotlin { 3300 method @VisibleForTesting(otherwise=androidx.annotation.VisibleForTesting.PROTECTED) protected final void shouldBeProtected(); 3301 } 3302 } 3303 """, 3304 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation") 3305 ) 3306 } 3307 3308 @Test References Deprecatednull3309 fun `References Deprecated`() { 3310 check( 3311 extraArguments = arrayOf( 3312 ARG_ERROR, "ReferencesDeprecated", 3313 ARG_ERROR, "ExtendsDeprecated" 3314 ), 3315 expectedIssues = """ 3316 src/test/pkg/MyClass.java:3: error: Parameter of deprecated type test.pkg.DeprecatedClass in test.pkg.MyClass.method1(): this method should also be deprecated [ReferencesDeprecated] 3317 src/test/pkg/MyClass.java:4: error: Return type of deprecated type test.pkg.DeprecatedInterface in test.pkg.MyClass.method2(): this method should also be deprecated [ReferencesDeprecated] 3318 src/test/pkg/MyClass.java:4: error: Returning deprecated type test.pkg.DeprecatedInterface from test.pkg.MyClass.method2(): this method should also be deprecated [ReferencesDeprecated] 3319 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] 3320 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] 3321 """, 3322 sourceFiles = arrayOf( 3323 java( 3324 """ 3325 package test.pkg; 3326 /** @deprecated */ 3327 @Deprecated 3328 public class DeprecatedClass { 3329 } 3330 """ 3331 ), 3332 java( 3333 """ 3334 package test.pkg; 3335 /** @deprecated */ 3336 @Deprecated 3337 public interface DeprecatedInterface { 3338 } 3339 """ 3340 ), 3341 java( 3342 """ 3343 package test.pkg; 3344 public class MyClass extends DeprecatedClass implements DeprecatedInterface { 3345 public void method1(DeprecatedClass p, int i) { } 3346 public DeprecatedInterface method2(int i) { return null; } 3347 3348 /** @deprecated */ 3349 @Deprecated 3350 public void method3(DeprecatedClass p, int i) { } 3351 } 3352 """ 3353 ) 3354 ) 3355 ) 3356 } 3357 3358 @Test v3 format for qualified references in typesnull3359 fun `v3 format for qualified references in types`() { 3360 check( 3361 format = FileFormat.V3, 3362 sourceFiles = arrayOf( 3363 java( 3364 """ 3365 package androidx.appcompat.app; 3366 import android.view.View; 3367 import android.view.View.OnClickListener; 3368 3369 public class ActionBarDrawerToggle { 3370 private ActionBarDrawerToggle() { } 3371 public View.OnClickListener getToolbarNavigationClickListener1() { 3372 return null; 3373 } 3374 public OnClickListener getToolbarNavigationClickListener2() { 3375 return null; 3376 } 3377 public android.view.View.OnClickListener getToolbarNavigationClickListener3() { 3378 return null; 3379 } 3380 } 3381 """ 3382 ) 3383 ), 3384 api = """ 3385 // Signature format: 3.0 3386 package androidx.appcompat.app { 3387 public class ActionBarDrawerToggle { 3388 method public android.view.View.OnClickListener! getToolbarNavigationClickListener1(); 3389 method public android.view.View.OnClickListener! getToolbarNavigationClickListener2(); 3390 method public android.view.View.OnClickListener! getToolbarNavigationClickListener3(); 3391 } 3392 } 3393 """ 3394 ) 3395 } 3396 3397 @Test FooKt class constructors are not publicnull3398 fun `FooKt class constructors are not public`() { 3399 check( 3400 format = FileFormat.V3, 3401 sourceFiles = arrayOf( 3402 kotlin( 3403 "src/main/java/test/pkg/Foo.kt", 3404 """ 3405 package test.pkg 3406 fun myCall() : Boolean = false 3407 class Bar 3408 """ 3409 ) 3410 ), 3411 api = """ 3412 // Signature format: 3.0 3413 package test.pkg { 3414 public final class Bar { 3415 ctor public Bar(); 3416 } 3417 public final class FooKt { 3418 method public static boolean myCall(); 3419 } 3420 } 3421 """ 3422 ) 3423 } 3424 3425 @Test Test inherited hidden methods for descendant classes - Package privatenull3426 fun `Test inherited hidden methods for descendant classes - Package private`() { 3427 check( 3428 sourceFiles = arrayOf( 3429 java( 3430 """ 3431 package test.pkg; 3432 public class Class4 extends Class3 { 3433 public void method4() { } 3434 } 3435 """ 3436 ), 3437 java( 3438 """ 3439 package test.pkg; 3440 public class Class3 extends Class2 { 3441 public void method3() { } 3442 } 3443 """ 3444 ), 3445 java( 3446 """ 3447 package test.pkg; 3448 class Class2 extends Class1 { 3449 public void method2() { } 3450 } 3451 """ 3452 ), 3453 java( 3454 """ 3455 package test.pkg; 3456 public class Class1 { 3457 public void method1() { } 3458 } 3459 """ 3460 ) 3461 ), 3462 expectedIssues = "", 3463 api = 3464 """ 3465 package test.pkg { 3466 public class Class1 { 3467 ctor public Class1(); 3468 method public void method1(); 3469 } 3470 public class Class3 extends test.pkg.Class1 { 3471 ctor public Class3(); 3472 method public void method2(); 3473 method public void method3(); 3474 } 3475 public class Class4 extends test.pkg.Class3 { 3476 ctor public Class4(); 3477 method public void method4(); 3478 } 3479 } 3480 """ 3481 ) 3482 } 3483 3484 @Test Test inherited hidden methods for descendant classes - Hidden annotationnull3485 fun `Test inherited hidden methods for descendant classes - Hidden annotation`() { 3486 check( 3487 sourceFiles = arrayOf( 3488 java( 3489 """ 3490 package test.pkg; 3491 public class Class4 extends Class3 { 3492 public void method4() { } 3493 } 3494 """ 3495 ), 3496 java( 3497 """ 3498 package test.pkg; 3499 public class Class3 extends Class2 { 3500 public void method3() { } 3501 } 3502 """ 3503 ), 3504 java( 3505 """ 3506 package test.pkg; 3507 /** @hide */ 3508 public class Class2 extends Class1 { 3509 public void method2() { } 3510 } 3511 """ 3512 ), 3513 java( 3514 """ 3515 package test.pkg; 3516 public class Class1 { 3517 public void method1() { } 3518 } 3519 """ 3520 ) 3521 ), 3522 expectedIssues = "src/test/pkg/Class3.java:2: warning: Public class test.pkg.Class3 stripped of unavailable superclass test.pkg.Class2 [HiddenSuperclass]", 3523 api = 3524 """ 3525 package test.pkg { 3526 public class Class1 { 3527 ctor public Class1(); 3528 method public void method1(); 3529 } 3530 public class Class3 extends test.pkg.Class1 { 3531 ctor public Class3(); 3532 method public void method2(); 3533 method public void method3(); 3534 } 3535 public class Class4 extends test.pkg.Class3 { 3536 ctor public Class4(); 3537 method public void method4(); 3538 } 3539 } 3540 """ 3541 3542 ) 3543 } 3544 3545 @Test Test inherited methods that use genericsnull3546 fun `Test inherited methods that use generics`() { 3547 check( 3548 format = FileFormat.V2, 3549 sourceFiles = arrayOf( 3550 java( 3551 """ 3552 package test.pkg; 3553 import androidx.annotation.NonNull; 3554 public class Class2 extends Class1<String> { 3555 @Override 3556 public void method1(String input) { } 3557 @Override 3558 public void method2(@NonNull String input) { } 3559 } 3560 """ 3561 ), 3562 java( 3563 """ 3564 package test.pkg; 3565 import androidx.annotation.NonNull; 3566 class Class1<T> { 3567 public void method1(T input) { } 3568 public void method2(T input) { } 3569 public void method3(T input) { } 3570 @NonNull 3571 public String method4(T input) { return ""; } 3572 public T method5(@NonNull String input) { return null; } 3573 } 3574 """ 3575 ), 3576 androidxNonNullSource 3577 ), 3578 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"), 3579 expectedIssues = "", 3580 api = 3581 """ 3582 package test.pkg { 3583 public class Class2 { 3584 ctor public Class2(); 3585 method public void method1(String); 3586 method public void method2(@NonNull String); 3587 method public void method3(String); 3588 method @NonNull public String method4(String); 3589 method public String method5(@NonNull String); 3590 } 3591 } 3592 """ 3593 3594 ) 3595 } 3596 3597 @Test Test merging API signature filesnull3598 fun `Test merging API signature files`() { 3599 val source1 = """ 3600 package Test.pkg { 3601 public final class Class1 { 3602 method public void method1(); 3603 } 3604 } 3605 package Test.pkg1 { 3606 public final class Class1 { 3607 method public void method1(); 3608 } 3609 } 3610 """ 3611 val source2 = """ 3612 package Test.pkg { 3613 public final class Class2 { 3614 method public void method1(String); 3615 } 3616 } 3617 package Test.pkg2 { 3618 public final class Class1 { 3619 method public void method1(String, String); 3620 } 3621 } 3622 """ 3623 val expected = """ 3624 package Test.pkg { 3625 public final class Class1 { 3626 method public void method1(); 3627 } 3628 public final class Class2 { 3629 method public void method1(String); 3630 } 3631 } 3632 package Test.pkg1 { 3633 public final class Class1 { 3634 method public void method1(); 3635 } 3636 } 3637 package Test.pkg2 { 3638 public final class Class1 { 3639 method public void method1(String, String); 3640 } 3641 } 3642 """ 3643 check( 3644 format = FileFormat.V1, 3645 signatureSources = arrayOf(source1, source2), 3646 api = expected 3647 ) 3648 } 3649 3650 val MERGE_TEST_SOURCE_1 = """ 3651 package test.pkg { 3652 public final class BaseClass { 3653 method public void method1(); 3654 } 3655 } 3656 """ 3657 val MERGE_TEST_SOURCE_2 = """ 3658 package test.pkg { 3659 public final class SubClass extends test.pkg.BaseClass { 3660 } 3661 } 3662 """ 3663 val MERGE_TEST_EXPECTED = """ 3664 package test.pkg { 3665 public final class BaseClass { 3666 method public void method1(); 3667 } 3668 public final class SubClass extends test.pkg.BaseClass { 3669 } 3670 } 3671 """ 3672 3673 @Test Test merging API signature files, one refer to anothernull3674 fun `Test merging API signature files, one refer to another`() { 3675 check( 3676 signatureSources = arrayOf(MERGE_TEST_SOURCE_1, MERGE_TEST_SOURCE_2), 3677 api = MERGE_TEST_EXPECTED 3678 ) 3679 } 3680 3681 @Test Test merging API signature files, one refer to another, in reverse ordernull3682 fun `Test merging API signature files, one refer to another, in reverse order`() { 3683 // Exactly the same as the previous test, but read them in the reverse order 3684 check( 3685 signatureSources = arrayOf(MERGE_TEST_SOURCE_2, MERGE_TEST_SOURCE_1), 3686 api = MERGE_TEST_EXPECTED 3687 ) 3688 } 3689 3690 @Test Test merging API signature files with reverse dependencynull3691 fun `Test merging API signature files with reverse dependency`() { 3692 val source1 = """ 3693 package test.pkg { 3694 public final class Class1 { 3695 method public void method1(test.pkg.Class2 arg); 3696 } 3697 } 3698 """ 3699 val source2 = """ 3700 package test.pkg { 3701 public final class Class2 { 3702 } 3703 } 3704 """ 3705 val expected = """ 3706 package test.pkg { 3707 public final class Class1 { 3708 method public void method1(test.pkg.Class2 arg); 3709 } 3710 public final class Class2 { 3711 } 3712 } 3713 """ 3714 check( 3715 format = FileFormat.V1, 3716 signatureSources = arrayOf(source1, source2), 3717 api = expected 3718 ) 3719 } 3720 3721 @Test Test merging 3 API signature filesnull3722 fun `Test merging 3 API signature files`() { 3723 val source1 = """ 3724 package test.pkg1 { 3725 public final class BaseClass1 { 3726 method public void method1(); 3727 } 3728 3729 public final class AnotherSubClass extends test.pkg2.AnotherBase { 3730 method public void method1(); 3731 } 3732 } 3733 """ 3734 val source2 = """ 3735 package test.pkg2 { 3736 public final class SubClass1 extends test.pkg1.BaseClass1 { 3737 } 3738 } 3739 """ 3740 val source3 = """ 3741 package test.pkg2 { 3742 public final class SubClass2 extends test.pkg2.SubClass1 { 3743 method public void bar(); 3744 } 3745 3746 public final class AnotherBase { 3747 method public void baz(); 3748 } 3749 } 3750 """ 3751 val expected = """ 3752 package test.pkg1 { 3753 public final class AnotherSubClass extends test.pkg2.AnotherBase { 3754 method public void method1(); 3755 } 3756 public final class BaseClass1 { 3757 method public void method1(); 3758 } 3759 } 3760 package test.pkg2 { 3761 public final class AnotherBase { 3762 method public void baz(); 3763 } 3764 public final class SubClass1 extends test.pkg1.BaseClass1 { 3765 } 3766 public final class SubClass2 extends test.pkg2.SubClass1 { 3767 method public void bar(); 3768 } 3769 } 3770 """ 3771 check( 3772 signatureSources = arrayOf(source1, source2, source3), 3773 api = expected 3774 ) 3775 } 3776 3777 @Test Test cannot merging API signature files with duplicate classnull3778 fun `Test cannot merging API signature files with duplicate class`() { 3779 val source1 = """ 3780 package Test.pkg { 3781 public final class Class1 { 3782 method public void method1(); 3783 } 3784 } 3785 """ 3786 val source2 = """ 3787 package Test.pkg { 3788 public final class Class1 { 3789 method public void method1(); 3790 } 3791 } 3792 """ 3793 check( 3794 signatureSources = arrayOf(source1, source2), 3795 expectedFail = "Aborting: Unable to parse signature file: TESTROOT/project/load-api2.txt:2: Duplicate class found: Test.pkg.Class1" 3796 ) 3797 } 3798 3799 @Test Test cannot merging API signature files with different file formatsnull3800 fun `Test cannot merging API signature files with different file formats`() { 3801 val source1 = """ 3802 // Signature format: 2.0 3803 package Test.pkg { 3804 } 3805 """ 3806 val source2 = """ 3807 // Signature format: 3.0 3808 package Test.pkg { 3809 } 3810 """ 3811 check( 3812 signatureSources = arrayOf(source1, source2), 3813 expectedFail = "Aborting: Unable to parse signature file: Cannot merge different formats of signature files. " + 3814 "First file format=V2, current file format=V3: file=TESTROOT/project/load-api2.txt" 3815 ) 3816 } 3817 3818 @Test Test tracking of @Composable annotation from classpathnull3819 fun `Test tracking of @Composable annotation from classpath`() { 3820 check( 3821 format = FileFormat.V3, 3822 classpath = arrayOf( 3823 /* The following source file, compiled, and root folder jar'ed and stored as base64 gzip: 3824 package test.pkg 3825 @MustBeDocumented 3826 @Retention(AnnotationRetention.BINARY) 3827 @Target( 3828 AnnotationTarget.CLASS, 3829 AnnotationTarget.FUNCTION, 3830 AnnotationTarget.TYPE, 3831 AnnotationTarget.TYPE_PARAMETER, 3832 AnnotationTarget.PROPERTY 3833 ) 3834 annotation class Composable 3835 */ 3836 base64gzip( 3837 "test.jar", 3838 "" + 3839 "UEsDBAoAAAgIAKx6s1AAAAAAAgAAAAAAAAAJAAAATUVUQS1JTkYvAwBQSwMECgAACAgAZ3qzULJ/" + 3840 "Au4bAAAAGQAAABQAAABNRVRBLUlORi9NQU5JRkVTVC5NRvNNzMtMSy0u0Q1LLSrOzM+zUjDUM+Dl" + 3841 "4uUCAFBLAwQKAAAICABnerNQDArdZgwAAAAQAAAAGwAAAE1FVEEtSU5GL3RlbXAua290bGluX21v" + 3842 "ZHVsZWNgYGBmYGBghGIBAFBLAwQKAAAICABnerNQAAAAAAIAAAAAAAAABQAAAHRlc3QvAwBQSwME" + 3843 "CgAACAgAZ3qzUAAAAAACAAAAAAAAAAkAAAB0ZXN0L3BrZy8DAFBLAwQKAAAICABnerNQbrgjGPQB" + 3844 "AACVAwAAGQAAAHRlc3QvcGtnL0NvbXBvc2FibGUuY2xhc3OFUk1v2kAQfWtioG6TkKRpSdI0H01I" + 3845 "P6S65doTEEdF4kvGrRRxqBZYIQdjo+xClRu3Xvsz+ht6qFCO/VFVZ4kCVLJU2Xo7O/PGM/M8v//8" + 3846 "/AUgjzcMW0pIZQ/7PbsUDYaR5O1ApMAYMld8zO2Ahz273r4SHZVCguFg4eVhGCmu/Ci0C3MzBZPh" + 3847 "pNKPVOCHy5TqSKqiOI86o4EIleh+YNiPoblCUZgsiptjHowEw1kMb1FxOSNZLNcK7iXDbkyKx697" + 3848 "QhFrjQdB9FV07xwyvt9FgXmeWaoUmk2G9MWnWskr12sMK95lw6Ev6uNLo+AWqo7nuERpuPWG43rU" + 3849 "ylElVrJ/lDiM5yyPlvsPpREFfudmpmoscT7FcXzcCYRux7sZCi0kzfGxfs6wcS9NVSje5YpT0BiM" + 3850 "E7Q+TEOGru3ZFRpoQ1ifXN33NNR0YllG1rCMzJ41naRvvxnZ6SRvvGPF6eT2R9LQvDzDdiVmBakM" + 3851 "SF4lBkOG1YX/bV8xWM1odN0RF35A27HjjkiAgfjsS58Ii/8mc1QAK/SZpG6P7FczfInXdH5Hih4g" + 3852 "TfEHAhYe4hGZqy2YAmtY15DRsKFhU8MWHlPC9l3CE6zjqTZbMASympbFDnZhYq+FRBnPZu8+nt/f" + 3853 "Dso4xBGZOG6BSbzACYUkTiVyEmd/AVBLAQIUAwoAAAgIAKx6s1AAAAAAAgAAAAAAAAAJAAAAAAAA" + 3854 "AAAAEADtQQAAAABNRVRBLUlORi9QSwECFAMKAAAICABnerNQsn8C7hsAAAAZAAAAFAAAAAAAAAAA" + 3855 "AAAApIEpAAAATUVUQS1JTkYvTUFOSUZFU1QuTUZQSwECFAMKAAAICABnerNQDArdZgwAAAAQAAAA" + 3856 "GwAAAAAAAAAAAAAAoIF2AAAATUVUQS1JTkYvdGVtcC5rb3RsaW5fbW9kdWxlUEsBAhQDCgAACAgA" + 3857 "Z3qzUAAAAAACAAAAAAAAAAUAAAAAAAAAAAAQAOhBuwAAAHRlc3QvUEsBAhQDCgAACAgAZ3qzUAAA" + 3858 "AAACAAAAAAAAAAkAAAAAAAAAAAAQAOhB4AAAAHRlc3QvcGtnL1BLAQIUAwoAAAgIAGd6s1BuuCMY" + 3859 "9AEAAJUDAAAZAAAAAAAAAAAAAACggQkBAAB0ZXN0L3BrZy9Db21wb3NhYmxlLmNsYXNzUEsFBgAA" + 3860 "AAAGAAYAcwEAADQDAAAAAA==" 3861 ) 3862 ), 3863 sourceFiles = arrayOf( 3864 kotlin( 3865 """ 3866 package test.pkg 3867 class RadioGroupScope() { 3868 @Composable 3869 fun RadioGroupItem( 3870 selected: Boolean, 3871 onSelect: () -> Unit, 3872 content: @Composable () -> Unit 3873 ) { } 3874 } 3875 """ 3876 ) 3877 ), 3878 expectedIssues = "", 3879 api = 3880 """ 3881 // Signature format: 3.0 3882 package test.pkg { 3883 public final class RadioGroupScope { 3884 ctor public RadioGroupScope(); 3885 method @test.pkg.Composable public void RadioGroupItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onSelect, kotlin.jvm.functions.Function0<kotlin.Unit> content); 3886 } 3887 } 3888 """ 3889 ) 3890 } 3891 3892 @Test Test for experimental annotations from classpathnull3893 fun `Test for experimental annotations from classpath`() { 3894 check( 3895 format = FileFormat.V3, 3896 classpath = arrayOf( 3897 /* The following source file, compiled, and root folder jar'ed and stored as base64 gzip 3898 Encoded using openssl base64 < test.jar | tr -d '\n' 3899 3900 package test.pkg 3901 @RequiresOptIn 3902 annotation class ExternalExperimentalAnnotation 3903 */ 3904 base64gzip( 3905 "test.jar", 3906 "" + 3907 "UEsDBAoAAAgIADt2U1IAAAAAAgAAAAAAAAAJAAAATUVUQS1JTkYvAwBQSwMECgAACAgAFXZ" + 3908 "TUrJ/Au4bAAAAGQAAABQAAABNRVRBLUlORi9NQU5JRkVTVC5NRvNNzMtMSy0u0Q1LLSrOzM" + 3909 "+zUjDUM+Dl4uUCAFBLAwQKAAAICAA7dlNSDWpm1BUAAAAYAAAAGwAAAE1FVEEtSU5GL3Rlc" + 3910 "3Qua290bGluX21vZHVsZWNgYGBmYGBgBGIWIGYCYgYlBi0GAFBLAwQKAAAICAA7dlNSAAAA" + 3911 "AAIAAAAAAAAABQAAAHRlc3QvAwBQSwMECgAACAgAO3ZTUgAAAAACAAAAAAAAAAkAAAB0ZXN" + 3912 "0L3BrZy8DAFBLAwQKAAAICAA7dlNSPYCyXGwBAABkAgAALQAAAHRlc3QvcGtnL0V4dGVybm" + 3913 "FsRXhwZXJpbWVudGFsQW5ub3RhdGlvbi5jbGFzc41Qy04CQRCsWZ6uL/CBICp6wXhxlasnT" + 3914 "TBuAmLwceE0wIQsLLPIzhK87c1f8Rs8GMLRjzL2qoiJRr309HRVdXf188vjE4ACcgy7SrjK" + 3915 "6HVaRnGoRF9yuzjsib7VFVJx+1hKR3FlOTIGxpBo8wE3bC5bRqXeFg0VQ4ghN63yT77xVRp" + 3916 "hSJU6jrItaVTFrWf1hVvpKVMeMWyXfpRXhaINKCNKZMBtTzDk/6BeOLbVuCNBrHp9fmWWiw" + 3917 "zJydiyULzJFSdU6w5CZJ8FIRwEjWr1txqCQJZYh0rNQ9pu5Ou6ltZ0LZHVR358fK+lR35BO" + 3918 "2AnI3/8EA2kzQLDXumfd6T5YAgHbIad37n7HeLol47Xb4hTy6YLZKoeOe2KG8u16raYUl2G" + 3919 "7AdmysE3NE9rIkyDo3h3uRHYRhab9J5RFidsRkDHLOYQwXwNIRMLJhZNJJCc/JZMLGOFUqz" + 3920 "WwFyksEaQi7SLjIt1bFG3KHWKAa9QSwECFAMKAAAICAA7dlNSAAAAAAIAAAAAAAAACQAAAA" + 3921 "AAAAAAABAA7UEAAAAATUVUQS1JTkYvUEsBAhQDCgAACAgAFXZTUrJ/Au4bAAAAGQAAABQAA" + 3922 "AAAAAAAAAAAAKSBKQAAAE1FVEEtSU5GL01BTklGRVNULk1GUEsBAhQDCgAACAgAO3ZTUg1q" + 3923 "ZtQVAAAAGAAAABsAAAAAAAAAAAAAAKCBdgAAAE1FVEEtSU5GL3Rlc3Qua290bGluX21vZHV" + 3924 "sZVBLAQIUAwoAAAgIADt2U1IAAAAAAgAAAAAAAAAFAAAAAAAAAAAAEADoQcQAAAB0ZXN0L1" + 3925 "BLAQIUAwoAAAgIADt2U1IAAAAAAgAAAAAAAAAJAAAAAAAAAAAAEADoQekAAAB0ZXN0L3BrZ" + 3926 "y9QSwECFAMKAAAICAA7dlNSPYCyXGwBAABkAgAALQAAAAAAAAAAAAAAoIESAQAAdGVzdC9w" + 3927 "a2cvRXh0ZXJuYWxFeHBlcmltZW50YWxBbm5vdGF0aW9uLmNsYXNzUEsFBgAAAAAGAAYAhwE" + 3928 "AAMkCAAAAAA==" 3929 ) 3930 ), 3931 sourceFiles = arrayOf( 3932 kotlin( 3933 """ 3934 package test.pkg 3935 3936 @ExternalExperimentalAnnotation 3937 class ClassUsingExternalExperimentalApi 3938 3939 @InLibraryExperimentalAnnotation 3940 class ClassUsingInLibraryExperimentalApi 3941 """ 3942 ), 3943 kotlin( 3944 """ 3945 package test.pkg 3946 @RequiresOptIn 3947 annotation class InLibraryExperimentalAnnotation 3948 """ 3949 ) 3950 ), 3951 expectedIssues = "", 3952 api = 3953 """ 3954 // Signature format: 3.0 3955 package test.pkg { 3956 @kotlin.RequiresOptIn public @interface InLibraryExperimentalAnnotation { 3957 } 3958 } 3959 """, 3960 extraArguments = arrayOf( 3961 ARG_HIDE_META_ANNOTATION, "kotlin.RequiresOptIn" 3962 ) 3963 ) 3964 } 3965 3966 @Test @IntRange value in kotlinnull3967 fun `@IntRange value in kotlin`() { 3968 check( 3969 format = FileFormat.V3, 3970 sourceFiles = arrayOf( 3971 kotlin( 3972 """ 3973 package test.pkg 3974 3975 import androidx.annotation.IntRange 3976 3977 class KotlinClass(@IntRange(from = 1) val param: Int) { 3978 constructor(@IntRange(from = 2) val differentParam: Int) 3979 fun myMethod(@IntRange(from = 3) val methodParam: Int) {} 3980 } 3981 """ 3982 ), 3983 androidxIntRangeSource 3984 ), 3985 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"), 3986 api = """ 3987 // Signature format: 3.0 3988 package test.pkg { 3989 public final class KotlinClass { 3990 ctor public KotlinClass(@IntRange(from=1L) int param); 3991 ctor public KotlinClass(@IntRange(from=2L) int differentParam); 3992 method public int getParam(); 3993 method public void myMethod(@IntRange(from=3L) int methodParam); 3994 property public final int param; 3995 } 3996 } 3997 """ 3998 ) 3999 } 4000 4001 @Test Annotation value visibilitynull4002 fun `Annotation value visibility`() { 4003 check( 4004 format = FileFormat.V2, 4005 sourceFiles = arrayOf( 4006 java( 4007 """ 4008 package test.pkg; 4009 4010 import androidx.annotation.IntRange; 4011 4012 public final class ApiClass { 4013 private int hiddenConstant = 1; 4014 public ApiClass(@IntRange(from=1) int x) {} 4015 public void method(@IntRange(from = hiddenConstant) int x) {} 4016 } 4017 """ 4018 ), 4019 androidxIntRangeSource 4020 ), 4021 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"), 4022 api = """ 4023 // Signature format: 2.0 4024 package test.pkg { 4025 public final class ApiClass { 4026 ctor public ApiClass(@IntRange(from=1) int); 4027 method public void method(@IntRange(from=0x1) int); 4028 } 4029 } 4030 """ 4031 ) 4032 } 4033 4034 @Test Kotlin properties with overriding getnull4035 fun `Kotlin properties with overriding get`() { 4036 check( 4037 format = FileFormat.V3, 4038 sourceFiles = arrayOf( 4039 kotlin( 4040 """ 4041 package test.pkg 4042 4043 import androidx.annotation.IntRange 4044 4045 class KotlinClass() { 4046 val propertyWithGetter: Boolean get() = true 4047 val propertyWithNoGetter: Boolean = true 4048 } 4049 """ 4050 ), 4051 androidxIntRangeSource 4052 ), 4053 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"), 4054 api = """ 4055 // Signature format: 3.0 4056 package test.pkg { 4057 public final class KotlinClass { 4058 ctor public KotlinClass(); 4059 method public boolean getPropertyWithGetter(); 4060 method public boolean getPropertyWithNoGetter(); 4061 property public final boolean propertyWithGetter; 4062 property public final boolean propertyWithNoGetter; 4063 } 4064 } 4065 """ 4066 ) 4067 } 4068 4069 @Test Constructor property trackingnull4070 fun `Constructor property tracking`() { 4071 check( 4072 format = FileFormat.V3, 4073 sourceFiles = arrayOf( 4074 kotlin( 4075 """ 4076 package test.pkg 4077 sealed class MyClass( 4078 val firstConstructorProperty: Int, 4079 val secondConstructorProperty: Boolean 4080 ) { 4081 val nonConstructorProperty: String = "PROP" 4082 } 4083 """ 4084 ), 4085 kotlin( 4086 """ 4087 package test.pkg 4088 data class MyDataClass( 4089 val constructorProperty: String, 4090 internal val internalConstructorProperty: String 4091 ) 4092 """ 4093 ) 4094 ), 4095 api = """ 4096 // Signature format: 3.0 4097 package test.pkg { 4098 public abstract sealed class MyClass { 4099 method public final int getFirstConstructorProperty(); 4100 method public final String getNonConstructorProperty(); 4101 method public final boolean getSecondConstructorProperty(); 4102 property public final int firstConstructorProperty; 4103 property public final String nonConstructorProperty; 4104 property public final boolean secondConstructorProperty; 4105 } 4106 public final class MyDataClass { 4107 ctor public MyDataClass(String constructorProperty, String internalConstructorProperty); 4108 method public String component1(); 4109 method public test.pkg.MyDataClass copy(String constructorProperty, String internalConstructorProperty); 4110 method public String getConstructorProperty(); 4111 property public final String constructorProperty; 4112 } 4113 } 4114 """ 4115 ) 4116 } 4117 4118 @Test Concise default Values Names in Javanull4119 fun `Concise default Values Names in Java`() { 4120 // Java code which explicitly specifies parameter names 4121 check( 4122 format = FileFormat.V4, 4123 sourceFiles = arrayOf( 4124 java( 4125 """ 4126 package test.pkg; 4127 import androidx.annotation.DefaultValue; 4128 4129 public class Foo { 4130 public void foo( 4131 @DefaultValue("null") String prefix, 4132 @DefaultValue("\"Hello World\"") String greeting, 4133 @DefaultValue("42") int meaning) { 4134 } 4135 } 4136 """ 4137 ), 4138 supportDefaultValue 4139 ), 4140 api = """ 4141 // Signature format: 4.0 4142 package test.pkg { 4143 public class Foo { 4144 ctor public Foo(); 4145 method public void foo(optional String!, optional String!, optional int); 4146 } 4147 } 4148 """, 4149 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation") 4150 ) 4151 } 4152 4153 @Test Concise default Values and Names in Kotlinnull4154 fun `Concise default Values and Names in Kotlin`() { 4155 // Kotlin code which explicitly specifies parameter names 4156 check( 4157 format = FileFormat.V4, 4158 sourceFiles = arrayOf( 4159 kotlin( 4160 """ 4161 package test.pkg 4162 import some.other.pkg.Constants.Misc.SIZE 4163 import android.graphics.Bitmap 4164 import android.view.View 4165 4166 class Foo(a: String = "1", b: String = "2") { 4167 fun method1(myInt: Int = 42, 4168 myInt2: Int? = null, 4169 myByte: Int = 2 * 21, 4170 str: String = "hello " + "world", 4171 vararg args: String) { } 4172 4173 fun method2(myInt: Int, myInt2: Int = (2*int) * SIZE) { } 4174 4175 fun method3(str: String, myInt: Int, myInt2: Int = double(int) + str.length) { } 4176 4177 fun emptyLambda(sizeOf: () -> Unit = { }) {} 4178 4179 fun View.drawToBitmap(config: Bitmap.Config = Bitmap.Config.ARGB_8888): Bitmap? = null 4180 4181 companion object { 4182 fun double(myInt: Int) = 2 * myInt 4183 fun print(foo: Foo = Foo()) { println(foo) } 4184 } 4185 } 4186 """ 4187 ), 4188 java( 4189 """ 4190 package some.other.pkg; 4191 public class Constants { 4192 public static class Misc { 4193 public static final int SIZE = 5; 4194 } 4195 } 4196 """ 4197 ) 4198 ), 4199 api = """ 4200 // Signature format: 4.0 4201 package test.pkg { 4202 public final class Foo { 4203 ctor public Foo(optional String a, optional String b); 4204 method public android.graphics.Bitmap? drawToBitmap(android.view.View, optional android.graphics.Bitmap.Config config); 4205 method public void emptyLambda(optional kotlin.jvm.functions.Function0<kotlin.Unit> sizeOf); 4206 method public void method1(optional int myInt, optional Integer? myInt2, optional int myByte, optional String str, java.lang.String... args); 4207 method public void method2(int myInt, optional int myInt2); 4208 method public void method3(String str, int myInt, optional int myInt2); 4209 field public static final test.pkg.Foo.Companion Companion; 4210 } 4211 public static final class Foo.Companion { 4212 method public int double(int myInt); 4213 method public void print(optional test.pkg.Foo foo); 4214 } 4215 } 4216 """, 4217 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation", ARG_HIDE_PACKAGE, "some.other.pkg"), 4218 includeSignatureVersion = true 4219 ) 4220 } 4221 4222 @Test Concise default Values in Kotlin for expressionsnull4223 fun `Concise default Values in Kotlin for expressions`() { 4224 // Testing trickier default values; regression test for problem 4225 // observed in androidx.core.util with LruCache 4226 check( 4227 format = FileFormat.V4, 4228 sourceFiles = arrayOf( 4229 kotlin( 4230 """ 4231 package androidx.core.util 4232 4233 import android.util.LruCache 4234 4235 inline fun <K : Any, V : Any> lruCache( 4236 maxSize: Int, 4237 crossinline sizeOf: (key: K, value: V) -> Int = { _, _ -> 1 }, 4238 @Suppress("USELESS_CAST") // https://youtrack.jetbrains.com/issue/KT-21946 4239 crossinline create: (key: K) -> V? = { null as V? }, 4240 crossinline onEntryRemoved: (evicted: Boolean, key: K, oldValue: V, newValue: V?) -> Unit = 4241 { _, _, _, _ -> } 4242 ): LruCache<K, V> { 4243 return object : LruCache<K, V>(maxSize) { 4244 override fun sizeOf(key: K, value: V) = sizeOf(key, value) 4245 override fun create(key: K) = create(key) 4246 override fun entryRemoved(evicted: Boolean, key: K, oldValue: V, newValue: V?) { 4247 onEntryRemoved(evicted, key, oldValue, newValue) 4248 } 4249 } 4250 } 4251 """ 4252 ), 4253 java( 4254 """ 4255 package androidx.collection; 4256 4257 import androidx.annotation.NonNull; 4258 import androidx.annotation.Nullable; 4259 4260 import java.util.LinkedHashMap; 4261 import java.util.Locale; 4262 import java.util.Map; 4263 4264 public class LruCache<K, V> { 4265 @Nullable 4266 protected V create(@NonNull K key) { 4267 return null; 4268 } 4269 4270 protected int sizeOf(@NonNull K key, @NonNull V value) { 4271 return 1; 4272 } 4273 4274 protected void entryRemoved(boolean evicted, @NonNull K key, @NonNull V oldValue, 4275 @Nullable V newValue) { 4276 } 4277 } 4278 """ 4279 ), 4280 androidxNullableSource, 4281 androidxNonNullSource 4282 ), 4283 api = """ 4284 // Signature format: 4.0 4285 package androidx.core.util { 4286 public final class TestKt { 4287 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); 4288 } 4289 } 4290 """, 4291 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation", ARG_HIDE_PACKAGE, "androidx.collection"), 4292 includeSignatureVersion = true 4293 ) 4294 } 4295 4296 @Test Test type erasure and dexApi from signaturenull4297 fun `Test type erasure and dexApi from signature`() { 4298 check( 4299 signatureSources = arrayOf( 4300 """ 4301 package android.widget { 4302 4303 @android.widget.RemoteViews.RemoteView public class ListView extends android.widget.AbsListView { 4304 method protected <T extends android.view.View> T findViewTraversal(@IdRes int); 4305 method protected long tryAcquireShared(long); 4306 } 4307 4308 } 4309 """ 4310 ), 4311 dexApi = """ 4312 Landroid/widget/ListView; 4313 Landroid/widget/ListView;->findViewTraversal(I)Landroid/view/View; 4314 Landroid/widget/ListView;->tryAcquireShared(J)J 4315 """ 4316 ) 4317 } 4318 4319 @Test Functional interface in signaturenull4320 fun `Functional interface in signature`() { 4321 check( 4322 format = FileFormat.V4, 4323 sourceFiles = arrayOf( 4324 kotlin( 4325 """ 4326 package test.pkg 4327 4328 fun interface FunctionalInterface { 4329 fun methodOne(number: Int): Boolean 4330 } 4331 4332 fun userOfFunctionalInterface(parameter: FunctionalInterface) { } 4333 """ 4334 ) 4335 ), 4336 api = """ 4337 // Signature format: 4.0 4338 package test.pkg { 4339 public fun interface FunctionalInterface { 4340 method public boolean methodOne(int number); 4341 } 4342 public final class FunctionalInterfaceKt { 4343 method public static void userOfFunctionalInterface(test.pkg.FunctionalInterface parameter); 4344 } 4345 } 4346 """ 4347 ) 4348 } 4349 4350 @Test Inline classnull4351 fun `Inline class`() { 4352 check( 4353 format = FileFormat.V4, 4354 sourceFiles = arrayOf( 4355 kotlin( 4356 """ 4357 package test.pkg 4358 4359 inline class Dp(val value: Float) : Comparable<Dp> { 4360 inline operator fun plus(other: Dp) = Dp(value = this.value + other.value) 4361 inline operator fun minus(other: Dp) = Dp(value = this.value - other.value) 4362 // Not tracked due to https://youtrack.jetbrains.com/issue/KTIJ-11559 4363 val someBits 4364 get() = value && 0x00ff 4365 // Not tracked due to https://youtrack.jetbrains.com/issue/KTIJ-11559 4366 fun doSomething() {} 4367 } 4368 """ 4369 ) 4370 ), 4371 api = """ 4372 // Signature format: 4.0 4373 package test.pkg { 4374 public final inline class Dp implements java.lang.Comparable<test.pkg.Dp> { 4375 ctor public Dp(); 4376 method public float getValue(); 4377 method public inline operator float minus(float other); 4378 method public inline operator float plus(float other); 4379 property public final float value; 4380 } 4381 } 4382 """ 4383 ) 4384 } 4385 4386 @Test Value classnull4387 fun `Value class`() { 4388 check( 4389 format = FileFormat.V4, 4390 sourceFiles = arrayOf( 4391 kotlin( 4392 """ 4393 package test.pkg 4394 @JvmInline 4395 value class Dp(val value: Float) : Comparable<Dp> { 4396 inline operator fun plus(other: Dp) = Dp(value = this.value + other.value) 4397 inline operator fun minus(other: Dp) = Dp(value = this.value - other.value) 4398 val someBits 4399 get() = value && 0x00ff 4400 fun doSomething() {} 4401 } 4402 """ 4403 ) 4404 ), 4405 api = """ 4406 // Signature format: 4.0 4407 package test.pkg { 4408 @kotlin.jvm.JvmInline public final value class Dp implements java.lang.Comparable<test.pkg.Dp> { 4409 ctor public Dp(float value); 4410 method public void doSomething(); 4411 method public boolean getSomeBits(); 4412 method public float getValue(); 4413 method public inline operator float minus(float other); 4414 method public inline operator float plus(float other); 4415 property public final boolean someBits; 4416 property public final float value; 4417 } 4418 } 4419 """ 4420 ) 4421 } 4422 4423 @Test Kotlin doesn't expand java named constantsnull4424 fun `Kotlin doesn't expand java named constants`() { 4425 check( 4426 format = FileFormat.V3, 4427 sourceFiles = 4428 arrayOf( 4429 kotlin( 4430 """ 4431 package test.pkg 4432 annotation class Foo(val bar: Long = java.lang.Long.MIN_VALUE) 4433 """ 4434 ) 4435 ), 4436 api = 4437 """ 4438 // Signature format: 3.0 4439 package test.pkg { 4440 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public @interface Foo { 4441 method public abstract long bar() default java.lang.Long.MIN_VALUE; 4442 property public abstract long bar; 4443 } 4444 } 4445 """ 4446 ) 4447 } 4448 4449 @Test 4450 fun `Kotlin constructors with JvmOverloads`() { 4451 check( 4452 format = FileFormat.V4, 4453 sourceFiles = arrayOf( 4454 kotlin( 4455 """ 4456 package test.pkg 4457 4458 class AllOptionalJvmOverloads @JvmOverloads constructor( 4459 private val foo: Int = 0, 4460 private val bar: Int = 0 4461 ) 4462 4463 class AllOptionalNoJvmOverloads( 4464 private val foo: Int = 0, 4465 private val bar: Int = 0 4466 ) 4467 4468 class SomeOptionalJvmOverloads @JvmOverloads constructor( 4469 private val foo: Int, 4470 private val bar: Int = 0 4471 ) 4472 4473 class SomeOptionalNoJvmOverloads( 4474 private val foo: Int, 4475 private val bar: Int = 0 4476 ) 4477 """ 4478 ) 4479 ), 4480 api = """ 4481 // Signature format: 4.0 4482 package test.pkg { 4483 public final class AllOptionalJvmOverloads { 4484 ctor public AllOptionalJvmOverloads(optional int foo, optional int bar); 4485 ctor public AllOptionalJvmOverloads(optional int foo); 4486 ctor public AllOptionalJvmOverloads(); 4487 } 4488 public final class AllOptionalNoJvmOverloads { 4489 ctor public AllOptionalNoJvmOverloads(optional int foo, optional int bar); 4490 } 4491 public final class SomeOptionalJvmOverloads { 4492 ctor public SomeOptionalJvmOverloads(int foo, optional int bar); 4493 ctor public SomeOptionalJvmOverloads(int foo); 4494 } 4495 public final class SomeOptionalNoJvmOverloads { 4496 ctor public SomeOptionalNoJvmOverloads(int foo, optional int bar); 4497 } 4498 } 4499 """ 4500 ) 4501 } 4502 4503 @Test 4504 fun `Kotlin public methods with DeprecationLevel HIDDEN are public API`() { 4505 check( 4506 format = FileFormat.V3, 4507 sourceFiles = arrayOf( 4508 kotlin( 4509 """ 4510 package test.pkg 4511 @Deprecated( 4512 message = "So much regret", 4513 level = DeprecationLevel.HIDDEN 4514 ) 4515 fun myMethod() { TODO() } 4516 @Deprecated( 4517 message = "So much regret", 4518 level = DeprecationLevel.HIDDEN 4519 ) 4520 internal fun myInternalMethod() { TODO() } 4521 @Deprecated( 4522 message = "So much regret", 4523 level = DeprecationLevel.HIDDEN 4524 ) 4525 private fun myPrivateMethod() { TODO() } 4526 @Deprecated( 4527 message = "So much regret", 4528 level = DeprecationLevel.WARNING 4529 ) 4530 fun myNormalDeprecatedMethod() { TODO() } 4531 """ 4532 ) 4533 ), 4534 api = """ 4535 // Signature format: 3.0 4536 package test.pkg { 4537 public final class TestKt { 4538 method @Deprecated public static void myMethod(); 4539 method @Deprecated public static void myNormalDeprecatedMethod(); 4540 } 4541 } 4542 """ 4543 ) 4544 } 4545 4546 @Test 4547 fun `Annotations aren't dropped when DeprecationLevel is HIDDEN`() { 4548 check( 4549 format = FileFormat.V3, 4550 sourceFiles = arrayOf( 4551 kotlin( 4552 """ 4553 package test.pkg 4554 @Deprecated( 4555 message = "So much regret", 4556 level = DeprecationLevel.HIDDEN 4557 ) 4558 @IntRange(from=0) 4559 fun myMethod() { TODO() } 4560 """ 4561 ) 4562 ), 4563 api = """ 4564 // Signature format: 3.0 4565 package test.pkg { 4566 public final class TestKt { 4567 method @Deprecated @kotlin.ranges.IntRange public static void myMethod(); 4568 } 4569 } 4570 """ 4571 ) 4572 } 4573 4574 @Test Constants in a file scope annotationnull4575 fun `Constants in a file scope annotation`() { 4576 check( 4577 format = FileFormat.V4, 4578 sourceFiles = arrayOf( 4579 kotlin( 4580 """ 4581 @file:RestrictTo(RestrictTo.Scope.LIBRARY) 4582 package test.pkg 4583 import androidx.annotation.RestrictTo 4584 private fun veryFun(): Boolean = true 4585 """ 4586 ), 4587 restrictToSource 4588 ), 4589 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"), 4590 api = """ 4591 // Signature format: 4.0 4592 package test.pkg { 4593 @RestrictTo({androidx.annotation.RestrictTo.Scope.LIBRARY}) public final class TestKt { 4594 } 4595 } 4596 """ 4597 ) 4598 } 4599 4600 @Test RestrictTo on a file hiding itnull4601 fun `RestrictTo on a file hiding it`() { 4602 check( 4603 format = FileFormat.V4, 4604 sourceFiles = arrayOf( 4605 kotlin( 4606 """ 4607 @file:RestrictTo(RestrictTo.Scope.LIBRARY) 4608 package test.pkg 4609 import androidx.annotation.RestrictTo 4610 private fun veryFun(): Boolean = true 4611 """ 4612 ), 4613 restrictToSource 4614 ), 4615 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation", "--show-unannotated"), 4616 hideAnnotations = arrayOf( 4617 "androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)" 4618 ), 4619 api = """ 4620 // Signature format: 4.0 4621 """ 4622 ) 4623 } 4624 4625 /** Regression test for b/202968090 */ 4626 @Test annotation arrays should be non-nullnull4627 fun `annotation arrays should be non-null`() { 4628 check( 4629 format = FileFormat.V4, 4630 sourceFiles = arrayOf( 4631 kotlin( 4632 """ 4633 package test.pkg 4634 annotation class Foo ( 4635 val bar: Array<String>, 4636 vararg val baz: String 4637 ) 4638 """ 4639 ) 4640 ), 4641 api = """ 4642 // Signature format: 4.0 4643 package test.pkg { 4644 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public @interface Foo { 4645 method public abstract String[] bar(); 4646 method public abstract String[] baz(); 4647 property public abstract String[] bar; 4648 property public abstract String[] baz; 4649 } 4650 } 4651 """ 4652 ) 4653 } 4654 4655 @Test property setter parameters are unnamednull4656 fun `property setter parameters are unnamed`() { 4657 check( 4658 sourceFiles = arrayOf( 4659 kotlin( 4660 """ 4661 package test.pkg 4662 class Foo(var bar: Int) 4663 """ 4664 ) 4665 ), 4666 api = """ 4667 package test.pkg { 4668 public final class Foo { 4669 ctor public Foo(int bar); 4670 method public int getBar(); 4671 method public void setBar(int); 4672 property public final int bar; 4673 } 4674 } 4675 """ 4676 ) 4677 } 4678 } 4679