Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 422468 | Differences between
and this patch

Collapse All | Expand All

(-)a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/CompletionParserTest18.java (-7 / +377 lines)
Lines 74-82 Link Here
74
			"  static void goo(J i) {\n" + 
74
			"  static void goo(J i) {\n" + 
75
			"  }\n" + 
75
			"  }\n" + 
76
			"  public static void main(String[] args) {\n" + 
76
			"  public static void main(String[] args) {\n" + 
77
			"    (<no type> first, <no type> second) ->     {\n" + 
77
			"    goo((<no type> first, <no type> second) -> {\n" + 
78
			"      (<no type> xyz, <no type> pqr) -> <CompleteOnName:first.>;\n" + 
78
			"  return (<no type> xyz, <no type> pqr) -> <CompleteOnName:first.>;\n" + 
79
			"    };\n" + 
79
			"});\n" + 
80
			"  }\n" + 
80
			"  }\n" + 
81
			"}\n";
81
			"}\n";
82
82
Lines 177-183 Link Here
177
	int cursorLocation = string.lastIndexOf(completeBehind) + completeBehind.length() - 1;
177
	int cursorLocation = string.lastIndexOf(completeBehind) + completeBehind.length() - 1;
178
178
179
	String expectedCompletionNodeToString = "<CompleteOnName:x>";
179
	String expectedCompletionNodeToString = "<CompleteOnName:x>";
180
	String expectedParentNodeToString = "<NONE>";
180
	String expectedParentNodeToString = "static Foo f = (<no type> x5, <no type> x6) -> {\n" +
181
										"  <CompleteOnName:x>;\n" +
182
										"};";
181
	String completionIdentifier = "x";
183
	String completionIdentifier = "x";
182
	String expectedReplacedSource = "x";
184
	String expectedReplacedSource = "x";
183
	String expectedUnitDisplayString =
185
	String expectedUnitDisplayString =
Lines 233-242 Link Here
233
			"  }\n" + 
235
			"  }\n" + 
234
			"  void go() {\n" + 
236
			"  void go() {\n" + 
235
			"    I i = (<no type> argument) ->     {\n" + 
237
			"    I i = (<no type> argument) ->     {\n" + 
236
			"      {\n" + 
238
			"      if (true)\n" + 
237
			"        if (true)\n" + 
239
			"          {\n" + 
238
			"            return <CompleteOnName:arg>;\n" + 
240
			"            return <CompleteOnName:arg>;\n" + 
239
			"      }\n" + 
241
			"          }\n" + 
240
			"    };\n" + 
242
			"    };\n" + 
241
			"  }\n" + 
243
			"  }\n" + 
242
			"}\n";
244
			"}\n";
Lines 345-348 Link Here
345
		expectedReplacedSource,
347
		expectedReplacedSource,
346
		"diet ast");
348
		"diet ast");
347
}
349
}
350
public void test0010() {
351
	String string =
352
			"interface I {\n" +
353
			"	void foo(String x);\n" +
354
			"}\n" +
355
			"public class X {\n" +
356
			"	String xField;\n" +
357
			"	static void goo(String s) {\n" +
358
			"	}\n" +
359
			"	static void goo(I i) {\n" +
360
			"	}\n" +
361
			"	public static void main(String[] args) {\n" +
362
			"		goo((xyz) -> {\n" +
363
			"			System.out.println(xyz.);\n" +
364
			"		});\n" +
365
			"	}\n" +
366
			"}\n";
367
368
	String completeBehind = "xyz.";
369
	int cursorLocation = string.lastIndexOf(completeBehind) + completeBehind.length() - 1;
370
371
	String expectedCompletionNodeToString = "<CompleteOnName:xyz.>";
372
	String expectedParentNodeToString = "System.out.println(<CompleteOnName:xyz.>)";
373
	String completionIdentifier = "";
374
	String expectedReplacedSource = "xyz.";
375
	String expectedUnitDisplayString =
376
			"interface I {\n" +
377
			"  void foo(String x);\n" +
378
			"}\n" +
379
			"public class X {\n" +
380
			"  String xField;\n" +
381
			"  public X() {\n" +
382
			"  }\n" +
383
			"  static void goo(String s) {\n" +
384
			"  }\n" +
385
			"  static void goo(I i) {\n" +
386
			"  }\n" +
387
			"  public static void main(String[] args) {\n" +
388
			"    goo((<no type> xyz) -> {\n" +
389
			"  System.out.println(<CompleteOnName:xyz.>);\n" +
390
			"});\n" +
391
			"  }\n" +
392
			"}\n";
393
394
	checkMethodParse(
395
		string.toCharArray(),
396
		cursorLocation,
397
		expectedCompletionNodeToString,
398
		expectedParentNodeToString,
399
		expectedUnitDisplayString,
400
		completionIdentifier,
401
		expectedReplacedSource,
402
		"diet ast");
403
}
404
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=417935, [1.8][code select] ICU#codeSelect doesn't work on reference to lambda parameter
405
public void test417935() {
406
	String string = 
407
			"import java.util.ArrayList;\n" +
408
			"import java.util.Arrays;\n" +
409
			"import java.util.Collections;\n" +
410
			"import java.util.Comparator;\n" +
411
			"public class X {\n" +
412
			"   int compareTo(X x) { return 0; }\n" +
413
			"	void foo() {\n" +
414
			"		Collections.sort(new ArrayList<X>(Arrays.asList(new X(), new X(), new X())),\n" +
415
			"				(X o1, X o2) -> o1.compa); //[2]\n" +
416
			"	}\n" +
417
			"}\n";
418
419
			String completeBehind = "compa";
420
			int cursorLocation = string.lastIndexOf(completeBehind) + completeBehind.length() - 1;
421
422
			String expectedCompletionNodeToString = "<CompleteOnName:o1.compa>";
423
			String expectedParentNodeToString = "<NONE>";
424
			String completionIdentifier = "compa";
425
			String expectedReplacedSource = "o1.compa";
426
			String expectedUnitDisplayString =
427
					"import java.util.ArrayList;\n" + 
428
					"import java.util.Arrays;\n" + 
429
					"import java.util.Collections;\n" + 
430
					"import java.util.Comparator;\n" + 
431
					"public class X {\n" + 
432
					"  public X() {\n" + 
433
					"  }\n" + 
434
					"  int compareTo(X x) {\n" + 
435
					"  }\n" + 
436
					"  void foo() {\n" + 
437
					"    Collections.sort(new ArrayList<X>(Arrays.asList(new X(), new X(), new X())), (X o1, X o2) -> <CompleteOnName:o1.compa>);\n" + 
438
					"  }\n" + 
439
					"}\n";
440
441
			checkMethodParse(
442
				string.toCharArray(),
443
				cursorLocation,
444
				expectedCompletionNodeToString,
445
				expectedParentNodeToString,
446
				expectedUnitDisplayString,
447
				completionIdentifier,
448
				expectedReplacedSource,
449
				"diet ast");
450
}
451
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=405126, [1.8][code assist] Lambda parameters incorrectly recovered as fields. 
452
public void test405126() {
453
	String string = 
454
			"public interface Foo { \n" +
455
			"	int run(int s1, int s2); \n" +
456
			"}\n" +
457
			"interface X {\n" +
458
			"    static Foo f = (int x5, int x11) -> x\n" +
459
			"    static int x1 = 2;\n" +
460
			"}\n" +
461
			"class C {\n" +
462
			"	void method1(){\n" +
463
			"		int p = X.\n" +
464
			"	}\n" +
465
			"}\n";
466
467
			String completeBehind = "X.";
468
			int cursorLocation = string.lastIndexOf(completeBehind) + completeBehind.length() - 1;
469
470
			String expectedCompletionNodeToString = "<CompleteOnName:X.>";
471
			String expectedParentNodeToString = "int p = <CompleteOnName:X.>;";
472
			String completionIdentifier = "";
473
			String expectedReplacedSource = "X.";
474
			String expectedUnitDisplayString =
475
					"public interface Foo {\n" + 
476
					"  int run(int s1, int s2);\n" + 
477
					"}\n" + 
478
					"interface X {\n" + 
479
					"  static Foo f;\n" + 
480
					"  static int x1;\n" + 
481
					"  <clinit>() {\n" + 
482
					"  }\n" + 
483
					"}\n" + 
484
					"class C {\n" + 
485
					"  C() {\n" + 
486
					"  }\n" + 
487
					"  void method1() {\n" + 
488
					"    int p = <CompleteOnName:X.>;\n" + 
489
					"  }\n" + 
490
					"}\n";
491
492
			checkMethodParse(
493
				string.toCharArray(),
494
				cursorLocation,
495
				expectedCompletionNodeToString,
496
				expectedParentNodeToString,
497
				expectedUnitDisplayString,
498
				completionIdentifier,
499
				expectedReplacedSource,
500
				"diet ast");
501
}
502
// Verify that locals inside a lambda block don't get promoted to the parent block.
503
public void testLocalsPromotion() {
504
	String string = 
505
			"interface I {\n" +
506
			"	void foo(int x);\n" +
507
			"}\n" +
508
			"public class X {\n" +
509
			"	static void goo(I i) {}\n" +
510
			"	public static void main(String[] args) {\n" +
511
			"       int outerLocal;\n" +
512
			"		goo ((x) -> {\n" +
513
			"			int lambdaLocal = 10;\n" +
514
			"			System.out.println(\"Statement inside lambda\");\n" +
515
			"			lam\n" +
516
			"		});\n" +
517
			"	}\n" +
518
			"}\n";
519
520
			String completeBehind = "lam";
521
			int cursorLocation = string.lastIndexOf(completeBehind) + completeBehind.length() - 1;
522
523
			String expectedCompletionNodeToString = "<CompleteOnName:lam>";
524
			String expectedParentNodeToString = "<NONE>";
525
			String completionIdentifier = "lam";
526
			String expectedReplacedSource = "lam";
527
			String expectedUnitDisplayString =
528
					"interface I {\n" + 
529
					"  void foo(int x);\n" + 
530
					"}\n" + 
531
					"public class X {\n" + 
532
					"  public X() {\n" + 
533
					"  }\n" + 
534
					"  static void goo(I i) {\n" + 
535
					"  }\n" + 
536
					"  public static void main(String[] args) {\n" + 
537
					"    int outerLocal;\n" + 
538
					"    goo((<no type> x) -> {\n" + 
539
					"  int lambdaLocal;\n" + 
540
					"  System.out.println(\"Statement inside lambda\");\n" + 
541
					"  <CompleteOnName:lam>;\n" + 
542
					"});\n" + 
543
					"  }\n" + 
544
					"}\n";
545
546
			checkMethodParse(
547
				string.toCharArray(),
548
				cursorLocation,
549
				expectedCompletionNodeToString,
550
				expectedParentNodeToString,
551
				expectedUnitDisplayString,
552
				completionIdentifier,
553
				expectedReplacedSource,
554
				"diet ast");
555
}
556
557
// 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
558
public void testCompletionLocation() {
559
	String string = 
560
			"interface I {\n" +
561
			"    void doit();\n" +
562
			"}\n" +
563
			"interface J {\n" +
564
			"}\n" +
565
			"public class X { \n" +
566
			"	Object o = (I & J) () -> {};\n" +
567
			"	/* AFTER */\n" +
568
			"}\n";
569
570
			String completeBehind = "/* AFTER */";
571
			int cursorLocation = string.lastIndexOf(completeBehind) + completeBehind.length() - 1;
572
573
			String expectedCompletionNodeToString = "<CompleteOnType:>";
574
			String expectedParentNodeToString = "<NONE>";
575
			String completionIdentifier = "";
576
			String expectedReplacedSource = "";
577
			String expectedUnitDisplayString =
578
					"interface I {\n" + 
579
					"  void doit();\n" + 
580
					"}\n" + 
581
					"interface J {\n" + 
582
					"}\n" + 
583
					"public class X {\n" + 
584
					"  Object o;\n" + 
585
					"  <CompleteOnType:>;\n" + 
586
					"  public X() {\n" + 
587
					"  }\n" + 
588
					"}\n";
589
590
			checkMethodParse(
591
				string.toCharArray(),
592
				cursorLocation,
593
				expectedCompletionNodeToString,
594
				expectedParentNodeToString,
595
				expectedUnitDisplayString,
596
				completionIdentifier,
597
				expectedReplacedSource,
598
				"diet ast");
599
}
600
public void testElidedCompletion() {
601
	String string = 
602
			"class Collections {\n" +
603
			"	public static void sort(ArrayList list, Comparator c) {\n" +
604
			"	}\n" +
605
			"}\n" +
606
			"interface Comparator {\n" +
607
			"	int compareTo(X t, X s);\n" +
608
			"}\n" +
609
			"class ArrayList {\n" +
610
			"}\n" +
611
			"public class X {\n" +
612
			"	int compareTo(X x) { return 0; }\n" +
613
			"	void foo() {\n" +
614
			"		Collections.sort(new ArrayList(), (X o1, X o2) -> o1.compa);\n" +
615
			"	}\n" +
616
			"}\n";
617
618
			String completeBehind = "compa";
619
			int cursorLocation = string.lastIndexOf(completeBehind) + completeBehind.length() - 1;
620
621
			String expectedCompletionNodeToString = "<CompleteOnName:o1.compa>";
622
			String expectedParentNodeToString = "<NONE>";
623
			String completionIdentifier = "compa";
624
			String expectedReplacedSource = "o1.compa";
625
			String expectedUnitDisplayString =
626
					"class Collections {\n" + 
627
					"  Collections() {\n" + 
628
					"  }\n" + 
629
					"  public static void sort(ArrayList list, Comparator c) {\n" + 
630
					"  }\n" + 
631
					"}\n" + 
632
					"interface Comparator {\n" + 
633
					"  int compareTo(X t, X s);\n" + 
634
					"}\n" + 
635
					"class ArrayList {\n" + 
636
					"  ArrayList() {\n" + 
637
					"  }\n" + 
638
					"}\n" + 
639
					"public class X {\n" + 
640
					"  public X() {\n" + 
641
					"  }\n" + 
642
					"  int compareTo(X x) {\n" + 
643
					"  }\n" + 
644
					"  void foo() {\n" + 
645
					"    Collections.sort(new ArrayList(), (X o1, X o2) -> <CompleteOnName:o1.compa>);\n" + 
646
					"  }\n" + 
647
					"}\n";
648
649
			checkMethodParse(
650
				string.toCharArray(),
651
				cursorLocation,
652
				expectedCompletionNodeToString,
653
				expectedParentNodeToString,
654
				expectedUnitDisplayString,
655
				completionIdentifier,
656
				expectedReplacedSource,
657
				"diet ast");
658
}
659
public void testElidedCompletion2() {
660
	String string = 
661
			"class Collections {\n" +
662
			"	public static void sort(ArrayList list, Comparator c) {\n" +
663
			"	}\n" +
664
			"}\n" +
665
			"interface Comparator {\n" +
666
			"	int compareTo(X t, X s);\n" +
667
			"}\n" +
668
			"class ArrayList {\n" +
669
			"}\n" +
670
			"public class X {\n" +
671
			"	int compareTo(X x) { return 0; }\n" +
672
			"	void foo() {\n" +
673
			"		Collections.sort(new ArrayList(), (o1, o2) -> o1.compa);\n" +
674
			"	}\n" +
675
			"}\n";
676
677
			String completeBehind = "compa";
678
			int cursorLocation = string.lastIndexOf(completeBehind) + completeBehind.length() - 1;
679
680
			String expectedCompletionNodeToString = "<CompleteOnName:o1.compa>";
681
			String expectedParentNodeToString = "<NONE>";
682
			String completionIdentifier = "compa";
683
			String expectedReplacedSource = "o1.compa";
684
			String expectedUnitDisplayString =
685
					"class Collections {\n" + 
686
					"  Collections() {\n" + 
687
					"  }\n" + 
688
					"  public static void sort(ArrayList list, Comparator c) {\n" + 
689
					"  }\n" + 
690
					"}\n" + 
691
					"interface Comparator {\n" + 
692
					"  int compareTo(X t, X s);\n" + 
693
					"}\n" + 
694
					"class ArrayList {\n" + 
695
					"  ArrayList() {\n" + 
696
					"  }\n" + 
697
					"}\n" + 
698
					"public class X {\n" + 
699
					"  public X() {\n" + 
700
					"  }\n" + 
701
					"  int compareTo(X x) {\n" + 
702
					"  }\n" + 
703
					"  void foo() {\n" + 
704
					"    Collections.sort(new ArrayList(), (<no type> o1, <no type> o2) -> <CompleteOnName:o1.compa>);\n" + 
705
					"  }\n" + 
706
					"}\n";
707
708
			checkMethodParse(
709
				string.toCharArray(),
710
				cursorLocation,
711
				expectedCompletionNodeToString,
712
				expectedParentNodeToString,
713
				expectedUnitDisplayString,
714
				completionIdentifier,
715
				expectedReplacedSource,
716
				"diet ast");
717
}
348
}
718
}
(-)a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/CompletionRecoveryTest.java (-2 lines)
Lines 1071-1078 Link Here
1071
		"        e.gc.setLineCap(<CompleteOnName:SWT.CAP_>);\n" + 
1071
		"        e.gc.setLineCap(<CompleteOnName:SWT.CAP_>);\n" + 
1072
		"      }\n" + 
1072
		"      }\n" + 
1073
		"    };\n" + 
1073
		"    };\n" + 
1074
		"    new ControlAdapter() {\n" + 
1075
		"    };\n" + 
1076
		"  }\n" + 
1074
		"  }\n" + 
1077
		"}\n",
1075
		"}\n",
1078
		// expectedCompletionIdentifier:
1076
		// expectedCompletionIdentifier:
