Home | History | Annotate | Download | only in doclava
      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 
     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
     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
     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 
     79     public Error error() {
     80       return error;
     81     }
     82   }
     83 
     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 
    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 
    128   public static void clearErrors() {
    129     hadError = false;
    130     allErrors.clear();
    131   }
    132 
    133   public static void printErrors() {
    134     printErrors(allErrors);
    135   }
    136 
    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 
    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 
    169   public static void setLintsAreErrors(boolean val) {
    170     lintsAreErrors = val;
    171   }
    172 
    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 
    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 
    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      */
    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      */
    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 
    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 
    318   public static boolean setErrorLevel(int code, int level) {
    319     for (Error e : sErrors) {
    320       if (e.code == code) {
    321         e.setLevel(level);
    322         return true;
    323       }
    324     }
    325     return false;
    326   }
    327 }
    328