import net.sourceforge.phpdt.core.WorkingCopyOwner;
import net.sourceforge.phpdt.internal.codeassist.ISearchableNameEnvironment;
import net.sourceforge.phpdt.internal.compiler.util.ObjectVector;
+import net.sourceforge.phpdt.internal.core.util.MementoTokenizer;
import net.sourceforge.phpdt.internal.core.util.Util;
import net.sourceforge.phpdt.internal.corext.Assert;
import net.sourceforge.phpeclipse.LoadPathEntry;
public static final IClasspathEntry[] INVALID_CLASSPATH = new IClasspathEntry[0];
private static final String CUSTOM_DEFAULT_OPTION_VALUE = "#\r\n\r#custom-non-empty-default-value#\r\n\r#"; //$NON-NLS-1$
-
+ /*
+ * Value of project's resolved classpath while it is being resolved
+ */
+ private static final IClasspathEntry[] RESOLUTION_IN_PROGRESS = new IClasspathEntry[0];
+
/**
* Returns a canonicalized path from the given external path.
* Note that the return path contains the same number of segments
// }
-
/**
* Internal computation of an expanded classpath. It will eliminate duplicates, and produce copies
* of exported classpath entries to avoid possible side-effects ever after.
*/
private void computeExpandedClasspath(
- JavaProject initialProject,
+ JavaProject initialProject,
boolean ignoreUnresolvedVariable,
boolean generateMarkerOnError,
- HashSet visitedProjects,
- ObjectVector accumulatedEntries) throws JavaModelException {
+ HashSet rootIDs,
+ ObjectVector accumulatedEntries,
+ Map preferredClasspaths,
+ Map preferredOutputs) throws JavaModelException {
- if (visitedProjects.contains(this)){
+ String projectRootId = this.rootID();
+ if (rootIDs.contains(projectRootId)){
return; // break cycles if any
}
- visitedProjects.add(this);
+ rootIDs.add(projectRootId);
- if (generateMarkerOnError && !this.equals(initialProject)){
- generateMarkerOnError = false;
- }
+ IClasspathEntry[] preferredClasspath = preferredClasspaths != null ? (IClasspathEntry[])preferredClasspaths.get(this) : null;
+ IPath preferredOutput = preferredOutputs != null ? (IPath)preferredOutputs.get(this) : null;
IClasspathEntry[] immediateClasspath =
- getResolvedClasspath(ignoreUnresolvedVariable, generateMarkerOnError);
+ preferredClasspath != null
+ ? getResolvedClasspath(preferredClasspath, preferredOutput, ignoreUnresolvedVariable, generateMarkerOnError, null)
+ : getResolvedClasspath(ignoreUnresolvedVariable, generateMarkerOnError, false/*don't returnResolutionInProgress*/);
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
+ boolean isInitialProject = this.equals(initialProject);
for (int i = 0, length = immediateClasspath.length; i < length; i++){
- IClasspathEntry entry = immediateClasspath[i];
-
- boolean isInitialProject = this.equals(initialProject);
+ ClasspathEntry entry = (ClasspathEntry) immediateClasspath[i];
if (isInitialProject || entry.isExported()){
+ String rootID = entry.rootID();
+ if (rootIDs.contains(rootID)) {
+ continue;
+ }
accumulatedEntries.add(entry);
// recurse in project to get all its indirect exports (only consider exported entries from there on)
- if (entry.getEntryKind() == ClasspathEntry.CPE_PROJECT) {
+ if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
IResource member = workspaceRoot.findMember(entry.getPath());
if (member != null && member.getType() == IResource.PROJECT){ // double check if bound to project (23977)
IProject projRsc = (IProject) member;
if (JavaProject.hasJavaNature(projRsc)) {
- JavaProject project = (JavaProject) JavaCore.create(projRsc);
- project.computeExpandedClasspath(
+ JavaProject javaProject = (JavaProject) JavaCore.create(projRsc);
+ javaProject.computeExpandedClasspath(
initialProject,
ignoreUnresolvedVariable,
- generateMarkerOnError,
- visitedProjects,
- accumulatedEntries);
+ false /* no marker when recursing in prereq*/,
+ rootIDs,
+ accumulatedEntries,
+ preferredClasspaths,
+ preferredOutputs);
}
}
+ } else {
+ rootIDs.add(rootID);
}
}
}
}
+ /**
+ * Internal computation of an expanded classpath. It will eliminate duplicates, and produce copies
+ * of exported classpath entries to avoid possible side-effects ever after.
+ */
+// private void computeExpandedClasspath(
+// JavaProject initialProject,
+// boolean ignoreUnresolvedVariable,
+// boolean generateMarkerOnError,
+// HashSet visitedProjects,
+// ObjectVector accumulatedEntries) throws JavaModelException {
+//
+// if (visitedProjects.contains(this)){
+// return; // break cycles if any
+// }
+// visitedProjects.add(this);
+//
+// if (generateMarkerOnError && !this.equals(initialProject)){
+// generateMarkerOnError = false;
+// }
+// IClasspathEntry[] immediateClasspath =
+// getResolvedClasspath(ignoreUnresolvedVariable, generateMarkerOnError);
+//
+// IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
+// for (int i = 0, length = immediateClasspath.length; i < length; i++){
+// IClasspathEntry entry = immediateClasspath[i];
+//
+// boolean isInitialProject = this.equals(initialProject);
+// if (isInitialProject || entry.isExported()){
+//
+// accumulatedEntries.add(entry);
+//
+// // recurse in project to get all its indirect exports (only consider exported entries from there on)
+// if (entry.getEntryKind() == ClasspathEntry.CPE_PROJECT) {
+// IResource member = workspaceRoot.findMember(entry.getPath());
+// if (member != null && member.getType() == IResource.PROJECT){ // double check if bound to project (23977)
+// IProject projRsc = (IProject) member;
+// if (JavaProject.hasJavaNature(projRsc)) {
+// JavaProject project = (JavaProject) JavaCore.create(projRsc);
+// project.computeExpandedClasspath(
+// initialProject,
+// ignoreUnresolvedVariable,
+// generateMarkerOnError,
+// visitedProjects,
+// accumulatedEntries);
+// }
+// }
+// }
+// }
+// }
+// }
/**
* Returns (local/all) the package fragment roots identified by the given project's classpath.
* This is a helper method returning the expanded classpath for the project, as a list of classpath entries,
* where all classpath variable entries have been resolved and substituted with their final target entries.
* All project exports have been appended to project entries.
+ * @param ignoreUnresolvedVariable boolean
+ * @return IClasspathEntry[]
+ * @throws JavaModelException
*/
public IClasspathEntry[] getExpandedClasspath(boolean ignoreUnresolvedVariable) throws JavaModelException {
- return getExpandedClasspath(ignoreUnresolvedVariable, false);
+ return getExpandedClasspath(ignoreUnresolvedVariable, false/*don't create markers*/, null, null);
}
+ /*
+ * @see JavaElement
+ */
+ public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) {
+ switch (token.charAt(0)) {
+ case JEM_COUNT:
+ return getHandleUpdatingCountFromMemento(memento, owner);
+ case JEM_PACKAGEFRAGMENTROOT:
+ String rootPath = IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH;
+ token = null;
+ while (memento.hasMoreTokens()) {
+ token = memento.nextToken();
+ char firstChar = token.charAt(0);
+ if (firstChar != JEM_PACKAGEFRAGMENT && firstChar != JEM_COUNT) {
+ rootPath += token;
+ } else {
+ break;
+ }
+ }
+ JavaElement root = (JavaElement)getPackageFragmentRoot(new Path(rootPath));
+ if (token != null && token.charAt(0) == JEM_PACKAGEFRAGMENT) {
+ return root.getHandleFromMemento(token, memento, owner);
+ } else {
+ return root.getHandleFromMemento(memento, owner);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the <code>char</code> that marks the start of this handles
+ * contribution to a memento.
+ */
+ protected char getHandleMementoDelimiter() {
+
+ return JEM_JAVAPROJECT;
+ }
+
/**
* Internal variant which can create marker on project for invalid entries,
* it will also perform classpath expansion in presence of project prerequisites
* exporting their entries.
+ * @param ignoreUnresolvedVariable boolean
+ * @param generateMarkerOnError boolean
+ * @param preferredClasspaths Map
+ * @param preferredOutputs Map
+ * @return IClasspathEntry[]
+ * @throws JavaModelException
*/
public IClasspathEntry[] getExpandedClasspath(
boolean ignoreUnresolvedVariable,
- boolean generateMarkerOnError) throws JavaModelException {
+ boolean generateMarkerOnError,
+ Map preferredClasspaths,
+ Map preferredOutputs) throws JavaModelException {
ObjectVector accumulatedEntries = new ObjectVector();
- computeExpandedClasspath(this, ignoreUnresolvedVariable, generateMarkerOnError, new HashSet(5), accumulatedEntries);
+ computeExpandedClasspath(this, ignoreUnresolvedVariable, generateMarkerOnError, new HashSet(5), accumulatedEntries, preferredClasspaths, preferredOutputs);
IClasspathEntry[] expandedPath = new IClasspathEntry[accumulatedEntries.size()];
accumulatedEntries.copyInto(expandedPath);
return expandedPath;
}
-
- /**
- * Returns the <code>char</code> that marks the start of this handles
- * contribution to a memento.
- */
- protected char getHandleMementoDelimiter() {
-
- return JEM_JAVAPROJECT;
- }
+// /**
+// * Internal variant which can create marker on project for invalid entries,
+// * it will also perform classpath expansion in presence of project prerequisites
+// * exporting their entries.
+// */
+// public IClasspathEntry[] getExpandedClasspath(
+// boolean ignoreUnresolvedVariable,
+// boolean generateMarkerOnError) throws JavaModelException {
+//
+// ObjectVector accumulatedEntries = new ObjectVector();
+// computeExpandedClasspath(this, ignoreUnresolvedVariable, generateMarkerOnError, new HashSet(5), accumulatedEntries);
+//
+// IClasspathEntry[] expandedPath = new IClasspathEntry[accumulatedEntries.size()];
+// accumulatedEntries.copyInto(expandedPath);
+//
+// return expandedPath;
+// }
/**
* Find the specific Java command amongst the build spec of a given description
// }
/**
- * @see org.eclipse.jdt.core.IJavaProject#getOption(String, boolean)
+ * @see net.sourceforge.phpdt.core.IJavaProject#getOption(String, boolean)
*/
public String getOption(String optionName, boolean inheritJavaCoreOptions) {
}
/**
- * @see org.eclipse.jdt.core.IJavaProject#getOptions(boolean)
+ * @see net.sourceforge.phpdt.core.IJavaProject#getOptions(boolean)
*/
public Map getOptions(boolean inheritJavaCoreOptions) {
/**
* @see IJavaProject
*/
+// public IPath getOutputLocation() throws JavaModelException {
+//
+// JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project);
+// IPath outputLocation = perProjectInfo.outputLocation;
+// if (outputLocation != null) return outputLocation;
+//
+// // force to read classpath - will position output location as well
+// this.getRawClasspath();
+// outputLocation = perProjectInfo.outputLocation;
+// if (outputLocation == null) {
+// return defaultOutputLocation();
+// }
+// return outputLocation;
+// }
+ /**
+ * @see IJavaProject
+ */
public IPath getOutputLocation() throws JavaModelException {
+ // Do not create marker but log problems while getting output location
+ return this.getOutputLocation(false, true);
+ }
+
+ /**
+ * @param createMarkers boolean
+ * @param logProblems boolean
+ * @return IPath
+ * @throws JavaModelException
+ */
+ public IPath getOutputLocation(boolean createMarkers, boolean logProblems) throws JavaModelException {
- JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project);
+ JavaModelManager.PerProjectInfo perProjectInfo = getPerProjectInfo();
IPath outputLocation = perProjectInfo.outputLocation;
if (outputLocation != null) return outputLocation;
// force to read classpath - will position output location as well
- this.getRawClasspath();
+ this.getRawClasspath(createMarkers, logProblems);
outputLocation = perProjectInfo.outputLocation;
if (outputLocation == null) {
return defaultOutputLocation();
}
return outputLocation;
}
-
/**
* @return A handle to the package fragment root identified by the given path.
* This method is handle-only and the element may or may not exist. Returns
return this.getProject().getFullPath();
}
+ public JavaModelManager.PerProjectInfo getPerProjectInfo() throws JavaModelException {
+ return JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(this.project);
+ }
+
/**
* @see IJavaProject
*/
/**
* @see IJavaProject
*/
+// public IClasspathEntry[] getRawClasspath() throws JavaModelException {
+//
+// JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project);
+// IClasspathEntry[] classpath = perProjectInfo.classpath;
+// if (classpath != null) return classpath;
+// classpath = this.readClasspathFile(false/*don't create markers*/, true/*log problems*/);
+//
+// // extract out the output location
+// IPath outputLocation = null;
+// if (classpath != null && classpath.length > 0) {
+// IClasspathEntry entry = classpath[classpath.length - 1];
+// if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
+// outputLocation = entry.getPath();
+// IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
+// System.arraycopy(classpath, 0, copy, 0, copy.length);
+// classpath = copy;
+// }
+// }
+// if (classpath == null) {
+// return defaultClasspath();
+// }
+// /* Disable validate: classpath can contain CP variables and container that need to be resolved
+// if (classpath != INVALID_CLASSPATH
+// && !JavaConventions.validateClasspath(this, classpath, outputLocation).isOK()) {
+// classpath = INVALID_CLASSPATH;
+// }
+// */
+// perProjectInfo.classpath = classpath;
+// perProjectInfo.outputLocation = outputLocation;
+// return classpath;
+// }
+ /**
+ * @see IJavaProject
+ */
public IClasspathEntry[] getRawClasspath() throws JavaModelException {
+ // Do not create marker but log problems while getting raw classpath
+ return getRawClasspath(false, true);
+ }
- JavaModelManager.PerProjectInfo perProjectInfo = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project);
- IClasspathEntry[] classpath = perProjectInfo.classpath;
- if (classpath != null) return classpath;
- classpath = this.readClasspathFile(false/*don't create markers*/, true/*log problems*/);
-
+ /*
+ * Internal variant allowing to parameterize problem creation/logging
+ */
+ public IClasspathEntry[] getRawClasspath(boolean createMarkers, boolean logProblems) throws JavaModelException {
+
+ JavaModelManager.PerProjectInfo perProjectInfo = null;
+ IClasspathEntry[] classpath;
+ if (createMarkers) {
+ this.flushClasspathProblemMarkers(false/*cycle*/, true/*format*/);
+ classpath = this.readClasspathFile(createMarkers, logProblems);
+ } else {
+ perProjectInfo = getPerProjectInfo();
+ classpath = perProjectInfo.rawClasspath;
+ if (classpath != null) return classpath;
+ classpath = this.readClasspathFile(createMarkers, logProblems);
+ }
// extract out the output location
IPath outputLocation = null;
if (classpath != null && classpath.length > 0) {
classpath = INVALID_CLASSPATH;
}
*/
- perProjectInfo.classpath = classpath;
- perProjectInfo.outputLocation = outputLocation;
+ if (!createMarkers) {
+ perProjectInfo.rawClasspath = classpath;
+ perProjectInfo.outputLocation = outputLocation;
+ }
return classpath;
}
-
+
/**
* @see IJavaProject#getRequiredProjectNames
*/
boolean ignoreUnresolvedEntry,
boolean generateMarkerOnError)
throws JavaModelException {
+ return
+ getResolvedClasspath(
+ ignoreUnresolvedEntry,
+ generateMarkerOnError,
+ true // returnResolutionInProgress
+ );
+// JavaModelManager manager = JavaModelManager.getJavaModelManager();
+// JavaModelManager.PerProjectInfo perProjectInfo = manager.getPerProjectInfoCheckExistence(project);
+//
+// // reuse cache if not needing to refresh markers or checking bound variables
+// if (ignoreUnresolvedEntry && !generateMarkerOnError && perProjectInfo != null){
+// // resolved path is cached on its info
+// IClasspathEntry[] infoPath = perProjectInfo.lastResolvedClasspath;
+// if (infoPath != null) return infoPath;
+// }
+// Map reverseMap = perProjectInfo == null ? null : new HashMap(5);
+// IClasspathEntry[] resolvedPath = getResolvedClasspath(
+// getRawClasspath(),
+// generateMarkerOnError ? getOutputLocation() : null,
+// ignoreUnresolvedEntry,
+// generateMarkerOnError,
+// reverseMap);
+//
+// if (perProjectInfo != null){
+// if (perProjectInfo.classpath == null // .classpath file could not be read
+// && generateMarkerOnError
+// && JavaProject.hasJavaNature(project)) {
+// this.createClasspathProblemMarker(new JavaModelStatus(
+// IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
+// Util.bind("classpath.cannotReadClasspathFile", this.getElementName()))); //$NON-NLS-1$
+// }
+//
+// perProjectInfo.lastResolvedClasspath = resolvedPath;
+// perProjectInfo.resolvedPathToRawEntries = reverseMap;
+// }
+// return resolvedPath;
+ }
+ /*
+ * Internal variant which can create marker on project for invalid entries
+ * and caches the resolved classpath on perProjectInfo.
+ * If requested, return a special classpath (RESOLUTION_IN_PROGRESS) if the classpath is being resolved.
+ */
+ public IClasspathEntry[] getResolvedClasspath(
+ boolean ignoreUnresolvedEntry,
+ boolean generateMarkerOnError,
+ boolean returnResolutionInProgress)
+ throws JavaModelException {
- JavaModelManager manager = JavaModelManager.getJavaModelManager();
- JavaModelManager.PerProjectInfo perProjectInfo = manager.getPerProjectInfoCheckExistence(project);
-
- // reuse cache if not needing to refresh markers or checking bound variables
- if (ignoreUnresolvedEntry && !generateMarkerOnError && perProjectInfo != null){
- // resolved path is cached on its info
- IClasspathEntry[] infoPath = perProjectInfo.lastResolvedClasspath;
- if (infoPath != null) return infoPath;
+ JavaModelManager manager = JavaModelManager.getJavaModelManager();
+ JavaModelManager.PerProjectInfo perProjectInfo = null;
+ if (ignoreUnresolvedEntry && !generateMarkerOnError) {
+ perProjectInfo = getPerProjectInfo();
+ if (perProjectInfo != null) {
+ // resolved path is cached on its info
+ IClasspathEntry[] infoPath = perProjectInfo.resolvedClasspath;
+ if (infoPath != null) {
+ return infoPath;
+ } else if (returnResolutionInProgress && manager.isClasspathBeingResolved(this)) {
+ if (JavaModelManager.CP_RESOLVE_VERBOSE) {
+ Util.verbose(
+ "CPResolution: reentering raw classpath resolution, will use empty classpath instead" + //$NON-NLS-1$
+ " project: " + getElementName() + '\n' + //$NON-NLS-1$
+ " invocation stack trace:"); //$NON-NLS-1$
+ new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
+ }
+ return RESOLUTION_IN_PROGRESS;
+ }
+ }
}
Map reverseMap = perProjectInfo == null ? null : new HashMap(5);
- IClasspathEntry[] resolvedPath = getResolvedClasspath(
- getRawClasspath(),
- generateMarkerOnError ? getOutputLocation() : null,
- ignoreUnresolvedEntry,
- generateMarkerOnError,
- reverseMap);
+ IClasspathEntry[] resolvedPath = null;
+ boolean nullOldResolvedCP = perProjectInfo != null && perProjectInfo.resolvedClasspath == null;
+ try {
+ // protect against misbehaving clients (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=61040)
+ if (nullOldResolvedCP) manager.setClasspathBeingResolved(this, true);
+ resolvedPath = getResolvedClasspath(
+ getRawClasspath(generateMarkerOnError, !generateMarkerOnError),
+ generateMarkerOnError ? getOutputLocation() : null,
+ ignoreUnresolvedEntry,
+ generateMarkerOnError,
+ reverseMap);
+ } finally {
+ if (nullOldResolvedCP) perProjectInfo.resolvedClasspath = null;
+ }
if (perProjectInfo != null){
- if (perProjectInfo.classpath == null // .classpath file could not be read
+ if (perProjectInfo.rawClasspath == null // .classpath file could not be read
&& generateMarkerOnError
- && JavaProject.hasJavaNature(project)) {
+ && JavaProject.hasJavaNature(this.project)) {
+ // flush .classpath format markers (bug 39877), but only when file cannot be read (bug 42366)
+ this.flushClasspathProblemMarkers(false, true);
this.createClasspathProblemMarker(new JavaModelStatus(
IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
Util.bind("classpath.cannotReadClasspathFile", this.getElementName()))); //$NON-NLS-1$
- }
+ }
- perProjectInfo.lastResolvedClasspath = resolvedPath;
+ perProjectInfo.resolvedClasspath = resolvedPath;
perProjectInfo.resolvedPathToRawEntries = reverseMap;
+ manager.setClasspathBeingResolved(this, false);
}
return resolvedPath;
}
-
/**
* Internal variant which can process any arbitrary classpath
*/
public ISearchableNameEnvironment getSearchableNameEnvironment()
throws JavaModelException {
- JavaProjectElementInfo info = getJavaProjectElementInfo();
- if (info.getSearchableEnvironment() == null) {
- info.setSearchableEnvironment(new SearchableEnvironment(this));
- }
- return info.getSearchableEnvironment();
+// JavaProjectElementInfo info = getJavaProjectElementInfo();
+// if (info.getSearchableEnvironment() == null) {
+// info.setSearchableEnvironment(new SearchableEnvironment(this));
+// }
+// return info.getSearchableEnvironment();
+ return null;
}
/**
for (int i = 0; i < classpath.length; i++) {
IClasspathEntry entry = classpath[i];
if (entry.getPath().isPrefixOf(path)
- && !Util.isExcluded(path, ((ClasspathEntry)entry).fullExclusionPatternChars())) {
+ && !Util.isExcluded(path, null,((ClasspathEntry)entry).fullExclusionPatternChars(),true)) {
return true;
}
}
}
/**
- * @see org.eclipse.jdt.core.IJavaProject#setOptions(Map)
+ * @see net.sourceforge.phpdt.core.IJavaProject#setOptions(Map)
*/
public void setOptions(Map newOptions) {
*
* @exception NotPresentException if this project does not exist.
*/
- protected void setRawClasspath0(IClasspathEntry[] rawEntries)
- throws JavaModelException {
-
- JavaModelManager.PerProjectInfo info = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project);
-
- synchronized (info) {
- if (rawEntries != null) {
- info.classpath = rawEntries;
- }
-
- // clear cache of resolved classpath
- info.lastResolvedClasspath = null;
- info.resolvedPathToRawEntries = null;
- }
- }
+// protected void setRawClasspath0(IClasspathEntry[] rawEntries)
+// throws JavaModelException {
+//
+// JavaModelManager.PerProjectInfo info = JavaModelManager.getJavaModelManager().getPerProjectInfoCheckExistence(project);
+//
+// synchronized (info) {
+// if (rawEntries != null) {
+// info.classpath = rawEntries;
+// }
+//
+// // clear cache of resolved classpath
+// info.lastResolvedClasspath = null;
+// info.resolvedPathToRawEntries = null;
+// }
+// }
/**
* Record a shared persistent property onto a project.