Merge remote-tracking branch 'origin/master' into BETA_JAVA16

Change-Id: I7d3092fb2520e1e0b348a73692d1a6865ac0a708
diff --git a/org.eclipse.jdt.debug.tests/java8/Bug571230.java b/org.eclipse.jdt.debug.tests/java8/Bug571230.java
new file mode 100644
index 0000000..52886cd
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/java8/Bug571230.java
@@ -0,0 +1,9 @@
+import java.util.ArrayList;
+import java.util.List;
+
+public class Bug571230 {
+    public static void main(String[] args) {
+    	List<Integer> list = new ArrayList<>();
+    	System.out.println(list);
+    }
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
index b6c7744..ab32cb6 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
@@ -487,6 +487,7 @@
 				cfgs.add(createLaunchConfiguration(jp, "Bug564486"));
 				cfgs.add(createLaunchConfiguration(jp, "Bug564801"));
 				cfgs.add(createLaunchConfiguration(jp, "Bug567801"));
+				cfgs.add(createLaunchConfiguration(jp, "Bug571230"));
 	    		loaded18 = true;
 	    		waitForBuild();
 	        }
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
index 2334837..ff5a253 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
@@ -90,6 +90,7 @@
 import org.eclipse.jdt.debug.tests.core.WatchExpressionTests;
 import org.eclipse.jdt.debug.tests.core.WorkingDirectoryTests;
 import org.eclipse.jdt.debug.tests.core.WorkspaceSourceContainerTests;
+import org.eclipse.jdt.debug.tests.eval.BlockStatementEvaluationTests;
 import org.eclipse.jdt.debug.tests.eval.GeneralEvalTests;
 import org.eclipse.jdt.debug.tests.eval.GenericsEvalTests;
 import org.eclipse.jdt.debug.tests.eval.LambdaVariableTest;
@@ -328,6 +329,7 @@
 
 	//add the complete eval suite
 		addTest(new TestSuite(GeneralEvalTests.class));
+		addTest(new TestSuite(BlockStatementEvaluationTests.class));
 		if (JavaProjectHelper.isJava8Compatible()) {
 			addTest(new TestSuite(LambdaVariableTest.class));
 		}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/EvalTestSuite.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/EvalTestSuite.java
index aca0228..db2b3b0 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/EvalTestSuite.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/EvalTestSuite.java
@@ -19,6 +19,7 @@
 import org.eclipse.jdt.debug.tests.eval.ArrayAllocationTests;
 import org.eclipse.jdt.debug.tests.eval.ArrayAssignmentTests;
 import org.eclipse.jdt.debug.tests.eval.ArrayValueTests;
+import org.eclipse.jdt.debug.tests.eval.BlockStatementEvaluationTests;
 import org.eclipse.jdt.debug.tests.eval.BooleanAssignmentOperatorsTests;
 import org.eclipse.jdt.debug.tests.eval.BooleanOperatorsTests;
 import org.eclipse.jdt.debug.tests.eval.ByteAssignmentOperatorsTests;
@@ -231,6 +232,7 @@
 		addTest(new TestSuite(LoopTests.class));
 		addTest(new TestSuite(LabelTests.class));
 		addTest(new TestSuite(TestsAnonymousClassVariable.class));