(-)a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunOnlyAssistTests18.java (+69 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2013 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * This is an implementation of an early-draft specification developed under the Java
9
 * Community Process (JCP) and is made available for testing and evaluation purposes
10
 * only. The code is not compatible with any specification of the JCP.
11
 *
12
 * Contributors:
13
 *     IBM Corporation - initial API and implementation
14
 *******************************************************************************/
15
package org.eclipse.jdt.core.tests;
16
17
import java.lang.reflect.InvocationTargetException;
18
import java.lang.reflect.Method;
19
20
import junit.framework.Test;
21
import junit.framework.TestCase;
22
import junit.framework.TestSuite;
23
24
import org.eclipse.jdt.core.tests.compiler.parser.CompletionParserTest18;
25
import org.eclipse.jdt.core.tests.model.CompletionTests18;
26
import org.eclipse.jdt.core.tests.model.ResolveTests18;
27
28
public class RunOnlyAssistTests18 extends TestCase {
29
	
30
	public RunOnlyAssistTests18(String name) {
31
		super(name);
32
	}
33
	public static Class[] getAllTestClasses() {
34
		return new Class[] {
35
			ResolveTests18.class,
36
			CompletionParserTest18.class,
37
			CompletionTests18.class,
38
		};
39
	}
40
	
41
	public static Test suite() {
42
		TestSuite ts = new TestSuite(RunOnlyAssistTests18.class.getName());
43
44
		Class[] testClasses = getAllTestClasses();
45
		addTestsToSuite(ts, testClasses);
46
		return ts;
47
	}
48
	public static void addTestsToSuite(TestSuite suite, Class[] testClasses) {
49
50
		for (int i = 0; i < testClasses.length; i++) {
51
			Class testClass = testClasses[i];
52
			// call the suite() method and add the resulting suite to the suite
53
			try {
54
				Method suiteMethod = testClass.getDeclaredMethod("suite", new Class[0]); //$NON-NLS-1$
55
				Test test = (Test)suiteMethod.invoke(null, new Object[0]);
56
				suite.addTest(test);
57
			} catch (IllegalAccessException e) {
58
				e.printStackTrace();
59
			} catch (InvocationTargetException e) {
60
				e.getTargetException().printStackTrace();
61
			} catch (NoSuchMethodException e) {
62
				e.printStackTrace();
63
			}
64
		}
65
	}
66
	protected void tearDown() throws Exception {
67
		super.tearDown();
68
	}
69
}
(-)a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java (-27 / +119 lines)
Lines 115-126 Link Here
115
	int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
115
	int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
116
	this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
116
	this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
117
	assertResults(
117
	assertResults(
118
			// INTERIM RESULTS, WILL FAIL ONCE ELIDED TYPE IS CORRECTLY INFERRED.
119
			"clone[METHOD_REF]{clone(), Ljava.lang.Object;, ()Ljava.lang.Object;, clone, null, 35}\n" +
118
			"clone[METHOD_REF]{clone(), Ljava.lang.Object;, ()Ljava.lang.Object;, clone, null, 35}\n" +
120
			"equals[METHOD_REF]{equals(), Ljava.lang.Object;, (Ljava.lang.Object;)Z, equals, (obj), 35}\n" +
119
			"equals[METHOD_REF]{equals(), Ljava.lang.Object;, (Ljava.lang.Object;)Z, equals, (obj), 35}\n" +
121
			"finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, finalize, null, 35}\n" +
120
			"finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, finalize, null, 35}\n" +
122
			"getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class<+Ljava.lang.Object;>;, getClass, null, 35}\n" +
121
			"getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class<+Ljava.lang.Object;>;, getClass, null, 35}\n" +
123
			"hashCode[METHOD_REF]{hashCode(), Ljava.lang.Object;, ()I, hashCode, null, 35}\n" +
122
			"hashCode[METHOD_REF]{hashCode(), Ljava.lang.Object;, ()I, hashCode, null, 35}\n" +
123
			"length[METHOD_REF]{length(), Ljava.lang.String;, ()I, length, null, 35}\n" +
124
			"notify[METHOD_REF]{notify(), Ljava.lang.Object;, ()V, notify, null, 35}\n" +
124
			"notify[METHOD_REF]{notify(), Ljava.lang.Object;, ()V, notify, null, 35}\n" +
125
			"notifyAll[METHOD_REF]{notifyAll(), Ljava.lang.Object;, ()V, notifyAll, null, 35}\n" +
125
			"notifyAll[METHOD_REF]{notifyAll(), Ljava.lang.Object;, ()V, notifyAll, null, 35}\n" +
126
			"toString[METHOD_REF]{toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, 35}\n" +
126
			"toString[METHOD_REF]{toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, 35}\n" +
Lines 331-342 Link Here
331
			"toString[METHOD_DECLARATION]{public String toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, 27}",
331
			"toString[METHOD_DECLARATION]{public String toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, 27}",
332
			requestor.getResults());
332
			requestor.getResults());
333
}
333
}
334
public void _test010() throws JavaModelException {
334
public void test010() throws JavaModelException {
335
	this.workingCopies = new ICompilationUnit[1];
335
	this.workingCopies = new ICompilationUnit[1];
336
	this.workingCopies[0] = getWorkingCopy(
336
	this.workingCopies[0] = getWorkingCopy(
337
			"/Completion/src/X.java",
337
			"/Completion/src/X.java",
338
			"interface I {\n" +
338
			"interface I {\n" +
339
			"  String foo(String x, Integer i); \n" +
339
			"  String foo(X x, X i); \n" +
340
			"} \n" +
340
			"} \n" +
341
			"public class X  {\n" +
341
			"public class X  {\n" +
342
			"	static void goo(I i) {\n" +
342
			"	static void goo(I i) {\n" +
Lines 358-386 Link Here
358
	int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
358
	int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
359
	this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
359
	this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
360
	assertResults(
360
	assertResults(
361
			"[POTENTIAL_METHOD_DECLARATION]{, LX;, ()V, , null, 14}\n" +
361
			"goo[METHOD_REF]{goo(), LX;, (LI;)V, goo, (i), 24}\n" +
362
			"abstract[KEYWORD]{abstract, null, null, abstract, null, 24}\n" +
362
			"goo[METHOD_REF]{goo(), LX;, (Ljava.lang.String;)V, goo, (s), 24}\n" +
363
			"class[KEYWORD]{class, null, null, class, null, 24}\n" +
363
			"main[METHOD_REF]{main(), LX;, ([Ljava.lang.String;)V, main, (args), 24}\n" +
364
			"enum[KEYWORD]{enum, null, null, enum, null, 24}\n" +
364
			"clone[METHOD_REF]{clone(), Ljava.lang.Object;, ()Ljava.lang.Object;, clone, null, 35}\n" +
365
			"final[KEYWORD]{final, null, null, final, null, 24}\n" +
365
			"equals[METHOD_REF]{equals(), Ljava.lang.Object;, (Ljava.lang.Object;)Z, equals, (obj), 35}\n" +
366
			"interface[KEYWORD]{interface, null, null, interface, null, 24}\n" +
366
			"finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, finalize, null, 35}\n" +
367
			"native[KEYWORD]{native, null, null, native, null, 24}\n" +
367
			"getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class<+Ljava.lang.Object;>;, getClass, null, 35}\n" +
368
			"private[KEYWORD]{private, null, null, private, null, 24}\n" +
368
			"hashCode[METHOD_REF]{hashCode(), Ljava.lang.Object;, ()I, hashCode, null, 35}\n" +
369
			"protected[KEYWORD]{protected, null, null, protected, null, 24}\n" +
369
			"notify[METHOD_REF]{notify(), Ljava.lang.Object;, ()V, notify, null, 35}\n" +
370
			"public[KEYWORD]{public, null, null, public, null, 24}\n" +
370
			"notifyAll[METHOD_REF]{notifyAll(), Ljava.lang.Object;, ()V, notifyAll, null, 35}\n" +
371
			"static[KEYWORD]{static, null, null, static, null, 24}\n" +
371
			"toString[METHOD_REF]{toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, 35}\n" +
372
			"strictfp[KEYWORD]{strictfp, null, null, strictfp, null, 24}\n" +
372
			"wait[METHOD_REF]{wait(), Ljava.lang.Object;, ()V, wait, null, 35}\n" +
373
			"synchronized[KEYWORD]{synchronized, null, null, synchronized, null, 24}\n" +
373
			"wait[METHOD_REF]{wait(), Ljava.lang.Object;, (J)V, wait, (millis), 35}\n" +
374
			"transient[KEYWORD]{transient, null, null, transient, null, 24}\n" +
374
			"wait[METHOD_REF]{wait(), Ljava.lang.Object;, (JI)V, wait, (millis, nanos), 35}",
375
			"volatile[KEYWORD]{volatile, null, null, volatile, null, 24}\n" +
376
			"I[TYPE_REF]{I, , LI;, null, null, 27}\n" +
377
			"J[TYPE_REF]{J, , LJ;, null, null, 27}\n" +
378
			"X[TYPE_REF]{X, , LX;, null, null, 27}\n" +
379
			"clone[METHOD_DECLARATION]{protected Object clone() throws CloneNotSupportedException, Ljava.lang.Object;, ()Ljava.lang.Object;, clone, null, 27}\n" +
380
			"equals[METHOD_DECLARATION]{public boolean equals(Object obj), Ljava.lang.Object;, (Ljava.lang.Object;)Z, equals, (obj), 27}\n" +
381
			"finalize[METHOD_DECLARATION]{protected void finalize() throws Throwable, Ljava.lang.Object;, ()V, finalize, null, 27}\n" +
382
			"hashCode[METHOD_DECLARATION]{public int hashCode(), Ljava.lang.Object;, ()I, hashCode, null, 27}\n" +
383
			"toString[METHOD_DECLARATION]{public String toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, 27}",
384
			requestor.getResults());
375
			requestor.getResults());
385
}
376
}
386
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=422901, [1.8][code assist] Code assistant sensitive to scope.referenceContext type identity.
377
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=422901, [1.8][code assist] Code assistant sensitive to scope.referenceContext type identity.
Lines 570-576 Link Here
570
			"	public static void main(String[] args) {\n" +
561
			"	public static void main(String[] args) {\n" +
571
			"			I i = () -> {\n" +
562
			"			I i = () -> {\n" +
572
			"               xyz\n" +
563
			"               xyz\n" +
573
			"			}\n" +
564
			"	}\n" +
574
			"	}\n" +
565
			"	}\n" +
575
			"}\n");
566
			"}\n");
576
567
Lines 597-600 Link Here
597
			"	goo() {key=LX;.goo()LX;} [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]],\n" +
588
			"	goo() {key=LX;.goo()LX;} [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]],\n" +
598
			"}" , requestor.getContext());
589
			"}" , requestor.getContext());
599
}
590
}
591
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=422468, [1.8][assist] Code assist issues with type elided lambda parameters
592
public void test018() throws JavaModelException { // computing visible elements in lambda scope.
593
	this.workingCopies = new ICompilationUnit[1];
594
	this.workingCopies[0] = getWorkingCopy(
595
			"/Completion/src/X.java",
596
			"interface I {\n" +
597
			"	void foo(String x);\n" +
598
			"}\n" +
599
			"public class X {\n" +
600
			"	static X xField;\n" +
601
			"	static X goo(String s) {\n" +
602
			"       return null;\n" +
603
			"	}\n" +
604
			"	static void goo(I i) {\n" +
605
			"	}\n" +
606
			"	public static void main(String[] args) {\n" +
607
			"		goo((xyz) -> {\n" +
608
			"			System.out.println(xyz.);\n" +
609
			"		});\n" +
610
			"	}\n" +
611
			"}\n");
612
613
	CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true, true, true, false);
614
	requestor.allowAllRequiredProposals();
615
	requestor.setRequireExtendedContext(true);
616
	requestor.setComputeEnclosingElement(false);
617
	requestor.setComputeVisibleElements(true);
618
	requestor.setAssignableType("LX;");
619
	
620
	String str = this.workingCopies[0].getSource();
621
	String completeBehind = "xyz.";
622
	int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
623
	this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
624
	assertEquals("completion offset=233\n" +
625
			"completion range=[233, 232]\n" +
626
			"completion token=\"\"\n" +
627
			"completion token kind=TOKEN_KIND_NAME\n" +
628
			"expectedTypesSignatures=null\n" +
629
			"expectedTypesKeys=null\n" +
630
			"completion token location=UNKNOWN\n" +
631
			"visibleElements={\n" +
632
			"	xField {key=LX;.xField)LX;} [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]],\n" +
633
			"	goo(String) {key=LX;.goo(Ljava/lang/String;)LX;} [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]],\n" +
634
			"}" , requestor.getContext());
635
}
636
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=422468, [1.8][assist] Code assist issues with type elided lambda parameters
637
public void test018a() throws JavaModelException { // computing visible elements in lambda scope.
638
	this.workingCopies = new ICompilationUnit[1];
639
	this.workingCopies[0] = getWorkingCopy(
640
			"/Completion/src/X.java",
641
			"interface I {\n" +
642
			"	void foo(X x);\n" +
643
			"}\n" +
644
			"public class X {\n" +
645
			"	static X xField;\n" +
646
			"	static X goo(String s) {\n" +
647
			"       return null;\n" +
648
			"	}\n" +
649
			"	static void goo(I i) {\n" +
650
			"	}\n" +
651
			"	public static void main(String[] args) {\n" +
652
			"       X xLocal = null;\n" +
653
			"       args = null;\n" +
654
			"       if (args != null) {\n" +
655
			"           xField = null;\n" +
656
			"       else \n" +
657
			"           xField = null;\n" +
658
			"       while (true);\n" +
659
			"		goo((xyz) -> {\n" +
660
			"           X xLambdaLocal = null;\n" +
661
			"			System.out.println(xyz.)\n" +
662
			"		});\n" +
663
			"	}\n" +
664
			"}\n");
665
666
	CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true, true, true, false);
667
	requestor.allowAllRequiredProposals();
668
	requestor.setRequireExtendedContext(true);
669
	requestor.setComputeEnclosingElement(false);
670
	requestor.setComputeVisibleElements(true);
671
	requestor.setAssignableType("LX;");
672
	
673
	String str = this.workingCopies[0].getSource();
674
	String completeBehind = "xyz.";
675
	int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
676
	this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
677
	assertEquals(
678
			"completion offset=419\n" +
679
			"completion range=[419, 418]\n" +
680
			"completion token=\"\"\n" +
681
			"completion token kind=TOKEN_KIND_NAME\n" +
682
			"expectedTypesSignatures=null\n" +
683
			"expectedTypesKeys=null\n" +
684
			"completion token location=UNKNOWN\n" +
685
			"visibleElements={\n" +
686
			"	xLocal [in main(String[]) [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]]],\n" +
687
	        "	xLambdaLocal [in main(String[]) [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]]],\n" +
688
			"	xField {key=LX;.xField)LX;} [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]],\n" +
689
			"	goo(String) {key=LX;.goo(Ljava/lang/String;)LX;} [in X [in [Working copy] X.java [in <default> [in src [in Completion]]]]],\n" +
690
			"}" , requestor.getContext());
691
}
600
}
692
}
(-)a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java (-11 / +112 lines)
Lines 1349-1368 Link Here
1349
	}
1349
	}
1350
}
1350
}
1351
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=417935, [1.8][code select] ICU#codeSelect doesn't work on reference to lambda parameter
1351
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=417935, [1.8][code select] ICU#codeSelect doesn't work on reference to lambda parameter
1352
public void test417935() throws JavaModelException {
1352
public void test417935() throws JavaModelException {  // JCL_MIN does not have the relevant classes - these are needed to handle lambda. Use local versions.
1353
	this.wc = getWorkingCopy(
1353
	this.wc = getWorkingCopy(
1354
			"/Resolve/src/X.java",
1354
			"/Resolve/src/X.java",
1355
			"import java.util.ArrayList;\n" +
1355
			"class Collections {\n" +
1356
			"import java.util.Arrays;\n" +
1356
			"	public static void sort(ArrayList list, Comparator c) {\n" +
1357
			"import java.util.Collections;\n" +
1358
			"import java.util.Comparator;\n" +
1359
			"public class X {\n" +
1360
			"   int compareTo(X x) { return 0; }\n" +
1361
			"	void foo() {\n" +
1362
			"		Collections.sort(new ArrayList<X>(Arrays.asList(new X(), new X(), new X())),\n" +
1363
			"				(X o1, X o2) -> o1.compareTo(o2)); //[2]\n" +
1364
			"	}\n" +
1357
			"	}\n" +
1365
			"\n" +
1358
			"}\n" +
1359
			"interface Comparator {\n" +
1360
			"	int compareTo(X t, X s);\n" +
1361
			"}\n" +
1362
			"class ArrayList {\n" +
1363
			"}\n" +
1364
			"public class X {\n" +
1365
			"	int compareTo(X x) { return 0; }\n" +
1366
			"	void foo() {\n" +
1367
			"		Collections.sort(new ArrayList(), (X o1, X o2) -> o1.compareTo(o2));\n" +
1366
			"	}\n" +
1368
			"	}\n" +
1367
			"}\n");
1369
			"}\n");
1368
1370
Lines 1531-1534 Link Here
1531
		elements
1533
		elements
1532
	);
1534
	);
1533
}
1535
}
1536
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=422468, [1.8][assist] Code assist issues with type elided lambda parameters
1537
public void test422468d() throws JavaModelException {
1538
	this.wc = getWorkingCopy(
1539
			"/Resolve/src/X.java",
1540
			"interface I {\n" +
1541
			"	J foo(String x, String y);\n" +
1542
			"}\n" +
1543
			"interface J {\n" +
1544
			"	K foo(String x, String y);\n" +
1545
			"}\n" +
1546
			"interface K {\n" +
1547
			"	int foo(String x, int y);\n" +
1548
			"}\n" +
1549
			"public class X {\n" +
1550
			"	static void goo(K i) {}\n" +
1551
			"	public static void main(String[] args) {\n" +
1552
			"		I i = (x, y) -> { return (a, b) -> (p, q) -> a.length(); };\n" +
1553
			"	}\n" +
1554
			"}\n");
1555
1556
	String str = this.wc.getSource();
1557
	String selection = "a.length";
1558
	int start = str.lastIndexOf(selection);
1559
	int length = selection.length();
1560
1561
	IJavaElement[] elements = this.wc.codeSelect(start, length);
1562
	assertElementsEqual(
1563
		"Unexpected elements",
1564
		"length() [in String [in String.class [in java.lang [in "+ getExternalPath() + "jclMin1.8.jar]]]]",
1565
		elements
1566
	);
1567
}
1568
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=422468, [1.8][assist] Code assist issues with type elided lambda parameters
1569
public void test422468e() throws JavaModelException {
1570
	this.wc = getWorkingCopy(
1571
			"/Resolve/src/X.java",
1572
			"interface I {\n" +
1573
			"	J foo(String x, String y);\n" +
1574
			"}\n" +
1575
			"interface J {\n" +
1576
			"	K foo(String x, String y);\n" +
1577
			"}\n" +
1578
			"interface K {\n" +
1579
			"	int foo(String x, int y);\n" +
1580
			"}\n" +
1581
			"public class X {\n" +
1582
			"	static void goo(K i) {}\n" +
1583
			"	public static void main(String[] args) {\n" +
1584
			"		I i = (x, y) -> { return (a, b) -> (p, q) -> a.length(); };\n" +
1585
			"	}\n" +
1586
			"}\n");
1587
1588
	String str = this.wc.getSource();
1589
	String selection = "q";
1590
	int start = str.lastIndexOf(selection);
1591
	int length = selection.length();
1592
1593
	IJavaElement[] elements = this.wc.codeSelect(start, length);
1594
	assertElementsEqual(
1595
		"Unexpected elements",
1596
		"q [in main(String[]) [in X [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]",
1597
		elements
1598
	);
1599
}
1600
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=422468, [1.8][assist] Code assist issues with type elided lambda parameters
1601
public void testParser() throws JavaModelException {
1602
	this.wc = getWorkingCopy(
1603
			"/Resolve/src/X.java",
1604
			"interface I {\n" +
1605
			"	int foo(String x, Integer y);\n" +
1606
			"}\n" +
1607
			"public class X {\n" +
1608
			"	public static void main(String[] args) {\n" +
1609
			"		I i = (x, y) -> {\n" +
1610
			"			x = \"Hello\"\n" +
1611
			"			y = 10;		\n" +
1612
			"			if (x.length() > y) {\n" +
1613
			"				System.out.println(\"if\");\n" +
1614
			"			} else {\n" +
1615
			"				System.out.println(\"else\");\n" +
1616
			"			}\n" +
1617
			"			return x.length();\n" +
1618
			"		};\n" +
1619
			"		// System.out.println((I) (p, q) -> { return q.\n" +
1620
			"	}\n" +
1621
			"}\n");
1622
1623
	String str = this.wc.getSource();
1624
	String selection = "x";
1625
	int start = str.lastIndexOf(selection);
1626
	int length = selection.length();
1627
1628
	IJavaElement[] elements = this.wc.codeSelect(start, length);
1629
	assertElementsEqual(
1630
		"Unexpected elements",
1631
		"x [in main(String[]) [in X [in [Working copy] X.java [in <default> [in src [in Resolve]]]]]]",
1632
		elements
1633
	);
1634
}
1534
}
1635
}
(-)a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java (-7 / +61 lines)
Lines 31-37 Link Here
31
import org.eclipse.jdt.internal.compiler.*;
31
import org.eclipse.jdt.internal.compiler.*;
32
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
32
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
33
import org.eclipse.jdt.internal.compiler.env.*;
33
import org.eclipse.jdt.internal.compiler.env.*;
34
35
import org.eclipse.jdt.internal.compiler.ast.*;
34
import org.eclipse.jdt.internal.compiler.ast.*;
36
import org.eclipse.jdt.internal.compiler.parser.*;
35
import org.eclipse.jdt.internal.compiler.parser.*;
37
import org.eclipse.jdt.internal.compiler.problem.*;
36
import org.eclipse.jdt.internal.compiler.problem.*;
Lines 156-161 Link Here
156
	int labelPtr = -1;
