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