Bug 573486 - Fix reference locating on binary types

When locating matches on class files the method and fields are not
searched for which result in loosing usages in method declarations and
variable declarations.

Change-Id: I7afcbb9e3c6d2508453bb14171acaf4c58d28db7
Signed-off-by: Gayan Perera <gayanper@gmail.com>
Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/185487
Tested-by: JDT Bot <jdt-bot@eclipse.org>
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs15Tests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs15Tests.java
index 54fbd1d..cad4a2b 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs15Tests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs15Tests.java
@@ -1382,7 +1382,8 @@
 		 			getJavaSearchScope(),
 		 			this.resultCollector);
 		 		assertSearchResults(
-		 			"lib/record_reference_in_nonsource_jar.jar pack.rr [No source] EXACT_MATCH",
+		 			"lib/record_reference_in_nonsource_jar.jar pack.c1.ob [No source] EXACT_MATCH\n"
+		 			+ "lib/record_reference_in_nonsource_jar.jar pack.rr [No source] EXACT_MATCH",
 		 			this.resultCollector);
 		 		// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=565180 ( reason for 1 result instead of 3)
 		}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs9Tests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs9Tests.java
index b7e986d..917b7fb 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs9Tests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs9Tests.java
@@ -1475,7 +1475,8 @@
 		assertSearchResults(
 				"src/pack1/X.java [ITwo] EXACT_MATCH\n" +
 				"src/pack1/X.java pack1.X.i2 [ITwo] EXACT_MATCH\n" +
-				"lib/bzero501162.jar zero [No source] EXACT_MATCH",
+				"lib/bzero501162.jar zero [No source] EXACT_MATCH\n"
+				+ "lib/bzero501162.jar pack.one.XOne.itwo [No source] EXACT_MATCH",
 			this.resultCollector);
 	}
 	finally {
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java
index cb02084..50963ef 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugsTests.java
@@ -15300,4 +15300,23 @@
 		deleteProject("P");
 	}
 }
+
+public void testBug573486_showReferences_inMethodsAndFields_whenNoSource() throws CoreException, IOException {
+	addLibraryEntry(JAVA_PROJECT, "/JavaSearchBugs/lib/search_lib_no_source.jar", false);
+	try {
+		IType type = getClassFile("JavaSearchBugs", "lib/search_lib_no_source.jar", "java.util", "Observable.class").getType();
+		search(type, REFERENCES);
+		assertSearchResults(
+			"lib/search_lib_no_source.jar java.util.List<java.util.Observable> search.ReferenceSubject.methodRef() [No source] POTENTIAL_MATCH\n"
+			+ "lib/search_lib_no_source.jar void search.ReferenceSubject.methodRefParam1(java.util.Observable) [No source] POTENTIAL_MATCH\n"
+			+ "lib/search_lib_no_source.jar void search.ReferenceSubject.methodRefParam2(java.util.Observable, java.util.Observable) [No source] POTENTIAL_MATCH\n"
+			+ "lib/search_lib_no_source.jar T search.ReferenceSubject.methodRefTP() [No source] POTENTIAL_MATCH\n"
+			+ "lib/search_lib_no_source.jar search.ReferenceSubject.fieldRef [No source] POTENTIAL_MATCH"
+		);
+	}
+	finally {
+		removeClasspathEntry(JAVA_PROJECT, new Path("/JavaSearchBugs/lib/b211872_ws.jar"));
+	}
+}
+
 }
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBugs/lib/search_lib_no_source.jar b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBugs/lib/search_lib_no_source.jar
new file mode 100644
index 0000000..2cfbe15
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBugs/lib/search_lib_no_source.jar
Binary files differ
diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBugs/lib/search_lib_prj_source.jar b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBugs/lib/search_lib_prj_source.jar
new file mode 100644
index 0000000..609e566
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchBugs/lib/search_lib_prj_source.jar
Binary files differ
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
index fd4ff75..efe286f 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
@@ -636,6 +636,12 @@
 @Override
 public int resolveLevel(Binding binding) {
 	if (binding == null) return INACCURATE_MATCH;
+
+	if(binding instanceof MethodBinding)
+		return resolveLevel((MethodBinding) binding);
+	if(binding instanceof VariableBinding)
+		return resolveLevel((VariableBinding) binding);
+
 	if (!(binding instanceof TypeBinding)) return IMPOSSIBLE_MATCH;
 
 	TypeBinding typeBinding = (TypeBinding) binding;
@@ -646,6 +652,51 @@
 
 	return resolveLevelForTypeOrEnclosingTypes(this.pattern.simpleName, this.pattern.qualification, typeBinding);
 }
+private int resolveLevel(MethodBinding binding) {
+	int level = resolveLevelForTypes(binding.parameters);
+	if(level != IMPOSSIBLE_MATCH) {
+		return level;
+	}
+
+	if(binding.typeVariables != null) {
+		for (TypeVariableBinding tv : binding.typeVariables) {
+			if(tv.superclass != null) {
+				level = resolveLevelForType(tv.superclass);
+				if(level != IMPOSSIBLE_MATCH) {
+					return level;
+				}
+			}
+
+			level = resolveLevelForTypes(tv.superInterfaces);
+			if(level != IMPOSSIBLE_MATCH) {
+				return level;
+			}
+		}
+	}
+
+	if(!binding.isVoidMethod() && binding.returnType != null) {
+		return resolveLevelForType(binding.returnType);
+	}
+
+	return IMPOSSIBLE_MATCH;
+}
+private int resolveLevel(VariableBinding binding) {
+	if(binding.type != null) {
+		return resolveLevelForType(binding.type);
+	}
+	return IMPOSSIBLE_MATCH;
+}
+private int resolveLevelForTypes(TypeBinding[] types) {
+	if(types != null) {
+		for (TypeBinding t : types) {
+			int levelForType = resolveLevelForType(t);
+			if(levelForType != IMPOSSIBLE_MATCH) {
+				return levelForType;
+			}
+		}
+	}
+	return IMPOSSIBLE_MATCH;
+}
 protected int resolveLevel(NameReference nameRef) {
 	Binding binding = nameRef.binding;