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.cli.common.ARG_WARNING 20 import com.android.tools.metalava.model.text.FileFormat 21 import com.android.tools.metalava.reporter.Issues 22 import com.android.tools.metalava.testing.KnownSourceFiles 23 import com.android.tools.metalava.testing.KnownSourceFiles.androidxAnnotationHide 24 import com.android.tools.metalava.testing.java 25 import org.junit.Test 26 27 class AnnotationsMergerTest : DriverTest() { 28 29 // TODO: Test what happens when we have conflicting data 30 // - NULLABLE_SOURCE on one non null on the other 31 // - annotation specified with different parameters (e.g @Size(4) vs @Size(6)) 32 // Test with jar file 33 34 @Test Merge conflicting nullability when merging from sourcesnull35 fun `Merge conflicting nullability when merging from sources`() { 36 check( 37 format = FileFormat.V2, 38 sourceFiles = 39 arrayOf( 40 androidxAnnotationHide, 41 androidxNullableSource, 42 androidxNonNullSource, 43 java( 44 """ 45 package test.pkg; 46 import androidx.annotation.Nullable; 47 import androidx.annotation.NonNull; 48 public class MyTest { 49 private MyTest() {} 50 public @NonNull Number nonNull; 51 public @Nullable Number nullable; 52 } 53 """ 54 ) 55 ), 56 mergeJavaStubAnnotations = 57 """ 58 package test.pkg; 59 import androidx.annotation.Nullable; 60 import androidx.annotation.NonNull; 61 public class MyTest { 62 private MyTest() {} 63 public @Nullable Number nonNull; 64 public @NonNull Number nullable; 65 } 66 """, 67 api = 68 """ 69 // Signature format: 2.0 70 package test.pkg { 71 public class MyTest { 72 field @NonNull public Number nonNull; 73 field @Nullable public Number nullable; 74 } 75 } 76 """, 77 expectedIssues = 78 """ 79 src/test/pkg/MyTest.java:6: warning: Merge conflict, has @NonNull (or equivalent) attempting to merge @Nullable (or equivalent) (ErrorWhenNew) [InconsistentMergeAnnotation] 80 src/test/pkg/MyTest.java:7: warning: Merge conflict, has @Nullable (or equivalent) attempting to merge @NonNull (or equivalent) (ErrorWhenNew) [InconsistentMergeAnnotation] 81 """, 82 ) 83 } 84 85 @Test Merge conflicting nullability when merging from XMLnull86 fun `Merge conflicting nullability when merging from XML`() { 87 check( 88 format = FileFormat.V2, 89 sourceFiles = 90 arrayOf( 91 androidxAnnotationHide, 92 androidxNullableSource, 93 androidxNonNullSource, 94 java( 95 """ 96 package test.pkg; 97 import androidx.annotation.Nullable; 98 import androidx.annotation.NonNull; 99 public class MyTest { 100 private MyTest() {} 101 public @NonNull Number nonNull; 102 public @Nullable Number nullable; 103 } 104 """ 105 ) 106 ), 107 mergeXmlAnnotations = 108 """<?xml version="1.0" encoding="UTF-8"?> 109 <root> 110 <item name="test.pkg.MyTest nonNull"> 111 <annotation name="androidx.annotation.Nullable" /> 112 </item> 113 <item name="test.pkg.MyTest nullable"> 114 <annotation name="androidx.annotation.NonNull" /> 115 </item> 116 </root> 117 """, 118 api = 119 """ 120 // Signature format: 2.0 121 package test.pkg { 122 public class MyTest { 123 field @NonNull public Number nonNull; 124 field @Nullable public Number nullable; 125 } 126 } 127 """, 128 expectedIssues = 129 """ 130 src/test/pkg/MyTest.java:6: warning: Merge conflict, has @NonNull (or equivalent) attempting to merge @Nullable (or equivalent) (ErrorWhenNew) [InconsistentMergeAnnotation] 131 src/test/pkg/MyTest.java:7: warning: Merge conflict, has @Nullable (or equivalent) attempting to merge @NonNull (or equivalent) (ErrorWhenNew) [InconsistentMergeAnnotation] 132 """, 133 ) 134 } 135 136 @Test Signature files contain annotationsnull137 fun `Signature files contain annotations`() { 138 check( 139 format = FileFormat.V2, 140 includeSystemApiAnnotations = false, 141 sourceFiles = 142 arrayOf( 143 java( 144 """ 145 package test.pkg; 146 147 import androidx.annotation.NonNull; 148 import androidx.annotation.Nullable; 149 import android.annotation.IntRange; 150 import androidx.annotation.UiThread; 151 152 @UiThread 153 public class MyTest { 154 public @Nullable Number myNumber; 155 public @Nullable Double convert(@NonNull Float f) { return null; } 156 public @IntRange(from=10,to=20) int clamp(int i) { return 10; } 157 }""" 158 ), 159 uiThreadSource, 160 intRangeAnnotationSource, 161 androidxNonNullSource, 162 androidxNullableSource, 163 // Hide android.annotation classes. 164 KnownSourceFiles.androidAnnotationHide, 165 // Hide androidx.annotation classes. 166 KnownSourceFiles.androidxAnnotationHide, 167 ), 168 api = 169 """ 170 package test.pkg { 171 @UiThread public class MyTest { 172 ctor public MyTest(); 173 method @IntRange(from=10, to=20) public int clamp(int); 174 method @Nullable public Double convert(@NonNull Float); 175 field @Nullable public Number myNumber; 176 } 177 } 178 """ 179 ) 180 } 181 182 @Test Merged class and method annotations with no argumentsnull183 fun `Merged class and method annotations with no arguments`() { 184 check( 185 format = FileFormat.V2, 186 sourceFiles = 187 arrayOf( 188 java( 189 """ 190 package test.pkg; 191 192 public class MyTest { 193 public Number myNumber; 194 public Double convert(Float f) { return null; } 195 public int clamp(int i) { return 10; } 196 } 197 """ 198 ) 199 ), 200 mergeXmlAnnotations = 201 """<?xml version="1.0" encoding="UTF-8"?> 202 <root> 203 <item name="test.pkg.MyTest"> 204 <annotation name="androidx.annotation.UiThread" /> 205 </item> 206 <item name="test.pkg.MyTest java.lang.Double convert(java.lang.Float)"> 207 <annotation name="androidx.annotation.Nullable" /> 208 </item> 209 <item name="test.pkg.MyTest java.lang.Double convert(java.lang.Float) 0"> 210 <annotation name="androidx.annotation.NonNull" /> 211 </item> 212 <item name="test.pkg.MyTest myNumber"> 213 <annotation name="androidx.annotation.Nullable" /> 214 </item> 215 <item name="test.pkg.MyTest int clamp(int)"> 216 <annotation name="androidx.annotation.IntRange"> 217 <val name="from" val="10" /> 218 <val name="to" val="20" /> 219 </annotation> 220 </item> 221 <item name="test.pkg.MyTest int clamp(int) 0"> 222 <annotation name='org.jetbrains.annotations.Range'> 223 <val name="from" val="-1"/> 224 <val name="to" val="java.lang.Integer.MAX_VALUE"/> 225 </annotation> 226 </item> 227 </root> 228 """, 229 api = 230 """ 231 package test.pkg { 232 @UiThread public class MyTest { 233 ctor public MyTest(); 234 method @IntRange(from=10, to=20) public int clamp(@IntRange(from=-1L, to=java.lang.Integer.MAX_VALUE) int); 235 method @Nullable public Double convert(@NonNull Float); 236 field @Nullable public Number myNumber; 237 } 238 } 239 """ 240 ) 241 } 242 243 @Test Merge signature filesnull244 fun `Merge signature files`() { 245 check( 246 format = FileFormat.V2, 247 sourceFiles = 248 arrayOf( 249 java( 250 """ 251 package test.pkg; 252 253 public interface Appendable { 254 Appendable append(CharSequence csq) throws IOException; 255 } 256 """ 257 ) 258 ), 259 mergeSignatureAnnotations = 260 """ 261 // Signature format: 3.0 262 package test.pkg { 263 public interface Appendable { 264 method public test.pkg.Appendable append(java.lang.CharSequence?); 265 method public test.pkg.Appendable append2(java.lang.CharSequence?); 266 method @Deprecated public java.lang.String! reverse(java.lang.String!); 267 } 268 @Deprecated public interface RandomClass { 269 method @Deprecated public test.pkg.Appendable append(java.lang.CharSequence); 270 } 271 } 272 """, 273 api = 274 """ 275 package test.pkg { 276 public interface Appendable { 277 method @NonNull public test.pkg.Appendable append(@Nullable CharSequence); 278 } 279 } 280 """, 281 expectedIssues = 282 """ 283 merged-annotations.txt:5: warning: qualifier annotations were given for method test.pkg.Appendable.append2(CharSequence) but no matching item was found [UnmatchedMergeAnnotation] 284 merged-annotations.txt:6: warning: qualifier annotations were given for method test.pkg.Appendable.reverse(String) but no matching item was found [UnmatchedMergeAnnotation] 285 merged-annotations.txt:8: warning: qualifier annotations were given for class test.pkg.RandomClass but no matching item was found [UnmatchedMergeAnnotation] 286 """, 287 extraArguments = arrayOf(ARG_WARNING, Issues.UNMATCHED_MERGE_ANNOTATION.name) 288 ) 289 } 290 291 @Test Merge qualifier annotations from Java stub filesnull292 fun `Merge qualifier annotations from Java stub files`() { 293 check( 294 format = FileFormat.V2, 295 sourceFiles = 296 arrayOf( 297 java( 298 """ 299 package test.pkg; 300 301 public interface Appendable { 302 Appendable append(CharSequence csq) throws IOException; 303 } 304 """ 305 ), 306 libcoreNonNullSource, 307 libcoreNullableSource, 308 // Hide libcore.util classes. 309 KnownSourceFiles.libcodeUtilHide, 310 ), 311 mergeJavaStubAnnotations = 312 """ 313 package test.pkg; 314 315 import libcore.util.NonNull; 316 import libcore.util.Nullable; 317 318 public interface Appendable { 319 @NonNull Appendable append(@Nullable java.lang.CharSequence csq); 320 @NonNull String notPresentWithAnnotations(); 321 void notPresentWithoutAnnotations(); 322 } 323 """, 324 api = 325 """ 326 package test.pkg { 327 public interface Appendable { 328 method @NonNull public test.pkg.Appendable append(@Nullable CharSequence); 329 } 330 } 331 """, 332 extraArguments = 333 arrayOf( 334 ARG_WARNING, 335 Issues.UNMATCHED_MERGE_ANNOTATION.name, 336 ), 337 expectedIssues = 338 """ 339 qualifier/test/pkg/Appendable.java:8: warning: qualifier annotations were given for method test.pkg.Appendable.notPresentWithAnnotations() but no matching item was found [UnmatchedMergeAnnotation] 340 """, 341 ) 342 } 343 344 @Test Merge qualifier annotations from Java stub files onto stubs that are not in the API signature filenull345 fun `Merge qualifier annotations from Java stub files onto stubs that are not in the API signature file`() { 346 check( 347 format = FileFormat.V2, 348 includeSystemApiAnnotations = true, 349 sourceFiles = 350 arrayOf( 351 java( 352 """ 353 package test.pkg; 354 355 public interface Appendable { 356 Appendable append(CharSequence csq) throws IOException; 357 } 358 """ 359 ), 360 java( 361 """ 362 package test.pkg; 363 364 /** @hide */ 365 @android.annotation.TestApi 366 public interface ForTesting { 367 void foo(); 368 } 369 """ 370 ), 371 libcoreNonNullSource, 372 libcoreNullableSource 373 ), 374 mergeJavaStubAnnotations = 375 """ 376 package test.pkg; 377 378 import libcore.util.NonNull; 379 import libcore.util.Nullable; 380 381 public interface Appendable { 382 @NonNull Appendable append(@Nullable java.lang.CharSequence csq); 383 } 384 """, 385 stubFiles = 386 arrayOf( 387 java( 388 """ 389 package test.pkg; 390 @SuppressWarnings({"unchecked", "deprecation", "all"}) 391 public interface Appendable { 392 @android.annotation.NonNull 393 public test.pkg.Appendable append(@android.annotation.Nullable java.lang.CharSequence csq); 394 } 395 """ 396 ), 397 java( 398 """ 399 package test.pkg; 400 /** @hide */ 401 @SuppressWarnings({"unchecked", "deprecation", "all"}) 402 public interface ForTesting { 403 public void foo(); 404 } 405 """ 406 ) 407 ), 408 api = 409 """ 410 package test.pkg { 411 public interface ForTesting { 412 method public void foo(); 413 } 414 } 415 """, 416 ) 417 } 418 419 @Test Merge type use qualifier annotations from Java stub filesnull420 fun `Merge type use qualifier annotations from Java stub files`() { 421 // See b/123223339 422 check( 423 format = FileFormat.V2, 424 sourceFiles = 425 arrayOf( 426 java( 427 """ 428 package test.pkg; 429 430 public class Test { 431 private Test() { } 432 public void foo(Object... args) { } 433 } 434 """ 435 ), 436 libcoreNonNullSource, 437 libcoreNullableSource, 438 // Hide libcore.util classes. 439 KnownSourceFiles.libcodeUtilHide, 440 ), 441 mergeJavaStubAnnotations = 442 """ 443 package test.pkg; 444 445 public class Test { 446 public void foo([email protected] Object @libcore.util.NonNull ... args) { throw new RuntimeException("Stub!"); } 447 } 448 """, 449 api = 450 """ 451 package test.pkg { 452 public class Test { 453 method public void foo(@NonNull java.lang.Object...); 454 } 455 } 456 """, 457 ) 458 } 459 460 @Test Merge qualifier annotations from Java stub files making sure they apply to public members of hidden superclassesnull461 fun `Merge qualifier annotations from Java stub files making sure they apply to public members of hidden superclasses`() { 462 check( 463 format = FileFormat.V2, 464 sourceFiles = 465 arrayOf( 466 java( 467 """ 468 package test.pkg; 469 class HiddenSuperClass { 470 @Override public String publicMethod(Object object) {return "";} 471 } 472 """ 473 ), 474 java( 475 """ 476 package test.pkg; 477 478 public class PublicClass extends HiddenSuperClass { 479 } 480 """ 481 ), 482 libcoreNonNullSource, 483 libcoreNullableSource, 484 // Hide libcore.util classes. 485 KnownSourceFiles.libcodeUtilHide, 486 ), 487 mergeJavaStubAnnotations = 488 """ 489 package test.pkg; 490 491 import libcore.util.NonNull; 492 import libcore.util.Nullable; 493 494 public class PublicClass { 495 @NonNull public String publicMethod(@Nullable Object object) {return "";} 496 } 497 """, 498 api = 499 """ 500 package test.pkg { 501 public class PublicClass { 502 ctor public PublicClass(); 503 method @NonNull public String publicMethod(@Nullable Object); 504 } 505 } 506 """, 507 ) 508 } 509 510 @Test Merge inclusion annotations from Java stub filesnull511 fun `Merge inclusion annotations from Java stub files`() { 512 check( 513 format = FileFormat.V2, 514 expectedIssues = 515 """ 516 inclusion1/src/test/pkg/HiddenExample.java:7: warning: inclusion annotations were given for method test.pkg.HiddenExample.notPresentWithAnnotations() but no matching item was found [UnmatchedMergeAnnotation] 517 """, 518 sourceFiles = 519 arrayOf( 520 java( 521 "src/test/pkg/Example.annotated.java", 522 """ 523 package test.pkg; 524 525 public interface Example { 526 void aNotAnnotated(); 527 void bHidden(); 528 void cShown(); 529 } 530 """ 531 ), 532 java( 533 "src/test/pkg/HiddenExample.annotated.java", 534 """ 535 package test.pkg; 536 537 public interface HiddenExample { 538 void method(); 539 } 540 """ 541 ) 542 ), 543 hideAnnotations = arrayOf("test.annotation.Hide"), 544 showAnnotations = arrayOf("test.annotation.Show"), 545 showUnannotated = true, 546 mergeInclusionAnnotations = 547 arrayOf( 548 java( 549 """ 550 package test.pkg; 551 552 public interface Example { 553 void aNotAnnotated(); 554 @test.annotation.Hide void bHidden(); 555 @test.annotation.Hide @test.annotation.Show void cShown(); 556 } 557 """ 558 ), 559 java( 560 """ 561 package test.pkg; 562 563 @test.annotation.Hide 564 public interface HiddenExample { 565 void method(); 566 @test.annotation.Hide 567 void notPresentWithAnnotations(); 568 void notPresentWithoutAnnotations(); 569 } 570 """ 571 ), 572 ), 573 api = 574 """ 575 package test.pkg { 576 public interface Example { 577 method public void aNotAnnotated(); 578 method public void cShown(); 579 } 580 } 581 """, 582 extraArguments = arrayOf(ARG_WARNING, Issues.UNMATCHED_MERGE_ANNOTATION.name), 583 ) 584 } 585 586 @Test Merge inclusion annotations from multiple Java stub filesnull587 fun `Merge inclusion annotations from multiple Java stub files`() { 588 check( 589 format = FileFormat.V2, 590 expectedIssues = "", 591 sourceFiles = 592 arrayOf( 593 java( 594 """ 595 package test.pkg; 596 597 public interface Example { 598 void aNotAnnotated(); 599 void bHidden(); 600 void cShown(); 601 } 602 """ 603 ), 604 java( 605 """ 606 package test.pkg; 607 608 public interface HiddenExample { 609 void method(); 610 } 611 """ 612 ), 613 ), 614 hideAnnotations = arrayOf("test.annotation.Hide"), 615 showAnnotations = arrayOf("test.annotation.Show"), 616 showUnannotated = true, 617 mergeInclusionAnnotations = 618 arrayOf( 619 java( 620 """ 621 package test.pkg; 622 623 public interface Example { 624 void aNotAnnotated(); 625 void bHidden(); 626 @test.annotation.Show void cShown(); 627 } 628 """ 629 ), 630 java( 631 """ 632 package test.pkg; 633 634 public interface Example { 635 void aNotAnnotated(); 636 @test.annotation.Hide void bHidden(); 637 @test.annotation.Hide void cShown(); 638 } 639 """ 640 ), 641 java( 642 """ 643 package test.pkg; 644 645 @test.annotation.Hide 646 public interface HiddenExample { 647 void method(); 648 } 649 """ 650 ), 651 ), 652 api = 653 """ 654 package test.pkg { 655 public interface Example { 656 method public void aNotAnnotated(); 657 method public void cShown(); 658 } 659 } 660 """ 661 ) 662 } 663 664 @Test Merge @FlaggedApi inclusion annotations from Java stub filesnull665 fun `Merge @FlaggedApi inclusion annotations from Java stub files`() { 666 check( 667 format = FileFormat.V2, 668 expectedIssues = "", 669 sourceFiles = 670 arrayOf( 671 java( 672 """ 673 package test.pkg; 674 675 public interface Example { 676 void aNotAnnotated(); 677 void cShown(); 678 } 679 """ 680 ), 681 ), 682 hideAnnotations = arrayOf("test.annotation.Hide"), 683 showAnnotations = arrayOf("test.annotation.Show"), 684 showUnannotated = true, 685 mergeInclusionAnnotations = 686 arrayOf( 687 java( 688 """ 689 package test.pkg; 690 691 public interface Example { 692 void aNotAnnotated(); 693 void bHidden(); 694 @test.annotation.Hide @test.annotation.Show void cShown(); 695 } 696 """ 697 ), 698 java( 699 """ 700 package test.pkg; 701 702 public interface Example { 703 void aNotAnnotated(); 704 @android.annotation.FlaggedApi("flag") 705 void cShown(); 706 } 707 """ 708 ), 709 ), 710 api = 711 """ 712 package test.pkg { 713 public interface Example { 714 method public void aNotAnnotated(); 715 method @FlaggedApi("flag") public void cShown(); 716 } 717 } 718 """ 719 ) 720 } 721 722 @Test Merge inclusion annotations from Java stub files using --show-single-annotationnull723 fun `Merge inclusion annotations from Java stub files using --show-single-annotation`() { 724 check( 725 format = FileFormat.V2, 726 sourceFiles = 727 arrayOf( 728 java( 729 "src/test/pkg/Example.annotated.java", 730 """ 731 package test.pkg; 732 733 public interface Example { 734 void aNotAnnotated(); 735 void bShown(); 736 } 737 """ 738 ) 739 ), 740 extraArguments = 741 arrayOf( 742 ARG_HIDE_ANNOTATION, 743 "test.annotation.Hide", 744 ARG_SHOW_SINGLE_ANNOTATION, 745 "test.annotation.Show" 746 ), 747 showUnannotated = true, 748 mergeInclusionAnnotations = 749 arrayOf( 750 java( 751 """ 752 package test.pkg; 753 754 @test.annotation.Hide 755 @test.annotation.Show 756 public interface Example { 757 void aNotAnnotated(); 758 @test.annotation.Show void bShown(); 759 } 760 """ 761 ), 762 ), 763 api = 764 """ 765 package test.pkg { 766 public interface Example { 767 method public void bShown(); 768 } 769 } 770 """ 771 ) 772 } 773 774 @Test Merge inclusion annotations on api in java namespacenull775 fun `Merge inclusion annotations on api in java namespace`() { 776 check( 777 format = FileFormat.V2, 778 sourceFiles = 779 arrayOf( 780 java( 781 "src/java/net/Example.java", 782 """ 783 package java.net; 784 785 public class Example { 786 public void aNotAnnotated() { } 787 public void bShown() { } 788 } 789 """ 790 ) 791 ), 792 extraArguments = arrayOf(ARG_SHOW_SINGLE_ANNOTATION, "test.annotation.Show"), 793 mergeInclusionAnnotations = 794 arrayOf( 795 java( 796 """ 797 package java.net; 798 799 public class Example { 800 void aNotAnnotated(); 801 @test.annotation.Show void bShown(); 802 } 803 """ 804 ), 805 ), 806 api = 807 """ 808 package java.net { 809 public class Example { 810 method public void bShown(); 811 } 812 } 813 """ 814 ) 815 } 816 817 @Test Redefining java lang object plus using some internal classesnull818 fun `Redefining java lang object plus using some internal classes`() { 819 check( 820 sourceFiles = 821 arrayOf( 822 java( 823 """ 824 package java.util; 825 public class HashMap { 826 static class Node { 827 } 828 static class TreeNode extends LinkedHashMap.LinkedHashMapEntry { 829 } 830 } 831 """ 832 ), 833 java( 834 """ 835 package java.util; 836 837 public class LinkedHashMap<K,V> 838 extends HashMap<K,V> 839 implements Map<K,V> 840 { 841 static class LinkedHashMapEntry<K,V> extends HashMap.Node<K,V> { 842 } 843 } 844 845 """ 846 ), 847 java( 848 """ 849 package java.lang; 850 851 public class Object { 852 protected void finalize() throws Throwable { } 853 } 854 """ 855 ) 856 ), 857 extraArguments = arrayOf(ARG_SHOW_SINGLE_ANNOTATION, "libcore.api.CorePlatformApi"), 858 mergeInclusionAnnotations = 859 arrayOf( 860 java( 861 """ 862 package java.util; 863 864 public class LinkedHashMap extends java.util.HashMap { 865 } 866 """ 867 ), 868 ), 869 api = "" // This test is checking that it doesn't crash 870 ) 871 } 872 873 @Test Merge nullability into childnull874 fun `Merge nullability into child`() { 875 // This is a contrived test that verifies that even if Child no longer directly declares 876 // method1, the inherited method1 is still found 877 check( 878 format = FileFormat.V2, 879 sourceFiles = 880 arrayOf( 881 java( 882 """ 883 package test.pkg; 884 public class Child extends Parent { 885 } 886 """ 887 ), 888 java( 889 """ 890 package test.pkg; 891 892 public class Parent { 893 public void method1(String arg) { 894 } 895 } 896 """ 897 ) 898 ), 899 mergeJavaStubAnnotations = 900 """ 901 package test.pkg; 902 903 public class Child { 904 public void method1(@Nullable String arg) { 905 } 906 } 907 """, 908 api = 909 """ 910 package test.pkg { 911 public class Child extends test.pkg.Parent { 912 ctor public Child(); 913 } 914 public class Parent { 915 ctor public Parent(); 916 method public void method1(String); 917 } 918 } 919 """, 920 expectedIssues = "" // should not report that Child.method1 is undefined 921 ) 922 } 923 924 @Test Merge Contract and Language annotations from XML filesnull925 fun `Merge Contract and Language annotations from XML files`() { 926 check( 927 sourceFiles = 928 arrayOf( 929 java( 930 """ 931 package android.text; 932 933 public class TextUtils { 934 public static boolean isEmpty(CharSequence str) { 935 return str == null || str.length() == 0; 936 } 937 } 938 """ 939 ), 940 java( 941 """ 942 package android.graphics; 943 import androidx.annotation.NonNull; 944 public class RuntimeShader { 945 public RuntimeShader(@NonNull String sksl) { 946 } 947 } 948 """ 949 ), 950 androidxNonNullSource, 951 ), 952 mergeXmlAnnotations = 953 """<?xml version="1.0" encoding="UTF-8"?> 954 <root> 955 <item name="android.text.TextUtils boolean isEmpty(java.lang.CharSequence)"> 956 <annotation name="org.jetbrains.annotations.Contract"> 957 <val name="value" val=""null->true"" /> 958 </annotation> 959 </item> 960 <item name="android.text.TextUtils boolean isEmpty(java.lang.CharSequence) 0"> 961 <annotation name="androidx.annotation.Nullable" /> 962 </item> 963 <item name="android.graphics.RuntimeShader RuntimeShader(java.lang.String) 0"> 964 <annotation name="org.intellij.lang.annotations.Language"> 965 <val name="value" val=""AGSL"" /> 966 </annotation> 967 </item> 968 <item name="android.graphics.RuntimeShader RuntimeShader(java.lang.String, boolean) 0"> 969 <annotation name="org.intellij.lang.annotations.Language"> 970 <val name="value" val=""AGSL"" /> 971 </annotation> 972 </item> 973 </root> 974 """, 975 format = FileFormat.V4, 976 api = 977 """ 978 // Signature format: 4.0 979 package android.graphics { 980 public class RuntimeShader { 981 ctor public RuntimeShader(String); 982 } 983 } 984 package android.text { 985 public class TextUtils { 986 ctor public TextUtils(); 987 method public static boolean isEmpty(CharSequence?); 988 } 989 } 990 """, 991 skipEmitPackages = listOf("androidx.annotation"), 992 extractAnnotations = 993 mapOf( 994 "android.text" to 995 """ 996 <?xml version="1.0" encoding="UTF-8"?> 997 <root> 998 <item name="android.text.TextUtils boolean isEmpty(java.lang.CharSequence)"> 999 <annotation name="org.jetbrains.annotations.Contract"> 1000 <val name="value" val=""null->true"" /> 1001 </annotation> 1002 </item> 1003 </root> 1004 """, 1005 "android.graphics" to 1006 """ 1007 <?xml version="1.0" encoding="UTF-8"?> 1008 <root> 1009 <item name="android.graphics.RuntimeShader RuntimeShader(java.lang.String) 0"> 1010 <annotation name="org.intellij.lang.annotations.Language"> 1011 <val name="value" val=""AGSL"" /> 1012 </annotation> 1013 </item> 1014 </root> 1015 """ 1016 ) 1017 ) 1018 } 1019 1020 @Test Merge Contract and Language annotations from signature filesnull1021 fun `Merge Contract and Language annotations from signature files`() { 1022 check( 1023 sourceFiles = 1024 arrayOf( 1025 java( 1026 """ 1027 package android.text; 1028 1029 public class TextUtils { 1030 public static boolean isEmpty(CharSequence str) { 1031 return str == null || str.length() == 0; 1032 } 1033 } 1034 """ 1035 ), 1036 java( 1037 """ 1038 package android.graphics; 1039 public class RuntimeShader { 1040 public RuntimeShader(@NonNull String sksl) { 1041 } 1042 } 1043 """ 1044 ) 1045 ), 1046 format = FileFormat.V4, 1047 mergeSignatureAnnotations = 1048 """ 1049 // Signature format: 4.0 1050 package android.graphics { 1051 public class RuntimeShader { 1052 ctor public RuntimeShader(@org.intellij.lang.annotations.Language("AGSL") String); 1053 } 1054 } 1055 package android.text { 1056 public class TextUtils { 1057 method @org.jetbrains.annotations.Contract("null->true") public static boolean isEmpty(CharSequence?); 1058 } 1059 } 1060 """, 1061 extractAnnotations = 1062 mapOf( 1063 "android.text" to 1064 """ 1065 <?xml version="1.0" encoding="UTF-8"?> 1066 <root> 1067 <item name="android.text.TextUtils boolean isEmpty(java.lang.CharSequence)"> 1068 <annotation name="org.jetbrains.annotations.Contract"> 1069 <val name="value" val=""null->true"" /> 1070 </annotation> 1071 </item> 1072 </root> 1073 """, 1074 "android.graphics" to 1075 """ 1076 <?xml version="1.0" encoding="UTF-8"?> 1077 <root> 1078 <item name="android.graphics.RuntimeShader RuntimeShader(java.lang.String) 0"> 1079 <annotation name="org.intellij.lang.annotations.Language"> 1080 <val name="value" val=""AGSL"" /> 1081 </annotation> 1082 </item> 1083 </root> 1084 """ 1085 ) 1086 ) 1087 } 1088 } 1089