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