blob: dc9801bd3088330fd25c1047eb69893a770e66a6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2017 IBM Corporation 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
*
*******************************************************************************/
package org.eclipse.dltk.internal.core;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.DLTKLanguageManager;
import org.eclipse.dltk.core.IBuildpathEntry;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IProjectFragment;
import org.eclipse.dltk.core.IScriptFolder;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.internal.core.util.HashtableOfArrayToObject;
import org.eclipse.dltk.internal.core.util.Util;
class ProjectElementInfo extends OpenableElementInfo {
static class ProjectCache {
ProjectCache(IProjectFragment[] allProjectFragmentCache,
HashtableOfArrayToObject allPkgFragmentsCache,
HashtableOfArrayToObject isPackageCache,
Map<IProjectFragment, BuildpathEntry> rootToResolvedEntries) {
this.allProjectFragmentCache = allProjectFragmentCache;
this.allPkgFragmentsCache = allPkgFragmentsCache;
this.rootToResolvedEntries = rootToResolvedEntries;
this.isPackageCache = isPackageCache;
}
/*
* A cache of all project fragments of this project.
*/
public IProjectFragment[] allProjectFragmentCache;
/*
* A cache of all package fragments in this project. (a map from
* String[] (the package name) to IProjectFragment[] (the package
* fragment roots that contain a package fragment with this name)
*/
public HashtableOfArrayToObject allPkgFragmentsCache;
/*
* A set of package names (String[]) that are known to be packages.
*/
public HashtableOfArrayToObject isPackageCache;
public Map<IProjectFragment, BuildpathEntry> rootToResolvedEntries;
}
ProjectCache projectCache;
/**
* A array with all the non-script resources contained by this Project
* fragment
*/
private Object[] foreignResources;
/*
* Reset the package fragment roots and package fragment caches
*/
void resetCaches() {
this.projectCache = null;
}
void setForeignResources(Object[] resources) {
this.foreignResources = resources;
}
public Object[] getForeignResources(ScriptProject project) {
if (this.foreignResources == null) {
this.foreignResources = computeForeignResources(project);
}
return this.foreignResources;
}
private Object[] computeForeignResources(ScriptProject project) {
// determine if src == project and/or if bin == project
IPath projectPath = project.getProject().getFullPath();
boolean srcIsProject = false;
char[][] inclusionPatterns = null;
char[][] exclusionPatterns = null;
IBuildpathEntry[] buildpath = null;
try {
buildpath = project.getResolvedBuildpath();
for (int i = 0; i < buildpath.length; i++) {
IBuildpathEntry entry = buildpath[i];
if (projectPath.equals(entry.getPath())) {
srcIsProject = true;
inclusionPatterns = ((BuildpathEntry) entry)
.fullInclusionPatternChars();
exclusionPatterns = ((BuildpathEntry) entry)
.fullExclusionPatternChars();
break;
}
}
} catch (ModelException e) {
// ignore
}
Object[] resources = new IResource[5];
int resourcesCounter = 0;
try {
IResource[] members = ((IContainer) project.getResource())
.members();
for (int i = 0, max = members.length; i < max; i++) {
IResource res = members[i];
switch (res.getType()) {
case IResource.FILE:
IPath resFullPath = res.getFullPath();
String resName = res.getName();
// ignore a archive file on the buildpath
if (org.eclipse.dltk.compiler.util.Util.isArchiveFileName(
DLTKLanguageManager.getLanguageToolkit(project),
resName)
&& this.isBuildpathEntry(resFullPath, buildpath)) {
break;
}
// ignore source file if src == project
if (srcIsProject && Util.isValidSourceModule(project, res)
&& !Util.isExcluded(res, inclusionPatterns,
exclusionPatterns)) {
break;
}
// TODO: Add language dependent filters here.
// else add nonscriptresource
if (resources.length == resourcesCounter) {
// resize
System.arraycopy(resources, 0,
(resources = new IResource[resourcesCounter
* 2]),
0, resourcesCounter);
}
resources[resourcesCounter++] = res;
break;
case IResource.FOLDER:
resFullPath = res.getFullPath();
// ignore non-excluded folders on the buildpath or that
// correspond to an output location
if ((srcIsProject
&& !Util.isExcluded(res, inclusionPatterns,
exclusionPatterns)
&& Util.isValidFolderNameForPackage(
(IContainer) project.getResource(),
res.getName()))
|| this.isBuildpathEntry(resFullPath, buildpath)) {
break;
}
// else add nonscriptresource
if (resources.length == resourcesCounter) {
// resize
System.arraycopy(resources, 0,
(resources = new IResource[resourcesCounter
* 2]),
0, resourcesCounter);
}
resources[resourcesCounter++] = res;
}
}
if (resources.length != resourcesCounter) {
System.arraycopy(resources, 0,
(resources = new IResource[resourcesCounter]), 0,
resourcesCounter);
}
} catch (CoreException e) {
resources = NO_NON_SCRIPT_RESOURCES;
resourcesCounter = 0;
}
return resources;
}
/*
* Returns whether the given path is a buildpath entry or an output
* location.
*/
private boolean isBuildpathEntry(IPath path,
IBuildpathEntry[] resolvedBuildpath) {
for (int i = 0, length = resolvedBuildpath.length; i < length; i++) {
IBuildpathEntry entry = resolvedBuildpath[i];
if (entry.getPath().equals(path)) {
return true;
}
}
return false;
}
/*
* Adds the given name and its super names to the given set (e.g. for {"a",
* "b", "c"}, adds {"a", "b", "c"}, {"a", "b"}, and {"a"})
*/
public static void addNames(String[] name, HashtableOfArrayToObject set) {
set.put(name, name);
int length = name.length;
for (int i = length - 1; i > 0; i--) {
String[] superName = new String[i];
System.arraycopy(name, 0, superName, 0, i);
set.put(superName, superName);
}
}
/*
* Creates a new name lookup for this project info. The given project is
* assumed to be the handle of this info. This name lookup first looks in
* the given working copies.
*/
NameLookup newNameLookup(ScriptProject project,
ISourceModule[] workingCopies) {
ProjectCache cache = getProjectCache(project);
return new NameLookup(cache.allProjectFragmentCache,
cache.allPkgFragmentsCache, cache.isPackageCache, workingCopies,
cache.rootToResolvedEntries);
}
ProjectCache getProjectCache(ScriptProject project) {
ProjectCache cache = this.projectCache;
if (cache == null) {
IProjectFragment[] roots;
Map<IProjectFragment, BuildpathEntry> reverseMap = new HashMap<>(
3);
try {
roots = project.getAllProjectFragments(reverseMap);
} catch (ModelException e) {
// project does not exist: cannot happen since this is the info
// of the project
roots = new IProjectFragment[0];
reverseMap.clear();
}
HashtableOfArrayToObject fragmentsCache = new HashtableOfArrayToObject();
HashtableOfArrayToObject isPackageCache = new HashtableOfArrayToObject();
for (int i = 0, length = roots.length; i < length; i++) {
IProjectFragment root = roots[i];
IModelElement[] frags = null;
try {
if (DLTKCore.DEBUG) {
System.err.println(
"TODO: Require to check for ExternalProjectFragment compatibility."); //$NON-NLS-1$
}
if (root.isArchive() && !root.isOpen()) {
ArchiveProjectFragmentInfo info = new ArchiveProjectFragmentInfo();
((ArchiveProjectFragment) root).computeChildren(info,
new HashMap());
frags = info.getChildren();
} else
frags = root.getChildren();
} catch (ModelException e) {
// root doesn't exist: ignore
continue;
}
for (int j = 0, length2 = frags.length; j < length2; j++) {
IScriptFolder fragment = (IScriptFolder) frags[j];
IPath parentPath = fragment.getParent().getPath();
String[] pkgName = fragment.getPath()
.removeFirstSegments(parentPath.segmentCount())
.segments();
Object existing = fragmentsCache.get(pkgName);
if (existing == null) {
fragmentsCache.put(pkgName, root);
// cache whether each package and its including packages
// (see
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=119161)
// are actual packages
addNames(pkgName, isPackageCache);
} else {
if (existing instanceof IProjectFragment) {
fragmentsCache.put(pkgName, new IProjectFragment[] {
(IProjectFragment) existing, root });
} else {
IProjectFragment[] entry = (IProjectFragment[]) existing;
IProjectFragment[] copy = new IProjectFragment[entry.length
+ 1];
System.arraycopy(entry, 0, copy, 0, entry.length);
copy[entry.length] = root;
fragmentsCache.put(pkgName, copy);
}
}
}
}
cache = new ProjectCache(roots, fragmentsCache, isPackageCache,
reverseMap);
this.projectCache = cache;
}
return cache;
}
}