Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java27
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java779
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java90
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java125
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java1
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties2
8 files changed, 866 insertions, 166 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java
index a5a0e5ecb2..ec6f7a7b42 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java
@@ -1049,7 +1049,6 @@ protected static class JavacTestOptions {
protected INameEnvironment javaClassLib;
protected TestVerifier verifier;
protected boolean shouldSwallowCaptureId;
- protected boolean enablePreview;
public AbstractRegressionTest(String name) {
super(name);
}
@@ -1734,6 +1733,9 @@ protected static class JavacTestOptions {
JavacTestOptions.DEFAULT /* default javac test options */);
}
protected void runConformTest(String[] testFiles, String expectedOutput, Map customOptions) {
+ runConformTest(testFiles, expectedOutput, customOptions, null);
+ }
+ protected void runConformTest(String[] testFiles, String expectedOutput, Map customOptions, String[] vmArguments) {
runTest(
// test directory preparation
true /* flush output directory */,
@@ -1748,7 +1750,7 @@ protected static class JavacTestOptions {
null /* do not check compiler log */,
// runtime options
false /* do not force execution */,
- null /* no vm arguments */,
+ vmArguments /* no vm arguments */,
// runtime results
expectedOutput /* expected output string */,
null /* do not check error string */,
@@ -2549,10 +2551,19 @@ protected void runNegativeTest(boolean skipJavac, JavacTestOptions javacTestOpti
JavacTestOptions.DEFAULT /* javac test options */);
}
protected void runNegativeTest(
+ String[] testFiles,
+ String expectedCompilerLog,
+ String[] classLibraries,
+ boolean shouldFlushOutputDirectory,
+ Map customOptions) {
+ runNegativeTest(testFiles, expectedCompilerLog, classLibraries, shouldFlushOutputDirectory, null, customOptions);
+ }
+ protected void runNegativeTest(
String[] testFiles,
String expectedCompilerLog,
String[] classLibraries,
boolean shouldFlushOutputDirectory,
+ String[] vmArguments,
Map customOptions) {
runTest(
// test directory preparation
@@ -2573,7 +2584,7 @@ protected void runNegativeTest(boolean skipJavac, JavacTestOptions javacTestOpti
expectedCompilerLog /* expected compiler log */,
// runtime options
false /* do not force execution */,
- null /* no vm arguments */,
+ vmArguments /* no vm arguments */,
// runtime results
null /* do not check output string */,
null /* do not check error string */,
@@ -3113,16 +3124,6 @@ protected void runNegativeTest(boolean skipJavac, JavacTestOptions javacTestOpti
this.verifier = new TestVerifier(false);
this.createdVerifier = true;
}
- if (this.enablePreview) {
- if (vmArguments == null) {
- vmArguments = new String[1];
- vmArguments[0] = "--enable-preview";
- } else {
- int size = vmArguments.length;
- System.arraycopy(vmArguments, 0, vmArguments = new String[size + 1], 0, size);
- vmArguments[size] = "--enable-preview";
- }
- }
boolean passed =
this.verifier.verifyClassFiles(
sourceFile,
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java
index 143f7c1757..4dc1e10c5d 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java
@@ -26,7 +26,7 @@ public class SwitchExpressionTest extends AbstractRegressionTest {
static {
// TESTS_NUMBERS = new int [] { 40 };
-// TESTS_NAMES = new String[] { "testBug531714_010" };
+// TESTS_NAMES = new String[] { "testBug543240_1" };
}
public static Class<?> testClass() {
@@ -51,37 +51,30 @@ public class SwitchExpressionTest extends AbstractRegressionTest {
public void testSimpleExpressions() {
- boolean old = this.enablePreview;
- try {
- this.enablePreview = true;
- runConformTest(
- new String[] {
+ runConformTest(
+ new String[] {
"X.java",
"public class X {\n" +
- " static int twice(int i) {\n" +
- " int tw = switch (i) {\n" +
- " case 0 -> i * 0;\n" +
- " case 1 -> 2;\n" +
- " default -> 3;\n" +
- " };\n" +
- " return tw;\n" +
- " }\n" +
- " public static void main(String... args) {\n" +
- " System.out.print(twice(3));\n" +
- " }\n" +
- "}\n"
- },
- "3");
- } finally {
- this.enablePreview = old;
- }
+ " static int twice(int i) {\n" +
+ " int tw = switch (i) {\n" +
+ " case 0 -> i * 0;\n" +
+ " case 1 -> 2;\n" +
+ " default -> 3;\n" +
+ " };\n" +
+ " return tw;\n" +
+ " }\n" +
+ " public static void main(String... args) {\n" +
+ " System.out.print(twice(3));\n" +
+ " }\n" +
+ "}\n"
+ },
+ "3",
+ null,
+ new String[] {"--enable-preview"});
}
public void testSwitchExpression_531714_002() {
- boolean old = this.enablePreview;
- try {
- this.enablePreview = true;
- runConformTest(
- new String[] {
+ runConformTest(
+ new String[] {
"X.java",
"public class X {\n"+
" static int twice(int i) throws Exception {\n"+
@@ -109,11 +102,10 @@ public class SwitchExpressionTest extends AbstractRegressionTest {
" }\n"+
" }\n"+
"}\n"
- },
- "Got Exception");
- } finally {
- this.enablePreview = old;
- }
+ },
+ "Got Exception",
+ null,
+ new String[] {"--enable-preview"});
}
public void testBug531714_error_003() {
this.runNegativeTest(
@@ -245,36 +237,32 @@ public class SwitchExpressionTest extends AbstractRegressionTest {
* dev note: ref consumeToken().case Switch
*/
public void testBug531714_error_007() {
- boolean old = this.enablePreview;
- try {
- this.enablePreview = true;
- runConformTest(
- new String[] {
+ runConformTest(
+ new String[] {
"X.java",
"public class X {\n"+
- " static int foo(int i) {\n"+
- " int tw = \n"+
- " switch (i) {\n"+
- " case 1 -> \n"+
- " {\n"+
- " int z = 100;\n"+
- " break z;\n"+
- " }\n"+
- " default -> {\n"+
- " break 12;\n"+
- " }\n"+
- " };\n"+
- " return tw;\n"+
- " }\n"+
- " public static void main(String[] args) {\n"+
- " System.out.print(foo(1));\n"+
- " }\n"+
- "}\n"
- },
- "100");
- } finally {
- this.enablePreview = old;
- }
+ " static int foo(int i) {\n"+
+ " int tw = \n"+
+ " switch (i) {\n"+
+ " case 1 -> \n"+
+ " {\n"+
+ " int z = 100;\n"+
+ " break z;\n"+
+ " }\n"+
+ " default -> {\n"+
+ " break 12;\n"+
+ " }\n"+
+ " };\n"+
+ " return tw;\n"+
+ " }\n"+
+ " public static void main(String[] args) {\n"+
+ " System.out.print(foo(1));\n"+
+ " }\n"+
+ "}\n"
+ },
+ "100",
+ null,
+ new String[] {"--enable-preview"});
}
public void testBug531714_008() {
Map<String, String> disablePreviewOptions = getCompilerOptions();
@@ -430,37 +418,32 @@ public class SwitchExpressionTest extends AbstractRegressionTest {
options);
}
public void testBug531714_011() {
- boolean old = this.enablePreview;
- try {
- Map<String, String> options = getCompilerOptions();
- options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
- options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.WARNING);
- this.enablePreview = true;
- String[] testFiles = new String[] {
- "X.java",
- "public class X {\n" +
- " @SuppressWarnings(\"preview\")\n" +
- " static int twice(int i) {\n" +
- " switch (i) {\n" +
- " default -> 3;\n" +
- " }\n" +
- " return 0;\n" +
- " }\n" +
- " public static void main(String[] args) {\n" +
- " System.out.print(twice(3));\n" +
- " }\n" +
- "}\n",
- };
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.WARNING);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ " @SuppressWarnings(\"preview\")\n" +
+ " static int twice(int i) {\n" +
+ " switch (i) {\n" +
+ " default -> 3;\n" +
+ " }\n" +
+ " return 0;\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " System.out.print(twice(3));\n" +
+ " }\n" +
+ "}\n",
+ };
- String expectedProblemLog =
- "0";
- this.runConformTest(
- testFiles,
- expectedProblemLog,
- options);
- } finally {
- this.enablePreview = old;
- }
+ String expectedProblemLog =
+ "0";
+ this.runConformTest(
+ testFiles,
+ expectedProblemLog,
+ options,
+ new String[] {"--enable-preview"});
}
public void testBug531714_012() {
Map<String, String> options = getCompilerOptions();
@@ -529,4 +512,618 @@ public class SwitchExpressionTest extends AbstractRegressionTest {
false,
new String[] { "--enable-preview"});
}
+ /*
+ * A simple multi constant case statement, compiled and run as expected
+ */
+ public void testBug543240_1() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ "public static void bar(Day day) {\n" +
+ " switch (day) {\n" +
+ " case SATURDAY, SUNDAY: \n" +
+ " System.out.println(Day.SUNDAY);\n" +
+ " break;\n" +
+ " case MONDAY : System.out.println(Day.MONDAY);\n" +
+ " break;\n" +
+ " }\n" +
+ " }" +
+ " public static void main(String[] args) {\n" +
+ " bar(Day.SATURDAY);\n" +
+ " }\n" +
+ "}\n" +
+ "enum Day { SATURDAY, SUNDAY, MONDAY;}",
+ };
+
+ String expectedProblemLog =
+ "SUNDAY";
+ this.runConformTest(
+ testFiles,
+ expectedProblemLog,
+ options,
+ new String[] { "--enable-preview"});
+ }
+ /*
+ * A simple multi constant case statement, compiler reports missing enum constants
+ */
+ public void testBug543240_1a() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " }\n" +
+ "public static void bar(Day day) {\n" +
+ " switch (day) {\n" +
+ " case SATURDAY, SUNDAY: \n" +
+ " System.out.println(Day.SUNDAY);\n" +
+ " break;\n" +
+ " case MONDAY : System.out.println(Day.MONDAY);\n" +
+ " break;\n" +
+ " }\n" +
+ " }" +
+ "}\n" +
+ "enum Day { SATURDAY, SUNDAY, MONDAY, TUESDAY;}",
+ };
+
+ String expectedProblemLog =
+ "----------\n" +
+ "1. WARNING in X.java (at line 5)\n" +
+ " switch (day) {\n" +
+ " ^^^\n" +
+ "The enum constant TUESDAY needs a corresponding case label in this enum switch on Day\n" +
+ "----------\n";
+ this.runNegativeTest(
+ testFiles,
+ expectedProblemLog,
+ null,
+ true,
+ new String[] { "--enable-preview"},
+ options);
+ }
+ /*
+ * A simple multi constant case statement with duplicate enums
+ */
+ public void testBug543240_2() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ "public static void bar(Day day) {\n" +
+ " switch (day) {\n" +
+ " case SATURDAY, SUNDAY: \n" +
+ " System.out.println(Day.SUNDAY);\n" +
+ " break;\n" +
+ " case SUNDAY : System.out.println(Day.SUNDAY);\n" +
+ " break;\n" +
+ " }\n" +
+ " }" +
+ " public static void main(String[] args) {\n" +
+ " bar(Day.SATURDAY);\n" +
+ " }\n" +
+ "}\n" +
+ "enum Day { SATURDAY, SUNDAY, MONDAY;}",
+ };
+
+ String expectedProblemLog =
+ "----------\n" +
+ "1. ERROR in X.java (at line 7)\n" +
+ " case SUNDAY : System.out.println(Day.SUNDAY);\n" +
+ " ^^^^^^^^^^^\n" +
+ "Duplicate case\n" +
+ "----------\n" +
+ "2. ERROR in X.java (at line 7)\n" +
+ " case SUNDAY : System.out.println(Day.SUNDAY);\n" +
+ " ^^^^^^^^^^^\n" +
+ "Duplicate case\n" +
+ "----------\n";
+ this.runNegativeTest(
+ testFiles,
+ expectedProblemLog,
+ null,
+ true,
+ options);
+ }
+ /*
+ * A simple multi constant case statement with duplicate enums
+ */
+ public void testBug543240_2a() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ "public static void bar(Day day) {\n" +
+ " switch (day) {\n" +
+ " case SATURDAY, SUNDAY: \n" +
+ " System.out.println(Day.SUNDAY);\n" +
+ " break;\n" +
+ " case SUNDAY, SATURDAY : \n" +
+ " System.out.println(Day.SUNDAY);\n" +
+ " break;\n" +
+ " }\n" +
+ " }" +
+ "}\n" +
+ "enum Day { SATURDAY, SUNDAY, MONDAY;}",
+ };
+
+ String expectedProblemLog =
+ "----------\n" +
+ "1. WARNING in X.java (at line 3)\n" +
+ " switch (day) {\n" +
+ " ^^^\n" +
+ "The enum constant MONDAY needs a corresponding case label in this enum switch on Day\n" +
+ "----------\n" +
+ "2. ERROR in X.java (at line 7)\n" +
+ " case SUNDAY, SATURDAY : \n" +
+ " ^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Duplicate case\n" +
+ "----------\n" +
+ "3. ERROR in X.java (at line 7)\n" +
+ " case SUNDAY, SATURDAY : \n" +
+ " ^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Duplicate case\n" +
+ "----------\n" +
+ "4. ERROR in X.java (at line 7)\n" +
+ " case SUNDAY, SATURDAY : \n" +
+ " ^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Duplicate case\n" +
+ "----------\n";
+ this.runNegativeTest(
+ testFiles,
+ expectedProblemLog,
+ null,
+ true,
+ options);
+ }
+ /*
+ *
+ */
+ public void testBug543240_3() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ "public static void bar(Day day) {\n" +
+ " switch (day) {\n" +
+ " case SATURDAY, SUNDAY: \n" +
+ " System.out.println(Day.SUNDAY);\n" +
+ " break;\n" +
+ " case TUESDAY : System.out.println(Day.SUNDAY);\n" +
+ " break;\n" +
+ " }\n" +
+ " }" +
+ " public static void main(String[] args) {\n" +
+ " bar(Day.SATURDAY);\n" +
+ " }\n" +
+ "}\n" +
+ "enum Day { SATURDAY, SUNDAY, MONDAY, TUESDAY;}",
+ };
+
+ String expectedProblemLog =
+ "----------\n" +
+ "1. WARNING in X.java (at line 3)\n" +
+ " switch (day) {\n" +
+ " ^^^\n" +
+ "The enum constant MONDAY needs a corresponding case label in this enum switch on Day\n" +
+ "----------\n";
+ this.runNegativeTest(
+ testFiles,
+ expectedProblemLog,
+ null,
+ true,
+ new String[] {"--enable-preview"},
+ options);
+ }
+ public void testBug543240_4() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ "public static void bar(Day day) {\n" +
+ " switch (day) {\n" +
+ " case SATURDAY, SUNDAY: \n" +
+ " System.out.println(day);\n" +
+ " break;\n" +
+ " case MONDAY : System.out.println(0);\n" +
+ " break;\n" +
+ " }\n" +
+ " }" +
+ " public static void main(String[] args) {\n" +
+ " bar(Day.SATURDAY);\n" +
+ " bar(Day.MONDAY);\n" +
+ " bar(Day.SUNDAY);\n" +
+ " }\n" +
+ "}\n" +
+ "enum Day { SATURDAY, SUNDAY, MONDAY;}",
+ };
+
+ String expectedProblemLog =
+ "SATURDAY\n" +
+ "0\n" +
+ "SUNDAY";
+ this.runConformTest(
+ testFiles,
+ expectedProblemLog,
+ options,
+ new String[] {"--enable-preview"});
+ }
+ /*
+ * Simple switch case with string literals
+ */
+ public void testBug543240_5() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " bar(\"a\");\n" +
+ " bar(\"b\");\n" +
+ " bar(\"c\");\n" +
+ " bar(\"d\");\n" +
+ " }\n" +
+ " public static void bar(String s) {\n" +
+ " switch(s) {\n" +
+ " case \"a\":\n" +
+ " case \"b\":\n" +
+ " System.out.println(\"A/B\");\n" +
+ " break;\n" +
+ " case \"c\":\n" +
+ " System.out.println(\"C\");\n" +
+ " break;\n" +
+ " default:\n" +
+ " System.out.println(\"NA\");\n" +
+ " }\n" +
+ " }\n" +
+ "}",
+ };
+ String expectedProblemLog =
+ "A/B\n" +
+ "A/B\n" +
+ "C\n" +
+ "NA";
+ this.runConformTest(
+ testFiles,
+ expectedProblemLog,
+ options,
+ new String[] {"--enable-preview"});
+ }
+ public void testBug543240_6() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " bar(\"a\");\n" +
+ " bar(\"b\");\n" +
+ " bar(\"c\");\n" +
+ " bar(\"d\");\n" +
+ " }\n" +
+ " public static void bar(String s) {\n" +
+ " switch(s) {\n" +
+ " case \"a\", \"b\":\n" +
+ " System.out.println(\"A/B\");\n" +
+ " break;\n" +
+ " case \"c\":\n" +
+ " System.out.println(\"C\");\n" +
+ " break;\n" +
+ " default:\n" +
+ " System.out.println(\"NA\");\n" +
+ " }\n" +
+ " }\n" +
+ "}",
+ };
+ String expectedProblemLog =
+ "A/B\n" +
+ "A/B\n" +
+ "C\n" +
+ "NA";
+ this.runConformTest(
+ testFiles,
+ expectedProblemLog,
+ options,
+ new String[] {"--enable-preview"});
+ }
+ /*
+ * Switch with multi constant case statements with string literals
+ * two string literals with same hashcode
+ */
+ public void testBug543240_7() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " bar(\"FB\");\n" +
+ " bar(\"Ea\");\n" +
+ " bar(\"c\");\n" +
+ " bar(\"D\");\n" +
+ " }\n" +
+ " public static void bar(String s) {\n" +
+ " switch(s) {\n" +
+ " case \"FB\", \"c\":\n" +
+ " System.out.println(\"A\");\n" +
+ " break;\n" +
+ " case \"Ea\":\n" +
+ " System.out.println(\"B\");\n" +
+ " break;\n" +
+ " default:\n" +
+ " System.out.println(\"NA\");\n" +
+ " }\n" +
+ " }\n" +
+ "}",
+ };
+ String expectedProblemLog =
+ "A\n" +
+ "B\n" +
+ "A\n" +
+ "NA";
+ this.runConformTest(
+ testFiles,
+ expectedProblemLog,
+ options,
+ new String[] {"--enable-preview"});
+ }
+ /*
+ * Switch with multi constant case statements with integer constants
+ */
+ public void testBug543240_8() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " bar(1);\n" +
+ " bar(2);\n" +
+ " bar(3);\n" +
+ " bar(4);\n" +
+ " bar(5);\n" +
+ " }\n" +
+ " public static void bar(int i) {\n" +
+ " switch (i) {\n" +
+ " case 1, 3: \n" +
+ " System.out.println(\"Odd\");\n" +
+ " break;\n" +
+ " case 2, 4: \n" +
+ " System.out.println(\"Even\");\n" +
+ " break;\n" +
+ " default:\n" +
+ " System.out.println(\"Out of range\");\n" +
+ " }\n" +
+ " }\n" +
+ "}",
+ };
+ String expectedProblemLog =
+ "Odd\n" +
+ "Even\n" +
+ "Odd\n" +
+ "Even\n" +
+ "Out of range";
+ this.runConformTest(
+ testFiles,
+ expectedProblemLog,
+ options,
+ new String[] {"--enable-preview"});
+ }
+ /*
+ * Switch multi-constant with mixed constant types, reported
+ */
+ public void testBug543240_9() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " }\n" +
+ " public static void bar(int i) {\n" +
+ " switch (i) {\n" +
+ " case 1, 3: \n" +
+ " System.out.println(\"Odd\");\n" +
+ " break;\n" +
+ " case \"2\": \n" +
+ " System.out.println(\"Even\");\n" +
+ " break;\n" +
+ " default:\n" +
+ " System.out.println(\"Out of range\");\n" +
+ " }\n" +
+ " }\n" +
+ "}",
+ };
+ String expectedProblemLog =
+ "----------\n" +
+ "1. ERROR in X.java (at line 9)\n" +
+ " case \"2\": \n" +
+ " ^^^\n" +
+ "Type mismatch: cannot convert from String to int\n" +
+ "----------\n";
+ this.runNegativeTest(
+ testFiles,
+ expectedProblemLog,
+ null,
+ true,
+ options);
+ }
+ /*
+ * Switch multi-constant without break statement, reported
+ */
+ public void testBug543240_10() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+ options.put(CompilerOptions.OPTION_ReportFallthroughCase, CompilerOptions.WARNING);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " }\n" +
+ " public static void bar(int i) {\n" +
+ " switch (i) {\n" +
+ " case 1, 3: \n" +
+ " System.out.println(\"Odd\");\n" +
+ " case 2, 4: \n" +
+ " System.out.println(\"Even\");\n" +
+ " break;\n" +
+ " default:\n" +
+ " System.out.println(\"Out of range\");\n" +
+ " }\n" +
+ " }\n" +
+ "}",
+ };
+ String expectedProblemLog =
+ "----------\n" +
+ "1. WARNING in X.java (at line 8)\n" +
+ " case 2, 4: \n" +
+ " ^^^^^^^^^\n" +
+ "Switch case may be entered by falling through previous case. If intended, add a new comment //$FALL-THROUGH$ on the line above\n" +
+ "----------\n";
+ this.runNegativeTest(
+ testFiles,
+ expectedProblemLog,
+ null,
+ true,
+ new String[] { "--enable-preview"},
+ options);
+ }
+ /*
+ * Switch multi-constant without break statement, reported
+ */
+ public void testBug543240_11() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+ options.put(CompilerOptions.OPTION_ReportMissingDefaultCase, CompilerOptions.WARNING);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " }\n" +
+ " public static void bar(int i) {\n" +
+ " switch (i) {\n" +
+ " case 1, 3: \n" +
+ " System.out.println(\"Odd\");\n" +
+ " case 2, 4: \n" +
+ " System.out.println(\"Even\");\n" +
+ " }\n" +
+ " }\n" +
+ "}",
+ };
+ String expectedProblemLog =
+ "----------\n" +
+ "1. WARNING in X.java (at line 5)\n" +
+ " switch (i) {\n" +
+ " ^\n" +
+ "The switch statement should have a default case\n" +
+ "----------\n";
+ this.runNegativeTest(
+ testFiles,
+ expectedProblemLog,
+ null,
+ true,
+ new String[] { "--enable-preview"},
+ options);
+ }
+ /*
+ * Switch multi-constant with duplicate int constants
+ */
+ public void testBug543240_12() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " }\n" +
+ " public static void bar(int i) {\n" +
+ " switch (i) {\n" +
+ " case 1, 3: \n" +
+ " System.out.println(\"Odd\");\n" +
+ " case 3, 4: \n" +
+ " System.out.println(\"Odd\");\n" +
+ " }\n" +
+ " }\n" +
+ "}",
+ };
+ String expectedProblemLog =
+ "----------\n" +
+ "1. ERROR in X.java (at line 8)\n" +
+ " case 3, 4: \n" +
+ " ^^^^^^^^^\n" +
+ "Duplicate case\n" +
+ "----------\n" +
+ "2. ERROR in X.java (at line 8)\n" +
+ " case 3, 4: \n" +
+ " ^^^^^^^^^\n" +
+ "Duplicate case\n" +
+ "----------\n";
+ this.runNegativeTest(
+ testFiles,
+ expectedProblemLog,
+ null,
+ true,
+ options);
+ }
+ /*
+ * Switch multi-constant with duplicate String literals
+ */
+ public void testBug543240_13() {
+ Map<String, String> options = getCompilerOptions();
+ options.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED);
+ options.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.IGNORE);
+ String[] testFiles = new String[] {
+ "X.java",
+ "public class X {\n" +
+ " public static void main(String[] args) {\n" +
+ " }\n" +
+ " public static void bar(String s) {\n" +
+ " switch (s) {\n" +
+ " case \"a\", \"b\": \n" +
+ " System.out.println(\"Odd\");\n" +
+ " case \"b\", \"c\": \n" +
+ " System.out.println(\"Odd\");\n" +
+ " }\n" +
+ " }\n" +
+ "}",
+ };
+ String expectedProblemLog =
+ "----------\n" +
+ "1. ERROR in X.java (at line 8)\n" +
+ " case \"b\", \"c\": \n" +
+ " ^^^^^^^^^^^^^\n" +
+ "Duplicate case\n" +
+ "----------\n" +
+ "2. ERROR in X.java (at line 8)\n" +
+ " case \"b\", \"c\": \n" +
+ " ^^^^^^^^^^^^^\n" +
+ "Duplicate case\n" +
+ "----------\n";
+ this.runNegativeTest(
+ testFiles,
+ expectedProblemLog,
+ null,
+ true,
+ options);
+ }
} \ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
index 849f870daa..5c41e1144b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
@@ -17,6 +17,9 @@
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
+import java.util.ArrayList;
+import java.util.List;
+
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.BranchLabel;
@@ -25,6 +28,7 @@ import org.eclipse.jdt.internal.compiler.flow.FlowContext;
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.impl.IntConstant;
+//import org.eclipse.jdt.internal.compiler.impl.IntConstant;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
@@ -49,13 +53,23 @@ public FlowInfo analyseCode(
BlockScope currentScope,
FlowContext flowContext,
FlowInfo flowInfo) {
-
- if (this.constantExpression != null) {
- if (this.constantExpression.constant == Constant.NotAConstant
- && !this.constantExpression.resolvedType.isEnum()) {
- currentScope.problemReporter().caseExpressionMustBeConstant(this.constantExpression);
+ if (this.constantExpressions != null && this.constantExpressions.length > 1) {
+ for (Expression e : this.constantExpressions) {
+ if (e.constant == Constant.NotAConstant
+ && !e.resolvedType.isEnum()) {
+ currentScope.problemReporter().caseExpressionMustBeConstant(e);
+ }
+ this.constantExpression.analyseCode(currentScope, flowContext, flowInfo);
+ }
+
+ } else {
+ if (this.constantExpression != null) {
+ if (this.constantExpression.constant == Constant.NotAConstant
+ && !this.constantExpression.resolvedType.isEnum()) {
+ currentScope.problemReporter().caseExpressionMustBeConstant(this.constantExpression);
+ }
+ this.constantExpression.analyseCode(currentScope, flowContext, flowInfo);
}
- this.constantExpression.analyseCode(currentScope, flowContext, flowInfo);
}
return flowInfo;
}
@@ -108,7 +122,7 @@ public void resolve(BlockScope scope) {
* see org.eclipse.jdt.internal.compiler.ast.Statement#resolveCase(org.eclipse.jdt.internal.compiler.lookup.BlockScope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.ast.SwitchStatement)
*/
@Override
-public Constant resolveCase(BlockScope scope, TypeBinding switchExpressionType, SwitchStatement switchStatement) {
+public Constant[] resolveCase(BlockScope scope, TypeBinding switchExpressionType, SwitchStatement switchStatement) {
// switchExpressionType maybe null in error case
scope.enclosingCase = this; // record entering in a switch case block
@@ -119,26 +133,55 @@ public Constant resolveCase(BlockScope scope, TypeBinding switchExpressionType,
// on error the last default will be the selected one ...
switchStatement.defaultCase = this;
- return Constant.NotAConstant;
+ return Constant.NotAConstantList;
}
// add into the collection of cases of the associated switch statement
switchStatement.cases[switchStatement.caseCount++] = this;
- // tag constant name with enum type for privileged access to its members
if (switchExpressionType != null && switchExpressionType.isEnum() && (this.constantExpression instanceof SingleNameReference)) {
((SingleNameReference) this.constantExpression).setActualReceiverType((ReferenceBinding)switchExpressionType);
}
TypeBinding caseType = this.constantExpression.resolveType(scope);
- if (caseType == null || switchExpressionType == null) return Constant.NotAConstant;
- if (this.constantExpression.isConstantValueOfTypeAssignableToType(caseType, switchExpressionType)
+ if (caseType == null || switchExpressionType == null) return Constant.NotAConstantList;
+ // tag constant name with enum type for privileged access to its members
+
+ if (this.constantExpressions != null && this.constantExpressions.length > 1) {
+ List<Constant> cases = new ArrayList<>();
+ for (Expression e : this.constantExpressions) {
+ if (e != this.constantExpression) {
+ if (switchExpressionType.isEnum() && (this.constantExpression instanceof SingleNameReference)) {
+ ((SingleNameReference) e).setActualReceiverType((ReferenceBinding)switchExpressionType);
+ }
+ e.resolveType(scope);
+ }
+ Constant con = resolveConstantExpression(scope, caseType, switchExpressionType, switchStatement, e);
+ if (con != Constant.NotAConstant) {
+ cases.add(con);
+ }
+ }
+ if (cases.size() > 0) {
+ return cases.toArray(new Constant[cases.size()]);
+ }
+ } else {
+ return new Constant[] { resolveConstantExpression(scope, caseType, switchExpressionType, switchStatement, this.constantExpression) };
+ }
+ return Constant.NotAConstantList;
+}
+public Constant resolveConstantExpression(BlockScope scope,
+ TypeBinding caseType,
+ TypeBinding switchExpressionType,
+ SwitchStatement switchStatement,
+ Expression expression) {
+
+ if (expression.isConstantValueOfTypeAssignableToType(caseType, switchExpressionType)
|| caseType.isCompatibleWith(switchExpressionType)) {
if (caseType.isEnum()) {
- if (((this.constantExpression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) != 0) {
- scope.problemReporter().enumConstantsCannotBeSurroundedByParenthesis(this.constantExpression);
+ if (((expression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) != 0) {
+ scope.problemReporter().enumConstantsCannotBeSurroundedByParenthesis(expression);
}
- if (this.constantExpression instanceof NameReference
- && (this.constantExpression.bits & ASTNode.RestrictiveFlagMASK) == Binding.FIELD) {
- NameReference reference = (NameReference) this.constantExpression;
+ if (expression instanceof NameReference
+ && (expression.bits & ASTNode.RestrictiveFlagMASK) == Binding.FIELD) {
+ NameReference reference = (NameReference) expression;
FieldBinding field = reference.fieldBinding();
if ((field.modifiers & ClassFileConstants.AccEnum) == 0) {
scope.problemReporter().enumSwitchCannotTargetField(reference, field);
@@ -148,11 +191,11 @@ public Constant resolveCase(BlockScope scope, TypeBinding switchExpressionType,
return IntConstant.fromValue(field.original().id + 1); // (ordinal value + 1) zero should not be returned see bug 141810
}
} else {
- return this.constantExpression.constant;
+ return expression.constant;
}
- } else if (isBoxingCompatible(caseType, switchExpressionType, this.constantExpression, scope)) {
+ } else if (isBoxingCompatible(caseType, switchExpressionType, expression, scope)) {
// constantExpression.computeConversion(scope, caseType, switchExpressionType); - do not report boxing/unboxing conversion
- return this.constantExpression.constant;
+ return expression.constant;
}
scope.problemReporter().typeMismatchError(caseType, switchExpressionType, this.constantExpression, switchStatement.expression);
return Constant.NotAConstant;
@@ -161,7 +204,14 @@ public Constant resolveCase(BlockScope scope, TypeBinding switchExpressionType,
@Override
public void traverse(ASTVisitor visitor, BlockScope blockScope) {
if (visitor.visit(this, blockScope)) {
- if (this.constantExpression != null) this.constantExpression.traverse(visitor, blockScope);
+ if (this.constantExpressions != null && this.constantExpressions.length > 1) {
+ for (Expression e : this.constantExpressions) {
+ e.traverse(visitor, blockScope);
+ }
+ } else {
+ if (this.constantExpression != null) this.constantExpression.traverse(visitor, blockScope);
+ }
+
}
visitor.endVisit(this, blockScope);
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
index bcafc9bd08..e7605c23ce 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
@@ -447,10 +447,10 @@ public abstract void resolve(BlockScope scope);
* Returns case constant associated to this statement (NotAConstant if none)
* parameter statement has to be either a SwitchStatement or a SwitchExpression
*/
-public Constant resolveCase(BlockScope scope, TypeBinding testType, SwitchStatement switchStatement) {
+public Constant[] resolveCase(BlockScope scope, TypeBinding testType, SwitchStatement switchStatement) {
// statement within a switch that are not case are treated as normal statement....
resolve(scope);
- return Constant.NotAConstant;
+ return new Constant[] {Constant.NotAConstant};
}
/**
* Returns the resolved expression if any associated to this statement - used
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
index c3e40cad0b..d21237a1b8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
@@ -59,6 +59,7 @@ public class SwitchStatement extends Expression {
public int blockStart;
public int caseCount;
int[] constants;
+ int[] constMapping;
String[] stringConstants;
public boolean switchLabeledRules = false; // true if case ->, false if case :
@@ -212,33 +213,60 @@ public class SwitchStatement extends Expression {
"case " + this.hashCode + ":(" + this.string + ")\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
-
+ /*
+ * With multi constant case statements, the number of case statements (hence branch labels)
+ * and number of constants (hence hashcode labels) could be different. For e.g:
+
+ switch(s) {
+ case "FB", "c":
+ System.out.println("A/C");
+ break;
+ case "Ea":
+ System.out.println("B");
+ break;
+
+ With the above code, we will have
+ 2 branch labels for FB and c
+ 3 stringCases for FB, c and Ea
+ 2 hashCodeCaseLabels one for FB, Ea and one for c
+
+ Should produce something like this:
+ lookupswitch { // 2
+ 99: 32
+ 2236: 44
+ default: 87
+
+ "FB" and "Ea" producing the same hashcode values, but still belonging in different case statements.
+ First, produce the two branch labels pertaining to the case statements
+ And the three string cases and use the this.constMapping to get the correct branch label.
+ */
final boolean hasCases = this.caseCount != 0;
-
- StringSwitchCase [] stringCases = new StringSwitchCase[this.caseCount]; // may have to shrink later if multiple strings hash to same code.
+ int constSize = hasCases ? this.stringConstants.length : 0;
BranchLabel[] sourceCaseLabels = new BranchLabel[this.caseCount];
- CaseLabel [] hashCodeCaseLabels = new CaseLabel[this.caseCount];
- this.constants = new int[this.caseCount]; // hashCode() values.
for (int i = 0, max = this.caseCount; i < max; i++) {
this.cases[i].targetLabel = (sourceCaseLabels[i] = new BranchLabel(codeStream)); // A branch label, not a case label.
sourceCaseLabels[i].tagBits |= BranchLabel.USED;
- stringCases[i] = new StringSwitchCase(this.stringConstants[i].hashCode(), this.stringConstants[i], sourceCaseLabels[i]);
+ }
+ StringSwitchCase [] stringCases = new StringSwitchCase[constSize]; // may have to shrink later if multiple strings hash to same code.
+ CaseLabel [] hashCodeCaseLabels = new CaseLabel[constSize];
+ this.constants = new int[constSize]; // hashCode() values.
+ for (int i = 0; i < constSize; i++) {
+ stringCases[i] = new StringSwitchCase(this.stringConstants[i].hashCode(), this.stringConstants[i], sourceCaseLabels[this.constMapping[i]]);
hashCodeCaseLabels[i] = new CaseLabel(codeStream);
hashCodeCaseLabels[i].tagBits |= BranchLabel.USED;
-
}
Arrays.sort(stringCases);
int uniqHashCount = 0;
int lastHashCode = 0;
- for (int i = 0, length = this.caseCount; i < length; ++i) {
+ for (int i = 0, length = constSize; i < length; ++i) {
int hashCode = stringCases[i].hashCode;
if (i == 0 || hashCode != lastHashCode) {
lastHashCode = this.constants[uniqHashCount++] = hashCode;
}
}
- if (uniqHashCount != this.caseCount) { // multiple keys hashed to the same value.
+ if (uniqHashCount != constSize) { // multiple keys hashed to the same value.
System.arraycopy(this.constants, 0, this.constants = new int[uniqHashCount], 0, uniqHashCount);
System.arraycopy(hashCodeCaseLabels, 0, hashCodeCaseLabels = new CaseLabel[uniqHashCount], 0, uniqHashCount);
}
@@ -265,7 +293,7 @@ public class SwitchStatement extends Expression {
codeStream.invokeStringHashCode();
if (hasCases) {
codeStream.lookupswitch(defaultCaseLabel, this.constants, sortedIndexes, hashCodeCaseLabels);
- for (int i = 0, j = 0, max = this.caseCount; i < max; i++) {
+ for (int i = 0, j = 0, max = constSize; i < max; i++) {
int hashCode = stringCases[i].hashCode;
if (i == 0 || hashCode != lastHashCode) {
lastHashCode = hashCode;
@@ -352,6 +380,7 @@ public class SwitchStatement extends Expression {
// prepare the labels and constants
this.breakLabel.initialize(codeStream);
+ int constantCount = this.constants == null ? 0 : this.constants.length;
CaseLabel[] caseLabels = new CaseLabel[this.caseCount];
for (int i = 0, max = this.caseCount; i < max; i++) {
this.cases[i].targetLabel = (caseLabels[i] = new CaseLabel(codeStream));
@@ -384,18 +413,18 @@ public class SwitchStatement extends Expression {
}
// generate the appropriate switch table/lookup bytecode
if (hasCases) {
- int[] sortedIndexes = new int[this.caseCount];
+ int[] sortedIndexes = new int[constantCount];
// we sort the keys to be able to generate the code for tableswitch or lookupswitch
- for (int i = 0; i < this.caseCount; i++) {
+ for (int i = 0; i < constantCount; i++) {
sortedIndexes[i] = i;
}
int[] localKeysCopy;
- System.arraycopy(this.constants, 0, (localKeysCopy = new int[this.caseCount]), 0, this.caseCount);
- CodeStream.sort(localKeysCopy, 0, this.caseCount - 1, sortedIndexes);
+ System.arraycopy(this.constants, 0, (localKeysCopy = new int[constantCount]), 0, constantCount);
+ CodeStream.sort(localKeysCopy, 0, constantCount - 1, sortedIndexes);
- int max = localKeysCopy[this.caseCount - 1];
+ int max = localKeysCopy[constantCount - 1];
int min = localKeysCopy[0];
- if ((long) (this.caseCount * 2.5) > ((long) max - (long) min)) {
+ if ((long) (constantCount * 2.5) > ((long) max - (long) min)) {
// work-around 1.3 VM bug, if max>0x7FFF0000, must use lookup bytecode
// see http://dev.eclipse.org/bugs/show_bug.cgi?id=21557
@@ -409,6 +438,7 @@ public class SwitchStatement extends Expression {
max,
this.constants,
sortedIndexes,
+ this.constMapping,
caseLabels);
}
} else {
@@ -424,7 +454,7 @@ public class SwitchStatement extends Expression {
if (this.statements != null) {
for (int i = 0, maxCases = this.statements.length; i < maxCases; i++) {
Statement statement = this.statements[i];
- if ((caseIndex < this.caseCount) && (statement == this.cases[caseIndex])) { // statements[i] is a case
+ if ((caseIndex < constantCount) && (statement == this.cases[caseIndex])) { // statements[i] is a case
this.scope.enclosingCase = this.cases[caseIndex]; // record entering in a switch case block
if (this.preSwitchInitStateIndex != -1) {
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preSwitchInitStateIndex);
@@ -535,32 +565,52 @@ public class SwitchStatement extends Expression {
this.cases = new CaseStatement[length = this.statements.length];
if (!isStringSwitch) {
this.constants = new int[length];
+ this.constMapping = new int[length];
} else {
this.stringConstants = new String[length];
+ this.constMapping = new int[length];
}
int counter = 0;
for (int i = 0; i < length; i++) {
- Constant constant1;
+ Constant[] constantsList;
final Statement statement = this.statements[i];
- if ((constant1 = statement.resolveCase(this.scope, expressionType, this)) != Constant.NotAConstant) {
- if (!isStringSwitch) {
- int key = constant1.intValue();
- //----check for duplicate case statement------------
- for (int j = 0; j < counter; j++) {
- if (this.constants[j] == key) {
- reportDuplicateCase((CaseStatement) statement, this.cases[j], length);
+ if (!(statement instanceof CaseStatement)) {
+ statement.resolve(this.scope);
+ continue;
+ }
+ if ((constantsList = statement.resolveCase(this.scope, expressionType, this)) != Constant.NotAConstantList) {
+ for (Constant con : constantsList) {
+ if (con == Constant.NotAConstant)
+ continue;
+ if (!isStringSwitch) {
+ int key = con.intValue();
+ //----check for duplicate case statement------------
+ for (int j = 0; j < counter; j++) {
+ if (this.constants[j] == key) {
+ reportDuplicateCase((CaseStatement) statement, this.cases[j], length);
+ }
}
- }
- this.constants[counter++] = key;
- } else {
- String key = constant1.stringValue();
- //----check for duplicate case statement------------
- for (int j = 0; j < counter; j++) {
- if (this.stringConstants[j].equals(key)) {
- reportDuplicateCase((CaseStatement) statement, this.cases[j], length);
+ if (this.constants.length == counter) {
+ System.arraycopy(this.constants, 0, this.constants = new int[counter+1], 0, counter);
+ System.arraycopy(this.constMapping, 0, this.constMapping = new int[counter+1], 0, counter);
+ }
+ this.constants[counter] = key;
+ this.constMapping[counter++] = this.caseCount - 1;
+ } else {
+ String key = con.stringValue();
+ //----check for duplicate case statement------------
+ for (int j = 0; j < counter; j++) {
+ if (this.stringConstants[j].equals(key)) {
+ reportDuplicateCase((CaseStatement) statement, this.cases[j], length);
+ }
+ }
+ if (this.stringConstants.length == counter) {
+ System.arraycopy(this.stringConstants, 0, this.stringConstants = new String[counter+1], 0, counter);
+ System.arraycopy(this.constMapping, 0, this.constMapping = new int[counter+1], 0, counter);
}
+ this.stringConstants[counter] = key;
+ this.constMapping[counter++] = this.caseCount - 1;
}
- this.stringConstants[counter++] = key;
}
}
}
@@ -570,6 +620,7 @@ public class SwitchStatement extends Expression {
} else {
System.arraycopy(this.stringConstants, 0, this.stringConstants = new String[counter], 0, counter);
}
+ System.arraycopy(this.constMapping, 0, this.constMapping = new int[counter], 0, counter);
}
} else {
if ((this.bits & UndocumentedEmptyBlock) != 0) {
@@ -591,14 +642,14 @@ public class SwitchStatement extends Expression {
if (isEnumSwitch && compilerOptions.complianceLevel >= ClassFileConstants.JDK1_5) {
if (this.defaultCase == null || compilerOptions.reportMissingEnumCaseDespiteDefault) {
int constantCount = this.constants == null ? 0 : this.constants.length; // could be null if no case statement
- if (constantCount == this.caseCount
- && this.caseCount != ((ReferenceBinding)expressionType).enumConstantCount()) {
+ if (constantCount >= this.caseCount
+ && constantCount != ((ReferenceBinding)expressionType).enumConstantCount()) {
FieldBinding[] enumFields = ((ReferenceBinding)expressionType.erasure()).fields();
for (int i = 0, max = enumFields.length; i <max; i++) {
FieldBinding enumConstant = enumFields[i];
if ((enumConstant.modifiers & ClassFileConstants.AccEnum) == 0) continue;
findConstant : {
- for (int j = 0; j < this.caseCount; j++) {
+ for (int j = 0; j < constantCount; j++) {
if ((enumConstant.id + 1) == this.constants[j]) // zero should not be returned see bug 141810
break findConstant;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
index cba674ab74..a3b5793bd9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
@@ -6895,7 +6895,7 @@ public void swap() {
this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_swap;
}
-public void tableswitch(CaseLabel defaultLabel, int low, int high, int[] keys, int[] sortedIndexes, CaseLabel[] casesLabel) {
+public void tableswitch(CaseLabel defaultLabel, int low, int high, int[] keys, int[] sortedIndexes, int[] mapping, CaseLabel[] casesLabel) {
this.countLabels = 0;
this.stackDepth--;
int length = casesLabel.length;
@@ -6926,7 +6926,7 @@ public void tableswitch(CaseLabel defaultLabel, int low, int high, int[] keys, i
int index;
int key = keys[index = sortedIndexes[j - low]];
if (key == i) {
- casesLabel[index].branch();
+ casesLabel[mapping[index]].branch();
j++;
if (i == high) break; // if high is maxint, then avoids wrapping to minint.
} else {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java
index 3cda404aa0..29a45a3928 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java
@@ -21,6 +21,7 @@ import org.eclipse.jdt.internal.compiler.util.Messages;
public abstract class Constant implements TypeIds, OperatorIds {
public static final Constant NotAConstant = DoubleConstant.fromValue(Double.NaN);
+ public static final Constant[] NotAConstantList = new Constant[] {DoubleConstant.fromValue(Double.NaN)};
public boolean booleanValue() {
throw new ShouldNotImplement(Messages.bind(Messages.constant_cannotCastedInto, new String[] { typeName(), "boolean" })); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
index 6201a1918a..37a77dfcf5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
@@ -976,7 +976,7 @@
# Switch-Expressions
1600 = Incompatible switch results expressions {0}
1601 = A switch expression should have a non-empty switch block
-1602 = A switch expression {0} should have at least one result expression
+1602 = A switch expression should have at least one result expression
1603 = A switch labeled block in a switch expression should not complete normally
1604 = The last statement of a switch block in a switch expression should not complete normally
1605 = Trailing switch labels are not allowed in a switch expression.

Back to the top