From cb17b37a0cea86b6074c6236eaddfc01a0836d22 Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Mon, 26 Aug 2013 14:25:48 +0200 Subject: [PATCH] Bug 411605: ResourceLookup should honor the PathCanonicalization strategy. --- .../core/resources/FileRelevance.java | 37 +++++++++++++++++-- .../PathCanonicalizationStrategy.java | 15 ++++++++ .../core/resources/ResourceLookup.java | 21 ++++++++--- 3 files changed, 63 insertions(+), 10 deletions(-) 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)) {