Skip to content

Commit

Permalink
Consider external paths in search scope (eclipse-jdt#190)
Browse files Browse the repository at this point in the history
If the given container path is internal but represents a link to an
external folder, converts it to the corresponding external path.

Fixes eclipse-jdt#190
  • Loading branch information
gerking authored and iloveeclipse committed May 3, 2024
1 parent 68e8c0c commit fd03825
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.core.tests.model.TEST_EXTERNAL_LIB_CONTAINER"/>
<classpathentry kind="src" path="src">
<attributes>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="bin"/>
</classpath>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.eclipse.jdt.core.tests.model.issue190</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
Original file line number Diff line number Diff line change
Expand Up @@ -302,9 +302,10 @@ public void add(IJavaElement element) throws JavaModelException {
private void add(String projectPath, String relativePath, String containerPath, boolean isPackage, AccessRuleSet access) {
// normalize containerPath and relativePath
containerPath = normalize(containerPath);
containerPath = convertInternalToExternalPath(containerPath);
relativePath = normalize(relativePath);
int length = this.containerPaths.length,
index = (containerPath.hashCode()& 0x7FFFFFFF) % length;
int length = this.containerPaths.length;
int index = (containerPath.hashCode() & 0x7FFFFFFF) % length;
String currentRelativePath, currentContainerPath;
while ((currentRelativePath = this.relativePaths[index]) != null && (currentContainerPath = this.containerPaths[index]) != null) {
if (currentRelativePath.equals(relativePath) && currentContainerPath.equals(containerPath))
Expand Down Expand Up @@ -370,6 +371,7 @@ public boolean encloses(String resourcePathString) {
private int indexOf(String fullPath) {
// cannot guess the index of the container path
// fallback to sequentially looking at all known paths
fullPath = convertInternalToExternalPath(fullPath);
for (int i = 0, length = this.relativePaths.length; i < length; i++) {
String currentRelativePath = this.relativePaths[i];
if (currentRelativePath == null) continue;
Expand All @@ -396,9 +398,10 @@ private int indexOf(String fullPath) {
* 4. (empty)
*/
private int indexOf(String containerPath, String relativePath) {
containerPath = convertInternalToExternalPath(containerPath);
int length = this.containerPaths.length;
// use the hash to get faster comparison
int length = this.containerPaths.length,
index = (containerPath.hashCode()& 0x7FFFFFFF) % length;
int index = (containerPath.hashCode()& 0x7FFFFFFF) % length;
String currentContainerPath;
while ((currentContainerPath = this.containerPaths[index]) != null) {
if (currentContainerPath.equals(containerPath)) {
Expand All @@ -413,6 +416,29 @@ 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.
* No conversion takes place if the given path does not represent an external folder.
* @param given the given path to convert if 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) {
IPath givenPath = new Path(given);
if (ExternalFoldersManager.isInternalPathForExternalFolder(givenPath)) {
IResource targetResource = JavaModel.getWorkspaceTarget(givenPath);
if (targetResource != null) {
IPath targetLocation = targetResource.getLocation();
if (targetLocation != null) {
return targetLocation.toOSString();
}
}
}
return given;
}

/*
* Returns whether the enclosing path encloses the given path (or is equal to it)
*/
Expand Down

0 comments on commit fd03825

Please sign in to comment.