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_7("7"),
  97         JDK_9("9");
  98 
  99         String sourceKey;
 100 
 101         SourceLevel(String sourceKey) {
 102             this.sourceKey = sourceKey;
 103         }
 104     }
 105 
 106     enum TrustMe implements ComboParameter {
 107         DONT_TRUST(""),
 108         TRUST("@java.lang.SafeVarargs");
 109 
 110         String anno;
 111 
 112         TrustMe(String anno) {
 113             this.anno = anno;
 114         }
 115 
 116         @Override
 117         public String expand(String optParameter) {
 118             return anno;
 119         }
 120     }
 121 
 122     enum ModifierKind implements ComboParameter {
 123         NONE(" "),
 124         FINAL("final "),
 125         STATIC("static "),
 126         PRIVATE("private ");
 127 
 128         String mod;
 129 
 130         ModifierKind(String mod) {
 131             this.mod = mod;
 132         }
 133 
 134         @Override
 135         public String expand(String optParameter) {
 136             return mod;
 137         }
 138     }
 139 
 140     enum SuppressLevel implements ComboParameter {
 141         NONE(""),
 142         UNCHECKED("unchecked");
 143 
 144         String lint;
 145 
 146         SuppressLevel(String lint) {
 147             this.lint = lint;
 148         }
 149 
 150         @Override
 151         public String expand(String optParameter) {
 152             return "@SuppressWarnings(\"" + lint + "\")";
 153         }
 154     }
 155 
 156     enum Signature implements ComboParameter {
 157         UNBOUND("void #NAME(List<?>#ARITY arg) { #BODY }",
 158             new Warning[][] {none, none, none, none, error}),
 159         INVARIANT_TVAR("<Z> void #NAME(List<Z>#ARITY arg) { #BODY }",
 160             new Warning[][] {both, both, error, both, error}),
 161         TVAR("<Z> void #NAME(Z#ARITY arg) { #BODY }",
 162             new Warning[][] {both, both, both, both, vararg}),
 163         INVARIANT("void #NAME(List<String>#ARITY arg) { #BODY }",
 164             new Warning[][] {error, error, error, both, error}),
 165         UNPARAMETERIZED("void #NAME(String#ARITY arg) { #BODY }",
 166             new Warning[][] {error, error, error, error, none});
 167 
 168         String template;
 169         Warning[][] warnings;
 170 
 171         Signature(String template, Warning[][] warnings) {
 172             this.template = template;
 173             this.warnings = warnings;
 174         }
 175 
 176         boolean isApplicableTo(Signature other) {
 177             return warnings[other.ordinal()] != null;
 178         }
 179 
 180         boolean giveUnchecked(Signature other) {
 181             return warnings[other.ordinal()] == unchecked ||
 182                     warnings[other.ordinal()] == both;
 183         }
 184 
 185         boolean giveVarargs(Signature other) {
 186             return warnings[other.ordinal()] == vararg ||
 187                     warnings[other.ordinal()] == both;
 188         }
 189 
 190         @Override
 191         public String expand(String optParameter) {
 192             if (optParameter.equals("CLIENT")) {
 193                 return template.replaceAll("#ARITY", "")
 194                         .replaceAll("#NAME", "test")
 195                         .replaceAll("#BODY", "m(arg)");
 196             } else {
 197                 return template.replaceAll("#ARITY", "...")
 198                         .replaceAll("#NAME", "m")
 199                         .replaceAll("#BODY", "");
 200             }
 201         }
 202     }
 203 
 204     public static void main(String... args) {
 205         new ComboTestHelper<Warn4>()
 206                 .withFilter(Warn4::badTestFilter)
 207                 .withDimension("SOURCE", (x, level) -> x.sourceLevel = level, SourceLevel.values())
 208                 .withDimension("TRUSTME", (x, trustme) -> x.trustMe = trustme, TrustMe.values())
 209                 .withArrayDimension("SUPPRESS", (x, suppress, idx) -> x.suppress[idx] = suppress, 2, SuppressLevel.values())
 210                 .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values())
 211                 .withArrayDimension("MTH", (x, sig, idx) -> x.sigs[idx] = sig, 2, Signature.values())
 212                 .run(Warn4::new);
 213     }
 214 
 215     SourceLevel sourceLevel;
 216     TrustMe trustMe;
 217     SuppressLevel[] suppress = new SuppressLevel[2];
 218     ModifierKind modKind;
 219     Signature[] sigs = new Signature[2];
 220 
 221     boolean badTestFilter() {
 222         return sigs[0].isApplicableTo(sigs[1]);
 223     }
 224 
 225     final String template = "import java.util.List;\n" +
 226                             "class Test {\n" +
 227                             "   #{TRUSTME} #{SUPPRESS[0]} #{MOD} #{MTH[0].VARARG}\n" +
 228                             "   #{SUPPRESS[1]} #{MTH[1].CLIENT}\n" +
 229                             "}";
 230 
 231     @Override
 232     public void doWork() throws IOException {
 233         newCompilationTask()
 234                 .withOption("-Xlint:unchecked")
 235                 .withOption("-source")
 236                 .withOption(sourceLevel.sourceKey)
 237                 .withSourceFromTemplate(template)
 238                 .analyze(this::check);
 239     }
 240 
 241     void check(Result<?> res) {
 242         boolean[] warnArr = new boolean[] {sigs[0].giveUnchecked(sigs[1]),
 243                                sigs[0].giveVarargs(sigs[1])};
 244 
 245         Set<Warning> warnings = new HashSet<>();
 246         for (Diagnostic<? extends JavaFileObject> d : res.diagnosticsForKind(Kind.MANDATORY_WARNING)) {
 247             if (d.getCode().contains(Warning.VARARGS.key)) {
 248                     warnings.add(Warning.VARARGS);
 249             } else if(d.getCode().contains(Warning.UNCHECKED.key)) {
 250                 warnings.add(Warning.UNCHECKED);
 251             }
 252         }
 253 
 254         boolean badOutput = false;
 255         for (Warning wkind : Warning.values()) {
 256             boolean isSuppressed = wkind.isSuppressed(trustMe, sourceLevel,
 257                     suppress[1], suppress[0], modKind);
 258             badOutput |= (warnArr[wkind.ordinal()] && !isSuppressed) !=
 259                     warnings.contains(wkind);
 260         }
 261         if (badOutput) {
 262             fail("invalid diagnostics for source:\n" +
 263                     res.compilationInfo() +
 264                     "\nExpected unchecked warning: " + warnArr[0] +
 265                     "\nExpected unsafe vararg warning: " + warnArr[1] +
 266                     "\nWarnings: " + warnings +
 267                     "\nSource level: " + sourceLevel);
 268         }
 269     }
 270 }