added index manager to the new builder;
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / builder / PHPBuilder.java
index ee59f34..575bb44 100644 (file)
@@ -9,7 +9,6 @@
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
 package net.sourceforge.phpdt.internal.core.builder;
-
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
@@ -18,7 +17,6 @@ import java.util.Date;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
-
 import net.sourceforge.phpdt.core.IClasspathEntry;
 import net.sourceforge.phpdt.core.IJavaModelMarker;
 import net.sourceforge.phpdt.core.JavaModelException;
@@ -28,130 +26,136 @@ import net.sourceforge.phpdt.internal.core.JavaModelManager;
 import net.sourceforge.phpdt.internal.core.JavaProject;
 import net.sourceforge.phpdt.internal.core.Util;
 import net.sourceforge.phpdt.internal.core.util.SimpleLookupTable;
+import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
 import net.sourceforge.phpeclipse.PHPCore;
-
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import net.sourceforge.phpeclipse.builder.IdentifierIndexManager;
+import net.sourceforge.phpeclipse.phpeditor.PHPParserAction;
+import net.sourceforge.phpeclipse.resourcesview.PHPProject;
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IResourceChangeEvent;
 import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceVisitor;
 import org.eclipse.core.resources.IWorkspaceRoot;
 import org.eclipse.core.resources.IncrementalProjectBuilder;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
-
+import org.eclipse.core.runtime.OperationCanceledException;
 public class PHPBuilder extends IncrementalProjectBuilder {
-
   IProject currentProject;
   JavaProject javaProject;
   IWorkspaceRoot workspaceRoot;
   NameEnvironment nameEnvironment;
-  SimpleLookupTable binaryLocationsPerProject; // maps a project to its binary resources (output folders, class folders, zip/jar files)
+  SimpleLookupTable binaryLocationsPerProject; // maps a project to its binary
+  // resources (output folders,
+  // class folders, zip/jar files)
   State lastState;
   BuildNotifier notifier;
   char[][] extraResourceFileFilters;
   String[] extraResourceFolderFilters;
-
   public static final String CLASS_EXTENSION = "class"; //$NON-NLS-1$
-
   public static boolean DEBUG = true;
-
   /**
-   * A list of project names that have been built.
-   * This list is used to reset the JavaModel.existingExternalFiles cache when a build cycle begins
-   * so that deleted external jars are discovered.
+   * A list of project names that have been built. This list is used to reset
+   * the JavaModel.existingExternalFiles cache when a build cycle begins so
+   * that deleted external jars are discovered.
    */
   static ArrayList builtProjects = null;
-
   public static IMarker[] getProblemsFor(IResource resource) {
     try {
       if (resource != null && resource.exists())
-        return resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
+        return resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
+            false, IResource.DEPTH_INFINITE);
     } catch (CoreException e) {
     } // assume there are no problems
     return new IMarker[0];
   }
-
   public static IMarker[] getTasksFor(IResource resource) {
     try {
       if (resource != null && resource.exists())
-        return resource.findMarkers(IJavaModelMarker.TASK_MARKER, false, IResource.DEPTH_INFINITE);
+        return resource.findMarkers(IJavaModelMarker.TASK_MARKER, false,
+            IResource.DEPTH_INFINITE);
     } catch (CoreException e) {
     } // assume there are no tasks
     return new IMarker[0];
   }
-
   public static void finishedBuilding(IResourceChangeEvent event) {
     BuildNotifier.resetProblemCounters();
   }
-
   public static void removeProblemsFor(IResource resource) {
     try {
       if (resource != null && resource.exists())
-        resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
+        resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
+            false, IResource.DEPTH_INFINITE);
     } catch (CoreException e) {
     } // assume there were no problems
   }
-
   public static void removeTasksFor(IResource resource) {
     try {
       if (resource != null && resource.exists())
-        resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false, IResource.DEPTH_INFINITE);
+        resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false,
+            IResource.DEPTH_INFINITE);
     } catch (CoreException e) {
     } // assume there were no problems
   }
-
   public static void removeProblemsAndTasksFor(IResource resource) {
     try {
       if (resource != null && resource.exists()) {
-        resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
-        resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false, IResource.DEPTH_INFINITE);
+        resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
+            false, IResource.DEPTH_INFINITE);
+        resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false,
+            IResource.DEPTH_INFINITE);
       }
     } catch (CoreException e) {
     } // assume there were no problems
   }
