• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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