blob: 55e5be3c29a784f5c551dd10ef1b9d96b4167a0b [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tools.metalava
import com.android.sdklib.SdkVersionInfo
import java.util.ArrayList
import java.util.HashMap
import java.util.Locale
import kotlin.reflect.full.declaredMemberProperties
object Issues {
private val allIssues: MutableList<Issue> = ArrayList(300)
private val nameToIssue: MutableMap<String, Issue> = HashMap(300)
val PARSE_ERROR = Issue(Severity.ERROR)
// Compatibility issues
val ADDED_PACKAGE = Issue(Severity.WARNING, Category.COMPATIBILITY)
val ADDED_CLASS = Issue(Severity.WARNING, Category.COMPATIBILITY)
val ADDED_METHOD = Issue(Severity.WARNING, Category.COMPATIBILITY)
val ADDED_FIELD = Issue(Severity.WARNING, Category.COMPATIBILITY)
val ADDED_INTERFACE = Issue(Severity.WARNING, Category.COMPATIBILITY)
val REMOVED_PACKAGE = Issue(Severity.WARNING, Category.COMPATIBILITY)
val REMOVED_CLASS = Issue(Severity.WARNING, Category.COMPATIBILITY)
val REMOVED_METHOD = Issue(Severity.WARNING, Category.COMPATIBILITY)
val REMOVED_FIELD = Issue(Severity.WARNING, Category.COMPATIBILITY)
val REMOVED_INTERFACE = Issue(Severity.WARNING, Category.COMPATIBILITY)
val CHANGED_STATIC = Issue(Severity.WARNING, Category.COMPATIBILITY)
val ADDED_FINAL = Issue(Severity.WARNING, Category.COMPATIBILITY)
val CHANGED_TRANSIENT = Issue(Severity.WARNING, Category.COMPATIBILITY)
val CHANGED_VOLATILE = Issue(Severity.WARNING, Category.COMPATIBILITY)
val CHANGED_TYPE = Issue(Severity.WARNING, Category.COMPATIBILITY)
val CHANGED_VALUE = Issue(Severity.WARNING, Category.COMPATIBILITY)
val CHANGED_SUPERCLASS = Issue(Severity.WARNING, Category.COMPATIBILITY)
val CHANGED_SCOPE = Issue(Severity.ERROR, Category.COMPATIBILITY)
val CHANGED_ABSTRACT = Issue(Severity.WARNING, Category.COMPATIBILITY)
val CHANGED_THROWS = Issue(Severity.WARNING, Category.COMPATIBILITY)
val CHANGED_NATIVE = Issue(Severity.HIDDEN, Category.COMPATIBILITY)
val CHANGED_CLASS = Issue(Severity.WARNING, Category.COMPATIBILITY)
val CHANGED_DEPRECATED = Issue(Severity.WARNING, Category.COMPATIBILITY)
val CHANGED_SYNCHRONIZED = Issue(Severity.WARNING, Category.COMPATIBILITY)
val ADDED_FINAL_UNINSTANTIABLE = Issue(Severity.WARNING, Category.COMPATIBILITY)
val REMOVED_FINAL = Issue(Severity.WARNING, Category.COMPATIBILITY)
val REMOVED_DEPRECATED_CLASS = Issue(REMOVED_CLASS, Category.COMPATIBILITY)
val REMOVED_DEPRECATED_METHOD = Issue(REMOVED_METHOD, Category.COMPATIBILITY)
val REMOVED_DEPRECATED_FIELD = Issue(REMOVED_FIELD, Category.COMPATIBILITY)
val ADDED_ABSTRACT_METHOD = Issue(ADDED_METHOD, Category.COMPATIBILITY)
val ADDED_REIFIED = Issue(Severity.WARNING, Category.COMPATIBILITY)
// Issues in javadoc generation
val UNRESOLVED_LINK = Issue(Severity.LINT, Category.DOCUMENTATION)
val BAD_INCLUDE_TAG = Issue(Severity.LINT, Category.DOCUMENTATION)
val UNKNOWN_TAG = Issue(Severity.LINT, Category.DOCUMENTATION)
val UNKNOWN_PARAM_TAG_NAME = Issue(Severity.LINT, Category.DOCUMENTATION)
val UNDOCUMENTED_PARAMETER = Issue(Severity.HIDDEN, Category.DOCUMENTATION)
val BAD_ATTR_TAG = Issue(Severity.LINT, Category.DOCUMENTATION)
val BAD_INHERITDOC = Issue(Severity.HIDDEN, Category.DOCUMENTATION)
val HIDDEN_LINK = Issue(Severity.LINT, Category.DOCUMENTATION)
val HIDDEN_CONSTRUCTOR = Issue(Severity.WARNING, Category.DOCUMENTATION)
val UNAVAILABLE_SYMBOL = Issue(Severity.WARNING, Category.DOCUMENTATION)
val HIDDEN_SUPERCLASS = Issue(Severity.WARNING, Category.DOCUMENTATION)
val DEPRECATED = Issue(Severity.HIDDEN, Category.DOCUMENTATION)
val DEPRECATION_MISMATCH = Issue(Severity.ERROR, Category.DOCUMENTATION)
val MISSING_COMMENT = Issue(Severity.LINT, Category.DOCUMENTATION)
val IO_ERROR = Issue(Severity.ERROR)
val NO_SINCE_DATA = Issue(Severity.HIDDEN, Category.DOCUMENTATION)
val NO_FEDERATION_DATA = Issue(Severity.WARNING, Category.DOCUMENTATION)
val BROKEN_SINCE_FILE = Issue(Severity.ERROR, Category.DOCUMENTATION)
val INVALID_CONTENT_TYPE = Issue(Severity.ERROR, Category.DOCUMENTATION)
val INVALID_SAMPLE_INDEX = Issue(Severity.ERROR, Category.DOCUMENTATION)
val HIDDEN_TYPE_PARAMETER = Issue(Severity.WARNING, Category.DOCUMENTATION)
val PRIVATE_SUPERCLASS = Issue(Severity.WARNING, Category.DOCUMENTATION)
val NULLABLE = Issue(Severity.HIDDEN, Category.DOCUMENTATION)
val INT_DEF = Issue(Severity.HIDDEN, Category.DOCUMENTATION)
val REQUIRES_PERMISSION = Issue(Severity.LINT, Category.DOCUMENTATION)
val BROADCAST_BEHAVIOR = Issue(Severity.LINT, Category.DOCUMENTATION)
val SDK_CONSTANT = Issue(Severity.LINT, Category.DOCUMENTATION)
val TODO = Issue(Severity.LINT, Category.DOCUMENTATION)
val NO_ARTIFACT_DATA = Issue(Severity.HIDDEN, Category.DOCUMENTATION)
val BROKEN_ARTIFACT_FILE = Issue(Severity.ERROR, Category.DOCUMENTATION)
// Metalava warnings (not from doclava)
val TYPO = Issue(Severity.WARNING, Category.DOCUMENTATION)
val MISSING_PERMISSION = Issue(Severity.LINT, Category.DOCUMENTATION)
val MULTIPLE_THREAD_ANNOTATIONS = Issue(Severity.LINT, Category.DOCUMENTATION)
val UNRESOLVED_CLASS = Issue(Severity.LINT, Category.DOCUMENTATION)
val INVALID_NULL_CONVERSION = Issue(Severity.ERROR, Category.COMPATIBILITY)
val PARAMETER_NAME_CHANGE = Issue(Severity.ERROR, Category.COMPATIBILITY)
val OPERATOR_REMOVAL = Issue(Severity.ERROR, Category.COMPATIBILITY)
val INFIX_REMOVAL = Issue(Severity.ERROR, Category.COMPATIBILITY)
val VARARG_REMOVAL = Issue(Severity.ERROR, Category.COMPATIBILITY)
val ADD_SEALED = Issue(Severity.ERROR, Category.COMPATIBILITY)
val FUN_REMOVAL = Issue(Severity.ERROR, Category.COMPATIBILITY)
val ANNOTATION_EXTRACTION = Issue(Severity.ERROR)
val SUPERFLUOUS_PREFIX = Issue(Severity.WARNING)
val HIDDEN_TYPEDEF_CONSTANT = Issue(Severity.ERROR)
val EXPECTED_PLATFORM_TYPE = Issue(Severity.HIDDEN)
val INTERNAL_ERROR = Issue(Severity.ERROR)
val RETURNING_UNEXPECTED_CONSTANT = Issue(Severity.WARNING)
val DEPRECATED_OPTION = Issue(Severity.WARNING)
val BOTH_PACKAGE_INFO_AND_HTML = Issue(Severity.WARNING, Category.DOCUMENTATION)
val UNMATCHED_MERGE_ANNOTATION = Issue(Severity.WARNING)
// The plan is for this to be set as an error once (1) existing code is marked as @deprecated
// and (2) the principle is adopted by the API council
val REFERENCES_DEPRECATED = Issue(Severity.HIDDEN)
val UNHIDDEN_SYSTEM_API = Issue(Severity.ERROR)
val SHOWING_MEMBER_IN_HIDDEN_CLASS = Issue(Severity.ERROR)
val INVALID_NULLABILITY_ANNOTATION = Issue(Severity.ERROR)
val REFERENCES_HIDDEN = Issue(Severity.ERROR)
val IGNORING_SYMLINK = Issue(Severity.INFO)
val INVALID_NULLABILITY_ANNOTATION_WARNING = Issue(Severity.WARNING)
// The plan is for this to be set as an error once (1) existing code is marked as @deprecated
// and (2) the principle is adopted by the API council
val EXTENDS_DEPRECATED = Issue(Severity.HIDDEN)
val FORBIDDEN_TAG = Issue(Severity.ERROR)
val MISSING_COLUMN = Issue(Severity.WARNING, Category.DOCUMENTATION)
val INVALID_SYNTAX = Issue(Severity.ERROR)
val UNRESOLVED_IMPORT = Issue(Severity.INFO)
val HIDDEN_ABSTRACT_METHOD = Issue(Severity.ERROR)
// API lint
val START_WITH_LOWER = Issue(Severity.ERROR, Category.API_LINT, "style-conventions")
val START_WITH_UPPER = Issue(Severity.ERROR, Category.API_LINT, "style-conventions")
val ALL_UPPER = Issue(Severity.ERROR, Category.API_LINT, "constant-naming")
val ACRONYM_NAME = Issue(Severity.WARNING, Category.API_LINT, "acronyms-in-method-name")
val ENUM = Issue(Severity.ERROR, Category.API_LINT, "avoid-enum")
val ENDS_WITH_IMPL = Issue(Severity.ERROR, Category.API_LINT, "dont-end-with-impl")
val MIN_MAX_CONSTANT = Issue(Severity.WARNING, Category.API_LINT, "min-max-constants")
val COMPILE_TIME_CONSTANT = Issue(Severity.ERROR, Category.API_LINT)
val SINGULAR_CALLBACK = Issue(Severity.ERROR, Category.API_LINT, "callback-class-singular")
val CALLBACK_NAME = Issue(Severity.WARNING, Category.API_LINT, "observer-should-be-callback")
val CALLBACK_INTERFACE =
Issue(Severity.ERROR, Category.API_LINT, "callback-abstract-instead-of-interface")
val CALLBACK_METHOD_NAME = Issue(Severity.ERROR, Category.API_LINT, "callback-method-naming")
val LISTENER_INTERFACE = Issue(Severity.ERROR, Category.API_LINT, "callbacks-listener")
val SINGLE_METHOD_INTERFACE = Issue(Severity.ERROR, Category.API_LINT, "callbacks-listener")
val INTENT_NAME =
Issue(Severity.ERROR, Category.API_LINT, "use-standard-prefixes-for-constants")
val ACTION_VALUE = Issue(Severity.ERROR, Category.API_LINT)
val EQUALS_AND_HASH_CODE = Issue(Severity.ERROR, Category.API_LINT, "equals-and-hashcode")
val PARCEL_CREATOR = Issue(Severity.ERROR, Category.API_LINT, "parcelable-creator")
val PARCEL_NOT_FINAL = Issue(Severity.ERROR, Category.API_LINT, "parcelable-final")
val PARCEL_CONSTRUCTOR = Issue(Severity.ERROR, Category.API_LINT, "parcelable-creator")
val PROTECTED_MEMBER = Issue(Severity.ERROR, Category.API_LINT, "avoid-protected")
val PAIRED_REGISTRATION = Issue(Severity.ERROR, Category.API_LINT, "callbacks-symmetry")
val REGISTRATION_NAME = Issue(Severity.ERROR, Category.API_LINT, "callbacks-accessors")
val VISIBLY_SYNCHRONIZED = Issue(Severity.ERROR, Category.API_LINT, "avoid-synchronized")
val INTENT_BUILDER_NAME =
Issue(Severity.WARNING, Category.API_LINT, "intent-builder-createintent")
val CONTEXT_NAME_SUFFIX = Issue(Severity.ERROR, Category.API_LINT, "classes-subclass-naming")
val INTERFACE_CONSTANT = Issue(Severity.ERROR, Category.API_LINT, "services-intents")
val ON_NAME_EXPECTED = Issue(Severity.WARNING, Category.API_LINT, "callback-method-naming")
val TOP_LEVEL_BUILDER = Issue(Severity.WARNING, Category.API_LINT, "builders-static-inner")
val MISSING_BUILD_METHOD =
Issue(Severity.WARNING, Category.API_LINT, "builder-must-declare-build")
val BUILDER_SET_STYLE = Issue(Severity.WARNING, Category.API_LINT, "builder-method-naming")
val SETTER_RETURNS_THIS = Issue(Severity.WARNING, Category.API_LINT)
val RAW_AIDL = Issue(Severity.ERROR, Category.API_LINT, "no-public-binder")
val INTERNAL_CLASSES = Issue(Severity.ERROR, Category.API_LINT)
val PACKAGE_LAYERING = Issue(Severity.WARNING, Category.API_LINT)
val GETTER_SETTER_NAMES = Issue(Severity.ERROR, Category.API_LINT)
val CONCRETE_COLLECTION = Issue(Severity.ERROR, Category.API_LINT, "classes-collections")
val OVERLAPPING_CONSTANTS = Issue(Severity.WARNING, Category.API_LINT, "overlapping-constants")
val GENERIC_EXCEPTION = Issue(Severity.ERROR, Category.API_LINT, "appropriate-exception")
val ILLEGAL_STATE_EXCEPTION =
Issue(Severity.WARNING, Category.API_LINT, "appropriate-exception")
val RETHROW_REMOTE_EXCEPTION = Issue(Severity.ERROR, Category.API_LINT, "appropriate-exception")
val MENTIONS_GOOGLE = Issue(Severity.ERROR, Category.API_LINT, "mentions-google")
val HEAVY_BIT_SET = Issue(Severity.ERROR, Category.API_LINT, "avoid-bitset")
val MANAGER_CONSTRUCTOR = Issue(Severity.ERROR, Category.API_LINT)
val MANAGER_LOOKUP = Issue(Severity.ERROR, Category.API_LINT)
val AUTO_BOXING = Issue(Severity.ERROR, Category.API_LINT, "auto-boxing")
val STATIC_UTILS = Issue(Severity.ERROR, Category.API_LINT)
val CONTEXT_FIRST = Issue(Severity.ERROR, Category.API_LINT)
val LISTENER_LAST = Issue(Severity.WARNING, Category.API_LINT, "placement-of-sam-parameters")
val EXECUTOR_REGISTRATION = Issue(Severity.WARNING, Category.API_LINT, "callbacks-listener")
val CONFIG_FIELD_NAME = Issue(Severity.ERROR, Category.API_LINT)
val RESOURCE_FIELD_NAME = Issue(Severity.ERROR, Category.API_LINT)
val RESOURCE_VALUE_FIELD_NAME = Issue(Severity.ERROR, Category.API_LINT)
val RESOURCE_STYLE_FIELD_NAME = Issue(Severity.ERROR, Category.API_LINT)
val STREAM_FILES = Issue(Severity.WARNING, Category.API_LINT)
val PARCELABLE_LIST = Issue(Severity.WARNING, Category.API_LINT)
val ABSTRACT_INNER = Issue(Severity.WARNING, Category.API_LINT)
val BANNED_THROW = Issue(Severity.ERROR, Category.API_LINT)
val EXTENDS_ERROR = Issue(Severity.ERROR, Category.API_LINT)
val EXCEPTION_NAME = Issue(Severity.ERROR, Category.API_LINT)
val METHOD_NAME_UNITS = Issue(Severity.ERROR, Category.API_LINT, "unit-names")
val FRACTION_FLOAT = Issue(Severity.ERROR, Category.API_LINT)
val PERCENTAGE_INT = Issue(Severity.ERROR, Category.API_LINT)
val NOT_CLOSEABLE = Issue(Severity.WARNING, Category.API_LINT)
val KOTLIN_OPERATOR = Issue(Severity.INFO, Category.API_LINT)
val ARRAY_RETURN =
Issue(Severity.WARNING, Category.API_LINT, "methods-prefer-collection-over-array")
val USER_HANDLE = Issue(Severity.WARNING, Category.API_LINT)
val USER_HANDLE_NAME = Issue(Severity.WARNING, Category.API_LINT)
val SERVICE_NAME = Issue(Severity.ERROR, Category.API_LINT)
val METHOD_NAME_TENSE = Issue(Severity.WARNING, Category.API_LINT)
val NO_CLONE = Issue(Severity.ERROR, Category.API_LINT, "avoid-clone")
val USE_ICU = Issue(Severity.WARNING, Category.API_LINT)
val USE_PARCEL_FILE_DESCRIPTOR =
Issue(Severity.ERROR, Category.API_LINT, "prefer-parcelfiledescriptor")
val NO_BYTE_OR_SHORT = Issue(Severity.WARNING, Category.API_LINT, "avoid-short-byte")
val SINGLETON_CONSTRUCTOR = Issue(Severity.ERROR, Category.API_LINT, "singleton-class")
val COMMON_ARGS_FIRST = Issue(Severity.WARNING, Category.API_LINT, "optional-params-last")
val CONSISTENT_ARGUMENT_ORDER = Issue(Severity.ERROR, Category.API_LINT, "optional-params-last")
val KOTLIN_KEYWORD = Issue(Severity.ERROR, Category.API_LINT)
val UNIQUE_KOTLIN_OPERATOR = Issue(Severity.ERROR, Category.API_LINT)
val SAM_SHOULD_BE_LAST =
Issue(Severity.WARNING, Category.API_LINT, "placement-of-sam-parameters")
val MISSING_JVMSTATIC = Issue(Severity.WARNING, Category.API_LINT)
val DEFAULT_VALUE_CHANGE = Issue(Severity.ERROR, Category.API_LINT, "default-value-removal")
val DOCUMENT_EXCEPTIONS = Issue(Severity.ERROR, Category.API_LINT, "docs-throws")
val FORBIDDEN_SUPER_CLASS = Issue(Severity.ERROR, Category.API_LINT)
val MISSING_NULLABILITY = Issue(Severity.ERROR, Category.API_LINT, "annotations")
val MUTABLE_BARE_FIELD = Issue(Severity.ERROR, Category.API_LINT, "mutable-bare-field")
val INTERNAL_FIELD = Issue(Severity.ERROR, Category.API_LINT, "internal-fields")
val PUBLIC_TYPEDEF = Issue(Severity.ERROR, Category.API_LINT, "no-public-typedefs")
val ANDROID_URI = Issue(Severity.ERROR, Category.API_LINT, "android-uri")
val BAD_FUTURE = Issue(Severity.ERROR, Category.API_LINT, "bad-future")
val STATIC_FINAL_BUILDER = Issue(Severity.WARNING, Category.API_LINT, "builders-static-inner")
val GETTER_ON_BUILDER = Issue(Severity.WARNING, Category.API_LINT, "getter-on-builder")
val MISSING_GETTER_MATCHING_BUILDER =
Issue(Severity.WARNING, Category.API_LINT, "builders-symmetric-setters")
val OPTIONAL_BUILDER_CONSTRUCTOR_ARGUMENT =
Issue(Severity.WARNING, Category.API_LINT, "builders-nonnull-constructors")
val NO_SETTINGS_PROVIDER = Issue(Severity.HIDDEN, Category.API_LINT, "no-settings-provider")
val NULLABLE_COLLECTION = Issue(Severity.WARNING, Category.API_LINT, "methods-prefer-non-null-collections")
val ASYNC_SUFFIX_FUTURE = Issue(Severity.ERROR, Category.API_LINT)
fun findIssueById(id: String?): Issue? {
return nameToIssue[id]
}
fun findIssueByIdIgnoringCase(id: String): Issue? {
for (e in allIssues) {
if (id.equals(e.name, ignoreCase = true)) {
return e
}
}
return null
}
class Issue private constructor(
val defaultLevel: Severity,
/**
* When `level` is set to [Severity.INHERIT], this is the parent from
* which the issue will inherit its level.
*/
val parent: Issue?,
/** Applicable category */
val category: Category,
/** Related rule, if any */
val rule: String?
) {
/**
* The name of this issue
*/
lateinit var name: String
internal set
internal constructor(
defaultLevel: Severity,
category: Category = Category.UNKNOWN
) : this(defaultLevel, null, category, null)
internal constructor(
defaultLevel: Severity,
category: Category,
rule: String
) : this(defaultLevel, null, category, rule)
internal constructor(
parent: Issue,
category: Category
) : this(Severity.INHERIT, parent, category, null)
override fun toString(): String {
return "Issue $name"
}
init {
allIssues.add(this)
}
}
enum class Category(val description: String, val ruleLink: String?) {
COMPATIBILITY("Compatibility", null),
DOCUMENTATION("Documentation", null),
API_LINT("API Lint", "https://s.android.com/api-guidelines#"),
UNKNOWN("Default", null)
}
init { // Initialize issue names based on the field names
for (property in Issues::class.declaredMemberProperties) {
if (property.returnType.classifier != Issue::class) continue
val issue = property.getter.call(Issues) as Issue
issue.name = SdkVersionInfo.underlinesToCamelCase(property.name.lowercase(Locale.US))
nameToIssue[issue.name] = issue
}
for (issue in allIssues) {
check(issue.name != "")
}
}
}