155
	int labelPtr = -1;
157
156
158
	boolean isAlreadyAttached;
157
	boolean isAlreadyAttached;
158
	boolean shouldStackAssistNode;
159
159
160
	public boolean record = false;
160
	public boolean record = false;
161
	public boolean skipRecord = false;
161
	public boolean skipRecord = false;
Lines 614-620 Link Here
614
public Object becomeSimpleParser() {
614
public Object becomeSimpleParser() {
615
	CompletionScanner completionScanner = (CompletionScanner)this.scanner;
615
	CompletionScanner completionScanner = (CompletionScanner)this.scanner;
616
	int[] parserState = new int[] {this.cursorLocation, completionScanner.cursorLocation};
616
	int[] parserState = new int[] {this.cursorLocation, completionScanner.cursorLocation};
617
	
617
	// ??
618
	this.cursorLocation = Integer.MAX_VALUE;
618
	this.cursorLocation = Integer.MAX_VALUE;
619
	completionScanner.cursorLocation = Integer.MAX_VALUE;
619
	completionScanner.cursorLocation = Integer.MAX_VALUE;
620
	
620
	
Lines 2407-2412 Link Here
2407
	// DimWithOrWithOutExpr ::= '[' ']'
2407
	// DimWithOrWithOutExpr ::= '[' ']'
2408
	pushOnExpressionStack(null);
2408
	pushOnExpressionStack(null);
2409
}
2409
}
2410
protected void consumeEmptyStatement() {
2411
	super.consumeEmptyStatement();
2412
	/* Sneak in the assist node. The reason we can't do that when we see the assist node is that 
2413
	   we don't know whether it is the first or subsequent statement in a block to be able to
2414
	   decide whether to call contactNodeLists. See Parser.consumeBlockStatement(s) 
2415
	*/
2416
	if (this.shouldStackAssistNode) {
2417
		this.shouldStackAssistNode = false;
2418
		if (this.assistNode != null)
2419
		//	this.astStack[this.astPtr] = this.assistNodeParent != null ? this.assistNodeParent : this.assistNode;
2420
		this.astStack[this.astPtr] = this.assistNode;
2421
	}
2422
}
2410
protected void consumeEnhancedForStatement() {
2423
protected void consumeEnhancedForStatement() {
2411
	super.consumeEnhancedForStatement();
2424
	super.consumeEnhancedForStatement();
2412
2425
Lines 2580-2586 Link Here
2580
		this.cursorLocation > variable.initialization.sourceEnd) {
2593
		this.cursorLocation > variable.initialization.sourceEnd) {
2581
		variable.initialization = null;
2594
		variable.initialization = null;
2582
	} else if (this.assistNode != null && this.assistNode == variable.initialization) {
2595
	} else if (this.assistNode != null && this.assistNode == variable.initialization) {
2583
		this.assistNodeParent = variable;
2596
			this.assistNodeParent = variable;
2584
	}
2597
	}
2585
}
2598
}
2586
protected void consumeExitVariableWithoutInitialization() {
2599
protected void consumeExitVariableWithoutInitialization() {
Lines 3470-3475 Link Here
3470
					case K_MEMBER_VALUE_ARRAY_INITIALIZER:
3483
					case K_MEMBER_VALUE_ARRAY_INITIALIZER:
3471
						popElement(K_MEMBER_VALUE_ARRAY_INITIALIZER);
3484
						popElement(K_MEMBER_VALUE_ARRAY_INITIALIZER);
3472
						break;
3485
						break;
3486
					case K_LAMBDA_EXPRESSION_DELIMITER:
3487
						break; // will be popped when the containing block statement is reduced.
3473
					default:
3488
					default:
3474
						popElement(K_ARRAY_INITIALIZER);
3489
						popElement(K_ARRAY_INITIALIZER);
3475
						break;
3490
						break;
Lines 3675-3680 Link Here
3675
								break;
3690
								break;
3676
							case TokenNamedo:
3691
							case TokenNamedo:
3677
								pushOnElementStack(K_BLOCK_DELIMITER, DO);
3692
								pushOnElementStack(K_BLOCK_DELIMITER, DO);
3693
								break;
3694
							case TokenNameARROW:
3678
								break;
3695
								break;
3679
							default :
3696
							default :
3680
								pushOnElementStack(K_BLOCK_DELIMITER);
3697
								pushOnElementStack(K_BLOCK_DELIMITER);
Lines 4609-4614 Link Here
4609
	this.labelPtr = -1;
4626
	this.labelPtr = -1;
4610
	initializeForBlockStatements();
4627
	initializeForBlockStatements();
4611
}
4628
}
4629
public void copyState(CommitRollbackParser from) {
4630
4631
	super.copyState(from);
4632
	
4633
	CompletionParser parser = (CompletionParser) from;
4634
	
4635
	this.invocationType = parser.invocationType;
4636
	this.qualifier = parser.qualifier;
4637
	this.inReferenceExpression = parser.inReferenceExpression;
4638
	this.hasUnusedModifiers = parser.hasUnusedModifiers;
4639
	this.canBeExplicitConstructor = parser.canBeExplicitConstructor;
4640
}
4612
/*
4641
/*
4613
 * Initializes the state of the parser that is about to go for BlockStatements.
4642
 * Initializes the state of the parser that is about to go for BlockStatements.
4614
 */
4643
 */
Lines 4954-4959 Link Here
4954
			break;
4983
			break;
4955
	}
4984
	}
4956
}
4985
}
4986
4987
protected CommitRollbackParser createSnapShotParser() {
4988
	return new CompletionParser(this.problemReporter, this.storeSourceEnds);
4989
}
4957
/*
4990
/*
4958
 * Reset internal state after completion is over
4991
 * Reset internal state after completion is over
4959
 */
4992
 */
Lines 4977-4983 Link Here
4977
	int[] state = (int[]) parserState;
5010
	int[] state = (int[]) parserState;
4978
	
5011
	
4979
	CompletionScanner completionScanner = (CompletionScanner)this.scanner;
5012
	CompletionScanner completionScanner = (CompletionScanner)this.scanner;
4980
	
5013
	// ??
4981
	this.cursorLocation = state[0];
5014
	this.cursorLocation = state[0];
4982
	completionScanner.cursorLocation = state[1];
5015
	completionScanner.cursorLocation = state[1];
4983
}
5016
}
Lines 4988-5000 Link Here
4988
 * Move checkpoint location, reset internal stacks and
5021
 * Move checkpoint location, reset internal stacks and
4989
 * decide which grammar goal is activated.
5022
 * decide which grammar goal is activated.
4990
 */
5023
 */
4991
protected boolean resumeAfterRecovery() {
5024
protected int resumeAfterRecovery() {
4992
	this.hasUnusedModifiers = false;
5025
	this.hasUnusedModifiers = false;
4993
	if (this.assistNode != null) {
5026
	if (this.assistNode != null) {
5027
		
5028
		if (requireExtendedRecovery()) {
5029
			if (this.unstackedAct != ERROR_ACTION) {
5030
				return RESUME;
5031
			}
5032
			return super.resumeAfterRecovery();
5033
		}
5034
		
4994
		/* if reached [eof] inside method body, but still inside nested type,
5035
		/* if reached [eof] inside method body, but still inside nested type,
4995
			or inside a field initializer, should continue in diet mode until
5036
			or inside a field initializer, should continue in diet mode until
4996
			the end of the method body or compilation unit */
5037
			the end of the method body or compilation unit */
4997
		if ((this.scanner.eofPosition == this.cursorLocation+1)
5038
		if ((this.scanner.eofPosition >= this.cursorLocation+1)
4998
			&& (!(this.referenceContext instanceof CompilationUnitDeclaration)
5039
			&& (!(this.referenceContext instanceof CompilationUnitDeclaration)
4999
			|| isIndirectlyInsideFieldInitialization()
5040
			|| isIndirectlyInsideFieldInitialization()
5000
			|| this.assistNodeParent instanceof FieldDeclaration && !(this.assistNodeParent instanceof Initializer))) {
5041
			|| this.assistNodeParent instanceof FieldDeclaration && !(this.assistNodeParent instanceof Initializer))) {
Lines 5022-5027 Link Here
5022
				}
5063
				}
5023
			}
5064
			}
5024
			*/
5065
			*/
5066
5025
			/* restart in diet mode for finding sibling constructs */
5067
			/* restart in diet mode for finding sibling constructs */
5026
			if (this.currentElement instanceof RecoveredType
5068
			if (this.currentElement instanceof RecoveredType
5027
				|| this.currentElement.enclosingType() != null){
5069
				|| this.currentElement.enclosingType() != null){
Lines 5035-5041 Link Here
5035
				this.scanner.eofPosition = end < Integer.MAX_VALUE ? end + 1 : end;
5077
				this.scanner.eofPosition = end < Integer.MAX_VALUE ? end + 1 : end;
5036
			} else {
5078
			} else {
5037
				resetStacks();
5079
				resetStacks();
5038
				return false;
5080
				return HALT;
5039
			}
5081
			}
5040
		}
5082
		}
5041
	}
5083
	}
Lines 5044-5049 Link Here
5044
public void setAssistIdentifier(char[] assistIdent){
5086
public void setAssistIdentifier(char[] assistIdent){
5045
	((CompletionScanner)this.scanner).completionIdentifier = assistIdent;
5087
	((CompletionScanner)this.scanner).completionIdentifier = assistIdent;
5046
}
5088
}
5089
5090
protected void shouldStackAssistNode() {
5091
	this.shouldStackAssistNode = true;
5092
}
5093
5047
public  String toString() {
5094
public  String toString() {
5048
	StringBuffer buffer = new StringBuffer();
5095
	StringBuffer buffer = new StringBuffer();
5049
	buffer.append("elementKindStack : int[] = {"); //$NON-NLS-1$
5096
	buffer.append("elementKindStack : int[] = {"); //$NON-NLS-1$
Lines 5070-5076 Link Here
5070
5117
5071
	/* may be able to retrieve completionNode as an orphan, and then attach it */
5118
	/* may be able to retrieve completionNode as an orphan, and then attach it */
5072
	completionIdentifierCheck();
5119
	completionIdentifierCheck();
5120
	CommitRollbackParser parser = null;
5121
	if (lastIndexOfElement(K_LAMBDA_EXPRESSION_DELIMITER) >= 0) {
5122
		parser = createSnapShotParser();
5123
		parser.copyState(this);
5124
	}
5073
	attachOrphanCompletionNode();
5125
	attachOrphanCompletionNode();
5126
	if (parser != null)
5127
		this.copyState(parser);
5074
5128
5075
	// if an assist node has been found and a recovered element exists,
5129
	// if an assist node has been found and a recovered element exists,
5076
	// mark enclosing blocks as to be preserved
5130
	// mark enclosing blocks as to be preserved
(-)a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java (+10 lines)
Lines 56-61 Link Here
56
		null/*taskPriorities*/,
56
		null/*taskPriorities*/,
57
		true/*taskCaseSensitive*/);
57
		true/*taskCaseSensitive*/);
58
}
58
}
59
protected boolean isAtAssistIdentifier() {
60
	if (this.cursorLocation < this.startPosition && this.currentPosition == this.startPosition) { // fake empty identifier got issued
61
		return true;
62
	}
63
	if (this.cursorLocation+1 >= this.startPosition && this.cursorLocation < this.currentPosition) {
64
		return true;
65
	}
66
	return false;
67
}
59
/*
68
/*
60
 * Truncate the current identifier if it is containing the cursor location. Since completion is performed
69
 * Truncate the current identifier if it is containing the cursor location. Since completion is performed
61
 * on an identifier prefix.
70
 * on an identifier prefix.
Lines 199-204 Link Here
199
					this.currentPosition = this.startPosition; // for being detected as empty free identifier
208
					this.currentPosition = this.startPosition; // for being detected as empty free identifier
200
					return TokenNameIdentifier;
209
					return TokenNameIdentifier;
201
				}
210
				}
211
				this.currentPosition = this.startPosition; // fake EOF should not drown the real next token.
202
				return TokenNameEOF;
212
				return TokenNameEOF;
203
			}
213
			}
204
214
(-)a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java (-43 / +167 lines)
Lines 19-24 Link Here
19
 *
19
 *
20
 */
20
 */
