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.doclava1; 17 18 import com.android.tools.metalava.Severity; 19 import com.google.common.base.Splitter; 20 import org.jetbrains.annotations.Nullable; 21 22 import java.lang.reflect.Field; 23 import java.util.ArrayList; 24 import java.util.HashMap; 25 import java.util.List; 26 import java.util.Locale; 27 import java.util.Map; 28 29 import static com.android.sdklib.SdkVersionInfo.underlinesToCamelCase; 30 import static com.android.tools.metalava.Severity.ERROR; 31 import static com.android.tools.metalava.Severity.HIDDEN; 32 import static com.android.tools.metalava.Severity.INFO; 33 import static com.android.tools.metalava.Severity.INHERIT; 34 import static com.android.tools.metalava.Severity.LINT; 35 import static com.android.tools.metalava.Severity.WARNING; 36 37 // Copied from doclava1 (and a bunch of stuff left alone; preserving to have same error id's) 38 public class Errors { 39 // Consider renaming to Issue; "Error" is special in Kotlin, and what does it mean for 40 // an "error" to have severity "warning" ? The severity shouldn't be implied by the name. 41 public static class Error { 42 public final int code; 43 @Nullable 44 String fieldName; 45 46 private Severity level; 47 private final Severity defaultLevel; 48 boolean setByUser; 49 50 /** 51 * The name of this error if known 52 */ 53 @Nullable 54 public String name; 55 56 /** 57 * When {@code level} is set to {@link Severity#INHERIT}, this is the parent from 58 * which the error will inherit its level. 59 */ 60 private final Error parent; 61 62 /** Related rule, if any */ 63 public final String rule; 64 65 /** Related explanation, if any */ 66 public final String explanation; 67 68 /** Applicable category */ 69 public final Category category; 70 Error(int code, Severity level)71 private Error(int code, Severity level) { 72 this(code, level, Category.UNKNOWN); 73 } 74 Error(int code, Severity level, Category category)75 private Error(int code, Severity level, Category category) { 76 this(code, level, null, category, null, null); 77 } 78 Error(int code, Severity level, Category category, String rule)79 private Error(int code, Severity level, Category category, String rule) { 80 this(code, level, null, category, rule, null); 81 } 82 Error(int code, Error parent, Category category)83 private Error(int code, Error parent, Category category) { 84 this(code, INHERIT, parent, category, null, null); 85 } 86 Error(int code, Severity level, Error parent, Category category, String rule, String explanation)87 private Error(int code, Severity level, Error parent, Category category, 88 String rule, String explanation) { 89 this.code = code; 90 this.level = level; 91 this.defaultLevel = level; 92 this.parent = parent; 93 this.category = category; 94 this.rule = rule; 95 this.explanation = explanation; 96 errors.add(this); 97 } 98 99 /** 100 * Returns the implied level for this error. 101 * <p> 102 * If the level is {@link Severity#INHERIT}, the level will be returned for the 103 * parent. 104 * 105 * @throws IllegalStateException if the level is {@link Severity#INHERIT} and the 106 * parent is {@code null} 107 */ getLevel()108 public Severity getLevel() { 109 if (level == INHERIT) { 110 if (parent == null) { 111 throw new IllegalStateException("Error with level INHERIT must have non-null parent"); 112 } 113 return parent.getLevel(); 114 } 115 return level; 116 } 117 118 /** 119 * Sets the level. 120 * <p> 121 * Valid arguments are: 122 * <ul> 123 * <li>{@link Severity#HIDDEN} 124 * <li>{@link Severity#WARNING} 125 * <li>{@link Severity#ERROR} 126 * </ul> 127 * 128 * @param level the level to set 129 */ setLevel(Severity level)130 void setLevel(Severity level) { 131 if (level == INHERIT) { 132 throw new IllegalArgumentException("Error level may not be set to INHERIT"); 133 } 134 this.level = level; 135 this.setByUser = true; 136 } 137 toString()138 public String toString() { 139 return "Error #" + this.code + " (" + this.name + ")"; 140 } 141 } 142 143 private static final List<Error> errors = new ArrayList<>(100); 144 private static final Map<String, Error> nameToError = new HashMap<>(100); 145 private static final Map<Integer, Error> idToError = new HashMap<>(100); 146 147 public enum Category { 148 COMPATIBILITY("Compatibility", null), 149 DOCUMENTATION("Documentation", null), 150 API_LINT("API Lint", "go/android-api-guidelines"), 151 UNKNOWN("Default", null); 152 153 public final String description; 154 public final String ruleLink; 155 Category(String description, String ruleLink)156 Category(String description, String ruleLink) { 157 this.description = description; 158 this.ruleLink = ruleLink; 159 } 160 } 161 162 // Errors for API verification 163 public static final Error PARSE_ERROR = new Error(1, ERROR); 164 public static final Error ADDED_PACKAGE = new Error(2, WARNING, Category.COMPATIBILITY); 165 public static final Error ADDED_CLASS = new Error(3, WARNING, Category.COMPATIBILITY); 166 public static final Error ADDED_METHOD = new Error(4, WARNING, Category.COMPATIBILITY); 167 public static final Error ADDED_FIELD = new Error(5, WARNING, Category.COMPATIBILITY); 168 public static final Error ADDED_INTERFACE = new Error(6, WARNING, Category.COMPATIBILITY); 169 public static final Error REMOVED_PACKAGE = new Error(7, WARNING, Category.COMPATIBILITY); 170 public static final Error REMOVED_CLASS = new Error(8, WARNING, Category.COMPATIBILITY); 171 public static final Error REMOVED_METHOD = new Error(9, WARNING, Category.COMPATIBILITY); 172 public static final Error REMOVED_FIELD = new Error(10, WARNING, Category.COMPATIBILITY); 173 public static final Error REMOVED_INTERFACE = new Error(11, WARNING, Category.COMPATIBILITY); 174 public static final Error CHANGED_STATIC = new Error(12, WARNING, Category.COMPATIBILITY); 175 public static final Error ADDED_FINAL = new Error(13, WARNING, Category.COMPATIBILITY); 176 public static final Error CHANGED_TRANSIENT = new Error(14, WARNING, Category.COMPATIBILITY); 177 public static final Error CHANGED_VOLATILE = new Error(15, WARNING, Category.COMPATIBILITY); 178 public static final Error CHANGED_TYPE = new Error(16, WARNING, Category.COMPATIBILITY); 179 public static final Error CHANGED_VALUE = new Error(17, WARNING, Category.COMPATIBILITY); 180 public static final Error CHANGED_SUPERCLASS = new Error(18, WARNING, Category.COMPATIBILITY); 181 public static final Error CHANGED_SCOPE = new Error(19, WARNING, Category.COMPATIBILITY); 182 public static final Error CHANGED_ABSTRACT = new Error(20, WARNING, Category.COMPATIBILITY); 183 public static final Error CHANGED_THROWS = new Error(21, WARNING, Category.COMPATIBILITY); 184 public static final Error CHANGED_NATIVE = new Error(22, HIDDEN, Category.COMPATIBILITY); 185 public static final Error CHANGED_CLASS = new Error(23, WARNING, Category.COMPATIBILITY); 186 public static final Error CHANGED_DEPRECATED = new Error(24, WARNING, Category.COMPATIBILITY); 187 public static final Error CHANGED_SYNCHRONIZED = new Error(25, WARNING, Category.COMPATIBILITY); 188 public static final Error ADDED_FINAL_UNINSTANTIABLE = new Error(26, WARNING, Category.COMPATIBILITY); 189 public static final Error REMOVED_FINAL = new Error(27, WARNING, Category.COMPATIBILITY); 190 public static final Error REMOVED_DEPRECATED_CLASS = new Error(28, REMOVED_CLASS, Category.COMPATIBILITY); 191 public static final Error REMOVED_DEPRECATED_METHOD = new Error(29, REMOVED_METHOD, Category.COMPATIBILITY); 192 public static final Error REMOVED_DEPRECATED_FIELD = new Error(30, REMOVED_FIELD, Category.COMPATIBILITY); 193 public static final Error ADDED_ABSTRACT_METHOD = new Error(31, ADDED_METHOD, Category.COMPATIBILITY); 194 public static final Error ADDED_REIFIED = new Error(32, WARNING, Category.COMPATIBILITY); 195 196 // Errors in javadoc generation 197 public static final Error UNRESOLVED_LINK = new Error(101, LINT, Category.DOCUMENTATION); 198 public static final Error BAD_INCLUDE_TAG = new Error(102, LINT, Category.DOCUMENTATION); 199 public static final Error UNKNOWN_TAG = new Error(103, LINT, Category.DOCUMENTATION); 200 public static final Error UNKNOWN_PARAM_TAG_NAME = new Error(104, LINT, Category.DOCUMENTATION); 201 public static final Error UNDOCUMENTED_PARAMETER = new Error(105, HIDDEN, Category.DOCUMENTATION); 202 public static final Error BAD_ATTR_TAG = new Error(106, LINT, Category.DOCUMENTATION); 203 public static final Error BAD_INHERITDOC = new Error(107, HIDDEN, Category.DOCUMENTATION); 204 public static final Error HIDDEN_LINK = new Error(108, LINT, Category.DOCUMENTATION); 205 public static final Error HIDDEN_CONSTRUCTOR = new Error(109, WARNING, Category.DOCUMENTATION); 206 public static final Error UNAVAILABLE_SYMBOL = new Error(110, WARNING, Category.DOCUMENTATION); 207 public static final Error HIDDEN_SUPERCLASS = new Error(111, WARNING, Category.DOCUMENTATION); 208 public static final Error DEPRECATED = new Error(112, HIDDEN, Category.DOCUMENTATION); 209 public static final Error DEPRECATION_MISMATCH = new Error(113, ERROR, Category.DOCUMENTATION); 210 public static final Error MISSING_COMMENT = new Error(114, LINT, Category.DOCUMENTATION); 211 public static final Error IO_ERROR = new Error(115, ERROR); 212 public static final Error NO_SINCE_DATA = new Error(116, HIDDEN, Category.DOCUMENTATION); 213 public static final Error NO_FEDERATION_DATA = new Error(117, WARNING, Category.DOCUMENTATION); 214 public static final Error BROKEN_SINCE_FILE = new Error(118, ERROR, Category.DOCUMENTATION); 215 public static final Error INVALID_CONTENT_TYPE = new Error(119, ERROR, Category.DOCUMENTATION); 216 public static final Error INVALID_SAMPLE_INDEX = new Error(120, ERROR, Category.DOCUMENTATION); 217 public static final Error HIDDEN_TYPE_PARAMETER = new Error(121, WARNING, Category.DOCUMENTATION); 218 public static final Error PRIVATE_SUPERCLASS = new Error(122, WARNING, Category.DOCUMENTATION); 219 public static final Error NULLABLE = new Error(123, HIDDEN, Category.DOCUMENTATION); 220 public static final Error INT_DEF = new Error(124, HIDDEN, Category.DOCUMENTATION); 221 public static final Error REQUIRES_PERMISSION = new Error(125, LINT, Category.DOCUMENTATION); 222 public static final Error BROADCAST_BEHAVIOR = new Error(126, LINT, Category.DOCUMENTATION); 223 public static final Error SDK_CONSTANT = new Error(127, LINT, Category.DOCUMENTATION); 224 public static final Error TODO = new Error(128, LINT, Category.DOCUMENTATION); 225 public static final Error NO_ARTIFACT_DATA = new Error(129, HIDDEN, Category.DOCUMENTATION); 226 public static final Error BROKEN_ARTIFACT_FILE = new Error(130, ERROR, Category.DOCUMENTATION); 227 228 // Metalava new warnings (not from doclava) 229 230 public static final Error TYPO = new Error(131, WARNING, Category.DOCUMENTATION); 231 public static final Error MISSING_PERMISSION = new Error(132, LINT, Category.DOCUMENTATION); 232 public static final Error MULTIPLE_THREAD_ANNOTATIONS = new Error(133, LINT, Category.DOCUMENTATION); 233 public static final Error UNRESOLVED_CLASS = new Error(134, LINT, Category.DOCUMENTATION); 234 public static final Error INVALID_NULL_CONVERSION = new Error(135, ERROR, Category.COMPATIBILITY); 235 public static final Error PARAMETER_NAME_CHANGE = new Error(136, ERROR, Category.COMPATIBILITY); 236 public static final Error OPERATOR_REMOVAL = new Error(137, ERROR, Category.COMPATIBILITY); 237 public static final Error INFIX_REMOVAL = new Error(138, ERROR, Category.COMPATIBILITY); 238 public static final Error VARARG_REMOVAL = new Error(139, ERROR, Category.COMPATIBILITY); 239 public static final Error ADD_SEALED = new Error(140, ERROR, Category.COMPATIBILITY); 240 public static final Error ANNOTATION_EXTRACTION = new Error(146, ERROR); 241 public static final Error SUPERFLUOUS_PREFIX = new Error(147, WARNING); 242 public static final Error HIDDEN_TYPEDEF_CONSTANT = new Error(148, ERROR); 243 public static final Error EXPECTED_PLATFORM_TYPE = new Error(149, HIDDEN); 244 public static final Error INTERNAL_ERROR = new Error(150, ERROR); 245 public static final Error RETURNING_UNEXPECTED_CONSTANT = new Error(151, WARNING); 246 public static final Error DEPRECATED_OPTION = new Error(152, WARNING); 247 public static final Error BOTH_PACKAGE_INFO_AND_HTML = new Error(153, WARNING, Category.DOCUMENTATION); 248 // The plan is for this to be set as an error once (1) existing code is marked as @deprecated 249 // and (2) the principle is adopted by the API council 250 public static final Error REFERENCES_DEPRECATED = new Error(154, HIDDEN); 251 public static final Error UNHIDDEN_SYSTEM_API = new Error(155, ERROR); 252 public static final Error SHOWING_MEMBER_IN_HIDDEN_CLASS = new Error(156, ERROR); 253 public static final Error INVALID_NULLABILITY_ANNOTATION = new Error(157, ERROR); 254 public static final Error REFERENCES_HIDDEN = new Error(158, ERROR); 255 public static final Error IGNORING_SYMLINK = new Error(159, INFO); 256 public static final Error INVALID_NULLABILITY_ANNOTATION_WARNING = new Error(160, WARNING); 257 // The plan is for this to be set as an error once (1) existing code is marked as @deprecated 258 // and (2) the principle is adopted by the API council 259 public static final Error EXTENDS_DEPRECATED = new Error(161, HIDDEN); 260 public static final Error FORBIDDEN_TAG = new Error(162, ERROR); 261 262 // API lint 263 public static final Error START_WITH_LOWER = new Error(300, ERROR, Category.API_LINT, "S1"); 264 public static final Error START_WITH_UPPER = new Error(301, ERROR, Category.API_LINT, "S1"); 265 public static final Error ALL_UPPER = new Error(302, ERROR, Category.API_LINT, "C2"); 266 public static final Error ACRONYM_NAME = new Error(303, WARNING, Category.API_LINT, "S1"); 267 public static final Error ENUM = new Error(304, ERROR, Category.API_LINT, "F5"); 268 public static final Error ENDS_WITH_IMPL = new Error(305, ERROR, Category.API_LINT); 269 public static final Error MIN_MAX_CONSTANT = new Error(306, WARNING, Category.API_LINT, "C8"); 270 public static final Error COMPILE_TIME_CONSTANT = new Error(307, ERROR, Category.API_LINT); 271 public static final Error SINGULAR_CALLBACK = new Error(308, ERROR, Category.API_LINT, "L1"); 272 public static final Error CALLBACK_NAME = new Error(309, WARNING, Category.API_LINT, "L1"); 273 public static final Error CALLBACK_INTERFACE = new Error(310, ERROR, Category.API_LINT, "CL3"); 274 public static final Error CALLBACK_METHOD_NAME = new Error(311, ERROR, Category.API_LINT, "L1"); 275 public static final Error LISTENER_INTERFACE = new Error(312, ERROR, Category.API_LINT, "L1"); 276 public static final Error SINGLE_METHOD_INTERFACE = new Error(313, ERROR, Category.API_LINT, "L1"); 277 public static final Error INTENT_NAME = new Error(314, ERROR, Category.API_LINT, "C3"); 278 public static final Error ACTION_VALUE = new Error(315, ERROR, Category.API_LINT, "C4"); 279 public static final Error EQUALS_AND_HASH_CODE = new Error(316, ERROR, Category.API_LINT, "M8"); 280 public static final Error PARCEL_CREATOR = new Error(317, ERROR, Category.API_LINT, "FW3"); 281 public static final Error PARCEL_NOT_FINAL = new Error(318, ERROR, Category.API_LINT, "FW8"); 282 public static final Error PARCEL_CONSTRUCTOR = new Error(319, ERROR, Category.API_LINT, "FW3"); 283 public static final Error PROTECTED_MEMBER = new Error(320, ERROR, Category.API_LINT, "M7"); 284 public static final Error PAIRED_REGISTRATION = new Error(321, ERROR, Category.API_LINT, "L2"); 285 public static final Error REGISTRATION_NAME = new Error(322, ERROR, Category.API_LINT, "L3"); 286 public static final Error VISIBLY_SYNCHRONIZED = new Error(323, ERROR, Category.API_LINT, "M5"); 287 public static final Error INTENT_BUILDER_NAME = new Error(324, WARNING, Category.API_LINT, "FW1"); 288 public static final Error CONTEXT_NAME_SUFFIX = new Error(325, ERROR, Category.API_LINT, "C4"); 289 public static final Error INTERFACE_CONSTANT = new Error(326, ERROR, Category.API_LINT, "C4"); 290 public static final Error ON_NAME_EXPECTED = new Error(327, WARNING, Category.API_LINT); 291 public static final Error TOP_LEVEL_BUILDER = new Error(328, WARNING, Category.API_LINT); 292 public static final Error MISSING_BUILD = new Error(329, WARNING, Category.API_LINT); 293 public static final Error BUILDER_SET_STYLE = new Error(330, WARNING, Category.API_LINT); 294 public static final Error SETTER_RETURNS_THIS = new Error(331, WARNING, Category.API_LINT, "M4"); 295 public static final Error RAW_AIDL = new Error(332, ERROR, Category.API_LINT); 296 public static final Error INTERNAL_CLASSES = new Error(333, ERROR, Category.API_LINT); 297 public static final Error PACKAGE_LAYERING = new Error(334, WARNING, Category.API_LINT, "FW6"); 298 public static final Error GETTER_SETTER_NAMES = new Error(335, ERROR, Category.API_LINT, "M6"); 299 public static final Error CONCRETE_COLLECTION = new Error(336, ERROR, Category.API_LINT, "CL2"); 300 public static final Error OVERLAPPING_CONSTANTS = new Error(337, WARNING, Category.API_LINT, "C1"); 301 public static final Error GENERIC_EXCEPTION = new Error(338, ERROR, Category.API_LINT, "S1"); 302 public static final Error ILLEGAL_STATE_EXCEPTION = new Error(339, WARNING, Category.API_LINT, "S1"); 303 public static final Error RETHROW_REMOTE_EXCEPTION = new Error(340, ERROR, Category.API_LINT, "FW9"); 304 public static final Error MENTIONS_GOOGLE = new Error(341, ERROR, Category.API_LINT); 305 public static final Error HEAVY_BIT_SET = new Error(342, ERROR, Category.API_LINT); 306 public static final Error MANAGER_CONSTRUCTOR = new Error(343, ERROR, Category.API_LINT); 307 public static final Error MANAGER_LOOKUP = new Error(344, ERROR, Category.API_LINT); 308 public static final Error AUTO_BOXING = new Error(345, ERROR, Category.API_LINT, "M11"); 309 public static final Error STATIC_UTILS = new Error(346, ERROR, Category.API_LINT); 310 public static final Error CONTEXT_FIRST = new Error(347, ERROR, Category.API_LINT, "M3"); 311 public static final Error LISTENER_LAST = new Error(348, WARNING, Category.API_LINT, "M3"); 312 public static final Error EXECUTOR_REGISTRATION = new Error(349, WARNING, Category.API_LINT, "L1"); 313 public static final Error CONFIG_FIELD_NAME = new Error(350, ERROR, Category.API_LINT); 314 public static final Error RESOURCE_FIELD_NAME = new Error(351, ERROR, Category.API_LINT); 315 public static final Error RESOURCE_VALUE_FIELD_NAME = new Error(352, ERROR, Category.API_LINT, "C7"); 316 public static final Error RESOURCE_STYLE_FIELD_NAME = new Error(353, ERROR, Category.API_LINT, "C7"); 317 public static final Error STREAM_FILES = new Error(354, WARNING, Category.API_LINT, "M10"); 318 public static final Error PARCELABLE_LIST = new Error(355, WARNING, Category.API_LINT); 319 public static final Error ABSTRACT_INNER = new Error(356, WARNING, Category.API_LINT); 320 public static final Error BANNED_THROW = new Error(358, ERROR, Category.API_LINT); 321 public static final Error EXTENDS_ERROR = new Error(359, ERROR, Category.API_LINT); 322 public static final Error EXCEPTION_NAME = new Error(360, ERROR, Category.API_LINT); 323 public static final Error METHOD_NAME_UNITS = new Error(361, ERROR, Category.API_LINT); 324 public static final Error FRACTION_FLOAT = new Error(362, ERROR, Category.API_LINT); 325 public static final Error PERCENTAGE_INT = new Error(363, ERROR, Category.API_LINT); 326 public static final Error NOT_CLOSEABLE = new Error(364, WARNING, Category.API_LINT); 327 public static final Error KOTLIN_OPERATOR = new Error(365, INFO, Category.API_LINT); 328 public static final Error ARRAY_RETURN = new Error(366, WARNING, Category.API_LINT); 329 public static final Error USER_HANDLE = new Error(367, WARNING, Category.API_LINT); 330 public static final Error USER_HANDLE_NAME = new Error(368, WARNING, Category.API_LINT); 331 public static final Error SERVICE_NAME = new Error(369, ERROR, Category.API_LINT, "C4"); 332 public static final Error METHOD_NAME_TENSE = new Error(370, WARNING, Category.API_LINT); 333 public static final Error NO_CLONE = new Error(371, ERROR, Category.API_LINT); 334 public static final Error USE_ICU = new Error(372, WARNING, Category.API_LINT); 335 public static final Error USE_PARCEL_FILE_DESCRIPTOR = new Error(373, ERROR, Category.API_LINT, "FW11"); 336 public static final Error NO_BYTE_OR_SHORT = new Error(374, WARNING, Category.API_LINT, "FW12"); 337 public static final Error SINGLETON_CONSTRUCTOR = new Error(375, ERROR, Category.API_LINT); 338 public static final Error COMMON_ARGS_FIRST = new Error(376, WARNING, Category.API_LINT, "M2"); 339 public static final Error CONSISTENT_ARGUMENT_ORDER = new Error(377, ERROR, Category.API_LINT, "M2"); 340 public static final Error KOTLIN_KEYWORD = new Error(378, ERROR, Category.API_LINT); // Formerly 141 341 public static final Error UNIQUE_KOTLIN_OPERATOR = new Error(379, ERROR, Category.API_LINT); 342 public static final Error SAM_SHOULD_BE_LAST = new Error(380, WARNING, Category.API_LINT); // Formerly 142 343 public static final Error MISSING_JVMSTATIC = new Error(381, WARNING, Category.API_LINT); // Formerly 143 344 public static final Error DEFAULT_VALUE_CHANGE = new Error(382, ERROR, Category.API_LINT); // Formerly 144 345 public static final Error DOCUMENT_EXCEPTIONS = new Error(383, ERROR, Category.API_LINT); // Formerly 145 346 public static final Error FORBIDDEN_SUPER_CLASS = new Error(384, ERROR, Category.API_LINT); 347 348 static { 349 // Attempt to initialize error names based on the field names 350 try { 351 for (Field field : Errors.class.getDeclaredFields()) { 352 Object o = field.get(null); 353 if (o instanceof Error) { 354 Error error = (Error) o; 355 String fieldName = field.getName(); 356 error.fieldName = fieldName; 357 error.name = underlinesToCamelCase(fieldName.toLowerCase(Locale.US)); nameToError.put(error.name, error)358 nameToError.put(error.name, error); idToError.put(error.code, error)359 idToError.put(error.code, error); 360 } 361 } 362 } catch (Throwable unexpected) { 363 unexpected.printStackTrace(); 364 } 365 } 366 367 @Nullable findErrorById(int id)368 public static Error findErrorById(int id) { 369 return idToError.get(id); 370 } 371 372 @Nullable findErrorById(String id)373 public static Error findErrorById(String id) { 374 return nameToError.get(id); 375 } 376 setErrorLevel(String id, Severity level, boolean setByUser)377 public static boolean setErrorLevel(String id, Severity level, boolean setByUser) { 378 if (id.contains(",")) { // Handle being passed in multiple comma separated id's 379 boolean ok = true; 380 for (String individualId : Splitter.on(',').trimResults().split(id)) { 381 ok = setErrorLevel(individualId, level, setByUser) && ok; 382 } 383 return ok; 384 } 385 int code = -1; 386 if (Character.isDigit(id.charAt(0))) { 387 code = Integer.parseInt(id); 388 } 389 390 Error error = nameToError.get(id); 391 if (error == null) { 392 try { 393 int n = Integer.parseInt(id); 394 error = idToError.get(n); 395 } catch (NumberFormatException ignore) { 396 } 397 } 398 399 if (error == null) { 400 for (Error e : errors) { 401 if (e.code == code || id.equalsIgnoreCase(e.name)) { 402 error = e; 403 break; 404 } 405 } 406 } 407 408 if (error != null) { 409 error.setLevel(level); 410 error.setByUser = setByUser; 411 return true; 412 } 413 return false; 414 } 415 416 // Primary needed by unit tests; ensure that a previous test doesn't influence 417 // a later one resetLevels()418 public static void resetLevels() { 419 for (Error error : errors) { 420 error.level = error.defaultLevel; 421 } 422 } 423 } 424