/******************************************************************************* * Copyright (c) 2000, 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package net.sourceforge.phpdt.internal.core; import java.util.HashMap; import java.util.HashSet; import net.sourceforge.phpdt.core.IClasspathEntry; import net.sourceforge.phpdt.core.IJavaModelStatus; import net.sourceforge.phpdt.core.IJavaModelStatusConstants; import net.sourceforge.phpdt.core.IJavaProject; import net.sourceforge.phpdt.core.IPackageFragmentRoot; import net.sourceforge.phpdt.core.JavaCore; import net.sourceforge.phpdt.core.JavaModelException; import net.sourceforge.phpdt.core.compiler.CharOperation; import net.sourceforge.phpdt.internal.core.util.Util; //incastrix //import net.sourceforge.phpdt.internal.corext.Assert; //import org.eclipse.core.runtime.Assert; import net.sourceforge.phpeclipse.PHPeclipsePlugin; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.AssertionFailedException; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * @see IClasspathEntry */ public class ClasspathEntry implements IClasspathEntry { /** * Describes the kind of classpath entry - one of CPE_PROJECT, CPE_LIBRARY, * CPE_SOURCE, CPE_VARIABLE or CPE_CONTAINER */ public int entryKind; /** * Describes the kind of package fragment roots found on this classpath * entry - either K_BINARY or K_SOURCE or K_OUTPUT. */ public int contentKind; /** * The meaning of the path of a classpath entry depends on its entry kind: *
CPE_SOURCE
) -
* The path associated with this entry is the absolute path to the root
* folder. CPE_LIBRARY
) -
* the path associated with this entry is the absolute path to the JAR (or
* root folder), and in case it refers to an external JAR, then there is no
* associated resource in the workbench.
* CPE_PROJECT
) - the path of the
* entry denotes the path to the corresponding project resource.CPE_VARIABLE
) - the first segment
* of the path is the name of a classpath variable. If this classpath
* variable is bound to the path CPE_CONTAINER
) - the first
* segment of the path is denoting the unique container identifier (for
* which a ClasspathContainerInitializer
could be
* registered), and the remaining segments are used as additional hints for
* resolving the container entry to an actual
* IClasspathContainer
.null
if this classpath entry has no source
* attachment.
*
* Only library and variable classpath entries may have source attachments.
* For library classpath entries, the result path (if present) locates a
* source archive. For variable classpath entries, the result path (if
* present) has an analogous form and meaning as the variable path, namely
* the first segment is the name of a classpath variable.
*/
public IPath sourceAttachmentPath;
/**
* Describes the path within the source archive where package fragments are
* located. An empty path indicates that packages are located at the root of
* the source archive. Returns a non-null
value if and only
* if getSourceAttachmentPath
returns a non-null
* value.
*/
public IPath sourceAttachmentRootPath;
/**
* Specific output location (for this source entry)
*/
public IPath specificOutputLocation;
/**
* A constant indicating an output location.
*/
public static final int K_OUTPUT = 10;
/**
* The export flag
*/
public boolean isExported;
/**
* Creates a class path entry of the specified kind with the given path.
*/
public ClasspathEntry(int contentKind, int entryKind, IPath path,
IPath[] inclusionPatterns, IPath[] exclusionPatterns,
IPath sourceAttachmentPath, IPath sourceAttachmentRootPath,
IPath specificOutputLocation, boolean isExported) {
this.contentKind = contentKind;
this.entryKind = entryKind;
this.path = path;
this.inclusionPatterns = inclusionPatterns;
if (inclusionPatterns != INCLUDE_ALL && inclusionPatterns.length > 0) {
this.fullCharInclusionPatterns = UNINIT_PATTERNS;
} else {
this.fullCharInclusionPatterns = null; // empty inclusion pattern
// means everything is
// included
}
this.exclusionPatterns = exclusionPatterns;
if (exclusionPatterns.length > 0) {
this.fullCharExclusionPatterns = UNINIT_PATTERNS;
}
this.sourceAttachmentPath = sourceAttachmentPath;
this.sourceAttachmentRootPath = sourceAttachmentRootPath;
this.specificOutputLocation = specificOutputLocation;
this.isExported = isExported;
}
/*
* Returns a char based representation of the exclusions patterns full path.
*/
public char[][] fullExclusionPatternChars() {
if (this.fullCharExclusionPatterns == UNINIT_PATTERNS) {
int length = this.exclusionPatterns.length;
this.fullCharExclusionPatterns = new char[length][];
IPath prefixPath = this.path.removeTrailingSeparator();
for (int i = 0; i < length; i++) {
this.fullCharExclusionPatterns[i] = prefixPath.append(
this.exclusionPatterns[i]).toString().toCharArray();
}
}
return this.fullCharExclusionPatterns;
}
/*
* Returns a char based representation of the exclusions patterns full path.
*/
public char[][] fullInclusionPatternChars() {
if (this.fullCharInclusionPatterns == UNINIT_PATTERNS) {
int length = this.inclusionPatterns.length;
this.fullCharInclusionPatterns = new char[length][];
IPath prefixPath = this.path.removeTrailingSeparator();
for (int i = 0; i < length; i++) {
this.fullCharInclusionPatterns[i] = prefixPath.append(
this.inclusionPatterns[i]).toString().toCharArray();
}
}
return this.fullCharInclusionPatterns;
}
/**
* Returns the XML encoding of the class path.
*/
public Element elementEncode(Document document, IPath projectPath)
throws JavaModelException {
Element element = document.createElement("classpathentry"); //$NON-NLS-1$
element.setAttribute("kind", kindToString(this.entryKind)); //$NON-NLS-1$
IPath xmlPath = this.path;
if (this.entryKind != IClasspathEntry.CPE_VARIABLE
&& this.entryKind != IClasspathEntry.CPE_CONTAINER) {
// translate to project relative from absolute (unless a device
// path)
if (xmlPath.isAbsolute()) {
if (projectPath != null && projectPath.isPrefixOf(xmlPath)) {
if (xmlPath.segment(0).equals(projectPath.segment(0))) {
xmlPath = xmlPath.removeFirstSegments(1);
xmlPath = xmlPath.makeRelative();
} else {
xmlPath = xmlPath.makeAbsolute();
}
}
}
}
element.setAttribute("path", xmlPath.toString()); //$NON-NLS-1$
if (this.sourceAttachmentPath != null) {
element.setAttribute(
"sourcepath", this.sourceAttachmentPath.toString()); //$NON-NLS-1$
}
if (this.sourceAttachmentRootPath != null) {
element.setAttribute(
"rootpath", this.sourceAttachmentRootPath.toString()); //$NON-NLS-1$
}
if (this.isExported) {
element.setAttribute("exported", "true"); //$NON-NLS-1$ //$NON-NLS-2$
}
if (this.exclusionPatterns.length > 0) {
StringBuffer excludeRule = new StringBuffer(10);
for (int i = 0, max = this.exclusionPatterns.length; i < max; i++) {
if (i > 0)
excludeRule.append('|');
excludeRule.append(this.exclusionPatterns[i]);
}
element.setAttribute("excluding", excludeRule.toString()); //$NON-NLS-1$
}
if (this.specificOutputLocation != null) {
IPath outputLocation = this.specificOutputLocation
.removeFirstSegments(1);
outputLocation = outputLocation.makeRelative();
element.setAttribute("output", outputLocation.toString()); //$NON-NLS-1$
}
return element;
}
public static IClasspathEntry elementDecode(Element element,
IJavaProject project) {
IPath projectPath = project.getProject().getFullPath();
String kindAttr = element.getAttribute("kind"); //$NON-NLS-1$
String pathAttr = element.getAttribute("path"); //$NON-NLS-1$
// ensure path is absolute
IPath path = new Path(pathAttr);
int kind = kindFromString(kindAttr);
if (kind != IClasspathEntry.CPE_VARIABLE
&& kind != IClasspathEntry.CPE_CONTAINER && !path.isAbsolute()) {
path = projectPath.append(path);
}
// source attachment info (optional)
// IPath sourceAttachmentPath = element.hasAttribute("sourcepath") //$NON-NLS-1$
// ? new Path(element.getAttribute("sourcepath")) //$NON-NLS-1$
// : null;
// IPath sourceAttachmentRootPath = element.hasAttribute("rootpath") //$NON-NLS-1$
// ? new Path(element.getAttribute("rootpath")) //$NON-NLS-1$
// : null;
// exported flag (optional)
boolean isExported = element.getAttribute("exported").equals("true"); //$NON-NLS-1$ //$NON-NLS-2$
// exclusion patterns (optional)
String exclusion = element.getAttribute("excluding"); //$NON-NLS-1$
IPath[] exclusionPatterns = ClasspathEntry.NO_EXCLUSION_PATTERNS;
if (!exclusion.equals("")) { //$NON-NLS-1$
char[][] patterns = CharOperation.splitOn('|', exclusion
.toCharArray());
int patternCount;
if ((patternCount = patterns.length) > 0) {
exclusionPatterns = new IPath[patternCount];
for (int j = 0; j < patterns.length; j++) {
exclusionPatterns[j] = new Path(new String(patterns[j]));
}
}
}
// custom output location
IPath outputLocation = element.hasAttribute("output") ? projectPath.append(element.getAttribute("output")) : null; //$NON-NLS-1$ //$NON-NLS-2$
// recreate the CP entry
switch (kind) {
case IClasspathEntry.CPE_PROJECT:
return JavaCore.newProjectEntry(path, isExported);
// case IClasspathEntry.CPE_LIBRARY :
// return JavaCore.newLibraryEntry(
// path,
// sourceAttachmentPath,
// sourceAttachmentRootPath,
// isExported);
case IClasspathEntry.CPE_SOURCE:
// must be an entry in this project or specify another project
String projSegment = path.segment(0);
if (projSegment != null
&& projSegment.equals(project.getElementName())) { // this
// project
return JavaCore.newSourceEntry(path, exclusionPatterns,
outputLocation);
} else { // another project
return JavaCore.newProjectEntry(path, isExported);
}
// case IClasspathEntry.CPE_VARIABLE :
// return PHPCore.newVariableEntry(
// path,
// sourceAttachmentPath,
// sourceAttachmentRootPath,
// isExported);
case IClasspathEntry.CPE_CONTAINER:
return JavaCore.newContainerEntry(path, isExported);
case ClasspathEntry.K_OUTPUT:
if (!path.isAbsolute())
return null;
return new ClasspathEntry(ClasspathEntry.K_OUTPUT,
IClasspathEntry.CPE_LIBRARY, path,
ClasspathEntry.INCLUDE_ALL, ClasspathEntry.EXCLUDE_NONE,
null, // source attachment
null, // source attachment root
null, // custom output location
false);
default:
throw new /*Assert.*/AssertionFailedException(Util.bind(
"classpath.unknownKind", kindAttr)); //$NON-NLS-1$
}
}
/**
* Returns true if the given object is a classpath entry with equivalent
* attributes.
*/
public boolean equals(Object object) {
if (this == object)
return true;
if (object instanceof IClasspathEntry) {
IClasspathEntry otherEntry = (IClasspathEntry) object;
if (this.contentKind != otherEntry.getContentKind())
return false;
if (this.entryKind != otherEntry.getEntryKind())
return false;
if (this.isExported != otherEntry.isExported())
return false;
if (!this.path.equals(otherEntry.getPath()))
return false;
IPath otherPath = otherEntry.getSourceAttachmentPath();
if (this.sourceAttachmentPath == null) {
if (otherPath != null)
return false;
} else {
if (!this.sourceAttachmentPath.equals(otherPath))
return false;
}
otherPath = otherEntry.getSourceAttachmentRootPath();
if (this.sourceAttachmentRootPath == null) {
if (otherPath != null)
return false;
} else {
if (!this.sourceAttachmentRootPath.equals(otherPath))
return false;
}
IPath[] otherIncludes = otherEntry.getInclusionPatterns();
if (this.inclusionPatterns != otherIncludes) {
if (this.inclusionPatterns == null)
return false;
int includeLength = this.inclusionPatterns.length;
if (otherIncludes == null
|| otherIncludes.length != includeLength)
return false;
for (int i = 0; i < includeLength; i++) {
// compare toStrings instead of IPaths
// since IPath.equals is specified to ignore trailing
// separators
if (!this.inclusionPatterns[i].toString().equals(
otherIncludes[i].toString()))
return false;
}
}
IPath[] otherExcludes = otherEntry.getExclusionPatterns();
if (this.exclusionPatterns != otherExcludes) {
int excludeLength = this.exclusionPatterns.length;
if (otherExcludes.length != excludeLength)
return false;
for (int i = 0; i < excludeLength; i++) {
// compare toStrings instead of IPaths
// since IPath.equals is specified to ignore trailing
// separators
if (!this.exclusionPatterns[i].toString().equals(
otherExcludes[i].toString()))
return false;
}
}
otherPath = otherEntry.getOutputLocation();
if (this.specificOutputLocation == null) {
if (otherPath != null)
return false;
} else {
if (!this.specificOutputLocation.equals(otherPath))
return false;
}
return true;
} else {
return false;
}
}
/**
* @see IClasspathEntry
*/
public int getContentKind() {
return this.contentKind;
}
/**
* @see IClasspathEntry
*/
public int getEntryKind() {
return this.entryKind;
}
/**
* @see IClasspathEntry#getExclusionPatterns()
*/
public IPath[] getExclusionPatterns() {
return this.exclusionPatterns;
}
/**
* @see IClasspathEntry#getExclusionPatterns()
*/
public IPath[] getInclusionPatterns() {
return this.inclusionPatterns;
}
/**
* @see IClasspathEntry#getOutputLocation()
*/
public IPath getOutputLocation() {
return this.specificOutputLocation;
}
/**
* @see IClasspathEntry
*/
public IPath getPath() {
return this.path;
}
/**
* @see IClasspathEntry
*/
public IPath getSourceAttachmentPath() {
return this.sourceAttachmentPath;
}
/**
* @see IClasspathEntry
*/
public IPath getSourceAttachmentRootPath() {
return this.sourceAttachmentRootPath;
}
/**
* Returns the hash code for this classpath entry
*/
public int hashCode() {
return this.path.hashCode();
}
/**
* @see IClasspathEntry#isExported()
*/
public boolean isExported() {
return this.isExported;
}
/**
* Returns the kind of a PackageFragmentRoot
from its
* String
form.
*/
static int kindFromString(String kindStr) {
if (kindStr.equalsIgnoreCase("prj")) //$NON-NLS-1$
return IClasspathEntry.CPE_PROJECT;
if (kindStr.equalsIgnoreCase("var")) //$NON-NLS-1$
return IClasspathEntry.CPE_VARIABLE;
if (kindStr.equalsIgnoreCase("con")) //$NON-NLS-1$
return IClasspathEntry.CPE_CONTAINER;
if (kindStr.equalsIgnoreCase("src")) //$NON-NLS-1$
return IClasspathEntry.CPE_SOURCE;
if (kindStr.equalsIgnoreCase("lib")) //$NON-NLS-1$
return IClasspathEntry.CPE_LIBRARY;
if (kindStr.equalsIgnoreCase("output")) //$NON-NLS-1$
return ClasspathEntry.K_OUTPUT;
return -1;
}
/**
* Returns a String
for the kind of a class path entry.
*/
static String kindToString(int kind) {
switch (kind) {
case IClasspathEntry.CPE_PROJECT:
return "src"; // backward compatibility //$NON-NLS-1$
case IClasspathEntry.CPE_SOURCE:
return "src"; //$NON-NLS-1$
case IClasspathEntry.CPE_LIBRARY:
return "lib"; //$NON-NLS-1$
case IClasspathEntry.CPE_VARIABLE:
return "var"; //$NON-NLS-1$
case IClasspathEntry.CPE_CONTAINER:
return "con"; //$NON-NLS-1$
case ClasspathEntry.K_OUTPUT:
return "output"; //$NON-NLS-1$
default:
return "unknown"; //$NON-NLS-1$
}
}
/**
* Returns a printable representation of this classpath entry.
*/
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(getPath().toString());
buffer.append('[');
switch (getEntryKind()) {
case IClasspathEntry.CPE_LIBRARY:
buffer.append("CPE_LIBRARY"); //$NON-NLS-1$
break;
case IClasspathEntry.CPE_PROJECT:
buffer.append("CPE_PROJECT"); //$NON-NLS-1$
break;
case IClasspathEntry.CPE_SOURCE:
buffer.append("CPE_SOURCE"); //$NON-NLS-1$
break;
case IClasspathEntry.CPE_VARIABLE:
buffer.append("CPE_VARIABLE"); //$NON-NLS-1$
break;
case IClasspathEntry.CPE_CONTAINER:
buffer.append("CPE_CONTAINER"); //$NON-NLS-1$
break;
}
buffer.append("]["); //$NON-NLS-1$
switch (getContentKind()) {
case IPackageFragmentRoot.K_BINARY:
buffer.append("K_BINARY"); //$NON-NLS-1$
break;
case IPackageFragmentRoot.K_SOURCE:
buffer.append("K_SOURCE"); //$NON-NLS-1$
break;
case ClasspathEntry.K_OUTPUT:
buffer.append("K_OUTPUT"); //$NON-NLS-1$
break;
}
buffer.append(']');
if (getSourceAttachmentPath() != null) {
buffer.append("[sourcePath:"); //$NON-NLS-1$
buffer.append(getSourceAttachmentPath());
buffer.append(']');
}
if (getSourceAttachmentRootPath() != null) {
buffer.append("[rootPath:"); //$NON-NLS-1$
buffer.append(getSourceAttachmentRootPath());
buffer.append(']');
}
buffer.append("[isExported:"); //$NON-NLS-1$
buffer.append(this.isExported);
buffer.append(']');
IPath[] patterns = getExclusionPatterns();
int length;
if ((length = patterns.length) > 0) {
buffer.append("[excluding:"); //$NON-NLS-1$
for (int i = 0; i < length; i++) {
buffer.append(patterns[i]);
if (i != length - 1) {
buffer.append('|');
}
}
buffer.append(']');
}
if (getOutputLocation() != null) {
buffer.append("[output:"); //$NON-NLS-1$
buffer.append(getOutputLocation());
buffer.append(']');
}
return buffer.toString();
}
/**
* Answers an ID which is used to distinguish entries during package
* fragment root computations
*/
public String rootID() {
if (this.rootID == null) {
switch (this.entryKind) {
case IClasspathEntry.CPE_LIBRARY:
this.rootID = "[LIB]" + this.path; //$NON-NLS-1$
break;
case IClasspathEntry.CPE_PROJECT:
this.rootID = "[PRJ]" + this.path; //$NON-NLS-1$
break;
case IClasspathEntry.CPE_SOURCE:
this.rootID = "[SRC]" + this.path; //$NON-NLS-1$
break;
case IClasspathEntry.CPE_VARIABLE:
this.rootID = "[VAR]" + this.path; //$NON-NLS-1$
break;
case IClasspathEntry.CPE_CONTAINER:
this.rootID = "[CON]" + this.path; //$NON-NLS-1$
break;
default:
this.rootID = ""; //$NON-NLS-1$
break;
}
}
return this.rootID;
}
/**
* @see IClasspathEntry
* @deprecated
*/
public IClasspathEntry getResolvedEntry() {
return JavaCore.getResolvedClasspathEntry(this);
}
/**
* Returns the XML encoding of the class path.
*/
public void elementEncode(XMLWriter writer, IPath projectPath,
boolean indent, boolean newLine) {
HashMap parameters = new HashMap();
parameters.put("kind", ClasspathEntry.kindToString(this.entryKind));//$NON-NLS-1$
IPath xmlPath = this.path;
if (this.entryKind != IClasspathEntry.CPE_VARIABLE
&& this.entryKind != IClasspathEntry.CPE_CONTAINER) {
// translate to project relative from absolute (unless a device
// path)
if (xmlPath.isAbsolute()) {
if (projectPath != null && projectPath.isPrefixOf(xmlPath)) {
if (xmlPath.segment(0).equals(projectPath.segment(0))) {
xmlPath = xmlPath.removeFirstSegments(1);
xmlPath = xmlPath.makeRelative();
} else {
xmlPath = xmlPath.makeAbsolute();
}
}
}
}
parameters.put("path", String.valueOf(xmlPath));//$NON-NLS-1$
if (this.sourceAttachmentPath != null) {
xmlPath = this.sourceAttachmentPath;
// translate to project relative from absolute
if (this.entryKind != IClasspathEntry.CPE_VARIABLE
&& projectPath != null && projectPath.isPrefixOf(xmlPath)) {
if (xmlPath.segment(0).equals(projectPath.segment(0))) {
xmlPath = xmlPath.removeFirstSegments(1);
xmlPath = xmlPath.makeRelative();
}
}
parameters.put("sourcepath", String.valueOf(xmlPath));//$NON-NLS-1$
}
if (this.sourceAttachmentRootPath != null) {
parameters.put(
"rootpath", String.valueOf(this.sourceAttachmentRootPath));//$NON-NLS-1$
}
if (this.isExported) {
parameters.put("exported", "true");//$NON-NLS-1$//$NON-NLS-2$
}
// if (this.inclusionPatterns != null && this.inclusionPatterns.length >
// 0) {
// StringBuffer includeRule = new StringBuffer(10);
// for (int i = 0, max = this.inclusionPatterns.length; i < max; i++){
// if (i > 0) includeRule.append('|');
// includeRule.append(this.inclusionPatterns[i]);
// }
// parameters.put("including",
// String.valueOf(includeRule));//$NON-NLS-1$
// }
if (this.exclusionPatterns != null && this.exclusionPatterns.length > 0) {
StringBuffer excludeRule = new StringBuffer(10);
for (int i = 0, max = this.exclusionPatterns.length; i < max; i++) {
if (i > 0)
excludeRule.append('|');
excludeRule.append(this.exclusionPatterns[i]);
}
parameters.put("excluding", String.valueOf(excludeRule));//$NON-NLS-1$
}
if (this.specificOutputLocation != null) {
IPath outputLocation = this.specificOutputLocation
.removeFirstSegments(1);
outputLocation = outputLocation.makeRelative();
parameters.put("output", String.valueOf(outputLocation));//$NON-NLS-1$
}
writer.printTag("classpathentry", parameters, indent, newLine, true);//$NON-NLS-1$
}
/**
* Validate a given classpath and output location for a project, using the
* following rules:
*
* This validation is intended to anticipate classpath issues prior to * assigning it to a project. In particular, it will automatically be * performed during the classpath setting operation (if validation fails, * the classpath setting will not complete). *
*
* @param javaProject
* the given java project
* @param rawClasspath
* a given classpath
* @param projectOutputLocation
* a given output location
* @return a status object with code IStatus.OK
if the given
* classpath and output location are compatible, otherwise a status
* object indicating what is wrong with the classpath or output
* location
*/
public static IJavaModelStatus validateClasspath(IJavaProject javaProject,
IClasspathEntry[] rawClasspath, IPath projectOutputLocation) {
IProject project = javaProject.getProject();
IPath projectPath = project.getFullPath();
String projectName = javaProject.getElementName();
/* validate output location */
if (projectOutputLocation == null) {
return new JavaModelStatus(IJavaModelStatusConstants.NULL_PATH);
}
if (projectOutputLocation.isAbsolute()) {
if (!projectPath.isPrefixOf(projectOutputLocation)) {
return new JavaModelStatus(
IJavaModelStatusConstants.PATH_OUTSIDE_PROJECT,
javaProject, projectOutputLocation.toString());
}
} else {
return new JavaModelStatus(IJavaModelStatusConstants.RELATIVE_PATH,
projectOutputLocation);
}
boolean hasSource = false;
boolean hasLibFolder = false;
// tolerate null path, it will be reset to default
if (rawClasspath == null)
return JavaModelStatus.VERIFIED_OK;
// retrieve resolved classpath
IClasspathEntry[] classpath;
try {
classpath = ((JavaProject) javaProject).getResolvedClasspath(
rawClasspath, null /* output */, true/* ignore pb */,
false/* no marker */, null /* no reverse map */);
} catch (JavaModelException e) {
return e.getJavaModelStatus();
}
int length = classpath.length;
int outputCount = 1;
IPath[] outputLocations = new IPath[length + 1];
boolean[] allowNestingInOutputLocations = new boolean[length + 1];
outputLocations[0] = projectOutputLocation;
// retrieve and check output locations
IPath potentialNestedOutput = null; // for error reporting purpose
int sourceEntryCount = 0;
boolean disableExclusionPatterns = JavaCore.DISABLED.equals(javaProject
.getOption(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS,
true));
boolean disableCustomOutputLocations = JavaCore.DISABLED
.equals(javaProject
.getOption(
JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS,
true));
for (int i = 0; i < length; i++) {
IClasspathEntry resolvedEntry = classpath[i];
switch (resolvedEntry.getEntryKind()) {
case IClasspathEntry.CPE_SOURCE:
sourceEntryCount++;
if (disableExclusionPatterns
&& ((resolvedEntry.getInclusionPatterns() != null && resolvedEntry
.getInclusionPatterns().length > 0) || (resolvedEntry
.getExclusionPatterns() != null && resolvedEntry
.getExclusionPatterns().length > 0))) {
return new JavaModelStatus(
IJavaModelStatusConstants.DISABLED_CP_EXCLUSION_PATTERNS,
javaProject, resolvedEntry.getPath());
}
IPath customOutput;
if ((customOutput = resolvedEntry.getOutputLocation()) != null) {
if (disableCustomOutputLocations) {
return new JavaModelStatus(
IJavaModelStatusConstants.DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS,
javaProject, resolvedEntry.getPath());
}
// ensure custom output is in project
if (customOutput.isAbsolute()) {
if (!javaProject.getPath().isPrefixOf(customOutput)) {
return new JavaModelStatus(
IJavaModelStatusConstants.PATH_OUTSIDE_PROJECT,
javaProject, customOutput.toString());
}
} else {
return new JavaModelStatus(
IJavaModelStatusConstants.RELATIVE_PATH,
customOutput);
}
// ensure custom output doesn't conflict with other outputs
// check exact match
if (Util.indexOfMatchingPath(customOutput, outputLocations,
outputCount) != -1) {
continue; // already found
}
// accumulate all outputs, will check nesting once all
// available (to handle ordering issues)
outputLocations[outputCount++] = customOutput;
}
}
}
// check nesting across output locations
for (int i = 1 /* no check for default output */; i < outputCount; i++) {
IPath customOutput = outputLocations[i];
int index;
// check nesting
if ((index = Util.indexOfEnclosingPath(customOutput,
outputLocations, outputCount)) != -1
&& index != i) {
if (index == 0) {
// custom output is nested in project's output: need to
// check if all source entries have a custom
// output before complaining
if (potentialNestedOutput == null)
potentialNestedOutput = customOutput;
} else {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.cannotNestOutputInOutput", customOutput.makeRelative().toString(), outputLocations[index].makeRelative().toString())); //$NON-NLS-1$
}
}
}
// allow custom output nesting in project's output if all source entries
// have a custom output
if (sourceEntryCount <= outputCount - 1) {
allowNestingInOutputLocations[0] = true;
} else if (potentialNestedOutput != null) {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.cannotNestOutputInOutput", potentialNestedOutput.makeRelative().toString(), outputLocations[0].makeRelative().toString())); //$NON-NLS-1$
}
for (int i = 0; i < length; i++) {
IClasspathEntry resolvedEntry = classpath[i];
IPath path = resolvedEntry.getPath();
int index;
switch (resolvedEntry.getEntryKind()) {
case IClasspathEntry.CPE_SOURCE:
hasSource = true;
if ((index = Util.indexOfMatchingPath(path, outputLocations,
outputCount)) != -1) {
allowNestingInOutputLocations[index] = true;
}
break;
// case IClasspathEntry.CPE_LIBRARY:
// hasLibFolder |=
// !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(path.lastSegment());
// if ((index = Util.indexOfMatchingPath(path, outputLocations,
// outputCount)) != -1){
// allowNestingInOutputLocations[index] = true;
// }
// break;
}
}
if (!hasSource && !hasLibFolder) { // if no source and no lib folder,
// then allowed
for (int i = 0; i < outputCount; i++)
allowNestingInOutputLocations[i] = true;
}
HashSet pathes = new HashSet(length);
// check all entries
for (int i = 0; i < length; i++) {
IClasspathEntry entry = classpath[i];
if (entry == null)
continue;
IPath entryPath = entry.getPath();
int kind = entry.getEntryKind();
// Build some common strings for status message
boolean isProjectRelative = entryPath.segment(0).toString().equals(
projectName);
String entryPathMsg = isProjectRelative ? entryPath
.removeFirstSegments(1).toString() : entryPath
.makeRelative().toString();
// complain if duplicate path
if (!pathes.add(entryPath)) {
return new JavaModelStatus(
IJavaModelStatusConstants.NAME_COLLISION,
Util
.bind(
"classpath.duplicateEntryPath", entryPathMsg, projectName)); //$NON-NLS-1$
}
// no further check if entry coincidates with project or output
// location
if (entryPath.equals(projectPath)) {
// complain if self-referring project entry
if (kind == IClasspathEntry.CPE_PROJECT) {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_PATH,
Util
.bind(
"classpath.cannotReferToItself", entryPath.makeRelative().toString()));//$NON-NLS-1$
}
// tolerate nesting output in src if src==prj
continue;
}
// allow nesting source entries in each other as long as the outer
// entry excludes the inner one
if (kind == IClasspathEntry.CPE_SOURCE) {
// || (kind == IClasspathEntry.CPE_LIBRARY &&
// !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(entryPath.lastSegment()))){
for (int j = 0; j < classpath.length; j++) {
IClasspathEntry otherEntry = classpath[j];
if (otherEntry == null)
continue;
int otherKind = otherEntry.getEntryKind();
IPath otherPath = otherEntry.getPath();
if (entry != otherEntry
&& (otherKind == IClasspathEntry.CPE_SOURCE)) {
// || (otherKind == IClasspathEntry.CPE_LIBRARY
// &&
// !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(otherPath.lastSegment())))){
char[][] inclusionPatterns, exclusionPatterns;
if (otherPath.isPrefixOf(entryPath)
&& !otherPath.equals(entryPath)
&& !Util
.isExcluded(
entryPath.append("*"), inclusionPatterns = ((ClasspathEntry) otherEntry).fullInclusionPatternChars(), exclusionPatterns = ((ClasspathEntry) otherEntry).fullExclusionPatternChars(), false)) { //$NON-NLS-1$
String exclusionPattern = entryPath
.removeFirstSegments(
otherPath.segmentCount())
.segment(0);
if (Util.isExcluded(entryPath, inclusionPatterns,
exclusionPatterns, false)) {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.mustEndWithSlash", exclusionPattern, entryPath.makeRelative().toString())); //$NON-NLS-1$
} else {
if (otherKind == IClasspathEntry.CPE_SOURCE) {
exclusionPattern += '/';
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.cannotNestEntryInEntry", new String[] { entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString(), exclusionPattern })); //$NON-NLS-1$
} else {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.cannotNestEntryInLibrary", entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString())); //$NON-NLS-1$
}
}
}
}
}
}
// prevent nesting output location inside entry unless enclosing is
// a source entry which explicitly exclude the output location
char[][] inclusionPatterns = ((ClasspathEntry) entry)
.fullInclusionPatternChars();
char[][] exclusionPatterns = ((ClasspathEntry) entry)
.fullExclusionPatternChars();
for (int j = 0; j < outputCount; j++) {
IPath currentOutput = outputLocations[j];
if (entryPath.equals(currentOutput))
continue;
if (entryPath.isPrefixOf(currentOutput)) {
if (kind != IClasspathEntry.CPE_SOURCE
|| !Util.isExcluded(currentOutput,
inclusionPatterns, exclusionPatterns, true)) {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.cannotNestOutputInEntry", currentOutput.makeRelative().toString(), entryPath.makeRelative().toString())); //$NON-NLS-1$
}
}
}
// prevent nesting entry inside output location - when distinct from
// project or a source folder
for (int j = 0; j < outputCount; j++) {
if (allowNestingInOutputLocations[j])
continue;
IPath currentOutput = outputLocations[j];
if (currentOutput.isPrefixOf(entryPath)) {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.cannotNestEntryInOutput", entryPath.makeRelative().toString(), currentOutput.makeRelative().toString())); //$NON-NLS-1$
}
}
}
// ensure that no specific output is coincidating with another source
// folder (only allowed if matching current source folder)
// 36465 - for 2.0 backward compatibility, only check specific output
// locations (the default can still coincidate)
// perform one separate iteration so as to not take precedence over
// previously checked scenarii (in particular should
// diagnose nesting source folder issue before this one, for example,
// [src]"Project/", [src]"Project/source/" and output="Project/" should
// first complain about missing exclusion pattern
for (int i = 0; i < length; i++) {
IClasspathEntry entry = classpath[i];
if (entry == null)
continue;
IPath entryPath = entry.getPath();
int kind = entry.getEntryKind();
// Build some common strings for status message
boolean isProjectRelative = entryPath.segment(0).toString().equals(
projectName);
String entryPathMsg = isProjectRelative ? entryPath
.removeFirstSegments(1).toString() : entryPath
.makeRelative().toString();
if (kind == IClasspathEntry.CPE_SOURCE) {
IPath output = entry.getOutputLocation();
if (output == null)
continue; // 36465 - for 2.0 backward compatibility, only
// check specific output locations (the default
// can still coincidate)
// if (output == null) output = projectOutputLocation; // if no
// specific output, still need to check using default output
// (this line would check default output)
for (int j = 0; j < length; j++) {
IClasspathEntry otherEntry = classpath[j];
if (otherEntry == entry)
continue;
// Build some common strings for status message
boolean opStartsWithProject = otherEntry.getPath().segment(
0).toString().equals(projectName);
String otherPathMsg = opStartsWithProject ? otherEntry
.getPath().removeFirstSegments(1).toString()
: otherEntry.getPath().makeRelative().toString();
switch (otherEntry.getEntryKind()) {
case IClasspathEntry.CPE_SOURCE:
if (otherEntry.getPath().equals(output)) {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.cannotUseDistinctSourceFolderAsOutput", new String[] { entryPathMsg, otherPathMsg, projectName })); //$NON-NLS-1$
}
break;
case IClasspathEntry.CPE_LIBRARY:
if (otherEntry.getPath().equals(output)) {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.cannotUseLibraryAsOutput", new String[] { entryPathMsg, otherPathMsg, projectName })); //$NON-NLS-1$
}
}
}
}
}
return JavaModelStatus.VERIFIED_OK;
}
/**
* Returns a Java model status describing the problem related to this
* classpath entry if any, a status object with code IStatus.OK
* if the entry is fine (that is, if the given classpath entry denotes a
* valid element to be referenced onto a classpath).
*
* @param project
* the given java project
* @param entry
* the given classpath entry
* @param checkSourceAttachment
* a flag to determine if source attachement should be checked
* @param recurseInContainers
* flag indicating whether validation should be applied to
* container entries recursively
* @return a java model status describing the problem related to this
* classpath entry if any, a status object with code
* IStatus.OK
if the entry is fine
*/
public static IJavaModelStatus validateClasspathEntry(IJavaProject project,
IClasspathEntry entry, boolean checkSourceAttachment,
boolean recurseInContainers) {
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IPath path = entry.getPath();
// Build some common strings for status message
String projectName = project.getElementName();
boolean pathStartsWithProject = path.segment(0).toString().equals(
projectName);
String entryPathMsg = pathStartsWithProject ? path.removeFirstSegments(
1).toString() : path.makeRelative().toString();
switch (entry.getEntryKind()) {
// container entry check
// case IClasspathEntry.CPE_CONTAINER :
// if (path != null && path.segmentCount() >= 1){
// try {
// IClasspathContainer container =
// JavaModelManager.getJavaModelManager().getClasspathContainer(path,
// project);
// // container retrieval is performing validation check on container
// entry kinds.
// if (container == null){
// return new
// JavaModelStatus(IJavaModelStatusConstants.CP_CONTAINER_PATH_UNBOUND,
// project, path);
// } else if (container ==
// JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS) {
// // don't create a marker if initialization is in progress (case of cp
// initialization batching)
// return JavaModelStatus.VERIFIED_OK;
// }
// IClasspathEntry[] containerEntries = container.getClasspathEntries();
// if (containerEntries != null){
// for (int i = 0, length = containerEntries.length; i < length; i++){
// IClasspathEntry containerEntry = containerEntries[i];
// int kind = containerEntry == null ? 0 :
// containerEntry.getEntryKind();
// if (containerEntry == null
// || kind == IClasspathEntry.CPE_SOURCE
// || kind == IClasspathEntry.CPE_VARIABLE
// || kind == IClasspathEntry.CPE_CONTAINER){
// String description = container.getDescription();
// if (description == null) description =
// path.makeRelative().toString();
// return new
// JavaModelStatus(IJavaModelStatusConstants.INVALID_CP_CONTAINER_ENTRY,
// project, path);
// }
// if (recurseInContainers) {
// IJavaModelStatus containerEntryStatus =
// validateClasspathEntry(project, containerEntry,
// checkSourceAttachment, recurseInContainers);
// if (!containerEntryStatus.isOK()){
// return containerEntryStatus;
// }
// }
// }
// }
// } catch(JavaModelException e){
// return new JavaModelStatus(e);
// }
// } else {
// return new
// JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
// Util.bind("classpath.illegalContainerPath", entryPathMsg,
// projectName)); //$NON-NLS-1$
// }
// break;
// variable entry check
case IClasspathEntry.CPE_VARIABLE:
if (path != null && path.segmentCount() >= 1) {
try {
entry = JavaCore.getResolvedClasspathEntry(entry);
} catch (/*Assert.*/AssertionFailedException e) {
// Catch the assertion failure and throw java model
// exception instead
// see bug
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=55992
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_PATH, e
.getMessage());
}
if (entry == null) {
return new JavaModelStatus(
IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND,
project, path);
}
return validateClasspathEntry(project, entry,
checkSourceAttachment, recurseInContainers);
} else {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.illegalVariablePath", path.makeRelative().toString(), projectName)); //$NON-NLS-1$
}
// library entry check
// case IClasspathEntry.CPE_LIBRARY :
// if (path != null && path.isAbsolute() && !path.isEmpty()) {
// IPath sourceAttachment = entry.getSourceAttachmentPath();
// Object target = JavaModel.getTarget(workspaceRoot, path, true);
// if (target != null &&
// project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true) !=
// JavaCore.IGNORE) {
// long projectTargetJDK =
// CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM,
// true));
// long libraryJDK = Util.getJdkLevel(target);
// if (libraryJDK != 0 && libraryJDK > projectTargetJDK) {
// return new
// JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL,
// project, path, CompilerOptions.versionFromJdkLevel(libraryJDK));
// }
// }
// if (target instanceof IResource){
// IResource resolvedResource = (IResource) target;
// switch(resolvedResource.getType()){
// case IResource.FILE :
// if
// (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(resolvedResource.getName()))
// {
// if (checkSourceAttachment
// && sourceAttachment != null
// && !sourceAttachment.isEmpty()
// && JavaModel.getTarget(workspaceRoot, sourceAttachment, true) ==
// null){
// return new
// JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
// Util.bind("classpath.unboundSourceAttachment", new String []
// {sourceAttachment.makeRelative().toString(),
// path.makeRelative().toString(), projectName})); //$NON-NLS-1$
// }
// } else {
// return new
// JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
// Util.bind("classpath.illegalLibraryArchive", entryPathMsg,
// projectName)); //$NON-NLS-1$
// }
// break;
// case IResource.FOLDER : // internal binary folder
// if (checkSourceAttachment
// && sourceAttachment != null
// && !sourceAttachment.isEmpty()
// && JavaModel.getTarget(workspaceRoot, sourceAttachment, true) ==
// null){
// return new
// JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
// Util.bind("classpath.unboundSourceAttachment", new String []
// {sourceAttachment.makeRelative().toString(),
// path.makeRelative().toString(), projectName})); //$NON-NLS-1$
// }
// }
// } else if (target instanceof File){
// File file = (File) target;
// if (!file.isFile()) {
// return new
// JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
// Util.bind("classpath.illegalExternalFolder", path.toOSString(),
// projectName)); //$NON-NLS-1$
// } else if
// (!org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(file.getName()))
// {
// return new
// JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
// Util.bind("classpath.illegalLibraryArchive", path.toOSString(),
// projectName)); //$NON-NLS-1$
// } else if (checkSourceAttachment
// && sourceAttachment != null
// && !sourceAttachment.isEmpty()
// && JavaModel.getTarget(workspaceRoot, sourceAttachment, true) ==
// null){
// return new
// JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
// Util.bind("classpath.unboundSourceAttachment", new String []
// {sourceAttachment.toString(), path.makeRelative().toString(),
// projectName})); //$NON-NLS-1$
// }
// } else {
// return new
// JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
// Util.bind("classpath.unboundLibrary",
// path.makeRelative().toString(), projectName)); //$NON-NLS-1$
// }
// } else {
// return new
// JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH,
// Util.bind("classpath.illegalLibraryPath",
// path.makeRelative().toString(), projectName)); //$NON-NLS-1$
// }
// break;
// project entry check
case IClasspathEntry.CPE_PROJECT:
if (path != null && path.isAbsolute() && !path.isEmpty()) {
IProject prereqProjectRsc = workspaceRoot.getProject(path
.segment(0));
//IJavaProject prereqProject = JavaCore.create(prereqProjectRsc);
try {
if (!prereqProjectRsc.exists()
|| !prereqProjectRsc
.hasNature(PHPeclipsePlugin.PHP_NATURE_ID)) {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.unboundProject", path.makeRelative().segment(0).toString(), projectName)); //$NON-NLS-1$
}
if (!prereqProjectRsc.isOpen()) {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.closedProject", path.segment(0).toString())); //$NON-NLS-1$
}
// if
// (project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL,
// true) != JavaCore.IGNORE) {
// long projectTargetJDK =
// CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM,
// true));
// long prereqProjectTargetJDK =
// CompilerOptions.versionToJdkLevel(prereqProject.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM,
// true));
// if (prereqProjectTargetJDK > projectTargetJDK) {
// return new
// JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL,
// project, path,
// CompilerOptions.versionFromJdkLevel(prereqProjectTargetJDK));
// }
// }
} catch (CoreException e) {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.unboundProject", path.segment(0).toString(), projectName)); //$NON-NLS-1$
}
} else {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.illegalProjectPath", path.segment(0).toString(), projectName)); //$NON-NLS-1$
}
break;
// project source folder
case IClasspathEntry.CPE_SOURCE:
if (((entry.getInclusionPatterns() != null && entry
.getInclusionPatterns().length > 0) || (entry
.getExclusionPatterns() != null && entry
.getExclusionPatterns().length > 0))
&& JavaCore.DISABLED.equals(project.getOption(
JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS,
true))) {
return new JavaModelStatus(
IJavaModelStatusConstants.DISABLED_CP_EXCLUSION_PATTERNS,
project, path);
}
if (entry.getOutputLocation() != null
&& JavaCore.DISABLED
.equals(project
.getOption(
JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS,
true))) {
return new JavaModelStatus(
IJavaModelStatusConstants.DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS,
project, path);
}
if (path != null && path.isAbsolute() && !path.isEmpty()) {
IPath projectPath = project.getProject().getFullPath();
if (!projectPath.isPrefixOf(path)
|| JavaModel.getTarget(workspaceRoot, path, true) == null) {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.unboundSourceFolder", entryPathMsg, projectName)); //$NON-NLS-1$
}
} else {
return new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH,
Util
.bind(
"classpath.illegalSourceFolderPath", entryPathMsg, projectName)); //$NON-NLS-1$
}
break;
}
return JavaModelStatus.VERIFIED_OK;
}
}