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 val CALLBACK_INTERFACE = 131 Issue(Severity.ERROR, Category.API_LINT, "callback-abstract-instead-of-interface") 132 val CALLBACK_METHOD_NAME = Issue(Severity.ERROR, Category.API_LINT, "callback-method-naming") 133 val LISTENER_INTERFACE = Issue(Severity.ERROR, Category.API_LINT, "callbacks-listener") 134 val SINGLE_METHOD_INTERFACE = Issue(Severity.ERROR, Category.API_LINT, "callbacks-listener") 135 val INTENT_NAME = 136 Issue(Severity.ERROR, Category.API_LINT, "use-standard-prefixes-for-constants") 137 val ACTION_VALUE = Issue(Severity.ERROR, Category.API_LINT) 138 val EQUALS_AND_HASH_CODE = Issue(Severity.ERROR, Category.API_LINT, "equals-and-hashcode") 139 val PARCEL_CREATOR = Issue(Severity.ERROR, Category.API_LINT, "parcelable-creator") 140 val PARCEL_NOT_FINAL = Issue(Severity.ERROR, Category.API_LINT, "parcelable-final") 141 val PARCEL_CONSTRUCTOR = Issue(Severity.ERROR, Category.API_LINT, "parcelable-creator") 142 val PROTECTED_MEMBER = Issue(Severity.ERROR, Category.API_LINT, "avoid-protected") 143 val PAIRED_REGISTRATION = Issue(Severity.ERROR, Category.API_LINT, "callbacks-symmetry") 144 val REGISTRATION_NAME = Issue(Severity.ERROR, Category.API_LINT, "callbacks-accessors") 145 val VISIBLY_SYNCHRONIZED = Issue(Severity.ERROR, Category.API_LINT, "avoid-synchronized") 146 val INTENT_BUILDER_NAME = 147 Issue(Severity.WARNING, Category.API_LINT, "intent-builder-createintent") 148 val CONTEXT_NAME_SUFFIX = Issue(Severity.ERROR, Category.API_LINT, "classes-subclass-naming") 149 val INTERFACE_CONSTANT = Issue(Severity.ERROR, Category.API_LINT, "services-intents") 150 val ON_NAME_EXPECTED = Issue(Severity.WARNING, Category.API_LINT, "callback-method-naming") 151 val TOP_LEVEL_BUILDER = Issue(Severity.WARNING, Category.API_LINT, "builders-static-inner") 152 val MISSING_BUILD_METHOD = 153 Issue(Severity.WARNING, Category.API_LINT, "builder-must-declare-build") 154 val BUILDER_SET_STYLE = Issue(Severity.WARNING, Category.API_LINT, "builder-method-naming") 155 val SETTER_RETURNS_THIS = Issue(Severity.WARNING, Category.API_LINT) 156 val RAW_AIDL = Issue(Severity.ERROR, Category.API_LINT, "no-public-binder") 157 val INTERNAL_CLASSES = Issue(Severity.ERROR, Category.API_LINT) 158 val PACKAGE_LAYERING = Issue(Severity.WARNING, Category.API_LINT) 159 val GETTER_SETTER_NAMES = Issue(Severity.ERROR, Category.API_LINT) 160 val CONCRETE_COLLECTION = Issue(Severity.ERROR, Category.API_LINT, "classes-collections") 161 val OVERLAPPING_CONSTANTS = Issue(Severity.WARNING, Category.API_LINT, "overlapping-constants") 162 val GENERIC_EXCEPTION = Issue(Severity.ERROR, Category.API_LINT, "appropriate-exception") 163 val ILLEGAL_STATE_EXCEPTION = 164 Issue(Severity.WARNING, Category.API_LINT, "appropriate-exception") 165 val RETHROW_REMOTE_EXCEPTION = Issue(Severity.ERROR, Category.API_LINT, "appropriate-exception") 166 val MENTIONS_GOOGLE = Issue(Severity.ERROR, Category.API_LINT, "mentions-google") 167 val HEAVY_BIT_SET = Issue(Severity.ERROR, Category.API_LINT, "avoid-bitset") 168 val MANAGER_CONSTRUCTOR = Issue(Severity.ERROR, Category.API_LINT) 169 val MANAGER_LOOKUP = Issue(Severity.ERROR, Category.API_LINT) 170 val AUTO_BOXING = Issue(Severity.ERROR, Category.API_LINT, "auto-boxing") 171 val STATIC_UTILS = Issue(Severity.ERROR, Category.API_LINT) 172 val CONTEXT_FIRST = Issue(Severity.ERROR, Category.API_LINT) 173 val LISTENER_LAST = Issue(Severity.WARNING, Category.API_LINT, "placement-of-sam-parameters") 174 val EXECUTOR_REGISTRATION = Issue(Severity.WARNING, Category.API_LINT, "callbacks-listener") 175 val CONFIG_FIELD_NAME = Issue(Severity.ERROR, Category.API_LINT) 176 val RESOURCE_FIELD_NAME = Issue(Severity.ERROR, Category.API_LINT) 177 val RESOURCE_VALUE_FIELD_NAME = Issue(Severity.ERROR, Category.API_LINT) 178 val RESOURCE_STYLE_FIELD_NAME = Issue(Severity.ERROR, Category.API_LINT) 179 val STREAM_FILES = Issue(Severity.WARNING, Category.API_LINT) 180 val PARCELABLE_LIST = Issue(Severity.WARNING, Category.API_LINT) 181 val ABSTRACT_INNER = Issue(Severity.WARNING, Category.API_LINT) 182 val BANNED_THROW = Issue(Severity.ERROR, Category.API_LINT) 183 val EXTENDS_ERROR = Issue(Severity.ERROR, Category.API_LINT) 184 val EXCEPTION_NAME = Issue(Severity.ERROR, Category.API_LINT) 185 val METHOD_NAME_UNITS = Issue(Severity.ERROR, Category.API_LINT, "unit-names") 186 val FRACTION_FLOAT = Issue(Severity.ERROR, Category.API_LINT) 187 val PERCENTAGE_INT = Issue(Severity.ERROR, Category.API_LINT) 188 val NOT_CLOSEABLE = Issue(Severity.WARNING, Category.API_LINT) 189 val KOTLIN_OPERATOR = Issue(Severity.INFO, Category.API_LINT) 190 val ARRAY_RETURN = 191 Issue(Severity.WARNING, Category.API_LINT, "methods-prefer-collection-over-array") 192 val USER_HANDLE = Issue(Severity.WARNING, Category.API_LINT) 193 val USER_HANDLE_NAME = Issue(Severity.WARNING, Category.API_LINT) 194 val SERVICE_NAME = Issue(Severity.ERROR, Category.API_LINT) 195 val METHOD_NAME_TENSE = Issue(Severity.WARNING, Category.API_LINT) 196 val NO_CLONE = Issue(Severity.ERROR, Category.API_LINT, "avoid-clone") 197 val USE_ICU = Issue(Severity.WARNING, Category.API_LINT) 198 val USE_PARCEL_FILE_DESCRIPTOR = 199 Issue(Severity.ERROR, Category.API_LINT, "prefer-parcelfiledescriptor") 200 val NO_BYTE_OR_SHORT = Issue(Severity.WARNING, Category.API_LINT, "avoid-short-byte") 201 val SINGLETON_CONSTRUCTOR = Issue(Severity.ERROR, Category.API_LINT, "singleton-class") 202 val COMMON_ARGS_FIRST = Issue(Severity.WARNING, Category.API_LINT, "optional-params-last") 203 val CONSISTENT_ARGUMENT_ORDER = Issue(Severity.ERROR, Category.API_LINT, "optional-params-last") 204 val KOTLIN_KEYWORD = Issue(Severity.ERROR, Category.API_LINT) 205 val UNIQUE_KOTLIN_OPERATOR = Issue(Severity.ERROR, Category.API_LINT) 206 val SAM_SHOULD_BE_LAST = 207 Issue(Severity.WARNING, Category.API_LINT, "placement-of-sam-parameters") 208 val MISSING_JVMSTATIC = Issue(Severity.WARNING, Category.API_LINT) 209 val DEFAULT_VALUE_CHANGE = Issue(Severity.ERROR, Category.API_LINT, "default-value-removal") 210 val DOCUMENT_EXCEPTIONS = Issue(Severity.ERROR, Category.API_LINT, "docs-throws") 211 val FORBIDDEN_SUPER_CLASS = Issue(Severity.ERROR, Category.API_LINT) 212 val MISSING_NULLABILITY = Issue(Severity.ERROR, Category.API_LINT, "annotations") 213 val INVALID_NULLABILITY_OVERRIDE = Issue(Severity.ERROR, Category.API_LINT, "annotations-nullability-overrides") 214 val MUTABLE_BARE_FIELD = Issue(Severity.ERROR, Category.API_LINT, "mutable-bare-field") 215 val INTERNAL_FIELD = Issue(Severity.ERROR, Category.API_LINT, "internal-fields") 216 val PUBLIC_TYPEDEF = Issue(Severity.ERROR, Category.API_LINT, "no-public-typedefs") 217 val ANDROID_URI = Issue(Severity.ERROR, Category.API_LINT, "android-uri") 218 val BAD_FUTURE = Issue(Severity.ERROR, Category.API_LINT, "bad-future") 219 val STATIC_FINAL_BUILDER = Issue(Severity.WARNING, Category.API_LINT, "builders-static-inner") 220 val GETTER_ON_BUILDER = Issue(Severity.WARNING, Category.API_LINT, "getter-on-builder") 221 val MISSING_GETTER_MATCHING_BUILDER = 222 Issue(Severity.WARNING, Category.API_LINT, "builders-symmetric-setters") 223 val OPTIONAL_BUILDER_CONSTRUCTOR_ARGUMENT = 224 Issue(Severity.WARNING, Category.API_LINT, "builders-nonnull-constructors") 225 val NO_SETTINGS_PROVIDER = Issue(Severity.HIDDEN, Category.API_LINT, "no-settings-provider") 226 val NULLABLE_COLLECTION = Issue(Severity.WARNING, Category.API_LINT, "methods-prefer-non-null-collections") 227 val ASYNC_SUFFIX_FUTURE = Issue(Severity.ERROR, Category.API_LINT) 228 val GENERIC_CALLBACKS = Issue(Severity.ERROR, Category.API_LINT, "callbacks-sam") 229 findIssueByIdnull230 fun findIssueById(id: String?): Issue? { 231 return nameToIssue[id] 232 } 233 findIssueByIdIgnoringCasenull234 fun findIssueByIdIgnoringCase(id: String): Issue? { 235 for (e in allIssues) { 236 if (id.equals(e.name, ignoreCase = true)) { 237 return e 238 } 239 } 240 return null 241 } 242 243 class Issue private constructor( 244 val defaultLevel: Severity, 245 /** 246 * When `level` is set to [Severity.INHERIT], this is the parent from 247 * which the issue will inherit its level. 248 */ 249 val parent: Issue?, 250 /** Applicable category */ 251 val category: Category, 252 /** Related rule, if any */ 253 val rule: String? 254 ) { 255 /** 256 * The name of this issue 257 */ 258 lateinit var name: String 259 internal set 260 261 internal constructor( 262 defaultLevel: Severity, 263 category: Category = Category.UNKNOWN 264 ) : this(defaultLevel, null, category, null) 265 266 internal constructor( 267 defaultLevel: Severity, 268 category: Category, 269 rule: String 270 ) : this(defaultLevel, null, category, rule) 271 272 internal constructor( 273 parent: Issue, 274 category: Category 275 ) : this(Severity.INHERIT, parent, category, null) 276 toStringnull277 override fun toString(): String { 278 return "Issue $name" 279 } 280 281 init { 282 allIssues.add(this) 283 } 284 } 285 286 enum class Category(val description: String, val ruleLink: String?) { 287 COMPATIBILITY("Compatibility", null), 288 DOCUMENTATION("Documentation", null), 289 API_LINT("API Lint", "https://s.android.com/api-guidelines#"), 290 UNKNOWN("Default", null) 291 } 292 293 init { // Initialize issue names based on the field names 294 for (property in Issues::class.declaredMemberProperties) { 295 if (property.returnType.classifier != Issue::class) continue 296 val issue = property.getter.call(Issues) as Issue 297 298 issue.name = SdkVersionInfo.underlinesToCamelCase(property.name.lowercase(Locale.US)) 299 nameToIssue[issue.name] = issue 300 } 301 for (issue in allIssues) { 302 check(issue.name != "") 303 } 304 } 305 } 306