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