Bug 572232 - Add vararg to enum constructor search

- Add functionality to jump to enum constructor with varargs
- Add support for compatible classes
- Update testcase
- Bump jdt.text.tests version to 3.13.1600.qualifier
Change-Id: I931610579602259e1852b7baa87219abe7f23181
Signed-off-by: Kenneth Styrberg <kenneth@kean.nu>
Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.ui/+/189546
Tested-by: JDT Bot <jdt-bot@eclipse.org>
Tested-by: Jeff Johnston <jjohnstn@redhat.com>
Reviewed-by: Jeff Johnston <jjohnstn@redhat.com>
diff --git a/org.eclipse.jdt.text.tests/META-INF/MANIFEST.MF b/org.eclipse.jdt.text.tests/META-INF/MANIFEST.MF
index bf2029e..3bee31e 100644
--- a/org.eclipse.jdt.text.tests/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.text.tests/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %Plugin.name
 Bundle-SymbolicName: org.eclipse.jdt.text.tests;singleton:=true
-Bundle-Version: 3.13.1500.qualifier
+Bundle-Version: 3.13.1600.qualifier
 Bundle-Activator: org.eclipse.jdt.text.tests.JdtTextTestPlugin
 Bundle-ActivationPolicy: lazy
 Bundle-Vendor: %Plugin.providerName
diff --git a/org.eclipse.jdt.text.tests/pom.xml b/org.eclipse.jdt.text.tests/pom.xml
index 2087329..eb51642 100644
--- a/org.eclipse.jdt.text.tests/pom.xml
+++ b/org.eclipse.jdt.text.tests/pom.xml
@@ -20,7 +20,7 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.text.tests</artifactId>
-  <version>3.13.1500-SNAPSHOT</version>
+  <version>3.13.1600-SNAPSHOT</version>
   <packaging>eclipse-test-plugin</packaging>
 
   <properties>
diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/EnumConstructorTargetFinderTest.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/EnumConstructorTargetFinderTest.java
index d137201..380712a 100644
--- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/EnumConstructorTargetFinderTest.java
+++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/EnumConstructorTargetFinderTest.java
@@ -283,12 +283,108 @@
 		{
 			int offset= s.indexOf("A1(\"\")");
 			int targetOffset= s.indexOf("A(String s)");
-			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1 /* 'A' */, 0, "A(String s)"));
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(String s)"));
 		}
 		{
 			int offset= s.indexOf("A2(\"\",\"\")");
-			int targetOffset= s.indexOf("A2(\"\",\"\")");
-			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 2 /* 'A2' */, 0, "A2(\"\",\"\")"));
+			int targetOffset= s.indexOf("A(String ... strings)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(String ... strings)"));
+		}
+	}
+
+	@Test
+	public void testEnumConstructorFinder_6() throws Exception {
+		String s= "" +
+				"package test1;\n" +
+				"class E {\n" +
+
+				"   public enum A {\n" +
+				"      A1(\"\"),\n" +
+				"      A2(new Object());\n" +
+				"      A(String s) {\n" +
+				"      }\n" +
+				"      A(Object o) {\n" +
+				"      }\n" +
+				"   }\n" +
+
+				"}\n";
+
+		CompilationUnit root= createCompilationUnit(s);
+
+		{
+			int offset= s.indexOf("A1");
+			int targetOffset= s.indexOf("A(String");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1 /* 'A' */, 0, "A(String"));
+		}
+		{
+			int offset= s.indexOf("A2");
+			int targetOffset= s.indexOf("A(Object");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1 /* 'A' */, 0, "A(Object"));
+		}
+	}
+
+	@Test
+	public void testEnumConstructorFinder_7() throws Exception {
+		String s= "" +
+				"package test1;\n" +
+				"class E {\n" +
+
+				"   public enum A {\n" +
+				"      A1(1L),\n" +
+				"      A2(new Long(1)),\n" +
+				"      A3(new Long(1), 1L),\n" +
+				"      A4(Long.valueOf(1)),\n" +
+				"      A5(Long.parseLong(\"1\")),\n" +
+				"      A6(1L, 2.0),\n" +
+				"      A7(Long.valueOf(1), Double.valueOf(2.0));\n" +
+				"      A(long l) {\n" +
+				"      }\n" +
+				"      A(Long l) {\n" +
+				"      }\n" +
+				"      A(long l, double d) {\n" +
+				"      }\n" +
+				"      A(Long l, Double d) {\n" +
+				"      }\n" +
+				"   }\n" +
+
+				"}\n";
+
+		CompilationUnit root= createCompilationUnit(s);
+
+		{
+			int offset= s.indexOf("A1");
+			int targetOffset= s.indexOf("A(long l)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(long l)"));
+		}
+		{
+			int offset= s.indexOf("A2");
+			int targetOffset= s.indexOf("A(Long l)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(Long l)"));
+		}
+		{
+			int offset= s.indexOf("A3");
+			int targetOffset= s.indexOf("A(long l, double d)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(long l, double d)"));
+		}
+		{
+			int offset= s.indexOf("A4");
+			int targetOffset= s.indexOf("A(Long l)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(Long l)"));
+		}
+		{
+			int offset= s.indexOf("A5");
+			int targetOffset= s.indexOf("A(long l)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(long l)"));
+		}
+		{
+			int offset= s.indexOf("A6");
+			int targetOffset= s.indexOf("A(long l, double d)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(long l, double d)"));
+		}
+		{
+			int offset= s.indexOf("A7");
+			int targetOffset= s.indexOf("A(Long l, Double d)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(Long l, Double d)"));
 		}
 	}
 }
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/EnumConstructorTargetFinder.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/EnumConstructorTargetFinder.java
index dfcb615..8456ca8 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/EnumConstructorTargetFinder.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/EnumConstructorTargetFinder.java
@@ -85,6 +85,11 @@
 		return location;
 	}
 
