duke@1: /* ohair@554: * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as ohair@554: * published by the Free Software Foundation. Oracle designates this duke@1: * particular file as subject to the "Classpath" exception as provided ohair@554: * by Oracle in the LICENSE file that accompanied this code. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. duke@1: */ duke@1: duke@1: package com.sun.tools.javac.code; duke@1: duke@1: import java.util.EnumSet; duke@1: import java.util.HashMap; duke@1: import java.util.Map; duke@1: import com.sun.tools.javac.code.Symbol.*; duke@1: import com.sun.tools.javac.util.Context; duke@1: import com.sun.tools.javac.util.List; duke@1: import com.sun.tools.javac.util.Options; duke@1: import com.sun.tools.javac.util.Pair; duke@1: import static com.sun.tools.javac.code.Flags.*; duke@1: duke@1: duke@1: /** duke@1: * A class for handling -Xlint suboptions and @SuppresssWarnings. duke@1: * jjg@581: *

This is NOT part of any supported API. jjg@581: * If you write code that depends on this, you do so at your own risk. duke@1: * This code and its internal interfaces are subject to change or duke@1: * deletion without notice. duke@1: */ duke@1: public class Lint duke@1: { duke@1: /** The context key for the root Lint object. */ duke@1: protected static final Context.Key lintKey = new Context.Key(); duke@1: duke@1: /** Get the root Lint instance. */ duke@1: public static Lint instance(Context context) { duke@1: Lint instance = context.get(lintKey); duke@1: if (instance == null) duke@1: instance = new Lint(context); duke@1: return instance; duke@1: } duke@1: duke@1: /** duke@1: * Returns the result of combining the values in this object with duke@1: * the given annotation. duke@1: */ duke@1: public Lint augment(Attribute.Compound attr) { duke@1: return augmentor.augment(this, attr); duke@1: } duke@1: duke@1: duke@1: /** duke@1: * Returns the result of combining the values in this object with duke@1: * the given annotations. duke@1: */ duke@1: public Lint augment(List attrs) { duke@1: return augmentor.augment(this, attrs); duke@1: } duke@1: duke@1: /** duke@1: * Returns the result of combining the values in this object with duke@1: * the given annotations and flags. duke@1: */ duke@1: public Lint augment(List attrs, long flags) { duke@1: Lint l = augmentor.augment(this, attrs); duke@1: if ((flags & DEPRECATED) != 0) { duke@1: if (l == this) duke@1: l = new Lint(this); duke@1: l.values.remove(LintCategory.DEPRECATION); duke@1: l.suppressedValues.add(LintCategory.DEPRECATION); duke@1: } duke@1: return l; duke@1: } duke@1: duke@1: duke@1: private final AugmentVisitor augmentor; duke@1: duke@1: private final EnumSet values; duke@1: private final EnumSet suppressedValues; duke@1: duke@1: private static Map map = new HashMap(); duke@1: duke@1: duke@1: protected Lint(Context context) { duke@1: // initialize values according to the lint options duke@1: Options options = Options.instance(context); duke@1: values = EnumSet.noneOf(LintCategory.class); duke@1: for (Map.Entry e: map.entrySet()) { duke@1: if (options.lint(e.getKey())) duke@1: values.add(e.getValue()); duke@1: } duke@1: duke@1: suppressedValues = EnumSet.noneOf(LintCategory.class); duke@1: duke@1: context.put(lintKey, this); duke@1: augmentor = new AugmentVisitor(context); duke@1: } duke@1: duke@1: protected Lint(Lint other) { duke@1: this.augmentor = other.augmentor; duke@1: this.values = other.values.clone(); duke@1: this.suppressedValues = other.suppressedValues.clone(); duke@1: } duke@1: jjg@612: @Override duke@1: public String toString() { duke@1: return "Lint:[values" + values + " suppressedValues" + suppressedValues + "]"; duke@1: } duke@1: duke@1: /** duke@1: * Categories of warnings that can be generated by the compiler. duke@1: */ duke@1: public enum LintCategory { duke@1: /** duke@1: * Warn about use of unnecessary casts. duke@1: */ duke@1: CAST("cast"), duke@1: duke@1: /** duke@1: * Warn about use of deprecated items. duke@1: */ duke@1: DEPRECATION("deprecation"), duke@1: duke@1: /** duke@1: * Warn about items which are documented with an {@code @deprecated} JavaDoc duke@1: * comment, but which do not have {@code @Deprecated} annotation. duke@1: */ duke@1: DEP_ANN("dep-ann"), duke@1: duke@1: /** duke@1: * Warn about division by constant integer 0. duke@1: */ duke@1: DIVZERO("divzero"), duke@1: duke@1: /** duke@1: * Warn about empty statement after if. duke@1: */ duke@1: EMPTY("empty"), duke@1: duke@1: /** duke@1: * Warn about falling through from one case of a switch statement to the next. duke@1: */ duke@1: FALLTHROUGH("fallthrough"), duke@1: duke@1: /** duke@1: * Warn about finally clauses that do not terminate normally. duke@1: */ duke@1: FINALLY("finally"), duke@1: duke@1: /** duke@1: * Warn about issues regarding method overrides. duke@1: */ duke@1: OVERRIDES("overrides"), duke@1: duke@1: /** duke@1: * Warn about invalid path elements on the command line. duke@1: * Such warnings cannot be suppressed with the SuppressWarnings duke@1: * annotation. duke@1: */ duke@1: PATH("path"), duke@1: duke@1: /** martin@124: * Warn about issues regarding annotation processing. martin@124: */ martin@124: PROCESSING("processing"), martin@124: martin@124: /** duke@1: * Warn about Serializable classes that do not provide a serial version ID. duke@1: */ duke@1: SERIAL("serial"), duke@1: duke@1: /** duke@1: * Warn about unchecked operations on raw types. duke@1: */ mcimadamore@122: UNCHECKED("unchecked"), mcimadamore@122: mcimadamore@122: /** mcimadamore@122: * Warn about unchecked operations on raw types. mcimadamore@122: */ jjg@377: RAW("rawtypes"), jjg@377: jjg@377: /** jjg@582: * Warn about proprietary API that may be removed in a future release. jjg@377: */ jjg@505: SUNAPI("sunapi", true), jjg@505: jjg@505: /** jjg@505: * Warn about issues relating to use of statics jjg@505: */ mcimadamore@580: STATIC("static"), mcimadamore@580: mcimadamore@580: /** mcimadamore@580: * Warn about potentially unsafe vararg methods mcimadamore@580: */ darcy@609: VARARGS("varargs"), darcy@609: darcy@609: /** darcy@609: * Warn about arm resources darcy@609: */ darcy@609: ARM("arm"); duke@1: duke@1: LintCategory(String option) { jjg@377: this(option, false); jjg@377: } jjg@377: jjg@377: LintCategory(String option, boolean hidden) { duke@1: this.option = option; jjg@377: this.hidden = hidden; duke@1: map.put(option, this); duke@1: } duke@1: duke@1: static LintCategory get(String option) { duke@1: return map.get(option); duke@1: } duke@1: jjg@11: public final String option; jjg@377: public final boolean hidden; duke@1: }; duke@1: duke@1: /** duke@1: * Checks if a warning category is enabled. A warning category may be enabled duke@1: * on the command line, or by default, and can be temporarily disabled with duke@1: * the SuppressWarnings annotation. duke@1: */ duke@1: public boolean isEnabled(LintCategory lc) { duke@1: return values.contains(lc); duke@1: } duke@1: duke@1: /** duke@1: * Checks is a warning category has been specifically suppressed, by means duke@1: * of the SuppressWarnings annotation, or, in the case of the deprecated duke@1: * category, whether it has been implicitly suppressed by virtue of the duke@1: * current entity being itself deprecated. duke@1: */ duke@1: public boolean isSuppressed(LintCategory lc) { duke@1: return suppressedValues.contains(lc); duke@1: } duke@1: duke@1: protected static class AugmentVisitor implements Attribute.Visitor { duke@1: private final Context context; duke@1: private Symtab syms; duke@1: private Lint parent; duke@1: private Lint lint; duke@1: duke@1: AugmentVisitor(Context context) { duke@1: // to break an ugly sequence of initialization dependencies, duke@1: // we defer the initialization of syms until it is needed duke@1: this.context = context; duke@1: } duke@1: duke@1: Lint augment(Lint parent, Attribute.Compound attr) { duke@1: initSyms(); duke@1: this.parent = parent; duke@1: lint = null; duke@1: attr.accept(this); duke@1: return (lint == null ? parent : lint); duke@1: } duke@1: duke@1: Lint augment(Lint parent, List attrs) { duke@1: initSyms(); duke@1: this.parent = parent; duke@1: lint = null; duke@1: for (Attribute.Compound a: attrs) { duke@1: a.accept(this); duke@1: } duke@1: return (lint == null ? parent : lint); duke@1: } duke@1: duke@1: private void initSyms() { duke@1: if (syms == null) duke@1: syms = Symtab.instance(context); duke@1: } duke@1: duke@1: private void suppress(LintCategory lc) { duke@1: if (lint == null) duke@1: lint = new Lint(parent); duke@1: lint.suppressedValues.add(lc); duke@1: lint.values.remove(lc); duke@1: } duke@1: duke@1: public void visitConstant(Attribute.Constant value) { duke@1: if (value.type.tsym == syms.stringType.tsym) { duke@1: LintCategory lc = LintCategory.get((String) (value.value)); duke@1: if (lc != null) duke@1: suppress(lc); duke@1: } duke@1: } duke@1: duke@1: public void visitClass(Attribute.Class clazz) { duke@1: } duke@1: duke@1: // If we find a @SuppressWarnings annotation, then we continue duke@1: // walking the tree, in order to suppress the individual warnings duke@1: // specified in the @SuppressWarnings annotation. duke@1: public void visitCompound(Attribute.Compound compound) { duke@1: if (compound.type.tsym == syms.suppressWarningsType.tsym) { duke@1: for (List> v = compound.values; duke@1: v.nonEmpty(); v = v.tail) { duke@1: Pair value = v.head; duke@1: if (value.fst.name.toString().equals("value")) duke@1: value.snd.accept(this); duke@1: } duke@1: duke@1: } duke@1: } duke@1: duke@1: public void visitArray(Attribute.Array array) { duke@1: for (Attribute value : array.values) duke@1: value.accept(this); duke@1: } duke@1: duke@1: public void visitEnum(Attribute.Enum e) { duke@1: } duke@1: duke@1: public void visitError(Attribute.Error e) { duke@1: } duke@1: }; duke@1: }