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