blob: e29cf5c24df2342e223b99f79752727346844da6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2012 QNX Software Systems 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:
* 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<>();
private Set<IPath> fContainerSet = new HashSet<>();
private Set<ICProject> fProjectSet = new HashSet<>();
private Set<ICProject> fEnclosingProjectSet = new HashSet<>();
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);
}
@Override
public Collection<IPath> pathSet() {
return fPathSet;
}
@Override
public Collection<IPath> containerSet() {
return fContainerSet;
}
@Override
public Collection<ICProject> projectSet() {
return fProjectSet;
}
@Override
public Collection<ICProject> enclosingProjectSet() {
return fEnclosingProjectSet;
}
@Override
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;
}
@Override
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;
}
@Override
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 (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;
}
@Override
public boolean encloses(String path) {
return encloses(new Path(path));
}
@Override
public boolean encloses(ICElement element) {
return encloses(element.getPath());
}
@Override
public boolean encloses(IWorkingCopy workingCopy) {
return encloses(workingCopy.getOriginalElement().getPath());
}
@Override
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];
}
}
@Override
public boolean isPathScope() {
return !fPathSet.isEmpty();
}
@Override
public boolean isProjectScope() {
return !fProjectSet.isEmpty();
}
@Override
public boolean isWorkspaceScope() {
return fWorkspaceScope;
}
@Override
public boolean isEmpty() {
return (!isWorkspaceScope() && fPathSet.isEmpty() && fContainerSet.isEmpty() && fProjectSet.isEmpty());
}
@Override
public void add(IWorkingCopy workingCopy) {
IPath path = workingCopy.getOriginalElement().getPath();
ICProject cProject = workingCopy.getCProject();
fPathSet.add(path);
addEnclosingProject(cProject);
}
@Override
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;
}
}
}
}
@Override
public void add(ICProject project) {
fProjectSet.add(project);
fProjects = null;
fAllProjects = null;
addEnclosingProject(project);
}
private void addEnclosingProject(ICProject project) {
fEnclosingProjectSet.add(project);
}
@Override
public void addWorkspace() {
fWorkspaceScope = true;
fProjects = null;
fAllProjects = null;
}
@Override
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;
}
}
}
@Override
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();
}
@Override
public void clear() {
fPathSet.clear();
fContainerSet.clear();
fProjectSet.clear();
fEnclosingProjectSet.clear();
fWorkspaceScope = false;
fProjects = null;
fAllProjects = null;
fContainerPaths = null;
}
}