1 /* 2 * Copyright (c) 2005, 2016, 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.Map; 30 import java.util.concurrent.ConcurrentHashMap; 31 32 import com.sun.tools.javac.code.Symbol.*; 33 import com.sun.tools.javac.util.Context; 34 import com.sun.tools.javac.util.List; 35 import com.sun.tools.javac.util.Options; 36 import com.sun.tools.javac.util.Pair; 37 38 /** 39 * A class for handling -Xlint suboptions and @SuppresssWarnings. 40 * 41 * <p><b>This is NOT part of any supported API. 42 * If you write code that depends on this, you do so at your own risk. 43 * This code and its internal interfaces are subject to change or 44 * deletion without notice.</b> 45 */ 46 public class Lint 47 { 48 /** The context key for the root Lint object. */ 49 protected static final Context.Key<Lint> lintKey = new Context.Key<>(); 50 51 /** Get the root Lint instance. */ 52 public static Lint instance(Context context) { 53 Lint instance = context.get(lintKey); 54 if (instance == null) 55 instance = new Lint(context); 56 return instance; 57 } 58 59 /** 60 * Returns the result of combining the values in this object with 61 * the given annotation. 62 */ 63 public Lint augment(Attribute.Compound attr) { 64 return augmentor.augment(this, attr); 65 } 66 67 68 /** 69 * Returns the result of combining the values in this object with 70 * the metadata on the given symbol. 71 */ 72 public Lint augment(Symbol sym) { 73 Lint l = augmentor.augment(this, sym.getDeclarationAttributes()); 74 if (sym.isDeprecated()) { 75 if (l == this) 76 l = new Lint(this); 77 l.values.remove(LintCategory.DEPRECATION); 78 l.suppressedValues.add(LintCategory.DEPRECATION); 79 } 80 return l; 81 } 82 83 /** 84 * Returns a new Lint that has the given LintCategory suppressed. 85 */ 86 public Lint suppress(LintCategory lc) { 87 Lint l = new Lint(this); 88 l.values.remove(lc); 89 l.suppressedValues.add(lc); 90 return l; 91 } 92 93 private final AugmentVisitor augmentor; 94 95 private final EnumSet<LintCategory> values; 96 private final EnumSet<LintCategory> suppressedValues; 97 98 private static final Map<String, LintCategory> map = new ConcurrentHashMap<>(20); 99 100 protected Lint(Context context) { 101 // initialize values according to the lint options 102 Options options = Options.instance(context); 103 values = EnumSet.noneOf(LintCategory.class); 104 for (Map.Entry<String, LintCategory> e: map.entrySet()) { 105 if (options.lint(e.getKey())) 106 values.add(e.getValue()); 107 } 108 109 suppressedValues = EnumSet.noneOf(LintCategory.class); 110 111 context.put(lintKey, this); 112 augmentor = new AugmentVisitor(context); 113 } 114 115 protected Lint(Lint other) { 116 this.augmentor = other.augmentor; 117 this.values = other.values.clone(); 118 this.suppressedValues = other.suppressedValues.clone(); 119 } 120 121 @Override 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 when code refers to a auxiliary class that is hidden in a source file (ie source file name is 132 * different from the class name, and the type is not properly nested) and the referring code 133 * is not located in the same source file. 134 */ 135 AUXILIARYCLASS("auxiliaryclass"), 136 137 /** 138 * Warn about use of unnecessary casts. 139 */ 140 CAST("cast"), 141 142 /** 143 * Warn about issues related to classfile contents 144 */ 145 CLASSFILE("classfile"), 146 147 /** 148 * Warn about use of deprecated items. 149 */ 150 DEPRECATION("deprecation"), 151 152 /** 153 * Warn about items which are documented with an {@code @deprecated} JavaDoc 154 * comment, but which do not have {@code @Deprecated} annotation. 155 */ 156 DEP_ANN("dep-ann"), 157 158 /** 159 * Warn about division by constant integer 0. 160 */ 161 DIVZERO("divzero"), 162 163 /** 164 * Warn about empty statement after if. 165 */ 166 EMPTY("empty"), 167 168 /** 169 * Warn about falling through from one case of a switch statement to the next. 170 */ 171 FALLTHROUGH("fallthrough"), 172 173 /** 174 * Warn about finally clauses that do not terminate normally. 175 */ 176 FINALLY("finally"), 177 178 /** 179 * Warn about issues relating to use of command line options 180 */ 181 OPTIONS("options"), 182 183 /** 184 * Warn about issues regarding method overloads. 185 */ 186 OVERLOADS("overloads"), 187 188 /** 189 * Warn about issues regarding method overrides. 190 */ 191 OVERRIDES("overrides"), 192 193 /** 194 * Warn about invalid path elements on the command line. 195 * Such warnings cannot be suppressed with the SuppressWarnings 196 * annotation. 197 */ 198 PATH("path"), 199 200 /** 201 * Warn about issues regarding annotation processing. 202 */ 203 PROCESSING("processing"), 204 205 /** 206 * Warn about unchecked operations on raw types. 207 */ 208 RAW("rawtypes"), 209 210 /** 211 * Warn about Serializable classes that do not provide a serial version ID. 212 */ 213 SERIAL("serial"), 214 215 /** 216 * Warn about issues relating to use of statics 217 */ 218 STATIC("static"), 219 220 /** 221 * Warn about issues relating to use of try blocks (i.e. try-with-resources) 222 */ 223 TRY("try"), 224 225 /** 226 * Warn about unchecked operations on raw types. 227 */ 228 UNCHECKED("unchecked"), 229 230 /** 231 * Warn about potentially unsafe vararg methods 232 */ 233 VARARGS("varargs"); 234 235 LintCategory(String option) { 236 this(option, false); 237 } 238 239 LintCategory(String option, boolean hidden) { 240 this.option = option; 241 this.hidden = hidden; 242 map.put(option, this); 243 } 244 245 static LintCategory get(String option) { 246 return map.get(option); 247 } 248 249 public final String option; 250 public final boolean hidden; 251 } 252 253 /** 254 * Checks if a warning category is enabled. A warning category may be enabled 255 * on the command line, or by default, and can be temporarily disabled with 256 * the SuppressWarnings annotation. 257 */ 258 public boolean isEnabled(LintCategory lc) { 259 return values.contains(lc); 260 } 261 262 /** 263 * Checks is a warning category has been specifically suppressed, by means 264 * of the SuppressWarnings annotation, or, in the case of the deprecated 265 * category, whether it has been implicitly suppressed by virtue of the 266 * current entity being itself deprecated. 267 */ 268 public boolean isSuppressed(LintCategory lc) { 269 return suppressedValues.contains(lc); 270 } 271 272 protected static class AugmentVisitor implements Attribute.Visitor { 273 private final Context context; 274 private Symtab syms; 275 private Lint parent; 276 private Lint lint; 277 278 AugmentVisitor(Context context) { 279 // to break an ugly sequence of initialization dependencies, 280 // we defer the initialization of syms until it is needed 281 this.context = context; 282 } 283 284 Lint augment(Lint parent, Attribute.Compound attr) { 285 initSyms(); 286 this.parent = parent; 287 lint = null; 288 attr.accept(this); 289 return (lint == null ? parent : lint); 290 } 291 292 Lint augment(Lint parent, List<Attribute.Compound> attrs) { 293 initSyms(); 294 this.parent = parent; 295 lint = null; 296 for (Attribute.Compound a: attrs) { 297 a.accept(this); 298 } 299 return (lint == null ? parent : lint); 300 } 301 302 private void initSyms() { 303 if (syms == null) 304 syms = Symtab.instance(context); 305 } 306 307 private void suppress(LintCategory lc) { 308 if (lint == null) 309 lint = new Lint(parent); 310 lint.suppressedValues.add(lc); 311 lint.values.remove(lc); 312 } 313 314 public void visitConstant(Attribute.Constant value) { 315 if (value.type.tsym == syms.stringType.tsym) { 316 LintCategory lc = LintCategory.get((String) (value.value)); 317 if (lc != null) 318 suppress(lc); 319 } 320 } 321 322 public void visitClass(Attribute.Class clazz) { 323 } 324 325 // If we find a @SuppressWarnings annotation, then we continue 326 // walking the tree, in order to suppress the individual warnings 327 // specified in the @SuppressWarnings annotation. 328 public void visitCompound(Attribute.Compound compound) { 329 if (compound.type.tsym == syms.suppressWarningsType.tsym) { 330 for (List<Pair<MethodSymbol,Attribute>> v = compound.values; 331 v.nonEmpty(); v = v.tail) { 332 Pair<MethodSymbol,Attribute> value = v.head; 333 if (value.fst.name.toString().equals("value")) 334 value.snd.accept(this); 335 } 336 337 } 338 } 339 340 public void visitArray(Attribute.Array array) { 341 for (Attribute value : array.values) 342 value.accept(this); 343 } 344 345 public void visitEnum(Attribute.Enum e) { 346 } 347 348 public void visitError(Attribute.Error e) { 349 } 350 } 351 }