Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Zarnekow2019-07-30 16:26:44 +0000
committerStephan Herrmann2019-08-08 13:20:11 +0000
commit714070211387f0595cd8df499e20cf559116fcea (patch)
tree94b15d3c6e9970ff6523de99894b45dfb5ea544a
parent181d12a804961d5320f326f8d24d7575ae4b84ac (diff)
downloadeclipse.jdt.core-714070211387f0595cd8df499e20cf559116fcea.tar.gz
eclipse.jdt.core-714070211387f0595cd8df499e20cf559116fcea.tar.xz
eclipse.jdt.core-714070211387f0595cd8df499e20cf559116fcea.zip
Bug 549646 - NPE in ReferenceBinding.binarySearchI20190810-1800I20190809-1800I20190808-1800
Proper handling of ReferenceBindings that do have a null value in the sourceName field. Change-Id: I9bdb5c472553dc165b64665e4c262287dd1fa946 Signed-off-by: Sebastian Zarnekow <sebastian.zarnekow@gmail.com> Also-by: Stephan Herrmann <stephan.herrmann@berlin.de>
-rw-r--r--org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/Bug549646Test.java73
-rw-r--r--org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BuilderTests.java1
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java3
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java34
4 files changed, 104 insertions, 7 deletions
diff --git a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/Bug549646Test.java b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/Bug549646Test.java
new file mode 100644
index 0000000000..f661339d08
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/Bug549646Test.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Sebastian Zarnekow 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:
+ * Sebastian Zarnekow - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.tests.builder;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.tests.util.Util;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+
+import junit.framework.Test;
+
+public class Bug549646Test extends BuilderTests {
+ public Bug549646Test(String name) {
+ super(name);
+ }
+
+ public static Test suite() {
+ return buildTestSuite(Bug549646Test.class);
+ }
+
+ public void testCompilerRegression() throws JavaModelException, Exception {
+ IPath projectPath = env.addProject("Bug549646Test", "10"); //$NON-NLS-1$
+ env.getJavaProject(projectPath).setOption(JavaCore.COMPILER_RELEASE, JavaCore.ENABLED);
+
+ env.addExternalJars(projectPath, Util.getJavaClassLibs());
+ env.addClass(projectPath, "test", "A", //$NON-NLS-1$ //$NON-NLS-2$
+ "package test;\n" +
+ "import java.util.Map;\n" +
+ "import java.util.Map.Entry;\n" +
+ "public class A {\n" +
+ " void a(Map<String,String> a) {\n" +
+ " for (Entry<String, String> iterableElement : a.entrySet()) {\n" +
+ " iterableElement.toString();\n" +
+ " }\n" +
+ " }\n" +
+ "}\n" //$NON-NLS-1$
+ );
+ env.addClass(projectPath, "test", "B", //$NON-NLS-1$ //$NON-NLS-2$
+ "package test;\n" +
+ "import java.util.HashMap;\n" +
+ "public class B {\n" +
+ " void test() {\n" +
+ " new A().a(new HashMap<String, String>());\n" +
+ " }\n" +
+ "}\n" //$NON-NLS-1$
+ );
+ fullBuild();
+
+ boolean isJRE11 = CompilerOptions.VERSION_11.equals(System.getProperty("java.specification.version"));
+ if (isJRE11 && env.getProblemsFor(projectPath).length > 0) {
+ // bogus class lookup (ignoring modules) due to insufficient data in ct.sym (non-deterministically triggers the below problems)
+ // see also https://bugs.eclipse.org/549647
+ expectingProblemsFor(projectPath,
+ "Problem : Entry cannot be resolved to a type [ resource : </Bug549646Test/test/A.java> range : <120,125> category : <40> severity : <2>]\n" +
+ "Problem : The type java.util.Map.Entry is not visible [ resource : </Bug549646Test/test/A.java> range : <43,62> category : <40> severity : <2>]\n" +
+ "Problem : Type mismatch: cannot convert from element type Map.Entry<String,String> to Entry [ resource : </Bug549646Test/test/A.java> range : <160,172> category : <40> severity : <2>]");
+ } else {
+ expectingNoProblems();
+ }
+ }
+}
diff --git a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BuilderTests.java b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BuilderTests.java
index 3a79787fd8..cc1ecf9b36 100644
--- a/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BuilderTests.java
+++ b/org.eclipse.jdt.core.tests.builder/src/org/eclipse/jdt/core/tests/builder/BuilderTests.java
@@ -562,6 +562,7 @@ public class BuilderTests extends TestCase {
}
if (matchesCompliance(F_9)) {
list.add(LeakTestsAfter9.class);
+ list.add(Bug549646Test.class);
}
return list.toArray(new Class[0]);
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java
index 51c920f155..08e7324679 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java
@@ -28,6 +28,9 @@ public class ProblemReferenceBinding extends ReferenceBinding {
public ProblemReferenceBinding(char[][] compoundName, ReferenceBinding closestMatch, int problemReason) {
this.compoundName = compoundName;
this.closestMatch = closestMatch;
+ if (closestMatch != null) {
+ this.sourceName = closestMatch.sourceName;
+ }
this.problemReason = problemReason;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
index 5c1e31fcaa..537d99fbc3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
@@ -241,9 +241,23 @@ static void sortMemberTypes(ReferenceBinding[] sortedMemberTypes, int left, int
Arrays.sort(sortedMemberTypes, left, right, BASIC_MEMBER_TYPES_COMPARATOR);
}
+/**
+ * Compares two reference bindings by the value of the {@link #sourceName} field.
+ * A ReferenceBinding with a sourceName field that has the value null is considered
+ * to be smaller than a ReferenceBinding that does have a source name.
+ */
static final Comparator<ReferenceBinding> BASIC_MEMBER_TYPES_COMPARATOR = (ReferenceBinding o1, ReferenceBinding o2) -> {
char[] n1 = o1.sourceName;
char[] n2 = o2.sourceName;
+ // n1 or n2 may be null - compare without accessing the length of the array
+ if (n1 == null) {
+ if (n2 == null) {
+ return 0;
+ }
+ return -1;
+ } else if (n2 == null) {
+ return 1;
+ }
return ReferenceBinding.compare(n1, n2, n1.length, n2.length);
};
@@ -1075,18 +1089,24 @@ public ReferenceBinding getMemberType(char[] typeName) {
return null;
}
-static int binarySearch(char[] name, ReferenceBinding[] sortedMemberTypes) {
+/**
+ * Search the given sourceName in the list of sorted member types.
+ *
+ * Neither the array of sortedMemberTypes nor the given sourceName may be null.
+ */
+static int binarySearch(char[] sourceName, ReferenceBinding[] sortedMemberTypes) {
if (sortedMemberTypes == null)
return -1;
- int max = sortedMemberTypes.length;
+ int max = sortedMemberTypes.length, nameLength = sourceName.length;
if (max == 0)
return -1;
- int left = 0, right = max - 1, nameLength = name.length;
- int mid = 0;
- char[] midName;
+ int left = 0, right = max - 1;
while (left <= right) {
- mid = left + (right - left) /2;
- int compare = compare(name, midName = sortedMemberTypes[mid].sourceName, nameLength, midName.length);
+ int mid = left + (right - left) / 2;
+ char[] midName = sortedMemberTypes[mid].sourceName;
+ // The read source name may be null. In that case, the given sourceName is considered
+ // to be larger than the current value at mid.
+ int compare = midName == null ? 1 : compare(sourceName, midName, nameLength, midName.length);
if (compare < 0) {
right = mid-1;
} else if (compare > 0) {

Back to the top