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