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