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 /** 214 * Warn about arm resources 215 */ 216 ARM("arm"); 217 218 LintCategory(String option) { 219 this(option, false); 220 } 221 222 LintCategory(String option, boolean hidden) { 223 this.option = option; 224 this.hidden = hidden; 225 map.put(option, this); 226 } 227 228 static LintCategory get(String option) { 229 return map.get(option); 230 } 231 232 public final String option; 233 public final boolean hidden; 234 }; 235 236 /** 237 * Checks if a warning category is enabled. A warning category may be enabled 238 * on the command line, or by default, and can be temporarily disabled with 239 * the SuppressWarnings annotation. 240 */ 241 public boolean isEnabled(LintCategory lc) { 242 return values.contains(lc); 243 } 244 245 /** 246 * Checks is a warning category has been specifically suppressed, by means 247 * of the SuppressWarnings annotation, or, in the case of the deprecated 248 * category, whether it has been implicitly suppressed by virtue of the 249 * current entity being itself deprecated. 250 */ 251 public boolean isSuppressed(LintCategory lc) { 252 return suppressedValues.contains(lc); 253 } 254 255 protected static class AugmentVisitor implements Attribute.Visitor { 256 private final Context context; 257 private Symtab syms; 258 private Lint parent; 259 private Lint lint; 260 261 AugmentVisitor(Context context) { 262 // to break an ugly sequence of initialization dependencies, 263 // we defer the initialization of syms until it is needed 264 this.context = context; 265 } 266 267 Lint augment(Lint parent, Attribute.Compound attr) { 268 initSyms(); 269 this.parent = parent; 270 lint = null; 271 attr.accept(this); 272 return (lint == null ? parent : lint); 273 } 274 275 Lint augment(Lint parent, List<Attribute.Compound> attrs) { 276 initSyms(); 277 this.parent = parent; 278 lint = null; 279 for (Attribute.Compound a: attrs) { 280 a.accept(this); 281 } 282 return (lint == null ? parent : lint); 283 } 284 285 private void initSyms() { 286 if (syms == null) 287 syms = Symtab.instance(context); 288 } 289 290 private void suppress(LintCategory lc) { 291 if (lint == null) 292 lint = new Lint(parent); 293 lint.suppressedValues.add(lc); 294 lint.values.remove(lc); 295 } 296 297 public void visitConstant(Attribute.Constant value) { 298 if (value.type.tsym == syms.stringType.tsym) { 299 LintCategory lc = LintCategory.get((String) (value.value)); 300 if (lc != null) 301 suppress(lc); 302 } 303 } 304 305 public void visitClass(Attribute.Class clazz) { 306 } 307 308 // If we find a @SuppressWarnings annotation, then we continue 309 // walking the tree, in order to suppress the individual warnings 310 // specified in the @SuppressWarnings annotation. 311 public void visitCompound(Attribute.Compound compound) { 312 if (compound.type.tsym == syms.suppressWarningsType.tsym) { 313 for (List<Pair<MethodSymbol,Attribute>> v = compound.values; 314 v.nonEmpty(); v = v.tail) { 315 Pair<MethodSymbol,Attribute> value = v.head; 316 if (value.fst.name.toString().equals("value")) 317 value.snd.accept(this); 318 } 319 320 } 321 } 322 323 public void visitArray(Attribute.Array array) { 324 for (Attribute value : array.values) 325 value.accept(this); 326 } 327 328 public void visitEnum(Attribute.Enum e) { 329 } 330 331 public void visitError(Attribute.Error e) { 332 } 333 }; 334 }