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 238301 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]
Patch v0.99
v0.99.patch (text/plain), 112.10 KB, created by
Srikanth Sankaran
on 2013-12-12 14:31:04 EST
(
hide
)
Description:
Patch v0.99
Filename:
MIME Type:
Creator:
Srikanth Sankaran
Created:
2013-12-12 14:31:04 EST
Size:
112.10 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..f560be0 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 >@@ -74,9 +74,9 @@ > " static void goo(J i) {\n" + > " }\n" + > " public static void main(String[] args) {\n" + >- " (<no type> first, <no type> second) -> {\n" + >- " (<no type> xyz, <no type> pqr) -> <CompleteOnName:first.>;\n" + >- " };\n" + >+ " goo((<no type> first, <no type> second) -> {\n" + >+ " return (<no type> xyz, <no type> pqr) -> <CompleteOnName:first.>;\n" + >+ "});\n" + > " }\n" + > "}\n"; > >@@ -177,7 +177,9 @@ > int cursorLocation = string.lastIndexOf(completeBehind) + completeBehind.length() - 1; > > String expectedCompletionNodeToString = "<CompleteOnName:x>"; >- String expectedParentNodeToString = "<NONE>"; >+ String expectedParentNodeToString = "static Foo f = (<no type> x5, <no type> x6) -> {\n" + >+ " <CompleteOnName:x>;\n" + >+ "};"; > String completionIdentifier = "x"; > String expectedReplacedSource = "x"; > String expectedUnitDisplayString = >@@ -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"; >@@ -345,4 +347,372 @@ > 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() { >+ 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.compa); //[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.compa"; >+ 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" + >+ " Collections.sort(new ArrayList<X>(Arrays.asList(new X(), new X(), new X())), (X o1, X o2) -> <CompleteOnName:o1.compa>);\n" + >+ " }\n" + >+ "}\n"; >+ >+ checkMethodParse( >+ string.toCharArray(), >+ cursorLocation, >+ expectedCompletionNodeToString, >+ expectedParentNodeToString, >+ expectedUnitDisplayString, >+ completionIdentifier, >+ expectedReplacedSource, >+ "diet ast"); >+} >+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=405126, [1.8][code assist] Lambda parameters incorrectly recovered as fields. >+public void test405126() { >+ String string = >+ "public interface Foo { \n" + >+ " int run(int s1, int s2); \n" + >+ "}\n" + >+ "interface X {\n" + >+ " static Foo f = (int x5, int x11) -> x\n" + >+ " static int x1 = 2;\n" + >+ "}\n" + >+ "class C {\n" + >+ " void method1(){\n" + >+ " int p = X.\n" + >+ " }\n" + >+ "}\n"; >+ >+ String completeBehind = "X."; >+ int cursorLocation = string.lastIndexOf(completeBehind) + completeBehind.length() - 1; >+ >+ String expectedCompletionNodeToString = "<CompleteOnName:X.>"; >+ String expectedParentNodeToString = "int p = <CompleteOnName:X.>;"; >+ String completionIdentifier = ""; >+ String expectedReplacedSource = "X."; >+ String expectedUnitDisplayString = >+ "public interface Foo {\n" + >+ " int run(int s1, int s2);\n" + >+ "}\n" + >+ "interface X {\n" + >+ " static Foo f;\n" + >+ " static int x1;\n" + >+ " <clinit>() {\n" + >+ " }\n" + >+ "}\n" + >+ "class C {\n" + >+ " C() {\n" + >+ " }\n" + >+ " void method1() {\n" + >+ " int p = <CompleteOnName:X.>;\n" + >+ " }\n" + >+ "}\n"; >+ >+ checkMethodParse( >+ string.toCharArray(), >+ cursorLocation, >+ expectedCompletionNodeToString, >+ expectedParentNodeToString, >+ expectedUnitDisplayString, >+ completionIdentifier, >+ expectedReplacedSource, >+ "diet ast"); >+} >+// Verify that locals inside a lambda block don't get promoted to the parent block. >+public void testLocalsPromotion() { >+ String string = >+ "interface I {\n" + >+ " void foo(int x);\n" + >+ "}\n" + >+ "public class X {\n" + >+ " static void goo(I i) {}\n" + >+ " public static void main(String[] args) {\n" + >+ " int outerLocal;\n" + >+ " goo ((x) -> {\n" + >+ " int lambdaLocal = 10;\n" + >+ " System.out.println(\"Statement inside lambda\");\n" + >+ " lam\n" + >+ " });\n" + >+ " }\n" + >+ "}\n"; >+ >+ String completeBehind = "lam"; >+ int cursorLocation = string.lastIndexOf(completeBehind) + completeBehind.length() - 1; >+ >+ String expectedCompletionNodeToString = "<CompleteOnName:lam>"; >+ String expectedParentNodeToString = "<NONE>"; >+ String completionIdentifier = "lam"; >+ String expectedReplacedSource = "lam"; >+ String expectedUnitDisplayString = >+ "interface I {\n" + >+ " void foo(int x);\n" + >+ "}\n" + >+ "public class X {\n" + >+ " public X() {\n" + >+ " }\n" + >+ " static void goo(I i) {\n" + >+ " }\n" + >+ " public static void main(String[] args) {\n" + >+ " int outerLocal;\n" + >+ " goo((<no type> x) -> {\n" + >+ " int lambdaLocal;\n" + >+ " System.out.println(\"Statement inside lambda\");\n" + >+ " <CompleteOnName:lam>;\n" + >+ "});\n" + >+ " }\n" + >+ "}\n"; >+ >+ checkMethodParse( >+ string.toCharArray(), >+ cursorLocation, >+ expectedCompletionNodeToString, >+ expectedParentNodeToString, >+ expectedUnitDisplayString, >+ completionIdentifier, >+ expectedReplacedSource, >+ "diet ast"); >+} >+ >+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=422107, [1.8][code assist] Invoking code assist just before and after a variable initialized using lambda gives different result >+public void testCompletionLocation() { >+ String string = >+ "interface I {\n" + >+ " void doit();\n" + >+ "}\n" + >+ "interface J {\n" + >+ "}\n" + >+ "public class X { \n" + >+ " Object o = (I & J) () -> {};\n" + >+ " /* AFTER */\n" + >+ "}\n"; >+ >+ String completeBehind = "/* AFTER */"; >+ int cursorLocation = string.lastIndexOf(completeBehind) + completeBehind.length() - 1; >+ >+ String expectedCompletionNodeToString = "<CompleteOnType:>"; >+ String expectedParentNodeToString = "<NONE>"; >+ String completionIdentifier = ""; >+ String expectedReplacedSource = ""; >+ String expectedUnitDisplayString = >+ "interface I {\n" + >+ " void doit();\n" + >+ "}\n" + >+ "interface J {\n" + >+ "}\n" + >+ "public class X {\n" + >+ " Object o;\n" + >+ " <CompleteOnType:>;\n" + >+ " public X() {\n" + >+ " }\n" + >+ "}\n"; >+ >+ checkMethodParse( >+ string.toCharArray(), >+ cursorLocation, >+ expectedCompletionNodeToString, >+ expectedParentNodeToString, >+ expectedUnitDisplayString, >+ completionIdentifier, >+ expectedReplacedSource, >+ "diet ast"); >+} >+public void testElidedCompletion() { >+ String string = >+ "class Collections {\n" + >+ " public static void sort(ArrayList list, Comparator c) {\n" + >+ " }\n" + >+ "}\n" + >+ "interface Comparator {\n" + >+ " int compareTo(X t, X s);\n" + >+ "}\n" + >+ "class ArrayList {\n" + >+ "}\n" + >+ "public class X {\n" + >+ " int compareTo(X x) { return 0; }\n" + >+ " void foo() {\n" + >+ " Collections.sort(new ArrayList(), (X o1, X o2) -> o1.compa);\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.compa"; >+ String expectedUnitDisplayString = >+ "class Collections {\n" + >+ " Collections() {\n" + >+ " }\n" + >+ " public static void sort(ArrayList list, Comparator c) {\n" + >+ " }\n" + >+ "}\n" + >+ "interface Comparator {\n" + >+ " int compareTo(X t, X s);\n" + >+ "}\n" + >+ "class ArrayList {\n" + >+ " ArrayList() {\n" + >+ " }\n" + >+ "}\n" + >+ "public class X {\n" + >+ " public X() {\n" + >+ " }\n" + >+ " int compareTo(X x) {\n" + >+ " }\n" + >+ " void foo() {\n" + >+ " Collections.sort(new ArrayList(), (X o1, X o2) -> <CompleteOnName:o1.compa>);\n" + >+ " }\n" + >+ "}\n"; >+ >+ checkMethodParse( >+ string.toCharArray(), >+ cursorLocation, >+ expectedCompletionNodeToString, >+ expectedParentNodeToString, >+ expectedUnitDisplayString, >+ completionIdentifier, >+ expectedReplacedSource, >+ "diet ast"); >+} >+public void testElidedCompletion2() { >+ String string = >+ "class Collections {\n" + >+ " public static void sort(ArrayList list, Comparator c) {\n" + >+ " }\n" + >+ "}\n" + >+ "interface Comparator {\n" + >+ " int compareTo(X t, X s);\n" + >+ "}\n" + >+ "class ArrayList {\n" + >+ "}\n" + >+ "public class X {\n" + >+ " int compareTo(X x) { return 0; }\n" + >+ " void foo() {\n" + >+ " Collections.sort(new ArrayList(), (o1, o2) -> o1.compa);\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.compa"; >+ String expectedUnitDisplayString = >+ "class Collections {\n" + >+ " Collections() {\n" + >+ " }\n" + >+ " public static void sort(ArrayList list, Comparator c) {\n" + >+ " }\n" + >+ "}\n" + >+ "interface Comparator {\n" + >+ " int compareTo(X t, X s);\n" + >+ "}\n" + >+ "class ArrayList {\n" + >+ " ArrayList() {\n" + >+ " }\n" + >+ "}\n" + >+ "public class X {\n" + >+ " public X() {\n" + >+ " }\n" + >+ " int compareTo(X x) {\n" + >+ " }\n" + >+ " void foo() {\n" + >+ " Collections.sort(new ArrayList(), (<no type> o1, <no type> 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.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/CompletionRecoveryTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/CompletionRecoveryTest.java >index abb6bbd..cfb6b33 100644 >--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/CompletionRecoveryTest.java >+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/CompletionRecoveryTest.java >@@ -1071,8 +1071,6 @@ > " e.gc.setLineCap(<CompleteOnName:SWT.CAP_>);\n" + > " }\n" + > " };\n" + >- " new ControlAdapter() {\n" + >- " };\n" + > " }\n" + > "}\n", > // expectedCompletionIdentifier: >diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunOnlyAssistTests18.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunOnlyAssistTests18.java >new file mode 100644 >index 0000000..b4392f7 >--- /dev/null >+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunOnlyAssistTests18.java >@@ -0,0 +1,69 @@ >+/******************************************************************************* >+ * 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.core.tests; >+ >+import java.lang.reflect.InvocationTargetException; >+import java.lang.reflect.Method; >+ >+import junit.framework.Test; >+import junit.framework.TestCase; >+import junit.framework.TestSuite; >+ >+import org.eclipse.jdt.core.tests.compiler.parser.CompletionParserTest18; >+import org.eclipse.jdt.core.tests.model.CompletionTests18; >+import org.eclipse.jdt.core.tests.model.ResolveTests18; >+ >+public class RunOnlyAssistTests18 extends TestCase { >+ >+ public RunOnlyAssistTests18(String name) { >+ super(name); >+ } >+ public static Class[] getAllTestClasses() { >+ return new Class[] { >+ ResolveTests18.class, >+ CompletionParserTest18.class, >+ CompletionTests18.class, >+ }; >+ } >+ >+ public static Test suite() { >+ TestSuite ts = new TestSuite(RunOnlyAssistTests18.class.getName()); >+ >+ Class[] testClasses = getAllTestClasses(); >+ addTestsToSuite(ts, testClasses); >+ return ts; >+ } >+ public static void addTestsToSuite(TestSuite suite, Class[] testClasses) { >+ >+ for (int i = 0; i < testClasses.length; i++) { >+ Class testClass = testClasses[i]; >+ // call the suite() method and add the resulting suite to the suite >+ try { >+ Method suiteMethod = testClass.getDeclaredMethod("suite", new Class[0]); //$NON-NLS-1$ >+ Test test = (Test)suiteMethod.invoke(null, new Object[0]); >+ suite.addTest(test); >+ } catch (IllegalAccessException e) { >+ e.printStackTrace(); >+ } catch (InvocationTargetException e) { >+ e.getTargetException().printStackTrace(); >+ } catch (NoSuchMethodException e) { >+ e.printStackTrace(); >+ } >+ } >+ } >+ protected void tearDown() throws Exception { >+ super.tearDown(); >+ } >+} >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..7a92cb3 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 >@@ -115,12 +115,12 @@ > int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); > this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner); > assertResults( >- // INTERIM RESULTS, WILL FAIL ONCE ELIDED TYPE IS CORRECTLY INFERRED. > "clone[METHOD_REF]{clone(), Ljava.lang.Object;, ()Ljava.lang.Object;, clone, null, 35}\n" + > "equals[METHOD_REF]{equals(), Ljava.lang.Object;, (Ljava.lang.Object;)Z, equals, (obj), 35}\n" + > "finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, finalize, null, 35}\n" + > "getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class<+Ljava.lang.Object;>;, getClass, null, 35}\n" + > "hashCode[METHOD_REF]{hashCode(), Ljava.lang.Object;, ()I, hashCode, null, 35}\n" + >+ "length[METHOD_REF]{length(), Ljava.lang.String;, ()I, length, null, 35}\n" + > "notify[METHOD_REF]{notify(), Ljava.lang.Object;, ()V, notify, null, 35}\n" + > "notifyAll[METHOD_REF]{notifyAll(), Ljava.lang.Object;, ()V, notifyAll, null, 35}\n" + > "toString[METHOD_REF]{toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, 35}\n" + >@@ -331,12 +331,12 @@ > "toString[METHOD_DECLARATION]{public String toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, 27}", > requestor.getResults()); > } >-public void _test010() throws JavaModelException { >+public void test010() throws JavaModelException { > this.workingCopies = new ICompilationUnit[1]; > this.workingCopies[0] = getWorkingCopy( > "/Completion/src/X.java", > "interface I {\n" + >- " String foo(String x, Integer i); \n" + >+ " String foo(X x, X i); \n" + > "} \n" + > "public class X {\n" + > " static void goo(I i) {\n" + >@@ -358,29 +358,20 @@ > int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); > this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner); > assertResults( >- "[POTENTIAL_METHOD_DECLARATION]{, LX;, ()V, , null, 14}\n" + >- "abstract[KEYWORD]{abstract, null, null, abstract, null, 24}\n" + >- "class[KEYWORD]{class, null, null, class, null, 24}\n" + >- "enum[KEYWORD]{enum, null, null, enum, null, 24}\n" + >- "final[KEYWORD]{final, null, null, final, null, 24}\n" + >- "interface[KEYWORD]{interface, null, null, interface, null, 24}\n" + >- "native[KEYWORD]{native, null, null, native, null, 24}\n" + >- "private[KEYWORD]{private, null, null, private, null, 24}\n" + >- "protected[KEYWORD]{protected, null, null, protected, null, 24}\n" + >- "public[KEYWORD]{public, null, null, public, null, 24}\n" + >- "static[KEYWORD]{static, null, null, static, null, 24}\n" + >- "strictfp[KEYWORD]{strictfp, null, null, strictfp, null, 24}\n" + >- "synchronized[KEYWORD]{synchronized, null, null, synchronized, null, 24}\n" + >- "transient[KEYWORD]{transient, null, null, transient, null, 24}\n" + >- "volatile[KEYWORD]{volatile, null, null, volatile, null, 24}\n" + >- "I[TYPE_REF]{I, , LI;, null, null, 27}\n" + >- "J[TYPE_REF]{J, , LJ;, null, null, 27}\n" + >- "X[TYPE_REF]{X, , LX;, null, null, 27}\n" + >- "clone[METHOD_DECLARATION]{protected Object clone() throws CloneNotSupportedException, Ljava.lang.Object;, ()Ljava.lang.Object;, clone, null, 27}\n" + >- "equals[METHOD_DECLARATION]{public boolean equals(Object obj), Ljava.lang.Object;, (Ljava.lang.Object;)Z, equals, (obj), 27}\n" + >- "finalize[METHOD_DECLARATION]{protected void finalize() throws Throwable, Ljava.lang.Object;, ()V, finalize, null, 27}\n" + >- "hashCode[METHOD_DECLARATION]{public int hashCode(), Ljava.lang.Object;, ()I, hashCode, null, 27}\n" + >- "toString[METHOD_DECLARATION]{public String toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, 27}", >+ "goo[METHOD_REF]{goo(), LX;, (LI;)V, goo, (i), 24}\n" + >+ "goo[METHOD_REF]{goo(), LX;, (Ljava.lang.String;)V, goo, (s), 24}\n" + >+ "main[METHOD_REF]{main(), LX;, ([Ljava.lang.String;)V, main, (args), 24}\n" + >+ "clone[METHOD_REF]{clone(), Ljava.lang.Object;, ()Ljava.lang.Object;, clone, null, 35}\n" + >+ "equals[METHOD_REF]{equals(), Ljava.lang.Object;, (Ljava.lang.Object;)Z, equals, (obj), 35}\n" + >+ "finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, finalize, null, 35}\n" + >+ "getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class<+Ljava.lang.Object;>;, getClass, null, 35}\n" + >+ "hashCode[METHOD_REF]{hashCode(), Ljava.lang.Object;, ()I, hashCode, null, 35}\n" + >+ "notify[METHOD_REF]{notify(), Ljava.lang.Object;, ()V, notify, null, 35}\n" + >+ "notifyAll[METHOD_REF]{notifyAll(), Ljava.lang.Object;, ()V, notifyAll, null, 35}\n" + >+ "toString[METHOD_REF]{toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, 35}\n" + >+ "wait[METHOD_REF]{wait(), Ljava.lang.Object;, ()V, wait, null, 35}\n" + >+ "wait[METHOD_REF]{wait(), Ljava.lang.Object;, (J)V, wait, (millis), 35}\n" + >+ "wait[METHOD_REF]{wait(), Ljava.lang.Object;, (JI)V, wait, (millis, nanos), 35}", > requestor.getResults()); > } > // https://bugs.eclipse.org/bugs/show_bug.cgi?id=422901, [1.8][code assist] Code assistant sensitive to scope.referenceContext type identity. >@@ -570,7 +561,7 @@ > " public static void main(String[] args) {\n" + > " I i = () -> {\n" + > " xyz\n" + >- " }\n" + >+ " }\n" + > " }\n" + > "}\n"); > >@@ -597,4 +588,105 @@ > " 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 { // computing visible elements in lambda scope. >+ 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" + >+ " static X xField;\n" + >+ " static X goo(String s) {\n" + >+ " return null;\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=233\n" + >+ "completion range=[233, 232]\n" + >+ "completion token=\"\"\n" + >+ "completion token kind=TOKEN_KIND_NAME\n" + >+ "expectedTypesSignatures=null\n" + >+ "expectedTypesKeys=null\n" + >+ "completion token location=UNKNOWN\n" + >+ "visibleElements={\n" + >+ " xField {key=LX;.xField)LX;} [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]],\n" + >+ " goo(String) {key=LX;.goo(Ljava/lang/String;)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 { // computing visible elements in lambda scope. >+ this.workingCopies = new ICompilationUnit[1]; >+ this.workingCopies[0] = getWorkingCopy( >+ "/Completion/src/X.java", >+ "interface I {\n" + >+ " void foo(X x);\n" + >+ "}\n" + >+ "public class X {\n" + >+ " static X xField;\n" + >+ " static X goo(String s) {\n" + >+ " return null;\n" + >+ " }\n" + >+ " static void goo(I i) {\n" + >+ " }\n" + >+ " public static void main(String[] args) {\n" + >+ " X xLocal = null;\n" + >+ " args = null;\n" + >+ " if (args != null) {\n" + >+ " xField = null;\n" + >+ " else \n" + >+ " xField = null;\n" + >+ " while (true);\n" + >+ " goo((xyz) -> {\n" + >+ " X xLambdaLocal = null;\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=419\n" + >+ "completion range=[419, 418]\n" + >+ "completion token=\"\"\n" + >+ "completion token kind=TOKEN_KIND_NAME\n" + >+ "expectedTypesSignatures=null\n" + >+ "expectedTypesKeys=null\n" + >+ "completion token location=UNKNOWN\n" + >+ "visibleElements={\n" + >+ " xLocal [in main(String[]) [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]]],\n" + >+ " xLambdaLocal [in main(String[]) [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]]],\n" + >+ " xField {key=LX;.xField)LX;} [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]],\n" + >+ " goo(String) {key=LX;.goo(Ljava/lang/String;)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..63b20f3 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 >@@ -1349,20 +1349,22 @@ > } > } > // 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 { >+public void test417935() throws JavaModelException { // JCL_MIN does not have the relevant classes - these are needed to handle lambda. Use local versions. > this.wc = getWorkingCopy( > "/Resolve/src/X.java", >- "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" + >+ "class Collections {\n" + >+ " public static void sort(ArrayList list, Comparator c) {\n" + > " }\n" + >- "\n" + >+ "}\n" + >+ "interface Comparator {\n" + >+ " int compareTo(X t, X s);\n" + >+ "}\n" + >+ "class ArrayList {\n" + >+ "}\n" + >+ "public class X {\n" + >+ " int compareTo(X x) { return 0; }\n" + >+ " void foo() {\n" + >+ " Collections.sort(new ArrayList(), (X o1, X o2) -> o1.compareTo(o2));\n" + > " }\n" + > "}\n"); > >@@ -1531,4 +1533,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/complete/CompletionParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java >index b8cbc0e..f29beb0 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.*; >@@ -156,6 +155,7 @@ > int labelPtr = -1; > > boolean isAlreadyAttached; >+ boolean shouldStackAssistNode; > > public boolean record = false; > public boolean skipRecord = false; >@@ -614,7 +614,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; > >@@ -2407,6 +2407,19 @@ > // DimWithOrWithOutExpr ::= '[' ']' > pushOnExpressionStack(null); > } >+protected void consumeEmptyStatement() { >+ super.consumeEmptyStatement(); >+ /* Sneak in the assist node. The reason we can't do that when we see the assist node is that >+ we don't know whether it is the first or subsequent statement in a block to be able to >+ decide whether to call contactNodeLists. See Parser.consumeBlockStatement(s) >+ */ >+ if (this.shouldStackAssistNode) { >+ this.shouldStackAssistNode = false; >+ if (this.assistNode != null) >+ // this.astStack[this.astPtr] = this.assistNodeParent != null ? this.assistNodeParent : this.assistNode; >+ this.astStack[this.astPtr] = this.assistNode; >+ } >+} > protected void consumeEnhancedForStatement() { > super.consumeEnhancedForStatement(); > >@@ -2580,7 +2593,7 @@ > this.cursorLocation > variable.initialization.sourceEnd) { > variable.initialization = null; > } else if (this.assistNode != null && this.assistNode == variable.initialization) { >- this.assistNodeParent = variable; >+ this.assistNodeParent = variable; > } > } > protected void consumeExitVariableWithoutInitialization() { >@@ -3470,6 +3483,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 +3690,8 @@ > break; > case TokenNamedo: > pushOnElementStack(K_BLOCK_DELIMITER, DO); >+ break; >+ case TokenNameARROW: > break; > default : > pushOnElementStack(K_BLOCK_DELIMITER); >@@ -4609,6 +4626,18 @@ > this.labelPtr = -1; > initializeForBlockStatements(); > } >+public 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 +4983,10 @@ > break; > } > } >+ >+protected CommitRollbackParser createSnapShotParser() { >+ return new CompletionParser(this.problemReporter, this.storeSourceEnds); >+} > /* > * Reset internal state after completion is over > */ >@@ -4977,7 +5010,7 @@ > int[] state = (int[]) parserState; > > CompletionScanner completionScanner = (CompletionScanner)this.scanner; >- >+ // ?? > this.cursorLocation = state[0]; > completionScanner.cursorLocation = state[1]; > } >@@ -4988,13 +5021,21 @@ > * Move checkpoint location, reset internal stacks and > * decide which grammar goal is activated. > */ >-protected boolean resumeAfterRecovery() { >+protected int resumeAfterRecovery() { > this.hasUnusedModifiers = false; > if (this.assistNode != null) { >+ >+ if (requireExtendedRecovery()) { >+ if (this.unstackedAct != ERROR_ACTION) { >+ return RESUME; >+ } >+ return super.resumeAfterRecovery(); >+ } >+ > /* 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 +5063,7 @@ > } > } > */ >+ > /* restart in diet mode for finding sibling constructs */ > if (this.currentElement instanceof RecoveredType > || this.currentElement.enclosingType() != null){ >@@ -5035,7 +5077,7 @@ > this.scanner.eofPosition = end < Integer.MAX_VALUE ? end + 1 : end; > } else { > resetStacks(); >- return false; >+ return HALT; > } > } > } >@@ -5044,6 +5086,11 @@ > public void setAssistIdentifier(char[] assistIdent){ > ((CompletionScanner)this.scanner).completionIdentifier = assistIdent; > } >+ >+protected void shouldStackAssistNode() { >+ this.shouldStackAssistNode = true; >+} >+ > public String toString() { > StringBuffer buffer = new StringBuffer(); > buffer.append("elementKindStack : int[] = {"); //$NON-NLS-1$ >@@ -5070,7 +5117,14 @@ > > /* may be able to retrieve completionNode as an orphan, and then attach it */ > completionIdentifierCheck(); >+ CommitRollbackParser parser = null; >+ if (lastIndexOfElement(K_LAMBDA_EXPRESSION_DELIMITER) >= 0) { >+ parser = createSnapShotParser(); >+ parser.copyState(this); >+ } > attachOrphanCompletionNode(); >+ if (parser != null) >+ this.copyState(parser); > > // if an assist node has been found and a recovered element exists, > // mark enclosing blocks as to be preserved >diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java >index 61a375a..3688795 100644 >--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java >+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java >@@ -56,6 +56,15 @@ > null/*taskPriorities*/, > true/*taskCaseSensitive*/); > } >+protected boolean isAtAssistIdentifier() { >+ if (this.cursorLocation < this.startPosition && this.currentPosition == this.startPosition) { // fake empty identifier got issued >+ return true; >+ } >+ if (this.cursorLocation+1 >= this.startPosition && this.cursorLocation < this.currentPosition) { >+ return true; >+ } >+ return false; >+} > /* > * Truncate the current identifier if it is containing the cursor location. Since completion is performed > * on an identifier prefix. >@@ -199,6 +208,7 @@ > this.currentPosition = this.startPosition; // for being detected as empty free identifier > return TokenNameIdentifier; > } >+ this.currentPosition = this.startPosition; // fake EOF should not drown the real next token. > return TokenNameEOF; > } > >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..59295aa 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 >@@ -19,6 +19,7 @@ > * > */ > >+import org.eclipse.jdt.internal.codeassist.complete.CompletionOnKeyword2; > import org.eclipse.jdt.internal.compiler.ast.ASTNode; > import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; > import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; >@@ -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; >@@ -58,6 +60,7 @@ > public abstract class AssistParser extends Parser { > public ASTNode assistNode; > public boolean isOrphanCompletionNode; >+ private boolean resumedAfterRepair = false; > // last modifiers info > protected int lastModifiers = ClassFileConstants.AccDefault; > protected int lastModifiersStart = -1; >@@ -93,7 +96,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 +105,12 @@ > // 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; > > 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(); > >+public 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 >@@ -144,6 +177,7 @@ > RecoveredElement element = super.buildInitialRecoveryState(); > flushAssistState(); > flushElementStack(); >+ this.snapShot = null; > return element; > } > >@@ -184,8 +218,9 @@ > element = element.add(block, 1); > int blockIndex = 1; // ignore first block start, since manually rebuilt here > >- for(int i = 0; i <= this.astPtr; i++){ >- ASTNode node = this.astStack[i]; >+ ASTNode node = null, lastNode = null; >+ for (int i = 0; i <= this.astPtr; i++, lastNode = node) { >+ node = this.astStack[i]; > if(node instanceof ForeachStatement && ((ForeachStatement)node).action == null) { > node = ((ForeachStatement)node).elementVariable; > } >@@ -198,7 +233,7 @@ > break; > } > if (this.blockStarts[j] != lastStart){ // avoid multiple block if at same position >- block = new Block(0); >+ block = new Block(0, lastNode instanceof LambdaExpression); > block.sourceStart = lastStart = this.blockStarts[j]; > element = element.add(block, 1); > } >@@ -277,12 +312,6 @@ > } > continue; > } >- if (node instanceof LambdaExpression) { >- LambdaExpression lambda = (LambdaExpression) node; >- element = element.add(lambda, 0); >- this.lastCheckPoint = lambda.sourceEnd + 1; >- continue; >- } > if (this.assistNode != null && node instanceof Statement) { > Statement stmt = (Statement) node; > if (!(stmt instanceof Expression) || ((Expression) stmt).statementExpression()) { >@@ -305,13 +334,16 @@ > } > > /* might need some extra block (after the last reduced node) */ >+ /* For block bodied lambdas we should create a block even though the lambda header appears before it, so elements from within don't get misattributed. */ > int pos = this.assistNode == null ? this.lastCheckPoint : this.assistNode.sourceStart; >+ boolean createLambdaBlock = lastNode instanceof LambdaExpression && ((LambdaExpression) node).body() instanceof Block; > for (int j = blockIndex; j <= this.realBlockPtr; j++){ > if (this.blockStarts[j] >= 0) { >- if ((this.blockStarts[j] < pos) && (this.blockStarts[j] != lastStart)){ // avoid multiple block if at same position >- block = new Block(0); >+ if ((this.blockStarts[j] < pos || createLambdaBlock) && (this.blockStarts[j] != lastStart)){ // avoid multiple block if at same position >+ block = new Block(0, createLambdaBlock); > block.sourceStart = lastStart = this.blockStarts[j]; > element = element.add(block, 1); >+ createLambdaBlock = false; > } > } else { > if ((this.blockStarts[j] < pos)){ // avoid multiple block if at same position >@@ -401,27 +433,64 @@ > 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; >+ >+protected boolean triggerRecoveryUponLambdaClosure() { >+ // Last block statement reduced is required to be on the AST stack top. >+ boolean lambdaClosed = false; >+ 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; >+ lambdaClosed = true; >+ } else { >+ int stackLength = this.stack.length; >+ if (++this.stateStackTop >= stackLength) { >+ System.arraycopy( >+ this.stack, 0, >+ this.stack = new int[stackLength + StackIncrement], 0, >+ stackLength); >+ } >+ this.stack[this.stateStackTop] = this.unstackedAct; >+ commit(); >+ this.stateStackTop --; >+ return false; > } >- this.restartRecovery = true; >- this.isOrphanCompletionNode = false; >- this.lambdaNeedsClosure = false; > } >+ >+ if (lambdaClosed && this.currentElement != null) { >+ this.restartRecovery = true; >+ if (!(statement instanceof AbstractVariableDeclaration)) // added already as part of standard recovery since these contribute a name to the scope prevailing at the cursor. >+ this.currentElement.add(statement, 0); >+ } >+ this.snapShot = null; >+ return lambdaClosed; > } >-protected void consumeExplicitConstructorInvocationWithTypeArguments(int flag, int recFlag) { >- super.consumeExplicitConstructorInvocationWithTypeArguments(flag, recFlag); >+protected boolean isAssistParser() { >+ return true; >+} >+protected void consumeBlockStatement() { >+ super.consumeBlockStatement(); > triggerRecoveryUponLambdaClosure(); > } > >+protected void consumeBlockStatements() { >+ super.consumeBlockStatements(); >+ triggerRecoveryUponLambdaClosure(); >+} >+protected void consumeFieldDeclaration() { >+ super.consumeFieldDeclaration(); >+ if (triggerRecoveryUponLambdaClosure()) { >+ if (this.currentElement instanceof RecoveredType) >+ popUntilElement(K_TYPE_DELIMITER); >+ } >+} > protected void consumeForceNoDiet() { > super.consumeForceNoDiet(); > // if we are not in a method (i.e. we are not in a local variable initializer) >@@ -444,9 +513,10 @@ > super.consumeInterfaceHeader(); > pushOnElementStack(K_TYPE_DELIMITER); > } >-protected void consumeExpressionStatement() { >- super.consumeExpressionStatement(); >- triggerRecoveryUponLambdaClosure(); >+protected void consumeLambdaHeader() { >+ super.consumeLambdaHeader(); >+ LambdaExpression lexp = (LambdaExpression) this.astStack[this.astPtr]; >+ pushOnElementStack(K_LAMBDA_EXPRESSION_DELIMITER, EXPRESSION_BODY, lexp); > } > protected void consumeMethodBody() { > super.consumeMethodBody(); >@@ -457,7 +527,6 @@ > popElement(K_METHOD_DELIMITER); > } > super.consumeMethodDeclaration(isNotAbstract, isDefaultMethod); >- triggerRecoveryUponLambdaClosure(); > } > protected void consumeMethodHeader() { > super.consumeMethodHeader(); >@@ -517,16 +586,30 @@ > } > protected void consumeOpenBlock() { > // 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); >+ this.blockStarts, 0, >+ this.blockStarts = new int[stackLength + StackIncrement], 0, >+ stackLength); > } > this.blockStarts[this.realBlockPtr] = this.scanner.startPosition; >+ if (requireExtendedRecovery()) { >+ // This is an epsilon production: We are in the state with kernel item: Block ::= .OpenBlock LBRACE BlockStatementsopt RBRACE >+ stackLength = this.stack.length; >+ if (++this.stateStackTop >= stackLength - 1) { // Need two slots. >+ System.arraycopy( >+ this.stack, 0, >+ this.stack = new int[stackLength + StackIncrement], 0, >+ stackLength); >+ } >+ this.stack[this.stateStackTop++] = this.unstackedAct; // transition to Block ::= OpenBlock .LBRACE BlockStatementsopt RBRACE >+ this.stack[this.stateStackTop] = tAction(this.unstackedAct, this.currentToken); // transition to Block ::= OpenBlock LBRACE .BlockStatementsopt RBRACE >+ commit(); >+ this.stateStackTop -= 2; >+ } > } > protected void consumeOpenFakeBlock() { > // OpenBlock ::= $empty >@@ -853,6 +936,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 +1351,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 +1693,13 @@ > flushElementStack(); > } > } >+ >+public boolean requireExtendedRecovery() { >+ if (this.assistNode instanceof TypeReference || this.assistNode instanceof CompletionOnKeyword2) >+ return false; >+ return lastIndexOfElement(K_LAMBDA_EXPRESSION_DELIMITER) >= 0; >+} >+ > protected void pushOnElementStack(int kind){ > this.pushOnElementStack(kind, 0, null); > } >@@ -1659,7 +1762,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,8 +1794,19 @@ > * Move checkpoint location, reset internal stacks and > * decide which grammar goal is activated. > */ >-protected boolean resumeAfterRecovery() { >- >+protected int resumeAfterRecovery() { >+ if (requireExtendedRecovery()) { >+ if (this.unstackedAct == ERROR_ACTION) { >+ int mode = fallBackToSpringForward((Statement) null); >+ this.resumedAfterRepair = mode == RESUME; >+ if (mode == RESUME || mode == HALT) >+ return mode; >+ // else fall through and RESTART >+ } else { >+ return RESUME; >+ } >+ } >+ > // reset internal stacks > this.astPtr = -1; > this.astLengthPtr = -1; >@@ -1700,15 +1814,20 @@ > 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; >@@ -1717,7 +1836,12 @@ > if (this.diet) this.dietInt = 0; > > /* attempt to move checkpoint location */ >- if (!moveRecoveryCheckpoint()) return false; >+ if (this.unstackedAct != ERROR_ACTION && this.resumedAfterRepair) { >+ this.scanner.ungetToken(this.currentToken); // effectively move recovery checkpoint *backwards*. >+ } else { >+ if (!moveRecoveryCheckpoint()) return HALT; >+ } >+ this.resumedAfterRepair = false; > > // only look for headers > if (this.referenceContext instanceof CompilationUnitDeclaration >@@ -1738,7 +1862,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 +1874,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 +1950,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..007f5be 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; >@@ -115,8 +115,10 @@ > if (orphan instanceof Expression) { > buildMoreCompletionContext((Expression)orphan); > } else { >- Statement statement = (Statement) orphan; >- this.currentElement = this.currentElement.add(statement, 0); >+ if (lastIndexOfElement(K_LAMBDA_EXPRESSION_DELIMITER) < 0) { // lambdas are recovered upto the containing expression statement and will carry along the assist node anyways. >+ Statement statement = (Statement) orphan; >+ this.currentElement = this.currentElement.add(statement, 0); >+ } > } > this.currentToken = 0; // given we are not on an eof, we do not want side effects caused by looked-ahead token > } >@@ -176,12 +178,15 @@ > break nextElement; > } > } >- if(parentNode != null) { >- this.currentElement = this.currentElement.add((Statement)parentNode, 0); >- } else { >- this.currentElement = this.currentElement.add((Statement)wrapWithExplicitConstructorCallIfNeeded(expression), 0); >- if(this.lastCheckPoint < expression.sourceEnd) { >- this.lastCheckPoint = expression.sourceEnd + 1; >+ // Do not add assist node/parent into the recovery system if we are inside a lambda. The lambda will be fully reovered including the containing statement and added. >+ if (lastIndexOfElement(K_LAMBDA_EXPRESSION_DELIMITER) < 0) { >+ if(parentNode != null) { >+ this.currentElement = this.currentElement.add((Statement)parentNode, 0); >+ } else { >+ this.currentElement = this.currentElement.add((Statement)wrapWithExplicitConstructorCallIfNeeded(expression), 0); >+ if(this.lastCheckPoint < expression.sourceEnd) { >+ this.lastCheckPoint = expression.sourceEnd + 1; >+ } > } > } > } >@@ -1184,6 +1189,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 +1421,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,23 +1428,29 @@ > * Move checkpoint location, reset internal stacks and > * decide which grammar goal is activated. > */ >-protected boolean resumeAfterRecovery() { >+protected int resumeAfterRecovery() { > > /* 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 (this.unstackedAct != ERROR_ACTION) { >+ return RESUME; >+ } >+ return super.resumeAfterRecovery(); >+ } > 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; > } > } > } >@@ -1504,15 +1496,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/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionScanner.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionScanner.java >index 0e81cd0..d08e534 100644 >--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionScanner.java >+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionScanner.java >@@ -32,6 +32,10 @@ > super(false /*comment*/, false /*whitespace*/, false /*nls*/, sourceLevel, null /*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/); > } > >+protected boolean isAtAssistIdentifier() { >+ return this.selectionStart == this.startPosition && this.selectionEnd == this.currentPosition - 1; >+} >+ > public char[] getCurrentIdentifierSource() { > > if (this.selectionIdentifier == null){ >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java >index e7af82f..cfcb72e 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java >@@ -5,6 +5,10 @@ > * 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 > * Stephan Herrmann - Contributions for >@@ -27,7 +31,12 @@ > public int explicitDeclarations; > // the number of explicit declaration , used to create scope > public BlockScope scope; >+ public boolean lambdaBody; > >+public Block(int explicitDeclarations, boolean lambdaBody) { >+ this.explicitDeclarations = explicitDeclarations; >+ this.lambdaBody = lambdaBody; >+} > public Block(int explicitDeclarations) { > this.explicitDeclarations = explicitDeclarations; > } >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..ecfd307 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,25 @@ > 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) { >+ private static final Block NO_BODY = new Block(0, true); >+ >+ 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 +102,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 +111,10 @@ > > public void setArrowPosition(int arrowPosition) { > this.arrowPosition = arrowPosition; >+ } >+ >+ public int getArrowPosition() { >+ return this.arrowPosition; > } > > protected FunctionalExpression original() { >@@ -188,7 +193,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 +529,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 +579,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 +626,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 +636,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..8927ec7 >--- /dev/null >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/CommitRollbackParser.java >@@ -0,0 +1,111 @@ >+/******************************************************************************* >+ * 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.Statement; >+ >+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 Scanner scanner; >+ public int currentToken; >+ protected int kurrentToken; // copy of currentToken as it is trampled over all over the place :-( >+ >+ public CommitRollbackParser snapShot; >+ private static final int[] RECOVERY_TOKENS = new int [] { TokenNameSEMICOLON, TokenNameRPAREN,}; >+ >+ protected CommitRollbackParser createSnapShotParser() { >+ return new Parser(); >+ } >+ >+ protected void commit() { >+ if (this.snapShot == null) { >+ this.snapShot = createSnapShotParser(); >+ } >+ this.snapShot.copyState(this); >+ } >+ >+ public void copyState(CommitRollbackParser commitRollbackParser) { >+ // Subclasses should implement. >+ } >+ >+ protected int getNextToken() { >+ try { >+ return this.scanner.getNextToken(); >+ } catch (InvalidInputException e) { >+ return TokenNameEOF; >+ } >+ } >+ >+ protected void shouldStackAssistNode() { >+ // Not relevant here. >+ } >+ >+ // 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; >+ boolean atCompletionSite = false; >+ int automatonState = automatonState(); >+ >+ // 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) { >+ atCompletionSite = true; >+ this.scanner.eofPosition = this.scanner.source.length; >+ nextToken = getNextToken(); >+ if (automatonWillShift(nextToken, automatonState)) { >+ this.currentToken = this.kurrentToken = nextToken; >+ 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. FIXME: need to make sure we don't get stuck keep reducing empty statements !! >+ for (int i = 0, length = RECOVERY_TOKENS.length; i < length; i++) { >+ if (automatonWillShift(RECOVERY_TOKENS[i], automatonState)) { >+ this.currentToken = this.kurrentToken = RECOVERY_TOKENS[i]; >+ return RESUME; >+ } >+ } >+ // OK, no in place resumption, no local repair, fast forward to next statement. >+ if (this.snapShot == null) >+ return RESTART; >+ >+ this.copyState(this.snapShot); >+ if (atCompletionSite) { >+ this.currentToken = TokenNameSEMICOLON; >+ shouldStackAssistNode(); >+ return RESUME; >+ } >+ this.currentToken = this.scanner.fastForward(unused); >+ return RESUME; >+ } >+ >+ public abstract int automatonState(); >+ >+ public abstract boolean automatonWillShift(int nextToken, int lastAction); >+} >+ >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..7e549c0 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 >@@ -45,7 +45,6 @@ > > import org.eclipse.jdt.core.compiler.CharOperation; > import org.eclipse.jdt.core.compiler.InvalidInputException; >-import org.eclipse.jdt.internal.codeassist.impl.AssistParser; > import org.eclipse.jdt.internal.compiler.ASTVisitor; > import org.eclipse.jdt.internal.compiler.CompilationResult; > import org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression; >@@ -159,7 +158,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; >@@ -896,7 +895,7 @@ > 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) >@@ -987,8 +986,7 @@ > protected int nextTypeStart; > protected TypeDeclaration pendingRecoveredType; > public RecoveryScanner recoveryScanner; >-//scanner token >-public Scanner scanner; >+ > protected int[] stack = new int[StackIncrement]; > protected int stateStackTop; > protected int synchronizedBlockSourceStart; >@@ -1004,7 +1002,7 @@ > // used for recovery > protected int lastJavadocEnd; > public org.eclipse.jdt.internal.compiler.ReadManager readManager; >-private int valueLambdaNestDepth = -1; >+protected int valueLambdaNestDepth = -1; > private int stateStackLengthStack[] = new int[0]; > protected boolean parsingJava8Plus; > protected int unstackedAct = ERROR_ACTION; >@@ -1013,14 +1011,7 @@ > 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 () { >+public Parser () { > // Caveat Emptor: For inheritance purposes and then only in very special needs. Only minimal state is initialized ! > } > public Parser(ProblemReporter problemReporter, boolean optimizeStringLiterals) { >@@ -2251,7 +2242,7 @@ > pushOnAstStack(block); > } > protected void consumeBlockStatement() { >- // todo. >+ // for assist parsers. > } > protected void consumeBlockStatements() { > // BlockStatements ::= BlockStatements BlockStatement >@@ -7855,17 +7846,15 @@ > pushOnIntStack(0); // signal explicit this > } > >+protected boolean isAssistParser() { >+ return false; >+} > protected void consumeNestedLambda() { > // NestedLambda ::= $empty - we get here just after the type+parenthesis elided singleton parameter or just before the '(' of the parameter list. > consumeNestedType(); > this.nestedMethod[this.nestedType] ++; >- LambdaExpression lambda = new LambdaExpression(this.compilationUnit.compilationResult, this instanceof AssistParser); >+ LambdaExpression lambda = new LambdaExpression(this.compilationUnit.compilationResult, isAssistParser()); > 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 +7885,15 @@ > } > 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.lastCheckPoint = arrowPosition + 1; >+ } > } > protected void consumeLambdaExpression() { > >@@ -7919,6 +7907,7 @@ > if (this.options.ignoreMethodBodies) { > body = new Block(0); > } >+ ((Block) body).lambdaBody = true; // for consistency's sakes. > } > > LambdaExpression lexp = (LambdaExpression) this.astStack[this.astPtr--]; >@@ -7935,10 +7924,7 @@ > } > 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; >+ this.lastCheckPoint = body.sourceEnd + 1; > } > } > >@@ -7984,9 +7970,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 >@@ -10464,7 +10448,7 @@ > 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 .... > >@@ -10797,41 +10781,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 +10809,7 @@ > > this.hasReportedError = false; > int act = START_STATE; >+ this.unstackedAct = ERROR_ACTION; > this.stateStackTop = -1; > this.currentToken = getFirstToken(); > >@@ -10866,8 +10824,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 +10836,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; >+ this.kurrentToken = this.currentToken; > switch (resumeOnSyntaxError()) { > 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.stack[this.stateStackTop--]; >+ continue ProcessTerminals; >+ } else { >+ this.currentToken = this.kurrentToken; // Gets trashed all over the place. >+ } >+ // FALL THROUGH. > } > } > if (act <= NUM_RULES) { >@@ -10914,7 +10875,6 @@ > this.recordStringLiterals = oldValue; > } > try { >- this.unstackedAct = act; > this.currentToken = this.scanner.getNextToken(); > } catch(InvalidInputException e){ > if (!this.hasReportedError){ >@@ -10924,13 +10884,11 @@ > this.lastCheckPoint = this.scanner.currentPosition; > this.currentToken = 0; > this.restartRecovery = true; >- } finally { >- this.unstackedAct = ERROR_ACTION; >- } >+ } > if(this.statementRecoveryActivated) { > jumpOverType(); > } >- act -= ERROR_ACTION; >+ this.unstackedAct = act -= ERROR_ACTION; > > if (DEBUG_AUTOMATON) { > System.out.print("Shift/Reduce - (" + name[terminal_index[this.currentToken]]+") "); //$NON-NLS-1$ //$NON-NLS-2$ >@@ -10946,7 +10904,6 @@ > this.recordStringLiterals = oldValue; > } > try{ >- this.unstackedAct = act; > this.currentToken = this.scanner.getNextToken(); > } catch(InvalidInputException e){ > if (!this.hasReportedError){ >@@ -10956,8 +10913,6 @@ > this.lastCheckPoint = this.scanner.currentPosition; > this.currentToken = 0; > this.restartRecovery = true; >- } finally { >- this.unstackedAct = ERROR_ACTION; > } > if(this.statementRecoveryActivated) { > jumpOverType(); >@@ -10978,8 +10933,9 @@ > } > > this.stateStackTop -= (rhs[act] - 1); >+ this.unstackedAct = ntAction(this.stack[this.stateStackTop], lhs[act]); > consumeRule(act); >- act = ntAction(this.stack[this.stateStackTop], lhs[act]); >+ act = this.unstackedAct; > > if (DEBUG_AUTOMATON) { > if (act <= NUM_RULES) { >@@ -10994,6 +10950,7 @@ > } > } > } finally { >+ this.unstackedAct = ERROR_ACTION; > this.scanner.setActiveParser(null); > } > >@@ -12164,8 +12121,10 @@ > 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; >@@ -12184,7 +12143,7 @@ > * Move checkpoint location, reset internal stacks and > * decide which grammar goal is activated. > */ >-protected boolean resumeAfterRecovery() { >+protected int resumeAfterRecovery() { > if(!this.methodRecoveryActivated && !this.statementRecoveryActivated) { > > // reset internal stacks >@@ -12193,18 +12152,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,14 +12172,14 @@ > > /* 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() { >@@ -12260,7 +12219,7 @@ > } > > /* attempt to reset state in order to resume to parse loop */ >- return resumeAfterRecovery() ? RESTART : HALT; >+ return resumeAfterRecovery(); > } > public void setMethodsFullRecovery(boolean enabled) { > this.options.performMethodsFullRecovery = enabled; >@@ -12368,4 +12327,96 @@ > exp.sourceEnd = this.intStack[this.intPtr--]; > exp.sourceStart = this.intStack[this.intPtr--]; > } >+public void copyState(CommitRollbackParser from) { >+ >+ Parser parser = (Parser) from; >+ >+ // 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; >+} >+ >+public int automatonState() { >+ return this.stack[this.stateStackTop]; >+} >+public 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; >+ } >+} > } >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..cc01976 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 >@@ -61,14 +61,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 > */ > public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) { >@@ -162,6 +154,10 @@ > * Record a statement declaration > */ > public RecoveredElement add(Statement stmt, int bracketBalanceValue, boolean delegatedByParent) { >+ >+ if (stmt instanceof LambdaExpression) // lambdas are recovered up to the containing statement anyways. >+ return this; >+ > resetPendingModifiers(); > > /* do not consider a nested block starting passed the block end (if set) >@@ -295,6 +291,11 @@ > > // if block was not marked to be preserved or empty, then ignore it > if (!this.preserveContent || this.statementCount == 0) return null; >+ >+ /* If this block stands for the lambda body, trash the contents. Lambda expressions are recovered as part of the enclosing statement. >+ We still have left in a block here to make sure that contained elements can be trapped and tossed out. >+ */ >+ if (this.blockDeclaration.lambdaBody) return null; > > Statement[] updatedStatements = new Statement[this.statementCount]; > int updatedCount = 0; >@@ -340,7 +341,7 @@ > Statement updatedStatement = this.statements[i].updatedStatement(depth, knownTypes); > if (updatedStatement != null){ > updatedStatements[updatedCount++] = updatedStatement; >- >+ > if (updatedStatement instanceof LocalDeclaration) { > LocalDeclaration localDeclaration = (LocalDeclaration) updatedStatement; > if(localDeclaration.declarationSourceEnd > lastEnd) { >@@ -431,6 +432,11 @@ > > // if block was closed or empty, then ignore it > if (this.blockDeclaration.sourceEnd != 0 || this.statementCount == 0) return null; >+ >+ /* If this block stands for the lambda body, trash the contents. Lambda expressions are recovered as part of the enclosing statement. >+ We still have left in a block here to make sure that contained elements can be trapped and tossed out. >+ */ >+ if (this.blockDeclaration.lambdaBody) return null; > > Statement[] updatedStatements = new Statement[this.statementCount]; > int updatedCount = 0; >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..16f0a48 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 >@@ -23,7 +19,6 @@ > 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 >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/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/Scanner.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java >index 9725ebd..c40a103 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; > >@@ -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; > } >@@ -4332,7 +4342,7 @@ > } else if (act > ERROR_ACTION) { /* shift-reduce */ > this.unstackedAct = act; > try { >- this.currentToken = this.scanner.getNextToken(); >+ this.currentToken = this.scanner.getNextToken(); > } finally { > this.unstackedAct = ERROR_ACTION; > } >@@ -4341,7 +4351,7 @@ > if (act < ACCEPT_ACTION) { /* shift */ > this.unstackedAct = act; > try { >- this.currentToken = this.scanner.getNextToken(); >+ this.currentToken = this.scanner.getNextToken(); > } finally { > this.unstackedAct = ERROR_ACTION; > } >@@ -4493,4 +4503,98 @@ > } > return token; > } >+ >+protected boolean isAtAssistIdentifier() { >+ return false; >+} >+ >+// 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: >+ if (isAtAssistIdentifier()) // do not fast forward past the assist identifier ! We don't handle collections as of now. >+ return token; >+ //$FALL-THROUGH$ >+ 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; >+ } >+ } >+} > }
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