+	private enum CheckEnum {
+		EXACT,
+		UNBOXED,
+		ASSIGNEMENT_COMPATIBLE
+	}
 	private ASTNode findEnumConstructor(CompilationUnit cu, EnumConstantDeclaration enumNode) {
 		ASTNode enumDeclarationNode= ASTResolving.findParentType(enumNode);
 		if (enumDeclarationNode == null) {
@@ -97,6 +102,18 @@
 		List<ASTNode> enumNodeArguments= enumNode.arguments();
 		List<ASTNode> enumBodyDeclarations= enumDeclaration.bodyDeclarations();
 
+		ASTNode foundEnumDeclaration= findEnumDeclaration(cu, enumDeclaration, enumNodeArguments, enumBodyDeclarations, CheckEnum.EXACT);
+		if (foundEnumDeclaration == null) {
+			foundEnumDeclaration= findEnumDeclaration(cu, enumDeclaration, enumNodeArguments, enumBodyDeclarations, CheckEnum.UNBOXED);
+		}
+		if (foundEnumDeclaration == null) {
+			foundEnumDeclaration= findEnumDeclaration(cu, enumDeclaration, enumNodeArguments, enumBodyDeclarations, CheckEnum.ASSIGNEMENT_COMPATIBLE);
+		}
+		return foundEnumDeclaration;
+	}
+
+	private ASTNode findEnumDeclaration(CompilationUnit cu, EnumDeclaration enumDeclaration,
+			List<ASTNode> enumNodeArguments, List<ASTNode> enumBodyDeclarations, CheckEnum checkEnum) {
 		declarationLoop: for (ASTNode enumBodyDeclarationNode : enumBodyDeclarations) {
 			if (enumBodyDeclarationNode.getNodeType() != ASTNode.METHOD_DECLARATION) {
 				continue;
@@ -107,16 +124,14 @@
 			}
 
 			List<SingleVariableDeclaration> enumBodyDeclarationNodeParameters= enumMethodDeclaration.parameters();
-			if (enumBodyDeclarationNodeParameters.size() != enumNodeArguments.size()) {
+			if (!enumMethodDeclaration.isVarargs()
+					&& enumBodyDeclarationNodeParameters.size() != enumNodeArguments.size()) {
 				continue;
 			}
 
 			for (int i= 0; i < enumBodyDeclarationNodeParameters.size(); i++) {
 				ASTNode nodeArgument= enumNodeArguments.get(i);
 				SingleVariableDeclaration singleVariableDeclaration= enumBodyDeclarationNodeParameters.get(i);
-				if(singleVariableDeclaration.isVarargs()) {
-					continue declarationLoop;
-				}
 				Type parameterType= singleVariableDeclaration.getType();
 				if (parameterType == null) {
 					continue declarationLoop;
@@ -139,7 +154,11 @@
 					if (parameterTypes.length != enumBodyDeclarationNodeParameters.size()) {
 						continue declarationLoop;
 					}
-					nodeTypeArgument= parameterTypes[i];
+					if (singleVariableDeclaration.isVarargs()) {
+						nodeTypeArgument= parameterTypes[i].getElementType();
+					} else {
+						nodeTypeArgument= parameterTypes[i];
+					}
 				}
 				if (nodeTypeArgument == null) {
 					nodeTypeArgument= ASTResolving.guessBindingForReference(nodeArgument);
@@ -148,13 +167,29 @@
 					continue declarationLoop;
 				}
 
-				if (Bindings.equals(nodeTypeArgument, nodeTypeParameter)) {
-					continue;
-				}
 				ITypeBinding unboxedTypeArgument= Bindings.getUnboxedTypeBinding(nodeTypeArgument, cu.getAST());
 				ITypeBinding unboxedTypeParameter= Bindings.getUnboxedTypeBinding(nodeTypeParameter, cu.getAST());
-				if (Bindings.equals(unboxedTypeArgument, unboxedTypeParameter)) {
-					continue;
+				switch (checkEnum) {
+					case EXACT:
+						if (Bindings.equals(nodeTypeArgument, nodeTypeParameter)) {
+							continue;
+						}
+						break;
+					case UNBOXED:
+						if (Bindings.equals(unboxedTypeArgument, unboxedTypeParameter)) {
+							continue;
+						}
+						break;
+					case ASSIGNEMENT_COMPATIBLE:
+						if (nodeTypeArgument.isAssignmentCompatible(nodeTypeParameter)) {
+							continue;
+						}
+						if (unboxedTypeArgument.isAssignmentCompatible(unboxedTypeParameter)) {
+							continue;
+						}
+						break;
+					default:
+						break;
 				}
 				continue declarationLoop;
 			} // for all enum constructor parameters