/*******************************************************************************
* Copyright (c) 2008 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.indexer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.cdt.core.index.IIndexFileLocation;
import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics;
import org.eclipse.cdt.internal.core.pdom.ASTFilePathResolver;
import org.eclipse.cdt.internal.core.resources.ResourceLookup;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
/**
* Heuristics for picking up includes from the project
*/
public class ProjectIndexerIncludeResolutionHeuristics implements IIncludeFileResolutionHeuristics {
private static final String TRUE = "true"; //$NON-NLS-1$
private IProject fProject;
private IProject[] fProjects;
private final ASTFilePathResolver fResolver;
private final boolean fIgnoreCase;
public ProjectIndexerIncludeResolutionHeuristics(IProject project, ASTFilePathResolver resolver) {
fProject= project;
fResolver= resolver;
fIgnoreCase= resolver.isCaseInsensitiveFileSystem();
}
public String findInclusion(String include, String currentFile) {
final IIndexFileLocation ifl= fResolver.resolveASTPath(currentFile);
if (ifl == null || ifl.getFullPath() == null) {
return null;
}
if (fProject == null)
return null;
if (fProjects == null) {
if (fProject.isOpen()) {
String val= IndexerPreferences.get(fProject, IndexerPreferences.KEY_INCLUDE_HEURISTICS, TRUE);
if (TRUE.equals(val)) {
fProjects= getOpenReferencedProjects(fProject);
}
}
if (fProjects == null) {
fProject= null;
return null;
}
}
IFile[] files= ResourceLookup.findFilesByName(new Path(include), fProjects, fIgnoreCase);
if (files.length == 0)
return null;
final IPath bestLocation = selectBest(files, ifl.getFullPath().toCharArray()).getLocation();
if (bestLocation == null)
return null;
return bestLocation.toString();
}
private IResource selectBest(IFile[] files, char[] currentFullPath) {
IFile best= files[0];
int bestScore= computeScore(best.getFullPath().toString().toCharArray(), currentFullPath);
for (int i = 1; i < files.length; i++) {
IFile file= files[i];
int score= computeScore(file.getFullPath().toString().toCharArray(), currentFullPath);
if (score > bestScore) {
bestScore= score;
best= file;
}
}
return best;
}
private int computeScore(char[] path1, char[] path2) {
final int limit= Math.min(path1.length, path2.length);
int match=0;
for (int i = 0; i < limit; i++) {
if (path1[i] != path2[i])
break;
if (path1[i] == '/')
match= i;
}
// prefer shortest path with longest matches with
return (match << 16) - path1.length;
}
private IProject[] getOpenReferencedProjects(IProject prj) {
Set<IProject> result= new HashSet<IProject>();
if (prj.isOpen()) {
result.add(prj);
List<IProject> projectsToSearch= new ArrayList<IProject>();
projectsToSearch.add(prj);
for (int i=0; i<projectsToSearch.size(); i++) {
IProject project= projectsToSearch.get(i);
IProject[] nextLevel;
try {
nextLevel= project.getReferencedProjects();
for (IProject prjNextLevel : nextLevel) {
if (prjNextLevel.isOpen() && result.add(prjNextLevel)) {
projectsToSearch.add(prjNextLevel);
}
}
} catch (CoreException e) {
}
}
}
return result.toArray(new IProject[result.size()]);
}
}