diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/resources/FileRelevance.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/resources/FileRelevance.java
index 8a50029e7d1..48c281ee054 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/resources/FileRelevance.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/resources/FileRelevance.java
@@ -11,12 +11,15 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.resources;
+import java.net.URI;
+
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.internal.core.model.CModelManager;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourceAttributes;
+import org.eclipse.core.runtime.IPath;
/**
* This class computes a relevance for files in case we have to select
@@ -43,6 +46,22 @@ public class FileRelevance {
* @return integer representing file relevance. Larger numbers are more relevant
*/
public static int getRelevance(IFile f, IProject preferredProject) {
+ return getRelevance(f, preferredProject, true, null);
+ }
+
+ /**
+ * Compute a relevance for the given file. The higher the score the more relevant the
+ * file. It is determined by the following criteria:
+ * - file belongs to preferred project
+ * - file belongs to a cdt-project
+ * - file belongs to a source folder of a cdt-project
+ * - file is accessible
+ * - file is not a link
+ * - file matches the original location
+ * @param f the file to compute the relevance for
+ * @return integer representing file relevance. Larger numbers are more relevant
+ */
+ public static int getRelevance(IFile f, IProject preferredProject, boolean degradeSymLinks, Object originalLocation) {
int result= 0;
IProject p= f.getProject();
if (p.equals(preferredProject))
@@ -55,14 +74,24 @@ public class FileRelevance {
result+= ON_SOURCE_ROOT;
}
- if (!f.isAccessible())
+ if (!f.isAccessible()) {
result >>= INACCESSIBLE_SHIFT;
- else {
+ } else if (f.isLinked()) {
+ result -= LINK_PENALTY;
+ } else if (degradeSymLinks) {
ResourceAttributes ra = f.getResourceAttributes();
- if (f.isLinked() || (ra != null && ra.isSymbolicLink()))
+ if (ra != null && ra.isSymbolicLink())
result -= LINK_PENALTY;
+ } else {
+ // Symbolic links are not degraded, prefer the original location
+ if (originalLocation instanceof URI) {
+ if (originalLocation.equals(f.getLocationURI()))
+ result += LINK_PENALTY;
+ } else if (originalLocation instanceof IPath) {
+ if (originalLocation.equals(f.getLocation()))
+ result+= LINK_PENALTY;
+ }
}
-
return result;
}
}
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/resources/PathCanonicalizationStrategy.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/resources/PathCanonicalizationStrategy.java
index e592fb95ab6..5f1fe6ae686 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/resources/PathCanonicalizationStrategy.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/resources/PathCanonicalizationStrategy.java
@@ -29,6 +29,10 @@ public abstract class PathCanonicalizationStrategy {
public static String getCanonicalPath(File file) {
return instance.getCanonicalPathInternal(file);
}
+
+ public static boolean resolvesSymbolicLinks() {
+ return instance.resolvesSymbolicLinksInternal();
+ }
/**
* Sets path canonicalization strategy. If canonicalize
is true
,
@@ -49,6 +53,11 @@ public abstract class PathCanonicalizationStrategy {
return file.getAbsolutePath();
}
}
+
+ @Override
+ protected boolean resolvesSymbolicLinksInternal() {
+ return true;
+ }
};
} else {
instance = new PathCanonicalizationStrategy() {
@@ -56,9 +65,15 @@ public abstract class PathCanonicalizationStrategy {
protected String getCanonicalPathInternal(File file) {
return file.getAbsolutePath();
}
+
+ @Override
+ protected boolean resolvesSymbolicLinksInternal() {
+ return false;
+ }
};
}
}
protected abstract String getCanonicalPathInternal(File file);
+ protected abstract boolean resolvesSymbolicLinksInternal();
}
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/resources/ResourceLookup.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/resources/ResourceLookup.java
index 4cabd11b6c2..73618007add 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/resources/ResourceLookup.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/resources/ResourceLookup.java
@@ -75,7 +75,7 @@ public class ResourceLookup {
* NB the returned IFile may not exist
*/
public static IFile selectFileForLocationURI(URI location, IProject preferredProject) {
- return selectFile(findFilesForLocationURI(location), preferredProject);
+ return selectFile(findFilesForLocationURI(location), preferredProject, location);
}
/**
@@ -88,10 +88,20 @@ public class ResourceLookup {
* NB the returned IFile may not exist
*/
public static IFile selectFileForLocation(IPath location, IProject preferredProject) {
- return selectFile(findFilesForLocation(location), preferredProject);
+ return selectFile(findFilesForLocation(location), preferredProject, location);
}
- private static IFile selectFile(IFile[] files, IProject preferredProject) {
+ /**
+ * Iterates through a list of 'file' resources, and selects the one with the highest "relevance score".
+ *
+ * NOTE: To compute the "relevance scores" this method may cause additional project-descriptions to load.
+ * To avoid the expense of loading additional project-descriptions, we first perform a quick first-pass
+ * through the list of IFiles (which would normally be a very small list), to see if any of them is in
+ * the preferred project. In other words, if we know that the file within the preferred project is the
+ * one that's most relevant, then first try to find it directly - before getting to the more expensive
+ * loop of computing the "relevance scores" for all the files.
+ */
+ private static IFile selectFile(IFile[] files, IProject preferredProject, Object originalLocation) {
if (files.length == 0)
return null;
@@ -101,9 +111,8 @@ public class ResourceLookup {
IFile best= null;
int bestRelevance= -1;
- for (int i = 0; i < files.length; i++) {
- IFile file = files[i];
- int relevance= FileRelevance.getRelevance(file, preferredProject);
+ for (IFile file : files) {
+ int relevance= FileRelevance.getRelevance(file, preferredProject, PathCanonicalizationStrategy.resolvesSymbolicLinks(), originalLocation);
if (best == null || relevance > bestRelevance ||
(relevance == bestRelevance &&
best.getFullPath().toString().compareTo(file.getFullPath().toString()) > 0)) {