1 /*
2 * Copyright (C) 2017 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 interface BaseModifierList {
annotationsnull20 fun annotations(): List<AnnotationItem>
21
22 fun getVisibilityLevel(): VisibilityLevel
23
24 fun isPublic(): Boolean
25
26 fun isProtected(): Boolean
27
28 fun isPrivate(): Boolean
29
30 @MetalavaApi fun isStatic(): Boolean
31
32 fun isAbstract(): Boolean
33
34 fun isFinal(): Boolean
35
36 fun isNative(): Boolean
37
38 fun isSynchronized(): Boolean
39
40 fun isStrictFp(): Boolean
41
42 fun isTransient(): Boolean
43
44 fun isVolatile(): Boolean
45
46 fun isDefault(): Boolean
47
48 fun isDeprecated(): Boolean
49
50 // Modifier in Kotlin, separate syntax (...) in Java but modeled as modifier here
51 fun isVarArg(): Boolean = false
52
53 // Kotlin
54 fun isSealed(): Boolean = false
55
56 fun isFunctional(): Boolean = false
57
58 fun isCompanion(): Boolean = false
59
60 fun isInfix(): Boolean = false
61
62 fun isConst(): Boolean = false
63
64 fun isSuspend(): Boolean = false
65
66 fun isOperator(): Boolean = false
67
68 fun isInline(): Boolean = false
69
70 fun isValue(): Boolean = false
71
72 fun isData(): Boolean = false
73
74 fun isExpect(): Boolean = false
75
76 fun isActual(): Boolean = false
77
78 fun isPackagePrivate() = !(isPublic() || isProtected() || isPrivate())
79
80 fun isPublicOrProtected() = isPublic() || isProtected()
81
82 /**
83 * Check whether this [ModifierList]'s modifiers are equivalent to the [other] [ModifierList]'s
84 * modifiers.
85 *
86 * Modifier meaning does depend on the [Item] to which they belong, e.g. just because `final`
87 * and `deprecated` are `false` does not mean that the [Item] is not final or deprecated as the
88 * containing class may be final or deprecated.
89 *
90 * It is used for:
91 * * Checking method overrides.
92 * * Checking consistent of classes whose definition is split across multiple signature files.
93 * * Testing the [InheritableItem.duplicate] works correctly.
94 *
95 * @param owner the optional [Item] that owns this [ModifierList] and which is used to tweak the
96 * check to make it take into account the content within which they are being used. If it is
97 * not provided then this will just compare modifiers like for like.
98 *
99 * TODO(b/356548977): Currently, [owner] only has an effect if it is a [MethodItem]. That is due
100 * to it historically only being used for method overrides. However, as the previous list
101 * shows that is no longer true so it will need to be updated to correctly handle the other
102 * cases.
103 */
104 fun equivalentTo(owner: Item?, other: BaseModifierList): Boolean
105
106 /** Returns true if this modifier list contains the `@JvmSynthetic` annotation */
107 fun hasJvmSyntheticAnnotation(): Boolean = hasAnnotation(AnnotationItem::isJvmSynthetic)
108
109 /** Returns true if this modifier list contains the given annotation */
110 fun isAnnotatedWith(qualifiedName: String): Boolean {
111 return findAnnotation(qualifiedName) != null
112 }
113
114 /**
115 * Returns the annotation of the given qualified name (or equivalent) if found in this modifier
116 * list
117 */
findAnnotationnull118 fun findAnnotation(qualifiedName: String): AnnotationItem? {
119 return findAnnotation { qualifiedName == it.qualifiedName }
120 }
121
122 /**
123 * Returns true if the visibility modifiers in this modifier list is as least as visible as the
124 * ones in the given [other] modifier list
125 */
asAccessibleAsnull126 fun asAccessibleAs(other: BaseModifierList): Boolean {
127 val otherLevel = other.getVisibilityLevel()
128 val thisLevel = getVisibilityLevel()
129 // Generally the access level enum order determines relative visibility. However, there is
130 // an exception because
131 // package private and internal are not directly comparable.
132 val result = thisLevel >= otherLevel
133 return when (otherLevel) {
134 VisibilityLevel.PACKAGE_PRIVATE -> result && thisLevel != VisibilityLevel.INTERNAL
135 VisibilityLevel.INTERNAL -> result && thisLevel != VisibilityLevel.PACKAGE_PRIVATE
136 else -> result
137 }
138 }
139
140 /** User visible description of the visibility in this modifier list */
getVisibilityStringnull141 fun getVisibilityString(): String {
142 return getVisibilityLevel().userVisibleDescription
143 }
144
145 /**
146 * Like [getVisibilityString], but package private has no modifiers; this typically corresponds
147 * to the source code for the visibility modifiers in the modifier list
148 */
getVisibilityModifiersnull149 fun getVisibilityModifiers(): String {
150 return getVisibilityLevel().javaSourceCodeModifier
151 }
152
153 /**
154 * Get a [MutableModifierList] from this.
155 *
156 * This will return the object on which it is called if that is already mutable, otherwise it
157 * will create a separate mutable copy of this.
158 */
toMutablenull159 fun toMutable(): MutableModifierList
160
161 /**
162 * Get an immutable [ModifierList] from this.
163 *
164 * This will return the object on which it is called if that is already immutable, otherwise it
165 * will create a separate immutable copy of this.
166 */
167 fun toImmutable(): ModifierList
168 }
169
170 /**
171 * Returns the first annotation in the modifier list that matches the supplied predicate, or null
172 * otherwise.
173 */
174 inline fun BaseModifierList.findAnnotation(
175 predicate: (AnnotationItem) -> Boolean
176 ): AnnotationItem? {
177 return annotations().firstOrNull(predicate)
178 }
179
180 /**
181 * Returns true iff the modifier list contains any annotation that matches the supplied predicate.
182 */
hasAnnotationnull183 inline fun BaseModifierList.hasAnnotation(predicate: (AnnotationItem) -> Boolean): Boolean {
184 return annotations().any(predicate)
185 }
186
187 interface ModifierList : BaseModifierList {
188 /**
189 * Take a snapshot of this for use in [targetCodebase].
190 *
191 * Creates a deep snapshot, including snapshots of each annotation for use in [targetCodebase].
192 *
193 * @param targetCodebase The [Codebase] of which the snapshot will be part.
194 */
snapshotnull195 fun snapshot(targetCodebase: Codebase): ModifierList
196 }
197