Bug 574882 - [content assist] No content assist for templates on last
line in lambda block

Change-Id: I5cf1ef440b541131eee9dd7a1fe5012a7e030178
Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/183573
Tested-by: JDT Bot <jdt-bot@eclipse.org>
Reviewed-by: Stephan Herrmann <stephan.herrmann@berlin.de>
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java
index 342d842..90aad65 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java
@@ -5979,4 +5979,49 @@
 	assertResults("xyz[FIELD_REF]{xyz, LLambdaFreeze2;, I, xyz, null, 82}",
 			result);
 }
+public void testBug574882() throws Exception {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy(
+			"Completion/src/ForLoop.java",
+			"import java.util.concurrent.ExecutorService;\n" +
+			"import java.util.concurrent.Executors;\n" +
+			"import java.util.concurrent.atomic.AtomicInteger;\n" +
+			"\n" +
+			"public class ForLoop {\n" +
+			"	public static void main(String[] args) {\n" +
+			"		AtomicInteger executions = new AtomicInteger();\n" +
+			"		ExecutorService pool = Executors.newFixedThreadPool(1);\n" +
+			"		for (int i = 0; i < 42; i++) {\n" +
+			"			pool.execute(() -> {\n" +
+			"				// sys| offers sysout etc templates here \n" +
+			"				executions.incrementAndGet();\n" +
+			"				// sys | content assist doesn't offer \"sysout\" etc templates here\n" +
+			"			});\n" +
+			"		}\n" +
+			"	}\n" +
+			"}\n");
+
+	CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(false, true, false, false, false, false, false, false);
+	requestor.allowAllRequiredProposals();
+	String str = this.workingCopies[0].getSource();
+	String completeBefore = "// sys | content assist doesn't offer";
+	int cursorLocation = str.lastIndexOf(completeBefore);
+	this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+	String result = requestor.getResults();
+	assertResults("ForLoop[TYPE_REF]{ForLoop, , LForLoop;, null, null, 52}\n" +
+			"args[LOCAL_VARIABLE_REF]{args, null, [Ljava.lang.String;, args, null, 52}\n" +
+			"executions[LOCAL_VARIABLE_REF]{executions, null, LAtomicInteger;, executions, null, 52}\n" +
+			"i[LOCAL_VARIABLE_REF]{i, null, I, i, null, 52}\n" +
+			"main[METHOD_REF]{main(), LForLoop;, ([Ljava.lang.String;)V, main, (args), 52}\n" +
+			"pool[LOCAL_VARIABLE_REF]{pool, null, Ljava.util.concurrent.ExecutorService;, pool, null, 52}",
+			result);
+	assertEquals("completion offset=449\n" +
+			"completion range=[449, 448]\n" +
+			"completion token=\"\"\n" +
+			"completion token kind=TOKEN_KIND_NAME\n" +
+			"expectedTypesSignatures=null\n" +
+			"expectedTypesKeys=null\n" +
+			"completion token location={STATEMENT_START}", // this is required for sysout template proposal
+			requestor.getContext());
+}
 }
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeDetector.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeDetector.java
index b159982..6aeda7a 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeDetector.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeDetector.java
@@ -36,9 +36,8 @@
 		protected boolean visitNode(ASTNode node) {
 			if (node == this.searchFor) {
 				this.found = true;
-				return false;
 			}
-			return true;
+			return !this.found;
 		}
 	}
 	public static boolean findAny(CompilationUnitDeclaration unit, ASTNode searchFor) {
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnAnnotationMemberValuePair.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnAnnotationMemberValuePair.java
index 6e568bd..06ffbcc 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnAnnotationMemberValuePair.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnAnnotationMemberValuePair.java
@@ -13,10 +13,12 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.codeassist.complete;
 
+import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
 import org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 
 public class CompletionOnAnnotationMemberValuePair extends NormalAnnotation {
@@ -57,4 +59,16 @@
 
 		return output;
 	}
+
+	@Override
+	public void traverse(ASTVisitor visitor, ClassScope scope) {
+		super.traverse(visitor, scope);
+		this.completedMemberValuePair.traverse(visitor, scope);
+	}
+
+	@Override
+	public void traverse(ASTVisitor visitor, BlockScope scope) {
+		super.traverse(visitor, scope);
+		this.completedMemberValuePair.traverse(visitor, scope);
+	}
 }
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
index 0d1eea0..ff22726 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
@@ -344,7 +344,7 @@
 	CompletionNodeDetector detector = new CompletionNodeDetector(this.assistNode, node);
 	if (detector.containsCompletionNode()) {
 		this.assistNodeParent = detector.getCompletionNodeParent();
-		if (this.assistNodeParent == null && node instanceof Statement)
+		if (this.assistNodeParent == null && node instanceof Statement && node != this.assistNode)
 			this.assistNodeParent = node;
 	}
 }
@@ -6144,7 +6144,7 @@
 			}
 			AbstractMethodDeclaration method = (AbstractMethodDeclaration) this.referenceContext;
 			if (statement != null && isInsideBody(statement, method)
-					&& this.assistNode != null && !CompletionNodeDetector.findAny(cud, statement))
+					&& this.assistNode != null && !CompletionNodeDetector.findAny(cud, this.assistNode))
 			{
 				// automaton ended right before transferring statements into the method?
 				if (method.statements == null) {