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 package com.android.tools.metalava 17 18 import com.android.sdklib.SdkVersionInfo 19 import java.util.Locale 20 import kotlin.reflect.full.declaredMemberProperties 21 22 object Issues { 23 private val allIssues: MutableList<Issue> = ArrayList(300) 24 private val nameToIssue: MutableMap<String, Issue> = HashMap(300) 25 26 val PARSE_ERROR = Issue(Severity.ERROR) 27 // Compatibility issues 28 val ADDED_PACKAGE = Issue(Severity.HIDDEN, Category.COMPATIBILITY) 29 val ADDED_CLASS = Issue(Severity.HIDDEN, Category.COMPATIBILITY) 30 val ADDED_METHOD = Issue(Severity.HIDDEN, Category.COMPATIBILITY) 31 val ADDED_FIELD = Issue(Severity.HIDDEN, Category.COMPATIBILITY) 32 val ADDED_INTERFACE = Issue(Severity.HIDDEN, Category.COMPATIBILITY) 33 val REMOVED_PACKAGE = Issue(Severity.ERROR, Category.COMPATIBILITY) 34 val REMOVED_CLASS = Issue(Severity.ERROR, Category.COMPATIBILITY) 35 val REMOVED_METHOD = Issue(Severity.ERROR, Category.COMPATIBILITY) 36 val REMOVED_FIELD = Issue(Severity.ERROR, Category.COMPATIBILITY) 37 val REMOVED_INTERFACE = Issue(Severity.ERROR, Category.COMPATIBILITY) 38 val CHANGED_STATIC = Issue(Severity.ERROR, Category.COMPATIBILITY) 39 val ADDED_FINAL = Issue(Severity.ERROR, Category.COMPATIBILITY) 40 val CHANGED_TRANSIENT = Issue(Severity.ERROR, Category.COMPATIBILITY) 41 val CHANGED_VOLATILE = Issue(Severity.ERROR, Category.COMPATIBILITY) 42 val CHANGED_TYPE = Issue(Severity.ERROR, Category.COMPATIBILITY) 43 val CHANGED_VALUE = Issue(Severity.ERROR, Category.COMPATIBILITY) 44 val CHANGED_SUPERCLASS = Issue(Severity.ERROR, Category.COMPATIBILITY) 45 val CHANGED_SCOPE = Issue(Severity.ERROR, Category.COMPATIBILITY) 46 val CHANGED_ABSTRACT = Issue(Severity.ERROR, Category.COMPATIBILITY) 47 val CHANGED_DEFAULT = Issue(Severity.ERROR, Category.COMPATIBILITY) 48 val CHANGED_THROWS = Issue(Severity.ERROR, Category.COMPATIBILITY) 49 val CHANGED_NATIVE = Issue(Severity.HIDDEN, Category.COMPATIBILITY) 50 val CHANGED_CLASS = Issue(Severity.ERROR, Category.COMPATIBILITY) 51 val CHANGED_DEPRECATED = Issue(Severity.HIDDEN, Category.COMPATIBILITY) 52 val CHANGED_SYNCHRONIZED = Issue(Severity.HIDDEN, Category.COMPATIBILITY) 53 val ADDED_FINAL_UNINSTANTIABLE = Issue(Severity.HIDDEN, Category.COMPATIBILITY) 54 val REMOVED_FINAL = Issue(Severity.ERROR, Category.COMPATIBILITY) 55 val REMOVED_DEPRECATED_CLASS = Issue(REMOVED_CLASS, Category.COMPATIBILITY) 56 val REMOVED_DEPRECATED_METHOD = Issue(REMOVED_METHOD, Category.COMPATIBILITY) 57 val REMOVED_DEPRECATED_FIELD = Issue(REMOVED_FIELD, Category.COMPATIBILITY) 58 val ADDED_ABSTRACT_METHOD = Issue(Severity.ERROR, Category.COMPATIBILITY) 59 val ADDED_REIFIED = Issue(Severity.ERROR, Category.COMPATIBILITY) 60 61 // Issues in javadoc generation 62 val UNRESOLVED_LINK = Issue(Severity.LINT, Category.DOCUMENTATION) 63 val UNAVAILABLE_SYMBOL = Issue(Severity.WARNING, Category.DOCUMENTATION) 64 val HIDDEN_SUPERCLASS = Issue(Severity.WARNING, Category.DOCUMENTATION) 65 val DEPRECATED = Issue(Severity.HIDDEN, Category.DOCUMENTATION) 66 val DEPRECATION_MISMATCH = Issue(Severity.ERROR, Category.DOCUMENTATION) 67 val IO_ERROR = Issue(Severity.ERROR) 68 val HIDDEN_TYPE_PARAMETER = Issue(Severity.WARNING, Category.DOCUMENTATION) 69 val PRIVATE_SUPERCLASS = Issue(Severity.WARNING, Category.DOCUMENTATION) 70 val NULLABLE = Issue(Severity.HIDDEN, Category.DOCUMENTATION) 71 val INT_DEF = Issue(Severity.HIDDEN, Category.DOCUMENTATION) 72 val REQUIRES_PERMISSION = Issue(Severity.LINT, Category.DOCUMENTATION) 73 val BROADCAST_BEHAVIOR = Issue(Severity.LINT, Category.DOCUMENTATION) 74 val SDK_CONSTANT = Issue(Severity.LINT, Category.DOCUMENTATION) 75 val TODO = Issue(Severity.LINT, Category.DOCUMENTATION) 76 val NO_ARTIFACT_DATA = Issue(Severity.HIDDEN, Category.DOCUMENTATION) 77 val BROKEN_ARTIFACT_FILE = Issue(Severity.ERROR, Category.DOCUMENTATION) 78 79 // Metalava warnings (not from doclava) 80 81 val TYPO = Issue(Severity.WARNING, Category.DOCUMENTATION) 82 val MISSING_PERMISSION = Issue(Severity.LINT, Category.DOCUMENTATION) 83 val MULTIPLE_THREAD_ANNOTATIONS = Issue(Severity.LINT, Category.DOCUMENTATION) 84 val UNRESOLVED_CLASS = Issue(Severity.LINT, Category.DOCUMENTATION) 85 val INVALID_NULL_CONVERSION = Issue(Severity.ERROR, Category.COMPATIBILITY) 86 val PARAMETER_NAME_CHANGE = Issue(Severity.ERROR, Category.COMPATIBILITY) 87 val OPERATOR_REMOVAL = Issue(Severity.ERROR, Category.COMPATIBILITY) 88 val INFIX_REMOVAL = Issue(Severity.ERROR, Category.COMPATIBILITY) 89 val VARARG_REMOVAL = Issue(Severity.ERROR, Category.COMPATIBILITY) 90 val ADD_SEALED = Issue(Severity.ERROR, Category.COMPATIBILITY) 91 val FUN_REMOVAL = Issue(Severity.ERROR, Category.COMPATIBILITY) 92 val ANNOTATION_EXTRACTION = Issue(Severity.ERROR) 93 val SUPERFLUOUS_PREFIX = Issue(Severity.WARNING) 94 val HIDDEN_TYPEDEF_CONSTANT = Issue(Severity.ERROR) 95 val EXPECTED_PLATFORM_TYPE = Issue(Severity.HIDDEN) 96 val INTERNAL_ERROR = Issue(Severity.ERROR) 97 val RETURNING_UNEXPECTED_CONSTANT = Issue(Severity.WARNING) 98 val DEPRECATED_OPTION = Issue(Severity.WARNING) 99 val BOTH_PACKAGE_INFO_AND_HTML = Issue(Severity.WARNING, Category.DOCUMENTATION) 100 val UNMATCHED_MERGE_ANNOTATION = Issue(Severity.WARNING) 101 // The plan is for this to be set as an error once (1) existing code is marked as @deprecated 102 // and (2) the principle is adopted by the API council 103 val REFERENCES_DEPRECATED = Issue(Severity.HIDDEN) 104 val UNHIDDEN_SYSTEM_API = Issue(Severity.ERROR) 105 val SHOWING_MEMBER_IN_HIDDEN_CLASS = Issue(Severity.ERROR) 106 val INVALID_NULLABILITY_ANNOTATION = Issue(Severity.ERROR) 107 val REFERENCES_HIDDEN = Issue(Severity.ERROR) 108 val IGNORING_SYMLINK = Issue(Severity.INFO) 109 val INVALID_NULLABILITY_ANNOTATION_WARNING = Issue(Severity.WARNING) 110 // The plan is for this to be set as an error once (1) existing code is marked as @deprecated 111 // and (2) the principle is adopted by the API council 112 val EXTENDS_DEPRECATED = Issue(Severity.HIDDEN) 113 val FORBIDDEN_TAG = Issue(Severity.ERROR) 114 val MISSING_COLUMN = Issue(Severity.WARNING, Category.DOCUMENTATION) 115 val INVALID_SYNTAX = Issue(Severity.ERROR) 116 val UNRESOLVED_IMPORT = Issue(Severity.INFO) 117 val HIDDEN_ABSTRACT_METHOD = Issue(Severity.ERROR) 118 119 // API lint 120 val START_WITH_LOWER = Issue(Severity.ERROR, Category.API_LINT, "style-conventions") 121 val START_WITH_UPPER = Issue(Severity.ERROR, Category.API_LINT, "style-conventions") 122 val ALL_UPPER = Issue(Severity.ERROR, Category.API_LINT, "constant-naming") 123 val ACRONYM_NAME = Issue(Severity.WARNING, Category.API_LINT, "acronyms-in-method-name") 124 val ENUM = Issue(Severity.ERROR, Category.API_LINT, "avoid-enum") 125 val ENDS_WITH_IMPL = Issue(Severity.ERROR, Category.API_LINT, "dont-end-with-impl") 126 val MIN_MAX_CONSTANT = Issue(Severity.WARNING, Category.API_LINT, "min-max-constants") 127 val COMPILE_TIME_CONSTANT = Issue(Severity.ERROR, Category.API_LINT) 128 val SINGULAR_CALLBACK = Issue(Severity.ERROR, Category.API_LINT, "callback-class-singular") 129 val CALLBACK_NAME = Issue(Severity.WARNING, Category.API_LINT, "observer-should-be-callback") 130 // Obsolete per https://s.android.com/api-guidelines. 131 val CALLBACK_INTERFACE = 132 Issue(Severity.HIDDEN, Category.API_LINT, "callback-abstract-instead-of-interface") 133 val CALLBACK_METHOD_NAME = Issue(Severity.ERROR, Category.API_LINT, "callback-method-naming") 134 val LISTENER_INTERFACE = Issue(Severity.ERROR, Category.API_LINT, "callbacks-listener") 135 val SINGLE_METHOD_INTERFACE = Issue(Severity.ERROR, Category.API_LINT, "callbacks-listener") 136 val INTENT_NAME = 137 Issue(Severity.ERROR, Category.API_LINT, "use-standard-prefixes-for-constants") 138 val ACTION_VALUE = Issue(Severity.ERROR, Category.API_LINT) 139 val EQUALS_AND_HASH_CODE = Issue(Severity.ERROR, Category.API_LINT, "equals-and-hashcode") 140 val PARCEL_CREATOR = Issue(Severity.ERROR, Category.API_LINT, "parcelable-creator") 141 val PARCEL_NOT_FINAL = Issue(Severity.ERROR, Category.API_LINT, "parcelable-final") 142 val PARCEL_CONSTRUCTOR = Issue(Severity.ERROR, Category.API_LINT, "parcelable-creator") 143 val PROTECTED_MEMBER = Issue(Severity.ERROR, Category.API_LINT, "avoid-protected") 144 val PAIRED_REGISTRATION = Issue(Severity.ERROR, Category.API_LINT, "callbacks-symmetry") 145 val REGISTRATION_NAME = Issue(Severity.ERROR, Category.API_LINT, "callbacks-accessors") 146 val VISIBLY_SYNCHRONIZED = Issue(Severity.ERROR, Category.API_LINT, "avoid-synchronized") 147 val INTENT_BUILDER_NAME = 148 Issue(Severity.WARNING, Category.API_LINT, "intent-builder-createintent") 149 val CONTEXT_NAME_SUFFIX = Issue(Severity.ERROR, Category.API_LINT, "classes-subclass-naming") 150 val INTERFACE_CONSTANT = Issue(Severity.ERROR, Category.API_LINT, "services-intents") 151 val ON_NAME_EXPECTED = Issue(Severity.WARNING, Category.API_LINT, "callback-method-naming") 152 val TOP_LEVEL_BUILDER = Issue(Severity.WARNING, Category.API_LINT, "builders-static-inner") 153 val MISSING_BUILD_METHOD = 154 Issue(Severity.WARNING, Category.API_LINT, "builder-must-declare-build") 155 val BUILDER_SET_STYLE = Issue(Severity.WARNING, Category.API_LINT, "builder-method-naming") 156 val SETTER_RETURNS_THIS = Issue(Severity.WARNING, Category.API_LINT) 157 val RAW_AIDL = Issue(Severity.ERROR, Category.API_LINT, "no-public-binder") 158 val INTERNAL_CLASSES = Issue(Severity.ERROR, Category.API_LINT) 159 val PACKAGE_LAYERING = Issue(Severity.WARNING, Category.API_LINT) 160 val GETTER_SETTER_NAMES = Issue(Severity.ERROR, Category.API_LINT) 161 val CONCRETE_COLLECTION = Issue(Severity.ERROR, Category.API_LINT, "classes-collections") 162 val OVERLAPPING_CONSTANTS = Issue(Severity.WARNING, Category.API_LINT, "overlapping-constants") 163 val GENERIC_EXCEPTION = Issue(Severity.ERROR, Category.API_LINT, "appropriate-exception") 164 val ILLEGAL_STATE_EXCEPTION = 165 Issue(Severity.WARNING, Category.API_LINT, "appropriate-exception") 166 val RETHROW_REMOTE_EXCEPTION = Issue(Severity.ERROR, Category.API_LINT, "appropriate-exception") 167 val MENTIONS_GOOGLE = Issue(Severity.ERROR, Category.API_LINT, "mentions-google") 168 val HEAVY_BIT_SET = Issue(Severity.ERROR, Category.API_LINT, "avoid-bitset") 169 val MANAGER_CONSTRUCTOR = Issue(Severity.ERROR, Category.API_LINT) 170 val MANAGER_LOOKUP = Issue(Severity.ERROR, Category.API_LINT) 171 val AUTO_BOXING = Issue(Severity.ERROR, Category.API_LINT, "auto-boxing") 172 val STATIC_UTILS = Issue(Severity.ERROR, Category.API_LINT) 173 val CONTEXT_FIRST = Issue(Severity.ERROR, Category.API_LINT) 174 val LISTENER_LAST = Issue(Severity.WARNING, Category.API_LINT, "placement-of-sam-parameters") 175 val EXECUTOR_REGISTRATION = Issue(Severity.WARNING, Category.API_LINT, "callbacks-listener") 176 val CONFIG_FIELD_NAME = Issue(Severity.ERROR, Category.API_LINT) 177 val RESOURCE_FIELD_NAME = Issue(Severity.ERROR, Category.API_LINT) 178 val RESOURCE_VALUE_FIELD_NAME = Issue(Severity.ERROR, Category.API_LINT) 179 val RESOURCE_STYLE_FIELD_NAME = Issue(Severity.ERROR, Category.API_LINT) 180 val STREAM_FILES = Issue(Severity.WARNING, Category.API_LINT) 181 val PARCELABLE_LIST = Issue(Severity.WARNING, Category.API_LINT) 182 val ABSTRACT_INNER = Issue(Severity.WARNING, Category.API_LINT) 183 val BANNED_THROW = Issue(Severity.ERROR, Category.API_LINT) 184 val EXTENDS_ERROR = Issue(Severity.ERROR, Category.API_LINT) 185 val EXCEPTION_NAME = Issue(Severity.ERROR, Category.API_LINT) 186 val METHOD_NAME_UNITS = Issue(Severity.ERROR, Category.API_LINT, "unit-names") 187 val FRACTION_FLOAT = Issue(Severity.ERROR, Category.API_LINT) 188 val PERCENTAGE_INT = Issue(Severity.ERROR, Category.API_LINT) 189 val NOT_CLOSEABLE = Issue(Severity.WARNING, Category.API_LINT) 190 val KOTLIN_OPERATOR = Issue(Severity.INFO, Category.API_LINT) 191 val ARRAY_RETURN = 192 Issue(Severity.WARNING, Category.API_LINT, "methods-prefer-collection-over-array") 193 val USER_HANDLE = Issue(Severity.WARNING, Category.API_LINT) 194 val USER_HANDLE_NAME = Issue(Severity.WARNING, Category.API_LINT) 195 val SERVICE_NAME = Issue(Severity.ERROR, Category.API_LINT) 196 val METHOD_NAME_TENSE = Issue(Severity.WARNING, Category.API_LINT) 197 val NO_CLONE = Issue(Severity.ERROR, Category.API_LINT, "avoid-clone") 198 val USE_ICU = Issue(Severity.WARNING, Category.API_LINT) 199 val USE_PARCEL_FILE_DESCRIPTOR = 200 Issue(Severity.ERROR, Category.API_LINT, "prefer-parcelfiledescriptor") 201 val NO_BYTE_OR_SHORT = Issue(Severity.WARNING, Category.API_LINT, "avoid-short-byte") 202 val SINGLETON_CONSTRUCTOR = Issue(Severity.ERROR, Category.API_LINT, "singleton-class") 203 val COMMON_ARGS_FIRST = Issue(Severity.WARNING, Category.API_LINT, "optional-params-last") 204 val CONSISTENT_ARGUMENT_ORDER = Issue(Severity.ERROR, Category.API_LINT, "optional-params-last") 205 val KOTLIN_KEYWORD = Issue(Severity.ERROR, Category.API_LINT) 206 val UNIQUE_KOTLIN_OPERATOR = Issue(Severity.ERROR, Category.API_LINT) 207 val SAM_SHOULD_BE_LAST = 208 Issue(Severity.WARNING, Category.API_LINT, "placement-of-sam-parameters") 209 val MISSING_JVMSTATIC = Issue(Severity.WARNING, Category.API_LINT) 210 val DEFAULT_VALUE_CHANGE = Issue(Severity.ERROR, Category.API_LINT, "default-value-removal") 211 val DOCUMENT_EXCEPTIONS = Issue(Severity.ERROR, Category.API_LINT, "docs-throws") 212 val FORBIDDEN_SUPER_CLASS = Issue(Severity.ERROR, Category.API_LINT) 213 val MISSING_NULLABILITY = Issue(Severity.ERROR, Category.API_LINT, "annotations") 214 val INVALID_NULLABILITY_OVERRIDE = Issue(Severity.ERROR, Category.API_LINT, "annotations-nullability-overrides") 215 val MUTABLE_BARE_FIELD = Issue(Severity.ERROR, Category.API_LINT, "mutable-bare-field") 216 val INTERNAL_FIELD = Issue(Severity.ERROR, Category.API_LINT, "internal-fields") 217 val PUBLIC_TYPEDEF = Issue(Severity.ERROR, Category.API_LINT, "no-public-typedefs") 218 val ANDROID_URI = Issue(Severity.ERROR, Category.API_LINT, "android-uri") 219 val BAD_FUTURE = Issue(Severity.ERROR, Category.API_LINT, "bad-future") 220 val STATIC_FINAL_BUILDER = Issue(Severity.WARNING, Category.API_LINT, "builders-static-inner") 221 val GETTER_ON_BUILDER = Issue(Severity.WARNING, Category.API_LINT, "getter-on-builder") 222 val MISSING_GETTER_MATCHING_BUILDER = 223 Issue(Severity.WARNING, Category.API_LINT, "builders-symmetric-setters") 224 val OPTIONAL_BUILDER_CONSTRUCTOR_ARGUMENT = 225 Issue(Severity.WARNING, Category.API_LINT, "builders-nonnull-constructors") 226 val NO_SETTINGS_PROVIDER = Issue(Severity.HIDDEN, Category.API_LINT, "no-settings-provider") 227 val NULLABLE_COLLECTION = Issue(Severity.WARNING, Category.API_LINT, "methods-prefer-non-null-collections") 228 val ASYNC_SUFFIX_FUTURE = Issue(Severity.ERROR, Category.API_LINT) 229 val GENERIC_CALLBACKS = Issue(Severity.ERROR, Category.API_LINT, "callbacks-sam") 230 findIssueByIdnull231 fun findIssueById(id: String?): Issue? { 232 return nameToIssue[id] 233 } 234 findIssueByIdIgnoringCasenull235 fun findIssueByIdIgnoringCase(id: String): Issue? { 236 for (e in allIssues) { 237 if (id.equals(e.name, ignoreCase = true)) { 238 return e 239 } 240 } 241 return null 242 } 243 244 class Issue private constructor( 245 val defaultLevel: Severity, 246 /** 247 * When `level` is set to [Severity.INHERIT], this is the parent from 248 * which the issue will inherit its level. 249 */ 250 val parent: Issue?, 251 /** Applicable category */ 252 val category: Category, 253 /** Related rule, if any */ 254 val rule: String? 255 ) { 256 /** 257 * The name of this issue 258 */ 259 lateinit var name: String 260 internal set 261 262 internal constructor( 263 defaultLevel: Severity, 264 category: Category = Category.UNKNOWN 265 ) : this(defaultLevel, null, category, null) 266 267 internal constructor( 268 defaultLevel: Severity, 269 category: Category, 270 rule: String 271 ) : this(defaultLevel, null, category, rule) 272 273 internal constructor( 274 parent: Issue, 275 category: Category 276 ) : this(Severity.INHERIT, parent, category, null) 277 toStringnull278 override fun toString(): String { 279 return "Issue $name" 280 } 281 282 init { 283 allIssues.add(this) 284 } 285 } 286 287 enum class Category(val description: String, val ruleLink: String?) { 288 COMPATIBILITY("Compatibility", null), 289 DOCUMENTATION("Documentation", null), 290 API_LINT("API Lint", "https://s.android.com/api-guidelines#"), 291 UNKNOWN("Default", null) 292 } 293 294 init { // Initialize issue names based on the field names 295 for (property in Issues::class.declaredMemberProperties) { 296 if (property.returnType.classifier != Issue::class) continue 297 val issue = property.getter.call(Issues) as Issue 298 299 issue.name = SdkVersionInfo.underlinesToCamelCase(property.name.lowercase(Locale.US)) 300 nameToIssue[issue.name] = issue 301 } 302 for (issue in allIssues) { 303 check(issue.name != "") 304 } 305 } 306 } 307