1 /*
   2  * Copyright (c) 2018, 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 import java.io.IOException;
  25 import java.util.List;
  26 
  27 import org.testng.ITestResult;
  28 import org.testng.annotations.AfterMethod;
  29 import org.testng.annotations.Test;
  30 import tools.javac.combo.JavacTemplateTestBase;
  31 
  32 import static java.util.stream.Collectors.toList;
  33 
  34 @Test
  35 public class ExpSwitchNestingTest extends JavacTemplateTestBase {
  36     private static final String RUNNABLE = "Runnable r = () -> { # };";
  37     private static final String INT_FN = "java.util.function.IntSupplier r = () -> { # };";
  38     private static final String LABEL = "label: #";
  39     private static final String DEF_LABEL_VAR = "int label = 0; { # }";
  40     private static final String FOR = "for (int i=0; i<10; i++) { # }";
  41     private static final String FOR_EACH = "for (int i : new int[] {}) { # }";
  42     private static final String WHILE = "while (cond) { # }";
  43     private static final String DO = "do { # } while (cond);";
  44     private static final String SSWITCH = "switch (x) { case 0: # };";
  45     private static final String ESWITCH_Z = "int res = switch (x) { case 0 -> { # } default -> 0; };";
  46     private static final String ESWITCH_S = "String res_string = switch (x) { case 0 -> { # } default -> \"default\"; };";
  47     private static final String INT_FN_ESWITCH = "java.util.function.IntSupplier r = switch (x) { case 0 -> { # } default -> null; };";
  48     private static final String INT_ESWITCH_DEFAULT = "int res = switch (x) { default -> { # } };";
  49     private static final String IF = "if (cond) { # } else throw new RuntimeException();";
  50     private static final String BLOCK = "{ # }";
  51     private static final String BREAK_Z = "break 0;";
  52     private static final String BREAK_S = "break \"hello world\";";
  53     private static final String BREAK_INT_FN = "break () -> 0 ;";
  54     private static final String BREAK_N = "break;";
  55     private static final String BREAK_L = "break label;";
  56     private static final String RETURN_Z = "return 0;";
  57     private static final String RETURN_N = "return;";
  58     private static final String RETURN_S = "return \"Hello\";";
  59     private static final String CONTINUE_N = "continue;";
  60     private static final String CONTINUE_L = "continue label;";
  61     private static final String NOTHING = "System.out.println();";
  62 
  63     // containers that do not require exhaustiveness
  64     private static final List<String> CONTAINERS
  65             = List.of(RUNNABLE, FOR, WHILE, DO, SSWITCH, IF, BLOCK);
  66     // containers that do not require exhaustiveness that are statements
  67     private static final List<String> CONTAINER_STATEMENTS
  68             = List.of(FOR, WHILE, DO, SSWITCH, IF, BLOCK);
  69 
  70     @AfterMethod
  71     public void dumpTemplateIfError(ITestResult result) {
  72         // Make sure offending template ends up in log file on failure
  73         if (!result.isSuccess()) {
  74             System.err.printf("Diagnostics: %s%nTemplate: %s%n", diags.errorKeys(), sourceFiles.stream().map(p -> p.snd).collect(toList()));
  75         }
  76     }
  77 
  78     private void program(String... constructs) {
  79         String s = "class C { static boolean cond = false; static int x = 0; void m() { # } }";
  80         for (String c : constructs)
  81             s = s.replace("#", c);
  82         addSourceFile("C.java", new StringTemplate(s));
  83     }
  84 
  85     private void assertOK(String... constructs) {
  86         reset();
  87         addCompileOptions("--enable-preview", "-source", "12");
  88         program(constructs);
  89         try {
  90             compile();
  91         }
  92         catch (IOException e) {
  93             throw new RuntimeException(e);
  94         }
  95         assertCompileSucceeded();
  96     }
  97 
  98     private void assertOKWithWarning(String warning, String... constructs) {
  99         reset();
 100         addCompileOptions("--enable-preview", "-source", "12");
 101         program(constructs);
 102         try {
 103             compile();
 104         }
 105         catch (IOException e) {
 106             throw new RuntimeException(e);
 107         }
 108         assertCompileSucceededWithWarning(warning);
 109     }
 110 
 111     private void assertFail(String expectedDiag, String... constructs) {
 112         reset();
 113         addCompileOptions("--enable-preview", "-source", "12");
 114         program(constructs);
 115         try {
 116             compile();
 117         }
 118         catch (IOException e) {
 119             throw new RuntimeException(e);
 120         }
 121         assertCompileFailed(expectedDiag);
 122     }
 123 
 124     public void testReallySimpleCases() {
 125         for (String s : CONTAINERS)
 126             assertOK(s, NOTHING);
 127         for (String s : CONTAINER_STATEMENTS)
 128             assertOK(LABEL, s, NOTHING);
 129     }
 130 
 131     public void testLambda() {
 132         assertOK(RUNNABLE, RETURN_N);
 133         assertOK(RUNNABLE, NOTHING);
 134         assertOK(INT_FN, RETURN_Z);
 135         assertFail("compiler.err.break.outside.switch.loop", RUNNABLE, BREAK_N);
 136         assertFail("compiler.err.break.complex.value.no.switch.expression", RUNNABLE, BREAK_Z);
 137         assertFail("compiler.err.break.complex.value.no.switch.expression", RUNNABLE, BREAK_S);
 138         assertFail("compiler.err.break.outside.switch.loop", INT_FN, BREAK_N);
 139         assertFail("compiler.err.break.complex.value.no.switch.expression", INT_FN, BREAK_Z);
 140         assertFail("compiler.err.break.complex.value.no.switch.expression", INT_FN, BREAK_S);
 141         assertFail("compiler.err.cont.outside.loop", RUNNABLE, CONTINUE_N);
 142         assertFail("compiler.err.undef.label", RUNNABLE, BREAK_L);
 143         assertFail("compiler.err.undef.label", RUNNABLE, CONTINUE_L);
 144         assertFail("compiler.err.cont.outside.loop", INT_FN, CONTINUE_N);
 145         assertFail("compiler.err.undef.label", INT_FN, BREAK_L);
 146         assertFail("compiler.err.undef.label", INT_FN, CONTINUE_L);
 147         assertFail("compiler.err.undef.label", LABEL, BLOCK, RUNNABLE, BREAK_L);
 148         assertFail("compiler.err.undef.label", LABEL, BLOCK, RUNNABLE, CONTINUE_L);
 149         assertFail("compiler.err.undef.label", LABEL, BLOCK, INT_FN, BREAK_L);
 150         assertFail("compiler.err.undef.label", LABEL, BLOCK, INT_FN, CONTINUE_L);
 151     }
 152 
 153     public void testEswitch() {
 154         //Int-valued switch expressions
 155         assertOK(ESWITCH_Z, BREAK_Z);
 156         assertOK(LABEL, BLOCK, ESWITCH_Z, BREAK_Z);
 157         assertFail("compiler.err.break.missing.value", ESWITCH_Z, BREAK_N);
 158         assertFail("compiler.err.prob.found.req", ESWITCH_Z, BREAK_S);
 159         assertFail("compiler.err.cant.resolve.location", ESWITCH_Z, BREAK_L);
 160         assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, ESWITCH_Z, BREAK_L);
 161         assertFail("compiler.err.undef.label", ESWITCH_Z, CONTINUE_L);
 162         assertFail("compiler.err.cont.outside.loop", ESWITCH_Z, CONTINUE_N);
 163         assertFail("compiler.err.return.outside.switch.expression", ESWITCH_Z, RETURN_N);
 164         assertFail("compiler.err.return.outside.switch.expression", ESWITCH_Z, RETURN_Z);
 165 
 166         assertOK(INT_ESWITCH_DEFAULT, BREAK_Z);
 167         assertFail("compiler.err.break.missing.value", INT_ESWITCH_DEFAULT, BREAK_N);
 168         assertFail("compiler.err.prob.found.req", INT_ESWITCH_DEFAULT, BREAK_S);
 169         assertFail("compiler.err.cant.resolve.location", INT_ESWITCH_DEFAULT, BREAK_L);
 170 
 171 
 172         // String-valued switch expressions
 173         assertOK(ESWITCH_S, BREAK_S);
 174         assertOK(LABEL, BLOCK, ESWITCH_S, BREAK_S);
 175         assertFail("compiler.err.break.missing.value", ESWITCH_S, BREAK_N);
 176         assertFail("compiler.err.prob.found.req", ESWITCH_S, BREAK_Z);
 177         assertFail("compiler.err.cant.resolve.location", ESWITCH_S, BREAK_L);
 178         assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, ESWITCH_S, BREAK_L);
 179         assertFail("compiler.err.undef.label", ESWITCH_S, CONTINUE_L);
 180         assertFail("compiler.err.cont.outside.loop", ESWITCH_S, CONTINUE_N);
 181         assertFail("compiler.err.return.outside.switch.expression", ESWITCH_S, RETURN_N);
 182         assertFail("compiler.err.return.outside.switch.expression", ESWITCH_S, RETURN_S);
 183         // Function-valued switch expression
 184         assertOK(INT_FN_ESWITCH, BREAK_INT_FN);
 185         assertFail("compiler.err.break.missing.value", INT_FN_ESWITCH, BREAK_N);
 186         assertFail("compiler.err.prob.found.req", INT_FN_ESWITCH, BREAK_Z);
 187         assertFail("compiler.err.prob.found.req", INT_FN_ESWITCH, BREAK_S);
 188 
 189         assertFail("compiler.err.cant.resolve.location", INT_FN_ESWITCH, BREAK_L);
 190         assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, INT_FN_ESWITCH, BREAK_L);
 191         assertFail("compiler.err.undef.label", INT_FN_ESWITCH, CONTINUE_L);
 192         assertFail("compiler.err.cont.outside.loop", INT_FN_ESWITCH, CONTINUE_N);
 193         assertFail("compiler.err.return.outside.switch.expression", INT_FN_ESWITCH, RETURN_N);
 194         assertFail("compiler.err.return.outside.switch.expression", INT_FN_ESWITCH, RETURN_S);
 195 
 196     }
 197 
 198     public void testNestedInExpSwitch() {
 199         assertOK(ESWITCH_Z, IF,     BREAK_Z);
 200         assertOK(ESWITCH_Z, BLOCK,  BREAK_Z);
 201         //
 202         assertOK(ESWITCH_Z, IF,     IF,     BREAK_Z);
 203         assertOK(ESWITCH_Z, IF,     BLOCK,  BREAK_Z);
 204         assertOK(ESWITCH_Z, BLOCK,  IF,     BREAK_Z);
 205         assertOK(ESWITCH_Z, BLOCK,  BLOCK,  BREAK_Z);
 206         //
 207         assertOK(ESWITCH_Z, IF,     IF,     IF,     BREAK_Z);
 208         assertOK(ESWITCH_Z, IF,     IF,     BLOCK,  BREAK_Z);
 209         assertOK(ESWITCH_Z, IF,     BLOCK,  IF,     BREAK_Z);
 210         assertOK(ESWITCH_Z, IF,     BLOCK,  BLOCK,  BREAK_Z);
 211         assertOK(ESWITCH_Z, BLOCK,  IF,     IF,     BREAK_Z);
 212         assertOK(ESWITCH_Z, BLOCK,  IF,     BLOCK,  BREAK_Z);
 213         assertOK(ESWITCH_Z, BLOCK,  BLOCK,  IF,     BREAK_Z);
 214         assertOK(ESWITCH_Z, BLOCK,  BLOCK,  BLOCK,  BREAK_Z);
 215         //
 216         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, SSWITCH, BREAK_Z);
 217         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, FOR, BREAK_Z);
 218         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, WHILE, BREAK_Z);
 219         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, DO, BREAK_Z);
 220         assertFail("compiler.err.break.complex.value.no.switch.expression", ESWITCH_Z, INT_FN, BREAK_Z);
 221         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, SSWITCH, IF, BREAK_Z);
 222         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, FOR, IF, BREAK_Z);
 223         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, WHILE, IF, BREAK_Z);
 224         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, DO, IF, BREAK_Z);
 225         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, SSWITCH, IF, BREAK_Z);
 226         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, FOR, IF, BREAK_Z);
 227         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, WHILE, IF, BREAK_Z);
 228         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, DO, IF, BREAK_Z);
 229     }
 230 
 231     public void testBreakExpressionLabelDisambiguation() {
 232         assertOK(DEF_LABEL_VAR, ESWITCH_Z, BREAK_L);
 233         assertFail("compiler.err.break.ambiguous.target", LABEL, FOR, BLOCK, DEF_LABEL_VAR, ESWITCH_Z, BREAK_L);
 234         assertFail("compiler.err.break.ambiguous.target", DEF_LABEL_VAR, ESWITCH_Z, LABEL, FOR, BREAK_L); //label break
 235         assertFail("compiler.err.break.ambiguous.target", DEF_LABEL_VAR, LABEL, BLOCK, ESWITCH_Z, BREAK_L); //expression break
 236         //
 237     }
 238 
 239     public void testFunReturningSwitchExp() {
 240         assertOK(INT_FN_ESWITCH, BREAK_INT_FN);
 241     }
 242 
 243     public void testContinueLoops() {
 244         assertOK(LABEL, FOR, CONTINUE_L);
 245         assertOK(LABEL, FOR_EACH, CONTINUE_L);
 246         assertOK(LABEL, WHILE, CONTINUE_L);
 247         assertOK(LABEL, DO, CONTINUE_L);
 248         assertFail("compiler.err.not.loop.label", LABEL, CONTINUE_L);
 249     }
 250 }