improved PHP parser
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / JavaModelManager.java
index 01d7c40..f860394 100644 (file)
@@ -38,13 +38,17 @@ import net.sourceforge.phpdt.core.IJavaModel;
 import net.sourceforge.phpdt.core.IJavaProject;
 import net.sourceforge.phpdt.core.IPackageFragment;
 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
+import net.sourceforge.phpdt.core.IParent;
+import net.sourceforge.phpdt.core.IProblemRequestor;
 import net.sourceforge.phpdt.core.IWorkingCopy;
-import net.sourceforge.phpdt.core.JavaModelException;
 import net.sourceforge.phpdt.core.JavaCore;
-import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
-import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import net.sourceforge.phpdt.core.JavaModelException;
+import net.sourceforge.phpdt.core.WorkingCopyOwner;
+import net.sourceforge.phpdt.core.compiler.IProblem;
 import net.sourceforge.phpdt.internal.core.builder.PHPBuilder;
 import net.sourceforge.phpdt.internal.core.util.Util;
+import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
@@ -68,23 +72,7 @@ import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Plugin;
 import org.eclipse.core.runtime.Preferences;
 import org.eclipse.core.runtime.Status;
-
-import net.sourceforge.phpdt.internal.core.DefaultWorkingCopyOwner;
-
-import net.sourceforge.phpdt.internal.core.DeltaProcessingState;
-
-import net.sourceforge.phpdt.internal.core.DeltaProcessor;
-
-import net.sourceforge.phpdt.core.IParent;
-import net.sourceforge.phpdt.internal.core.JavaElementInfo;
-
-import net.sourceforge.phpdt.core.IProblemRequestor;
-import net.sourceforge.phpdt.core.WorkingCopyOwner;
-import net.sourceforge.phpdt.core.compiler.IProblem;
-import net.sourceforge.phpdt.internal.core.CompilationUnit;
-import net.sourceforge.phpdt.internal.core.JavaElement;
-import net.sourceforge.phpdt.internal.core.JavaElementDeltaBuilder;
-import net.sourceforge.phpdt.internal.core.JavaModelManager.PerWorkingCopyInfo;
+import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
 
 /**
  * The <code>JavaModelManager</code> manages instances of <code>IJavaModel</code>.
@@ -95,12 +83,11 @@ import net.sourceforge.phpdt.internal.core.JavaModelManager.PerWorkingCopyInfo;
  * the static method <code>JavaModelManager.getJavaModelManager()</code>.
  */
 public class JavaModelManager implements ISaveParticipant {    
-       /**
+       /**
         * Unique handle onto the JavaModel
         */
        final JavaModel javaModel = new JavaModel();
-       
+//     public IndexManager indexManager = new IndexManager();
        /**
         * Classpath variables pool
         */
@@ -108,13 +95,13 @@ public class JavaModelManager implements ISaveParticipant {
        public static HashMap PreviousSessionVariables = new HashMap(5);
        public static HashSet OptionNames = new HashSet(20);
        public final static String CP_VARIABLE_PREFERENCES_PREFIX = PHPeclipsePlugin.PLUGIN_ID+".classpathVariable."; //$NON-NLS-1$
-//     public final static String CP_CONTAINER_PREFERENCES_PREFIX = PHPCore.PLUGIN_ID+".classpathContainer."; //$NON-NLS-1$
+       public final static String CP_CONTAINER_PREFERENCES_PREFIX = PHPeclipsePlugin.PLUGIN_ID+".classpathContainer."; //$NON-NLS-1$
        public final static String CP_ENTRY_IGNORE = "##<cp entry ignore>##"; //$NON-NLS-1$
                
        /**
         * Classpath containers pool
         */
-       public static HashMap Containers = new HashMap(5);
+       public static HashMap containers = new HashMap(5);
        public static HashMap PreviousSessionContainers = new HashMap(5);
 
        /**
@@ -444,8 +431,8 @@ public class JavaModelManager implements ISaveParticipant {
                                if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) continue;
                                IPath rootPath = entry.getPath();
                                if (rootPath.equals(resourcePath)) {
-                                       return project.getPackageFragmentRoot(resource);
-                               } else if (rootPath.isPrefixOf(resourcePath) && !Util.isExcluded(resource, ((ClasspathEntry)entry).fullExclusionPatternChars())) {
+                                       return project.getPackageFragmentRoot(resource);  
+                               } else if (rootPath.isPrefixOf(resourcePath) && !Util.isExcluded(resource, null, ((ClasspathEntry)entry).fullExclusionPatternChars())) {
                                        // given we have a resource child of the root, it cannot be a JAR pkg root
                                        IPackageFragmentRoot root = ((JavaProject) project).getFolderPackageFragmentRoot(rootPath);
                                        if (root == null) return null;
@@ -531,7 +518,7 @@ public class JavaModelManager implements ISaveParticipant {
        /**
         * Used to update the JavaModel for <code>IJavaElementDelta</code>s.
         */
-//     private final ModelUpdater modelUpdater =new ModelUpdater();
+       private final ModelUpdater modelUpdater =new ModelUpdater();
        /**
         * Workaround for bug 15168 circular errors not reported  
         * This is a cache of the projects before any project addition/deletion has started.
@@ -553,24 +540,85 @@ public class JavaModelManager implements ISaveParticipant {
        /**
         * A weak set of the known scopes.
         */
-       protected WeakHashMap scopes = new WeakHashMap();
-
+       protected WeakHashMap searchScopes = new WeakHashMap();
+
+//     public static class PerProjectInfo {
+//             public IProject project;
+//             public Object savedState;
+//             public boolean triedRead;
+//             public IClasspathEntry[] classpath;
+//             public IClasspathEntry[] lastResolvedClasspath;
+//             public Map resolvedPathToRawEntries; // reverse map from resolved path to raw entries
+//             public IPath outputLocation;
+//             public Preferences preferences;
+//             public PerProjectInfo(IProject project) {
+//
+//                     this.triedRead = false;
+//                     this.savedState = null;
+//                     this.project = project;
+//             }
+//     }
+       
        public static class PerProjectInfo {
+               
                public IProject project;
                public Object savedState;
                public boolean triedRead;
-               public IClasspathEntry[] classpath;
-               public IClasspathEntry[] lastResolvedClasspath;
+               public IClasspathEntry[] rawClasspath;
+               public IClasspathEntry[] resolvedClasspath;
                public Map resolvedPathToRawEntries; // reverse map from resolved path to raw entries
                public IPath outputLocation;
                public Preferences preferences;
+               
                public PerProjectInfo(IProject project) {
 
                        this.triedRead = false;
                        this.savedState = null;
                        this.project = project;
                }
+               
+               // updating raw classpath need to flush obsoleted cached information about resolved entries
+               public synchronized void updateClasspathInformation(IClasspathEntry[] newRawClasspath) {
+
+                       this.rawClasspath = newRawClasspath;
+                       this.resolvedClasspath = null;
+                       this.resolvedPathToRawEntries = null;
+               }
+               public String toString() {
+                       StringBuffer buffer = new StringBuffer();
+                       buffer.append("Info for "); //$NON-NLS-1$
+                       buffer.append(this.project.getFullPath());
+                       buffer.append("\nRaw classpath:\n"); //$NON-NLS-1$
+                       if (this.rawClasspath == null) {
+                               buffer.append("  <null>\n"); //$NON-NLS-1$
+                       } else {
+                               for (int i = 0, length = this.rawClasspath.length; i < length; i++) {
+                                       buffer.append("  "); //$NON-NLS-1$
+                                       buffer.append(this.rawClasspath[i]);
+                                       buffer.append('\n');
+                               }
+                       }
+                       buffer.append("Resolved classpath:\n"); //$NON-NLS-1$
+                       IClasspathEntry[] resolvedCP = this.resolvedClasspath;
+                       if (resolvedCP == null) {
+                               buffer.append("  <null>\n"); //$NON-NLS-1$
+                       } else {
+                               for (int i = 0, length = resolvedCP.length; i < length; i++) {
+                                       buffer.append("  "); //$NON-NLS-1$
+                                       buffer.append(resolvedCP[i]);
+                                       buffer.append('\n');
+                               }
+                       }
+                       buffer.append("Output location:\n  "); //$NON-NLS-1$
+                       if (this.outputLocation == null) {
+                               buffer.append("<null>"); //$NON-NLS-1$
+                       } else {
+                               buffer.append(this.outputLocation);
+                       }
+                       return buffer.toString();
+               }
        }
+       
        public static class PerWorkingCopyInfo implements IProblemRequestor {
                int useCount = 0;
                IProblemRequestor problemRequestor;
@@ -991,6 +1039,9 @@ public class JavaModelManager implements ISaveParticipant {
                return this.elementsOutOfSynchWithBuffers;
        }
 
+//     public IndexManager getIndexManager() {
+//             return this.indexManager;
+//     }
        /**
         * Returns the <code>IJavaElement</code> represented by the 
         * <code>String</code> memento.
@@ -1203,6 +1254,7 @@ public class JavaModelManager implements ISaveParticipant {
                IPath workingLocation = project.getWorkingLocation(JavaCore.PLUGIN_ID);
                return workingLocation.append("state.dat").toFile(); //$NON-NLS-1$
        }
+       
        /*
         * Returns the temporary cache for newly opened elements for the current thread.
         * Creates it if not already created.
@@ -1329,8 +1381,8 @@ public class JavaModelManager implements ISaveParticipant {
 //             }
 //             
 //             // load variables and containers from preferences into cache
-//             Preferences preferences = PHPCore.getPlugin().getPluginPreferences();
-//
+//             Preferences preferences = PHPeclipsePlugin.getDefault().getPluginPreferences();
+
 //             // only get variable from preferences not set to their default
 //             String[] propertyNames = preferences.propertyNames();
 //             int variablePrefixLength = CP_VARIABLE_PREFERENCES_PREFIX.length();
@@ -1593,9 +1645,14 @@ public class JavaModelManager implements ISaveParticipant {
                }
        }
        
-//     PROTECTED VOID REMOVEINFO(IJAVAELEMENT ELEMENT) {
-//             THIS.CACHE.REMOVEINFO(ELEMENT);
-//     }
+       /**
+        * Remembers the given scope in a weak set
+        * (so no need to remove it: it will be removed by the garbage collector)
+        */
+//     public void rememberScope(AbstractSearchScope scope) {
+//             // NB: The value has to be null so as to not create a strong reference on the scope
+//             this.searchScopes.put(scope, null); 
+//     }       
        /*
         * Removes all cached info for the given element (including all children)
         * from the cache.
@@ -1700,11 +1757,55 @@ public class JavaModelManager implements ISaveParticipant {
                        System.out.println(Util.bind("build.saveStateComplete", String.valueOf(t))); //$NON-NLS-1$
                }
        }
-
+       private synchronized Map containerClone(IJavaProject project) {
+               Map originalProjectContainers = (Map)this.containers.get(project); 
+               if (originalProjectContainers == null) return null;
+               Map projectContainers = new HashMap(originalProjectContainers.size());
+               projectContainers.putAll(originalProjectContainers);
+               return projectContainers;
+       }
        /**
         * @see ISaveParticipant
         */
        public void saving(ISaveContext context) throws CoreException {
+               
+           // save container values on snapshot/full save
+               Preferences preferences = JavaCore.getPlugin().getPluginPreferences();
+               IJavaProject[] projects = getJavaModel().getJavaProjects();
+               for (int i = 0, length = projects.length; i < length; i++) {
+                   IJavaProject project = projects[i];
+                       // clone while iterating (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59638)
+                       Map projectContainers = containerClone(project);
+                       if (projectContainers == null) continue;
+                       for (Iterator keys = projectContainers.keySet().iterator(); keys.hasNext();) {
+                           IPath containerPath = (IPath) keys.next();
+//                         IClasspathContainer container = (IClasspathContainer) projectContainers.get(containerPath);
+                               String containerKey = CP_CONTAINER_PREFERENCES_PREFIX+project.getElementName() +"|"+containerPath;//$NON-NLS-1$
+                               String containerString = CP_ENTRY_IGNORE;
+//                             try {
+//                                     if (container != null) {
+//                                             containerString = ((JavaProject)project).encodeClasspath(container.getClasspathEntries(), null, false);
+//                                     }
+//                             } catch(JavaModelException e){
+//                                     // could not encode entry: leave it as CP_ENTRY_IGNORE
+//                             }
+                               preferences.setDefault(containerKey, CP_ENTRY_IGNORE); // use this default to get rid of removed ones
+                               preferences.setValue(containerKey, containerString);
+                       }
+               }
+               JavaCore.getPlugin().savePluginPreferences();
+               
+//             if (context.getKind() == ISaveContext.FULL_SAVE) {
+//                     // will need delta since this save (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658)
+//                     context.needDelta();
+//                     
+//                     // clean up indexes on workspace full save
+//                     // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52347)
+//                     IndexManager manager = this.indexManager;
+//                     if (manager != null) {
+//                             manager.cleanUpIndexes();
+//                     }
+//             }
        
                IProject savedProject = context.getProject();
                if (savedProject != null) {
@@ -1731,6 +1832,36 @@ public class JavaModelManager implements ISaveParticipant {
                        throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID, IStatus.ERROR, stats, Util.bind("build.cannotSaveStates"), null)); //$NON-NLS-1$
                }
        }
+       /**
+        * @see ISaveParticipant
+        */
+//     public void saving(ISaveContext context) throws CoreException {
+//     
+//             IProject savedProject = context.getProject();
+//             if (savedProject != null) {
+//                     if (!JavaProject.hasJavaNature(savedProject)) return; // ignore
+//                     PerProjectInfo info = getPerProjectInfo(savedProject, true /* create info */);
+//                     saveState(info, context);
+//                     return;
+//             }
+//
+//             ArrayList vStats= null; // lazy initialized
+//             for (Iterator iter =  perProjectInfo.values().iterator(); iter.hasNext();) {
+//                     try {
+//                             PerProjectInfo info = (PerProjectInfo) iter.next();
+//                             saveState(info, context);
+//                     } catch (CoreException e) {
+//                             if (vStats == null)
+//                                     vStats= new ArrayList();
+//                             vStats.add(e.getStatus());
+//                     }
+//             }
+//             if (vStats != null) {
+//                     IStatus[] stats= new IStatus[vStats.size()];
+//                     vStats.toArray(stats);
+//                     throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID, IStatus.ERROR, stats, Util.bind("build.cannotSaveStates"), null)); //$NON-NLS-1$
+//             }
+//     }
 
        /**
         * Record the order in which to build the java projects (batch build). This order is based
@@ -1838,17 +1969,17 @@ public class JavaModelManager implements ISaveParticipant {
        /**
         * Update Java Model given some delta
         */
-//     public void updateJavaModel(IJavaElementDelta customDelta) {
-//
-//             if (customDelta == null){
-//                     for (int i = 0, length = this.javaModelDeltas.size(); i < length; i++){
-//                             IJavaElementDelta delta = (IJavaElementDelta)this.javaModelDeltas.get(i);
-//                             this.modelUpdater.processJavaDelta(delta);
-//                     }
-//             } else {
-//                     this.modelUpdater.processJavaDelta(customDelta);
-//             }
-//     }
+       public void updateJavaModel(IJavaElementDelta customDelta) {
+
+               if (customDelta == null){
+                       for (int i = 0, length = this.javaModelDeltas.size(); i < length; i++){
+                               IJavaElementDelta delta = (IJavaElementDelta)this.javaModelDeltas.get(i);
+                               this.modelUpdater.processJavaDelta(delta);
+                       }
+               } else {
+                       this.modelUpdater.processJavaDelta(customDelta);
+               }
+       }
 
 
        
@@ -1914,4 +2045,29 @@ public class JavaModelManager implements ISaveParticipant {
                        return result;
                }               
        }
+       
+       /*
+        * A HashSet that contains the IJavaProject whose classpath is being resolved.
+        */
+       private ThreadLocal classpathsBeingResolved = new ThreadLocal();
+       
+       private HashSet getClasspathBeingResolved() {
+           HashSet result = (HashSet) this.classpathsBeingResolved.get();
+           if (result == null) {
+               result = new HashSet();
+               this.classpathsBeingResolved.set(result);
+           }
+           return result;
+       }
+       public boolean isClasspathBeingResolved(IJavaProject project) {
+           return getClasspathBeingResolved().contains(project);
+       }
+       
+       public void setClasspathBeingResolved(IJavaProject project, boolean classpathIsResolved) {
+           if (classpathIsResolved) {
+               getClasspathBeingResolved().add(project);
+           } else {
+               getClasspathBeingResolved().remove(project);
+           }
+       }
 }