xref: /aosp_15_r20/tools/metalava/metalava/src/test/java/com/android/tools/metalava/NullnessMigrationTest.kt (revision 115816f9299ab6ddd6b9673b81f34e707f6bacab)
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 package com.android.tools.metalava
18 
19 import com.android.tools.metalava.model.SUPPORT_TYPE_USE_ANNOTATIONS
20 import com.android.tools.metalava.model.text.FileFormat
21 import com.android.tools.metalava.testing.KnownSourceFiles
22 import com.android.tools.metalava.testing.java
23 import org.junit.Test
24 
25 class NullnessMigrationTest : DriverTest() {
26     @Test
Test Kotlin-style null signaturesnull27     fun `Test Kotlin-style null signatures`() {
28         check(
29             format = FileFormat.V3,
30             sourceFiles =
31                 arrayOf(
32                     java(
33                         """
34                             package test.pkg;
35                             import androidx.annotation.NonNull;
36                             import androidx.annotation.Nullable;
37                             public class MyTest {
38                                 public Double convert0(Float f) { return null; }
39                                 @Nullable public Double convert1(@NonNull Float f) { return null; }
40                                 @Nullable public Double convert2(@NonNull Float f) { return null; }
41                                 @NonNull public Double convert3(@Nullable Float f) { return null; }
42                                 @NonNull public Double convert4(@NonNull Float f) { return null; }
43                             }
44                         """
45                     ),
46                     androidxNonNullSource,
47                     androidxNullableSource,
48                     // Hide androidx.annotation classes.
49                     KnownSourceFiles.androidxAnnotationHide,
50                 ),
51             api =
52                 """
53                     // Signature format: 3.0
54                     package test.pkg {
55                       public class MyTest {
56                         ctor public MyTest();
57                         method public Double! convert0(Float!);
58                         method public Double? convert1(Float);
59                         method public Double? convert2(Float);
60                         method public Double convert3(Float?);
61                         method public Double convert4(Float);
62                       }
63                     }
64                 """,
65         )
66     }
67 
68     @Test
Method which is now marked null should be marked as recently migrated nullnull69     fun `Method which is now marked null should be marked as recently migrated null`() {
70         check(
71             format = FileFormat.V2,
72             sourceFiles =
73                 arrayOf(
74                     java(
75                         """
76                             package test.pkg;
77                             import androidx.annotation.Nullable;
78                             import androidx.annotation.NonNull;
79                             public abstract class MyTest {
80                                 private MyTest() { }
81                                 @Nullable public Double convert1(Float f) { return null; }
82                             }
83                         """
84                     ),
85                     androidxNonNullSource,
86                     androidxNullableSource,
87                     // Hide androidx.annotation classes.
88                     KnownSourceFiles.androidxAnnotationHide,
89                 ),
90             migrateNullsApi =
91                 """
92                     package test.pkg {
93                       public abstract class MyTest {
94                         method public Double convert1(Float);
95                       }
96                     }
97                 """,
98             api =
99                 """
100                     package test.pkg {
101                       public abstract class MyTest {
102                         method @Nullable public Double convert1(Float);
103                       }
104                     }
105                 """,
106             stubFiles =
107                 arrayOf(
108                     java(
109                         """
110                             package test.pkg;
111                             @SuppressWarnings({"unchecked", "deprecation", "all"})
112                             public abstract class MyTest {
113                             MyTest() { throw new RuntimeException("Stub!"); }
114                             @androidx.annotation.RecentlyNullable
115                             public java.lang.Double convert1(java.lang.Float f) { throw new RuntimeException("Stub!"); }
116                             }
117                         """,
118                     )
119                 ),
120         )
121     }
122 
123     @Test
Parameter which is now marked null should be marked as recently migrated nullnull124     fun `Parameter which is now marked null should be marked as recently migrated null`() {
125         check(
126             format = FileFormat.V2,
127             sourceFiles =
128                 arrayOf(
129                     java(
130                         """
131                             package test.pkg;
132                             import androidx.annotation.NonNull;
133                             public abstract class MyTest {
134                                 private MyTest() { }
135                                 public Double convert1(@NonNull Float f) { return null; }
136                             }
137                         """
138                     ),
139                     androidxNonNullSource,
140                     androidxNullableSource,
141                     // Hide androidx.annotation classes.
142                     KnownSourceFiles.androidxAnnotationHide,
143                 ),
144             migrateNullsApi =
145                 """
146                     package test.pkg {
147                       public abstract class MyTest {
148                         method public Double convert1(Float);
149                       }
150                     }
151                 """,
152             api =
153                 """
154                     package test.pkg {
155                       public abstract class MyTest {
156                         method public Double convert1(@NonNull Float);
157                       }
158                     }
159                 """,
160             stubFiles =
161                 arrayOf(
162                     java(
163                         """
164                             package test.pkg;
165                             @SuppressWarnings({"unchecked", "deprecation", "all"})
166                             public abstract class MyTest {
167                             MyTest() { throw new RuntimeException("Stub!"); }
168                             public java.lang.Double convert1(@androidx.annotation.RecentlyNonNull java.lang.Float f) { throw new RuntimeException("Stub!"); }
169                             }
170                         """
171                     ),
172                 ),
173         )
174     }
175 
176     @Test
Comprehensive check of migrationnull177     fun `Comprehensive check of migration`() {
178         check(
179             format = FileFormat.V2,
180             sourceFiles =
181                 arrayOf(
182                     java(
183                         """
184                             package test.pkg;
185                             import androidx.annotation.Nullable;
186                             import androidx.annotation.NonNull;
187                             public class MyTest {
188                                 public Double convert0(Float f) { return null; }
189                                 @Nullable public Double convert1(@NonNull Float f) { return null; }
190                                 @Nullable public Double convert2(@NonNull Float f) { return null; }
191                                 @Nullable public Double convert3(@NonNull Float f) { return null; }
192                                 @Nullable public Double convert4(@NonNull Float f) { return null; }
193                             }
194                         """
195                     ),
196                     androidxNonNullSource,
197                     androidxNullableSource,
198                     // Hide androidx.annotation classes.
199                     KnownSourceFiles.androidxAnnotationHide,
200                 ),
201             migrateNullsApi =
202                 """
203                     package test.pkg {
204                       public class MyTest {
205                         ctor public MyTest();
206                         method public Double convert0(Float);
207                         method public Double convert1(Float);
208                         method @RecentlyNullable public Double convert2(@RecentlyNonNull Float);
209                         method @RecentlyNullable public Double convert3(@RecentlyNonNull Float);
210                         method @Nullable public Double convert4(@NonNull Float);
211                       }
212                     }
213                 """,
214             api =
215                 """
216                     package test.pkg {
217                       public class MyTest {
218                         ctor public MyTest();
219                         method public Double convert0(Float);
220                         method @Nullable public Double convert1(@NonNull Float);
221                         method @Nullable public Double convert2(@NonNull Float);
222                         method @Nullable public Double convert3(@NonNull Float);
223                         method @Nullable public Double convert4(@NonNull Float);
224                       }
225                     }
226                 """,
227             stubFiles =
228                 arrayOf(
229                     java(
230                         """
231                             package test.pkg;
232                             @SuppressWarnings({"unchecked", "deprecation", "all"})
233                             public class MyTest {
234                             public MyTest() { throw new RuntimeException("Stub!"); }
235                             public java.lang.Double convert0(java.lang.Float f) { throw new RuntimeException("Stub!"); }
236                             @androidx.annotation.RecentlyNullable
237                             public java.lang.Double convert1(@androidx.annotation.RecentlyNonNull java.lang.Float f) { throw new RuntimeException("Stub!"); }
238                             @android.annotation.Nullable
239                             public java.lang.Double convert2(@android.annotation.NonNull java.lang.Float f) { throw new RuntimeException("Stub!"); }
240                             @android.annotation.Nullable
241                             public java.lang.Double convert3(@android.annotation.NonNull java.lang.Float f) { throw new RuntimeException("Stub!"); }
242                             @android.annotation.Nullable
243                             public java.lang.Double convert4(@android.annotation.NonNull java.lang.Float f) { throw new RuntimeException("Stub!"); }
244                             }
245                         """
246                     ),
247                 ),
248         )
249     }
250 
251     @Test
Comprehensive check of migration, Kotlin-style outputnull252     fun `Comprehensive check of migration, Kotlin-style output`() {
253         check(
254             format = FileFormat.V3,
255             sourceFiles =
256                 arrayOf(
257                     java(
258                         """
259                             package test.pkg;
260                             import androidx.annotation.Nullable;
261                             import androidx.annotation.NonNull;
262                             public class MyTest {
263                                 public Double convert0(Float f) { return null; }
264                                 @Nullable public Double convert1(@NonNull Float f) { return null; }
265                                 @Nullable public Double convert2(@NonNull Float f) { return null; }
266                                 @Nullable public Double convert3(@NonNull Float f) { return null; }
267                                 @Nullable public Double convert4(@NonNull Float f) { return null; }
268                             }
269                         """
270                     ),
271                     androidxNonNullSource,
272                     androidxNullableSource,
273                     // Hide androidx.annotation classes.
274                     KnownSourceFiles.androidxAnnotationHide,
275                 ),
276             migrateNullsApi =
277                 """
278                     package test.pkg {
279                       public class MyTest {
280                         ctor public MyTest();
281                         method public Double convert0(Float);
282                         method public Double convert1(Float);
283                         method @RecentlyNullable public Double convert2(@RecentlyNonNull Float);
284                         method @RecentlyNullable public Double convert3(@RecentlyNonNull Float);
285                         method @Nullable public Double convert4(@NonNull Float);
286                       }
287                     }
288                 """,
289             api =
290                 """
291                     // Signature format: 3.0
292                     package test.pkg {
293                       public class MyTest {
294                         ctor public MyTest();
295                         method public Double! convert0(Float!);
296                         method public Double? convert1(Float);
297                         method public Double? convert2(Float);
298                         method public Double? convert3(Float);
299                         method public Double? convert4(Float);
300                       }
301                     }
302                 """,
303         )
304     }
305 
306     @Test
Convert libcore nullness annotations to supportnull307     fun `Convert libcore nullness annotations to support`() {
308         check(
309             format = FileFormat.V2,
310             sourceFiles =
311                 arrayOf(
312                     java(
313                         """
314                             package test.pkg;
315                             public class Test {
316                                 public @libcore.util.NonNull Object compute() {
317                                     return 5;
318                                 }
319                             }
320                         """
321                     ),
322                     java(
323                         """
324                             package libcore.util;
325                             import static java.lang.annotation.ElementType.TYPE_USE;
326                             import static java.lang.annotation.ElementType.TYPE_PARAMETER;
327                             import static java.lang.annotation.RetentionPolicy.SOURCE;
328                             import java.lang.annotation.Documented;
329                             import java.lang.annotation.Retention;
330                             @Documented
331                             @Retention(SOURCE)
332                             @Target({TYPE_USE})
333                             public @interface NonNull {
334                                int from() default Integer.MIN_VALUE;
335                                int to() default Integer.MAX_VALUE;
336                             }
337                         """
338                     ),
339                 ),
340             api =
341                 """
342                     package libcore.util {
343                       @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public @interface NonNull {
344                         method public abstract int from() default java.lang.Integer.MIN_VALUE;
345                         method public abstract int to() default java.lang.Integer.MAX_VALUE;
346                       }
347                     }
348                     package test.pkg {
349                       public class Test {
350                         ctor public Test();
351                         method @NonNull public Object compute();
352                       }
353                     }
354                 """,
355         )
356     }
357 
358     @Test
Check type use annotationsnull359     fun `Check type use annotations`() {
360         check(
361             format = FileFormat.V2, // compat=false, kotlin-style-nulls=false
362             sourceFiles =
363                 arrayOf(
364                     java(
365                         """
366                             package test.pkg;
367                             import androidx.annotation.Nullable;
368                             import androidx.annotation.NonNull;
369                             import java.util.List;
370                             public class Test {
371                                 public @Nullable Integer compute1(@Nullable java.util.List<@Nullable String> list) {
372                                     return 5;
373                                 }
374                                 public @Nullable Integer compute2(@Nullable java.util.List<@Nullable List<?>> list) {
375                                     return 5;
376                                 }
377                                 public Integer compute3(@NonNull String @Nullable [] @Nullable [] array) {
378                                     return 5;
379                                 }
380                             }
381                         """
382                     ),
383                     androidxNonNullSource,
384                     androidxNullableSource,
385                     // Hide androidx.annotation classes.
386                     KnownSourceFiles.androidxAnnotationHide,
387                 ),
388             api =
389                 if (SUPPORT_TYPE_USE_ANNOTATIONS) {
390                     """
391                         // Signature format: 2.0
392                         package test.pkg {
393                           public class Test {
394                             ctor public Test();
395                             method @Nullable public @Nullable Integer compute1(@Nullable java.util.List<java.lang.@Nullable String>);
396                             method @Nullable public @Nullable Integer compute2(@Nullable java.util.List<java.util.@Nullable List<?>>);
397                             method public Integer compute3(@NonNull String[][]);
398                           }
399                         }
400                     """
401                 } else {
402                     """
403                         // Signature format: 2.0
404                         package test.pkg {
405                           public class Test {
406                             ctor public Test();
407                             method @Nullable public Integer compute1(@Nullable java.util.List<java.lang.String>);
408                             method @Nullable public Integer compute2(@Nullable java.util.List<java.util.List<?>>);
409                             method public Integer compute3(@NonNull String[][]);
410                           }
411                         }
412                     """
413                 },
414         )
415     }
416 
417     @Test
Check androidx package annotationnull418     fun `Check androidx package annotation`() {
419         check(
420             format = FileFormat.V2,
421             sourceFiles =
422                 arrayOf(
423                     java(
424                         """
425                             package test.pkg;
426                             import androidx.annotation.Nullable;
427                             import androidx.annotation.NonNull;
428                             import java.util.List;
429                             public class Test {
430                                 public @Nullable Integer compute1(@Nullable java.util.List<@Nullable String> list) {
431                                     return 5;
432                                 }
433                                 public @Nullable Integer compute2(@NonNull java.util.List<@NonNull List<?>> list) {
434                                     return 5;
435                                 }
436                             }
437                         """
438                     ),
439                     androidxNonNullSource,
440                     androidxNullableSource,
441                     // Hide androidx.annotation classes.
442                     KnownSourceFiles.androidxAnnotationHide,
443                 ),
444             api =
445                 if (SUPPORT_TYPE_USE_ANNOTATIONS) {
446                     """
447                         package test.pkg {
448                           public class Test {
449                             ctor public Test();
450                             method @Nullable public Integer compute1(@Nullable java.util.List<@Nullable java.lang.String>);
451                             method @Nullable public Integer compute2(@NonNull java.util.List<@NonNull java.util.List<?>>);
452                           }
453                         }
454                     """
455                 } else {
456                     """
457                         package test.pkg {
458                           public class Test {
459                             ctor public Test();
460                             method @Nullable public Integer compute1(@Nullable java.util.List<java.lang.String>);
461                             method @Nullable public Integer compute2(@NonNull java.util.List<java.util.List<?>>);
462                           }
463                         }
464                     """
465                 },
466         )
467     }
468 
469     @Test
Migrate nullness for type-use annotationsnull470     fun `Migrate nullness for type-use annotations`() {
471         check(
472             format = FileFormat.V2,
473             sourceFiles =
474                 arrayOf(
475                     java(
476                         """
477                             package test.pkg;
478                             import androidx.annotation.Nullable;
479                             import androidx.annotation.NonNull;
480                             public class Foo {
481                                public static char @NonNull [] toChars(int codePoint) { return new char[0]; }
482                                public static int codePointAt(char @NonNull [] a, int index) { throw new RuntimeException("Stub!"); }
483                                public <T> T @NonNull [] toArray(T @NonNull [] a);
484                                // New APIs should not be marked *recently* nullable; they're fully nullable
485                                public static @NonNull String newMethod(@Nullable String argument) { return ""; }
486                             }
487                         """
488                     ),
489                     androidxNonNullSource,
490                     androidxNullableSource,
491                     // Hide androidx.annotation classes.
492                     KnownSourceFiles.androidxAnnotationHide,
493                 ),
494             // TODO: Handle multiple nullness annotations
495             migrateNullsApi =
496                 """
497                     package test.pkg {
498                       public class Foo {
499                         ctor public Foo();
500                         method public static int codePointAt(char[], int);
501                         method public <T> T[] toArray(T[]);
502                         method public static char[] toChars(int);
503                       }
504                     }
505                 """,
506             stubFiles =
507                 if (SUPPORT_TYPE_USE_ANNOTATIONS) {
508                     arrayOf(
509                         java(
510                             """
511                                 package test.pkg;
512                                 @SuppressWarnings({"unchecked", "deprecation", "all"})
513                                 public class Foo {
514                                 public Foo() { throw new RuntimeException("Stub!"); }
515                                 public static int codePointAt(char @androidx.annotation.RecentlyNonNull [] a, int index) { throw new RuntimeException("Stub!"); }
516                                 @androidx.annotation.NonNull
517                                 public static java.lang.String newMethod(@android.annotation.Nullable java.lang.String argument) { throw new RuntimeException("Stub!"); }
518                                 public <T> T @android.annotation.RecentlyNonNull [] toArray(T @androidx.annotation.RecentlyNonNull [] a) { throw new RuntimeException("Stub!"); }
519                                 public static char @androidx.annotation.RecentlyNonNull [] toChars(int codePoint) { throw new RuntimeException("Stub!"); }
520                                 }
521                             """
522                         ),
523                     )
524                 } else {
525                     arrayOf(
526                         java(
527                             """
528                                 package test.pkg;
529                                 @SuppressWarnings({"unchecked", "deprecation", "all"})
530                                 public class Foo {
531                                 public Foo() { throw new RuntimeException("Stub!"); }
532                                 public static int codePointAt(char[] a, int index) { throw new RuntimeException("Stub!"); }
533                                 @android.annotation.NonNull
534                                 public static java.lang.String newMethod(@android.annotation.Nullable java.lang.String argument) { throw new RuntimeException("Stub!"); }
535                                 public <T> T[] toArray(T[] a) { throw new RuntimeException("Stub!"); }
536                                 public static char[] toChars(int codePoint) { throw new RuntimeException("Stub!"); }
537                                 }
538                             """
539                         ),
540                     )
541                 },
542         )
543     }
544 
545     @Test
Do not migrate type-use annotations when not changednull546     fun `Do not migrate type-use annotations when not changed`() {
547         check(
548             format = FileFormat.V2,
549             sourceFiles =
550                 arrayOf(
551                     java(
552                         """
553                             package test.pkg;
554                             import androidx.annotation.Nullable;
555                             import androidx.annotation.NonNull;
556                             public class Foo {
557                                public static char @NonNull [] toChars(int codePoint) { return new char[0]; }
558                                public static int codePointAt(char @NonNull [] a, int index) { throw new RuntimeException("Stub!"); }
559                                public <T> T @NonNull [] toArray(T @NonNull [] a);
560                             }
561                         """
562                     ),
563                     androidxNonNullSource,
564                     androidxNullableSource,
565                     // Hide androidx.annotation classes.
566                     KnownSourceFiles.androidxAnnotationHide,
567                 ),
568             // TODO: Handle multiple nullness annotations
569             migrateNullsApi =
570                 """
571                     package test.pkg {
572                       public class Foo {
573                         ctor public Foo();
574                         method public static int codePointAt(char[], int);
575                         method public <T> T[] toArray(T[]);
576                         method public static char[] toChars(int);
577                       }
578                     }
579                 """,
580             stubFiles =
581                 if (SUPPORT_TYPE_USE_ANNOTATIONS) {
582                     arrayOf(
583                         java(
584                             """
585                                 package test.pkg;
586                                 @SuppressWarnings({"unchecked", "deprecation", "all"})
587                                 public class Foo {
588                                 public Foo() { throw new RuntimeException("Stub!"); }
589                                 public static int codePointAt(char @androidx.annotation.RecentlyNonNull [] a, int index) { throw new RuntimeException("Stub!"); }
590                                 public <T> T @androidx.annotation.RecentlyNonNull [] toArray(T @androidx.annotation.RecentlyNonNull [] a) { throw new RuntimeException("Stub!"); }
591                                 public static char @androidx.annotation.RecentlyNonNull [] toChars(int codePoint) { throw new RuntimeException("Stub!"); }
592                                 }
593                             """
594                         ),
595                     )
596                 } else {
597                     arrayOf(
598                         java(
599                             """
600                                 package test.pkg;
601                                 @SuppressWarnings({"unchecked", "deprecation", "all"})
602                                 public class Foo {
603                                 public Foo() { throw new RuntimeException("Stub!"); }
604                                 public static int codePointAt(char[] a, int index) { throw new RuntimeException("Stub!"); }
605                                 public <T> T[] toArray(T[] a) { throw new RuntimeException("Stub!"); }
606                                 public static char[] toChars(int codePoint) { throw new RuntimeException("Stub!"); }
607                                 }
608                             """
609                         ),
610                     )
611                 },
612         )
613     }
614 
615     @Test
Regression test for issue 111054266, type use annotationsnull616     fun `Regression test for issue 111054266, type use annotations`() {
617         check(
618             format = FileFormat.V2,
619             sourceFiles =
620                 arrayOf(
621                     java(
622                         """
623                             package test.pkg;
624                             import androidx.annotation.NonNull;
625                             import java.lang.reflect.TypeVariable;
626 
627                             public class Foo {
628                                 @NonNull public java.lang.reflect.Constructor<?> @NonNull [] getConstructors() {
629                                     return null;
630                                 }
631 
632                                 public synchronized @NonNull TypeVariable<@NonNull Class<T>> @NonNull [] getTypeParameters() {
633                                     return null;
634                                 }
635                             }
636                         """
637                     ),
638                     androidxNonNullSource,
639                     androidxNullableSource,
640                     // Hide androidx.annotation classes.
641                     KnownSourceFiles.androidxAnnotationHide,
642                 ),
643             migrateNullsApi =
644                 """
645                     package test.pkg {
646                       public class Foo {
647                         ctor public Foo();
648                         method public java.lang.reflect.Constructor<?>[] getConstructors();
649                         method public synchronized java.lang.reflect.TypeVariable<@java.lang.Class<T>>[] getTypeParameters();
650                       }
651                     }
652                 """,
653             stubFiles =
654                 if (SUPPORT_TYPE_USE_ANNOTATIONS) {
655                     arrayOf(
656                         java(
657                             """
658                                 package test.pkg;
659                                 @SuppressWarnings({"unchecked", "deprecation", "all"})
660                                 public class Foo {
661                                 public Foo() { throw new RuntimeException("Stub!"); }
662                                 @androidx.annotation.RecentlyNonNull
663                                 public java.lang.reflect.Constructor<?> @androidx.annotation.RecentlyNonNull [] getConstructors() { throw new RuntimeException("Stub!"); }
664                                 @androidx.annotation.RecentlyNonNull
665                                 public synchronized java.lang.reflect.TypeVariable<[email protected] Class<T>> @androidx.annotation.RecentlyNonNull [] getTypeParameters() { throw new RuntimeException("Stub!"); }
666                                 }
667                             """
668                         ),
669                     )
670                 } else {
671                     arrayOf(
672                         java(
673                             """
674                                 package test.pkg;
675                                 @SuppressWarnings({"unchecked", "deprecation", "all"})
676                                 public class Foo {
677                                 public Foo() { throw new RuntimeException("Stub!"); }
678                                 @androidx.annotation.RecentlyNonNull
679                                 public java.lang.reflect.Constructor<?>[] getConstructors() { throw new RuntimeException("Stub!"); }
680                                 @androidx.annotation.RecentlyNonNull
681                                 public synchronized java.lang.reflect.TypeVariable<java.lang.Class<T>>[] getTypeParameters() { throw new RuntimeException("Stub!"); }
682                                 }
683                             """
684                         ),
685                     )
686                 },
687         )
688     }
689 
690     @Test
Merge nullness annotations in stubs that are not in the API signature filenull691     fun `Merge nullness annotations in stubs that are not in the API signature file`() {
692         check(
693             format = FileFormat.V2,
694             includeSystemApiAnnotations = true,
695             sourceFiles =
696                 arrayOf(
697                     java(
698                         """
699                             package test.pkg;
700 
701                             import androidx.annotation.NonNull;
702                             import androidx.annotation.Nullable;
703 
704                             public interface Appendable {
705                                 @NonNull Appendable append(@Nullable java.lang.CharSequence csq) throws IOException;
706                             }
707                         """
708                     ),
709                     java(
710                         """
711                             package test.pkg;
712 
713                             import androidx.annotation.NonNull;
714                             import androidx.annotation.Nullable;
715 
716                             public class PublicClass {
717                                 public PublicClass(@Nullable String s) {}
718                                 @Nullable public String method(@NonNull Integer i) {}
719                                 @Nullable public String field;
720                             }
721                         """
722                     ),
723                     java(
724                         """
725                             package test.pkg;
726 
727                             import androidx.annotation.NonNull;
728                             import androidx.annotation.Nullable;
729 
730                             /** @hide */
731                             @android.annotation.SystemApi
732                             public class ForSystemUse {
733                                 public ForSystemUse(@NonNull String s) {}
734                                 @NonNull public Object foo(@Nullable String foo) {return "";}
735                                 @Nullable public String bar;
736                             }
737                         """
738                     ),
739                     androidxNonNullSource,
740                     androidxNullableSource,
741                 ),
742             migrateNullsApiList =
743                 listOf(
744                     """
745                         package test.pkg {
746                           public interface Appendable {
747                             method public Appendable append(java.lang.CharSequence csq) throws IOException;
748                           }
749                           public class PublicClass {
750                             ctor public PublicClass(String);
751                             method public String method(Integer);
752                             field public String field;
753                           }
754                         }
755                     """,
756                     """
757                         package test.pkg {
758                           public class ForSystemUse {
759                             ctor public ForSystemUse(String);
760                             method public Object foo(String foo);
761                             field public String bar;
762                           }
763                         }
764                     """,
765                 ),
766             stubFiles =
767                 arrayOf(
768                     java(
769                         """
770                             package test.pkg;
771                             @SuppressWarnings({"unchecked", "deprecation", "all"})
772                             public interface Appendable {
773                             @androidx.annotation.RecentlyNonNull
774                             public test.pkg.Appendable append(@androidx.annotation.RecentlyNullable java.lang.CharSequence csq);
775                             }
776                         """
777                     ),
778                     java(
779                         // TODO(b/347885819): The `field` should be `@RecentlyNullable`.
780                         """
781                             package test.pkg;
782                             @SuppressWarnings({"unchecked", "deprecation", "all"})
783                             public class PublicClass {
784                             public PublicClass(@androidx.annotation.RecentlyNullable java.lang.String s) { throw new RuntimeException("Stub!"); }
785                             @androidx.annotation.RecentlyNullable
786                             public java.lang.String method(@androidx.annotation.RecentlyNonNull java.lang.Integer i) { throw new RuntimeException("Stub!"); }
787                             @androidx.annotation.RecentlyNullable public java.lang.String field;
788                             }
789                         """
790                     ),
791                     java(
792                         """
793                             package test.pkg;
794                             /** @hide */
795                             @SuppressWarnings({"unchecked", "deprecation", "all"})
796                             public class ForSystemUse {
797                             public ForSystemUse(@androidx.annotation.RecentlyNonNull java.lang.String s) { throw new RuntimeException("Stub!"); }
798                             @androidx.annotation.RecentlyNonNull
799                             public java.lang.Object foo(@androidx.annotation.RecentlyNullable java.lang.String foo) { throw new RuntimeException("Stub!"); }
800                             @androidx.annotation.RecentlyNullable public java.lang.String bar;
801                             }
802                         """
803                     ),
804                 ),
805             api =
806                 """
807                     // Signature format: 2.0
808                     package test.pkg {
809                       public class ForSystemUse {
810                         ctor public ForSystemUse(@NonNull String);
811                         method @NonNull public Object foo(@Nullable String);
812                         field @Nullable public String bar;
813                       }
814                     }
815                 """,
816         )
817     }
818 
819     @Test
Test inherited methodsnull820     fun `Test inherited methods`() {
821         check(
822             migrateNullsApi =
823                 """
824                     package test.pkg {
825                       public class Child1 extends test.pkg.Parent {
826                       }
827                       public class Child2 extends test.pkg.Parent {
828                         method public void method0(java.lang.String, int);
829                         method public void method4(java.lang.String, int);
830                       }
831                       public class Parent {
832                         method public void method1(java.lang.String, int);
833                         method public void method2(java.lang.String, int);
834                         method public void method3(java.lang.String, int);
835                       }
836                     }
837                 """,
838             sourceFiles =
839                 arrayOf(
840                     java(
841                         """
842                             package test.pkg;
843 
844                             import androidx.annotation.NonNull;
845 
846                             public class Child1 extends Parent {
847                                 private Child1() {}
848                                 @Override
849                                 public void method1(@NonNull String first, int second) {
850                                 }
851                             }
852                         """
853                     ),
854                     java(
855                         """
856                             package test.pkg;
857 
858                             import androidx.annotation.NonNull;
859 
860                             public class Child2 extends Parent {
861                                 private Child2() {}
862                                 @Override
863                                 public void method0(String first, int second) {
864                                 }
865                                 @Override
866                                 public void method1(String first, int second) {
867                                 }
868                                 @Override
869                                 public void method2(@NonNull String first, int second) {
870                                 }
871                                 @Override
872                                 public void method3(String first, int second) {
873                                 }
874                                 @Override
875                                 public void method4(String first, int second) {
876                                 }
877                             }
878                         """
879                     ),
880                     java(
881                         """
882                             package test.pkg;
883 
884                             import androidx.annotation.Nullable;
885                             import androidx.annotation.NonNull;
886 
887                             public class Parent {
888                                 private Parent() { }
889                                 public void method1(String first, int second) {
890                                 }
891                                 public void method2(@NonNull String first, int second) {
892                                 }
893                                 public void method3(String first, int second) {
894                                 }
895                             }
896                         """
897                     ),
898                     androidxNonNullSource,
899                     androidxNullableSource,
900                 ),
901             stubFiles =
902                 arrayOf(
903                     java(
904                         """
905                             package test.pkg;
906                             @SuppressWarnings({"unchecked", "deprecation", "all"})
907                             public class Child1 extends test.pkg.Parent {
908                             Child1() { throw new RuntimeException("Stub!"); }
909                             public void method1(@androidx.annotation.RecentlyNonNull java.lang.String first, int second) { throw new RuntimeException("Stub!"); }
910                             }
911                         """
912                     ),
913                     java(
914                         """
915                             package test.pkg;
916                             @SuppressWarnings({"unchecked", "deprecation", "all"})
917                             public class Child2 extends test.pkg.Parent {
918                             Child2() { throw new RuntimeException("Stub!"); }
919                             public void method0(java.lang.String first, int second) { throw new RuntimeException("Stub!"); }
920                             public void method1(java.lang.String first, int second) { throw new RuntimeException("Stub!"); }
921                             public void method2(@androidx.annotation.RecentlyNonNull java.lang.String first, int second) { throw new RuntimeException("Stub!"); }
922                             public void method3(java.lang.String first, int second) { throw new RuntimeException("Stub!"); }
923                             public void method4(java.lang.String first, int second) { throw new RuntimeException("Stub!"); }
924                             }
925                         """
926                     ),
927                 ),
928         )
929     }
930 }
931