• 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
Check generic type signature insertionnull2290     fun `Check generic type signature insertion`() {
2291         check(
2292             format = FileFormat.V2,
2293             sourceFiles = arrayOf(
2294                 java(
2295                     """
2296                     package test.pkg;
2297                     public class MyClass {
2298                         public <T> MyClass(Class<T> klass) { }
2299                         public <U> void method1(Function<U> func) { }
2300                     }
2301                     """
2302                 )
2303             ),
2304             expectedIssues = "",
2305             api = """
2306                     package test.pkg {
2307                       public class MyClass {
2308                         ctor public <T> MyClass(Class<T>);
2309                         method public <U> void method1(Function<U>);
2310                       }
2311                     }
2312             """
2313         )
2314     }
2315 
2316     @Test
When implementing rather than extending package private class, inline members insteadnull2317     fun `When implementing rather than extending package private class, inline members instead`() {
2318         // If you implement a package private interface, we just remove it and inline the members into
2319         // the subclass
2320         check(
2321             sourceFiles = arrayOf(
2322                 java(
2323                     """
2324                     package test.pkg;
2325                     public class MyClass implements HiddenInterface {
2326                         @Override public void method() { }
2327                         @Override public void other() { }
2328                     }
2329                     """
2330                 ),
2331                 java(
2332                     """
2333                     package test.pkg;
2334                     public interface OtherInterface {
2335                         void other();
2336                     }
2337                     """
2338                 ),
2339                 java(
2340                     """
2341                     package test.pkg;
2342                     interface HiddenInterface extends OtherInterface {
2343                         void method() { }
2344                         String CONSTANT = "MyConstant";
2345                     }
2346                     """
2347                 )
2348             ),
2349             api = """
2350                 package test.pkg {
2351                   public class MyClass implements test.pkg.OtherInterface {
2352                     ctor public MyClass();
2353                     method public void method();
2354                     method public void other();
2355                     field public static final String CONSTANT = "MyConstant";
2356                   }
2357                   public interface OtherInterface {
2358                     method public void other();
2359                   }
2360                 }
2361                 """
2362         )
2363     }
2364 
2365     @Test
Implementing package private classnull2366     fun `Implementing package private class`() {
2367         // Include all the non-hidden public interfaces into the signature
2368 
2369         // BUG: Note that we need to implement the parent
2370         check(
2371             sourceFiles = arrayOf(
2372                 java(
2373                     """
2374                     package test.pkg;
2375                     public class MyClass implements HiddenInterface {
2376                         @Override public void method() { }
2377                         @Override public void other() { }
2378                     }
2379                     """
2380                 ),
2381                 java(
2382                     """
2383                     package test.pkg;
2384                     public interface OtherInterface {
2385                         void other();
2386                     }
2387                     """
2388                 ),
2389                 java(
2390                     """
2391                     package test.pkg;
2392                     interface HiddenInterface extends OtherInterface {
2393                         void method() { }
2394                         String CONSTANT = "MyConstant";
2395                     }
2396                     """
2397                 )
2398             ),
2399             api = """
2400                 package test.pkg {
2401                   public class MyClass implements test.pkg.OtherInterface {
2402                     ctor public MyClass();
2403                     method public void method();
2404                     method public void other();
2405                     field public static final String CONSTANT = "MyConstant";
2406                   }
2407                   public interface OtherInterface {
2408                     method public void other();
2409                   }
2410                 }
2411                 """
2412         )
2413     }
2414 
2415     @Test
Default modifiers should be omittednull2416     fun `Default modifiers should be omitted`() {
2417         // If signatures vary only by the "default" modifier in the interface, don't show it on the implementing
2418         // class
2419         check(
2420             format = FileFormat.V1,
2421             sourceFiles = arrayOf(
2422                 java(
2423                     """
2424                     package test.pkg;
2425 
2426                     public class MyClass implements SuperInterface {
2427                         @Override public void method() {  }
2428                         @Override public void method2() { }
2429                     }
2430                     """
2431                 ),
2432                 java(
2433                     """
2434                     package test.pkg;
2435 
2436                     public interface SuperInterface {
2437                         void method();
2438                         default void method2() {
2439                         }
2440                     }
2441                     """
2442                 )
2443             ),
2444             api = """
2445                 package test.pkg {
2446                   public class MyClass implements test.pkg.SuperInterface {
2447                     ctor public MyClass();
2448                     method public void method();
2449                   }
2450                   public interface SuperInterface {
2451                     method public void method();
2452                     method public default void method2();
2453                   }
2454                 }
2455             """
2456         )
2457     }
2458 
2459     @Test
Override via different throws list should be includednull2460     fun `Override via different throws list should be included`() {
2461         // If a method overrides another but changes the throws list, the overriding
2462         // method must be listed in the subclass. This is observed for example in
2463         // AbstractCursor#finalize, which omits the throws clause from Object's finalize.
2464         check(
2465             sourceFiles = arrayOf(
2466                 java(
2467                     """
2468                     package test.pkg;
2469 
2470                     public abstract class AbstractCursor extends Parent {
2471                         @Override protected void finalize2() {  } // note: not throws Throwable!
2472                     }
2473                     """
2474                 ),
2475                 java(
2476                     """
2477                     package test.pkg;
2478 
2479                     @SuppressWarnings("RedundantThrows")
2480                     public class Parent {
2481                         protected void finalize2() throws Throwable {
2482                         }
2483                     }
2484                     """
2485                 )
2486             ),
2487             api = """
2488                 package test.pkg {
2489                   public abstract class AbstractCursor extends test.pkg.Parent {
2490                     ctor public AbstractCursor();
2491                     method protected void finalize2();
2492                   }
2493                   public class Parent {
2494                     ctor public Parent();
2495                     method protected void finalize2() throws java.lang.Throwable;
2496                   }
2497                 }
2498             """
2499         )
2500     }
2501 
2502     @Test
Implementing interface methodnull2503     fun `Implementing interface method`() {
2504         // If you have a public method that implements an interface method,
2505         // they'll vary in the "abstract" modifier, but it shouldn't be listed on the
2506         // class. This is an issue for example for the ZonedDateTime#getLong method
2507         // implementing the TemporalAccessor#getLong method
2508         check(
2509             format = FileFormat.V1,
2510             sourceFiles = arrayOf(
2511                 java(
2512                     """
2513                     package test.pkg;
2514                     public interface SomeInterface2 {
2515                         @Override default long getLong() {
2516                             return 42;
2517                         }
2518                     }
2519                     """
2520                 ),
2521                 java(
2522                     """
2523                     package test.pkg;
2524                     public class Foo implements SomeInterface2 {
2525                         @Override
2526                         public long getLong() { return 0L; }
2527                     }
2528                     """
2529                 )
2530             ),
2531             api = """
2532             package test.pkg {
2533               public class Foo implements test.pkg.SomeInterface2 {
2534                 ctor public Foo();
2535               }
2536               public interface SomeInterface2 {
2537                 method public default long getLong();
2538               }
2539             }
2540         """
2541         )
2542     }
2543 
2544     @Test
Implementing interface method 2null2545     fun `Implementing interface method 2`() {
2546         check(
2547             format = FileFormat.V1,
2548             sourceFiles = arrayOf(
2549                 java(
2550                     """
2551                     package test.pkg;
2552                     public interface SomeInterface {
2553                         long getLong();
2554                     }
2555                     """
2556                 ),
2557                 java(
2558                     """
2559                     package test.pkg;
2560                     public interface SomeInterface2 {
2561                         @Override default long getLong() {
2562                             return 42;
2563                         }
2564                     }
2565                     """
2566                 ),
2567                 java(
2568                     """
2569                     package test.pkg;
2570                     public class Foo implements SomeInterface, SomeInterface2 {
2571                         @Override
2572                         public long getLong() { return 0L; }
2573                     }
2574                     """
2575                 )
2576             ),
2577             api = """
2578                 package test.pkg {
2579                   public class Foo implements test.pkg.SomeInterface test.pkg.SomeInterface2 {
2580                     ctor public Foo();
2581                   }
2582                   public interface SomeInterface {
2583                     method public long getLong();
2584                   }
2585                   public interface SomeInterface2 {
2586                     method public default long getLong();
2587                   }
2588                 }
2589                 """
2590         )
2591     }
2592 
2593     @Test
Check basic @remove scenariosnull2594     fun `Check basic @remove scenarios`() {
2595         // Test basic @remove handling for methods and fields
2596         check(
2597             sourceFiles = arrayOf(
2598                 java(
2599                     """
2600                     package test.pkg;
2601                     @SuppressWarnings("JavaDoc")
2602                     public class Bar {
2603                         /** @removed */
2604                         public Bar() { }
2605                         public int field;
2606                         public void test() { }
2607                         /** @removed */
2608                         public int removedField;
2609                         /** @removed */
2610                         public void removedMethod() { }
2611                         /** @removed and @hide - should not be listed */
2612                         public int hiddenField;
2613 
2614                         /** @removed */
2615                         public class Inner { }
2616 
2617                         public class Inner2 {
2618                             public class Inner3 {
2619                                 /** @removed */
2620                                 public class Inner4 { }
2621                             }
2622                         }
2623 
2624                         public class Inner5 {
2625                             public class Inner6 {
2626                                 public class Inner7 {
2627                                     /** @removed */
2628                                     public int removed;
2629                                 }
2630                             }
2631                         }
2632                     }
2633                     """
2634                 )
2635             ),
2636             removedApi = """
2637                 package test.pkg {
2638                   public class Bar {
2639                     ctor public Bar();
2640                     method public void removedMethod();
2641                     field public int removedField;
2642                   }
2643                   public class Bar.Inner {
2644                     ctor public Bar.Inner();
2645                   }
2646                   public class Bar.Inner2.Inner3.Inner4 {
2647                     ctor public Bar.Inner2.Inner3.Inner4();
2648                   }
2649                   public class Bar.Inner5.Inner6.Inner7 {
2650                     field public int removed;
2651                   }
2652                 }
2653                 """
2654         )
2655     }
2656 
2657     @Test
Check @remove classnull2658     fun `Check @remove class`() {
2659         // Test removing classes
2660         check(
2661             format = FileFormat.V2,
2662             sourceFiles = arrayOf(
2663                 java(
2664                     """
2665                     package test.pkg;
2666                     /** @removed */
2667                     @SuppressWarnings("JavaDoc")
2668                     public class Foo {
2669                         public void foo() { }
2670                         public class Inner {
2671                         }
2672                     }
2673                     """
2674                 ),
2675                 java(
2676                     """
2677                     package test.pkg;
2678                     @SuppressWarnings("JavaDoc")
2679                     public class Bar implements Parcelable {
2680                         public int field;
2681                         public void method();
2682 
2683                         /** @removed */
2684                         public int removedField;
2685                         /** @removed */
2686                         public void removedMethod() { }
2687 
2688                         public class Inner1 {
2689                         }
2690                         /** @removed */
2691                         public class Inner2 {
2692                         }
2693                     }
2694                     """
2695                 ),
2696                 java(
2697                     """
2698                     package test.pkg;
2699                     @SuppressWarnings("ALL")
2700                     public interface Parcelable {
2701                         void method();
2702                     }
2703                     """
2704                 )
2705             ),
2706             /*
2707             I expected this: but doclava1 doesn't do that (and we now match its behavior)
2708             package test.pkg {
2709               public class Bar {
2710                 method public void removedMethod();
2711                 field public int removedField;
2712               }
2713               public class Bar.Inner2 {
2714               }
2715               public class Foo {
2716                 method public void foo();
2717               }
2718             }
2719              */
2720             removedApi = """
2721                     package test.pkg {
2722                       public class Bar implements test.pkg.Parcelable {
2723                         method public void removedMethod();
2724                         field public int removedField;
2725                       }
2726                       public class Bar.Inner2 {
2727                         ctor public Bar.Inner2();
2728                       }
2729                       public class Foo {
2730                         ctor public Foo();
2731                         method public void foo();
2732                       }
2733                       public class Foo.Inner {
2734                         ctor public Foo.Inner();
2735                       }
2736                     }
2737                 """
2738         )
2739     }
2740 
2741     @Test
Test include overridden @Deprecated even if annotated with @hidenull2742     fun `Test include overridden @Deprecated even if annotated with @hide`() {
2743         check(
2744             format = FileFormat.V1,
2745             sourceFiles = arrayOf(
2746                 java(
2747                     """
2748                     package test.pkg;
2749                     @SuppressWarnings("JavaDoc")
2750                     public class Child extends Parent {
2751                         /**
2752                         * @deprecated
2753                         * @hide
2754                         */
2755                         @Deprecated @Override
2756                         public String toString() {
2757                             return "Child";
2758                         }
2759 
2760                         /**
2761                          * @hide
2762                          */
2763                         public void hiddenApi() {
2764                         }
2765                     }
2766                     """
2767                 ),
2768                 java(
2769                     """
2770                     package test.pkg;
2771                     public class Parent {
2772                         public String toString() {
2773                             return "Parent";
2774                         }
2775                     }
2776                     """
2777                 )
2778             ),
2779             api = """
2780                     package test.pkg {
2781                       public class Child extends test.pkg.Parent {
2782                         ctor public Child();
2783                         method @Deprecated public String toString();
2784                       }
2785                       public class Parent {
2786                         ctor public Parent();
2787                       }
2788                     }
2789                     """,
2790             dexApi = """
2791                 Ltest/pkg/Child;
2792                 Ltest/pkg/Child;-><init>()V
2793                 Ltest/pkg/Child;->toString()Ljava/lang/String;
2794                 Ltest/pkg/Parent;
2795                 Ltest/pkg/Parent;-><init>()V
2796                 Ltest/pkg/Parent;->toString()Ljava/lang/String;
2797             """
2798         )
2799     }
2800 
2801     @Test
Test invalid class namenull2802     fun `Test invalid class name`() {
2803         // Regression test for b/73018978
2804         check(
2805             format = FileFormat.V1,
2806             sourceFiles = arrayOf(
2807                 kotlin(
2808                     "src/test/pkg/Foo.kt",
2809                     """
2810                     @file:JvmName("-Foo")
2811 
2812                     package test.pkg
2813 
2814                     @Suppress("unused")
2815                     inline fun String.printHelloWorld() { println("Hello World") }
2816                     """
2817                 )
2818             ),
2819             api = """
2820                 package test.pkg {
2821                   public final class -Foo {
2822                     method public static inline void printHelloWorld(@NonNull String);
2823                   }
2824                 }
2825                 """
2826         )
2827     }
2828 
2829     @Test
Indirect Field Includes from Interfacesnull2830     fun `Indirect Field Includes from Interfaces`() {
2831         // Real-world example: include ZipConstants into ZipFile and JarFile
2832         check(
2833             sourceFiles = arrayOf(
2834                 java(
2835                     """
2836                     package test.pkg1;
2837                     interface MyConstants {
2838                         long CONSTANT1 = 12345;
2839                         long CONSTANT2 = 67890;
2840                         long CONSTANT3 = 42;
2841                     }
2842                     """
2843                 ),
2844                 java(
2845                     """
2846                     package test.pkg1;
2847                     import java.io.Closeable;
2848                     @SuppressWarnings("WeakerAccess")
2849                     public class MyParent implements MyConstants, Closeable {
2850                     }
2851                     """
2852                 ),
2853                 java(
2854                     """
2855                     package test.pkg2;
2856 
2857                     import test.pkg1.MyParent;
2858                     public class MyChild extends MyParent {
2859                     }
2860                     """
2861                 )
2862 
2863             ),
2864             api = """
2865                     package test.pkg1 {
2866                       public class MyParent implements java.io.Closeable {
2867                         ctor public MyParent();
2868                         field public static final long CONSTANT1 = 12345L; // 0x3039L
2869                         field public static final long CONSTANT2 = 67890L; // 0x10932L
2870                         field public static final long CONSTANT3 = 42L; // 0x2aL
2871                       }
2872                     }
2873                     package test.pkg2 {
2874                       public class MyChild extends test.pkg1.MyParent {
2875                         ctor public MyChild();
2876                         field public static final long CONSTANT1 = 12345L; // 0x3039L
2877                         field public static final long CONSTANT2 = 67890L; // 0x10932L
2878                         field public static final long CONSTANT3 = 42L; // 0x2aL
2879                       }
2880                     }
2881                 """
2882         )
2883     }
2884 
2885     @Test
Skip interfaces from packages explicitly hidden via argumentsnull2886     fun `Skip interfaces from packages explicitly hidden via arguments`() {
2887         // Real-world example: HttpResponseCache implements OkCacheContainer but hides the only inherited method
2888         check(
2889             extraArguments = arrayOf(
2890                 ARG_HIDE_PACKAGE, "com.squareup.okhttp"
2891             ),
2892             sourceFiles = arrayOf(
2893                 java(
2894                     """
2895                     package android.net.http;
2896                     import com.squareup.okhttp.Cache;
2897                     import com.squareup.okhttp.OkCacheContainer;
2898                     import java.io.Closeable;
2899                     import java.net.ResponseCache;
2900                     @SuppressWarnings("JavaDoc")
2901                     public final class HttpResponseCache implements Closeable, OkCacheContainer {
2902                         /** @hide Needed for OkHttp integration. */
2903                         @Override
2904                         public Cache getCache() {
2905                             return delegate.getCache();
2906                         }
2907                     }
2908                     """
2909                 ),
2910                 java(
2911                     """
2912                     package com.squareup.okhttp;
2913                     public interface OkCacheContainer {
2914                       Cache getCache();
2915                     }
2916                     """
2917                 ),
2918                 java(
2919                     """
2920                     package com.squareup.okhttp;
2921                     public class Cache {
2922                     }
2923                     """
2924                 )
2925             ),
2926             expectedIssues = """
2927                 src/android/net/http/HttpResponseCache.java:7: warning: Public class android.net.http.HttpResponseCache stripped of unavailable superclass com.squareup.okhttp.OkCacheContainer [HiddenSuperclass]
2928             """,
2929             api = """
2930                 package android.net.http {
2931                   public final class HttpResponseCache implements java.io.Closeable {
2932                     ctor public HttpResponseCache();
2933                   }
2934                 }
2935                 """
2936         )
2937     }
2938 
2939     @Test
Extend from multiple interfacesnull2940     fun `Extend from multiple interfaces`() {
2941         // Real-world example: XmlResourceParser
2942         check(
2943             format = FileFormat.V1,
2944             checkCompilation = true,
2945             sourceFiles = arrayOf(
2946                 java(
2947                     """
2948                     package android.content.res;
2949                     import android.util.AttributeSet;
2950                     import org.xmlpull.v1.XmlPullParser;
2951                     import my.AutoCloseable;
2952 
2953                     @SuppressWarnings("UnnecessaryInterfaceModifier")
2954                     public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable {
2955                         public void close();
2956                     }
2957                     """
2958                 ),
2959                 java(
2960                     """
2961                     package android.util;
2962                     @SuppressWarnings("WeakerAccess")
2963                     public interface AttributeSet {
2964                     }
2965                     """
2966                 ),
2967                 java(
2968                     """
2969                     package my;
2970                     public interface AutoCloseable {
2971                     }
2972                     """
2973                 ),
2974                 java(
2975                     """
2976                     package org.xmlpull.v1;
2977                     @SuppressWarnings("WeakerAccess")
2978                     public interface XmlPullParser {
2979                     }
2980                     """
2981                 )
2982             ),
2983             api = """
2984                 package android.content.res {
2985                   public interface XmlResourceParser extends org.xmlpull.v1.XmlPullParser android.util.AttributeSet my.AutoCloseable {
2986                     method public void close();
2987                   }
2988                 }
2989                 package android.util {
2990                   public interface AttributeSet {
2991                   }
2992                 }
2993                 package my {
2994                   public interface AutoCloseable {
2995                   }
2996                 }
2997                 package org.xmlpull.v1 {
2998                   public interface XmlPullParser {
2999                   }
3000                 }
3001                 """
3002         )
3003     }
3004 
3005     @Test
Test KDoc suppressnull3006     fun `Test KDoc suppress`() {
3007         // Basic class; also checks that default constructor is made explicit
3008         check(
3009             sourceFiles = arrayOf(
3010                 java(
3011                     """
3012                     package test.pkg;
3013                     public class Foo {
3014                         private Foo() { }
3015                         /** @suppress */
3016                         public void hidden() {
3017                         }
3018                     }
3019                     """
3020                 ),
3021                 java(
3022                     """
3023                     package test.pkg;
3024                     /**
3025                     * Some comment.
3026                     * @suppress
3027                     */
3028                     public class Hidden {
3029                         private Hidden() { }
3030                         public void hidden() {
3031                         }
3032                         public class Inner {
3033                         }
3034                     }
3035                     """
3036                 )
3037             ),
3038             api = """
3039                     package test.pkg {
3040                       public class Foo {
3041                       }
3042                     }
3043                 """
3044         )
3045     }
3046 
3047     @Test
Check skipping implicit final or deprecated overridenull3048     fun `Check skipping implicit final or deprecated override`() {
3049         // Regression test for 122358225
3050         check(
3051             sourceFiles = arrayOf(
3052                 java(
3053                     """
3054                     package test.pkg;
3055 
3056                     public class Parent {
3057                         public void foo1() { }
3058                         public void foo2() { }
3059                         public void foo3() { }
3060                         public void foo4() { }
3061                     }
3062                     """
3063                 ),
3064                 java(
3065                     """
3066                     package test.pkg;
3067 
3068                     public final class Child1 extends Parent {
3069                         private Child1() { }
3070                         public final void foo1() { }
3071                         public void foo2() { }
3072                     }
3073                     """
3074                 ),
3075                 java(
3076                     """
3077                     package test.pkg;
3078 
3079                     /** @deprecated */
3080                     @Deprecated
3081                     public final class Child2 extends Parent {
3082                         private Child2() { }
3083                         /** @deprecated */
3084                         @Deprecated
3085                         public void foo3() { }
3086                         public void foo4() { }
3087                     }
3088                     """
3089                 ),
3090                 java(
3091                     """
3092                     package test.pkg;
3093 
3094                     /** @deprecated */
3095                     @Deprecated
3096                     public final class Child3 extends Parent {
3097                         private Child3() { }
3098                         public final void foo1() { }
3099                         public void foo2() { }
3100                         /** @deprecated */
3101                         @Deprecated
3102                         public void foo3() { }
3103                         /** @deprecated */
3104                         @Deprecated
3105                         public final void foo4() { }
3106                     }
3107                     """
3108                 )
3109             ),
3110             api = """
3111                 package test.pkg {
3112                   public final class Child1 extends test.pkg.Parent {
3113                   }
3114                   @Deprecated public final class Child2 extends test.pkg.Parent {
3115                   }
3116                   @Deprecated public final class Child3 extends test.pkg.Parent {
3117                   }
3118                   public class Parent {
3119                     ctor public Parent();
3120                     method public void foo1();
3121                     method public void foo2();
3122                     method public void foo3();
3123                     method public void foo4();
3124                   }
3125                 }
3126                 """
3127         )
3128     }
3129 
3130     @Test
Ignore synchronized differencesnull3131     fun `Ignore synchronized differences`() {
3132         check(
3133             sourceFiles = arrayOf(
3134                 java(
3135                     """
3136                     package test.pkg2;
3137 
3138                     public class Parent {
3139                         public void foo1() { }
3140                         public synchronized void foo2() { }
3141                     }
3142                     """
3143                 ),
3144                 java(
3145                     """
3146                     package test.pkg2;
3147 
3148                     public class Child1 extends Parent {
3149                         private Child1() { }
3150                         public synchronized void foo1() { }
3151                         public void foo2() { }
3152                     }
3153                     """
3154                 )
3155             ),
3156             api = """
3157                 package test.pkg2 {
3158                   public class Child1 extends test.pkg2.Parent {
3159                   }
3160                   public class Parent {
3161                     ctor public Parent();
3162                     method public void foo1();
3163                     method public void foo2();
3164                   }
3165                 }
3166                 """
3167         )
3168     }
3169 
3170     @Test
Skip incorrect inheritnull3171     fun `Skip incorrect inherit`() {
3172         check(
3173             // Simulate test-mock scenario for getIContentProvider
3174             extraArguments = arrayOf("--stub-packages", "android.test.mock"),
3175             expectedIssues = "src/android/test/mock/MockContentProvider.java:6: warning: Public class android.test.mock.MockContentProvider stripped of unavailable superclass android.content.ContentProvider [HiddenSuperclass]",
3176             sourceFiles = arrayOf(
3177                 java(
3178                     """
3179                     package android.test.mock;
3180 
3181                     import android.content.ContentProvider;
3182                     import android.content.IContentProvider;
3183 
3184                     public abstract class MockContentProvider extends ContentProvider {
3185                         /**
3186                          * Returns IContentProvider which calls back same methods in this class.
3187                          * By overriding this class, we avoid the mechanism hidden behind ContentProvider
3188                          * (IPC, etc.)
3189                          *
3190                          * @hide
3191                          */
3192                         @Override
3193                         public final IContentProvider getIContentProvider() {
3194                             return mIContentProvider;
3195                         }
3196                     }
3197                     """
3198                 ),
3199                 java(
3200                     """
3201                     package android.content;
3202 
3203                     /** @hide */
3204                     public abstract class ContentProvider {
3205                         protected boolean isTemporary() {
3206                             return false;
3207                         }
3208 
3209                         // This is supposed to be @hide, but in turbine-combined/framework.jar included
3210                         // by java_sdk_library like test-mock, it's not; this is what the special
3211                         // flag is used to test
3212                         public IContentProvider getIContentProvider() {
3213                             return null;
3214                         }
3215                     }
3216                     """
3217                 ),
3218                 java(
3219                     """
3220                     package android.content;
3221                     import android.os.IInterface;
3222 
3223                     /**
3224                      * The ipc interface to talk to a content provider.
3225                      * @hide
3226                      */
3227                     public interface IContentProvider extends IInterface {
3228                     }
3229                     """
3230                 ),
3231                 java(
3232                     """
3233                     package android.content;
3234 
3235                     // Not hidden. Here to make sure that we respect stub-packages
3236                     // and exclude it from everything, including signatures.
3237                     public class ClipData {
3238                     }
3239                     """
3240                 )
3241             ),
3242             api = """
3243                 package android.test.mock {
3244                   public abstract class MockContentProvider {
3245                     ctor public MockContentProvider();
3246                   }
3247                 }
3248                 """
3249         )
3250     }
3251 
3252     @Test
Test Visible For Testingnull3253     fun `Test Visible For Testing`() {
3254         // Use the otherwise= visibility in signatures
3255         // Regression test for issue 118763806
3256         check(
3257             format = FileFormat.V1,
3258             sourceFiles = arrayOf(
3259                 java(
3260                     """
3261                     package test.pkg;
3262                     import androidx.annotation.VisibleForTesting;
3263 
3264                     @SuppressWarnings({"ClassNameDiffersFromFileName", "WeakerAccess"})
3265                     public class ProductionCodeJava {
3266                         private ProductionCodeJava() { }
3267 
3268                         @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
3269                         public void shouldBeProtected() {
3270                         }
3271 
3272                         @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
3273                         protected void shouldBePrivate1() {
3274                         }
3275 
3276                         @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
3277                         public void shouldBePrivate2() {
3278                         }
3279 
3280                         @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
3281                         public void shouldBePackagePrivate() {
3282                         }
3283 
3284                         @VisibleForTesting(otherwise = VisibleForTesting.NONE)
3285                         public void shouldBeHidden() {
3286                         }
3287                     }
3288                     """
3289                 ).indented(),
3290                 kotlin(
3291                     """
3292                     package test.pkg
3293                     import androidx.annotation.VisibleForTesting
3294 
3295                     open class ProductionCodeKotlin private constructor() {
3296 
3297                         @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
3298                         fun shouldBeProtected() {
3299                         }
3300 
3301                         @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
3302                         protected fun shouldBePrivate1() {
3303                         }
3304 
3305                         @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
3306                         fun shouldBePrivate2() {
3307                         }
3308 
3309                         @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
3310                         fun shouldBePackagePrivate() {
3311                         }
3312 
3313                         @VisibleForTesting(otherwise = VisibleForTesting.NONE)
3314                         fun shouldBeHidden() {
3315                         }
3316                     }
3317                     """
3318                 ).indented(),
3319                 visibleForTestingSource
3320             ),
3321             api = """
3322                 package test.pkg {
3323                   public class ProductionCodeJava {
3324                     method @VisibleForTesting(otherwise=androidx.annotation.VisibleForTesting.PROTECTED) protected void shouldBeProtected();
3325                   }
3326                   public class ProductionCodeKotlin {
3327                     method @VisibleForTesting(otherwise=androidx.annotation.VisibleForTesting.PROTECTED) protected final void shouldBeProtected();
3328                   }
3329                 }
3330                 """,
3331             extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation")
3332         )
3333     }
3334 
3335     @Test
References Deprecatednull3336     fun `References Deprecated`() {
3337         check(
3338             extraArguments = arrayOf(
3339                 ARG_ERROR, "ReferencesDeprecated",
3340                 ARG_ERROR, "ExtendsDeprecated"
3341             ),
3342             expectedIssues = """
3343             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]
3344             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]
3345             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]
3346             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]
3347             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]
3348             """,
3349             sourceFiles = arrayOf(
3350                 java(
3351                     """
3352                     package test.pkg;
3353                     /** @deprecated */
3354                     @Deprecated
3355                     public class DeprecatedClass {
3356                     }
3357                     """
3358                 ),
3359                 java(
3360                     """
3361                     package test.pkg;
3362                     /** @deprecated */
3363                     @Deprecated
3364                     public interface DeprecatedInterface {
3365                     }
3366                     """
3367                 ),
3368                 java(
3369                     """
3370                     package test.pkg;
3371                     public class MyClass extends DeprecatedClass implements DeprecatedInterface {
3372                         public void method1(DeprecatedClass p, int i) { }
3373                         public DeprecatedInterface method2(int i) { return null; }
3374 
3375                         /** @deprecated */
3376                         @Deprecated
3377                         public void method3(DeprecatedClass p, int i) { }
3378                     }
3379                     """
3380                 )
3381             )
3382         )
3383     }
3384 
3385     @Test
v3 format for qualified references in typesnull3386     fun `v3 format for qualified references in types`() {
3387         check(
3388             format = FileFormat.V3,
3389             sourceFiles = arrayOf(
3390                 java(
3391                     """
3392                     package androidx.appcompat.app;
3393                     import android.view.View;
3394                     import android.view.View.OnClickListener;
3395 
3396                     public class ActionBarDrawerToggle {
3397                         private ActionBarDrawerToggle() { }
3398                         public View.OnClickListener getToolbarNavigationClickListener1() {
3399                             return null;
3400                         }
3401                         public OnClickListener getToolbarNavigationClickListener2() {
3402                             return null;
3403                         }
3404                         public android.view.View.OnClickListener getToolbarNavigationClickListener3() {
3405                             return null;
3406                         }
3407                     }
3408                     """
3409                 )
3410             ),
3411             api = """
3412                 // Signature format: 3.0
3413                 package androidx.appcompat.app {
3414                   public class ActionBarDrawerToggle {
3415                     method public android.view.View.OnClickListener! getToolbarNavigationClickListener1();
3416                     method public android.view.View.OnClickListener! getToolbarNavigationClickListener2();
3417                     method public android.view.View.OnClickListener! getToolbarNavigationClickListener3();
3418                   }
3419                 }
3420                 """
3421         )
3422     }
3423 
3424     @Test
FooKt class constructors are not publicnull3425     fun `FooKt class constructors are not public`() {
3426         check(
3427             format = FileFormat.V3,
3428             sourceFiles = arrayOf(
3429                 kotlin(
3430                     "src/main/java/test/pkg/Foo.kt",
3431                     """
3432                     package test.pkg
3433                     fun myCall() : Boolean = false
3434                     class Bar
3435                     """
3436                 )
3437             ),
3438             api = """
3439                 // Signature format: 3.0
3440                 package test.pkg {
3441                   public final class Bar {
3442                     ctor public Bar();
3443                   }
3444                   public final class FooKt {
3445                     method public static boolean myCall();
3446                   }
3447                 }
3448                 """
3449         )
3450     }
3451 
3452     @Test
Test inherited hidden methods for descendant classes - Package privatenull3453     fun `Test inherited hidden methods for descendant classes - Package private`() {
3454         check(
3455             sourceFiles = arrayOf(
3456                 java(
3457                     """
3458                     package test.pkg;
3459                     public class Class4 extends Class3 {
3460                         public void method4() { }
3461                     }
3462                     """
3463                 ),
3464                 java(
3465                     """
3466                     package test.pkg;
3467                     public class Class3 extends Class2 {
3468                         public void method3() { }
3469                     }
3470                     """
3471                 ),
3472                 java(
3473                     """
3474                     package test.pkg;
3475                     class Class2 extends Class1 {
3476                         public void method2() { }
3477                     }
3478                     """
3479                 ),
3480                 java(
3481                     """
3482                     package test.pkg;
3483                     public class Class1 {
3484                         public void method1() { }
3485                     }
3486                     """
3487                 )
3488             ),
3489             expectedIssues = "",
3490             api =
3491             """
3492                 package test.pkg {
3493                   public class Class1 {
3494                     ctor public Class1();
3495                     method public void method1();
3496                   }
3497                   public class Class3 extends test.pkg.Class1 {
3498                     ctor public Class3();
3499                     method public void method2();
3500                     method public void method3();
3501                   }
3502                   public class Class4 extends test.pkg.Class3 {
3503                     ctor public Class4();
3504                     method public void method4();
3505                   }
3506                 }
3507                 """
3508         )
3509     }
3510 
3511     @Test
Test inherited hidden methods for descendant classes - Hidden annotationnull3512     fun `Test inherited hidden methods for descendant classes - Hidden annotation`() {
3513         check(
3514             sourceFiles = arrayOf(
3515                 java(
3516                     """
3517                     package test.pkg;
3518                     public class Class4 extends Class3 {
3519                         public void method4() { }
3520                     }
3521                     """
3522                 ),
3523                 java(
3524                     """
3525                     package test.pkg;
3526                     public class Class3 extends Class2 {
3527                         public void method3() { }
3528                     }
3529                     """
3530                 ),
3531                 java(
3532                     """
3533                     package test.pkg;
3534                     /** @hide */
3535                     public class Class2 extends Class1 {
3536                         public void method2() { }
3537                     }
3538                     """
3539                 ),
3540                 java(
3541                     """
3542                     package test.pkg;
3543                     public class Class1 {
3544                         public void method1() { }
3545                     }
3546                     """
3547                 )
3548             ),
3549             expectedIssues = "src/test/pkg/Class3.java:2: warning: Public class test.pkg.Class3 stripped of unavailable superclass test.pkg.Class2 [HiddenSuperclass]",
3550             api =
3551             """
3552                 package test.pkg {
3553                   public class Class1 {
3554                     ctor public Class1();
3555                     method public void method1();
3556                   }
3557                   public class Class3 extends test.pkg.Class1 {
3558                     ctor public Class3();
3559                     method public void method2();
3560                     method public void method3();
3561                   }
3562                   public class Class4 extends test.pkg.Class3 {
3563                     ctor public Class4();
3564                     method public void method4();
3565                   }
3566                 }
3567                 """
3568 
3569         )
3570     }
3571 
3572     @Test
Test inherited methods that use genericsnull3573     fun `Test inherited methods that use generics`() {
3574         check(
3575             format = FileFormat.V2,
3576             sourceFiles = arrayOf(
3577                 java(
3578                     """
3579                     package test.pkg;
3580                     import androidx.annotation.NonNull;
3581                     public class Class2 extends Class1<String> {
3582                         @Override
3583                         public void method1(String input) { }
3584                         @Override
3585                         public void method2(@NonNull String input) { }
3586                     }
3587                     """
3588                 ),
3589                 java(
3590                     """
3591                     package test.pkg;
3592                     import androidx.annotation.NonNull;
3593                     class Class1<T> {
3594                         public void method1(T input) { }
3595                         public void method2(T input) { }
3596                         public void method3(T input) { }
3597                         @NonNull
3598                         public String method4(T input) { return ""; }
3599                         public T method5(@NonNull String input) { return null; }
3600                     }
3601                     """
3602                 ),
3603                 androidxNonNullSource
3604             ),
3605             extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"),
3606             expectedIssues = "",
3607             api =
3608             """
3609                 package test.pkg {
3610                   public class Class2 {
3611                     ctor public Class2();
3612                     method public void method1(String);
3613                     method public void method2(@NonNull String);
3614                     method public void method3(String);
3615                     method @NonNull public String method4(String);
3616                     method public String method5(@NonNull String);
3617                   }
3618                 }
3619                 """
3620 
3621         )
3622     }
3623 
3624     @Test
Test merging API signature filesnull3625     fun `Test merging API signature files`() {
3626         val source1 = """
3627             package Test.pkg {
3628               public final class Class1 {
3629                 method public void method1();
3630               }
3631             }
3632             package Test.pkg1 {
3633               public final class Class1 {
3634                 method public void method1();
3635               }
3636             }
3637                     """
3638         val source2 = """
3639             package Test.pkg {
3640               public final class Class2 {
3641                 method public void method1(String);
3642               }
3643             }
3644             package Test.pkg2 {
3645               public final class Class1 {
3646                 method public void method1(String, String);
3647               }
3648             }
3649                     """
3650         val expected = """
3651             package Test.pkg {
3652               public final class Class1 {
3653                 method public void method1();
3654               }
3655               public final class Class2 {
3656                 method public void method1(String);
3657               }
3658             }
3659             package Test.pkg1 {
3660               public final class Class1 {
3661                 method public void method1();
3662               }
3663             }
3664             package Test.pkg2 {
3665               public final class Class1 {
3666                 method public void method1(String, String);
3667               }
3668             }
3669                     """
3670         check(
3671             format = FileFormat.V1,
3672             signatureSources = arrayOf(source1, source2),
3673             api = expected
3674         )
3675     }
3676 
3677     val MERGE_TEST_SOURCE_1 = """
3678             package test.pkg {
3679               public final class BaseClass {
3680                 method public void method1();
3681               }
3682             }
3683                     """
3684     val MERGE_TEST_SOURCE_2 = """
3685             package test.pkg {
3686               public final class SubClass extends test.pkg.BaseClass {
3687               }
3688             }
3689                     """
3690     val MERGE_TEST_EXPECTED = """
3691             package test.pkg {
3692               public final class BaseClass {
3693                 method public void method1();
3694               }
3695               public final class SubClass extends test.pkg.BaseClass {
3696               }
3697             }
3698             """
3699 
3700     @Test
Test merging API signature files, one refer to anothernull3701     fun `Test merging API signature files, one refer to another`() {
3702         check(
3703             signatureSources = arrayOf(MERGE_TEST_SOURCE_1, MERGE_TEST_SOURCE_2),
3704             api = MERGE_TEST_EXPECTED
3705         )
3706     }
3707 
3708     @Test
Test merging API signature files, one refer to another, in reverse ordernull3709     fun `Test merging API signature files, one refer to another, in reverse order`() {
3710         // Exactly the same as the previous test, but read them in the reverse order
3711         check(
3712             signatureSources = arrayOf(MERGE_TEST_SOURCE_2, MERGE_TEST_SOURCE_1),
3713             api = MERGE_TEST_EXPECTED
3714         )
3715     }
3716 
3717     @Test
Test merging API signature files with reverse dependencynull3718     fun `Test merging API signature files with reverse dependency`() {
3719         val source1 = """
3720             package test.pkg {
3721               public final class Class1 {
3722                 method public void method1(test.pkg.Class2 arg);
3723               }
3724             }
3725                     """
3726         val source2 = """
3727             package test.pkg {
3728               public final class Class2 {
3729               }
3730             }
3731                     """
3732         val expected = """
3733             package test.pkg {
3734               public final class Class1 {
3735                 method public void method1(test.pkg.Class2 arg);
3736               }
3737               public final class Class2 {
3738               }
3739             }
3740                     """
3741         check(
3742             format = FileFormat.V1,
3743             signatureSources = arrayOf(source1, source2),
3744             api = expected
3745         )
3746     }
3747 
3748     @Test
Test merging 3 API signature filesnull3749     fun `Test merging 3 API signature files`() {
3750         val source1 = """
3751             package test.pkg1 {
3752               public final class BaseClass1 {
3753                 method public void method1();
3754               }
3755 
3756               public final class AnotherSubClass extends test.pkg2.AnotherBase {
3757                 method public void method1();
3758               }
3759             }
3760                     """
3761         val source2 = """
3762             package test.pkg2 {
3763               public final class SubClass1 extends test.pkg1.BaseClass1 {
3764               }
3765             }
3766                     """
3767         val source3 = """
3768             package test.pkg2 {
3769               public final class SubClass2 extends test.pkg2.SubClass1 {
3770                 method public void bar();
3771               }
3772 
3773               public final class AnotherBase {
3774                 method public void baz();
3775               }
3776             }
3777                     """
3778         val expected = """
3779             package test.pkg1 {
3780               public final class AnotherSubClass extends test.pkg2.AnotherBase {
3781                 method public void method1();
3782               }
3783               public final class BaseClass1 {
3784                 method public void method1();
3785               }
3786             }
3787             package test.pkg2 {
3788               public final class AnotherBase {
3789                 method public void baz();
3790               }
3791               public final class SubClass1 extends test.pkg1.BaseClass1 {
3792               }
3793               public final class SubClass2 extends test.pkg2.SubClass1 {
3794                 method public void bar();
3795               }
3796             }
3797                     """
3798         check(
3799             signatureSources = arrayOf(source1, source2, source3),
3800             api = expected
3801         )
3802     }
3803 
3804     @Test
Test can merge API signature files with duplicate classnull3805     fun `Test can merge API signature files with duplicate class`() {
3806         val source1 = """
3807             package Test.pkg {
3808               public final class Class1 {
3809                 method public void method1();
3810               }
3811             }
3812                     """
3813         val source2 = """
3814             package Test.pkg {
3815               public final class Class1 {
3816                 method public void method1();
3817               }
3818             }
3819                     """
3820         val expected = """
3821             package Test.pkg {
3822               public final class Class1 {
3823                 method public void method1();
3824               }
3825             }
3826                     """
3827         check(
3828             signatureSources = arrayOf(source1, source2),
3829             api = expected
3830         )
3831     }
3832 
3833     @Test
Test cannot merge API signature files with incompatible class definitionsnull3834     fun `Test cannot merge API signature files with incompatible class definitions`() {
3835         val source1 = """
3836             package Test.pkg {
3837               public class Class1 {
3838                 method public void method2();
3839               }
3840             }
3841                     """
3842         val source2 = """
3843             package Test.pkg {
3844               public final class Class1 {
3845                 method public void method1();
3846               }
3847             }
3848                     """
3849         check(
3850             signatureSources = arrayOf(source1, source2),
3851             expectedFail = "Aborting: Unable to parse signature file: Incompatible class Test.pkg.Class1 definitions"
3852         )
3853     }
3854 
3855     @Test
Test cannot merging API signature files with different file formatsnull3856     fun `Test cannot merging API signature files with different file formats`() {
3857         val source1 = """
3858             // Signature format: 2.0
3859             package Test.pkg {
3860             }
3861                     """
3862         val source2 = """
3863             // Signature format: 3.0
3864             package Test.pkg {
3865             }
3866                     """
3867         check(
3868             signatureSources = arrayOf(source1, source2),
3869             expectedFail = "Aborting: Unable to parse signature file: Cannot merge different formats of signature files. " +
3870                 "First file format=V2, current file format=V3: file=TESTROOT/project/load-api2.txt"
3871         )
3872     }
3873 
3874     @Test
Test tracking of @Composable annotation from classpathnull3875     fun `Test tracking of @Composable annotation from classpath`() {
3876         check(
3877             format = FileFormat.V3,
3878             classpath = arrayOf(
3879                 /* The following source file, compiled, and root folder jar'ed and stored as base64 gzip:
3880                     package test.pkg
3881                     @MustBeDocumented
3882                     @Retention(AnnotationRetention.BINARY)
3883                     @Target(
3884                         AnnotationTarget.CLASS,
3885                         AnnotationTarget.FUNCTION,
3886                         AnnotationTarget.TYPE,
3887                         AnnotationTarget.TYPE_PARAMETER,
3888                         AnnotationTarget.PROPERTY
3889                     )
3890                     annotation class Composable
3891                  */
3892                 base64gzip(
3893                     "test.jar",
3894                     "" +
3895                         "UEsDBAoAAAgIAKx6s1AAAAAAAgAAAAAAAAAJAAAATUVUQS1JTkYvAwBQSwMECgAACAgAZ3qzULJ/" +
3896                         "Au4bAAAAGQAAABQAAABNRVRBLUlORi9NQU5JRkVTVC5NRvNNzMtMSy0u0Q1LLSrOzM+zUjDUM+Dl" +
3897                         "4uUCAFBLAwQKAAAICABnerNQDArdZgwAAAAQAAAAGwAAAE1FVEEtSU5GL3RlbXAua290bGluX21v" +
3898                         "ZHVsZWNgYGBmYGBghGIBAFBLAwQKAAAICABnerNQAAAAAAIAAAAAAAAABQAAAHRlc3QvAwBQSwME" +
3899                         "CgAACAgAZ3qzUAAAAAACAAAAAAAAAAkAAAB0ZXN0L3BrZy8DAFBLAwQKAAAICABnerNQbrgjGPQB" +
3900                         "AACVAwAAGQAAAHRlc3QvcGtnL0NvbXBvc2FibGUuY2xhc3OFUk1v2kAQfWtioG6TkKRpSdI0H01I" +
3901                         "P6S65doTEEdF4kvGrRRxqBZYIQdjo+xClRu3Xvsz+ht6qFCO/VFVZ4kCVLJU2Xo7O/PGM/M8v//8" +
3902                         "/AUgjzcMW0pIZQ/7PbsUDYaR5O1ApMAYMld8zO2Ahz273r4SHZVCguFg4eVhGCmu/Ci0C3MzBZPh" +
3903                         "pNKPVOCHy5TqSKqiOI86o4EIleh+YNiPoblCUZgsiptjHowEw1kMb1FxOSNZLNcK7iXDbkyKx697" +
3904                         "QhFrjQdB9FV07xwyvt9FgXmeWaoUmk2G9MWnWskr12sMK95lw6Ev6uNLo+AWqo7nuERpuPWG43rU" +
3905                         "ylElVrJ/lDiM5yyPlvsPpREFfudmpmoscT7FcXzcCYRux7sZCi0kzfGxfs6wcS9NVSje5YpT0BiM" +
3906                         "E7Q+TEOGru3ZFRpoQ1ifXN33NNR0YllG1rCMzJ41naRvvxnZ6SRvvGPF6eT2R9LQvDzDdiVmBakM" +
3907                         "SF4lBkOG1YX/bV8xWM1odN0RF35A27HjjkiAgfjsS58Ii/8mc1QAK/SZpG6P7FczfInXdH5Hih4g" +
3908                         "TfEHAhYe4hGZqy2YAmtY15DRsKFhU8MWHlPC9l3CE6zjqTZbMASympbFDnZhYq+FRBnPZu8+nt/f" +
3909                         "Dso4xBGZOG6BSbzACYUkTiVyEmd/AVBLAQIUAwoAAAgIAKx6s1AAAAAAAgAAAAAAAAAJAAAAAAAA" +
3910                         "AAAAEADtQQAAAABNRVRBLUlORi9QSwECFAMKAAAICABnerNQsn8C7hsAAAAZAAAAFAAAAAAAAAAA" +
3911                         "AAAApIEpAAAATUVUQS1JTkYvTUFOSUZFU1QuTUZQSwECFAMKAAAICABnerNQDArdZgwAAAAQAAAA" +
3912                         "GwAAAAAAAAAAAAAAoIF2AAAATUVUQS1JTkYvdGVtcC5rb3RsaW5fbW9kdWxlUEsBAhQDCgAACAgA" +
3913                         "Z3qzUAAAAAACAAAAAAAAAAUAAAAAAAAAAAAQAOhBuwAAAHRlc3QvUEsBAhQDCgAACAgAZ3qzUAAA" +
3914                         "AAACAAAAAAAAAAkAAAAAAAAAAAAQAOhB4AAAAHRlc3QvcGtnL1BLAQIUAwoAAAgIAGd6s1BuuCMY" +
3915                         "9AEAAJUDAAAZAAAAAAAAAAAAAACggQkBAAB0ZXN0L3BrZy9Db21wb3NhYmxlLmNsYXNzUEsFBgAA" +
3916                         "AAAGAAYAcwEAADQDAAAAAA=="
3917                 )
3918             ),
3919             sourceFiles = arrayOf(
3920                 kotlin(
3921                     """
3922                     package test.pkg
3923                     class RadioGroupScope() {
3924                         @Composable
3925                         fun RadioGroupItem(
3926                             selected: Boolean,
3927                             onSelect: () -> Unit,
3928                             content: @Composable () -> Unit
3929                         ) { }
3930                     }
3931                 """
3932                 )
3933             ),
3934             expectedIssues = "",
3935             api =
3936             """
3937                 // Signature format: 3.0
3938                 package test.pkg {
3939                   public final class RadioGroupScope {
3940                     ctor public RadioGroupScope();
3941                     method @test.pkg.Composable public void RadioGroupItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onSelect, kotlin.jvm.functions.Function0<kotlin.Unit> content);
3942                   }
3943                 }
3944             """
3945         )
3946     }
3947 
3948     @Test
Test for experimental annotations from classpathnull3949     fun `Test for experimental annotations from classpath`() {
3950         check(
3951             format = FileFormat.V3,
3952             classpath = arrayOf(
3953                 /* The following source file, compiled, and root folder jar'ed and stored as base64 gzip
3954                    Encoded using openssl base64 < test.jar | tr -d '\n'
3955 
3956                     package test.pkg
3957                     @RequiresOptIn
3958                     annotation class ExternalExperimentalAnnotation
3959                  */
3960                 base64gzip(
3961                     "test.jar",
3962                     "" +
3963                         "UEsDBAoAAAgIADt2U1IAAAAAAgAAAAAAAAAJAAAATUVUQS1JTkYvAwBQSwMECgAACAgAFXZ" +
3964                         "TUrJ/Au4bAAAAGQAAABQAAABNRVRBLUlORi9NQU5JRkVTVC5NRvNNzMtMSy0u0Q1LLSrOzM" +
3965                         "+zUjDUM+Dl4uUCAFBLAwQKAAAICAA7dlNSDWpm1BUAAAAYAAAAGwAAAE1FVEEtSU5GL3Rlc" +
3966                         "3Qua290bGluX21vZHVsZWNgYGBmYGBgBGIWIGYCYgYlBi0GAFBLAwQKAAAICAA7dlNSAAAA" +
3967                         "AAIAAAAAAAAABQAAAHRlc3QvAwBQSwMECgAACAgAO3ZTUgAAAAACAAAAAAAAAAkAAAB0ZXN" +
3968                         "0L3BrZy8DAFBLAwQKAAAICAA7dlNSPYCyXGwBAABkAgAALQAAAHRlc3QvcGtnL0V4dGVybm" +
3969                         "FsRXhwZXJpbWVudGFsQW5ub3RhdGlvbi5jbGFzc41Qy04CQRCsWZ6uL/CBICp6wXhxlasnT" +
3970                         "TBuAmLwceE0wIQsLLPIzhK87c1f8Rs8GMLRjzL2qoiJRr309HRVdXf188vjE4ACcgy7SrjK" +
3971                         "6HVaRnGoRF9yuzjsib7VFVJx+1hKR3FlOTIGxpBo8wE3bC5bRqXeFg0VQ4ghN63yT77xVRp" +
3972                         "hSJU6jrItaVTFrWf1hVvpKVMeMWyXfpRXhaINKCNKZMBtTzDk/6BeOLbVuCNBrHp9fmWWiw" +
3973                         "zJydiyULzJFSdU6w5CZJ8FIRwEjWr1txqCQJZYh0rNQ9pu5Ou6ltZ0LZHVR358fK+lR35BO" +
3974                         "2AnI3/8EA2kzQLDXumfd6T5YAgHbIad37n7HeLol47Xb4hTy6YLZKoeOe2KG8u16raYUl2G" +
3975                         "7AdmysE3NE9rIkyDo3h3uRHYRhab9J5RFidsRkDHLOYQwXwNIRMLJhZNJJCc/JZMLGOFUqz" +
3976                         "WwFyksEaQi7SLjIt1bFG3KHWKAa9QSwECFAMKAAAICAA7dlNSAAAAAAIAAAAAAAAACQAAAA" +
3977                         "AAAAAAABAA7UEAAAAATUVUQS1JTkYvUEsBAhQDCgAACAgAFXZTUrJ/Au4bAAAAGQAAABQAA" +
3978                         "AAAAAAAAAAAAKSBKQAAAE1FVEEtSU5GL01BTklGRVNULk1GUEsBAhQDCgAACAgAO3ZTUg1q" +
3979                         "ZtQVAAAAGAAAABsAAAAAAAAAAAAAAKCBdgAAAE1FVEEtSU5GL3Rlc3Qua290bGluX21vZHV" +
3980                         "sZVBLAQIUAwoAAAgIADt2U1IAAAAAAgAAAAAAAAAFAAAAAAAAAAAAEADoQcQAAAB0ZXN0L1" +
3981                         "BLAQIUAwoAAAgIADt2U1IAAAAAAgAAAAAAAAAJAAAAAAAAAAAAEADoQekAAAB0ZXN0L3BrZ" +
3982                         "y9QSwECFAMKAAAICAA7dlNSPYCyXGwBAABkAgAALQAAAAAAAAAAAAAAoIESAQAAdGVzdC9w" +
3983                         "a2cvRXh0ZXJuYWxFeHBlcmltZW50YWxBbm5vdGF0aW9uLmNsYXNzUEsFBgAAAAAGAAYAhwE" +
3984                         "AAMkCAAAAAA=="
3985                 )
3986             ),
3987             sourceFiles = arrayOf(
3988                 kotlin(
3989                     """
3990                     package test.pkg
3991 
3992                     @ExternalExperimentalAnnotation
3993                     class ClassUsingExternalExperimentalApi
3994 
3995                     @InLibraryExperimentalAnnotation
3996                     class ClassUsingInLibraryExperimentalApi
3997                 """
3998                 ),
3999                 kotlin(
4000                     """
4001                         package test.pkg
4002                         @RequiresOptIn
4003                         annotation class InLibraryExperimentalAnnotation
4004                     """
4005                 )
4006             ),
4007             expectedIssues = "",
4008             api =
4009             """
4010                 // Signature format: 3.0
4011                 package test.pkg {
4012                   @kotlin.RequiresOptIn public @interface InLibraryExperimentalAnnotation {
4013                   }
4014                 }
4015             """,
4016             extraArguments = arrayOf(
4017                 ARG_HIDE_META_ANNOTATION, "kotlin.RequiresOptIn"
4018             )
4019         )
4020     }
4021 
4022     @Test
@IntRange value in kotlinnull4023     fun `@IntRange value in kotlin`() {
4024         check(
4025             format = FileFormat.V3,
4026             sourceFiles = arrayOf(
4027                 kotlin(
4028                     """
4029                     package test.pkg
4030 
4031                     import androidx.annotation.IntRange
4032 
4033                     class KotlinClass(@IntRange(from = 1) val param: Int) {
4034                         constructor(@IntRange(from = 2) val differentParam: Int)
4035                         fun myMethod(@IntRange(from = 3) val methodParam: Int) {}
4036                     }
4037                 """
4038                 ),
4039                 androidxIntRangeSource
4040             ),
4041             extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"),
4042             api = """
4043                 // Signature format: 3.0
4044                 package test.pkg {
4045                   public final class KotlinClass {
4046                     ctor public KotlinClass(@IntRange(from=1L) int param);
4047                     ctor public KotlinClass(@IntRange(from=2L) int differentParam);
4048                     method public int getParam();
4049                     method public void myMethod(@IntRange(from=3L) int methodParam);
4050                     property public final int param;
4051                   }
4052                 }
4053             """
4054         )
4055     }
4056 
4057     @Test
Annotation value visibilitynull4058     fun `Annotation value visibility`() {
4059         check(
4060             format = FileFormat.V2,
4061             sourceFiles = arrayOf(
4062                 java(
4063                     """
4064                     package test.pkg;
4065 
4066                     import androidx.annotation.IntRange;
4067 
4068                     public final class ApiClass {
4069                         private int hiddenConstant = 1;
4070                         public ApiClass(@IntRange(from=1) int x) {}
4071                         public void method(@IntRange(from = hiddenConstant) int x) {}
4072                     }
4073                 """
4074                 ),
4075                 androidxIntRangeSource
4076             ),
4077             extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"),
4078             api = """
4079                 // Signature format: 2.0
4080                 package test.pkg {
4081                   public final class ApiClass {
4082                     ctor public ApiClass(@IntRange(from=1) int);
4083                     method public void method(@IntRange(from=0x1) int);
4084                   }
4085                 }
4086             """
4087         )
4088     }
4089 
4090     @Test
Kotlin properties with overriding getnull4091     fun `Kotlin properties with overriding get`() {
4092         check(
4093             format = FileFormat.V3,
4094             sourceFiles = arrayOf(
4095                 kotlin(
4096                     """
4097                     package test.pkg
4098 
4099                     import androidx.annotation.IntRange
4100 
4101                     class KotlinClass() {
4102                         val propertyWithGetter: Boolean get() = true
4103                         val propertyWithNoGetter: Boolean = true
4104                     }
4105                 """
4106                 ),
4107                 androidxIntRangeSource
4108             ),
4109             extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"),
4110             api = """
4111                 // Signature format: 3.0
4112                 package test.pkg {
4113                   public final class KotlinClass {
4114                     ctor public KotlinClass();
4115                     method public boolean getPropertyWithGetter();
4116                     method public boolean getPropertyWithNoGetter();
4117                     property public final boolean propertyWithGetter;
4118                     property public final boolean propertyWithNoGetter;
4119                   }
4120                 }
4121             """
4122         )
4123     }
4124 
4125     @Test
Constructor property trackingnull4126     fun `Constructor property tracking`() {
4127         check(
4128             format = FileFormat.V3,
4129             sourceFiles = arrayOf(
4130                 kotlin(
4131                     """
4132                     package test.pkg
4133                     sealed class MyClass(
4134                         val firstConstructorProperty: Int,
4135                         val secondConstructorProperty: Boolean
4136                     ) {
4137                         val nonConstructorProperty: String = "PROP"
4138                     }
4139                     """
4140                 ),
4141                 kotlin(
4142                     """
4143                     package test.pkg
4144                     data class MyDataClass(
4145                         val constructorProperty: String,
4146                         internal val internalConstructorProperty: String
4147                     )
4148                 """
4149                 )
4150             ),
4151             api = """
4152                 // Signature format: 3.0
4153                 package test.pkg {
4154                   public abstract sealed class MyClass {
4155                     method public final int getFirstConstructorProperty();
4156                     method public final String getNonConstructorProperty();
4157                     method public final boolean getSecondConstructorProperty();
4158                     property public final int firstConstructorProperty;
4159                     property public final String nonConstructorProperty;
4160                     property public final boolean secondConstructorProperty;
4161                   }
4162                   public final class MyDataClass {
4163                     ctor public MyDataClass(String constructorProperty, String internalConstructorProperty);
4164                     method public String component1();
4165                     method public test.pkg.MyDataClass copy(String constructorProperty, String internalConstructorProperty);
4166                     method public String getConstructorProperty();
4167                     property public final String constructorProperty;
4168                   }
4169                 }
4170             """
4171         )
4172     }
4173 
4174     @Test
Concise default Values Names in Javanull4175     fun `Concise default Values Names in Java`() {
4176         // Java code which explicitly specifies parameter names
4177         check(
4178             format = FileFormat.V4,
4179             sourceFiles = arrayOf(
4180                 java(
4181                     """
4182                     package test.pkg;
4183                     import androidx.annotation.DefaultValue;
4184 
4185                     public class Foo {
4186                         public void foo(
4187                             @DefaultValue("null") String prefix,
4188                             @DefaultValue("\"Hello World\"") String greeting,
4189                             @DefaultValue("42") int meaning) {
4190                         }
4191                     }
4192                     """
4193                 ),
4194                 supportDefaultValue
4195             ),
4196             api = """
4197                 // Signature format: 4.0
4198                 package test.pkg {
4199                   public class Foo {
4200                     ctor public Foo();
4201                     method public void foo(optional String!, optional String!, optional int);
4202                   }
4203                 }
4204                  """,
4205             extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation")
4206         )
4207     }
4208 
4209     @Test
Concise default Values and Names in Kotlinnull4210     fun `Concise default Values and Names in Kotlin`() {
4211         // Kotlin code which explicitly specifies parameter names
4212         check(
4213             format = FileFormat.V4,
4214             sourceFiles = arrayOf(
4215                 kotlin(
4216                     """
4217                     package test.pkg
4218                     import some.other.pkg.Constants.Misc.SIZE
4219                     import android.graphics.Bitmap
4220                     import android.view.View
4221 
4222                     class Foo(a: String = "1", b: String = "2") {
4223                         fun method1(myInt: Int = 42,
4224                             myInt2: Int? = null,
4225                             myByte: Int = 2 * 21,
4226                             str: String = "hello " + "world",
4227                             vararg args: String) { }
4228 
4229                         fun method2(myInt: Int, myInt2: Int = (2*int) * SIZE) { }
4230 
4231                         fun method3(str: String, myInt: Int, myInt2: Int = double(int) + str.length) { }
4232 
4233                         fun emptyLambda(sizeOf: () -> Unit = {  }) {}
4234 
4235                         fun View.drawToBitmap(config: Bitmap.Config = Bitmap.Config.ARGB_8888): Bitmap? = null
4236 
4237                         companion object {
4238                             fun double(myInt: Int) = 2 * myInt
4239                             fun print(foo: Foo = Foo()) { println(foo) }
4240                         }
4241                     }
4242                     """
4243                 ),
4244                 java(
4245                     """
4246                     package some.other.pkg;
4247                     public class Constants {
4248                         public static class Misc {
4249                             public static final int SIZE = 5;
4250                         }
4251                     }
4252                     """
4253                 )
4254             ),
4255             api = """
4256                 // Signature format: 4.0
4257                 package test.pkg {
4258                   public final class Foo {
4259                     ctor public Foo(optional String a, optional String b);
4260                     method public android.graphics.Bitmap? drawToBitmap(android.view.View, optional android.graphics.Bitmap.Config config);
4261                     method public void emptyLambda(optional kotlin.jvm.functions.Function0<kotlin.Unit> sizeOf);
4262                     method public void method1(optional int myInt, optional Integer? myInt2, optional int myByte, optional String str, java.lang.String... args);
4263                     method public void method2(int myInt, optional int myInt2);
4264                     method public void method3(String str, int myInt, optional int myInt2);
4265                     field public static final test.pkg.Foo.Companion Companion;
4266                   }
4267                   public static final class Foo.Companion {
4268                     method public int double(int myInt);
4269                     method public void print(optional test.pkg.Foo foo);
4270                   }
4271                 }
4272                 """,
4273             extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation", ARG_HIDE_PACKAGE, "some.other.pkg"),
4274             includeSignatureVersion = true
4275         )
4276     }
4277 
4278     @Test
Concise default Values in Kotlin for expressionsnull4279     fun `Concise default Values in Kotlin for expressions`() {
4280         // Testing trickier default values; regression test for problem
4281         // observed in androidx.core.util with LruCache
4282         check(
4283             format = FileFormat.V4,
4284             sourceFiles = arrayOf(
4285                 kotlin(
4286                     """
4287                     package androidx.core.util
4288 
4289                     import android.util.LruCache
4290 
4291                     inline fun <K : Any, V : Any> lruCache(
4292                         maxSize: Int,
4293                         crossinline sizeOf: (key: K, value: V) -> Int = { _, _ -> 1 },
4294                         @Suppress("USELESS_CAST") // https://youtrack.jetbrains.com/issue/KT-21946
4295                         crossinline create: (key: K) -> V? = { null as V? },
4296                         crossinline onEntryRemoved: (evicted: Boolean, key: K, oldValue: V, newValue: V?) -> Unit =
4297                             { _, _, _, _ -> }
4298                     ): LruCache<K, V> {
4299                         return object : LruCache<K, V>(maxSize) {
4300                             override fun sizeOf(key: K, value: V) = sizeOf(key, value)
4301                             override fun create(key: K) = create(key)
4302                             override fun entryRemoved(evicted: Boolean, key: K, oldValue: V, newValue: V?) {
4303                                 onEntryRemoved(evicted, key, oldValue, newValue)
4304                             }
4305                         }
4306                     }
4307                     """
4308                 ),
4309                 java(
4310                     """
4311                     package androidx.collection;
4312 
4313                     import androidx.annotation.NonNull;
4314                     import androidx.annotation.Nullable;
4315 
4316                     import java.util.LinkedHashMap;
4317                     import java.util.Locale;
4318                     import java.util.Map;
4319 
4320                     public class LruCache<K, V> {
4321                         @Nullable
4322                         protected V create(@NonNull K key) {
4323                             return null;
4324                         }
4325 
4326                         protected int sizeOf(@NonNull K key, @NonNull V value) {
4327                             return 1;
4328                         }
4329 
4330                         protected void entryRemoved(boolean evicted, @NonNull K key, @NonNull V oldValue,
4331                                 @Nullable V newValue) {
4332                         }
4333                     }
4334                     """
4335                 ),
4336                 androidxNullableSource,
4337                 androidxNonNullSource
4338             ),
4339             api = """
4340                 // Signature format: 4.0
4341                 package androidx.core.util {
4342                   public final class TestKt {
4343                     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);
4344                   }
4345                 }
4346                 """,
4347             extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation", ARG_HIDE_PACKAGE, "androidx.collection"),
4348             includeSignatureVersion = true
4349         )
4350     }
4351 
4352     @Test
Test type erasure and dexApi from signaturenull4353     fun `Test type erasure and dexApi from signature`() {
4354         check(
4355             signatureSources = arrayOf(
4356                 """
4357                 package android.widget {
4358 
4359                   @android.widget.RemoteViews.RemoteView public class ListView extends android.widget.AbsListView {
4360                     method protected <T extends android.view.View> T findViewTraversal(@IdRes int);
4361                     method protected long tryAcquireShared(long);
4362                   }
4363 
4364                 }
4365 """
4366             ),
4367             dexApi = """
4368             Landroid/widget/ListView;
4369             Landroid/widget/ListView;->findViewTraversal(I)Landroid/view/View;
4370             Landroid/widget/ListView;->tryAcquireShared(J)J
4371             """
4372         )
4373     }
4374 
4375     @Test
Functional interface in signaturenull4376     fun `Functional interface in signature`() {
4377         check(
4378             format = FileFormat.V4,
4379             sourceFiles = arrayOf(
4380                 kotlin(
4381                     """
4382                     package test.pkg
4383 
4384                     fun interface FunctionalInterface {
4385                         fun methodOne(number: Int): Boolean
4386                     }
4387 
4388                     fun userOfFunctionalInterface(parameter: FunctionalInterface) { }
4389                 """
4390                 )
4391             ),
4392             api = """
4393                 // Signature format: 4.0
4394                 package test.pkg {
4395                   public fun interface FunctionalInterface {
4396                     method public boolean methodOne(int number);
4397                   }
4398                   public final class FunctionalInterfaceKt {
4399                     method public static void userOfFunctionalInterface(test.pkg.FunctionalInterface parameter);
4400                   }
4401                 }
4402             """
4403         )
4404     }
4405 
4406     @Test
Inline classnull4407     fun `Inline class`() {
4408         check(
4409             format = FileFormat.V4,
4410             sourceFiles = arrayOf(
4411                 kotlin(
4412                     """
4413                     package test.pkg
4414 
4415                     inline class Dp(val value: Float) : Comparable<Dp> {
4416                         inline operator fun plus(other: Dp) = Dp(value = this.value + other.value)
4417                         inline operator fun minus(other: Dp) = Dp(value = this.value - other.value)
4418                         // Not tracked due to https://youtrack.jetbrains.com/issue/KTIJ-11559
4419                         val someBits
4420                             get() = value && 0x00ff
4421                         // Not tracked due to https://youtrack.jetbrains.com/issue/KTIJ-11559
4422                         fun doSomething() {}
4423                     }
4424                 """
4425                 )
4426             ),
4427             api = """
4428                 // Signature format: 4.0
4429                 package test.pkg {
4430                   public final inline class Dp implements java.lang.Comparable<test.pkg.Dp> {
4431                     ctor public Dp();
4432                     method public float getValue();
4433                     method public inline operator float minus(float other);
4434                     method public inline operator float plus(float other);
4435                     property public final float value;
4436                   }
4437                 }
4438             """
4439         )
4440     }
4441 
4442     @Test
Value classnull4443     fun `Value class`() {
4444         check(
4445             format = FileFormat.V4,
4446             sourceFiles = arrayOf(
4447                 kotlin(
4448                     """
4449                     package test.pkg
4450                     @JvmInline
4451                     value class Dp(val value: Float) : Comparable<Dp> {
4452                         inline operator fun plus(other: Dp) = Dp(value = this.value + other.value)
4453                         inline operator fun minus(other: Dp) = Dp(value = this.value - other.value)
4454                         val someBits
4455                             get() = value && 0x00ff
4456                         fun doSomething() {}
4457                     }
4458                 """
4459                 )
4460             ),
4461             api = """
4462                 // Signature format: 4.0
4463                 package test.pkg {
4464                   @kotlin.jvm.JvmInline public final value class Dp implements java.lang.Comparable<test.pkg.Dp> {
4465                     ctor public Dp(float value);
4466                     method public void doSomething();
4467                     method public boolean getSomeBits();
4468                     method public float getValue();
4469                     method public inline operator float minus(float other);
4470                     method public inline operator float plus(float other);
4471                     property public final boolean someBits;
4472                     property public final float value;
4473                   }
4474                 }
4475             """
4476         )
4477     }
4478 
4479     @Test
Kotlin doesn't expand java named constantsnull4480     fun `Kotlin doesn't expand java named constants`() {
4481         check(
4482             format = FileFormat.V3,
4483             sourceFiles =
4484             arrayOf(
4485                 kotlin(
4486                     """
4487                         package test.pkg
4488                         annotation class Foo(val bar: Long = java.lang.Long.MIN_VALUE)
4489                     """
4490                 )
4491             ),
4492             api =
4493             """
4494                 // Signature format: 3.0
4495                 package test.pkg {
4496                   @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public @interface Foo {
4497                     method public abstract long bar() default java.lang.Long.MIN_VALUE;
4498                     property public abstract long bar;
4499                   }
4500                 }
4501             """
4502         )
4503     }
4504 
4505     @Test
4506     fun `Kotlin constructors with JvmOverloads`() {
4507         check(
4508             format = FileFormat.V4,
4509             sourceFiles = arrayOf(
4510                 kotlin(
4511                     """
4512                         package test.pkg
4513 
4514                         class AllOptionalJvmOverloads @JvmOverloads constructor(
4515                             private val foo: Int = 0,
4516                             private val bar: Int = 0
4517                         )
4518 
4519                         class AllOptionalNoJvmOverloads(
4520                             private val foo: Int = 0,
4521                             private val bar: Int = 0
4522                         )
4523 
4524                         class SomeOptionalJvmOverloads @JvmOverloads constructor(
4525                             private val foo: Int,
4526                             private val bar: Int = 0
4527                         )
4528 
4529                         class SomeOptionalNoJvmOverloads(
4530                             private val foo: Int,
4531                             private val bar: Int = 0
4532                         )
4533                     """
4534                 )
4535             ),
4536             api = """
4537                 // Signature format: 4.0
4538                 package test.pkg {
4539                   public final class AllOptionalJvmOverloads {
4540                     ctor public AllOptionalJvmOverloads(optional int foo, optional int bar);
4541                     ctor public AllOptionalJvmOverloads(optional int foo);
4542                     ctor public AllOptionalJvmOverloads();
4543                   }
4544                   public final class AllOptionalNoJvmOverloads {
4545                     ctor public AllOptionalNoJvmOverloads(optional int foo, optional int bar);
4546                   }
4547                   public final class SomeOptionalJvmOverloads {
4548                     ctor public SomeOptionalJvmOverloads(int foo, optional int bar);
4549                     ctor public SomeOptionalJvmOverloads(int foo);
4550                   }
4551                   public final class SomeOptionalNoJvmOverloads {
4552                     ctor public SomeOptionalNoJvmOverloads(int foo, optional int bar);
4553                   }
4554                 }
4555             """
4556         )
4557     }
4558 
4559     @Test
4560     fun `Kotlin public methods with DeprecationLevel HIDDEN are public API`() {
4561         check(
4562             format = FileFormat.V3,
4563             sourceFiles = arrayOf(
4564                 kotlin(
4565                     """
4566                         package test.pkg
4567                         @Deprecated(
4568                             message = "So much regret",
4569                             level = DeprecationLevel.HIDDEN
4570                         )
4571                         fun myMethod() { TODO() }
4572                         @Deprecated(
4573                             message = "So much regret",
4574                             level = DeprecationLevel.HIDDEN
4575                         )
4576                         internal fun myInternalMethod() { TODO() }
4577                         @Deprecated(
4578                             message = "So much regret",
4579                             level = DeprecationLevel.HIDDEN
4580                         )
4581                         private fun myPrivateMethod() { TODO() }
4582                         @Deprecated(
4583                             message = "So much regret",
4584                             level = DeprecationLevel.WARNING
4585                         )
4586                         fun myNormalDeprecatedMethod() { TODO() }
4587                     """
4588                 )
4589             ),
4590             api = """
4591                 // Signature format: 3.0
4592                 package test.pkg {
4593                   public final class TestKt {
4594                     method @Deprecated public static void myMethod();
4595                     method @Deprecated public static void myNormalDeprecatedMethod();
4596                   }
4597                 }
4598             """
4599         )
4600     }
4601 
4602     @Test
4603     fun `Annotations aren't dropped when DeprecationLevel is HIDDEN`() {
4604         check(
4605             format = FileFormat.V3,
4606             sourceFiles = arrayOf(
4607                 kotlin(
4608                     """
4609                         package test.pkg
4610                         @Deprecated(
4611                             message = "So much regret",
4612                             level = DeprecationLevel.HIDDEN
4613                         )
4614                         @IntRange(from=0)
4615                         fun myMethod() { TODO() }
4616                     """
4617                 )
4618             ),
4619             api = """
4620                 // Signature format: 3.0
4621                 package test.pkg {
4622                   public final class TestKt {
4623                     method @Deprecated @kotlin.ranges.IntRange public static void myMethod();
4624                   }
4625                 }
4626             """
4627         )
4628     }
4629 
4630     @Test
Constants in a file scope annotationnull4631     fun `Constants in a file scope annotation`() {
4632         check(
4633             format = FileFormat.V4,
4634             sourceFiles = arrayOf(
4635                 kotlin(
4636                     """
4637                     @file:RestrictTo(RestrictTo.Scope.LIBRARY)
4638                     package test.pkg
4639                     import androidx.annotation.RestrictTo
4640                     private fun veryFun(): Boolean = true
4641                 """
4642                 ),
4643                 restrictToSource
4644             ),
4645             extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation"),
4646             api = """
4647                 // Signature format: 4.0
4648                 package test.pkg {
4649                   @RestrictTo({androidx.annotation.RestrictTo.Scope.LIBRARY}) public final class TestKt {
4650                   }
4651                 }
4652             """
4653         )
4654     }
4655 
4656     @Test
RestrictTo on a file hiding itnull4657     fun `RestrictTo on a file hiding it`() {
4658         check(
4659             format = FileFormat.V4,
4660             sourceFiles = arrayOf(
4661                 kotlin(
4662                     """
4663                     @file:RestrictTo(RestrictTo.Scope.LIBRARY)
4664                     package test.pkg
4665                     import androidx.annotation.RestrictTo
4666                     private fun veryFun(): Boolean = true
4667                 """
4668                 ),
4669                 restrictToSource
4670             ),
4671             extraArguments = arrayOf(ARG_HIDE_PACKAGE, "androidx.annotation", "--show-unannotated"),
4672             hideAnnotations = arrayOf(
4673                 "androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)"
4674             ),
4675             api = """
4676                 // Signature format: 4.0
4677             """
4678         )
4679     }
4680 
4681     /** Regression test for b/202968090 */
4682     @Test
annotation arrays should be non-nullnull4683     fun `annotation arrays should be non-null`() {
4684         check(
4685             format = FileFormat.V4,
4686             sourceFiles = arrayOf(
4687                 kotlin(
4688                     """
4689                         package test.pkg
4690                         annotation class Foo (
4691                             val bar: Array<String>,
4692                             vararg val baz: String
4693                         )
4694                     """
4695                 )
4696             ),
4697             api = """
4698                 // Signature format: 4.0
4699                 package test.pkg {
4700                   @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) public @interface Foo {
4701                     method public abstract String[] bar();
4702                     method public abstract String[] baz();
4703                     property public abstract String[] bar;
4704                     property public abstract String[] baz;
4705                   }
4706                 }
4707             """
4708         )
4709     }
4710 
4711     @Test
property setter parameters are unnamednull4712     fun `property setter parameters are unnamed`() {
4713         check(
4714             sourceFiles = arrayOf(
4715                 kotlin(
4716                     """
4717                         package test.pkg
4718                         class Foo(var bar: Int)
4719                     """
4720                 )
4721             ),
4722             api = """
4723                 package test.pkg {
4724                   public final class Foo {
4725                     ctor public Foo(int bar);
4726                     method public int getBar();
4727                     method public void setBar(int);
4728                     property public final int bar;
4729                   }
4730                 }
4731             """
4732         )
4733     }
4734 }
4735