Bug 565462 - SourceLookup + Java 11 + Find Duplicates broken
Don't use equals() to compare two class files. The equals() implemented
in AbstractClassFile considers attributes of parent container elements
that are irrelevant for debugger.
Change-Id: Ife6c4f5c18ed1d3ad3567533d5584c0af2ed5767
Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
Signed-off-by: Simeon Andreev <simeon.danailov.andreev@gmail.com>
diff --git a/org.eclipse.jdt.debug.tests/testresources/bug565462/NonModuleJREProject/src/p2/Main.java b/org.eclipse.jdt.debug.tests/testresources/bug565462/NonModuleJREProject/src/p2/Main.java
new file mode 100644
index 0000000..7294643
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/testresources/bug565462/NonModuleJREProject/src/p2/Main.java
@@ -0,0 +1,12 @@
+package p2;
+
+import java.lang.reflect.Method;
+
+public class Main {
+
+ public static void main(String[] args) throws NoSuchMethodException, SecurityException {
+ Method m = Main.class.getDeclaredMethod("Name", String[].class);
+ System.out.println(m);
+ }
+
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/Bug565462Tests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/Bug565462Tests.java
new file mode 100644
index 0000000..e897c7d
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/sourcelookup/Bug565462Tests.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Simeon Andreev 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:
+ * Simeon Andreev - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.debug.tests.sourcelookup;
+
+import java.util.Arrays;
+
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.jdt.core.IAccessRule;
+import org.eclipse.jdt.core.IClasspathAttribute;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.launching.JavaSourceLookupDirector;
+
+/**
+ * Tests for bug 565462.
+ */
+public class Bug565462Tests extends AbstractDebugTest {
+
+ private static final String MODULE_JRE_PROJECT_NAME = "ModuleJREProject";
+ private static final String NON_MODULE_JRE_PROJECT_NAME = "NonModuleJREProject";
+
+ public Bug565462Tests(String name) {
+ super(name);
+ }
+
+ /**
+ * Test for bug 565462.
+ *
+ * Tests searching for a class with 2 Java projects in the workspace, one with {@code module=true} attribute for the JRE container, one without
+ * that attribute.
+ */
+ public void testFindDuplicatesBug565462() throws Exception {
+ IJavaProject moduleProject = createJavaProject(MODULE_JRE_PROJECT_NAME);
+ boolean attributeValue = true;
+ addModuleAttribute(moduleProject, attributeValue);
+ moduleProject.getProject().build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor());
+ IJavaProject nonModuleProject = createJavaProject(NON_MODULE_JRE_PROJECT_NAME);
+ removeModuleAttribute(nonModuleProject);
+ nonModuleProject.getProject().build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor());
+
+ waitForBuild();
+ assertTrue("Expected Java project to have module=true attribute: " + moduleProject, isModularProject(moduleProject));
+ assertFalse("Expected Java project to not have module attribute: " + nonModuleProject, isModularProject(nonModuleProject));
+
+ moduleProject.getProject().close(new NullProgressMonitor());
+ nonModuleProject.getProject().close(new NullProgressMonitor());
+ waitForBuild();
+ moduleProject.getProject().open(new NullProgressMonitor());
+ nonModuleProject.getProject().open(new NullProgressMonitor());
+ moduleProject.getProject().build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor());
+ nonModuleProject.getProject().build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor());
+ waitForBuild();
+ assertTrue("Expected Java project to have module=true attribute: " + moduleProject, isModularProject(moduleProject));
+ assertFalse("Expected Java project to not have module attribute: " + nonModuleProject, isModularProject(nonModuleProject));
+
+ JavaSourceLookupDirector director = new JavaSourceLookupDirector();
+ ILaunchConfiguration configuration = createLaunchConfiguration(nonModuleProject, "Main");
+ director.initializeDefaults(configuration);
+ director.setFindDuplicates(true);
+
+ String className = "java/lang/Class.java";
+ Object[] foundElements = director.findSourceElements(className);
+ assertEquals("Expected only 1 match for class " + className + ", but found: " + Arrays.toString(foundElements), 1, foundElements.length);
+ }
+
+ private static void removeModuleAttribute(IJavaProject javaProject) throws JavaModelException {
+ boolean isModularProject = isModularProject(javaProject);
+ if (isModularProject) {
+ IClasspathEntry[] classpath = javaProject.getRawClasspath();
+ for (int i = 0; i < classpath.length; ++i) {
+ IClasspathEntry classpathEntry = classpath[i];
+ if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
+ IPath containerPath = classpathEntry.getPath();
+ classpathEntry = JavaCore.newContainerEntry(containerPath);
+ classpath[i] = classpathEntry;
+ }
+ }
+ javaProject.setRawClasspath(classpath, new NullProgressMonitor());
+ }
+ }
+
+ private static void addModuleAttribute(IJavaProject javaProject, boolean attributeValue) throws JavaModelException {
+ boolean isModularProject = isModularProject(javaProject);
+ if (!isModularProject) {
+ IClasspathEntry[] classpath = javaProject.getRawClasspath();
+ for (int i = 0; i < classpath.length; ++i) {
+ IClasspathEntry classpathEntry = classpath[i];
+ if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
+ IPath containerPath = classpathEntry.getPath();
+ IClasspathAttribute[] attributes = classpathEntry.getExtraAttributes();
+ IClasspathAttribute[] newAttributes = Arrays.copyOf(attributes, attributes.length + 1);
+ IClasspathAttribute moduleAttribute = JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, String.valueOf(attributeValue));
+ newAttributes[attributes.length] = moduleAttribute;
+ boolean isExported = false;
+ classpathEntry = JavaCore.newContainerEntry(containerPath, new IAccessRule[0], newAttributes, isExported);
+ classpath[i] = classpathEntry;
+ }
+ }
+ javaProject.setRawClasspath(classpath, new NullProgressMonitor());
+ }
+ }
+
+ private static boolean isModularProject(IJavaProject javaProject) throws JavaModelException {
+ IClasspathEntry[] classpath = javaProject.getRawClasspath();
+ return isModularClasspath(classpath);
+ }
+
+ private static boolean isModularClasspath(IClasspathEntry[] classpath) {
+ for (int i = 0; i < classpath.length; ++i) {
+ IClasspathEntry classpathEntry = classpath[i];
+ if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
+ boolean isModule = isModularEntry(classpathEntry);
+ return isModule;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isModularEntry(IClasspathEntry classpathEntry) {
+ IClasspathAttribute[] attributes = classpathEntry.getExtraAttributes();
+ for (IClasspathAttribute attribute : attributes) {
+ String attributeName = attribute.getName();
+ if (IClasspathAttribute.MODULE.equals(attributeName)) {
+ String attributeValue = attribute.getValue();
+ boolean isModule = Boolean.parseBoolean(attributeValue);
+ return isModule;
+ }
+ }
+ return false;
+ }
+
+ private IJavaProject createJavaProject(String projectName) throws Exception {
+ IPath testrpath = new Path("testresources").append("bug565462");
+ IJavaProject javaProject = createJavaProjectClone(projectName, testrpath.append(projectName).toString(), "JavaSE-11", true);
+ javaProject.setOption(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_11);
+ javaProject.setOption(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_11);
+ javaProject.setOption(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_11);
+ javaProject.setOption(CompilerOptions.OPTION_Release, CompilerOptions.ENABLED);
+ return javaProject;
+ }
+}
diff --git a/org.eclipse.jdt.launching/META-INF/MANIFEST.MF b/org.eclipse.jdt.launching/META-INF/MANIFEST.MF
index 1fee4af..692d8fe 100644
--- a/org.eclipse.jdt.launching/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.launching/META-INF/MANIFEST.MF
@@ -15,9 +15,9 @@
org.eclipse.jdt.launching.sourcelookup.advanced,
org.eclipse.jdt.launching.sourcelookup.containers
Require-Bundle: org.eclipse.core.resources;bundle-version="[3.5.0,4.0.0)",
- org.eclipse.jdt.core;bundle-version="[3.22.0,4.0.0)",
- org.eclipse.debug.core;bundle-version="[3.14.0,4.0.0)",
- org.eclipse.jdt.debug;bundle-version="[3.11.0,4.0.0)",
+ org.eclipse.jdt.core;bundle-version="[3.24.0,4.0.0)",
+ org.eclipse.debug.core;bundle-version="[3.17.0,4.0.0)",
+ org.eclipse.jdt.debug;bundle-version="[3.17.0,4.0.0)",
org.eclipse.core.variables;bundle-version="[3.2.0,4.0.0)",
org.eclipse.core.runtime;bundle-version="[3.11.0,4.0.0)",
org.eclipse.osgi;bundle-version="[3.8.0,4.0.0)",
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/JavaSourceLookupDirector.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/JavaSourceLookupDirector.java
index 6b83d40..64c403a 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/JavaSourceLookupDirector.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/JavaSourceLookupDirector.java
@@ -14,6 +14,7 @@
package org.eclipse.jdt.internal.launching;
import java.util.HashSet;
+import java.util.Objects;
import java.util.Set;
import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupDirector;
@@ -21,6 +22,7 @@
import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
import org.eclipse.debug.core.sourcelookup.containers.ProjectSourceContainer;
import org.eclipse.debug.core.sourcelookup.containers.WorkspaceSourceContainer;
+import org.eclipse.jdt.internal.core.AbstractClassFile;
import org.eclipse.jdt.launching.sourcelookup.containers.JavaSourceLookupParticipant;
/**
@@ -40,18 +42,25 @@
fFilteredTypes.add("org.eclipse.debug.ui.containerType.workingSet"); //$NON-NLS-1$
}
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.core.sourcelookup.ISourceLookupDirector#initializeParticipants()
- */
@Override
public void initializeParticipants() {
addParticipants(new ISourceLookupParticipant[] {new JavaSourceLookupParticipant()});
}
- /* (non-Javadoc)
- * @see org.eclipse.debug.internal.core.sourcelookup.ISourceLookupDirector#supportsSourceContainerType(org.eclipse.debug.internal.core.sourcelookup.ISourceContainerType)
- */
+
@Override
public boolean supportsSourceContainerType(ISourceContainerType type) {
return !fFilteredTypes.contains(type.getId());
}
+
+ @Override
+ public boolean equalSourceElements(Object o1, Object o2) {
+ if (o1 instanceof AbstractClassFile && o2 instanceof AbstractClassFile) {
+ AbstractClassFile c1 = (AbstractClassFile) o1;
+ AbstractClassFile c2 = (AbstractClassFile) o2;
+ String pathIdentifier1 = c1.getPathIdentifier();
+ String pathIdentifier2 = c2.getPathIdentifier();
+ return Objects.equals(pathIdentifier1, pathIdentifier2);
+ }
+ return super.equalSourceElements(o1, o2);
+ }
}
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/sourcelookup/containers/PackageFragmentRootSourceContainer.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/sourcelookup/containers/PackageFragmentRootSourceContainer.java
index fc67a9b..ecd0575 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/sourcelookup/containers/PackageFragmentRootSourceContainer.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/launching/sourcelookup/containers/PackageFragmentRootSourceContainer.java
@@ -144,4 +144,20 @@
public IPath getPath() {
return getPackageFragmentRoot().getPath();
}
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("["); //$NON-NLS-1$
+ if (fRoot != null) {
+ builder.append(fRoot.getElementName());
+ builder.append(", parent="); //$NON-NLS-1$
+ builder.append(fRoot.getParent().getElementName());
+ builder.append(", path="); //$NON-NLS-1$
+ builder.append(getPath());
+ }
+ builder.append("]"); //$NON-NLS-1$
+ return builder.toString();
+ }
+
}