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 static String[] PREVIEW_OPTIONS = {"--enable-preview", "-source", "13"};
  79 
  80     private void program(String... constructs) {
  81         String s = "class C { static boolean cond = false; static int x = 0; void m() { # } }";
  82         for (String c : constructs)
  83             s = s.replace("#", c);
  84         addSourceFile("C.java", new StringTemplate(s));
  85     }
  86 
  87     private void assertOK(String... constructs) {
  88         reset();
  89         addCompileOptions(PREVIEW_OPTIONS);
  90         program(constructs);
  91         try {
  92             compile();
  93         }
  94         catch (IOException e) {
  95             throw new RuntimeException(e);
  96         }
  97         assertCompileSucceeded();
  98     }
  99 
 100     private void assertOKWithWarning(String warning, String... constructs) {
 101         reset();
 102         addCompileOptions(PREVIEW_OPTIONS);
 103         program(constructs);
 104         try {
 105             compile();
 106         }
 107         catch (IOException e) {
 108             throw new RuntimeException(e);
 109         }
 110         assertCompileSucceededWithWarning(warning);
 111     }
 112 
 113     private void assertFail(String expectedDiag, String... constructs) {
 114         reset();
 115         addCompileOptions(PREVIEW_OPTIONS);
 116         program(constructs);
 117         try {
 118             compile();
 119         }
 120         catch (IOException e) {
 121             throw new RuntimeException(e);
 122         }
 123         assertCompileFailed(expectedDiag);
 124     }
 125 
 126     public void testReallySimpleCases() {
 127         for (String s : CONTAINERS)
 128             assertOK(s, NOTHING);
 129         for (String s : CONTAINER_STATEMENTS)
 130             assertOK(LABEL, s, NOTHING);
 131     }
 132 
 133     public void testLambda() {
 134         assertOK(RUNNABLE, RETURN_N);
 135         assertOK(RUNNABLE, NOTHING);
 136         assertOK(INT_FN, RETURN_Z);
 137         assertFail("compiler.err.break.outside.switch.loop", RUNNABLE, BREAK_N);
 138         assertFail("compiler.err.break.complex.value.no.switch.expression", RUNNABLE, BREAK_Z);
 139         assertFail("compiler.err.break.complex.value.no.switch.expression", RUNNABLE, BREAK_S);
 140         assertFail("compiler.err.break.outside.switch.loop", INT_FN, BREAK_N);
 141         assertFail("compiler.err.break.complex.value.no.switch.expression", INT_FN, BREAK_Z);
 142         assertFail("compiler.err.break.complex.value.no.switch.expression", INT_FN, BREAK_S);
 143         assertFail("compiler.err.cont.outside.loop", RUNNABLE, CONTINUE_N);
 144         assertFail("compiler.err.undef.label", RUNNABLE, BREAK_L);
 145         assertFail("compiler.err.undef.label", RUNNABLE, CONTINUE_L);
 146         assertFail("compiler.err.cont.outside.loop", INT_FN, CONTINUE_N);
 147         assertFail("compiler.err.undef.label", INT_FN, BREAK_L);
 148         assertFail("compiler.err.undef.label", INT_FN, CONTINUE_L);
 149         assertFail("compiler.err.undef.label", LABEL, BLOCK, RUNNABLE, BREAK_L);
 150         assertFail("compiler.err.undef.label", LABEL, BLOCK, RUNNABLE, CONTINUE_L);
 151         assertFail("compiler.err.undef.label", LABEL, BLOCK, INT_FN, BREAK_L);
 152         assertFail("compiler.err.undef.label", LABEL, BLOCK, INT_FN, CONTINUE_L);
 153     }
 154 
 155     public void testEswitch() {
 156         //Int-valued switch expressions
 157         assertOK(ESWITCH_Z, BREAK_Z);
 158         assertOK(LABEL, BLOCK, ESWITCH_Z, BREAK_Z);
 159         assertFail("compiler.err.break.missing.value", ESWITCH_Z, BREAK_N);
 160         assertFail("compiler.err.prob.found.req", ESWITCH_Z, BREAK_S);
 161         assertFail("compiler.err.cant.resolve.location", ESWITCH_Z, BREAK_L);
 162         assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, ESWITCH_Z, BREAK_L);
 163         assertFail("compiler.err.undef.label", ESWITCH_Z, CONTINUE_L);
 164         assertFail("compiler.err.cont.outside.loop", ESWITCH_Z, CONTINUE_N);
 165         assertFail("compiler.err.return.outside.switch.expression", ESWITCH_Z, RETURN_N);
 166         assertFail("compiler.err.return.outside.switch.expression", ESWITCH_Z, RETURN_Z);
 167 
 168         assertOK(INT_ESWITCH_DEFAULT, BREAK_Z);
 169         assertFail("compiler.err.break.missing.value", INT_ESWITCH_DEFAULT, BREAK_N);
 170         assertFail("compiler.err.prob.found.req", INT_ESWITCH_DEFAULT, BREAK_S);
 171         assertFail("compiler.err.cant.resolve.location", INT_ESWITCH_DEFAULT, BREAK_L);
 172 
 173 
 174         // String-valued switch expressions
 175         assertOK(ESWITCH_S, BREAK_S);
 176         assertOK(LABEL, BLOCK, ESWITCH_S, BREAK_S);
 177         assertFail("compiler.err.break.missing.value", ESWITCH_S, BREAK_N);
 178         assertFail("compiler.err.prob.found.req", ESWITCH_S, BREAK_Z);
 179         assertFail("compiler.err.cant.resolve.location", ESWITCH_S, BREAK_L);
 180         assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, ESWITCH_S, BREAK_L);
 181         assertFail("compiler.err.undef.label", ESWITCH_S, CONTINUE_L);
 182         assertFail("compiler.err.cont.outside.loop", ESWITCH_S, CONTINUE_N);
 183         assertFail("compiler.err.return.outside.switch.expression", ESWITCH_S, RETURN_N);
 184         assertFail("compiler.err.return.outside.switch.expression", ESWITCH_S, RETURN_S);
 185         // Function-valued switch expression
 186         assertOK(INT_FN_ESWITCH, BREAK_INT_FN);
 187         assertFail("compiler.err.break.missing.value", INT_FN_ESWITCH, BREAK_N);
 188         assertFail("compiler.err.prob.found.req", INT_FN_ESWITCH, BREAK_Z);
 189         assertFail("compiler.err.prob.found.req", INT_FN_ESWITCH, BREAK_S);
 190 
 191         assertFail("compiler.err.cant.resolve.location", INT_FN_ESWITCH, BREAK_L);
 192         assertFail("compiler.err.break.outside.switch.expression", LABEL, BLOCK, INT_FN_ESWITCH, BREAK_L);
 193         assertFail("compiler.err.undef.label", INT_FN_ESWITCH, CONTINUE_L);
 194         assertFail("compiler.err.cont.outside.loop", INT_FN_ESWITCH, CONTINUE_N);
 195         assertFail("compiler.err.return.outside.switch.expression", INT_FN_ESWITCH, RETURN_N);
 196         assertFail("compiler.err.return.outside.switch.expression", INT_FN_ESWITCH, RETURN_S);
 197 
 198     }
 199 
 200     public void testNestedInExpSwitch() {
 201         assertOK(ESWITCH_Z, IF,     BREAK_Z);
 202         assertOK(ESWITCH_Z, BLOCK,  BREAK_Z);
 203         //
 204         assertOK(ESWITCH_Z, IF,     IF,     BREAK_Z);
 205         assertOK(ESWITCH_Z, IF,     BLOCK,  BREAK_Z);
 206         assertOK(ESWITCH_Z, BLOCK,  IF,     BREAK_Z);
 207         assertOK(ESWITCH_Z, BLOCK,  BLOCK,  BREAK_Z);
 208         //
 209         assertOK(ESWITCH_Z, IF,     IF,     IF,     BREAK_Z);
 210         assertOK(ESWITCH_Z, IF,     IF,     BLOCK,  BREAK_Z);
 211         assertOK(ESWITCH_Z, IF,     BLOCK,  IF,     BREAK_Z);
 212         assertOK(ESWITCH_Z, IF,     BLOCK,  BLOCK,  BREAK_Z);
 213         assertOK(ESWITCH_Z, BLOCK,  IF,     IF,     BREAK_Z);
 214         assertOK(ESWITCH_Z, BLOCK,  IF,     BLOCK,  BREAK_Z);
 215         assertOK(ESWITCH_Z, BLOCK,  BLOCK,  IF,     BREAK_Z);
 216         assertOK(ESWITCH_Z, BLOCK,  BLOCK,  BLOCK,  BREAK_Z);
 217         //
 218         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, SSWITCH, BREAK_Z);
 219         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, FOR, BREAK_Z);
 220         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, WHILE, BREAK_Z);
 221         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, DO, BREAK_Z);
 222         assertFail("compiler.err.break.complex.value.no.switch.expression", ESWITCH_Z, INT_FN, BREAK_Z);
 223         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, SSWITCH, IF, BREAK_Z);
 224         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, FOR, IF, BREAK_Z);
 225         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, WHILE, IF, BREAK_Z);
 226         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, DO, IF, BREAK_Z);
 227         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, SSWITCH, IF, BREAK_Z);
 228         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, FOR, IF, BREAK_Z);
 229         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, WHILE, IF, BREAK_Z);
 230         assertFail("compiler.err.break.expr.not.immediate", ESWITCH_Z, BLOCK, DO, IF, BREAK_Z);
 231     }
 232 
 233     public void testBreakExpressionLabelDisambiguation() {
 234         assertOK(DEF_LABEL_VAR, ESWITCH_Z, BREAK_L);
 235         assertFail("compiler.err.break.ambiguous.target", LABEL, FOR, BLOCK, DEF_LABEL_VAR, ESWITCH_Z, BREAK_L);
 236         assertFail("compiler.err.break.ambiguous.target", DEF_LABEL_VAR, ESWITCH_Z, LABEL, FOR, BREAK_L); //label break
 237         assertFail("compiler.err.break.ambiguous.target", DEF_LABEL_VAR, LABEL, BLOCK, ESWITCH_Z, BREAK_L); //expression break
 238         //
 239     }
 240 
 241     public void testFunReturningSwitchExp() {
 242         assertOK(INT_FN_ESWITCH, BREAK_INT_FN);
 243     }
 244 
 245     public void testContinueLoops() {
 246         assertOK(LABEL, FOR, CONTINUE_L);
 247         assertOK(LABEL, FOR_EACH, CONTINUE_L);
 248         assertOK(LABEL, WHILE, CONTINUE_L);
 249         assertOK(LABEL, DO, CONTINUE_L);
 250         assertFail("compiler.err.not.loop.label", LABEL, CONTINUE_L);
 251     }
 252 }