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