diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/extensions/TestExternalLibContainerInitializer.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/extensions/TestExternalLibContainerInitializer.java index e34346f30d1..dede9b808a3 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/extensions/TestExternalLibContainerInitializer.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/extensions/TestExternalLibContainerInitializer.java @@ -47,7 +47,7 @@ public String getDescription() { public IClasspathEntry[] getClasspathEntries() { if (TestExternalLibContainerInitializer.this.entries == null) { TestExternalLibContainerInitializer.this.entries = new IClasspathEntry[] { - JavaCore.newLibraryEntry(containerPath, null, null) + JavaCore.newLibraryEntry(containerPath, containerPath, null) }; } return TestExternalLibContainerInitializer.this.entries; diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchIssue190Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchIssue190Test.java new file mode 100644 index 00000000000..195b298eb57 --- /dev/null +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchIssue190Test.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2022 Christopher Gerking 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: + * Christopher Gerking - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.tests.model; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.search.IJavaSearchConstants; +import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.SearchEngine; +import org.eclipse.jdt.core.search.SearchMatch; +import org.eclipse.jdt.core.search.SearchRequestor; + +import junit.framework.Test; + +public class JavaSearchIssue190Test extends AbstractJavaSearchTests { + + public String getProjectName() { + return "JavaSearchIssue190"; + } + + public JavaSearchIssue190Test(String name) { + super(name); + } + + public static Test suite() { + return buildModelTestSuite(JavaSearchIssue190Test.class, BYTECODE_DECLARATION_ORDER); + } + + @Override + public void setUpSuite() throws Exception { + super.setUpSuite(); + + createExternalFolder("TestContainer/p"); + + String sourceWorkspacePath = getSourceWorkspacePath(); + IWorkspace targetWorkspace = ResourcesPlugin.getWorkspace(); + File targetWorkspaceLocation = new File(targetWorkspace.getRoot().getLocation().toOSString()); + + File javaFileSrc = new File(sourceWorkspacePath, "JavaSearchMultipleProjects2/lib/p/Y.java"); + File javaFileDst = new File(targetWorkspaceLocation.getParentFile().getCanonicalFile(), "TestContainer/p/Y.java"); + copy(javaFileSrc, javaFileDst); + + File classFileSrc = new File(sourceWorkspacePath, "JavaSearchMultipleProjects2/lib/p/Y.class"); + File classFileDst = new File(targetWorkspaceLocation.getParentFile().getCanonicalFile(), "TestContainer/p/Y.class"); + copy(classFileSrc, classFileDst); + + JAVA_PROJECT = setUpJavaProject(getProjectName(), "11"); + + JavaCore.setOptions(JavaCore.getDefaultOptions()); + } + + @Override + IJavaSearchScope getJavaSearchScope() { + IJavaElement[] elements = new IJavaElement[] { getJavaProject(getProjectName()) }; + return SearchEngine.createJavaSearchScope(elements, true); + } + + public void testIssue190() throws CoreException, IOException { + List searchResults = new ArrayList(); + + SearchRequestor searchRequestor = new SearchRequestor() { + public void acceptSearchMatch(SearchMatch match) { + Object element = match.getElement(); + + if (element instanceof IType) { + String fqn = ((IType) element).getFullyQualifiedName(); + searchResults.add(fqn); + } + } + }; + + search("Y", IJavaSearchConstants.CLASS, + IJavaSearchConstants.DECLARATIONS, getJavaSearchScope(), searchRequestor); + + assertTrue("Searched class not found in external classpath container", searchResults.contains("p.Y")); + } + + @Override + public void tearDownSuite() throws Exception { + deleteProject(getProjectName()); + deleteExternalResource("TestContainer"); + super.tearDownSuite(); + JAVA_PROJECT = null; + } +} diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchTests.java index 2c1661b22a0..d1f1a33ca3e 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchTests.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchTests.java @@ -80,6 +80,7 @@ public static Test suite() { allClasses.add(JavaSearchBug565512Test.class); allClasses.add(JavaSearchNameEnvironmentTest.class); allClasses.add(JavaSearchSuperAfterStatementTests.class); + allClasses.add(JavaSearchIssue190Test.class); // Reset forgotten subsets of tests TestCase.TESTS_PREFIX = null; diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchIssue190/.classpath b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchIssue190/.classpath new file mode 100644 index 00000000000..5844931af19 --- /dev/null +++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchIssue190/.classpath @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/org.eclipse.jdt.core.tests.model/workspace/JavaSearchIssue190/.project b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchIssue190/.project new file mode 100644 index 00000000000..9c13e992538 --- /dev/null +++ b/org.eclipse.jdt.core.tests.model/workspace/JavaSearchIssue190/.project @@ -0,0 +1,17 @@ + + + org.eclipse.jdt.core.tests.model.issue190 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java index b322580db4b..86315a0f444 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchScope.java @@ -374,6 +374,7 @@ private int indexOf(String fullPath) { String currentRelativePath = this.relativePaths[i]; if (currentRelativePath == null) continue; String currentContainerPath = this.containerPaths[i]; + currentContainerPath = convertInternalToExternalPath(currentContainerPath, fullPath); String currentFullPath = currentRelativePath.length() == 0 ? currentContainerPath : (currentContainerPath + '/' + currentRelativePath); if (encloses(currentFullPath, fullPath, i)) return i; @@ -401,6 +402,7 @@ private int indexOf(String containerPath, String relativePath) { index = (containerPath.hashCode()& 0x7FFFFFFF) % length; String currentContainerPath; while ((currentContainerPath = this.containerPaths[index]) != null) { + currentContainerPath = convertInternalToExternalPath(currentContainerPath, containerPath); if (currentContainerPath.equals(containerPath)) { String currentRelativePath = this.relativePaths[index]; if (encloses(currentRelativePath, relativePath, index)) @@ -413,6 +415,34 @@ private int indexOf(String containerPath, String relativePath) { return -1; } +/** + * If the given path is internal but represents an external folder, + * converts it to the corresponding external path. + * The reference path indicates if conversion is necessary. + * No conversion takes place if the given path does not represent an external folder, + * or if conversion is unnecessary because the reference path also represents an external folder. + * @param given the given path to convert if necessary + * @param reference the reference path that indicates if conversion is necessary + * @return the external path that corresponds to the given path, + * or the given path itself if no conversion is necessary + */ +private String convertInternalToExternalPath(String given, String reference) { + IPath givenPath = new Path(given); + if (ExternalFoldersManager.isInternalPathForExternalFolder(givenPath)) { + IPath referencePath = new Path(reference); + if (!ExternalFoldersManager.isInternalPathForExternalFolder(referencePath)) { + IResource targetResource = JavaModel.getWorkspaceTarget(givenPath); + if (targetResource != null) { + IPath targetLocation = targetResource.getLocation(); + if (targetLocation != null) + return targetLocation.toString(); + } + } + } + + return given; +} + /* * Returns whether the enclosing path encloses the given path (or is equal to it) */