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;
14 import java.util.HashMap;
15 import java.util.HashSet;
17 import net.sourceforge.phpdt.core.IClasspathEntry;
18 import net.sourceforge.phpdt.core.IJavaModelStatus;
19 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
20 import net.sourceforge.phpdt.core.IJavaProject;
21 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
22 import net.sourceforge.phpdt.core.JavaCore;
23 import net.sourceforge.phpdt.core.JavaModelException;
24 import net.sourceforge.phpdt.core.compiler.CharOperation;
25 import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
26 import net.sourceforge.phpdt.internal.core.util.Util;
27 import net.sourceforge.phpdt.internal.corext.Assert;
28 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
30 import org.eclipse.core.resources.IProject;
31 import org.eclipse.core.resources.IResource;
32 import org.eclipse.core.resources.IWorkspaceRoot;
33 import org.eclipse.core.resources.ResourcesPlugin;
34 import org.eclipse.core.runtime.CoreException;
35 import org.eclipse.core.runtime.IPath;
36 import org.eclipse.core.runtime.Path;
37 import org.w3c.dom.Document;
38 import org.w3c.dom.Element;
41 * @see IClasspathEntry
43 public class ClasspathEntry implements IClasspathEntry {
46 * Describes the kind of classpath entry - one of
47 * CPE_PROJECT, CPE_LIBRARY, CPE_SOURCE, CPE_VARIABLE or CPE_CONTAINER
52 * Describes the kind of package fragment roots found on
53 * this classpath entry - either K_BINARY or K_SOURCE or
56 public int contentKind;
59 * The meaning of the path of a classpath entry depends on its entry kind:<ul>
60 * <li>Source code in the current project (<code>CPE_SOURCE</code>) -
61 * The path associated with this entry is the absolute path to the root folder. </li>
62 * <li>A binary library in the current project (<code>CPE_LIBRARY</code>) - the path
63 * associated with this entry is the absolute path to the JAR (or root folder), and
64 * in case it refers to an external JAR, then there is no associated resource in
66 * <li>A required project (<code>CPE_PROJECT</code>) - the path of the entry denotes the
67 * path to the corresponding project resource.</li>
68 * <li>A variable entry (<code>CPE_VARIABLE</code>) - the first segment of the path
69 * is the name of a classpath variable. If this classpath variable
70 * is bound to the path <it>P</it>, the path of the corresponding classpath entry
71 * is computed by appending to <it>P</it> the segments of the returned
72 * path without the variable.</li>
73 * <li> A container entry (<code>CPE_CONTAINER</code>) - the first segment of the path is denoting
74 * the unique container identifier (for which a <code>ClasspathContainerInitializer</code> could be
75 * registered), and the remaining segments are used as additional hints for resolving the container entry to
76 * an actual <code>IClasspathContainer</code>.</li>
82 * Patterns allowing to include/exclude portions of the resource tree denoted by this entry path.
84 public IPath[] inclusionPatterns;
85 private char[][] fullCharInclusionPatterns;
86 public IPath[] exclusionPatterns;
87 private char[][] fullCharExclusionPatterns;
88 private final static char[][] UNINIT_PATTERNS = new char[][] { "Non-initialized yet".toCharArray() }; //$NON-NLS-1$
90 private String rootID;
92 * Default inclusion pattern set
94 public final static IPath[] INCLUDE_ALL = {};
97 * Default exclusion pattern set
99 public final static IPath[] EXCLUDE_NONE = {};
101 * Default exclusion pattern set
103 public final static IPath[] NO_EXCLUSION_PATTERNS = {};
106 * Describes the path to the source archive associated with this
107 * classpath entry, or <code>null</code> if this classpath entry has no
110 * Only library and variable classpath entries may have source attachments.
111 * For library classpath entries, the result path (if present) locates a source
112 * archive. For variable classpath entries, the result path (if present) has
113 * an analogous form and meaning as the variable path, namely the first segment
114 * is the name of a classpath variable.
116 public IPath sourceAttachmentPath;
119 * Describes the path within the source archive where package fragments
120 * are located. An empty path indicates that packages are located at
121 * the root of the source archive. Returns a non-<code>null</code> value
122 * if and only if <code>getSourceAttachmentPath</code> returns
123 * a non-<code>null</code> value.
125 public IPath sourceAttachmentRootPath;
128 * Specific output location (for this source entry)
130 public IPath specificOutputLocation;
133 * A constant indicating an output location.
135 public static final int K_OUTPUT = 10;
140 public boolean isExported;
143 * Creates a class path entry of the specified kind with the given path.
145 public ClasspathEntry(
149 IPath[] inclusionPatterns,
150 IPath[] exclusionPatterns,
151 IPath sourceAttachmentPath,
152 IPath sourceAttachmentRootPath,
153 IPath specificOutputLocation,
154 boolean isExported) {
156 this.contentKind = contentKind;
157 this.entryKind = entryKind;
159 this.inclusionPatterns = inclusionPatterns;
160 if (inclusionPatterns != INCLUDE_ALL && inclusionPatterns.length > 0) {
161 this.fullCharInclusionPatterns = UNINIT_PATTERNS;
163 this.fullCharInclusionPatterns = null; // empty inclusion pattern means everything is included
165 this.exclusionPatterns = exclusionPatterns;
166 if (exclusionPatterns.length > 0) {
167 this.fullCharExclusionPatterns = UNINIT_PATTERNS;
169 this.sourceAttachmentPath = sourceAttachmentPath;
170 this.sourceAttachmentRootPath = sourceAttachmentRootPath;
171 this.specificOutputLocation = specificOutputLocation;
172 this.isExported = isExported;
176 * Returns a char based representation of the exclusions patterns full path.
178 public char[][] fullExclusionPatternChars() {
180 if (this.fullCharExclusionPatterns == UNINIT_PATTERNS) {
181 int length = this.exclusionPatterns.length;
182 this.fullCharExclusionPatterns = new char[length][];
183 IPath prefixPath = this.path.removeTrailingSeparator();
184 for (int i = 0; i < length; i++) {
185 this.fullCharExclusionPatterns[i] =
186 prefixPath.append(this.exclusionPatterns[i]).toString().toCharArray();
189 return this.fullCharExclusionPatterns;
193 * Returns a char based representation of the exclusions patterns full path.
195 public char[][] fullInclusionPatternChars() {
197 if (this.fullCharInclusionPatterns == UNINIT_PATTERNS) {
198 int length = this.inclusionPatterns.length;
199 this.fullCharInclusionPatterns = new char[length][];
200 IPath prefixPath = this.path.removeTrailingSeparator();
201 for (int i = 0; i < length; i++) {
202 this.fullCharInclusionPatterns[i] =
203 prefixPath.append(this.inclusionPatterns[i]).toString().toCharArray();
206 return this.fullCharInclusionPatterns;
209 * Returns the XML encoding of the class path.
211 public Element elementEncode(
214 throws JavaModelException {
216 Element element = document.createElement("classpathentry"); //$NON-NLS-1$
217 element.setAttribute("kind", kindToString(this.entryKind)); //$NON-NLS-1$
218 IPath xmlPath = this.path;
219 if (this.entryKind != IClasspathEntry.CPE_VARIABLE && this.entryKind != IClasspathEntry.CPE_CONTAINER) {
220 // translate to project relative from absolute (unless a device path)
221 if (xmlPath.isAbsolute()) {
222 if (projectPath != null && projectPath.isPrefixOf(xmlPath)) {
223 if (xmlPath.segment(0).equals(projectPath.segment(0))) {
224 xmlPath = xmlPath.removeFirstSegments(1);
225 xmlPath = xmlPath.makeRelative();
227 xmlPath = xmlPath.makeAbsolute();
232 element.setAttribute("path", xmlPath.toString()); //$NON-NLS-1$
233 if (this.sourceAttachmentPath != null) {
234 element.setAttribute("sourcepath", this.sourceAttachmentPath.toString()); //$NON-NLS-1$
236 if (this.sourceAttachmentRootPath != null) {
237 element.setAttribute("rootpath", this.sourceAttachmentRootPath.toString()); //$NON-NLS-1$
239 if (this.isExported) {
240 element.setAttribute("exported", "true"); //$NON-NLS-1$ //$NON-NLS-2$
243 if (this.exclusionPatterns.length > 0) {
244 StringBuffer excludeRule = new StringBuffer(10);
245 for (int i = 0, max = this.exclusionPatterns.length; i < max; i++){
246 if (i > 0) excludeRule.append('|');
247 excludeRule.append(this.exclusionPatterns[i]);
249 element.setAttribute("excluding", excludeRule.toString()); //$NON-NLS-1$
252 if (this.specificOutputLocation != null) {
253 IPath outputLocation = this.specificOutputLocation.removeFirstSegments(1);
254 outputLocation = outputLocation.makeRelative();
255 element.setAttribute("output", outputLocation.toString()); //$NON-NLS-1$
260 public static IClasspathEntry elementDecode(Element element, IJavaProject project) {
262 IPath projectPath = project.getProject().getFullPath();
263 String kindAttr = element.getAttribute("kind"); //$NON-NLS-1$
264 String pathAttr = element.getAttribute("path"); //$NON-NLS-1$
266 // ensure path is absolute
267 IPath path = new Path(pathAttr);
268 int kind = kindFromString(kindAttr);
269 if (kind != IClasspathEntry.CPE_VARIABLE && kind != IClasspathEntry.CPE_CONTAINER && !path.isAbsolute()) {
270 path = projectPath.append(path);
272 // source attachment info (optional)
273 IPath sourceAttachmentPath =
274 element.hasAttribute("sourcepath") //$NON-NLS-1$
275 ? new Path(element.getAttribute("sourcepath")) //$NON-NLS-1$
277 IPath sourceAttachmentRootPath =
278 element.hasAttribute("rootpath") //$NON-NLS-1$
279 ? new Path(element.getAttribute("rootpath")) //$NON-NLS-1$
282 // exported flag (optional)
283 boolean isExported = element.getAttribute("exported").equals("true"); //$NON-NLS-1$ //$NON-NLS-2$
285 // exclusion patterns (optional)
286 String exclusion = element.getAttribute("excluding"); //$NON-NLS-1$
287 IPath[] exclusionPatterns = ClasspathEntry.NO_EXCLUSION_PATTERNS;
288 if (!exclusion.equals("")) { //$NON-NLS-1$
289 char[][] patterns = CharOperation.splitOn('|', exclusion.toCharArray());
291 if ((patternCount = patterns.length) > 0) {
292 exclusionPatterns = new IPath[patternCount];
293 for (int j = 0; j < patterns.length; j++){
294 exclusionPatterns[j] = new Path(new String(patterns[j]));
299 // custom output location
300 IPath outputLocation = element.hasAttribute("output") ? projectPath.append(element.getAttribute("output")) : null; //$NON-NLS-1$ //$NON-NLS-2$
302 // recreate the CP entry
305 case IClasspathEntry.CPE_PROJECT :
306 return JavaCore.newProjectEntry(path, isExported);
308 // case IClasspathEntry.CPE_LIBRARY :
309 // return JavaCore.newLibraryEntry(
311 // sourceAttachmentPath,
312 // sourceAttachmentRootPath,
315 case IClasspathEntry.CPE_SOURCE :
316 // must be an entry in this project or specify another project
317 String projSegment = path.segment(0);
318 if (projSegment != null && projSegment.equals(project.getElementName())) { // this project
319 return JavaCore.newSourceEntry(path, exclusionPatterns, outputLocation);
320 } else { // another project
321 return JavaCore.newProjectEntry(path, isExported);
324 // case IClasspathEntry.CPE_VARIABLE :
325 // return PHPCore.newVariableEntry(
327 // sourceAttachmentPath,
328 // sourceAttachmentRootPath,
331 case IClasspathEntry.CPE_CONTAINER :
332 return JavaCore.newContainerEntry(
336 case ClasspathEntry.K_OUTPUT :
337 if (!path.isAbsolute()) return null;
338 return new ClasspathEntry(
339 ClasspathEntry.K_OUTPUT,
340 IClasspathEntry.CPE_LIBRARY,
342 ClasspathEntry.INCLUDE_ALL,
343 ClasspathEntry.EXCLUDE_NONE,
344 null, // source attachment
345 null, // source attachment root
346 null, // custom output location
350 throw new Assert.AssertionFailedException(Util.bind("classpath.unknownKind", kindAttr)); //$NON-NLS-1$
355 * Returns true if the given object is a classpath entry
356 * with equivalent attributes.
358 public boolean equals(Object object) {
361 if (object instanceof IClasspathEntry) {
362 IClasspathEntry otherEntry = (IClasspathEntry) object;
364 if (this.contentKind != otherEntry.getContentKind())
367 if (this.entryKind != otherEntry.getEntryKind())
370 if (this.isExported != otherEntry.isExported())
373 if (!this.path.equals(otherEntry.getPath()))
376 IPath otherPath = otherEntry.getSourceAttachmentPath();
377 if (this.sourceAttachmentPath == null) {
378 if (otherPath != null)
381 if (!this.sourceAttachmentPath.equals(otherPath))
385 otherPath = otherEntry.getSourceAttachmentRootPath();
386 if (this.sourceAttachmentRootPath == null) {
387 if (otherPath != null)
390 if (!this.sourceAttachmentRootPath.equals(otherPath))
394 IPath[] otherIncludes = otherEntry.getInclusionPatterns();
395 if (this.inclusionPatterns != otherIncludes){
396 if (this.inclusionPatterns == null) return false;
397 int includeLength = this.inclusionPatterns.length;
398 if (otherIncludes == null || otherIncludes.length != includeLength)
400 for (int i = 0; i < includeLength; i++) {
401 // compare toStrings instead of IPaths
402 // since IPath.equals is specified to ignore trailing separators
403 if (!this.inclusionPatterns[i].toString().equals(otherIncludes[i].toString()))
408 IPath[] otherExcludes = otherEntry.getExclusionPatterns();
409 if (this.exclusionPatterns != otherExcludes){
410 int excludeLength = this.exclusionPatterns.length;
411 if (otherExcludes.length != excludeLength)
413 for (int i = 0; i < excludeLength; i++) {
414 // compare toStrings instead of IPaths
415 // since IPath.equals is specified to ignore trailing separators
416 if (!this.exclusionPatterns[i].toString().equals(otherExcludes[i].toString()))
421 otherPath = otherEntry.getOutputLocation();
422 if (this.specificOutputLocation == null) {
423 if (otherPath != null)
426 if (!this.specificOutputLocation.equals(otherPath))
436 * @see IClasspathEntry
438 public int getContentKind() {
439 return this.contentKind;
443 * @see IClasspathEntry
445 public int getEntryKind() {
446 return this.entryKind;
450 * @see IClasspathEntry#getExclusionPatterns()
452 public IPath[] getExclusionPatterns() {
453 return this.exclusionPatterns;
456 * @see IClasspathEntry#getExclusionPatterns()
458 public IPath[] getInclusionPatterns() {
459 return this.inclusionPatterns;
462 * @see IClasspathEntry#getOutputLocation()
464 public IPath getOutputLocation() {
465 return this.specificOutputLocation;
469 * @see IClasspathEntry
471 public IPath getPath() {
476 * @see IClasspathEntry
478 public IPath getSourceAttachmentPath() {
479 return this.sourceAttachmentPath;
483 * @see IClasspathEntry
485 public IPath getSourceAttachmentRootPath() {
486 return this.sourceAttachmentRootPath;
490 * Returns the hash code for this classpath entry
492 public int hashCode() {
493 return this.path.hashCode();
497 * @see IClasspathEntry#isExported()
499 public boolean isExported() {
500 return this.isExported;
504 * Returns the kind of a <code>PackageFragmentRoot</code> from its <code>String</code> form.
506 static int kindFromString(String kindStr) {
508 if (kindStr.equalsIgnoreCase("prj")) //$NON-NLS-1$
509 return IClasspathEntry.CPE_PROJECT;
510 if (kindStr.equalsIgnoreCase("var")) //$NON-NLS-1$
511 return IClasspathEntry.CPE_VARIABLE;
512 if (kindStr.equalsIgnoreCase("con")) //$NON-NLS-1$
513 return IClasspathEntry.CPE_CONTAINER;
514 if (kindStr.equalsIgnoreCase("src")) //$NON-NLS-1$
515 return IClasspathEntry.CPE_SOURCE;
516 if (kindStr.equalsIgnoreCase("lib")) //$NON-NLS-1$
517 return IClasspathEntry.CPE_LIBRARY;
518 if (kindStr.equalsIgnoreCase("output")) //$NON-NLS-1$
519 return ClasspathEntry.K_OUTPUT;
524 * Returns a <code>String</code> for the kind of a class path entry.
526 static String kindToString(int kind) {
529 case IClasspathEntry.CPE_PROJECT :
530 return "src"; // backward compatibility //$NON-NLS-1$
531 case IClasspathEntry.CPE_SOURCE :
532 return "src"; //$NON-NLS-1$
533 case IClasspathEntry.CPE_LIBRARY :
534 return "lib"; //$NON-NLS-1$
535 case IClasspathEntry.CPE_VARIABLE :
536 return "var"; //$NON-NLS-1$
537 case IClasspathEntry.CPE_CONTAINER :
538 return "con"; //$NON-NLS-1$
539 case ClasspathEntry.K_OUTPUT :
540 return "output"; //$NON-NLS-1$
542 return "unknown"; //$NON-NLS-1$
547 * Returns a printable representation of this classpath entry.
549 public String toString() {
550 StringBuffer buffer = new StringBuffer();
551 buffer.append(getPath().toString());
553 switch (getEntryKind()) {
554 case IClasspathEntry.CPE_LIBRARY :
555 buffer.append("CPE_LIBRARY"); //$NON-NLS-1$
557 case IClasspathEntry.CPE_PROJECT :
558 buffer.append("CPE_PROJECT"); //$NON-NLS-1$
560 case IClasspathEntry.CPE_SOURCE :
561 buffer.append("CPE_SOURCE"); //$NON-NLS-1$
563 case IClasspathEntry.CPE_VARIABLE :
564 buffer.append("CPE_VARIABLE"); //$NON-NLS-1$
566 case IClasspathEntry.CPE_CONTAINER :
567 buffer.append("CPE_CONTAINER"); //$NON-NLS-1$
570 buffer.append("]["); //$NON-NLS-1$
571 switch (getContentKind()) {
572 case IPackageFragmentRoot.K_BINARY :
573 buffer.append("K_BINARY"); //$NON-NLS-1$
575 case IPackageFragmentRoot.K_SOURCE :
576 buffer.append("K_SOURCE"); //$NON-NLS-1$
578 case ClasspathEntry.K_OUTPUT :
579 buffer.append("K_OUTPUT"); //$NON-NLS-1$
583 if (getSourceAttachmentPath() != null) {
584 buffer.append("[sourcePath:"); //$NON-NLS-1$
585 buffer.append(getSourceAttachmentPath());
588 if (getSourceAttachmentRootPath() != null) {
589 buffer.append("[rootPath:"); //$NON-NLS-1$
590 buffer.append(getSourceAttachmentRootPath());
593 buffer.append("[isExported:"); //$NON-NLS-1$
594 buffer.append(this.isExported);
596 IPath[] patterns = getExclusionPatterns();
598 if ((length = patterns.length) > 0) {
599 buffer.append("[excluding:"); //$NON-NLS-1$
600 for (int i = 0; i < length; i++) {
601 buffer.append(patterns[i]);
608 if (getOutputLocation() != null) {
609 buffer.append("[output:"); //$NON-NLS-1$
610 buffer.append(getOutputLocation());
613 return buffer.toString();
617 * Answers an ID which is used to distinguish entries during package
618 * fragment root computations
620 public String rootID(){
622 if (this.rootID == null) {
623 switch(this.entryKind){
624 case IClasspathEntry.CPE_LIBRARY :
625 this.rootID = "[LIB]"+this.path; //$NON-NLS-1$
627 case IClasspathEntry.CPE_PROJECT :
628 this.rootID = "[PRJ]"+this.path; //$NON-NLS-1$
630 case IClasspathEntry.CPE_SOURCE :
631 this.rootID = "[SRC]"+this.path; //$NON-NLS-1$
633 case IClasspathEntry.CPE_VARIABLE :
634 this.rootID = "[VAR]"+this.path; //$NON-NLS-1$
636 case IClasspathEntry.CPE_CONTAINER :
637 this.rootID = "[CON]"+this.path; //$NON-NLS-1$
640 this.rootID = ""; //$NON-NLS-1$
648 * @see IClasspathEntry
651 public IClasspathEntry getResolvedEntry() {
653 return JavaCore.getResolvedClasspathEntry(this);
656 * Returns the XML encoding of the class path.
658 public void elementEncode(XMLWriter writer, IPath projectPath, boolean indent, boolean newLine) {
659 HashMap parameters = new HashMap();
661 parameters.put("kind", ClasspathEntry.kindToString(this.entryKind));//$NON-NLS-1$
663 IPath xmlPath = this.path;
664 if (this.entryKind != IClasspathEntry.CPE_VARIABLE && this.entryKind != IClasspathEntry.CPE_CONTAINER) {
665 // translate to project relative from absolute (unless a device path)
666 if (xmlPath.isAbsolute()) {
667 if (projectPath != null && projectPath.isPrefixOf(xmlPath)) {
668 if (xmlPath.segment(0).equals(projectPath.segment(0))) {
669 xmlPath = xmlPath.removeFirstSegments(1);
670 xmlPath = xmlPath.makeRelative();
672 xmlPath = xmlPath.makeAbsolute();
677 parameters.put("path", String.valueOf(xmlPath));//$NON-NLS-1$
679 if (this.sourceAttachmentPath != null) {
680 xmlPath = this.sourceAttachmentPath;
681 // translate to project relative from absolute
682 if (this.entryKind != IClasspathEntry.CPE_VARIABLE && projectPath != null && projectPath.isPrefixOf(xmlPath)) {
683 if (xmlPath.segment(0).equals(projectPath.segment(0))) {
684 xmlPath = xmlPath.removeFirstSegments(1);
685 xmlPath = xmlPath.makeRelative();
688 parameters.put("sourcepath", String.valueOf(xmlPath));//$NON-NLS-1$
690 if (this.sourceAttachmentRootPath != null) {
691 parameters.put("rootpath", String.valueOf(this.sourceAttachmentRootPath));//$NON-NLS-1$
693 if (this.isExported) {
694 parameters.put("exported", "true");//$NON-NLS-1$//$NON-NLS-2$
696 // if (this.inclusionPatterns != null && this.inclusionPatterns.length > 0) {
697 // StringBuffer includeRule = new StringBuffer(10);
698 // for (int i = 0, max = this.inclusionPatterns.length; i < max; i++){
699 // if (i > 0) includeRule.append('|');
700 // includeRule.append(this.inclusionPatterns[i]);
702 // parameters.put("including", String.valueOf(includeRule));//$NON-NLS-1$
704 if (this.exclusionPatterns != null && this.exclusionPatterns.length > 0) {
705 StringBuffer excludeRule = new StringBuffer(10);
706 for (int i = 0, max = this.exclusionPatterns.length; i < max; i++){
707 if (i > 0) excludeRule.append('|');
708 excludeRule.append(this.exclusionPatterns[i]);
710 parameters.put("excluding", String.valueOf(excludeRule));//$NON-NLS-1$
713 if (this.specificOutputLocation != null) {
714 IPath outputLocation = this.specificOutputLocation.removeFirstSegments(1);
715 outputLocation = outputLocation.makeRelative();
716 parameters.put("output", String.valueOf(outputLocation));//$NON-NLS-1$
719 writer.printTag("classpathentry", parameters, indent, newLine, true);//$NON-NLS-1$
723 * Validate a given classpath and output location for a project, using the following rules:
725 * <li> Classpath entries cannot collide with each other; that is, all entry paths must be unique.
726 * <li> The project output location path cannot be null, must be absolute and located inside the project.
727 * <li> Specific output locations (specified on source entries) can be null, if not they must be located inside the project,
728 * <li> A project entry cannot refer to itself directly (that is, a project cannot prerequisite itself).
729 * <li> Classpath entries or output locations cannot coincidate or be nested in each other, except for the following scenarii listed below:
730 * <ul><li> A source folder can coincidate with its own output location, in which case this output can then contain library archives.
731 * However, a specific output location cannot coincidate with any library or a distinct source folder than the one referring to it. </li>
732 * <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>
733 * <li> An output location can be nested in a source folder, if the source folder coincidates with the project itself, or if the output
734 * location is excluded from the source folder. </li>
738 * Note that the classpath entries are not validated automatically. Only bound variables or containers are considered
739 * in the checking process (this allows to perform a consistency check on a classpath which has references to
740 * yet non existing projects, folders, ...).
742 * This validation is intended to anticipate classpath issues prior to assigning it to a project. In particular, it will automatically
743 * be performed during the classpath setting operation (if validation fails, the classpath setting will not complete).
745 * @param javaProject the given java project
746 * @param rawClasspath a given classpath
747 * @param projectOutputLocation a given output location
748 * @return a status object with code <code>IStatus.OK</code> if
749 * the given classpath and output location are compatible, otherwise a status
750 * object indicating what is wrong with the classpath or output location
752 public static IJavaModelStatus validateClasspath(IJavaProject javaProject, IClasspathEntry[] rawClasspath, IPath projectOutputLocation) {
754 IProject project = javaProject.getProject();
755 IPath projectPath= project.getFullPath();
756 String projectName = javaProject.getElementName();
758 /* validate output location */
759 if (projectOutputLocation == null) {
760 return new JavaModelStatus(IJavaModelStatusConstants.NULL_PATH);
762 if (projectOutputLocation.isAbsolute()) {
763 if (!projectPath.isPrefixOf(projectOutputLocation)) {
764 return new JavaModelStatus(IJavaModelStatusConstants.PATH_OUTSIDE_PROJECT, javaProject, projectOutputLocation.toString());
767 return new JavaModelStatus(IJavaModelStatusConstants.RELATIVE_PATH, projectOutputLocation);
770 boolean hasSource = false;
771 boolean hasLibFolder = false;
774 // tolerate null path, it will be reset to default
775 if (rawClasspath == null)
776 return JavaModelStatus.VERIFIED_OK;
778 // retrieve resolved classpath
779 IClasspathEntry[] classpath;
781 classpath = ((JavaProject)javaProject).getResolvedClasspath(rawClasspath, null /*output*/, true/*ignore pb*/, false/*no marker*/, null /*no reverse map*/);
782 } catch(JavaModelException e){
783 return e.getJavaModelStatus();
785 int length = classpath.length;
788 IPath[] outputLocations = new IPath[length+1];
789 boolean[] allowNestingInOutputLocations = new boolean[length+1];
790 outputLocations[0] = projectOutputLocation;
792 // retrieve and check output locations
793 IPath potentialNestedOutput = null; // for error reporting purpose
794 int sourceEntryCount = 0;
795 boolean disableExclusionPatterns = JavaCore.DISABLED.equals(javaProject.getOption(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, true));
796 boolean disableCustomOutputLocations = JavaCore.DISABLED.equals(javaProject.getOption(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, true));
798 for (int i = 0 ; i < length; i++) {
799 IClasspathEntry resolvedEntry = classpath[i];
800 switch(resolvedEntry.getEntryKind()){
801 case IClasspathEntry.CPE_SOURCE :
804 if (disableExclusionPatterns &&
805 ((resolvedEntry.getInclusionPatterns() != null && resolvedEntry.getInclusionPatterns().length > 0)
806 || (resolvedEntry.getExclusionPatterns() != null && resolvedEntry.getExclusionPatterns().length > 0))) {
807 return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_EXCLUSION_PATTERNS, javaProject, resolvedEntry.getPath());
810 if ((customOutput = resolvedEntry.getOutputLocation()) != null) {
812 if (disableCustomOutputLocations) {
813 return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS, javaProject, resolvedEntry.getPath());
815 // ensure custom output is in project
816 if (customOutput.isAbsolute()) {
817 if (!javaProject.getPath().isPrefixOf(customOutput)) {
818 return new JavaModelStatus(IJavaModelStatusConstants.PATH_OUTSIDE_PROJECT, javaProject, customOutput.toString());
821 return new JavaModelStatus(IJavaModelStatusConstants.RELATIVE_PATH, customOutput);
824 // ensure custom output doesn't conflict with other outputs
826 if (Util.indexOfMatchingPath(customOutput, outputLocations, outputCount) != -1) {
827 continue; // already found
829 // accumulate all outputs, will check nesting once all available (to handle ordering issues)
830 outputLocations[outputCount++] = customOutput;
834 // check nesting across output locations
835 for (int i = 1 /*no check for default output*/ ; i < outputCount; i++) {
836 IPath customOutput = outputLocations[i];
839 if ((index = Util.indexOfEnclosingPath(customOutput, outputLocations, outputCount)) != -1 && index != i) {
841 // custom output is nested in project's output: need to check if all source entries have a custom
842 // output before complaining
843 if (potentialNestedOutput == null) potentialNestedOutput = customOutput;
845 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestOutputInOutput", customOutput.makeRelative().toString(), outputLocations[index].makeRelative().toString())); //$NON-NLS-1$
849 // allow custom output nesting in project's output if all source entries have a custom output
850 if (sourceEntryCount <= outputCount-1) {
851 allowNestingInOutputLocations[0] = true;
852 } else if (potentialNestedOutput != null) {
853 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestOutputInOutput", potentialNestedOutput.makeRelative().toString(), outputLocations[0].makeRelative().toString())); //$NON-NLS-1$
856 for (int i = 0 ; i < length; i++) {
857 IClasspathEntry resolvedEntry = classpath[i];
858 IPath path = resolvedEntry.getPath();
860 switch(resolvedEntry.getEntryKind()){
862 case IClasspathEntry.CPE_SOURCE :
864 if ((index = Util.indexOfMatchingPath(path, outputLocations, outputCount)) != -1){
865 allowNestingInOutputLocations[index] = true;
869 // case IClasspathEntry.CPE_LIBRARY:
870 // hasLibFolder |= !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(path.lastSegment());
871 // if ((index = Util.indexOfMatchingPath(path, outputLocations, outputCount)) != -1){
872 // allowNestingInOutputLocations[index] = true;
877 if (!hasSource && !hasLibFolder) { // if no source and no lib folder, then allowed
878 for (int i = 0; i < outputCount; i++) allowNestingInOutputLocations[i] = true;
881 HashSet pathes = new HashSet(length);
884 for (int i = 0 ; i < length; i++) {
885 IClasspathEntry entry = classpath[i];
886 if (entry == null) continue;
887 IPath entryPath = entry.getPath();
888 int kind = entry.getEntryKind();
890 // Build some common strings for status message
891 boolean isProjectRelative = entryPath.segment(0).toString().equals(projectName);
892 String entryPathMsg = isProjectRelative ? entryPath.removeFirstSegments(1).toString() : entryPath.makeRelative().toString();
894 // complain if duplicate path
895 if (!pathes.add(entryPath)){
896 return new JavaModelStatus(IJavaModelStatusConstants.NAME_COLLISION, Util.bind("classpath.duplicateEntryPath", entryPathMsg, projectName)); //$NON-NLS-1$
898 // no further check if entry coincidates with project or output location
899 if (entryPath.equals(projectPath)){
900 // complain if self-referring project entry
901 if (kind == IClasspathEntry.CPE_PROJECT){
902 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, Util.bind("classpath.cannotReferToItself", entryPath.makeRelative().toString()));//$NON-NLS-1$
904 // tolerate nesting output in src if src==prj
908 // allow nesting source entries in each other as long as the outer entry excludes the inner one
909 if (kind == IClasspathEntry.CPE_SOURCE ) {
910 // || (kind == IClasspathEntry.CPE_LIBRARY && !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(entryPath.lastSegment()))){
911 for (int j = 0; j < classpath.length; j++){
912 IClasspathEntry otherEntry = classpath[j];
913 if (otherEntry == null) continue;
914 int otherKind = otherEntry.getEntryKind();
915 IPath otherPath = otherEntry.getPath();
916 if (entry != otherEntry
917 && (otherKind == IClasspathEntry.CPE_SOURCE ) ) {
918 // || (otherKind == IClasspathEntry.CPE_LIBRARY
919 // && !org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(otherPath.lastSegment())))){
920 char[][] inclusionPatterns, exclusionPatterns;
921 if (otherPath.isPrefixOf(entryPath)
922 && !otherPath.equals(entryPath)
923 && !Util.isExcluded(entryPath.append("*"), inclusionPatterns = ((ClasspathEntry)otherEntry).fullInclusionPatternChars(), exclusionPatterns = ((ClasspathEntry)otherEntry).fullExclusionPatternChars(), false)) { //$NON-NLS-1$
924 String exclusionPattern = entryPath.removeFirstSegments(otherPath.segmentCount()).segment(0);
925 if (Util.isExcluded(entryPath, inclusionPatterns, exclusionPatterns, false)) {
926 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.mustEndWithSlash", exclusionPattern, entryPath.makeRelative().toString())); //$NON-NLS-1$
928 if (otherKind == IClasspathEntry.CPE_SOURCE) {
929 exclusionPattern += '/';
930 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestEntryInEntry", new String[] {entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString(), exclusionPattern})); //$NON-NLS-1$
932 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestEntryInLibrary", entryPath.makeRelative().toString(), otherEntry.getPath().makeRelative().toString())); //$NON-NLS-1$
940 // prevent nesting output location inside entry unless enclosing is a source entry which explicitly exclude the output location
941 char[][] inclusionPatterns = ((ClasspathEntry)entry).fullInclusionPatternChars();
942 char[][] exclusionPatterns = ((ClasspathEntry)entry).fullExclusionPatternChars();
943 for (int j = 0; j < outputCount; j++){
944 IPath currentOutput = outputLocations[j];
945 if (entryPath.equals(currentOutput)) continue;
946 if (entryPath.isPrefixOf(currentOutput)) {
947 if (kind != IClasspathEntry.CPE_SOURCE || !Util.isExcluded(currentOutput, inclusionPatterns, exclusionPatterns, true)) {
948 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestOutputInEntry", currentOutput.makeRelative().toString(), entryPath.makeRelative().toString())); //$NON-NLS-1$
953 // prevent nesting entry inside output location - when distinct from project or a source folder
954 for (int j = 0; j < outputCount; j++){
955 if (allowNestingInOutputLocations[j]) continue;
956 IPath currentOutput = outputLocations[j];
957 if (currentOutput.isPrefixOf(entryPath)) {
958 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotNestEntryInOutput", entryPath.makeRelative().toString(), currentOutput.makeRelative().toString())); //$NON-NLS-1$
962 // ensure that no specific output is coincidating with another source folder (only allowed if matching current source folder)
963 // 36465 - for 2.0 backward compatibility, only check specific output locations (the default can still coincidate)
964 // perform one separate iteration so as to not take precedence over previously checked scenarii (in particular should
965 // diagnose nesting source folder issue before this one, for example, [src]"Project/", [src]"Project/source/" and output="Project/" should
966 // first complain about missing exclusion pattern
967 for (int i = 0 ; i < length; i++) {
968 IClasspathEntry entry = classpath[i];
969 if (entry == null) continue;
970 IPath entryPath = entry.getPath();
971 int kind = entry.getEntryKind();
973 // Build some common strings for status message
974 boolean isProjectRelative = entryPath.segment(0).toString().equals(projectName);
975 String entryPathMsg = isProjectRelative ? entryPath.removeFirstSegments(1).toString() : entryPath.makeRelative().toString();
977 if (kind == IClasspathEntry.CPE_SOURCE) {
978 IPath output = entry.getOutputLocation();
979 if (output == null) continue; // 36465 - for 2.0 backward compatibility, only check specific output locations (the default can still coincidate)
980 // if (output == null) output = projectOutputLocation; // if no specific output, still need to check using default output (this line would check default output)
981 for (int j = 0; j < length; j++) {
982 IClasspathEntry otherEntry = classpath[j];
983 if (otherEntry == entry) continue;
985 // Build some common strings for status message
986 boolean opStartsWithProject = otherEntry.getPath().segment(0).toString().equals(projectName);
987 String otherPathMsg = opStartsWithProject ? otherEntry.getPath().removeFirstSegments(1).toString() : otherEntry.getPath().makeRelative().toString();
989 switch (otherEntry.getEntryKind()) {
990 case IClasspathEntry.CPE_SOURCE :
991 if (otherEntry.getPath().equals(output)) {
992 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotUseDistinctSourceFolderAsOutput", new String[] {entryPathMsg, otherPathMsg, projectName})); //$NON-NLS-1$
995 case IClasspathEntry.CPE_LIBRARY :
996 if (otherEntry.getPath().equals(output)) {
997 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.cannotUseLibraryAsOutput", new String[] {entryPathMsg, otherPathMsg, projectName})); //$NON-NLS-1$
1003 return JavaModelStatus.VERIFIED_OK;
1007 * Returns a Java model status describing the problem related to this classpath entry if any,
1008 * a status object with code <code>IStatus.OK</code> if the entry is fine (that is, if the
1009 * given classpath entry denotes a valid element to be referenced onto a classpath).
1011 * @param project the given java project
1012 * @param entry the given classpath entry
1013 * @param checkSourceAttachment a flag to determine if source attachement should be checked
1014 * @param recurseInContainers flag indicating whether validation should be applied to container entries recursively
1015 * @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
1017 public static IJavaModelStatus validateClasspathEntry(IJavaProject project, IClasspathEntry entry, boolean checkSourceAttachment, boolean recurseInContainers){
1019 IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
1020 IPath path = entry.getPath();
1022 // Build some common strings for status message
1023 String projectName = project.getElementName();
1024 boolean pathStartsWithProject = path.segment(0).toString().equals(projectName);
1025 String entryPathMsg = pathStartsWithProject ? path.removeFirstSegments(1).toString() : path.makeRelative().toString();
1027 switch(entry.getEntryKind()){
1029 // container entry check
1030 // case IClasspathEntry.CPE_CONTAINER :
1031 // if (path != null && path.segmentCount() >= 1){
1033 // IClasspathContainer container = JavaModelManager.getJavaModelManager().getClasspathContainer(path, project);
1034 // // container retrieval is performing validation check on container entry kinds.
1035 // if (container == null){
1036 // return new JavaModelStatus(IJavaModelStatusConstants.CP_CONTAINER_PATH_UNBOUND, project, path);
1037 // } else if (container == JavaModelManager.CONTAINER_INITIALIZATION_IN_PROGRESS) {
1038 // // don't create a marker if initialization is in progress (case of cp initialization batching)
1039 // return JavaModelStatus.VERIFIED_OK;
1041 // IClasspathEntry[] containerEntries = container.getClasspathEntries();
1042 // if (containerEntries != null){
1043 // for (int i = 0, length = containerEntries.length; i < length; i++){
1044 // IClasspathEntry containerEntry = containerEntries[i];
1045 // int kind = containerEntry == null ? 0 : containerEntry.getEntryKind();
1046 // if (containerEntry == null
1047 // || kind == IClasspathEntry.CPE_SOURCE
1048 // || kind == IClasspathEntry.CPE_VARIABLE
1049 // || kind == IClasspathEntry.CPE_CONTAINER){
1050 // String description = container.getDescription();
1051 // if (description == null) description = path.makeRelative().toString();
1052 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CP_CONTAINER_ENTRY, project, path);
1054 // if (recurseInContainers) {
1055 // IJavaModelStatus containerEntryStatus = validateClasspathEntry(project, containerEntry, checkSourceAttachment, recurseInContainers);
1056 // if (!containerEntryStatus.isOK()){
1057 // return containerEntryStatus;
1062 // } catch(JavaModelException e){
1063 // return new JavaModelStatus(e);
1066 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalContainerPath", entryPathMsg, projectName)); //$NON-NLS-1$
1070 // variable entry check
1071 case IClasspathEntry.CPE_VARIABLE :
1072 if (path != null && path.segmentCount() >= 1){
1074 entry = JavaCore.getResolvedClasspathEntry(entry);
1075 } catch (Assert.AssertionFailedException e) {
1076 // Catch the assertion failure and throw java model exception instead
1077 // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=55992
1078 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_PATH, e.getMessage());
1081 return new JavaModelStatus(IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND, project, path);
1083 return validateClasspathEntry(project, entry, checkSourceAttachment, recurseInContainers);
1085 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalVariablePath", path.makeRelative().toString(), projectName)); //$NON-NLS-1$
1088 // library entry check
1089 // case IClasspathEntry.CPE_LIBRARY :
1090 // if (path != null && path.isAbsolute() && !path.isEmpty()) {
1091 // IPath sourceAttachment = entry.getSourceAttachmentPath();
1092 // Object target = JavaModel.getTarget(workspaceRoot, path, true);
1093 // if (target != null && project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true) != JavaCore.IGNORE) {
1094 // long projectTargetJDK = CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
1095 // long libraryJDK = Util.getJdkLevel(target);
1096 // if (libraryJDK != 0 && libraryJDK > projectTargetJDK) {
1097 // return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL, project, path, CompilerOptions.versionFromJdkLevel(libraryJDK));
1100 // if (target instanceof IResource){
1101 // IResource resolvedResource = (IResource) target;
1102 // switch(resolvedResource.getType()){
1103 // case IResource.FILE :
1104 // if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(resolvedResource.getName())) {
1105 // if (checkSourceAttachment
1106 // && sourceAttachment != null
1107 // && !sourceAttachment.isEmpty()
1108 // && JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
1109 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundSourceAttachment", new String [] {sourceAttachment.makeRelative().toString(), path.makeRelative().toString(), projectName})); //$NON-NLS-1$
1112 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalLibraryArchive", entryPathMsg, projectName)); //$NON-NLS-1$
1115 // case IResource.FOLDER : // internal binary folder
1116 // if (checkSourceAttachment
1117 // && sourceAttachment != null
1118 // && !sourceAttachment.isEmpty()
1119 // && JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
1120 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundSourceAttachment", new String [] {sourceAttachment.makeRelative().toString(), path.makeRelative().toString(), projectName})); //$NON-NLS-1$
1123 // } else if (target instanceof File){
1124 // File file = (File) target;
1125 // if (!file.isFile()) {
1126 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalExternalFolder", path.toOSString(), projectName)); //$NON-NLS-1$
1127 // } else if (!org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(file.getName())) {
1128 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalLibraryArchive", path.toOSString(), projectName)); //$NON-NLS-1$
1129 // } else if (checkSourceAttachment
1130 // && sourceAttachment != null
1131 // && !sourceAttachment.isEmpty()
1132 // && JavaModel.getTarget(workspaceRoot, sourceAttachment, true) == null){
1133 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundSourceAttachment", new String [] {sourceAttachment.toString(), path.makeRelative().toString(), projectName})); //$NON-NLS-1$
1136 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundLibrary", path.makeRelative().toString(), projectName)); //$NON-NLS-1$
1139 // return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalLibraryPath", path.makeRelative().toString(), projectName)); //$NON-NLS-1$
1143 // project entry check
1144 case IClasspathEntry.CPE_PROJECT :
1145 if (path != null && path.isAbsolute() && !path.isEmpty()) {
1146 IProject prereqProjectRsc = workspaceRoot.getProject(path.segment(0));
1147 IJavaProject prereqProject = JavaCore.create(prereqProjectRsc);
1149 if (!prereqProjectRsc.exists() || !prereqProjectRsc.hasNature(PHPeclipsePlugin.PHP_NATURE_ID)){
1150 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundProject", path.makeRelative().segment(0).toString(), projectName)); //$NON-NLS-1$
1152 if (!prereqProjectRsc.isOpen()){
1153 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.closedProject", path.segment(0).toString())); //$NON-NLS-1$
1155 // if (project.getOption(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, true) != JavaCore.IGNORE) {
1156 // long projectTargetJDK = CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
1157 // long prereqProjectTargetJDK = CompilerOptions.versionToJdkLevel(prereqProject.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
1158 // if (prereqProjectTargetJDK > projectTargetJDK) {
1159 // return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL, project, path, CompilerOptions.versionFromJdkLevel(prereqProjectTargetJDK));
1162 } catch (CoreException e){
1163 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundProject", path.segment(0).toString(), projectName)); //$NON-NLS-1$
1166 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalProjectPath", path.segment(0).toString(), projectName)); //$NON-NLS-1$
1170 // project source folder
1171 case IClasspathEntry.CPE_SOURCE :
1172 if (((entry.getInclusionPatterns() != null && entry.getInclusionPatterns().length > 0)
1173 || (entry.getExclusionPatterns() != null && entry.getExclusionPatterns().length > 0))
1174 && JavaCore.DISABLED.equals(project.getOption(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, true))) {
1175 return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_EXCLUSION_PATTERNS, project, path);
1177 if (entry.getOutputLocation() != null && JavaCore.DISABLED.equals(project.getOption(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, true))) {
1178 return new JavaModelStatus(IJavaModelStatusConstants.DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS, project, path);
1180 if (path != null && path.isAbsolute() && !path.isEmpty()) {
1181 IPath projectPath= project.getProject().getFullPath();
1182 if (!projectPath.isPrefixOf(path) || JavaModel.getTarget(workspaceRoot, path, true) == null){
1183 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.unboundSourceFolder", entryPathMsg, projectName)); //$NON-NLS-1$
1186 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Util.bind("classpath.illegalSourceFolderPath", entryPathMsg, projectName)); //$NON-NLS-1$
1190 return JavaModelStatus.VERIFIED_OK;