Bug 553149 - [14] Pattern instanceof - Code Select

Change-Id: I38cb22c813675cd665b35da83c71d876ede2aab6
Signed-off-by: Jay Arthanareeswaran <jarthana@in.ibm.com>
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/PatternMatchingSelectionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/PatternMatchingSelectionTest.java
new file mode 100644
index 0000000..eac50c6
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/PatternMatchingSelectionTest.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2020 IBM Corporation 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:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.tests.compiler.parser;
+
+import org.eclipse.jdt.core.JavaModelException;
+
+import junit.framework.Test;
+
+public class PatternMatchingSelectionTest extends AbstractSelectionTest {
+static {
+//		TESTS_NUMBERS = new int[] { 1 };
+//		TESTS_NAMES = new String[] { "test005" };
+}
+public static Test suite() {
+	return buildMinimalComplianceTestSuite(PatternMatchingSelectionTest.class, F_15);
+}
+
+public PatternMatchingSelectionTest(String testName) {
+	super(testName);
+}
+public void test001() throws JavaModelException {
+	String string =  "public class X {\n"
+			+ "    protected Object x_ = \"FIELD X\";\n"
+			+ "    @SuppressWarnings(\"preview\")\n"
+			+ "	   public void f(Object obj, boolean b) {\n"
+			+ "        if ((x_ instanceof String y) && y.length() > 0) {\n"
+			+ "            System.out.println(y.toLowerCase());\n"
+			+ "        }\n"
+			+ "    }\n"
+			+ "}";
+
+	String selection = "x_";
+	String selectKey = "<SelectOnName:";
+	String expectedSelection = selectKey + selection + ">";
+
+	String selectionIdentifier = "x_";
+	String expectedUnitDisplayString =
+			"public class X {\n" +
+					"  protected Object x_;\n" +
+					"  public X() {\n" +
+					"  }\n" +
+					"  public @SuppressWarnings(\"preview\") void f(Object obj, boolean b) {\n" +
+					"    <SelectOnName:x_>;\n" +
+					"  }\n" +
+					"}\n";
+	String expectedReplacedSource = "x_";
+	String testName = "X.java";
+
+	int selectionStart = string.lastIndexOf(selection);
+	int selectionEnd = string.lastIndexOf(selection) + selection.length() - 1;
+
+	checkMethodParse(string.toCharArray(), selectionStart, selectionEnd, expectedSelection, expectedUnitDisplayString,
+			selectionIdentifier, expectedReplacedSource, testName);
+}
+public void test002() throws JavaModelException {
+	String string =  "public class X {\n"
+			+ "    protected Object x_ = \"FIELD X\";\n"
+			+ "    @SuppressWarnings(\"preview\")\n"
+			+ "	   public void f(Object obj, boolean b) {\n"
+			+ "        if ((x_ instanceof String y_) && y_.length() > 0) {\n"
+			+ "            System.out.println(y_.toLowerCase());\n"
+			+ "        }\n"
+			+ "    }\n"
+			+ "}";
+
+	String selection = "y_";
+	String selectKey = "<SelectOnName:";
+	String expectedSelection = selectKey + selection + ">";
+
+	String selectionIdentifier = "y_";
+	String expectedUnitDisplayString =
+			"public class X {\n" +
+					"  protected Object x_;\n" +
+					"  public X() {\n" +
+					"  }\n" +
+					"  public @SuppressWarnings(\"preview\") void f(Object obj, boolean b) {\n" +
+					"    final String y_;\n" +
+					"    {\n" +
+					"      <SelectOnName:y_>;\n" +
+					"    }\n" +
+					"  }\n" +
+					"}\n";
+	String expectedReplacedSource = "y_";
+	String testName = "X.java";
+
+	int selectionStart = string.lastIndexOf(selection);
+	int selectionEnd = string.lastIndexOf(selection) + selection.length() - 1;
+
+	checkMethodParse(string.toCharArray(), selectionStart, selectionEnd, expectedSelection, expectedUnitDisplayString,
+			selectionIdentifier, expectedReplacedSource, testName);
+}
+public void test003() throws JavaModelException {
+	String string =  "public class X {\n"
+			+ "    protected Object x_ = \"FIELD X\";\n"
+			+ "    @SuppressWarnings(\"preview\")\n"
+			+ "	   public void f(Object obj, boolean b) {\n"
+			+ "        b = (x_ instanceof String y_) && (y_.length() > 0);\n"
+			+ "    }\n"
+			+ "}";
+
+	String selection = "y_";
+	String selectKey = "<SelectOnName:";
+	String expectedSelection = selectKey + selection + ">";
+
+	String selectionIdentifier = "y_";
+	String expectedUnitDisplayString =
+			"public class X {\n" +
+					"  protected Object x_;\n" +
+					"  public X() {\n" +
+					"  }\n" +
+					"  public @SuppressWarnings(\"preview\") void f(Object obj, boolean b) {\n" +
+					"    final String y_;\n" +
+					"    <SelectOnName:y_>;\n" +
+					"  }\n" +
+					"}\n";
+	String expectedReplacedSource = "y_";
+	String testName = "X.java";
+
+	int selectionStart = string.lastIndexOf(selection);
+	int selectionEnd = string.lastIndexOf(selection) + selection.length() - 1;
+
+	checkMethodParse(string.toCharArray(), selectionStart, selectionEnd, expectedSelection, expectedUnitDisplayString,
+			selectionIdentifier, expectedReplacedSource, testName);
+}
+}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java
index f6ba112..64e6478 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java
@@ -106,7 +106,7 @@
 		ResolveTests18.class,
 		ResolveTests9.class,
 		ResolveTests10.class,
