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

Mon, 13 Dec 2010 15:11:00 -0800

author
mcimadamore
date
Mon, 13 Dec 2010 15:11:00 -0800
changeset 795
7b99f98b3035
child 892
3e30c95da3c6
permissions
-rw-r--r--

6993978: Project Coin: Compiler support of annotation to reduce varargs warnings
Reviewed-by: jjg, darcy

     1 /*
     2  * Copyright (c) 2010, 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
    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 java.net.URI;
    33 import java.util.ArrayList;
    34 import java.util.Arrays;
    35 import javax.tools.Diagnostic;
    36 import javax.tools.JavaCompiler;
    37 import javax.tools.JavaFileObject;
    38 import javax.tools.SimpleJavaFileObject;
    39 import javax.tools.ToolProvider;
    41 public class Warn5 {
    43     enum XlintOption {
    44         NONE("none"),
    45         ALL("all");
    47         String opt;
    49         XlintOption(String opt) {
    50             this.opt = opt;
    51         }
    53         String getXlintOption() {
    54             return "-Xlint:" + opt;
    55         }
    56     }
    58     enum TrustMe {
    59         DONT_TRUST(""),
    60         TRUST("@java.lang.SafeVarargs");
    62         String anno;
    64         TrustMe(String anno) {
    65             this.anno = anno;
    66         }
    67     }
    69     enum SuppressLevel {
    70         NONE,
    71         VARARGS;
    73         String getSuppressAnno() {
    74             return this == VARARGS ?
    75                 "@SuppressWarnings(\"varargs\")" :
    76                 "";
    77         }
    78     }
    80     enum ModifierKind {
    81         NONE(""),
    82         FINAL("final"),
    83         STATIC("static");
    85         String mod;
    87         ModifierKind(String mod) {
    88             this.mod = mod;
    89         }
    90     }
    92     enum MethodKind {
    93         METHOD("void m"),
    94         CONSTRUCTOR("Test");
    97         String name;
    99         MethodKind(String name) {
   100             this.name = name;
   101         }
   102     }
   104     enum SourceLevel {
   105         JDK_6("6"),
   106         JDK_7("7");
   108         String sourceKey;
   110         SourceLevel(String sourceKey) {
   111             this.sourceKey = sourceKey;
   112         }
   113     }
   115     enum SignatureKind {
   116         VARARGS_X("#K <X>#N(X... x)", false, true),
   117         VARARGS_STRING("#K #N(String... x)", true, true),
   118         ARRAY_X("#K <X>#N(X[] x)", false, false),
   119         ARRAY_STRING("#K #N(String[] x)", true, false);
   121         String stub;
   122         boolean isReifiableArg;
   123         boolean isVarargs;
   125         SignatureKind(String stub, boolean isReifiableArg, boolean isVarargs) {
   126             this.stub = stub;
   127             this.isReifiableArg = isReifiableArg;
   128             this.isVarargs = isVarargs;
   129         }
   131         String getSignature(ModifierKind modKind, MethodKind methKind) {
   132             return methKind != MethodKind.CONSTRUCTOR ?
   133                 stub.replace("#K", modKind.mod).replace("#N", methKind.name) :
   134                 stub.replace("#K", "").replace("#N", methKind.name);
   135         }
   136     }
   138     enum BodyKind {
   139         ASSIGN("Object o = x;", true),
   140         CAST("Object o = (Object)x;", true),
   141         METH("test(x);", true),
   142         PRINT("System.out.println(x.toString());", false),
   143         ARRAY_ASSIGN("Object[] o = x;", true),
   144         ARRAY_CAST("Object[] o = (Object[])x;", true),
   145         ARRAY_METH("testArr(x);", true);
   147         String body;
   148         boolean hasAliasing;
   150         BodyKind(String body, boolean hasAliasing) {
   151             this.body = body;
   152             this.hasAliasing = hasAliasing;
   153         }
   154     }
   156     static class JavaSource extends SimpleJavaFileObject {
   158         String template = "import com.sun.tools.javac.api.*;\n" +
   159                           "import java.util.List;\n" +
   160                           "class Test {\n" +
   161                           "   static void test(Object o) {}\n" +
   162                           "   static void testArr(Object[] o) {}\n" +
   163                           "   #T \n #S #M { #B }\n" +
   164                           "}\n";
   166         String source;
   168         public JavaSource(TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind,
   169                 MethodKind methKind, SignatureKind meth, BodyKind body) {
   170             super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
   171             source = template.replace("#T", trustMe.anno).
   172                     replace("#S", suppressLevel.getSuppressAnno()).
   173                     replace("#M", meth.getSignature(modKind, methKind)).
   174                     replace("#B", body.body);
   175         }
   177         @Override
   178         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   179             return source;
   180         }
   181     }
   183     public static void main(String... args) throws Exception {
   184         for (SourceLevel sourceLevel : SourceLevel.values()) {
   185             for (XlintOption xlint : XlintOption.values()) {
   186                 for (TrustMe trustMe : TrustMe.values()) {
   187                     for (SuppressLevel suppressLevel : SuppressLevel.values()) {
   188                         for (ModifierKind modKind : ModifierKind.values()) {
   189                             for (MethodKind methKind : MethodKind.values()) {
   190                                 for (SignatureKind sig : SignatureKind.values()) {
   191                                     for (BodyKind body : BodyKind.values()) {
   192                                         test(sourceLevel,
   193                                                 xlint,
   194                                                 trustMe,
   195                                                 suppressLevel,
   196                                                 modKind,
   197                                                 methKind,
   198                                                 sig,
   199                                                 body);
   200                                     }
   201                                 }
   202                             }
   203                         }
   204                     }
   205                 }
   206             }
   207         }
   208     }
   210     static void test(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel,
   211             ModifierKind modKind, MethodKind methKind, SignatureKind sig, BodyKind body) throws Exception {
   212         final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
   213         JavaSource source = new JavaSource(trustMe, suppressLevel, modKind, methKind, sig, body);
   214         DiagnosticChecker dc = new DiagnosticChecker();
   215         JavacTask ct = (JavacTask)tool.getTask(null, null, dc,
   216                 Arrays.asList(xlint.getXlintOption(), "-source", sourceLevel.sourceKey), null, Arrays.asList(source));
   217         ct.analyze();
   218         check(sourceLevel, dc, source, xlint, trustMe,
   219                 suppressLevel, modKind, methKind, sig, body);
   220     }
   222     static void check(SourceLevel sourceLevel, DiagnosticChecker dc, JavaSource source,
   223             XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind,
   224             MethodKind methKind, SignatureKind meth, BodyKind body) {
   226         boolean hasPotentiallyUnsafeBody = sourceLevel == SourceLevel.JDK_7 &&
   227                 trustMe == TrustMe.TRUST &&
   228                 suppressLevel != SuppressLevel.VARARGS &&
   229                 xlint != XlintOption.NONE &&
   230                 meth.isVarargs && !meth.isReifiableArg && body.hasAliasing &&
   231                 (methKind == MethodKind.CONSTRUCTOR || (methKind == MethodKind.METHOD && modKind != ModifierKind.NONE));
   233         boolean hasPotentiallyPollutingDecl = sourceLevel == SourceLevel.JDK_7 &&
   234                 trustMe == TrustMe.DONT_TRUST &&
   235                 meth.isVarargs &&
   236                 !meth.isReifiableArg &&
   237                 xlint == XlintOption.ALL;
   239         boolean hasMalformedAnnoInDecl = sourceLevel == SourceLevel.JDK_7 &&
   240                 trustMe == TrustMe.TRUST &&
   241                 (!meth.isVarargs ||
   242                 (modKind == ModifierKind.NONE && methKind == MethodKind.METHOD));
   244         boolean hasRedundantAnnoInDecl = sourceLevel == SourceLevel.JDK_7 &&
   245                 trustMe == TrustMe.TRUST &&
   246                 xlint != XlintOption.NONE &&
   247                 suppressLevel != SuppressLevel.VARARGS &&
   248                 (modKind != ModifierKind.NONE || methKind == MethodKind.CONSTRUCTOR) &&
   249                 meth.isVarargs &&
   250                 meth.isReifiableArg;
   252         if (hasPotentiallyUnsafeBody != dc.hasPotentiallyUnsafeBody ||
   253                 hasPotentiallyPollutingDecl != dc.hasPotentiallyPollutingDecl ||
   254                 hasMalformedAnnoInDecl != dc.hasMalformedAnnoInDecl ||
   255                 hasRedundantAnnoInDecl != dc.hasRedundantAnnoInDecl) {
   256             throw new Error("invalid diagnostics for source:\n" +
   257                     source.getCharContent(true) +
   258                     "\nOptions: " + xlint.getXlintOption() +
   259                     "\nExpected potentially unsafe body warning: " + hasPotentiallyUnsafeBody +
   260                     "\nExpected potentially polluting decl warning: " + hasPotentiallyPollutingDecl +
   261                     "\nExpected malformed anno error: " + hasMalformedAnnoInDecl +
   262                     "\nExpected redundant anno warning: " + hasRedundantAnnoInDecl +
   263                     "\nFound potentially unsafe body warning: " + dc.hasPotentiallyUnsafeBody +
   264                     "\nFound potentially polluting decl warning: " + dc.hasPotentiallyPollutingDecl +
   265                     "\nFound malformed anno error: " + dc.hasMalformedAnnoInDecl +
   266                     "\nFound redundant anno warning: " + dc.hasRedundantAnnoInDecl);
   267         }
   268     }
   270     static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
   272         boolean hasPotentiallyUnsafeBody = false;
   273         boolean hasPotentiallyPollutingDecl = false;
   274         boolean hasMalformedAnnoInDecl = false;
   275         boolean hasRedundantAnnoInDecl = false;
   277         public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   278             if (diagnostic.getKind() == Diagnostic.Kind.WARNING) {
   279                     if (diagnostic.getCode().contains("unsafe.use.varargs.param")) {
   280                         hasPotentiallyUnsafeBody = true;
   281                     } else if (diagnostic.getCode().contains("redundant.trustme")) {
   282                         hasRedundantAnnoInDecl = true;
   283                     }
   284             } else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING &&
   285                     diagnostic.getCode().contains("varargs.non.reifiable.type")) {
   286                 hasPotentiallyPollutingDecl = true;
   287             } else if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
   288                     diagnostic.getCode().contains("invalid.trustme")) {
   289                 hasMalformedAnnoInDecl = true;
   290             }
   291         }
   292     }
   293 }

mercurial