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     6993978 7097436 8006694 7196160
27 * @summary Project Coin: Annotation to reduce varargs warnings
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/othervm Warn5
38 */
39
40import java.io.IOException;
41import java.util.EnumSet;
42import javax.tools.Diagnostic;
43import javax.tools.Diagnostic.Kind;
44import javax.tools.JavaFileObject;
45
46import combo.ComboInstance;
47import combo.ComboParameter;
48import combo.ComboTask.Result;
49import combo.ComboTestHelper;
50
51
52public class Warn5 extends ComboInstance<Warn5> {
53
54    enum XlintOption {
55        NONE("none"),
56        ALL("all");
57
58        String opt;
59
60        XlintOption(String opt) {
61            this.opt = opt;
62        }
63
64        String getXlintOption() {
65            return "-Xlint:" + opt;
66        }
67    }
68
69    enum TrustMe implements ComboParameter {
70        DONT_TRUST(""),
71        TRUST("@java.lang.SafeVarargs");
72
73        String anno;
74
75        TrustMe(String anno) {
76            this.anno = anno;
77        }
78
79        @Override
80        public String expand(String optParameter) {
81            return anno;
82        }
83    }
84
85    enum SuppressLevel implements ComboParameter {
86        NONE,
87        VARARGS;
88
89        @Override
90        public String expand(String optParameter) {
91            return this == VARARGS ?
92                "@SuppressWarnings(\"varargs\")" :
93                "";
94        }
95    }
96
97    enum ModifierKind implements ComboParameter {
98        NONE(""),
99        FINAL("final"),
100        STATIC("static"),
101        PRIVATE("private");
102
103        String mod;
104
105        ModifierKind(String mod) {
106            this.mod = mod;
107        }
108
109        @Override
110        public String expand(String optParameter) {
111            return mod;
112        }
113    }
114
115    enum MethodKind implements ComboParameter {
116        METHOD("void m"),
117        CONSTRUCTOR("Test");
118
119        String name;
120
121        MethodKind(String name) {
122            this.name = name;
123        }
124
125        @Override
126        public String expand(String optParameter) {
127            return name;
128        }
129    }
130
131    enum SourceLevel {
132        JDK_6("6"),
133        JDK_7("7"),
134        JDK_9("9");
135
136        String sourceKey;
137
138        SourceLevel(String sourceKey) {
139            this.sourceKey = sourceKey;
140        }
141    }
142
143    enum SignatureKind implements ComboParameter {
144        VARARGS_X("<X>#{NAME}(X... x)", false, true),
145        VARARGS_STRING("#{NAME}(String... x)", true, true),
146        ARRAY_X("<X>#{NAME}(X[] x)", false, false),
147        ARRAY_STRING("#{NAME}(String[] x)", true, false);
148
149        String stub;
150        boolean isReifiableArg;
151        boolean isVarargs;
152
153        SignatureKind(String stub, boolean isReifiableArg, boolean isVarargs) {
154            this.stub = stub;
155            this.isReifiableArg = isReifiableArg;
156            this.isVarargs = isVarargs;
157        }
158
159        @Override
160        public String expand(String optParameter) {
161            return stub;
162        }
163    }
164
165    enum BodyKind implements ComboParameter {
166        ASSIGN("Object o = x;", true),
167        CAST("Object o = (Object)x;", true),
168        METH("test(x);", true),
169        PRINT("System.out.println(x.toString());", false),
170        ARRAY_ASSIGN("Object[] o = x;", true),
171        ARRAY_CAST("Object[] o = (Object[])x;", true),
172        ARRAY_METH("testArr(x);", true);
173
174        String body;
175        boolean hasAliasing;
176
177        BodyKind(String body, boolean hasAliasing) {
178            this.body = body;
179            this.hasAliasing = hasAliasing;
180        }
181
182        @Override
183        public String expand(String optParameter) {
184            return body;
185        }
186    }
187
188    enum WarningKind {
189        UNSAFE_BODY("compiler.warn.varargs.unsafe.use.varargs.param"),
190        UNSAFE_DECL("compiler.warn.unchecked.varargs.non.reifiable.type"),
191        MALFORMED_SAFEVARARGS("compiler.err.varargs.invalid.trustme.anno"),
192        REDUNDANT_SAFEVARARGS("compiler.warn.varargs.redundant.trustme.anno");
193
194        String code;
195
196        WarningKind(String code) {
197            this.code = code;
198        }
199    }
200
201    public static void main(String[] args) {
202        new ComboTestHelper<Warn5>()
203                .withFilter(Warn5::badTestFilter)
204                .withDimension("SOURCE", (x, level) -> x.sourceLevel = level, SourceLevel.values())
205                .withDimension("LINT", (x, lint) -> x.xlint = lint, XlintOption.values())
206                .withDimension("TRUSTME", (x, trustme) -> x.trustMe = trustme, TrustMe.values())
207                .withDimension("SUPPRESS", (x, suppress) -> x.suppressLevel = suppress, SuppressLevel.values())
208                .withDimension("MOD", (x, mod) -> x.modKind = mod, ModifierKind.values())
209                .withDimension("NAME", (x, name) -> x.methKind = name, MethodKind.values())
210                .withDimension("SIG", (x, sig) -> x.sig = sig, SignatureKind.values())
211                .withDimension("BODY", (x, body) -> x.body = body, BodyKind.values())
212                .run(Warn5::new);
213    }
214
215    SourceLevel sourceLevel;
216    XlintOption xlint;
217    TrustMe trustMe;
218    SuppressLevel suppressLevel;
219    ModifierKind modKind;
220    MethodKind methKind;
221    SignatureKind sig;
222    BodyKind body;
223
224    boolean badTestFilter() {
225        return (methKind != MethodKind.CONSTRUCTOR || modKind == ModifierKind.NONE);
226    }
227
228    String template = "import com.sun.tools.javac.api.*;\n" +
229                      "import java.util.List;\n" +
230                      "class Test {\n" +
231                      "   static void test(Object o) {}\n" +
232                      "   static void testArr(Object[] o) {}\n" +
233                      "   #{TRUSTME} #{SUPPRESS} #{MOD} #{SIG} { #{BODY} }\n" +
234                      "}\n";
235
236    @Override
237    public void doWork() throws IOException {
238        check(newCompilationTask()
239                .withOption(xlint.getXlintOption())
240                .withOption("-source")
241                .withOption(sourceLevel.sourceKey)
242                .withSourceFromTemplate(template)
243                .analyze());
244    }
245
246    void check(Result<?> res) {
247
248        EnumSet<WarningKind> foundWarnings = EnumSet.noneOf(WarningKind.class);
249        for (Diagnostic.Kind kind : new Kind[] { Kind.ERROR, Kind.MANDATORY_WARNING, Kind.WARNING}) {
250            for (Diagnostic<? extends JavaFileObject> diag : res.diagnosticsForKind(kind)) {
251                for (WarningKind wk : WarningKind.values()) {
252                    if (wk.code.equals(diag.getCode())) {
253                        foundWarnings.add(wk);
254                    }
255                }
256            }
257        }
258
259        EnumSet<WarningKind> expectedWarnings =
260                EnumSet.noneOf(WarningKind.class);
261
262        if (sourceLevel.compareTo(SourceLevel.JDK_7) >= 0 &&
263                trustMe == TrustMe.TRUST &&
264                suppressLevel != SuppressLevel.VARARGS &&
265                xlint != XlintOption.NONE &&
266                sig.isVarargs &&
267                !sig.isReifiableArg &&
268                body.hasAliasing &&
269                (methKind == MethodKind.CONSTRUCTOR ||
270                (methKind == MethodKind.METHOD &&
271                 modKind == ModifierKind.FINAL || modKind == ModifierKind.STATIC ||
272                 (modKind == ModifierKind.PRIVATE && sourceLevel.compareTo(SourceLevel.JDK_9) >= 0)))) {
273            expectedWarnings.add(WarningKind.UNSAFE_BODY);
274        }
275
276        if (sourceLevel.compareTo(SourceLevel.JDK_7) >= 0 &&
277                trustMe == TrustMe.DONT_TRUST &&
278                sig.isVarargs &&
279                !sig.isReifiableArg &&
280                xlint == XlintOption.ALL) {
281            expectedWarnings.add(WarningKind.UNSAFE_DECL);
282        }
283
284        if (sourceLevel.compareTo(SourceLevel.JDK_7) >= 0 &&
285                trustMe == TrustMe.TRUST &&
286                (!sig.isVarargs ||
287                 ((modKind == ModifierKind.NONE ||
288                 modKind == ModifierKind.PRIVATE && sourceLevel.compareTo(SourceLevel.JDK_9) < 0 ) &&
289                 methKind == MethodKind.METHOD))) {
290            expectedWarnings.add(WarningKind.MALFORMED_SAFEVARARGS);
291        }
292
293        if (sourceLevel.compareTo(SourceLevel.JDK_7) >= 0 &&
294                trustMe == TrustMe.TRUST &&
295                xlint != XlintOption.NONE &&
296                suppressLevel != SuppressLevel.VARARGS &&
297                (modKind == ModifierKind.FINAL || modKind == ModifierKind.STATIC ||
298                 (modKind == ModifierKind.PRIVATE && sourceLevel.compareTo(SourceLevel.JDK_9) >= 0) ||
299                 methKind == MethodKind.CONSTRUCTOR) &&
300                sig.isVarargs &&
301                sig.isReifiableArg) {
302            expectedWarnings.add(WarningKind.REDUNDANT_SAFEVARARGS);
303        }
304
305        if (!expectedWarnings.containsAll(foundWarnings) ||
306                !foundWarnings.containsAll(expectedWarnings)) {
307            fail("invalid diagnostics for source:\n" +
308                    res.compilationInfo() +
309                    "\nOptions: " + xlint.getXlintOption() +
310                    "\nSource Level: " + sourceLevel +
311                    "\nExpected warnings: " + expectedWarnings +
312                    "\nFound warnings: " + foundWarnings);
313        }
314    }
315}
316