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