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