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