package org.checkerframework.eclipse.util;
import static org.checkerframework.eclipse.util.JavaUtils.iterable;
import static org.eclipse.core.resources.IResource.FILE;
import static org.eclipse.core.resources.IResource.FOLDER;
import java.io.File;
import java.lang.RuntimeException;
import java.util.*;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jface.viewers.IStructuredSelection;
public class ResourceUtils {
private ResourceUtils() {
throw new AssertionError("Shouldn't be initialized");
}
/**
* @param relativePath workspace relative path
* @return given path if path is not known in workspace
*/
public static IPath relativeToAbsolute(IPath relativePath) {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IResource resource = root.findMember(relativePath);
return (resource != null) ? resource.getLocation() : relativePath;
}
/**
* Returns a list of all files in a resource delta. This is of help when performing an
* incremental build.
*
* @return Collection A list of all files to be built.
*/
public static List<IResource> collectIncremental(IResourceDelta delta) {
// XXX deleted packages should be considered to remove markers
List<IResource> result = new ArrayList<IResource>();
List<IResourceDelta> foldersDelta = new ArrayList<IResourceDelta>();
for (IResourceDelta childDelta : delta.getAffectedChildren()) {
IResource child = childDelta.getResource();
if (child.isDerived()) {
continue;
}
int childType = child.getType();
int deltaKind = childDelta.getKind();
if (childType == FILE) {
if ((deltaKind == IResourceDelta.ADDED || deltaKind == IResourceDelta.CHANGED)
&& Util.isJavaArtifact(child)) {
result.add(child);
}
} else if (childType == FOLDER) {
if (deltaKind == IResourceDelta.ADDED) {
result.add(child);
} else if (deltaKind == IResourceDelta.REMOVED) {
// TODO should just remove markers....
IContainer parent = child.getParent();
if (parent instanceof IProject) {
// have to recompute entire project if one of root
// folders is removed
result.clear();
result.add(parent);
return result;
}
result.add(parent);
} else {
foldersDelta.add(childDelta);
}
}
}
for (IResourceDelta childDelta : foldersDelta) {
result.addAll(collectIncremental(childDelta));
}
return result;
}
/**
* Convenient method to get resources from adaptables
*
* @param element an IAdaptable object which may provide an adapter for IResource
* @return resource object or null
*/
public static IResource getResource(Object element) {
if (element instanceof IResource) {
return (IResource) element;
}
if (element instanceof IAdaptable) {
IAdaptable adaptable = (IAdaptable) element;
return (IResource) adaptable.getAdapter(IResource.class);
}
return null;
}
/**
* Collects and combines the selection which may contain sources from different projects and /
* or multiple sources from same project.
*
* <p>If selection contains hierarchical data (like file and its parent directory), the only
* topmost element is returned (same for directories from projects).
*
* <p>The children from selected parents are not resolved, so that the return value contains the
* 'highest' possible hierarchical elements without children.
*
* @param structuredSelection
* @return a map with the project as a key and selected resources as value. If project itself
* was selected, then key is the same as value.
*/
public static Map<IProject, List<IResource>> getResourcesPerProject(
IStructuredSelection structuredSelection) {
Map<IProject, List<IResource>> projectsMap = new HashMap<IProject, List<IResource>>();
@SuppressWarnings("unchecked")
Iterable<?> iterable = iterable(structuredSelection.iterator());
for (Object element : iterable) {
IResource resource = getResource(element);
mapResource(resource, projectsMap, false);
}
return projectsMap;
}
/** Maps the resource into its project */
private static void mapResource(
IResource resource,
Map<IProject, List<IResource>> projectsMap,
boolean checkJavaProject) {
if (resource.getType() == FILE && !Util.isJavaArtifact(resource)) {
// Ignore non java files
return;
}
IProject project = resource.getProject();
if (checkJavaProject && !Util.isJavaProject(project)) {
// non java projects: can happen only for changesets
return;
}
List<IResource> resources = projectsMap.get(project);
if (resources == null) {
resources = new ArrayList<IResource>();
projectsMap.put(project, resources);
}
// do not need to check for duplicates, cause user cannot select
// the same element twice
if (!containsParents(resources, resource)) {
resources.add(resource);
}
}
/**
* @param resources
* @param candidate
* @return true if the given list contains at least one parent of the given candidate
*/
private static boolean containsParents(List<IResource> resources, IResource candidate) {
IPath location = candidate.getLocation();
for (IResource resource : resources) {
if (resource.getType() == FILE) {
continue;
}
IPath resourceLoc = resource.getLocation();
if (resourceLoc != null && resourceLoc.isPrefixOf(location)) return true;
}
return false;
}
public static IWorkspaceRoot workspaceRoot() {
return ResourcesPlugin.getWorkspace().getRoot();
}
public static Set<String> sourceFilesOf(IJavaElement element) throws CoreException {
final Set<String> fileNames = new LinkedHashSet<String>();
for (ICompilationUnit cu : Util.getAllCompilationUnits(element)) {
fileNames.add(cu.getResource().getLocation().toOSString());
}
return fileNames;
}
public static Set<String> sourceFilesOf(List<IJavaElement> elements) throws CoreException {
final Set<String> fileNames = new LinkedHashSet<String>();
for (final IJavaElement element : elements) {
final Set<String> files = sourceFilesOf(element);
for (String file : files) {
if (file.endsWith(".java")) {
fileNames.add(file);
}
}
}
return fileNames;
}
/**
* Get the specified project file as an Eclipse resource.
*
* <p>Returns null if the file isn't found.
*/
public static IResource getFile(IJavaProject jProject, File file) {
IProject project = jProject.getProject();
IPath filePath = Path.fromOSString(file.getPath());
int segCount = project.getLocation().segmentCount();
return project.findMember(filePath.removeFirstSegments(segCount));
}
/** Returns the path of the output directory of the project */
public static String outputLocation(IClasspathEntry cp, IJavaProject project) {
IPath out = cp.getOutputLocation();
if (out == null) {
try {
out = project.getOutputLocation();
//TODO: THERE HAS TO BE A BETTER WAY TO DO THIS BECAUSE THIS IS KLUDGERIFFIC
if (out != null) {
String path =
project.getProject().getLocation().toOSString()
+ File.separator
+ ".."
+ File.separator
+ project.getOutputLocation().toOSString();
return new File(path).getCanonicalPath();
}
} catch (final Exception exc) {
throw new RuntimeException(exc);
}
} else {
return out.toOSString();
}
// location is null if the classpath entry outputs to the 'default'
// location, i.e. project
IFile outDir = ResourceUtils.workspaceRoot().getFile(cp.getPath());
return outDir.getLocation().toOSString();
}
}