summaryrefslogtreecommitdiff
path: root/src/com/google/doclava/Errors.java
blob: 9edd2395f17dc4cd53cb84ac8a818e126090aea3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
/*
 * Copyright (C) 2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.doclava;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

public class Errors {
  public static boolean hadError = false;
  private static boolean lintsAreErrors = false;
  private static boolean warningsAreErrors = false;
  private static TreeSet<ErrorMessage> allErrors = new TreeSet<ErrorMessage>();

  public static class ErrorMessage implements Comparable<ErrorMessage> {
    final int resolvedLevel;
    final Error error;
    final SourcePositionInfo pos;
    final String msg;

    ErrorMessage(int r, Error e, SourcePositionInfo p, String m) {
      resolvedLevel = r;
      error = e;
      pos = p;
      msg = m;
    }

    @Override
    public int compareTo(ErrorMessage other) {
      int r = pos.compareTo(other.pos);
      if (r != 0) return r;
      return msg.compareTo(other.msg);
    }

    @Override
    public String toString() {
      StringBuilder res = new StringBuilder();
      if (Doclava.android) {
        res.append("\033[1m").append(pos.toString()).append(": ");
        switch (error.getLevel()) {
          case LINT: res.append("\033[36mlint: "); break;
          case WARNING: res.append("\033[33mwarning: "); break;
          case ERROR: res.append("\033[31merror: "); break;
          default: break;
        }
        res.append("\033[0m");
        res.append(msg);
        res.append(" [").append(error.code).append("]");
      } else {
        // Sigh, some people are parsing the old format.
        res.append(pos.toString()).append(": ");
        switch (error.getLevel()) {
          case LINT: res.append("lint "); break;
          case WARNING: res.append("warning "); break;
          case ERROR: res.append("error "); break;
          default: break;
        }
        res.append(error.code).append(": ");
        res.append(msg);
      }
      return res.toString();
    }
    
    public Error error() {
      return error;
    }
  }

  public static void error(Error error, MemberInfo mi, String text) {
    if (error.getLevel() == Errors.LINT) {
      final String ident = "Doclava" + error.code;
      for (AnnotationInstanceInfo a : mi.annotations()) {
        if (a.type().qualifiedNameMatches("android", "annotation.SuppressLint")) {
          for (AnnotationValueInfo val : a.elementValues()) {
            if ("value".equals(val.element().name())) {
              for (AnnotationValueInfo inner : (ArrayList<AnnotationValueInfo>) val.value()) {
                if (ident.equals(String.valueOf(inner.value()))) {
                  return;
                }
              }
            }
          }
        }
      }
    }
    error(error, mi.position(), text);
  }

  public static void error(Error error, SourcePositionInfo where, String text) {
    if (error.getLevel() == HIDDEN) {
      return;
    }

    int resolvedLevel = error.getLevel();
    if (resolvedLevel == LINT && lintsAreErrors) {
      resolvedLevel = ERROR;
    }
    if (resolvedLevel == WARNING && warningsAreErrors) {
      resolvedLevel = ERROR;
    }

    if (where == null) {
      where = new SourcePositionInfo("unknown", 0, 0);
    }

    allErrors.add(new ErrorMessage(resolvedLevel, error, where, text));

    if (resolvedLevel == ERROR) {
      hadError = true;
    }
  }
  
  public static void clearErrors() {
    hadError = false;
    allErrors.clear();
  }

  public static void printErrors() {
    printErrors(allErrors);
  }
  
  public static void printErrors(Set<ErrorMessage> errors) {
    for (ErrorMessage m : errors) {
      System.err.println(m.toString());
    }
    System.err.flush();
  }
  
  public static Set<ErrorMessage> getErrors() {
    return allErrors;
  }

  public static final int INHERIT = -1;
  public static final int HIDDEN = 0;

  /**
   * Lint level means that we encountered inconsistent or broken documentation.
   * These should be resolved, but don't impact API compatibility.
   */
  public static final int LINT = 1;

  /**
   * Warning level means that we encountered some incompatible or inconsistent
   * API change. These must be resolved to preserve API compatibility.
   */
  public static final int WARNING = 2;

  /**
   * Error level means that we encountered severe trouble and were unable to
   * output the requested documentation.
   */
  public static final int ERROR = 3;

  public static void setLintsAreErrors(boolean val) {
    lintsAreErrors = val;
  }

  public static void setWarningsAreErrors(boolean val) {
    warningsAreErrors = val;
  }

  public static class Error {
    public int code;

    /**
     * @deprecated This field should not be access directly. Instead, use
     *             {@link #getLevel()}.
     */
    @Deprecated
    public int level;

    /**
     * When {@code level} is set to {@link #INHERIT}, this is the parent from
     * which the error will inherit its level.
     */
    private final Error parent;

    public Error(int code, int level) {
      this.code = code;
      this.level = level;
      this.parent = null;
      sErrors.add(this);
    }

    public Error(int code, Error parent) {
      this.code = code;
      this.level = -1;
      this.parent = parent;
      sErrors.add(this);
    }

    /**
     * Returns the implied level for this error.
     * <p>
     * If the level is {@link #INHERIT}, the level will be returned for the
     * parent.
     *
     * @return
     * @throws IllegalStateException if the level is {@link #INHERIT} and the
     *         parent is {@code null}
     */
    public int getLevel() {
      if (level == INHERIT) {
        if (parent == null) {
          throw new IllegalStateException("Error with level INHERIT must have non-null parent");
        }
        return parent.getLevel();
      }
      return level;
    }

    /**
     * Sets the level.
     * <p>
     * Valid arguments are:
     * <ul>
     *     <li>{@link #HIDDEN}
     *     <li>{@link #WARNING}
     *     <li>{@link #ERROR}
     * </ul>
     *
     * @param level the level to set
     */
    public void setLevel(int level) {
      if (level == INHERIT) {
        throw new IllegalArgumentException("Error level may not be set to INHERIT");
      }
      this.level = level;
    }

    public String toString() {
      return "Error #" + this.code;
    }
  }

  public static final List<Error> sErrors = new ArrayList<>();

  // Errors for API verification
  public static final Error PARSE_ERROR = new Error(1, ERROR);
  public static final Error ADDED_PACKAGE = new Error(2, WARNING);
  public static final Error ADDED_CLASS = new Error(3, WARNING);
  public static final Error ADDED_METHOD = new Error(4, WARNING);
  public static final Error ADDED_FIELD = new Error(5, WARNING);
  public static final Error ADDED_INTERFACE = new Error(6, WARNING);
  public static final Error REMOVED_PACKAGE = new Error(7, WARNING);
  public static final Error REMOVED_CLASS = new Error(8, WARNING);
  public static final Error REMOVED_METHOD = new Error(9, WARNING);
  public static final Error REMOVED_FIELD = new Error(10, WARNING);
  public static final Error REMOVED_INTERFACE = new Error(11, WARNING);
  public static final Error CHANGED_STATIC = new Error(12, WARNING);
  public static final Error ADDED_FINAL = new Error(13, WARNING);
  public static final Error CHANGED_TRANSIENT = new Error(14, WARNING);
  public static final Error CHANGED_VOLATILE = new Error(15, WARNING);
  public static final Error CHANGED_TYPE = new Error(16, WARNING);
  public static final Error CHANGED_VALUE = new Error(17, WARNING);
  public static final Error CHANGED_SUPERCLASS = new Error(18, WARNING);
  public static final Error CHANGED_SCOPE = new Error(19, WARNING);
  public static final Error CHANGED_ABSTRACT = new Error(20, WARNING);
  public static final Error CHANGED_THROWS = new Error(21, WARNING);
  public static final Error CHANGED_NATIVE = new Error(22, HIDDEN);
  public static final Error CHANGED_CLASS = new Error(23, WARNING);
  public static final Error CHANGED_DEPRECATED = new Error(24, WARNING);
  public static final Error CHANGED_SYNCHRONIZED = new Error(25, WARNING);
  public static final Error ADDED_FINAL_UNINSTANTIABLE = new Error(26, WARNING);
  public static final Error REMOVED_FINAL = new Error(27, WARNING);
  public static final Error REMOVED_DEPRECATED_CLASS = new Error(28, REMOVED_CLASS);
  public static final Error REMOVED_DEPRECATED_METHOD = new Error(29, REMOVED_METHOD);
  public static final Error REMOVED_DEPRECATED_FIELD = new Error(30, REMOVED_FIELD);

  // Errors in javadoc generation
  public static final Error UNRESOLVED_LINK = new Error(101, LINT);
  public static final Error BAD_INCLUDE_TAG = new Error(102, LINT);
  public static final Error UNKNOWN_TAG = new Error(103, LINT);
  public static final Error UNKNOWN_PARAM_TAG_NAME = new Error(104, LINT);
  public static final Error UNDOCUMENTED_PARAMETER = new Error(105, HIDDEN); // LINT
  public static final Error BAD_ATTR_TAG = new Error(106, LINT);
  public static final Error BAD_INHERITDOC = new Error(107, HIDDEN); // LINT
  public static final Error HIDDEN_LINK = new Error(108, LINT);
  public static final Error HIDDEN_CONSTRUCTOR = new Error(109, WARNING);
  public static final Error UNAVAILABLE_SYMBOL = new Error(110, WARNING);
  public static final Error HIDDEN_SUPERCLASS = new Error(111, WARNING);
  public static final Error DEPRECATED = new Error(112, HIDDEN);
  public static final Error DEPRECATION_MISMATCH = new Error(113, WARNING);
  public static final Error MISSING_COMMENT = new Error(114, LINT);
  public static final Error IO_ERROR = new Error(115, ERROR);
  public static final Error NO_SINCE_DATA = new Error(116, HIDDEN);
  public static final Error NO_FEDERATION_DATA = new Error(117, WARNING);
  public static final Error BROKEN_SINCE_FILE = new Error(118, ERROR);
  public static final Error INVALID_CONTENT_TYPE = new Error(119, ERROR);
  public static final Error INVALID_SAMPLE_INDEX = new Error(120, ERROR);
  public static final Error HIDDEN_TYPE_PARAMETER = new Error(121, WARNING);
  public static final Error PRIVATE_SUPERCLASS = new Error(122, WARNING);
  public static final Error NULLABLE = new Error(123, HIDDEN); // LINT
  public static final Error INT_DEF = new Error(124, HIDDEN); // LINT
  public static final Error REQUIRES_PERMISSION = new Error(125, LINT);
  public static final Error BROADCAST_BEHAVIOR = new Error(126, LINT);
  public static final Error SDK_CONSTANT = new Error(127, LINT);
  public static final Error TODO = new Error(128, LINT);
  public static final Error NO_ARTIFACT_DATA = new Error(129, HIDDEN);
  public static final Error BROKEN_ARTIFACT_FILE = new Error(130, ERROR);

  public static boolean setErrorLevel(int code, int level) {
    for (Error e : sErrors) {
      if (e.code == code) {
        e.setLevel(level);
        return true;
      }
    }
    return false;
  }
}