xref: /aosp_15_r20/tools/metalava/metalava/src/test/java/com/android/tools/metalava/stub/StubsAnnotationTest.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.stub
18 
19 import com.android.tools.metalava.ARG_EXCLUDE_ALL_ANNOTATIONS
20 import com.android.tools.metalava.ARG_EXCLUDE_ANNOTATION
21 import com.android.tools.metalava.ARG_PASS_THROUGH_ANNOTATION
22 import com.android.tools.metalava.androidxNullableSource
23 import com.android.tools.metalava.libcoreNonNullSource
24 import com.android.tools.metalava.model.SUPPORT_TYPE_USE_ANNOTATIONS
25 import com.android.tools.metalava.model.text.FileFormat
26 import com.android.tools.metalava.requiresApiSource
27 import com.android.tools.metalava.supportParameterName
28 import com.android.tools.metalava.testing.KnownSourceFiles
29 import com.android.tools.metalava.testing.java
30 import org.junit.Test
31 
32 @SuppressWarnings("ALL")
33 class StubsAnnotationTest : AbstractStubsTest() {
34     @Test
Generate stubs for annotation typenull35     fun `Generate stubs for annotation type`() {
36         // Interface: makes sure the right modifiers etc are shown (and that "package private"
37         // methods
38         // in the interface are taken to be public etc)
39         checkStubs(
40             sourceFiles =
41                 arrayOf(
42                     java(
43                         """
44                     package test.pkg;
45                     import static java.lang.annotation.ElementType.*;
46                     import java.lang.annotation.*;
47                     @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
48                     @Retention(RetentionPolicy.CLASS)
49                     public @interface Foo {
50                         String value();
51                     }
52                     """
53                     )
54                 ),
55             source =
56                 """
57                 package test.pkg;
58                 @SuppressWarnings({"unchecked", "deprecation", "all"})
59                 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS)
60                 @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE})
61                 public @interface Foo {
62                 public java.lang.String value();
63                 }
64                 """
65         )
66     }
67 
68     @Test
Remove Hidden Annotationsnull69     fun `Remove Hidden Annotations`() {
70         // When APIs reference annotations that are hidden, make sure the're excluded from the stubs
71         // and
72         // signature files
73         checkStubs(
74             format = FileFormat.V2,
75             sourceFiles =
76                 arrayOf(
77                     java(
78                         """
79                     package test.pkg;
80 
81                     public class Foo {
82                         public void foo(int p1, @MyAnnotation("publicParameterName") java.util.Map<java.lang.String, @MyAnnotation("Something") String> p2) {
83                         }
84                     }
85                     """
86                     ),
87                     java(
88                         """
89                     package test.pkg;
90                     import java.lang.annotation.*;
91                     import static java.lang.annotation.ElementType.*;
92                     import static java.lang.annotation.RetentionPolicy.SOURCE;
93                     /** @hide */
94                     @SuppressWarnings("WeakerAccess")
95                     @Retention(SOURCE)
96                     @Target({METHOD, PARAMETER, FIELD, TYPE_USE})
97                     public @interface MyAnnotation {
98                         String value();
99                     }
100                     """
101                     )
102                 ),
103             api =
104                 if (SUPPORT_TYPE_USE_ANNOTATIONS) {
105                     """
106                 package test.pkg {
107                   public class Foo {
108                     ctor public Foo();
109                     method public void foo(int, java.util.Map<java.lang.String!,java.lang.String!>!);
110                   }
111                 }
112                 """
113                 } else {
114                     """
115                 package test.pkg {
116                   public class Foo {
117                     ctor public Foo();
118                     method public void foo(int, java.util.Map<java.lang.String,java.lang.String>);
119                   }
120                 }
121                 """
122                 },
123             source =
124                 if (SUPPORT_TYPE_USE_ANNOTATIONS) {
125                     """
126                 package test.pkg;
127                 @SuppressWarnings({"unchecked", "deprecation", "all"})
128                 public class Foo {
129                 public Foo() { throw new RuntimeException("Stub!"); }
130                 public void foo(int p1, java.util.Map<java.lang.String, java.lang.String> p2) { throw new RuntimeException("Stub!"); }
131                 }
132                 """
133                 } else {
134                     """
135                 package test.pkg;
136                 @SuppressWarnings({"unchecked", "deprecation", "all"})
137                 public class Foo {
138                 public Foo() { throw new RuntimeException("Stub!"); }
139                 public void foo(int p1, java.util.Map<java.lang.String,java.lang.String> p2) { throw new RuntimeException("Stub!"); }
140                 }
141                 """
142                 }
143         )
144     }
145 
146     @Test
Rewrite unknown nullability annotations as sdk stubsnull147     fun `Rewrite unknown nullability annotations as sdk stubs`() {
148         check(
149             format = FileFormat.V2,
150             checkCompilation = true,
151             sourceFiles =
152                 arrayOf(
153                     java(
154                         "package my.pkg;\n" +
155                             "public class String {\n" +
156                             "public String(@other.NonNull char[] value) { throw new RuntimeException(\"Stub!\"); }\n" +
157                             "}\n"
158                     )
159                 ),
160             expectedIssues = "",
161             api =
162                 """
163                     package my.pkg {
164                       public class String {
165                         ctor public String(@NonNull char[]);
166                       }
167                     }
168                     """,
169             stubFiles =
170                 arrayOf(
171                     java(
172                         """
173                     package my.pkg;
174                     @SuppressWarnings({"unchecked", "deprecation", "all"})
175                     public class String {
176                     public String(@android.annotation.NonNull char[] value) { throw new RuntimeException("Stub!"); }
177                     }
178                     """
179                     )
180                 )
181         )
182     }
183 
184     @Test
Rewrite unknown nullability annotations as doc stubsnull185     fun `Rewrite unknown nullability annotations as doc stubs`() {
186         check(
187             format = FileFormat.V2,
188             checkCompilation = true,
189             sourceFiles =
190                 arrayOf(
191                     java(
192                         "package my.pkg;\n" +
193                             "public class String {\n" +
194                             "public String(@other.NonNull char[] value) { throw new RuntimeException(\"Stub!\"); }\n" +
195                             "}\n"
196                     )
197                 ),
198             expectedIssues = "",
199             api =
200                 """
201                     package my.pkg {
202                       public class String {
203                         ctor public String(@NonNull char[]);
204                       }
205                     }
206                     """,
207             docStubs = true,
208             stubFiles =
209                 arrayOf(
210                     java(
211                         """
212                         package my.pkg;
213                         @SuppressWarnings({"unchecked", "deprecation", "all"})
214                         public class String {
215                         public String(@androidx.annotation.NonNull char[] value) { throw new RuntimeException("Stub!"); }
216                         }
217                     """
218                     )
219                 )
220         )
221     }
222 
223     @Test
Rewrite libcore annotationsnull224     fun `Rewrite libcore annotations`() {
225         check(
226             checkCompilation = true,
227             sourceFiles =
228                 arrayOf(
229                     java(
230                         "package my.pkg;\n" +
231                             "public class String {\n" +
232                             "public String(char @libcore.util.NonNull [] value) { throw new RuntimeException(\"Stub!\"); }\n" +
233                             "}\n"
234                     )
235                 ),
236             expectedIssues = "",
237             api =
238                 """
239                     package my.pkg {
240                       public class String {
241                         ctor public String(char[]);
242                       }
243                     }
244                     """,
245             stubFiles =
246                 if (SUPPORT_TYPE_USE_ANNOTATIONS) {
247                     arrayOf(
248                         java(
249                             """
250                         package my.pkg;
251                         @SuppressWarnings({"unchecked", "deprecation", "all"})
252                         public class String {
253                         public String(char @androidx.annotation.NonNull [] value) { throw new RuntimeException("Stub!"); }
254                         }
255                         """
256                         )
257                     )
258                 } else {
259                     arrayOf(
260                         java(
261                             """
262                         package my.pkg;
263                         @SuppressWarnings({"unchecked", "deprecation", "all"})
264                         public class String {
265                         public String(char[] value) { throw new RuntimeException("Stub!"); }
266                         }
267                         """
268                         )
269                     )
270                 }
271         )
272     }
273 
274     @Test
Pass through libcore annotationsnull275     fun `Pass through libcore annotations`() {
276         check(
277             format = FileFormat.V2,
278             checkCompilation = true,
279             extraArguments = arrayOf(ARG_PASS_THROUGH_ANNOTATION, "libcore.util.NonNull"),
280             sourceFiles =
281                 arrayOf(
282                     java(
283                         """
284                     package my.pkg;
285                     public class String {
286                     public String(@libcore.util.NonNull char[] value) { throw new RuntimeException("Stub!"); }
287                     }
288                     """
289                     ),
290                     libcoreNonNullSource
291                 ),
292             expectedIssues = "",
293             api =
294                 """
295                     package libcore.util {
296                       @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE_USE}) public @interface NonNull {
297                       }
298                     }
299                     package my.pkg {
300                       public class String {
301                         ctor public String(@libcore.util.NonNull char[]);
302                       }
303                     }
304                     """,
305             stubFiles =
306                 arrayOf(
307                     java(
308                         """
309                     package my.pkg;
310                     @SuppressWarnings({"unchecked", "deprecation", "all"})
311                     public class String {
312                     public String(@libcore.util.NonNull char[] value) { throw new RuntimeException("Stub!"); }
313                     }
314                     """
315                     )
316                 )
317         )
318     }
319 
320     @Test
Pass through multiple annotationsnull321     fun `Pass through multiple annotations`() {
322         checkStubs(
323             extraArguments =
324                 arrayOf(
325                     ARG_PASS_THROUGH_ANNOTATION,
326                     "androidx.annotation.RequiresApi,androidx.annotation.Nullable",
327                 ),
328             sourceFiles =
329                 arrayOf(
330                     java(
331                         """
332                     package my.pkg;
333                     public class MyClass {
334                         @androidx.annotation.RequiresApi(21)
335                         public void testMethod() {}
336                         @androidx.annotation.Nullable
337                         public String anotherTestMethod() { return null; }
338                     }
339                     """
340                     ),
341                     supportParameterName,
342                     requiresApiSource,
343                     androidxNullableSource,
344                     // Hide androidx.annotation classes.
345                     KnownSourceFiles.androidxAnnotationHide,
346                 ),
347             source =
348                 """
349                 package my.pkg;
350                 @SuppressWarnings({"unchecked", "deprecation", "all"})
351                 public class MyClass {
352                 public MyClass() { throw new RuntimeException("Stub!"); }
353                 @androidx.annotation.Nullable
354                 public java.lang.String anotherTestMethod() { throw new RuntimeException("Stub!"); }
355                 @androidx.annotation.RequiresApi(21)
356                 public void testMethod() { throw new RuntimeException("Stub!"); }
357                 }
358                  """
359         )
360     }
361 
362     @Test
Skip RequiresApi annotationnull363     fun `Skip RequiresApi annotation`() {
364         check(
365             extraArguments = arrayOf(ARG_EXCLUDE_ANNOTATION, "androidx.annotation.RequiresApi"),
366             sourceFiles =
367                 arrayOf(
368                     java(
369                         """
370                     package my.pkg;
371                     public class MyClass {
372                         @androidx.annotation.RequiresApi(21)
373                         public void testMethod() {}
374                     }
375                     """
376                     ),
377                     requiresApiSource
378                 ),
379             expectedIssues = "",
380             api =
381                 """
382                     package androidx.annotation {
383                       @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR}) public @interface RequiresApi {
384                         method public abstract int api() default 1;
385                         method public abstract int value() default 1;
386                       }
387                     }
388                     package my.pkg {
389                       public class MyClass {
390                         ctor public MyClass();
391                         method public void testMethod();
392                       }
393                     }
394                     """,
395             stubFiles =
396                 arrayOf(
397                     java(
398                         """
399                     package my.pkg;
400                     @SuppressWarnings({"unchecked", "deprecation", "all"})
401                     public class MyClass {
402                     public MyClass() { throw new RuntimeException("Stub!"); }
403                     public void testMethod() { throw new RuntimeException("Stub!"); }
404                     }
405                     """
406                     )
407                 )
408         )
409     }
410 
411     @Test
Annotation default valuesnull412     fun `Annotation default values`() {
413         checkStubs(
414             sourceFiles =
415                 arrayOf(
416                     java(
417                         """
418                     package test.pkg;
419 
420                     import java.lang.annotation.ElementType;
421                     import java.lang.annotation.Retention;
422                     import java.lang.annotation.RetentionPolicy;
423                     import java.lang.annotation.Target;
424 
425                     import static java.lang.annotation.RetentionPolicy.SOURCE;
426 
427                     /**
428                      * This annotation can be used to mark fields and methods to be dumped by
429                      * the view server. Only non-void methods with no arguments can be annotated
430                      * by this annotation.
431                      */
432                     @Target({ElementType.FIELD, ElementType.METHOD})
433                     @Retention(RetentionPolicy.RUNTIME)
434                     public @interface ExportedProperty {
435                         /**
436                          * When resolveId is true, and if the annotated field/method return value
437                          * is an int, the value is converted to an Android's resource name.
438                          *
439                          * @return true if the property's value must be transformed into an Android
440                          * resource name, false otherwise
441                          */
442                         boolean resolveId() default false;
443                         String prefix() default "";
444                         String category() default "";
445                         boolean formatToHexString() default false;
446                         boolean hasAdjacentMapping() default false;
447                         Class<? extends Number> myCls() default Integer.class;
448                         char[] letters1() default {};
449                         char[] letters2() default {'a', 'b', 'c'};
450                         double from() default Double.NEGATIVE_INFINITY;
451                         double fromWithCast() default (double)Float.NEGATIVE_INFINITY;
452                         InnerAnnotation value() default @InnerAnnotation;
453                         char letter() default 'a';
454                         int integer() default 1;
455                         long large_integer() default 1L;
456                         float floating() default 1.0f;
457                         double large_floating() default 1.0;
458                         byte small() default 1;
459                         short medium() default 1;
460                         int math() default 1+2*3;
461                         @InnerAnnotation
462                         int unit() default PX;
463                         int DP = 0;
464                         int PX = 1;
465                         int SP = 2;
466                         @Retention(SOURCE)
467                         @interface InnerAnnotation {
468                         }
469                     }
470                     """
471                     )
472                 ),
473             warnings = "",
474             api =
475                 """
476                 package test.pkg {
477                   @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public @interface ExportedProperty {
478                     method public abstract String category() default "";
479                     method public abstract float floating() default 1.0f;
480                     method public abstract boolean formatToHexString() default false;
481                     method public abstract double from() default java.lang.Double.NEGATIVE_INFINITY;
482                     method public abstract double fromWithCast() default (double)java.lang.Float.NEGATIVE_INFINITY;
483                     method public abstract boolean hasAdjacentMapping() default false;
484                     method public abstract int integer() default 1;
485                     method public abstract double large_floating() default 1.0;
486                     method public abstract long large_integer() default 1L;
487                     method public abstract char letter() default 'a';
488                     method public abstract char[] letters1() default {};
489                     method public abstract char[] letters2() default {'a', 'b', 'c'};
490                     method public abstract int math() default 7;
491                     method public abstract short medium() default 1;
492                     method public abstract Class<? extends java.lang.Number!> myCls() default java.lang.Integer.class;
493                     method public abstract String prefix() default "";
494                     method public abstract boolean resolveId() default false;
495                     method public abstract byte small() default 1;
496                     method @test.pkg.ExportedProperty.InnerAnnotation public abstract int unit() default test.pkg.ExportedProperty.PX;
497                     method public abstract test.pkg.ExportedProperty.InnerAnnotation value() default @test.pkg.ExportedProperty.InnerAnnotation;
498                     field public static final int DP = 0; // 0x0
499                     field public static final int PX = 1; // 0x1
500                     field public static final int SP = 2; // 0x2
501                   }
502                   @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ExportedProperty.InnerAnnotation {
503                   }
504                 }
505             """,
506             source =
507                 """
508                 package test.pkg;
509                 /**
510                  * This annotation can be used to mark fields and methods to be dumped by
511                  * the view server. Only non-void methods with no arguments can be annotated
512                  * by this annotation.
513                  */
514                 @SuppressWarnings({"unchecked", "deprecation", "all"})
515                 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
516                 @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD})
517                 public @interface ExportedProperty {
518                 public java.lang.String category() default "";
519                 public float floating() default 1.0f;
520                 public boolean formatToHexString() default false;
521                 public double from() default java.lang.Double.NEGATIVE_INFINITY;
522                 public double fromWithCast() default (double)java.lang.Float.NEGATIVE_INFINITY;
523                 public boolean hasAdjacentMapping() default false;
524                 public int integer() default 1;
525                 public double large_floating() default 1.0;
526                 public long large_integer() default 1L;
527                 public char letter() default 'a';
528                 public char[] letters1() default {};
529                 public char[] letters2() default {'a', 'b', 'c'};
530                 public int math() default 7;
531                 public short medium() default 1;
532                 public java.lang.Class<? extends java.lang.Number> myCls() default java.lang.Integer.class;
533                 public java.lang.String prefix() default "";
534                 /**
535                  * When resolveId is true, and if the annotated field/method return value
536                  * is an int, the value is converted to an Android's resource name.
537                  *
538                  * @return true if the property's value must be transformed into an Android
539                  * resource name, false otherwise
540                  */
541                 public boolean resolveId() default false;
542                 public byte small() default 1;
543                 public int unit() default test.pkg.ExportedProperty.PX;
544                 public test.pkg.ExportedProperty.InnerAnnotation value() default @test.pkg.ExportedProperty.InnerAnnotation;
545                 public static final int DP = 0; // 0x0
546                 public static final int PX = 1; // 0x1
547                 public static final int SP = 2; // 0x2
548                 @SuppressWarnings({"unchecked", "deprecation", "all"})
549                 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
550                 public static @interface InnerAnnotation {
551                 }
552                 }
553                 """
554         )
555     }
556 
557     @Test
Annotation metadata in stubsnull558     fun `Annotation metadata in stubs`() {
559         checkStubs(
560             skipEmitPackages = emptyList(),
561             sourceFiles =
562                 arrayOf(
563                     java(
564                         """
565                     package com.android.metalava.test;
566 
567                     import java.lang.annotation.*;
568 
569                     @Target(ElementType.METHOD)
570                     @Retention(RetentionPolicy.SOURCE)
571                     public @interface MyAnnotation {
572                     }
573                     """
574                     )
575                 ),
576             warnings = "",
577             source =
578                 """
579                 package com.android.metalava.test;
580                 @SuppressWarnings({"unchecked", "deprecation", "all"})
581                 @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
582                 @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD)
583                 public @interface MyAnnotation {
584                 }
585                 """
586         )
587     }
588 
589     @Test
Ensure we emit both deprecated javadoc and annotation with exclude-all-annotationsnull590     fun `Ensure we emit both deprecated javadoc and annotation with exclude-all-annotations`() {
591         check(
592             extraArguments = arrayOf(ARG_EXCLUDE_ALL_ANNOTATIONS),
593             sourceFiles =
594                 arrayOf(
595                     java(
596                         """
597                     package test.pkg;
598                     public class Foo {
599                         /**
600                          * @deprecated Use checkPermission instead.
601                          */
602                         @Deprecated
603                         protected boolean inClass(String name) {
604                             return false;
605                         }
606                     }
607                     """
608                     )
609                 ),
610             stubFiles =
611                 arrayOf(
612                     java(
613                         """
614                     package test.pkg;
615                     @SuppressWarnings({"unchecked", "deprecation", "all"})
616                     public class Foo {
617                     public Foo() { throw new RuntimeException("Stub!"); }
618                     /**
619                      * @deprecated Use checkPermission instead.
620                      */
621                     @Deprecated
622                     protected boolean inClass(java.lang.String name) { throw new RuntimeException("Stub!"); }
623                     }
624                     """
625                     )
626                 )
627         )
628     }
629 
630     @Test
Ensure we emit runtime and deprecated annotations in stubs with exclude-annotationsnull631     fun `Ensure we emit runtime and deprecated annotations in stubs with exclude-annotations`() {
632         check(
633             extraArguments = arrayOf(ARG_EXCLUDE_ALL_ANNOTATIONS),
634             sourceFiles =
635                 arrayOf(
636                     java(
637                         """
638                     package test.pkg;
639                     /** @deprecated */
640                     @MySourceRetentionAnnotation
641                     @MyClassRetentionAnnotation
642                     @MyRuntimeRetentionAnnotation
643                     @Deprecated
644                     public class Foo {
645                         private Foo() {}
646                     }
647                     """
648                     ),
649                     java(
650                         """
651                     package test.pkg;
652                     import java.lang.annotation.Retention;
653                     import static java.lang.annotation.RetentionPolicy.SOURCE;
654                     @Retention(SOURCE)
655                     public @interface MySourceRetentionAnnotation {
656                     }
657                     """
658                     ),
659                     java(
660                         """
661                     package test.pkg;
662                     import java.lang.annotation.Retention;
663                     import static java.lang.annotation.RetentionPolicy.CLASS;
664                     @Retention(CLASS)
665                     public @interface MyClassRetentionAnnotation {
666                     }
667                     """
668                     ),
669                     java(
670                         """
671                     package test.pkg;
672                     import java.lang.annotation.Retention;
673                     import static java.lang.annotation.RetentionPolicy.RUNTIME;
674                     @Retention(RUNTIME)
675                     public @interface MyRuntimeRetentionAnnotation {
676                     }
677                     """
678                     )
679                 ),
680             stubFiles =
681                 arrayOf(
682                     java(
683                         """
684                     package test.pkg;
685                     /** @deprecated */
686                     @SuppressWarnings({"unchecked", "deprecation", "all"})
687                     @Deprecated
688                     @test.pkg.MyRuntimeRetentionAnnotation
689                     public class Foo {
690                     @Deprecated
691                     Foo() { throw new RuntimeException("Stub!"); }
692                     }
693                     """
694                     )
695                 )
696         )
697     }
698 
699     @Test
Ensure we include class and runtime and not source annotations in stubs with include-annotationsnull700     fun `Ensure we include class and runtime and not source annotations in stubs with include-annotations`() {
701         check(
702             extraArguments = arrayOf("--include-annotations"),
703             sourceFiles =
704                 arrayOf(
705                     java(
706                         """
707                     package test.pkg;
708                     /** @deprecated */
709                     @MySourceRetentionAnnotation
710                     @MyClassRetentionAnnotation
711                     @MyRuntimeRetentionAnnotation
712                     @Deprecated
713                     public class Foo {
714                         private Foo() {}
715                         protected int foo;
716                         public void bar();
717                     }
718                     """
719                     ),
720                     java(
721                         """
722                     package test.pkg;
723                     import java.lang.annotation.Retention;
724                     import static java.lang.annotation.RetentionPolicy.SOURCE;
725                     @Retention(SOURCE)
726                     public @interface MySourceRetentionAnnotation {
727                     }
728                     """
729                     ),
730                     java(
731                         """
732                     package test.pkg;
733                     import java.lang.annotation.Retention;
734                     import static java.lang.annotation.RetentionPolicy.CLASS;
735                     @Retention(CLASS)
736                     public @interface MyClassRetentionAnnotation {
737                     }
738                     """
739                     ),
740                     java(
741                         """
742                     package test.pkg;
743                     import java.lang.annotation.Retention;
744                     import static java.lang.annotation.RetentionPolicy.RUNTIME;
745                     @Retention(RUNTIME)
746                     public @interface MyRuntimeRetentionAnnotation {
747                     }
748                     """
749                     )
750                 ),
751             stubFiles =
752                 arrayOf(
753                     java(
754                         """
755                     package test.pkg;
756                     /** @deprecated */
757                     @SuppressWarnings({"unchecked", "deprecation", "all"})
758                     @Deprecated
759                     @test.pkg.MyClassRetentionAnnotation
760                     @test.pkg.MyRuntimeRetentionAnnotation
761                     public class Foo {
762                     @Deprecated
763                     Foo() { throw new RuntimeException("Stub!"); }
764                     @Deprecated
765                     public void bar() { throw new RuntimeException("Stub!"); }
766                     @Deprecated protected int foo;
767                     }
768                     """
769                     )
770                 )
771         )
772     }
773 
774     @Test
Annotation nested rewritingnull775     fun `Annotation nested rewriting`() {
776         checkStubs(
777             sourceFiles =
778                 arrayOf(
779                     java(
780                         """
781                     package test.pkg;
782 
783                     import android.view.Gravity;
784 
785                     public class ActionBar {
786                         @ViewDebug.ExportedProperty(category = "layout", mapping = {
787                                 @ViewDebug.IntToString(from =  -1,                       to = "NONE"),
788                                 @ViewDebug.IntToString(from = Gravity.NO_GRAVITY,        to = "NONE"),
789                                 @ViewDebug.IntToString(from = Gravity.TOP,               to = "TOP"),
790                                 @ViewDebug.IntToString(from = Gravity.BOTTOM,            to = "BOTTOM"),
791                         })
792                         public int gravity = Gravity.NO_GRAVITY;
793                     }
794                     """
795                     ),
796                     java(
797                         """
798                     package android.view;
799 
800                     public class Gravity {
801                         public static final int NO_GRAVITY = 0;
802                         public static final int TOP = 1;
803                         public static final int BOTTOM = 2;
804                     }
805                     """
806                     ),
807                     java(
808                         """
809                     package test.pkg;
810 
811                     import java.lang.annotation.ElementType;
812                     import java.lang.annotation.Retention;
813                     import java.lang.annotation.RetentionPolicy;
814                     import java.lang.annotation.Target;
815 
816                     public class ViewDebug {
817                         @Target({ElementType.FIELD, ElementType.METHOD})
818                         @Retention(RetentionPolicy.RUNTIME)
819                         public @interface ExportedProperty {
820                             boolean resolveId() default false;
821                             IntToString[] mapping() default {};
822                             IntToString[] indexMapping() default {};
823                             boolean deepExport() default false;
824                             String prefix() default "";
825                             String category() default "";
826                             boolean formatToHexString() default false;
827                             boolean hasAdjacentMapping() default false;
828                         }
829                         @Target({ElementType.TYPE})
830                         @Retention(RetentionPolicy.RUNTIME)
831                         public @interface IntToString {
832                             int from();
833                             String to();
834                         }
835                     }
836                     """
837                     )
838                 ),
839             source =
840                 """
841                 package test.pkg;
842                 @SuppressWarnings({"unchecked", "deprecation", "all"})
843                 public class ActionBar {
844                 public ActionBar() { throw new RuntimeException("Stub!"); }
845                 @test.pkg.ViewDebug.ExportedProperty(category="layout", mapping={@test.pkg.ViewDebug.IntToString(from=0xffffffff, to="NONE"), @test.pkg.ViewDebug.IntToString(from=android.view.Gravity.NO_GRAVITY, to="NONE"), @test.pkg.ViewDebug.IntToString(from=android.view.Gravity.TOP, to="TOP"), @test.pkg.ViewDebug.IntToString(from=android.view.Gravity.BOTTOM, to="BOTTOM")}) public int gravity = 0; // 0x0
846                 }
847                 """
848         )
849     }
850 }
851