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