X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElement.java index 590b8db..8cfe6d8 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElement.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElement.java @@ -10,20 +10,39 @@ *******************************************************************************/ 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.ISourceReference; import net.sourceforge.phpdt.core.JavaModelException; +import net.sourceforge.phpdt.core.jdom.IDOMCompilationUnit; +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. @@ -52,83 +71,58 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement * 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 null if this * element does not have a parent. */ - protected IJavaElement fParent; + protected IJavaElement parent; /** * This element's name, or an empty String 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; -// } -// } -// } + public void close() throws JavaModelException { + 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 @@ -145,102 +139,98 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement 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 JavaElement is equivalent to the given * IDOMNode. */ -// protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException { -// return false; -// } + protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException { + return false; + } /** * @see IJavaElement */ -// public boolean exists() { -// -// try { -// getElementInfo(); -// return true; -// } catch (JavaModelException e) { -// } -// return false; -// } + public boolean exists() { + + try { + getElementInfo(); + return true; + } catch (JavaModelException e) { + } + return false; + } /** * Returns the IDOMNode that corresponds to this JavaElement * or null if there is no corresponding node. */ -// public IDOMNode findNode(IDOMCompilationUnit dom) { -// int type = getElementType(); -// if (type == IJavaElement.COMPILATION_UNIT || -// type == IJavaElement.FIELD || -// type == IJavaElement.IMPORT_DECLARATION || -// type == IJavaElement.INITIALIZER || -// type == IJavaElement.METHOD || -// type == IJavaElement.PACKAGE_DECLARATION || -// type == IJavaElement.TYPE) { -// ArrayList path = new ArrayList(); -// IJavaElement element = this; -// while (element != null && element.getElementType() != IJavaElement.COMPILATION_UNIT) { -// if (element.getElementType() != IJavaElement.IMPORT_CONTAINER) { -// // the DOM does not have import containers, so skip them -// path.add(0, element); -// } -// element = element.getParent(); -// } -// if (path.size() == 0) { -// try { -// if (equalsDOMNode(dom)) { -// return dom; -// } else { -// return null; -// } -// } catch(JavaModelException e) { -// return null; -// } -// } -// return ((JavaElement) path.get(0)).followPath(path, 0, dom.getFirstChild()); -// } else { -// return null; -// } -// } -// /** -// */ -// protected IDOMNode followPath(ArrayList path, int position, IDOMNode node) { -// -// try { -// if (equalsDOMNode(node)) { -// if (position == (path.size() - 1)) { -// return node; -// } else { -// if (node.getFirstChild() != null) { -// position++; -// return ((JavaElement)path.get(position)).followPath(path, position, node.getFirstChild()); -// } else { -// return null; -// } -// } -// } else if (node.getNextNode() != null) { -// return followPath(path, position, node.getNextNode()); -// } else { -// return null; -// } -// } catch (JavaModelException e) { -// return null; -// } -// -// } + public IDOMNode findNode(IDOMCompilationUnit dom) { + int type = getElementType(); + if (type == IJavaElement.COMPILATION_UNIT || + type == IJavaElement.FIELD || + type == IJavaElement.IMPORT_DECLARATION || + type == IJavaElement.INITIALIZER || + type == IJavaElement.METHOD || + type == IJavaElement.PACKAGE_DECLARATION || + type == IJavaElement.TYPE) { + ArrayList path = new ArrayList(); + IJavaElement element = this; + while (element != null && element.getElementType() != IJavaElement.COMPILATION_UNIT) { + if (element.getElementType() != IJavaElement.IMPORT_CONTAINER) { + // the DOM does not have import containers, so skip them + path.add(0, element); + } + element = element.getParent(); + } + if (path.size() == 0) { + try { + if (equalsDOMNode(dom)) { + return dom; + } else { + return null; + } + } catch(JavaModelException e) { + return null; + } + } + return ((JavaElement) path.get(0)).followPath(path, 0, dom.getFirstChild()); + } else { + return null; + } + } + /** + */ + protected IDOMNode followPath(ArrayList path, int position, IDOMNode node) { + + try { + if (equalsDOMNode(node)) { + if (position == (path.size() - 1)) { + return node; + } else { + if (node.getFirstChild() != null) { + position++; + return ((JavaElement)path.get(position)).followPath(path, position, node.getFirstChild()); + } else { + return null; + } + } + } else if (node.getNextNode() != null) { + return followPath(path, position, node.getNextNode()); + } else { + return null; + } + } catch (JavaModelException e) { + return null; + } + + } /** * @see IJavaElement */ @@ -254,88 +244,78 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement 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 { -// return ((JavaElementInfo)getElementInfo()).getChildren(); -// } + public IJavaElement[] getChildren() throws JavaModelException { + return ((JavaElementInfo)getElementInfo()).getChildren(); + } /** * Returns a collection of (immediate) children of this node of the * specified type. * * @param type - one of constants defined by IJavaLanguageElementTypes */ -// public ArrayList getChildrenOfType(int type) throws JavaModelException { -// IJavaElement[] children = getChildren(); -// int size = children.length; -// ArrayList list = new ArrayList(size); -// for (int i = 0; i < size; ++i) { -// JavaElement elt = (JavaElement)children[i]; -// if (elt.getElementType() == type) { -// list.add(elt); -// } -// } -// return list; -// } + public ArrayList getChildrenOfType(int type) throws JavaModelException { + IJavaElement[] children = getChildren(); + int size = children.length; + ArrayList list = new ArrayList(size); + for (int i = 0; i < size; ++i) { + JavaElement elt = (JavaElement)children[i]; + if (elt.getElementType() == type) { + list.add(elt); + } + } + return list; + } /** * @see IMember */ // public IClassFile getClassFile() { // return null; // } -// /** -// * @see IMember -// */ -// public ICompilationUnit getCompilationUnit() { -// return null; -// } + /** + * @see IMember + */ + public ICompilationUnit getCompilationUnit() { + return null; + } /** * 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; -// } -// } + public Object getElementInfo() throws JavaModelException { + 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 */ @@ -366,22 +346,22 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement } while ((current = current.getParent()) != null); return null; } -// -// /** -// * @see IJavaElement -// */ -// public IJavaProject getJavaProject() { -// IJavaElement current = this; -// do { -// if (current instanceof IJavaProject) return (IJavaProject) current; -// } while ((current = current.getParent()) != null); -// return null; -// } + + /** + * @see IJavaElement + */ + public IJavaProject getJavaProject() { + IJavaElement current = this; + do { + if (current instanceof IJavaProject) return (IJavaProject) current; + } while ((current = current.getParent()) != null); + return null; + } /** * Returns the occurrence count of the handle. */ protected int getOccurrenceCount() { - return fOccurrenceCount; + return occurrenceCount; } /* * @see IJavaElement @@ -397,15 +377,28 @@ public abstract class JavaElement extends PlatformObject implements 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 ICompilationUnit#getElementAt, @@ -413,30 +406,30 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement * known to be within this element's source range already, and if no finer * grained element is found at the position, this element is returned. */ -// protected IJavaElement getSourceElementAt(int position) throws JavaModelException { -// if (this instanceof ISourceReference) { -// IJavaElement[] children = getChildren(); -// int i; -// for (i = 0; i < children.length; i++) { -// IJavaElement aChild = children[i]; -// if (aChild instanceof SourceRefElement) { -// SourceRefElement child = (SourceRefElement) children[i]; -// ISourceRange range = child.getSourceRange(); -// if (position < range.getOffset() + range.getLength() && position >= range.getOffset()) { -// if (child instanceof IParent) { -// return child.getSourceElementAt(position); -// } else { -// return child; -// } -// } -// } -// } -// } else { -// // should not happen -// Assert.isTrue(false); -// } -// return this; -// } + protected IJavaElement getSourceElementAt(int position) throws JavaModelException { + if (this instanceof ISourceReference) { + IJavaElement[] children = getChildren(); + int i; + for (i = 0; i < children.length; i++) { + IJavaElement aChild = children[i]; + if (aChild instanceof SourceRefElement) { + SourceRefElement child = (SourceRefElement) children[i]; + ISourceRange range = child.getSourceRange(); + if (position < range.getOffset() + range.getLength() && position >= range.getOffset()) { + if (child instanceof IParent) { + return child.getSourceElementAt(position); + } else { + return child; + } + } + } + } + } else { + // should not happen + Assert.isTrue(false); + } + return this; + } /** * Returns the SourceMapper facility for this element, or * null if this element does not have a @@ -445,6 +438,51 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement // 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, @@ -453,9 +491,10 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement * 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. @@ -477,20 +516,20 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement /** * @see IJavaElement */ -// public boolean isStructureKnown() throws JavaModelException { -// return ((JavaElementInfo)getElementInfo()).isStructureKnown(); -// } -// /** -// * Creates and returns and not present exception for this element. -// */ -// protected JavaModelException newNotPresentException() { -// return new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this)); -// } -// /** -// * Opens this element and all parents that are not already open. -// * -// * @exception JavaModelException this element is not present or accessible -// */ + public boolean isStructureKnown() throws JavaModelException { + return ((JavaElementInfo)getElementInfo()).isStructureKnown(); + } + /** + * Creates and returns and not present exception for this element. + */ + protected JavaModelException newNotPresentException() { + return new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this)); + } + /** + * Opens this element and all parents that are not already open. + * + * @exception JavaModelException this element is not present or accessible + */ // protected void openHierarchy() throws JavaModelException { // if (this instanceof IOpenable) { // ((Openable) this).openWhenClosed(null); @@ -511,6 +550,40 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement */ protected void opening(Object info) { } + /* + * Opens an Openable that is known to be closed (no check for isOpen()). + * 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() { @@ -537,36 +610,36 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement // * Returns a copy of this element rooted at the given project. // */ // public abstract IJavaElement rootedAt(IJavaProject project); -// /** -// * Runs a Java Model Operation -// */ -// public static void runOperation(JavaModelOperation operation, IProgressMonitor monitor) throws JavaModelException { -// try { -// if (operation.isReadOnly() || ResourcesPlugin.getWorkspace().isTreeLocked()) { -// operation.run(monitor); -// } else { -// // use IWorkspace.run(...) to ensure that a build will be done in autobuild mode -// ResourcesPlugin.getWorkspace().run(operation, monitor); -// } -// } catch (CoreException ce) { -// if (ce instanceof JavaModelException) { -// throw (JavaModelException)ce; -// } else { -// if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) { -// Throwable e= ce.getStatus().getException(); -// if (e instanceof JavaModelException) { -// throw (JavaModelException) e; -// } -// } -// throw new JavaModelException(ce); -// } -// } -// } + /** + * Runs a Java Model Operation + */ + public static void runOperation(JavaModelOperation operation, IProgressMonitor monitor) throws JavaModelException { + try { + if (operation.isReadOnly() || ResourcesPlugin.getWorkspace().isTreeLocked()) { + operation.run(monitor); + } else { + // use IWorkspace.run(...) to ensure that a build will be done in autobuild mode + ResourcesPlugin.getWorkspace().run(operation, monitor); + } + } catch (CoreException ce) { + if (ce instanceof JavaModelException) { + throw (JavaModelException)ce; + } else { + if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) { + Throwable e= ce.getStatus().getException(); + if (e instanceof JavaModelException) { + throw (JavaModelException) e; + } + } + throw new JavaModelException(ce); + } + } + } /** * 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();