1 /*
2  * Copyright 2022 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 androidx.build.lint
18 
19 import org.junit.Test
20 import org.junit.runner.RunWith
21 import org.junit.runners.JUnit4
22 
23 @RunWith(JUnit4::class)
24 class ExperimentalPropertyAnnotationDetectorTest :
25     AbstractLintDetectorTest(
26         useDetector = ExperimentalPropertyAnnotationDetector(),
27         useIssues = listOf(ExperimentalPropertyAnnotationDetector.ISSUE),
28         stubs =
29             arrayOf(
30                 kotlin(
31                     """
32         package java.androidx
33 
34         @RequiresOptIn(level = RequiresOptIn.Level.ERROR)
35         @Retention(AnnotationRetention.BINARY)
36         annotation class ExperimentalKotlinAnnotation
37     """
38                 )
39             )
40     ) {
41     @Test
Test correctly annotated var propertiesnull42     fun `Test correctly annotated var properties`() {
43         val input =
44             arrayOf(
45                 kotlin(
46                     """
47                 package java.androidx
48 
49                 class AnnotatedProperty {
50                     @get:ExperimentalKotlinAnnotation
51                     @set:ExperimentalKotlinAnnotation
52                     @ExperimentalKotlinAnnotation
53                     var correctlyAnnotatedWithDefault: Int = 3
54 
55                     @get:ExperimentalKotlinAnnotation
56                     @set:ExperimentalKotlinAnnotation
57                     @property:ExperimentalKotlinAnnotation
58                     var correctlyAnnotatedWithDefault: Int = 3
59                 }
60             """
61                 )
62             )
63 
64         check(*input).expectClean()
65     }
66 
67     @Test
Test var properties annotated with one targetnull68     fun `Test var properties annotated with one target`() {
69         val input =
70             arrayOf(
71                 kotlin(
72                     """
73                 package java.androidx
74 
75                 class AnnotatedProperty {
76                     @get:ExperimentalKotlinAnnotation
77                     var annotatedWithGet = 3
78 
79                     @set:ExperimentalKotlinAnnotation
80                     var annotatedWithSet = 3
81 
82                     @property:ExperimentalKotlinAnnotation
83                     var annotatedWithProperty = 3
84 
85                     @ExperimentalKotlinAnnotation
86                     var annotatedWithDefault = 3
87                 }
88             """
89                 )
90             )
91 
92         val expected =
93             """
94 src/java/androidx/AnnotatedProperty.kt:5: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
95                     @get:ExperimentalKotlinAnnotation
96                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
97 src/java/androidx/AnnotatedProperty.kt:8: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
98                     @set:ExperimentalKotlinAnnotation
99                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
100 src/java/androidx/AnnotatedProperty.kt:11: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
101                     @property:ExperimentalKotlinAnnotation
102                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
103 src/java/androidx/AnnotatedProperty.kt:14: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
104                     @ExperimentalKotlinAnnotation
105                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
106 4 errors, 0 warnings
107         """
108 
109         val expectedFixDiffs =
110             """
111 Fix for src/java/androidx/AnnotatedProperty.kt line 5: Add missing annotations:
112 @@ -5 +5
113 +                     @set:ExperimentalKotlinAnnotation
114 +                     @property:ExperimentalKotlinAnnotation
115 Fix for src/java/androidx/AnnotatedProperty.kt line 8: Add missing annotations:
116 @@ -8 +8
117 +                     @get:ExperimentalKotlinAnnotation
118 +                     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
119 +                     @property:ExperimentalKotlinAnnotation
120 Fix for src/java/androidx/AnnotatedProperty.kt line 11: Add missing annotations:
121 @@ -11 +11
122 +                     @set:ExperimentalKotlinAnnotation
123 +                     @get:ExperimentalKotlinAnnotation
124 +                     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
125 Fix for src/java/androidx/AnnotatedProperty.kt line 14: Add missing annotations:
126 @@ -14 +14
127 +                     @set:ExperimentalKotlinAnnotation
128 +                     @get:ExperimentalKotlinAnnotation
129 +                     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
130         """
131 
132         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
133     }
134 
135     @Test
Test var property annotated with two targetsnull136     fun `Test var property annotated with two targets`() {
137         val input =
138             arrayOf(
139                 kotlin(
140                     """
141                 package java.androidx
142 
143                 class AnnotatedProperty {
144                     @get:ExperimentalKotlinAnnotation
145                     @ExperimentalKotlinAnnotation
146                     var annotatedWithGetAndDefault = 3
147 
148                     @ExperimentalKotlinAnnotation
149                     @set:ExperimentalKotlinAnnotation
150                     var annotatedWithSetAndDefault = 3
151 
152                     @get:ExperimentalKotlinAnnotation
153                     @set:ExperimentalKotlinAnnotation
154                     var annotatedWithGetAndSet = 3
155 
156                     @property:ExperimentalKotlinAnnotation
157                     @get:ExperimentalKotlinAnnotation
158                     var annotatedWithGetAndProperty = 3
159 
160                     @set:ExperimentalKotlinAnnotation
161                     @property:ExperimentalKotlinAnnotation
162                     var annotatedWithSetAndProperty = 3
163                 }
164             """
165                 )
166             )
167 
168         val expected =
169             """
170 src/java/androidx/AnnotatedProperty.kt:5: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
171                     @get:ExperimentalKotlinAnnotation
172                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
173 src/java/androidx/AnnotatedProperty.kt:9: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
174                     @ExperimentalKotlinAnnotation
175                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
176 src/java/androidx/AnnotatedProperty.kt:13: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
177                     @get:ExperimentalKotlinAnnotation
178                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
179 src/java/androidx/AnnotatedProperty.kt:17: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
180                     @property:ExperimentalKotlinAnnotation
181                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
182 src/java/androidx/AnnotatedProperty.kt:21: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
183                     @set:ExperimentalKotlinAnnotation
184                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
185 5 errors, 0 warnings
186         """
187 
188         val expectedFixDiffs =
189             """
190 Fix for src/java/androidx/AnnotatedProperty.kt line 5: Add missing annotations:
191 @@ -5 +5
192 +                     @set:ExperimentalKotlinAnnotation
193 Fix for src/java/androidx/AnnotatedProperty.kt line 9: Add missing annotations:
194 @@ -9 +9
195 +                     @get:ExperimentalKotlinAnnotation
196 +                     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
197 Fix for src/java/androidx/AnnotatedProperty.kt line 13: Add missing annotations:
198 @@ -13 +13
199 +                     @property:ExperimentalKotlinAnnotation
200 Fix for src/java/androidx/AnnotatedProperty.kt line 17: Add missing annotations:
201 @@ -17 +17
202 +                     @set:ExperimentalKotlinAnnotation
203 Fix for src/java/androidx/AnnotatedProperty.kt line 21: Add missing annotations:
204 @@ -21 +21
205 +                     @get:ExperimentalKotlinAnnotation
206 +                     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
207         """
208 
209         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
210     }
211 
212     @Test
Test correctly annotated val propertynull213     fun `Test correctly annotated val property`() {
214         val input =
215             arrayOf(
216                 kotlin(
217                     """
218                 package java.androidx
219 
220                 class AnnotatedProperty {
221                     @get:ExperimentalKotlinAnnotation
222                     @ExperimentalKotlinAnnotation
223                     val correctlyAnnotatedWithDefault: Int = 3
224 
225                     @get:ExperimentalKotlinAnnotation
226                     @property:ExperimentalKotlinAnnotation
227                     val correctlyAnnotatedWithProperty: Int = 3
228                 }
229             """
230                 )
231             )
232 
233         check(*input).expectClean()
234     }
235 
236     @Test
Test val properties annotated with one targetnull237     fun `Test val properties annotated with one target`() {
238         val input =
239             arrayOf(
240                 kotlin(
241                     """
242                 package java.androidx
243 
244                 class AnnotatedProperty {
245                     @get:ExperimentalKotlinAnnotation
246                     val annotatedWithGet = 3
247 
248                     @property:ExperimentalKotlinAnnotation
249                     val annotatedWithProperty = 3
250 
251                     @ExperimentalKotlinAnnotation
252                     val annotatedWithDefault = 3
253                 }
254             """
255                 )
256             )
257 
258         val expected =
259             """
260 src/java/androidx/AnnotatedProperty.kt:5: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
261                     @get:ExperimentalKotlinAnnotation
262                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
263 src/java/androidx/AnnotatedProperty.kt:8: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
264                     @property:ExperimentalKotlinAnnotation
265                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
266 src/java/androidx/AnnotatedProperty.kt:11: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
267                     @ExperimentalKotlinAnnotation
268                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
269 3 errors, 0 warnings
270         """
271 
272         val expectedFixDiffs =
273             """
274 Fix for src/java/androidx/AnnotatedProperty.kt line 5: Add missing annotations:
275 @@ -5 +5
276 +                     @property:ExperimentalKotlinAnnotation
277 Fix for src/java/androidx/AnnotatedProperty.kt line 8: Add missing annotations:
278 @@ -8 +8
279 +                     @get:ExperimentalKotlinAnnotation
280 +                     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
281 Fix for src/java/androidx/AnnotatedProperty.kt line 11: Add missing annotations:
282 @@ -11 +11
283 +                     @get:ExperimentalKotlinAnnotation
284 +                     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
285         """
286 
287         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
288     }
289 
290     @Test
Test property annotated with non-experimental annotationnull291     fun `Test property annotated with non-experimental annotation`() {
292         val input =
293             arrayOf(
294                 kotlin(
295                     """
296                 package java.androidx
297 
298                 class AnnotatedProperty {
299                     @NonExperimentalAnnotation
300                     var correctlyAnnotated: Int = 3
301                 }
302             """
303                 ),
304                 kotlin(
305                     """
306                 package java.androidx
307 
308                 annotation class NonExperimentalAnnotation
309             """
310                 )
311             )
312 
313         check(*input).expectClean()
314     }
315 
316     @Test
Test property using Java defined annotationnull317     fun `Test property using Java defined annotation`() {
318         val input =
319             arrayOf(
320                 kotlin(
321                     """
322                 package java.androidx
323 
324                 import java.androidx.ExperimentalJavaAnnotation
325 
326                 class AnnotatedProperty {
327                     @get:ExperimentalJavaAnnotation
328                     var annotatedWithGet = 3
329                 }
330         """
331                 ),
332                 java(
333                     """
334                 package java.androidx;
335 
336                 import static androidx.annotation.RequiresOptIn.Level.ERROR;
337 
338                 import androidx.annotation.RequiresOptIn;
339 
340                 @RequiresOptIn(level = ERROR)
341                 public @interface ExperimentalJavaAnnotation {}
342             """
343                         .trimIndent()
344                 ),
345                 kotlin(
346                     """
347             package androidx.annotation
348 
349             import kotlin.annotation.Retention
350             import kotlin.annotation.Target
351 
352             @Retention(AnnotationRetention.BINARY)
353             @Target(AnnotationTarget.ANNOTATION_CLASS)
354             annotation class RequiresOptIn(
355                 val level: Level = Level.ERROR
356             ) {
357                 enum class Level {
358                     WARNING,
359                     ERROR
360                 }
361             }
362             """
363                         .trimIndent()
364                 )
365             )
366 
367         val expected =
368             """
369 src/java/androidx/AnnotatedProperty.kt:7: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
370                     @get:ExperimentalJavaAnnotation
371                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
372 1 errors, 0 warnings
373         """
374 
375         val expectedFixDiffs =
376             """
377 Fix for src/java/androidx/AnnotatedProperty.kt line 7: Add missing annotations:
378 @@ -7 +7
379 +                     @set:ExperimentalJavaAnnotation
380 +                     @property:ExperimentalJavaAnnotation
381         """
382 
383         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
384     }
385 
386     @Test
Test property defined at top-levelnull387     fun `Test property defined at top-level`() {
388         val input =
389             arrayOf(
390                 kotlin(
391                     """
392                 package java.androidx
393 
394                 @get:ExperimentalKotlinAnnotation
395                 var annotatedWithGet = 3
396             """
397                 )
398             )
399 
400         val expected =
401             """
402 src/java/androidx/test.kt:4: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
403                 @get:ExperimentalKotlinAnnotation
404                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
405 1 errors, 0 warnings
406         """
407 
408         val expectedFixDiffs =
409             """
410 Fix for src/java/androidx/test.kt line 4: Add missing annotations:
411 @@ -4 +4
412 +                 @set:ExperimentalKotlinAnnotation
413 +                 @property:ExperimentalKotlinAnnotation
414         """
415 
416         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
417     }
418 
419     @Test
Test property defined in companion objectnull420     fun `Test property defined in companion object`() {
421         val input =
422             arrayOf(
423                 kotlin(
424                     """
425                 package java.androidx
426 
427                 class AnnotatedProperty {
428                     companion object {
429                         @get:ExperimentalKotlinAnnotation
430                         var annotatedWithGet = 3
431                     }
432                 }
433             """
434                 )
435             )
436 
437         val expected =
438             """
439 src/java/androidx/AnnotatedProperty.kt:6: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
440                         @get:ExperimentalKotlinAnnotation
441                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
442 1 errors, 0 warnings
443         """
444 
445         val expectedFixDiffs =
446             """
447 Fix for src/java/androidx/AnnotatedProperty.kt line 6: Add missing annotations:
448 @@ -6 +6
449 +                         @set:ExperimentalKotlinAnnotation
450 +                         @property:ExperimentalKotlinAnnotation
451         """
452 
453         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
454     }
455 
456     @Test
Test property defined in interfacenull457     fun `Test property defined in interface`() {
458         val input =
459             arrayOf(
460                 kotlin(
461                     """
462                 package java.androidx
463 
464                 interface AnnotatedProperty {
465                     @get:ExperimentalKotlinAnnotation
466                     val annotatedWithGet: Int
467                 }
468             """
469                 )
470             )
471 
472         val expected =
473             """
474 src/java/androidx/AnnotatedProperty.kt:5: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
475                     @get:ExperimentalKotlinAnnotation
476                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
477 1 errors, 0 warnings
478         """
479 
480         val expectedFixDiffs =
481             """
482 Fix for src/java/androidx/AnnotatedProperty.kt line 5: Add missing annotations:
483 @@ -5 +5
484 +                     @property:ExperimentalKotlinAnnotation
485         """
486 
487         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
488     }
489 
490     @Test
Test experimental annotations on non-properties don't trigger lintnull491     fun `Test experimental annotations on non-properties don't trigger lint`() {
492         val input =
493             arrayOf(
494                 kotlin(
495                     """
496                 package java.androidx
497 
498                 @file:ExperimentalKotlinAnnotation
499 
500                 @ExperimentalKotlinAnnotation
501                 class ExperimentalClass {
502                     @ExperimentalKotlinAnnotation
503                     fun experimentalFunction() {}
504                 }
505             """
506                 )
507             )
508 
509         check(*input).expectClean()
510     }
511 
512     @Test
513     fun `Test property annotated with JvmField doesn't trigger lint`() {
514         val input =
515             arrayOf(
516                 kotlin(
517                     """
518                 package java.androidx
519 
520                 class AnnotatedWithJvmField {
521                     @JvmField
522                     @ExperimentalKotlinAnnotation
523                     var experimentalProperty = 3
524                 }
525             """
526                 )
527             )
528 
529         check(*input).expectClean()
530     }
531 
532     @Test
Test const property doesn't trigger lintnull533     fun `Test const property doesn't trigger lint`() {
534         val input =
535             arrayOf(
536                 kotlin(
537                     """
538                 package java.androidx
539 
540                 @ExperimentalKotlinAnnotation
541                 const val EXPERIMENTAL_CONST = 3
542             """
543                 )
544             )
545 
546         check(*input).expectClean()
547     }
548 
549     @Test
550     fun `Test property with delegate doesn't trigger lint`() {
551         val input =
552             arrayOf(
553                 kotlin(
554                     """
555                 package java.androidx
556 
557                 @ExperimentalKotlinAnnotation
558                 var experimentalProperty by mutableStateOf(0L)
559                 """
560                 )
561             )
562 
563         check(*input).expectClean()
564     }
565 
566     @Test
Test property within function doesn't trigger lintnull567     fun `Test property within function doesn't trigger lint`() {
568         val input =
569             arrayOf(
570                 kotlin(
571                     """
572                 package java.androidx
573 
574                 fun functionWithProperty() {
575                     @ExperimentalKotlinAnnotation
576                     val experimentalProperty = 3
577                 }
578                 """
579                         .trimIndent()
580                 )
581             )
582 
583         check(*input).expectClean()
584     }
585 
586     @Test
587     fun `Test private property doesn't trigger lint but other non-public properties do`() {
588         val input =
589             arrayOf(
590                 kotlin(
591                     """
592                 package java.androidx
593 
594                 class AnnotatedProperty {
595                     @ExperimentalKotlinAnnotation
596                     private var privateProperty = 3
597 
598                     @ExperimentalKotlinAnnotation
599                     protected var protectedProperty = 3
600 
601                     @ExperimentalKotlinAnnotation
602                     internal var internalProperty = 3
603                 }
604                 """
605                         .trimIndent()
606                 )
607             )
608 
609         val expected =
610             """
611 src/java/androidx/AnnotatedProperty.kt:7: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
612     @ExperimentalKotlinAnnotation
613     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
614 src/java/androidx/AnnotatedProperty.kt:10: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
615     @ExperimentalKotlinAnnotation
616     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
617 2 errors, 0 warnings
618         """
619 
620         val expectedFixDiffs =
621             """
622 Fix for src/java/androidx/AnnotatedProperty.kt line 7: Add missing annotations:
623 @@ -7 +7
624 +     @set:ExperimentalKotlinAnnotation
625 +     @get:ExperimentalKotlinAnnotation
626 +     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
627 Fix for src/java/androidx/AnnotatedProperty.kt line 10: Add missing annotations:
628 @@ -10 +10
629 +     @set:ExperimentalKotlinAnnotation
630 +     @get:ExperimentalKotlinAnnotation
631 +     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
632         """
633 
634         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
635     }
636 
637     @Test
Test property in private class doesn't trigger lintnull638     fun `Test property in private class doesn't trigger lint`() {
639         val input =
640             arrayOf(
641                 kotlin(
642                     """
643                 package java.androidx
644 
645                 private class AnnotatedProperty {
646                     @ExperimentalKotlinAnnotation
647                     var experimentalProperty = 3
648                 }
649                 """
650                         .trimIndent()
651                 )
652             )
653 
654         check(*input).expectClean()
655     }
656 
657     @Test
658     fun `Test property with private setter only has get annotation added`() {
659         val input =
660             arrayOf(
661                 kotlin(
662                     """
663                 package java.androidx
664 
665                 @ExperimentalKotlinAnnotation
666                 var experimentalProperty = 3
667                     private set
668                 """
669                         .trimIndent()
670                 )
671             )
672 
673         val expected =
674             """
675 src/java/androidx/test.kt:3: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
676 @ExperimentalKotlinAnnotation
677 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
678 1 errors, 0 warnings
679         """
680 
681         val expectedFixDiffs =
682             """
683 Fix for src/java/androidx/test.kt line 3: Add missing annotations:
684 @@ -3 +3
685 + @get:ExperimentalKotlinAnnotation
686 + @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
687         """
688 
689         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
690     }
691 
692     @Test
693     fun `Test constructor var property-parameter fully annotated`() {
694         val input =
695             arrayOf(
696                 kotlin(
697                     """
698                     package java.androidx
699                     class Foo(
700                         @get:ExperimentalKotlinAnnotation
701                         @set:ExperimentalKotlinAnnotation
702                         @ExperimentalKotlinAnnotation
703                         var correctlyAnnotatedWithDefault: Int,
704 
705                         @get:ExperimentalKotlinAnnotation
706                         @set:ExperimentalKotlinAnnotation
707                         @property:ExperimentalKotlinAnnotation
708                         var correctlyAnnotatedWithProperty: Int,
709                     )
710                     """
711                         .trimIndent()
712                 )
713             )
714 
715         check(*input).expectClean()
716     }
717 
718     @Test
719     fun `Test constructor var property-parameter partially annotated`() {
720         val input =
721             arrayOf(
722                 kotlin(
723                     """
724                     package java.androidx
725                     class Foo(
726                         @get:ExperimentalKotlinAnnotation
727                         var annotatedWithGet: Int,
728 
729                         @set:ExperimentalKotlinAnnotation
730                         var annotatedWithSet: Int,
731 
732                         @property:ExperimentalKotlinAnnotation
733                         var annotatedWithProperty: Int,
734 
735                         // Technically parameters should never be annotated with experimental
736                         // annotations on the param target
737                         @param:ExperimentalKotlinAnnotation
738                         var annotatedWithDefault: Int,
739 
740                         @ExperimentalKotlinAnnotation
741                         var annotatedWithDefault: Int,
742                     )
743                     """
744                         .trimIndent()
745                 )
746             )
747 
748         val expected =
749             """
750             src/java/androidx/Foo.kt:3: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
751                 @get:ExperimentalKotlinAnnotation
752                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
753             src/java/androidx/Foo.kt:6: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
754                 @set:ExperimentalKotlinAnnotation
755                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
756             src/java/androidx/Foo.kt:9: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
757                 @property:ExperimentalKotlinAnnotation
758                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
759             src/java/androidx/Foo.kt:14: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
760                 @param:ExperimentalKotlinAnnotation
761                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
762             src/java/androidx/Foo.kt:17: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
763                 @ExperimentalKotlinAnnotation
764                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
765             5 errors
766             """
767 
768         val expectedFixDiffs =
769             """
770             Autofix for src/java/androidx/Foo.kt line 3: Add missing annotations:
771             @@ -3 +3
772             +     @set:ExperimentalKotlinAnnotation
773             +     @property:ExperimentalKotlinAnnotation
774             Autofix for src/java/androidx/Foo.kt line 6: Add missing annotations:
775             @@ -6 +6
776             +     @get:ExperimentalKotlinAnnotation
777             +     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
778             +     @property:ExperimentalKotlinAnnotation
779             Autofix for src/java/androidx/Foo.kt line 9: Add missing annotations:
780             @@ -9 +9
781             +     @set:ExperimentalKotlinAnnotation
782             +     @get:ExperimentalKotlinAnnotation
783             +     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
784             Autofix for src/java/androidx/Foo.kt line 14: Add missing annotations:
785             @@ -14 +14
786             +     @set:ExperimentalKotlinAnnotation
787             +     @get:ExperimentalKotlinAnnotation
788             +     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
789             +     @property:ExperimentalKotlinAnnotation
790             Autofix for src/java/androidx/Foo.kt line 17: Add missing annotations:
791             @@ -17 +17
792             +     @set:ExperimentalKotlinAnnotation
793             +     @get:ExperimentalKotlinAnnotation
794             +     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
795             """
796 
797         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
798     }
799 
800     @Test
801     fun `Test constructor property-parameter incorrectly annotated with param target`() {
802         val input =
803             kotlin(
804                 """
805                     package java.androidx
806                     class Foo(
807                         // Technically parameters should never be annotated with experimental
808                         // annotations on the param target
809                         @get:ExperimentalKotlinAnnotation
810                         @set:ExperimentalKotlinAnnotation
811                         @param:ExperimentalKotlinAnnotation
812                         var incorrectlyAnnotatedWithParam: Int,
813                     )
814                 """
815                     .trimIndent()
816             )
817 
818         val expected =
819             """
820             src/java/androidx/Foo.kt:5: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
821                 @get:ExperimentalKotlinAnnotation
822                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
823             1 error
824             """
825                 .trimIndent()
826 
827         val expectedFixDiffs =
828             """
829             Autofix for src/java/androidx/Foo.kt line 5: Add missing annotations:
830             @@ -5 +5
831             +     @property:ExperimentalKotlinAnnotation
832             """
833                 .trimIndent()
834 
835         check(input).expect(expected).expectFixDiffs(expectedFixDiffs)
836     }
837 
838     @Test
839     fun `Test constructor val property-parameter`() {
840         val input =
841             arrayOf(
842                 kotlin(
843                     """
844                     package java.androidx
845                     class Foo(
846                         @property:ExperimentalKotlinAnnotation
847                         val experimentalProperty: Int
848                     )
849                     """
850                         .trimIndent()
851                 )
852             )
853 
854         val expected =
855             """
856             src/java/androidx/Foo.kt:3: Error: This property does not have all required annotations to correctly mark it as experimental. [ExperimentalPropertyAnnotation]
857                 @property:ExperimentalKotlinAnnotation
858                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
859             1 error
860             """
861 
862         val expectedFixDiffs =
863             """
864             Autofix for src/java/androidx/Foo.kt line 3: Add missing annotations:
865             @@ -3 +3
866             +     @get:ExperimentalKotlinAnnotation
867             +     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
868             """
869 
870         check(*input).expect(expected).expectFixDiffs(expectedFixDiffs)
871     }
872 
873     @Test
874     fun `Test constructor property-parameter private`() {
875         val input =
876             arrayOf(
877                 kotlin(
878                     """
879                     package java.androidx
880                     class Foo(
881                         @property:ExperimentalKotlinAnnotation
882                         private val experimentalProperty: Int
883                     )
884                     """
885                         .trimIndent()
886                 )
887             )
888 
889         check(*input).expectClean()
890     }
891 
892     @Test
893     fun `Test private constructor property-parameter`() {
894         val input =
895             arrayOf(
896                 kotlin(
897                     """
898                     package java.androidx
899                     class Foo private constructor (
900                         @property:ExperimentalKotlinAnnotation
901                         val experimentalProperty: Int
902                     )
903                     """
904                         .trimIndent()
905                 )
906             )
907 
908         check(*input).expectClean()
909     }
910 
911     @Test
912     fun `Test constructor property-parameter of private class`() {
913         val input =
914             arrayOf(
915                 kotlin(
916                     """
917                     package java.androidx
918                     class Foo private constructor (
919                         @property:ExperimentalKotlinAnnotation
920                         val experimentalProperty: Int
921                     )
922                     """
923                         .trimIndent()
924                 )
925             )
926 
927         check(*input).expectClean()
928     }
929 
930     @Test
931     fun `Test constructor parameter, non property`() {
932         val input =
933             arrayOf(
934                 kotlin(
935                     """
936                     package java.androidx
937                     class Foo(
938                         @ExperimentalKotlinAnnotation
939                         experimentalParameter: Int
940                     )
941                     """
942                         .trimIndent()
943                 )
944             )
945 
946         check(*input).expectClean()
947     }
948 
949     @Test
950     fun `Test parameter of non-constructor`() {
951         val input =
952             arrayOf(
953                 kotlin(
954                     """
955                     package java.androidx
956                     class Foo {
957                         fun foo(
958                             @ExperimentalKotlinAnnotation
959                             experimentalParameter: Int
960                         ) = Unit
961                     }
962                     """
963                         .trimIndent()
964                 )
965             )
966 
967         check(*input).expectClean()
968     }
969 }
970