+		addTest(new TestSuite(BlockStatementEvaluationTests.class));
 
 		addTest(new TestSuite(TestsBreakpointConditions.class));
 
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/BlockStatementEvaluationTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/BlockStatementEvaluationTests.java
new file mode 100644
index 0000000..6610997
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/BlockStatementEvaluationTests.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Gayan Perera and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Gayan Perera - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.debug.tests.eval;
+
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.debug.core.IJavaThread;
+import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+
+public class BlockStatementEvaluationTests extends AbstractDebugTest {
+	private IJavaThread javaThread;
+
+	@Override
+	protected IJavaProject getProjectContext() {
+		return get18Project();
+	}
+
+	public BlockStatementEvaluationTests(String name) {
+		super(name);
+	}
+
+	public void testEvaluate_ForLoopBlock_ShouldEvaluate() throws Exception {
+		debugWithBreakpoint("Bug571230", 7);
+		String snippet = "for(int i = 0; i < 5; i++){\n" + "	list.add(i);\n" + "}";
+
+		doEval(javaThread, snippet);
+
+		snippet = "list.size()";
+		IValue value = doEval(javaThread, snippet);
+		assertEquals("wrong result : " + value.getValueString(), "5", value.getValueString());
+	}
+
+	public void testEvaluate_ForLoopBlockWithReturn_ShouldEvaluate() throws Exception {
+		debugWithBreakpoint("Bug571230", 7);
+		String snippet = "for(int i = 0; i < 5; i++){\n" + "	list.add(i);\n" + "	return list.size();\n" + "}";
+
+		IValue value = doEval(javaThread, snippet);
+		assertEquals("wrong result : " + value.getValueString(), "1", value.getValueString());
+	}
+
+	public void testEvaluate_ForLoopBlockWithReturnWithExpressionAtEnd_ShouldEvaluate() throws Exception {
+		debugWithBreakpoint("Bug571230", 7);
+		String snippet = "for(int i = 0; i < 5; i++){\n" + "	list.add(i);\n" + "	return list;\n" + "}\n" + "list.size()";
+
+		IValue value = doEval(javaThread, snippet);
+		assertEquals("wrong result : " + value.getReferenceTypeName(), "java.util.ArrayList<E>", value.getReferenceTypeName());
+	}
+
+	public void testEvaluate_IfBlock_ShouldEvaluate() throws Exception {
+		debugWithBreakpoint("Bug571230", 7);
+		String snippet = "if(list.isEmpty()){\n" + "	list.add(10);\n" + "}";
+
+		doEval(javaThread, snippet);
+
+		snippet = "list.size() > 0";
+		IValue value = doEval(javaThread, snippet);
+		assertEquals("wrong result : " + value.getValueString(), "true", value.getValueString());
+	}
+
+	public void testEvaluate_IfElseWithReturnBlock_ShouldEvaluate() throws Exception {
+		debugWithBreakpoint("Bug571230", 7);
+		String snippet = "if(list.isEmpty()){\n" + "	list.add(10);\n" + "} else {\n" + "	return 10;" + "}";
+
+		doEval(javaThread, snippet);
+
+		snippet = "list.size() > 0";
+		IValue value = doEval(javaThread, snippet);
+		assertEquals("wrong result : " + value.getValueString(), "true", value.getValueString());
+	}
+
+	public void testEvaluate_IfElseWithReturnBlock_WithExpressionAtEnd_ShouldEvaluateExpression() throws Exception {
+		debugWithBreakpoint("Bug571230", 7);
+		String snippet = "if(list.isEmpty()){\n" + "	list.add(10);\n" + "} else {\n" + "	return 10;" + "}\n" + "list.size() > 0";
+
+		IValue value = doEval(javaThread, snippet);
+		assertEquals("wrong result : " + value.getValueString(), "true", value.getValueString());
+	}
+
+	private void debugWithBreakpoint(String testClass, int lineNumber) throws Exception {
+		createLineBreakpoint(lineNumber, testClass);
+		javaThread = launchToBreakpoint(testClass);
+		assertNotNull("The program did not suspend", javaThread);
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		try {
+			terminateAndRemove(javaThread);
+		} finally {
+			super.tearDown();
+			removeAllBreakpoints();
+		}
+	}
+}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/launcher/LauncherMessages.properties b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/launcher/LauncherMessages.properties
index fac6a6f..3422552 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/launcher/LauncherMessages.properties
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/launcher/LauncherMessages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-#  Copyright (c) 2000, 2018 IBM Corporation and others.
+#  Copyright (c) 2000, 2021 IBM Corporation and others.
 #
 #  This program and the accompanying materials
 #  are made available under the terms of the Eclipse Public License 2.0
@@ -34,7 +34,7 @@
 VMArgumentsBlock_0=Use the -&XstartOnFirstThread argument when launching with SWT
 VMArgumentsBlock_1=Use temporary JAR to speci&fy classpath (to avoid classpath length limitations)
 VMArgumentsBlock_2=Use the -XX:+ShowCode&DetailsInExceptionMessages argument when launching
