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 Check generic type signature insertionnull2290 fun `Check generic type signature insertion`() { 2291 check( 2292 format = FileFormat.V2, 2293 sourceFiles = arrayOf( 2294 java( 2295 """ 2296 package test.pkg; 2297 public class MyClass { 2298 public <T> MyClass(Class<T> klass) { } 2299 public <U> void method1(Function<U> func) { } 2300 } 2301 """ 2302 ) 2303 ), 2304 expectedIssues = "", 2305 api = """ 2306 package test.pkg { 2307 public class MyClass { 2308 ctor public <T> MyClass(Class<T>); 2309 method public <U> void method1(Function<U>); 2310 } 2311 } 2312 """ 2313 ) 2314 } 2315 2316 @Test When implementing rather than extending package private class, inline members insteadnull2317 fun `When implementing rather than extending package private class, inline members instead`() { 2318 // If you implement a package private interface, we just remove it and inline the members into 2319 // the subclass 2320 check( 2321 sourceFiles = arrayOf( 2322 java( 2323 """ 2324 package test.pkg; 2325 public class MyClass implements HiddenInterface { 2326 @Override public void method() { } 2327 @Override public void other() { } 2328 } 2329 """ 2330 ), 2331 java( 2332 """ 2333 package test.pkg; 2334 public interface OtherInterface { 2335 void other(); 2336 } 2337 """ 2338 ), 2339 java( 2340 """ 2341 package test.pkg; 2342 interface HiddenInterface extends OtherInterface { 2343 void method() { } 2344 String CONSTANT = "MyConstant"; 2345 } 2346 """ 2347 ) 2348 ), 2349 api = """ 2350 package test.pkg { 2351 public class MyClass implements test.pkg.OtherInterface { 2352 ctor public MyClass(); 2353 method public void method(); 2354 method public void other(); 2355 field public static final String CONSTANT = "MyConstant"; 2356 } 2357 public interface OtherInterface { 2358 method public void other(); 2359 } 2360 } 2361 """ 2362 ) 2363 } 2364 2365 @Test Implementing package private classnull2366 fun `Implementing package private class`() { 2367 // Include all the non-hidden public interfaces into the signature 2368 2369 // BUG: Note that we need to implement the parent 2370 check( 2371 sourceFiles = arrayOf( 2372 java( 2373 """ 2374 package test.pkg; 2375 public class MyClass implements HiddenInterface { 2376 @Override public void method() { } 2377 @Override public void other() { } 2378 } 2379 """ 2380 ), 2381 java( 2382 """ 2383 package test.pkg; 2384 public interface OtherInterface { 2385 void other(); 2386 } 2387 """ 2388 ), 2389 java( 2390 """ 2391 package test.pkg; 2392 interface HiddenInterface extends OtherInterface { 2393 void method() { } 2394 String CONSTANT = "MyConstant"; 2395 } 2396 """ 2397 ) 2398 ), 2399 api = """ 2400 package test.pkg { 2401 public class MyClass implements test.pkg.OtherInterface { 2402 ctor public MyClass(); 2403 method public void method(); 2404 method public void other(); 2405 field public static final String CONSTANT = "MyConstant"; 2406 } 2407 public interface OtherInterface { 2408 method public void other(); 2409 } 2410 } 2411 """ 2412 ) 2413 } 2414 2415 @Test Default modifiers should be omittednull2416 fun `Default modifiers should be omitted`() { 2417 // If signatures vary only by the "default" modifier in the interface, don't show it on the implementing 2418 // class 2419 check( 2420 format = FileFormat.V1, 2421 sourceFiles = arrayOf( 2422 java( 2423 """ 2424 package test.pkg; 2425 2426 public class MyClass implements SuperInterface { 2427 @Override public void method() { } 2428 @Override public void method2() { } 2429 } 2430 """ 2431 ), 2432 java( 2433 """ 2434 package test.pkg; 2435 2436 public interface SuperInterface { 2437 void method(); 2438 default void method2() { 2439 } 2440 } 2441 """ 2442 ) 2443 ), 2444 api = """ 2445 package test.pkg { 2446 public class MyClass implements test.pkg.SuperInterface { 2447 ctor public MyClass(); 2448 method public void method(); 2449 } 2450 public interface SuperInterface { 2451 method public void method(); 2452 method public default void method2(); 2453 } 2454 } 2455 """ 2456 ) 2457 } 2458 2459 @Test Override via different throws list should be includednull2460 fun `Override via different throws list should be included`() { 2461 // If a method overrides another but changes the throws list, the overriding 2462 // method must be listed in the subclass. This is observed for example in 2463 // AbstractCursor#finalize, which omits the throws clause from Object's finalize. 2464 check( 2465 sourceFiles = arrayOf( 2466 java( 2467 """ 2468 package test.pkg; 2469 2470 public abstract class AbstractCursor extends Parent { 2471 @Override protected void finalize2() { } // note: not throws Throwable! 2472 } 2473 """ 2474 ), 2475 java( 2476 """ 2477 package test.pkg; 2478 2479 @SuppressWarnings("RedundantThrows") 2480 public class Parent { 2481 protected void finalize2() throws Throwable { 2482 } 2483 } 2484 """ 2485 ) 2486 ), 2487 api = """ 2488 package test.pkg { 2489 public abstract class AbstractCursor extends test.pkg.Parent { 2490 ctor public AbstractCursor(); 2491 method protected void finalize2(); 2492 } 2493 public class Parent { 2494 ctor public Parent(); 2495 method protected void finalize2() throws java.lang.Throwable; 2496 } 2497 } 2498 """ 2499 ) 2500 } 2501 2502 @Test Implementing interface methodnull2503 fun `Implementing interface method`() { 2504 // If you have a public method that implements an interface method, 2505 // they'll vary in the "abstract" modifier, but it shouldn't be listed on the 2506 // class. This is an issue for example for the ZonedDateTime#getLong method 2507 // implementing the TemporalAccessor#getLong method 2508 check( 2509 format = FileFormat.V1, 2510 sourceFiles = arrayOf( 2511 java( 2512 """ 2513 package test.pkg; 2514 public interface SomeInterface2 { 2515 @Override default long getLong() { 2516 return 42; 2517 } 2518 } 2519 """ 2520 ), 2521 java( 2522 """ 2523 package test.pkg; 2524 public class Foo implements SomeInterface2 { 2525 @Override 2526 public long getLong() { return 0L; } 2527 } 2528 """ 2529 ) 2530 ), 2531 api = """ 2532 package test.pkg { 2533 public class Foo implements test.pkg.SomeInterface2 { 2534 ctor public Foo(); 2535 } 2536 public interface SomeInterface2 { 2537 method public default long getLong(); 2538 } 2539 } 2540 """ 2541 ) 2542 } 2543 2544 @Test Implementing interface method 2null2545 fun `Implementing interface method 2`() { 2546 check( 2547 format = FileFormat.V1, 2548 sourceFiles = arrayOf( 2549 java( 2550 """ 2551 package test.pkg; 2552 public interface SomeInterface { 2553 long getLong(); 2554 } 2555 """ 2556 ), 2557 java( 2558 """ 2559 package test.pkg; 2560 public interface SomeInterface2 { 2561 @Override default long getLong() { 2562 return 42; 2563 } 2564 } 2565 """ 2566 ), 2567 java( 2568 """ 2569 package test.pkg; 2570 public class Foo implements SomeInterface, SomeInterface2 { 2571 @Override 2572 public long getLong() { return 0L; } 2573 } 2574 """ 2575 ) 2576 ), 2577 api = """ 2578 package test.pkg { 2579 public class Foo implements test.pkg.SomeInterface test.pkg.SomeInterface2 { 2580 ctor public Foo(); 2581 } 2582 public interface SomeInterface { 2583 method public long getLong(); 2584 } 2585 public interface SomeInterface2 { 2586 method public default long getLong(); 2587 } 2588 } 2589 """ 2590 ) 2591 } 2592 2593 @Test Check basic @remove scenariosnull2594 fun `Check basic @remove scenarios`() { 2595 // Test basic @remove handling for methods and fields 2596 check( 2597 sourceFiles = arrayOf( 2598 java( 2599 """ 2600 package test.pkg; 2601 @SuppressWarnings("JavaDoc") 2602 public class Bar { 2603 /** @removed */ 2604 public Bar() { } 2605 public int field; 2606 public void test() { } 2607 /** @removed */ 2608 public int removedField; 2609 /** @removed */ 2610 public void removedMethod() { } 2611 /** @removed and @hide - should not be listed */ 2612 public int hiddenField; 2613 2614 /** @removed */ 2615 public class Inner { } 2616 2617 public class Inner2 { 2618 public class Inner3 { 2619 /** @removed */ 2620 public class Inner4 { } 2621 } 2622 } 2623 2624 public class Inner5 { 2625 public class Inner6 { 2626 public class Inner7 { 2627 /** @removed */ 2628 public int removed; 2629 } 2630 } 2631 } 2632 } 2633 """ 2634 ) 2635 ), 2636 removedApi = """ 2637 package test.pkg { 2638 public class Bar { 2639 ctor public Bar(); 2640 method public void removedMethod(); 2641 field public int removedField; 2642 } 2643 public class Bar.Inner { 2644 ctor public Bar.Inner(); 2645 } 2646 public class Bar.Inner2.Inner3.Inner4 { 2647 ctor public Bar.Inner2.Inner3.Inner4(); 2648 } 2649 public class Bar.Inner5.Inner6.Inner7 { 2650 field public int removed; 2651 } 2652 } 2653 """ 2654 ) 2655 } 2656 2657 @Test Check @remove classnull2658 fun `Check @remove class`() { 2659 // Test removing classes 2660 check( 2661 format = FileFormat.V2, 2662 sourceFiles = arrayOf( 2663 java( 2664 """ 2665 package test.pkg; 2666 /** @removed */ 2667 @SuppressWarnings("JavaDoc") 2668 public class Foo { 2669 public void foo() { } 2670 public class Inner { 2671 } 2672 } 2673 """ 2674 ), 2675 java( 2676 """ 2677 package test.pkg; 2678 @SuppressWarnings("JavaDoc") 2679 public class Bar implements Parcelable { 2680 public int field; 2681 public void method(); 2682 2683 /** @removed */ 2684 public int removedField; 2685 /** @removed */ 2686 public void removedMethod() { } 2687 2688 public class Inner1 { 2689 } 2690 /** @removed */ 2691 public class Inner2 { 2692 } 2693 } 2694 """ 2695 ), 2696 java( 2697 """ 2698 package test.pkg; 2699 @SuppressWarnings("ALL") 2700 public interface Parcelable { 2701 void method(); 2702 } 2703 """ 2704 ) 2705 ), 2706 /* 2707 I expected this: but doclava1 doesn't do that (and we now match its behavior) 2708 package test.pkg { 2709 public class Bar { 2710 method public void removedMethod(); 2711 field public int removedField; 2712 } 2713 public class Bar.Inner2 { 2714 } 2715 public class Foo { 2716 method public void foo(); 2717 } 2718 } 2719 */ 2720 removedApi = """ 2721 package test.pkg { 2722 public class Bar implements test.pkg.Parcelable { 2723 method public void removedMethod(); 2724 field public int removedField; 2725 } 2726 public class Bar.Inner2 { 2727 ctor public Bar.Inner2(); 2728 } 2729 public class Foo { 2730 ctor public Foo(); 2731 method public void foo(); 2732 } 2733 public class Foo.Inner { 2734 ctor public Foo.Inner(); 2735 } 2736 } 2737 """ 2738 ) 2739 } 2740 2741 @Test Test include overridden @Deprecated even if annotated with @hidenull2742 fun `Test include overridden @Deprecated even if annotated with @hide`() { 2743 check( 2744 format = FileFormat.V1, 2745 sourceFiles = arrayOf( 2746 java( 2747 """ 2748 package test.pkg; 2749 @SuppressWarnings("JavaDoc") 2750 public class Child extends Parent { 2751 /** 2752 * @deprecated 2753 * @hide 2754 */ 2755 @Deprecated @Override 2756 public String toString() { 2757 return "Child"; 2758 } 2759 2760 /** 2761 * @hide 2762 */ 2763 public void hiddenApi() { 2764 } 2765 } 2766 """ 2767 ), 2768 java( 2769 """ 2770 package test.pkg; 2771 public class Parent { 2772 public String toString() { 2773 return "Parent"; 2774 } 2775 } 2776 """ 2777 ) 2778 ), 2779 api = """ 2780 package test.pkg { 2781 public class Child extends test.pkg.Parent { 2782 ctor public Child(); 2783 method @Deprecated public String toString(); 2784 } 2785 public class Parent { 2786 ctor public Parent(); 2787 } 2788 } 2789 """, 2790 dexApi = """ 2791 Ltest/pkg/Child; 2792 Ltest/pkg/Child;-><init>()V 2793 Ltest/pkg/Child;->toString()Ljava/lang/String; 2794 Ltest/pkg/Parent; 2795 Ltest/pkg/Parent;-><init>()V 2796 Ltest/pkg/Parent;->toString()Ljava/lang/String; 2797 """ 2798 ) 2799 } 2800 2801 @Test Test invalid class namenull2802 fun `Test invalid class name`() { 2803 // Regression test for b/73018978 2804 check( 2805 format = FileFormat.V1, 2806 sourceFiles = arrayOf( 2807 kotlin( 2808 "src/test/pkg/Foo.kt", 2809 """ 2810 @file:JvmName("-Foo") 2811 2812 package test.pkg 2813 2814 @Suppress("unused") 2815 inline fun String.printHelloWorld() { println("Hello World") } 2816 """ 2817 ) 2818 ), 2819 api = """ 2820 package test.pkg { 2821 public final class -Foo { 2822 method public static inline void printHelloWorld(@NonNull String); 2823 } 2824 } 2825 """ 2826 ) 2827 } 2828 2829 @Test Indirect Field Includes from Interfacesnull2830 fun `Indirect Field Includes from Interfaces`() { 2831 // Real-world example: include ZipConstants into ZipFile and JarFile 2832 check( 2833 sourceFiles = arrayOf( 2834 java( 2835 """ 2836 package test.pkg1; 2837 interface MyConstants { 2838 long CONSTANT1 = 12345; 2839 long CONSTANT2 = 67890; 2840 long CONSTANT3 = 42; 2841 } 2842 """ 2843 ), 2844 java( 2845 """ 2846 package test.pkg1; 2847 import java.io.Closeable; 2848 @SuppressWarnings("WeakerAccess") 2849 public class MyParent implements MyConstants, Closeable { 2850 } 2851 """ 2852 ), 2853 java( 2854 """ 2855 package test.pkg2; 2856 2857 import test.pkg1.MyParent; 2858 public class MyChild extends MyParent { 2859 } 2860 """ 2861 ) 2862 2863 ), 2864 api = """ 2865 package test.pkg1 { 2866 public class MyParent implements java.io.Closeable { 2867 ctor public MyParent(); 2868 field public static final long CONSTANT1 = 12345L; // 0x3039L 2869 field public static final long CONSTANT2 = 67890L; // 0x10932L 2870 field public static final long CONSTANT3 = 42L; // 0x2aL 2871 } 2872 } 2873 package test.pkg2 { 2874 public class MyChild extends test.pkg1.MyParent { 2875 ctor public MyChild(); 2876 field public static final long CONSTANT1 = 12345L; // 0x3039L 2877 field public static final long CONSTANT2 = 67890L; // 0x10932L 2878 field public static final long CONSTANT3 = 42L; // 0x2aL 2879 } 2880 } 2881 """ 2882 ) 2883 } 2884 2885 @Test Skip interfaces from packages explicitly hidden via argumentsnull2886 fun `Skip interfaces from packages explicitly hidden via arguments`() { 2887 // Real-world example: HttpResponseCache implements OkCacheContainer but hides the only inherited method 2888 check( 2889 extraArguments = arrayOf( 2890 ARG_HIDE_PACKAGE, "com.squareup.okhttp" 2891 ), 2892 sourceFiles = arrayOf( 2893 java( 2894 """ 2895 package android.net.http; 2896 import com.squareup.okhttp.Cache; 2897 import com.squareup.okhttp.OkCacheContainer; 2898 import java.io.Closeable; 2899 import java.net.ResponseCache; 2900 @SuppressWarnings("JavaDoc") 2901 public final class HttpResponseCache implements Closeable, OkCacheContainer { 2902 /** @hide Needed for OkHttp integration. */ 2903 @Override 2904 public Cache getCache() { 2905 return delegate.getCache(); 2906 } 2907 } 2908 """ 2909 ), 2910 java( 2911 """ 2912 package com.squareup.okhttp; 2913 public interface OkCacheContainer { 2914 Cache getCache(); 2915 } 2916 """ 2917 ), 2918 java( 2919 """ 2920 package com.squareup.okhttp; 2921 public class Cache { 2922 } 2923 """ 2924 ) 2925 ), 2926 expectedIssues = """ 2927 src/android/net/http/HttpResponseCache.java:7: warning: Public class android.net.http.HttpResponseCache stripped of unavailable superclass com.squareup.okhttp.OkCacheContainer [HiddenSuperclass] 2928 """, 2929 api = """ 2930 package android.net.http { 2931 public final class HttpResponseCache implements java.io.Closeable { 2932 ctor public HttpResponseCache(); 2933 } 2934 } 2935 """ 2936 ) 2937 } 2938 2939 @Test Extend from multiple interfacesnull2940 fun `Extend from multiple interfaces`() { 2941 // Real-world example: XmlResourceParser 2942 check( 2943 format = FileFormat.V1, 2944 checkCompilation = true, 2945 sourceFiles = arrayOf( 2946 java( 2947 """ 2948 package android.content.res; 2949 import android.util.AttributeSet; 2950 import org.xmlpull.v1.XmlPullParser; 2951 import my.AutoCloseable; 2952 2953 @SuppressWarnings("UnnecessaryInterfaceModifier") 2954 public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable { 2955 public void close(); 2956 } 2957 """ 2958 ), 2959 java( 2960 """ 2961 package android.util; 2962 @SuppressWarnings("WeakerAccess") 2963 public interface AttributeSet { 2964 } 2965 """ 2966 ), 2967 java( 2968 """ 2969 package my; 2970 public interface AutoCloseable { 2971 } 2972 """ 2973 ), 2974 java( 2975 """ 2976 package org.xmlpull.v1; 2977 @SuppressWarnings("WeakerAccess") 2978 public interface XmlPullParser { 2979 } 2980 """ 2981 ) 2982 ), 2983 api = """ 2984 package android.content.res { 2985 public interface XmlResourceParser extends org.xmlpull.v1.XmlPullParser android.util.AttributeSet my.AutoCloseable { 2986 method public void close(); 2987 } 2988 } 2989 package android.util { 2990 public interface AttributeSet { 2991 } 2992 } 2993 package my { 2994 public interface AutoCloseable { 2995 } 2996 } 2997 package org.xmlpull.v1 { 2998 public interface XmlPullParser { 2999 } 3000 } 3001 """ 3002 ) 3003 } 3004 3005 @Test Test KDoc suppressnull3006 fun `Test KDoc suppress`() { 3007 // Basic class; also checks that default constructor is made explicit 3008 check( 3009 sourceFiles = arrayOf( 3010 java( 3011 """ 3012 package test.pkg; 3013 public class Foo { 3014 private Foo() { } 3015 /** @suppress */ 3016 public void hidden() { 3017 } 3018 } 3019 """ 3020 ), 3021 java( 3022 """ 3023 package test.pkg; 3024 /** 3025 * Some comment. 3026 * @suppress 3027 */ 3028 public class Hidden { 3029 private Hidden() { } 3030 public void hidden() { 3031 } 3032 public class Inner { 3033 } 3034 } 3035 """ 3036 ) 3037 ), 3038 api = """ 3039 package test.pkg { 3040 public class Foo { 3041 } 3042 } 3043 """ 3044 ) 3045 } 3046 3047 @Test Check skipping implicit final or deprecated overridenull3048 fun `Check skipping implicit final or deprecated override`() { 3049 // Regression test for 122358225 3050 check( 3051 sourceFiles = arrayOf( 3052 java( 3053 """ 3054 package test.pkg; 3055 3056 public class Parent { 3057 public void foo1() { } 3058 public void foo2() { } 3059 public void foo3() { } 3060 public void foo4() { } 3061 } 3062 """ 3063 ), 3064 java( 3065 """ 3066 package test.pkg; 3067 3068 public final class Child1 extends Parent { 3069 private Child1() { } 3070 public final void foo1() { } 3071 public void foo2() { } 3072 } 3073 """ 3074 ), 3075 java( 3076 """ 3077 package test.pkg; 3078 3079 /** @deprecated */ 3080 @Deprecated 3081 public final class Child2 extends Parent { 3082 private Child2() { } 3083 /** @deprecated */ 3084 @Deprecated 3085 public void foo3() { } 3086 public void foo4() { } 3087 } 3088 """ 3089 ), 3090 java( 3091 """ 3092 package test.pkg; 3093 3094 /** @deprecated */ 3095 @Deprecated 3096 public final class Child3 extends Parent { 3097 private Child3() { } 3098 public final void foo1() { } 3099 public void foo2() { } 3100 /** @deprecated */ 3101 @Deprecated 3102 public void foo3() { } 3103 /** @deprecated */ 3104 @Deprecated 3105 public final void foo4() { } 3106 } 3107 """ 3108 ) 3109 ), 3110 api = """ 3111 package test.pkg { 3112 public final class Child1 extends test.pkg.Parent { 3113 } 3114 @Deprecated public final class Child2 extends test.pkg.Parent { 3115 } 3116 @Deprecated public final class Child3 extends test.pkg.Parent { 3117 } 3118 public class Parent { 3119 ctor public Parent(); 3120 method public void foo1(); 3121 method public void foo2(); 3122 method public void foo3(); 3123 method public void foo4(); 3124 } 3125 } 3126 """ 3127 ) 3128 } 3129 3130 @Test Ignore synchronized differencesnull3131 fun `Ignore synchronized differences`() { 3132 check( 3133 sourceFiles = arrayOf( 3134 java( 3135 """ 3136 package test.pkg2; 3137 3138 public class Parent { 3139 public void foo1() { } 3140 public synchronized void foo2() { } 3141 } 3142 """ 3143 ), 3144 java( 3145 """ 3146 package test.pkg2; 3147 3148 public class Child1 extends Parent { 3149 private Child1() { } 3150 public synchronized void foo1() { } 3151 public void foo2() { } 3152 } 3153 """ 3154 ) 3155 ), 3156 api = """ 3157 package test.pkg2 { 3158 public class Child1 extends test.pkg2.Parent { 3159 } 3160 public class Parent { 3161 ctor public Parent(); 3162 method public void foo1(); 3163 method public void foo2(); 3164 } 3165 } 3166 """ 3167 ) 3168 } 3169 3170 @Test Skip incorrect inheritnull3171 fun `Skip incorrect inherit`() { 3172 check( 3173 // Simulate test-mock scenario for getIContentProvider 3174 extraArguments = arrayOf("--stub-packages", "android.test.mock"), 3175 expectedIssues = "src/android/test/mock/MockContentProvider.java:6: warning: Public class android.test.mock.MockContentProvider stripped of unavailable superclass android.content.ContentProvider [HiddenSuperclass]", 3176 sourceFiles = arrayOf( 3177 java( 3178 """ 3179 package android.test.mock; 3180 3181 import android.content.ContentProvider; 3182 import android.content.IContentProvider; 3183 3184 public abstract class MockContentProvider extends ContentProvider { 3185 /** 3186 * Returns IContentProvider which calls back same methods in this class. 3187 * By overriding this class, we avoid the mechanism hidden behind ContentProvider 3188 * (IPC, etc.) 3189 * 3190 * @hide 3191 */ 3192 @Override 3193 public final IContentProvider getIContentProvider() { 3194 return mIContentProvider; 3195 } 3196 } 3197 """ 3198 ), 3199 java( 3200 """ 3201 package android.content; 3202 3203 /** @hide */ 3204 public abstract class ContentProvider { 3205 protected boolean isTemporary() { 3206 return false; 3207 } 3208 3209 // This is supposed to be @hide, but in turbine-combined/framework.jar included 3210 // by java_sdk_library like test-mock, it's not; this is what the special 3211 // flag is used to test 3212 public IContentProvider getIContentProvider() { 3213 return null; 3214 } 3215 } 3216 """ 3217 ), 3218 java( 3219 """ 3220 package android.content; 3221 import android.os.IInterface; 3222 3223 /** 3224 * The ipc interface to talk to a content provider. 3225 * @hide 3226 */ 3227 public interface IContentProvider extends IInterface { 3228 } 3229 """ 3230 ), 3231 java( 3232 """ 3233 package android.content; 3234 3235 // Not hidden. Here to make sure that we respect stub-packages 3236 // and exclude it from everything, including signatures. 3237 public class ClipData { 3238 } 3239 """ 3240 ) 3241 ), 3242 api = """ 3243 package android.test.mock { 3244 public abstract class MockContentProvider { 3245 ctor public MockContentProvider(); 3246 } 3247 } 3248 """ 3249 ) 3250 } 3251 3252 @Test Test Visible For Testingnull3253 fun `Test Visible For Testing`() { 3254 // Use the otherwise= visibility in signatures 3255 // Regression test for issue 118763806 3256 check( 3257 format = FileFormat.V1, 3258 sourceFiles = arrayOf( 3259 java( 3260 """ 3261 package test.pkg; 3262 import androidx.annotation.VisibleForTesting; 3263 3264 @SuppressWarnings({"ClassNameDiffersFromFileName", "WeakerAccess"}) 3265 public class ProductionCodeJava { 3266 private ProductionCodeJava() { } 3267 3268 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 3269 public void shouldBeProtected() { 3270 } 3271 3272 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 3273 protected void shouldBePrivate1() { 3274 } 3275 3276 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 3277 public void shouldBePrivate2() { 3278 } 3279 3280 @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) 3281 public void shouldBePackagePrivate() { 3282 } 3283 3284 @VisibleForTesting(otherwise = VisibleForTesting.NONE) 3285 public void shouldBeHidden() { 3286 } 3287 } 3288 """ 3289 ).indented(), 3290 kotlin( 3291 """ 3292 package test.pkg 3293 import androidx.annotation.VisibleForTesting 3294 3295 open class ProductionCodeKotlin private constructor() { 3296 3297 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 3298 fun shouldBeProtected() { 3299 } 3300 3301 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 3302 protected fun shouldBePrivate1() { 3303 } 3304 3305 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 3306 fun shouldBePrivate2() { 3307 } 3308 3309 @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) 3310 fun shouldBePackagePrivate() { 3311 } 3312 3313 @VisibleForTesting(otherwise = VisibleForTesting.NONE) 3314 fun shouldBeHidden() { 3315 } 3316 } 3317 """ 3318 ).indented(), 3319 visibleForTestingSource 3320 ), 3321 api = """ 3322 package test.pkg { 3323 public class ProductionCodeJava { 3324 method @VisibleForTesting(otherwise=androidx.annotation.VisibleForTesting.PROTECTED) protected void shouldBeProtected(); 3325 } 3326 public class ProductionCodeKotlin { 3327 method @VisibleForTesting(otherwise=androidx.annotation.VisibleForTesting.PROTECTED) protected final void shouldBeProtected(); 3328 } 3329 } 3330 """, 3331 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation") 3332 ) 3333 } 3334 3335 @Test References Deprecatednull3336 fun `References Deprecated`() { 3337 check( 3338 extraArguments = arrayOf( 3339 ARG_ERROR, "ReferencesDeprecated", 3340 ARG_ERROR, "ExtendsDeprecated" 3341 ), 3342 expectedIssues = """ 3343 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] 3344 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] 3345 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] 3346 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] 3347 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] 3348 """, 3349 sourceFiles = arrayOf( 3350 java( 3351 """ 3352 package test.pkg; 3353 /** @deprecated */ 3354 @Deprecated 3355 public class DeprecatedClass { 3356 } 3357 """ 3358 ), 3359 java( 3360 """ 3361 package test.pkg; 3362 /** @deprecated */ 3363 @Deprecated 3364 public interface DeprecatedInterface { 3365 } 3366 """ 3367 ), 3368 java( 3369 """ 3370 package test.pkg; 3371 public class MyClass extends DeprecatedClass implements DeprecatedInterface { 3372 public void method1(DeprecatedClass p, int i) { } 3373 public DeprecatedInterface method2(int i) { return null; } 3374 3375 /** @deprecated */ 3376 @Deprecated 3377 public void method3(DeprecatedClass p, int i) { } 3378 } 3379 """ 3380 ) 3381 ) 3382 ) 3383 } 3384 3385 @Test v3 format for qualified references in typesnull3386 fun `v3 format for qualified references in types`() { 3387 check( 3388 format = FileFormat.V3, 3389 sourceFiles = arrayOf( 3390 java( 3391 """ 3392 package androidx.appcompat.app; 3393 import android.view.View; 3394 import android.view.View.OnClickListener; 3395 3396 public class ActionBarDrawerToggle { 3397 private ActionBarDrawerToggle() { } 3398 public View.OnClickListener getToolbarNavigationClickListener1() { 3399 return null; 3400 } 3401 public OnClickListener getToolbarNavigationClickListener2() { 3402 return null; 3403 } 3404 public android.view.View.OnClickListener getToolbarNavigationClickListener3() { 3405 return null; 3406 } 3407 } 3408 """ 3409 ) 3410 ), 3411 api = """ 3412 // Signature format: 3.0 3413 package androidx.appcompat.app { 3414 public class ActionBarDrawerToggle { 3415 method public android.view.View.OnClickListener! getToolbarNavigationClickListener1(); 3416 method public android.view.View.OnClickListener! getToolbarNavigationClickListener2(); 3417 method public android.view.View.OnClickListener! getToolbarNavigationClickListener3(); 3418 } 3419 } 3420 """ 3421 ) 3422 } 3423 3424 @Test FooKt class constructors are not publicnull3425 fun `FooKt class constructors are not public`() { 3426 check( 3427 format = FileFormat.V3, 3428 sourceFiles = arrayOf( 3429 kotlin( 3430 "src/main/java/test/pkg/Foo.kt", 3431 """ 3432 package test.pkg 3433 fun myCall() : Boolean = false 3434 class Bar 3435 """ 3436 ) 3437 ), 3438 api = """ 3439 // Signature format: 3.0 3440 package test.pkg { 3441 public final class Bar { 3442 ctor public Bar(); 3443 } 3444 public final class FooKt { 3445 method public static boolean myCall(); 3446 } 3447 } 3448 """ 3449 ) 3450 } 3451 3452 @Test Test inherited hidden methods for descendant classes - Package privatenull3453 fun `Test inherited hidden methods for descendant classes - Package private`() { 3454 check( 3455 sourceFiles = arrayOf( 3456 java( 3457 """ 3458 package test.pkg; 3459 public class Class4 extends Class3 { 3460 public void method4() { } 3461 } 3462 """ 3463 ), 3464 java( 3465 """ 3466 package test.pkg; 3467 public class Class3 extends Class2 { 3468 public void method3() { } 3469 } 3470 """ 3471 ), 3472 java( 3473 """ 3474 package test.pkg; 3475 class Class2 extends Class1 { 3476 public void method2() { } 3477 } 3478 """ 3479 ), 3480 java( 3481 """ 3482 package test.pkg; 3483 public class Class1 { 3484 public void method1() { } 3485 } 3486 """ 3487 ) 3488 ), 3489 expectedIssues = "", 3490 api = 3491 """ 3492 package test.pkg { 3493 public class Class1 { 3494 ctor public Class1(); 3495 method public void method1(); 3496 } 3497 public class Class3 extends test.pkg.Class1 { 3498 ctor public Class3(); 3499 method public void method2(); 3500 method public void method3(); 3501 } 3502 public class Class4 extends test.pkg.Class3 { 3503 ctor public Class4(); 3504 method public void method4(); 3505 } 3506 } 3507 """ 3508 ) 3509 } 3510 3511 @Test Test inherited hidden methods for descendant classes - Hidden annotationnull3512 fun `Test inherited hidden methods for descendant classes - Hidden annotation`() { 3513 check( 3514 sourceFiles = arrayOf( 3515 java( 3516 """ 3517 package test.pkg; 3518 public class Class4 extends Class3 { 3519 public void method4() { } 3520 } 3521 """ 3522 ), 3523 java( 3524 """ 3525 package test.pkg; 3526 public class Class3 extends Class2 { 3527 public void method3() { } 3528 } 3529 """ 3530 ), 3531 java( 3532 """ 3533 package test.pkg; 3534 /** @hide */ 3535 public class Class2 extends Class1 { 3536 public void method2() { } 3537 } 3538 """ 3539 ), 3540 java( 3541 """ 3542 package test.pkg; 3543 public class Class1 { 3544 public void method1() { } 3545 } 3546 """ 3547 ) 3548 ), 3549 expectedIssues = "src/test/pkg/Class3.java:2: warning: Public class test.pkg.Class3 stripped of unavailable superclass test.pkg.Class2 [HiddenSuperclass]", 3550 api = 3551 """ 3552 package test.pkg { 3553 public class Class1 { 3554 ctor public Class1(); 3555 method public void method1(); 3556 } 3557 public class Class3 extends test.pkg.Class1 { 3558 ctor public Class3(); 3559 method public void method2(); 3560 method public void method3(); 3561 } 3562 public class Class4 extends test.pkg.Class3 { 3563 ctor public Class4(); 3564 method public void method4(); 3565 } 3566 } 3567 """ 3568 3569 ) 3570 } 3571 3572 @Test Test inherited methods that use genericsnull3573 fun `Test inherited methods that use generics`() { 3574 check( 3575 format = FileFormat.V2, 3576 sourceFiles = arrayOf( 3577 java( 3578 """ 3579 package test.pkg; 3580 import androidx.annotation.NonNull; 3581 public class Class2 extends Class1<String> { 3582 @Override 3583 public void method1(String input) { } 3584 @Override 3585 public void method2(@NonNull String input) { } 3586 } 3587 """ 3588 ), 3589 java( 3590 """ 3591 package test.pkg; 3592 import androidx.annotation.NonNull; 3593 class Class1<T> { 3594 public void method1(T input) { } 3595 public void method2(T input) { } 3596 public void method3(T input) { } 3597 @NonNull 3598 public String method4(T input) { return ""; } 3599 public T method5(@NonNull String input) { return null; } 3600 } 3601 """ 3602 ), 3603 androidxNonNullSource 3604 ), 3605 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"), 3606 expectedIssues = "", 3607 api = 3608 """ 3609 package test.pkg { 3610 public class Class2 { 3611 ctor public Class2(); 3612 method public void method1(String); 3613 method public void method2(@NonNull String); 3614 method public void method3(String); 3615 method @NonNull public String method4(String); 3616 method public String method5(@NonNull String); 3617 } 3618 } 3619 """ 3620 3621 ) 3622 } 3623 3624 @Test Test merging API signature filesnull3625 fun `Test merging API signature files`() { 3626 val source1 = """ 3627 package Test.pkg { 3628 public final class Class1 { 3629 method public void method1(); 3630 } 3631 } 3632 package Test.pkg1 { 3633 public final class Class1 { 3634 method public void method1(); 3635 } 3636 } 3637 """ 3638 val source2 = """ 3639 package Test.pkg { 3640 public final class Class2 { 3641 method public void method1(String); 3642 } 3643 } 3644 package Test.pkg2 { 3645 public final class Class1 { 3646 method public void method1(String, String); 3647 } 3648 } 3649 """ 3650 val expected = """ 3651 package Test.pkg { 3652 public final class Class1 { 3653 method public void method1(); 3654 } 3655 public final class Class2 { 3656 method public void method1(String); 3657 } 3658 } 3659 package Test.pkg1 { 3660 public final class Class1 { 3661 method public void method1(); 3662 } 3663 } 3664 package Test.pkg2 { 3665 public final class Class1 { 3666 method public void method1(String, String); 3667 } 3668 } 3669 """ 3670 check( 3671 format = FileFormat.V1, 3672 signatureSources = arrayOf(source1, source2), 3673 api = expected 3674 ) 3675 } 3676 3677 val MERGE_TEST_SOURCE_1 = """ 3678 package test.pkg { 3679 public final class BaseClass { 3680 method public void method1(); 3681 } 3682 } 3683 """ 3684 val MERGE_TEST_SOURCE_2 = """ 3685 package test.pkg { 3686 public final class SubClass extends test.pkg.BaseClass { 3687 } 3688 } 3689 """ 3690 val MERGE_TEST_EXPECTED = """ 3691 package test.pkg { 3692 public final class BaseClass { 3693 method public void method1(); 3694 } 3695 public final class SubClass extends test.pkg.BaseClass { 3696 } 3697 } 3698 """ 3699 3700 @Test Test merging API signature files, one refer to anothernull3701 fun `Test merging API signature files, one refer to another`() { 3702 check( 3703 signatureSources = arrayOf(MERGE_TEST_SOURCE_1, MERGE_TEST_SOURCE_2), 3704 api = MERGE_TEST_EXPECTED 3705 ) 3706 } 3707 3708 @Test Test merging API signature files, one refer to another, in reverse ordernull3709 fun `Test merging API signature files, one refer to another, in reverse order`() { 3710 // Exactly the same as the previous test, but read them in the reverse order 3711 check( 3712 signatureSources = arrayOf(MERGE_TEST_SOURCE_2, MERGE_TEST_SOURCE_1), 3713 api = MERGE_TEST_EXPECTED 3714 ) 3715 } 3716 3717 @Test Test merging API signature files with reverse dependencynull3718 fun `Test merging API signature files with reverse dependency`() { 3719 val source1 = """ 3720 package test.pkg { 3721 public final class Class1 { 3722 method public void method1(test.pkg.Class2 arg); 3723 } 3724 } 3725 """ 3726 val source2 = """ 3727 package test.pkg { 3728 public final class Class2 { 3729 } 3730 } 3731 """ 3732 val expected = """ 3733 package test.pkg { 3734 public final class Class1 { 3735 method public void method1(test.pkg.Class2 arg); 3736 } 3737 public final class Class2 { 3738 } 3739 } 3740 """ 3741 check( 3742 format = FileFormat.V1, 3743 signatureSources = arrayOf(source1, source2), 3744 api = expected 3745 ) 3746 } 3747 3748 @Test Test merging 3 API signature filesnull3749 fun `Test merging 3 API signature files`() { 3750 val source1 = """ 3751 package test.pkg1 { 3752 public final class BaseClass1 { 3753 method public void method1(); 3754 } 3755 3756 public final class AnotherSubClass extends test.pkg2.AnotherBase { 3757 method public void method1(); 3758 } 3759 } 3760 """ 3761 val source2 = """ 3762 package test.pkg2 { 3763 public final class SubClass1 extends test.pkg1.BaseClass1 { 3764 } 3765 } 3766 """ 3767 val source3 = """ 3768 package test.pkg2 { 3769 public final class SubClass2 extends test.pkg2.SubClass1 { 3770 method public void bar(); 3771 } 3772 3773 public final class AnotherBase { 3774 method public void baz(); 3775 } 3776 } 3777 """ 3778 val expected = """ 3779 package test.pkg1 { 3780 public final class AnotherSubClass extends test.pkg2.AnotherBase { 3781 method public void method1(); 3782 } 3783 public final class BaseClass1 { 3784 method public void method1(); 3785 } 3786 } 3787 package test.pkg2 { 3788 public final class AnotherBase { 3789 method public void baz(); 3790 } 3791 public final class SubClass1 extends test.pkg1.BaseClass1 { 3792 } 3793 public final class SubClass2 extends test.pkg2.SubClass1 { 3794 method public void bar(); 3795 } 3796 } 3797 """ 3798 check( 3799 signatureSources = arrayOf(source1, source2, source3), 3800 api = expected 3801 ) 3802 } 3803 3804 @Test Test can merge API signature files with duplicate classnull3805 fun `Test can merge API signature files with duplicate class`() { 3806 val source1 = """ 3807 package Test.pkg { 3808 public final class Class1 { 3809 method public void method1(); 3810 } 3811 } 3812 """ 3813 val source2 = """ 3814 package Test.pkg { 3815 public final class Class1 { 3816 method public void method1(); 3817 } 3818 } 3819 """ 3820 val expected = """ 3821 package Test.pkg { 3822 public final class Class1 { 3823 method public void method1(); 3824 } 3825 } 3826 """ 3827 check( 3828 signatureSources = arrayOf(source1, source2), 3829 api = expected 3830 ) 3831 } 3832 3833 @Test Test cannot merge API signature files with incompatible class definitionsnull3834 fun `Test cannot merge API signature files with incompatible class definitions`() { 3835 val source1 = """ 3836 package Test.pkg { 3837 public class Class1 { 3838 method public void method2(); 3839 } 3840 } 3841 """ 3842 val source2 = """ 3843 package Test.pkg { 3844 public final class Class1 { 3845 method public void method1(); 3846 } 3847 } 3848 """ 3849 check( 3850 signatureSources = arrayOf(source1, source2), 3851 expectedFail = "Aborting: Unable to parse signature file: Incompatible class Test.pkg.Class1 definitions" 3852 ) 3853 } 3854 3855 @Test Test cannot merging API signature files with different file formatsnull3856 fun `Test cannot merging API signature files with different file formats`() { 3857 val source1 = """ 3858 // Signature format: 2.0 3859 package Test.pkg { 3860 } 3861 """ 3862 val source2 = """ 3863 // Signature format: 3.0 3864 package Test.pkg { 3865 } 3866 """ 3867 check( 3868 signatureSources = arrayOf(source1, source2), 3869 expectedFail = "Aborting: Unable to parse signature file: Cannot merge different formats of signature files. " + 3870 "First file format=V2, current file format=V3: file=TESTROOT/project/load-api2.txt" 3871 ) 3872 } 3873 3874 @Test Test tracking of @Composable annotation from classpathnull3875 fun `Test tracking of @Composable annotation from classpath`() { 3876 check( 3877 format = FileFormat.V3, 3878 classpath = arrayOf( 3879 /* The following source file, compiled, and root folder jar'ed and stored as base64 gzip: 3880 package test.pkg 3881 @MustBeDocumented 3882 @Retention(AnnotationRetention.BINARY) 3883 @Target( 3884 AnnotationTarget.CLASS, 3885 AnnotationTarget.FUNCTION, 3886 AnnotationTarget.TYPE, 3887 AnnotationTarget.TYPE_PARAMETER, 3888 AnnotationTarget.PROPERTY 3889 ) 3890 annotation class Composable 3891 */ 3892 base64gzip( 3893 "test.jar", 3894 "" + 3895 "UEsDBAoAAAgIAKx6s1AAAAAAAgAAAAAAAAAJAAAATUVUQS1JTkYvAwBQSwMECgAACAgAZ3qzULJ/" + 3896 "Au4bAAAAGQAAABQAAABNRVRBLUlORi9NQU5JRkVTVC5NRvNNzMtMSy0u0Q1LLSrOzM+zUjDUM+Dl" + 3897 "4uUCAFBLAwQKAAAICABnerNQDArdZgwAAAAQAAAAGwAAAE1FVEEtSU5GL3RlbXAua290bGluX21v" + 3898 "ZHVsZWNgYGBmYGBghGIBAFBLAwQKAAAICABnerNQAAAAAAIAAAAAAAAABQAAAHRlc3QvAwBQSwME" + 3899 "CgAACAgAZ3qzUAAAAAACAAAAAAAAAAkAAAB0ZXN0L3BrZy8DAFBLAwQKAAAICABnerNQbrgjGPQB" + 3900 "AACVAwAAGQAAAHRlc3QvcGtnL0NvbXBvc2FibGUuY2xhc3OFUk1v2kAQfWtioG6TkKRpSdI0H01I" + 3901 "P6S65doTEEdF4kvGrRRxqBZYIQdjo+xClRu3Xvsz+ht6qFCO/VFVZ4kCVLJU2Xo7O/PGM/M8v//8" + 3902 "/AUgjzcMW0pIZQ/7PbsUDYaR5O1ApMAYMld8zO2Ahz273r4SHZVCguFg4eVhGCmu/Ci0C3MzBZPh" + 3903 "pNKPVOCHy5TqSKqiOI86o4EIleh+YNiPoblCUZgsiptjHowEw1kMb1FxOSNZLNcK7iXDbkyKx697" + 3904 "QhFrjQdB9FV07xwyvt9FgXmeWaoUmk2G9MWnWskr12sMK95lw6Ev6uNLo+AWqo7nuERpuPWG43rU" + 3905 "ylElVrJ/lDiM5yyPlvsPpREFfudmpmoscT7FcXzcCYRux7sZCi0kzfGxfs6wcS9NVSje5YpT0BiM" + 3906 "E7Q+TEOGru3ZFRpoQ1ifXN33NNR0YllG1rCMzJ41naRvvxnZ6SRvvGPF6eT2R9LQvDzDdiVmBakM" + 3907 "SF4lBkOG1YX/bV8xWM1odN0RF35A27HjjkiAgfjsS58Ii/8mc1QAK/SZpG6P7FczfInXdH5Hih4g" + 3908 "TfEHAhYe4hGZqy2YAmtY15DRsKFhU8MWHlPC9l3CE6zjqTZbMASympbFDnZhYq+FRBnPZu8+nt/f" + 3909 "Dso4xBGZOG6BSbzACYUkTiVyEmd/AVBLAQIUAwoAAAgIAKx6s1AAAAAAAgAAAAAAAAAJAAAAAAAA" + 3910 "AAAAEADtQQAAAABNRVRBLUlORi9QSwECFAMKAAAICABnerNQsn8C7hsAAAAZAAAAFAAAAAAAAAAA" + 3911 "AAAApIEpAAAATUVUQS1JTkYvTUFOSUZFU1QuTUZQSwECFAMKAAAICABnerNQDArdZgwAAAAQAAAA" + 3912 "GwAAAAAAAAAAAAAAoIF2AAAATUVUQS1JTkYvdGVtcC5rb3RsaW5fbW9kdWxlUEsBAhQDCgAACAgA" + 3913 "Z3qzUAAAAAACAAAAAAAAAAUAAAAAAAAAAAAQAOhBuwAAAHRlc3QvUEsBAhQDCgAACAgAZ3qzUAAA" + 3914 "AAACAAAAAAAAAAkAAAAAAAAAAAAQAOhB4AAAAHRlc3QvcGtnL1BLAQIUAwoAAAgIAGd6s1BuuCMY" + 3915 "9AEAAJUDAAAZAAAAAAAAAAAAAACggQkBAAB0ZXN0L3BrZy9Db21wb3NhYmxlLmNsYXNzUEsFBgAA" + 3916 "AAAGAAYAcwEAADQDAAAAAA==" 3917 ) 3918 ), 3919 sourceFiles = arrayOf( 3920 kotlin( 3921 """ 3922 package test.pkg 3923 class RadioGroupScope() { 3924 @Composable 3925 fun RadioGroupItem( 3926 selected: Boolean, 3927 onSelect: () -> Unit, 3928 content: @Composable () -> Unit 3929 ) { } 3930 } 3931 """ 3932 ) 3933 ), 3934 expectedIssues = "", 3935 api = 3936 """ 3937 // Signature format: 3.0 3938 package test.pkg { 3939 public final class RadioGroupScope { 3940 ctor public RadioGroupScope(); 3941 method @test.pkg.Composable public void RadioGroupItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onSelect, kotlin.jvm.functions.Function0<kotlin.Unit> content); 3942 } 3943 } 3944 """ 3945 ) 3946 } 3947 3948 @Test Test for experimental annotations from classpathnull3949 fun `Test for experimental annotations from classpath`() { 3950 check( 3951 format = FileFormat.V3, 3952 classpath = arrayOf( 3953 /* The following source file, compiled, and root folder jar'ed and stored as base64 gzip 3954 Encoded using openssl base64 < test.jar | tr -d '\n' 3955 3956 package test.pkg 3957 @RequiresOptIn 3958 annotation class ExternalExperimentalAnnotation 3959 */ 3960 base64gzip( 3961 "test.jar", 3962 "" + 3963 "UEsDBAoAAAgIADt2U1IAAAAAAgAAAAAAAAAJAAAATUVUQS1JTkYvAwBQSwMECgAACAgAFXZ" + 3964 "TUrJ/Au4bAAAAGQAAABQAAABNRVRBLUlORi9NQU5JRkVTVC5NRvNNzMtMSy0u0Q1LLSrOzM" + 3965 "+zUjDUM+Dl4uUCAFBLAwQKAAAICAA7dlNSDWpm1BUAAAAYAAAAGwAAAE1FVEEtSU5GL3Rlc" + 3966 "3Qua290bGluX21vZHVsZWNgYGBmYGBgBGIWIGYCYgYlBi0GAFBLAwQKAAAICAA7dlNSAAAA" + 3967 "AAIAAAAAAAAABQAAAHRlc3QvAwBQSwMECgAACAgAO3ZTUgAAAAACAAAAAAAAAAkAAAB0ZXN" + 3968 "0L3BrZy8DAFBLAwQKAAAICAA7dlNSPYCyXGwBAABkAgAALQAAAHRlc3QvcGtnL0V4dGVybm" + 3969 "FsRXhwZXJpbWVudGFsQW5ub3RhdGlvbi5jbGFzc41Qy04CQRCsWZ6uL/CBICp6wXhxlasnT" + 3970 "TBuAmLwceE0wIQsLLPIzhK87c1f8Rs8GMLRjzL2qoiJRr309HRVdXf188vjE4ACcgy7SrjK" + 3971 "6HVaRnGoRF9yuzjsib7VFVJx+1hKR3FlOTIGxpBo8wE3bC5bRqXeFg0VQ4ghN63yT77xVRp" + 3972 "hSJU6jrItaVTFrWf1hVvpKVMeMWyXfpRXhaINKCNKZMBtTzDk/6BeOLbVuCNBrHp9fmWWiw" + 3973 "zJydiyULzJFSdU6w5CZJ8FIRwEjWr1txqCQJZYh0rNQ9pu5Ou6ltZ0LZHVR358fK+lR35BO" + 3974 "2AnI3/8EA2kzQLDXumfd6T5YAgHbIad37n7HeLol47Xb4hTy6YLZKoeOe2KG8u16raYUl2G" + 3975 "7AdmysE3NE9rIkyDo3h3uRHYRhab9J5RFidsRkDHLOYQwXwNIRMLJhZNJJCc/JZMLGOFUqz" + 3976 "WwFyksEaQi7SLjIt1bFG3KHWKAa9QSwECFAMKAAAICAA7dlNSAAAAAAIAAAAAAAAACQAAAA" + 3977 "AAAAAAABAA7UEAAAAATUVUQS1JTkYvUEsBAhQDCgAACAgAFXZTUrJ/Au4bAAAAGQAAABQAA" + 3978 "AAAAAAAAAAAAKSBKQAAAE1FVEEtSU5GL01BTklGRVNULk1GUEsBAhQDCgAACAgAO3ZTUg1q" + 3979 "ZtQVAAAAGAAAABsAAAAAAAAAAAAAAKCBdgAAAE1FVEEtSU5GL3Rlc3Qua290bGluX21vZHV" + 3980 "sZVBLAQIUAwoAAAgIADt2U1IAAAAAAgAAAAAAAAAFAAAAAAAAAAAAEADoQcQAAAB0ZXN0L1" + 3981 "BLAQIUAwoAAAgIADt2U1IAAAAAAgAAAAAAAAAJAAAAAAAAAAAAEADoQekAAAB0ZXN0L3BrZ" + 3982 "y9QSwECFAMKAAAICAA7dlNSPYCyXGwBAABkAgAALQAAAAAAAAAAAAAAoIESAQAAdGVzdC9w" + 3983 "a2cvRXh0ZXJuYWxFeHBlcmltZW50YWxBbm5vdGF0aW9uLmNsYXNzUEsFBgAAAAAGAAYAhwE" + 3984 "AAMkCAAAAAA==" 3985 ) 3986 ), 3987 sourceFiles = arrayOf( 3988 kotlin( 3989 """ 3990 package test.pkg 3991 3992 @ExternalExperimentalAnnotation 3993 class ClassUsingExternalExperimentalApi 3994 3995 @InLibraryExperimentalAnnotation 3996 class ClassUsingInLibraryExperimentalApi 3997 """ 3998 ), 3999 kotlin( 4000 """ 4001 package test.pkg 4002 @RequiresOptIn 4003 annotation class InLibraryExperimentalAnnotation 4004 """ 4005 ) 4006 ), 4007 expectedIssues = "", 4008 api = 4009 """ 4010 // Signature format: 3.0 4011 package test.pkg { 4012 @kotlin.RequiresOptIn public @interface InLibraryExperimentalAnnotation { 4013 } 4014 } 4015 """, 4016 extraArguments = arrayOf( 4017 ARG_HIDE_META_ANNOTATION, "kotlin.RequiresOptIn" 4018 ) 4019 ) 4020 } 4021 4022 @Test @IntRange value in kotlinnull4023 fun `@IntRange value in kotlin`() { 4024 check( 4025 format = FileFormat.V3, 4026 sourceFiles = arrayOf( 4027 kotlin( 4028 """ 4029 package test.pkg 4030 4031 import androidx.annotation.IntRange 4032 4033 class KotlinClass(@IntRange(from = 1) val param: Int) { 4034 constructor(@IntRange(from = 2) val differentParam: Int) 4035 fun myMethod(@IntRange(from = 3) val methodParam: Int) {} 4036 } 4037 """ 4038 ), 4039 androidxIntRangeSource 4040 ), 4041 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"), 4042 api = """ 4043 // Signature format: 3.0 4044 package test.pkg { 4045 public final class KotlinClass { 4046 ctor public KotlinClass(@IntRange(from=1L) int param); 4047 ctor public KotlinClass(@IntRange(from=2L) int differentParam); 4048 method public int getParam(); 4049 method public void myMethod(@IntRange(from=3L) int methodParam); 4050 property public final int param; 4051 } 4052 } 4053 """ 4054 ) 4055 } 4056 4057 @Test Annotation value visibilitynull4058 fun `Annotation value visibility`() { 4059 check( 4060 format = FileFormat.V2, 4061 sourceFiles = arrayOf( 4062 java( 4063 """ 4064 package test.pkg; 4065 4066 import androidx.annotation.IntRange; 4067 4068 public final class ApiClass { 4069 private int hiddenConstant = 1; 4070 public ApiClass(@IntRange(from=1) int x) {} 4071 public void method(@IntRange(from = hiddenConstant) int x) {} 4072 } 4073 """ 4074 ), 4075 androidxIntRangeSource 4076 ), 4077 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"), 4078 api = """ 4079 // Signature format: 2.0 4080 package test.pkg { 4081 public final class ApiClass { 4082 ctor public ApiClass(@IntRange(from=1) int); 4083 method public void method(@IntRange(from=0x1) int); 4084 } 4085 } 4086 """ 4087 ) 4088 } 4089 4090 @Test Kotlin properties with overriding getnull4091 fun `Kotlin properties with overriding get`() { 4092 check( 4093 format = FileFormat.V3, 4094 sourceFiles = arrayOf( 4095 kotlin( 4096 """ 4097 package test.pkg 4098 4099 import androidx.annotation.IntRange 4100 4101 class KotlinClass() { 4102 val propertyWithGetter: Boolean get() = true 4103 val propertyWithNoGetter: Boolean = true 4104 } 4105 """ 4106 ), 4107 androidxIntRangeSource 4108 ), 4109 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"), 4110 api = """ 4111 // Signature format: 3.0 4112 package test.pkg { 4113 public final class KotlinClass { 4114 ctor public KotlinClass(); 4115 method public boolean getPropertyWithGetter(); 4116 method public boolean getPropertyWithNoGetter(); 4117 property public final boolean propertyWithGetter; 4118 property public final boolean propertyWithNoGetter; 4119 } 4120 } 4121 """ 4122 ) 4123 } 4124 4125 @Test Constructor property trackingnull4126 fun `Constructor property tracking`() { 4127 check( 4128 format = FileFormat.V3, 4129 sourceFiles = arrayOf( 4130 kotlin( 4131 """ 4132 package test.pkg 4133 sealed class MyClass( 4134 val firstConstructorProperty: Int, 4135 val secondConstructorProperty: Boolean 4136 ) { 4137 val nonConstructorProperty: String = "PROP" 4138 } 4139 """ 4140 ), 4141 kotlin( 4142 """ 4143 package test.pkg 4144 data class MyDataClass( 4145 val constructorProperty: String, 4146 internal val internalConstructorProperty: String 4147 ) 4148 """ 4149 ) 4150 ), 4151 api = """ 4152 // Signature format: 3.0 4153 package test.pkg { 4154 public abstract sealed class MyClass { 4155 method public final int getFirstConstructorProperty(); 4156 method public final String getNonConstructorProperty(); 4157 method public final boolean getSecondConstructorProperty(); 4158 property public final int firstConstructorProperty; 4159 property public final String nonConstructorProperty; 4160 property public final boolean secondConstructorProperty; 4161 } 4162 public final class MyDataClass { 4163 ctor public MyDataClass(String constructorProperty, String internalConstructorProperty); 4164 method public String component1(); 4165 method public test.pkg.MyDataClass copy(String constructorProperty, String internalConstructorProperty); 4166 method public String getConstructorProperty(); 4167 property public final String constructorProperty; 4168 } 4169 } 4170 """ 4171 ) 4172 } 4173 4174 @Test Concise default Values Names in Javanull4175 fun `Concise default Values Names in Java`() { 4176 // Java code which explicitly specifies parameter names 4177 check( 4178 format = FileFormat.V4, 4179 sourceFiles = arrayOf( 4180 java( 4181 """ 4182 package test.pkg; 4183 import androidx.annotation.DefaultValue; 4184 4185 public class Foo { 4186 public void foo( 4187 @DefaultValue("null") String prefix, 4188 @DefaultValue("\"Hello World\"") String greeting, 4189 @DefaultValue("42") int meaning) { 4190 } 4191 } 4192 """ 4193 ), 4194 supportDefaultValue 4195 ), 4196 api = """ 4197 // Signature format: 4.0 4198 package test.pkg { 4199 public class Foo { 4200 ctor public Foo(); 4201 method public void foo(optional String!, optional String!, optional int); 4202 } 4203 } 4204 """, 4205 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation") 4206 ) 4207 } 4208 4209 @Test Concise default Values and Names in Kotlinnull4210 fun `Concise default Values and Names in Kotlin`() { 4211 // Kotlin code which explicitly specifies parameter names 4212 check( 4213 format = FileFormat.V4, 4214 sourceFiles = arrayOf( 4215 kotlin( 4216 """ 4217 package test.pkg 4218 import some.other.pkg.Constants.Misc.SIZE 4219 import android.graphics.Bitmap 4220 import android.view.View 4221 4222 class Foo(a: String = "1", b: String = "2") { 4223 fun method1(myInt: Int = 42, 4224 myInt2: Int? = null, 4225 myByte: Int = 2 * 21, 4226 str: String = "hello " + "world", 4227 vararg args: String) { } 4228 4229 fun method2(myInt: Int, myInt2: Int = (2*int) * SIZE) { } 4230 4231 fun method3(str: String, myInt: Int, myInt2: Int = double(int) + str.length) { } 4232 4233 fun emptyLambda(sizeOf: () -> Unit = { }) {} 4234 4235 fun View.drawToBitmap(config: Bitmap.Config = Bitmap.Config.ARGB_8888): Bitmap? = null 4236 4237 companion object { 4238 fun double(myInt: Int) = 2 * myInt 4239 fun print(foo: Foo = Foo()) { println(foo) } 4240 } 4241 } 4242 """ 4243 ), 4244 java( 4245 """ 4246 package some.other.pkg; 4247 public class Constants { 4248 public static class Misc { 4249 public static final int SIZE = 5; 4250 } 4251 } 4252 """ 4253 ) 4254 ), 4255 api = """ 4256 // Signature format: 4.0 4257 package test.pkg { 4258 public final class Foo { 4259 ctor public Foo(optional String a, optional String b); 4260 method public android.graphics.Bitmap? drawToBitmap(android.view.View, optional android.graphics.Bitmap.Config config); 4261 method public void emptyLambda(optional kotlin.jvm.functions.Function0<kotlin.Unit> sizeOf); 4262 method public void method1(optional int myInt, optional Integer? myInt2, optional int myByte, optional String str, java.lang.String... args); 4263 method public void method2(int myInt, optional int myInt2); 4264 method public void method3(String str, int myInt, optional int myInt2); 4265 field public static final test.pkg.Foo.Companion Companion; 4266 } 4267 public static final class Foo.Companion { 4268 method public int double(int myInt); 4269 method public void print(optional test.pkg.Foo foo); 4270 } 4271 } 4272 """, 4273 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation", ARG_HIDE_PACKAGE, "some.other.pkg"), 4274 includeSignatureVersion = true 4275 ) 4276 } 4277 4278 @Test Concise default Values in Kotlin for expressionsnull4279 fun `Concise default Values in Kotlin for expressions`() { 4280 // Testing trickier default values; regression test for problem 4281 // observed in androidx.core.util with LruCache 4282 check( 4283 format = FileFormat.V4, 4284 sourceFiles = arrayOf( 4285 kotlin( 4286 """ 4287 package androidx.core.util 4288 4289 import android.util.LruCache 4290 4291 inline fun <K : Any, V : Any> lruCache( 4292 maxSize: Int, 4293 crossinline sizeOf: (key: K, value: V) -> Int = { _, _ -> 1 }, 4294 @Suppress("USELESS_CAST") // https://youtrack.jetbrains.com/issue/KT-21946 4295 crossinline create: (key: K) -> V? = { null as V? }, 4296 crossinline onEntryRemoved: (evicted: Boolean, key: K, oldValue: V, newValue: V?) -> Unit = 4297 { _, _, _, _ -> } 4298 ): LruCache<K, V> { 4299 return object : LruCache<K, V>(maxSize) { 4300 override fun sizeOf(key: K, value: V) = sizeOf(key, value) 4301 override fun create(key: K) = create(key) 4302 override fun entryRemoved(evicted: Boolean, key: K, oldValue: V, newValue: V?) { 4303 onEntryRemoved(evicted, key, oldValue, newValue) 4304 } 4305 } 4306 } 4307 """ 4308 ), 4309 java( 4310 """ 4311 package androidx.collection; 4312 4313 import androidx.annotation.NonNull; 4314 import androidx.annotation.Nullable; 4315 4316 import java.util.LinkedHashMap; 4317 import java.util.Locale; 4318 import java.util.Map; 4319 4320 public class LruCache<K, V> { 4321 @Nullable 4322 protected V create(@NonNull K key) { 4323 return null; 4324 } 4325 4326 protected int sizeOf(@NonNull K key, @NonNull V value) { 4327 return 1; 4328 } 4329 4330 protected void entryRemoved(boolean evicted, @NonNull K key, @NonNull V oldValue, 4331 @Nullable V newValue) { 4332 } 4333 } 4334 """ 4335 ), 4336 androidxNullableSource, 4337 androidxNonNullSource 4338 ), 4339 api = """ 4340 // Signature format: 4.0 4341 package androidx.core.util { 4342 public final class TestKt { 4343 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); 4344 } 4345 } 4346 """, 4347 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation", ARG_HIDE_PACKAGE, "androidx.collection"), 4348 includeSignatureVersion = true 4349 ) 4350 } 4351 4352 @Test Test type erasure and dexApi from signaturenull4353 fun `Test type erasure and dexApi from signature`() { 4354 check( 4355 signatureSources = arrayOf( 4356 """ 4357 package android.widget { 4358 4359 @android.widget.RemoteViews.RemoteView public class ListView extends android.widget.AbsListView { 4360 method protected <T extends android.view.View> T findViewTraversal(@IdRes int); 4361 method protected long tryAcquireShared(long); 4362 } 4363 4364 } 4365 """ 4366 ), 4367 dexApi = """ 4368 Landroid/widget/ListView; 4369 Landroid/widget/ListView;->findViewTraversal(I)Landroid/view/View; 4370 Landroid/widget/ListView;->tryAcquireShared(J)J 4371 """ 4372 ) 4373 } 4374 4375 @Test Functional interface in signaturenull4376 fun `Functional interface in signature`() { 4377 check( 4378 format = FileFormat.V4, 4379 sourceFiles = arrayOf( 4380 kotlin( 4381 """ 4382 package test.pkg 4383 4384 fun interface FunctionalInterface { 4385 fun methodOne(number: Int): Boolean 4386 } 4387 4388 fun userOfFunctionalInterface(parameter: FunctionalInterface) { } 4389 """ 4390 ) 4391 ), 4392 api = """ 4393 // Signature format: 4.0 4394 package test.pkg { 4395 public fun interface FunctionalInterface { 4396 method public boolean methodOne(int number); 4397 } 4398 public final class FunctionalInterfaceKt { 4399 method public static void userOfFunctionalInterface(test.pkg.FunctionalInterface parameter); 4400 } 4401 } 4402 """ 4403 ) 4404 } 4405 4406 @Test Inline classnull4407 fun `Inline class`() { 4408 check( 4409 format = FileFormat.V4, 4410 sourceFiles = arrayOf( 4411 kotlin( 4412 """ 4413 package test.pkg 4414 4415 inline class Dp(val value: Float) : Comparable<Dp> { 4416 inline operator fun plus(other: Dp) = Dp(value = this.value + other.value) 4417 inline operator fun minus(other: Dp) = Dp(value = this.value - other.value) 4418 // Not tracked due to https://youtrack.jetbrains.com/issue/KTIJ-11559 4419 val someBits 4420 get() = value && 0x00ff 4421 // Not tracked due to https://youtrack.jetbrains.com/issue/KTIJ-11559 4422 fun doSomething() {} 4423 } 4424 """ 4425 ) 4426 ), 4427 api = """ 4428 // Signature format: 4.0 4429 package test.pkg { 4430 public final inline class Dp implements java.lang.Comparable<test.pkg.Dp> { 4431 ctor public Dp(); 4432 method public float getValue(); 4433 method public inline operator float minus(float other); 4434 method public inline operator float plus(float other); 4435 property public final float value; 4436 } 4437 } 4438 """ 4439 ) 4440 } 4441 4442 @Test Value classnull4443 fun `Value class`() { 4444 check( 4445 format = FileFormat.V4, 4446 sourceFiles = arrayOf( 4447 kotlin( 4448 """ 4449 package test.pkg 4450 @JvmInline 4451 value class Dp(val value: Float) : Comparable<Dp> { 4452 inline operator fun plus(other: Dp) = Dp(value = this.value + other.value) 4453 inline operator fun minus(other: Dp) = Dp(value = this.value - other.value) 4454 val someBits 4455 get() = value && 0x00ff 4456 fun doSomething() {} 4457 } 4458 """ 4459 ) 4460 ), 4461 api = """ 4462 // Signature format: 4.0 4463 package test.pkg { 4464 @kotlin.jvm.JvmInline public final value class Dp implements java.lang.Comparable<test.pkg.Dp> { 4465 ctor public Dp(float value); 4466 method public void doSomething(); 4467 method public boolean getSomeBits(); 4468 method public float getValue(); 4469 method public inline operator float minus(float other); 4470 method public inline operator float plus(float other); 4471 property public final boolean someBits; 4472 property public final float value; 4473 } 4474 } 4475 """ 4476 ) 4477 } 4478 4479 @Test Kotlin doesn't expand java named constantsnull4480 fun `Kotlin doesn't expand java named constants`() { 4481 check( 4482 format = FileFormat.V3, 4483 sourceFiles = 4484 arrayOf( 4485 kotlin( 4486 """ 4487 package test.pkg 4488 annotation class Foo(val bar: Long = java.lang.Long.MIN_VALUE) 4489 """ 4490 ) 4491 ), 4492 api = 4493 """ 4494 // Signature format: 3.0 4495 package test.pkg { 4496 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public @interface Foo { 4497 method public abstract long bar() default java.lang.Long.MIN_VALUE; 4498 property public abstract long bar; 4499 } 4500 } 4501 """ 4502 ) 4503 } 4504 4505 @Test 4506 fun `Kotlin constructors with JvmOverloads`() { 4507 check( 4508 format = FileFormat.V4, 4509 sourceFiles = arrayOf( 4510 kotlin( 4511 """ 4512 package test.pkg 4513 4514 class AllOptionalJvmOverloads @JvmOverloads constructor( 4515 private val foo: Int = 0, 4516 private val bar: Int = 0 4517 ) 4518 4519 class AllOptionalNoJvmOverloads( 4520 private val foo: Int = 0, 4521 private val bar: Int = 0 4522 ) 4523 4524 class SomeOptionalJvmOverloads @JvmOverloads constructor( 4525 private val foo: Int, 4526 private val bar: Int = 0 4527 ) 4528 4529 class SomeOptionalNoJvmOverloads( 4530 private val foo: Int, 4531 private val bar: Int = 0 4532 ) 4533 """ 4534 ) 4535 ), 4536 api = """ 4537 // Signature format: 4.0 4538 package test.pkg { 4539 public final class AllOptionalJvmOverloads { 4540 ctor public AllOptionalJvmOverloads(optional int foo, optional int bar); 4541 ctor public AllOptionalJvmOverloads(optional int foo); 4542 ctor public AllOptionalJvmOverloads(); 4543 } 4544 public final class AllOptionalNoJvmOverloads { 4545 ctor public AllOptionalNoJvmOverloads(optional int foo, optional int bar); 4546 } 4547 public final class SomeOptionalJvmOverloads { 4548 ctor public SomeOptionalJvmOverloads(int foo, optional int bar); 4549 ctor public SomeOptionalJvmOverloads(int foo); 4550 } 4551 public final class SomeOptionalNoJvmOverloads { 4552 ctor public SomeOptionalNoJvmOverloads(int foo, optional int bar); 4553 } 4554 } 4555 """ 4556 ) 4557 } 4558 4559 @Test 4560 fun `Kotlin public methods with DeprecationLevel HIDDEN are public API`() { 4561 check( 4562 format = FileFormat.V3, 4563 sourceFiles = arrayOf( 4564 kotlin( 4565 """ 4566 package test.pkg 4567 @Deprecated( 4568 message = "So much regret", 4569 level = DeprecationLevel.HIDDEN 4570 ) 4571 fun myMethod() { TODO() } 4572 @Deprecated( 4573 message = "So much regret", 4574 level = DeprecationLevel.HIDDEN 4575 ) 4576 internal fun myInternalMethod() { TODO() } 4577 @Deprecated( 4578 message = "So much regret", 4579 level = DeprecationLevel.HIDDEN 4580 ) 4581 private fun myPrivateMethod() { TODO() } 4582 @Deprecated( 4583 message = "So much regret", 4584 level = DeprecationLevel.WARNING 4585 ) 4586 fun myNormalDeprecatedMethod() { TODO() } 4587 """ 4588 ) 4589 ), 4590 api = """ 4591 // Signature format: 3.0 4592 package test.pkg { 4593 public final class TestKt { 4594 method @Deprecated public static void myMethod(); 4595 method @Deprecated public static void myNormalDeprecatedMethod(); 4596 } 4597 } 4598 """ 4599 ) 4600 } 4601 4602 @Test 4603 fun `Annotations aren't dropped when DeprecationLevel is HIDDEN`() { 4604 check( 4605 format = FileFormat.V3, 4606 sourceFiles = arrayOf( 4607 kotlin( 4608 """ 4609 package test.pkg 4610 @Deprecated( 4611 message = "So much regret", 4612 level = DeprecationLevel.HIDDEN 4613 ) 4614 @IntRange(from=0) 4615 fun myMethod() { TODO() } 4616 """ 4617 ) 4618 ), 4619 api = """ 4620 // Signature format: 3.0 4621 package test.pkg { 4622 public final class TestKt { 4623 method @Deprecated @kotlin.ranges.IntRange public static void myMethod(); 4624 } 4625 } 4626 """ 4627 ) 4628 } 4629 4630 @Test Constants in a file scope annotationnull4631 fun `Constants in a file scope annotation`() { 4632 check( 4633 format = FileFormat.V4, 4634 sourceFiles = arrayOf( 4635 kotlin( 4636 """ 4637 @file:RestrictTo(RestrictTo.Scope.LIBRARY) 4638 package test.pkg 4639 import androidx.annotation.RestrictTo 4640 private fun veryFun(): Boolean = true 4641 """ 4642 ), 4643 restrictToSource 4644 ), 4645 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"), 4646 api = """ 4647 // Signature format: 4.0 4648 package test.pkg { 4649 @RestrictTo({androidx.annotation.RestrictTo.Scope.LIBRARY}) public final class TestKt { 4650 } 4651 } 4652 """ 4653 ) 4654 } 4655 4656 @Test RestrictTo on a file hiding itnull4657 fun `RestrictTo on a file hiding it`() { 4658 check( 4659 format = FileFormat.V4, 4660 sourceFiles = arrayOf( 4661 kotlin( 4662 """ 4663 @file:RestrictTo(RestrictTo.Scope.LIBRARY) 4664 package test.pkg 4665 import androidx.annotation.RestrictTo 4666 private fun veryFun(): Boolean = true 4667 """ 4668 ), 4669 restrictToSource 4670 ), 4671 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation", "--show-unannotated"), 4672 hideAnnotations = arrayOf( 4673 "androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)" 4674 ), 4675 api = """ 4676 // Signature format: 4.0 4677 """ 4678 ) 4679 } 4680 4681 /** Regression test for b/202968090 */ 4682 @Test annotation arrays should be non-nullnull4683 fun `annotation arrays should be non-null`() { 4684 check( 4685 format = FileFormat.V4, 4686 sourceFiles = arrayOf( 4687 kotlin( 4688 """ 4689 package test.pkg 4690 annotation class Foo ( 4691 val bar: Array<String>, 4692 vararg val baz: String 4693 ) 4694 """ 4695 ) 4696 ), 4697 api = """ 4698 // Signature format: 4.0 4699 package test.pkg { 4700 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public @interface Foo { 4701 method public abstract String[] bar(); 4702 method public abstract String[] baz(); 4703 property public abstract String[] bar; 4704 property public abstract String[] baz; 4705 } 4706 } 4707 """ 4708 ) 4709 } 4710 4711 @Test property setter parameters are unnamednull4712 fun `property setter parameters are unnamed`() { 4713 check( 4714 sourceFiles = arrayOf( 4715 kotlin( 4716 """ 4717 package test.pkg 4718 class Foo(var bar: Int) 4719 """ 4720 ) 4721 ), 4722 api = """ 4723 package test.pkg { 4724 public final class Foo { 4725 ctor public Foo(int bar); 4726 method public int getBar(); 4727 method public void setBar(int); 4728 property public final int bar; 4729 } 4730 } 4731 """ 4732 ) 4733 } 4734 } 4735