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 ModifierList {
20 val codebase: Codebase
21
annotationsnull22 fun annotations(): List<AnnotationItem>
23
24 fun owner(): Item
25
26 fun getVisibilityLevel(): VisibilityLevel
27
28 fun isPublic(): Boolean
29
30 fun isProtected(): Boolean
31
32 fun isPrivate(): Boolean
33
34 @MetalavaApi fun isStatic(): Boolean
35
36 fun isAbstract(): Boolean
37
38 fun isFinal(): Boolean
39
40 fun isNative(): Boolean
41
42 fun isSynchronized(): Boolean
43
44 fun isStrictFp(): Boolean
45
46 fun isTransient(): Boolean
47
48 fun isVolatile(): Boolean
49
50 fun isDefault(): Boolean
51
52 fun isDeprecated(): Boolean
53
54 // Modifier in Kotlin, separate syntax (...) in Java but modeled as modifier here
55 fun isVarArg(): Boolean = false
56
57 // Kotlin
58 fun isSealed(): Boolean = false
59
60 fun isFunctional(): Boolean = false
61
62 fun isCompanion(): Boolean = false
63
64 fun isInfix(): Boolean = false
65
66 fun isConst(): Boolean = false
67
68 fun isSuspend(): Boolean = false
69
70 fun isOperator(): Boolean = false
71
72 fun isInline(): Boolean = false
73
74 fun isValue(): Boolean = false
75
76 fun isData(): Boolean = false
77
78 fun isExpect(): Boolean = false
79
80 fun isActual(): Boolean = false
81
82 fun isEmpty(): Boolean
83
84 fun isPackagePrivate() = !(isPublic() || isProtected() || isPrivate())
85
86 fun isPublicOrProtected() = isPublic() || isProtected()
87
88 // Rename? It's not a full equality, it's whether an override's modifier set is significant
89 fun equivalentTo(other: ModifierList): Boolean {
90 if (isPublic() != other.isPublic()) return false
91 if (isProtected() != other.isProtected()) return false
92 if (isPrivate() != other.isPrivate()) return false
93
94 if (isStatic() != other.isStatic()) return false
95 if (isAbstract() != other.isAbstract()) return false
96 if (isFinal() != other.isFinal()) {
97 return false
98 }
99 if (isTransient() != other.isTransient()) return false
100 if (isVolatile() != other.isVolatile()) return false
101
102 // Default does not require an override to "remove" it
103 // if (isDefault() != other.isDefault()) return false
104
105 return true
106 }
107
108 /** Returns true if this modifier list contains the `@JvmSynthetic` annotation */
hasJvmSyntheticAnnotationnull109 fun hasJvmSyntheticAnnotation(): Boolean = hasAnnotation(AnnotationItem::isJvmSynthetic)
110
111 /**
112 * Returns true if this modifier list contains any suppress compatibility meta-annotations.
113 *
114 * Metalava will suppress compatibility checks for APIs which are within the scope of a
115 * "suppress compatibility" meta-annotation, but they may still be written to API files or stub
116 * JARs.
117 *
118 * "Suppress compatibility" meta-annotations allow Metalava to handle concepts like Jetpack
119 * experimental APIs, where developers can use the [RequiresOptIn] meta-annotation to mark
120 * feature sets with unstable APIs.
121 */
122 fun hasSuppressCompatibilityMetaAnnotations(): Boolean {
123 return codebase.annotationManager.hasSuppressCompatibilityMetaAnnotations(this)
124 }
125
126 /** Returns true if this modifier list contains the given annotation */
isAnnotatedWithnull127 fun isAnnotatedWith(qualifiedName: String): Boolean {
128 return findAnnotation(qualifiedName) != null
129 }
130
131 /**
132 * Returns the annotation of the given qualified name (or equivalent) if found in this modifier
133 * list
134 */
findAnnotationnull135 fun findAnnotation(qualifiedName: String): AnnotationItem? {
136 val mappedName = codebase.annotationManager.normalizeInputName(qualifiedName)
137 return findAnnotation { mappedName == it.qualifiedName }
138 }
139
140 /**
141 * Returns true if the visibility modifiers in this modifier list is as least as visible as the
142 * ones in the given [other] modifier list
143 */
asAccessibleAsnull144 fun asAccessibleAs(other: ModifierList): Boolean {
145 val otherLevel = other.getVisibilityLevel()
146 val thisLevel = getVisibilityLevel()
147 // Generally the access level enum order determines relative visibility. However, there is
148 // an exception because
149 // package private and internal are not directly comparable.
150 val result = thisLevel >= otherLevel
151 return when (otherLevel) {
152 VisibilityLevel.PACKAGE_PRIVATE -> result && thisLevel != VisibilityLevel.INTERNAL
153 VisibilityLevel.INTERNAL -> result && thisLevel != VisibilityLevel.PACKAGE_PRIVATE
154 else -> result
155 }
156 }
157
158 /** User visible description of the visibility in this modifier list */
getVisibilityStringnull159 fun getVisibilityString(): String {
160 return getVisibilityLevel().userVisibleDescription
161 }
162
163 /**
164 * Like [getVisibilityString], but package private has no modifiers; this typically corresponds
165 * to the source code for the visibility modifiers in the modifier list
166 */
getVisibilityModifiersnull167 fun getVisibilityModifiers(): String {
168 return getVisibilityLevel().javaSourceCodeModifier
169 }
170 }
171
172 /**
173 * Returns the first annotation in the modifier list that matches the supplied predicate, or null
174 * otherwise.
175 */
findAnnotationnull176 inline fun ModifierList.findAnnotation(predicate: (AnnotationItem) -> Boolean): 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 ModifierList.hasAnnotation(predicate: (AnnotationItem) -> Boolean): Boolean {
184 return annotations().any(predicate)
185 }
186