21
21
22
import org.eclipse.jdt.internal.codeassist.complete.CompletionOnKeyword2;
22
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
23
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
23
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
24
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
24
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
25
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
Lines 44-49 Link Here
44
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
45
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
45
import org.eclipse.jdt.internal.compiler.lookup.Binding;
46
import org.eclipse.jdt.internal.compiler.lookup.Binding;
46
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
47
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
48
import org.eclipse.jdt.internal.compiler.parser.CommitRollbackParser;
47
import org.eclipse.jdt.internal.compiler.parser.Parser;
49
import org.eclipse.jdt.internal.compiler.parser.Parser;
48
import org.eclipse.jdt.internal.compiler.parser.RecoveredBlock;
50
import org.eclipse.jdt.internal.compiler.parser.RecoveredBlock;
49
import org.eclipse.jdt.internal.compiler.parser.RecoveredElement;
51
import org.eclipse.jdt.internal.compiler.parser.RecoveredElement;
Lines 58-63 Link Here
58
public abstract class AssistParser extends Parser {
60
public abstract class AssistParser extends Parser {
59
	public ASTNode assistNode;
61
	public ASTNode assistNode;
60
	public boolean isOrphanCompletionNode;
62
	public boolean isOrphanCompletionNode;
63
	private boolean resumedAfterRepair = false;
61
	// last modifiers info
64
	// last modifiers info
62
	protected int lastModifiers = ClassFileConstants.AccDefault;
65
	protected int lastModifiers = ClassFileConstants.AccDefault;
63
	protected int lastModifiersStart = -1;
66
	protected int lastModifiersStart = -1;
Lines 93-99 Link Here
93
	protected static final int K_FIELD_INITIALIZER_DELIMITER = ASSIST_PARSER + 4; // whether we are inside a field initializer
96
	protected static final int K_FIELD_INITIALIZER_DELIMITER = ASSIST_PARSER + 4; // whether we are inside a field initializer
94
	protected static final int K_ATTRIBUTE_VALUE_DELIMITER = ASSIST_PARSER + 5; // whether we are inside a annotation attribute valuer
97
	protected static final int K_ATTRIBUTE_VALUE_DELIMITER = ASSIST_PARSER + 5; // whether we are inside a annotation attribute valuer
95
	protected static final int K_ENUM_CONSTANT_DELIMITER = ASSIST_PARSER + 6; // whether we are inside a field initializer
98
	protected static final int K_ENUM_CONSTANT_DELIMITER = ASSIST_PARSER + 6; // whether we are inside a field initializer
96
99
	protected static final int K_LAMBDA_EXPRESSION_DELIMITER = ASSIST_PARSER + 7; // whether we are inside a lambda expression
100
	
97
	// selector constants
101
	// selector constants
98
	protected static final int THIS_CONSTRUCTOR = -1;
102
	protected static final int THIS_CONSTRUCTOR = -1;
99
	protected static final int SUPER_CONSTRUCTOR = -2;
103
	protected static final int SUPER_CONSTRUCTOR = -2;
Lines 101-109 Link Here
101
	// enum constant constants
105
	// enum constant constants
102
	protected static final int NO_BODY = 0;
106
	protected static final int NO_BODY = 0;
103
	protected static final int WITH_BODY = 1;
107
	protected static final int WITH_BODY = 1;
108
	
109
	protected static final int EXPRESSION_BODY = 0;
110
	protected static final int BLOCK_BODY = 1;
104
111
105
	protected boolean isFirst = false;
112
	protected boolean isFirst = false;
106
	protected boolean lambdaNeedsClosure = false; // :)
113
107
114
108
public AssistParser(ProblemReporter problemReporter) {
115
public AssistParser(ProblemReporter problemReporter) {
109
	super(problemReporter, true);
116
	super(problemReporter, true);
Lines 112-119 Link Here
112
	setMethodsFullRecovery(false);
119
	setMethodsFullRecovery(false);
113
	setStatementsRecovery(false);
120
	setStatementsRecovery(false);
114
}
121
}
122
115
public abstract char[] assistIdentifier();
123
public abstract char[] assistIdentifier();
116
124
125
public void copyState(CommitRollbackParser from) {
126
	
127
	super.copyState(from);
128
129
	AssistParser parser = (AssistParser) from;
130
	
131
	this.previousToken = parser.previousToken;
132
	this.previousIdentifierPtr = parser.previousIdentifierPtr;
133
	
134
	this.lastModifiers = parser.lastModifiers;
135
	this.lastModifiersStart = parser.lastModifiersStart;
136
	
137
	this.bracketDepth = parser.bracketDepth;
138
	this.elementPtr = parser.elementPtr;
139
	
140
	int length;
141
	System.arraycopy(parser.blockStarts, 0, this.blockStarts = new int [length = parser.blockStarts.length], 0, length);
142
	System.arraycopy(parser.elementKindStack, 0, this.elementKindStack = new int [length = parser.elementKindStack.length], 0, length);
143
	System.arraycopy(parser.elementInfoStack, 0, this.elementInfoStack = new int [length = parser.elementInfoStack.length], 0, length);
144
	System.arraycopy(parser.elementObjectInfoStack, 0, this.elementObjectInfoStack = new Object [length = parser.elementObjectInfoStack.length], 0, length);
145
	
146
	this.previousKind = parser.previousKind;
147
	this.previousInfo = parser.previousInfo;
148
	this.previousObjectInfo = parser.previousObjectInfo;
149
}
117
/**
150
/**
118
 * The parser become a simple parser which behave like a Parser
151
 * The parser become a simple parser which behave like a Parser
119
 * @return the state of the assist parser to be able to restore the assist parser state
152
 * @return the state of the assist parser to be able to restore the assist parser state
Lines 144-149 Link Here
144
		RecoveredElement element = super.buildInitialRecoveryState();
177
		RecoveredElement element = super.buildInitialRecoveryState();
145
		flushAssistState();
178
		flushAssistState();
146
		flushElementStack();
179
		flushElementStack();
180
		this.snapShot = null;
147
		return element;
181
		return element;
148
	}
182
	}
149
183
Lines 184-191 Link Here
184
	element = element.add(block, 1);
218
	element = element.add(block, 1);
185
	int blockIndex = 1;	// ignore first block start, since manually rebuilt here
219
	int blockIndex = 1;	// ignore first block start, since manually rebuilt here
186
220
187
	for(int i = 0; i <= this.astPtr; i++){
221
	ASTNode node = null, lastNode = null;
188
		ASTNode node = this.astStack[i];
222
	for (int i = 0; i <= this.astPtr; i++, lastNode = node) {
223
		node = this.astStack[i];
189
		if(node instanceof ForeachStatement && ((ForeachStatement)node).action == null) {
224
		if(node instanceof ForeachStatement && ((ForeachStatement)node).action == null) {
190
			node = ((ForeachStatement)node).elementVariable;
225
			node = ((ForeachStatement)node).elementVariable;
191
		}
226
		}
Lines 198-204 Link Here
198
					break;
233
					break;
199
				}
234
				}
200
				if (this.blockStarts[j] != lastStart){ // avoid multiple block if at same position
235
				if (this.blockStarts[j] != lastStart){ // avoid multiple block if at same position
201
					block = new Block(0);
236
					block = new Block(0, lastNode instanceof LambdaExpression);
202
					block.sourceStart = lastStart = this.blockStarts[j];
237
					block.sourceStart = lastStart = this.blockStarts[j];
203
					element = element.add(block, 1);
238
					element = element.add(block, 1);
204
				}
239
				}
Lines 277-288 Link Here
277
			}
312
			}
278
			continue;
313
			continue;
279
		}
314
		}
280
		if (node instanceof LambdaExpression) {
281
			LambdaExpression lambda = (LambdaExpression) node;
282
			element = element.add(lambda, 0);
283
			this.lastCheckPoint = lambda.sourceEnd + 1;
284
			continue;
285
		}
286
		if (this.assistNode != null && node instanceof Statement) {
315
		if (this.assistNode != null && node instanceof Statement) {
287
			Statement stmt = (Statement) node;
316
			Statement stmt = (Statement) node;
288
			if (!(stmt instanceof Expression) || ((Expression) stmt).statementExpression()) {
317
			if (!(stmt instanceof Expression) || ((Expression) stmt).statementExpression()) {
Lines 305-317 Link Here
305
	}
334
	}
306
335
307
	/* might need some extra block (after the last reduced node) */
336
	/* might need some extra block (after the last reduced node) */
337
	/* 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. */
308
	int pos = this.assistNode == null ? this.lastCheckPoint : this.assistNode.sourceStart;
338
	int pos = this.assistNode == null ? this.lastCheckPoint : this.assistNode.sourceStart;
339
	boolean createLambdaBlock = lastNode instanceof LambdaExpression && ((LambdaExpression) node).body() instanceof Block;
309
	for (int j = blockIndex; j <= this.realBlockPtr; j++){
340
	for (int j = blockIndex; j <= this.realBlockPtr; j++){
310
		if (this.blockStarts[j] >= 0) {
341
		if (this.blockStarts[j] >= 0) {
311
			if ((this.blockStarts[j] < pos) && (this.blockStarts[j] != lastStart)){ // avoid multiple block if at same position
342
			if ((this.blockStarts[j] < pos || createLambdaBlock) && (this.blockStarts[j] != lastStart)){ // avoid multiple block if at same position
312
				block = new Block(0);
343
				block = new Block(0, createLambdaBlock);
313
				block.sourceStart = lastStart = this.blockStarts[j];
344
				block.sourceStart = lastStart = this.blockStarts[j];
314
				element = element.add(block, 1);
345
				element = element.add(block, 1);
346
				createLambdaBlock = false;
315
			}
347
			}
316
		} else {
348
		} else {
317
			if ((this.blockStarts[j] < pos)){ // avoid multiple block if at same position
349
			if ((this.blockStarts[j] < pos)){ // avoid multiple block if at same position
Lines 401-427 Link Here
401
protected void consumeExplicitConstructorInvocation(int flag, int recFlag) {
433
protected void consumeExplicitConstructorInvocation(int flag, int recFlag) {
402
	super.consumeExplicitConstructorInvocation(flag, recFlag);
434
	super.consumeExplicitConstructorInvocation(flag, recFlag);
403
	popElement(K_SELECTOR);
435
	popElement(K_SELECTOR);
404
	triggerRecoveryUponLambdaClosure();
405
}
436
}
406
protected void triggerRecoveryUponLambdaClosure() {
437
407
	if (this.assistNode == null || !this.lambdaNeedsClosure)
438
protected boolean triggerRecoveryUponLambdaClosure() {
408
		return;
439
	// Last block statement reduced is required to be on the AST stack top.
409
	ASTNode node = this.astStack[this.astPtr];
440
	boolean lambdaClosed = false;
410
	if (this.assistNode.sourceStart >= node.sourceStart && this.assistNode.sourceEnd <= node.sourceEnd) {
441
	Statement statement = (Statement) this.astStack[this.astPtr];
411
		for (int i = 0; i <= this.astPtr; i++) {
442
	int statementStart, statementEnd;
412
			if (this.astStack[i] instanceof LambdaExpression)
443
	statementStart = statement.sourceStart;
413
				return;
444
	statementEnd = statement instanceof AbstractVariableDeclaration ? ((AbstractVariableDeclaration)statement).declarationSourceEnd : statement.sourceEnd;
445
	for (int i = this.elementPtr; i >= 0; --i) {
446
		if (this.elementKindStack[i] != K_LAMBDA_EXPRESSION_DELIMITER)
447
			continue;
448
		LambdaExpression expression = (LambdaExpression) this.elementObjectInfoStack[i];
449
		if (expression.sourceStart >= statementStart && expression.sourceEnd <= statementEnd) {
450
			this.elementPtr = i - 1;
451
			lambdaClosed = true;
452
		} else {
453
			int stackLength = this.stack.length;
454
			if (++this.stateStackTop >= stackLength) {
455
				System.arraycopy(
456
					this.stack, 0,
457
					this.stack = new int[stackLength + StackIncrement], 0,
458
					stackLength);
459
			}
460
			this.stack[this.stateStackTop] = this.unstackedAct;
461
			commit();
462
			this.stateStackTop --;
463
			return false;
414
		}
464
		}
415
		this.restartRecovery = true;
416
		this.isOrphanCompletionNode = false;
417
		this.lambdaNeedsClosure = false;
418
	}
465
	}
466
	
467
	if (lambdaClosed && this.currentElement != null) {
468
		this.restartRecovery = true;
469
		if (!(statement instanceof AbstractVariableDeclaration)) // added already as part of standard recovery since these contribute a name to the scope prevailing at the cursor.
470
			this.currentElement.add(statement, 0);
471
	}
472
	this.snapShot = null;
473
	return lambdaClosed;
419
}
474
}
420
protected void consumeExplicitConstructorInvocationWithTypeArguments(int flag, int recFlag) {
475
protected boolean isAssistParser() {
421
	super.consumeExplicitConstructorInvocationWithTypeArguments(flag, recFlag);
476
	return true;
477
}
478
protected void consumeBlockStatement() {
479
	super.consumeBlockStatement();
422
	triggerRecoveryUponLambdaClosure();
480
	triggerRecoveryUponLambdaClosure();
423
}
481
}
424
482
483
protected void consumeBlockStatements() {
484
	super.consumeBlockStatements();
485
	triggerRecoveryUponLambdaClosure();
486
}
487
protected void consumeFieldDeclaration() {
488
	super.consumeFieldDeclaration();
489
	if (triggerRecoveryUponLambdaClosure()) {
490
		if (this.currentElement instanceof RecoveredType)
491
			popUntilElement(K_TYPE_DELIMITER);
492
	}
493
}
425
protected void consumeForceNoDiet() {
494
protected void consumeForceNoDiet() {
426
	super.consumeForceNoDiet();
495
	super.consumeForceNoDiet();
427
	// if we are not in a method (i.e. we are not in a local variable initializer)
496
	// if we are not in a method (i.e. we are not in a local variable initializer)
Lines 444-452 Link Here
444
	super.consumeInterfaceHeader();
513
	super.consumeInterfaceHeader();
445
	pushOnElementStack(K_TYPE_DELIMITER);
514
	pushOnElementStack(K_TYPE_DELIMITER);
446
}
515
}
447
protected void consumeExpressionStatement() {
516
protected void consumeLambdaHeader() {
448
	super.consumeExpressionStatement();
517
	super.consumeLambdaHeader();
449
	triggerRecoveryUponLambdaClosure();
518
	LambdaExpression lexp = (LambdaExpression) this.astStack[this.astPtr];
519
	pushOnElementStack(K_LAMBDA_EXPRESSION_DELIMITER, EXPRESSION_BODY, lexp);
450
}
520
}
451
protected void consumeMethodBody() {
521
protected void consumeMethodBody() {
452
	super.consumeMethodBody();
522
	super.consumeMethodBody();
Lines 457-463 Link Here
457
		popElement(K_METHOD_DELIMITER);
527
		popElement(K_METHOD_DELIMITER);
458
	}
528
	}
459
	super.consumeMethodDeclaration(isNotAbstract, isDefaultMethod);
529
	super.consumeMethodDeclaration(isNotAbstract, isDefaultMethod);
460
	triggerRecoveryUponLambdaClosure();
461
}
530
}
462
protected void consumeMethodHeader() {
531
protected void consumeMethodHeader() {
463
	super.consumeMethodHeader();
532
	super.consumeMethodHeader();
Lines 517-532 Link Here
517
}
586
}
518
protected void consumeOpenBlock() {
587
protected void consumeOpenBlock() {
519
	// OpenBlock ::= $empty
588
	// OpenBlock ::= $empty
520
521
	super.consumeOpenBlock();
589
	super.consumeOpenBlock();
590
522
	int stackLength = this.blockStarts.length;
591
	int stackLength = this.blockStarts.length;
523
	if (this.realBlockPtr >= stackLength) {
592
	if (this.realBlockPtr >= stackLength) {
524
		System.arraycopy(
593
		System.arraycopy(
525
			this.blockStarts, 0,
594
				this.blockStarts, 0,
526
			this.blockStarts = new int[stackLength + StackIncrement], 0,
595
				this.blockStarts = new int[stackLength + StackIncrement], 0,
527
			stackLength);
596
				stackLength);
528
	}
597
	}
529
	this.blockStarts[this.realBlockPtr] = this.scanner.startPosition;
598
	this.blockStarts[this.realBlockPtr] = this.scanner.startPosition;
599
	if (requireExtendedRecovery()) {
600
		// This is an epsilon production: We are in the state with kernel item: Block ::= .OpenBlock LBRACE BlockStatementsopt RBRACE
601
		stackLength = this.stack.length;
602
		if (++this.stateStackTop >= stackLength - 1) {   // Need two slots.
603
			System.arraycopy(
604
				this.stack, 0,
605
				this.stack = new int[stackLength + StackIncrement], 0,
606
				stackLength);
607
		}
608
		this.stack[this.stateStackTop++] = this.unstackedAct; // transition to Block ::= OpenBlock  .LBRACE BlockStatementsopt RBRACE
609
		this.stack[this.stateStackTop] = tAction(this.unstackedAct, this.currentToken); // transition to Block ::= OpenBlock LBRACE  .BlockStatementsopt RBRACE 
610
		commit();
611
		this.stateStackTop -= 2;
612
	}
530
}
613
}
531
protected void consumeOpenFakeBlock() {
614
protected void consumeOpenFakeBlock() {
532
	// OpenBlock ::= $empty
615
	// OpenBlock ::= $empty
Lines 853-858 Link Here
853
				}
936
				}
854
				break;
937
				break;
855
			case TokenNameLBRACE:
938
			case TokenNameLBRACE:
939
				if (this.previousToken == TokenNameARROW) {
940
					popElement(K_LAMBDA_EXPRESSION_DELIMITER);
941
					pushOnElementStack(K_LAMBDA_EXPRESSION_DELIMITER, BLOCK_BODY, this.previousObjectInfo);
942
				}
856
				this.bracketDepth++;
943
				this.bracketDepth++;
857
				break;
944
				break;
858
			case TokenNameLBRACKET:
945
			case TokenNameLBRACKET:
Lines 1264-1269 Link Here
1264
	}
1351
	}
1265
	return false;
1352
	return false;
1266
}
1353
}
1354
protected boolean isIndirectlyInsideLambdaExpression(){
1355
	int i = this.elementPtr;
1356
	while (i > -1) {
1357
		if (this.elementKindStack[i] == K_LAMBDA_EXPRESSION_DELIMITER)
1358
			return true;
1359
		i--;
1360
	}
1361
	return false;
1362
}
1267
protected boolean isIndirectlyInsideType(){
1363
protected boolean isIndirectlyInsideType(){
1268
	int i = this.elementPtr;
1364
	int i = this.elementPtr;
1269
	while(i > -1) {
1365
	while(i > -1) {
Lines 1597-1602 Link Here
1597
		flushElementStack();
1693
		flushElementStack();
1598
	}
1694
	}
1599
}
1695
}
1696
1697
public boolean requireExtendedRecovery() {
1698
	if (this.assistNode instanceof TypeReference || this.assistNode instanceof CompletionOnKeyword2)
1699
		return false;
1700
	return lastIndexOfElement(K_LAMBDA_EXPRESSION_DELIMITER) >= 0;
1701
}
1702
1600
protected void pushOnElementStack(int kind){
1703
protected void pushOnElementStack(int kind){
1601
	this.pushOnElementStack(kind, 0, null);
1704
	this.pushOnElementStack(kind, 0, null);
1602
}
1705
}
Lines 1659-1665 Link Here
1659
			break;
1762
			break;
1660
		case TokenNameRBRACE :
1763
		case TokenNameRBRACE :
1661
			super.recoveryTokenCheck();
1764
			super.recoveryTokenCheck();
1662
			if(this.currentElement != oldElement && !isInsideAttributeValue()) {
1765
			if(this.currentElement != oldElement && !isInsideAttributeValue() && !isIndirectlyInsideLambdaExpression()) {
1663
				if(oldElement instanceof RecoveredInitializer
1766
				if(oldElement instanceof RecoveredInitializer
1664
					|| oldElement instanceof RecoveredMethod
1767
					|| oldElement instanceof RecoveredMethod
1665
					|| (oldElement instanceof RecoveredBlock && oldElement.parent instanceof RecoveredInitializer)
1768
					|| (oldElement instanceof RecoveredBlock && oldElement.parent instanceof RecoveredInitializer)
Lines 1691-1698 Link Here
1691
 * Move checkpoint location, reset internal stacks and
1794
 * Move checkpoint location, reset internal stacks and
1692
 * decide which grammar goal is activated.
1795
 * decide which grammar goal is activated.
1693
 */
1796
 */
1694
protected boolean resumeAfterRecovery() {
1797
protected int resumeAfterRecovery() {
1695
1798
	if (requireExtendedRecovery()) {
1799
		if (this.unstackedAct == ERROR_ACTION) {
1800
			int mode = fallBackToSpringForward((Statement) null);
1801
			this.resumedAfterRepair = mode == RESUME;
1802
			if (mode == RESUME || mode == HALT)
1803
				return mode;
1804
			// else fall through and RESTART
1805
		} else {
1806
			return RESUME;
1807
		}
1808
	}
1809
		
1696
	// reset internal stacks
1810
	// reset internal stacks
1697
	this.astPtr = -1;
1811
	this.astPtr = -1;
1698
	this.astLengthPtr = -1;
1812
	this.astLengthPtr = -1;
Lines 1700-1714 Link Here
1700
	this.expressionLengthPtr = -1;
1814
	this.expressionLengthPtr = -1;
1701
	this.typeAnnotationLengthPtr = -1;
1815
	this.typeAnnotationLengthPtr = -1;
1702
	this.typeAnnotationPtr = -1;
1816
	this.typeAnnotationPtr = -1;
1817
	
1703
	this.identifierPtr = -1;
1818
	this.identifierPtr = -1;
1704
	this.identifierLengthPtr	= -1;
1819
	this.identifierLengthPtr	= -1;
1705
	this.intPtr = -1;
1820
	this.intPtr = -1;
1821
	
1822
	
1706
	this.dimensions = 0 ;
1823
	this.dimensions = 0 ;
1707
	this.recoveredStaticInitializerStart = 0;
1824
	this.recoveredStaticInitializerStart = 0;
1708
1825
1709
	this.genericsIdentifiersLengthPtr = -1;
1826
	this.genericsIdentifiersLengthPtr = -1;
1710
	this.genericsLengthPtr = -1;
1827
	this.genericsLengthPtr = -1;
1711
	this.genericsPtr = -1;
1828
	this.genericsPtr = -1;
1829
	
1830
	this.valueLambdaNestDepth = -1;
1712
1831
1713
	this.modifiers = ClassFileConstants.AccDefault;
1832
	this.modifiers = ClassFileConstants.AccDefault;
1714
	this.modifiersSourceStart = -1;
1833
	this.modifiersSourceStart = -1;
Lines 1717-1723 Link Here
1717
	if (this.diet) this.dietInt = 0;
1836
	if (this.diet) this.dietInt = 0;
1718
1837
1719
	/* attempt to move checkpoint location */
1838
	/* attempt to move checkpoint location */
1720
	if (!moveRecoveryCheckpoint()) return false;
1839
	if (this.unstackedAct != ERROR_ACTION && this.resumedAfterRepair) {
1840
		this.scanner.ungetToken(this.currentToken);  // effectively move recovery checkpoint *backwards*.
1841
	} else {
1842
		if (!moveRecoveryCheckpoint()) return HALT;
1843
	}
1844
	this.resumedAfterRepair = false;
1721
1845
1722
	// only look for headers
1846
	// only look for headers
1723
	if (this.referenceContext instanceof CompilationUnitDeclaration
1847
	if (this.referenceContext instanceof CompilationUnitDeclaration
Lines 1738-1744 Link Here
1738
			goForHeaders();
1862
			goForHeaders();
1739
			this.diet = true; // passed this point, will not consider method bodies
1863
			this.diet = true; // passed this point, will not consider method bodies
1740
		}
1864
		}
1741
		return true;
1865
		return RESTART;
1742
	}
1866
	}
1743
	if (this.referenceContext instanceof AbstractMethodDeclaration
1867
	if (this.referenceContext instanceof AbstractMethodDeclaration
1744
		|| this.referenceContext instanceof TypeDeclaration){
1868
		|| this.referenceContext instanceof TypeDeclaration){
Lines 1750-1759 Link Here
1750
			prepareForBlockStatements();
1874
			prepareForBlockStatements();
1751
			goForBlockStatementsOrCatchHeader();
1875
			goForBlockStatementsOrCatchHeader();
1752
		}
1876
		}
1753
		return true;
1877
		return RESTART;
1754
	}
1878
	}
1755
	// does not know how to restart
1879
	// does not know how to restart
1756
	return false;
1880
	return HALT;
1757
}
1881
}
1758
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=292087
1882
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=292087
1759
// To be implemented in children viz. CompletionParser that are aware of array initializers
1883
// To be implemented in children viz. CompletionParser that are aware of array initializers
Lines 1826-1829 Link Here
1826
		return ast;
1950
		return ast;
1827
	}
1951
	}
1828
}
1952
}
1829
}
1953
}
(-)a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java (-41 / +34 lines)
Lines 40-46 Link Here
40
import org.eclipse.jdt.internal.compiler.ast.Expression;
40
import org.eclipse.jdt.internal.compiler.ast.Expression;
41
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
41
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
42
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
42
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
43
import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
44
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
43
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
45
import org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation;
44
import org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation;
46
import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
45
import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
Lines 62-67 Link Here
62
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
61
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
63
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
62
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
64
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
63
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
64
import org.eclipse.jdt.internal.compiler.parser.CommitRollbackParser;
65
import org.eclipse.jdt.internal.compiler.parser.JavadocParser;
65
import org.eclipse.jdt.internal.compiler.parser.JavadocParser;
66
import org.eclipse.jdt.internal.compiler.parser.RecoveredType;
66
import org.eclipse.jdt.internal.compiler.parser.RecoveredType;
67
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
67
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
Lines 115-122 Link Here
115
		if (orphan instanceof Expression) {
115
		if (orphan instanceof Expression) {
116
			buildMoreCompletionContext((Expression)orphan);
116
			buildMoreCompletionContext((Expression)orphan);
117
		} else {
117
		} else {
118
			Statement statement = (Statement) orphan;
118
			if (lastIndexOfElement(K_LAMBDA_EXPRESSION_DELIMITER) < 0) { // lambdas are recovered upto the containing expression statement and will carry along the assist node anyways.
119
			this.currentElement = this.currentElement.add(statement, 0);
119
				Statement statement = (Statement) orphan;
120
				this.currentElement = this.currentElement.add(statement, 0);
121
			}
120
		}
122
		}
121
		this.currentToken = 0; // given we are not on an eof, we do not want side effects caused by looked-ahead token
