1 /*
  2  * Copyright (c) 2021, 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 8260593
 27  * @summary Verify that a temporary storage variable is or is not used as needed when pattern matching.
 28  * @library /tools/lib /tools/javac/lib
 29  * @modules
 30  *      jdk.compiler/com.sun.tools.javac.api
 31  *      jdk.compiler/com.sun.tools.javac.file
 32  *      jdk.compiler/com.sun.tools.javac.main
 33  *      jdk.compiler/com.sun.tools.javac.util
 34  * @build toolbox.ToolBox toolbox.JavacTask
 35  * @build combo.ComboTestHelper
 36  * @compile LocalVariableReuse.java
 37  * @run main LocalVariableReuse
 38  */
 39 
 40 import combo.ComboInstance;
 41 import combo.ComboParameter;
 42 import combo.ComboTask;
 43 import combo.ComboTestHelper;
 44 import java.io.IOException;
 45 import javax.tools.JavaFileObject;
 46 import toolbox.ToolBox;
 47 
 48 public class LocalVariableReuse extends ComboInstance<LocalVariableReuse> {
 49     protected ToolBox tb;
 50 
 51     LocalVariableReuse() {
 52         super();
 53         tb = new ToolBox();
 54     }
 55 
 56     public static void main(String... args) throws Exception {
 57         new ComboTestHelper<LocalVariableReuse>()
 58                 .withDimension("CODE", (x, code) -> x.code = code, Code.values())
 59                 .run(LocalVariableReuse::new);
 60     }
 61 
 62     private Code code;
 63 
 64     private static final String MAIN_TEMPLATE =
 65             """
 66             public class Test {
 67                 #{CODE}
 68             }
 69             """;
 70 
 71     @Override
 72     protected void doWork() throws Throwable {
 73         ComboTask task = newCompilationTask()
 74                 .withSourceFromTemplate(MAIN_TEMPLATE, pname -> switch (pname) {
 75                         case "CODE" -> code;
 76                         default -> throw new UnsupportedOperationException(pname);
 77                     });
 78 
 79         task.withOption("-printsource");
 80         task.generate(result -> {
 81             for (JavaFileObject out : result.get()) {
 82                 try {
 83                     String actualDesugared = out.getCharContent(false).toString();
 84                     boolean hasTempVar = actualDesugared.contains("$temp");
 85                     if (hasTempVar != code.useTemporaryVariable) {
 86                         throw new AssertionError("Expected temporary variable: " + code.useTemporaryVariable +
 87                                                   ", but got: " + actualDesugared);
 88                     }
 89                 } catch (IOException ex) {
 90                     throw new AssertionError(ex);
 91                 }
 92             }
 93         });
 94     }
 95 
 96     public enum Code implements ComboParameter {
 97         LOCAL_VARIABLE(
 98                 """
 99                 private boolean test() {
100                     Object o = null;
101                     return o instanceof String s && s.length() > 0;
102                 }
103                 """, false),
104         PARAMETER(
105                 """
106                 private boolean test(Object o) {
107                     return o instanceof String s && s.length() > 0;
108                 }
109                 """, false),
110         LAMBDA_PARAMETER(
111                 """
112                 private void test(Object o) {
113                     I i = o -> o instanceof String s && s.length() > 0;
114                 interface I {
115                     public boolean run(Object o);
116                 }
117                 """, false),
118         EXCEPTION(
119                 """
120                 private boolean test() {
121                     try {
122                         throw new Exception();
123                     } catch (Exception o) {
124                         return o instanceof RuntimeException re && re.getMessage() != null;
125                     }
126                 }
127                 """, false),
128         RESOURCE(
129                 """
130                 private boolean test() throws Exception {
131                     try (AutoCloseable r = null) {
132                         return r instanceof java.io.InputStream in && in.read() != (-1);
133                     } catch (Exception o) {
134                     }
135                 }
136                 """, false),
137         FIELD("""
138               private Object o;
139               private boolean test() {
140                   return o instanceof String s && s.length() > 0;
141               }
142               """,
143               true),
144         FINAL_FIELD("""
145               private final Object o;
146               private boolean test() {
147                   return o instanceof String s && s.length() > 0;
148               }
149               """,
150               true),
151         ARRAY_ACCESS("""
152               private boolean test() {
153                   Object[] o = null;
154                   return o[0] instanceof String s && s.length() > 0;
155               }
156               """,
157               true),
158         METHOD_INVOCATION("""
159               private boolean test() {
160                   return get() instanceof String s && s.length() > 0;
161               }
162               private Object get() {
163                   return null;
164               }
165               """,
166               true),
167         ;
168         private final String body;
169         private final boolean useTemporaryVariable;
170 
171         private Code(String body, boolean useTemporaryVariable) {
172             this.body = body;
173             this.useTemporaryVariable = useTemporaryVariable;
174         }
175 
176         @Override
177         public String expand(String optParameter) {
178             return body;
179         }
180     }
181 
182 }