-VMArgumentsBlock_3=Use @&argfile when launching
+VMArgumentsBlock_3=Use @a&rgfile when launching
 VMArgumentsBlock_VM_Arguments=VM Arguments
 
 JavaConnectTab__Allow_termination_of_remote_VM_6=&Allow termination of remote VM
diff --git a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/RemoteEvaluatorBuilder.java b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/RemoteEvaluatorBuilder.java
index 149ff12..1701071 100644
--- a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/RemoteEvaluatorBuilder.java
+++ b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/RemoteEvaluatorBuilder.java
@@ -250,9 +250,9 @@
 		}
 
 		private boolean isParentInLocalBinding(ASTNode parent) {
-			if (parent instanceof Name) {
+			if (parent instanceof QualifiedName) {
 				// this will avoid unwanted upward traversals
-				if (isLocalBinding(((Name) parent).resolveBinding())) {
+				if (isLocalBinding(((QualifiedName) parent).getQualifier().resolveBinding())) {
 					return true;
 				}
 				// traverse upstream to see if a parent is already handled
@@ -1509,7 +1509,7 @@
 			// when having code like arr.length the length is identified as a field variable. But since the arr is
 			// already pushed as a variable we don't need to handle length here. So if we have chained field access like
 			// obj.f1.f2 we will only push the obj as a variable.
-			if (!isLocalBinding(binding) && isParentInLocalBinding(node.getParent())) {
+			if (!isLocalBinding(binding) && !isParentInLocalBinding(node.getParent())) {
 				if (binding instanceof IVariableBinding) {
 					IVariableBinding vb = ((IVariableBinding) binding);
 					// For future optimization: Check for duplicates, so same value is only bound once
diff --git a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationSourceGenerator.java b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationSourceGenerator.java
index c733adf..64b1dc8 100644
--- a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationSourceGenerator.java
+++ b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationSourceGenerator.java
@@ -124,8 +124,12 @@
 		String returnString = "return "; //$NON-NLS-1$
 		int index = codeSnippet.lastIndexOf(returnString);
 		if (index == -1){
-			if (needsReturn(lastSentence))
+			// empty lastSentence means we have statement block above which requires a empty return
+			if (needsReturn(lastSentence)) {
 				wordBuffer.append(returnString);
+			} else if (lastSentence.isBlank()) {
+				wordBuffer.append(returnString + ';');
+			}
 		}
 		else if (index > i){
 			if (!Character.isWhitespace(chars[index-1]) || !(Character.isWhitespace(chars[index+6]) || chars[index+6] == '}')){
@@ -147,11 +151,12 @@
 		else if (chars[chars.length -1] !=';' && chars[chars.length -1] =='}'){
 			int j = lastSentence.lastIndexOf('=') ;
 			int k = lastSentence.lastIndexOf("==") ; //$NON-NLS-1$
-			if ( j != -1 && (j!=k))
+			if (j != -1 && (j != k))
 				wordBuffer.append(';');
 		}
 		
-		if(lastSentence.length() <= 1 && needsReturn(wordBuffer.toString())) {
+		// make sure last char is not at end of a block before treating this as a statement
+		if (lastSentence.length() <= 1 && needsReturn(wordBuffer.toString())) {
 			wordBuffer.insert(0, returnString).append(' ');
 		}
 		
@@ -192,7 +197,9 @@
 				else if (count == 0 && (token == ITerminalSymbols.TokenNamethrow)){
 					return false;
 				}
-				else if ( count == 0 && (token == ITerminalSymbols.TokenNameif || token == ITerminalSymbols.TokenNamewhile || token == ITerminalSymbols.TokenNamedo)) {
+				else if (count == 0 && (token == ITerminalSymbols.TokenNameif || token == ITerminalSymbols.TokenNamewhile
+						|| token == ITerminalSymbols.TokenNamedo || token == ITerminalSymbols.TokenNamefor || token == ITerminalSymbols.TokenNametry
+						|| token == ITerminalSymbols.TokenNameswitch)) {
 					return false;
 				}
 				else if (count ==1 && (token == ITerminalSymbols.TokenNameLBRACE || token == ITerminalSymbols.TokenNameEQUAL)){