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 public static final Error ADDED_ABSTRACT_METHOD = new Error(31, ADDED_METHOD); 285 286 // Errors in javadoc generation 287 public static final Error UNRESOLVED_LINK = new Error(101, LINT); 288 public static final Error BAD_INCLUDE_TAG = new Error(102, LINT); 289 public static final Error UNKNOWN_TAG = new Error(103, LINT); 290 public static final Error UNKNOWN_PARAM_TAG_NAME = new Error(104, LINT); 291 public static final Error UNDOCUMENTED_PARAMETER = new Error(105, HIDDEN); // LINT 292 public static final Error BAD_ATTR_TAG = new Error(106, LINT); 293 public static final Error BAD_INHERITDOC = new Error(107, HIDDEN); // LINT 294 public static final Error HIDDEN_LINK = new Error(108, LINT); 295 public static final Error HIDDEN_CONSTRUCTOR = new Error(109, WARNING); 296 public static final Error UNAVAILABLE_SYMBOL = new Error(110, WARNING); 297 public static final Error HIDDEN_SUPERCLASS = new Error(111, WARNING); 298 public static final Error DEPRECATED = new Error(112, HIDDEN); 299 public static final Error DEPRECATION_MISMATCH = new Error(113, WARNING); 300 public static final Error MISSING_COMMENT = new Error(114, LINT); 301 public static final Error IO_ERROR = new Error(115, ERROR); 302 public static final Error NO_SINCE_DATA = new Error(116, HIDDEN); 303 public static final Error NO_FEDERATION_DATA = new Error(117, WARNING); 304 public static final Error BROKEN_SINCE_FILE = new Error(118, ERROR); 305 public static final Error INVALID_CONTENT_TYPE = new Error(119, ERROR); 306 public static final Error INVALID_SAMPLE_INDEX = new Error(120, ERROR); 307 public static final Error HIDDEN_TYPE_PARAMETER = new Error(121, WARNING); 308 public static final Error PRIVATE_SUPERCLASS = new Error(122, WARNING); 309 public static final Error NULLABLE = new Error(123, HIDDEN); // LINT 310 public static final Error INT_DEF = new Error(124, HIDDEN); // LINT 311 public static final Error REQUIRES_PERMISSION = new Error(125, LINT); 312 public static final Error BROADCAST_BEHAVIOR = new Error(126, LINT); 313 public static final Error SDK_CONSTANT = new Error(127, LINT); 314 public static final Error TODO = new Error(128, LINT); 315 public static final Error NO_ARTIFACT_DATA = new Error(129, HIDDEN); 316 public static final Error BROKEN_ARTIFACT_FILE = new Error(130, ERROR); 317 public static final Error JAVA_TAG_IN_COMMENT = new Error(131, LINT); 318 setErrorLevel(int code, int level)319 public static boolean setErrorLevel(int code, int level) { 320 for (Error e : sErrors) { 321 if (e.code == code) { 322 e.setLevel(level); 323 return true; 324 } 325 } 326 return false; 327 } 328 } 329