xref: /aosp_15_r20/tools/metalava/metalava/src/test/java/com/android/tools/metalava/AnnotationsMergerTest.kt (revision 115816f9299ab6ddd6b9673b81f34e707f6bacab)
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tools.metalava
18 
19 import com.android.tools.metalava.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="&quot;null-&gt;true&quot;" />
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="&quot;AGSL&quot;" />
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="&quot;AGSL&quot;" />
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="&quot;null-&gt;true&quot;" />
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="&quot;AGSL&quot;" />
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="&quot;null-&gt;true&quot;" />
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="&quot;AGSL&quot;" />
1081                     </annotation>
1082                   </item>
1083                 </root>
1084                 """
1085                 )
1086         )
1087     }
1088 }
1089