123
		this.currentToken = 0; // given we are not on an eof, we do not want side effects caused by looked-ahead token
122
	}
124
	}
Lines 176-187 Link Here
176
				break nextElement;
178
				break nextElement;
177
		}
179
		}
178
	}
180
	}
179
	if(parentNode != null) {
181
	// 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.
180
		this.currentElement = this.currentElement.add((Statement)parentNode, 0);
182
	if (lastIndexOfElement(K_LAMBDA_EXPRESSION_DELIMITER) < 0) {
181
	} else {
183
		if(parentNode != null) {
182
		this.currentElement = this.currentElement.add((Statement)wrapWithExplicitConstructorCallIfNeeded(expression), 0);
184
			this.currentElement = this.currentElement.add((Statement)parentNode, 0);
183
		if(this.lastCheckPoint < expression.sourceEnd) {
185
		} else {
184
			this.lastCheckPoint = expression.sourceEnd + 1;
186
			this.currentElement = this.currentElement.add((Statement)wrapWithExplicitConstructorCallIfNeeded(expression), 0);
187
			if(this.lastCheckPoint < expression.sourceEnd) {
188
				this.lastCheckPoint = expression.sourceEnd + 1;
189
			}
185
		}
190
		}
186
	}
191
	}
187
}
192
}
Lines 1184-1189 Link Here
1184
		this.restartRecovery = true; // used to avoid branching back into the regular automaton
1189
		this.restartRecovery = true; // used to avoid branching back into the regular automaton
1185
	}
1190
	}
1186
}
1191
}
1192
protected CommitRollbackParser createSnapShotParser() {
1193
	return new SelectionParser(this.problemReporter);
1194
}
1187
public ImportReference createAssistImportReference(char[][] tokens, long[] positions, int mod){
1195
public ImportReference createAssistImportReference(char[][] tokens, long[] positions, int mod){
1188
	return new SelectionOnImportReference(tokens, positions, mod);
1196
	return new SelectionOnImportReference(tokens, positions, mod);
1189
}
1197
}
Lines 1413-1440 Link Here
1413
	return super.parse(sourceUnit, compilationResult, -1, -1/*parse without reseting the scanner*/);
1421
	return super.parse(sourceUnit, compilationResult, -1, -1/*parse without reseting the scanner*/);
1414
}
1422
}
1415
1423
1416
protected int resumeOnSyntaxError() {
1417
	
1418
	if (this.referenceContext instanceof CompilationUnitDeclaration)
1419
		return super.resumeOnSyntaxError();
1420
	
1421
	// Defer initial *triggered* recovery if we see a type elided lambda expression on the stack. 
1422
	if (this.assistNode != null && this.restartRecovery) {
1423
		this.lambdaNeedsClosure = false;
1424
		for (int i = this.astPtr; i >= 0; i--) {
1425
			if (this.astStack[i] instanceof LambdaExpression) {
1426
				LambdaExpression expression = (LambdaExpression) this.astStack[i];
1427
				if (expression.argumentsTypeElided()) {
1428
					this.restartRecovery = false; // will be restarted in when the containing expression statement or explicit constructor call is reduced.
1429
					this.lambdaNeedsClosure = true;
1430
					return RESUME;
1431
				}
1432
			}
1433
		}
1434
	}
1435
	return super.resumeOnSyntaxError();
1436
}
1437
1438
/*
1424
/*
1439
 * Reset context so as to resume to regular parse loop
1425
 * Reset context so as to resume to regular parse loop
1440
 * If unable to reset for resuming, answers false.
1426
 * If unable to reset for resuming, answers false.
Lines 1442-1464 Link Here
1442
 * Move checkpoint location, reset internal stacks and
1428
 * Move checkpoint location, reset internal stacks and
1443
 * decide which grammar goal is activated.
1429
 * decide which grammar goal is activated.
1444
 */
1430
 */
1445
protected boolean resumeAfterRecovery() {
1431
protected int resumeAfterRecovery() {
1446
1432
1447
	/* if reached assist node inside method body, but still inside nested type,
1433
	/* if reached assist node inside method body, but still inside nested type,
1448
		should continue in diet mode until the end of the method body */
1434
		should continue in diet mode until the end of the method body */
1449
	if (this.assistNode != null
1435
	if (this.assistNode != null
1450
		&& !(this.referenceContext instanceof CompilationUnitDeclaration)){
1436
		&& !(this.referenceContext instanceof CompilationUnitDeclaration)){
1451
		this.currentElement.preserveEnclosingBlocks();
1437
		this.currentElement.preserveEnclosingBlocks();
1438
		if (requireExtendedRecovery()) {
1439
			if (this.unstackedAct != ERROR_ACTION) {
1440
				return RESUME;
1441
			}
1442
			return super.resumeAfterRecovery();
1443
		}
1452
		if (this.currentElement.enclosingType() == null) {
1444
		if (this.currentElement.enclosingType() == null) {
1453
			if(!(this.currentElement instanceof RecoveredType)) {
1445
			if (!(this.currentElement instanceof RecoveredType)) {
1454
				resetStacks();
1446
				resetStacks();
1455
				return false;
1447
				return HALT;
1456
	}
1448
			}
1457
1449
1458
			RecoveredType recoveredType = (RecoveredType)this.currentElement;
1450
			RecoveredType recoveredType = (RecoveredType) this.currentElement;
1459
			if(recoveredType.typeDeclaration != null && recoveredType.typeDeclaration.allocation == this.assistNode){
1451
			if (recoveredType.typeDeclaration != null && recoveredType.typeDeclaration.allocation == this.assistNode) {
1460
				resetStacks();
1452
				resetStacks();
1461
				return false;
1453
				return HALT;
1462
			}
1454
			}
1463
		}
1455
		}
1464
	}
1456
	}
Lines 1504-1518 Link Here
1504
	char[] identifierName = this.identifierStack[this.identifierPtr];
1496
	char[] identifierName = this.identifierStack[this.identifierPtr];
1505
	long namePositions = this.identifierPositionStack[this.identifierPtr--];
1497
	long namePositions = this.identifierPositionStack[this.identifierPtr--];
1506
1498
1507
	Argument arg =
1499
	Argument argument =
1508
		new SelectionOnArgumentName(
1500
		new SelectionOnArgumentName(
1509
			identifierName,
1501
			identifierName,
1510
			namePositions,
1502
			namePositions,
1511
			null, // elided type
1503
			null, // elided type
1512
			ClassFileConstants.AccDefault,
1504
			ClassFileConstants.AccDefault,
1513
			true);
1505
			true);
1514
	arg.declarationSourceStart = (int) (namePositions >>> 32);
1506
	argument.declarationSourceStart = (int) (namePositions >>> 32);
1515
	return arg;
1507
	this.assistNode = argument;
1508
	return argument;
1516
}
1509
}
1517
public  String toString() {
1510
public  String toString() {
1518
	String s = Util.EMPTY_STRING;
1511
	String s = Util.EMPTY_STRING;
(-)a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionScanner.java (+4 lines)
Lines 32-37 Link Here
32
	super(false /*comment*/, false /*whitespace*/, false /*nls*/, sourceLevel, null /*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
32
	super(false /*comment*/, false /*whitespace*/, false /*nls*/, sourceLevel, null /*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
33
}
33
}
34
34
35
protected boolean isAtAssistIdentifier() {
36
	return this.selectionStart == this.startPosition && this.selectionEnd == this.currentPosition - 1;
37
}
38
35
public char[] getCurrentIdentifierSource() {
39
public char[] getCurrentIdentifierSource() {
36
40
37
	if (this.selectionIdentifier == null){
41
	if (this.selectionIdentifier == null){
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java (+9 lines)
Lines 5-10 Link Here
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
7
 *
8
 * This is an implementation of an early-draft specification developed under the Java
9
 * Community Process (JCP) and is made available for testing and evaluation purposes
10
 * only. The code is not compatible with any specification of the JCP.
11
 * 
8
 * Contributors:
12
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
13
 *     IBM Corporation - initial API and implementation
10
 *     Stephan Herrmann - Contributions for
14
 *     Stephan Herrmann - Contributions for
Lines 27-33 Link Here
27
	public int explicitDeclarations;
31
	public int explicitDeclarations;
28
	// the number of explicit declaration , used to create scope
32
	// the number of explicit declaration , used to create scope
29
	public BlockScope scope;
33
	public BlockScope scope;
34
	public boolean lambdaBody;
30
35
36
public Block(int explicitDeclarations, boolean lambdaBody) {
37
	this.explicitDeclarations = explicitDeclarations;
38
	this.lambdaBody = lambdaBody;
39
}
31
public Block(int explicitDeclarations) {
40
public Block(int explicitDeclarations) {
32
	this.explicitDeclarations = explicitDeclarations;
41
	this.explicitDeclarations = explicitDeclarations;
33
}
42
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java (-17 / +66 lines)
Lines 71-94 Link Here
71
	private Statement body;
71
	private Statement body;
72
	public boolean hasParentheses;
72
	public boolean hasParentheses;
73
	public MethodScope scope;
73
	public MethodScope scope;
74
	private boolean voidCompatible = true;
74
	boolean voidCompatible = true;
75
	private boolean valueCompatible = false;
75
	boolean valueCompatible = false;
76
	private boolean shapeAnalysisComplete = false;
76
	private boolean shapeAnalysisComplete = false;
77
	private boolean returnsValue;
77
	boolean returnsValue;
78
	private boolean returnsVoid;
78
	boolean returnsVoid;
79
	private LambdaExpression original = this;
79
	private LambdaExpression original = this;
80
	private SyntheticArgumentBinding[] outerLocalVariables = NO_SYNTHETIC_ARGUMENTS;
80
	private SyntheticArgumentBinding[] outerLocalVariables = NO_SYNTHETIC_ARGUMENTS;
81
	private int outerLocalVariablesSlotSize = 0;
81
	private int outerLocalVariablesSlotSize = 0;
82
	public boolean shouldCaptureInstance = false;
82
	public boolean shouldCaptureInstance = false;
83
	private boolean shouldUnelideTypes = false;
83
	private boolean assistNode = false;
84
	private boolean hasIgnoredMandatoryErrors = false;
84
	private boolean hasIgnoredMandatoryErrors = false;
85
	private static final SyntheticArgumentBinding [] NO_SYNTHETIC_ARGUMENTS = new SyntheticArgumentBinding[0];
85
	private static final SyntheticArgumentBinding [] NO_SYNTHETIC_ARGUMENTS = new SyntheticArgumentBinding[0];
86
	
86
	private static final Block NO_BODY = new Block(0, true);
87
	public LambdaExpression(CompilationResult compilationResult, boolean shouldUnelideTypes) {
87
88
	public LambdaExpression(CompilationResult compilationResult, boolean assistNode) {
88
		super(compilationResult);
89
		super(compilationResult);
89
		this.shouldUnelideTypes = shouldUnelideTypes;
90
		this.assistNode = assistNode;
90
		setArguments(NO_ARGUMENTS);
91
		setArguments(NO_ARGUMENTS);
91
		setBody(new Block(0));
92
		setBody(NO_BODY);
92
	}
93
	}
93
	
94
	
94
	public void setArguments(Argument [] arguments) {
95
	public void setArguments(Argument [] arguments) {
Lines 101-107 Link Here
101
	}
102
	}
102
103
103
	public void setBody(Statement body) {
104
	public void setBody(Statement body) {
104
		this.body = body == null ? new Block(0) : body;
105
		this.body = body == null ? NO_BODY : body;
105
	}
106
	}
106
	
107
	
107
	public Statement body() {
108
	public Statement body() {
Lines 110-115 Link Here
110
111
111
	public void setArrowPosition(int arrowPosition) {
112
	public void setArrowPosition(int arrowPosition) {
112
		this.arrowPosition = arrowPosition;
113
		this.arrowPosition = arrowPosition;
114
	}
115
	
116
	public int getArrowPosition() {
117
		return this.arrowPosition;
113
	}
118
	}
114
	
119
	
115
	protected FunctionalExpression original() {
120
	protected FunctionalExpression original() {
Lines 188-194 Link Here
188
		
193
		
189
		if (!haveDescriptor) {
194
		if (!haveDescriptor) {
190
			if (argumentsTypeElided) {
195
			if (argumentsTypeElided) {
191
				if (!this.shouldUnelideTypes)
196
				if (!this.assistNode)
192
					return null; // FUBAR, bail out...
197
					return null; // FUBAR, bail out...
193
				// for code assist ONLY, keep the sluice gate shut on bogus errors otherwise.
198
				// for code assist ONLY, keep the sluice gate shut on bogus errors otherwise.
194
				argumentsTypeElided = false;
199
				argumentsTypeElided = false;
Lines 524-529 Link Here
524
		return false;
529
		return false;
525
	}
530
	}
526
		
531
		
532
	private void analyzeShape() { // simple minded analysis for code assist.
533
		class ShapeComputer extends ASTVisitor {
534
			public boolean visit(TypeDeclaration type, BlockScope skope) {
535
				return false;
536
			}
537
			public boolean visit(TypeDeclaration type, ClassScope skope) {
538
				return false;
539
			}
540
			public boolean visit(LambdaExpression type, BlockScope skope) {
541
				return false;
542
			}
543
		    public boolean visit(ReturnStatement returnStatement, BlockScope skope) {
544
		    	if (returnStatement.expression != null) {
545
		    		LambdaExpression.this.valueCompatible = true;
546
		    		LambdaExpression.this.voidCompatible = false;
547
		    	} else {
548
		    		LambdaExpression.this.voidCompatible = true;
549
		    		LambdaExpression.this.valueCompatible = false;
550
		    	}
551
		    	return false;
552
		    }
553
		}
554
		if (this.body instanceof Expression) {
555
			this.voidCompatible = ((Expression) this.body).statementExpression();
556
			this.valueCompatible = true;
557
		} else {
558
			// 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;
559
			this.voidCompatible = true;
560
			this.valueCompatible = true;
561
			this.body.traverse(new ShapeComputer(), null);
562
		}
563
		this.shapeAnalysisComplete = true;
564
	}
565
	
527
	public boolean isCompatibleWith(final TypeBinding left, final Scope someScope) {
566
	public boolean isCompatibleWith(final TypeBinding left, final Scope someScope) {
528
		
567
		
529
		final MethodBinding sam = left.getSingleAbstractMethod(this.enclosingScope);
568
		final MethodBinding sam = left.getSingleAbstractMethod(this.enclosingScope);
Lines 540-547 Link Here
540
			compilerOptions.isAnnotationBasedNullAnalysisEnabled = false;
579
			compilerOptions.isAnnotationBasedNullAnalysisEnabled = false;
541
			try {
580
			try {
542
				final LambdaExpression copy = copy();
581
				final LambdaExpression copy = copy();
543
				if (copy == null)
582
				if (copy == null) {
544
					return false;
583
					if (this.assistNode) {
584
						analyzeShape(); // not on terra firma here !
585
						if (sam.returnType.id == TypeIds.T_void) {
586
							if (!this.voidCompatible)
587
								return false;
588
						} else {
589
							if (!this.valueCompatible)
590
								return false;
591
						}
592
					}
593
					return !isPertinentToApplicability(left);
594
				}
545
				copy.setExpressionContext(this.expressionContext);
595
				copy.setExpressionContext(this.expressionContext);
546
				copy.setExpectedType(left);
596
				copy.setExpectedType(left);
547
				this.hasIgnoredMandatoryErrors = false;
597
				this.hasIgnoredMandatoryErrors = false;
Lines 576-584 Link Here
576
			}
626
			}
577
		}
627
		}
578
628
579
		if (!isPertinentToApplicability(left))
629
		if (!isPertinentToApplicability(left))  // This check should happen after return type check below, but for buggy javac compatibility we have left it in.
580
			return true;
630
			return true;
581
	
631
582
		if (sam.returnType.id == TypeIds.T_void) {
632
		if (sam.returnType.id == TypeIds.T_void) {
583
			if (!this.voidCompatible)
633
			if (!this.voidCompatible)
584
				return false;
634
				return false;
Lines 586-593 Link Here
586
			if (!this.valueCompatible)
636
			if (!this.valueCompatible)
587
				return false;
637
				return false;
588
		}
638
		}
589
		
639
			Expression [] returnExpressions = this.resultExpressions;
590
		Expression [] returnExpressions = this.resultExpressions;
591
		for (int i = 0, length = returnExpressions.length; i < length; i++) {
640
		for (int i = 0, length = returnExpressions.length; i < length; i++) {
592
			if (returnExpressions[i] instanceof FunctionalExpression) { // don't want to use the resolvedType - polluted from some other overload resolution candidate
641
			if (returnExpressions[i] instanceof FunctionalExpression) { // don't want to use the resolvedType - polluted from some other overload resolution candidate
593
				if (!returnExpressions[i].isCompatibleWith(sam.returnType, this.enclosingScope))
642
				if (!returnExpressions[i].isCompatibleWith(sam.returnType, this.enclosingScope))
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/CommitRollbackParser.java (+111 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2013 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * This is an implementation of an early-draft specification developed under the Java
9
 * Community Process (JCP) and is made available for testing and evaluation purposes
10
 * only. The code is not compatible with any specification of the JCP.
11
 * 
12
 * Contributors:
13
 *     IBM Corporation - initial API and implementation
14
 *******************************************************************************/
15
package org.eclipse.jdt.internal.compiler.parser;
16
17
import org.eclipse.jdt.core.compiler.InvalidInputException;
18
import org.eclipse.jdt.internal.compiler.ast.Statement;
19
20
public abstract class CommitRollbackParser implements TerminalTokens, ParserBasicInformation {
21
	
22
	// resumeOnSyntaxError codes:
23
	protected static final int HALT = 0;     // halt and throw up hands.
24
	protected static final int RESTART = 1;  // stacks adjusted, alternate goal from check point.
25
	protected static final int RESUME = 2;   // stacks untouched, just continue from where left off.
26
27
	public Scanner scanner;
28
	public int currentToken;
29
	protected int kurrentToken; // copy of currentToken as it is trampled over all over the place :-(
30
	
31
	public CommitRollbackParser snapShot;
32
	private static final int[] RECOVERY_TOKENS = new int [] { TokenNameSEMICOLON, TokenNameRPAREN,};
33
	
34
	protected CommitRollbackParser createSnapShotParser() {
35
		return new Parser();
36
	}
37
	
38
	protected void commit() {
39
		if (this.snapShot == null) {
40
			this.snapShot = createSnapShotParser();
41
		}
42
		this.snapShot.copyState(this);
43
	}
44
	
45
	public void copyState(CommitRollbackParser commitRollbackParser) {
46
		// Subclasses should implement.
47
	}
48
49
	protected int getNextToken() {
50
		try {
51
			return this.scanner.getNextToken();
52
		} catch (InvalidInputException e) {
53
			return TokenNameEOF;
54
		}
55
	}
56
	
57
	protected void shouldStackAssistNode() {
58
		// Not relevant here.
59
	}
60
	
61
	// We get here on real syntax error or syntax error triggered by fake EOF at completion site, never due to triggered recovery.
62
	protected int fallBackToSpringForward(Statement unused) {
63
		int nextToken;
64
		boolean atCompletionSite = false;
65
		int automatonState = automatonState();
66
				
67
		// If triggered fake EOF at completion site, see if the real next token would have passed muster.
68
		if (this.kurrentToken == TokenNameEOF) {
69
			if (this.scanner.eofPosition < this.scanner.source.length) {
70
				atCompletionSite = true;
71
				this.scanner.eofPosition = this.scanner.source.length;
72
				nextToken = getNextToken();
73
				if (automatonWillShift(nextToken, automatonState)) {
74
					this.currentToken = this.kurrentToken = nextToken;
75
					return RESUME;
76
				}
77
			} else {
78
				nextToken = TokenNameEOF;
79
			}
80
		} else {
81
			nextToken = this.kurrentToken;
82
		}
83
		if (nextToken == TokenNameEOF)
84
			return HALT; // don't know how to proceed.
85
		this.scanner.ungetToken(nextToken); // spit out what has been bitten more than we can chew.
86
		// 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 !!
87
		for (int i = 0, length = RECOVERY_TOKENS.length; i < length; i++) {
88
			if (automatonWillShift(RECOVERY_TOKENS[i], automatonState)) {
89
				this.currentToken = this.kurrentToken = RECOVERY_TOKENS[i];
90
				return RESUME;
91
			}
92
		}
93
		// OK, no in place resumption, no local repair, fast forward to next statement.
94
		if (this.snapShot == null)
95
			return RESTART;
96
97
		this.copyState(this.snapShot);
98
		if (atCompletionSite) {
99
			this.currentToken = TokenNameSEMICOLON;
100
			shouldStackAssistNode();
101
			return RESUME;
102
		}
103
		this.currentToken = this.scanner.fastForward(unused);
104
		return RESUME;
105
	}
106
107
	public abstract int automatonState();
108
109
	public abstract boolean automatonWillShift(int nextToken, int lastAction);
110
}
111
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java (-89 / +140 lines)
Lines 45-51 Link Here
45
45
46
import org.eclipse.jdt.core.compiler.CharOperation;
46
import org.eclipse.jdt.core.compiler.CharOperation;
47
import org.eclipse.jdt.core.compiler.InvalidInputException;
47
import org.eclipse.jdt.core.compiler.InvalidInputException;
48
import org.eclipse.jdt.internal.codeassist.impl.AssistParser;
49
import org.eclipse.jdt.internal.compiler.ASTVisitor;
48
import org.eclipse.jdt.internal.compiler.ASTVisitor;
50
import org.eclipse.jdt.internal.compiler.CompilationResult;
49
import org.eclipse.jdt.internal.compiler.CompilationResult;
51
import org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression;
50
import org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression;
Lines 159-165 Link Here
159
import org.eclipse.jdt.internal.compiler.util.Messages;
158
import org.eclipse.jdt.internal.compiler.util.Messages;
160
import org.eclipse.jdt.internal.compiler.util.Util;
159
import org.eclipse.jdt.internal.compiler.util.Util;
161
160
162
public class Parser implements ConflictedParser, ParserBasicInformation, TerminalTokens, OperatorIds, TypeIds {
161
public class Parser extends CommitRollbackParser implements ConflictedParser, OperatorIds, TypeIds {
163
	
162
	
164
	protected static final int THIS_CALL = ExplicitConstructorCall.This;
163
	protected static final int THIS_CALL = ExplicitConstructorCall.This;
165
	protected static final int SUPER_CALL = ExplicitConstructorCall.Super;
164
	protected static final int SUPER_CALL = ExplicitConstructorCall.Super;
Lines 896-902 Link Here
896
	public CompilationUnitDeclaration compilationUnit; /*the result from parse()*/
895
	public CompilationUnitDeclaration compilationUnit; /*the result from parse()*/
897
896
898
	protected RecoveredElement currentElement;
897
	protected RecoveredElement currentElement;
899
	public int currentToken;
898
	
900
	protected boolean diet = false; //tells the scanner to jump over some parts of the code/expressions like method bodies
899
	protected boolean diet = false; //tells the scanner to jump over some parts of the code/expressions like method bodies
901
	protected int dietInt = 0; // if > 0 force the none-diet-parsing mode (even if diet if requested) [field parsing with anonymous inner classes...]
900
	protected int dietInt = 0; // if > 0 force the none-diet-parsing mode (even if diet if requested) [field parsing with anonymous inner classes...]
902
	protected int endPosition; //accurate only when used ! (the start position is pushed into intStack while the end the current one)
901
	protected int endPosition; //accurate only when used ! (the start position is pushed into intStack while the end the current one)
Lines 987-994 Link Here
987
protected int nextTypeStart;
986
protected int nextTypeStart;
988
protected TypeDeclaration pendingRecoveredType;
987
protected TypeDeclaration pendingRecoveredType;
989
public RecoveryScanner recoveryScanner;
988
public RecoveryScanner recoveryScanner;
990
//scanner token
989
991
public Scanner scanner;
992
protected int[] stack = new int[StackIncrement];
990
protected int[] stack = new int[StackIncrement];
993
protected int stateStackTop;
991
protected int stateStackTop;
994
protected int synchronizedBlockSourceStart;
992
protected int synchronizedBlockSourceStart;
Lines 1004-1010 Link Here
1004
// used for recovery
1002
// used for recovery
1005
protected int lastJavadocEnd;
1003
protected int lastJavadocEnd;
1006
public org.eclipse.jdt.internal.compiler.ReadManager readManager;
1004
public org.eclipse.jdt.internal.compiler.ReadManager readManager;
1007
private int valueLambdaNestDepth = -1;
1005
protected int valueLambdaNestDepth = -1;
1008
private int stateStackLengthStack[] = new int[0];
1006
private int stateStackLengthStack[] = new int[0];
1009
protected boolean parsingJava8Plus;
1007
protected boolean parsingJava8Plus;
1010
protected int unstackedAct = ERROR_ACTION;
1008
protected int unstackedAct = ERROR_ACTION;
Lines 1013-1026 Link Here
1013
private boolean processingLambdaParameterList = false;
1011
private boolean processingLambdaParameterList = false;
1014
private boolean expectTypeAnnotation = false;
1012
private boolean expectTypeAnnotation = false;
1015
1013
1016
// resumeOnSyntaxError codes:
1014
public Parser () {
1017
1018
protected static final int HALT = 0;     // halt and throw up hands.
1019
protected static final int RESTART = 1;  // stacks reset, alternate goal from check point.
1020
protected static final int RESUME = 2;   // stacks untouched, just continue from where left off.
1021
1022
1023
protected Parser () {
1024
	// Caveat Emptor: For inheritance purposes and then only in very special needs. Only minimal state is initialized !
1015
	// Caveat Emptor: For inheritance purposes and then only in very special needs. Only minimal state is initialized !
1025
}
1016
}
1026
public Parser(ProblemReporter problemReporter, boolean optimizeStringLiterals) {
1017
public Parser(ProblemReporter problemReporter, boolean optimizeStringLiterals) {
Lines 2251-2257 Link Here
2251
	pushOnAstStack(block);
2242
	pushOnAstStack(block);
2252
}
2243
}
2253
protected void consumeBlockStatement() {
2244
protected void consumeBlockStatement() {
2254
	// todo.
2245
	// for assist parsers.
2255
}
2246
}
2256
protected void consumeBlockStatements() {
2247
protected void consumeBlockStatements() {
2257
	// BlockStatements ::= BlockStatements BlockStatement
2248
	// BlockStatements ::= BlockStatements BlockStatement
Lines 7855-7871 Link Here
7855
	pushOnIntStack(0);  // signal explicit this
7846
	pushOnIntStack(0);  // signal explicit this
7856
}
7847
}
7857
7848
7849
protected boolean isAssistParser() {
7850
	return false;
7851
}
7858
protected void consumeNestedLambda() {
7852
protected void consumeNestedLambda() {
7859
	// NestedLambda ::= $empty - we get here just after the type+parenthesis elided singleton parameter or just before the '(' of the parameter list. 
7853
	// NestedLambda ::= $empty - we get here just after the type+parenthesis elided singleton parameter or just before the '(' of the parameter list. 
7860
	consumeNestedType();
7854
	consumeNestedType();
7861
	this.nestedMethod[this.nestedType] ++;
7855
	this.nestedMethod[this.nestedType] ++;
7862
	LambdaExpression lambda = new LambdaExpression(this.compilationUnit.compilationResult, this instanceof AssistParser);
7856
	LambdaExpression lambda = new LambdaExpression(this.compilationUnit.compilationResult, isAssistParser());
7863
	pushOnAstStack(lambda);
7857
	pushOnAstStack(lambda);
7864
	if (this.currentElement != null) {
7865
		this.currentElement = this.currentElement.add(lambda, 0);
7866
		this.lastCheckPoint = this.scanner.currentPosition;
7867
		this.lastIgnoredToken = -1;
7868
	}
7869
	this.processingLambdaParameterList = true;	
7858
	this.processingLambdaParameterList = true;	
7870
}
7859
}
7871
7860
Lines 7896-7911 Link Here
7896
	}
7885
	}
7897
	LambdaExpression lexp = (LambdaExpression) this.astStack[this.astPtr];
7886
	LambdaExpression lexp = (LambdaExpression) this.astStack[this.astPtr];
7898
	lexp.setArguments(arguments);
7887
	lexp.setArguments(arguments);
7899
	lexp.setArrowPosition(arrowPosition); // '->' position
7888
	lexp.setArrowPosition(arrowPosition);
7900
	lexp.sourceEnd = this.intStack[this.intPtr--];   // ')' position or identifier position.
7889
	lexp.sourceEnd = this.intStack[this.intPtr--];   // ')' position or identifier position.
7901
	lexp.sourceStart = this.intStack[this.intPtr--]; // '(' position or identifier position.
7890
	lexp.sourceStart = this.intStack[this.intPtr--]; // '(' position or identifier position.
7902
	lexp.hasParentheses = (this.scanner.getSource()[lexp.sourceStart] == '(');
7891
	lexp.hasParentheses = (this.scanner.getSource()[lexp.sourceStart] == '(');
7903
	this.listLength = 0; // reset this.listLength after having read all parameters
7892
	this.listLength -= arguments == null ? 0 : arguments.length;  // not necessary really.
7904
	if (this.currentElement != null) {
7905
		this.lastCheckPoint = lexp.sourceEnd + 1;
7906
		this.lastIgnoredToken = -1;
7907
	}
7908
	this.processingLambdaParameterList = false;
7893
	this.processingLambdaParameterList = false;
7894
	if (this.currentElement != null) {
7895
		this.lastCheckPoint = arrowPosition + 1;
7896
	}
7909
}
7897
}
7910
protected void consumeLambdaExpression() {
7898
protected void consumeLambdaExpression() {
7911
	
7899
	
Lines 7919-7924 Link Here
7919
		if (this.options.ignoreMethodBodies) {
7907
		if (this.options.ignoreMethodBodies) {
7920
			body = new Block(0);
7908
			body = new Block(0);
7921
		}
7909
		}
7910
		((Block) body).lambdaBody = true; // for consistency's sakes.
7922
	}
7911
	}
7923
7912
7924
	LambdaExpression lexp = (LambdaExpression) this.astStack[this.astPtr--];
7913
	LambdaExpression lexp = (LambdaExpression) this.astStack[this.astPtr--];
Lines 7935-7944 Link Here
7935
	}
