3m9 compatible;
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / JavaElement.java
index a55c97a..8cfe6d8 100644 (file)
 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;
@@ -26,12 +29,20 @@ 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.
@@ -60,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 <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
@@ -153,17 +139,13 @@ 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 <code>JavaElement</code> is equivalent to the given
@@ -262,6 +244,12 @@ 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 {
@@ -301,48 +289,33 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement
         * 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
         */
@@ -388,7 +361,7 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement
         * Returns the occurrence count of the handle.
         */
        protected int getOccurrenceCount() {
-               return fOccurrenceCount;
+               return occurrenceCount;
        }
        /*
         * @see IJavaElement
@@ -404,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 <code>ICompilationUnit#getElementAt</code>,
@@ -452,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,
@@ -460,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.
@@ -498,26 +530,60 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement
         *
         * @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() {
@@ -527,23 +593,23 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement
         * 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
         */
@@ -573,7 +639,7 @@ public abstract class JavaElement extends PlatformObject implements IJavaElement
         * 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();