1 /*
2  * Copyright 2021 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 @file:Suppress("unused")
17 
18 package sample.optin
19 
20 /**
21  * Regression test for b/193110413 where the lint check does not handle nested annotations.
22  *
23  * This uses the Kotlin compiler's enforcement and is guaranteed to be correct.
24  */
25 class RegressionTestKotlin193110413 {
26     @ExperimentalKotlinAnnotation
27     internal interface ExperimentalInterface {
experimentalMethodnull28         fun experimentalMethod()
29 
30         fun anotherExperimentalMethod()
31 
32         fun defaultExperimentalMethod() {
33             // Stub!
34         }
35     }
36 
37     /** Safe usage due to opting in to the experimental annotation. */
38     @OptIn(ExperimentalKotlinAnnotation::class)
39     internal class Foo : ExperimentalInterface {
40         @Suppress("OPT_IN_MARKER_ON_OVERRIDE_WARNING")
41         @ExperimentalKotlinAnnotation
experimentalMethodnull42         override fun experimentalMethod() {
43             // Stub!
44         }
45 
anotherExperimentalMethodnull46         override fun anotherExperimentalMethod() {
47             // Stub!
48         }
49 
stableClassLevelOptInnull50         fun stableClassLevelOptIn() {
51             // Stub!
52         }
53     }
54 
55     /** Safe usage due to propagating the experimental annotation. */
56     @ExperimentalKotlinAnnotation
57     internal class Bar : ExperimentalInterface {
experimentalMethodnull58         override fun experimentalMethod() {
59             // Stub!
60         }
61 
anotherExperimentalMethodnull62         override fun anotherExperimentalMethod() {
63             // Stub!
64         }
65 
66         @OptIn(ExperimentalKotlinAnnotation::class)
stableMethodLevelOptInnull67         fun stableMethodLevelOptIn() {
68             // Stub!
69         }
70     }
71 
72     /**
73      * Unsafe call to an experimental method where the containing class has opted-in to an unstable
74      * interface, thus the constructor and stable method calls are safe.
75      *
76      * The expected behavior has been verified against the Kotlin compiler's implementation of
77      * opt-in.
78      */
regressionTestMixedStabilitynull79     fun regressionTestMixedStability() {
80         val foo = Foo() // safe
81         foo.stableClassLevelOptIn() // safe
82         foo.anotherExperimentalMethod() // safe
83         foo.defaultExperimentalMethod() // safe
84         foo.experimentalMethod() // unsafe
85         val bar = Bar() // unsafe
86         bar.stableMethodLevelOptIn() // unsafe due to class reference
87         bar.experimentalMethod() // unsafe
88     }
89 }
90