7924
	}
7936
	pushOnExpressionStack(lexp);
7925
	pushOnExpressionStack(lexp);
7937
	if (this.currentElement != null) {
7926
	if (this.currentElement != null) {
7938
		if (this.currentElement.parseTree() == lexp && this.currentElement.parent != null) {
7927
		this.lastCheckPoint = body.sourceEnd + 1;
7939
			this.currentElement = this.currentElement.parent;
7940
		}
7941
		this.lastCheckPoint = lexp.sourceEnd + 1;
7942
	}
7928
	}
7943
}
7929
}
7944
7930
Lines 7984-7992 Link Here
7984
		pushOnIntStack(arg.declarationSourceEnd);
7970
		pushOnIntStack(arg.declarationSourceEnd);
7985
	}
7971
	}
7986
	pushOnAstStack(arg);
7972
	pushOnAstStack(arg);
7987
	/* if incomplete method header, this.listLength counter will not have been reset,
7973
	this.listLength++;  // not relevant really.
7988
		indicating that some arguments are available on the stack */
7989
	this.listLength++;
7990
}
7974
}
7991
protected void consumeElidedLeftBraceAndReturn() {
7975
protected void consumeElidedLeftBraceAndReturn() {
7992
	/* ElidedLeftBraceAndReturn ::= $empty
7976
	/* ElidedLeftBraceAndReturn ::= $empty
Lines 10464-10470 Link Here
10464
	this.referenceContext = null;
10448
	this.referenceContext = null;
10465
	this.endStatementPosition = 0;
10449
	this.endStatementPosition = 0;
10466
	this.valueLambdaNestDepth = -1;
10450
	this.valueLambdaNestDepth = -1;
10467
10451
	
10468
	//remove objects from stack too, while the same parser/compiler couple is
10452
	//remove objects from stack too, while the same parser/compiler couple is
10469
	//re-used between two compilations ....
10453
	//re-used between two compilations ....
10470
10454
Lines 10797-10837 Link Here
10797
	         
10781
	         
10798
	    Though this code looks complex, we should exit early in most situations.     
10782
	    Though this code looks complex, we should exit early in most situations.     
10799
	 */
10783
	 */
10800
	int lastAction = this.unstackedAct;
10784
	if (this.unstackedAct == ERROR_ACTION) { // automaton is not running.
10801
	if (lastAction == ERROR_ACTION) { // automaton is not running.
10802
		return false;
10785
		return false;
10803
	}
10786
	}
10804
	int stackTop = this.stateStackTop;        // local copy of stack pointer
10805
	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.
10806
	int highWaterMark = stackTop;
10807
	
10808
	if (token != TokenNameAT) {
10787
	if (token != TokenNameAT) {
10809
		token = token == TokenNameLPAREN ? TokenNameBeginLambda : TokenNameBeginTypeArguments;
10788
		token = token == TokenNameLPAREN ? TokenNameBeginLambda : TokenNameBeginTypeArguments;
10810
	}
10789
	}
10811
	
10790
	
10812
	// A rotated version of the automaton - cf. parse()'s for(;;)
10791
	return automatonWillShift(token, this.unstackedAct);
10813
	for (;;) {  
10814
		if (lastAction > ERROR_ACTION) {  
10815
			lastAction -= ERROR_ACTION;    /* shift-reduce on loop entry from above, reduce on loop back */
10816
			do { /* reduce */
10817
				stackTop -= rhs[lastAction] - 1;
10818
				if (stackTop < highWaterMark) {
10819
					stackTopState = this.stack[highWaterMark = stackTop];
10820
				} // else stackTopState is upto date already.
10821
				lastAction = ntAction(stackTopState, lhs[lastAction]);
10822
			} while (lastAction <= NUM_RULES);
10823
		}
10824
		highWaterMark = ++stackTop;
10825
		stackTopState = lastAction; // "push"
10826
		lastAction = tAction(lastAction, token); // can be looked up from a precomputed cache.
10827
		if (lastAction <= NUM_RULES) {
10828
			stackTop --; 
10829
		    lastAction += ERROR_ACTION;
10830
			continue;
10831
		}
10832
		// Error => false, Shift, Shift/Reduce => true, Accept => impossible. 
10833
		return lastAction != ERROR_ACTION;
10834
	}
10835
}
10792
}
10836
/*main loop of the automat
10793
/*main loop of the automat
10837
When a rule is reduced, the method consumeRule(int) is called with the number
10794
When a rule is reduced, the method consumeRule(int) is called with the number
Lines 10852-10857 Link Here
10852
10809
10853
	this.hasReportedError = false;
10810
	this.hasReportedError = false;
10854
	int act = START_STATE;
10811
	int act = START_STATE;
10812
	this.unstackedAct = ERROR_ACTION;
10855
	this.stateStackTop = -1;
10813
	this.stateStackTop = -1;
10856
	this.currentToken = getFirstToken();
10814
	this.currentToken = getFirstToken();
10857
	
10815
	
Lines 10866-10873 Link Here
10866
				stackLength);
10824
				stackLength);
10867
		}
10825
		}
10868
		this.stack[this.stateStackTop] = act;
10826
		this.stack[this.stateStackTop] = act;
10869
10827
		this.unstackedAct = act = tAction(act, this.currentToken);
10870
		act = tAction(act, this.currentToken);
10871
		if (act == ERROR_ACTION || this.restartRecovery) {
10828
		if (act == ERROR_ACTION || this.restartRecovery) {
10872
			if (DEBUG_AUTOMATON) {
10829
			if (DEBUG_AUTOMATON) {
10873
				if (this.restartRecovery) {
10830
				if (this.restartRecovery) {
Lines 10879-10901 Link Here
10879
10836
10880
			int errorPos = this.scanner.currentPosition - 1;
10837
			int errorPos = this.scanner.currentPosition - 1;
10881
			if (!this.hasReportedError) {
10838
			if (!this.hasReportedError) {
10882
				this.hasError = true;  // looks incorrect for recovery case ?
10839
				this.hasError = true;
10883
			}
10840
			}
10884
			int previousToken = this.currentToken;
10841
			this.kurrentToken = this.currentToken;
10885
			switch (resumeOnSyntaxError()) {
10842
			switch (resumeOnSyntaxError()) {
10886
				case HALT:
10843
				case HALT:
10887
					act = ERROR_ACTION;
10844
					act = ERROR_ACTION;
10888
					break ProcessTerminals;
10845
					break ProcessTerminals;
10889
				case RESTART:
10846
				case RESTART:
10890
					if (act == ERROR_ACTION && previousToken != 0) this.lastErrorEndPosition = errorPos;
10847
					if (act == ERROR_ACTION && this.kurrentToken != 0) this.lastErrorEndPosition = errorPos;
10891
					act = START_STATE;
10848
					act = START_STATE;
10892
					this.stateStackTop = -1;
10849
					this.stateStackTop = -1;
10893
					this.currentToken = getFirstToken();
10850
					this.currentToken = getFirstToken();
10894
					continue ProcessTerminals;
10851
					continue ProcessTerminals;
10895
				case RESUME:
10852
				case RESUME:
10896
					break; // We presume the world is virgin so we can continue exactly from where we left off.
10853
					if (act == ERROR_ACTION) {
10897
				default:
10854
						act = this.stack[this.stateStackTop--];
10898
					throw new IllegalStateException();
10855
						continue ProcessTerminals;
10856
					} else {
10857
						this.currentToken = this.kurrentToken; // Gets trashed all over the place.
10858
					}
10859
					// FALL THROUGH.
10899
			}
10860
			}
10900
		}
10861
		}
10901
		if (act <= NUM_RULES) {
10862
		if (act <= NUM_RULES) {
Lines 10914-10920 Link Here
10914
				this.recordStringLiterals = oldValue;
10875
				this.recordStringLiterals = oldValue;
10915
			}
10876
			}
10916
			try {
10877
			try {
10917
				this.unstackedAct = act;
10918
				this.currentToken = this.scanner.getNextToken();
10878
				this.currentToken = this.scanner.getNextToken();
10919
			} catch(InvalidInputException e){
10879
			} catch(InvalidInputException e){
10920
				if (!this.hasReportedError){
10880
				if (!this.hasReportedError){
Lines 10924-10936 Link Here
10924
				this.lastCheckPoint = this.scanner.currentPosition;
10884
				this.lastCheckPoint = this.scanner.currentPosition;
10925
				this.currentToken = 0;
10885
				this.currentToken = 0;
10926
				this.restartRecovery = true;
10886
				this.restartRecovery = true;
10927
			} finally {
10887
			} 
10928
				this.unstackedAct = ERROR_ACTION;
10929
			}
10930
			if(this.statementRecoveryActivated) {
10888
			if(this.statementRecoveryActivated) {
10931
				jumpOverType();
10889
				jumpOverType();
10932
			}
10890
			}
10933
			act -= ERROR_ACTION;
10891
			this.unstackedAct = act -= ERROR_ACTION;
10934
10892
10935
			if (DEBUG_AUTOMATON) {
10893
			if (DEBUG_AUTOMATON) {
10936
				System.out.print("Shift/Reduce - (" + name[terminal_index[this.currentToken]]+") ");  //$NON-NLS-1$  //$NON-NLS-2$
10894
				System.out.print("Shift/Reduce - (" + name[terminal_index[this.currentToken]]+") ");  //$NON-NLS-1$  //$NON-NLS-2$
Lines 10946-10952 Link Here
10946
					this.recordStringLiterals = oldValue;
10904
					this.recordStringLiterals = oldValue;
10947
				}
10905
				}
10948
				try{
10906
				try{
10949
					this.unstackedAct = act;
10950
					this.currentToken = this.scanner.getNextToken();
10907
					this.currentToken = this.scanner.getNextToken();
10951
				} catch(InvalidInputException e){
10908
				} catch(InvalidInputException e){
10952
					if (!this.hasReportedError){
10909
					if (!this.hasReportedError){
Lines 10956-10963 Link Here
10956
					this.lastCheckPoint = this.scanner.currentPosition;
10913
					this.lastCheckPoint = this.scanner.currentPosition;
10957
					this.currentToken = 0;
10914
					this.currentToken = 0;
10958
					this.restartRecovery = true;
10915
					this.restartRecovery = true;
10959
				} finally {
10960
					this.unstackedAct = ERROR_ACTION;
10961
				}
10916
				}
10962
				if(this.statementRecoveryActivated) {
10917
				if(this.statementRecoveryActivated) {
10963
					jumpOverType();
10918
					jumpOverType();
Lines 10978-10985 Link Here
10978
			}
10933
			}
10979
10934
10980
			this.stateStackTop -= (rhs[act] - 1);
10935
			this.stateStackTop -= (rhs[act] - 1);
10936
			this.unstackedAct = ntAction(this.stack[this.stateStackTop], lhs[act]);
10981
			consumeRule(act);
10937
			consumeRule(act);
10982
			act = ntAction(this.stack[this.stateStackTop], lhs[act]);
10938
			act = this.unstackedAct;
10983
10939
10984
			if (DEBUG_AUTOMATON) {
10940
			if (DEBUG_AUTOMATON) {
10985
				if (act <= NUM_RULES) {
10941
				if (act <= NUM_RULES) {
Lines 10994-10999 Link Here
10994
		}
10950
		}
10995
	}
10951
	}
10996
} finally {
10952
} finally {
10953
	this.unstackedAct = ERROR_ACTION;
10997
	this.scanner.setActiveParser(null);
10954
	this.scanner.setActiveParser(null);
10998
}
10955
}
10999
10956
Lines 12164-12171 Link Here
12164
	this.identifierPtr = -1;
12121
	this.identifierPtr = -1;
12165
	this.identifierLengthPtr	= -1;
12122
	this.identifierLengthPtr	= -1;
12166
	this.intPtr = -1;
12123
	this.intPtr = -1;
12124
	
12167
	this.nestedMethod[this.nestedType = 0] = 0; // need to reset for further reuse
12125
	this.nestedMethod[this.nestedType = 0] = 0; // need to reset for further reuse
12168
	this.variablesCounter[this.nestedType] = 0;
12126
	this.variablesCounter[this.nestedType] = 0;
12127
	
12169
	this.dimensions = 0 ;
12128
	this.dimensions = 0 ;
12170
	this.realBlockStack[this.realBlockPtr = 0] = 0;
12129
	this.realBlockStack[this.realBlockPtr = 0] = 0;
12171
	this.recoveredStaticInitializerStart = 0;
12130
	this.recoveredStaticInitializerStart = 0;
Lines 12184-12190 Link Here
12184
 * Move checkpoint location, reset internal stacks and
12143
 * Move checkpoint location, reset internal stacks and
12185
 * decide which grammar goal is activated.
12144
 * decide which grammar goal is activated.
12186
 */
