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