xref: /aosp_15_r20/tools/metalava/metalava-model/src/main/java/com/android/tools/metalava/model/AnnotationInfo.kt (revision 115816f9299ab6ddd6b9673b81f34e707f6bacab)
1 /*
2  * Copyright (C) 2023 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.model
18 
19 /**
20  * Encapsulates information that metalava needs to know about a specific annotation type.
21  *
22  * Instances of [AnnotationInfo] will be shared across [AnnotationItem]s that have the same
23  * qualified name and (where applicable) the same attributes. That will allow the information in
24  * [AnnotationInfo] to be computed once and then reused whenever needed.
25  */
26 interface AnnotationInfo {
27 
28     /** The applicable targets for this annotation */
29     val targets: Set<AnnotationTarget>
30 
31     /**
32      * Determines whether the annotation is nullability related.
33      *
34      * If this is null then the annotation is not a nullability annotation, otherwise this
35      * determines whether it is nullable or non-null.
36      */
37     val typeNullability: TypeNullability?
38 
39     /**
40      * Determines whether this annotation affects whether the annotated item is shown or hidden and
41      * if so how.
42      */
43     val showability: Showability
44 
45     val suppressCompatibility: Boolean
46 }
47 
48 /** Compute the [TypeNullability], if any, for the annotation with [qualifiedName]. */
computeTypeNullabilitynull49 internal fun computeTypeNullability(qualifiedName: String): TypeNullability? =
50     when {
51         isNullableAnnotation(qualifiedName) -> TypeNullability.NULLABLE
52         isNonNullAnnotation(qualifiedName) -> TypeNullability.NONNULL
53         else -> null
54     }
55 
56 /**
57  * The set of possible effects on whether an `Item` is part of an API.
58  *
59  * They are in order from the lowest priority to the highest priority, see [highestPriority].
60  */
61 enum class ShowOrHide(private val show: Boolean?) {
62     /** No effect either way. */
63     NO_EFFECT(show = null),
64 
65     /** Hide an item from the API. */
66     HIDE(show = false),
67 
68     /** Show an item as part of the API. */
69     SHOW(show = true),
70 
71     /**
72      * Revert an unstable API.
73      *
74      * The effect of reverting an unstable API depends on what the previously released API contains
75      * but in the case when the item is new and does not exist in the previously released API
76      * reverting requires hiding the API. As the items being hidden could have show annotations
77      * (which override hide annotations) then in order for the item to be hidden then this needs to
78      * come after [SHOW].
79      */
80     REVERT_UNSTABLE_API(show = null) {
81         /**
82          * If the [revertItem] is not null and `emit = true`, i.e. is for the API surface currently
83          * being generated, then reverting will still show this item.
84          */
shownull85         override fun show(revertItem: SelectableItem?): Boolean {
86             return revertItem != null && revertItem.emit
87         }
88 
89         /** If the [revertItem] is null then reverting will hide this item. */
hidenull90         override fun hide(revertItem: SelectableItem?): Boolean {
91             return revertItem == null
92         }
93     },
94     ;
95 
96     /**
97      * Return true if this shows an `Item` as part of the API.
98      *
99      * @param revertItem the optional [Item] in the previously released API to which this will be
100      *   reverted. This is only set for, and only has an effect on, [REVERT_UNSTABLE_API], see
101      *   [REVERT_UNSTABLE_API.show] for details.
102      */
shownull103     open fun show(revertItem: SelectableItem?): Boolean = show == true
104 
105     /**
106      * Return true if this hides an `Item` from the API.
107      *
108      * @param revertItem the optional [Item] in the previously released API to which this will be
109      *   reverted. This is only set for, and only has an effect on, [REVERT_UNSTABLE_API], see
110      *   [REVERT_UNSTABLE_API.show] for details.
111      */
112     open fun hide(revertItem: SelectableItem?): Boolean = show == false
113 
114     /** Return the highest priority between this and another [ShowOrHide]. */
115     fun highestPriority(other: ShowOrHide): ShowOrHide = maxOf(this, other)
116 }
117 
118 /**
119  * Determines how an annotation will affect whether [SelectableItem]s annotated with it are part of
120  * the API or not and also determines whether a [SelectableItem] is part of the API or not.
121  */
122 data class Showability(
123     /**
124      * Determines whether an API [SelectableItem] is shown as part of the API or hidden from the
125      * API.
126      *
127      * If [ShowOrHide.show] is `true` then the annotated [SelectableItem] will be shown as part of
128      * the API. That is the case for annotations that match `--show-annotation`, or
129      * `--show-single-annotation`, but not `--show-for-stub-purposes-annotation`.
130      *
131      * If [ShowOrHide.hide] is `true` then the annotated [SelectableItem] will NOT be shown as part
132      * of the API. That is the case for annotations that match `--hide-annotation`.
133      *
134      * If neither of the above is then this has no effect on whether an annotated [SelectableItem]
135      * will be shown or not, that decision will be determined by its container's
136      * [Showability.recursive] setting.
137      */
138     private val show: ShowOrHide,
139 
140     /**
141      * Determines whether the contents of an API [Item] is shown as part of the API or hidden from
142      * the API.
143      *
144      * If [ShowOrHide.show] is `true` then the contents of the annotated [Item] will be included in
145      * the API unless overridden by a closer annotation. That is the case for annotations that match
146      * `--show-annotation`, but not `--show-single-annotation`, or
147      * `--show-for-stub-purposes-annotation`.
148      *
149      * If [ShowOrHide.hide] is `true` then the contents of the annotated [Item] will be included in
150      * the API unless overridden by a closer annotation. That is the case for annotations that match
151      * `--hide-annotation`.
152      */
153     private val recursive: ShowOrHide,
154 
155     /**
156      * Determines whether an API [Item] ands its contents is considered to be part of the base API
157      * and so must be included in the stubs but not the signature files.
158      *
159      * If [ShowOrHide.show] is `true` then the API [Item] ands its contents are considered to be
160      * part of the base API. That is the case for annotations that match
161      * `--show-for-stub-purposes-annotation` but not `--show-annotation`, or
162      * `--show-single-annotation`.
163      */
164     private val forStubsOnly: ShowOrHide,
165 
166     /** The item to which this item should be reverted. Null if no such item exists. */
167     val revertItem: SelectableItem? = null,
168 ) {
169     /**
170      * Check whether the annotated item should be considered part of the API or not.
171      *
172      * Returns `true` if the item is annotated with a `--show-annotation`,
173      * `--show-single-annotation`, or `--show-for-stub-purposes-annotation`.
174      */
175     fun show() = show.show(revertItem) || forStubsOnly.show(revertItem)
176 
177     /**
178      * Check whether the annotated item should only be considered part of the API when generating
179      * stubs.
180      *
181      * Returns `true` if the item is annotated with a `--show-for-stub-purposes-annotation`. Such
182      * items will be part of an API surface that the API being generated extends.
183      */
184     fun showForStubsOnly() = forStubsOnly.show(revertItem)
185 
186     /**
187      * Check whether the annotations on this item affect nested `Item`s.
188      *
189      * Returns `true` if they do, `false` if they do not affect nested `Item`s.
190      */
191     fun showRecursive() = recursive.show(revertItem) || forStubsOnly.show(revertItem)
192 
193     /**
194      * Check whether the annotations on this item only affect the current `Item`.
195      *
196      * Returns `true` if they do, `false` if they can also affect nested `Item`s.
197      */
198     fun showNonRecursive() =
199         show.show(revertItem) && !recursive.show(revertItem) && !forStubsOnly.show(revertItem)
200 
201     /**
202      * Check whether the annotated item should be hidden from the API.
203      *
204      * Returns `true` if the annotation matches an `--hide-annotation`.
205      */
206     fun hide() = show.hide(revertItem)
207 
208     /**
209      * Check whether the annotated item is part of an unstable API that needs to be reverted.
210      *
211      * Returns `true` if the annotation matches `--hide-annotation android.annotation.FlaggedApi` or
212      * if this is on an item then when the item is annotated with such an annotation or is a method
213      * that overrides such an item or is contained within a class that is annotated with such an
214      * annotation.
215      */
216     fun revertUnstableApi() = show == ShowOrHide.REVERT_UNSTABLE_API
217 
218     /** Combine this with [other] to produce a combination [Showability]. */
219     fun combineWith(other: Showability): Showability {
220         // Show wins over not showing.
221         val newShow = show.highestPriority(other.show)
222 
223         // Recursive wins over not recursive.
224         val newRecursive = recursive.highestPriority(other.recursive)
225 
226         // For everything wins over only for stubs.
227         val forStubsOnly =
228             if (newShow.show(revertItem)) {
229                 ShowOrHide.NO_EFFECT
230             } else {
231                 forStubsOnly.highestPriority(other.forStubsOnly)
232             }
233 
234         return Showability(newShow, newRecursive, forStubsOnly)
235     }
236 
237     companion object {
238         /** The annotation does not affect whether an annotated item is shown. */
239         val NO_EFFECT =
240             Showability(
241                 show = ShowOrHide.NO_EFFECT,
242                 recursive = ShowOrHide.NO_EFFECT,
243                 forStubsOnly = ShowOrHide.NO_EFFECT
244             )
245     }
246 }
247