1 /* 2 * Copyright (c) 2005, 2008, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * 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 supported API. 43 * If 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 issues regarding annotation processing. 180 */ 181 PROCESSING("processing"), 182 183 /** 184 * Warn about Serializable classes that do not provide a serial version ID. 185 */ 186 SERIAL("serial"), 187 188 /** 189 * Warn about unchecked operations on raw types. 190 */ 191 UNCHECKED("unchecked"), 192 193 /** 194 * Warn about unchecked operations on raw types. 195 */ 196 RAW("rawtypes"), 197 198 /** 199 * Warn about proprietary API that may be removed in a future release. 200 */ 201 SUNAPI("sunapi", true), 202 203 /** 204 * Warn about issues relating to use of statics 205 */ 206 STATIC("static"), 207 208 /** 209 * Warn about potentially unsafe vararg methods 210 */ 211 VARARGS("varargs"); 212 213 LintCategory(String option) { 214 this(option, false); 215 } 216 217 LintCategory(String option, boolean hidden) { 218 this.option = option; 219 this.hidden = hidden; 220 map.put(option, this); 221 } 222 223 static LintCategory get(String option) { 224 return map.get(option); 225 } 226 227 public final String option; 228 public final boolean hidden; 229 }; 230 231 /** 232 * Checks if a warning category is enabled. A warning category may be enabled 233 * on the command line, or by default, and can be temporarily disabled with 234 * the SuppressWarnings annotation. 235 */ 236 public boolean isEnabled(LintCategory lc) { 237 return values.contains(lc); 238 } 239 240 /** 241 * Checks is a warning category has been specifically suppressed, by means 242 * of the SuppressWarnings annotation, or, in the case of the deprecated 243 * category, whether it has been implicitly suppressed by virtue of the 244 * current entity being itself deprecated. 245 */ 246 public boolean isSuppressed(LintCategory lc) { 247 return suppressedValues.contains(lc); 248 } 249 250 protected static class AugmentVisitor implements Attribute.Visitor { 251 private final Context context; 252 private Symtab syms; 253 private Lint parent; 254 private Lint lint; 255 256 AugmentVisitor(Context context) { 257 // to break an ugly sequence of initialization dependencies, 258 // we defer the initialization of syms until it is needed 259 this.context = context; 260 } 261 262 Lint augment(Lint parent, Attribute.Compound attr) { 263 initSyms(); 264 this.parent = parent; 265 lint = null; 266 attr.accept(this); 267 return (lint == null ? parent : lint); 268 } 269 270 Lint augment(Lint parent, List<Attribute.Compound> attrs) { 271 initSyms(); 272 this.parent = parent; 273 lint = null; 274 for (Attribute.Compound a: attrs) { 275 a.accept(this); 276 } 277 return (lint == null ? parent : lint); 278 } 279 280 private void initSyms() { 281 if (syms == null) 282 syms = Symtab.instance(context); 283 } 284 285 private void suppress(LintCategory lc) { 286 if (lint == null) 287 lint = new Lint(parent); 288 lint.suppressedValues.add(lc); 289 lint.values.remove(lc); 290 } 291 292 public void visitConstant(Attribute.Constant value) { 293 if (value.type.tsym == syms.stringType.tsym) { 294 LintCategory lc = LintCategory.get((String) (value.value)); 295 if (lc != null) 296 suppress(lc); 297 } 298 } 299 300 public void visitClass(Attribute.Class clazz) { 301 } 302 303 // If we find a @SuppressWarnings annotation, then we continue 304 // walking the tree, in order to suppress the individual warnings 305 // specified in the @SuppressWarnings annotation. 306 public void visitCompound(Attribute.Compound compound) { 307 if (compound.type.tsym == syms.suppressWarningsType.tsym) { 308 for (List<Pair<MethodSymbol,Attribute>> v = compound.values; 309 v.nonEmpty(); v = v.tail) { 310 Pair<MethodSymbol,Attribute> value = v.head; 311 if (value.fst.name.toString().equals("value")) 312 value.snd.accept(this); 313 } 314 315 } 316 } 317 318 public void visitArray(Attribute.Array array) { 319 for (Attribute value : array.values) 320 value.accept(this); 321 } 322 323 public void visitEnum(Attribute.Enum e) { 324 } 325 326 public void visitError(Attribute.Error e) { 327 } 328 }; 329 }