12145
 */
12187
protected boolean resumeAfterRecovery() {
12146
protected int resumeAfterRecovery() {
12188
	if(!this.methodRecoveryActivated && !this.statementRecoveryActivated) {
12147
	if(!this.methodRecoveryActivated && !this.statementRecoveryActivated) {
12189
12148
12190
		// reset internal stacks
12149
		// reset internal stacks
Lines 12193-12210 Link Here
12193
12152
12194
		/* attempt to move checkpoint location */
12153
		/* attempt to move checkpoint location */
12195
		if (!moveRecoveryCheckpoint()) {
12154
		if (!moveRecoveryCheckpoint()) {
12196
			return false;
12155
			return HALT;
12197
		}
12156
		}
12198
12157
12199
		// only look for headers
12158
		// only look for headers
12200
		if (this.referenceContext instanceof CompilationUnitDeclaration){
12159
		if (this.referenceContext instanceof CompilationUnitDeclaration){
12201
			goForHeaders();
12160
			goForHeaders();
12202
			this.diet = true; // passed this point, will not consider method bodies
12161
			this.diet = true; // passed this point, will not consider method bodies
12203
			return true;
12162
			return RESTART;
12204
		}
12163
		}
12205
12164
12206
		// does not know how to restart
12165
		// does not know how to restart
12207
		return false;
12166
		return HALT;
12208
	} else if(!this.statementRecoveryActivated) {
12167
	} else if(!this.statementRecoveryActivated) {
12209
12168
12210
		// reset internal stacks
12169
		// reset internal stacks
Lines 12213-12226 Link Here
12213
12172
12214
		/* attempt to move checkpoint location */
12173
		/* attempt to move checkpoint location */
12215
		if (!moveRecoveryCheckpoint()) {
12174
		if (!moveRecoveryCheckpoint()) {
12216
			return false;
12175
			return HALT;
12217
		}
12176
		}
12218
12177
12219
		// only look for headers
12178
		// only look for headers
12220
		goForHeaders();
12179
		goForHeaders();
12221
		return true;
12180
		return RESTART;
12222
	} else {
12181
	} else {
12223
		return false;
12182
		return HALT;
12224
	}
12183
	}
12225
}
12184
}
12226
protected int resumeOnSyntaxError() {
12185
protected int resumeOnSyntaxError() {
Lines 12260-12266 Link Here
12260
	}
12219
	}
12261
12220
12262
	/* attempt to reset state in order to resume to parse loop */
12221
	/* attempt to reset state in order to resume to parse loop */
12263
	return resumeAfterRecovery() ? RESTART : HALT;
12222
	return resumeAfterRecovery();
12264
}
12223
}
12265
public void setMethodsFullRecovery(boolean enabled) {
12224
public void setMethodsFullRecovery(boolean enabled) {
12266
	this.options.performMethodsFullRecovery = enabled;
12225
	this.options.performMethodsFullRecovery = enabled;
Lines 12368-12371 Link Here
12368
	exp.sourceEnd = this.intStack[this.intPtr--];
12327
	exp.sourceEnd = this.intStack[this.intPtr--];
12369
	exp.sourceStart = this.intStack[this.intPtr--];
12328
	exp.sourceStart = this.intStack[this.intPtr--];
12370
}
12329
}
12330
public void copyState(CommitRollbackParser from) {
12331
	
12332
	Parser parser = (Parser) from;
12333
12334
	// Stack pointers.
12335
	
12336
	this.stateStackTop = parser.stateStackTop;
12337
	this.unstackedAct = parser.unstackedAct;
12338
	this.identifierPtr = parser.identifierPtr;
12339
	this.identifierLengthPtr = parser.identifierLengthPtr;
12340
	this.astPtr = parser.astPtr;
12341
	this.astLengthPtr = parser.astLengthPtr;
12342
	this.expressionPtr = parser.expressionPtr;
12343
	this.expressionLengthPtr = parser.expressionLengthPtr;
12344
	this.genericsPtr = parser.genericsPtr;
12345
	this.genericsLengthPtr = parser.genericsLengthPtr;
12346
	this.genericsIdentifiersLengthPtr = parser.genericsIdentifiersLengthPtr;
12347
	this.typeAnnotationPtr = parser.typeAnnotationPtr;
12348
	this.typeAnnotationLengthPtr = parser.typeAnnotationLengthPtr;
12349
	this.intPtr = parser.intPtr;
12350
	this.nestedType = parser.nestedType;
12351
	this.realBlockPtr = parser.realBlockPtr;
12352
	this.valueLambdaNestDepth = parser.valueLambdaNestDepth;
12353
	
12354
	// Stacks.
12355
	
12356
	int length;
12357
	System.arraycopy(parser.stack, 0, this.stack = new int [length = parser.stack.length], 0, length);
12358
	System.arraycopy(parser.identifierStack, 0, this.identifierStack = new char [length = parser.identifierStack.length][], 0, length);
12359
	System.arraycopy(parser.identifierLengthStack, 0, this.identifierLengthStack = new int [length = parser.identifierLengthStack.length], 0, length);
12360
	System.arraycopy(parser.identifierPositionStack, 0, this.identifierPositionStack = new long[length = parser.identifierPositionStack.length], 0, length);
12361
	System.arraycopy(parser.astStack, 0, this.astStack = new ASTNode [length = parser.astStack.length], 0, length);
12362
	System.arraycopy(parser.astLengthStack, 0, this.astLengthStack = new int [length = parser.astLengthStack.length], 0, length);
12363
	System.arraycopy(parser.expressionStack, 0, this.expressionStack = new Expression [length = parser.expressionStack.length], 0, length);
12364
	System.arraycopy(parser.expressionLengthStack, 0, this.expressionLengthStack = new int [length = parser.expressionLengthStack.length], 0, length);
12365
	System.arraycopy(parser.genericsStack, 0, this.genericsStack = new ASTNode [length = parser.genericsStack.length], 0, length);
12366
	System.arraycopy(parser.genericsLengthStack, 0, this.genericsLengthStack = new int [length = parser.genericsLengthStack.length], 0, length);
12367
	System.arraycopy(parser.genericsIdentifiersLengthStack, 0, this.genericsIdentifiersLengthStack = new int [length = parser.genericsIdentifiersLengthStack.length], 0, length);
12368
	System.arraycopy(parser.typeAnnotationStack, 0, this.typeAnnotationStack = new Annotation [length = parser.typeAnnotationStack.length], 0, length);
12369
	System.arraycopy(parser.typeAnnotationLengthStack, 0, this.typeAnnotationLengthStack = new int [length = parser.typeAnnotationLengthStack.length], 0, length);
12370
	System.arraycopy(parser.intStack, 0, this.intStack = new int [length = parser.intStack.length], 0, length);
12371
	System.arraycopy(parser.nestedMethod, 0, this.nestedMethod = new int [length = parser.nestedMethod.length], 0, length);
12372
	System.arraycopy(parser.realBlockStack, 0, this.realBlockStack = new int [length = parser.realBlockStack.length], 0, length);
12373
	System.arraycopy(parser.stateStackLengthStack, 0, this.stateStackLengthStack = new int [length = parser.stateStackLengthStack.length], 0, length);
12374
	System.arraycopy(parser.variablesCounter, 0, this.variablesCounter = new int [length = parser.variablesCounter.length], 0, length);
12375
	System.arraycopy(parser.stack, 0, this.stack = new int [length = parser.stack.length], 0, length);
12376
	System.arraycopy(parser.stack, 0, this.stack = new int [length = parser.stack.length], 0, length);
12377
	System.arraycopy(parser.stack, 0, this.stack = new int [length = parser.stack.length], 0, length);
12378
12379
	// Loose variables.
12380
	
12381
	this.listLength = parser.listLength;
12382
	this.listTypeParameterLength = parser.listTypeParameterLength;
12383
	this.dimensions = parser.dimensions;
12384
	this.recoveredStaticInitializerStart = parser.recoveredStaticInitializerStart;
12385
12386
	// Parser.resetStacks is not clearing the modifiers, but AssistParser.resumeAfterRecovery is - why ? (the former doesn't)
12387
	// this.modifiers = parser.modifiers;
12388
	// this.modifiersSourceStart = parser.modifiersSourceStart;
12389
}
12390
12391
public int automatonState() {
12392
	return this.stack[this.stateStackTop];
12393
}
12394
public boolean automatonWillShift(int token, int lastAction) {
12395
	int stackTop = this.stateStackTop;        // local copy of stack pointer
12396
	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.
12397
	int highWaterMark = stackTop;
12398
	// A rotated version of the automaton - cf. parse()'s for(;;)
12399
	for (;;) {  
12400
		if (lastAction > ERROR_ACTION) {  
12401
			lastAction -= ERROR_ACTION;    /* shift-reduce on loop entry from above, reduce on loop back */
12402
			do { /* reduce */
12403
				stackTop -= rhs[lastAction] - 1;
12404
				if (stackTop < highWaterMark) {
12405
					stackTopState = this.stack[highWaterMark = stackTop];
12406
				} // else stackTopState is upto date already.
12407
				lastAction = ntAction(stackTopState, lhs[lastAction]);
12408
			} while (lastAction <= NUM_RULES);
12409
		}
12410
		highWaterMark = ++stackTop;
12411
		stackTopState = lastAction; // "push"
12412
		lastAction = tAction(lastAction, token); // can be looked up from a precomputed cache.
12413
		if (lastAction <= NUM_RULES) {
12414
			stackTop --; 
12415
		    lastAction += ERROR_ACTION;
12416
			continue;
12417
		}
12418
		// Error => false, Shift, Shift/Reduce => true, Accept => impossible. 
12419
		return lastAction != ERROR_ACTION;
12420
	}
12421
}
12371
}
12422
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java (-9 / +15 lines)
Lines 61-74 Link Here
61
	return super.add(methodDeclaration, bracketBalanceValue);
61
	return super.add(methodDeclaration, bracketBalanceValue);
62
}
62
}
63
/*
63
/*
64
 * Record a Lambda declaration
65
 */
66
public RecoveredElement add(LambdaExpression expression, int bracketBalanceValue) {
67
	RecoveredLambdaExpression element = new RecoveredLambdaExpression(expression, this, bracketBalanceValue);
68
	attach(element);
69
	return element;
70
}
71
/*
72
 * Record a nested block declaration
64
 * Record a nested block declaration
73
 */
65
 */
