• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 Google Inc.
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 
17 package com.google.doclava;
18 
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.Set;
22 import java.util.TreeSet;
23 
24 public class Errors {
25   public static boolean hadError = false;
26   private static boolean lintsAreErrors = false;
27   private static boolean warningsAreErrors = false;
28   private static TreeSet<ErrorMessage> allErrors = new TreeSet<ErrorMessage>();
29 
30   public static class ErrorMessage implements Comparable<ErrorMessage> {
31     final int resolvedLevel;
32     final Error error;
33     final SourcePositionInfo pos;
34     final String msg;
35 
ErrorMessage(int r, Error e, SourcePositionInfo p, String m)36     ErrorMessage(int r, Error e, SourcePositionInfo p, String m) {
37       resolvedLevel = r;
38       error = e;
39       pos = p;
40       msg = m;
41     }
42 
43     @Override
compareTo(ErrorMessage other)44     public int compareTo(ErrorMessage other) {
45       int r = pos.compareTo(other.pos);
46       if (r != 0) return r;
47       return msg.compareTo(other.msg);
48     }
49 
50     @Override
toString()51     public String toString() {
52       StringBuilder res = new StringBuilder();
53       if (Doclava.android) {
54         res.append("\033[1m").append(pos.toString()).append(": ");
55         switch (error.getLevel()) {
56           case LINT: res.append("\033[36mlint: "); break;
57           case WARNING: res.append("\033[33mwarning: "); break;
58           case ERROR: res.append("\033[31merror: "); break;
59           default: break;
60         }
61         res.append("\033[0m");
62         res.append(msg);
63         res.append(" [").append(error.code).append("]");
64       } else {
65         // Sigh, some people are parsing the old format.
66         res.append(pos.toString()).append(": ");
67         switch (error.getLevel()) {
68           case LINT: res.append("lint "); break;
69           case WARNING: res.append("warning "); break;
70           case ERROR: res.append("error "); break;
71           default: break;
72         }
73         res.append(error.code).append(": ");
74         res.append(msg);
75       }
76       return res.toString();
77     }
78 
error()79     public Error error() {
80       return error;
81     }
82   }
83 
error(Error error, MemberInfo mi, String text)84   public static void error(Error error, MemberInfo mi, String text) {
85     if (error.getLevel() == Errors.LINT) {
86       final String ident = "Doclava" + error.code;
87       for (AnnotationInstanceInfo a : mi.annotations()) {
88         if (a.type().qualifiedNameMatches("android", "annotation.SuppressLint")) {
89           for (AnnotationValueInfo val : a.elementValues()) {
90             if ("value".equals(val.element().name())) {
91               for (AnnotationValueInfo inner : (ArrayList<AnnotationValueInfo>) val.value()) {
92                 if (ident.equals(String.valueOf(inner.value()))) {
93                   return;
94                 }
95               }
96             }
97           }
98         }
99       }
100     }
101     error(error, mi.position(), text);
102   }
103 
error(Error error, SourcePositionInfo where, String text)104   public static void error(Error error, SourcePositionInfo where, String text) {
105     if (error.getLevel() == HIDDEN) {
106       return;
107     }
108 
109     int resolvedLevel = error.getLevel();
110     if (resolvedLevel == LINT && lintsAreErrors) {
111       resolvedLevel = ERROR;
112     }
113     if (resolvedLevel == WARNING && warningsAreErrors) {
114       resolvedLevel = ERROR;
115     }
116 
117     if (where == null) {
118       where = new SourcePositionInfo("unknown", 0, 0);
119     }
120 
121     allErrors.add(new ErrorMessage(resolvedLevel, error, where, text));
122 
123     if (resolvedLevel == ERROR) {
124       hadError = true;
125     }
126   }
127 
clearErrors()128   public static void clearErrors() {
129     hadError = false;
130     allErrors.clear();
131   }
132 
printErrors()133   public static void printErrors() {
134     printErrors(allErrors);
135   }
136 
printErrors(Set<ErrorMessage> errors)137   public static void printErrors(Set<ErrorMessage> errors) {
138     for (ErrorMessage m : errors) {
139       System.err.println(m.toString());
140     }
141     System.err.flush();
142   }
143 
getErrors()144   public static Set<ErrorMessage> getErrors() {
145     return allErrors;
146   }
147 
148   public static final int INHERIT = -1;
149   public static final int HIDDEN = 0;
150 
151   /**
152    * Lint level means that we encountered inconsistent or broken documentation.
153    * These should be resolved, but don't impact API compatibility.
154    */
155   public static final int LINT = 1;
156 
157   /**
158    * Warning level means that we encountered some incompatible or inconsistent
159    * API change. These must be resolved to preserve API compatibility.
160    */
161   public static final int WARNING = 2;
162 
163   /**
164    * Error level means that we encountered severe trouble and were unable to
165    * output the requested documentation.
166    */
167   public static final int ERROR = 3;
168 
setLintsAreErrors(boolean val)169   public static void setLintsAreErrors(boolean val) {
170     lintsAreErrors = val;
171   }
172 
setWarningsAreErrors(boolean val)173   public static void setWarningsAreErrors(boolean val) {
174     warningsAreErrors = val;
175   }
176 
177   public static class Error {
178     public int code;
179 
180     /**
181      * @deprecated This field should not be access directly. Instead, use
182      *             {@link #getLevel()}.
183      */
184     @Deprecated
185     public int level;
186 
187     /**
188      * When {@code level} is set to {@link #INHERIT}, this is the parent from
189      * which the error will inherit its level.
190      */
191     private final Error parent;
192 
Error(int code, int level)193     public Error(int code, int level) {
194       this.code = code;
195       this.level = level;
196       this.parent = null;
197       sErrors.add(this);
198     }
199 
Error(int code, Error parent)200     public Error(int code, Error parent) {
201       this.code = code;
202       this.level = -1;
203       this.parent = parent;
204       sErrors.add(this);
205     }
206 
207     /**
208      * Returns the implied level for this error.
209      * <p>
210      * If the level is {@link #INHERIT}, the level will be returned for the
211      * parent.
212      *
213      * @return
214      * @throws IllegalStateException if the level is {@link #INHERIT} and the
215      *         parent is {@code null}
216      */
getLevel()217     public int getLevel() {
218       if (level == INHERIT) {
219         if (parent == null) {
220           throw new IllegalStateException("Error with level INHERIT must have non-null parent");
221         }
222         return parent.getLevel();
223       }
224       return level;
225     }
226 
227     /**
228      * Sets the level.
229      * <p>
230      * Valid arguments are:
231      * <ul>
232      *     <li>{@link #HIDDEN}
233      *     <li>{@link #WARNING}
234      *     <li>{@link #ERROR}
235      * </ul>
236      *
237      * @param level the level to set
238      */
setLevel(int level)239     public void setLevel(int level) {
240       if (level == INHERIT) {
241         throw new IllegalArgumentException("Error level may not be set to INHERIT");
242       }
243       this.level = level;
244     }
245 
toString()246     public String toString() {
247       return "Error #" + this.code;
248     }
249   }
250 
251   public static final List<Error> sErrors = new ArrayList<>();
252 
253   // Errors for API verification
254   public static final Error PARSE_ERROR = new Error(1, ERROR);
255   public static final Error ADDED_PACKAGE = new Error(2, WARNING);
256   public static final Error ADDED_CLASS = new Error(3, WARNING);
257   public static final Error ADDED_METHOD = new Error(4, WARNING);
258   public static final Error ADDED_FIELD = new Error(5, WARNING);
259   public static final Error ADDED_INTERFACE = new Error(6, WARNING);
260   public static final Error REMOVED_PACKAGE = new Error(7, WARNING);
261   public static final Error REMOVED_CLASS = new Error(8, WARNING);
262   public static final Error REMOVED_METHOD = new Error(9, WARNING);
263   public static final Error REMOVED_FIELD = new Error(10, WARNING);
264   public static final Error REMOVED_INTERFACE = new Error(11, WARNING);
265   public static final Error CHANGED_STATIC = new Error(12, WARNING);
266   public static final Error ADDED_FINAL = new Error(13, WARNING);
267   public static final Error CHANGED_TRANSIENT = new Error(14, WARNING);
268   public static final Error CHANGED_VOLATILE = new Error(15, WARNING);
269   public static final Error CHANGED_TYPE = new Error(16, WARNING);
270   public static final Error CHANGED_VALUE = new Error(17, WARNING);
271   public static final Error CHANGED_SUPERCLASS = new Error(18, WARNING);
272   public static final Error CHANGED_SCOPE = new Error(19, WARNING);
273   public static final Error CHANGED_ABSTRACT = new Error(20, WARNING);
274   public static final Error CHANGED_THROWS = new Error(21, WARNING);
275   public static final Error CHANGED_NATIVE = new Error(22, HIDDEN);
276   public static final Error CHANGED_CLASS = new Error(23, WARNING);
277   public static final Error CHANGED_DEPRECATED = new Error(24, WARNING);
278   public static final Error CHANGED_SYNCHRONIZED = new Error(25, WARNING);
279   public static final Error ADDED_FINAL_UNINSTANTIABLE = new Error(26, WARNING);
280   public static final Error REMOVED_FINAL = new Error(27, WARNING);
281   public static final Error REMOVED_DEPRECATED_CLASS = new Error(28, REMOVED_CLASS);
282   public static final Error REMOVED_DEPRECATED_METHOD = new Error(29, REMOVED_METHOD);
283   public static final Error REMOVED_DEPRECATED_FIELD = new Error(30, REMOVED_FIELD);
284 
285   // Errors in javadoc generation
286   public static final Error UNRESOLVED_LINK = new Error(101, LINT);
287   public static final Error BAD_INCLUDE_TAG = new Error(102, LINT);
288   public static final Error UNKNOWN_TAG = new Error(103, LINT);
289   public static final Error UNKNOWN_PARAM_TAG_NAME = new Error(104, LINT);
290   public static final Error UNDOCUMENTED_PARAMETER = new Error(105, HIDDEN); // LINT
291   public static final Error BAD_ATTR_TAG = new Error(106, LINT);
292   public static final Error BAD_INHERITDOC = new Error(107, HIDDEN); // LINT
293   public static final Error HIDDEN_LINK = new Error(108, LINT);
294   public static final Error HIDDEN_CONSTRUCTOR = new Error(109, WARNING);
295   public static final Error UNAVAILABLE_SYMBOL = new Error(110, WARNING);
296   public static final Error HIDDEN_SUPERCLASS = new Error(111, WARNING);
297   public static final Error DEPRECATED = new Error(112, HIDDEN);
298   public static final Error DEPRECATION_MISMATCH = new Error(113, WARNING);
299   public static final Error MISSING_COMMENT = new Error(114, LINT);
300   public static final Error IO_ERROR = new Error(115, ERROR);
301   public static final Error NO_SINCE_DATA = new Error(116, HIDDEN);
302   public static final Error NO_FEDERATION_DATA = new Error(117, WARNING);
303   public static final Error BROKEN_SINCE_FILE = new Error(118, ERROR);
304   public static final Error INVALID_CONTENT_TYPE = new Error(119, ERROR);
305   public static final Error INVALID_SAMPLE_INDEX = new Error(120, ERROR);
306   public static final Error HIDDEN_TYPE_PARAMETER = new Error(121, WARNING);
307   public static final Error PRIVATE_SUPERCLASS = new Error(122, WARNING);
308   public static final Error NULLABLE = new Error(123, HIDDEN); // LINT
309   public static final Error INT_DEF = new Error(124, HIDDEN); // LINT
310   public static final Error REQUIRES_PERMISSION = new Error(125, LINT);
311   public static final Error BROADCAST_BEHAVIOR = new Error(126, LINT);
312   public static final Error SDK_CONSTANT = new Error(127, LINT);
313   public static final Error TODO = new Error(128, LINT);
314   public static final Error NO_ARTIFACT_DATA = new Error(129, HIDDEN);
315   public static final Error BROKEN_ARTIFACT_FILE = new Error(130, ERROR);
316 
setErrorLevel(int code, int level)317   public static boolean setErrorLevel(int code, int level) {
318     for (Error e : sErrors) {
319       if (e.code == code) {
320         e.setLevel(level);
321         return true;
322       }
323     }
324     return false;
325   }
326 }
327