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