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