package net.sourceforge.phpdt.internal.core;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
import net.sourceforge.phpdt.core.ICompilationUnit;
import net.sourceforge.phpdt.core.IJavaElement;
import net.sourceforge.phpdt.core.IJavaModel;
import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
import net.sourceforge.phpdt.core.IJavaProject;
+import net.sourceforge.phpdt.core.IMember;
import net.sourceforge.phpdt.core.IOpenable;
import net.sourceforge.phpdt.core.IParent;
import net.sourceforge.phpdt.core.ISourceRange;
import net.sourceforge.phpdt.core.jdom.IDOMNode;
import net.sourceforge.phpdt.internal.corext.Assert;
+import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import net.sourceforge.phpdt.internal.core.JavaElementInfo;
+
+import net.sourceforge.phpdt.internal.core.JavaModelManager;
+import net.sourceforge.phpdt.internal.core.util.Util;
/**
* Root of Java element handle hierarchy.
* them. The occurrence count starts at 1 (thus the first
* occurrence is occurrence 1, not occurrence 0).
*/
- protected int fOccurrenceCount = 1;
+ protected int occurrenceCount = 1;
/**
* This element's type - one of the constants defined
* in IJavaLanguageElementTypes.
*/
- protected int fLEType = 0;
+ //protected int fLEType = 0;
/**
* This element's parent, or <code>null</code> if this
* element does not have a parent.
*/
- protected IJavaElement fParent;
+ protected IJavaElement parent;
/**
* This element's name, or an empty <code>String</code> if this
* element does not have a name.
*/
- protected String fName;
+ protected String name;
protected static final Object NO_INFO = new Object();
/**
- * Constructs a handle for a java element of the specified type, with
+ * Constructs a handle for a java element with
* the given parent element and name.
*
- * @param type - one of the constants defined in IJavaLanguageElement
+ * @param parent The parent of java element
+ * @param name The name of java element
*
* @exception IllegalArgumentException if the type is not one of the valid
* Java element type constants
*
*/
- protected JavaElement(int type, IJavaElement parent, String name) throws IllegalArgumentException {
- if (type < JAVA_MODEL || type > IMPORT_DECLARATION) {
- throw new IllegalArgumentException(Util.bind("element.invalidType")); //$NON-NLS-1$
- }
- fLEType= type;
- fParent= parent;
- fName= name;
+ protected JavaElement(JavaElement parent, String name) throws IllegalArgumentException {
+ this.parent = parent;
+ this.name = name;
}
/**
* @see IOpenable
*/
public void close() throws JavaModelException {
- Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
- if (info != null) {
- boolean wasVerbose = false;
- try {
- if (JavaModelManager.VERBOSE) {
- System.out.println("CLOSING Element ("+ Thread.currentThread()+"): " + this.toStringWithAncestors()); //$NON-NLS-1$//$NON-NLS-2$
- wasVerbose = true;
- JavaModelManager.VERBOSE = false;
- }
- if (this instanceof IParent) {
- IJavaElement[] children = ((JavaElementInfo) info).getChildren();
- for (int i = 0, size = children.length; i < size; ++i) {
- JavaElement child = (JavaElement) children[i];
- child.close();
- }
- }
- closing(info);
- JavaModelManager.getJavaModelManager().removeInfo(this);
- if (wasVerbose) {
- System.out.println("-> Package cache size = " + JavaModelManager.getJavaModelManager().cache.pkgSize()); //$NON-NLS-1$
- System.out.println("-> Openable cache filling ratio = " + JavaModelManager.getJavaModelManager().cache.openableFillingRatio() + "%"); //$NON-NLS-1$//$NON-NLS-2$
- }
- } finally {
- JavaModelManager.VERBOSE = wasVerbose;
- }
- }
+ JavaModelManager.getJavaModelManager().removeInfoAndChildren(this);
}
/**
* This element is being closed. Do any necessary cleanup.
*/
- protected void closing(Object info) throws JavaModelException {
- }
+ protected abstract void closing(Object info) throws JavaModelException;
+ /*
+ * Returns a new element info for this element.
+ */
+ protected abstract Object createElementInfo();
/**
* Returns true if this handle represents the same Java element
* as the given handle. By default, two handles represent the same
if (this == o) return true;
// Java model parent is null
- if (fParent == null) return super.equals(o);
+ if (this.parent == null) return super.equals(o);
- if (o instanceof JavaElement) {
- JavaElement other = (JavaElement) o;
- if (fLEType != other.fLEType) return false;
-
- return fName.equals(other.fName) &&
- fParent.equals(other.fParent) &&
- fOccurrenceCount == other.fOccurrenceCount;
- }
- return false;
+ // assume instanceof check is done in subclass
+ JavaElement other = (JavaElement) o;
+ return this.occurrenceCount == other.occurrenceCount &&
+ this.name.equals(other.name) &&
+ this.parent.equals(other.parent);
}
/**
* Returns true if this <code>JavaElement</code> is equivalent to the given
return null;
}
/**
+ * Generates the element infos for this element, its ancestors (if they are not opened) and its children (if it is an Openable).
+ * Puts the newly created element info in the given map.
+ */
+ protected abstract void generateInfos(Object info, HashMap newElements, IProgressMonitor pm) throws JavaModelException;
+
+ /**
* @see IParent
*/
public IJavaElement[] getChildren() throws JavaModelException {
* Returns the info for this handle.
* If this element is not already open, it and all of its parents are opened.
* Does not return null.
- * NOTE: BinaryType infos are NJOT rooted under JavaElementInfo.
+ * NOTE: BinaryType infos are NOT rooted under JavaElementInfo.
* @exception JavaModelException if the element is not present or not accessible
*/
public Object getElementInfo() throws JavaModelException {
- // workaround to ensure parent project resolved classpath is available to avoid triggering initializers
- // while the JavaModelManager lock is acquired (can cause deadlocks in clients)
- IJavaProject project = getJavaProject();
- if (project != null && !project.isOpen()) {
- // TODO: need to revisit, since deadlock could still occur if perProjectInfo is removed concurrent before entering the lock
- try {
- project.getResolvedClasspath(true); // trigger all possible container/variable initialization outside the model lock
- } catch (JavaModelException e) {
- // project is not accessible or is not a java project
- }
- }
-
- // element info creation is done inside a lock on the JavaModelManager
- JavaModelManager manager;
- synchronized(manager = JavaModelManager.getJavaModelManager()){
- Object info = manager.getInfo(this);
- if (info == null) {
- openHierarchy();
- info= manager.getInfo(this);
- if (info == null) {
- throw newNotPresentException();
- }
- }
- return info;
- }
+ return getElementInfo(null);
}
/**
- * @see IAdaptable
+ * Returns the info for this handle.
+ * If this element is not already open, it and all of its parents are opened.
+ * Does not return null.
+ * NOTE: BinaryType infos are NOT rooted under JavaElementInfo.
+ * @exception JavaModelException if the element is not present or not accessible
*/
- public String getElementName() {
- return fName;
+ public Object getElementInfo(IProgressMonitor monitor) throws JavaModelException {
+
+ JavaModelManager manager = JavaModelManager.getJavaModelManager();
+ Object info = manager.getInfo(this);
+ if (info != null) return info;
+ return openWhenClosed(createElementInfo(), monitor);
}
/**
- * @see IJavaElement
+ * @see IAdaptable
*/
- public int getElementType() {
- return fLEType;
+ public String getElementName() {
+ return name;
}
+
/**
* @see IJavaElement
*/
* Returns the occurrence count of the handle.
*/
protected int getOccurrenceCount() {
- return fOccurrenceCount;
+ return occurrenceCount;
}
/*
* @see IJavaElement
*/
public IOpenable getOpenableParent() {
- return (IOpenable)fParent;
+ return (IOpenable)parent;
}
/**
* @see IJavaElement
*/
public IJavaElement getParent() {
- return fParent;
+ return parent;
}
+ /*
+ * @see IJavaElement#getPrimaryElement()
+ */
+ public IJavaElement getPrimaryElement() {
+ return getPrimaryElement(true);
+ }
+ /*
+ * Returns the primary element. If checkOwner, and the cu owner is primary,
+ * return this element.
+ */
+ public IJavaElement getPrimaryElement(boolean checkOwner) {
+ return this;
+ }
/**
* Returns the element that is located at the given source position
* in this element. This is a helper method for <code>ICompilationUnit#getElementAt</code>,
// public SourceMapper getSourceMapper() {
// return ((JavaElement)getParent()).getSourceMapper();
// }
+ /* (non-Javadoc)
+ * @see org.eclipse.jdt.core.IJavaElement#getSchedulingRule()
+ */
+ public ISchedulingRule getSchedulingRule() {
+ IResource resource = getResource();
+ if (resource == null) {
+ class NoResourceSchedulingRule implements ISchedulingRule {
+ public IPath path;
+ public NoResourceSchedulingRule(IPath path) {
+ this.path = path;
+ }
+ public boolean contains(ISchedulingRule rule) {
+ if (rule instanceof NoResourceSchedulingRule) {
+ return this.path.isPrefixOf(((NoResourceSchedulingRule)rule).path);
+ } else {
+ return false;
+ }
+ }
+ public boolean isConflicting(ISchedulingRule rule) {
+ if (rule instanceof NoResourceSchedulingRule) {
+ IPath otherPath = ((NoResourceSchedulingRule)rule).path;
+ return this.path.isPrefixOf(otherPath) || otherPath.isPrefixOf(this.path);
+ } else {
+ return false;
+ }
+ }
+ }
+ return new NoResourceSchedulingRule(getPath());
+ } else {
+ return resource;
+ }
+ }
+ /**
+ * @see IParent
+ */
+ public boolean hasChildren() throws JavaModelException {
+ // if I am not open, return true to avoid opening (case of a Java project, a compilation unit or a class file).
+ // also see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52474
+ Object elementInfo = JavaModelManager.getJavaModelManager().getInfo(this);
+ if (elementInfo instanceof JavaElementInfo) {
+ return ((JavaElementInfo)elementInfo).getChildren().length > 0;
+ } else {
+ return true;
+ }
+ }
/**
* Returns the hash code for this Java element. By default,
* override this method.
*/
public int hashCode() {
- if (fParent == null) return super.hashCode();
- return Util.combineHashCodes(fName.hashCode(), fParent.hashCode());
+ if (this.parent == null) return super.hashCode();
+ return Util.combineHashCodes(this.name.hashCode(), this.parent.hashCode());
}
+
/**
* Returns true if this element is an ancestor of the given element,
* otherwise false.
*
* @exception JavaModelException this element is not present or accessible
*/
- protected void openHierarchy() throws JavaModelException {
- if (this instanceof IOpenable) {
- ((Openable) this).openWhenClosed(null);
- } else {
- Openable openableParent = (Openable)getOpenableParent();
- if (openableParent != null) {
- JavaElementInfo openableParentInfo = (JavaElementInfo) JavaModelManager.getJavaModelManager().getInfo((IJavaElement) openableParent);
- if (openableParentInfo == null) {
- openableParent.openWhenClosed(null);
- } else {
- throw newNotPresentException();
- }
- }
- }
- }
+// protected void openHierarchy() throws JavaModelException {
+// if (this instanceof IOpenable) {
+// ((Openable) this).openWhenClosed(null);
+// } else {
+// Openable openableParent = (Openable)getOpenableParent();
+// if (openableParent != null) {
+// JavaElementInfo openableParentInfo = (JavaElementInfo) JavaModelManager.getJavaModelManager().getInfo((IJavaElement) openableParent);
+// if (openableParentInfo == null) {
+// openableParent.openWhenClosed(null);
+// } else {
+// throw newNotPresentException();
+// }
+// }
+// }
+// }
/**
* This element has just been opened. Do any necessary setup.
*/
protected void opening(Object info) {
}
+ /*
+ * Opens an <code>Openable</code> that is known to be closed (no check for <code>isOpen()</code>).
+ * Returns the created element info.
+ */
+ protected Object openWhenClosed(Object info, IProgressMonitor monitor) throws JavaModelException {
+ JavaModelManager manager = JavaModelManager.getJavaModelManager();
+ boolean hadTemporaryCache = manager.hasTemporaryCache();
+ try {
+ HashMap newElements = manager.getTemporaryCache();
+ generateInfos(info, newElements, monitor);
+ if (info == null) {
+ info = newElements.get(this);
+ }
+ if (info == null) { // a source ref element could not be opened
+ // close any buffer that was opened for the openable parent
+ Iterator iterator = newElements.keySet().iterator();
+ while (iterator.hasNext()) {
+ IJavaElement element = (IJavaElement)iterator.next();
+ if (element instanceof Openable) {
+ ((Openable)element).closeBuffer();
+ }
+ }
+ throw newNotPresentException();
+ }
+ if (!hadTemporaryCache) {
+ manager.putInfos(this, newElements);
+ }
+ } finally {
+ if (!hadTemporaryCache) {
+ manager.resetTemporaryCache();
+ }
+ }
+ return info;
+ }
/**
*/
public String readableName() {
* Removes all cached info from the Java Model, including all children,
* but does not close this element.
*/
- protected void removeInfo() {
- Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
- if (info != null) {
- if (this instanceof IParent) {
- IJavaElement[] children = ((JavaElementInfo)info).getChildren();
- for (int i = 0, size = children.length; i < size; ++i) {
- JavaElement child = (JavaElement) children[i];
- child.removeInfo();
- }
- }
- JavaModelManager.getJavaModelManager().removeInfo(this);
- }
- }
- /**
- * Returns a copy of this element rooted at the given project.
- */
- public abstract IJavaElement rootedAt(IJavaProject project);
+// protected void removeInfo() {
+// Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
+// if (info != null) {
+// if (this instanceof IParent) {
+// IJavaElement[] children = ((JavaElementInfo)info).getChildren();
+// for (int i = 0, size = children.length; i < size; ++i) {
+// JavaElement child = (JavaElement) children[i];
+// child.removeInfo();
+// }
+// }
+// JavaModelManager.getJavaModelManager().removeInfo(this);
+// }
+// }
+// /**
+// * Returns a copy of this element rooted at the given project.
+// */
+// public abstract IJavaElement rootedAt(IJavaProject project);
/**
* Runs a Java Model Operation
*/
* Sets the occurrence count of the handle.
*/
protected void setOccurrenceCount(int count) {
- fOccurrenceCount = count;
+ occurrenceCount = count;
}
protected String tabString(int tab) {
StringBuffer buffer = new StringBuffer();