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