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
40import java.io.IOException;
41import java.util.Set;
42import java.util.HashSet;
43import javax.tools.Diagnostic;
44import javax.tools.Diagnostic.Kind;
45import javax.tools.JavaFileObject;
46
47import combo.ComboInstance;
48import combo.ComboParameter;
49import combo.ComboTask.Result;
50import combo.ComboTestHelper;
51
52public 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        check(newCompilationTask()
235                .withOption("-Xlint:unchecked")
236                .withOption("-source")
237                .withOption(sourceLevel.sourceKey)
238                .withSourceFromTemplate(template)
239                .analyze());
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}
272