Lint.java revision 3641:af5eb8f3ffd2
1183840Sraj/* 2239277Sgonzo * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. 3183840Sraj * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4183840Sraj * 5183840Sraj * This code is free software; you can redistribute it and/or modify it 6183840Sraj * under the terms of the GNU General Public License version 2 only, as 7183840Sraj * published by the Free Software Foundation. Oracle designates this 8183840Sraj * particular file as subject to the "Classpath" exception as provided 9183840Sraj * by Oracle in the LICENSE file that accompanied this code. 10183840Sraj * 11183840Sraj * This code is distributed in the hope that it will be useful, but WITHOUT 12183840Sraj * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13183840Sraj * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14183840Sraj * version 2 for more details (a copy is included in the LICENSE file that 15183840Sraj * accompanied this code). 16183840Sraj * 17183840Sraj * You should have received a copy of the GNU General Public License version 18183840Sraj * 2 along with this work; if not, write to the Free Software Foundation, 19183840Sraj * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20183840Sraj * 21183840Sraj * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22183840Sraj * or visit www.oracle.com if you need additional information or have any 23183840Sraj * questions. 24183840Sraj */ 25183840Sraj 26183840Srajpackage com.sun.tools.javac.code; 27183840Sraj 28183840Srajimport java.util.EnumSet; 29183840Srajimport java.util.Map; 30183840Srajimport java.util.concurrent.ConcurrentHashMap; 31183840Sraj 32183840Srajimport com.sun.tools.javac.code.Symbol.*; 33183840Srajimport com.sun.tools.javac.util.Context; 34183840Srajimport com.sun.tools.javac.util.List; 35183840Srajimport com.sun.tools.javac.util.Options; 36183840Srajimport com.sun.tools.javac.util.Pair; 37294426Szbb 38294426Szbb/** 39183840Sraj * A class for handling -Xlint suboptions and @SuppresssWarnings. 40183840Sraj * 41183840Sraj * <p><b>This is NOT part of any supported API. 42183840Sraj * If you write code that depends on this, you do so at your own risk. 43183840Sraj * This code and its internal interfaces are subject to change or 44183840Sraj * deletion without notice.</b> 45183840Sraj */ 46183840Srajpublic class Lint 47183840Sraj{ 48183840Sraj /** The context key for the root Lint object. */ 49183840Sraj protected static final Context.Key<Lint> lintKey = new Context.Key<>(); 50183840Sraj 51239277Sgonzo /** Get the root Lint instance. */ 52239277Sgonzo public static Lint instance(Context context) { 53239277Sgonzo Lint instance = context.get(lintKey); 54183840Sraj if (instance == null) 55239277Sgonzo instance = new Lint(context); 56183840Sraj return instance; 57183840Sraj } 58183840Sraj 59239277Sgonzo /** 60239277Sgonzo * Returns the result of combining the values in this object with 61239277Sgonzo * the given annotation. 62239277Sgonzo */ 63239277Sgonzo public Lint augment(Attribute.Compound attr) { 64239277Sgonzo return augmentor.augment(this, attr); 65239277Sgonzo } 66239277Sgonzo 67239277Sgonzo 68239277Sgonzo /** 69239277Sgonzo * Returns the result of combining the values in this object with 70296825Swma * the metadata on the given symbol. 71296825Swma */ 72296825Swma public Lint augment(Symbol sym) { 73296825Swma Lint l = augmentor.augment(this, sym.getDeclarationAttributes()); 74239277Sgonzo if (sym.isDeprecated()) { 75239277Sgonzo if (l == this) 76239277Sgonzo l = new Lint(this); 77239277Sgonzo l.values.remove(LintCategory.DEPRECATION); 78183840Sraj l.suppressedValues.add(LintCategory.DEPRECATION); 79183840Sraj } 80183840Sraj return l; 81239277Sgonzo } 82239277Sgonzo 83183840Sraj /** 84183840Sraj * Returns a new Lint that has the given LintCategory suppressed. 85183840Sraj */ 86183840Sraj public Lint suppress(LintCategory lc) { 87239277Sgonzo Lint l = new Lint(this); 88239277Sgonzo l.values.remove(lc); 89239277Sgonzo l.suppressedValues.add(lc); 90239277Sgonzo return l; 91239277Sgonzo } 92239277Sgonzo 93239277Sgonzo private final AugmentVisitor augmentor; 94239277Sgonzo 95239277Sgonzo private final EnumSet<LintCategory> values; 96239277Sgonzo private final EnumSet<LintCategory> suppressedValues; 97239277Sgonzo 98239277Sgonzo private static final Map<String, LintCategory> map = new ConcurrentHashMap<>(20); 99239277Sgonzo 100239277Sgonzo protected Lint(Context context) { 101239277Sgonzo // initialize values according to the lint options 102239277Sgonzo Options options = Options.instance(context); 103183840Sraj values = EnumSet.noneOf(LintCategory.class); 104183840Sraj for (Map.Entry<String, LintCategory> e: map.entrySet()) { 105183840Sraj if (options.lint(e.getKey())) 106183840Sraj values.add(e.getValue()); 107183840Sraj } 108183840Sraj 109183840Sraj suppressedValues = EnumSet.noneOf(LintCategory.class); 110183840Sraj 111183840Sraj context.put(lintKey, this); 112183840Sraj augmentor = new AugmentVisitor(context); 113183840Sraj } 114239277Sgonzo 115183840Sraj protected Lint(Lint other) { 116239277Sgonzo this.augmentor = other.augmentor; 117239277Sgonzo this.values = other.values.clone(); 118239277Sgonzo this.suppressedValues = other.suppressedValues.clone(); 119239277Sgonzo } 120239277Sgonzo 121239277Sgonzo @Override 122239277Sgonzo public String toString() { 123239277Sgonzo return "Lint:[values" + values + " suppressedValues" + suppressedValues + "]"; 124239277Sgonzo } 125239277Sgonzo 126239277Sgonzo /** 127239277Sgonzo * Categories of warnings that can be generated by the compiler. 128183840Sraj */ 129183840Sraj public enum LintCategory { 130183840Sraj /** 131294416Szbb * Warn when code refers to a auxiliary class that is hidden in a source file (ie source file name is 132240488Sgber * different from the class name, and the type is not properly nested) and the referring code 133294436Szbb * is not located in the same source file. 134240488Sgber */ 135240488Sgber AUXILIARYCLASS("auxiliaryclass"), 136240488Sgber 137240488Sgber /** 138240488Sgber * Warn about use of unnecessary casts. 139240488Sgber */ 140240488Sgber CAST("cast"), 141183840Sraj 142183840Sraj /** 143183840Sraj * Warn about issues related to classfile contents 144183840Sraj */ 145183840Sraj CLASSFILE("classfile"), 146240488Sgber 147183840Sraj /** 148183840Sraj * Warn about use of deprecated items. 149183840Sraj */ 150183840Sraj DEPRECATION("deprecation"), 151256760Srrs 152256760Srrs /** 153256760Srrs * Warn about items which are documented with an {@code @deprecated} JavaDoc 154183840Sraj * comment, but which do not have {@code @Deprecated} annotation. 155256760Srrs */ 156183840Sraj DEP_ANN("dep-ann"), 157196532Sraj 158183840Sraj /** 159183840Sraj * Warn about division by constant integer 0. 160183840Sraj */ 161183840Sraj DIVZERO("divzero"), 162183840Sraj 163183840Sraj /** 164183840Sraj * Warn about empty statement after if. 165183840Sraj */ 166183840Sraj EMPTY("empty"), 167183840Sraj 168183840Sraj /** 169183840Sraj * Warn about issues regarding module exports. 170183840Sraj */ 171183840Sraj EXPORTS("exports"), 172183840Sraj 173183840Sraj /** 174196532Sraj * Warn about falling through from one case of a switch statement to the next. 175196532Sraj */ 176196532Sraj FALLTHROUGH("fallthrough"), 177196532Sraj 178196532Sraj /** 179209131Sraj * Warn about finally clauses that do not terminate normally. 180209131Sraj */ 181209131Sraj FINALLY("finally"), 182183840Sraj 183183840Sraj /** 184183840Sraj * Warn about issues relating to use of command line options 185183840Sraj */ 186183840Sraj OPTIONS("options"), 187183840Sraj 188183840Sraj /** 189183840Sraj * Warn about issues regarding method overloads. 190183840Sraj */ 191183840Sraj OVERLOADS("overloads"), 192183840Sraj 193183840Sraj /** 194183840Sraj * Warn about issues regarding method overrides. 195183840Sraj */ 196183840Sraj OVERRIDES("overrides"), 197183840Sraj 198183840Sraj /** 199183840Sraj * Warn about invalid path elements on the command line. 200183840Sraj * Such warnings cannot be suppressed with the SuppressWarnings 201183840Sraj * annotation. 202183840Sraj */ 203183840Sraj PATH("path"), 204196532Sraj 205196532Sraj /** 206209131Sraj * Warn about issues regarding annotation processing. 207209131Sraj */ 208196532Sraj PROCESSING("processing"), 209196532Sraj 210196532Sraj /** 211196532Sraj * Warn about unchecked operations on raw types. 212196532Sraj */ 213196532Sraj RAW("rawtypes"), 214209131Sraj 215183840Sraj /** 216183840Sraj * Warn about Serializable classes that do not provide a serial version ID. 217183840Sraj */ 218183840Sraj SERIAL("serial"), 219183840Sraj 220239277Sgonzo /** 221183840Sraj * Warn about issues relating to use of statics 222183840Sraj */ 223183840Sraj STATIC("static"), 224183840Sraj 225183840Sraj /** 226294436Szbb * Warn about issues relating to use of try blocks (i.e. try-with-resources) 227294436Szbb */ 228294436Szbb TRY("try"), 229294436Szbb 230251371Sgber /** 231251371Sgber * Warn about unchecked operations on raw types. 232251371Sgber */ 233251371Sgber UNCHECKED("unchecked"), 234183840Sraj 235183840Sraj /** 236183840Sraj * Warn about potentially unsafe vararg methods 237183840Sraj */ 238194845Sraj VARARGS("varargs"); 239194845Sraj 240194845Sraj LintCategory(String option) { 241194845Sraj this(option, false); 242194845Sraj } 243194845Sraj 244194845Sraj LintCategory(String option, boolean hidden) { 245194845Sraj this.option = option; 246194845Sraj this.hidden = hidden; 247194845Sraj map.put(option, this); 248194845Sraj } 249194845Sraj 250194845Sraj static LintCategory get(String option) { 251194845Sraj return map.get(option); 252194845Sraj } 253194845Sraj 254239277Sgonzo public final String option; 255239277Sgonzo public final boolean hidden; 256239277Sgonzo } 257239277Sgonzo 258239277Sgonzo /** 259239277Sgonzo * Checks if a warning category is enabled. A warning category may be enabled 260239277Sgonzo * on the command line, or by default, and can be temporarily disabled with 261239277Sgonzo * the SuppressWarnings annotation. 262239277Sgonzo */ 263194845Sraj public boolean isEnabled(LintCategory lc) { 264194845Sraj return values.contains(lc); 265194845Sraj } 266194845Sraj 267194845Sraj /** 268194845Sraj * Checks is a warning category has been specifically suppressed, by means 269194845Sraj * of the SuppressWarnings annotation, or, in the case of the deprecated 270194845Sraj * category, whether it has been implicitly suppressed by virtue of the 271194845Sraj * current entity being itself deprecated. 272194845Sraj */ 273194845Sraj public boolean isSuppressed(LintCategory lc) { 274194845Sraj return suppressedValues.contains(lc); 275194845Sraj } 276194845Sraj 277194845Sraj protected static class AugmentVisitor implements Attribute.Visitor { 278194845Sraj private final Context context; 279194845Sraj private Symtab syms; 280194845Sraj private Lint parent; 281194845Sraj private Lint lint; 282194845Sraj 283194845Sraj AugmentVisitor(Context context) { 284194845Sraj // to break an ugly sequence of initialization dependencies, 285194845Sraj // we defer the initialization of syms until it is needed 286194845Sraj this.context = context; 287194845Sraj } 288194845Sraj 289194845Sraj Lint augment(Lint parent, Attribute.Compound attr) { 290194845Sraj initSyms(); 291194845Sraj this.parent = parent; 292194845Sraj lint = null; 293194845Sraj attr.accept(this); 294194845Sraj return (lint == null ? parent : lint); 295194845Sraj } 296194845Sraj 297194845Sraj Lint augment(Lint parent, List<Attribute.Compound> attrs) { 298194845Sraj initSyms(); 299194845Sraj this.parent = parent; 300194845Sraj lint = null; 301194845Sraj for (Attribute.Compound a: attrs) { 302194845Sraj a.accept(this); 303194845Sraj } 304194845Sraj return (lint == null ? parent : lint); 305194845Sraj } 306194845Sraj 307194845Sraj private void initSyms() { 308194845Sraj if (syms == null) 309194845Sraj syms = Symtab.instance(context); 310194845Sraj } 311194845Sraj 312194845Sraj private void suppress(LintCategory lc) { 313194845Sraj if (lint == null) 314194845Sraj lint = new Lint(parent); 315183840Sraj lint.suppressedValues.add(lc); 316183840Sraj lint.values.remove(lc); 317183840Sraj } 318183840Sraj 319183840Sraj public void visitConstant(Attribute.Constant value) { 320183840Sraj if (value.type.tsym == syms.stringType.tsym) { 321183840Sraj LintCategory lc = LintCategory.get((String) (value.value)); 322183840Sraj if (lc != null) 323183840Sraj suppress(lc); 324183840Sraj } 325183840Sraj } 326183840Sraj 327183840Sraj public void visitClass(Attribute.Class clazz) { 328183840Sraj } 329183840Sraj 330183840Sraj // If we find a @SuppressWarnings annotation, then we continue 331183840Sraj // walking the tree, in order to suppress the individual warnings 332183840Sraj // specified in the @SuppressWarnings annotation. 333183840Sraj public void visitCompound(Attribute.Compound compound) { 334183840Sraj if (compound.type.tsym == syms.suppressWarningsType.tsym) { 335183840Sraj for (List<Pair<MethodSymbol,Attribute>> v = compound.values; 336183840Sraj v.nonEmpty(); v = v.tail) { 337183840Sraj Pair<MethodSymbol,Attribute> value = v.head; 338209131Sraj if (value.fst.name.toString().equals("value")) 339209131Sraj value.snd.accept(this); 340209131Sraj } 341209131Sraj 342209131Sraj } 343209131Sraj } 344209131Sraj 345209131Sraj public void visitArray(Attribute.Array array) { 346183840Sraj for (Attribute value : array.values) 347183840Sraj value.accept(this); 348183840Sraj } 349183840Sraj 350183840Sraj public void visitEnum(Attribute.Enum e) { 351239277Sgonzo } 352183840Sraj 353186899Sraj public void visitError(Attribute.Error e) { 354183840Sraj } 355243580Smarcel } 356243580Smarcel} 357294416Szbb