diff options
author | Jay Arthanareeswaran | 2020-02-05 10:27:16 +0000 |
---|---|---|
committer | Stephan Herrmann | 2020-02-16 01:17:35 +0000 |
commit | f8f67606ae10780ec62f44189f86b4bf1a166ba8 (patch) | |
tree | 174bb6422f5fb02f560dd4712de6f5b2027d69b3 | |
parent | b82b9536f86899de9c0d6386e0843e89b677dc72 (diff) | |
download | eclipse.jdt.core-f8f67606ae10780ec62f44189f86b4bf1a166ba8.tar.gz eclipse.jdt.core-f8f67606ae10780ec62f44189f86b4bf1a166ba8.tar.xz eclipse.jdt.core-f8f67606ae10780ec62f44189f86b4bf1a166ba8.zip |
Flow analysis looking good
Change-Id: Iec4e81d7379bdf97f18c62afc918ae46d66512d6
Signed-off-by: Jay Arthanareeswaran <jarthana@in.ibm.com>
Also-by: Stephan Herrmann <stephan.herrmann@berlin.de>
20 files changed, 234 insertions, 347 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java index 37cdd0c7a6..45c96d788a 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java @@ -941,6 +941,7 @@ public void test011_problem_categories() { expectedProblemAttributes.put("ParsingErrorOnKeywordNoSuggestion", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX)); expectedProblemAttributes.put("ParsingErrorReplaceTokens", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX)); expectedProblemAttributes.put("ParsingErrorUnexpectedEOF", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX)); + expectedProblemAttributes.put("PatternVariableNotInScope", new ProblemAttributes(CategorizedProblem.CAT_PREVIEW_RELATED)); expectedProblemAttributes.put("PolymorphicMethodNotBelow17", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); expectedProblemAttributes.put("PossibleAccidentalBooleanAssignment", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM)); expectedProblemAttributes.put("PotentialHeapPollutionFromVararg", new ProblemAttributes(CategorizedProblem.CAT_UNCHECKED_RAW)); @@ -1958,6 +1959,7 @@ public void test012_compiler_problems_tuning() { expectedProblemAttributes.put("ParsingErrorOnKeywordNoSuggestion", SKIP); expectedProblemAttributes.put("ParsingErrorReplaceTokens", SKIP); expectedProblemAttributes.put("ParsingErrorUnexpectedEOF", SKIP); + expectedProblemAttributes.put("PatternVariableNotInScope", SKIP); expectedProblemAttributes.put("PolymorphicMethodNotBelow17", SKIP); expectedProblemAttributes.put("PossibleAccidentalBooleanAssignment", new ProblemAttributes(JavaCore.COMPILER_PB_POSSIBLE_ACCIDENTAL_BOOLEAN_ASSIGNMENT)); expectedProblemAttributes.put("PotentialHeapPollutionFromVararg", new ProblemAttributes(JavaCore.COMPILER_PB_UNCHECKED_TYPE_OPERATION)); diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PatternMatching14Test.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PatternMatching14Test.java index d688bfaaf0..652efc5091 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PatternMatching14Test.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PatternMatching14Test.java @@ -24,11 +24,11 @@ import junit.framework.Test; public class PatternMatching14Test extends AbstractRegressionTest { - private static final JavacTestOptions JAVAC_OPTIONS = new JavacTestOptions("-source 14 --enable-preview"); + private static final JavacTestOptions JAVAC_OPTIONS = new JavacTestOptions("-source 14 --enable-preview -Xlint:-preview"); static { // TESTS_NUMBERS = new int [] { 40 }; // TESTS_RANGE = new int[] { 1, -1 }; -// TESTS_NAMES = new String[] { "test022" }; +// TESTS_NAMES = new String[] { "test005" }; } public static Class<?> testClass() { @@ -89,7 +89,7 @@ public class PatternMatching14Test extends AbstractRegressionTest { " ^^^^^^^^\n" + "Instanceof Pattern is a preview feature and disabled by default. Use --enable-preview to enable\n" + "----------\n", - "", + /* omit one arg to directly call super method without JAVA_OPTIONS */ null, true, options); @@ -240,12 +240,12 @@ public class PatternMatching14Test extends AbstractRegressionTest { "1. ERROR in X6a.java (at line 8)\n" + " System.out.print(i);\n" + " ^\n" + - "i cannot be resolved to a variable\n" + + "The pattern variable i is not in scope in this location\n" + "----------\n" + "2. ERROR in X6a.java (at line 11)\n" + " System.out.print(i);\n" + " ^\n" + - "i cannot be resolved to a variable\n" + + "The pattern variable i is not in scope in this location\n" + "----------\n", "", null, @@ -278,12 +278,12 @@ public class PatternMatching14Test extends AbstractRegressionTest { "1. ERROR in X6b.java (at line 8)\n" + " System.out.print(i);\n" + " ^\n" + - "i cannot be resolved to a variable\n" + + "The pattern variable i is not in scope in this location\n" + "----------\n" + "2. ERROR in X6b.java (at line 11)\n" + " System.out.print(s);\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, @@ -313,7 +313,7 @@ public class PatternMatching14Test extends AbstractRegressionTest { "1. ERROR in X6c.java (at line 7)\n" + " System.out.print(i);\n" + " ^\n" + - "i cannot be resolved to a variable\n" + + "The pattern variable i is not in scope in this location\n" + "----------\n", "", null, @@ -343,7 +343,7 @@ public class PatternMatching14Test extends AbstractRegressionTest { "1. ERROR in X6d.java (at line 7)\n" + " System.out.print(i);\n" + " ^\n" + - "i cannot be resolved to a variable\n" + + "The pattern variable i is not in scope in this location\n" + "----------\n", "", null, @@ -373,7 +373,7 @@ public class PatternMatching14Test extends AbstractRegressionTest { "1. ERROR in X7.java (at line 7)\n" + " System.out.print(i);\n" + " ^\n" + - "i cannot be resolved to a variable\n" + + "The pattern variable i is not in scope in this location\n" + "----------\n", "X7.java:4: warning: [preview] pattern matching in instanceof is a preview feature and may be removed in a future release.\n" + " if (obj instanceof Integer i) {\n" + @@ -494,7 +494,7 @@ public class PatternMatching14Test extends AbstractRegressionTest { "1. ERROR in X11.java (at line 7)\n" + " System.out.println(s);\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, @@ -509,11 +509,11 @@ public class PatternMatching14Test extends AbstractRegressionTest { "@SuppressWarnings(\"preview\")\n" + "public class X12 {\n" + " public static void foo(Object b) {\n" + - " Object c = null;\n" + + " Object c = new Object();\n" + " if (b != c) {\n" + " if (b == null && (b instanceof String s)) {\n" + " System.out.println(\"s:\" + s);\n" + - " } else { " + + " } else {\n" + " System.out.println(\"b:\" + b);\n" + " }\n" + " s = null;\n" + @@ -526,10 +526,10 @@ public class PatternMatching14Test extends AbstractRegressionTest { "}\n", }, "----------\n" + - "1. ERROR in X12.java (at line 10)\n" + + "1. ERROR in X12.java (at line 11)\n" + " s = null;\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, @@ -560,10 +560,15 @@ public class PatternMatching14Test extends AbstractRegressionTest { "}\n", }, "----------\n" + - "1. ERROR in X13.java (at line 9)\n" + + "1. WARNING in X13.java (at line 7)\n" + + " System.out.println(\"s:\" + s);\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Dead code\n" + + "----------\n" + + "2. ERROR in X13.java (at line 9)\n" + " System.out.println(s);\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, @@ -593,7 +598,7 @@ public class PatternMatching14Test extends AbstractRegressionTest { "1. ERROR in X14.java (at line 5)\n" + " System.out.print(\"then:\" + s);\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, @@ -604,9 +609,9 @@ public class PatternMatching14Test extends AbstractRegressionTest { Map<String, String> options = getCompilerOptions(true); runNegativeTest( new String[] { - "X14.java", + "X14a.java", "@SuppressWarnings(\"preview\")\n" + - "public class X14 {\n" + + "public class X14a {\n" + " public static void foo(Object o) {\n" + " if (!(o instanceof String s)) {\n" + " System.out.print(\"then:\" + s);\n" + @@ -620,10 +625,10 @@ public class PatternMatching14Test extends AbstractRegressionTest { "}\n", }, "----------\n" + - "1. ERROR in X14.java (at line 5)\n" + + "1. ERROR in X14a.java (at line 5)\n" + " System.out.print(\"then:\" + s);\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, @@ -634,9 +639,9 @@ public class PatternMatching14Test extends AbstractRegressionTest { Map<String, String> options = getCompilerOptions(true); runNegativeTest( new String[] { - "X14.java", + "X14b.java", "@SuppressWarnings(\"preview\")\n" + - "public class X14 {\n" + + "public class X14b {\n" + " public static void foo(Object o) {\n" + " if (!!(o instanceof String s)) {\n" + " System.out.print(\"then:\" + s);\n" + @@ -650,10 +655,10 @@ public class PatternMatching14Test extends AbstractRegressionTest { "}\n", }, "----------\n" + - "1. ERROR in X14.java (at line 7)\n" + + "1. ERROR in X14b.java (at line 7)\n" + " System.out.print(\"else:\" + s);\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, @@ -664,9 +669,9 @@ public class PatternMatching14Test extends AbstractRegressionTest { Map<String, String> options = getCompilerOptions(true); runNegativeTest( new String[] { - "X14.java", + "X14c.java", "@SuppressWarnings(\"preview\")\n" + - "public class X14 {\n" + + "public class X14c {\n" + " public static void foo(Object o) {\n" + " if (o == null) {\n" + " System.out.print(\"null\");\n" + @@ -680,10 +685,10 @@ public class PatternMatching14Test extends AbstractRegressionTest { "}\n", }, "----------\n" + - "1. ERROR in X14.java (at line 7)\n" + + "1. ERROR in X14c.java (at line 7)\n" + " System.out.print(\"else:\" + s);\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, @@ -694,9 +699,9 @@ public class PatternMatching14Test extends AbstractRegressionTest { Map<String, String> options = getCompilerOptions(true); runConformTest( new String[] { - "X14.java", + "X14d.java", "@SuppressWarnings(\"preview\")\n" + - "public class X14 {\n" + + "public class X14d {\n" + " public static void foo(Object o) {\n" + " if (o == null) {\n" + " System.out.print(\"null\");\n" + @@ -813,7 +818,7 @@ public class PatternMatching14Test extends AbstractRegressionTest { "1. ERROR in X15b.java (at line 9)\n" + " System.out.print(s);\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, @@ -859,7 +864,7 @@ public class PatternMatching14Test extends AbstractRegressionTest { "1. ERROR in X17.java (at line 5)\n" + " System.out.print(s[0]);\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, @@ -914,6 +919,35 @@ public class PatternMatching14Test extends AbstractRegressionTest { "false,true", options); } + /* Test that we still detect duplicate pattern variable declarations + */ + public void test019b() { + Map<String, String> options = getCompilerOptions(true); + runNegativeTest( + new String[] { + "X19b.java", + "@SuppressWarnings(\"preview\")\n" + + "public class X19b {\n" + + " public static void main(String[] obj) {\n" + + " boolean a = true;\n" + + " if (obj instanceof String[] s && s.length == 0) {\n" + + " boolean b = (obj instanceof String[] s && s.length == 0);\n" + + " System.out.print(b);\n" + + " }\n" + + " }\n" + + "}\n", + }, + "----------\n" + + "1. ERROR in X19b.java (at line 6)\n" + + " boolean b = (obj instanceof String[] s && s.length == 0);\n" + + " ^\n" + + "Duplicate local variable s\n" + + "----------\n", + "", + null, + true, + options); + } /* Test that we allow consequent pattern expressions in the same statement */ public void test020() { @@ -952,12 +986,12 @@ public class PatternMatching14Test extends AbstractRegressionTest { "1. ERROR in X21.java (at line 5)\n" + " System.out.print(s);\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n" + "2. ERROR in X21.java (at line 6)\n" + " System.out.print(s2);\n" + " ^^\n" + - "s2 cannot be resolved to a variable\n" + + "The pattern variable s2 is not in scope in this location\n" + "----------\n", "", null, @@ -1011,12 +1045,12 @@ public class PatternMatching14Test extends AbstractRegressionTest { "1. ERROR in X23.java (at line 7)\n" + " while (!(o instanceof String s) && s.length() > 0) {\n" + " ^\n" + - "s cannot be resolved\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n" + "2. ERROR in X23.java (at line 8)\n" + " System.out.println(s);\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, @@ -1029,9 +1063,9 @@ public class PatternMatching14Test extends AbstractRegressionTest { Map<String, String> options = getCompilerOptions(true); runNegativeTest( new String[] { - "X23.java", + "X23a.java", "@SuppressWarnings(\"preview\")\n" + - "public class X23 {\n" + + "public class X23a {\n" + " public static void main(String[] o) {\n" + " foo(\"one\");\n" + " }\n" + @@ -1044,15 +1078,15 @@ public class PatternMatching14Test extends AbstractRegressionTest { "}\n", }, "----------\n" + - "1. ERROR in X23.java (at line 7)\n" + + "1. ERROR in X23a.java (at line 7)\n" + " while (!(o instanceof String s) && s.length() > 0) {\n" + " ^\n" + - "s cannot be resolved\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n" + - "2. ERROR in X23.java (at line 8)\n" + + "2. ERROR in X23a.java (at line 8)\n" + " System.out.println(s);\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, @@ -1080,8 +1114,9 @@ public class PatternMatching14Test extends AbstractRegressionTest { "one", options); } - /* Test that we reject two patter variables with same name in the same - * equals expression + /* + * It's not a problem to define the same var in two operands of a binary expression, + * but then it is not in scope below. */ public void test025() { Map<String, String> options = getCompilerOptions(true); @@ -1101,18 +1136,19 @@ public class PatternMatching14Test extends AbstractRegressionTest { "}\n", }, "----------\n" + - "1. ERROR in X25.java (at line 7)\n" + - " if ((o instanceof String s) != p instanceof String s) {\n" + - " ^\n" + - "Duplicate local variable s\n" + + "1. ERROR in X25.java (at line 8)\n" + + " System.out.print(\"s:\" + s);\n" + + " ^\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, true, options); } - /* Test that we reject two patter variables with same name in the same - * equals expression + /* + * It's not a problem to define the same var in two operands of a binary expression, + * but then it is not in scope below. */ public void test026() { Map<String, String> options = getCompilerOptions(true); @@ -1132,10 +1168,10 @@ public class PatternMatching14Test extends AbstractRegressionTest { "}\n", }, "----------\n" + - "1. ERROR in X26.java (at line 7)\n" + - " if ((o instanceof String s) == p instanceof String s) {\n" + - " ^\n" + - "Duplicate local variable s\n" + + "1. ERROR in X26.java (at line 8)\n" + + " System.out.print(\"s:\" + s);\n" + + " ^\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, @@ -1200,12 +1236,11 @@ public class PatternMatching14Test extends AbstractRegressionTest { getCompilerOptions(true)); } /* - * Test that pattern variables are accepted in initialization of - * a for statement - * TODO: Javac rejects this + * Test that pattern variables are accepted in initialization of a for statement, + * but unavailable in the body if uncertain which if instanceof check was true */ public void test030() { - runConformTest( + runNegativeTest( new String[] { "X30.java", "@SuppressWarnings(\"preview\")\n" + @@ -1220,7 +1255,15 @@ public class PatternMatching14Test extends AbstractRegressionTest { " }\n" + "}\n", }, - "one", + "----------\n" + + "1. ERROR in X30.java (at line 8)\n" + + " System.out.print(s.charAt(i));\n" + + " ^\n" + + "The pattern variable s is not in scope in this location\n" + + "----------\n", + "", + null, + true, getCompilerOptions(true)); } public void test031() { @@ -1243,17 +1286,17 @@ public class PatternMatching14Test extends AbstractRegressionTest { "1. ERROR in X31.java (at line 7)\n" + " for(int i = 0; !(obj instanceof String[] s) && s.length > 0 && i < s.length; i++) {\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n" + "2. ERROR in X31.java (at line 7)\n" + " for(int i = 0; !(obj instanceof String[] s) && s.length > 0 && i < s.length; i++) {\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n" + "3. ERROR in X31.java (at line 8)\n" + " System.out.println(s[i]);\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, @@ -1285,11 +1328,8 @@ public class PatternMatching14Test extends AbstractRegressionTest { "one", getCompilerOptions(true)); } - /* - * FAILURE: Javac rejects this code, but we accept. - */ public void test033() { - runConformTest( + runNegativeTest( new String[] { "X33.java", "@SuppressWarnings(\"preview\")\n" + @@ -1311,7 +1351,15 @@ public class PatternMatching14Test extends AbstractRegressionTest { " }\n" + "}\n", }, - "ne", + "----------\n" + + "1. ERROR in X33.java (at line 12)\n" + + " res = s.substring(1);\n" + + " ^\n" + + "The pattern variable s is not in scope in this location\n" + + "----------\n", + "", + null, + true, getCompilerOptions(true)); } public void test034() { @@ -1377,12 +1425,12 @@ public class PatternMatching14Test extends AbstractRegressionTest { "1. ERROR in X35.java (at line 11)\n" + " yield s;\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n" + "2. ERROR in X35.java (at line 14)\n" + " yield s;\n" + " ^\n" + - "s cannot be resolved to a variable\n" + + "The pattern variable s is not in scope in this location\n" + "----------\n", "", null, @@ -1435,6 +1483,7 @@ public class PatternMatching14Test extends AbstractRegressionTest { " ^^^^\n" + "The type of the expression must be an array type but it resolved to String\n" + "----------\n", + "", null, true, getCompilerOptions(true)); @@ -1462,6 +1511,7 @@ public class PatternMatching14Test extends AbstractRegressionTest { " ^\n" + "s cannot be resolved to a variable\n" + "----------\n", + "", null, true, getCompilerOptions(true)); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java index 1a89cf7759..ddcff78c6a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java @@ -2315,5 +2315,9 @@ void setSourceStart(int sourceStart); * @noreference preview feature error */ int RecordIllegalVararg= PreviewRelated + 1754; /* records - end */ + /* instanceof pattern: */ + /** @since 3.21 BETA_JAVA14 + * @noreference preview feature error */ + int PatternVariableNotInScope = PreviewRelated + 1760; /* Java14 errors - end */ } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java index 2bd0f31c60..66a6adb113 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java @@ -282,7 +282,6 @@ public class AND_AND_Expression extends BinaryExpression { */ @Override public TypeBinding resolveType(BlockScope scope) { - resolvePatternVariable(scope, true); TypeBinding result = super.resolveType(scope); // check whether comparing identical expressions Binding leftDirect = Expression.getDirectBinding(this.left); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java index 8f2086af01..33893e8756 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java @@ -346,8 +346,6 @@ public abstract class AbstractMethodDeclaration if (this.statements != null) { for (Statement stmt : this.statements) { stmt.generateCode(this.scope, codeStream); - if ((stmt.bits & ASTNode.HasInstancePatternExpression) != 0) - stmt.exitPatternVariableScope(codeStream); } } // if a problem got reported during code gen, then trigger problem method creation @@ -650,12 +648,7 @@ public abstract class AbstractMethodDeclaration if (this.statements != null) { for (int i = 0, length = this.statements.length; i < length; i++) { Statement stmt = this.statements[i]; - stmt.lookForPatternVariables(this.scope); - if ((stmt.bits & ASTNode.HasInstancePatternExpression) == 0) { - stmt.resolve(this.scope); - } else { - stmt.resolve(stmt.patternScope); - } + stmt.resolve(this.scope); } } else if ((this.bits & UndocumentedEmptyBlock) != 0) { if (!this.isConstructor() || this.arguments != null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=319626 diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java index 86033e1cf7..915b205026 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java @@ -1812,16 +1812,6 @@ public void initializePatternVariables(BlockScope scope, CodeStream codeStream) this.right.initializePatternVariables(scope, codeStream); } @Override -public void resolvePatternVariable(BlockScope scope, boolean trueFalse) { - this.left.resolvePatternVariable(scope, trueFalse); - this.right.resolvePatternVariable(scope, trueFalse); -} -@Override -public void generatePatternVariable(BlockScope currentScope, CodeStream codeStream) { - this.left.generatePatternVariable(currentScope, codeStream); - this.right.generatePatternVariable(currentScope, codeStream); -} -@Override public TypeBinding resolveType(BlockScope scope) { // keep implementation in sync with CombinedBinaryExpression#resolveType // and nonRecursiveResolveTypeUpwards @@ -1929,6 +1919,7 @@ public TypeBinding resolveType(BlockScope scope) { } // compute the constant when valid computeConstant(scope, leftTypeID, rightTypeID); + this.bits |= (this.left.bits | this.right.bits) & ASTNode.HasInstancePatternExpression; return this.resolvedType; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java index ab8efa0069..de2a55f30f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java @@ -90,8 +90,6 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream) { if (this.statements != null) { for (Statement stmt : this.statements) { stmt.generateCode(this.scope, codeStream); - if ((stmt.bits & ASTNode.HasInstancePatternExpression) != 0) - stmt.exitPatternVariableScope(codeStream); } } // for local variable debug attributes if (this.scope != currentScope) { // was really associated with its own scope @@ -134,12 +132,7 @@ public void resolve(BlockScope upperScope) { : new BlockScope(upperScope, this.explicitDeclarations); for (int i = 0, length = this.statements.length; i < length; i++) { final Statement stmt = this.statements[i]; - stmt.lookForPatternVariables(this.scope); - if ((stmt.bits & ASTNode.HasInstancePatternExpression) == 0) { - stmt.resolve(this.scope); - } else { - stmt.resolve(stmt.patternScope); - } + stmt.resolve(this.scope); } } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java index 12fbf324ea..0d6abb2775 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java @@ -451,9 +451,9 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, @Override public void initializePatternVariables(BlockScope scope, CodeStream codeStream) { - this.condition.initializePatternVariables(this.patternScope, codeStream); - this.valueIfTrue.initializePatternVariables(this.patternScope, codeStream); - this.valueIfFalse.initializePatternVariables(this.patternScope, codeStream); + this.condition.initializePatternVariables(scope, codeStream); + this.valueIfTrue.initializePatternVariables(scope, codeStream); + this.valueIfFalse.initializePatternVariables(scope, codeStream); } @Override @@ -475,7 +475,6 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, if (this.constant != Constant.NotAConstant) { this.constant = Constant.NotAConstant; - this.condition.resolvePatternVariable(scope, true); TypeBinding conditionType = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); this.condition.computeConversion(scope, TypeBinding.BOOLEAN, conditionType); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java index a6706b9286..6e572a300f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java @@ -778,15 +778,9 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean throw new ShouldNotImplement(Messages.ast_missingCode); } } -public void resolvePatternVariable(BlockScope scope, boolean trueFalse) { - // Nothing by default -} public void initializePatternVariables(BlockScope scope, CodeStream codeStream) { // Nothing by default } -public void generatePatternVariable(BlockScope currentScope, CodeStream codeStream) { - // Nothing by default -} /** * Default generation of a boolean value * @param currentScope diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java index 56a5c6aec0..298e92f5f6 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java @@ -265,7 +265,7 @@ public class ForStatement extends Statement { this.initializations[i].generateCode(this.scope, codeStream); } } - if (this.condition != null && (this.bits & ASTNode.HasInstancePatternExpression) != 0) { + if (this.condition != null && (this.condition.bits & ASTNode.HasInstancePatternExpression) != 0) { this.condition.initializePatternVariables(currentScope, codeStream); } Constant cst = this.condition == null ? null : this.condition.optimizedBooleanConstant(); @@ -402,60 +402,21 @@ public class ForStatement extends Statement { } @Override - public void lookForPatternVariables(BlockScope outerScope) { - if (this.condition == null) - return; - this.condition.traverse(new ASTVisitor() { - @Override - public boolean visit( - InstanceOfExpression instanceOfExpression, - BlockScope sc) { - if (instanceOfExpression.elementVariable != null) { - ForStatement.this.bits |= ASTNode.HasInstancePatternExpression; - } - return false; // mission finished, exit - } - }, outerScope); - this.patternScope = new BlockScope(outerScope); - } - - @Override public void resolve(BlockScope upperScope) { - boolean hasPatternVariable = (this.bits & ASTNode.HasInstancePatternExpression) != 0; - if (hasPatternVariable) - upperScope = (BlockScope) upperScope.parent; // use the scope that will hold the init declarations this.scope = (this.bits & ASTNode.NeededScope) != 0 ? new BlockScope(upperScope) : upperScope; if (this.initializations != null) for (int i = 0, length = this.initializations.length; i < length; i++) this.initializations[i].resolve(this.scope); if (this.condition != null) { - if (hasPatternVariable) { - this.scope = this.patternScope = new BlockScope(this.scope); - this.condition.resolvePatternVariable(this.scope, true); - } - } - - if (this.condition != null) { TypeBinding type = this.condition.resolveTypeExpecting(this.scope, TypeBinding.BOOLEAN); this.condition.computeConversion(this.scope, type, type); } if (this.increments != null) for (int i = 0, length = this.increments.length; i < length; i++) this.increments[i].resolve(this.scope); - if (this.action != null) { - BlockScope falseScope = null; - BlockScope trueScope = null; - if (hasPatternVariable) { - trueScope = this.patternScope; - if (this.action.doesNotCompleteNormally()) { - falseScope = upperScope; - } - } - this.action.resolve(hasPatternVariable ? trueScope : this.scope); - if (falseScope != null) - this.condition.resolvePatternVariable(falseScope, false); - } + if (this.action != null) + this.action.resolve(this.scope); } @Override diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java index 11aae31732..a75062fbef 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java @@ -202,10 +202,6 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream) { } // generate then statement this.thenStatement.generateCode(currentScope, codeStream); - boolean hasPatternVariable = (this.bits & ASTNode.HasInstancePatternExpression) != 0; - if (hasPatternVariable) { - this.exitPatternVariableScope(codeStream); - } // jump around the else statement if (hasElsePart) { if ((this.bits & ASTNode.ThenExit) == 0) { @@ -279,62 +275,13 @@ public StringBuffer printStatement(int indent, StringBuffer output) { return output; } @Override -public void lookForPatternVariables(BlockScope scope) { - this.condition.traverse(new ASTVisitor() { - @Override - public boolean visit( - InstanceOfExpression instanceOfExpression, - BlockScope sc) { - if (instanceOfExpression.elementVariable != null) { - IfStatement.this.bits |= ASTNode.HasInstancePatternExpression; - IfStatement.this.patternScope = new BlockScope(scope); - } - return false; // mission finished, exit - } - }, scope); -} -@Override -public void resolve(BlockScope outerScope) { - boolean hasPatternVariable = (this.bits & ASTNode.HasInstancePatternExpression) != 0; - BlockScope trueScope = null; - if (hasPatternVariable) { - trueScope = this.patternScope; - //new BlockScope((BlockScope) outerScope.parent); - this.condition.resolvePatternVariable(trueScope, true); - } - TypeBinding type = this.condition.resolveTypeExpecting(hasPatternVariable ? trueScope : outerScope, TypeBinding.BOOLEAN); - this.condition.computeConversion(hasPatternVariable ? trueScope : outerScope, type, type); - if (this.thenStatement != null) { - this.thenStatement.resolve(hasPatternVariable ? trueScope : outerScope); - } - if (hasPatternVariable) { - BlockScope falseScope = null; - if (this.thenStatement.doesNotCompleteNormally()) { - falseScope = (BlockScope) outerScope.parent; - } else { - falseScope = new BlockScope((BlockScope) outerScope.parent); - } - this.condition.resolvePatternVariable(falseScope, false); - outerScope = falseScope; - } - if (this.elseStatement != null) { - this.elseStatement.traverse(new ASTVisitor() { - @Override - public boolean visit( - InstanceOfExpression instanceOfExpression, - BlockScope sc) { - if (instanceOfExpression.elementVariable != null) { - IfStatement.this.elseStatement.bits |= ASTNode.HasInstancePatternExpression; - } - return false; - } - }, outerScope); - if ((this.elseStatement.bits & ASTNode.HasInstancePatternExpression) != 0) { - this.elseStatement.patternScope = new BlockScope(outerScope); - this.elseStatement.resolve(this.elseStatement.patternScope); - } else - this.elseStatement.resolve(outerScope); - } +public void resolve(BlockScope scope) { + TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); + this.condition.computeConversion(scope, type, type); + if (this.thenStatement != null) + this.thenStatement.resolve(scope); + if (this.elseStatement != null) + this.elseStatement.resolve(scope); } @Override diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java index 559283e261..6b827df116 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java @@ -63,9 +63,6 @@ public InstanceOfExpression(Expression expression, LocalDeclaration local) { @Override public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - if (this.elementVariable != null) { - flowInfo.markAsDefinitelyAssigned(this.elementVariable.binding); - } LocalVariableBinding local = this.expression.localVariableBinding(); if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo). @@ -74,6 +71,12 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl initsWhenTrue.markAsComparedEqualToNonNull(local); flowContext.recordUsingNullReference(currentScope, local, this.expression, FlowContext.CAN_ONLY_NULL | FlowContext.IN_INSTANCEOF, flowInfo); + if (this.elementVariable != null) { + if (this.elementVariable.duplicateCheckObligation != null) { + this.elementVariable.duplicateCheckObligation.accept(flowInfo); + } + initsWhenTrue.markAsDefinitelyAssigned(this.elementVariable.binding); + } // no impact upon enclosing try context return FlowInfo.conditional(initsWhenTrue, flowInfo.copy()); } @@ -86,28 +89,6 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl return this.expression.analyseCode(currentScope, flowContext, flowInfo). unconditionalInits(); } -@Override -public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); - generatePatternVariable(currentScope, codeStream); -// if (this.elementVariable != null) { -// int position = codeStream.position; -// codeStream.load(this.expression.localVariableBinding()); -// codeStream.checkcast(this.type, this.type.resolvedType, position); -// codeStream.store(this.elementVariable.binding, false); -// codeStream.recordPositionsFrom(position, this.sourceEnd); -// } -} -@Override -public void generatePatternVariable(BlockScope currentScope, CodeStream codeStream) { -// if (this.elementVariable != null) { -// int position = codeStream.position; -// codeStream.load(this.expression.localVariableBinding()); -// codeStream.checkcast(this.type, this.type.resolvedType, position); -// codeStream.store(this.elementVariable.binding, false); -// codeStream.recordPositionsFrom(position, this.sourceEnd); -// } -} /** * Code generation for instanceOfExpression * @@ -161,33 +142,25 @@ public void initializePatternVariables(BlockScope currentScope, CodeStream codeS this.isInitialized = true; codeStream.aconst_null(); codeStream.store(this.elementVariable.binding, false); -// int position = codeStream.position; -// codeStream.addVisibleLocalVariable(this.elementVariable.binding); -// this.elementVariable.binding.recordInitializationStartPC(position); } int position = codeStream.position; codeStream.addVisibleLocalVariable(this.elementVariable.binding); this.elementVariable.binding.recordInitializationStartPC(position); } - //generatePatternVariable(currentScope, codeStream); } -@Override -public void resolvePatternVariable(BlockScope scope, boolean inScope) { - if (!inScope) return; +public void resolvePatternVariable(BlockScope scope) { if (this.elementVariable != null && this.elementVariable.binding == null) { - this.patternScope = scope; - this.elementVariable.resolve(scope); + this.elementVariable.resolve(scope, true); + this.elementVariable.binding.modifiers |= ExtraCompilerModifiers.AccPatterVariable; // Why cant this be done in the constructor? this.type = this.elementVariable.type; + this.bits |= ASTNode.HasInstancePatternExpression; } } @Override public TypeBinding resolveType(BlockScope scope) { -// resolvePatternVariable(scope, scope); this.constant = Constant.NotAConstant; - if (this.type == null && this.elementVariable != null) { - this.type = this.elementVariable.type; - } + resolvePatternVariable(scope); TypeBinding checkedType = this.type.resolveType(scope, true /* check bounds*/); if (this.expression instanceof CastExpression) { ((CastExpression) this.expression).setInstanceofType(checkedType); // for cast expression we need to know instanceof type to not tag unnecessary when needed diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java index 57f81073df..e7f562d4e0 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java @@ -45,6 +45,7 @@ import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.VANILLA_CO import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.function.Consumer; import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.jdt.internal.compiler.impl.*; @@ -60,6 +61,12 @@ public class LocalDeclaration extends AbstractVariableDeclaration { public LocalVariableBinding binding; + /** + * For pattern variable, resolve() may store here an obligation to be checked when we have + * a flow info that tells us whether a potential duplicates is in fact in scope. + */ + Consumer<FlowInfo> duplicateCheckObligation; + public LocalDeclaration( char[] name, int sourceStart, @@ -257,7 +264,9 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl @Override public void resolve(BlockScope scope) { - + resolve(scope, false); + } + public void resolve(BlockScope scope, boolean isPatternVariable) { // prescan NNBD handleNonNullByDefault(scope, this.annotations, this); @@ -296,13 +305,23 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl Binding existingVariable = scope.getBinding(this.name, Binding.VARIABLE, this, false /*do not resolve hidden field*/); if (existingVariable != null && existingVariable.isValidBinding()){ - boolean localExists = existingVariable instanceof LocalVariableBinding; - if (localExists && (this.bits & ASTNode.ShadowsOuterLocal) != 0 && scope.isLambdaSubscope() && this.hiddenVariableDepth == 0) { + boolean localExists = existingVariable instanceof LocalVariableBinding; + if (localExists && isPatternVariable + && (((LocalVariableBinding) existingVariable).modifiers & ExtraCompilerModifiers.AccPatterVariable) != 0) + { + this.duplicateCheckObligation = (flowInfo) -> { + if (flowInfo.isDefinitelyAssigned((LocalVariableBinding) existingVariable)) { + scope.problemReporter().redefineLocal(this); + } + }; + } else { + if (localExists && (this.bits & ASTNode.ShadowsOuterLocal) != 0 && scope.isLambdaSubscope() && this.hiddenVariableDepth == 0) { scope.problemReporter().lambdaRedeclaresLocal(this); - } else if (localExists && this.hiddenVariableDepth == 0) { + } else if (localExists && this.hiddenVariableDepth == 0) { scope.problemReporter().redefineLocal(this); - } else { - scope.problemReporter().localVariableHiding(this, existingVariable, false); + } else { + scope.problemReporter().localVariableHiding(this, existingVariable, false); + } } } 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 1cf1230ac7..9d386d58a5 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -8,10 +8,6 @@ * * SPDX-License-Identifier: EPL-2.0 * - * This is an implementation of an early-draft specification developed under the Java - * Community Process (JCP) and is made available for testing and evaluation purposes - * only. The code is not compatible with any specification of the JCP. - * * Contributors: * IBM Corporation - initial API and implementation * Stephan Herrmann - Contributions for @@ -107,7 +103,6 @@ public boolean doesNotCompleteNormally() { public boolean completesByContinue() { return false; } - public BlockScope patternScope; public static final int NOT_COMPLAINED = 0; public static final int COMPLAINED_FAKE_REACHABLE = 1; @@ -427,15 +422,6 @@ public void generateArguments(MethodBinding binding, Expression[] arguments, Blo } public abstract void generateCode(BlockScope currentScope, CodeStream codeStream); -public void exitPatternVariableScope(CodeStream stream) { - if (this.patternScope != null && (this.bits & ASTNode.HasInstancePatternExpression) != 0) { - for (Scope s : this.patternScope.subscopes) { - if (s == null) continue; - stream.exitUserScope((BlockScope) s); - } - stream.exitUserScope(this.patternScope); - } -} public boolean isBoxingCompatible(TypeBinding expressionType, TypeBinding targetType, Expression expression, Scope scope) { if (scope.isBoxingCompatibleWith(expressionType, targetType)) @@ -477,21 +463,6 @@ public abstract StringBuffer printStatement(int indent, StringBuffer output); public abstract void resolve(BlockScope scope); -public void lookForPatternVariables(BlockScope scope) { - this.traverse(new ASTVisitor() { - @Override - public boolean visit( - InstanceOfExpression instanceOfExpression, - BlockScope sc) { - if (instanceOfExpression.elementVariable != null) { - Statement.this.bits |= ASTNode.HasInstancePatternExpression; - } - return false; // mission finished, exit - } - }, scope); - if ((this.bits & ASTNode.HasInstancePatternExpression) != 0) - this.patternScope = new BlockScope(scope); -} /** * Returns case constant associated to this statement (NotAConstant if none) * parameter statement has to be either a SwitchStatement or a SwitchExpression diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java index c1d0368878..b25157f635 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java @@ -224,16 +224,6 @@ public FlowInfo analyseCode( } @Override - public void resolvePatternVariable(BlockScope scope, boolean trueFalse) { - if ((((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT)) { - this.expression.resolvePatternVariable(scope, !trueFalse); - } - } - @Override - public void generatePatternVariable(BlockScope currentScope, CodeStream codeStream) { - this.expression.generatePatternVariable(currentScope, codeStream); - } - @Override public TypeBinding resolveType(BlockScope scope) { boolean expressionIsCast; if ((expressionIsCast = this.expression instanceof CastExpression) == true) this.expression.bits |= DisableUnnecessaryCastCheck; // will check later on diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java index c0e5790e5c..09ef32e52e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java @@ -194,6 +194,7 @@ public class WhileStatement extends Statement { if ((this.bits & IsReachable) == 0) { return; } + // TODO: Do this at the appropriate point only this.condition.initializePatternVariables(currentScope, codeStream); int pc = codeStream.position; Constant cst = this.condition.optimizedBooleanConstant(); @@ -236,7 +237,6 @@ public class WhileStatement extends Statement { // generate the action BranchLabel actionLabel = new BranchLabel(codeStream); if (this.action != null) { - this.condition.generatePatternVariable(currentScope, codeStream); actionLabel.tagBits |= BranchLabel.USED; // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect if (this.condIfTrueInitStateIndex != -1) { @@ -275,42 +275,11 @@ public class WhileStatement extends Statement { } @Override - public void lookForPatternVariables(BlockScope scope) { - this.condition.traverse(new ASTVisitor() { - @Override - public boolean visit( - InstanceOfExpression instanceOfExpression, - BlockScope sc) { - if (instanceOfExpression.elementVariable != null) { - WhileStatement.this.bits |= ASTNode.HasInstancePatternExpression; - } - return false; // mission finished, exit - } - }, scope); - this.patternScope = new BlockScope(scope); - } - - @Override public void resolve(BlockScope scope) { - boolean hasPatternVariable = (this.bits & ASTNode.HasInstancePatternExpression) != 0; - BlockScope trueScope = null; - BlockScope falseScope = null; - if (hasPatternVariable) { - trueScope = this.patternScope; - this.condition.resolvePatternVariable(trueScope, true); - } - TypeBinding type = this.condition.resolveTypeExpecting(hasPatternVariable ? trueScope : scope, TypeBinding.BOOLEAN); + TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); this.condition.computeConversion(scope, type, type); - if (this.action != null) { - if (hasPatternVariable) { - if (this.action.doesNotCompleteNormally()) { - falseScope = (BlockScope) scope.parent; - } - } - this.action.resolve(hasPatternVariable ? trueScope : scope); - if (falseScope != null) - this.condition.resolvePatternVariable(falseScope, false); - } + if (this.action != null) + this.action.resolve(scope); } @Override diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java index 6980158b37..39d64e3762 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java @@ -134,7 +134,6 @@ public final void addLocalType(TypeDeclaration localType) { methodScope = methodScope.enclosingMethodScope(); } } - /* Insert a local variable into a given scope, updating its position * and checking there are not too many locals or arguments allocated. */ @@ -419,7 +418,7 @@ public LocalDeclaration[] findLocalVariableDeclarations(int position) { } else { // consider variable first LocalVariableBinding local = this.locals[ilocal]; // if no local at all, will be locals[ilocal]==null - if (local != null) { + if (local != null && (local.modifiers & ExtraCompilerModifiers.AccPatterVariable) == 0) { LocalDeclaration localDecl = local.declaration; if (localDecl != null) { if (localDecl.declarationSourceStart <= position) { @@ -447,9 +446,20 @@ public LocalDeclaration[] findLocalVariableDeclarations(int position) { public LocalVariableBinding findVariable(char[] variableName) { int varLength = variableName.length; for (int i = this.localIndex-1; i >= 0; i--) { // lookup backward to reach latest additions first - LocalVariableBinding local; + LocalVariableBinding local = this.locals[i]; + if ((local.modifiers & ExtraCompilerModifiers.AccPatterVariable) != 0) + continue; + char[] localName; + if ((localName = local.name).length == varLength && CharOperation.equals(localName, variableName)) + return local; + } + // Look at the pattern variables now + for (int i = this.localIndex-1; i >= 0; i--) { // lookup backward to reach latest additions first + LocalVariableBinding local = this.locals[i]; + if ((local.modifiers & ExtraCompilerModifiers.AccPatterVariable) == 0) + continue; char[] localName; - if ((localName = (local = this.locals[i]).name).length == varLength && CharOperation.equals(localName, variableName)) + if ((localName = local.name).length == varLength && CharOperation.equals(localName, variableName)) return local; } return null; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java index fdba43ae5d..cc2f201db4 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java @@ -57,4 +57,5 @@ public interface ExtraCompilerModifiers { // modifier constant final int AccOverriding = ASTNode.Bit29; // record fact a method overrides another one final int AccImplementing = ASTNode.Bit30; // record fact a method implements another one (it is concrete and overrides an abstract one) final int AccGenericSignature = ASTNode.Bit31; // record fact a type/method/field involves generics in its signature (and need special signature attr) + final int AccPatterVariable = ASTNode.Bit29; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java index aa2193a718..74d5ef7c87 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java @@ -2102,12 +2102,20 @@ public void duplicateInitializationOfBlankFinalField(FieldBinding field, Referen } public void duplicateInitializationOfFinalLocal(LocalVariableBinding local, ASTNode location) { String[] arguments = new String[] { new String(local.readableName())}; - this.handle( - IProblem.DuplicateFinalLocalInitialization, - arguments, - arguments, - nodeSourceStart(local, location), - nodeSourceEnd(local, location)); + if ((local.modifiers & ExtraCompilerModifiers.AccPatterVariable) == 0) { + this.handle( + IProblem.DuplicateFinalLocalInitialization, + arguments, + arguments, + nodeSourceStart(local, location), + nodeSourceEnd(local, location)); + } else { + this.handle(IProblem.PatternVariableNotInScope, + arguments, + arguments, + nodeSourceStart(local, location), + nodeSourceEnd(local, location)); + } } public void duplicateMethodInType(AbstractMethodDeclaration methodDecl, boolean equalParameters, int severity) { MethodBinding method = methodDecl.binding; @@ -8716,14 +8724,25 @@ public void uninitializedNonNullField(FieldBinding field, ASTNode location) { nodeSourceEnd(field, location)); } public void uninitializedLocalVariable(LocalVariableBinding binding, ASTNode location, Scope scope) { - binding.markAsUninitializedIn(scope); - String[] arguments = new String[] {new String(binding.readableName())}; - this.handle( - methodHasMissingSwitchDefault() ? IProblem.UninitializedLocalVariableHintMissingDefault : IProblem.UninitializedLocalVariable, - arguments, - arguments, - nodeSourceStart(binding, location), - nodeSourceEnd(binding, location)); + if ((binding.modifiers & ExtraCompilerModifiers.AccPatterVariable) == 0) { + binding.markAsUninitializedIn(scope); + String[] arguments = new String[] {new String(binding.readableName())}; + this.handle( + methodHasMissingSwitchDefault() ? IProblem.UninitializedLocalVariableHintMissingDefault : IProblem.UninitializedLocalVariable, + arguments, + arguments, + nodeSourceStart(binding, location), + nodeSourceEnd(binding, location)); + } else { + String[] arguments = new String[] {new String(binding.readableName())}; + this.handle( + IProblem.PatternVariableNotInScope, + arguments, + arguments, + nodeSourceStart(binding, location), + nodeSourceEnd(binding, location)); + + } } private boolean methodHasMissingSwitchDefault() { MethodScope methodScope = null; 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 61367457cf..05d990a28a 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 @@ -1051,6 +1051,8 @@ 1753 = void is an invalid type for the component {0} of a record 1754 = The variable argument type {0} of the record {1} must be the last parameter +1760 = The pattern variable {0} is not in scope in this location + # Java 14 Preview - end # Additional doc |