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