/******************************************************************************* * Copyright (c) 2004, 2009 QNX Software Systems 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: * QNX Software Systems - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.core.browser; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.IWorkingCopy; import org.eclipse.cdt.core.parser.IScannerInfo; import org.eclipse.cdt.core.parser.IScannerInfoProvider; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; /** * @noextend This class is not intended to be subclassed by clients. */ public class TypeSearchScope implements ITypeSearchScope { private Set<IPath> fPathSet = new HashSet<IPath>(); private Set<IPath> fContainerSet = new HashSet<IPath>(); private Set<ICProject> fProjectSet = new HashSet<ICProject>(); private Set<ICProject> fEnclosingProjectSet = new HashSet<ICProject>(); private boolean fWorkspaceScope = false; // cached arrays private ICProject[] fAllProjects = null; private ICProject[] fProjects = null; private IPath[] fContainerPaths = null; public TypeSearchScope() { } public TypeSearchScope(boolean workspaceScope) { fWorkspaceScope = workspaceScope; } public TypeSearchScope(ITypeSearchScope scope) { add(scope); } public TypeSearchScope(ICProject project) { add(project); } public Collection<IPath> pathSet() { return fPathSet; } public Collection<IPath> containerSet() { return fContainerSet; } public Collection<ICProject> projectSet() { return fProjectSet; } public Collection<ICProject> enclosingProjectSet() { return fEnclosingProjectSet; } public boolean encloses(ITypeSearchScope scope) { if (isWorkspaceScope()) return true; if (!scope.pathSet().isEmpty()) { // check if this scope encloses the other scope's paths for (Iterator<IPath> i = scope.pathSet().iterator(); i.hasNext(); ) { IPath path = i.next(); if (!encloses(path)) return false; } } if (!scope.containerSet().isEmpty()) { // check if this scope encloses the other scope's containers for (Iterator<IPath> i = scope.containerSet().iterator(); i.hasNext(); ) { IPath path = i.next(); if (!encloses(path)) return false; } } if (!scope.projectSet().isEmpty()) { // check if this scope encloses the other scope's projects for (Iterator<ICProject> i = scope.projectSet().iterator(); i.hasNext(); ) { ICProject project = i.next(); if (!encloses(project)) return false; } } return true; } public boolean encloses(ICProject project) { if (isWorkspaceScope()) return true; // check projects that were explicity added to scope if (fProjectSet.contains(project)) return true; return false; } public boolean encloses(IPath path) { if (isWorkspaceScope()) return true; // check files that were explicity added to scope if (fPathSet.contains(path)) return true; // check containers that were explicity added to scope // including subdirs if (fContainerSet.contains(path)) return true; if (fContainerPaths == null) { fContainerPaths = fContainerSet.toArray(new IPath[fContainerSet.size()]); // java.util.Arrays.sort(fContainerPaths); } for (int i = 0; i < fContainerPaths.length; ++i) { if (fContainerPaths[i].isPrefixOf(path)) { return true; } } // check projects that were explicity added to scope if (fProjectSet.contains(path)) return true; // check projects that were explicity added to scope if (fProjects == null) { fProjects = fProjectSet.toArray(new ICProject[fProjectSet.size()]); } // check if one of the projects contains path for (int i = 0; i < fProjects.length; ++i) { if (projectContainsPath(fProjects[i], path, false)) { return true; } } return false; } public boolean encloses(String path) { return encloses(new Path(path)); } public boolean encloses(ICElement element) { return encloses(element.getPath()); } public boolean encloses(IWorkingCopy workingCopy) { return encloses(workingCopy.getOriginalElement().getPath()); } public ICProject[] getEnclosingProjects() { if (isWorkspaceScope()) { return getAllProjects(); } return fEnclosingProjectSet.toArray(new ICProject[fEnclosingProjectSet.size()]); } private static boolean projectContainsPath(ICProject project, IPath path, boolean checkIncludePaths) { IPath projectPath = project.getProject().getFullPath(); if (projectPath.isPrefixOf(path)) { // ISourceRoot[] sourceRoots = null; // try { // sourceRoots = cProject.getSourceRoots(); // } catch (CModelException ex) { // } // if (sourceRoots != null) { // for (int j = 0; j < sourceRoots.length; ++j) { // ISourceRoot root = sourceRoots[j]; // if (root.isOnSourceEntry(path)) // return true; // } // } return true; } if (checkIncludePaths) { //TODO this appears to be very slow -- cache this? IPath[] includePaths = getIncludePaths(project); if (includePaths != null) { for (int i = 0; i < includePaths.length; ++i) { IPath include = includePaths[i]; if (include.isPrefixOf(path) || include.equals(path)) return true; } } } return false; } private static IPath[] getIncludePaths(ICProject project) { IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(project.getProject()); if (provider != null) { IScannerInfo info = provider.getScannerInformation(project.getProject()); if (info != null) { String[] includes = info.getIncludePaths(); if (includes != null && includes.length > 0) { IPath[] includePaths = new IPath[includes.length]; for (int i = 0; i < includes.length; ++i) { includePaths[i] = new Path(includes[i]); } // java.util.Arrays.sort(includePaths); return includePaths; } } } return null; } private static ICProject[] getAllProjects() { ICProject[] projects = getCProjects(); if (projects == null) projects = new ICProject[0]; return projects; } private static ICProject[] getCProjects() { try { return CoreModel.getDefault().getCModel().getCProjects(); } catch (CModelException e) { CCorePlugin.log(e); return new ICProject[0]; } } public boolean isPathScope() { return !fPathSet.isEmpty(); } public boolean isProjectScope() { return !fProjectSet.isEmpty(); } public boolean isWorkspaceScope() { return fWorkspaceScope; } public boolean isEmpty() { return (!isWorkspaceScope() && fPathSet.isEmpty() && fContainerSet.isEmpty() && fProjectSet.isEmpty()); } public void add(IWorkingCopy workingCopy) { IPath path = workingCopy.getOriginalElement().getPath(); ICProject cProject = workingCopy.getCProject(); fPathSet.add(path); addEnclosingProject(cProject); } public void add(IPath path, boolean addSubfolders, ICProject enclosingProject) { if (addSubfolders) { fContainerSet.add(path); fContainerPaths = null; } else { fPathSet.add(path); } if (enclosingProject != null) { addEnclosingProject(enclosingProject); } else { // check all projects in workspace if (fAllProjects == null) { fAllProjects = getAllProjects(); } // check if one of the projects contains path for (int i = 0; i < fAllProjects.length; ++i) { if (projectContainsPath(fAllProjects[i], path, false)) { addEnclosingProject(fAllProjects[i]); break; } } } } public void add(ICProject project) { fProjectSet.add(project); fProjects = null; fAllProjects = null; addEnclosingProject(project); } private void addEnclosingProject(ICProject project) { fEnclosingProjectSet.add(project); } public void addWorkspace() { fWorkspaceScope = true; fProjects = null; fAllProjects = null; } public void add(ICElement elem) { if (elem == null) return; switch (elem.getElementType()) { case ICElement.C_MODEL: { addWorkspace(); break; } case ICElement.C_PROJECT: { ICProject project = ((ICProject)elem); add(project); break; } case ICElement.C_CCONTAINER: { ICProject project = elem.getCProject(); add(elem.getPath(), true, project); break; } case ICElement.C_UNIT: { ICProject project = elem.getCProject(); add(elem.getPath(), false, project); break; } case ICElement.C_INCLUDE: case ICElement.C_NAMESPACE: case ICElement.C_TEMPLATE_CLASS: case ICElement.C_CLASS: case ICElement.C_STRUCT: case ICElement.C_UNION: case ICElement.C_ENUMERATION: case ICElement.C_TYPEDEF: { ICProject project = elem.getCProject(); add(elem.getPath(), false, project); break; } } } public void add(ITypeSearchScope scope) { fPathSet.addAll(scope.pathSet()); fContainerSet.addAll(scope.containerSet()); fProjectSet.addAll(scope.projectSet()); fEnclosingProjectSet.addAll(scope.enclosingProjectSet()); fProjects = null; fAllProjects = null; fContainerPaths = null; fWorkspaceScope |= scope.isWorkspaceScope(); } public void clear() { fPathSet.clear(); fContainerSet.clear(); fProjectSet.clear(); fEnclosingProjectSet.clear(); fWorkspaceScope = false; fProjects = null; fAllProjects = null; fContainerPaths = null; } }