*******************************************************************************/
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;
import net.sourceforge.phpdt.internal.corext.Assert;
-import net.sourceforge.phpeclipse.PHPCore;
+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.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.w3c.dom.Document;
*/
public IPath path;
+
/**
- * Patterns allowing to exclude portions of the resource tree denoted by this entry path.
+ * Patterns allowing to include/exclude portions of the resource tree denoted by this entry path.
*/
-
+ public IPath[] inclusionPatterns;
+ private char[][] fullCharInclusionPatterns;
public IPath[] exclusionPatterns;
private char[][] fullCharExclusionPatterns;
private final static char[][] UNINIT_PATTERNS = new char[][] { "Non-initialized yet".toCharArray() }; //$NON-NLS-1$
private String rootID;
+ /*
+ * Default inclusion pattern set
+ */
+ public final static IPath[] INCLUDE_ALL = {};
+ /*
+ * Default exclusion pattern set
+ */
+ public final static IPath[] EXCLUDE_NONE = {};
/**
* Default exclusion pattern set
*/
int contentKind,
int entryKind,
IPath path,
+ IPath[] inclusionPatterns,
IPath[] exclusionPatterns,
IPath sourceAttachmentPath,
IPath sourceAttachmentRootPath,
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;
if (this.fullCharExclusionPatterns == UNINIT_PATTERNS) {
int length = this.exclusionPatterns.length;
this.fullCharExclusionPatterns = new char[length][];
- IPath prefixPath = path.removeTrailingSeparator();
+ 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.
*/
switch (kind) {
case IClasspathEntry.CPE_PROJECT :
- return PHPCore.newProjectEntry(path, isExported);
+ return JavaCore.newProjectEntry(path, isExported);
// case IClasspathEntry.CPE_LIBRARY :
// return JavaCore.newLibraryEntry(
// 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 PHPCore.newSourceEntry(path, exclusionPatterns, outputLocation);
+ return JavaCore.newSourceEntry(path, exclusionPatterns, outputLocation);
} else { // another project
- return PHPCore.newProjectEntry(path, isExported);
+ return JavaCore.newProjectEntry(path, isExported);
}
// case IClasspathEntry.CPE_VARIABLE :
// isExported);
case IClasspathEntry.CPE_CONTAINER :
- return PHPCore.newContainerEntry(
+ 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.NO_EXCLUSION_PATTERNS,
- null, // source attachment
- null, // source attachment root
- null, // custom output location
- false);
+ 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$
}
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;
public IPath[] getExclusionPatterns() {
return this.exclusionPatterns;
}
-
+ /**
+ * @see IClasspathEntry#getExclusionPatterns()
+ */
+ public IPath[] getInclusionPatterns() {
+ return this.inclusionPatterns;
+ }
/**
* @see IClasspathEntry#getOutputLocation()
*/
*/
public IClasspathEntry getResolvedEntry() {
- return PHPCore.getResolvedClasspathEntry(this);
+ 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:
+ * <ul>
+ * <li> Classpath entries cannot collide with each other; that is, all entry paths must be unique.
+ * <li> The project output location path cannot be null, must be absolute and located inside the project.
+ * <li> Specific output locations (specified on source entries) can be null, if not they must be located inside the project,
+ * <li> A project entry cannot refer to itself directly (that is, a project cannot prerequisite itself).
+ * <li> Classpath entries or output locations cannot coincidate or be nested in each other, except for the following scenarii listed below:
+ * <ul><li> A source folder can coincidate with its own output location, in which case this output can then contain library archives.
+ * However, a specific output location cannot coincidate with any library or a distinct source folder than the one referring to it. </li>
+ * <li> A source/library folder can be nested in any source folder as long as the nested folder is excluded from the enclosing one. </li>
+ * <li> An output location can be nested in a source folder, if the source folder coincidates with the project itself, or if the output
+ * location is excluded from the source folder. </li>
+ * </ul>
+ * </ul>
+ *
+ * Note that the classpath entries are not validated automatically. Only bound variables or containers are considered
+ * in the checking process (this allows to perform a consistency check on a classpath which has references to
+ * yet non existing projects, folders, ...).
+ * <p>
+ * 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).
+ * <p>
+ * @param javaProject the given java project
+ * @param rawClasspath a given classpath
+ * @param projectOutputLocation a given output location
+ * @return a status object with code <code>IStatus.OK</code> 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 <code>IStatus.OK</code> 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 <code>IStatus.OK</code> 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;
}
}
+