74
public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) {
66
public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) {
Lines 162-167 Link Here
162
 * Record a statement declaration
154
 * Record a statement declaration
163
 */
155
 */
164
public RecoveredElement add(Statement stmt, int bracketBalanceValue, boolean delegatedByParent) {
156
public RecoveredElement add(Statement stmt, int bracketBalanceValue, boolean delegatedByParent) {
157
	
158
	if (stmt instanceof LambdaExpression) // lambdas are recovered up to the containing statement anyways.
159
		return this;
160
	
165
	resetPendingModifiers();
161
	resetPendingModifiers();
166
162
167
	/* do not consider a nested block starting passed the block end (if set)
163
	/* do not consider a nested block starting passed the block end (if set)
Lines 295-300 Link Here
295
291
296
	// if block was not marked to be preserved or empty, then ignore it
292
	// if block was not marked to be preserved or empty, then ignore it
297
	if (!this.preserveContent || this.statementCount == 0) return null;
293
	if (!this.preserveContent || this.statementCount == 0) return null;
294
	
295
	/* If this block stands for the lambda body, trash the contents. Lambda expressions are recovered as part of the enclosing statement.
296
	   We still have left in a block here to make sure that contained elements can be trapped and tossed out.
297
	*/
298
	if (this.blockDeclaration.lambdaBody) return null; 
298
299
299
	Statement[] updatedStatements = new Statement[this.statementCount];
300
	Statement[] updatedStatements = new Statement[this.statementCount];
300
	int updatedCount = 0;
301
	int updatedCount = 0;
Lines 340-346 Link Here
340
		Statement updatedStatement = this.statements[i].updatedStatement(depth, knownTypes);
341
		Statement updatedStatement = this.statements[i].updatedStatement(depth, knownTypes);
341
		if (updatedStatement != null){
342
		if (updatedStatement != null){
342
			updatedStatements[updatedCount++] = updatedStatement;
343
			updatedStatements[updatedCount++] = updatedStatement;
343
344
			
344
			if (updatedStatement instanceof LocalDeclaration) {
345
			if (updatedStatement instanceof LocalDeclaration) {
345
				LocalDeclaration localDeclaration = (LocalDeclaration) updatedStatement;
346
				LocalDeclaration localDeclaration = (LocalDeclaration) updatedStatement;
346
				if(localDeclaration.declarationSourceEnd > lastEnd) {
347
				if(localDeclaration.declarationSourceEnd > lastEnd) {
Lines 431-436 Link Here
431
432
432
	// if block was closed or empty, then ignore it
433
	// if block was closed or empty, then ignore it
433
	if (this.blockDeclaration.sourceEnd != 0 || this.statementCount == 0) return null;
434
	if (this.blockDeclaration.sourceEnd != 0 || this.statementCount == 0) return null;
435
	
436
	/* If this block stands for the lambda body, trash the contents. Lambda expressions are recovered as part of the enclosing statement.
437
	   We still have left in a block here to make sure that contained elements can be trapped and tossed out.
438
	*/
439
	if (this.blockDeclaration.lambdaBody) return null; 
434
440
435
	Statement[] updatedStatements = new Statement[this.statementCount];
441
	Statement[] updatedStatements = new Statement[this.statementCount];
436
	int updatedCount = 0;
442
	int updatedCount = 0;
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java (-13 / +1 lines)
Lines 1-13 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2013 IBM Corporation and others.
2
 * Copyright (c) 2000, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * This is an implementation of an early-draft specification developed under the Java
9
 * Community Process (JCP) and is made available for testing and evaluation purposes
10
 * only. The code is not compatible with any specification of the JCP.
11
 * 
7
 * 
12
 * Contributors:
8
 * Contributors:
13
 *     IBM Corporation - initial API and implementation
9
 *     IBM Corporation - initial API and implementation
Lines 23-29 Link Here
23
import org.eclipse.jdt.internal.compiler.ast.Block;
19
import org.eclipse.jdt.internal.compiler.ast.Block;
24
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
20
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
25
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
21
import org.eclipse.jdt.internal.compiler.ast.ImportReference;
26
import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
27
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
22
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
28
import org.eclipse.jdt.internal.compiler.ast.Statement;
23
import org.eclipse.jdt.internal.compiler.ast.Statement;
29
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
24
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
Lines 104-116 Link Here
104
	if (this.parent == null) return this; // ignore
99
	if (this.parent == null) return this; // ignore
105
	this.updateSourceEndIfNecessary(previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1));
100
	this.updateSourceEndIfNecessary(previousAvailableLineEnd(localDeclaration.declarationSourceStart - 1));
106
	return this.parent.add(localDeclaration, bracketBalanceValue);
101
	return this.parent.add(localDeclaration, bracketBalanceValue);
107
}
108
109
/*
110
 * Record a LambdaExpression: Only can occur inside a block. Note: Field initializers are wrapped into a block.
111
 */
112
public RecoveredElement add(LambdaExpression expression, int bracketBalanceValue) {
113
	return this;
114
}
102
}
115
/*
103
/*
116
 * Record a statement
104
 * Record a statement
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java (-24 lines)
Lines 24-30 Link Here
24
import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
24
import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
25
import org.eclipse.jdt.internal.compiler.ast.Expression;
25
import org.eclipse.jdt.internal.compiler.ast.Expression;
26
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
26
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
27
import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
28
import org.eclipse.jdt.internal.compiler.ast.Statement;
27
import org.eclipse.jdt.internal.compiler.ast.Statement;
29
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
28
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
30
29
Lines 35-42 Link Here
35
34
36
	public RecoveredAnnotation[] annotations;
35
	public RecoveredAnnotation[] annotations;
37
	public int annotationCount;
36
	public int annotationCount;
38
39
	public RecoveredLambdaExpression initializerLambda;
40
	
37
	
41
	public int modifiers;
38
	public int modifiers;
42
	public int modifiersStart;
39
	public int modifiersStart;
Lines 87-110 Link Here
87
		this.fieldDeclaration.declarationSourceEnd = statement.sourceEnd;
84
		this.fieldDeclaration.declarationSourceEnd = statement.sourceEnd;
88
		this.fieldDeclaration.declarationEnd = statement.sourceEnd;
85
		this.fieldDeclaration.declarationEnd = statement.sourceEnd;
89
		return this;
86
		return this;
90
	}
91
}
92
/*
93
 * Record a lambda expression if field is expecting an initialization expression,
94
 * used for completion inside field initializers.
95
 */
96
public RecoveredElement add(LambdaExpression expression, int bracketBalanceValue) {
97
98
	if (this.alreadyCompletedFieldInitialization) {
99
		return super.add(expression, bracketBalanceValue);
100
	} else {
101
		if (expression.sourceEnd > 0)
102
				this.alreadyCompletedFieldInitialization = true;
103
		// else we may still be inside the initialization, having parsed only a part of it yet
104
		this.fieldDeclaration.initialization = expression;
105
		this.fieldDeclaration.declarationSourceEnd = expression.sourceEnd;
106
		this.fieldDeclaration.declarationEnd = expression.sourceEnd;
107
		return this.initializerLambda = new RecoveredLambdaExpression(expression, this, bracketBalanceValue);
108
	}
87
	}
109
}
88
}
110
/*
89
/*
Lines 269-277 Link Here
269
			}
248
			}
270
		}
249
		}
271
	}
250
	}
272
	if (this.initializerLambda != null)
273
		this.initializerLambda.updateParseTree();
274
	
275
	return this.fieldDeclaration;
251
	return this.fieldDeclaration;
276
}
252
}
277
/*
253
/*
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredLambdaExpression.java (-126 lines)
Lines 1-126 Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2013 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * This is an implementation of an early-draft specification developed under the Java
9
 * Community Process (JCP) and is made available for testing and evaluation purposes
10
 * only. The code is not compatible with any specification of the JCP.
11
 *
12
 * Contributors:
13
 *     IBM Corporation - initial API and implementation
14
 *******************************************************************************/
15
16
package org.eclipse.jdt.internal.compiler.parser;
17
18
import java.util.HashSet;
19
import java.util.Set;
20
21
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
22
import org.eclipse.jdt.internal.compiler.ast.Block;
23
import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
24
import org.eclipse.jdt.internal.compiler.ast.Statement;
25
26
public class RecoveredLambdaExpression extends RecoveredBlock {
27
28
	private LambdaExpression expression;
29
	private boolean haveBlockBody = false;
30
	private boolean haveExpressionBody = false;
31
	private RecoveredStatement bodyExpression;
32
	
33
	public RecoveredLambdaExpression(LambdaExpression expression, RecoveredElement parent, int bracketBalance){
34
		super(new Block(0), parent, bracketBalance); // don't have a block yet. May never have, in that event will course correct.
35
		this.expression = expression;
36
		this.expression.setBody(this.blockDeclaration);
37
	}
38
	
39
	/*
40
	 * Record a nested block declaration
41
	 */
42
	public RecoveredElement add(Block block, int bracketBalanceValue) {
43
		if (!this.haveBlockBody && !this.haveExpressionBody) {
44
			this.haveBlockBody = true;
45
			this.haveExpressionBody = false;
46
			this.blockDeclaration = block;
47
			return this; 
48
		}
49
		return super.add(block, bracketBalanceValue);
50
	}
51
52
	/*
53
	 * Record a nested block declaration
54
	 */
55
	public RecoveredElement add(LambdaExpression lambda, int bracketBalanceValue) {
56
		if (!this.haveBlockBody && !this.haveExpressionBody) {
57
			this.haveBlockBody = false;
58
			this.haveExpressionBody = true;
59
			this.bodyExpression = new RecoveredLambdaExpression(lambda, this, bracketBalanceValue);
60
			this.expression.setBody(lambda);
61
			return this.bodyExpression;
62
		}
63
		return super.add(lambda, bracketBalanceValue);
64
	}
65
	
66
	/*
67
	 * Record a statement declaration
68
	 */
69
	public RecoveredElement add(Statement stmt, int bracketBalanceValue) {
70
		return this.add(stmt, bracketBalanceValue, false);
71
	}
72
73
	/*
74
	 * Record a statement declaration
75
	 */
76
	public RecoveredElement add(Statement stmt, int bracketBalanceValue, boolean delegatedByParent) {
77
		if (!this.haveBlockBody && !this.haveExpressionBody) {
78
			this.haveBlockBody = false;
79
			this.haveExpressionBody = true;
80
			this.bodyExpression = new RecoveredStatement(stmt, this, bracketBalanceValue);
81
			this.expression.setBody(stmt);
82
			return this.bodyExpression;
83
		}
84
		return super.add(stmt, bracketBalanceValue, delegatedByParent);
85
	}
86
	
87
	/*
88
	 * Answer the associated parsed structure
89
	 */
90
	public ASTNode parseTree(){
91
		return updatedLambdaExpression(0, new HashSet());
92
	}
93
94
	public LambdaExpression updatedLambdaExpression(int depth, Set knownTypes) {
95
		if (this.haveBlockBody)
96
			this.expression.setBody(super.updatedStatement(depth, knownTypes));
97
		else if (this.bodyExpression != null)
98
			this.expression.setBody(this.bodyExpression.updatedStatement(depth, knownTypes));
99
		return this.expression;
100
	}
101
	/*
102
	 * Rebuild a statement from the nested structure which is in scope
103
	 */
104
	public Statement updatedStatement(int depth, Set knownTypes){
105
		return updatedLambdaExpression(depth, knownTypes);
106
	}
107
	/*
108
	 * Final update the corresponding parse node
109
	 */
110
	public void updateParseTree(){
111
		updatedLambdaExpression(0, new HashSet());
112
	}
113
	/*
114
	 * Rebuild a flattened block from the nested structure which is in scope
115
	 */
116
	public Statement updateStatement(int depth, Set knownTypes){
117
		return updatedLambdaExpression(depth, knownTypes);
118
	}
119
	
120
	public String toString(int tab) {
121
		StringBuffer result = new StringBuffer(tabString(tab));
122
		result.append("Recovered Lambda Expression:\n"); //$NON-NLS-1$
123
		this.expression.print(tab + 1, result);
124
		return result.toString();
125
	}
126
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredLocalVariable.java (-19 lines)
Lines 21-27 Link Here
21
import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
21
import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
22
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
22
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
23
import org.eclipse.jdt.internal.compiler.ast.Expression;
23
import org.eclipse.jdt.internal.compiler.ast.Expression;
24
import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
25
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
24
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
26
import org.eclipse.jdt.internal.compiler.ast.Statement;
25
import org.eclipse.jdt.internal.compiler.ast.Statement;
27
26
Lines 29-35 Link Here
29
28
30
	public RecoveredAnnotation[] annotations;
29
	public RecoveredAnnotation[] annotations;
31
	public int annotationCount;
30
	public int annotationCount;
32
	private RecoveredLambdaExpression initializer;
33
	public int modifiers;
31
	public int modifiers;
34
	public int modifiersStart;
32
	public int modifiersStart;
35
33
Lines 53-73 Link Here
53
		this.localDeclaration.declarationSourceEnd = stmt.sourceEnd;
51
		this.localDeclaration.declarationSourceEnd = stmt.sourceEnd;
54
		this.localDeclaration.declarationEnd = stmt.sourceEnd;
52
		this.localDeclaration.declarationEnd = stmt.sourceEnd;
55
		return this;
53
		return this;
56
	}
57
}
58
/*
59
 * Record an expression statement if local variable is expecting an initialization expression.
60
 */
61
public RecoveredElement add(LambdaExpression expression, int bracketBalanceValue) {
62
63
	if (this.alreadyCompletedLocalInitialization) {
64
		return this;
65
	} else {
66
		this.alreadyCompletedLocalInitialization = true;
67
		this.localDeclaration.initialization = expression;
68
		this.localDeclaration.declarationSourceEnd = expression.sourceEnd;
69
		this.localDeclaration.declarationEnd = expression.sourceEnd;
70
		return this.initializer = new RecoveredLambdaExpression(expression, this, bracketBalanceValue);
71
	}
54
	}
72
}
55
}
73
public void attach(RecoveredAnnotation[] annots, int annotCount, int mods, int modsSourceStart) {
56
public void attach(RecoveredAnnotation[] annots, int annotCount, int mods, int modsSourceStart) {
Lines 133-140 Link Here
133
			this.localDeclaration.declarationSourceStart = start;
116
			this.localDeclaration.declarationSourceStart = start;
134
		}
117
		}
135
	}
118
	}
136
	if (this.initializer != null)
137
		this.initializer.updateParseTree();
138
	return this.localDeclaration;
119
	return this.localDeclaration;
139
}
120
}
140
/*
121
/*
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java (-7 lines)
Lines 17-44 Link Here
17
import java.util.Set;
17
import java.util.Set;
18
18
19
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
19
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
20
import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
21
import org.eclipse.jdt.internal.compiler.ast.Statement;
20
import org.eclipse.jdt.internal.compiler.ast.Statement;
22
21
23
public class RecoveredStatement extends RecoveredElement {
22
public class RecoveredStatement extends RecoveredElement {
24
23
25
	public Statement statement;
24
	public Statement statement;
26
	public RecoveredLambdaExpression subExpression;
27
	
25
	
28
public RecoveredStatement(Statement statement, RecoveredElement parent, int bracketBalance){
26
public RecoveredStatement(Statement statement, RecoveredElement parent, int bracketBalance){
29
	super(parent, bracketBalance);
27
	super(parent, bracketBalance);
30
	this.statement = statement;
28
	this.statement = statement;
31
}
29
}
32
30
33
public RecoveredElement add(LambdaExpression expression, int bracketBalanceValue) {
34
	return this.subExpression = new RecoveredLambdaExpression(expression, this, bracketBalanceValue);
35
}
36
/*
31
/*
37
 * Answer the associated parsed structure
32
 * Answer the associated parsed structure
38
 */
33
 */
39
public ASTNode parseTree() {
34
public ASTNode parseTree() {
40
	if (this.subExpression != null)
41
		this.subExpression.updateParseTree();
42
	return this.statement;
35
	return this.statement;
43
}
36
}
44
/*
37
/*
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java (-5 / +109 lines)
Lines 19-24 Link Here
19
import org.eclipse.jdt.core.compiler.CharOperation;
19
import org.eclipse.jdt.core.compiler.CharOperation;
20
import org.eclipse.jdt.core.compiler.InvalidInputException;
20
import org.eclipse.jdt.core.compiler.InvalidInputException;
21
import org.eclipse.jdt.internal.compiler.CompilationResult;
21
import org.eclipse.jdt.internal.compiler.CompilationResult;
22
import org.eclipse.jdt.internal.compiler.ast.Statement;
22
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
23
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
23
import org.eclipse.jdt.internal.compiler.util.Util;
24
import org.eclipse.jdt.internal.compiler.util.Util;
24
25
Lines 4241-4252 Link Here
4241
	static int IntersectionCastRule = 0;
4242
	static int IntersectionCastRule = 0;
4242
	static int ReferenceExpressionRule = 0;
4243
	static int ReferenceExpressionRule = 0;
4243
	static int VarargTypeAnnotationsRule  = 0;
4244
	static int VarargTypeAnnotationsRule  = 0;
4245
	static int BlockStatementoptRule = 0;
4244
	
4246
	
4245
	static Goal LambdaParameterListGoal;
4247
	static Goal LambdaParameterListGoal;
4246
	static Goal IntersectionCastGoal;
4248
	static Goal IntersectionCastGoal;
4247
	static Goal VarargTypeAnnotationGoal;
4249
	static Goal VarargTypeAnnotationGoal;
4248
	static Goal ReferenceExpressionGoal;
4250
	static Goal ReferenceExpressionGoal;
4249
	
4251
	static Goal BlockStatementoptGoal;
4250
	static {
4252
	static {
4251
		
4253
		
4252
		for (int i = 1; i <= ParserBasicInformation.NUM_RULES; i++) {  // 0 == $acc
4254
		for (int i = 1; i <= ParserBasicInformation.NUM_RULES; i++) {  // 0 == $acc
Lines 4261-4272 Link Here
4261
			else 
4263
			else 
4262
			if ("TypeAnnotations".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$
4264
			if ("TypeAnnotations".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$
4263
				VarargTypeAnnotationsRule = i;
4265
				VarargTypeAnnotationsRule = i;
4266
			else
4267
			if ("BlockStatementopt".equals(Parser.name[Parser.non_terminal_index[Parser.lhs[i]]])) //$NON-NLS-1$
4268
				BlockStatementoptRule = i;
4269
					
4264
		}
4270
		}
4265
		
4271
		
4266
		LambdaParameterListGoal =  new Goal(TokenNameARROW, new int[] { TokenNameARROW }, LambdaParameterListRule);
4272
		LambdaParameterListGoal =  new Goal(TokenNameARROW, new int[] { TokenNameARROW }, LambdaParameterListRule);
4267
		IntersectionCastGoal =     new Goal(TokenNameLPAREN, followSetOfCast(), IntersectionCastRule);
4273
		IntersectionCastGoal =     new Goal(TokenNameLPAREN, followSetOfCast(), IntersectionCastRule);
4268
		VarargTypeAnnotationGoal = new Goal(TokenNameAT, new int[] { TokenNameELLIPSIS }, VarargTypeAnnotationsRule);
4274
		VarargTypeAnnotationGoal = new Goal(TokenNameAT, new int[] { TokenNameELLIPSIS }, VarargTypeAnnotationsRule);
4269
		ReferenceExpressionGoal =  new Goal(TokenNameLESS, new int[] { TokenNameCOLON_COLON }, ReferenceExpressionRule);
4275
		ReferenceExpressionGoal =  new Goal(TokenNameLESS, new int[] { TokenNameCOLON_COLON }, ReferenceExpressionRule);
4276
		BlockStatementoptGoal =    new Goal(TokenNameLBRACE, new int [0], BlockStatementoptRule);
4270
	}
4277
	}
4271
4278
4272
4279
Lines 4279-4288 Link Here
4279
	boolean hasBeenReached(int act, int token) {
4286
	boolean hasBeenReached(int act, int token) {
4280
		/*
4287
		/*
4281
		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$
4288
		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$
4282
				Parser.name[Parser.terminal_index[token]]);
4289
					Parser.name[Parser.terminal_index[token]]);
4283
		*/
4290
		*/
4284
		if (act == this.rule) {
4291
		if (act == this.rule) {
4285
			for (int i = 0, length = this.follow.length; i < length; i++)
4292
			final int length = this.follow.length;
4293
			if (length == 0)
4294
				return true;
4295
			for (int i = 0; i < length; i++)
4286
				if (this.follow[i] == token)
4296
				if (this.follow[i] == token)
4287
					return true;
4297
					return true;
4288
		}
4298
		}
Lines 4332-4338 Link Here
4332
				} else if (act > ERROR_ACTION) { /* shift-reduce */
4342
				} else if (act > ERROR_ACTION) { /* shift-reduce */
4333
					this.unstackedAct = act;
4343
					this.unstackedAct = act;
4334
					try {
4344
					try {
4335
						this.currentToken = this.scanner.getNextToken();
4345
					this.currentToken = this.scanner.getNextToken();
4336
					} finally {
4346
					} finally {
4337
						this.unstackedAct = ERROR_ACTION;
4347
						this.unstackedAct = ERROR_ACTION;
4338
					}
4348
					}
Lines 4341-4347 Link Here
4341
				    if (act < ACCEPT_ACTION) { /* shift */
4351
				    if (act < ACCEPT_ACTION) { /* shift */
4342
				    	this.unstackedAct = act;
4352
				    	this.unstackedAct = act;
4343
						try {
4353
						try {
4344
							this.currentToken = this.scanner.getNextToken();
4354
				    	this.currentToken = this.scanner.getNextToken();
4345
						} finally {
4355
						} finally {
4346
							this.unstackedAct = ERROR_ACTION;
4356
							this.unstackedAct = ERROR_ACTION;
4347
						}
4357
						}
Lines 4493-4496 Link Here
4493
	}
4503
	}
4494
	return token;
4504
	return token;
4495
}
4505
}
4506
4507
protected boolean isAtAssistIdentifier() {
4508
	return false;
4509
}
4510
4511
// Position the scanner at the next block statement and return the start token. We recognize empty statements.
4512
public int fastForward(Statement unused) {
4513
	
4514
	int token;
4515
4516
	while (true) {
4517
		try {
4518
			token = getNextToken();
4519
		} catch (InvalidInputException e) {
4520
			return TokenNameEOF;
4521
		}
4522
		/* FOLLOW map of BlockStatement, since the non-terminal is recursive is a super set of its own FIRST set. 
4523
	   	   We use FOLLOW rather than FIRST since we want to recognize empty statements. i.e if (x > 10) {  x = 0 }
4524
		*/
4525
		switch(token) {
4526
			case TokenNameIdentifier:
4527
				if (isAtAssistIdentifier()) // do not fast forward past the assist identifier ! We don't handle collections as of now.
4528
					return token;
4529
				//$FALL-THROUGH$
4530
			case TokenNameabstract:
4531
			case TokenNameassert:
4532
			case TokenNameboolean:
4533
			case TokenNamebreak:
4534
			case TokenNamebyte:
4535
			case TokenNamecase:
4536
			case TokenNamechar:
4537
			case TokenNameclass:
4538
			case TokenNamecontinue:
4539
			case TokenNamedefault:
4540
			case TokenNamedo:
4541
			case TokenNamedouble:
4542
			case TokenNameenum:
4543
			case TokenNamefalse:
4544
			case TokenNamefinal:
4545
			case TokenNamefloat:
4546
			case TokenNamefor:
4547
			case TokenNameif:
4548
			case TokenNameint:
4549
			case TokenNameinterface:
4550
			case TokenNamelong:
4551
			case TokenNamenative:
4552
			case TokenNamenew:
4553
			case TokenNamenull:
4554
			case TokenNameprivate:
4555
			case TokenNameprotected:
4556
			case TokenNamepublic:
4557
			case TokenNamereturn:
4558
			case TokenNameshort:
4559
			case TokenNamestatic:
4560
			case TokenNamestrictfp:
4561
			case TokenNamesuper:
4562
			case TokenNameswitch:
4563
			case TokenNamesynchronized:
4564
			case TokenNamethis:
4565
			case TokenNamethrow:
4566
			case TokenNametransient:
4567
			case TokenNametrue:
4568
			case TokenNametry:
4569
			case TokenNamevoid:
4570
			case TokenNamevolatile:
4571
			case TokenNamewhile:
4572
			case TokenNameIntegerLiteral: // ??!
4573
			case TokenNameLongLiteral:
4574
			case TokenNameFloatingPointLiteral:
4575
			case TokenNameDoubleLiteral:
4576
			case TokenNameCharacterLiteral:
4577
			case TokenNameStringLiteral:
4578
			case TokenNamePLUS_PLUS:
4579
			case TokenNameMINUS_MINUS:
4580
			case TokenNameLESS:
4581
			case TokenNameLPAREN:
4582
			case TokenNameLBRACE:
4583
			case TokenNameAT:
4584
			case TokenNameBeginLambda:
4585
			case TokenNameAT308:
4586
				if(getVanguardParser().parse(Goal.BlockStatementoptGoal) == VanguardParser.SUCCESS)
4587
					return token;
4588
				break;
4589
			case TokenNameSEMICOLON:
4590
			case TokenNameEOF:
4591
				return token;
4592
			case TokenNameRBRACE: // simulate empty statement.
4593
				ungetToken(token);
4594
				return TokenNameSEMICOLON;
4595
			default:
4596
				break;
4597
		}
4598
	}
4599
}
4496
}
4600
}

Return to bug 422468