-
-  public static State readState(IProject project, DataInputStream in) throws IOException {
+  public static State readState(IProject project, DataInputStream in)
+      throws IOException {
     return State.read(project, in);
   }
-
-  public static void writeState(Object state, DataOutputStream out) throws IOException {
+  public static void writeState(Object state, DataOutputStream out)
+      throws IOException {
     ((State) state).write(out);
   }
-
   public PHPBuilder() {
   }
-
-  protected IProject[] build(int kind, Map ignored, IProgressMonitor monitor) throws CoreException {
+  protected IProject[] build(int kind, Map ignored, IProgressMonitor monitor)
+      throws CoreException {
     this.currentProject = getProject();
     if (currentProject == null || !currentProject.isAccessible())
       return new IProject[0];
-
     if (DEBUG)
       System.out.println("\nStarting build of " + currentProject.getName() //$NON-NLS-1$
-      +" @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
+          + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
     this.notifier = new BuildNotifier(monitor, currentProject);
     notifier.begin();
     boolean ok = false;
     try {
       notifier.checkCancel();
       initializeBuilder();
-
       if (isWorthBuilding()) {
         if (kind == FULL_BUILD) {
+          processFullPHPIndex(currentProject, monitor);
           buildAll();
         } else {
           if ((this.lastState = getLastState(currentProject)) == null) {
             if (DEBUG)
-              System.out.println("Performing full build since last saved state was not found"); //$NON-NLS-1$
-            buildAll();
-          } else if (hasClasspathChanged()) {
-            // if the output location changes, do not delete the binary files from old location
-            // the user may be trying something
+              System.out
+                  .println("Performing full build since last saved state was not found"); //$NON-NLS-1$
+            processFullPHPIndex(currentProject, monitor);
             buildAll();
+//          } else if (hasClasspathChanged()) {
+//            // if the output location changes, do not delete the binary files
+//            // from old location
+//            // the user may be trying something
+//            buildAll();
           } else if (nameEnvironment.sourceLocations.length > 0) {
-            // if there is no source to compile & no classpath changes then we are done
+            // if there is no source to compile & no classpath changes then we
+            // are done
             SimpleLookupTable deltas = findDeltas();
             if (deltas == null)
               buildAll();
@@ -160,11 +164,14 @@ public class PHPBuilder extends IncrementalProjectBuilder {
             else if (DEBUG)
               System.out.println("Nothing to build since deltas were empty"); //$NON-NLS-1$
           } else {
-            if (hasStructuralDelta()) { // double check that a jar file didn't get replaced in a binary project
+            if (hasStructuralDelta()) { // double check that a jar file didn't
+              // get replaced in a binary project
+              processFullPHPIndex(currentProject, monitor);
               buildAll();
             } else {
               if (DEBUG)
-                System.out.println("Nothing to build since there are no source folders and no deltas"); //$NON-NLS-1$
+                System.out
+                    .println("Nothing to build since there are no source folders and no deltas"); //$NON-NLS-1$
               lastState.tagAsNoopBuild();
             }
           }
@@ -173,32 +180,47 @@ public class PHPBuilder extends IncrementalProjectBuilder {
       }
     } catch (CoreException e) {
       Util.log(e, "JavaBuilder handling CoreException"); //$NON-NLS-1$
-      IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
-      marker.setAttribute(IMarker.MESSAGE, Util.bind("build.inconsistentProject", e.getLocalizedMessage())); //$NON-NLS-1$
+      IMarker marker = currentProject
+          .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
+      marker.setAttribute(IMarker.MESSAGE, Util.bind(
+          "build.inconsistentProject", e.getLocalizedMessage())); //$NON-NLS-1$
       marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
     } catch (ImageBuilderInternalException e) {
-      Util.log(e.getThrowable(), "JavaBuilder handling ImageBuilderInternalException"); //$NON-NLS-1$
-      IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
-      marker.setAttribute(IMarker.MESSAGE, Util.bind("build.inconsistentProject", e.coreException.getLocalizedMessage())); //$NON-NLS-1$
+      Util.log(e.getThrowable(),
+          "JavaBuilder handling ImageBuilderInternalException"); //$NON-NLS-1$
+      IMarker marker = currentProject
+          .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
+      marker.setAttribute(IMarker.MESSAGE, Util.bind(
+          "build.inconsistentProject", e.coreException.getLocalizedMessage())); //$NON-NLS-1$
       marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
     } catch (MissingClassFileException e) {
-      // do not log this exception since its thrown to handle aborted compiles because of missing class files
+      // do not log this exception since its thrown to handle aborted compiles
+      // because of missing class files
       if (DEBUG)
-        System.out.println(Util.bind("build.incompleteClassPath", e.missingClassFile)); //$NON-NLS-1$
-      IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
-      marker.setAttribute(IMarker.MESSAGE, Util.bind("build.incompleteClassPath", e.missingClassFile)); //$NON-NLS-1$
+        System.out.println(Util.bind("build.incompleteClassPath",
+            e.missingClassFile)); //$NON-NLS-1$
+      IMarker marker = currentProject
+          .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
+      marker.setAttribute(IMarker.MESSAGE, Util.bind(
+          "build.incompleteClassPath", e.missingClassFile)); //$NON-NLS-1$
       marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
     } catch (MissingSourceFileException e) {
-      // do not log this exception since its thrown to handle aborted compiles because of missing source files
+      // do not log this exception since its thrown to handle aborted compiles
+      // because of missing source files
       if (DEBUG)
-        System.out.println(Util.bind("build.missingSourceFile", e.missingSourceFile)); //$NON-NLS-1$
-      removeProblemsAndTasksFor(currentProject); // make this the only problem for this project
-      IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
-      marker.setAttribute(IMarker.MESSAGE, Util.bind("build.missingSourceFile", e.missingSourceFile)); //$NON-NLS-1$
+        System.out.println(Util.bind("build.missingSourceFile",
+            e.missingSourceFile)); //$NON-NLS-1$
+      removeProblemsAndTasksFor(currentProject); // make this the only problem
+      // for this project
+      IMarker marker = currentProject
+          .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
+      marker.setAttribute(IMarker.MESSAGE, Util.bind("build.missingSourceFile",
+          e.missingSourceFile)); //$NON-NLS-1$
       marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
     } finally {
       if (!ok)
-        // If the build failed, clear the previously built state, forcing a full build next time.
+        // If the build failed, clear the previously built state, forcing a
+        // full build next time.
         clearLastState();
       notifier.done();
       cleanup();
@@ -206,10 +228,52 @@ public class PHPBuilder extends IncrementalProjectBuilder {
     IProject[] requiredProjects = getRequiredProjects(true);
     if (DEBUG)
       System.out.println("Finished build of " + currentProject.getName() //$NON-NLS-1$
-      +" @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
+          + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
     return requiredProjects;
   }
-
+  /**
+   * Performs a <code>FULL_BUILD</code> by visiting all nodes in the resource
+   * tree under the specified project.
+   * 
+   * @param iProject
+   */
+  private void processFullPHPIndex(final IProject iProject,
+      final IProgressMonitor monitor) {
+    final IdentifierIndexManager indexManager = PHPeclipsePlugin.getDefault()
+        .getIndexManager(iProject);
+    // Create resource visitor logic
+    IResourceVisitor myVisitor = new IResourceVisitor() {
+      public boolean visit(IResource resource) throws CoreException {
+        if (resource.getType() == IResource.FILE) {
+          if (monitor.isCanceled()) {
+            throw new OperationCanceledException();
+          }
+          if ((resource.getFileExtension() != null)
+              && PHPFileUtil.isPHPFile((IFile) resource)) {
+            monitor.worked(1);
+            monitor.subTask("Parsing: " + resource.getFullPath());
+            // update indexfile for the project:
+//            PHPProject nature = (PHPProject) iProject
+//                .getNature(PHPeclipsePlugin.PHP_NATURE_ID);
+            indexManager.addFile((IFile) resource);
+          }
+        }
+        return true;
+      }
+    };
+    // Process the project using the visitor just created
+    try {
+      //      if (iProject.hasNature(PHPeclipsePlugin.PHP_NATURE_ID)) {
+      //        thePHPProject = new PHPProject();
+      //        thePHPProject.setProject(iProject);
+      //      }
+      indexManager.initialize();
+      iProject.accept(myVisitor);
+      indexManager.writeFile();
+    } catch (CoreException e) {
+      e.printStackTrace();
+    }
+  }
   private void buildAll() {
     notifier.checkCancel();
     notifier.subTask(Util.bind("build.preparingBuild")); //$NON-NLS-1$
@@ -220,20 +284,21 @@ public class PHPBuilder extends IncrementalProjectBuilder {
     imageBuilder.build();
     recordNewState(imageBuilder.newState);
   }
-
   private void buildDeltas(SimpleLookupTable deltas) {
     notifier.checkCancel();
     notifier.subTask(Util.bind("build.preparingBuild")); //$NON-NLS-1$
     if (DEBUG && lastState != null)
       System.out.println("Clearing last state : " + lastState); //$NON-NLS-1$
-    clearLastState(); // clear the previously built state so if the build fails, a full build will occur next time
+    clearLastState(); // clear the previously built state so if the build
+    // fails, a full build will occur next time
     IncrementalImageBuilder imageBuilder = new IncrementalImageBuilder(this);
     if (imageBuilder.build(deltas))
       recordNewState(imageBuilder.newState);
-    else
+    else {
+      processFullPHPIndex(currentProject, notifier.monitor);
       buildAll();
+    }
   }
-
   private void cleanup() {
     this.nameEnvironment = null;
     this.binaryLocationsPerProject = null;
@@ -242,11 +307,10 @@ public class PHPBuilder extends IncrementalProjectBuilder {
     this.extraResourceFileFilters = null;
     this.extraResourceFolderFilters = null;
   }
-
   private void clearLastState() {
-    JavaModelManager.getJavaModelManager().setLastBuiltState(currentProject, null);
+    JavaModelManager.getJavaModelManager().setLastBuiltState(currentProject,
+        null);
   }
-
   boolean filterExtraResource(IResource resource) {
     if (extraResourceFileFilters != null) {
       char[] name = resource.getName().toCharArray();
@@ -268,7 +332,6 @@ public class PHPBuilder extends IncrementalProjectBuilder {
     }
     return false;
   }
-
   private SimpleLookupTable findDeltas() {
     notifier.subTask(Util.bind("build.readingDelta", currentProject.getName())); //$NON-NLS-1$
     IResourceDelta delta = getDelta(currentProject);
@@ -276,7 +339,8 @@ public class PHPBuilder extends IncrementalProjectBuilder {
     if (delta != null) {
       if (delta.getKind() != IResourceDelta.NO_CHANGE) {
         if (DEBUG)
-          System.out.println("Found source delta for: " + currentProject.getName()); //$NON-NLS-1$
+          System.out.println("Found source delta for: "
+              + currentProject.getName()); //$NON-NLS-1$
         deltas.put(currentProject, delta);
       }
     } else {
@@ -285,28 +349,31 @@ public class PHPBuilder extends IncrementalProjectBuilder {
       notifier.subTask(""); //$NON-NLS-1$
       return null;
     }
-
     Object[] keyTable = binaryLocationsPerProject.keyTable;
     Object[] valueTable = binaryLocationsPerProject.valueTable;
     nextProject : for (int i = 0, l = keyTable.length; i < l; i++) {
       IProject p = (IProject) keyTable[i];
       if (p != null && p != currentProject) {
         State s = getLastState(p);
-        if (!lastState.wasStructurallyChanged(p, s)) { // see if we can skip its delta
+        if (!lastState.wasStructurallyChanged(p, s)) { // see if we can skip
+          // its delta
           if (s.wasNoopBuild())
-            continue nextProject; // project has no source folders and can be skipped
-          //                           ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[]) valueTable[i];
+            continue nextProject; // project has no source folders and can be
+          // skipped
+          //                           ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[])
+          // valueTable[i];
           boolean canSkip = true;
           //                           for (int j = 0, m = classFoldersAndJars.length; j < m; j++) {
           //                                   if (classFoldersAndJars[j].isOutputFolder())
-          //                                           classFoldersAndJars[j] = null; // can ignore output folder since project was not structurally changed
+          //                                           classFoldersAndJars[j] = null; // can ignore output folder since
+          // project was not structurally changed
           //                                   else
           //                                           canSkip = false;
           //                           }
           if (canSkip)
-            continue nextProject; // project has no structural changes in its output folders
+            continue nextProject; // project has no structural changes in its
+          // output folders
         }
-
         notifier.subTask(Util.bind("build.readingDelta", p.getName())); //$NON-NLS-1$
         delta = getDelta(p);
         if (delta != null) {
@@ -326,21 +393,21 @@ public class PHPBuilder extends IncrementalProjectBuilder {
     notifier.subTask(""); //$NON-NLS-1$
     return deltas;
   }
-
   private State getLastState(IProject project) {
-    return (State) JavaModelManager.getJavaModelManager().getLastBuiltState(project, notifier.monitor);
+    return (State) JavaModelManager.getJavaModelManager().getLastBuiltState(
+        project, notifier.monitor);
   }
-
-  /* Return the list of projects for which it requires a resource delta. This builder's project
-  * is implicitly included and need not be specified. Builders must re-specify the list 
-  * of interesting projects every time they are run as this is not carried forward
-  * beyond the next build. Missing projects should be specified but will be ignored until
-  * they are added to the workspace.
-  */
+  /*
+   * Return the list of projects for which it requires a resource delta. This
+   * builder's project is implicitly included and need not be specified.
+   * Builders must re-specify the list of interesting projects every time they
+   * are run as this is not carried forward beyond the next build. Missing
+   * projects should be specified but will be ignored until they are added to
+   * the workspace.
+   */
   private IProject[] getRequiredProjects(boolean includeBinaryPrerequisites) {
     if (javaProject == null || workspaceRoot == null)
       return new IProject[0];
-
     ArrayList projects = new ArrayList();
     try {
       IClasspathEntry[] entries = javaProject.getExpandedClasspath(true);
@@ -350,11 +417,14 @@ public class PHPBuilder extends IncrementalProjectBuilder {
         IProject p = null;
         switch (entry.getEntryKind()) {
           case IClasspathEntry.CPE_PROJECT :
-            p = workspaceRoot.getProject(path.lastSegment()); // missing projects are considered too
+            p = workspaceRoot.getProject(path.lastSegment()); // missing
+            // projects are
+            // considered too
             break;
           case IClasspathEntry.CPE_LIBRARY :
             if (includeBinaryPrerequisites && path.segmentCount() > 1) {
-              // some binary resources on the class path can come from projects that are not included in the project references
+              // some binary resources on the class path can come from projects
+              // that are not included in the project references
               IResource resource = workspaceRoot.findMember(path.segment(0));
               if (resource instanceof IProject)
                 p = (IProject) resource;
@@ -370,76 +440,89 @@ public class PHPBuilder extends IncrementalProjectBuilder {
     projects.toArray(result);
     return result;
   }
-
-  private boolean hasClasspathChanged() {
-    ClasspathMultiDirectory[] newSourceLocations = nameEnvironment.sourceLocations;
-    ClasspathMultiDirectory[] oldSourceLocations = lastState.sourceLocations;
-    int newLength = newSourceLocations.length;
-    int oldLength = oldSourceLocations.length;
-    int n, o;
-    for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
-      if (newSourceLocations[n].equals(oldSourceLocations[o]))
-        continue; // checks source & output folders
-      try {
-        if (newSourceLocations[n].sourceFolder.members().length == 0) { // added new empty source folder
-          o--;
-          continue;
-        }
-      } catch (CoreException ignore) {
-      }
-      if (DEBUG)
-        System.out.println(newSourceLocations[n] + " != " + oldSourceLocations[o]); //$NON-NLS-1$
-      return true;
-    }
-    while (n < newLength) {
-      try {
-        if (newSourceLocations[n].sourceFolder.members().length == 0) { // added new empty source folder
-          n++;
-          continue;
-        }
-      } catch (CoreException ignore) {
-      }
-      if (DEBUG)
-        System.out.println("Added non-empty source folder"); //$NON-NLS-1$
-      return true;
-    }
-    if (o < oldLength) {
-      if (DEBUG)
-        System.out.println("Removed source folder"); //$NON-NLS-1$
-      return true;
-    }
-
-    // ClasspathLocation[] newBinaryLocations = nameEnvironment.binaryLocations;
-    // ClasspathLocation[] oldBinaryLocations = lastState.binaryLocations;
-    // newLength = newBinaryLocations.length;
-    // oldLength = oldBinaryLocations.length;
-    // for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
-    //         if (newBinaryLocations[n].equals(oldBinaryLocations[o])) continue;
-    //         if (DEBUG)
-    //                 System.out.println(newBinaryLocations[n] + " != " + oldBinaryLocations[o]); //$NON-NLS-1$
-    //         return true;
-    // }
-    // if (n < newLength || o < oldLength) {
-    //         if (DEBUG)
-    //                 System.out.println("Number of binary folders/jar files has changed"); //$NON-NLS-1$
-    //         return true;
-    // }
-    return false;
-  }
-
+//  private boolean hasClasspathChanged() {
+//    ClasspathMultiDirectory[] newSourceLocations = nameEnvironment.sourceLocations;
+//    ClasspathMultiDirectory[] oldSourceLocations = lastState.sourceLocations;
+//    int newLength = newSourceLocations.length;
+//    int oldLength = oldSourceLocations.length;
+//    int n, o;
+//    for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
+//      if (newSourceLocations[n].equals(oldSourceLocations[o]))
+//        continue; // checks source & output folders
+//      try {
+//        if (newSourceLocations[n].sourceFolder.members().length == 0) { // added
+//          // new
+//          // empty
+//          // source
+//          // folder
+//          o--;
+//          continue;
+//        }
+//      } catch (CoreException ignore) {
+//      }
+//      if (DEBUG)
+//        System.out.println(newSourceLocations[n] + " != "
+//            + oldSourceLocations[o]); //$NON-NLS-1$
+//      return true;
+//    }
+//    while (n < newLength) {
+//      try {
+//        if (newSourceLocations[n].sourceFolder.members().length == 0) { // added
+//          // new
+//          // empty
+//          // source
+//          // folder
+//          n++;
+//          continue;
+//        }
+//      } catch (CoreException ignore) {
+//      }
+//      if (DEBUG)
+//        System.out.println("Added non-empty source folder"); //$NON-NLS-1$
+//      return true;
+//    }
+//    if (o < oldLength) {
+//      if (DEBUG)
+//        System.out.println("Removed source folder"); //$NON-NLS-1$
+//      return true;
+//    }
+//    //       ClasspathLocation[] newBinaryLocations =
+//    // nameEnvironment.binaryLocations;
+//    //       ClasspathLocation[] oldBinaryLocations = lastState.binaryLocations;
+//    //       newLength = newBinaryLocations.length;
+//    //       oldLength = oldBinaryLocations.length;
+//    //       for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
+//    //               if (newBinaryLocations[n].equals(oldBinaryLocations[o])) continue;
+//    //               if (DEBUG)
+//    //                       System.out.println(newBinaryLocations[n] + " != " +
+//    // oldBinaryLocations[o]); //$NON-NLS-1$
+//    //               return true;
+//    //       }
+//    //       if (n < newLength || o < oldLength) {
+//    //               if (DEBUG)
+//    //                       System.out.println("Number of binary folders/jar files has changed");
+//    // //$NON-NLS-1$
+//    //               return true;
+//    //       }
+//    return false;
+//  }
   private boolean hasStructuralDelta() {
-    // handle case when currentProject has only .class file folders and/or jar files... no source/output folders
+    // handle case when currentProject has only .class file folders and/or jar
+    // files... no source/output folders
     IResourceDelta delta = getDelta(currentProject);
     if (delta != null && delta.getKind() != IResourceDelta.NO_CHANGE) {
-      //               ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[]) binaryLocationsPerProject.get(currentProject);
+      //               ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[])
+      // binaryLocationsPerProject.get(currentProject);
       //               if (classFoldersAndJars != null) {
       //                       for (int i = 0, l = classFoldersAndJars.length; i < l; i++) {
-      //                               ClasspathLocation classFolderOrJar = classFoldersAndJars[i]; // either a .class file folder or a zip/jar file
+      //                               ClasspathLocation classFolderOrJar = classFoldersAndJars[i]; // either
+      // a .class file folder or a zip/jar file
       //                               if (classFolderOrJar != null) {
       //                                       IPath p = classFolderOrJar.getProjectRelativePath();
       //                                       if (p != null) {
       //                                               IResourceDelta binaryDelta = delta.findMember(p);
-      //                                               if (binaryDelta != null && binaryDelta.getKind() != IResourceDelta.NO_CHANGE)
+      //                                               if (binaryDelta != null && binaryDelta.getKind() !=
+      // IResourceDelta.NO_CHANGE)
       //                                                       return true;
       //                                       }
       //                               }
@@ -448,24 +531,25 @@ public class PHPBuilder extends IncrementalProjectBuilder {
     }
     return false;
   }
-
   private void initializeBuilder() throws CoreException {
     this.javaProject = (JavaProject) PHPCore.create(currentProject);
     this.workspaceRoot = currentProject.getWorkspace().getRoot();
-
-    // Flush the existing external files cache if this is the beginning of a build cycle
+    // Flush the existing external files cache if this is the beginning of a
+    // build cycle
     String projectName = currentProject.getName();
     if (builtProjects == null || builtProjects.contains(projectName)) {
       JavaModel.flushExternalFileCache();
       builtProjects = new ArrayList();
     }
     builtProjects.add(projectName);
-
     this.binaryLocationsPerProject = new SimpleLookupTable(3);
-    this.nameEnvironment = new NameEnvironment(workspaceRoot, javaProject, binaryLocationsPerProject);
-
-    String filterSequence = javaProject.getOption(PHPCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, true);
-    char[][] filters = filterSequence != null && filterSequence.length() > 0 ? CharOperation.splitAndTrimOn(',', filterSequence.toCharArray()) : null;
+    this.nameEnvironment = new NameEnvironment(workspaceRoot, javaProject,
+        binaryLocationsPerProject);
+    String filterSequence = javaProject.getOption(
+        PHPCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, true);
+    char[][] filters = filterSequence != null && filterSequence.length() > 0
+        ? CharOperation.splitAndTrimOn(',', filterSequence.toCharArray())
+        : null;
     if (filters == null) {
       this.extraResourceFileFilters = null;
       this.extraResourceFolderFilters = null;
@@ -487,112 +571,126 @@ public class PHPBuilder extends IncrementalProjectBuilder {
         if (f.length == 0)
           continue;
         if (f[f.length - 1] == '/')
-          extraResourceFolderFilters[--folderCount] = new String(CharOperation.subarray(f, 0, f.length - 1));
+          extraResourceFolderFilters[--folderCount] = new String(CharOperation
+              .subarray(f, 0, f.length - 1));
         else
           extraResourceFileFilters[--fileCount] = f;
       }
     }
   }
-
-  private boolean isClasspathBroken(IClasspathEntry[] classpath, IProject p) throws CoreException {
-    if (classpath == JavaProject.INVALID_CLASSPATH) // the .classpath file could not be read
+  private boolean isClasspathBroken(IClasspathEntry[] classpath, IProject p)
+      throws CoreException {
+    if (classpath == JavaProject.INVALID_CLASSPATH) // the .classpath file
+      // could not be read
       return true;
-
-    IMarker[] markers = p.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
+    IMarker[] markers = p.findMarkers(
+        IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
     for (int i = 0, l = markers.length; i < l; i++)
       if (((Integer) markers[i].getAttribute(IMarker.SEVERITY)).intValue() == IMarker.SEVERITY_ERROR)
         return true;
     return false;
   }
-
   private boolean isWorthBuilding() throws CoreException {
-    boolean abortBuilds = PHPCore.ABORT.equals(javaProject.getOption(PHPCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, true));
+    boolean abortBuilds = PHPCore.ABORT.equals(javaProject.getOption(
+        PHPCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, true));
     if (!abortBuilds)
       return true;
-
     // Abort build only if there are classpath errors
-//    if (isClasspathBroken(javaProject.getRawClasspath(), currentProject)) {
-//      if (DEBUG)
-//        System.out.println("Aborted build because project has classpath errors (incomplete or involved in cycle)"); //$NON-NLS-1$
-//
-//      JavaModelManager.getJavaModelManager().deltaProcessor.addForRefresh(javaProject);
-//
-//      removeProblemsAndTasksFor(currentProject); // remove all compilation problems
-//
-//      IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
-//      marker.setAttribute(IMarker.MESSAGE, Util.bind("build.abortDueToClasspathProblems")); //$NON-NLS-1$
-//      marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
-//      return false;
-//    }
-
-    // make sure all prereq projects have valid build states... only when aborting builds since projects in cycles do not have build states
+    //    if (isClasspathBroken(javaProject.getRawClasspath(), currentProject)) {
+    //      if (DEBUG)
+    //        System.out.println("Aborted build because project has classpath errors
+    // (incomplete or involved in cycle)"); //$NON-NLS-1$
+    //
+    //      JavaModelManager.getJavaModelManager().deltaProcessor.addForRefresh(javaProject);
+    //
+    //      removeProblemsAndTasksFor(currentProject); // remove all compilation
+    // problems
+    //
+    //      IMarker marker =
+    // currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
+    //      marker.setAttribute(IMarker.MESSAGE,
+    // Util.bind("build.abortDueToClasspathProblems")); //$NON-NLS-1$
+    //      marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
+    //      return false;
+    //    }
+    // make sure all prereq projects have valid build states... only when
+    // aborting builds since projects in cycles do not have build states
     // except for projects involved in a 'warning' cycle (see below)
     IProject[] requiredProjects = getRequiredProjects(false);
     next : for (int i = 0, l = requiredProjects.length; i < l; i++) {
       IProject p = requiredProjects[i];
       if (getLastState(p) == null) {
-        // The prereq project has no build state: if this prereq project has a 'warning' cycle marker then allow build (see bug id 23357)
+        // The prereq project has no build state: if this prereq project has a
+        // 'warning' cycle marker then allow build (see bug id 23357)
         JavaProject prereq = (JavaProject) PHPCore.create(p);
-        if (prereq.hasCycleMarker() && PHPCore.WARNING.equals(javaProject.getOption(PHPCore.CORE_CIRCULAR_CLASSPATH, true)))
+        if (prereq.hasCycleMarker()
+            && PHPCore.WARNING.equals(javaProject.getOption(
+                PHPCore.CORE_CIRCULAR_CLASSPATH, true)))
           continue;
         if (DEBUG)
-          System.out.println("Aborted build because prereq project " + p.getName() //$NON-NLS-1$
-          +" was not built"); //$NON-NLS-1$
-
-        removeProblemsAndTasksFor(currentProject); // make this the only problem for this project
-        IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
-        marker.setAttribute(IMarker.MESSAGE, isClasspathBroken(prereq.getRawClasspath(), p) ? Util.bind("build.prereqProjectHasClasspathProblems", p.getName()) //$NON-NLS-1$
-        : Util.bind("build.prereqProjectMustBeRebuilt", p.getName())); //$NON-NLS-1$
+          System.out.println("Aborted build because prereq project "
+              + p.getName() //$NON-NLS-1$
+              + " was not built"); //$NON-NLS-1$
+        removeProblemsAndTasksFor(currentProject); // make this the only
+        // problem for this project
+        IMarker marker = currentProject
+            .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
+        marker.setAttribute(IMarker.MESSAGE, isClasspathBroken(prereq
+            .getRawClasspath(), p) ? Util.bind(
+            "build.prereqProjectHasClasspathProblems", p.getName()) //$NON-NLS-1$
+            : Util.bind("build.prereqProjectMustBeRebuilt", p.getName())); //$NON-NLS-1$
         marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
         return false;
       }
     }
     return true;
   }
-
   /*
    * Instruct the build manager that this project is involved in a cycle and
    * needs to propagate structural changes to the other projects in the cycle.
    */
   void mustPropagateStructuralChanges() {
     HashSet cycleParticipants = new HashSet(3);
-    javaProject.updateCycleParticipants(null, new ArrayList(), cycleParticipants, workspaceRoot, new HashSet(3));
+    javaProject.updateCycleParticipants(null, new ArrayList(),
+        cycleParticipants, workspaceRoot, new HashSet(3));
     IPath currentPath = javaProject.getPath();
     Iterator i = cycleParticipants.iterator();
     while (i.hasNext()) {
       IPath participantPath = (IPath) i.next();
       if (participantPath != currentPath) {
-        IProject project = this.workspaceRoot.getProject(participantPath.segment(0));
+        IProject project = this.workspaceRoot.getProject(participantPath
+            .segment(0));
         if (hasBeenBuilt(project)) {
           if (DEBUG)
-            System.out.println("Requesting another build iteration since cycle participant " + project.getName() //$NON-NLS-1$
-            +" has not yet seen some structural changes"); //$NON-NLS-1$
+            System.out
+                .println("Requesting another build iteration since cycle participant "
+                    + project.getName() //$NON-NLS-1$
+                    + " has not yet seen some structural changes"); //$NON-NLS-1$
           needRebuild();
           return;
         }
       }
     }
   }
-
   private void recordNewState(State state) {
     Object[] keyTable = binaryLocationsPerProject.keyTable;
     for (int i = 0, l = keyTable.length; i < l; i++) {
       IProject prereqProject = (IProject) keyTable[i];
       if (prereqProject != null && prereqProject != currentProject)
-        state.recordStructuralDependency(prereqProject, getLastState(prereqProject));
+        state.recordStructuralDependency(prereqProject,
+            getLastState(prereqProject));
     }
-
     if (DEBUG)
       System.out.println("Recording new state : " + state); //$NON-NLS-1$
     // state.dump();
-    JavaModelManager.getJavaModelManager().setLastBuiltState(currentProject, state);
+    JavaModelManager.getJavaModelManager().setLastBuiltState(currentProject,
+        state);
   }
-
   /**
    * String representation for debugging purposes
    */
   public String toString() {
     return currentProject == null ? "JavaBuilder for unknown project" //$NON-NLS-1$
-    : "JavaBuilder for " + currentProject.getName(); //$NON-NLS-1$
+        : "JavaBuilder for " + currentProject.getName(); //$NON-NLS-1$
   }
 }