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 8234922 27 * @summary Verify proper scope of binding related to loops and breaks. 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 BreakAndLoops.java 38 * @run main BreakAndLoops 39 */ 40 41 import combo.ComboInstance; 42 import combo.ComboParameter; 43 import combo.ComboTask; 44 import combo.ComboTestHelper; 45 import java.nio.file.Path; 46 import java.nio.file.Paths; 47 import toolbox.ToolBox; 48 49 public class BreakAndLoops extends ComboInstance<BreakAndLoops> { 50 protected ToolBox tb; 51 52 BreakAndLoops() { 53 super(); 54 tb = new ToolBox(); 55 } 56 57 public static void main(String... args) throws Exception { 58 new ComboTestHelper<BreakAndLoops>() 59 .withDimension("OUTTER_LABEL", (x, outterLabel) -> x.outterLabel = outterLabel, OutterLabel.values()) 60 .withDimension("OUTTER_LOOP", (x, outterLoop) -> x.outterLoop = outterLoop, OutterLoop.values()) 61 .withDimension("MAIN_LOOP", (x, mainLoop) -> x.mainLoop = mainLoop, MainLoop.values()) 62 .withDimension("INNER_LABEL", (x, innerLabel) -> x.innerLabel = innerLabel, Label.values()) 63 .withDimension("INNER_LOOP", (x, innerLoop) -> x.innerLoop = innerLoop, Loop.values()) 64 .withDimension("BREAK", (x, brk) -> x.brk = brk, Break.values()) 65 .withFilter(bal -> bal.outterLabel != OutterLabel.LABEL || bal.innerLabel != Label.LABEL) 66 .run(BreakAndLoops::new); 67 } 68 69 private OutterLabel outterLabel; 70 private OutterLoop outterLoop; 71 private MainLoop mainLoop; 72 private Label innerLabel; 73 private Loop innerLoop; 74 private Break brk; 75 76 private static final String MAIN_TEMPLATE = 77 """ 78 public class Test { 79 public static void doTest(Object o, int i, Object[] arr) { 80 #{OUTTER_LABEL} 81 } 82 } 83 """; 84 85 @Override 86 protected void doWork() throws Throwable { 87 Path base = Paths.get("."); 88 89 ComboTask task = newCompilationTask() 90 .withSourceFromTemplate(MAIN_TEMPLATE, pname -> switch (pname) { 91 case "OUTTER_LABEL" -> outterLabel; 92 case "OUTTER_LOOP" -> outterLoop; 93 case "MAIN_LOOP" -> mainLoop; 94 case "NESTED_LOOP" -> innerLoop; 95 case "NESTED" -> brk; 96 case "BODY" -> innerLabel; 97 default -> throw new UnsupportedOperationException(pname); 98 }); 99 100 task.generate(result -> { 101 boolean shouldPass; 102 if (brk == Break.NONE) { 103 shouldPass = true; 104 } else if (innerLabel == Label.LABEL && brk == Break.BREAK_LABEL) { 105 shouldPass = true; 106 } else if (innerLoop.supportsAnonymousBreak && brk == Break.BREAK) { 107 shouldPass = true; 108 } else if (outterLabel == OutterLabel.LABEL && brk == Break.BREAK_LABEL && outterLoop != OutterLoop.NONE) { 109 shouldPass = switch(mainLoop) { 110 case WHILE, FOR -> true; 111 case DO_WHILE -> switch (innerLoop) { 112 case WHILE, FOR, FOR_EACH -> true; 113 //the statement following the do-while is unreachable: 114 case BLOCK, DO_WHILE, NONE -> { 115 yield false; 116 } 117 }; 118 }; 119 } else { 120 shouldPass = false; 121 } 122 if (!(shouldPass ^ result.hasErrors())) { 123 throw new AssertionError("Unexpected result: " + result.compilationInfo()); 124 } 125 }); 126 } 127 128 public enum MainLoop implements ComboParameter { 129 WHILE(""" 130 while (!(o instanceof String s)) { 131 #{BODY} 132 } 133 """), 134 FOR(""" 135 for( ; !(o instanceof String s) ; ) { 136 #{BODY} 137 } 138 """), 139 DO_WHILE(""" 140 do { 141 #{BODY} 142 } while (!(o instanceof String s)); 143 """); 144 private final String body; 145 146 private MainLoop(String body) { 147 this.body = body; 148 } 149 150 @Override 151 public String expand(String optParameter) { 152 return body; 153 } 154 } 155 156 public enum OutterLabel implements ComboParameter { 157 NONE("#{OUTTER_LOOP}"), 158 LABEL("LABEL: #{OUTTER_LOOP}"); 159 private final String code; 160 161 private OutterLabel(String code) { 162 this.code = code; 163 } 164 165 @Override 166 public String expand(String optParameter) { 167 return code; 168 } 169 } 170 171 public enum OutterLoop implements ComboParameter { 172 NONE("#{MAIN_LOOP} System.err.println(s);"), 173 BLOCK("{ #{MAIN_LOOP} System.err.println(s); }"), 174 WHILE("while (i-- > 0) { #{MAIN_LOOP} System.err.println(s); }"), 175 FOR("for ( ; i-- > 0; ) { #{MAIN_LOOP} System.err.println(s); }"), 176 FOR_EACH("for (Object outterO : arr) { #{MAIN_LOOP} System.err.println(s); }"), 177 DO_WHILE("do { #{MAIN_LOOP} System.err.println(s); } while (i-- > 0);"); 178 private final String code; 179 180 private OutterLoop(String code) { 181 this.code = code; 182 } 183 184 @Override 185 public String expand(String optParameter) { 186 return code; 187 } 188 } 189 190 public enum Label implements ComboParameter { 191 NONE("#{NESTED_LOOP}"), 192 LABEL("LABEL: #{NESTED_LOOP}"); 193 private final String code; 194 195 private Label(String code) { 196 this.code = code; 197 } 198 199 @Override 200 public String expand(String optParameter) { 201 return code; 202 } 203 } 204 205 public enum Loop implements ComboParameter { 206 NONE("#{NESTED}", false), 207 BLOCK("{ #{NESTED} }", false), 208 WHILE("while (i-- > 0) { #{NESTED} }", true), 209 FOR("for ( ; i-- > 0; ) { #{NESTED} }", true), 210 FOR_EACH("for (Object innerO : arr) { #{NESTED} }", true), 211 DO_WHILE("do { #{NESTED} } while (i-- > 0);", true); 212 private final String code; 213 private final boolean supportsAnonymousBreak; 214 215 private Loop(String code, boolean supportsAnonymousBreak) { 216 this.code = code; 217 this.supportsAnonymousBreak = supportsAnonymousBreak; 218 } 219 220 @Override 221 public String expand(String optParameter) { 222 return code; 223 } 224 } 225 226 public enum Break implements ComboParameter { 227 NONE(";"), 228 BREAK("break;"), 229 BREAK_LABEL("break LABEL;"); 230 private final String code; 231 232 private Break(String code) { 233 this.code = code; 234 } 235 236 @Override 237 public String expand(String optParameter) { 238 return code; 239 } 240 } 241 }