src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
changeset 47216 71c04702a3d5
parent 44576 9e18c9ce29e7
child 48054 702043a4cdeb
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2005, 2017, 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.Arrays;
       
    29 import java.util.EnumSet;
       
    30 import java.util.Map;
       
    31 import java.util.concurrent.ConcurrentHashMap;
       
    32 
       
    33 import com.sun.tools.javac.code.Symbol.*;
       
    34 import com.sun.tools.javac.main.Option;
       
    35 import com.sun.tools.javac.util.Context;
       
    36 import com.sun.tools.javac.util.List;
       
    37 import com.sun.tools.javac.util.Options;
       
    38 import com.sun.tools.javac.util.Pair;
       
    39 
       
    40 /**
       
    41  * A class for handling -Xlint suboptions and @SuppresssWarnings.
       
    42  *
       
    43  *  <p><b>This is NOT part of any supported API.
       
    44  *  If you write code that depends on this, you do so at your own risk.
       
    45  *  This code and its internal interfaces are subject to change or
       
    46  *  deletion without notice.</b>
       
    47  */
       
    48 public class Lint
       
    49 {
       
    50     /** The context key for the root Lint object. */
       
    51     protected static final Context.Key<Lint> lintKey = new Context.Key<>();
       
    52 
       
    53     /** Get the root Lint instance. */
       
    54     public static Lint instance(Context context) {
       
    55         Lint instance = context.get(lintKey);
       
    56         if (instance == null)
       
    57             instance = new Lint(context);
       
    58         return instance;
       
    59     }
       
    60 
       
    61     /**
       
    62      * Returns the result of combining the values in this object with
       
    63      * the given annotation.
       
    64      */
       
    65     public Lint augment(Attribute.Compound attr) {
       
    66         return augmentor.augment(this, attr);
       
    67     }
       
    68 
       
    69 
       
    70     /**
       
    71      * Returns the result of combining the values in this object with
       
    72      * the metadata on the given symbol.
       
    73      */
       
    74     public Lint augment(Symbol sym) {
       
    75         Lint l = augmentor.augment(this, sym.getDeclarationAttributes());
       
    76         if (sym.isDeprecated()) {
       
    77             if (l == this)
       
    78                 l = new Lint(this);
       
    79             l.values.remove(LintCategory.DEPRECATION);
       
    80             l.suppressedValues.add(LintCategory.DEPRECATION);
       
    81         }
       
    82         return l;
       
    83     }
       
    84 
       
    85     /**
       
    86      * Returns a new Lint that has the given LintCategorys suppressed.
       
    87      * @param lc one or more categories to be suppressed
       
    88      */
       
    89     public Lint suppress(LintCategory... lc) {
       
    90         Lint l = new Lint(this);
       
    91         l.values.removeAll(Arrays.asList(lc));
       
    92         l.suppressedValues.addAll(Arrays.asList(lc));
       
    93         return l;
       
    94     }
       
    95 
       
    96     private final AugmentVisitor augmentor;
       
    97 
       
    98     private final EnumSet<LintCategory> values;
       
    99     private final EnumSet<LintCategory> suppressedValues;
       
   100 
       
   101     private static final Map<String, LintCategory> map = new ConcurrentHashMap<>(20);
       
   102 
       
   103     protected Lint(Context context) {
       
   104         // initialize values according to the lint options
       
   105         Options options = Options.instance(context);
       
   106 
       
   107         if (options.isSet(Option.XLINT) || options.isSet(Option.XLINT_CUSTOM, "all")) {
       
   108             // If -Xlint or -Xlint:all is given, enable all categories by default
       
   109             values = EnumSet.allOf(LintCategory.class);
       
   110         } else if (options.isSet(Option.XLINT_CUSTOM, "none")) {
       
   111             // if -Xlint:none is given, disable all categories by default
       
   112             values = EnumSet.noneOf(LintCategory.class);
       
   113         } else {
       
   114             // otherwise, enable on-by-default categories
       
   115             values = EnumSet.noneOf(LintCategory.class);
       
   116 
       
   117             Source source = Source.instance(context);
       
   118             if (source.compareTo(Source.JDK1_9) >= 0) {
       
   119                 values.add(LintCategory.DEP_ANN);
       
   120             }
       
   121             values.add(LintCategory.REQUIRES_TRANSITIVE_AUTOMATIC);
       
   122             values.add(LintCategory.OPENS);
       
   123             values.add(LintCategory.MODULE);
       
   124             values.add(LintCategory.REMOVAL);
       
   125         }
       
   126 
       
   127         // Look for specific overrides
       
   128         for (LintCategory lc : LintCategory.values()) {
       
   129             if (options.isSet(Option.XLINT_CUSTOM, lc.option)) {
       
   130                 values.add(lc);
       
   131             } else if (options.isSet(Option.XLINT_CUSTOM, "-" + lc.option)) {
       
   132                 values.remove(lc);
       
   133             }
       
   134         }
       
   135 
       
   136         suppressedValues = EnumSet.noneOf(LintCategory.class);
       
   137 
       
   138         context.put(lintKey, this);
       
   139         augmentor = new AugmentVisitor(context);
       
   140     }
       
   141 
       
   142     protected Lint(Lint other) {
       
   143         this.augmentor = other.augmentor;
       
   144         this.values = other.values.clone();
       
   145         this.suppressedValues = other.suppressedValues.clone();
       
   146     }
       
   147 
       
   148     @Override
       
   149     public String toString() {
       
   150         return "Lint:[values" + values + " suppressedValues" + suppressedValues + "]";
       
   151     }
       
   152 
       
   153     /**
       
   154      * Categories of warnings that can be generated by the compiler.
       
   155      */
       
   156     public enum LintCategory {
       
   157         /**
       
   158          * Warn when code refers to a auxiliary class that is hidden in a source file (ie source file name is
       
   159          * different from the class name, and the type is not properly nested) and the referring code
       
   160          * is not located in the same source file.
       
   161          */
       
   162         AUXILIARYCLASS("auxiliaryclass"),
       
   163 
       
   164         /**
       
   165          * Warn about use of unnecessary casts.
       
   166          */
       
   167         CAST("cast"),
       
   168 
       
   169         /**
       
   170          * Warn about issues related to classfile contents
       
   171          */
       
   172         CLASSFILE("classfile"),
       
   173 
       
   174         /**
       
   175          * Warn about use of deprecated items.
       
   176          */
       
   177         DEPRECATION("deprecation"),
       
   178 
       
   179         /**
       
   180          * Warn about items which are documented with an {@code @deprecated} JavaDoc
       
   181          * comment, but which do not have {@code @Deprecated} annotation.
       
   182          */
       
   183         DEP_ANN("dep-ann"),
       
   184 
       
   185         /**
       
   186          * Warn about division by constant integer 0.
       
   187          */
       
   188         DIVZERO("divzero"),
       
   189 
       
   190         /**
       
   191          * Warn about empty statement after if.
       
   192          */
       
   193         EMPTY("empty"),
       
   194 
       
   195         /**
       
   196          * Warn about issues regarding module exports.
       
   197          */
       
   198         EXPORTS("exports"),
       
   199 
       
   200         /**
       
   201          * Warn about falling through from one case of a switch statement to the next.
       
   202          */
       
   203         FALLTHROUGH("fallthrough"),
       
   204 
       
   205         /**
       
   206          * Warn about finally clauses that do not terminate normally.
       
   207          */
       
   208         FINALLY("finally"),
       
   209 
       
   210         /**
       
   211          * Warn about module system related issues.
       
   212          */
       
   213         MODULE("module"),
       
   214 
       
   215         /**
       
   216          * Warn about issues regarding module opens.
       
   217          */
       
   218         OPENS("opens"),
       
   219 
       
   220         /**
       
   221          * Warn about issues relating to use of command line options
       
   222          */
       
   223         OPTIONS("options"),
       
   224 
       
   225         /**
       
   226          * Warn about issues regarding method overloads.
       
   227          */
       
   228         OVERLOADS("overloads"),
       
   229 
       
   230         /**
       
   231          * Warn about issues regarding method overrides.
       
   232          */
       
   233         OVERRIDES("overrides"),
       
   234 
       
   235         /**
       
   236          * Warn about invalid path elements on the command line.
       
   237          * Such warnings cannot be suppressed with the SuppressWarnings
       
   238          * annotation.
       
   239          */
       
   240         PATH("path"),
       
   241 
       
   242         /**
       
   243          * Warn about issues regarding annotation processing.
       
   244          */
       
   245         PROCESSING("processing"),
       
   246 
       
   247         /**
       
   248          * Warn about unchecked operations on raw types.
       
   249          */
       
   250         RAW("rawtypes"),
       
   251 
       
   252         /**
       
   253          * Warn about use of deprecated-for-removal items.
       
   254          */
       
   255         REMOVAL("removal"),
       
   256 
       
   257         /**
       
   258          * Warn about use of automatic modules in the requires clauses.
       
   259          */
       
   260         REQUIRES_AUTOMATIC("requires-automatic"),
       
   261 
       
   262         /**
       
   263          * Warn about automatic modules in requires transitive.
       
   264          */
       
   265         REQUIRES_TRANSITIVE_AUTOMATIC("requires-transitive-automatic"),
       
   266 
       
   267         /**
       
   268          * Warn about Serializable classes that do not provide a serial version ID.
       
   269          */
       
   270         SERIAL("serial"),
       
   271 
       
   272         /**
       
   273          * Warn about issues relating to use of statics
       
   274          */
       
   275         STATIC("static"),
       
   276 
       
   277         /**
       
   278          * Warn about issues relating to use of try blocks (i.e. try-with-resources)
       
   279          */
       
   280         TRY("try"),
       
   281 
       
   282         /**
       
   283          * Warn about unchecked operations on raw types.
       
   284          */
       
   285         UNCHECKED("unchecked"),
       
   286 
       
   287         /**
       
   288          * Warn about potentially unsafe vararg methods
       
   289          */
       
   290         VARARGS("varargs");
       
   291 
       
   292         LintCategory(String option) {
       
   293             this(option, false);
       
   294         }
       
   295 
       
   296         LintCategory(String option, boolean hidden) {
       
   297             this.option = option;
       
   298             this.hidden = hidden;
       
   299             map.put(option, this);
       
   300         }
       
   301 
       
   302         static LintCategory get(String option) {
       
   303             return map.get(option);
       
   304         }
       
   305 
       
   306         public final String option;
       
   307         public final boolean hidden;
       
   308     }
       
   309 
       
   310     /**
       
   311      * Checks if a warning category is enabled. A warning category may be enabled
       
   312      * on the command line, or by default, and can be temporarily disabled with
       
   313      * the SuppressWarnings annotation.
       
   314      */
       
   315     public boolean isEnabled(LintCategory lc) {
       
   316         return values.contains(lc);
       
   317     }
       
   318 
       
   319     /**
       
   320      * Checks is a warning category has been specifically suppressed, by means
       
   321      * of the SuppressWarnings annotation, or, in the case of the deprecated
       
   322      * category, whether it has been implicitly suppressed by virtue of the
       
   323      * current entity being itself deprecated.
       
   324      */
       
   325     public boolean isSuppressed(LintCategory lc) {
       
   326         return suppressedValues.contains(lc);
       
   327     }
       
   328 
       
   329     protected static class AugmentVisitor implements Attribute.Visitor {
       
   330         private final Context context;
       
   331         private Symtab syms;
       
   332         private Lint parent;
       
   333         private Lint lint;
       
   334 
       
   335         AugmentVisitor(Context context) {
       
   336             // to break an ugly sequence of initialization dependencies,
       
   337             // we defer the initialization of syms until it is needed
       
   338             this.context = context;
       
   339         }
       
   340 
       
   341         Lint augment(Lint parent, Attribute.Compound attr) {
       
   342             initSyms();
       
   343             this.parent = parent;
       
   344             lint = null;
       
   345             attr.accept(this);
       
   346             return (lint == null ? parent : lint);
       
   347         }
       
   348 
       
   349         Lint augment(Lint parent, List<Attribute.Compound> attrs) {
       
   350             initSyms();
       
   351             this.parent = parent;
       
   352             lint = null;
       
   353             for (Attribute.Compound a: attrs) {
       
   354                 a.accept(this);
       
   355             }
       
   356             return (lint == null ? parent : lint);
       
   357         }
       
   358 
       
   359         private void initSyms() {
       
   360             if (syms == null)
       
   361                 syms = Symtab.instance(context);
       
   362         }
       
   363 
       
   364         private void suppress(LintCategory lc) {
       
   365             if (lint == null)
       
   366                 lint = new Lint(parent);
       
   367             lint.suppressedValues.add(lc);
       
   368             lint.values.remove(lc);
       
   369         }
       
   370 
       
   371         public void visitConstant(Attribute.Constant value) {
       
   372             if (value.type.tsym == syms.stringType.tsym) {
       
   373                 LintCategory lc = LintCategory.get((String) (value.value));
       
   374                 if (lc != null)
       
   375                     suppress(lc);
       
   376             }
       
   377         }
       
   378 
       
   379         public void visitClass(Attribute.Class clazz) {
       
   380         }
       
   381 
       
   382         // If we find a @SuppressWarnings annotation, then we continue
       
   383         // walking the tree, in order to suppress the individual warnings
       
   384         // specified in the @SuppressWarnings annotation.
       
   385         public void visitCompound(Attribute.Compound compound) {
       
   386             if (compound.type.tsym == syms.suppressWarningsType.tsym) {
       
   387                 for (List<Pair<MethodSymbol,Attribute>> v = compound.values;
       
   388                      v.nonEmpty(); v = v.tail) {
       
   389                     Pair<MethodSymbol,Attribute> value = v.head;
       
   390                     if (value.fst.name.toString().equals("value"))
       
   391                         value.snd.accept(this);
       
   392                 }
       
   393 
       
   394             }
       
   395         }
       
   396 
       
   397         public void visitArray(Attribute.Array array) {
       
   398             for (Attribute value : array.values)
       
   399                 value.accept(this);
       
   400         }
       
   401 
       
   402         public void visitEnum(Attribute.Enum e) {
       
   403         }
       
   404 
       
   405         public void visitError(Attribute.Error e) {
       
   406         }
       
   407     }
       
   408 }