• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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