1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
13 import java.util.HashMap;
14 import java.util.HashSet;
16 import net.sourceforge.phpdt.core.IClasspathEntry;
17 import net.sourceforge.phpdt.core.IJavaModelStatus;
18 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
19 import net.sourceforge.phpdt.core.IJavaProject;
20 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
21 import net.sourceforge.phpdt.core.JavaCore;
22 import net.sourceforge.phpdt.core.JavaModelException;
23 import net.sourceforge.phpdt.core.compiler.CharOperation;
24 import net.sourceforge.phpdt.internal.core.util.Util;
25 import net.sourceforge.phpdt.internal.corext.Assert;
26 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
28 import org.eclipse.core.resources.IProject;
29 import org.eclipse.core.resources.IWorkspaceRoot;
30 import org.eclipse.core.resources.ResourcesPlugin;
31 import org.eclipse.core.runtime.CoreException;
32 import org.eclipse.core.runtime.IPath;
33 import org.eclipse.core.runtime.Path;
34 import org.w3c.dom.Document;
35 import org.w3c.dom.Element;
38 * @see IClasspathEntry
40 public class ClasspathEntry implements IClasspathEntry {
43 * Describes the kind of classpath entry - one of
44 * CPE_PROJECT, CPE_LIBRARY, CPE_SOURCE, CPE_VARIABLE or CPE_CONTAINER
49 * Describes the kind of package fragment roots found on
50 * this classpath entry - either K_BINARY or K_SOURCE or
53 public int contentKind;
56 * The meaning of the path of a classpath entry depends on its entry kind:<ul>
57 * <li>Source code in the current project (<code>CPE_SOURCE</code>) -
58 * The path associated with this entry is the absolute path to the root folder. </li>
59 * <li>A binary library in the current project (<code>CPE_LIBRARY</code>) - the path
60 * associated with this entry is the absolute path to the JAR (or root folder), and
61 * in case it refers to an external JAR, then there is no associated resource in
63 * <li>A required project (<code>CPE_PROJECT</code>) - the path of the entry denotes the
64 * path to the corresponding project resource.</li>
65 * <li>A variable entry (<code>CPE_VARIABLE</code>) - the first segment of the path
66 * is the name of a classpath variable. If this classpath variable
67 * is bound to the path <it>P</it>, the path of the corresponding classpath entry
68 * is computed by appending to <it>P</it> the segments of the returned
69 * path without the variable.</li>
70 * <li> A container entry (<code>CPE_CONTAINER</code>) - the first segment of the path is denoting
71 * the unique container identifier (for which a <code>ClasspathContainerInitializer</code> could be
72 * registered), and the remaining segments are used as additional hints for resolving the container entry to
73 * an actual <code>IClasspathContainer</code>.</li>
79 * Patterns allowing to include/exclude portions of the resource tree denoted by this entry path.
81 public IPath[] inclusionPatterns;
82 private char[][] fullCharInclusionPatterns;
83 public IPath[] exclusionPatterns;
84 private char[][] fullCharExclusionPatterns;
85 private final static char[][] UNINIT_PATTERNS = new char[][] { "Non-initialized yet".toCharArray() }; //$NON-NLS-1$
87 private String rootID;
89 * Default inclusion pattern set
91 public final static IPath[] INCLUDE_ALL = {};
94 * Default exclusion pattern set
96 public final static IPath[] EXCLUDE_NONE = {};
98 * Default exclusion pattern set
100 public final static IPath[] NO_EXCLUSION_PATTERNS = {};
103 * Describes the path to the source archive associated with this
104 * classpath entry, or <code>null</code> if this classpath entry has no
107 * Only library and variable classpath entries may have source attachments.
108 * For library classpath entries, the result path (if present) locates a source
109 * archive. For variable classpath entries, the result path (if present) has
110 * an analogous form and meaning as the variable path, namely the first segment
111 * is the name of a classpath variable.
113 public IPath sourceAttachmentPath;
116 * Describes the path within the source archive where package fragments
117 * are located. An empty path indicates that packages are located at
118 * the root of the source archive. Returns a non-<code>null</code> value
119 * if and only if <code>getSourceAttachmentPath</code> returns
120 * a non-<code>null</code> value.
122 public IPath sourceAttachmentRootPath;
125 * Specific output location (for this source entry)
127 public IPath specificOutputLocation;
130 * A constant indicating an output location.
132 public static final int K_OUTPUT = 10;
137 public boolean isExported;
140 * Creates a class path entry of the specified kind with the given path.
142 public ClasspathEntry(
146 IPath[] inclusionPatterns,
147 IPath[] exclusionPatterns,
148 IPath sourceAttachmentPath,
149 IPath sourceAttachmentRootPath,
150 IPath specificOutputLocation,
151 boolean isExported) {
153 this.contentKind = contentKind;
154 this.entryKind = entryKind;
156 this.inclusionPatterns = inclusionPatterns;
157 if (inclusionPatterns != INCLUDE_ALL && inclusionPatterns.length > 0) {
158 this.fullCharInclusionPatterns = UNINIT_PATTERNS;
160 this.fullCharInclusionPatterns = null; // empty inclusion pattern means everything is included
162 this.exclusionPatterns = exclusionPatterns;
163 if (exclusionPatterns.length > 0) {
164 this.fullCharExclusionPatterns = UNINIT_PATTERNS;
166 this.sourceAttachmentPath = sourceAttachmentPath;
167 this.sourceAttachmentRootPath = sourceAttachmentRootPath;
168 this.specificOutputLocation = specificOutputLocation;
169 this.isExported = isExported;
173 * Returns a char based representation of the exclusions patterns full path.
175 public char[][] fullExclusionPatternChars() {
177 if (this.fullCharExclusionPatterns == UNINIT_PATTERNS) {
178 int length = this.exclusionPatterns.length;
179 this.fullCharExclusionPatterns = new char[length][];
180 IPath prefixPath = this.path.removeTrailingSeparator();
181 for (int i = 0; i < length; i++) {
182 this.fullCharExclusionPatterns[i] =
183 prefixPath.append(this.exclusionPatterns[i]).toString().toCharArray();
186 return this.fullCharExclusionPatterns;
190 * Returns a char based representation of the exclusions patterns full path.
192 public char[][] fullInclusionPatternChars() {
194 if (this.fullCharInclusionPatterns == UNINIT_PATTERNS) {
195 int length = this.inclusionPatterns.length;
196 this.fullCharInclusionPatterns = new char[length][];
197 IPath prefixPath = this.path.removeTrailingSeparator();
198 for (int i = 0; i < length; i++) {
199 this.fullCharInclusionPatterns[i] =
200 prefixPath.append(this.inclusionPatterns[i]).toString().toCharArray();
203 return this.fullCharInclusionPatterns;
206 * Returns the XML encoding of the class path.
208 public Element elementEncode(
211 throws JavaModelException {
213 Element element = document.createElement("classpathentry"); //$NON-NLS-1$
214 element.setAttribute("kind", kindToString(this.entryKind)); //$NON-NLS-1$
215 IPath xmlPath = this.path;
216 if (this.entryKind != IClasspathEntry.CPE_VARIABLE && this.entryKind != IClasspathEntry.CPE_CONTAINER) {
217 // translate to project relative from absolute (unless a device path)
218 if (xmlPath.isAbsolute()) {
219 if (projectPath != null && projectPath.isPrefixOf(xmlPath)) {
220 if (xmlPath.segment(0).equals(projectPath.segment(0))) {
221 xmlPath = xmlPath.removeFirstSegments(1);
222 xmlPath = xmlPath.makeRelative();
224 xmlPath = xmlPath.makeAbsolute();
229 element.setAttribute("path", xmlPath.toString()); //$NON-NLS-1$
230 if (this.sourceAttachmentPath != null) {
231 element.setAttribute("sourcepath", this.sourceAttachmentPath.toString()); //$NON-NLS-1$
233 if (this.sourceAttachmentRootPath != null) {
234 element.setAttribute("rootpath", this.sourceAttachmentRootPath.toString()); //$NON-NLS-1$
236 if (this.isExported) {
237 element.setAttribute("exported", "true"); //$NON-NLS-1$ //$NON-NLS-2$
240 if (this.exclusionPatterns.length > 0) {
241 StringBuffer excludeRule = new StringBuffer(10);
242 for (int i = 0, max = this.exclusionPatterns.length; i < max; i++){
243 if (i > 0) excludeRule.append('|');
244 excludeRule.append(this.exclusionPatterns[i]);
246 element.setAttribute("excluding", excludeRule.toString()); //$NON-NLS-1$
249 if (this.specificOutputLocation != null) {
250 IPath outputLocation = this.specificOutputLocation.removeFirstSegments(1);
251 outputLocation = outputLocation.makeRelative();
252 element.setAttribute("output", outputLocation.toString()); //$NON-NLS-1$
257 public static IClasspathEntry elementDecode(Element element, IJavaProject project) {
259 IPath projectPath = project.getProject().getFullPath();
260 String kindAttr = element.getAttribute("kind"); //$NON-NLS-1$
261 String pathAttr = element.getAttribute("path"); //$NON-NLS-1$
263 // ensure path is absolute
264 IPath path = new Path(pathAttr);
265 int kind = kindFromString(kindAttr);
266 if (kind != IClasspathEntry.CPE_VARIABLE && kind != IClasspathEntry.CPE_CONTAINER && !path.isAbsolute()) {
267 path = projectPath.append(path);
269 // source attachment info (optional)
270 IPath sourceAttachmentPath =
271 element.hasAttribute("sourcepath") //$NON-NLS-1$
272 ? new Path(element.getAttribute("sourcepath")) //$NON-NLS-1$
274 IPath sourceAttachmentRootPath =
275 element.hasAttribute("rootpath") //$NON-NLS-1$
276 ? new Path(element.getAttribute("rootpath")) //$NON-NLS-1$
279 // exported flag (optional)
280 boolean isExported = element.getAttribute("exported").equals("true"); //$NON-NLS-1$ //$NON-NLS-2$
282 // exclusion patterns (optional)
283 String exclusion = element.getAttribute("excluding"); //$NON-NLS-1$
284 IPath[] exclusionPatterns = ClasspathEntry.NO_EXCLUSION_PATTERNS;
285 if (!exclusion.equals("")) { //$NON-NLS-1$
286 char[][] patterns = CharOperation.splitOn('|', exclusion.toCharArray());
288 if ((patternCount = patterns.length) > 0) {
289 exclusionPatterns = new IPath[patternCount];
290 for (int j = 0; j < patterns.length; j++){
291 exclusionPatterns[j] = new Path(new String(patterns[j]));
296 // custom output location
297 IPath outputLocation = element.hasAttribute("output") ? projectPath.append(element.getAttribute("output")) : null; //$NON-NLS-1$ //$NON-NLS-2$
299 // recreate the CP entry
302 case IClasspathEntry.CPE_PROJECT :
303 return JavaCore.newProjectEntry(path, isExported);
305 // case IClasspathEntry.CPE_LIBRARY :
306 // return JavaCore.newLibraryEntry(
308 // sourceAttachmentPath,
309 // sourceAttachmentRootPath,
312 case IClasspathEntry.CPE_SOURCE :
313 // must be an entry in this project or specify another project
314 String projSegment = path.segment(0);
315 if (projSegment != null && projSegment.equals(project.getElementName())) { // this project
316 return JavaCore.newSourceEntry(path, exclusionPatterns, outputLocation);
317 } else { // another project
318 return JavaCore.newProjectEntry(path, isExported);
321 // case IClasspathEntry.CPE_VARIABLE :
322 // return PHPCore.newVariableEntry(
324 // sourceAttachmentPath,
325 // sourceAttachmentRootPath,
328 case IClasspathEntry.CPE_CONTAINER :
329 return JavaCore.newContainerEntry(
333 case ClasspathEntry.K_OUTPUT :
334 if (!path.isAbsolute()) return null;
335 return new ClasspathEntry(
336 ClasspathEntry.K_OUTPUT,
337 IClasspathEntry.CPE_LIBRARY,
339 ClasspathEntry.INCLUDE_ALL,
340 ClasspathEntry.EXCLUDE_NONE,
341 null, // source attachment
342 null, // source attachment root
343 null, // custom output location
347 throw new Assert.AssertionFailedException(Util.bind("classpath.unknownKind", kindAttr)); //$NON-NLS-1$
352 * Returns true if the given object is a classpath entry
353 * with equivalent attributes.
355 public boolean equals(Object object) {
358 if (object instanceof IClasspathEntry) {
359 IClasspathEntry otherEntry = (IClasspathEntry) object;
361 if (this.contentKind != otherEntry.getContentKind())
364 if (this.entryKind != otherEntry.getEntryKind())
367 if (this.isExported != otherEntry.isExported())
370 if (!this.path.equals(otherEntry.getPath()))
373 IPath otherPath = otherEntry.getSourceAttachmentPath();
374 if (this.sourceAttachmentPath == null) {
375 if (otherPath != null)
378 if (!this.sourceAttachmentPath.equals(otherPath))
382 otherPath = otherEntry.getSourceAttachmentRootPath();
383 if (this.sourceAttachmentRootPath == null) {
384 if (otherPath != null)
387 if (!this.sourceAttachmentRootPath.equals(otherPath))
391 IPath[] otherIncludes = otherEntry.getInclusionPatterns();
392 if (this.inclusionPatterns != otherIncludes){
393 if (this.inclusionPatterns == null) return false;
394 int includeLength = this.inclusionPatterns.length;
395 if (otherIncludes == null || otherIncludes.length != includeLength)
397 for (int i = 0; i < includeLength; i++) {
398 // compare toStrings instead of IPaths
399 // since IPath.equals is specified to ignore trailing separators
400 if (!this.inclusionPatterns[i].toString().equals(otherIncludes[i].toString()))
405 IPath[] otherExcludes = otherEntry.getExclusionPatterns();
406 if (this.exclusionPatterns != otherExcludes){
407 int excludeLength = this.exclusionPatterns.length;
408 if (otherExcludes.length != excludeLength)
410 for (int i = 0; i < excludeLength; i++) {
411 // compare toStrings instead of IPaths
412 // since IPath.equals is specified to ignore trailing separators
413 if (!this.exclusionPatterns[i].toString().equals(otherExcludes[i].toString()))
418 otherPath = otherEntry.getOutputLocation();
419 if (this.specificOutputLocation == null) {
420 if (otherPath != null)
423 if (!this.specificOutputLocation.equals(otherPath))
433 * @see IClasspathEntry
435 public int getContentKind() {
436 return this.contentKind;
440 * @see IClasspathEntry
442 public int getEntryKind() {
443 return this.entryKind;
447 * @see IClasspathEntry#getExclusionPatterns()
449 public IPath[] getExclusionPatterns() {
450 return this.exclusionPatterns;
453 * @see IClasspathEntry#getExclusionPatterns()
455 public IPath[] getInclusionPatterns() {
456 return this.inclusionPatterns;
459 * @see IClasspathEntry#getOutputLocation()
461 public IPath getOutputLocation() {
462 return this.specificOutputLocation;
466 * @see IClasspathEntry
468 public IPath getPath() {
473 * @see IClasspathEntry
475 public IPath getSourceAttachmentPath() {
476 return this.sourceAttachmentPath;
480 * @see IClasspathEntry
482 public IPath getSourceAttachmentRootPath() {
483 return this.sourceAttachmentRootPath;
487 * Returns the hash code for this classpath entry
489 public int hashCode() {
490 return this.path.hashCode();
494 * @see IClasspathEntry#isExported()
496 public boolean isExported() {
497 return this.isExported;
501 * Returns the kind of a <code>PackageFragmentRoot</code> from its <code>String</code> form.
503 static int kindFromString(String kindStr) {
505 if (kindStr.equalsIgnoreCase("prj")) //$NON-NLS-1$
506 return IClasspathEntry.CPE_PROJECT;
507 if (kindStr.equalsIgnoreCase("var")) //$NON-NLS-1$
508 return IClasspathEntry.CPE_VARIABLE;
509 if (kindStr.equalsIgnoreCase("con")) //$NON-NLS-1$
510 return IClasspathEntry.CPE_CONTAINER;
511 if (kindStr.equalsIgnoreCase("src")) //$NON-NLS-1$
512 return IClasspathEntry.CPE_SOURCE;
513 if (kindStr.equalsIgnoreCase("lib")) //$NON-NLS-1$
514 return IClasspathEntry.CPE_LIBRARY;
515 if (kindStr.equalsIgnoreCase("output")) //$NON-NLS-1$
516 return ClasspathEntry.K_OUTPUT;
521 * Returns a <code>String</code> for the kind of a class path entry.
523 static String kindToString(int kind) {
526 case IClasspathEntry.CPE_PROJECT :
527 return "src"; // backward compatibility //$NON-NLS-1$
528 case IClasspathEntry.CPE_SOURCE :
529 return "src"; //$NON-NLS-1$
530 case IClasspathEntry.CPE_LIBRARY :
531 return "lib"; //$NON-NLS-1$
532 case IClasspathEntry.CPE_VARIABLE :
533 return "var"; //$NON-NLS-1$
534 case IClasspathEntry.CPE_CONTAINER :
535 return "con"; //$NON-NLS-1$
536 case ClasspathEntry.K_OUTPUT :
537 return "output"; //$NON-NLS-1$
539 return "unknown"; //$NON-NLS-1$
544 * Returns a printable representation of this classpath entry.
546 public String toString() {
547 StringBuffer buffer = new StringBuffer();
548 buffer.append(getPath().toString());
550 switch (getEntryKind()) {
551 case IClasspathEntry.CPE_LIBRARY :
552 buffer.append("CPE_LIBRARY"); //$NON-NLS-1$
554 case IClasspathEntry.CPE_PROJECT :
555 buffer.append("CPE_PROJECT"); //$NON-NLS-1$
557 case IClasspathEntry.CPE_SOURCE :
558 buffer.append("CPE_SOURCE"); //$NON-NLS-1$
560 case IClasspathEntry.CPE_VARIABLE :
561 buffer.append("CPE_VARIABLE"); //$NON-NLS-1$
563 case IClasspathEntry.CPE_CONTAINER :
564 buffer.append("CPE_CONTAINER"); //$NON-NLS-1$
567 buffer.append("]["); //$NON-NLS-1$
568 switch (getContentKind()) {
569 case IPackageFragmentRoot.K_BINARY :
570 buffer.append("K_BINARY"); //$NON-NLS-1$
572 case IPackageFragmentRoot.K_SOURCE :
573 buffer.append("K_SOURCE"); //$NON-NLS-1$
575 case ClasspathEntry.K_OUTPUT :
576 buffer.append("K_OUTPUT"); //$NON-NLS-1$
580 if (getSourceAttachmentPath() != null) {
581 buffer.append("[sourcePath:"); //$NON-NLS-1$
582 buffer.append(getSourceAttachmentPath());
585 if (getSourceAttachmentRootPath() != null) {
586 buffer.append("[rootPath:"); //$NON-NLS-1$
587 buffer.append(getSourceAttachmentRootPath());
590 buffer.append("[isExported:"); //$NON-NLS-1$
591 buffer.append(this.isExported);
593 IPath[] patterns = getExclusionPatterns();
595 if ((length = patterns.length) > 0) {
596 buffer.append("[excluding:"); //$NON-NLS-1$
597 for (int i = 0; i < length; i++) {
598 buffer.append(patterns[i]);
605 if (getOutputLocation() != null) {
606 buffer.append("[output:"); //$NON-NLS-1$
607 buffer.append(getOutputLocation());
610 return buffer.toString();
614 * Answers an ID which is used to distinguish entries during package
615 * fragment root computations
617 public String rootID(){
619 if (this.rootID == null) {
620 switch(this.entryKind){
621 case IClasspathEntry.CPE_LIBRARY :
622 this.rootID = "[LIB]"+this.path; //$NON-NLS-1$
624 case IClasspathEntry.CPE_PROJECT :
625 this.rootID = "[PRJ]"+this.path; //$NON-NLS-1$
627 case IClasspathEntry.CPE_SOURCE :
628 this.rootID = "[SRC]"+this.path; //$NON-NLS-1$
630 case IClasspathEntry.CPE_VARIABLE :
631 this.rootID = "[VAR]"+this.path; //$NON-NLS-1$
633 case IClasspathEntry.CPE_CONTAINER :
634 this.rootID = "[CON]"+this.path; //$NON-NLS-1$
637 this.rootID = ""; //$NON-NLS-1$
645 * @see IClasspathEntry
648 public IClasspathEntry getResolvedEntry() {
650 return JavaCore.getResolvedClasspathEntry(this);
653 * Returns the XML encoding of the class path.
655 public void elementEncode(XMLWriter writer, IPath projectPath, boolean indent, boolean newLine) {
656 HashMap parameters = new HashMap();
658 parameters.put("kind", ClasspathEntry.kindToString(this.entryKind));//$NON-NLS-1$
660 IPath xmlPath = this.path;
661 if (this.entryKind != IClasspathEntry.CPE_VARIABLE && this.entryKind != IClasspathEntry.CPE_CONTAINER) {
662 // translate to project relative from absolute (unless a device path)
663 if (xmlPath.isAbsolute()) {
664 if (projectPath != null && projectPath.isPrefixOf(xmlPath)) {
665 if (xmlPath.segment(0).equals(projectPath.segment(0))) {
666 xmlPath = xmlPath.removeFirstSegments(1);
667 xmlPath = xmlPath.makeRelative();
669 xmlPath = xmlPath.makeAbsolute();
674 parameters.put("path", String.valueOf(xmlPath));//$NON-NLS-1$
676 if (this.sourceAttachmentPath != null) {
677 xmlPath = this.sourceAttachmentPath;
678 // translate to project relative from absolute
679 if (this.entryKind != IClasspathEntry.CPE_VARIABLE && projectPath != null && projectPath.isPrefixOf(xmlPath)) {
680 if (xmlPath.segment(0).equals(projectPath.segment(0))) {
681 xmlPath = xmlPath.removeFirstSegments(1);
682 xmlPath = xmlPath.makeRelative();
685 parameters.put("sourcepath", String.valueOf(xmlPath));//$NON-NLS-1$
687 if (this.sourceAttachmentRootPath != null) {
688 parameters.put("rootpath", String.valueOf(this.sourceAttachmentRootPath));//$NON-NLS-1$
690 if (this.isExported) {
691 parameters.put("exported", "true");//$NON-NLS-1$//$NON-NLS-2$
693 // if (this.inclusionPatterns != null && this.inclusionPatterns.length > 0) {
694 // StringBuffer includeRule = new StringBuffer(10);
695 // for (int i = 0, max = this.inclusionPatterns.length; i < max; i++){
696 // if (i > 0) includeRule.append('|');
697 // includeRule.append(this.inclusionPatterns[i]);
699 // parameters.put("including", String.valueOf(includeRule));//$NON-NLS-1$
701 if (this.exclusionPatterns != null && this.exclusionPatterns.length > 0) {
702 StringBuffer excludeRule = new StringBuffer(10);
703 for (int i = 0, max = this.exclusionPatterns.length; i < max; i++){
704 if (i > 0) excludeRule.append('|');
705 excludeRule.append(this.exclusionPatterns[i]);
707 parameters.put("excluding", String.valueOf(excludeRule));//$NON-NLS-1$
710 if (this.specificOutputLocation != null) {
711 IPath outputLocation = this.specificOutputLocation.removeFirstSegments(1);
712 outputLocation = outputLocation.makeRelative();
713 parameters.put("output", String.valueOf(outputLocation));//$NON-NLS-1$
716 writer.printTag("classpathentry", parameters, indent, newLine, true);//$NON-NLS-1$
720 * Validate a given classpath and output location for a project, using the following rules:
722 * <li> Classpath entries cannot collide with each other; that is, all entry paths must be unique.
723 * <li> The project output location path cannot be null, must be absolute and located inside the project.
724 * <li> Specific output locations (specified on source entries) can be null, if not they must be located inside the project,
725 * <li> A project entry cannot refer to itself directly (that is, a project cannot prerequisite itself).
726 * <li> Classpath entries or output locations cannot coincidate or be nested in each other, except for the following scenarii listed below:
727 * <ul><li> A source folder can coincidate with its own output location, in which case this output can then contain library archives.
728 * However, a specific output location cannot coincidate with any library or a distinct source folder than the one referring to it. </li>
729 * <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>
730 * <li> An output location can be nested in a source folder, if the source folder coincidates with the project itself, or if the output
731 * location is excluded from the source folder. </li>
735 * Note that the classpath entries are not validated automatically. Only bound variables or containers are considered
736 * in the checking process (this allows to perform a consistency check on a classpath which has references to
737 * yet non existing projects, folders, ...).
739 * This validation is intended to anticipate classpath issues prior to assigning it to a project. In particular, it will automatically
740 * be performed during the classpath setting operation (if validation fails, the classpath setting will not complete).
742 * @param javaProject the given java project
743 * @param rawClasspath a given classpath
744 * @param projectOutputLocation a given output location
745 * @return a status object with code <code>IStatus.OK</code> if
746 * the given classpath and output location are compatible, otherwise a status
747 * object indicating what is wrong with the classpath or output location
749 public static IJavaModelStatus validateClasspath(IJavaProject javaProject, IClasspathEntry[] rawClasspath, IPath projectOutputLocation) {
751 IProject project = javaProject.getProject();
752 IPath projectPath= project.getFullPath();
753 String projectName = javaProject.getElementName();
755 /* validate output location */
756 if (projectOutputLocation == null) {
757 return new JavaModelStatus(IJavaModelStatusConstants.NULL_PATH);
759 if (projectOutputLocation.isAbsolute()) {
760 if (!projectPath.isPrefixOf(projectOutputLocation)) {
761 return new JavaModelStatus(IJavaModelStatusConstants.PATH_OUTSIDE_PROJECT, javaProject, projectOutputLocation.toString());
764 return new JavaModelStatus(IJavaModelStatusConstants.RELATIVE_PATH, projectOutputLocation);
767 boolean hasSource = false;
768 boolean hasLibFolder = false;
771 // tolerate null path, it will be reset to default
772 if (rawClasspath == null)
773 return JavaModelStatus.VERIFIED_OK;
775 // retrieve resolved classpath
776 IClasspathEntry[] classpath;
778 classpath = ((JavaProject)javaProject).getResolvedClasspath(rawClasspath, null /*output*/, true/*ignore pb*/, false/*no marker*/, null /*no reverse map*/);
779 } catch(JavaModelException e){
780 return e.getJavaModelStatus();
782 int length = classpath.length;
785 IPath[] outputLocations = new IPath[length+1];
786 boolean[] allowNestingInOutputLocations = new boolean[length+1];
787 outputLocations[0] = projectOutputLocation;
789 // retrieve and check output locations
790 IPath potentialNestedOutput = null; // for error reporting purpose
791 int sourceEntryCount = 0;
792 boolean disableExclusionPatterns = JavaCore.DISABLED.equals(javaProject.getOption(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, true));
793 boolean disableCustomOutputLocations = JavaCore.DISABLED.equals(javaProject.getOption(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, true));
795 for (int i = 0 ; i < length; i++) {
796 IClasspathEntry resolvedEntry = classpath[i];
797 switch(resolvedEntry.getEntryKind()){
798 case IClasspathEntry.CPE_SOURCE :
801 if (disableExclusionPatterns &&
802 ((resolvedEntry.getInclusionPatterns() != null && resolvedEntry.getInclusionPatterns().length > 0)
803 || (resolvedEntry.getExclusionPatterns() != null && resolvedEntry.getExclusionPatterns().length > 0))) {
804 return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_EXCLUSION_PATTERNS, javaProject, resolvedEntry.getPath());
807 if ((customOutput = resolvedEntry.getOutputLocation()) != null) {
809 if (disableCustomOutputLocations) {
810 return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS, javaProject, resolvedEntry.getPath());
812 // ensure custom output is in project
813 if (customOutput.isAbsolute()) {
814 if (!javaProject.getPath().isPrefixOf(customOutput)) {
815 return new JavaModelStatus(IJavaModelStatusConstants.PATH_OUTSIDE_PROJECT, javaProject, customOutput.toString());
818 return new JavaModelStatus(IJavaModelStatusConstants.RELATIVE_PATH, customOutput);
821 // ensure custom output doesn't conflict with other outputs
823 if (Util.indexOfMatchingPath(customOutput, outputLocations, outputCount) != -1) {
824 continue; // already found
826 // accumulate all outputs, will check nesting once all available (to handle ordering issues)
827 outputLocations[outputCount++] = customOutput;
831 // check nesting across output locations
832 for (int i = 1 /*no check for default output*/ ; i < outputCount; i++) {
833 IPath customOutput = outputLocations[i];
836 if ((index = Util.indexOfEnclosingPath(customOutput, outputLocations, outputCount)) != -1 && index != i) {
838 // custom output is nested in project's output: need to check if all source entries have a custom
839 // output before complaining
840 if (potentialNestedOutput == null) potentialNestedOutput = customOutput;
842 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestOutputInOutput", customOutput.makeRelative().toString(), outputLocations[index].makeRelative().toString())); //$NON-NLS-1$
846 // allow custom output nesting in project's output if all source entries have a custom output
847 if (sourceEntryCount <= outputCount-1) {
848 allowNestingInOutputLocations[0] = true;
849 } else if (potentialNestedOutput != null) {
850 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestOutputInOutput", potentialNestedOutput.makeRelative().toString(), outputLocations[0].makeRelative().toString())); //$NON-NLS-1$
853 for (int i = 0 ; i < length; i++) {
854 IClasspathEntry resolvedEntry = classpath[i];
855 IPath path = resolvedEntry.getPath();
857 switch(resolvedEntry.getEntryKind()){
859 case IClasspathEntry.CPE_SOURCE :
861 if ((index = Util.indexOfMatchingPath(path, outputLocations, outputCount)) != -1){
862 allowNestingInOutputLocations[index] = true;
866 // case IClasspathEntry.CPE_LIBRARY:
867 // hasLibFolder |= !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(path.lastSegment());
868 // if ((index = Util.indexOfMatchingPath(path, outputLocations, outputCount)) != -1){
869 // allowNestingInOutputLocations[index] = true;
874 if (!hasSource && !hasLibFolder) { // if no source and no lib folder, then allowed
875 for (int i = 0; i < outputCount; i++) allowNestingInOutputLocations[i] = true;
878 HashSet pathes = new HashSet(length);
881 for (int i = 0 ; i < length; i++) {
882 IClasspathEntry entry = classpath[i];
883 if (entry == null) continue;
884 IPath entryPath = entry.getPath();
885 int kind = entry.getEntryKind();
887 // Build some common strings for status message
888 boolean isProjectRelative = entryPath.segment(0).toString().equals(projectName);
889 String entryPathMsg = isProjectRelative ? entryPath.removeFirstSegments(1).toString() : entryPath.makeRelative().toString();
891 // complain if duplicate path
892 if (!pathes.add(entryPath)){
893 return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, Util.bind("classpath.duplicateEntryPath", entryPathMsg, projectName)); //$NON-NLS-1$
895 // no further check if entry coincidates with project or output location
896 if (entryPath.equals(projectPath)){
897 // complain if self-referring project entry
898 if (kind == IClasspathEntry.CPE_PROJECT){
899 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, Util.bind("classpath.cannotReferToItself", entryPath.makeRelative().toString()));//$NON-NLS-1$
901 // tolerate nesting output in src if src==prj
905 // allow nesting source entries in each other as long as the outer entry excludes the inner one
906 if (kind == IClasspathEntry.CPE_SOURCE ) {
907 // || (kind == IClasspathEntry.CPE_LIBRARY && !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(entryPath.lastSegment()))){
908 for (int j = 0; j < classpath.length; j++){
909 IClasspathEntry otherEntry = classpath[j];
910 if (otherEntry == null) continue;
911 int otherKind = otherEntry.getEntryKind();
912 IPath otherPath = otherEntry.getPath();
913 if (entry != otherEntry
914 && (otherKind == IClasspathEntry.CPE_SOURCE ) ) {
915 // || (otherKind == IClasspathEntry.CPE_LIBRARY
916 // && !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(otherPath.lastSegment())))){
917 char[][] inclusionPatterns, exclusionPatterns;
918 if (otherPath.isPrefixOf(entryPath)
919 && !otherPath.equals(entryPath)
920 && !Util.isExcluded(entryPath.append("*"), inclusionPatterns = ((ClasspathEntry)otherEntry).fullInclusionPatternChars(), exclusionPatterns = ((ClasspathEntry)otherEntry).fullExclusionPatternChars(), false)) { //$NON-NLS-1$
921 String exclusionPattern = entryPath.removeFirstSegments(otherPath.segmentCount()).segment(0);
922 if (Util.isExcluded(entryPath, inclusionPatterns, exclusionPatterns, false)) {
923 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.mustEndWithSlash", exclusionPattern, entryPath.makeRelative().toString())); //$NON-NLS-1$
925 if (otherKind == IClasspathEntry.CPE_SOURCE) {
926 exclusionPattern += '/';
927 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestEntryInEntry", new String[] {entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString(), exclusionPattern})); //$NON-NLS-1$
929 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestEntryInLibrary", entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString())); //$NON-NLS-1$
937 // prevent nesting output location inside entry unless enclosing is a source entry which explicitly exclude the output location
938 char[][] inclusionPatterns = ((ClasspathEntry)entry).fullInclusionPatternChars();
939 char[][] exclusionPatterns = ((ClasspathEntry)entry).fullExclusionPatternChars();
940 for (int j = 0; j < outputCount; j++){
941 IPath currentOutput = outputLocations[j];
942 if (entryPath.equals(currentOutput)) continue;
943 if (entryPath.isPrefixOf(currentOutput)) {
944 if (kind != IClasspathEntry.CPE_SOURCE || !Util.isExcluded(currentOutput, inclusionPatterns, exclusionPatterns, true)) {
945 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestOutputInEntry", currentOutput.makeRelative().toString(), entryPath.makeRelative().toString())); //$NON-NLS-1$
950 // prevent nesting entry inside output location - when distinct from project or a source folder
951 for (int j = 0; j < outputCount; j++){
952 if (allowNestingInOutputLocations[j]) continue;
953 IPath currentOutput = outputLocations[j];
954 if (currentOutput.isPrefixOf(entryPath)) {
955 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestEntryInOutput", entryPath.makeRelative().toString(), currentOutput.makeRelative().toString())); //$NON-NLS-1$
959 // ensure that no specific output is coincidating with another source folder (only allowed if matching current source folder)
960 // 36465 - for 2.0 backward compatibility, only check specific output locations (the default can still coincidate)
961 // perform one separate iteration so as to not take precedence over previously checked scenarii (in particular should
962 // diagnose nesting source folder issue before this one, for example, [src]"Project/", [src]"Project/source/" and output="Project/" should
963 // first complain about missing exclusion pattern
964 for (int i = 0 ; i < length; i++) {
965 IClasspathEntry entry = classpath[i];
966 if (entry == null) continue;
967 IPath entryPath = entry.getPath();
968 int kind = entry.getEntryKind();
970 // Build some common strings for status message
971 boolean isProjectRelative = entryPath.segment(0).toString().equals(projectName);
972 String entryPathMsg = isProjectRelative ? entryPath.removeFirstSegments(1).toString() : entryPath.makeRelative().toString();
974 if (kind == IClasspathEntry.CPE_SOURCE) {
975 IPath output = entry.getOutputLocation();
976 if (output == null) continue; // 36465 - for 2.0 backward compatibility, only check specific output locations (the default can still coincidate)
977 // if (output == null) output = projectOutputLocation; // if no specific output, still need to check using default output (this line would check default output)
978 for (int j = 0; j < length; j++) {
979 IClasspathEntry otherEntry = classpath[j];
980 if (otherEntry == entry) continue;
982 // Build some common strings for status message
983 boolean opStartsWithProject = otherEntry.getPath().segment(0).toString().equals(projectName);
984 String otherPathMsg = opStartsWithProject ? otherEntry.getPath().removeFirstSegments(1).toString() : otherEntry.getPath().makeRelative().toString();
986 switch (otherEntry.getEntryKind()) {
987 case IClasspathEntry.CPE_SOURCE :
988 if (otherEntry.getPath().equals(output)) {
989 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotUseDistinctSourceFolderAsOutput", new String[] {entryPathMsg, otherPathMsg, projectName})); //$NON-NLS-1$
992 case IClasspathEntry.CPE_LIBRARY :
993 if (otherEntry.getPath().equals(output)) {
994 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotUseLibraryAsOutput", new String[] {entryPathMsg, otherPathMsg, projectName})); //$NON-NLS-1$
1000 return JavaModelStatus.VERIFIED_OK;
1004 * Returns a Java model status describing the problem related to this classpath entry if any,
1005 * a status object with code <code>IStatus.OK</code> if the entry is fine (that is, if the
1006 * given classpath entry denotes a valid element to be referenced onto a classpath).
1008 * @param project the given java project
1009 * @param entry the given classpath entry
1010 * @param checkSourceAttachment a flag to determine if source attachement should be checked
1011 * @param recurseInContainers flag indicating whether validation should be applied to container entries recursively
1012 * @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
1014 public static IJavaModelStatus validateClasspathEntry(IJavaProject project, IClasspathEntry entry, boolean checkSourceAttachment, boolean recurseInContainers){
1016 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
1017 IPath path = entry.getPath();
1019 // Build some common strings for status message
1020 String projectName = project.getElementName();
1021 boolean pathStartsWithProject = path.segment(0).toString().equals(projectName);
1022 String entryPathMsg = pathStartsWithProject ? path.removeFirstSegments(1).toString() : path.makeRelative().toString();
1024 switch(entry.getEntryKind()){
1026 // container entry check
1027 // case IClasspathEntry.CPE_CONTAINER :
1028 // if (path != null && path.segmentCount() >= 1){
1030 // IClasspathContainer container = JavaModelManager.getJavaModelManager().getClasspathContainer(path, project);
1031 // // container retrieval is performing validation check on container entry kinds.
1032 // if (container == null){
1033 // return new JavaModelStatus(IJavaModelStatusConstants.CP_CONTAINER_PATH_UNBOUND, project, path);
1034 // } else if (container == JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS) {
1035 // // don't create a marker if initialization is in progress (case of cp initialization batching)
1036 // return JavaModelStatus.VERIFIED_OK;
1038 // IClasspathEntry[] containerEntries = container.getClasspathEntries();
1039 // if (containerEntries != null){
1040 // for (int i = 0, length = containerEntries.length; i < length; i++){
1041 // IClasspathEntry containerEntry = containerEntries[i];
1042 // int kind = containerEntry == null ? 0 : containerEntry.getEntryKind();
1043 // if (containerEntry == null
1044 // || kind == IClasspathEntry.CPE_SOURCE
1045 // || kind == IClasspathEntry.CPE_VARIABLE
1046 // || kind == IClasspathEntry.CPE_CONTAINER){
1047 // String description = container.getDescription();
1048 // if (description == null) description = path.makeRelative().toString();
1049 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CP_CONTAINER_ENTRY, project, path);
1051 // if (recurseInContainers) {
1052 // IJavaModelStatus containerEntryStatus = validateClasspathEntry(project, containerEntry, checkSourceAttachment, recurseInContainers);
1053 // if (!containerEntryStatus.isOK()){
1054 // return containerEntryStatus;
1059 // } catch(JavaModelException e){
1060 // return new JavaModelStatus(e);
1063 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalContainerPath", entryPathMsg, projectName)); //$NON-NLS-1$
1067 // variable entry check
1068 case IClasspathEntry.CPE_VARIABLE :
1069 if (path != null && path.segmentCount() >= 1){
1071 entry = JavaCore.getResolvedClasspathEntry(entry);
1072 } catch (Assert.AssertionFailedException e) {
1073 // Catch the assertion failure and throw java model exception instead
1074 // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=55992
1075 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage());
1078 return new JavaModelStatus(IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND, project, path);
1080 return validateClasspathEntry(project, entry, checkSourceAttachment, recurseInContainers);
1082 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalVariablePath", path.makeRelative().toString(), projectName)); //$NON-NLS-1$
1085 // library entry check
1086 // case IClasspathEntry.CPE_LIBRARY :
1087 // if (path != null && path.isAbsolute() && !path.isEmpty()) {
1088 // IPath sourceAttachment = entry.getSourceAttachmentPath();
1089 // Object target = JavaModel.getTarget(workspaceRoot, path, true);
1090 // if (target != null && project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true) != JavaCore.IGNORE) {
1091 // long projectTargetJDK = CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
1092 // long libraryJDK = Util.getJdkLevel(target);
1093 // if (libraryJDK != 0 && libraryJDK > projectTargetJDK) {
1094 // return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL, project, path, CompilerOptions.versionFromJdkLevel(libraryJDK));
1097 // if (target instanceof IResource){
1098 // IResource resolvedResource = (IResource) target;
1099 // switch(resolvedResource.getType()){
1100 // case IResource.FILE :
1101 // if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(resolvedResource.getName())) {
1102 // if (checkSourceAttachment
1103 // && sourceAttachment != null
1104 // && !sourceAttachment.isEmpty()
1105 // && JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
1106 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundSourceAttachment", new String [] {sourceAttachment.makeRelative().toString(), path.makeRelative().toString(), projectName})); //$NON-NLS-1$
1109 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalLibraryArchive", entryPathMsg, projectName)); //$NON-NLS-1$
1112 // case IResource.FOLDER : // internal binary folder
1113 // if (checkSourceAttachment
1114 // && sourceAttachment != null
1115 // && !sourceAttachment.isEmpty()
1116 // && JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
1117 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundSourceAttachment", new String [] {sourceAttachment.makeRelative().toString(), path.makeRelative().toString(), projectName})); //$NON-NLS-1$
1120 // } else if (target instanceof File){
1121 // File file = (File) target;
1122 // if (!file.isFile()) {
1123 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalExternalFolder", path.toOSString(), projectName)); //$NON-NLS-1$
1124 // } else if (!org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(file.getName())) {
1125 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalLibraryArchive", path.toOSString(), projectName)); //$NON-NLS-1$
1126 // } else if (checkSourceAttachment
1127 // && sourceAttachment != null
1128 // && !sourceAttachment.isEmpty()
1129 // && JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
1130 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundSourceAttachment", new String [] {sourceAttachment.toString(), path.makeRelative().toString(), projectName})); //$NON-NLS-1$
1133 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundLibrary", path.makeRelative().toString(), projectName)); //$NON-NLS-1$
1136 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalLibraryPath", path.makeRelative().toString(), projectName)); //$NON-NLS-1$
1140 // project entry check
1141 case IClasspathEntry.CPE_PROJECT :
1142 if (path != null && path.isAbsolute() && !path.isEmpty()) {
1143 IProject prereqProjectRsc = workspaceRoot.getProject(path.segment(0));
1144 IJavaProject prereqProject = JavaCore.create(prereqProjectRsc);
1146 if (!prereqProjectRsc.exists() || !prereqProjectRsc.hasNature(PHPeclipsePlugin.PHP_NATURE_ID)){
1147 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundProject", path.makeRelative().segment(0).toString(), projectName)); //$NON-NLS-1$
1149 if (!prereqProjectRsc.isOpen()){
1150 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.closedProject", path.segment(0).toString())); //$NON-NLS-1$
1152 // if (project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true) != JavaCore.IGNORE) {
1153 // long projectTargetJDK = CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
1154 // long prereqProjectTargetJDK = CompilerOptions.versionToJdkLevel(prereqProject.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
1155 // if (prereqProjectTargetJDK > projectTargetJDK) {
1156 // return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL, project, path, CompilerOptions.versionFromJdkLevel(prereqProjectTargetJDK));
1159 } catch (CoreException e){
1160 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundProject", path.segment(0).toString(), projectName)); //$NON-NLS-1$
1163 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalProjectPath", path.segment(0).toString(), projectName)); //$NON-NLS-1$
1167 // project source folder
1168 case IClasspathEntry.CPE_SOURCE :
1169 if (((entry.getInclusionPatterns() != null && entry.getInclusionPatterns().length > 0)
1170 || (entry.getExclusionPatterns() != null && entry.getExclusionPatterns().length > 0))
1171 && JavaCore.DISABLED.equals(project.getOption(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, true))) {
1172 return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_EXCLUSION_PATTERNS, project, path);
1174 if (entry.getOutputLocation() != null && JavaCore.DISABLED.equals(project.getOption(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, true))) {
1175 return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS, project, path);
1177 if (path != null && path.isAbsolute() && !path.isEmpty()) {
1178 IPath projectPath= project.getProject().getFullPath();
1179 if (!projectPath.isPrefixOf(path) || JavaModel.getTarget(workspaceRoot, path, true) == null){
1180 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundSourceFolder", entryPathMsg, projectName)); //$NON-NLS-1$
1183 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalSourceFolderPath", entryPathMsg, projectName)); //$NON-NLS-1$
1187 return JavaModelStatus.VERIFIED_OK;