| 1 | /* | 
| 2 |  * Copyright 2005-2006 Sun Microsystems, Inc.  All Rights Reserved. | 
| 3 |  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
| 4 |  * | 
| 5 |  * This code is free software; you can redistribute it and/or modify it | 
| 6 |  * under the terms of the GNU General Public License version 2 only, as | 
| 7 |  * published by the Free Software Foundation.  Sun designates this | 
| 8 |  * particular file as subject to the "Classpath" exception as provided | 
| 9 |  * by Sun in the LICENSE file that accompanied this code. | 
| 10 |  * | 
| 11 |  * This code is distributed in the hope that it will be useful, but WITHOUT | 
| 12 |  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
| 13 |  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
| 14 |  * version 2 for more details (a copy is included in the LICENSE file that | 
| 15 |  * accompanied this code). | 
| 16 |  * | 
| 17 |  * You should have received a copy of the GNU General Public License version | 
| 18 |  * 2 along with this work; if not, write to the Free Software Foundation, | 
| 19 |  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
| 20 |  * | 
| 21 |  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | 
| 22 |  * CA 95054 USA or visit www.sun.com if you need additional information or | 
| 23 |  * have any questions. | 
| 24 |  */ | 
| 25 |   | 
| 26 | package com.sun.tools.javac.code; | 
| 27 |   | 
| 28 | import java.util.EnumSet; | 
| 29 | import java.util.HashMap; | 
| 30 | import java.util.Map; | 
| 31 | import com.sun.tools.javac.code.Symbol.*; | 
| 32 | import com.sun.tools.javac.util.Context; | 
| 33 | import com.sun.tools.javac.util.List; | 
| 34 | import com.sun.tools.javac.util.Options; | 
| 35 | import com.sun.tools.javac.util.Pair; | 
| 36 | import static com.sun.tools.javac.code.Flags.*; | 
| 37 |   | 
| 38 |   | 
| 39 | /** | 
| 40 |  * A class for handling -Xlint suboptions and @SuppresssWarnings. | 
| 41 |  * | 
| 42 |  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If | 
| 43 |  *  you write code that depends on this, you do so at your own risk. | 
| 44 |  *  This code and its internal interfaces are subject to change or | 
| 45 |  *  deletion without notice.</b> | 
| 46 |  */ | 
| 47 | public class Lint | 
| 48 | { | 
| 49 |     /** The context key for the root Lint object. */ | 
| 50 |     protected static final Context.Key<Lint> lintKey = new Context.Key<Lint>(); | 
| 51 |   | 
| 52 |     /** Get the root Lint instance. */ | 
| 53 |     public static Lint instance(Context context) { | 
| 54 |         Lint instance = context.get(lintKey); | 
| 55 |         if (instance == null) | 
| 56 |             instance = new Lint(context); | 
| 57 |         return instance; | 
| 58 |     } | 
| 59 |   | 
| 60 |     /** | 
| 61 |      * Returns the result of combining the values in this object with | 
| 62 |      * the given annotation. | 
| 63 |      */ | 
| 64 |     public Lint augment(Attribute.Compound attr) { | 
| 65 |         return augmentor.augment(this, attr); | 
| 66 |     } | 
| 67 |   | 
| 68 |   | 
| 69 |     /** | 
| 70 |      * Returns the result of combining the values in this object with | 
| 71 |      * the given annotations. | 
| 72 |      */ | 
| 73 |     public Lint augment(List<Attribute.Compound> attrs) { | 
| 74 |         return augmentor.augment(this, attrs); | 
| 75 |     } | 
| 76 |   | 
| 77 |     /** | 
| 78 |      * Returns the result of combining the values in this object with | 
| 79 |      * the given annotations and flags. | 
| 80 |      */ | 
| 81 |     public Lint augment(List<Attribute.Compound> attrs, long flags) { | 
| 82 |         Lint l = augmentor.augment(this, attrs); | 
| 83 |         if ((flags & DEPRECATED) != 0) { | 
| 84 |             if (l == this) | 
| 85 |                 l = new Lint(this); | 
| 86 |             l.values.remove(LintCategory.DEPRECATION); | 
| 87 |             l.suppressedValues.add(LintCategory.DEPRECATION); | 
| 88 |         } | 
| 89 |         return l; | 
| 90 |     } | 
| 91 |   | 
| 92 |   | 
| 93 |     private final AugmentVisitor augmentor; | 
| 94 |   | 
| 95 |     private final EnumSet<LintCategory> values; | 
| 96 |     private final EnumSet<LintCategory> suppressedValues; | 
| 97 |   | 
| 98 |     private static Map<String, LintCategory> map = new HashMap<String,LintCategory>(); | 
| 99 |   | 
| 100 |   | 
| 101 |     protected Lint(Context context) { | 
| 102 |         // initialize values according to the lint options | 
| 103 |         Options options = Options.instance(context); | 
| 104 |         values = EnumSet.noneOf(LintCategory.class); | 
| 105 |         for (Map.Entry<String, LintCategory> e: map.entrySet()) { | 
| 106 |             if (options.lint(e.getKey())) | 
| 107 |                 values.add(e.getValue()); | 
| 108 |         } | 
| 109 |   | 
| 110 |         suppressedValues = EnumSet.noneOf(LintCategory.class); | 
| 111 |   | 
| 112 |         context.put(lintKey, this); | 
| 113 |         augmentor = new AugmentVisitor(context); | 
| 114 |     } | 
| 115 |   | 
| 116 |     protected Lint(Lint other) { | 
| 117 |         this.augmentor = other.augmentor; | 
| 118 |         this.values = other.values.clone(); | 
| 119 |         this.suppressedValues = other.suppressedValues.clone(); | 
| 120 |     } | 
| 121 |   | 
| 122 |     public String toString() { | 
| 123 |         return "Lint:[values" + values + " suppressedValues" + suppressedValues + "]"; | 
| 124 |     } | 
| 125 |   | 
| 126 |     /** | 
| 127 |      * Categories of warnings that can be generated by the compiler. | 
| 128 |      */ | 
| 129 |     public enum LintCategory { | 
| 130 |         /** | 
| 131 |          * Warn about use of unnecessary casts. | 
| 132 |          */ | 
| 133 |         CAST("cast"), | 
| 134 |   | 
| 135 |         /** | 
| 136 |          * Warn about use of deprecated items. | 
| 137 |          */ | 
| 138 |         DEPRECATION("deprecation"), | 
| 139 |   | 
| 140 |         /** | 
| 141 |          * Warn about items which are documented with an {@code @deprecated} JavaDoc | 
| 142 |          * comment, but which do not have {@code @Deprecated} annotation. | 
| 143 |          */ | 
| 144 |         DEP_ANN("dep-ann"), | 
| 145 |   | 
| 146 |         /** | 
| 147 |          * Warn about division by constant integer 0. | 
| 148 |          */ | 
| 149 |         DIVZERO("divzero"), | 
| 150 |   | 
| 151 |         /** | 
| 152 |          * Warn about empty statement after if. | 
| 153 |          */ | 
| 154 |         EMPTY("empty"), | 
| 155 |   | 
| 156 |         /** | 
| 157 |          * Warn about falling through from one case of a switch statement to the next. | 
| 158 |          */ | 
| 159 |         FALLTHROUGH("fallthrough"), | 
| 160 |   | 
| 161 |         /** | 
| 162 |          * Warn about finally clauses that do not terminate normally. | 
| 163 |          */ | 
| 164 |         FINALLY("finally"), | 
| 165 |   | 
| 166 |         /** | 
| 167 |          * Warn about issues regarding method overrides. | 
| 168 |          */ | 
| 169 |         OVERRIDES("overrides"), | 
| 170 |   | 
| 171 |         /** | 
| 172 |          * Warn about invalid path elements on the command line. | 
| 173 |          * Such warnings cannot be suppressed with the SuppressWarnings | 
| 174 |          * annotation. | 
| 175 |          */ | 
| 176 |         PATH("path"), | 
| 177 |   | 
| 178 |         /** | 
| 179 |          * Warn about Serializable classes that do not provide a serial version ID. | 
| 180 |          */ | 
| 181 |         SERIAL("serial"), | 
| 182 |   | 
| 183 |         /** | 
| 184 |          * Warn about unchecked operations on raw types. | 
| 185 |          */ | 
| 186 |         UNCHECKED("unchecked"); | 
| 187 |   | 
| 188 |         LintCategory(String option) { | 
| 189 |             this.option = option; | 
| 190 |             map.put(option, this); | 
| 191 |         } | 
| 192 |   | 
| 193 |         static LintCategory get(String option) { | 
| 194 |             return map.get(option); | 
| 195 |         } | 
| 196 |   | 
| 197 |         private final String option; | 
| 198 |     }; | 
| 199 |   | 
| 200 |     /** | 
| 201 |      * Checks if a warning category is enabled. A warning category may be enabled | 
| 202 |      * on the command line, or by default, and can be temporarily disabled with | 
| 203 |      * the SuppressWarnings annotation. | 
| 204 |      */ | 
| 205 |     public boolean isEnabled(LintCategory lc) { | 
| 206 |         return values.contains(lc); | 
| 207 |     } | 
| 208 |   | 
| 209 |     /** | 
| 210 |      * Checks is a warning category has been specifically suppressed, by means | 
| 211 |      * of the SuppressWarnings annotation, or, in the case of the deprecated | 
| 212 |      * category, whether it has been implicitly suppressed by virtue of the | 
| 213 |      * current entity being itself deprecated. | 
| 214 |      */ | 
| 215 |     public boolean isSuppressed(LintCategory lc) { | 
| 216 |         return suppressedValues.contains(lc); | 
| 217 |     } | 
| 218 |   | 
| 219 |     protected static class AugmentVisitor implements Attribute.Visitor { | 
| 220 |         private final Context context; | 
| 221 |         private Symtab syms; | 
| 222 |         private Lint parent; | 
| 223 |         private Lint lint; | 
| 224 |   | 
| 225 |         AugmentVisitor(Context context) { | 
| 226 |             // to break an ugly sequence of initialization dependencies, | 
| 227 |             // we defer the initialization of syms until it is needed | 
| 228 |             this.context = context; | 
| 229 |         } | 
| 230 |   | 
| 231 |         Lint augment(Lint parent, Attribute.Compound attr) { | 
| 232 |             initSyms(); | 
| 233 |             this.parent = parent; | 
| 234 |             lint = null; | 
| 235 |             attr.accept(this); | 
| 236 |             return (lint == null ? parent : lint); | 
| 237 |         } | 
| 238 |   | 
| 239 |         Lint augment(Lint parent, List<Attribute.Compound> attrs) { | 
| 240 |             initSyms(); | 
| 241 |             this.parent = parent; | 
| 242 |             lint = null; | 
| 243 |             for (Attribute.Compound a: attrs) { | 
| 244 |                 a.accept(this); | 
| 245 |             } | 
| 246 |             return (lint == null ? parent : lint); | 
| 247 |         } | 
| 248 |   | 
| 249 |         private void initSyms() { | 
| 250 |             if (syms == null) | 
| 251 |                 syms = Symtab.instance(context); | 
| 252 |         } | 
| 253 |   | 
| 254 |         private void suppress(LintCategory lc) { | 
| 255 |             if (lint == null) | 
| 256 |                 lint = new Lint(parent); | 
| 257 |             lint.suppressedValues.add(lc); | 
| 258 |             lint.values.remove(lc); | 
| 259 |         } | 
| 260 |   | 
| 261 |         public void visitConstant(Attribute.Constant value) { | 
| 262 |             if (value.type.tsym == syms.stringType.tsym) { | 
| 263 |                 LintCategory lc = LintCategory.get((String) (value.value)); | 
| 264 |                 if (lc != null) | 
| 265 |                     suppress(lc); | 
| 266 |             } | 
| 267 |         } | 
| 268 |   | 
| 269 |         public void visitClass(Attribute.Class clazz) { | 
| 270 |         } | 
| 271 |   | 
| 272 |         // If we find a @SuppressWarnings annotation, then we continue | 
| 273 |         // walking the tree, in order to suppress the individual warnings | 
| 274 |         // specified in the @SuppressWarnings annotation. | 
| 275 |         public void visitCompound(Attribute.Compound compound) { | 
| 276 |             if (compound.type.tsym == syms.suppressWarningsType.tsym) { | 
| 277 |                 for (List<Pair<MethodSymbol,Attribute>> v = compound.values; | 
| 278 |                      v.nonEmpty(); v = v.tail) { | 
| 279 |                     Pair<MethodSymbol,Attribute> value = v.head; | 
| 280 |                     if (value.fst.name.toString().equals("value")) | 
| 281 |                         value.snd.accept(this); | 
| 282 |                 } | 
| 283 |   | 
| 284 |             } | 
| 285 |         } | 
| 286 |   | 
| 287 |         public void visitArray(Attribute.Array array) { | 
| 288 |             for (Attribute value : array.values) | 
| 289 |                 value.accept(this); | 
| 290 |         } | 
| 291 |   | 
| 292 |         public void visitEnum(Attribute.Enum e) { | 
| 293 |         } | 
| 294 |   | 
| 295 |         public void visitError(Attribute.Error e) { | 
| 296 |         } | 
| 297 |     }; | 
| 298 | } |