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 package com.android.tools.metalava.reporter
17 
18 import java.util.Locale
19 import kotlin.properties.ReadOnlyProperty
20 import kotlin.reflect.KProperty
21 
22 object Issues {
23     private val allIssues: MutableList<Issue> = ArrayList(300)
24 
25     /** A list of all the issues. */
26     val all: List<Issue> by this::allIssues
27 
28     private val nameToIssue: MutableMap<String, Issue> = HashMap(300)
29 
30     val PARSE_ERROR by Issue(Severity.ERROR)
31     val DUPLICATE_SOURCE_CLASS by Issue(Severity.WARNING)
32     // Compatibility issues
33     val ADDED_PACKAGE by Issue(Severity.HIDDEN, Category.COMPATIBILITY)
34     val ADDED_CLASS by Issue(Severity.HIDDEN, Category.COMPATIBILITY)
35     val ADDED_METHOD by Issue(Severity.HIDDEN, Category.COMPATIBILITY)
36     val ADDED_FIELD by Issue(Severity.HIDDEN, Category.COMPATIBILITY)
37     val ADDED_INTERFACE by Issue(Severity.HIDDEN, Category.COMPATIBILITY)
38     val REMOVED_PACKAGE by Issue(Severity.ERROR, Category.COMPATIBILITY)
39     val REMOVED_CLASS by Issue(Severity.ERROR, Category.COMPATIBILITY)
40     val REMOVED_METHOD by Issue(Severity.ERROR, Category.COMPATIBILITY)
41     val REMOVED_FIELD by Issue(Severity.ERROR, Category.COMPATIBILITY)
42     val REMOVED_INTERFACE by Issue(Severity.ERROR, Category.COMPATIBILITY)
43     val CHANGED_STATIC by Issue(Severity.ERROR, Category.COMPATIBILITY)
44     val ADDED_FINAL by Issue(Severity.ERROR, Category.COMPATIBILITY)
45     val CHANGED_TRANSIENT by Issue(Severity.ERROR, Category.COMPATIBILITY)
46     val CHANGED_VOLATILE by Issue(Severity.ERROR, Category.COMPATIBILITY)
47     val CHANGED_TYPE by Issue(Severity.ERROR, Category.COMPATIBILITY)
48     val CHANGED_VALUE by Issue(Severity.ERROR, Category.COMPATIBILITY)
49     val CHANGED_SUPERCLASS by Issue(Severity.ERROR, Category.COMPATIBILITY)
50     val CHANGED_SCOPE by Issue(Severity.ERROR, Category.COMPATIBILITY)
51     val CHANGED_ABSTRACT by Issue(Severity.ERROR, Category.COMPATIBILITY)
52     val CHANGED_DEFAULT by Issue(Severity.ERROR, Category.COMPATIBILITY)
53     val CHANGED_THROWS by Issue(Severity.ERROR, Category.COMPATIBILITY)
54     val CHANGED_NATIVE by Issue(Severity.HIDDEN, Category.COMPATIBILITY)
55     val CHANGED_CLASS by Issue(Severity.ERROR, Category.COMPATIBILITY)
56     val CHANGED_DEPRECATED by Issue(Severity.HIDDEN, Category.COMPATIBILITY)
57     val CHANGED_SYNCHRONIZED by Issue(Severity.HIDDEN, Category.COMPATIBILITY)
58     val CONFLICTING_SHOW_ANNOTATIONS by Issue(Severity.ERROR, Category.UNKNOWN)
59     val ADDED_FINAL_UNINSTANTIABLE by Issue(Severity.HIDDEN, Category.COMPATIBILITY)
60     val REMOVED_FINAL by Issue(Severity.ERROR, Category.COMPATIBILITY)
61     val REMOVED_FINAL_STRICT by Issue(Severity.ERROR, Category.COMPATIBILITY)
62     val REMOVED_DEPRECATED_CLASS by Issue(REMOVED_CLASS, Category.COMPATIBILITY)
63     val REMOVED_DEPRECATED_METHOD by Issue(REMOVED_METHOD, Category.COMPATIBILITY)
64     val REMOVED_DEPRECATED_FIELD by Issue(REMOVED_FIELD, Category.COMPATIBILITY)
65     val ADDED_ABSTRACT_METHOD by Issue(Severity.ERROR, Category.COMPATIBILITY)
66     val ADDED_REIFIED by Issue(Severity.ERROR, Category.COMPATIBILITY)
67     val REMOVED_JVM_DEFAULT_WITH_COMPATIBILITY by Issue(Severity.ERROR, Category.COMPATIBILITY)
68 
69     // Issues in javadoc generation
70     val UNRESOLVED_LINK by Issue(Severity.ERROR, Category.DOCUMENTATION)
71     val UNAVAILABLE_SYMBOL by Issue(Severity.WARNING, Category.DOCUMENTATION)
72     val HIDDEN_SUPERCLASS by Issue(Severity.WARNING, Category.DOCUMENTATION)
73     val DEPRECATED by Issue(Severity.HIDDEN, Category.DOCUMENTATION)
74     val DEPRECATION_MISMATCH by Issue(Severity.ERROR, Category.DOCUMENTATION)
75     val IO_ERROR by Issue(Severity.ERROR)
76     val HIDDEN_TYPE_PARAMETER by Issue(Severity.WARNING, Category.DOCUMENTATION)
77     val PRIVATE_SUPERCLASS by Issue(Severity.WARNING, Category.DOCUMENTATION)
78     val NULLABLE by Issue(Severity.HIDDEN, Category.DOCUMENTATION)
79     val INT_DEF by Issue(Severity.HIDDEN, Category.DOCUMENTATION)
80     val REQUIRES_PERMISSION by Issue(Severity.ERROR, Category.DOCUMENTATION)
81     val BROADCAST_BEHAVIOR by Issue(Severity.ERROR, Category.DOCUMENTATION)
82     val SDK_CONSTANT by Issue(Severity.ERROR, Category.DOCUMENTATION)
83     val TODO by Issue(Severity.ERROR, Category.DOCUMENTATION)
84     val NO_ARTIFACT_DATA by Issue(Severity.HIDDEN, Category.DOCUMENTATION)
85     val BROKEN_ARTIFACT_FILE by Issue(Severity.ERROR, Category.DOCUMENTATION)
86 
87     // Metalava warnings (not from doclava)
88 
89     val INVALID_FEATURE_ENFORCEMENT by Issue(Severity.ERROR, Category.DOCUMENTATION)
90 
91     val MISSING_PERMISSION by Issue(Severity.ERROR, Category.DOCUMENTATION)
92     val MULTIPLE_THREAD_ANNOTATIONS by Issue(Severity.ERROR, Category.DOCUMENTATION)
93     val UNRESOLVED_CLASS by Issue(Severity.ERROR, Category.DOCUMENTATION)
94     val INVALID_NULL_CONVERSION by Issue(Severity.ERROR, Category.COMPATIBILITY)
95     val PARAMETER_NAME_CHANGE by Issue(Severity.ERROR, Category.COMPATIBILITY)
96     val OPERATOR_REMOVAL by Issue(Severity.ERROR, Category.COMPATIBILITY)
97     val INFIX_REMOVAL by Issue(Severity.ERROR, Category.COMPATIBILITY)
98     val VARARG_REMOVAL by Issue(Severity.ERROR, Category.COMPATIBILITY)
99     val ADD_SEALED by Issue(Severity.ERROR, Category.COMPATIBILITY)
100     val FUN_REMOVAL by Issue(Severity.ERROR, Category.COMPATIBILITY)
101     val BECAME_UNCHECKED by Issue(Severity.ERROR, Category.COMPATIBILITY)
102     val ANNOTATION_EXTRACTION by Issue(Severity.ERROR)
103     val SUPERFLUOUS_PREFIX by Issue(Severity.WARNING)
104     val HIDDEN_TYPEDEF_CONSTANT by Issue(Severity.ERROR)
105     val EXPECTED_PLATFORM_TYPE by Issue(Severity.HIDDEN)
106     val INTERNAL_ERROR by Issue(Severity.ERROR)
107     val RETURNING_UNEXPECTED_CONSTANT by Issue(Severity.WARNING)
108     val DEPRECATED_OPTION by Issue(Severity.WARNING)
109     val BOTH_PACKAGE_INFO_AND_HTML by Issue(Severity.WARNING, Category.DOCUMENTATION)
110     val UNMATCHED_MERGE_ANNOTATION by Issue(Severity.ERROR)
111     // The plan is for this to be set as an error once (1) existing code is marked as @deprecated
112     // and (2) the principle is adopted by the API council
113     val REFERENCES_DEPRECATED by Issue(Severity.HIDDEN)
114     val UNHIDDEN_SYSTEM_API by Issue(Severity.ERROR)
115     val SHOWING_MEMBER_IN_HIDDEN_CLASS by Issue(Severity.ERROR)
116     val INVALID_NULLABILITY_ANNOTATION by Issue(Severity.ERROR)
117     val REFERENCES_HIDDEN by Issue(Severity.ERROR)
118     val IGNORING_SYMLINK by Issue(Severity.INFO)
119     val INVALID_NULLABILITY_ANNOTATION_WARNING by Issue(Severity.WARNING)
120     // The plan is for this to be set as an error once (1) existing code is marked as @deprecated
121     // and (2) the principle is adopted by the API council
122     val EXTENDS_DEPRECATED by Issue(Severity.HIDDEN)
123     val FORBIDDEN_TAG by Issue(Severity.ERROR)
124     val MISSING_COLUMN by Issue(Severity.WARNING, Category.DOCUMENTATION)
125     val INVALID_SYNTAX by Issue(Severity.ERROR)
126     val UNRESOLVED_IMPORT by Issue(Severity.INFO)
127     val HIDDEN_ABSTRACT_METHOD by Issue(Severity.ERROR)
128 
129     // API lint
130     val START_WITH_LOWER by Issue(Severity.ERROR, Category.API_LINT)
131     val START_WITH_UPPER by Issue(Severity.ERROR, Category.API_LINT)
132     val ALL_UPPER by Issue(Severity.ERROR, Category.API_LINT)
133     val ACRONYM_NAME by Issue(Severity.WARNING, Category.API_LINT)
134     val ENUM by Issue(Severity.ERROR, Category.API_LINT)
135     val ENDS_WITH_IMPL by Issue(Severity.ERROR, Category.API_LINT)
136     val MIN_MAX_CONSTANT by Issue(Severity.WARNING, Category.API_LINT)
137     val COMPILE_TIME_CONSTANT by Issue(Severity.ERROR, Category.API_LINT)
138     val SINGULAR_CALLBACK by Issue(Severity.ERROR, Category.API_LINT)
139     val CALLBACK_NAME by Issue(Severity.WARNING, Category.API_LINT)
140     // Obsolete per https://s.android.com/api-guidelines.
141     val CALLBACK_INTERFACE by Issue(Severity.HIDDEN, Category.API_LINT)
142     val CALLBACK_METHOD_NAME by Issue(Severity.ERROR, Category.API_LINT)
143     val LISTENER_INTERFACE by Issue(Severity.ERROR, Category.API_LINT)
144     val SINGLE_METHOD_INTERFACE by Issue(Severity.ERROR, Category.API_LINT)
145     val INTENT_NAME by Issue(Severity.ERROR, Category.API_LINT)
146     val ACTION_VALUE by Issue(Severity.ERROR, Category.API_LINT)
147     val EQUALS_AND_HASH_CODE by Issue(Severity.ERROR, Category.API_LINT)
148     val PARCEL_CREATOR by Issue(Severity.ERROR, Category.API_LINT)
149     val PARCEL_NOT_FINAL by Issue(Severity.ERROR, Category.API_LINT)
150     val PARCEL_CONSTRUCTOR by Issue(Severity.ERROR, Category.API_LINT)
151     val PROTECTED_MEMBER by Issue(Severity.ERROR, Category.API_LINT)
152     val PAIRED_REGISTRATION by Issue(Severity.ERROR, Category.API_LINT)
153     val REGISTRATION_NAME by Issue(Severity.ERROR, Category.API_LINT)
154     val VISIBLY_SYNCHRONIZED by Issue(Severity.ERROR, Category.API_LINT)
155     val INTENT_BUILDER_NAME by Issue(Severity.WARNING, Category.API_LINT)
156     val CONTEXT_NAME_SUFFIX by Issue(Severity.ERROR, Category.API_LINT)
157     val INTERFACE_CONSTANT by Issue(Severity.ERROR, Category.API_LINT)
158     val ON_NAME_EXPECTED by Issue(Severity.WARNING, Category.API_LINT)
159     val TOP_LEVEL_BUILDER by Issue(Severity.WARNING, Category.API_LINT)
160     val MISSING_BUILD_METHOD by Issue(Severity.WARNING, Category.API_LINT)
161     val BUILDER_SET_STYLE by Issue(Severity.WARNING, Category.API_LINT)
162     val SETTER_RETURNS_THIS by Issue(Severity.WARNING, Category.API_LINT)
163     val RAW_AIDL by Issue(Severity.ERROR, Category.API_LINT)
164     val INTERNAL_CLASSES by Issue(Severity.ERROR, Category.API_LINT)
165     val PACKAGE_LAYERING by Issue(Severity.WARNING, Category.API_LINT)
166     val GETTER_SETTER_NAMES by Issue(Severity.ERROR, Category.API_LINT)
167     val CONCRETE_COLLECTION by Issue(Severity.ERROR, Category.API_LINT)
168     val OVERLAPPING_CONSTANTS by Issue(Severity.WARNING, Category.API_LINT)
169     val GENERIC_EXCEPTION by Issue(Severity.ERROR, Category.API_LINT)
170     val ILLEGAL_STATE_EXCEPTION by Issue(Severity.WARNING, Category.API_LINT)
171     val RETHROW_REMOTE_EXCEPTION by Issue(Severity.ERROR, Category.API_LINT)
172     val MENTIONS_GOOGLE by Issue(Severity.ERROR, Category.API_LINT)
173     val HEAVY_BIT_SET by Issue(Severity.ERROR, Category.API_LINT)
174     val MANAGER_CONSTRUCTOR by Issue(Severity.ERROR, Category.API_LINT)
175     val MANAGER_LOOKUP by Issue(Severity.ERROR, Category.API_LINT)
176     val AUTO_BOXING by Issue(Severity.ERROR, Category.API_LINT)
177     val STATIC_UTILS by Issue(Severity.ERROR, Category.API_LINT)
178     val CONTEXT_FIRST by Issue(Severity.ERROR, Category.API_LINT)
179     val LISTENER_LAST by Issue(Severity.WARNING, Category.API_LINT)
180     val EXECUTOR_REGISTRATION by Issue(Severity.WARNING, Category.API_LINT)
181     val CONFIG_FIELD_NAME by Issue(Severity.ERROR, Category.API_LINT)
182     val RESOURCE_FIELD_NAME by Issue(Severity.ERROR, Category.API_LINT)
183     val RESOURCE_VALUE_FIELD_NAME by Issue(Severity.ERROR, Category.API_LINT)
184     val RESOURCE_STYLE_FIELD_NAME by Issue(Severity.ERROR, Category.API_LINT)
185     val STREAM_FILES by Issue(Severity.WARNING, Category.API_LINT)
186     val PARCELABLE_LIST by Issue(Severity.WARNING, Category.API_LINT)
187     val ABSTRACT_INNER by Issue(Severity.WARNING, Category.API_LINT)
188     val BANNED_THROW by Issue(Severity.ERROR, Category.API_LINT)
189     val EXTENDS_ERROR by Issue(Severity.ERROR, Category.API_LINT)
190     val EXCEPTION_NAME by Issue(Severity.ERROR, Category.API_LINT)
191     val METHOD_NAME_UNITS by Issue(Severity.ERROR, Category.API_LINT)
192     val FRACTION_FLOAT by Issue(Severity.ERROR, Category.API_LINT)
193     val PERCENTAGE_INT by Issue(Severity.ERROR, Category.API_LINT)
194     val NOT_CLOSEABLE by Issue(Severity.WARNING, Category.API_LINT)
195     val KOTLIN_OPERATOR by Issue(Severity.INFO, Category.API_LINT)
196     val ARRAY_RETURN by Issue(Severity.WARNING, Category.API_LINT)
197     val USER_HANDLE by Issue(Severity.WARNING, Category.API_LINT)
198     val USER_HANDLE_NAME by Issue(Severity.WARNING, Category.API_LINT)
199     val SERVICE_NAME by Issue(Severity.ERROR, Category.API_LINT)
200     val METHOD_NAME_TENSE by Issue(Severity.WARNING, Category.API_LINT)
201     val NO_CLONE by Issue(Severity.ERROR, Category.API_LINT)
202     val USE_ICU by Issue(Severity.WARNING, Category.API_LINT)
203     val USE_PARCEL_FILE_DESCRIPTOR by Issue(Severity.ERROR, Category.API_LINT)
204     val NO_BYTE_OR_SHORT by Issue(Severity.WARNING, Category.API_LINT)
205     val SINGLETON_CONSTRUCTOR by Issue(Severity.ERROR, Category.API_LINT)
206     val KOTLIN_KEYWORD by Issue(Severity.ERROR, Category.API_LINT)
207     val UNIQUE_KOTLIN_OPERATOR by Issue(Severity.ERROR, Category.API_LINT)
208     val SAM_SHOULD_BE_LAST by Issue(Severity.WARNING, Category.API_LINT)
209     val MISSING_JVMSTATIC by Issue(Severity.WARNING, Category.API_LINT)
210     val DEFAULT_VALUE_CHANGE by Issue(Severity.ERROR, Category.API_LINT)
211     val DOCUMENT_EXCEPTIONS by Issue(Severity.ERROR, Category.API_LINT)
212     val FORBIDDEN_SUPER_CLASS by Issue(Severity.ERROR, Category.API_LINT)
213     val MISSING_NULLABILITY by Issue(Severity.ERROR, Category.API_LINT)
214     // This issue must be manually enabled
215     val MISSING_INNER_NULLABILITY by Issue(Severity.HIDDEN, Category.API_LINT)
216     val INVALID_NULLABILITY_OVERRIDE by Issue(Severity.ERROR, Category.API_LINT)
217     val MUTABLE_BARE_FIELD by Issue(Severity.ERROR, Category.API_LINT)
218     val INTERNAL_FIELD by Issue(Severity.ERROR, Category.API_LINT)
219     val PUBLIC_TYPEDEF by Issue(Severity.ERROR, Category.API_LINT)
220     val ANDROID_URI by Issue(Severity.ERROR, Category.API_LINT)
221     val BAD_FUTURE by Issue(Severity.ERROR, Category.API_LINT)
222     val STATIC_FINAL_BUILDER by Issue(Severity.WARNING, Category.API_LINT)
223     val GETTER_ON_BUILDER by Issue(Severity.WARNING, Category.API_LINT)
224     val MISSING_GETTER_MATCHING_BUILDER by Issue(Severity.WARNING, Category.API_LINT)
225     val OPTIONAL_BUILDER_CONSTRUCTOR_ARGUMENT by Issue(Severity.WARNING, Category.API_LINT)
226     val NO_SETTINGS_PROVIDER by Issue(Severity.HIDDEN, Category.API_LINT)
227     val NULLABLE_COLLECTION by Issue(Severity.WARNING, Category.API_LINT)
228     val NULLABLE_COLLECTION_ELEMENT by Issue(Severity.WARNING, Category.API_LINT)
229     val ASYNC_SUFFIX_FUTURE by Issue(Severity.ERROR, Category.API_LINT)
230     val GENERIC_CALLBACKS by Issue(Severity.ERROR, Category.API_LINT)
231     val KOTLIN_DEFAULT_PARAMETER_ORDER by Issue(Severity.ERROR, Category.API_LINT)
232     val UNFLAGGED_API by Issue(Severity.HIDDEN, Category.API_LINT)
233     val FLAGGED_API_LITERAL by Issue(Severity.WARNING_ERROR_WHEN_NEW, Category.API_LINT)
234     val GETTER_SETTER_NULLABILITY by Issue(Severity.WARNING_ERROR_WHEN_NEW, Category.API_LINT)
235 
findIssueByIdnull236     fun findIssueById(id: String?): Issue? {
237         return nameToIssue[id]
238     }
239 
findIssueByIdIgnoringCasenull240     fun findIssueByIdIgnoringCase(id: String): Issue? {
241         for (e in allIssues) {
242             if (id.equals(e.name, ignoreCase = true)) {
243                 return e
244             }
245         }
246         return null
247     }
248 
<lambda>null249     fun findCategoryById(id: String?): Category? = Category.values().find { it.id == id }
250 
findIssuesByCategorynull251     fun findIssuesByCategory(category: Category?): List<Issue> =
252         allIssues.filter { it.category == category }
253 
254     class Issue
255     private constructor(
256         val defaultLevel: Severity,
257         /**
258          * When `level` is set to [Severity.INHERIT], this is the parent from which the issue will
259          * inherit its level.
260          */
261         val parent: Issue?,
262         /** Applicable category */
263         val category: Category,
264     ) : ReadOnlyProperty<Issues, Issue> {
265         /** The name of this issue */
266         lateinit var name: String
267             internal set
268 
269         internal constructor(
270             defaultLevel: Severity,
271             category: Category = Category.UNKNOWN
272         ) : this(defaultLevel, null, category)
273 
274         internal constructor(
275             parent: Issue,
276             category: Category
277         ) : this(Severity.INHERIT, parent, category)
278 
279         /**
280          * Called to get the value of the delegating property; as this is the value just return it.
281          */
getValuenull282         override fun getValue(thisRef: Issues, property: KProperty<*>): Issue {
283             return this
284         }
285 
286         /**
287          * Called once on creation to retrieve the property delegate.
288          *
289          * Initializes the name and adds a mapping from the name to this and then just returns this
290          * as the delegate.
291          */
provideDelegatenull292         operator fun provideDelegate(thisRef: Issues, property: KProperty<*>): Issue {
293             // Initialize issue names based on the property names.
294             name = enumConstantToCamelCase(property.name)
295             nameToIssue[name] = this
296             return this
297         }
298 
toStringnull299         override fun toString(): String {
300             return "Issue $name"
301         }
302 
303         init {
304             allIssues.add(this)
305         }
306     }
307 
308     enum class Category(val description: String) {
309         COMPATIBILITY("Compatibility"),
310         DOCUMENTATION("Documentation"),
311         API_LINT("API Lint"),
312         UNKNOWN("Default");
313 
314         /** Identifier for use in command-line arguments and reporting. */
315         val id: String = enumConstantToCamelCase(name)
316     }
317 
318     init {
319         // Make sure that every Issue was created as a property delegate using `by` and not just
320         // assigned to the field using `=`.
321         for (issue in allIssues) {
322             check(issue.name != "")
323         }
324     }
325 }
326 
327 /**
328  * Convert enum constant name to camel case starting with an upper case letter.
329  *
330  * e.g. `ALPHA_BETA` becomes `AlphaBeta`.
331  */
enumConstantToCamelCasenull332 private fun enumConstantToCamelCase(name: String): String {
333     return name
334         .splitToSequence("_")
335         .map { "${it[0]}${it.substring(1).lowercase(Locale.US)}" }
336         .joinToString("")
337 }
338