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