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