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 org.junit.Test 22 23 class ApiFileTest : DriverTest() { 24 /* 25 Conditions to test: 26 - test all the error scenarios found in the notStrippable case! 27 - split up test into many individual test cases 28 - try referencing a class from an annotation! 29 - test having a throws list where some exceptions are hidden but extend 30 public exceptions: do we map over to the referenced ones? 31 32 - test type reference from all the possible places -- in type signatures - interfaces, 33 extends, throws, type bounds, etc. 34 - method which overrides @hide method: should appear in subclass (test chain 35 of two nested too) 36 - BluetoothGattCharacteristic.java#describeContents: Was marked @hide, 37 but is unhidden because it extends a public interface method 38 - package javadoc (also make sure merging both!, e.g. try having @hide in each) 39 - StopWatchMap -- inner class with @hide marks allh top levels! 40 - Test field inlining: should I include fields from an interface, if that 41 inteface was implemented by the parent class (and therefore appears there too?) 42 What if the superclass is abstract? 43 - Exposing package private classes. Test that I only do this for package private 44 classes, NOT Those marked @hide (is that, having @hide on a used type, illegal?) 45 - Test error handling (invalid @hide combinations)) 46 - Consider what happens if we promote a package private class (because it's 47 extended by a public class), and then we restore its public members; the 48 override logic there isn't quite right. We've duplicated the significant-override 49 code to not skip private members, but that could change semantics. This isn't 50 ideal; instead we should now mark this class as public, and re-run the analysis 51 again (with the new hidden state for this class). 52 - compilation unit sorting - top level classes out of order 53 - Massive classes such as android.R.java? Maybe do synthetic test. 54 - HttpResponseCache implemented a public OkHttp interface, but the sole implementation 55 method was marked @hide, so the method doesn't show up. Is that some other rule -- 56 that we skip interfaces if their implementation methods are marked @hide? 57 - Test recursive package filtering. 58 */ 59 60 @Test Basic class signature extractionnull61 fun `Basic class signature extraction`() { 62 // Basic class; also checks that default constructor is made explicit 63 check( 64 sourceFiles = *arrayOf( 65 java( 66 """ 67 package test.pkg; 68 public class Foo { 69 } 70 """ 71 ) 72 ), 73 api = """ 74 package test.pkg { 75 public class Foo { 76 ctor public Foo(); 77 } 78 } 79 """ 80 ) 81 } 82 83 @Test Parameter Names in Javanull84 fun `Parameter Names in Java`() { 85 // Java code which explicitly specifies parameter names 86 check( 87 compatibilityMode = false, // parameter names only in v2 88 sourceFiles = *arrayOf( 89 java( 90 """ 91 package test.pkg; 92 import androidx.annotation.ParameterName; 93 94 public class Foo { 95 public void foo(int javaParameter1, @ParameterName("publicParameterName") int javaParameter2) { 96 } 97 } 98 """ 99 ), 100 supportParameterName 101 ), 102 api = """ 103 package test.pkg { 104 public class Foo { 105 ctor public Foo(); 106 method public void foo(int, int publicParameterName); 107 } 108 } 109 """, 110 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"), 111 checkDoclava1 = false /* doesn't support parameter names */ 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 checkDoclava1 = false /* doesn't support default Values */ 148 ) 149 } 150 151 @Test Default Values and Names in Kotlinnull152 fun `Default Values and Names in Kotlin`() { 153 // Kotlin code which explicitly specifies parameter names 154 check( 155 format = FileFormat.V3, 156 compatibilityMode = false, 157 sourceFiles = *arrayOf( 158 kotlin( 159 """ 160 package test.pkg 161 import some.other.pkg.Constants.Misc.SIZE 162 import android.graphics.Bitmap 163 import android.view.View 164 165 class Foo { 166 fun method1(int: Int = 42, 167 int2: Int? = null, 168 byte: Int = 2 * 21, 169 str: String = "hello " + "world", 170 vararg args: String) { } 171 172 fun method2(int: Int, int2: Int = (2*int) * SIZE) { } 173 174 fun method3(str: String, int: Int, int2: Int = double(int) + str.length) { } 175 176 fun emptyLambda(sizeOf: () -> Unit = { }) {} 177 178 fun View.drawToBitmap(config: Bitmap.Config = Bitmap.Config.ARGB_8888): Bitmap? = null 179 180 companion object { 181 fun double(int: Int) = 2 * int 182 fun print(foo: Foo = Foo()) { println(foo) } 183 } 184 } 185 """ 186 ), 187 java( 188 """ 189 package some.other.pkg; 190 public class Constants { 191 public static class Misc { 192 public static final int SIZE = 5; 193 } 194 } 195 """ 196 ) 197 ), 198 api = """ 199 // Signature format: 3.0 200 package test.pkg { 201 public final class Foo { 202 ctor public Foo(); 203 method public android.graphics.Bitmap? drawToBitmap(android.view.View, android.graphics.Bitmap.Config config = android.graphics.Bitmap.Config.ARGB_8888); 204 method public void emptyLambda(kotlin.jvm.functions.Function0<kotlin.Unit> sizeOf = {}); 205 method public void method1(int p = 42, Integer? int2 = null, int p1 = 42, String str = "hello world", java.lang.String... args); 206 method public void method2(int p, int int2 = (2 * int) * some.other.pkg.Constants.Misc.SIZE); 207 method public void method3(String str, int p, int int2 = double(int) + str.length); 208 field public static final test.pkg.Foo.Companion! Companion; 209 } 210 public static final class Foo.Companion { 211 method public int double(int p); 212 method public void print(test.pkg.Foo foo = test.pkg.Foo()); 213 } 214 } 215 """, 216 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation", ARG_HIDE_PACKAGE, "some.other.pkg"), 217 includeSignatureVersion = true, 218 checkDoclava1 = false /* doesn't support default Values */ 219 ) 220 } 221 222 @Test Default Values in Kotlin for expressionsnull223 fun `Default Values in Kotlin for expressions`() { 224 // Testing trickier default values; regression test for problem 225 // observed in androidx.core.util with LruCache 226 check( 227 format = FileFormat.V3, 228 sourceFiles = *arrayOf( 229 kotlin( 230 """ 231 package androidx.core.util 232 233 import android.util.LruCache 234 235 inline fun <K : Any, V : Any> lruCache( 236 maxSize: Int, 237 crossinline sizeOf: (key: K, value: V) -> Int = { _, _ -> 1 }, 238 @Suppress("USELESS_CAST") // https://youtrack.jetbrains.com/issue/KT-21946 239 crossinline create: (key: K) -> V? = { null as V? }, 240 crossinline onEntryRemoved: (evicted: Boolean, key: K, oldValue: V, newValue: V?) -> Unit = 241 { _, _, _, _ -> } 242 ): LruCache<K, V> { 243 return object : LruCache<K, V>(maxSize) { 244 override fun sizeOf(key: K, value: V) = sizeOf(key, value) 245 override fun create(key: K) = create(key) 246 override fun entryRemoved(evicted: Boolean, key: K, oldValue: V, newValue: V?) { 247 onEntryRemoved(evicted, key, oldValue, newValue) 248 } 249 } 250 } 251 """ 252 ), 253 java( 254 """ 255 package androidx.collection; 256 257 import androidx.annotation.NonNull; 258 import androidx.annotation.Nullable; 259 260 import java.util.LinkedHashMap; 261 import java.util.Locale; 262 import java.util.Map; 263 264 public class LruCache<K, V> { 265 @Nullable 266 protected V create(@NonNull K key) { 267 return null; 268 } 269 270 protected int sizeOf(@NonNull K key, @NonNull V value) { 271 return 1; 272 } 273 274 protected void entryRemoved(boolean evicted, @NonNull K key, @NonNull V oldValue, 275 @Nullable V newValue) { 276 } 277 } 278 """ 279 ), 280 androidxNullableSource, 281 androidxNonNullSource 282 ), 283 api = """ 284 // Signature format: 3.0 285 package androidx.core.util { 286 public final class TestKt { 287 ctor public TestKt(); 288 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 = { _, _ -> 1 }, kotlin.jvm.functions.Function1<? super K,? extends V> create = { (java.lang.Object)null }, kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved = { _, _, _, _ -> }); 289 } 290 } 291 """, 292 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation", ARG_HIDE_PACKAGE, "androidx.collection"), 293 includeSignatureVersion = true, 294 checkDoclava1 = false /* doesn't support default Values */ 295 ) 296 } 297 298 @Test Basic Kotlin classnull299 fun `Basic Kotlin class`() { 300 check( 301 format = FileFormat.V1, 302 extraArguments = arrayOf("--parameter-names=true"), 303 sourceFiles = *arrayOf( 304 kotlin( 305 """ 306 package test.pkg 307 class Kotlin(val property1: String = "Default Value", arg2: Int) : Parent() { 308 override fun method() = "Hello World" 309 fun otherMethod(ok: Boolean, times: Int) { 310 } 311 312 var property2: String? = null 313 314 private var someField = 42 315 @JvmField 316 var someField2 = 42 317 318 internal var myHiddenVar = false 319 internal fun myHiddenMethod(): Unit { } 320 internal data class myHiddenClass(): Unit { } 321 322 companion object { 323 const val MY_CONST = 42 324 } 325 } 326 327 //@get:RequiresApi(26) 328 inline val @receiver:String Long.isSrgb get() = true 329 inline val /*@receiver:ColorInt*/ Int.red get() = 0 330 inline operator fun String.component1() = "" 331 332 open class Parent { 333 open fun method(): String? = null 334 open fun method2(value: Boolean, value: Boolean?): String? = null 335 open fun method3(value: Int?, value2: Int): Int = null 336 } 337 """ 338 ) 339 ), 340 api = """ 341 package test.pkg { 342 public final class Kotlin extends test.pkg.Parent { 343 ctor public Kotlin(java.lang.String property1, int arg2); 344 method public java.lang.String getProperty1(); 345 method public java.lang.String getProperty2(); 346 method public void otherMethod(boolean ok, int times); 347 method public void setProperty2(java.lang.String p); 348 property public final java.lang.String property2; 349 field public static final test.pkg.Kotlin.Companion Companion; 350 field public static final int MY_CONST = 42; // 0x2a 351 field public int someField2; 352 } 353 public static final class Kotlin.Companion { 354 } 355 public final class KotlinKt { 356 ctor public KotlinKt(); 357 method public static inline operator java.lang.String component1(java.lang.String); 358 method public static inline int getRed(int); 359 method public static inline boolean isSrgb(long); 360 } 361 public class Parent { 362 ctor public Parent(); 363 method public java.lang.String method(); 364 method public java.lang.String method2(boolean value, java.lang.Boolean value); 365 method public int method3(java.lang.Integer value, int value2); 366 } 367 } 368 """, 369 privateApi = """ 370 package test.pkg { 371 public final class Kotlin extends test.pkg.Parent { 372 method internal boolean getMyHiddenVar${"$"}lintWithKotlin(); 373 method internal void myHiddenMethod${"$"}lintWithKotlin(); 374 method internal void setMyHiddenVar${"$"}lintWithKotlin(boolean p); 375 property internal final boolean myHiddenVar; 376 field internal boolean myHiddenVar; 377 field private final java.lang.String property1; 378 field private java.lang.String property2; 379 field private int someField; 380 } 381 public static final class Kotlin.Companion { 382 ctor private Kotlin.Companion(); 383 } 384 internal static final class Kotlin.myHiddenClass extends kotlin.Unit { 385 ctor public Kotlin.myHiddenClass(); 386 method internal test.pkg.Kotlin.myHiddenClass copy(); 387 } 388 } 389 """, 390 checkDoclava1 = false /* doesn't support Kotlin... */ 391 ) 392 } 393 394 @Test Kotlin Reified Methodsnull395 fun `Kotlin Reified Methods`() { 396 check( 397 sourceFiles = *arrayOf( 398 java( 399 """ 400 package test.pkg; 401 402 public class Context { 403 @SuppressWarnings("unchecked") 404 public final <T> T getSystemService(Class<T> serviceClass) { 405 return null; 406 } 407 } 408 """ 409 ), 410 kotlin( 411 """ 412 package test.pkg 413 414 inline fun <reified T> Context.systemService1() = getSystemService(T::class.java) 415 inline fun Context.systemService2() = getSystemService(String::class.java) 416 """ 417 ) 418 ), 419 api = """ 420 package test.pkg { 421 public class Context { 422 ctor public Context(); 423 method public final <T> T getSystemService(java.lang.Class<T>); 424 } 425 public final class _java_Kt { 426 ctor public _java_Kt(); 427 method public static inline <reified T> T systemService1(test.pkg.Context); 428 method public static inline java.lang.String systemService2(test.pkg.Context); 429 } 430 } 431 """, 432 checkDoclava1 = false /* doesn't support Kotlin... */ 433 ) 434 } 435 436 @Test Kotlin Reified Methods 2null437 fun `Kotlin Reified Methods 2`() { 438 check( 439 compatibilityMode = false, 440 sourceFiles = *arrayOf( 441 kotlin( 442 """ 443 @file:Suppress("NOTHING_TO_INLINE", "RedundantVisibilityModifier", "unused") 444 445 package test.pkg 446 447 inline fun <T> a(t: T) { } 448 inline fun <reified T> b(t: T) { } 449 private inline fun <reified T> c(t: T) { } // hide 450 internal inline fun <reified T> d(t: T) { } // hide 451 public inline fun <reified T> e(t: T) { } 452 inline fun <reified T> T.f(t: T) { } 453 """ 454 ) 455 ), 456 api = """ 457 package test.pkg { 458 public final class TestKt { 459 ctor public TestKt(); 460 method public static inline <T> void a(@Nullable T t); 461 method public static inline <reified T> void b(@Nullable T t); 462 method public static inline <reified T> void e(@Nullable T t); 463 method public static inline <reified T> void f(@Nullable T, @Nullable T t); 464 } 465 } 466 """, 467 checkDoclava1 = false /* doesn't support Kotlin... */ 468 ) 469 } 470 471 @Test Suspend functionsnull472 fun `Suspend functions`() { 473 check( 474 compatibilityMode = false, 475 sourceFiles = *arrayOf( 476 kotlin( 477 """ 478 package test.pkg 479 suspend inline fun hello() { } 480 """ 481 ) 482 ), 483 api = """ 484 package test.pkg { 485 public final class TestKt { 486 ctor public TestKt(); 487 method public static suspend inline Object hello(@NonNull kotlin.coroutines.Continuation<? super kotlin.Unit> p); 488 } 489 } 490 """, 491 checkDoclava1 = false /* doesn't support Kotlin... */ 492 ) 493 } 494 495 @Test Kotlin Genericsnull496 fun `Kotlin Generics`() { 497 check( 498 format = FileFormat.V3, 499 sourceFiles = *arrayOf( 500 kotlin( 501 """ 502 package test.pkg 503 class Bar 504 class Type<in T> { 505 fun foo(param: Type<Bar>) { 506 } 507 } 508 """ 509 ) 510 ), 511 compatibilityMode = false, 512 api = """ 513 // Signature format: 3.0 514 package test.pkg { 515 public final class Bar { 516 ctor public Bar(); 517 } 518 public final class Type<T> { 519 ctor public Type(); 520 method public void foo(test.pkg.Type<? super test.pkg.Bar> param); 521 } 522 } 523 """, 524 checkDoclava1 = false /* doesn't support Kotlin... */ 525 ) 526 } 527 528 @Test Nullness in reified signaturesnull529 fun `Nullness in reified signatures`() { 530 check( 531 compatibilityMode = false, 532 sourceFiles = *arrayOf( 533 kotlin( 534 "src/test/pkg/test.kt", 535 """ 536 package test.pkg 537 538 import androidx.annotation.UiThread 539 import test.pkg2.NavArgs 540 import test.pkg2.NavArgsLazy 541 import test.pkg2.Fragment 542 import test.pkg2.Bundle 543 544 @UiThread 545 inline fun <reified Args : NavArgs> Fragment.navArgs() = NavArgsLazy(Args::class) { 546 throw IllegalStateException("Fragment $this has null arguments") 547 } 548 """ 549 ), 550 kotlin( 551 """ 552 package test.pkg2 553 554 import kotlin.reflect.KClass 555 556 interface NavArgs 557 class Fragment 558 class Bundle 559 class NavArgsLazy<Args : NavArgs>( 560 private val navArgsClass: KClass<Args>, 561 private val argumentProducer: () -> Bundle 562 ) 563 """ 564 ), 565 uiThreadSource 566 ), 567 api = """ 568 // Signature format: 3.0 569 package test.pkg { 570 public final class TestKt { 571 ctor public TestKt(); 572 method @UiThread public static inline <reified Args extends test.pkg2.NavArgs> test.pkg2.NavArgsLazy<Args> navArgs(test.pkg2.Fragment); 573 } 574 } 575 """, 576 format = FileFormat.V3, 577 extraArguments = arrayOf( 578 ARG_HIDE_PACKAGE, "androidx.annotation", 579 ARG_HIDE_PACKAGE, "test.pkg2", 580 ARG_HIDE, "ReferencesHidden", 581 ARG_HIDE, "UnavailableSymbol", 582 ARG_HIDE, "HiddenTypeParameter" 583 ), 584 checkDoclava1 = false /* doesn't support parameter names */ 585 ) 586 } 587 588 @Test Nullness in varargsnull589 fun `Nullness in varargs`() { 590 check( 591 compatibilityMode = false, 592 sourceFiles = *arrayOf( 593 java( 594 """ 595 package androidx.collection; 596 597 import java.util.Collection; 598 import java.util.HashMap; 599 import java.util.Map; 600 601 public class ArrayMap<K, V> extends HashMap<K, V> implements Map<K, V> { 602 public ArrayMap() { 603 } 604 } 605 """ 606 ), 607 kotlin( 608 "src/main/java/androidx/collection/ArrayMap.kt", 609 """ 610 package androidx.collection 611 612 inline fun <K, V> arrayMapOf(): ArrayMap<K, V> = ArrayMap() 613 614 fun <K, V> arrayMapOf(vararg pairs: Pair<K, V>): ArrayMap<K, V> { 615 val map = ArrayMap<K, V>(pairs.size) 616 for (pair in pairs) { 617 map[pair.first] = pair.second 618 } 619 return map 620 } 621 fun <K, V> arrayMapOfNullable(vararg pairs: Pair<K, V>?): ArrayMap<K, V>? { 622 return null 623 } 624 """ 625 ) 626 ), 627 api = """ 628 // Signature format: 3.0 629 package androidx.collection { 630 public class ArrayMap<K, V> extends java.util.HashMap<K,V> implements java.util.Map<K,V> { 631 ctor public ArrayMap(); 632 } 633 public final class ArrayMapKt { 634 ctor public ArrayMapKt(); 635 method public static inline <K, V> androidx.collection.ArrayMap<K,V> arrayMapOf(); 636 method public static <K, V> androidx.collection.ArrayMap<K,V> arrayMapOf(kotlin.Pair<? extends K,? extends V>... pairs); 637 method public static <K, V> androidx.collection.ArrayMap<K,V>? arrayMapOfNullable(kotlin.Pair<? extends K,? extends V>?... pairs); 638 } 639 } 640 """, 641 format = FileFormat.V3, 642 extraArguments = arrayOf( 643 ARG_HIDE_PACKAGE, "androidx.annotation", 644 ARG_HIDE, "ReferencesHidden", 645 ARG_HIDE, "UnavailableSymbol", 646 ARG_HIDE, "HiddenTypeParameter" 647 ), 648 checkDoclava1 = false /* doesn't support parameter names */ 649 ) 650 } 651 652 @Test Propagate Platform types in Kotlinnull653 fun `Propagate Platform types in Kotlin`() { 654 check( 655 compatibilityMode = false, 656 format = FileFormat.V3, 657 sourceFiles = *arrayOf( 658 kotlin( 659 """ 660 // Nullable Pair in Kotlin 661 package androidx.util 662 663 class NullableKotlinPair<out F, out S>(val first: F?, val second: S?) 664 """ 665 ), 666 kotlin( 667 """ 668 // Non-nullable Pair in Kotlin 669 package androidx.util 670 class NonNullableKotlinPair<out F: Any, out S: Any>(val first: F, val second: S) 671 """ 672 ), 673 java( 674 """ 675 // Platform nullability Pair in Java 676 package androidx.util; 677 678 @SuppressWarnings("WeakerAccess") 679 public class PlatformJavaPair<F, S> { 680 public final F first; 681 public final S second; 682 683 public PlatformJavaPair(F first, S second) { 684 this.first = first; 685 this.second = second; 686 } 687 } 688 """ 689 ), 690 java( 691 """ 692 // Platform nullability Pair in Java 693 package androidx.util; 694 import androidx.annotation.NonNull; 695 import androidx.annotation.Nullable; 696 697 @SuppressWarnings("WeakerAccess") 698 public class NullableJavaPair<F, S> { 699 public final @Nullable F first; 700 public final @Nullable S second; 701 702 public NullableJavaPair(@Nullable F first, @Nullable S second) { 703 this.first = first; 704 this.second = second; 705 } 706 } 707 """ 708 ), 709 java( 710 """ 711 // Platform nullability Pair in Java 712 package androidx.util; 713 714 import androidx.annotation.NonNull; 715 716 @SuppressWarnings("WeakerAccess") 717 public class NonNullableJavaPair<F, S> { 718 public final @NonNull F first; 719 public final @NonNull S second; 720 721 public NonNullableJavaPair(@NonNull F first, @NonNull S second) { 722 this.first = first; 723 this.second = second; 724 } 725 } 726 """ 727 ), 728 kotlin( 729 """ 730 package androidx.util 731 732 @Suppress("HasPlatformType") // Intentionally propagating platform type with unknown nullability. 733 inline operator fun <F, S> PlatformJavaPair<F, S>.component1() = first 734 """ 735 ), 736 androidxNonNullSource, 737 androidxNullableSource 738 ), 739 api = """ 740 // Signature format: 3.0 741 package androidx.util { 742 public class NonNullableJavaPair<F, S> { 743 ctor public NonNullableJavaPair(F, S); 744 field public final F first; 745 field public final S second; 746 } 747 public final class NonNullableKotlinPair<F, S> { 748 ctor public NonNullableKotlinPair(F first, S second); 749 method public F getFirst(); 750 method public S getSecond(); 751 } 752 public class NullableJavaPair<F, S> { 753 ctor public NullableJavaPair(F?, S?); 754 field public final F? first; 755 field public final S? second; 756 } 757 public final class NullableKotlinPair<F, S> { 758 ctor public NullableKotlinPair(F? first, S? second); 759 method public F? getFirst(); 760 method public S? getSecond(); 761 } 762 public class PlatformJavaPair<F, S> { 763 ctor public PlatformJavaPair(F!, S!); 764 field public final F! first; 765 field public final S! second; 766 } 767 public final class TestKt { 768 ctor public TestKt(); 769 method public static inline operator <F, S> F! component1(androidx.util.PlatformJavaPair<F,S>); 770 } 771 } 772 """, 773 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"), 774 checkDoclava1 = false /* doesn't support Kotlin... */ 775 ) 776 } 777 778 @Test Known nullnessnull779 fun `Known nullness`() { 780 // Don't emit platform types for some unannotated elements that we know the 781 // nullness for: annotation type members, equals-parameters, initialized constants, etc. 782 check( 783 compatibilityMode = false, 784 outputKotlinStyleNulls = true, 785 sourceFiles = *arrayOf( 786 java( 787 """ 788 // Platform nullability Pair in Java 789 package test; 790 791 import androidx.annotation.NonNull; 792 793 public class MyClass { 794 public static final String MY_CONSTANT1 = "constant"; // Not nullable 795 public final String MY_CONSTANT2 = "constant"; // Not nullable 796 public String MY_CONSTANT3 = "constant"; // Unknown 797 798 /** @deprecated */ 799 @Deprecated 800 @Override 801 public boolean equals( 802 Object parameter // nullable 803 ) { 804 return super.equals(parameter); 805 } 806 807 /** @deprecated */ 808 @Deprecated 809 @Override // Not nullable 810 public String toString() { 811 return super.toString(); 812 } 813 } 814 """ 815 ), 816 java( 817 """ 818 package test.pkg; 819 820 import static java.lang.annotation.ElementType.*; 821 import java.lang.annotation.*; 822 public @interface MyAnnotation { 823 String[] value(); // Not nullable 824 } 825 """ 826 ).indented(), 827 java( 828 """ 829 package test.pkg; 830 @SuppressWarnings("ALL") 831 public enum Foo { 832 A, B; 833 } 834 """ 835 ), 836 androidxNonNullSource, 837 androidxNullableSource 838 ), 839 api = """ 840 // Signature format: 3.0 841 package test { 842 public class MyClass { 843 ctor public MyClass(); 844 method @Deprecated public boolean equals(Object?); 845 method @Deprecated public String toString(); 846 field public static final String MY_CONSTANT1 = "constant"; 847 field public final String MY_CONSTANT2 = "constant"; 848 field public String! MY_CONSTANT3; 849 } 850 } 851 package test.pkg { 852 public enum Foo { 853 enum_constant public static final test.pkg.Foo A; 854 enum_constant public static final test.pkg.Foo B; 855 } 856 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface MyAnnotation { 857 method public abstract String[] value(); 858 } 859 } 860 """, 861 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"), 862 checkDoclava1 = false /* doesn't support Kotlin... */ 863 ) 864 } 865 866 @Test JvmOverloadsnull867 fun `JvmOverloads`() { 868 // Regression test for https://github.com/android/android-ktx/issues/366 869 check( 870 format = FileFormat.V3, 871 compatibilityMode = false, 872 sourceFiles = *arrayOf( 873 kotlin( 874 """ 875 package androidx.content 876 877 import android.annotation.SuppressLint 878 import android.content.SharedPreferences 879 880 @SuppressLint("ApplySharedPref") 881 @JvmOverloads 882 inline fun SharedPreferences.edit( 883 commit: Boolean = false, 884 action: SharedPreferences.Editor.() -> Unit 885 ) { 886 val editor = edit() 887 action(editor) 888 if (commit) { 889 editor.commit() 890 } else { 891 editor.apply() 892 } 893 } 894 895 @JvmOverloads 896 fun String.blahblahblah(firstArg: String = "hello", secondArg: Int = 42, thirdArg: String = "world") { 897 } 898 """ 899 ) 900 ), 901 api = """ 902 // Signature format: 3.0 903 package androidx.content { 904 public final class TestKt { 905 ctor public TestKt(); 906 method public static void blahblahblah(String, String firstArg = "hello", int secondArg = 42, String thirdArg = "world"); 907 method public static void blahblahblah(String, String firstArg = "hello", int secondArg = 42); 908 method public static void blahblahblah(String, String firstArg = "hello"); 909 method public static void blahblahblah(String); 910 method public static inline void edit(android.content.SharedPreferences, boolean commit = false, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action); 911 method public static inline void edit(android.content.SharedPreferences, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action); 912 } 913 } 914 """, 915 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"), 916 checkDoclava1 = false /* doesn't support default Values */ 917 ) 918 } 919 920 @Test Extract class with genericsnull921 fun `Extract class with generics`() { 922 // Basic interface with generics; makes sure <T extends Object> is written as just <T> 923 // Also include some more complex generics expressions to make sure they're serialized 924 // correctly (in particular, using fully qualified names instead of what appears in 925 // the source code.) 926 check( 927 checkDoclava1 = true, 928 sourceFiles = *arrayOf( 929 java( 930 """ 931 package test.pkg; 932 @SuppressWarnings("ALL") 933 public interface MyInterface<T extends Object> 934 extends MyBaseInterface { 935 } 936 """ 937 ), java( 938 """ 939 package a.b.c; 940 @SuppressWarnings("ALL") 941 public interface MyStream<T, S extends MyStream<T, S>> extends test.pkg.AutoCloseable { 942 } 943 """ 944 ), java( 945 """ 946 package test.pkg; 947 @SuppressWarnings("ALL") 948 public interface MyInterface2<T extends Number> 949 extends MyBaseInterface { 950 class TtsSpan<C extends MyInterface<?>> { } 951 abstract class Range<T extends Comparable<? super T>> { 952 protected String myString; 953 } 954 } 955 """ 956 ), 957 java( 958 """ 959 package test.pkg; 960 public interface MyBaseInterface { 961 void fun(int a, String b); 962 } 963 """ 964 ), 965 java( 966 """ 967 package test.pkg; 968 public interface MyOtherInterface extends MyBaseInterface, AutoCloseable { 969 void fun(int a, String b); 970 } 971 """ 972 ), 973 java( 974 """ 975 package test.pkg; 976 public interface AutoCloseable { 977 } 978 """ 979 ) 980 ), 981 api = """ 982 package a.b.c { 983 public abstract interface MyStream<T, S extends a.b.c.MyStream<T, S>> implements test.pkg.AutoCloseable { 984 } 985 } 986 package test.pkg { 987 public abstract interface AutoCloseable { 988 } 989 public abstract interface MyBaseInterface { 990 method public abstract void fun(int, java.lang.String); 991 } 992 public abstract interface MyInterface<T> implements test.pkg.MyBaseInterface { 993 } 994 public abstract interface MyInterface2<T extends java.lang.Number> implements test.pkg.MyBaseInterface { 995 } 996 public static abstract class MyInterface2.Range<T extends java.lang.Comparable<? super T>> { 997 ctor public MyInterface2.Range(); 998 field protected java.lang.String myString; 999 } 1000 public static class MyInterface2.TtsSpan<C extends test.pkg.MyInterface<?>> { 1001 ctor public MyInterface2.TtsSpan(); 1002 } 1003 public abstract interface MyOtherInterface implements test.pkg.AutoCloseable test.pkg.MyBaseInterface { 1004 } 1005 } 1006 """, 1007 extraArguments = arrayOf(ARG_HIDE, "KotlinKeyword") 1008 ) 1009 } 1010 1011 @Test Basic class without default constructor, has constructors with argsnull1012 fun `Basic class without default constructor, has constructors with args`() { 1013 // Class without private constructors (shouldn't insert default constructor) 1014 check( 1015 sourceFiles = *arrayOf( 1016 java( 1017 """ 1018 package test.pkg; 1019 public class Foo { 1020 public Foo(int i) { 1021 1022 } 1023 public Foo(int i, int j) { 1024 } 1025 } 1026 """ 1027 ) 1028 ), 1029 api = """ 1030 package test.pkg { 1031 public class Foo { 1032 ctor public Foo(int); 1033 ctor public Foo(int, int); 1034 } 1035 } 1036 """ 1037 ) 1038 } 1039 1040 @Test Basic class without default constructor, has private constructornull1041 fun `Basic class without default constructor, has private constructor`() { 1042 // Class without private constructors; no default constructor should be inserted 1043 check( 1044 sourceFiles = *arrayOf( 1045 java( 1046 """ 1047 package test.pkg; 1048 @SuppressWarnings("ALL") 1049 public class Foo { 1050 private Foo() { 1051 } 1052 } 1053 """ 1054 ) 1055 ), 1056 api = """ 1057 package test.pkg { 1058 public class Foo { 1059 } 1060 } 1061 """ 1062 ) 1063 } 1064 1065 @Test Interface class extractionnull1066 fun `Interface class extraction`() { 1067 // Interface: makes sure the right modifiers etc are shown (and that "package private" methods 1068 // in the interface are taken to be public etc) 1069 check( 1070 sourceFiles = *arrayOf( 1071 java( 1072 """ 1073 package test.pkg; 1074 @SuppressWarnings("ALL") 1075 public interface Foo { 1076 void foo(); 1077 } 1078 """ 1079 ) 1080 ), 1081 api = """ 1082 package test.pkg { 1083 public abstract interface Foo { 1084 method public abstract void foo(); 1085 } 1086 } 1087 """ 1088 ) 1089 } 1090 1091 @Test Enum class extractionnull1092 fun `Enum class extraction`() { 1093 // Interface: makes sure the right modifiers etc are shown (and that "package private" methods 1094 // in the interface are taken to be public etc) 1095 check( 1096 sourceFiles = *arrayOf( 1097 java( 1098 """ 1099 package test.pkg; 1100 @SuppressWarnings("ALL") 1101 public enum Foo { 1102 A, B; 1103 } 1104 """ 1105 ) 1106 ), 1107 api = """ 1108 package test.pkg { 1109 public final class Foo extends java.lang.Enum { 1110 method public static test.pkg.Foo valueOf(java.lang.String); 1111 method public static final test.pkg.Foo[] values(); 1112 enum_constant public static final test.pkg.Foo A; 1113 enum_constant public static final test.pkg.Foo B; 1114 } 1115 } 1116 """ 1117 ) 1118 } 1119 1120 @Test Enum class, non-compat modenull1121 fun `Enum class, non-compat mode`() { 1122 // Interface: makes sure the right modifiers etc are shown (and that "package private" methods 1123 // in the interface are taken to be public etc) 1124 check( 1125 sourceFiles = *arrayOf( 1126 java( 1127 """ 1128 package test.pkg; 1129 @SuppressWarnings("ALL") 1130 public enum Foo { 1131 A, B; 1132 } 1133 """ 1134 ) 1135 ), 1136 compatibilityMode = false, 1137 api = """ 1138 package test.pkg { 1139 public enum Foo { 1140 enum_constant public static final test.pkg.Foo A; 1141 enum_constant public static final test.pkg.Foo B; 1142 } 1143 } 1144 """ 1145 ) 1146 } 1147 1148 @Test Annotation class extractionnull1149 fun `Annotation class extraction`() { 1150 // Interface: makes sure the right modifiers etc are shown (and that "package private" methods 1151 // in the interface are taken to be public etc) 1152 check( 1153 // For unknown reasons, doclava1 behaves differently here than when invoked on the 1154 // whole platform 1155 checkDoclava1 = false, 1156 sourceFiles = *arrayOf( 1157 java( 1158 """ 1159 package test.pkg; 1160 @SuppressWarnings("ALL") 1161 public @interface Foo { 1162 String value(); 1163 } 1164 """ 1165 ), 1166 java( 1167 """ 1168 package android.annotation; 1169 import static java.lang.annotation.ElementType.*; 1170 import java.lang.annotation.*; 1171 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) 1172 @Retention(RetentionPolicy.CLASS) 1173 @SuppressWarnings("ALL") 1174 public @interface SuppressLint { 1175 String[] value(); 1176 } 1177 """ 1178 ) 1179 ), 1180 api = """ 1181 package android.annotation { 1182 public abstract class SuppressLint implements java.lang.annotation.Annotation { 1183 } 1184 } 1185 package test.pkg { 1186 public abstract class Foo implements java.lang.annotation.Annotation { 1187 } 1188 } 1189 """ 1190 ) 1191 } 1192 1193 @Test Do not include inherited public methods from private parents in compat modenull1194 fun `Do not include inherited public methods from private parents in compat mode`() { 1195 // Real life example: StringBuilder.setLength, in compat mode 1196 check( 1197 compatibilityMode = true, 1198 sourceFiles = *arrayOf( 1199 java( 1200 """ 1201 package test.pkg; 1202 public class MyStringBuilder extends AbstractMyStringBuilder { 1203 } 1204 """ 1205 ), 1206 java( 1207 """ 1208 package test.pkg; 1209 class AbstractMyStringBuilder { 1210 public void setLength(int length) { 1211 } 1212 } 1213 """ 1214 ) 1215 ), 1216 api = """ 1217 package test.pkg { 1218 public class MyStringBuilder { 1219 ctor public MyStringBuilder(); 1220 } 1221 } 1222 """ 1223 ) 1224 } 1225 1226 @Test Include inherited public methods from private parentsnull1227 fun `Include inherited public methods from private parents`() { 1228 // In non-compat mode, include public methods from hidden parents too. 1229 // Real life example: StringBuilder.setLength 1230 // This is just like the above test, but with compat mode disabled. 1231 check( 1232 compatibilityMode = false, 1233 sourceFiles = *arrayOf( 1234 java( 1235 """ 1236 package test.pkg; 1237 public class MyStringBuilder extends AbstractMyStringBuilder { 1238 } 1239 """ 1240 ), 1241 java( 1242 """ 1243 package test.pkg; 1244 class AbstractMyStringBuilder { 1245 public void setLength(int length) { 1246 } 1247 } 1248 """ 1249 ) 1250 ), 1251 api = """ 1252 package test.pkg { 1253 public class MyStringBuilder { 1254 ctor public MyStringBuilder(); 1255 method public void setLength(int); 1256 } 1257 } 1258 """ 1259 ) 1260 } 1261 1262 @Test Skip inherited package private methods from private parentsnull1263 fun `Skip inherited package private methods from private parents`() { 1264 // In non-compat mode, include public methods from hidden parents too. 1265 // Real life example: StringBuilder.setLength 1266 // This is just like the above test, but with compat mode disabled. 1267 check( 1268 compatibilityMode = false, 1269 sourceFiles = *arrayOf( 1270 java( 1271 """ 1272 package test.pkg; 1273 public class MyStringBuilder<A,B> extends AbstractMyStringBuilder<A,B> { 1274 } 1275 """ 1276 ), 1277 java( 1278 """ 1279 package test.pkg; 1280 class AbstractMyStringBuilder<C,D> extends PublicSuper<C,D> { 1281 public void setLength(int length) { 1282 } 1283 @Override boolean isContiguous() { 1284 return true; 1285 } 1286 @Override boolean concrete() { 1287 return false; 1288 } 1289 } 1290 """ 1291 ), 1292 java( 1293 """ 1294 package test.pkg; 1295 public class PublicSuper<E,F> { 1296 abstract boolean isContiguous(); 1297 boolean concrete() { 1298 return false; 1299 } 1300 } 1301 """ 1302 ) 1303 ), 1304 api = """ 1305 package test.pkg { 1306 public class MyStringBuilder<A, B> extends test.pkg.PublicSuper<A,B> { 1307 ctor public MyStringBuilder(); 1308 method public void setLength(int); 1309 } 1310 public class PublicSuper<E, F> { 1311 ctor public PublicSuper(); 1312 } 1313 } 1314 """ 1315 ) 1316 } 1317 1318 @Test Annotation class extraction, non-compat modenull1319 fun `Annotation class extraction, non-compat mode`() { 1320 // Interface: makes sure the right modifiers etc are shown (and that "package private" methods 1321 // in the interface are taken to be public etc) 1322 check( 1323 sourceFiles = *arrayOf( 1324 java( 1325 """ 1326 package test.pkg; 1327 public @interface Foo { 1328 String value(); 1329 } 1330 """ 1331 ), 1332 java( 1333 """ 1334 package android.annotation; 1335 import static java.lang.annotation.ElementType.*; 1336 import java.lang.annotation.*; 1337 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) 1338 @Retention(RetentionPolicy.CLASS) 1339 @SuppressWarnings("ALL") 1340 public @interface SuppressLint { 1341 String[] value(); 1342 } 1343 """ 1344 ) 1345 ), 1346 compatibilityMode = false, 1347 api = """ 1348 package android.annotation { 1349 @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 { 1350 method public abstract String[] value(); 1351 } 1352 } 1353 package test.pkg { 1354 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface Foo { 1355 method public abstract String value(); 1356 } 1357 } 1358 """ 1359 ) 1360 } 1361 1362 @Test Annotation retentionnull1363 fun `Annotation retention`() { 1364 // For annotations where the java.lang.annotation classes themselves are not 1365 // part of the source tree, ensure that we compute the right retention (runtime, meaning 1366 // it should show up in the stubs file.). 1367 check( 1368 extraArguments = arrayOf(ARG_EXCLUDE_ANNOTATIONS), 1369 sourceFiles = *arrayOf( 1370 java( 1371 """ 1372 package test.pkg; 1373 public @interface Foo { 1374 String value(); 1375 } 1376 """ 1377 ), 1378 java( 1379 """ 1380 package android.annotation; 1381 import static java.lang.annotation.ElementType.*; 1382 import java.lang.annotation.*; 1383 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) 1384 @Retention(RetentionPolicy.CLASS) 1385 @SuppressWarnings("ALL") 1386 public @interface SuppressLint { 1387 String[] value(); 1388 } 1389 """ 1390 ), 1391 kotlin( 1392 """ 1393 package test.pkg 1394 1395 @DslMarker 1396 annotation class ImplicitRuntimeRetention 1397 1398 @Retention(AnnotationRetention.RUNTIME) 1399 annotation class ExplicitRuntimeRetention { 1400 } 1401 """.trimIndent() 1402 ) 1403 ), 1404 format = FileFormat.V3, 1405 api = """ 1406 // Signature format: 3.0 1407 package android.annotation { 1408 @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 { 1409 method public abstract String[] value(); 1410 } 1411 } 1412 package test.pkg { 1413 @kotlin.annotation.Retention(AnnotationRetention.RUNTIME) public @interface ExplicitRuntimeRetention { 1414 } 1415 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface Foo { 1416 method public abstract String value(); 1417 } 1418 @kotlin.DslMarker public @interface ImplicitRuntimeRetention { 1419 } 1420 } 1421 """.trimIndent(), 1422 compatibilityMode = true, 1423 stubs = arrayOf( 1424 // For annotations where the java.lang.annotation classes themselves are not 1425 // part of the source tree, ensure that we compute the right retention (runtime, meaning 1426 // it should show up in the stubs file.). 1427 """ 1428 package test.pkg; 1429 @SuppressWarnings({"unchecked", "deprecation", "all"}) 1430 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) 1431 public @interface Foo { 1432 public java.lang.String value(); 1433 } 1434 """, 1435 """ 1436 package android.annotation; 1437 @SuppressWarnings({"unchecked", "deprecation", "all"}) 1438 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) 1439 @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}) 1440 public @interface SuppressLint { 1441 public java.lang.String[] value(); 1442 } 1443 """ 1444 ), 1445 checkDoclava1 = false 1446 ) 1447 } 1448 1449 @Test Superclass signature extractionnull1450 fun `Superclass signature extraction`() { 1451 // Make sure superclass statement is correct; inherited method from parent that has same 1452 // signature isn't included in the child 1453 check( 1454 sourceFiles = *arrayOf( 1455 java( 1456 """ 1457 package test.pkg; 1458 @SuppressWarnings("ALL") 1459 public class Foo extends Super { 1460 @Override public void base() { } 1461 public void child() { } 1462 } 1463 """ 1464 ), 1465 java( 1466 """ 1467 package test.pkg; 1468 @SuppressWarnings("ALL") 1469 public class Super { 1470 public void base() { } 1471 } 1472 """ 1473 ) 1474 ), 1475 api = """ 1476 package test.pkg { 1477 public class Foo extends test.pkg.Super { 1478 ctor public Foo(); 1479 method public void child(); 1480 } 1481 public class Super { 1482 ctor public Super(); 1483 method public void base(); 1484 } 1485 } 1486 """ 1487 ) 1488 } 1489 1490 @Test Extract fields with types and initial valuesnull1491 fun `Extract fields with types and initial values`() { 1492 check( 1493 sourceFiles = *arrayOf( 1494 java( 1495 """ 1496 package test.pkg; 1497 @SuppressWarnings("ALL") 1498 public class Foo { 1499 private int hidden = 1; 1500 int hidden2 = 2; 1501 /** @hide */ 1502 int hidden3 = 3; 1503 1504 protected int field00; // No value 1505 public static final boolean field01 = true; 1506 public static final int field02 = 42; 1507 public static final long field03 = 42L; 1508 public static final short field04 = 5; 1509 public static final byte field05 = 5; 1510 public static final char field06 = 'c'; 1511 public static final float field07 = 98.5f; 1512 public static final double field08 = 98.5; 1513 public static final String field09 = "String with \"escapes\" and \u00a9..."; 1514 public static final double field10 = Double.NaN; 1515 public static final double field11 = Double.POSITIVE_INFINITY; 1516 1517 public static final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef"; 1518 public static final char HEX_INPUT = 61184; 1519 } 1520 """ 1521 ) 1522 ), 1523 api = """ 1524 package test.pkg { 1525 public class Foo { 1526 ctor public Foo(); 1527 field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef"; 1528 field public static final char HEX_INPUT = 61184; // 0xef00 '\uef00' 1529 field protected int field00; 1530 field public static final boolean field01 = true; 1531 field public static final int field02 = 42; // 0x2a 1532 field public static final long field03 = 42L; // 0x2aL 1533 field public static final short field04 = 5; // 0x5 1534 field public static final byte field05 = 5; // 0x5 1535 field public static final char field06 = 99; // 0x0063 'c' 1536 field public static final float field07 = 98.5f; 1537 field public static final double field08 = 98.5; 1538 field public static final java.lang.String field09 = "String with \"escapes\" and \u00a9..."; 1539 field public static final double field10 = (0.0/0.0); 1540 field public static final double field11 = (1.0/0.0); 1541 } 1542 } 1543 """ 1544 ) 1545 } 1546 1547 @Test Check all modifiersnull1548 fun `Check all modifiers`() { 1549 // Include as many modifiers as possible to see which ones are included 1550 // in the signature files, and the expected sorting order. 1551 // Note that the signature files treat "deprecated" as a fake modifier. 1552 // Note also how the "protected" modifier on the interface method gets 1553 // promoted to public. 1554 check( 1555 checkDoclava1 = true, 1556 sourceFiles = *arrayOf( 1557 java( 1558 """ 1559 package test.pkg; 1560 1561 @SuppressWarnings("ALL") 1562 public abstract class Foo { 1563 @Deprecated private static final long field1 = 5; 1564 @Deprecated private static volatile long field2 = 5; 1565 @Deprecated public static strictfp final synchronized void method1() { } 1566 @Deprecated public static final synchronized native void method2(); 1567 @Deprecated protected static final class Inner1 { } 1568 @Deprecated protected static abstract class Inner2 { } 1569 @Deprecated protected interface Inner3 { 1570 default void method3() { } 1571 static void method4(final int arg) { } 1572 } 1573 } 1574 """ 1575 ) 1576 ), 1577 1578 warnings = """ 1579 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] 1580 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] 1581 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] 1582 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] 1583 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] 1584 """, 1585 1586 api = """ 1587 package test.pkg { 1588 public abstract class Foo { 1589 ctor public Foo(); 1590 method public static final deprecated synchronized void method1(); 1591 method public static final deprecated synchronized void method2(); 1592 } 1593 protected static final deprecated class Foo.Inner1 { 1594 ctor protected Foo.Inner1(); 1595 } 1596 protected static abstract deprecated class Foo.Inner2 { 1597 ctor protected Foo.Inner2(); 1598 } 1599 protected static abstract deprecated interface Foo.Inner3 { 1600 method public default void method3(); 1601 method public static void method4(int); 1602 } 1603 } 1604 """ 1605 ) 1606 } 1607 1608 @Test Warn about findViewByIdnull1609 fun `Warn about findViewById`() { 1610 // Include as many modifiers as possible to see which ones are included 1611 // in the signature files, and the expected sorting order. 1612 // Note that the signature files treat "deprecated" as a fake modifier. 1613 // Note also how the "protected" modifier on the interface method gets 1614 // promoted to public. 1615 check( 1616 checkDoclava1 = false, 1617 compatibilityMode = false, 1618 outputKotlinStyleNulls = false, 1619 sourceFiles = *arrayOf( 1620 java( 1621 """ 1622 package test.pkg; 1623 import android.annotation.Nullable; 1624 1625 @SuppressWarnings("ALL") 1626 public abstract class Foo { 1627 @Nullable public String findViewById(int id) { return ""; } 1628 } 1629 """ 1630 ), 1631 nullableSource 1632 ), 1633 1634 warnings = """ 1635 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] 1636 """, 1637 extraArguments = arrayOf(ARG_WARNING, "ExpectedPlatformType"), 1638 api = """ 1639 package test.pkg { 1640 public abstract class Foo { 1641 ctor public Foo(); 1642 method public String findViewById(int); 1643 } 1644 } 1645 """ 1646 ) 1647 } 1648 1649 @Test Check all modifiers, non-compat modenull1650 fun `Check all modifiers, non-compat mode`() { 1651 // Like testModifiers but turns off compat mode, such that we have 1652 // a modifier order more in line with standard code conventions 1653 check( 1654 compatibilityMode = false, 1655 sourceFiles = *arrayOf( 1656 java( 1657 """ 1658 package test.pkg; 1659 1660 @SuppressWarnings("ALL") 1661 public abstract class Foo { 1662 @Deprecated private static final long field1 = 5; 1663 @Deprecated private static volatile long field2 = 5; 1664 /** @deprecated */ @Deprecated public static strictfp final synchronized void method1() { } 1665 /** @deprecated */ @Deprecated public static final synchronized native void method2(); 1666 /** @deprecated */ @Deprecated protected static final class Inner1 { } 1667 /** @deprecated */ @Deprecated protected static abstract class Inner2 { } 1668 /** @deprecated */ @Deprecated protected interface Inner3 { 1669 protected default void method3() { } 1670 static void method4(final int arg) { } 1671 } 1672 } 1673 """ 1674 ) 1675 ), 1676 api = """ 1677 package test.pkg { 1678 public abstract class Foo { 1679 ctor public Foo(); 1680 method @Deprecated public static final void method1(); 1681 method @Deprecated public static final void method2(); 1682 } 1683 @Deprecated protected static final class Foo.Inner1 { 1684 ctor @Deprecated protected Foo.Inner1(); 1685 } 1686 @Deprecated protected abstract static class Foo.Inner2 { 1687 ctor @Deprecated protected Foo.Inner2(); 1688 } 1689 @Deprecated protected static interface Foo.Inner3 { 1690 method @Deprecated public default void method3(); 1691 method @Deprecated public static void method4(int); 1692 } 1693 } 1694 """ 1695 ) 1696 } 1697 1698 @Test Package with only hidden classes should be removed from signature filesnull1699 fun `Package with only hidden classes should be removed from signature files`() { 1700 // Checks that if we have packages that are hidden, or contain only hidden or doconly 1701 // classes, the entire package is omitted from the signature file. Note how the test.pkg1.sub 1702 // package is not marked @hide, but doclava now treats subpackages of a hidden package 1703 // as also hidden. 1704 check( 1705 sourceFiles = *arrayOf( 1706 java( 1707 """ 1708 ${"/** @hide hidden package */" /* avoid dangling javadoc warning */} 1709 package test.pkg1; 1710 """ 1711 ), 1712 java( 1713 """ 1714 package test.pkg1; 1715 @SuppressWarnings("ALL") 1716 public class Foo { 1717 // Hidden by package hide 1718 } 1719 """ 1720 ), 1721 java( 1722 """ 1723 package test.pkg2; 1724 /** @hide hidden class in this package */ 1725 @SuppressWarnings("ALL") 1726 public class Bar { 1727 } 1728 """ 1729 ), 1730 java( 1731 """ 1732 package test.pkg2; 1733 /** @doconly hidden class in this package */ 1734 @SuppressWarnings("ALL") 1735 public class Baz { 1736 } 1737 """ 1738 ), 1739 java( 1740 """ 1741 package test.pkg1.sub; 1742 // Hidden by @hide in package above 1743 @SuppressWarnings("ALL") 1744 public class Test { 1745 } 1746 """ 1747 ), 1748 java( 1749 """ 1750 package test.pkg3; 1751 // The only really visible class 1752 @SuppressWarnings("ALL") 1753 public class Boo { 1754 } 1755 """ 1756 ) 1757 ), 1758 api = """ 1759 package test.pkg3 { 1760 public class Boo { 1761 ctor public Boo(); 1762 } 1763 } 1764 """ 1765 ) 1766 } 1767 1768 @Test Enums can be abstractnull1769 fun `Enums can be abstract`() { 1770 // As per https://bugs.openjdk.java.net/browse/JDK-6287639 1771 // abstract methods in enums should not be listed as abstract, 1772 // but doclava1 does, so replicate this. 1773 // Also checks that we handle both enum fields and regular fields 1774 // and that they are listed separately. 1775 1776 check( 1777 sourceFiles = *arrayOf( 1778 java( 1779 """ 1780 package test.pkg; 1781 1782 @SuppressWarnings("ALL") 1783 public enum FooBar { 1784 ABC { 1785 @Override 1786 protected void foo() { } 1787 }, DEF { 1788 @Override 1789 protected void foo() { } 1790 }; 1791 1792 protected abstract void foo(); 1793 public static int field1 = 1; 1794 public int field2 = 2; 1795 } 1796 """ 1797 ) 1798 ), 1799 api = """ 1800 package test.pkg { 1801 public class FooBar extends java.lang.Enum { 1802 method protected abstract void foo(); 1803 method public static test.pkg.FooBar valueOf(java.lang.String); 1804 method public static final test.pkg.FooBar[] values(); 1805 enum_constant public static final test.pkg.FooBar ABC; 1806 enum_constant public static final test.pkg.FooBar DEF; 1807 field public static int field1; 1808 field public int field2; 1809 } 1810 } 1811 """ 1812 ) 1813 } 1814 1815 @Test Check erasure in throws-listnull1816 fun `Check erasure in throws-list`() { 1817 // Makes sure that when we have a generic signature in the throws list we take 1818 // the erasure instead (in compat mode); "Throwable" instead of "X" in the below 1819 // test. Real world example: Optional.orElseThrow. 1820 check( 1821 compatibilityMode = true, 1822 sourceFiles = *arrayOf( 1823 java( 1824 """ 1825 package test.pkg; 1826 1827 import java.util.function.Supplier; 1828 1829 @SuppressWarnings("ALL") 1830 public final class Test<T> { 1831 public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { 1832 return null; 1833 } 1834 } 1835 """ 1836 ) 1837 ), 1838 api = """ 1839 package test.pkg { 1840 public final class Test<T> { 1841 ctor public Test(); 1842 method public <X extends java.lang.Throwable> T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable; 1843 } 1844 } 1845 """ 1846 ) 1847 } 1848 1849 @Test Check various generics signature subtletiesnull1850 fun `Check various generics signature subtleties`() { 1851 // Some additional declarations where PSI default type handling diffs from doclava1 1852 check( 1853 sourceFiles = *arrayOf( 1854 java( 1855 """ 1856 package test.pkg; 1857 1858 @SuppressWarnings("ALL") 1859 public abstract class Collections { 1860 public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T> collection) { 1861 return null; 1862 } 1863 public abstract <T extends java.util.Collection<java.lang.String>> T addAllTo(T t); 1864 public final class Range<T extends java.lang.Comparable<? super T>> { } 1865 } 1866 """ 1867 ), 1868 java( 1869 """ 1870 package test.pkg; 1871 1872 import java.util.Set; 1873 1874 @SuppressWarnings("ALL") 1875 public class MoreAsserts { 1876 public static void assertEquals(String arg0, Set<? extends Object> arg1, Set<? extends Object> arg2) { } 1877 public static void assertEquals(Set<? extends Object> arg1, Set<? extends Object> arg2) { } 1878 } 1879 1880 """ 1881 ) 1882 ), 1883 1884 // This is the output from doclava1; I'm not quite matching this yet (sorting order differs, 1885 // and my heuristic to remove "extends java.lang.Object" is somehow preserved here. I'm 1886 // not clear on when they do it and when they don't. 1887 /* 1888 api = """ 1889 package test.pkg { 1890 public abstract class Collections { 1891 ctor public Collections(); 1892 method public abstract <T extends java.util.Collection<java.lang.String>> T addAllTo(T); 1893 method public static <T & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>); 1894 } 1895 public final class Collections.Range<T extends java.lang.Comparable<? super T>> { 1896 ctor public Collections.Range(); 1897 } 1898 public class MoreAsserts { 1899 ctor public MoreAsserts(); 1900 method public static void assertEquals(java.util.Set<? extends java.lang.Object>, java.util.Set<? extends java.lang.Object>); 1901 method public static void assertEquals(java.lang.String, java.util.Set<? extends java.lang.Object>, java.util.Set<? extends java.lang.Object>); 1902 } 1903 } 1904 """, 1905 */ 1906 api = """ 1907 package test.pkg { 1908 public abstract class Collections { 1909 ctor public Collections(); 1910 method public abstract <T extends java.util.Collection<java.lang.String>> T addAllTo(T); 1911 method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>); 1912 } 1913 public final class Collections.Range<T extends java.lang.Comparable<? super T>> { 1914 ctor public Collections.Range(); 1915 } 1916 public class MoreAsserts { 1917 ctor public MoreAsserts(); 1918 method public static void assertEquals(java.lang.String, java.util.Set<?>, java.util.Set<?>); 1919 method public static void assertEquals(java.util.Set<?>, java.util.Set<?>); 1920 } 1921 } 1922 """, 1923 1924 // Can't check doclava1 on this: its output doesn't match javac, e.g. for the above declaration 1925 // of max, javap shows this signature: 1926 // public static <T extends java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>); 1927 // which matches metalava's output: 1928 // method public static <T & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>); 1929 // and not doclava1: 1930 // method public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(java.util.Collection<? extends T>); 1931 1932 checkDoclava1 = false 1933 ) 1934 } 1935 1936 @Test Check instance methods in enumsnull1937 fun `Check instance methods in enums`() { 1938 // Make sure that when we have instance methods in an enum they're handled 1939 // correctly (there's some special casing around enums to insert extra methods 1940 // that was broken, as exposed by ChronoUnit#toString) 1941 check( 1942 sourceFiles = *arrayOf( 1943 java( 1944 """ 1945 package test.pkg; 1946 1947 @SuppressWarnings("ALL") 1948 public interface TempUnit { 1949 @Override 1950 String toString(); 1951 } 1952 """ 1953 ), 1954 java( 1955 """ 1956 package test.pkg; 1957 1958 @SuppressWarnings("ALL") 1959 public enum ChronUnit implements TempUnit { 1960 C, B, A; 1961 1962 public String valueOf(int x) { 1963 return Integer.toString(x + 5); 1964 } 1965 1966 public String values(String separator) { 1967 return null; 1968 } 1969 1970 @Override 1971 public String toString() { 1972 return name(); 1973 } 1974 } 1975 """ 1976 ) 1977 ), 1978 importedPackages = emptyList(), 1979 api = """ 1980 package test.pkg { 1981 public final class ChronUnit extends java.lang.Enum implements test.pkg.TempUnit { 1982 method public static test.pkg.ChronUnit valueOf(java.lang.String); 1983 method public java.lang.String valueOf(int); 1984 method public static final test.pkg.ChronUnit[] values(); 1985 method public final java.lang.String values(java.lang.String); 1986 enum_constant public static final test.pkg.ChronUnit A; 1987 enum_constant public static final test.pkg.ChronUnit B; 1988 enum_constant public static final test.pkg.ChronUnit C; 1989 } 1990 public abstract interface TempUnit { 1991 method public abstract java.lang.String toString(); 1992 } 1993 } 1994 """ 1995 ) 1996 } 1997 1998 @Test Mixing enums and fieldsnull1999 fun `Mixing enums and fields`() { 2000 // Checks sorting order of enum constant values 2001 val source = """ 2002 package java.nio.file.attribute { 2003 public final class AclEntryPermission extends java.lang.Enum { 2004 method public static java.nio.file.attribute.AclEntryPermission valueOf(java.lang.String); 2005 method public static final java.nio.file.attribute.AclEntryPermission[] values(); 2006 enum_constant public static final java.nio.file.attribute.AclEntryPermission APPEND_DATA; 2007 enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE; 2008 enum_constant public static final java.nio.file.attribute.AclEntryPermission DELETE_CHILD; 2009 enum_constant public static final java.nio.file.attribute.AclEntryPermission EXECUTE; 2010 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_ACL; 2011 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_ATTRIBUTES; 2012 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_DATA; 2013 enum_constant public static final java.nio.file.attribute.AclEntryPermission READ_NAMED_ATTRS; 2014 enum_constant public static final java.nio.file.attribute.AclEntryPermission SYNCHRONIZE; 2015 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_ACL; 2016 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_ATTRIBUTES; 2017 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_DATA; 2018 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_NAMED_ATTRS; 2019 enum_constant public static final java.nio.file.attribute.AclEntryPermission WRITE_OWNER; 2020 field public static final java.nio.file.attribute.AclEntryPermission ADD_FILE; 2021 field public static final java.nio.file.attribute.AclEntryPermission ADD_SUBDIRECTORY; 2022 field public static final java.nio.file.attribute.AclEntryPermission LIST_DIRECTORY; 2023 } 2024 } 2025 """ 2026 check( 2027 signatureSource = source, 2028 api = source 2029 ) 2030 } 2031 2032 @Test Superclass filtering, should skip intermediate hidden classesnull2033 fun `Superclass filtering, should skip intermediate hidden classes`() { 2034 check( 2035 sourceFiles = *arrayOf( 2036 java( 2037 """ 2038 package test.pkg; 2039 @SuppressWarnings("ALL") 2040 public class MyClass extends HiddenParent { 2041 public void method4() { } 2042 } 2043 """ 2044 ), 2045 java( 2046 """ 2047 package test.pkg; 2048 /** @hide */ 2049 @SuppressWarnings("ALL") 2050 public class HiddenParent extends HiddenParent2 { 2051 public static final String CONSTANT = "MyConstant"; 2052 protected int mContext; 2053 public void method3() { } 2054 } 2055 """ 2056 ), 2057 java( 2058 """ 2059 package test.pkg; 2060 /** @hide */ 2061 @SuppressWarnings("ALL") 2062 public class HiddenParent2 extends PublicParent { 2063 public void method2() { } 2064 } 2065 """ 2066 ), 2067 java( 2068 """ 2069 package test.pkg; 2070 @SuppressWarnings("ALL") 2071 public class PublicParent { 2072 public void method1() { } 2073 } 2074 """ 2075 ) 2076 ), 2077 // Notice how the intermediate methods (method2, method3) have been removed 2078 includeStrippedSuperclassWarnings = true, 2079 warnings = "src/test/pkg/MyClass.java:2: warning: Public class test.pkg.MyClass stripped of unavailable superclass test.pkg.HiddenParent [HiddenSuperclass]", 2080 api = """ 2081 package test.pkg { 2082 public class MyClass extends test.pkg.PublicParent { 2083 ctor public MyClass(); 2084 method public void method4(); 2085 } 2086 public class PublicParent { 2087 ctor public PublicParent(); 2088 method public void method1(); 2089 } 2090 } 2091 """ 2092 ) 2093 } 2094 2095 @Test Inheriting from package private classes, package private class should be includednull2096 fun `Inheriting from package private classes, package private class should be included`() { 2097 check( 2098 checkDoclava1 = false, // doclava1 does not include method2, which it should 2099 compatibilityMode = false, 2100 sourceFiles = 2101 *arrayOf( 2102 java( 2103 """ 2104 package test.pkg; 2105 @SuppressWarnings("ALL") 2106 public class MyClass extends HiddenParent { 2107 public void method1() { } 2108 } 2109 """ 2110 ), 2111 java( 2112 """ 2113 package test.pkg; 2114 @SuppressWarnings("ALL") 2115 class HiddenParent { 2116 public static final String CONSTANT = "MyConstant"; 2117 protected int mContext; 2118 public void method2() { } 2119 } 2120 """ 2121 ) 2122 ), 2123 warnings = "", 2124 api = """ 2125 package test.pkg { 2126 public class MyClass { 2127 ctor public MyClass(); 2128 method public void method1(); 2129 method public void method2(); 2130 field public static final String CONSTANT = "MyConstant"; 2131 } 2132 } 2133 """ 2134 ) 2135 } 2136 2137 @Test Using compatibility flag manuallynull2138 fun `Using compatibility flag manually`() { 2139 // Like previous test, but using compatibility mode and explicitly turning on 2140 // the hidden super class compatibility flag. This test is mostly intended 2141 // to test the flag handling for individual compatibility flags. 2142 check( 2143 checkDoclava1 = false, // doclava1 does not include method2, which it should 2144 compatibilityMode = true, 2145 extraArguments = arrayOf("--skip-inherited-methods=false"), 2146 sourceFiles = 2147 *arrayOf( 2148 java( 2149 """ 2150 package test.pkg; 2151 @SuppressWarnings("ALL") 2152 public class MyClass extends HiddenParent { 2153 public void method1() { } 2154 } 2155 """ 2156 ), 2157 java( 2158 """ 2159 package test.pkg; 2160 @SuppressWarnings("ALL") 2161 class HiddenParent { 2162 public static final String CONSTANT = "MyConstant"; 2163 protected int mContext; 2164 public void method2() { } 2165 } 2166 """ 2167 ) 2168 ), 2169 warnings = "", 2170 api = """ 2171 package test.pkg { 2172 public class MyClass { 2173 ctor public MyClass(); 2174 method public void method1(); 2175 method public void method2(); 2176 } 2177 } 2178 """ 2179 ) 2180 } 2181 2182 @Test When implementing rather than extending package private class, inline members insteadnull2183 fun `When implementing rather than extending package private class, inline members instead`() { 2184 // If you implement a package private interface, we just remove it and inline the members into 2185 // the subclass 2186 check( 2187 compatibilityMode = true, 2188 sourceFiles = *arrayOf( 2189 java( 2190 """ 2191 package test.pkg; 2192 public class MyClass implements HiddenInterface { 2193 @Override public void method() { } 2194 @Override public void other() { } 2195 } 2196 """ 2197 ), 2198 java( 2199 """ 2200 package test.pkg; 2201 public interface OtherInterface { 2202 void other(); 2203 } 2204 """ 2205 ), 2206 java( 2207 """ 2208 package test.pkg; 2209 interface HiddenInterface extends OtherInterface { 2210 void method() { } 2211 String CONSTANT = "MyConstant"; 2212 } 2213 """ 2214 ) 2215 ), 2216 api = """ 2217 package test.pkg { 2218 public class MyClass implements test.pkg.OtherInterface { 2219 ctor public MyClass(); 2220 method public void method(); 2221 method public void other(); 2222 field public static final java.lang.String CONSTANT = "MyConstant"; 2223 } 2224 public abstract interface OtherInterface { 2225 method public abstract void other(); 2226 } 2227 } 2228 """ 2229 ) 2230 } 2231 2232 @Test Implementing package private class, non-compat modenull2233 fun `Implementing package private class, non-compat mode`() { 2234 // Like the previous test, but in non compat mode we correctly 2235 // include all the non-hidden public interfaces into the signature 2236 2237 // BUG: Note that we need to implement the parent 2238 check( 2239 compatibilityMode = false, 2240 sourceFiles = *arrayOf( 2241 java( 2242 """ 2243 package test.pkg; 2244 public class MyClass implements HiddenInterface { 2245 @Override public void method() { } 2246 @Override public void other() { } 2247 } 2248 """ 2249 ), 2250 java( 2251 """ 2252 package test.pkg; 2253 public interface OtherInterface { 2254 void other(); 2255 } 2256 """ 2257 ), 2258 java( 2259 """ 2260 package test.pkg; 2261 interface HiddenInterface extends OtherInterface { 2262 void method() { } 2263 String CONSTANT = "MyConstant"; 2264 } 2265 """ 2266 ) 2267 ), 2268 api = """ 2269 package test.pkg { 2270 public class MyClass implements test.pkg.OtherInterface { 2271 ctor public MyClass(); 2272 method public void method(); 2273 method public void other(); 2274 field public static final String CONSTANT = "MyConstant"; 2275 } 2276 public interface OtherInterface { 2277 method public void other(); 2278 } 2279 } 2280 """ 2281 ) 2282 } 2283 2284 @Test Default modifiers should be omittednull2285 fun `Default modifiers should be omitted`() { 2286 // If signatures vary only by the "default" modifier in the interface, don't show it on the implementing 2287 // class 2288 check( 2289 sourceFiles = 2290 *arrayOf( 2291 java( 2292 """ 2293 package test.pkg; 2294 2295 public class MyClass implements SuperInterface { 2296 @Override public void method() { } 2297 @Override public void method2() { } 2298 } 2299 """ 2300 ), 2301 java( 2302 """ 2303 package test.pkg; 2304 2305 public interface SuperInterface { 2306 void method(); 2307 default void method2() { 2308 } 2309 } 2310 """ 2311 ) 2312 ), 2313 api = """ 2314 package test.pkg { 2315 public class MyClass implements test.pkg.SuperInterface { 2316 ctor public MyClass(); 2317 method public void method(); 2318 } 2319 public abstract interface SuperInterface { 2320 method public abstract void method(); 2321 method public default void method2(); 2322 } 2323 } 2324 """ 2325 ) 2326 } 2327 2328 @Test Override via different throws list should be includednull2329 fun `Override via different throws list should be included`() { 2330 // If a method overrides another but changes the throws list, the overriding 2331 // method must be listed in the subclass. This is observed for example in 2332 // AbstractCursor#finalize, which omits the throws clause from Object's finalize. 2333 check( 2334 sourceFiles = 2335 *arrayOf( 2336 java( 2337 """ 2338 package test.pkg; 2339 2340 public abstract class AbstractCursor extends Parent { 2341 @Override protected void finalize2() { } // note: not throws Throwable! 2342 } 2343 """ 2344 ), 2345 java( 2346 """ 2347 package test.pkg; 2348 2349 @SuppressWarnings("RedundantThrows") 2350 public class Parent { 2351 protected void finalize2() throws Throwable { 2352 } 2353 } 2354 """ 2355 ) 2356 ), 2357 api = """ 2358 package test.pkg { 2359 public abstract class AbstractCursor extends test.pkg.Parent { 2360 ctor public AbstractCursor(); 2361 method protected void finalize2(); 2362 } 2363 public class Parent { 2364 ctor public Parent(); 2365 method protected void finalize2() throws java.lang.Throwable; 2366 } 2367 } 2368 """ 2369 ) 2370 } 2371 2372 @Test Implementing interface methodnull2373 fun `Implementing interface method`() { 2374 // If you have a public method that implements an interface method, 2375 // they'll vary in the "abstract" modifier, but it shouldn't be listed on the 2376 // class. This is an issue for example for the ZonedDateTime#getLong method 2377 // implementing the TemporalAccessor#getLong method 2378 check( 2379 sourceFiles = *arrayOf( 2380 java( 2381 """ 2382 package test.pkg; 2383 public interface SomeInterface2 { 2384 @Override default long getLong() { 2385 return 42; 2386 } 2387 } 2388 """ 2389 ), 2390 java( 2391 """ 2392 package test.pkg; 2393 public class Foo implements SomeInterface2 { 2394 @Override 2395 public long getLong() { return 0L; } 2396 } 2397 """ 2398 ) 2399 ), 2400 api = """ 2401 package test.pkg { 2402 public class Foo implements test.pkg.SomeInterface2 { 2403 ctor public Foo(); 2404 } 2405 public abstract interface SomeInterface2 { 2406 method public default long getLong(); 2407 } 2408 } 2409 """ 2410 ) 2411 } 2412 2413 @Test Implementing interface method 2null2414 fun `Implementing interface method 2`() { 2415 check( 2416 sourceFiles = *arrayOf( 2417 java( 2418 """ 2419 package test.pkg; 2420 public interface SomeInterface { 2421 long getLong(); 2422 } 2423 """ 2424 ), 2425 java( 2426 """ 2427 package test.pkg; 2428 public interface SomeInterface2 { 2429 @Override default long getLong() { 2430 return 42; 2431 } 2432 } 2433 """ 2434 ), 2435 java( 2436 """ 2437 package test.pkg; 2438 public class Foo implements SomeInterface, SomeInterface2 { 2439 @Override 2440 public long getLong() { return 0L; } 2441 } 2442 """ 2443 ) 2444 ), 2445 api = """ 2446 package test.pkg { 2447 public class Foo implements test.pkg.SomeInterface test.pkg.SomeInterface2 { 2448 ctor public Foo(); 2449 } 2450 public abstract interface SomeInterface { 2451 method public abstract long getLong(); 2452 } 2453 public abstract interface SomeInterface2 { 2454 method public default long getLong(); 2455 } 2456 } 2457 """ 2458 ) 2459 } 2460 2461 @Test Check basic @remove scenariosnull2462 fun `Check basic @remove scenarios`() { 2463 // Test basic @remove handling for methods and fields 2464 check( 2465 checkDoclava1 = true, 2466 sourceFiles = *arrayOf( 2467 java( 2468 """ 2469 package test.pkg; 2470 @SuppressWarnings("JavaDoc") 2471 public class Bar { 2472 /** @removed */ 2473 public Bar() { } 2474 public int field; 2475 public void test() { } 2476 /** @removed */ 2477 public int removedField; 2478 /** @removed */ 2479 public void removedMethod() { } 2480 /** @removed and @hide - should not be listed */ 2481 public int hiddenField; 2482 2483 /** @removed */ 2484 public class Inner { } 2485 2486 public class Inner2 { 2487 public class Inner3 { 2488 /** @removed */ 2489 public class Inner4 { } 2490 } 2491 } 2492 2493 public class Inner5 { 2494 public class Inner6 { 2495 public class Inner7 { 2496 /** @removed */ 2497 public int removed; 2498 } 2499 } 2500 } 2501 } 2502 """ 2503 ) 2504 ), 2505 removedApi = """ 2506 package test.pkg { 2507 public class Bar { 2508 ctor public Bar(); 2509 method public void removedMethod(); 2510 field public int removedField; 2511 } 2512 public class Bar.Inner { 2513 ctor public Bar.Inner(); 2514 } 2515 public class Bar.Inner2.Inner3.Inner4 { 2516 ctor public Bar.Inner2.Inner3.Inner4(); 2517 } 2518 public class Bar.Inner5.Inner6.Inner7 { 2519 field public int removed; 2520 } 2521 } 2522 """, 2523 removedDexApi = "" + 2524 "Ltest/pkg/Bar;-><init>()V\n" + 2525 "Ltest/pkg/Bar;->removedMethod()V\n" + 2526 "Ltest/pkg/Bar;->removedField:I\n" + 2527 "Ltest/pkg/Bar\$Inner;\n" + 2528 "Ltest/pkg/Bar\$Inner;-><init>()V\n" + 2529 "Ltest/pkg/Bar\$Inner2\$Inner3\$Inner4;\n" + 2530 "Ltest/pkg/Bar\$Inner2\$Inner3\$Inner4;-><init>()V\n" + 2531 "Ltest/pkg/Bar\$Inner5\$Inner6\$Inner7;->removed:I" 2532 ) 2533 } 2534 2535 @Test Check @remove classnull2536 fun `Check @remove class`() { 2537 // Test removing classes 2538 check( 2539 checkDoclava1 = true, 2540 sourceFiles = *arrayOf( 2541 java( 2542 """ 2543 package test.pkg; 2544 /** @removed */ 2545 @SuppressWarnings("JavaDoc") 2546 public class Foo { 2547 public void foo() { } 2548 public class Inner { 2549 } 2550 } 2551 """ 2552 ), 2553 java( 2554 """ 2555 package test.pkg; 2556 @SuppressWarnings("JavaDoc") 2557 public class Bar implements Parcelable { 2558 public int field; 2559 public void method(); 2560 2561 /** @removed */ 2562 public int removedField; 2563 /** @removed */ 2564 public void removedMethod() { } 2565 2566 public class Inner1 { 2567 } 2568 /** @removed */ 2569 public class Inner2 { 2570 } 2571 } 2572 """ 2573 ), 2574 java( 2575 """ 2576 package test.pkg; 2577 @SuppressWarnings("ALL") 2578 public interface Parcelable { 2579 void method(); 2580 } 2581 """ 2582 ) 2583 ), 2584 /* 2585 I expected this: but doclava1 doesn't do that (and we now match its behavior) 2586 package test.pkg { 2587 public class Bar { 2588 method public void removedMethod(); 2589 field public int removedField; 2590 } 2591 public class Bar.Inner2 { 2592 } 2593 public class Foo { 2594 method public void foo(); 2595 } 2596 } 2597 */ 2598 removedApi = """ 2599 package test.pkg { 2600 public class Bar implements test.pkg.Parcelable { 2601 method public void removedMethod(); 2602 field public int removedField; 2603 } 2604 public class Bar.Inner2 { 2605 ctor public Bar.Inner2(); 2606 } 2607 public class Foo { 2608 ctor public Foo(); 2609 method public void foo(); 2610 } 2611 public class Foo.Inner { 2612 ctor public Foo.Inner(); 2613 } 2614 } 2615 """ 2616 ) 2617 } 2618 2619 @Test Test include overridden @Deprecated even if annotated with @hidenull2620 fun `Test include overridden @Deprecated even if annotated with @hide`() { 2621 check( 2622 checkDoclava1 = false, // line numbers differ; they include comments; we point straight to modifier list 2623 sourceFiles = *arrayOf( 2624 java( 2625 """ 2626 package test.pkg; 2627 @SuppressWarnings("JavaDoc") 2628 public class Child extends Parent { 2629 /** 2630 * @deprecated 2631 * @hide 2632 */ 2633 @Deprecated @Override 2634 public String toString() { 2635 return "Child"; 2636 } 2637 2638 /** 2639 * @hide 2640 */ 2641 public void hiddenApi() { 2642 } 2643 } 2644 """ 2645 ), 2646 java( 2647 """ 2648 package test.pkg; 2649 public class Parent { 2650 public String toString() { 2651 return "Parent"; 2652 } 2653 } 2654 """ 2655 ) 2656 ), 2657 api = """ 2658 package test.pkg { 2659 public class Child extends test.pkg.Parent { 2660 ctor public Child(); 2661 method public deprecated java.lang.String toString(); 2662 } 2663 public class Parent { 2664 ctor public Parent(); 2665 } 2666 } 2667 """, 2668 dexApi = """ 2669 Ltest/pkg/Child; 2670 Ltest/pkg/Child;-><init>()V 2671 Ltest/pkg/Child;->toString()Ljava/lang/String; 2672 Ltest/pkg/Parent; 2673 Ltest/pkg/Parent;-><init>()V 2674 Ltest/pkg/Parent;->toString()Ljava/lang/String; 2675 """, 2676 dexApiMapping = """ 2677 Ltest/pkg/Child;-><init>()V 2678 src/test/pkg/Child.java:2 2679 Ltest/pkg/Child;->hiddenApi()V 2680 src/test/pkg/Child.java:16 2681 Ltest/pkg/Child;->toString()Ljava/lang/String; 2682 src/test/pkg/Child.java:8 2683 Ltest/pkg/Parent;-><init>()V 2684 src/test/pkg/Parent.java:2 2685 Ltest/pkg/Parent;->toString()Ljava/lang/String; 2686 src/test/pkg/Parent.java:3 2687 """ 2688 ) 2689 } 2690 2691 @Test Test invalid class namenull2692 fun `Test invalid class name`() { 2693 // Regression test for b/73018978 2694 check( 2695 checkDoclava1 = false, 2696 sourceFiles = *arrayOf( 2697 kotlin( 2698 "src/test/pkg/Foo.kt", 2699 """ 2700 @file:JvmName("-Foo") 2701 2702 package test.pkg 2703 2704 @Suppress("unused") 2705 inline fun String.printHelloWorld() { println("Hello World") } 2706 """ 2707 ) 2708 ), 2709 api = """ 2710 package test.pkg { 2711 public final class -Foo { 2712 method public static inline void printHelloWorld(java.lang.String); 2713 } 2714 } 2715 """ 2716 ) 2717 } 2718 2719 @Test Indirect Field Includes from Interfacesnull2720 fun `Indirect Field Includes from Interfaces`() { 2721 // Real-world example: include ZipConstants into ZipFile and JarFile 2722 check( 2723 checkDoclava1 = true, 2724 sourceFiles = *arrayOf( 2725 java( 2726 """ 2727 package test.pkg1; 2728 interface MyConstants { 2729 long CONSTANT1 = 12345; 2730 long CONSTANT2 = 67890; 2731 long CONSTANT3 = 42; 2732 } 2733 """ 2734 ), 2735 java( 2736 """ 2737 package test.pkg1; 2738 import java.io.Closeable; 2739 @SuppressWarnings("WeakerAccess") 2740 public class MyParent implements MyConstants, Closeable { 2741 } 2742 """ 2743 ), 2744 java( 2745 """ 2746 package test.pkg2; 2747 2748 import test.pkg1.MyParent; 2749 public class MyChild extends MyParent { 2750 } 2751 """ 2752 ) 2753 2754 ), 2755 api = """ 2756 package test.pkg1 { 2757 public class MyParent implements java.io.Closeable { 2758 ctor public MyParent(); 2759 field public static final long CONSTANT1 = 12345L; // 0x3039L 2760 field public static final long CONSTANT2 = 67890L; // 0x10932L 2761 field public static final long CONSTANT3 = 42L; // 0x2aL 2762 } 2763 } 2764 package test.pkg2 { 2765 public class MyChild extends test.pkg1.MyParent { 2766 ctor public MyChild(); 2767 field public static final long CONSTANT1 = 12345L; // 0x3039L 2768 field public static final long CONSTANT2 = 67890L; // 0x10932L 2769 field public static final long CONSTANT3 = 42L; // 0x2aL 2770 } 2771 } 2772 """ 2773 ) 2774 } 2775 2776 @Test Skip interfaces from packages explicitly hidden via argumentsnull2777 fun `Skip interfaces from packages explicitly hidden via arguments`() { 2778 // Real-world example: HttpResponseCache implements OkCacheContainer but hides the only inherited method 2779 check( 2780 checkDoclava1 = true, 2781 extraArguments = arrayOf( 2782 ARG_HIDE_PACKAGE, "com.squareup.okhttp" 2783 ), 2784 sourceFiles = *arrayOf( 2785 java( 2786 """ 2787 package android.net.http; 2788 import com.squareup.okhttp.Cache; 2789 import com.squareup.okhttp.OkCacheContainer; 2790 import java.io.Closeable; 2791 import java.net.ResponseCache; 2792 @SuppressWarnings("JavaDoc") 2793 public final class HttpResponseCache implements Closeable, OkCacheContainer { 2794 /** @hide Needed for OkHttp integration. */ 2795 @Override 2796 public Cache getCache() { 2797 return delegate.getCache(); 2798 } 2799 } 2800 """ 2801 ), 2802 java( 2803 """ 2804 package com.squareup.okhttp; 2805 public interface OkCacheContainer { 2806 Cache getCache(); 2807 } 2808 """ 2809 ) 2810 ), 2811 api = """ 2812 package android.net.http { 2813 public final class HttpResponseCache implements java.io.Closeable { 2814 ctor public HttpResponseCache(); 2815 } 2816 } 2817 """ 2818 ) 2819 } 2820 2821 @Test Private API signaturesnull2822 fun `Private API signatures`() { 2823 check( 2824 checkDoclava1 = false, // doclava1 doesn't have the same behavior: see 2825 // https://android-review.googlesource.com/c/platform/external/doclava/+/589515 2826 sourceFiles = *arrayOf( 2827 java( 2828 """ 2829 package test.pkg; 2830 public class Class1 implements MyInterface { 2831 Class1(int arg) { } 2832 /** @hide */ 2833 public void method1() { } 2834 void method2() { } 2835 private void method3() { } 2836 public int field1 = 1; 2837 protected int field2 = 2; 2838 int field3 = 3; 2839 float[][] field4 = 3; 2840 long[] field5 = null; 2841 private int field6 = 4; 2842 void myVarargsMethod(int x, String... args) { } 2843 2844 public class Inner { // Fully public, should not be included 2845 public void publicMethod() { } 2846 } 2847 } 2848 """ 2849 ), 2850 2851 java( 2852 """ 2853 package test.pkg; 2854 class Class2 { 2855 public void method4() { } 2856 2857 private class Class3 { 2858 public void method5() { } 2859 } 2860 } 2861 """ 2862 ), 2863 2864 java( 2865 """ 2866 package test.pkg; 2867 /** @doconly */ 2868 class Class4 { 2869 public void method5() { } 2870 } 2871 """ 2872 ), 2873 2874 java( 2875 """ 2876 package test.pkg; 2877 /** @hide */ 2878 @SuppressWarnings("UnnecessaryInterfaceModifier") 2879 public interface MyInterface { 2880 public static final String MY_CONSTANT = "5"; 2881 } 2882 """ 2883 ) 2884 ), 2885 privateApi = """ 2886 package test.pkg { 2887 public class Class1 implements test.pkg.MyInterface { 2888 ctor Class1(int); 2889 method public void method1(); 2890 method void method2(); 2891 method private void method3(); 2892 method void myVarargsMethod(int, java.lang.String...); 2893 field int field3; 2894 field float[][] field4; 2895 field long[] field5; 2896 field private int field6; 2897 } 2898 class Class2 { 2899 ctor Class2(); 2900 method public void method4(); 2901 } 2902 private class Class2.Class3 { 2903 ctor private Class2.Class3(); 2904 method public void method5(); 2905 } 2906 class Class4 { 2907 ctor Class4(); 2908 method public void method5(); 2909 } 2910 public abstract interface MyInterface { 2911 field public static final java.lang.String MY_CONSTANT = "5"; 2912 } 2913 } 2914 """, 2915 privateDexApi = """ 2916 Ltest/pkg/Class1;-><init>(I)V 2917 Ltest/pkg/Class1;->method1()V 2918 Ltest/pkg/Class1;->method2()V 2919 Ltest/pkg/Class1;->method3()V 2920 Ltest/pkg/Class1;->myVarargsMethod(I[Ljava/lang/String;)V 2921 Ltest/pkg/Class1;->field3:I 2922 Ltest/pkg/Class1;->field4:[[F 2923 Ltest/pkg/Class1;->field5:[J 2924 Ltest/pkg/Class1;->field6:I 2925 Ltest/pkg/Class2; 2926 Ltest/pkg/Class2;-><init>()V 2927 Ltest/pkg/Class2;->method4()V 2928 Ltest/pkg/Class2${"$"}Class3; 2929 Ltest/pkg/Class2${"$"}Class3;-><init>()V 2930 Ltest/pkg/Class2${"$"}Class3;->method5()V 2931 Ltest/pkg/Class4; 2932 Ltest/pkg/Class4;-><init>()V 2933 Ltest/pkg/Class4;->method5()V 2934 Ltest/pkg/MyInterface; 2935 Ltest/pkg/MyInterface;->MY_CONSTANT:Ljava/lang/String; 2936 """ 2937 ) 2938 } 2939 2940 @Test Private API signature corner casesnull2941 fun `Private API signature corner cases`() { 2942 // Some corner case scenarios exposed by differences in output from doclava and metalava 2943 check( 2944 checkDoclava1 = false, 2945 sourceFiles = *arrayOf( 2946 java( 2947 """ 2948 package test.pkg; 2949 import android.os.Parcel; 2950 import android.os.Parcelable; 2951 import java.util.concurrent.FutureTask; 2952 2953 public class Class1 extends PrivateParent implements MyInterface { 2954 Class1(int arg) { } 2955 2956 @Override public String toString() { 2957 return "Class1"; 2958 } 2959 2960 private abstract class AmsTask extends FutureTask<String> { 2961 @Override 2962 protected void set(String bundle) { 2963 super.set(bundle); 2964 } 2965 } 2966 2967 /** @hide */ 2968 public abstract static class TouchPoint implements Parcelable { 2969 } 2970 } 2971 """ 2972 ), 2973 2974 java( 2975 """ 2976 package test.pkg; 2977 class PrivateParent { 2978 final String getValue() { 2979 return ""; 2980 } 2981 } 2982 """ 2983 ), 2984 2985 java( 2986 """ 2987 package test.pkg; 2988 /** @hide */ 2989 public enum MyEnum { 2990 FOO, BAR 2991 } 2992 """ 2993 ), 2994 2995 java( 2996 """ 2997 package test.pkg; 2998 @SuppressWarnings("UnnecessaryInterfaceModifier") 2999 public interface MyInterface { 3000 public static final String MY_CONSTANT = "5"; 3001 } 3002 """ 3003 ) 3004 ), 3005 privateApi = """ 3006 package test.pkg { 3007 public class Class1 extends test.pkg.PrivateParent implements test.pkg.MyInterface { 3008 ctor Class1(int); 3009 } 3010 private abstract class Class1.AmsTask extends java.util.concurrent.FutureTask { 3011 } 3012 public static abstract class Class1.TouchPoint implements android.os.Parcelable { 3013 ctor public Class1.TouchPoint(); 3014 } 3015 public final class MyEnum extends java.lang.Enum { 3016 ctor private MyEnum(); 3017 enum_constant public static final test.pkg.MyEnum BAR; 3018 enum_constant public static final test.pkg.MyEnum FOO; 3019 } 3020 class PrivateParent { 3021 ctor PrivateParent(); 3022 method final java.lang.String getValue(); 3023 } 3024 } 3025 """, 3026 privateDexApi = """ 3027 Ltest/pkg/Class1;-><init>(I)V 3028 Ltest/pkg/Class1${"$"}AmsTask; 3029 Ltest/pkg/Class1${"$"}TouchPoint; 3030 Ltest/pkg/Class1${"$"}TouchPoint;-><init>()V 3031 Ltest/pkg/MyEnum; 3032 Ltest/pkg/MyEnum;-><init>()V 3033 Ltest/pkg/MyEnum;->valueOf(Ljava/lang/String;)Ltest/pkg/MyEnum; 3034 Ltest/pkg/MyEnum;->values()[Ltest/pkg/MyEnum; 3035 Ltest/pkg/MyEnum;->BAR:Ltest/pkg/MyEnum; 3036 Ltest/pkg/MyEnum;->FOO:Ltest/pkg/MyEnum; 3037 Ltest/pkg/PrivateParent; 3038 Ltest/pkg/PrivateParent;-><init>()V 3039 Ltest/pkg/PrivateParent;->getValue()Ljava/lang/String; 3040 """ 3041 ) 3042 } 3043 3044 @Test Extend from multiple interfacesnull3045 fun `Extend from multiple interfaces`() { 3046 // Real-world example: XmlResourceParser 3047 check( 3048 checkDoclava1 = true, 3049 checkCompilation = true, 3050 sourceFiles = *arrayOf( 3051 java( 3052 """ 3053 package android.content.res; 3054 import android.util.AttributeSet; 3055 import org.xmlpull.v1.XmlPullParser; 3056 import my.AutoCloseable; 3057 3058 @SuppressWarnings("UnnecessaryInterfaceModifier") 3059 public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable { 3060 public void close(); 3061 } 3062 """ 3063 ), 3064 java( 3065 """ 3066 package android.util; 3067 @SuppressWarnings("WeakerAccess") 3068 public interface AttributeSet { 3069 } 3070 """ 3071 ), 3072 java( 3073 """ 3074 package my; 3075 public interface AutoCloseable { 3076 } 3077 """ 3078 ), 3079 java( 3080 """ 3081 package org.xmlpull.v1; 3082 @SuppressWarnings("WeakerAccess") 3083 public interface XmlPullParser { 3084 } 3085 """ 3086 ) 3087 ), 3088 api = """ 3089 package android.content.res { 3090 public abstract interface XmlResourceParser implements android.util.AttributeSet my.AutoCloseable org.xmlpull.v1.XmlPullParser { 3091 method public abstract void close(); 3092 } 3093 } 3094 package android.util { 3095 public abstract interface AttributeSet { 3096 } 3097 } 3098 package my { 3099 public abstract interface AutoCloseable { 3100 } 3101 } 3102 package org.xmlpull.v1 { 3103 public abstract interface XmlPullParser { 3104 } 3105 } 3106 """ 3107 ) 3108 } 3109 3110 @Test Test KDoc suppressnull3111 fun `Test KDoc suppress`() { 3112 // Basic class; also checks that default constructor is made explicit 3113 check( 3114 sourceFiles = *arrayOf( 3115 java( 3116 """ 3117 package test.pkg; 3118 public class Foo { 3119 private Foo() { } 3120 /** @suppress */ 3121 public void hidden() { 3122 } 3123 } 3124 """ 3125 ), 3126 java( 3127 """ 3128 package test.pkg; 3129 /** 3130 * Some comment. 3131 * @suppress 3132 */ 3133 public class Hidden { 3134 private Hidden() { } 3135 public void hidden() { 3136 } 3137 public class Inner { 3138 } 3139 } 3140 """ 3141 ) 3142 ), 3143 api = """ 3144 package test.pkg { 3145 public class Foo { 3146 } 3147 } 3148 """, 3149 checkDoclava1 = false // doclava is unaware of @suppress 3150 ) 3151 } 3152 3153 @Test Check skipping implicit final or deprecated overridenull3154 fun `Check skipping implicit final or deprecated override`() { 3155 // Regression test for 122358225 3156 check( 3157 compatibilityMode = false, 3158 sourceFiles = *arrayOf( 3159 java( 3160 """ 3161 package test.pkg; 3162 3163 public class Parent { 3164 public void foo1() { } 3165 public void foo2() { } 3166 public void foo3() { } 3167 public void foo4() { } 3168 } 3169 """ 3170 ), 3171 java( 3172 """ 3173 package test.pkg; 3174 3175 public final class Child1 extends Parent { 3176 private Child1() { } 3177 public final void foo1() { } 3178 public void foo2() { } 3179 } 3180 """ 3181 ), 3182 java( 3183 """ 3184 package test.pkg; 3185 3186 /** @deprecated */ 3187 @Deprecated 3188 public final class Child2 extends Parent { 3189 private Child2() { } 3190 /** @deprecated */ 3191 @Deprecated 3192 public void foo3() { } 3193 public void foo4() { } 3194 } 3195 """ 3196 ), 3197 java( 3198 """ 3199 package test.pkg; 3200 3201 /** @deprecated */ 3202 @Deprecated 3203 public final class Child3 extends Parent { 3204 private Child3() { } 3205 public final void foo1() { } 3206 public void foo2() { } 3207 /** @deprecated */ 3208 @Deprecated 3209 public void foo3() { } 3210 /** @deprecated */ 3211 @Deprecated 3212 public final void foo4() { } 3213 } 3214 """ 3215 ) 3216 ), 3217 api = """ 3218 package test.pkg { 3219 public final class Child1 extends test.pkg.Parent { 3220 } 3221 @Deprecated public final class Child2 extends test.pkg.Parent { 3222 } 3223 @Deprecated public final class Child3 extends test.pkg.Parent { 3224 } 3225 public class Parent { 3226 ctor public Parent(); 3227 method public void foo1(); 3228 method public void foo2(); 3229 method public void foo3(); 3230 method public void foo4(); 3231 } 3232 } 3233 """ 3234 ) 3235 } 3236 3237 @Test Ignore synchronized differencesnull3238 fun `Ignore synchronized differences`() { 3239 check( 3240 compatibilityMode = false, 3241 sourceFiles = *arrayOf( 3242 java( 3243 """ 3244 package test.pkg2; 3245 3246 public class Parent { 3247 public void foo1() { } 3248 public synchronized void foo2() { } 3249 } 3250 """ 3251 ), 3252 java( 3253 """ 3254 package test.pkg2; 3255 3256 public class Child1 extends Parent { 3257 private Child1() { } 3258 public synchronized void foo1() { } 3259 public void foo2() { } 3260 } 3261 """ 3262 ) 3263 ), 3264 api = """ 3265 package test.pkg2 { 3266 public class Child1 extends test.pkg2.Parent { 3267 } 3268 public class Parent { 3269 ctor public Parent(); 3270 method public void foo1(); 3271 method public void foo2(); 3272 } 3273 } 3274 """ 3275 ) 3276 } 3277 3278 @Test Skip incorrect inheritnull3279 fun `Skip incorrect inherit`() { 3280 check( 3281 // Simulate test-mock scenario for getIContentProvider 3282 extraArguments = arrayOf("--stub-packages", "android.test.mock"), 3283 compatibilityMode = false, 3284 warnings = "src/android/test/mock/MockContentProvider.java:6: warning: Public class android.test.mock.MockContentProvider stripped of unavailable superclass android.content.ContentProvider [HiddenSuperclass]", 3285 sourceFiles = *arrayOf( 3286 java( 3287 """ 3288 package android.test.mock; 3289 3290 import android.content.ContentProvider; 3291 import android.content.IContentProvider; 3292 3293 public abstract class MockContentProvider extends ContentProvider { 3294 /** 3295 * Returns IContentProvider which calls back same methods in this class. 3296 * By overriding this class, we avoid the mechanism hidden behind ContentProvider 3297 * (IPC, etc.) 3298 * 3299 * @hide 3300 */ 3301 @Override 3302 public final IContentProvider getIContentProvider() { 3303 return mIContentProvider; 3304 } 3305 } 3306 """ 3307 ), 3308 java( 3309 """ 3310 package android.content; 3311 3312 /** @hide */ 3313 public abstract class ContentProvider { 3314 protected boolean isTemporary() { 3315 return false; 3316 } 3317 3318 // This is supposed to be @hide, but in turbine-combined/framework.jar included 3319 // by java_sdk_library like test-mock, it's not; this is what the special 3320 // flag is used to test 3321 public IContentProvider getIContentProvider() { 3322 return null; 3323 } 3324 } 3325 """ 3326 ), 3327 java( 3328 """ 3329 package android.content; 3330 import android.os.IInterface; 3331 3332 /** 3333 * The ipc interface to talk to a content provider. 3334 * @hide 3335 */ 3336 public interface IContentProvider extends IInterface { 3337 } 3338 """ 3339 ), 3340 java( 3341 """ 3342 package android.content; 3343 3344 // Not hidden. Here to make sure that we respect stub-packages 3345 // and exclude it from everything, including signatures. 3346 public class ClipData { 3347 } 3348 """ 3349 ) 3350 ), 3351 api = """ 3352 package android.test.mock { 3353 public abstract class MockContentProvider { 3354 ctor public MockContentProvider(); 3355 } 3356 } 3357 """ 3358 ) 3359 } 3360 3361 @Test Test Visible For Testingnull3362 fun `Test Visible For Testing`() { 3363 // Use the otherwise= visibility in signatures 3364 // Regression test for issue 118763806 3365 check( 3366 sourceFiles = *arrayOf( 3367 java( 3368 """ 3369 package test.pkg; 3370 import androidx.annotation.VisibleForTesting; 3371 3372 @SuppressWarnings({"ClassNameDiffersFromFileName", "WeakerAccess"}) 3373 public class ProductionCodeJava { 3374 private ProductionCodeJava() { } 3375 3376 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 3377 public void shouldBeProtected() { 3378 } 3379 3380 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 3381 protected void shouldBePrivate1() { 3382 } 3383 3384 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 3385 public void shouldBePrivate2() { 3386 } 3387 3388 @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) 3389 public void shouldBePackagePrivate() { 3390 } 3391 3392 @VisibleForTesting(otherwise = VisibleForTesting.NONE) 3393 public void shouldBeHidden() { 3394 } 3395 } 3396 """ 3397 ).indented(), 3398 kotlin( 3399 """ 3400 package test.pkg 3401 import androidx.annotation.VisibleForTesting 3402 3403 open class ProductionCodeKotlin private constructor() { 3404 3405 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 3406 fun shouldBeProtected() { 3407 } 3408 3409 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 3410 protected fun shouldBePrivate1() { 3411 } 3412 3413 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 3414 fun shouldBePrivate2() { 3415 } 3416 3417 @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) 3418 fun shouldBePackagePrivate() { 3419 } 3420 3421 @VisibleForTesting(otherwise = VisibleForTesting.NONE) 3422 fun shouldBeHidden() { 3423 } 3424 } 3425 """ 3426 ).indented(), 3427 visibleForTestingSource 3428 ), 3429 api = """ 3430 package test.pkg { 3431 public class ProductionCodeJava { 3432 method protected void shouldBeProtected(); 3433 } 3434 public class ProductionCodeKotlin { 3435 method protected final void shouldBeProtected(); 3436 } 3437 } 3438 """, 3439 extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation") 3440 ) 3441 } 3442 3443 @Test References Deprecatednull3444 fun `References Deprecated`() { 3445 check( 3446 extraArguments = arrayOf( 3447 ARG_ERROR, "ReferencesDeprecated", 3448 ARG_ERROR, "ExtendsDeprecated" 3449 ), 3450 warnings = """ 3451 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] 3452 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] 3453 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] 3454 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] 3455 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] 3456 """, 3457 sourceFiles = *arrayOf( 3458 java( 3459 """ 3460 package test.pkg; 3461 /** @deprecated */ 3462 @Deprecated 3463 public class DeprecatedClass { 3464 } 3465 """ 3466 ), 3467 java( 3468 """ 3469 package test.pkg; 3470 /** @deprecated */ 3471 @Deprecated 3472 public interface DeprecatedInterface { 3473 } 3474 """ 3475 ), 3476 java( 3477 """ 3478 package test.pkg; 3479 public class MyClass extends DeprecatedClass implements DeprecatedInterface { 3480 public void method1(DeprecatedClass p, int i) { } 3481 public DeprecatedInterface method2(int i) { return null; } 3482 3483 /** @deprecated */ 3484 @Deprecated 3485 public void method3(DeprecatedClass p, int i) { } 3486 } 3487 """ 3488 ) 3489 ) 3490 ) 3491 } 3492 3493 @Test v3 format for qualified references in typesnull3494 fun `v3 format for qualified references in types`() { 3495 check( 3496 format = FileFormat.V3, 3497 sourceFiles = *arrayOf( 3498 java( 3499 """ 3500 package androidx.appcompat.app; 3501 import android.view.View; 3502 import android.view.View.OnClickListener; 3503 3504 public class ActionBarDrawerToggle { 3505 private ActionBarDrawerToggle() { } 3506 public View.OnClickListener getToolbarNavigationClickListener1() { 3507 return null; 3508 } 3509 public OnClickListener getToolbarNavigationClickListener2() { 3510 return null; 3511 } 3512 public android.view.View.OnClickListener getToolbarNavigationClickListener3() { 3513 return null; 3514 } 3515 } 3516 """ 3517 ) 3518 ), 3519 api = """ 3520 // Signature format: 3.0 3521 package androidx.appcompat.app { 3522 public class ActionBarDrawerToggle { 3523 method public android.view.View.OnClickListener! getToolbarNavigationClickListener1(); 3524 method public android.view.View.OnClickListener! getToolbarNavigationClickListener2(); 3525 method public android.view.View.OnClickListener! getToolbarNavigationClickListener3(); 3526 } 3527 } 3528 """ 3529 ) 3530 } 3531 } 3532