test/tools/javac/varargs/warning/Warn5.java

Mon, 14 Nov 2011 15:11:10 -0800

author
ksrini
date
Mon, 14 Nov 2011 15:11:10 -0800
changeset 1138
7375d4979bd3
parent 1108
b5d0b8effc85
child 1482
954541f13717
permissions
-rw-r--r--

7106166: (javac) re-factor EndPos parser
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2010, 2011, 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.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  */
    24 /**
    25  * @test
    26  * @bug     6993978 7097436
    27  * @summary Project Coin: Annotation to reduce varargs warnings
    28  * @author  mcimadamore
    29  * @run main Warn5
    30  */
    31 import com.sun.source.util.JavacTask;
    32 import com.sun.tools.javac.api.JavacTool;
    33 import java.net.URI;
    34 import java.util.Arrays;
    35 import java.util.EnumSet;
    36 import javax.tools.Diagnostic;
    37 import javax.tools.JavaCompiler;
    38 import javax.tools.JavaFileObject;
    39 import javax.tools.SimpleJavaFileObject;
    40 import javax.tools.StandardJavaFileManager;
    41 import javax.tools.ToolProvider;
    43 public class Warn5 {
    45     enum XlintOption {
    46         NONE("none"),
    47         ALL("all");
    49         String opt;
    51         XlintOption(String opt) {
    52             this.opt = opt;
    53         }
    55         String getXlintOption() {
    56             return "-Xlint:" + opt;
    57         }
    58     }
    60     enum TrustMe {
    61         DONT_TRUST(""),
    62         TRUST("@java.lang.SafeVarargs");
    64         String anno;
    66         TrustMe(String anno) {
    67             this.anno = anno;
    68         }
    69     }
    71     enum SuppressLevel {
    72         NONE,
    73         VARARGS;
    75         String getSuppressAnno() {
    76             return this == VARARGS ?
    77                 "@SuppressWarnings(\"varargs\")" :
    78                 "";
    79         }
    80     }
    82     enum ModifierKind {
    83         NONE(""),
    84         FINAL("final"),
    85         STATIC("static");
    87         String mod;
    89         ModifierKind(String mod) {
    90             this.mod = mod;
    91         }
    92     }
    94     enum MethodKind {
    95         METHOD("void m"),
    96         CONSTRUCTOR("Test");
    98         String name;
   100         MethodKind(String name) {
   101             this.name = name;
   102         }
   103     }
   105     enum SourceLevel {
   106         JDK_6("6"),
   107         JDK_7("7");
   109         String sourceKey;
   111         SourceLevel(String sourceKey) {
   112             this.sourceKey = sourceKey;
   113         }
   114     }
   116     enum SignatureKind {
   117         VARARGS_X("#K <X>#N(X... x)", false, true),
   118         VARARGS_STRING("#K #N(String... x)", true, true),
   119         ARRAY_X("#K <X>#N(X[] x)", false, false),
   120         ARRAY_STRING("#K #N(String[] x)", true, false);
   122         String stub;
   123         boolean isReifiableArg;
   124         boolean isVarargs;
   126         SignatureKind(String stub, boolean isReifiableArg, boolean isVarargs) {
   127             this.stub = stub;
   128             this.isReifiableArg = isReifiableArg;
   129             this.isVarargs = isVarargs;
   130         }
   132         String getSignature(ModifierKind modKind, MethodKind methKind) {
   133             return methKind != MethodKind.CONSTRUCTOR ?
   134                 stub.replace("#K", modKind.mod).replace("#N", methKind.name) :
   135                 stub.replace("#K", "").replace("#N", methKind.name);
   136         }
   137     }
   139     enum BodyKind {
   140         ASSIGN("Object o = x;", true),
   141         CAST("Object o = (Object)x;", true),
   142         METH("test(x);", true),
   143         PRINT("System.out.println(x.toString());", false),
   144         ARRAY_ASSIGN("Object[] o = x;", true),
   145         ARRAY_CAST("Object[] o = (Object[])x;", true),
   146         ARRAY_METH("testArr(x);", true);
   148         String body;
   149         boolean hasAliasing;
   151         BodyKind(String body, boolean hasAliasing) {
   152             this.body = body;
   153             this.hasAliasing = hasAliasing;
   154         }
   155     }
   157     enum WarningKind {
   158         UNSAFE_BODY,
   159         UNSAFE_DECL,
   160         MALFORMED_SAFEVARARGS,
   161         REDUNDANT_SAFEVARARGS;
   162     }
   164     // Create a single file manager and reuse it for each compile to save time.
   165     static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null);
   167     public static void main(String... args) throws Exception {
   168         for (SourceLevel sourceLevel : SourceLevel.values()) {
   169             for (XlintOption xlint : XlintOption.values()) {
   170                 for (TrustMe trustMe : TrustMe.values()) {
   171                     for (SuppressLevel suppressLevel : SuppressLevel.values()) {
   172                         for (ModifierKind modKind : ModifierKind.values()) {
   173                             for (MethodKind methKind : MethodKind.values()) {
   174                                 for (SignatureKind sig : SignatureKind.values()) {
   175                                     for (BodyKind body : BodyKind.values()) {
   176                                         new Warn5(sourceLevel,
   177                                                 xlint,
   178                                                 trustMe,
   179                                                 suppressLevel,
   180                                                 modKind,
   181                                                 methKind,
   182                                                 sig,
   183                                                 body).test();
   184                                     }
   185                                 }
   186                             }
   187                         }
   188                     }
   189                 }
   190             }
   191         }
   192     }
   194     final SourceLevel sourceLevel;
   195     final XlintOption xlint;
   196     final TrustMe trustMe;
   197     final SuppressLevel suppressLevel;
   198     final ModifierKind modKind;
   199     final MethodKind methKind;
   200     final SignatureKind sig;
   201     final BodyKind body;
   202     final JavaSource source;
   203     final DiagnosticChecker dc;
   205     public Warn5(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind, MethodKind methKind, SignatureKind sig, BodyKind body) {
   206         this.sourceLevel = sourceLevel;
   207         this.xlint = xlint;
   208         this.trustMe = trustMe;
   209         this.suppressLevel = suppressLevel;
   210         this.modKind = modKind;
   211         this.methKind = methKind;
   212         this.sig = sig;
   213         this.body = body;
   214         this.source = new JavaSource();
   215         this.dc = new DiagnosticChecker();
   216     }
   218     void test() throws Exception {
   219         final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
   220         JavacTask ct = (JavacTask)tool.getTask(null, fm, dc,
   221                 Arrays.asList(xlint.getXlintOption(), "-source", sourceLevel.sourceKey), null, Arrays.asList(source));
   222         ct.analyze();
   223         check();
   224     }
   226     void check() {
   228         EnumSet<WarningKind> expectedWarnings = EnumSet.noneOf(WarningKind.class);
   230         if (sourceLevel == SourceLevel.JDK_7 &&
   231                 trustMe == TrustMe.TRUST &&
   232                 suppressLevel != SuppressLevel.VARARGS &&
   233                 xlint != XlintOption.NONE &&
   234                 sig.isVarargs && !sig.isReifiableArg && body.hasAliasing &&
   235                 (methKind == MethodKind.CONSTRUCTOR || (methKind == MethodKind.METHOD && modKind != ModifierKind.NONE))) {
   236             expectedWarnings.add(WarningKind.UNSAFE_BODY);
   237         }
   239         if (sourceLevel == SourceLevel.JDK_7 &&
   240                 trustMe == TrustMe.DONT_TRUST &&
   241                 sig.isVarargs &&
   242                 !sig.isReifiableArg &&
   243                 xlint == XlintOption.ALL) {
   244             expectedWarnings.add(WarningKind.UNSAFE_DECL);
   245         }
   247         if (sourceLevel == SourceLevel.JDK_7 &&
   248                 trustMe == TrustMe.TRUST &&
   249                 (!sig.isVarargs ||
   250                 (modKind == ModifierKind.NONE && methKind == MethodKind.METHOD))) {
   251             expectedWarnings.add(WarningKind.MALFORMED_SAFEVARARGS);
   252         }
   254         if (sourceLevel == SourceLevel.JDK_7 &&
   255                 trustMe == TrustMe.TRUST &&
   256                 xlint != XlintOption.NONE &&
   257                 suppressLevel != SuppressLevel.VARARGS &&
   258                 (modKind != ModifierKind.NONE || methKind == MethodKind.CONSTRUCTOR) &&
   259                 sig.isVarargs &&
   260                 sig.isReifiableArg) {
   261             expectedWarnings.add(WarningKind.REDUNDANT_SAFEVARARGS);
   262         }
   264         if (!expectedWarnings.containsAll(dc.warnings) ||
   265                 !dc.warnings.containsAll(expectedWarnings)) {
   266             throw new Error("invalid diagnostics for source:\n" +
   267                     source.getCharContent(true) +
   268                     "\nOptions: " + xlint.getXlintOption() +
   269                     "\nExpected warnings: " + expectedWarnings +
   270                     "\nFound warnings: " + dc.warnings);
   271         }
   272     }
   274     class JavaSource extends SimpleJavaFileObject {
   276         String template = "import com.sun.tools.javac.api.*;\n" +
   277                           "import java.util.List;\n" +
   278                           "class Test {\n" +
   279                           "   static void test(Object o) {}\n" +
   280                           "   static void testArr(Object[] o) {}\n" +
   281                           "   #T \n #S #M { #B }\n" +
   282                           "}\n";
   284         String source;
   286         public JavaSource() {
   287             super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
   288             source = template.replace("#T", trustMe.anno).
   289                     replace("#S", suppressLevel.getSuppressAnno()).
   290                     replace("#M", sig.getSignature(modKind, methKind)).
   291                     replace("#B", body.body);
   292         }
   294         @Override
   295         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   296             return source;
   297         }
   298     }
   300     class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
   302         EnumSet<WarningKind> warnings = EnumSet.noneOf(WarningKind.class);
   304         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   305             if (diagnostic.getKind() == Diagnostic.Kind.WARNING) {
   306                     if (diagnostic.getCode().contains("unsafe.use.varargs.param")) {
   307                         setWarning(WarningKind.UNSAFE_BODY);
   308                     } else if (diagnostic.getCode().contains("redundant.trustme")) {
   309                         setWarning(WarningKind.REDUNDANT_SAFEVARARGS);
   310                     }
   311             } else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING &&
   312                     diagnostic.getCode().contains("varargs.non.reifiable.type")) {
   313                 setWarning(WarningKind.UNSAFE_DECL);
   314             } else if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
   315                     diagnostic.getCode().contains("invalid.trustme")) {
   316                 setWarning(WarningKind.MALFORMED_SAFEVARARGS);
   317             }
   318         }
   320         void setWarning(WarningKind wk) {
   321             if (!warnings.add(wk)) {
   322                 throw new AssertionError("Duplicate warning of kind " + wk + " in source:\n" + source);
   323             }
   324         }
   326         boolean hasWarning(WarningKind wk) {
   327             return warnings.contains(wk);
   328         }
   329     }
   330 }

mercurial