Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 238163 Details for
Bug 422468
[1.8][assist] Code assist issues with type elided lambda parameters
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read
this important communication.
[patch]
Snap shot of work in progress
typeelided.patch (text/plain), 105.21 KB, created by
Srikanth Sankaran
on 2013-12-09 09:29:15 EST
(
hide
)
Description:
Snap shot of work in progress
Filename:
MIME Type:
Creator:
Srikanth Sankaran
Created:
2013-12-09 09:29:15 EST
Size:
105.21 KB
patch
obsolete
>diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/CompletionParserTest18.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/CompletionParserTest18.java >index 6a3bb73..12db48e 100644 >--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/CompletionParserTest18.java >+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/CompletionParserTest18.java >@@ -15,12 +15,14 @@ > > package org.eclipse.jdt.core.tests.compiler.parser; > >+import org.eclipse.jdt.core.JavaModelException; >+ > import junit.framework.Test; > > public class CompletionParserTest18 extends AbstractCompletionTest { > > static { >-// TESTS_NAMES = new String [] { "test0001" }; >+// TESTS_NAMES = new String [] { "test0005" }; > } > > public CompletionParserTest18(String testName) { >@@ -233,10 +235,10 @@ > " }\n" + > " void go() {\n" + > " I i = (<no type> argument) -> {\n" + >- " {\n" + >- " if (true)\n" + >+ " if (true)\n" + >+ " {\n" + > " return <CompleteOnName:arg>;\n" + >- " }\n" + >+ " }\n" + > " };\n" + > " }\n" + > "}\n"; >@@ -251,7 +253,7 @@ > expectedReplacedSource, > "diet ast"); > } >-public void test0006() { >+public void _test0006() { > String string = > "interface I {\n" + > " int foo(int x);\n" + >@@ -345,4 +347,105 @@ > expectedReplacedSource, > "diet ast"); > } >+public void test0010() { >+ String string = >+ "interface I {\n" + >+ " void foo(String x);\n" + >+ "}\n" + >+ "public class X {\n" + >+ " String xField;\n" + >+ " static void goo(String s) {\n" + >+ " }\n" + >+ " static void goo(I i) {\n" + >+ " }\n" + >+ " public static void main(String[] args) {\n" + >+ " goo((xyz) -> {\n" + >+ " System.out.println(xyz.);\n" + >+ " });\n" + >+ " }\n" + >+ "}\n"; >+ >+ String completeBehind = "xyz."; >+ int cursorLocation = string.lastIndexOf(completeBehind) + completeBehind.length() - 1; >+ >+ String expectedCompletionNodeToString = "<CompleteOnName:xyz.>"; >+ String expectedParentNodeToString = "System.out.println(<CompleteOnName:xyz.>)"; >+ String completionIdentifier = ""; >+ String expectedReplacedSource = "xyz."; >+ String expectedUnitDisplayString = >+ "interface I {\n" + >+ " void foo(String x);\n" + >+ "}\n" + >+ "public class X {\n" + >+ " String xField;\n" + >+ " public X() {\n" + >+ " }\n" + >+ " static void goo(String s) {\n" + >+ " }\n" + >+ " static void goo(I i) {\n" + >+ " }\n" + >+ " public static void main(String[] args) {\n" + >+ " goo((<no type> xyz) -> {\n" + >+ " System.out.println(<CompleteOnName:xyz.>);\n" + >+ "});\n" + >+ " }\n" + >+ "}\n"; >+ >+ checkMethodParse( >+ string.toCharArray(), >+ cursorLocation, >+ expectedCompletionNodeToString, >+ expectedParentNodeToString, >+ expectedUnitDisplayString, >+ completionIdentifier, >+ expectedReplacedSource, >+ "diet ast"); >+} >+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=417935, [1.8][code select] ICU#codeSelect doesn't work on reference to lambda parameter >+public void test417935() throws JavaModelException { >+ String string = >+ "import java.util.ArrayList;\n" + >+ "import java.util.Arrays;\n" + >+ "import java.util.Collections;\n" + >+ "import java.util.Comparator;\n" + >+ "public class X {\n" + >+ " int compareTo(X x) { return 0; }\n" + >+ " void foo() {\n" + >+ " Collections.sort(new ArrayList<X>(Arrays.asList(new X(), new X(), new X())),\n" + >+ " (X o1, X o2) -> o1.compareTo(o2)); //[2]\n" + >+ " }\n" + >+ "}\n"; >+ >+ String completeBehind = "compa"; >+ int cursorLocation = string.lastIndexOf(completeBehind) + completeBehind.length() - 1; >+ >+ String expectedCompletionNodeToString = "<CompleteOnName:o1.compa>"; >+ String expectedParentNodeToString = "<NONE>"; >+ String completionIdentifier = "compa"; >+ String expectedReplacedSource = "o1.compareTo"; >+ String expectedUnitDisplayString = >+ "import java.util.ArrayList;\n" + >+ "import java.util.Arrays;\n" + >+ "import java.util.Collections;\n" + >+ "import java.util.Comparator;\n" + >+ "public class X {\n" + >+ " public X() {\n" + >+ " }\n" + >+ " int compareTo(X x) {\n" + >+ " }\n" + >+ " void foo() {\n" + >+ " (X o1, X o2) -> <CompleteOnName:o1.compa>;\n" + >+ " }\n" + >+ "}\n"; >+ >+ checkMethodParse( >+ string.toCharArray(), >+ cursorLocation, >+ expectedCompletionNodeToString, >+ expectedParentNodeToString, >+ expectedUnitDisplayString, >+ completionIdentifier, >+ expectedReplacedSource, >+ "diet ast"); >+} > } >diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java >index 9b21be2..e4fa9b9 100644 >--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java >+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java >@@ -570,7 +570,7 @@ > " public static void main(String[] args) {\n" + > " I i = () -> {\n" + > " xyz\n" + >- " }\n" + >+ " }\n" + > " }\n" + > "}\n"); > >@@ -597,4 +597,98 @@ > " goo() {key=LX;.goo()LX;} [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]],\n" + > "}" , requestor.getContext()); > } >+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=422468, [1.8][assist] Code assist issues with type elided lambda parameters >+public void _test018() throws JavaModelException { // ensure higher relevance for matching return type. >+ this.workingCopies = new ICompilationUnit[1]; >+ this.workingCopies[0] = getWorkingCopy( >+ "/Completion/src/X.java", >+ "interface I {\n" + >+ " void foo(String x);\n" + >+ "}\n" + >+ "public class X {\n" + >+ " String xField;\n" + >+ " static void goo(String s) {\n" + >+ " }\n" + >+ " static void goo(I i) {\n" + >+ " }\n" + >+ " public static void main(String[] args) {\n" + >+ " goo((xyz) -> {\n" + >+ " System.out.println(xyz.);\n" + >+ " });\n" + >+ " }\n" + >+ "}\n"); >+ >+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true, true, true, false); >+ requestor.allowAllRequiredProposals(); >+ requestor.setRequireExtendedContext(true); >+ requestor.setComputeEnclosingElement(false); >+ requestor.setComputeVisibleElements(true); >+ requestor.setAssignableType("LX;"); >+ >+ String str = this.workingCopies[0].getSource(); >+ String completeBehind = "xyz."; >+ int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); >+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner); >+ assertEquals("completion offset=192\n" + >+ "completion range=[189, 191]\n" + >+ "completion token=\"xyz\"\n" + >+ "completion token kind=TOKEN_KIND_NAME\n" + >+ "expectedTypesSignatures=null\n" + >+ "expectedTypesKeys=null\n" + >+ "completion token location={STATEMENT_START}\n" + >+ "visibleElements={\n" + >+ " xField {key=LX;.xField)LX;} [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]],\n" + >+ " goo() {key=LX;.goo()LX;} [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]],\n" + >+ "}" , requestor.getContext()); >+} >+//https://bugs.eclipse.org/bugs/show_bug.cgi?id=422468, [1.8][assist] Code assist issues with type elided lambda parameters >+public void _test018a() throws JavaModelException { // ensure higher relevance for matching return type. >+ this.workingCopies = new ICompilationUnit[1]; >+ this.workingCopies[0] = getWorkingCopy( >+ "/Completion/src/X.java", >+ "interface I {\n" + >+ " void foo(String x);\n" + >+ "}\n" + >+ "public class X {\n" + >+ " String xField;\n" + >+ " static void goo(String s) {\n" + >+ " }\n" + >+ " static void goo(I i) {\n" + >+ " }\n" + >+ " public static void main(String[] args) {\n" + >+ " args = null;\n" + >+ " if (args != null) {\n" + >+ " xField = null;\n" + >+ " else \n" + >+ " xField = null;\n" + >+ " while (true);\n" + >+ " goo((xyz) -> {\n" + >+ " System.out.println(xyz.)\n" + >+ " });\n" + >+ " }\n" + >+ "}\n"); >+ >+ CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true, true, true, false); >+ requestor.allowAllRequiredProposals(); >+ requestor.setRequireExtendedContext(true); >+ requestor.setComputeEnclosingElement(false); >+ requestor.setComputeVisibleElements(true); >+ requestor.setAssignableType("LX;"); >+ >+ String str = this.workingCopies[0].getSource(); >+ String completeBehind = "xyz."; >+ int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); >+ this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner); >+ assertEquals("completion offset=192\n" + >+ "completion range=[189, 191]\n" + >+ "completion token=\"xyz\"\n" + >+ "completion token kind=TOKEN_KIND_NAME\n" + >+ "expectedTypesSignatures=null\n" + >+ "expectedTypesKeys=null\n" + >+ "completion token location={STATEMENT_START}\n" + >+ "visibleElements={\n" + >+ " xField {key=LX;.xField)LX;} [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]],\n" + >+ " goo() {key=LX;.goo()LX;} [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]],\n" + >+ "}" , requestor.getContext()); >+} > } >diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java >index e12991f..ce95a4c 100644 >--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java >+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java >@@ -28,7 +28,7 @@ > ICompilationUnit wc = null; > > static { >- // TESTS_NAMES = new String[] { "test0023" }; >+// TESTS_NAMES = new String[] { "testParser" }; > // TESTS_NUMBERS = new int[] { 124 }; > // TESTS_RANGE = new int[] { 16, -1 }; > } >@@ -1531,4 +1531,103 @@ > elements > ); > } >+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=422468, [1.8][assist] Code assist issues with type elided lambda parameters >+public void test422468d() throws JavaModelException { >+ this.wc = getWorkingCopy( >+ "/Resolve/src/X.java", >+ "interface I {\n" + >+ " J foo(String x, String y);\n" + >+ "}\n" + >+ "interface J {\n" + >+ " K foo(String x, String y);\n" + >+ "}\n" + >+ "interface K {\n" + >+ " int foo(String x, int y);\n" + >+ "}\n" + >+ "public class X {\n" + >+ " static void goo(K i) {}\n" + >+ " public static void main(String[] args) {\n" + >+ " I i = (x, y) -> { return (a, b) -> (p, q) -> a.length(); };\n" + >+ " }\n" + >+ "}\n"); >+ >+ String str = this.wc.getSource(); >+ String selection = "a.length"; >+ int start = str.lastIndexOf(selection); >+ int length = selection.length(); >+ >+ IJavaElement[] elements = this.wc.codeSelect(start, length); >+ assertElementsEqual( >+ "Unexpected elements", >+ "length() [in String [in String.class [in java.lang [in "+ getExternalPath() + "jclMin1.8.jar]]]]", >+ elements >+ ); >+} >+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=422468, [1.8][assist] Code assist issues with type elided lambda parameters >+public void test422468e() throws JavaModelException { >+ this.wc = getWorkingCopy( >+ "/Resolve/src/X.java", >+ "interface I {\n" + >+ " J foo(String x, String y);\n" + >+ "}\n" + >+ "interface J {\n" + >+ " K foo(String x, String y);\n" + >+ "}\n" + >+ "interface K {\n" + >+ " int foo(String x, int y);\n" + >+ "}\n" + >+ "public class X {\n" + >+ " static void goo(K i) {}\n" + >+ " public static void main(String[] args) {\n" + >+ " I i = (x, y) -> { return (a, b) -> (p, q) -> a.length(); };\n" + >+ " }\n" + >+ "}\n"); >+ >+ String str = this.wc.getSource(); >+ String selection = "q"; >+ int start = str.lastIndexOf(selection); >+ int length = selection.length(); >+ >+ IJavaElement[] elements = this.wc.codeSelect(start, length); >+ assertElementsEqual( >+ "Unexpected elements", >+ "q [in main(String[]) [in X [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]", >+ elements >+ ); >+} >+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=422468, [1.8][assist] Code assist issues with type elided lambda parameters >+public void testParser() throws JavaModelException { >+ this.wc = getWorkingCopy( >+ "/Resolve/src/X.java", >+ "interface I {\n" + >+ " int foo(String x, Integer y);\n" + >+ "}\n" + >+ "public class X {\n" + >+ " public static void main(String[] args) {\n" + >+ " I i = (x, y) -> {\n" + >+ " x = \"Hello\"\n" + >+ " y = 10; \n" + >+ " if (x.length() > y) {\n" + >+ " System.out.println(\"if\");\n" + >+ " } else {\n" + >+ " System.out.println(\"else\");\n" + >+ " }\n" + >+ " return x.length();\n" + >+ " };\n" + >+ " // System.out.println((I) (p, q) -> { return q.\n" + >+ " }\n" + >+ "}\n"); >+ >+ String str = this.wc.getSource(); >+ String selection = "x"; >+ int start = str.lastIndexOf(selection); >+ int length = selection.length(); >+ >+ IJavaElement[] elements = this.wc.codeSelect(start, length); >+ assertElementsEqual( >+ "Unexpected elements", >+ "x [in main(String[]) [in X [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]", >+ elements >+ ); >+} > } >diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionUnitStructureRequestor.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionUnitStructureRequestor.java >index 0d600d3..881ca15 100644 >--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionUnitStructureRequestor.java >+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionUnitStructureRequestor.java >@@ -37,7 +37,7 @@ > import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference; > import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; > import org.eclipse.jdt.internal.compiler.ast.TypeReference; >-import org.eclipse.jdt.internal.compiler.parser.Parser; >+import org.eclipse.jdt.internal.compiler.parser.CommitRollbackParser; > import org.eclipse.jdt.internal.core.AnnotatableInfo; > import org.eclipse.jdt.internal.core.Annotation; > import org.eclipse.jdt.internal.core.CompilationUnit; >@@ -64,7 +64,7 @@ > public CompletionUnitStructureRequestor( > ICompilationUnit unit, > CompilationUnitElementInfo unitInfo, >- Parser parser, >+ CommitRollbackParser parser, > ASTNode assistNode, > Map bindingCache, > Map elementCache, >diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java >index b8cbc0e..a96efb8 100644 >--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java >+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java >@@ -31,7 +31,6 @@ > import org.eclipse.jdt.internal.compiler.*; > import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; > import org.eclipse.jdt.internal.compiler.env.*; >- > import org.eclipse.jdt.internal.compiler.ast.*; > import org.eclipse.jdt.internal.compiler.parser.*; > import org.eclipse.jdt.internal.compiler.problem.*; >@@ -614,7 +613,7 @@ > public Object becomeSimpleParser() { > CompletionScanner completionScanner = (CompletionScanner)this.scanner; > int[] parserState = new int[] {this.cursorLocation, completionScanner.cursorLocation}; >- >+ // ?? > this.cursorLocation = Integer.MAX_VALUE; > completionScanner.cursorLocation = Integer.MAX_VALUE; > >@@ -3470,6 +3469,8 @@ > case K_MEMBER_VALUE_ARRAY_INITIALIZER: > popElement(K_MEMBER_VALUE_ARRAY_INITIALIZER); > break; >+ case K_LAMBDA_EXPRESSION_DELIMITER: >+ break; // will be popped when the containing block statement is reduced. > default: > popElement(K_ARRAY_INITIALIZER); > break; >@@ -3675,6 +3676,8 @@ > break; > case TokenNamedo: > pushOnElementStack(K_BLOCK_DELIMITER, DO); >+ break; >+ case TokenNameARROW: > break; > default : > pushOnElementStack(K_BLOCK_DELIMITER); >@@ -4609,6 +4612,18 @@ > this.labelPtr = -1; > initializeForBlockStatements(); > } >+protected void copyState(CommitRollbackParser from) { >+ >+ super.copyState(from); >+ >+ CompletionParser parser = (CompletionParser) from; >+ >+ this.invocationType = parser.invocationType; >+ this.qualifier = parser.qualifier; >+ this.inReferenceExpression = parser.inReferenceExpression; >+ this.hasUnusedModifiers = parser.hasUnusedModifiers; >+ this.canBeExplicitConstructor = parser.canBeExplicitConstructor; >+} > /* > * Initializes the state of the parser that is about to go for BlockStatements. > */ >@@ -4954,6 +4969,10 @@ > break; > } > } >+ >+protected CommitRollbackParser createSnapShotParser() { >+ return new CompletionParser(this.problemReporter, this.storeSourceEnds); >+} > /* > * Reset internal state after completion is over > */ >@@ -4977,7 +4996,7 @@ > int[] state = (int[]) parserState; > > CompletionScanner completionScanner = (CompletionScanner)this.scanner; >- >+ // ?? > this.cursorLocation = state[0]; > completionScanner.cursorLocation = state[1]; > } >@@ -4988,13 +5007,21 @@ > * Move checkpoint location, reset internal stacks and > * decide which grammar goal is activated. > */ >-protected boolean resumeAfterRecovery() { >+protected int resumeAfterRecovery(boolean errorRecovery) { > this.hasUnusedModifiers = false; > if (this.assistNode != null) { >+ >+ if (requireExtendedRecovery()) { >+ if (!errorRecovery) { >+ return RESUME; >+ } >+ return super.resumeAfterRecovery(errorRecovery); >+ } >+ > /* if reached [eof] inside method body, but still inside nested type, > or inside a field initializer, should continue in diet mode until > the end of the method body or compilation unit */ >- if ((this.scanner.eofPosition == this.cursorLocation+1) >+ if ((this.scanner.eofPosition >= this.cursorLocation+1) > && (!(this.referenceContext instanceof CompilationUnitDeclaration) > || isIndirectlyInsideFieldInitialization() > || this.assistNodeParent instanceof FieldDeclaration && !(this.assistNodeParent instanceof Initializer))) { >@@ -5022,6 +5049,7 @@ > } > } > */ >+ > /* restart in diet mode for finding sibling constructs */ > if (this.currentElement instanceof RecoveredType > || this.currentElement.enclosingType() != null){ >@@ -5035,11 +5063,11 @@ > this.scanner.eofPosition = end < Integer.MAX_VALUE ? end + 1 : end; > } else { > resetStacks(); >- return false; >+ return HALT; > } > } > } >- return super.resumeAfterRecovery(); >+ return super.resumeAfterRecovery(errorRecovery); > } > public void setAssistIdentifier(char[] assistIdent){ > ((CompletionScanner)this.scanner).completionIdentifier = assistIdent; >diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java >index 5a08e9a..2e03b11 100644 >--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java >+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java >@@ -23,6 +23,7 @@ > import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; > import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; > import org.eclipse.jdt.internal.compiler.ast.Annotation; >+import org.eclipse.jdt.internal.compiler.ast.Argument; > import org.eclipse.jdt.internal.compiler.ast.Block; > import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; > import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; >@@ -44,6 +45,7 @@ > import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; > import org.eclipse.jdt.internal.compiler.lookup.Binding; > import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; >+import org.eclipse.jdt.internal.compiler.parser.CommitRollbackParser; > import org.eclipse.jdt.internal.compiler.parser.Parser; > import org.eclipse.jdt.internal.compiler.parser.RecoveredBlock; > import org.eclipse.jdt.internal.compiler.parser.RecoveredElement; >@@ -93,7 +95,8 @@ > protected static final int K_FIELD_INITIALIZER_DELIMITER = ASSIST_PARSER + 4; // whether we are inside a field initializer > protected static final int K_ATTRIBUTE_VALUE_DELIMITER = ASSIST_PARSER + 5; // whether we are inside a annotation attribute valuer > protected static final int K_ENUM_CONSTANT_DELIMITER = ASSIST_PARSER + 6; // whether we are inside a field initializer >- >+ protected static final int K_LAMBDA_EXPRESSION_DELIMITER = ASSIST_PARSER + 7; // whether we are inside a lambda expression >+ > // selector constants > protected static final int THIS_CONSTRUCTOR = -1; > protected static final int SUPER_CONSTRUCTOR = -2; >@@ -101,9 +104,13 @@ > // enum constant constants > protected static final int NO_BODY = 0; > protected static final int WITH_BODY = 1; >+ >+ protected static final int EXPRESSION_BODY = 0; >+ protected static final int BLOCK_BODY = 1; >+ private static final boolean DEBUG_COMMIT_ROLLBACK = true; > > protected boolean isFirst = false; >- protected boolean lambdaNeedsClosure = false; // :) >+ > > public AssistParser(ProblemReporter problemReporter) { > super(problemReporter, true); >@@ -112,8 +119,34 @@ > setMethodsFullRecovery(false); > setStatementsRecovery(false); > } >+ > public abstract char[] assistIdentifier(); > >+protected void copyState(CommitRollbackParser from) { >+ >+ super.copyState(from); >+ >+ AssistParser parser = (AssistParser) from; >+ >+ this.previousToken = parser.previousToken; >+ this.previousIdentifierPtr = parser.previousIdentifierPtr; >+ >+ this.lastModifiers = parser.lastModifiers; >+ this.lastModifiersStart = parser.lastModifiersStart; >+ >+ this.bracketDepth = parser.bracketDepth; >+ this.elementPtr = parser.elementPtr; >+ >+ int length; >+ System.arraycopy(parser.blockStarts, 0, this.blockStarts = new int [length = parser.blockStarts.length], 0, length); >+ System.arraycopy(parser.elementKindStack, 0, this.elementKindStack = new int [length = parser.elementKindStack.length], 0, length); >+ System.arraycopy(parser.elementInfoStack, 0, this.elementInfoStack = new int [length = parser.elementInfoStack.length], 0, length); >+ System.arraycopy(parser.elementObjectInfoStack, 0, this.elementObjectInfoStack = new Object [length = parser.elementObjectInfoStack.length], 0, length); >+ >+ this.previousKind = parser.previousKind; >+ this.previousInfo = parser.previousInfo; >+ this.previousObjectInfo = parser.previousObjectInfo; >+} > /** > * The parser become a simple parser which behave like a Parser > * @return the state of the assist parser to be able to restore the assist parser state >@@ -279,8 +312,12 @@ > } > if (node instanceof LambdaExpression) { > LambdaExpression lambda = (LambdaExpression) node; >- element = element.add(lambda, 0); >- this.lastCheckPoint = lambda.sourceEnd + 1; >+ if (!lambda.argumentsTypeElided()) { >+ Argument [] arguments = lambda.arguments(); >+ for (int j = 0, length = arguments.length; j < length; j++) { >+ element = element.add(fakeLocalFromArgument(arguments[j]), 0); >+ } >+ } > continue; > } > if (this.assistNode != null && node instanceof Statement) { >@@ -401,27 +438,46 @@ > protected void consumeExplicitConstructorInvocation(int flag, int recFlag) { > super.consumeExplicitConstructorInvocation(flag, recFlag); > popElement(K_SELECTOR); >- triggerRecoveryUponLambdaClosure(); >-} >-protected void triggerRecoveryUponLambdaClosure() { >- if (this.assistNode == null || !this.lambdaNeedsClosure) >- return; >- ASTNode node = this.astStack[this.astPtr]; >- if (this.assistNode.sourceStart >= node.sourceStart && this.assistNode.sourceEnd <= node.sourceEnd) { >- for (int i = 0; i <= this.astPtr; i++) { >- if (this.astStack[i] instanceof LambdaExpression) >- return; >- } >- this.restartRecovery = true; >- this.isOrphanCompletionNode = false; >- this.lambdaNeedsClosure = false; >- } >-} >-protected void consumeExplicitConstructorInvocationWithTypeArguments(int flag, int recFlag) { >- super.consumeExplicitConstructorInvocationWithTypeArguments(flag, recFlag); >- triggerRecoveryUponLambdaClosure(); > } > >+protected void consumeBlock() { >+ super.consumeBlock(); >+ if (DEBUG_COMMIT_ROLLBACK) { >+ System.out.println("----- }");//$NON-NLS-1$ >+ } >+} >+protected void consumeBlockStatement() { >+ super.consumeBlockStatement(); >+ Statement statement = (Statement) this.astStack[this.astPtr]; >+ int statementStart, statementEnd; >+ statementStart = statement.sourceStart; >+ statementEnd = statement instanceof AbstractVariableDeclaration ? ((AbstractVariableDeclaration)statement).declarationSourceEnd : statement.sourceEnd; >+ for (int i = this.elementPtr; i >= 0; --i) { >+ if (this.elementKindStack[i] != K_LAMBDA_EXPRESSION_DELIMITER) >+ continue; >+ LambdaExpression expression = (LambdaExpression) this.elementObjectInfoStack[i]; >+ if (expression.sourceStart >= statementStart && expression.sourceEnd <= statementEnd) { >+ this.elementPtr = i - 1; >+ this.restartRecovery = true; >+ } else { >+ this.restartRecovery = false; // lambda is still awaiting closure. >+ return; >+ } >+ } >+} >+ >+protected void consumeBlockStatements() { >+ super.consumeBlockStatements(); >+ if (requireExtendedRecovery()) { >+ this.commit = true; >+ if (DEBUG_COMMIT_ROLLBACK) { >+ System.out.println(this.astStack[this.astPtr]); >+ System.out.println("---------------------------------------------------------");//$NON-NLS-1$ >+ } >+ } else { >+ this.restartRecovery = true; >+ } >+} > protected void consumeForceNoDiet() { > super.consumeForceNoDiet(); > // if we are not in a method (i.e. we are not in a local variable initializer) >@@ -444,9 +500,27 @@ > super.consumeInterfaceHeader(); > pushOnElementStack(K_TYPE_DELIMITER); > } >-protected void consumeExpressionStatement() { >- super.consumeExpressionStatement(); >- triggerRecoveryUponLambdaClosure(); >+ >+LocalDeclaration fakeLocalFromArgument(Argument argument) { >+ LocalDeclaration local = new LocalDeclaration(argument.name, argument.sourceStart, argument.sourceEnd); >+ local.declarationSourceStart = argument.declarationSourceStart; >+ local.declarationSourceEnd = argument.declarationSourceEnd; >+ local.modifiers = argument.modifiers; >+ local.modifiersSourceStart = argument.modifiersSourceStart; >+ local.annotations = argument.annotations; >+ local.type = argument.type; >+ return local; >+} >+protected void consumeLambdaHeader() { >+ super.consumeLambdaHeader(); >+ LambdaExpression lexp = (LambdaExpression) this.astStack[this.astPtr]; >+ pushOnElementStack(K_LAMBDA_EXPRESSION_DELIMITER, EXPRESSION_BODY, lexp); >+ >+// if (this.currentElement != null) { >+// for (int i = 0, length = arguments.length; i < length; i++) { >+// this.currentElement = this.currentElement.add(fakeLocalFromArgument(arguments[i]), 0); >+// } >+// } > } > protected void consumeMethodBody() { > super.consumeMethodBody(); >@@ -457,7 +531,6 @@ > popElement(K_METHOD_DELIMITER); > } > super.consumeMethodDeclaration(isNotAbstract, isDefaultMethod); >- triggerRecoveryUponLambdaClosure(); > } > protected void consumeMethodHeader() { > super.consumeMethodHeader(); >@@ -519,14 +592,22 @@ > // OpenBlock ::= $empty > > super.consumeOpenBlock(); >- int stackLength = this.blockStarts.length; >- if (this.realBlockPtr >= stackLength) { >- System.arraycopy( >- this.blockStarts, 0, >- this.blockStarts = new int[stackLength + StackIncrement], 0, >- stackLength); >+ // if (this.astPtr < 0 || !(this.astStack[this.astPtr] instanceof LambdaExpression && this.previousToken == TokenNameARROW)) { >+ int stackLength = this.blockStarts.length; >+ if (this.realBlockPtr >= stackLength) { >+ System.arraycopy( >+ this.blockStarts, 0, >+ this.blockStarts = new int[stackLength + StackIncrement], 0, >+ stackLength); >+ } >+ this.blockStarts[this.realBlockPtr] = this.scanner.startPosition; >+ // } >+ if (requireExtendedRecovery()) { >+ this.commit = true; >+ if (DEBUG_COMMIT_ROLLBACK) { >+ System.out.println(" --- {"); //$NON-NLS-1$ >+ } > } >- this.blockStarts[this.realBlockPtr] = this.scanner.startPosition; > } > protected void consumeOpenFakeBlock() { > // OpenBlock ::= $empty >@@ -853,6 +934,10 @@ > } > break; > case TokenNameLBRACE: >+ if (this.previousToken == TokenNameARROW) { >+ popElement(K_LAMBDA_EXPRESSION_DELIMITER); >+ pushOnElementStack(K_LAMBDA_EXPRESSION_DELIMITER, BLOCK_BODY, this.previousObjectInfo); >+ } > this.bracketDepth++; > break; > case TokenNameLBRACKET: >@@ -1264,6 +1349,15 @@ > } > return false; > } >+protected boolean isIndirectlyInsideLambdaExpression(){ >+ int i = this.elementPtr; >+ while (i > -1) { >+ if (this.elementKindStack[i] == K_LAMBDA_EXPRESSION_DELIMITER) >+ return true; >+ i--; >+ } >+ return false; >+} > protected boolean isIndirectlyInsideType(){ > int i = this.elementPtr; > while(i > -1) { >@@ -1597,6 +1691,13 @@ > flushElementStack(); > } > } >+ >+public boolean requireExtendedRecovery() { >+ if (this.assistNode instanceof TypeReference) >+ return false; >+ return lastIndexOfElement(K_LAMBDA_EXPRESSION_DELIMITER) >= 0; >+} >+ > protected void pushOnElementStack(int kind){ > this.pushOnElementStack(kind, 0, null); > } >@@ -1659,7 +1760,7 @@ > break; > case TokenNameRBRACE : > super.recoveryTokenCheck(); >- if(this.currentElement != oldElement && !isInsideAttributeValue()) { >+ if(this.currentElement != oldElement && !isInsideAttributeValue() && !isIndirectlyInsideLambdaExpression()) { > if(oldElement instanceof RecoveredInitializer > || oldElement instanceof RecoveredMethod > || (oldElement instanceof RecoveredBlock && oldElement.parent instanceof RecoveredInitializer) >@@ -1691,7 +1792,18 @@ > * Move checkpoint location, reset internal stacks and > * decide which grammar goal is activated. > */ >-protected boolean resumeAfterRecovery() { >+protected int resumeAfterRecovery(boolean errorRecovery) { >+ >+ if (requireExtendedRecovery()) { >+ if (errorRecovery) { >+ int mode = fallBackToSpringForward((Statement) null); >+ if (mode == RESUME || mode == HALT) >+ return mode; >+ // else fall through and RESTART >+ } else { >+ return RESUME; >+ } >+ } > > // reset internal stacks > this.astPtr = -1; >@@ -1700,24 +1812,31 @@ > this.expressionLengthPtr = -1; > this.typeAnnotationLengthPtr = -1; > this.typeAnnotationPtr = -1; >+ > this.identifierPtr = -1; > this.identifierLengthPtr = -1; > this.intPtr = -1; >+ >+ > this.dimensions = 0 ; > this.recoveredStaticInitializerStart = 0; > > this.genericsIdentifiersLengthPtr = -1; > this.genericsLengthPtr = -1; > this.genericsPtr = -1; >+ >+ this.valueLambdaNestDepth = -1; > > this.modifiers = ClassFileConstants.AccDefault; > this.modifiersSourceStart = -1; > >+ // Assist state should require some rewinding too ??? >+ > // if in diet mode, reset the diet counter because we're going to restart outside an initializer. > if (this.diet) this.dietInt = 0; > > /* attempt to move checkpoint location */ >- if (!moveRecoveryCheckpoint()) return false; >+ if (!moveRecoveryCheckpoint()) return HALT; > > // only look for headers > if (this.referenceContext instanceof CompilationUnitDeclaration >@@ -1738,7 +1857,7 @@ > goForHeaders(); > this.diet = true; // passed this point, will not consider method bodies > } >- return true; >+ return RESTART; > } > if (this.referenceContext instanceof AbstractMethodDeclaration > || this.referenceContext instanceof TypeDeclaration){ >@@ -1750,10 +1869,10 @@ > prepareForBlockStatements(); > goForBlockStatementsOrCatchHeader(); > } >- return true; >+ return RESTART; > } > // does not know how to restart >- return false; >+ return HALT; > } > // https://bugs.eclipse.org/bugs/show_bug.cgi?id=292087 > // To be implemented in children viz. CompletionParser that are aware of array initializers >@@ -1826,4 +1945,4 @@ > return ast; > } > } >-} >+} >\ No newline at end of file >diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java >index 357ab58..a9fa376 100644 >--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java >+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java >@@ -40,7 +40,6 @@ > import org.eclipse.jdt.internal.compiler.ast.Expression; > import org.eclipse.jdt.internal.compiler.ast.FieldReference; > import org.eclipse.jdt.internal.compiler.ast.ImportReference; >-import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; > import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; > import org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation; > import org.eclipse.jdt.internal.compiler.ast.MemberValuePair; >@@ -62,6 +61,7 @@ > import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; > import org.eclipse.jdt.internal.compiler.lookup.BlockScope; > import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; >+import org.eclipse.jdt.internal.compiler.parser.CommitRollbackParser; > import org.eclipse.jdt.internal.compiler.parser.JavadocParser; > import org.eclipse.jdt.internal.compiler.parser.RecoveredType; > import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; >@@ -1184,6 +1184,9 @@ > this.restartRecovery = true; // used to avoid branching back into the regular automaton > } > } >+protected CommitRollbackParser createSnapShotParser() { >+ return new SelectionParser(this.problemReporter); >+} > public ImportReference createAssistImportReference(char[][] tokens, long[] positions, int mod){ > return new SelectionOnImportReference(tokens, positions, mod); > } >@@ -1413,28 +1416,6 @@ > return super.parse(sourceUnit, compilationResult, -1, -1/*parse without reseting the scanner*/); > } > >-protected int resumeOnSyntaxError() { >- >- if (this.referenceContext instanceof CompilationUnitDeclaration) >- return super.resumeOnSyntaxError(); >- >- // Defer initial *triggered* recovery if we see a type elided lambda expression on the stack. >- if (this.assistNode != null && this.restartRecovery) { >- this.lambdaNeedsClosure = false; >- for (int i = this.astPtr; i >= 0; i--) { >- if (this.astStack[i] instanceof LambdaExpression) { >- LambdaExpression expression = (LambdaExpression) this.astStack[i]; >- if (expression.argumentsTypeElided()) { >- this.restartRecovery = false; // will be restarted in when the containing expression statement or explicit constructor call is reduced. >- this.lambdaNeedsClosure = true; >- return RESUME; >- } >- } >- } >- } >- return super.resumeOnSyntaxError(); >-} >- > /* > * Reset context so as to resume to regular parse loop > * If unable to reset for resuming, answers false. >@@ -1442,27 +1423,33 @@ > * Move checkpoint location, reset internal stacks and > * decide which grammar goal is activated. > */ >-protected boolean resumeAfterRecovery() { >+protected int resumeAfterRecovery(boolean errorRecovery) { > > /* if reached assist node inside method body, but still inside nested type, > should continue in diet mode until the end of the method body */ > if (this.assistNode != null > && !(this.referenceContext instanceof CompilationUnitDeclaration)){ > this.currentElement.preserveEnclosingBlocks(); >+ if (requireExtendedRecovery()) { >+ if (!errorRecovery) { >+ return RESUME; >+ } >+ return super.resumeAfterRecovery(errorRecovery); >+ } > if (this.currentElement.enclosingType() == null) { >- if(!(this.currentElement instanceof RecoveredType)) { >+ if (!(this.currentElement instanceof RecoveredType)) { > resetStacks(); >- return false; >- } >+ return HALT; >+ } > >- RecoveredType recoveredType = (RecoveredType)this.currentElement; >- if(recoveredType.typeDeclaration != null && recoveredType.typeDeclaration.allocation == this.assistNode){ >+ RecoveredType recoveredType = (RecoveredType) this.currentElement; >+ if (recoveredType.typeDeclaration != null && recoveredType.typeDeclaration.allocation == this.assistNode) { > resetStacks(); >- return false; >+ return HALT; > } > } > } >- return super.resumeAfterRecovery(); >+ return super.resumeAfterRecovery(errorRecovery); > } > > public void selectionIdentifierCheck(){ >@@ -1504,15 +1491,16 @@ > char[] identifierName = this.identifierStack[this.identifierPtr]; > long namePositions = this.identifierPositionStack[this.identifierPtr--]; > >- Argument arg = >+ Argument argument = > new SelectionOnArgumentName( > identifierName, > namePositions, > null, // elided type > ClassFileConstants.AccDefault, > true); >- arg.declarationSourceStart = (int) (namePositions >>> 32); >- return arg; >+ argument.declarationSourceStart = (int) (namePositions >>> 32); >+ this.assistNode = argument; >+ return argument; > } > public String toString() { > String s = Util.EMPTY_STRING; >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java >index bc1870a..054442f 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java >@@ -307,6 +307,8 @@ > public static final int IsSynthetic = ASTNode.Bit7; > > public static final Argument [] NO_ARGUMENTS = new Argument [0]; >+ >+ public static final Block NO_BODY = new Block(0); > > public ASTNode() { > >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java >index 010aacd..6d715eb 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java >@@ -71,24 +71,24 @@ > private Statement body; > public boolean hasParentheses; > public MethodScope scope; >- private boolean voidCompatible = true; >- private boolean valueCompatible = false; >+ boolean voidCompatible = true; >+ boolean valueCompatible = false; > private boolean shapeAnalysisComplete = false; >- private boolean returnsValue; >- private boolean returnsVoid; >+ boolean returnsValue; >+ boolean returnsVoid; > private LambdaExpression original = this; > private SyntheticArgumentBinding[] outerLocalVariables = NO_SYNTHETIC_ARGUMENTS; > private int outerLocalVariablesSlotSize = 0; > public boolean shouldCaptureInstance = false; >- private boolean shouldUnelideTypes = false; >+ private boolean assistNode = false; > private boolean hasIgnoredMandatoryErrors = false; > private static final SyntheticArgumentBinding [] NO_SYNTHETIC_ARGUMENTS = new SyntheticArgumentBinding[0]; > >- public LambdaExpression(CompilationResult compilationResult, boolean shouldUnelideTypes) { >+ public LambdaExpression(CompilationResult compilationResult, boolean assistNode) { > super(compilationResult); >- this.shouldUnelideTypes = shouldUnelideTypes; >+ this.assistNode = assistNode; > setArguments(NO_ARGUMENTS); >- setBody(new Block(0)); >+ setBody(NO_BODY); > } > > public void setArguments(Argument [] arguments) { >@@ -101,7 +101,7 @@ > } > > public void setBody(Statement body) { >- this.body = body == null ? new Block(0) : body; >+ this.body = body == null ? NO_BODY : body; > } > > public Statement body() { >@@ -110,6 +110,10 @@ > > public void setArrowPosition(int arrowPosition) { > this.arrowPosition = arrowPosition; >+ } >+ >+ public int getArrowPosition() { >+ return this.arrowPosition; > } > > protected FunctionalExpression original() { >@@ -188,7 +192,7 @@ > > if (!haveDescriptor) { > if (argumentsTypeElided) { >- if (!this.shouldUnelideTypes) >+ if (!this.assistNode) > return null; // FUBAR, bail out... > // for code assist ONLY, keep the sluice gate shut on bogus errors otherwise. > argumentsTypeElided = false; >@@ -524,6 +528,40 @@ > return false; > } > >+ private void analyzeShape() { // simple minded analysis for code assist. >+ class ShapeComputer extends ASTVisitor { >+ public boolean visit(TypeDeclaration type, BlockScope skope) { >+ return false; >+ } >+ public boolean visit(TypeDeclaration type, ClassScope skope) { >+ return false; >+ } >+ public boolean visit(LambdaExpression type, BlockScope skope) { >+ return false; >+ } >+ public boolean visit(ReturnStatement returnStatement, BlockScope skope) { >+ if (returnStatement.expression != null) { >+ LambdaExpression.this.valueCompatible = true; >+ LambdaExpression.this.voidCompatible = false; >+ } else { >+ LambdaExpression.this.voidCompatible = true; >+ LambdaExpression.this.valueCompatible = false; >+ } >+ return false; >+ } >+ } >+ if (this.body instanceof Expression) { >+ this.voidCompatible = ((Expression) this.body).statementExpression(); >+ this.valueCompatible = true; >+ } else { >+ // We need to be a bit tolerant/fuzzy here: the code is being written "just now", if we are too pedantic, selection/completion will break; >+ this.voidCompatible = true; >+ this.valueCompatible = true; >+ this.body.traverse(new ShapeComputer(), null); >+ } >+ this.shapeAnalysisComplete = true; >+ } >+ > public boolean isCompatibleWith(final TypeBinding left, final Scope someScope) { > > final MethodBinding sam = left.getSingleAbstractMethod(this.enclosingScope); >@@ -540,8 +578,19 @@ > compilerOptions.isAnnotationBasedNullAnalysisEnabled = false; > try { > final LambdaExpression copy = copy(); >- if (copy == null) >- return false; >+ if (copy == null) { >+ if (this.assistNode) { >+ analyzeShape(); // not on terra firma here ! >+ if (sam.returnType.id == TypeIds.T_void) { >+ if (!this.voidCompatible) >+ return false; >+ } else { >+ if (!this.valueCompatible) >+ return false; >+ } >+ } >+ return !isPertinentToApplicability(left); >+ } > copy.setExpressionContext(this.expressionContext); > copy.setExpectedType(left); > this.hasIgnoredMandatoryErrors = false; >@@ -576,9 +625,9 @@ > } > } > >- if (!isPertinentToApplicability(left)) >+ if (!isPertinentToApplicability(left)) // This check should happen after return type check below, but for buggy javac compatibility we have left it in. > return true; >- >+ > if (sam.returnType.id == TypeIds.T_void) { > if (!this.voidCompatible) > return false; >@@ -586,8 +635,7 @@ > if (!this.valueCompatible) > return false; > } >- >- Expression [] returnExpressions = this.resultExpressions; >+ Expression [] returnExpressions = this.resultExpressions; > for (int i = 0, length = returnExpressions.length; i < length; i++) { > if (returnExpressions[i] instanceof FunctionalExpression) { // don't want to use the resolvedType - polluted from some other overload resolution candidate > if (!returnExpressions[i].isCompatibleWith(sam.returnType, this.enclosingScope)) >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/CommitRollbackParser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/CommitRollbackParser.java >new file mode 100644 >index 0000000..aa3a176 >--- /dev/null >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/CommitRollbackParser.java >@@ -0,0 +1,308 @@ >+/******************************************************************************* >+ * Copyright (c) 2013 IBM Corporation and others. >+ * All rights reserved. This program and the accompanying materials >+ * are made available under the terms of the Eclipse Public License v1.0 >+ * which accompanies this distribution, and is available at >+ * http://www.eclipse.org/legal/epl-v10.html >+ * >+ * 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 >+ *******************************************************************************/ >+package org.eclipse.jdt.internal.compiler.parser; >+ >+import org.eclipse.jdt.core.compiler.InvalidInputException; >+import org.eclipse.jdt.internal.compiler.ast.ASTNode; >+import org.eclipse.jdt.internal.compiler.ast.Annotation; >+import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; >+import org.eclipse.jdt.internal.compiler.ast.Expression; >+import org.eclipse.jdt.internal.compiler.ast.Statement; >+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; >+ >+public abstract class CommitRollbackParser implements TerminalTokens, ParserBasicInformation { >+ >+ // resumeOnSyntaxError codes: >+ protected static final int HALT = 0; // halt and throw up hands. >+ protected static final int RESTART = 1; // stacks adjusted, alternate goal from check point. >+ protected static final int RESUME = 2; // stacks untouched, just continue from where left off. >+ >+ public static byte rhs[] = null; >+ public static char lhs[] = null; >+ public static char term_action[] = null; >+ public static byte term_check[] = null; >+ public static char base_action[] = null; >+ >+ public ReferenceContext referenceContext; >+ >+ >+ // Constants. >+ protected static final int AstStackIncrement = 100; >+ protected static final int ExpressionStackIncrement = 100; >+ protected static final int GenericsStackIncrement = 10; >+ protected static final int StackIncrement = 255; >+ protected static final int TypeAnnotationStackIncrement = 100; >+ >+ public Scanner scanner; >+ public int currentToken; >+ protected int kurrentToken; // copy of currentToken as it is trampled over all over the place :-( >+ protected boolean commit = false; >+ >+ // ------------- Stack pointers --------------- >+ >+ protected int stateStackTop; >+ protected int unstackedAct; >+ >+ protected int identifierPtr; >+ protected int identifierLengthPtr; >+ >+ protected int astPtr; >+ protected int astLengthPtr; >+ >+ protected int expressionPtr; >+ protected int expressionLengthPtr; >+ >+ protected int genericsPtr; >+ protected int genericsLengthPtr; >+ protected int genericsIdentifiersLengthPtr; >+ >+ protected int typeAnnotationPtr; >+ protected int typeAnnotationLengthPtr; >+ >+ protected int intPtr; >+ protected int nestedType; >+ protected int realBlockPtr; >+ public int valueLambdaNestDepth = -1; >+ >+ // ---------------- Stacks ---------------- >+ >+ protected int[] stack = new int[StackIncrement]; >+ >+ protected char[][] identifierStack; >+ protected int[] identifierLengthStack; >+ protected long[] identifierPositionStack; >+ >+ protected ASTNode[] astStack = new ASTNode[AstStackIncrement]; >+ protected int[] astLengthStack; >+ >+ protected Expression[] expressionStack = new Expression[ExpressionStackIncrement]; >+ protected int[] expressionLengthStack; >+ >+ protected ASTNode[] genericsStack = new ASTNode[GenericsStackIncrement]; >+ protected int[] genericsLengthStack = new int[GenericsStackIncrement]; >+ protected int[] genericsIdentifiersLengthStack = new int[GenericsStackIncrement]; >+ >+ protected Annotation [] typeAnnotationStack = new Annotation[TypeAnnotationStackIncrement]; >+ protected int [] typeAnnotationLengthStack; >+ >+ protected int[] intStack; >+ protected int[] nestedMethod; >+ protected int[] realBlockStack; >+ protected int stateStackLengthStack[] = new int[0]; >+ protected int[] variablesCounter; >+ >+ // Loose variables. >+ >+ protected int listLength; >+ protected int listTypeParameterLength; >+ protected int modifiers; >+ protected int modifiersSourceStart; >+ protected int dimensions; >+ protected int recoveredStaticInitializerStart; >+ >+ CommitRollbackParser cryogenicallyFrozenParser; >+ private static final int[] RECOVERY_TOKENS = new int [] { TokenNameSEMICOLON, TokenNameRPAREN,}; >+ >+ protected void copyState(CommitRollbackParser parser) { >+ >+ // Stack pointers. >+ >+ this.stateStackTop = parser.stateStackTop; >+ this.unstackedAct = parser.unstackedAct; >+ this.identifierPtr = parser.identifierPtr; >+ this.identifierLengthPtr = parser.identifierLengthPtr; >+ this.astPtr = parser.astPtr; >+ this.astLengthPtr = parser.astLengthPtr; >+ this.expressionPtr = parser.expressionPtr; >+ this.expressionLengthPtr = parser.expressionLengthPtr; >+ this.genericsPtr = parser.genericsPtr; >+ this.genericsLengthPtr = parser.genericsLengthPtr; >+ this.genericsIdentifiersLengthPtr = parser.genericsIdentifiersLengthPtr; >+ this.typeAnnotationPtr = parser.typeAnnotationPtr; >+ this.typeAnnotationLengthPtr = parser.typeAnnotationLengthPtr; >+ this.intPtr = parser.intPtr; >+ this.nestedType = parser.nestedType; >+ this.realBlockPtr = parser.realBlockPtr; >+ this.valueLambdaNestDepth = parser.valueLambdaNestDepth; >+ >+ // Stacks. >+ >+ int length; >+ System.arraycopy(parser.stack, 0, this.stack = new int [length = parser.stack.length], 0, length); >+ System.arraycopy(parser.identifierStack, 0, this.identifierStack = new char [length = parser.identifierStack.length][], 0, length); >+ System.arraycopy(parser.identifierLengthStack, 0, this.identifierLengthStack = new int [length = parser.identifierLengthStack.length], 0, length); >+ System.arraycopy(parser.identifierPositionStack, 0, this.identifierPositionStack = new long[length = parser.identifierPositionStack.length], 0, length); >+ System.arraycopy(parser.astStack, 0, this.astStack = new ASTNode [length = parser.astStack.length], 0, length); >+ System.arraycopy(parser.astLengthStack, 0, this.astLengthStack = new int [length = parser.astLengthStack.length], 0, length); >+ System.arraycopy(parser.expressionStack, 0, this.expressionStack = new Expression [length = parser.expressionStack.length], 0, length); >+ System.arraycopy(parser.expressionLengthStack, 0, this.expressionLengthStack = new int [length = parser.expressionLengthStack.length], 0, length); >+ System.arraycopy(parser.genericsStack, 0, this.genericsStack = new ASTNode [length = parser.genericsStack.length], 0, length); >+ System.arraycopy(parser.genericsLengthStack, 0, this.genericsLengthStack = new int [length = parser.genericsLengthStack.length], 0, length); >+ System.arraycopy(parser.genericsIdentifiersLengthStack, 0, this.genericsIdentifiersLengthStack = new int [length = parser.genericsIdentifiersLengthStack.length], 0, length); >+ System.arraycopy(parser.typeAnnotationStack, 0, this.typeAnnotationStack = new Annotation [length = parser.typeAnnotationStack.length], 0, length); >+ System.arraycopy(parser.typeAnnotationLengthStack, 0, this.typeAnnotationLengthStack = new int [length = parser.typeAnnotationLengthStack.length], 0, length); >+ System.arraycopy(parser.intStack, 0, this.intStack = new int [length = parser.intStack.length], 0, length); >+ System.arraycopy(parser.nestedMethod, 0, this.nestedMethod = new int [length = parser.nestedMethod.length], 0, length); >+ System.arraycopy(parser.realBlockStack, 0, this.realBlockStack = new int [length = parser.realBlockStack.length], 0, length); >+ System.arraycopy(parser.stateStackLengthStack, 0, this.stateStackLengthStack = new int [length = parser.stateStackLengthStack.length], 0, length); >+ System.arraycopy(parser.variablesCounter, 0, this.variablesCounter = new int [length = parser.variablesCounter.length], 0, length); >+ System.arraycopy(parser.stack, 0, this.stack = new int [length = parser.stack.length], 0, length); >+ System.arraycopy(parser.stack, 0, this.stack = new int [length = parser.stack.length], 0, length); >+ System.arraycopy(parser.stack, 0, this.stack = new int [length = parser.stack.length], 0, length); >+ >+ // Loose variables. >+ >+ this.listLength = parser.listLength; >+ this.listTypeParameterLength = parser.listTypeParameterLength; >+ this.dimensions = parser.dimensions; >+ this.recoveredStaticInitializerStart = parser.recoveredStaticInitializerStart; >+ >+ // Parser.resetStacks is not clearing the modifiers, but AssistParser.resumeAfterRecovery is - why ? (the former doesn't) >+ // this.modifiers = parser.modifiers; >+ // this.modifiersSourceStart = parser.modifiersSourceStart; >+ } >+ >+ protected CommitRollbackParser createSnapShotParser() { >+ return new Parser(); >+ } >+ >+ /* Must be called from Parser.parse ONLY. Rule reduction routine must simply set the flag to request commit. >+ This ensures the end state of chain rule reductions gets committed rather than some intermediate state. >+ See the reduce do-while loop. >+ */ >+ protected void commit() { >+ if (this.cryogenicallyFrozenParser == null) { >+ this.cryogenicallyFrozenParser = createSnapShotParser(); >+ } >+ this.cryogenicallyFrozenParser.copyState(this); >+ this.commit = false; >+ } >+ >+ protected int getNextToken() { >+ try { >+ return this.scanner.getNextToken(); >+ } catch (InvalidInputException e) { >+ return TokenNameEOF; >+ } >+ } >+ >+ // We get here on real syntax error or syntax error triggered by fake EOF at completion site, never due to triggered recovery. >+ protected int fallBackToSpringForward(Statement unused) { >+ int nextToken; >+ int lastAction = this.stack[this.stateStackTop]; >+ >+ // If triggered fake EOF at completion site, see if the real next token would have passed muster. >+ if (this.kurrentToken == TokenNameEOF) { >+ if (this.scanner.eofPosition < this.scanner.source.length) { >+ this.scanner.eofPosition = this.scanner.source.length; >+ nextToken = getNextToken(); >+ if (automatonWillShift(nextToken, lastAction)) { >+ this.currentToken = this.kurrentToken = nextToken; >+ this.unstackedAct = this.stack[this.stateStackTop--]; >+ return RESUME; >+ } >+ } else { >+ nextToken = TokenNameEOF; >+ } >+ } else { >+ nextToken = this.kurrentToken; >+ } >+ if (nextToken == TokenNameEOF) >+ return HALT; // don't know how to proceed. >+ this.scanner.ungetToken(nextToken); // spit out what has been bitten more than we can chew. >+ // OK, next token is no good to resume "in place", attempt some local repair. >+ for (int i = 0, length = RECOVERY_TOKENS.length; i < length; i++) { >+ if (automatonWillShift(RECOVERY_TOKENS[i], lastAction)) { >+ this.currentToken = this.kurrentToken = RECOVERY_TOKENS[i]; >+ this.unstackedAct = this.stack[this.stateStackTop--]; >+ return RESUME; >+ } >+ } >+ // OK, no in place resumption, no local repair, fast forward to next statement. >+ if (this.cryogenicallyFrozenParser == null || this.referenceContext instanceof CompilationUnitDeclaration) { >+ return RESTART; >+ } >+ this.copyState(this.cryogenicallyFrozenParser); >+ this.currentToken = this.scanner.fastForward(unused); >+ return RESUME; >+ } >+ >+ protected void resetStacks() { >+ >+ this.astPtr = -1; >+ this.astLengthPtr = -1; >+ this.expressionPtr = -1; >+ this.expressionLengthPtr = -1; >+ this.typeAnnotationLengthPtr = -1; >+ this.typeAnnotationPtr = -1; >+ this.identifierPtr = -1; >+ this.identifierLengthPtr = -1; >+ this.intPtr = -1; >+ >+ this.nestedMethod[this.nestedType = 0] = 0; // need to reset for further reuse >+ this.variablesCounter[this.nestedType] = 0; >+ >+ this.dimensions = 0 ; >+ this.realBlockStack[this.realBlockPtr = 0] = 0; >+ this.recoveredStaticInitializerStart = 0; >+ this.listLength = 0; >+ this.listTypeParameterLength = 0; >+ >+ this.genericsIdentifiersLengthPtr = -1; >+ this.genericsLengthPtr = -1; >+ this.genericsPtr = -1; >+ this.valueLambdaNestDepth = -1; >+ } >+ >+ protected boolean automatonWillShift(int token, int lastAction) { >+ int stackTop = this.stateStackTop; // local copy of stack pointer >+ int stackTopState = this.stack[stackTop]; // single cell non write through "alternate stack" - the automaton's stack pointer either stays fixed during this manoeuvre or monotonically decreases. >+ int highWaterMark = stackTop; >+ // A rotated version of the automaton - cf. parse()'s for(;;) >+ for (;;) { >+ if (lastAction > ERROR_ACTION) { >+ lastAction -= ERROR_ACTION; /* shift-reduce on loop entry from above, reduce on loop back */ >+ do { /* reduce */ >+ stackTop -= rhs[lastAction] - 1; >+ if (stackTop < highWaterMark) { >+ stackTopState = this.stack[highWaterMark = stackTop]; >+ } // else stackTopState is upto date already. >+ lastAction = ntAction(stackTopState, lhs[lastAction]); >+ } while (lastAction <= NUM_RULES); >+ } >+ highWaterMark = ++stackTop; >+ stackTopState = lastAction; // "push" >+ lastAction = tAction(lastAction, token); // can be looked up from a precomputed cache. >+ if (lastAction <= NUM_RULES) { >+ stackTop --; >+ lastAction += ERROR_ACTION; >+ continue; >+ } >+ // Error => false, Shift, Shift/Reduce => true, Accept => impossible. >+ return lastAction != ERROR_ACTION; >+ } >+ } >+ >+public static int tAction(int state, int sym) { >+ return term_action[term_check[base_action[state]+sym] == sym ? base_action[state] + sym : base_action[state]]; >+} >+ >+public static int ntAction(int state, int sym) { >+ return base_action[state + sym]; >+} >+ >+ >+} >+ >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ConflictedParser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ConflictedParser.java >index 6ee4085..fbf68b8 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ConflictedParser.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ConflictedParser.java >@@ -22,4 +22,8 @@ > we treat the type annotation as a declarative annotation. > */ > boolean atConflictScenario(int token); >+ >+ void startRecovery(); >+ >+ boolean requireExtendedRecovery(); > } >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java >index 2fe9401..ac5ac19 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java >@@ -159,7 +159,7 @@ > import org.eclipse.jdt.internal.compiler.util.Messages; > import org.eclipse.jdt.internal.compiler.util.Util; > >-public class Parser implements ConflictedParser, ParserBasicInformation, TerminalTokens, OperatorIds, TypeIds { >+public class Parser extends CommitRollbackParser implements ConflictedParser, OperatorIds, TypeIds { > > protected static final int THIS_CALL = ExplicitConstructorCall.This; > protected static final int SUPER_CALL = ExplicitConstructorCall.Super; >@@ -168,26 +168,17 @@ > > public static char asb[] = null; > public static char asr[] = null; >- //ast stack >- protected final static int AstStackIncrement = 100; >- public static char base_action[] = null; > public static final int BracketKinds = 3; > > public static short check_table[] = null; > public static final int CurlyBracket = 2; >- private static final boolean DEBUG = false; >- private static final boolean DEBUG_AUTOMATON = false; >+ private static final boolean DEBUG = true; >+ private static final boolean DEBUG_AUTOMATON = true; > private static final String EOF_TOKEN = "$eof" ; //$NON-NLS-1$ > private static final String ERROR_TOKEN = "$error" ; //$NON-NLS-1$ >- //expression stack >- protected final static int ExpressionStackIncrement = 100; >- >- protected final static int GenericsStackIncrement = 10; >- > private final static String FILEPREFIX = "parser"; //$NON-NLS-1$ > public static char in_symb[] = null; > private static final String INVALID_CHARACTER = "Invalid Character" ; //$NON-NLS-1$ >- public static char lhs[] = null; > > public static String name[] = null; > public static char nasb[] = null; >@@ -197,7 +188,6 @@ > > public static String readableName[] = null; > >- public static byte rhs[] = null; > > public static int[] reverse_index = null; > public static char[] recovery_templates_index = null; >@@ -219,11 +209,6 @@ > public static char scope_suffix[] = null; > public static final int SquareBracket = 1; > >- //internal data for the automat >- protected final static int StackIncrement = 255; >- >- public static char term_action[] = null; >- public static byte term_check[] = null; > > public static char terminal_index[] = null; > >@@ -737,9 +722,6 @@ > public static int nasi(int state) { > return nasb[original_state(state)]; > } >- public static int ntAction(int state, int sym) { >- return base_action[state + sym]; >- } > protected static int original_state(int state) { > return -base_check(state); > } >@@ -885,65 +867,20 @@ > } > return chars; > } >- public static int tAction(int state, int sym) { >- return term_action[term_check[base_action[state]+sym] == sym ? base_action[state] + sym : base_action[state]]; >- } >- protected int astLengthPtr; >- >- protected int[] astLengthStack; >- protected int astPtr; >- protected ASTNode[] astStack = new ASTNode[AstStackIncrement]; > public CompilationUnitDeclaration compilationUnit; /*the result from parse()*/ > > protected RecoveredElement currentElement; >- public int currentToken; >+ > protected boolean diet = false; //tells the scanner to jump over some parts of the code/expressions like method bodies > protected int dietInt = 0; // if > 0 force the none-diet-parsing mode (even if diet if requested) [field parsing with anonymous inner classes...] > protected int endPosition; //accurate only when used ! (the start position is pushed into intStack while the end the current one) > protected int endStatementPosition; >- protected int expressionLengthPtr; >- protected int[] expressionLengthStack; >- protected int expressionPtr; >- protected Expression[] expressionStack = new Expression[ExpressionStackIncrement]; > public int firstToken ; // handle for multiple parsing goals > >- /* jsr308 -- Type annotation management, we now maintain type annotations in a separate stack >- as otherwise they get interspersed with other expressions and some of the code is not prepared >- to handle such interleaving and will look ugly if changed. >- >- See consumeArrayCreationExpressionWithoutInitializer for example. >- >- Where SE8 annotations occur in a place SE5 annotations are legal, the SE8 annotations end up in >- the expression stack as we have no way of distinguishing between the two. >- */ >- protected int typeAnnotationPtr; >- protected int typeAnnotationLengthPtr; >- protected Annotation [] typeAnnotationStack = new Annotation[TypeAnnotationStackIncrement]; >- protected int [] typeAnnotationLengthStack; >- // annotation stack >- protected final static int TypeAnnotationStackIncrement = 100; >- >- // generics management >- protected int genericsIdentifiersLengthPtr; >- protected int[] genericsIdentifiersLengthStack = new int[GenericsStackIncrement]; >- protected int genericsLengthPtr; >- protected int[] genericsLengthStack = new int[GenericsStackIncrement]; >- protected int genericsPtr; >- protected ASTNode[] genericsStack = new ASTNode[GenericsStackIncrement]; > protected boolean hasError; > protected boolean hasReportedError; >- //identifiers stacks >- protected int identifierLengthPtr; >- protected int[] identifierLengthStack; >- protected long[] identifierPositionStack; >- protected int identifierPtr; >- protected char[][] identifierStack; > protected boolean ignoreNextOpeningBrace; > >- //positions , dimensions , .... (int stacks) >- protected int intPtr; >- >- protected int[] intStack; > public int lastAct ; //handle for multiple parsing goals > //error recovery management > protected int lastCheckPoint; >@@ -951,18 +888,7 @@ > protected int lastErrorEndPositionBeforeRecovery = -1; > protected int lastIgnoredToken, nextIgnoredToken; > >- protected int listLength; // for recovering some incomplete list (interfaces, throws or parameters) >- >- protected int listTypeParameterLength; // for recovering some incomplete list (type parameters) > protected int lParenPos,rParenPos; //accurate only when used ! >- protected int modifiers; >- protected int modifiersSourceStart; >- protected int[] nestedMethod; //the ptr is nestedType >- >- protected int nestedType, dimensions; >- ASTNode [] noAstNodes = new ASTNode[AstStackIncrement]; >- >- Expression [] noExpressions = new Expression[ExpressionStackIncrement]; > //modifiers dimensions nestedType etc....... > protected boolean optimizeStringLiterals =true; > protected CompilerOptions options; >@@ -970,10 +896,6 @@ > protected ProblemReporter problemReporter; > > protected int rBraceStart, rBraceEnd, rBraceSuccessorStart; //accurate only when used ! >-protected int realBlockPtr; >-protected int[] realBlockStack; >-protected int recoveredStaticInitializerStart; >-public ReferenceContext referenceContext; > public boolean reportOnlyOneSyntaxError = false; > public boolean reportSyntaxErrorIsRequired = true; > protected boolean restartRecovery; >@@ -988,12 +910,7 @@ > protected TypeDeclaration pendingRecoveredType; > public RecoveryScanner recoveryScanner; > //scanner token >-public Scanner scanner; >-protected int[] stack = new int[StackIncrement]; >-protected int stateStackTop; > protected int synchronizedBlockSourceStart; >- >-protected int[] variablesCounter; > > protected boolean checkExternalizeStrings; > >@@ -1004,21 +921,11 @@ > // used for recovery > protected int lastJavadocEnd; > public org.eclipse.jdt.internal.compiler.ReadManager readManager; >-private int valueLambdaNestDepth = -1; >-private int stateStackLengthStack[] = new int[0]; >-protected boolean parsingJava8Plus; >-protected int unstackedAct = ERROR_ACTION; >+private boolean parsingJava8Plus; > private boolean haltOnSyntaxError = false; > private boolean tolerateDefaultClassMethods = false; > private boolean processingLambdaParameterList = false; > private boolean expectTypeAnnotation = false; >- >-// resumeOnSyntaxError codes: >- >-protected static final int HALT = 0; // halt and throw up hands. >-protected static final int RESTART = 1; // stacks reset, alternate goal from check point. >-protected static final int RESUME = 2; // stacks untouched, just continue from where left off. >- > > protected Parser () { > // Caveat Emptor: For inheritance purposes and then only in very special needs. Only minimal state is initialized ! >@@ -2251,7 +2158,7 @@ > pushOnAstStack(block); > } > protected void consumeBlockStatement() { >- // todo. >+ // for assist parsers. > } > protected void consumeBlockStatements() { > // BlockStatements ::= BlockStatements BlockStatement >@@ -7861,11 +7768,6 @@ > this.nestedMethod[this.nestedType] ++; > LambdaExpression lambda = new LambdaExpression(this.compilationUnit.compilationResult, this instanceof AssistParser); > pushOnAstStack(lambda); >- if (this.currentElement != null) { >- this.currentElement = this.currentElement.add(lambda, 0); >- this.lastCheckPoint = this.scanner.currentPosition; >- this.lastIgnoredToken = -1; >- } > this.processingLambdaParameterList = true; > } > >@@ -7896,16 +7798,16 @@ > } > LambdaExpression lexp = (LambdaExpression) this.astStack[this.astPtr]; > lexp.setArguments(arguments); >- lexp.setArrowPosition(arrowPosition); // '->' position >+ lexp.setArrowPosition(arrowPosition); > lexp.sourceEnd = this.intStack[this.intPtr--]; // ')' position or identifier position. > lexp.sourceStart = this.intStack[this.intPtr--]; // '(' position or identifier position. > lexp.hasParentheses = (this.scanner.getSource()[lexp.sourceStart] == '('); >- this.listLength = 0; // reset this.listLength after having read all parameters >- if (this.currentElement != null) { >- this.lastCheckPoint = lexp.sourceEnd + 1; >- this.lastIgnoredToken = -1; >- } >+ this.listLength -= arguments == null ? 0 : arguments.length; // not necessary really. > this.processingLambdaParameterList = false; >+ if (this.currentElement != null) { >+ this.ignoreNextOpeningBrace = true; >+ this.currentElement.bracketBalance++; >+ } > } > protected void consumeLambdaExpression() { > >@@ -7934,11 +7836,8 @@ > problemReporter().lambdaExpressionsNotBelow18(lexp); > } > pushOnExpressionStack(lexp); >- if (this.currentElement != null) { >- if (this.currentElement.parseTree() == lexp && this.currentElement.parent != null) { >- this.currentElement = this.currentElement.parent; >- } >- this.lastCheckPoint = lexp.sourceEnd + 1; >+ if (this.currentElement != null && lexp.body() instanceof Expression) { >+ this.currentElement.bracketBalance--; > } > } > >@@ -7984,9 +7883,7 @@ > pushOnIntStack(arg.declarationSourceEnd); > } > pushOnAstStack(arg); >- /* if incomplete method header, this.listLength counter will not have been reset, >- indicating that some arguments are available on the stack */ >- this.listLength++; >+ this.listLength++; // not relevant really. > } > protected void consumeElidedLeftBraceAndReturn() { > /* ElidedLeftBraceAndReturn ::= $empty >@@ -8740,26 +8637,8 @@ > optimizedConcatNodeLists(); > } > protected void consumeToken(int type) { >- /* remember the last consumed value */ >- /* try to minimize the number of build values */ >-// // clear the commentPtr of the scanner in case we read something different from a modifier >-// switch(type) { >-// case TokenNameabstract : >-// case TokenNamestrictfp : >-// case TokenNamefinal : >-// case TokenNamenative : >-// case TokenNameprivate : >-// case TokenNameprotected : >-// case TokenNamepublic : >-// case TokenNametransient : >-// case TokenNamevolatile : >-// case TokenNamestatic : >-// case TokenNamesynchronized : >-// break; >-// default: >-// this.scanner.commentPtr = -1; >-// } >- //System.out.println(this.scanner.toStringAction(type)); >+ if (this.commit) >+ commit(); > switch (type) { > case TokenNameARROW: > consumeLambdaHeader(); >@@ -10464,24 +10343,14 @@ > this.referenceContext = null; > this.endStatementPosition = 0; > this.valueLambdaNestDepth = -1; >- >- //remove objects from stack too, while the same parser/compiler couple is >- //re-used between two compilations .... >- >+ > int astLength = this.astStack.length; >- if (this.noAstNodes.length < astLength){ >- this.noAstNodes = new ASTNode[astLength]; >- //System.out.println("Resized AST stacks : "+ astLength); >- >- } >- System.arraycopy(this.noAstNodes, 0, this.astStack, 0, astLength); >+ for (int i = 0; i < astLength; i++) >+ this.astStack[i] = null; > > int expressionLength = this.expressionStack.length; >- if (this.noExpressions.length < expressionLength){ >- this.noExpressions = new Expression[expressionLength]; >- //System.out.println("Resized EXPR stacks : "+ expressionLength); >- } >- System.arraycopy(this.noExpressions, 0, this.expressionStack, 0, expressionLength); >+ for (int i = 0; i < expressionLength; i++) >+ this.expressionStack[i] = null; > > // reset this.scanner state > this.scanner.commentPtr = -1; >@@ -10797,41 +10666,14 @@ > > Though this code looks complex, we should exit early in most situations. > */ >- int lastAction = this.unstackedAct; >- if (lastAction == ERROR_ACTION) { // automaton is not running. >+ if (this.unstackedAct == ERROR_ACTION) { // automaton is not running. > return false; > } >- int stackTop = this.stateStackTop; // local copy of stack pointer >- int stackTopState = this.stack[stackTop]; // single cell non write through "alternate stack" - the automaton's stack pointer either stays fixed during this manoeuvre or monotonically decreases. >- int highWaterMark = stackTop; >- > if (token != TokenNameAT) { > token = token == TokenNameLPAREN ? TokenNameBeginLambda : TokenNameBeginTypeArguments; > } > >- // A rotated version of the automaton - cf. parse()'s for(;;) >- for (;;) { >- if (lastAction > ERROR_ACTION) { >- lastAction -= ERROR_ACTION; /* shift-reduce on loop entry from above, reduce on loop back */ >- do { /* reduce */ >- stackTop -= rhs[lastAction] - 1; >- if (stackTop < highWaterMark) { >- stackTopState = this.stack[highWaterMark = stackTop]; >- } // else stackTopState is upto date already. >- lastAction = ntAction(stackTopState, lhs[lastAction]); >- } while (lastAction <= NUM_RULES); >- } >- highWaterMark = ++stackTop; >- stackTopState = lastAction; // "push" >- lastAction = tAction(lastAction, token); // can be looked up from a precomputed cache. >- if (lastAction <= NUM_RULES) { >- stackTop --; >- lastAction += ERROR_ACTION; >- continue; >- } >- // Error => false, Shift, Shift/Reduce => true, Accept => impossible. >- return lastAction != ERROR_ACTION; >- } >+ return automatonWillShift(token, this.unstackedAct); > } > /*main loop of the automat > When a rule is reduced, the method consumeRule(int) is called with the number >@@ -10852,6 +10694,7 @@ > > this.hasReportedError = false; > int act = START_STATE; >+ this.unstackedAct = ERROR_ACTION; > this.stateStackTop = -1; > this.currentToken = getFirstToken(); > >@@ -10866,8 +10709,7 @@ > stackLength); > } > this.stack[this.stateStackTop] = act; >- >- act = tAction(act, this.currentToken); >+ this.unstackedAct = act = tAction(act, this.currentToken); > if (act == ERROR_ACTION || this.restartRecovery) { > if (DEBUG_AUTOMATON) { > if (this.restartRecovery) { >@@ -10879,23 +10721,27 @@ > > int errorPos = this.scanner.currentPosition - 1; > if (!this.hasReportedError) { >- this.hasError = true; // looks incorrect for recovery case ? >+ this.hasError = true; > } >- int previousToken = this.currentToken; >- switch (resumeOnSyntaxError()) { >+ this.kurrentToken = this.currentToken; >+ switch (resumeOnErrorOrTriggeredRecovery(act == ERROR_ACTION)) { > case HALT: > act = ERROR_ACTION; > break ProcessTerminals; > case RESTART: >- if (act == ERROR_ACTION && previousToken != 0) this.lastErrorEndPosition = errorPos; >+ if (act == ERROR_ACTION && this.kurrentToken != 0) this.lastErrorEndPosition = errorPos; > act = START_STATE; > this.stateStackTop = -1; > this.currentToken = getFirstToken(); > continue ProcessTerminals; > case RESUME: >- break; // We presume the world is virgin so we can continue exactly from where we left off. >- default: >- throw new IllegalStateException(); >+ if (act == ERROR_ACTION) { >+ act = this.unstackedAct; >+ continue ProcessTerminals; >+ } else { >+ this.currentToken = this.kurrentToken; // Gets trashed all over the place. >+ } >+ // FALL THROUGH. > } > } > if (act <= NUM_RULES) { >@@ -10914,7 +10760,6 @@ > this.recordStringLiterals = oldValue; > } > try { >- this.unstackedAct = act; > this.currentToken = this.scanner.getNextToken(); > } catch(InvalidInputException e){ > if (!this.hasReportedError){ >@@ -10924,9 +10769,7 @@ > this.lastCheckPoint = this.scanner.currentPosition; > this.currentToken = 0; > this.restartRecovery = true; >- } finally { >- this.unstackedAct = ERROR_ACTION; >- } >+ } > if(this.statementRecoveryActivated) { > jumpOverType(); > } >@@ -10946,7 +10789,6 @@ > this.recordStringLiterals = oldValue; > } > try{ >- this.unstackedAct = act; > this.currentToken = this.scanner.getNextToken(); > } catch(InvalidInputException e){ > if (!this.hasReportedError){ >@@ -10956,8 +10798,6 @@ > this.lastCheckPoint = this.scanner.currentPosition; > this.currentToken = 0; > this.restartRecovery = true; >- } finally { >- this.unstackedAct = ERROR_ACTION; > } > if(this.statementRecoveryActivated) { > jumpOverType(); >@@ -10994,6 +10834,7 @@ > } > } > } finally { >+ this.unstackedAct = ERROR_ACTION; > this.scanner.setActiveParser(null); > } > >@@ -11993,6 +11834,14 @@ > } > } > >+public boolean requireExtendedRecovery() { >+ return false; // for assist parsers. >+} >+ >+public void startRecovery() { >+ this.restartRecovery = true; >+} >+ > public void recoveryExitFromVariable() { > if(this.currentElement != null && this.currentElement.parent != null) { > if(this.currentElement instanceof RecoveredLocalVariable) { >@@ -12152,39 +12001,12 @@ > } > /* > * Reset context so as to resume to regular parse loop >- */ >-protected void resetStacks() { >- >- this.astPtr = -1; >- this.astLengthPtr = -1; >- this.expressionPtr = -1; >- this.expressionLengthPtr = -1; >- this.typeAnnotationLengthPtr = -1; >- this.typeAnnotationPtr = -1; >- this.identifierPtr = -1; >- this.identifierLengthPtr = -1; >- this.intPtr = -1; >- this.nestedMethod[this.nestedType = 0] = 0; // need to reset for further reuse >- this.variablesCounter[this.nestedType] = 0; >- this.dimensions = 0 ; >- this.realBlockStack[this.realBlockPtr = 0] = 0; >- this.recoveredStaticInitializerStart = 0; >- this.listLength = 0; >- this.listTypeParameterLength = 0; >- >- this.genericsIdentifiersLengthPtr = -1; >- this.genericsLengthPtr = -1; >- this.genericsPtr = -1; >- this.valueLambdaNestDepth = -1; >-} >-/* >- * Reset context so as to resume to regular parse loop > * If unable to reset for resuming, answers false. > * > * Move checkpoint location, reset internal stacks and > * decide which grammar goal is activated. > */ >-protected boolean resumeAfterRecovery() { >+protected int resumeAfterRecovery(boolean errorRecovery) { > if(!this.methodRecoveryActivated && !this.statementRecoveryActivated) { > > // reset internal stacks >@@ -12193,18 +12015,18 @@ > > /* attempt to move checkpoint location */ > if (!moveRecoveryCheckpoint()) { >- return false; >+ return HALT; > } > > // only look for headers > if (this.referenceContext instanceof CompilationUnitDeclaration){ > goForHeaders(); > this.diet = true; // passed this point, will not consider method bodies >- return true; >+ return RESTART; > } > > // does not know how to restart >- return false; >+ return HALT; > } else if(!this.statementRecoveryActivated) { > > // reset internal stacks >@@ -12213,17 +12035,17 @@ > > /* attempt to move checkpoint location */ > if (!moveRecoveryCheckpoint()) { >- return false; >+ return HALT; > } > > // only look for headers > goForHeaders(); >- return true; >+ return RESTART; > } else { >- return false; >+ return HALT; > } > } >-protected int resumeOnSyntaxError() { >+protected int resumeOnErrorOrTriggeredRecovery(boolean errorRecovery) { > if (this.haltOnSyntaxError) > return HALT; > /* request recovery initialization */ >@@ -12260,7 +12082,7 @@ > } > > /* attempt to reset state in order to resume to parse loop */ >- return resumeAfterRecovery() ? RESTART : HALT; >+ return resumeAfterRecovery(errorRecovery); > } > public void setMethodsFullRecovery(boolean enabled) { > this.options.performMethodsFullRecovery = enabled; >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredAnnotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredAnnotation.java >index 05edc47..29b2bfa 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredAnnotation.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredAnnotation.java >@@ -194,7 +194,7 @@ > > public int sourceEnd() { > if (this.annotation == null) { >- Parser parser = parser(); >+ CommitRollbackParser parser = parser(); > if (this.identifierPtr < parser.identifierPositionStack.length) { > return (int) parser.identifierPositionStack[this.identifierPtr]; > } else { >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java >index 37fce6f..9aa8a6a 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java >@@ -1,13 +1,10 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2013 IBM Corporation and others. >+ * Copyright (c) 2000, 2009 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at > * http://www.eclipse.org/legal/epl-v10.html > * >- * 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 > *******************************************************************************/ >@@ -18,11 +15,11 @@ > > import org.eclipse.jdt.core.compiler.*; > import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; >+import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; > import org.eclipse.jdt.internal.compiler.ast.Argument; > import org.eclipse.jdt.internal.compiler.ast.ASTNode; > import org.eclipse.jdt.internal.compiler.ast.Block; > import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; >-import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; > import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; > import org.eclipse.jdt.internal.compiler.ast.Statement; > import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; >@@ -59,14 +56,6 @@ > } > } > return super.add(methodDeclaration, bracketBalanceValue); >-} >-/* >- * Record a Lambda declaration >- */ >-public RecoveredElement add(LambdaExpression expression, int bracketBalanceValue) { >- RecoveredLambdaExpression element = new RecoveredLambdaExpression(expression, this, bracketBalanceValue); >- attach(element); >- return element; > } > /* > * Record a nested block declaration >@@ -340,6 +329,25 @@ > Statement updatedStatement = this.statements[i].updatedStatement(depth, knownTypes); > if (updatedStatement != null){ > updatedStatements[updatedCount++] = updatedStatement; >+ >+ // Statements inside lambda body have been collected into a block. Replace the block if we see a statement that completely subsumes it. >+ if (updatedCount > 1) { >+ Statement penultimateStatement = updatedStatements[updatedCount - 1]; >+ int penultimateStatementStart = penultimateStatement.sourceStart; >+ int penultimateStatementEnd = penultimateStatement instanceof AbstractVariableDeclaration ? >+ ((AbstractVariableDeclaration) penultimateStatement).declarationSourceEnd : penultimateStatement.sourceEnd; >+ int ultimateStatementStart = updatedStatement.sourceStart; >+ int ultimateStatementEnd = updatedStatement instanceof AbstractVariableDeclaration ? >+ ((AbstractVariableDeclaration) updatedStatement).declarationSourceEnd : updatedStatement.sourceEnd; >+ if (penultimateStatementStart <= ultimateStatementStart && penultimateStatementEnd >= ultimateStatementEnd) { >+ updatedCount--; >+ continue; >+ } >+ if (ultimateStatementStart <= penultimateStatementStart && ultimateStatementEnd >= penultimateStatementEnd) { >+ updatedStatements[updatedCount - 1] = updatedStatement; >+ updatedCount--; >+ } >+ } > > if (updatedStatement instanceof LocalDeclaration) { > LocalDeclaration localDeclaration = (LocalDeclaration) updatedStatement; >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java >index 68b9688..8ac189c 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java >@@ -1,13 +1,9 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2013 IBM Corporation and others. >+ * Copyright (c) 2000, 2012 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at > * http://www.eclipse.org/legal/epl-v10.html >- * >- * 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 >@@ -18,12 +14,11 @@ > /** > * Internal structure for parsing recovery > */ >-import org.eclipse.jdt.internal.compiler.ast.ASTNode; > import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; >+import org.eclipse.jdt.internal.compiler.ast.ASTNode; > import org.eclipse.jdt.internal.compiler.ast.Block; > import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; > import org.eclipse.jdt.internal.compiler.ast.ImportReference; >-import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; > import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; > import org.eclipse.jdt.internal.compiler.ast.Statement; > import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; >@@ -104,13 +99,6 @@ > if (this.parent == null) return this; // ignore > this.updateSourceEndIfNecessary(previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1)); > return this.parent.add(localDeclaration, bracketBalanceValue); >-} >- >-/* >- * Record a LambdaExpression: Only can occur inside a block. Note: Field initializers are wrapped into a block. >- */ >-public RecoveredElement add(LambdaExpression expression, int bracketBalanceValue) { >- return this; > } > /* > * Record a statement >@@ -248,7 +236,7 @@ > */ > public int previousAvailableLineEnd(int position){ > >- Parser parser = parser(); >+ CommitRollbackParser parser = parser(); > if (parser == null) return position; > > Scanner scanner = parser.scanner; >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java >index 6e724a2..ca7e2a5 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java >@@ -24,7 +24,6 @@ > import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference; > import org.eclipse.jdt.internal.compiler.ast.Expression; > import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; >-import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; > import org.eclipse.jdt.internal.compiler.ast.Statement; > import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; > >@@ -35,8 +34,6 @@ > > public RecoveredAnnotation[] annotations; > public int annotationCount; >- >- public RecoveredLambdaExpression initializerLambda; > > public int modifiers; > public int modifiersStart; >@@ -87,24 +84,6 @@ > this.fieldDeclaration.declarationSourceEnd = statement.sourceEnd; > this.fieldDeclaration.declarationEnd = statement.sourceEnd; > return this; >- } >-} >-/* >- * Record a lambda expression if field is expecting an initialization expression, >- * used for completion inside field initializers. >- */ >-public RecoveredElement add(LambdaExpression expression, int bracketBalanceValue) { >- >- if (this.alreadyCompletedFieldInitialization) { >- return super.add(expression, bracketBalanceValue); >- } else { >- if (expression.sourceEnd > 0) >- this.alreadyCompletedFieldInitialization = true; >- // else we may still be inside the initialization, having parsed only a part of it yet >- this.fieldDeclaration.initialization = expression; >- this.fieldDeclaration.declarationSourceEnd = expression.sourceEnd; >- this.fieldDeclaration.declarationEnd = expression.sourceEnd; >- return this.initializerLambda = new RecoveredLambdaExpression(expression, this, bracketBalanceValue); > } > } > /* >@@ -269,9 +248,6 @@ > } > } > } >- if (this.initializerLambda != null) >- this.initializerLambda.updateParseTree(); >- > return this.fieldDeclaration; > } > /* >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredLambdaExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredLambdaExpression.java >deleted file mode 100644 >index 5e956e0..0000000 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredLambdaExpression.java >+++ /dev/null >@@ -1,126 +0,0 @@ >-/******************************************************************************* >- * Copyright (c) 2013 IBM Corporation and others. >- * All rights reserved. This program and the accompanying materials >- * are made available under the terms of the Eclipse Public License v1.0 >- * which accompanies this distribution, and is available at >- * http://www.eclipse.org/legal/epl-v10.html >- * >- * 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 >- *******************************************************************************/ >- >-package org.eclipse.jdt.internal.compiler.parser; >- >-import java.util.HashSet; >-import java.util.Set; >- >-import org.eclipse.jdt.internal.compiler.ast.ASTNode; >-import org.eclipse.jdt.internal.compiler.ast.Block; >-import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; >-import org.eclipse.jdt.internal.compiler.ast.Statement; >- >-public class RecoveredLambdaExpression extends RecoveredBlock { >- >- private LambdaExpression expression; >- private boolean haveBlockBody = false; >- private boolean haveExpressionBody = false; >- private RecoveredStatement bodyExpression; >- >- public RecoveredLambdaExpression(LambdaExpression expression, RecoveredElement parent, int bracketBalance){ >- super(new Block(0), parent, bracketBalance); // don't have a block yet. May never have, in that event will course correct. >- this.expression = expression; >- this.expression.setBody(this.blockDeclaration); >- } >- >- /* >- * Record a nested block declaration >- */ >- public RecoveredElement add(Block block, int bracketBalanceValue) { >- if (!this.haveBlockBody && !this.haveExpressionBody) { >- this.haveBlockBody = true; >- this.haveExpressionBody = false; >- this.blockDeclaration = block; >- return this; >- } >- return super.add(block, bracketBalanceValue); >- } >- >- /* >- * Record a nested block declaration >- */ >- public RecoveredElement add(LambdaExpression lambda, int bracketBalanceValue) { >- if (!this.haveBlockBody && !this.haveExpressionBody) { >- this.haveBlockBody = false; >- this.haveExpressionBody = true; >- this.bodyExpression = new RecoveredLambdaExpression(lambda, this, bracketBalanceValue); >- this.expression.setBody(lambda); >- return this.bodyExpression; >- } >- return super.add(lambda, bracketBalanceValue); >- } >- >- /* >- * Record a statement declaration >- */ >- public RecoveredElement add(Statement stmt, int bracketBalanceValue) { >- return this.add(stmt, bracketBalanceValue, false); >- } >- >- /* >- * Record a statement declaration >- */ >- public RecoveredElement add(Statement stmt, int bracketBalanceValue, boolean delegatedByParent) { >- if (!this.haveBlockBody && !this.haveExpressionBody) { >- this.haveBlockBody = false; >- this.haveExpressionBody = true; >- this.bodyExpression = new RecoveredStatement(stmt, this, bracketBalanceValue); >- this.expression.setBody(stmt); >- return this.bodyExpression; >- } >- return super.add(stmt, bracketBalanceValue, delegatedByParent); >- } >- >- /* >- * Answer the associated parsed structure >- */ >- public ASTNode parseTree(){ >- return updatedLambdaExpression(0, new HashSet()); >- } >- >- public LambdaExpression updatedLambdaExpression(int depth, Set knownTypes) { >- if (this.haveBlockBody) >- this.expression.setBody(super.updatedStatement(depth, knownTypes)); >- else if (this.bodyExpression != null) >- this.expression.setBody(this.bodyExpression.updatedStatement(depth, knownTypes)); >- return this.expression; >- } >- /* >- * Rebuild a statement from the nested structure which is in scope >- */ >- public Statement updatedStatement(int depth, Set knownTypes){ >- return updatedLambdaExpression(depth, knownTypes); >- } >- /* >- * Final update the corresponding parse node >- */ >- public void updateParseTree(){ >- updatedLambdaExpression(0, new HashSet()); >- } >- /* >- * Rebuild a flattened block from the nested structure which is in scope >- */ >- public Statement updateStatement(int depth, Set knownTypes){ >- return updatedLambdaExpression(depth, knownTypes); >- } >- >- public String toString(int tab) { >- StringBuffer result = new StringBuffer(tabString(tab)); >- result.append("Recovered Lambda Expression:\n"); //$NON-NLS-1$ >- this.expression.print(tab + 1, result); >- return result.toString(); >- } >-} >\ No newline at end of file >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredLocalVariable.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredLocalVariable.java >index 57bae05..7755ca2 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredLocalVariable.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredLocalVariable.java >@@ -21,7 +21,6 @@ > import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference; > import org.eclipse.jdt.internal.compiler.ast.ASTNode; > import org.eclipse.jdt.internal.compiler.ast.Expression; >-import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; > import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; > import org.eclipse.jdt.internal.compiler.ast.Statement; > >@@ -29,7 +28,6 @@ > > public RecoveredAnnotation[] annotations; > public int annotationCount; >- private RecoveredLambdaExpression initializer; > public int modifiers; > public int modifiersStart; > >@@ -53,21 +51,6 @@ > this.localDeclaration.declarationSourceEnd = stmt.sourceEnd; > this.localDeclaration.declarationEnd = stmt.sourceEnd; > return this; >- } >-} >-/* >- * Record an expression statement if local variable is expecting an initialization expression. >- */ >-public RecoveredElement add(LambdaExpression expression, int bracketBalanceValue) { >- >- if (this.alreadyCompletedLocalInitialization) { >- return this; >- } else { >- this.alreadyCompletedLocalInitialization = true; >- this.localDeclaration.initialization = expression; >- this.localDeclaration.declarationSourceEnd = expression.sourceEnd; >- this.localDeclaration.declarationEnd = expression.sourceEnd; >- return this.initializer = new RecoveredLambdaExpression(expression, this, bracketBalanceValue); > } > } > public void attach(RecoveredAnnotation[] annots, int annotCount, int mods, int modsSourceStart) { >@@ -133,8 +116,6 @@ > this.localDeclaration.declarationSourceStart = start; > } > } >- if (this.initializer != null) >- this.initializer.updateParseTree(); > return this.localDeclaration; > } > /* >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java >index c7f8c80..122201b 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java >@@ -626,7 +626,7 @@ > > int lastParameterEnd = parameters[parameters.length - 1].sourceEnd; > >- Parser parser = parser(); >+ CommitRollbackParser parser = parser(); > Scanner scanner = parser.scanner; > if(Util.getLineNumber(this.methodDeclaration.declarationSourceStart, scanner.lineEnds, 0, scanner.linePtr) > != Util.getLineNumber(lastParameterEnd, scanner.lineEnds, 0, scanner.linePtr)) return; >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java >index 326d985..b587af5 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java >@@ -17,28 +17,21 @@ > import java.util.Set; > > import org.eclipse.jdt.internal.compiler.ast.ASTNode; >-import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; > import org.eclipse.jdt.internal.compiler.ast.Statement; > > public class RecoveredStatement extends RecoveredElement { > > public Statement statement; >- public RecoveredLambdaExpression subExpression; > > public RecoveredStatement(Statement statement, RecoveredElement parent, int bracketBalance){ > super(parent, bracketBalance); > this.statement = statement; > } > >-public RecoveredElement add(LambdaExpression expression, int bracketBalanceValue) { >- return this.subExpression = new RecoveredLambdaExpression(expression, this, bracketBalanceValue); >-} > /* > * Answer the associated parsed structure > */ > public ASTNode parseTree() { >- if (this.subExpression != null) >- this.subExpression.updateParseTree(); > return this.statement; > } > /* >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java >index 9c2c3aa..e0e0cca 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java >@@ -753,7 +753,7 @@ > // might be an initializer > if (this.bracketBalance == 1){ > Block block = new Block(0); >- Parser parser = parser(); >+ CommitRollbackParser parser = parser(); > block.sourceStart = parser.scanner.startPosition; > Initializer init; > if (parser.recoveredStaticInitializerStart == 0){ >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java >index 9725ebd..60de8a7 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java >@@ -19,6 +19,7 @@ > import org.eclipse.jdt.core.compiler.CharOperation; > import org.eclipse.jdt.core.compiler.InvalidInputException; > import org.eclipse.jdt.internal.compiler.CompilationResult; >+import org.eclipse.jdt.internal.compiler.ast.Statement; > import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; > import org.eclipse.jdt.internal.compiler.util.Util; > >@@ -200,7 +201,7 @@ > private int nextToken = TokenNameNotAToken; // allows for one token push back, only the most recent token can be reliably ungotten. > private VanguardScanner vanguardScanner; > private VanguardParser vanguardParser; >- private ConflictedParser activeParser = null; >+ protected ConflictedParser activeParser = null; > private boolean consumingEllipsisAnnotations = false; > > public static final int RoundBracket = 0; >@@ -4241,12 +4242,13 @@ > static int IntersectionCastRule = 0; > static int ReferenceExpressionRule = 0; > static int VarargTypeAnnotationsRule = 0; >+ static int BlockStatementoptRule = 0; > > static Goal LambdaParameterListGoal; > static Goal IntersectionCastGoal; > static Goal VarargTypeAnnotationGoal; > static Goal ReferenceExpressionGoal; >- >+ static Goal BlockStatementoptGoal; > static { > > for (int i = 1; i <= ParserBasicInformation.NUM_RULES; i++) { // 0 == $acc >@@ -4261,12 +4263,17 @@ > else > if ("TypeAnnotations".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$ > VarargTypeAnnotationsRule = i; >+ else >+ if ("BlockStatementopt".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$ >+ BlockStatementoptRule = i; >+ > } > > LambdaParameterListGoal = new Goal(TokenNameARROW, new int[] { TokenNameARROW }, LambdaParameterListRule); > IntersectionCastGoal = new Goal(TokenNameLPAREN, followSetOfCast(), IntersectionCastRule); > VarargTypeAnnotationGoal = new Goal(TokenNameAT, new int[] { TokenNameELLIPSIS }, VarargTypeAnnotationsRule); > ReferenceExpressionGoal = new Goal(TokenNameLESS, new int[] { TokenNameCOLON_COLON }, ReferenceExpressionRule); >+ BlockStatementoptGoal = new Goal(TokenNameLBRACE, new int [0], BlockStatementoptRule); > } > > >@@ -4279,10 +4286,13 @@ > boolean hasBeenReached(int act, int token) { > /* > System.out.println("[Goal = " + Parser.name[Parser.non_terminal_index[Parser.lhs[this.rule]]] + "] " + "Saw: " + Parser.name[Parser.non_terminal_index[Parser.lhs[act]]] + "::" + //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ >- Parser.name[Parser.terminal_index[token]]); >+ Parser.name[Parser.terminal_index[token]]); > */ > if (act == this.rule) { >- for (int i = 0, length = this.follow.length; i < length; i++) >+ final int length = this.follow.length; >+ if (length == 0) >+ return true; >+ for (int i = 0; i < length; i++) > if (this.follow[i] == token) > return true; > } >@@ -4330,21 +4340,11 @@ > if (act <= NUM_RULES) { > this.stateStackTop--; > } else if (act > ERROR_ACTION) { /* shift-reduce */ >- this.unstackedAct = act; >- try { >- this.currentToken = this.scanner.getNextToken(); >- } finally { >- this.unstackedAct = ERROR_ACTION; >- } >+ this.currentToken = this.scanner.getNextToken(); > act -= ERROR_ACTION; > } else { > if (act < ACCEPT_ACTION) { /* shift */ >- this.unstackedAct = act; >- try { >- this.currentToken = this.scanner.getNextToken(); >- } finally { >- this.unstackedAct = ERROR_ACTION; >- } >+ this.currentToken = this.scanner.getNextToken(); > continue ProcessTerminals; > } > return FAILURE; // accept - we should never reach this state, we accept at reduce with a right member of follow set below. >@@ -4493,4 +4493,91 @@ > } > return token; > } >+ >+// Position the scanner at the next block statement and return the start token. We recognize empty statements. >+public int fastForward(Statement unused) { >+ >+ int token; >+ >+ while (true) { >+ try { >+ token = getNextToken(); >+ } catch (InvalidInputException e) { >+ return TokenNameEOF; >+ } >+ /* FOLLOW map of BlockStatement, since the non-terminal is recursive is a super set of its own FIRST set. >+ We use FOLLOW rather than FIRST since we want to recognize empty statements. i.e if (x > 10) { x = 0 } >+ */ >+ switch(token) { >+ case TokenNameIdentifier: >+ case TokenNameabstract: >+ case TokenNameassert: >+ case TokenNameboolean: >+ case TokenNamebreak: >+ case TokenNamebyte: >+ case TokenNamecase: >+ case TokenNamechar: >+ case TokenNameclass: >+ case TokenNamecontinue: >+ case TokenNamedefault: >+ case TokenNamedo: >+ case TokenNamedouble: >+ case TokenNameenum: >+ case TokenNamefalse: >+ case TokenNamefinal: >+ case TokenNamefloat: >+ case TokenNamefor: >+ case TokenNameif: >+ case TokenNameint: >+ case TokenNameinterface: >+ case TokenNamelong: >+ case TokenNamenative: >+ case TokenNamenew: >+ case TokenNamenull: >+ case TokenNameprivate: >+ case TokenNameprotected: >+ case TokenNamepublic: >+ case TokenNamereturn: >+ case TokenNameshort: >+ case TokenNamestatic: >+ case TokenNamestrictfp: >+ case TokenNamesuper: >+ case TokenNameswitch: >+ case TokenNamesynchronized: >+ case TokenNamethis: >+ case TokenNamethrow: >+ case TokenNametransient: >+ case TokenNametrue: >+ case TokenNametry: >+ case TokenNamevoid: >+ case TokenNamevolatile: >+ case TokenNamewhile: >+ case TokenNameIntegerLiteral: // ??! >+ case TokenNameLongLiteral: >+ case TokenNameFloatingPointLiteral: >+ case TokenNameDoubleLiteral: >+ case TokenNameCharacterLiteral: >+ case TokenNameStringLiteral: >+ case TokenNamePLUS_PLUS: >+ case TokenNameMINUS_MINUS: >+ case TokenNameLESS: >+ case TokenNameLPAREN: >+ case TokenNameLBRACE: >+ case TokenNameAT: >+ case TokenNameBeginLambda: >+ case TokenNameAT308: >+ if(getVanguardParser().parse(Goal.BlockStatementoptGoal) == VanguardParser.SUCCESS) >+ return token; >+ break; >+ case TokenNameSEMICOLON: >+ case TokenNameEOF: >+ return token; >+ case TokenNameRBRACE: // simulate empty statement. >+ ungetToken(token); >+ return TokenNameSEMICOLON; >+ default: >+ break; >+ } >+ } >+} > } >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/diagnose/DiagnoseParser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/diagnose/DiagnoseParser.java >index 5fddbf7..01452ed 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/diagnose/DiagnoseParser.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/diagnose/DiagnoseParser.java >@@ -2588,4 +2588,12 @@ > */ > return (token == TokenNameLPAREN || token == TokenNameAT || (token == TokenNameLESS && !this.lexStream.awaitingColonColon())); > } >+ >+ public void startRecovery() { >+ return; // not in that business. >+ } >+ >+ public boolean requireExtendedRecovery() { >+ return false; // not in that business. >+ } > } >diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java >index 800a69c..730ad41 100644 >--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java >+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java >@@ -790,7 +790,7 @@ > * A syntax error was detected. If a method is being parsed, records the number of errors and > * attempts to restart from the last statement by going for an expression. > */ >-protected int resumeOnSyntaxError() { >+protected int resumeOnErrorOrTriggeredRecovery(boolean errorRecovery) { > if (this.diet || this.hasRecoveredOnExpression) { // no reentering inside expression recovery > return HALT; > } >diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DocumentElementParser.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DocumentElementParser.java >index c05ba97..e1888c6 100644 >--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DocumentElementParser.java >+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DocumentElementParser.java >@@ -1511,7 +1511,7 @@ > * Syntax error was detected. Will attempt to perform some recovery action in order > * to resume to the regular parse loop. > */ >-protected int resumeOnSyntaxError() { >+protected int resumeOnErrorOrTriggeredRecovery(boolean errorRecovery) { > return HALT; > } > /* >diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java >index 2d08411..c9f7945 100644 >--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java >+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java >@@ -41,7 +41,7 @@ > import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; > import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; > import org.eclipse.jdt.internal.compiler.ast.UnaryExpression; >-import org.eclipse.jdt.internal.compiler.parser.Parser; >+import org.eclipse.jdt.internal.compiler.parser.CommitRollbackParser; > import org.eclipse.jdt.internal.compiler.parser.RecoveryScanner; > import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; > import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt; >@@ -122,7 +122,7 @@ > /* > * The parser this requestor is using. > */ >- protected Parser parser; >+ protected CommitRollbackParser parser; > > protected HashtableOfObject fieldRefCache; > protected HashtableOfObject messageRefCache;
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 422468
:
238163
|
238252
|
238301