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