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