-		ResolveTests12.class,
+		ResolveTests12To15.class,
 		SelectionJavadocModelTests.class,
 
 		// Support for completion tests
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests12.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests12To15.java
similarity index 81%
rename from org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests12.java
rename to org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests12To15.java
index fa80a70..21a7dd6 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests12.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests12To15.java
@@ -21,7 +21,7 @@
 
 import junit.framework.Test;
 
-public class ResolveTests12 extends AbstractJavaModelTests {
+public class ResolveTests12To15 extends AbstractJavaModelTests {
 	ICompilationUnit wc = null;
 
 static {
@@ -30,9 +30,9 @@
 	// TESTS_RANGE = new int[] { 16, -1 };
 }
 public static Test suite() {
-	return buildModelTestSuite(ResolveTests12.class);
+	return buildModelTestSuite(ResolveTests12To15.class);
 }
-public ResolveTests12(String name) {
+public ResolveTests12To15(String name) {
 	super(name);
 }
 @Override
@@ -43,6 +43,7 @@
 public void setUpSuite() throws Exception {
 	super.setUpSuite();
 	setUpJavaProject("Resolve", "12", false);
+	setUpJavaProject("Resolve15", "15", false);
 	waitUntilIndexesReady();
 }
 @Override
@@ -53,6 +54,7 @@
 @Override
 public void tearDownSuite() throws Exception {
 	deleteProject("Resolve");
+	deleteProject("Resolve15");
 	super.tearDownSuite();
 }
 
@@ -610,4 +612,115 @@
 		elements
 	);
 }
+public void testBug553149_1() throws JavaModelException {
+	this.wc = getWorkingCopy("/Resolve15/src/X.java",
+			"public class X {\n"
+					+ "    protected Object x_ = \"FIELD X\";\n"
+					+ "    @SuppressWarnings(\"preview\")\n"
+					+ "	   public void f(Object obj, boolean b) {\n"
+					+ "        if ((x_ instanceof String y) && y.length() > 0) {\n"
+					+ "            System.out.println(y.toLowerCase());\n"
+					+ "        }\n"
+					+ "    }\n"
+					+ "}");
+	String str = this.wc.getSource();
+	String selection = "x_";
+	int start = str.lastIndexOf(selection);
+	int length = selection.length();
+	IJavaElement[] elements = this.wc.codeSelect(start, length);
+	assertElementsEqual(
+		"Unexpected elements",
+		"x_ [in X [in [Working copy] X.java [in <default> [in src [in Resolve15]]]]]",
+		elements
+	);
+}
+public void testBug553149_2() throws JavaModelException {
+	this.wc = getWorkingCopy("/Resolve15/src/X.java",
+			"public class X {\n"
+					+ "    protected Object x_ = \"FIELD X\";\n"
+					+ "    @SuppressWarnings(\"preview\")\n"
+					+ "	   public void f(Object obj, boolean b) {\n"
+					+ "        if ((x_ instanceof String y_) && y_.length() > 0) {\n"
+					+ "            System.out.println(y.toLowerCase());\n"
+					+ "        }\n"
+					+ "    }\n"
+					+ "}");
+	String str = this.wc.getSource();
+	String selection = "y_";
+	int start = str.lastIndexOf(selection);
+	int length = selection.length();
+	IJavaElement[] elements = this.wc.codeSelect(start, length);
+	assertElementsEqual(
+		"Unexpected elements",
+		"y_ [in f(Object, boolean) [in X [in [Working copy] X.java [in <default> [in src [in Resolve15]]]]]]",
+		elements
+	);
+}
+public void testBug553149_3() throws JavaModelException {
+	this.wc = getWorkingCopy("/Resolve15/src/X.java",
+			"public class X {\n"
+					+ "    protected Object x_ = \"FIELD X\";\n"
+					+ "    @SuppressWarnings(\"preview\")\n"
+					+ "	   public void f(Object obj, boolean b) {\n"
+					+ "        if ((x_ instanceof String x_) && x_.length() > 0) {\n"
+					+ "            System.out.println(y.toLowerCase());\n"
+					+ "        }\n"
+					+ "    }\n"
+					+ "}");
+	String str = this.wc.getSource();
+	String selection = "x_";
+	int start = str.lastIndexOf(selection);
+	int length = selection.length();
+	IJavaElement[] elements = this.wc.codeSelect(start, length);
+	assertElementsEqual(
+		"Unexpected elements",
+		"x_ [in f(Object, boolean) [in X [in [Working copy] X.java [in <default> [in src [in Resolve15]]]]]]",
+		elements
+	);
+}
+public void _testBug553149_4() throws JavaModelException {
+	this.wc = getWorkingCopy("/Resolve15/src/X.java",
+			"public class X {\n"
+					+ "    protected Object x_ = \"FIELD X\";\n"
+					+ "    @SuppressWarnings(\"preview\")\n"
+					+ "	   public void f(Object obj, boolean b) {\n"
+					+ "        if ((x_ instanceof String x_) && x_.length() > 0) {\n"
+					+ "            System.out.println(x_.toLowerCase());\n"
+					+ "        }\n"
+					+ "    }\n"
+					+ "}");
+	String str = this.wc.getSource();
+	String selection = "x_ instanceof";
+	int start = str.lastIndexOf(selection);
+	int length = "x_".length();
+	IJavaElement[] elements = this.wc.codeSelect(start, length);
+	assertElementsEqual(
+		"Unexpected elements",
+		"x_ [in X [in [Working copy] X.java [in <default> [in src [in Resolve15]]]]]",
+		elements
+	);
+}
+public void _testBug553149_5() throws JavaModelException {
+	this.wc = getWorkingCopy("/Resolve15/src/X.java",
+			"public class X {\n"
+					+ "    protected Object x_ = \"FIELD X\";\n"
+					+ "    @SuppressWarnings(\"preview\")\n"
+					+ "	   public void f(Object obj, boolean b) {\n"
+					+ "        if ((x_ instanceof String x_) && x_.length() > 0) {\n"
+					+ "            System.out.println(x_.toLowerCase());\n"
+					+ "        }\n"
+					+ "        System.out.println(x_.toLowerCase());\n"
+					+ "    }\n"
+					+ "}");
+	String str = this.wc.getSource();
+	String selection = "x_";
+	int start = str.lastIndexOf(selection);
+	int length = "x_".length();
+	IJavaElement[] elements = this.wc.codeSelect(start, length);
+	assertElementsEqual(
+		"Unexpected elements",
+		"x_ [in X [in [Working copy] X.java [in <default> [in src [in Resolve15]]]]]",
+		elements
+	);
+}
 }
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Resolve15/.classpath b/org.eclipse.jdt.core.tests.model/workspace/Resolve15/.classpath
new file mode 100644
index 0000000..49cabdd
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Resolve15/.classpath
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+    <classpathentry kind="src" path="src"/>
+    <classpathentry kind="var" path="JCL_LIB" sourcepath="JCL_SRC" rootpath="JCL_SRCROOT"/>
+    <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.jdt.core.tests.model/workspace/Resolve15/.project b/org.eclipse.jdt.core.tests.model/workspace/Resolve15/.project
new file mode 100644
index 0000000..c05ce73
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/Resolve15/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.jdt.core</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java
index 2a8bb8b..c9d7580 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java
@@ -801,7 +801,22 @@
 }
 @Override
 protected void consumeInstanceOfExpressionWithName() {
-	if (indexOfAssistIdentifier() < 0) {
+	int length = this.patternLengthPtr >= 0 ?
+			this.patternLengthStack[this.patternLengthPtr--] : 0;
+	if (length > 0) {
+		LocalDeclaration typeDecl = (LocalDeclaration) this.patternStack[this.patternPtr--];
+		pushOnExpressionStack(getUnspecifiedReferenceOptimized());
+		if (this.assistNode == null || this.expressionStack[this.expressionPtr] != this.assistNode) {
+			// Push only when the selection node is not the expression of this
+			// pattern matching instanceof expression
+			pushOnAstStack(typeDecl);
+		}
+		if (indexOfAssistIdentifier() >= 0) {
+			this.isOrphanCompletionNode = true;
+			this.restartRecovery = true;
+			this.lastIgnoredToken = -1;
+		}
+	} else if (indexOfAssistIdentifier() < 0) {
 		super.consumeInstanceOfExpressionWithName();
 	} else {
 		getTypeReference(this.intStack[this.intPtr--]);