1 /*
   2  * Copyright (c) 2010, 2015, 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  */
  23 
  24 /**
  25  * @test
  26  * @bug     6945418 6993978 8006694 7196160 8129962
  27  * @summary Project Coin: Simplified Varargs Method Invocation
  28  *  temporarily workaround combo tests are causing time out in several platforms
  29  * @library /tools/javac/lib
  30  * @modules jdk.compiler/com.sun.tools.javac.api
  31  *          jdk.compiler/com.sun.tools.javac.code
  32  *          jdk.compiler/com.sun.tools.javac.comp
  33  *          jdk.compiler/com.sun.tools.javac.main
  34  *          jdk.compiler/com.sun.tools.javac.tree
  35  *          jdk.compiler/com.sun.tools.javac.util
  36  * @build combo.ComboTestHelper
  37  * @run main Warn4
  38  */
  39 
  40 import java.io.IOException;
  41 import java.util.Set;
  42 import java.util.HashSet;
  43 import javax.tools.Diagnostic;
  44 import javax.tools.Diagnostic.Kind;
  45 import javax.tools.JavaFileObject;
  46 
  47 import combo.ComboInstance;
  48 import combo.ComboParameter;
  49 import combo.ComboTask.Result;
  50 import combo.ComboTestHelper;
  51 
  52 public class Warn4 extends ComboInstance<Warn4> {
  53 
  54     final static Warning[] error = null;
  55     final static Warning[] none = new Warning[] {};
  56     final static Warning[] vararg = new Warning[] { Warning.VARARGS };
  57     final static Warning[] unchecked = new Warning[] { Warning.UNCHECKED };
  58     final static Warning[] both = new Warning[] { Warning.VARARGS, Warning.UNCHECKED };
  59 
  60     enum Warning {
  61         UNCHECKED("generic.array.creation"),
  62         VARARGS("varargs.non.reifiable.type");
  63 
  64         String key;
  65 
  66         Warning(String key) {
  67             this.key = key;
  68         }
  69 
  70         boolean isSuppressed(TrustMe trustMe, SourceLevel source,
  71                 SuppressLevel suppressLevelClient,
  72                 SuppressLevel suppressLevelDecl,
  73                 ModifierKind modKind) {
  74             switch(this) {
  75                 case VARARGS:
  76                     return source.compareTo(SourceLevel.JDK_7) < 0 ||
  77                             suppressLevelDecl == SuppressLevel.UNCHECKED ||
  78                             trustMe == TrustMe.TRUST;
  79                 case UNCHECKED:
  80                     return suppressLevelClient == SuppressLevel.UNCHECKED ||
  81                         (trustMe == TrustMe.TRUST &&
  82                          (((modKind == ModifierKind.FINAL || modKind == ModifierKind.STATIC) &&
  83                            source.compareTo( SourceLevel.JDK_7) >= 0 ) ||
  84                           (modKind == ModifierKind.PRIVATE && source.compareTo( SourceLevel.JDK_9) >= 0 )));
  85             }
  86 
  87             SuppressLevel supLev = this == VARARGS ?
  88                 suppressLevelDecl :
  89                 suppressLevelClient;
  90             return supLev == SuppressLevel.UNCHECKED ||
  91                     (trustMe == TrustMe.TRUST && modKind != ModifierKind.NONE);
  92         }
  93     }
  94 
  95     enum SourceLevel {
  96         JDK_6("6"),
  97         JDK_7("7"),
  98         JDK_9("9");
  99 
 100         String sourceKey;
 101 
 102         SourceLevel(String sourceKey) {
 103             this.sourceKey = sourceKey;
 104         }
 105     }
 106 
 107     enum TrustMe implements ComboParameter {
 108         DONT_TRUST(""),
 109         TRUST("@java.lang.SafeVarargs");
 110 
 111         String anno;
 112 
 113         TrustMe(String anno) {
 114             this.anno = anno;
 115         }
 116 
 117         @Override
 118         public String expand(String optParameter) {
 119             return anno;
 120         }
 121     }
 122 
 123     enum ModifierKind implements ComboParameter {
 124         NONE(" "),
 125         FINAL("final "),
 126         STATIC("static "),
 127         PRIVATE("private ");
 128 
 129         String mod;
 130 
 131         ModifierKind(String mod) {
 132             this.mod = mod;
 133         }
 134 
 135         @Override
 136         public String expand(String optParameter) {
 137             return mod;
 138         }
 139     }
 140 
 141     enum SuppressLevel implements ComboParameter {
 142         NONE(""),
 143         UNCHECKED("unchecked");
 144 
 145         String lint;
 146 
 147         SuppressLevel(String lint) {
 148             this.lint = lint;
 149         }
 150 
 151         @Override
 152         public String expand(String optParameter) {
 153             return "@SuppressWarnings(\"" + lint + "\")";
 154         }
 155     }
 156 
 157     enum Signature implements ComboParameter {
 158         UNBOUND("void #NAME(List<?>#ARITY arg) { #BODY }",
 159             new Warning[][] {none, none, none, none, error}),
 160         INVARIANT_TVAR("<Z> void #NAME(List<Z>#ARITY arg) { #BODY }",
 161             new Warning[][] {both, both, error, both, error}),
 162         TVAR("<Z> void #NAME(Z#ARITY arg) { #BODY }",
 163             new Warning[][] {both, both, both, both, vararg}),
 164         INVARIANT("void #NAME(List<String>#ARITY arg) { #BODY }",
 165             new Warning[][] {error, error, error, both, error}),
 166         UNPARAMETERIZED("void #NAME(String#ARITY arg) { #BODY }",
 167             new Warning[][] {error, error, error, error, none});
 168 
 169         String template;
 170         Warning[][] warnings;
 171 
 172         Signature(String template, Warning[][] warnings) {
 173             this.template = template;
 174             this.warnings = warnings;
 175         }
 176 
 177         boolean isApplicableTo(Signature other) {
 178             return warnings[other.ordinal()] != null;
 179         }
 180 
 181         boolean giveUnchecked(Signature other) {
 182             return warnings[other.ordinal()] == unchecked ||
 183                     warnings[other.ordinal()] == both;
 184         }
 185 
 186         boolean giveVarargs(Signature other) {
 187             return warnings[other.ordinal()] == vararg ||
 188                     warnings[other.ordinal()] == both;
 189         }
 190 
 191         @Override
 192         public String expand(String optParameter) {
 193             if (optParameter.equals("CLIENT")) {
 194                 return template.replaceAll("#ARITY", "")
 195                         .replaceAll("#NAME", "test")
 196                         .replaceAll("#BODY", "m(arg)");
 197             } else {
 198                 return template.replaceAll("#ARITY", "...")
 199                         .replaceAll("#NAME", "m")
 200                         .replaceAll("#BODY", "");
 201             }
 202         }
 203     }
 204 
 205     public static void main(String... args) {
 206         new ComboTestHelper<Warn4>()
 207                 .withFilter(Warn4::badTestFilter)
 208                 .withDimension("SOURCE", (x, level) -> x.sourceLevel = level, SourceLevel.values())
 209                 .withDimension("TRUSTME", (x, trustme) -> x.trustMe = trustme, TrustMe.values())
 210                 .withArrayDimension("SUPPRESS", (x, suppress, idx) -> x.suppress[idx] = suppress, 2, SuppressLevel.values())
 211                 .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values())
 212                 .withArrayDimension("MTH", (x, sig, idx) -> x.sigs[idx] = sig, 2, Signature.values())
 213                 .run(Warn4::new);
 214     }
 215 
 216     SourceLevel sourceLevel;
 217     TrustMe trustMe;
 218     SuppressLevel[] suppress = new SuppressLevel[2];
 219     ModifierKind modKind;
 220     Signature[] sigs = new Signature[2];
 221 
 222     boolean badTestFilter() {
 223         return sigs[0].isApplicableTo(sigs[1]);
 224     }
 225 
 226     final String template = "import java.util.List;\n" +
 227                             "class Test {\n" +
 228                             "   #{TRUSTME} #{SUPPRESS[0]} #{MOD} #{MTH[0].VARARG}\n" +
 229                             "   #{SUPPRESS[1]} #{MTH[1].CLIENT}\n" +
 230                             "}";
 231 
 232     @Override
 233     public void doWork() throws IOException {
 234         newCompilationTask()
 235                 .withOption("-Xlint:unchecked")
 236                 .withOption("-source")
 237                 .withOption(sourceLevel.sourceKey)
 238                 .withSourceFromTemplate(template)
 239                 .analyze(this::check);
 240     }
 241 
 242     void check(Result<?> res) {
 243         boolean[] warnArr = new boolean[] {sigs[0].giveUnchecked(sigs[1]),
 244                                sigs[0].giveVarargs(sigs[1])};
 245 
 246         Set<Warning> warnings = new HashSet<>();
 247         for (Diagnostic<? extends JavaFileObject> d : res.diagnosticsForKind(Kind.MANDATORY_WARNING)) {
 248             if (d.getCode().contains(Warning.VARARGS.key)) {
 249                     warnings.add(Warning.VARARGS);
 250             } else if(d.getCode().contains(Warning.UNCHECKED.key)) {
 251                 warnings.add(Warning.UNCHECKED);
 252             }
 253         }
 254 
 255         boolean badOutput = false;
 256         for (Warning wkind : Warning.values()) {
 257             boolean isSuppressed = wkind.isSuppressed(trustMe, sourceLevel,
 258                     suppress[1], suppress[0], modKind);
 259             badOutput |= (warnArr[wkind.ordinal()] && !isSuppressed) !=
 260                     warnings.contains(wkind);
 261         }
 262         if (badOutput) {
 263             fail("invalid diagnostics for source:\n" +
 264                     res.compilationInfo() +
 265                     "\nExpected unchecked warning: " + warnArr[0] +
 266                     "\nExpected unsafe vararg warning: " + warnArr[1] +
 267                     "\nWarnings: " + warnings +
 268                     "\nSource level: " + sourceLevel);
 269         }
 270     }
 271 }