1 /*
  2  * Copyright (c) 2019, 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 8234899
 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 ConditionalExpressionResolvePending.java
 38  * @run main/othervm ConditionalExpressionResolvePending
 39  */
 40 
 41 import combo.ComboInstance;
 42 import combo.ComboParameter;
 43 import combo.ComboTask;
 44 import combo.ComboTestHelper;
 45 import java.io.InputStream;
 46 import java.nio.file.Path;
 47 import java.nio.file.Paths;
 48 import java.util.Iterator;
 49 import java.util.Objects;
 50 import java.util.function.BiPredicate;
 51 import toolbox.ToolBox;
 52 
 53 import javax.tools.JavaFileObject;
 54 
 55 public class ConditionalExpressionResolvePending extends ComboInstance<ConditionalExpressionResolvePending> {
 56     protected ToolBox tb;
 57 
 58     ConditionalExpressionResolvePending() {
 59         super();
 60         tb = new ToolBox();
 61     }
 62 
 63     public static void main(String... args) throws Exception {
 64         new ComboTestHelper<ConditionalExpressionResolvePending>()
 65                 .withDimension("METHOD", (x, method) -> x.method = method, Method.values())
 66                 .withDimension("EXPRESSION", (x, expression) -> x.expression = expression, Expression.values())
 67                 .withDimension("TRUE", (x, True) -> x.True = True, TestOrDummy.values())
 68                 .withDimension("FALSE", (x, False) -> x.False = False, TestOrDummy.values())
 69                 .withDimension("SNIPPET", (x, snippet) -> x.snippet = snippet, Snippet.values())
 70                 .run(ConditionalExpressionResolvePending::new);
 71     }
 72 
 73     private Method method;
 74     private Expression expression;
 75     private TestOrDummy True;
 76     private TestOrDummy False;
 77     private Snippet snippet;
 78 
 79     private static final String MAIN_TEMPLATE =
 80             """
 81             public class Test {
 82                 public static boolean doTest(boolean c, Object input) {
 83                     String clazzName = input.getClass().getName();
 84                     int len = clazzName.length();
 85                     #{METHOD}
 86                 }
 87             }
 88             """;
 89 
 90     @Override
 91     protected void doWork() throws Throwable {
 92         Path base = Paths.get(".");
 93 
 94         ComboTask task = newCompilationTask()
 95                 .withSourceFromTemplate(MAIN_TEMPLATE, pname -> switch (pname) {
 96                         case "METHOD" -> method;
 97                         case "EXPRESSION" -> expression;
 98                         case "TRUE" -> True;
 99                         case "FALSE" -> False;
100                         case "SNIPPET" -> snippet;
101                         default -> throw new UnsupportedOperationException(pname);
102                     });
103 
104         task.generate(result -> {
105             try {
106                 Iterator<? extends JavaFileObject> filesIt = result.get().iterator();
107                 JavaFileObject file = filesIt.next();
108                 if (filesIt.hasNext()) {
109                     throw new IllegalStateException("More than one classfile returned!");
110                 }
111                 byte[] data;
112                 try (InputStream input = file.openInputStream()) {
113                     data = input.readAllBytes();
114                 }
115                 ClassLoader inMemoryLoader = new ClassLoader() {
116                     protected Class<?> findClass(String name) throws ClassNotFoundException {
117                         if ("Test".equals(name)) {
118                             return defineClass(name, data, 0, data.length);
119                         }
120                         return super.findClass(name);
121                     }
122                 };
123                 Class<?> test = Class.forName("Test", false, inMemoryLoader);
124                 java.lang.reflect.Method doTest = test.getDeclaredMethod("doTest", boolean.class, Object.class);
125                 runTest((c, input) -> {
126                     try {
127                         return (boolean) doTest.invoke(null, c, input);
128                     } catch (Exception ex) {
129                         throw new IllegalStateException(ex);
130                     }
131                 });
132             } catch (Throwable ex) {
133                 throw new IllegalStateException(ex);
134             }
135         });
136     }
137 
138     private void runTest(BiPredicate<Boolean, Object> test) {
139         assertEquals(false, test.test(true, ""));
140         assertEquals(true, test.test(true, 1));
141         assertEquals(false, test.test(false, ""));
142         assertEquals(true, test.test(false, 1));
143     }
144 
145     private void assertEquals(Object o1, Object o2) {
146         if (!Objects.equals(o1, o2)) {
147             throw new AssertionError();
148         }
149     }
150 
151     public enum Method implements ComboParameter {
152         VARIABLE("""
153                  boolean b = #{EXPRESSION};
154                  return b;
155                  """),
156         IF("""
157            boolean b;
158            if (#{EXPRESSION}) b = true;
159            else b = false;
160            return b;
161            """),
162         RETURN("""
163                return #{EXPRESSION};
164                """);
165         private final String body;
166 
167         private Method(String body) {
168             this.body = body;
169         }
170 
171         @Override
172         public String expand(String optParameter) {
173             return body;
174         }
175 
176     }
177     public enum Expression implements ComboParameter {
178         CONDITIONAL("c ? #{TRUE} : #{FALSE}"),
179         AND("(c && #{TRUE}) || (!c && #{FALSE})");
180         private final String expression;
181 
182         private Expression(String expression) {
183             this.expression = expression;
184         }
185 
186         @Override
187         public String expand(String optParameter) {
188             return expression;
189         }
190     }
191     public enum TestOrDummy implements ComboParameter {
192         TEST("!(#{SNIPPET})"),
193         DUMMY("input.getClass() == Integer.class");
194         private final String code;
195         private TestOrDummy(String code) {
196             this.code = code;
197         }
198         @Override
199         public String expand(String optParameter) {
200             return code;
201         }
202     }
203     public enum Snippet implements ComboParameter {
204         PATTERN("input instanceof String sX"),
205         SWITCH_EXPRESSION("switch (len) { case 16 -> {boolean r = true; yield r; } default -> {boolean r = false; yield r; } }"),
206         SWITCH_EXPRESSION_STRING("switch (clazzName) { case \"java.lang.String\"-> {boolean r = true; yield r; } default -> {boolean r = false; yield r; } }");
207         private static int idx;
208         private final String snippet;
209 
210         private Snippet(String snippet) {
211             this.snippet = snippet;
212         }
213 
214         @Override
215         public String expand(String optParameter) {
216             return snippet.replace("sX", "s" + idx++);
217         }
218 
219     }
220 }