1 /*
2  * Copyright (c) 2019, 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 8226585
27  * @summary Verify behavior w.r.t. preview feature API errors and warnings
28  * @library /tools/lib /tools/javac/lib
29  * @modules
30  *      java.base/jdk.internal
31  *      jdk.compiler/com.sun.tools.javac.api
32  *      jdk.compiler/com.sun.tools.javac.file
33  *      jdk.compiler/com.sun.tools.javac.main
34  *      jdk.compiler/com.sun.tools.javac.util
35  * @build toolbox.ToolBox toolbox.JavacTask
36  * @build combo.ComboTestHelper
37  * @compile --enable-preview -source ${jdk.version} PreviewErrors.java
38  * @run main/othervm --enable-preview PreviewErrors
39  */
40 
41 import java.io.IOException;
42 import java.nio.file.Files;
43 import java.nio.file.Path;
44 import java.nio.file.Paths;
45 
46 import combo.ComboInstance;
47 import combo.ComboParameter;
48 import combo.ComboTask;
49 import combo.ComboTestHelper;
50 import java.util.Arrays;
51 import java.util.Set;
52 import java.util.stream.Collectors;
53 import javax.tools.Diagnostic;
54 
55 import jdk.internal.PreviewFeature;
56 
57 import toolbox.JavacTask;
58 import toolbox.ToolBox;
59 
60 public class PreviewErrors extends ComboInstance<PreviewErrors> {
61 
62     protected ToolBox tb;
63 
PreviewErrors()64     PreviewErrors() {
65         super();
66         tb = new ToolBox();
67     }
68 
main(String... args)69     public static void main(String... args) throws Exception {
70         new ComboTestHelper<PreviewErrors>()
71                 .withDimension("ESSENTIAL", (x, essential) -> x.essential = essential, EssentialAPI.values())
72                 .withDimension("PREVIEW", (x, preview) -> x.preview = preview, Preview.values())
73                 .withDimension("LINT", (x, lint) -> x.lint = lint, Lint.values())
74                 .withDimension("SUPPRESS", (x, suppress) -> x.suppress = suppress, Suppress.values())
75                 .withDimension("FROM", (x, from) -> x.from = from, PreviewFrom.values())
76                 .run(PreviewErrors::new);
77     }
78 
79     private EssentialAPI essential;
80     private Preview preview;
81     private Lint lint;
82     private Suppress suppress;
83     private PreviewFrom from;
84 
85     @Override
doWork()86     public void doWork() throws IOException {
87         Path base = Paths.get(".");
88         Path src = base.resolve("src");
89         Path srcJavaBase = src.resolve("java.base");
90         Path classes = base.resolve("classes");
91         Path classesJavaBase = classes.resolve("java.base");
92 
93         Files.createDirectories(classesJavaBase);
94 
95         String previewAPI = """
96                             package preview.api;
97                             public class Extra {
98                                 @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.${preview}
99                                                              ${essential})
100                                 public static void test() { }
101                                 @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.${preview}
102                                                              ${essential})
103                                 public static class Clazz {}
104                             }
105                             """.replace("${preview}", PreviewFeature.Feature.values()[0].name())
106                                .replace("${essential}", essential.expand(null));
107 
108          if (from == PreviewFrom.CLASS) {
109             tb.writeJavaFiles(srcJavaBase, previewAPI);
110 
111             new JavacTask(tb)
112                     .outdir(classesJavaBase)
113                     .options("--patch-module", "java.base=" + srcJavaBase.toString())
114                     .files(tb.findJavaFiles(srcJavaBase))
115                     .run()
116                     .writeAll();
117          }
118 
119         ComboTask task = newCompilationTask()
120                 .withSourceFromTemplate("""
121                                         package test;
122                                         public class Test {
123                                             #{SUPPRESS}
124                                             public void test() {
125                                                 preview.api.Extra.test();
126                                                 preview.api.Extra.Clazz c;
127                                             }
128                                         }
129                                         """)
130                 .withOption("-XDrawDiagnostics")
131                 .withOption("-source")
132                 .withOption(String.valueOf(Runtime.version().feature()));
133 
134         if (from == PreviewFrom.CLASS) {
135             task.withOption("--patch-module")
136                 .withOption("java.base=" + classesJavaBase.toString())
137                 .withOption("--add-exports")
138                 .withOption("java.base/preview.api=ALL-UNNAMED");
139         } else {
140             task.withSourceFromTemplate("Extra", previewAPI)
141                 .withOption("--add-exports")
142                 .withOption("java.base/jdk.internal=ALL-UNNAMED");
143         }
144 
145         if (preview.expand(null)!= null) {
146             task = task.withOption(preview.expand(null));
147         }
148 
149         if (lint.expand(null) != null) {
150             task = task.withOption(lint.expand(null));
151         }
152 
153         task.generate(result -> {
154                 Set<String> actual = Arrays.stream(Diagnostic.Kind.values())
155                                             .flatMap(kind -> result.diagnosticsForKind(kind).stream())
156                                             .map(d -> d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode())
157                                             .collect(Collectors.toSet());
158                 Set<String> expected;
159                 boolean ok;
160                 if (essential == EssentialAPI.YES) {
161                     if (preview == Preview.YES) {
162                         if (suppress == Suppress.YES) {
163                             expected = Set.of();
164                         } else if (lint == Lint.ENABLE_PREVIEW) {
165                             expected = Set.of("5:26:compiler.warn.is.preview", "6:26:compiler.warn.is.preview");
166                         } else {
167                             expected = Set.of("-1:-1:compiler.note.preview.filename",
168                                               "-1:-1:compiler.note.preview.recompile");
169                         }
170                         ok = true;
171                     } else {
172                         expected = Set.of("5:26:compiler.err.is.preview", "6:26:compiler.err.is.preview");
173                         ok = false;
174                     }
175                 } else {
176                     if (suppress == Suppress.YES) {
177                         expected = Set.of();
178                     } else if ((preview == Preview.YES && (lint == Lint.NONE || lint == Lint.DISABLE_PREVIEW)) ||
179                                (preview == Preview.NO && lint == Lint.DISABLE_PREVIEW)) {
180                         expected = Set.of("-1:-1:compiler.note.preview.filename",
181                                           "-1:-1:compiler.note.preview.recompile");
182                     } else {
183                         expected = Set.of("5:26:compiler.warn.is.preview", "6:26:compiler.warn.is.preview");
184                     }
185                     ok = true;
186                 }
187                 if (ok) {
188                     if (!result.get().iterator().hasNext()) {
189                         throw new IllegalStateException("Did not succeed as expected." + actual);
190                     }
191                 } else {
192                     if (result.get().iterator().hasNext()) {
193                         throw new IllegalStateException("Succeed unexpectedly.");
194                     }
195                 }
196                 if (!expected.equals(actual)) {
197                     throw new IllegalStateException("Unexpected output for " + essential + ", " + preview + ", " + lint + ", " + suppress + ", " + from + ": actual: \"" + actual + "\", expected: \"" + expected + "\"");
198                 }
199             });
200     }
201 
202     public enum EssentialAPI implements ComboParameter {
203         YES(", essentialAPI=true"),
204         NO(", essentialAPI=false");
205 
206         private final String code;
207 
EssentialAPI(String code)208         private EssentialAPI(String code) {
209             this.code = code;
210         }
211 
expand(String optParameter)212         public String expand(String optParameter) {
213             return code;
214         }
215     }
216 
217     public enum Preview implements ComboParameter {
218         YES("--enable-preview"),
219         NO(null);
220 
221         private final String opt;
222 
Preview(String opt)223         private Preview(String opt) {
224             this.opt = opt;
225         }
226 
expand(String optParameter)227         public String expand(String optParameter) {
228             return opt;
229         }
230     }
231 
232     public enum Lint implements ComboParameter {
233         NONE(null),
234         ENABLE_PREVIEW("-Xlint:preview"),
235         DISABLE_PREVIEW("-Xlint:-preview");
236 
237         private final String opt;
238 
Lint(String opt)239         private Lint(String opt) {
240             this.opt = opt;
241         }
242 
expand(String optParameter)243         public String expand(String optParameter) {
244             return opt;
245         }
246     }
247 
248     public enum Suppress implements ComboParameter {
249         YES("@SuppressWarnings(\"preview\")"),
250         NO("");
251 
252         private final String code;
253 
Suppress(String code)254         private Suppress(String code) {
255             this.code = code;
256         }
257 
expand(String optParameter)258         public String expand(String optParameter) {
259             return code;
260         }
261     }
262 
263     public enum PreviewFrom implements ComboParameter {
264         CLASS,
265         SOURCE;
266 
PreviewFrom()267         private PreviewFrom() {
268         }
269 
expand(String optParameter)270         public String expand(String optParameter) {
271             throw new IllegalStateException();
272         }
273     }
274 }
275