misc changes
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / builder / IncrementalImageBuilder.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core.builder;
12 import java.util.ArrayList;
13
14 import net.sourceforge.phpdt.core.compiler.IProblem;
15 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
16 import net.sourceforge.phpdt.internal.core.Util;
17 import net.sourceforge.phpdt.internal.core.util.SimpleLookupTable;
18 import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
19 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
20 import net.sourceforge.phpeclipse.builder.IdentifierIndexManager;
21
22 import org.eclipse.core.resources.IFile;
23 import org.eclipse.core.resources.IFolder;
24 import org.eclipse.core.resources.IMarker;
25 import org.eclipse.core.resources.IResource;
26 import org.eclipse.core.resources.IResourceDelta;
27 import org.eclipse.core.runtime.CoreException;
28 import org.eclipse.core.runtime.IPath;
29 /**
30  * The incremental image builder
31  */
32 public class IncrementalImageBuilder extends AbstractImageBuilder {
33   protected ArrayList sourceFiles;
34   protected ArrayList previousSourceFiles;
35   protected ArrayList qualifiedStrings;
36   protected ArrayList simpleStrings;
37   protected SimpleLookupTable secondaryTypesToRemove;
38   protected boolean hasStructuralChanges;
39   protected int compileLoop;
40   public static int MaxCompileLoop = 5; // perform a full build if it takes
41   // more than ? incremental compile
42   // loops
43   protected IncrementalImageBuilder(PHPBuilder javaBuilder) {
44     super(javaBuilder);
45     this.nameEnvironment.isIncrementalBuild = true;
46     this.newState.copyFrom(javaBuilder.lastState);
47     this.sourceFiles = new ArrayList(33);
48     this.previousSourceFiles = null;
49     this.qualifiedStrings = new ArrayList(33);
50     this.simpleStrings = new ArrayList(33);
51     this.hasStructuralChanges = false;
52     this.compileLoop = 0;
53   }
54   public boolean build(SimpleLookupTable deltas) {
55     // initialize builder
56     // walk this project's deltas, find changed source files
57     // walk prereq projects' deltas, find changed class files & add affected
58     // source files
59     //   use the build state # to skip the deltas for certain prereq projects
60     //   ignore changed zip/jar files since they caused a full build
61     // compile the source files & acceptResult()
62     // compare the produced class files against the existing ones on disk
63     // recompile all dependent source files of any type with structural changes
64     // or new/removed secondary type
65     // keep a loop counter to abort & perform a full build
66     if (PHPBuilder.DEBUG)
67       System.out.println("INCREMENTAL build"); //$NON-NLS-1$
68     try {
69       resetCollections();
70       notifier.subTask(Util.bind("build.analyzingDeltas")); //$NON-NLS-1$
71       IResourceDelta sourceDelta = (IResourceDelta) deltas
72           .get(javaBuilder.currentProject);
73       if (sourceDelta != null) {
74         sourceDelta.accept(new ParserVisitor(javaBuilder.currentProject, notifier.monitor));
75         
76         if (!findSourceFiles(sourceDelta))
77           return false;
78       }
79       notifier.updateProgressDelta(0.10f);
80 //      Object[] keyTable = deltas.keyTable;
81 //      Object[] valueTable = deltas.valueTable;
82 ////      final IdentifierIndexManager indexManager = PHPeclipsePlugin.getDefault()
83 ////          .getIndexManager(javaBuilder.currentProject);
84 //      for (int i = 0, l = valueTable.length; i < l; i++) {
85 //        IResourceDelta delta = (IResourceDelta) valueTable[i];
86 //        if (delta != null) {
87 //          IResource resource = delta.getResource();
88 //          int resourceType = resource.getType();
89 //          if (resourceType == IResource.FILE) {
90 //            switch (delta.getKind()) {
91 //              case IResourceDelta.ADDED :
92 //                if ((resource.getFileExtension() != null)
93 //                    && PHPFileUtil.isPHPFile((IFile) resource)) {
94 //                  // update indexfile for the project:
95 ////                  indexManager.addFile((IFile) resource);
96 //                }
97 //                break;
98 //              case IResourceDelta.CHANGED :
99 //                if ((resource.getFileExtension() != null)
100 //                    && PHPFileUtil.isPHPFile((IFile) resource)) {
101 //                  // update indexfile for the project:
102 ////                  indexManager.changeFile((IFile) resource);
103 //                }
104 //                break;
105 //              case IResourceDelta.REMOVED :
106 //                if ((resource.getFileExtension() != null)
107 //                    && PHPFileUtil.isPHPFile((IFile) resource)) {
108 //                  // update indexfile for the project:
109 ////                  indexManager.removeFile((IFile) resource);
110 //                }
111 //                break;
112 //            }
113 //          }
114 //          //                          ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[])
115 //          // javaBuilder.binaryLocationsPerProject.get(keyTable[i]);
116 //          //                          if (classFoldersAndJars != null)
117 //          //                                  if (!findAffectedSourceFiles(delta, classFoldersAndJars)) return
118 //          // false;
119 //        }
120 //      }
121       notifier.updateProgressDelta(0.10f);
122       notifier.subTask(Util.bind("build.analyzingSources")); //$NON-NLS-1$
123       addAffectedSourceFiles();
124       notifier.updateProgressDelta(0.05f);
125       this.compileLoop = 0;
126       float increment = 0.40f;
127       while (sourceFiles.size() > 0) { // added to in acceptResult
128         if (++this.compileLoop > MaxCompileLoop) {
129           if (PHPBuilder.DEBUG)
130             System.out
131                 .println("ABORTING incremental build... exceeded loop count"); //$NON-NLS-1$
132           return false;
133         }
134         notifier.checkCancel();
135         SourceFile[] allSourceFiles = new SourceFile[sourceFiles.size()];
136         sourceFiles.toArray(allSourceFiles);
137         resetCollections();
138         workQueue.addAll(allSourceFiles);
139         notifier.setProgressPerCompilationUnit(increment
140             / allSourceFiles.length);
141         increment = increment / 2;
142         compile(allSourceFiles);
143 //        removeSecondaryTypes();
144         addAffectedSourceFiles();
145       }
146       if (this.hasStructuralChanges && javaBuilder.javaProject.hasCycleMarker())
147         javaBuilder.mustPropagateStructuralChanges();
148     } catch (AbortIncrementalBuildException e) {
149       // abort the incremental build and let the batch builder handle the
150       // problem
151       if (PHPBuilder.DEBUG)
152         System.out.println("ABORTING incremental build... cannot find "
153             + e.qualifiedTypeName + //$NON-NLS-1$
154             ". Could have been renamed inside its existing source file."); //$NON-NLS-1$
155       return false;
156     } catch (CoreException e) {
157       throw internalException(e);
158     } finally {
159       cleanUp();
160     }
161     return true;
162   }
163   protected void addAffectedSourceFiles() {
164     if (qualifiedStrings.isEmpty() && simpleStrings.isEmpty())
165       return;
166     // the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are
167     // just 'X'
168 //    char[][][] qualifiedNames = ReferenceCollection
169 //        .internQualifiedNames(qualifiedStrings);
170     // if a well known qualified name was found then we can skip over these
171 //    if (qualifiedNames.length < qualifiedStrings.size())
172 //      qualifiedNames = null;
173 //    char[][] simpleNames = ReferenceCollection.internSimpleNames(simpleStrings);
174     // if a well known name was found then we can skip over these
175 //    if (simpleNames.length < simpleStrings.size())
176 //      simpleNames = null;
177 //    Object[] keyTable = newState.references.keyTable;
178 //    Object[] valueTable = newState.references.valueTable;
179 //    next : for (int i = 0, l = valueTable.length; i < l; i++) {
180 //      ReferenceCollection refs = (ReferenceCollection) valueTable[i];
181 //      if (refs != null && refs.includes(qualifiedNames, simpleNames)) {
182 //        String typeLocator = (String) keyTable[i];
183 //        IFile file = javaBuilder.currentProject.getFile(typeLocator);
184 //        if (file.exists()) {
185 //          ClasspathMultiDirectory md = sourceLocations[0];
186 //          if (sourceLocations.length > 1) {
187 //            IPath sourceFileFullPath = file.getFullPath();
188 //            for (int j = 0, m = sourceLocations.length; j < m; j++) {
189 //              if (sourceLocations[j].sourceFolder.getFullPath().isPrefixOf(
190 //                  sourceFileFullPath)) {
191 //                md = sourceLocations[j];
192 //                if (md.exclusionPatterns == null
193 //                    || !Util.isExcluded(file, md.exclusionPatterns))
194 //                  break;
195 //              }
196 //            }
197 //          }
198 //          SourceFile sourceFile = new SourceFile(file, md, encoding);
199 //          if (sourceFiles.contains(sourceFile))
200 //            continue next;
201 //          if (compiledAllAtOnce && previousSourceFiles != null
202 //              && previousSourceFiles.contains(sourceFile))
203 //            continue next; // can skip previously compiled files since already
204 //          // saw hierarchy related problems
205 //          if (PHPBuilder.DEBUG)
206 //            System.out.println("  adding affected source file " + typeLocator); //$NON-NLS-1$
207 //          //                          // update indexfile for the project:
208 //          sourceFiles.add(sourceFile);
209 //        }
210 //      }
211 //    }
212   }
213   protected void addDependentsOf(IPath path, boolean hasStructuralChanges) {
214     if (hasStructuralChanges) {
215       newState.tagAsStructurallyChanged();
216       this.hasStructuralChanges = true;
217     }
218     // the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are
219     // just 'X'
220     path = path.setDevice(null);
221     String packageName = path.removeLastSegments(1).toString();
222     if (!qualifiedStrings.contains(packageName))
223       qualifiedStrings.add(packageName);
224     String typeName = path.lastSegment();
225     int memberIndex = typeName.indexOf('$');
226     if (memberIndex > 0)
227       typeName = typeName.substring(0, memberIndex);
228     if (!simpleStrings.contains(typeName)) {
229       if (PHPBuilder.DEBUG)
230         System.out.println("  will look for dependents of " //$NON-NLS-1$
231             + typeName + " in " + packageName); //$NON-NLS-1$
232       simpleStrings.add(typeName);
233     }
234   }
235   protected void cleanUp() {
236     super.cleanUp();
237     this.sourceFiles = null;
238     this.previousSourceFiles = null;
239     this.qualifiedStrings = null;
240     this.simpleStrings = null;
241     this.secondaryTypesToRemove = null;
242     this.hasStructuralChanges = false;
243     this.compileLoop = 0;
244   }
245   //protected boolean findAffectedSourceFiles(IResourceDelta delta,
246   // ClasspathLocation[] classFoldersAndJars) {
247   //    for (int i = 0, l = classFoldersAndJars.length; i < l; i++) {
248   //            ClasspathLocation bLocation = classFoldersAndJars[i];
249   //            // either a .class file folder or a zip/jar file
250   //            if (bLocation != null) { // skip unchanged output folder
251   //                    IPath p = bLocation.getProjectRelativePath();
252   //                    if (p != null) {
253   //                            IResourceDelta binaryDelta = delta.findMember(p);
254   //                            if (binaryDelta != null) {
255   //                                    if (bLocation instanceof ClasspathJar) {
256   //                                            if (JavaBuilder.DEBUG)
257   //                                                    System.out.println("ABORTING incremental build... found delta to jar/zip
258   // file"); //$NON-NLS-1$
259   //                                            return false; // do full build since jar file was changed (added/removed
260   // were caught as classpath change)
261   //                                    }
262   //                                    if (binaryDelta.getKind() == IResourceDelta.ADDED || binaryDelta.getKind()
263   // == IResourceDelta.REMOVED) {
264   //                                            if (JavaBuilder.DEBUG)
265   //                                                    System.out.println("ABORTING incremental build... found added/removed
266   // binary folder"); //$NON-NLS-1$
267   //                                            return false; // added/removed binary folder should not make it here
268   // (classpath change), but handle anyways
269   //                                    }
270   //                                    int segmentCount = binaryDelta.getFullPath().segmentCount();
271   //                                    IResourceDelta[] children = binaryDelta.getAffectedChildren(); // .class
272   // files from class folder
273   //                                    for (int j = 0, m = children.length; j < m; j++)
274   //                                            findAffectedSourceFiles(children[j], segmentCount);
275   //                                    notifier.checkCancel();
276   //                            }
277   //                    }
278   //            }
279   //    }
280   //    return true;
281   //}
282   protected void findAffectedSourceFiles(IResourceDelta binaryDelta,
283       int segmentCount) {
284     // When a package becomes a type or vice versa, expect 2 deltas,
285     // one on the folder & one on the class file
286     IResource resource = binaryDelta.getResource();
287     switch (resource.getType()) {
288       case IResource.FOLDER :
289         switch (binaryDelta.getKind()) {
290           case IResourceDelta.ADDED :
291           case IResourceDelta.REMOVED :
292             IPath packagePath = resource.getFullPath().removeFirstSegments(
293                 segmentCount);
294             String packageName = packagePath.toString();
295             if (binaryDelta.getKind() == IResourceDelta.ADDED) {
296               // see if any known source file is from the same package...
297               // classpath already includes new package
298 //              if (!newState.isKnownPackage(packageName)) {
299 //                if (PHPBuilder.DEBUG)
300 //                  System.out.println("Found added package " + packageName); //$NON-NLS-1$
301 //                addDependentsOf(packagePath, false);
302 //                return;
303 //              }
304               if (PHPBuilder.DEBUG)
305                 System.out.println("Skipped dependents of added package "
306                     + packageName); //$NON-NLS-1$
307             } else {
308               // see if the package still exists on the classpath
309               //                                                if (!nameEnvironment.isPackage(packageName)) {
310               //                                                        if (JavaBuilder.DEBUG)
311               //                                                                System.out.println("Found removed package " + packageName);
312               // //$NON-NLS-1$
313               //                                                        addDependentsOf(packagePath, false);
314               //                                                        return;
315               //                                                }
316               if (PHPBuilder.DEBUG)
317                 System.out.println("Skipped dependents of removed package "
318                     + packageName); //$NON-NLS-1$
319             }
320           // fall thru & traverse the sub-packages and .class files
321           case IResourceDelta.CHANGED :
322             IResourceDelta[] children = binaryDelta.getAffectedChildren();
323             for (int i = 0, l = children.length; i < l; i++)
324               findAffectedSourceFiles(children[i], segmentCount);
325         }
326         return;
327       case IResource.FILE :
328     //                  if (Util.isClassFileName(resource.getName())) {
329     //                          IPath typePath =
330     // resource.getFullPath().removeFirstSegments(segmentCount).removeFileExtension();
331     //                          switch (binaryDelta.getKind()) {
332     //                                  case IResourceDelta.ADDED :
333     //                                  case IResourceDelta.REMOVED :
334     //                                          if (JavaBuilder.DEBUG)
335     //                                                  System.out.println("Found added/removed class file " + typePath);
336     // //$NON-NLS-1$
337     //                                          addDependentsOf(typePath, false);
338     //                                          return;
339     //                                  case IResourceDelta.CHANGED :
340     //                                          if ((binaryDelta.getFlags() & IResourceDelta.CONTENT) == 0)
341     //                                                  return; // skip it since it really isn't changed
342     //                                          if (JavaBuilder.DEBUG)
343     //                                                  System.out.println("Found changed class file " + typePath);
344     // //$NON-NLS-1$
345     //                                          addDependentsOf(typePath, false);
346     //                          }
347     //                          return;
348     //                  }
349     }
350   }
351   protected boolean findSourceFiles(IResourceDelta delta) throws CoreException {
352     for (int i = 0, l = sourceLocations.length; i < l; i++) {
353       ClasspathMultiDirectory md = sourceLocations[i];
354       if (md.sourceFolder.equals(javaBuilder.currentProject)) {
355         // skip nested source & output folders when the project is a source
356         // folder
357         int segmentCount = delta.getFullPath().segmentCount();
358         IResourceDelta[] children = delta.getAffectedChildren();
359         for (int j = 0, m = children.length; j < m; j++)
360           if (!isExcludedFromProject(children[j].getFullPath()))
361             findSourceFiles(children[j], md, segmentCount);
362       } else {
363         IResourceDelta sourceDelta = delta.findMember(md.sourceFolder
364             .getProjectRelativePath());
365         if (sourceDelta != null) {
366           if (sourceDelta.getKind() == IResourceDelta.REMOVED) {
367             if (PHPBuilder.DEBUG)
368               System.out
369                   .println("ABORTING incremental build... found removed source folder"); //$NON-NLS-1$
370             return false; // removed source folder should not make it here, but
371             // handle anyways (ADDED is supported)
372           }
373           int segmentCount = sourceDelta.getFullPath().segmentCount();
374           IResourceDelta[] children = sourceDelta.getAffectedChildren();
375           for (int j = 0, m = children.length; j < m; j++)
376             findSourceFiles(children[j], md, segmentCount);
377         }
378       }
379       notifier.checkCancel();
380     }
381     return true;
382   }
383   protected void findSourceFiles(IResourceDelta sourceDelta,
384       ClasspathMultiDirectory md, int segmentCount) throws CoreException {
385     // When a package becomes a type or vice versa, expect 2 deltas,
386     // one on the folder & one on the source file
387     IResource resource = sourceDelta.getResource();
388     if (md.exclusionPatterns != null
389         && Util.isExcluded(resource, md.exclusionPatterns))
390       return;
391     switch (resource.getType()) {
392       case IResource.FOLDER :
393         switch (sourceDelta.getKind()) {
394           case IResourceDelta.ADDED :
395             IPath addedPackagePath = resource.getFullPath()
396                 .removeFirstSegments(segmentCount);
397             createFolder(addedPackagePath, md.binaryFolder); // ensure package
398             // exists in the
399             // output folder
400             // add dependents even when the package thinks it exists to be on
401             // the safe side
402             if (PHPBuilder.DEBUG)
403               System.out.println("Found added package " + addedPackagePath); //$NON-NLS-1$
404             addDependentsOf(addedPackagePath, true);
405           // fall thru & collect all the source files
406           case IResourceDelta.CHANGED :
407             IResourceDelta[] children = sourceDelta.getAffectedChildren();
408             for (int i = 0, l = children.length; i < l; i++)
409               findSourceFiles(children[i], md, segmentCount);
410             return;
411           case IResourceDelta.REMOVED :
412             IPath removedPackagePath = resource.getFullPath()
413                 .removeFirstSegments(segmentCount);
414             if (sourceLocations.length > 1) {
415               for (int i = 0, l = sourceLocations.length; i < l; i++) {
416                 if (sourceLocations[i].sourceFolder.getFolder(
417                     removedPackagePath).exists()) {
418                   // only a package fragment was removed, same as removing
419                   // multiple source files
420                   createFolder(removedPackagePath, md.binaryFolder); // ensure
421                   // package
422                   // exists
423                   // in the
424                   // output
425                   // folder
426                   IResourceDelta[] removedChildren = sourceDelta
427                       .getAffectedChildren();
428                   for (int j = 0, m = removedChildren.length; j < m; j++)
429                     findSourceFiles(removedChildren[j], md, segmentCount);
430                   return;
431                 }
432               }
433             }
434             IFolder removedPackageFolder = md.binaryFolder
435                 .getFolder(removedPackagePath);
436             if (removedPackageFolder.exists())
437               removedPackageFolder.delete(IResource.FORCE, null);
438             // add dependents even when the package thinks it does not exist to
439             // be on the safe side
440             if (PHPBuilder.DEBUG)
441               System.out.println("Found removed package " + removedPackagePath); //$NON-NLS-1$
442             addDependentsOf(removedPackagePath, true);
443             newState.removePackage(sourceDelta);
444         }
445         return;
446       case IResource.FILE :
447         String resourceName = resource.getName();
448         if (Util.isJavaFileName(resourceName)) {
449           IPath typePath = resource.getFullPath().removeFirstSegments(
450               segmentCount).removeFileExtension();
451           String typeLocator = resource.getProjectRelativePath().toString();
452           switch (sourceDelta.getKind()) {
453             case IResourceDelta.ADDED :
454               if (PHPBuilder.DEBUG)
455                 System.out.println("Compile this added source file "
456                     + typeLocator); //$NON-NLS-1$
457               sourceFiles.add(new SourceFile((IFile) resource, md, encoding));
458               String typeName = typePath.toString();
459 //              if (!newState.isDuplicateLocator(typeName, typeLocator)) { // adding
460 //                // dependents
461 //                // results
462 //                // in
463 //                // 2
464 //                // duplicate
465 //                // errors
466 //                if (PHPBuilder.DEBUG)
467 //                  System.out.println("Found added source file " + typeName); //$NON-NLS-1$
468 //                addDependentsOf(typePath, true);
469 //              }
470               return;
471             case IResourceDelta.REMOVED :
472 //              char[][] definedTypeNames = newState
473 //                  .getDefinedTypeNamesFor(typeLocator);
474 //              if (definedTypeNames == null) { // defined a single type matching
475 //                // typePath
476 //                removeClassFile(typePath, md.binaryFolder);
477 //                if ((sourceDelta.getFlags() & IResourceDelta.MOVED_TO) != 0) {
478 //                  // remove problems and tasks for a compilation unit that is
479 //                  // being moved (to another package or renamed)
480 //                  // if the target file is a compilation unit, the new cu will
481 //                  // be recompiled
482 //                  // if the target file is a non-java resource, then markers
483 //                  // are removed
484 //                  // see bug 2857
485 //                  IResource movedFile = javaBuilder.workspaceRoot
486 //                      .getFile(sourceDelta.getMovedToPath());
487 //                  PHPBuilder.removeProblemsAndTasksFor(movedFile);
488 //                }
489 //              } else {
490                 if (PHPBuilder.DEBUG)
491                   System.out.println("Found removed source file "
492                       + typePath.toString()); //$NON-NLS-1$
493                 addDependentsOf(typePath, true); // add dependents of the
494                 // source file since it may be
495                 // involved in a name
496                 // collision
497 //                if (definedTypeNames.length > 0) { // skip it if it failed to
498 //                  // successfully define a
499 //                  // type
500 //                  IPath packagePath = typePath.removeLastSegments(1);
501 //                  for (int i = 0, l = definedTypeNames.length; i < l; i++)
502 //                    removeClassFile(packagePath.append(new String(
503 //                        definedTypeNames[i])), md.binaryFolder);
504 //                }
505 //              }
506 //              newState.removeLocator(typeLocator);
507               return;
508             case IResourceDelta.CHANGED :
509               if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0)
510                 return; // skip it since it really isn't changed
511               if (PHPBuilder.DEBUG)
512                 System.out.println("Compile this changed source file "
513                     + typeLocator); //$NON-NLS-1$
514               sourceFiles.add(new SourceFile((IFile) resource, md, encoding));
515           }
516           return;
517           //                    } else if (Util.isClassFileName(resourceName)) {
518           //                            return; // skip class files
519         } else if (md.hasIndependentOutputFolder) {
520           if (javaBuilder.filterExtraResource(resource))
521             return;
522           // copy all other resource deltas to the output folder
523           IPath resourcePath = resource.getFullPath().removeFirstSegments(
524               segmentCount);
525           IResource outputFile = md.binaryFolder.getFile(resourcePath);
526           switch (sourceDelta.getKind()) {
527             case IResourceDelta.ADDED :
528               if (outputFile.exists()) {
529                 if (PHPBuilder.DEBUG)
530                   System.out.println("Deleting existing file " + resourcePath); //$NON-NLS-1$
531                 outputFile.delete(IResource.FORCE, null);
532               }
533               if (PHPBuilder.DEBUG)
534                 System.out.println("Copying added file " + resourcePath); //$NON-NLS-1$
535               createFolder(resourcePath.removeLastSegments(1), md.binaryFolder); // ensure
536               // package
537               // exists
538               // in
539               // the
540               // output
541               // folder
542               resource.copy(outputFile.getFullPath(), IResource.FORCE, null);
543               outputFile.setDerived(true);
544               return;
545             case IResourceDelta.REMOVED :
546               if (outputFile.exists()) {
547                 if (PHPBuilder.DEBUG)
548                   System.out.println("Deleting removed file " + resourcePath); //$NON-NLS-1$
549                 outputFile.delete(IResource.FORCE, null);
550               }
551               return;
552             case IResourceDelta.CHANGED :
553               if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0)
554                 return; // skip it since it really isn't changed
555               if (outputFile.exists()) {
556                 if (PHPBuilder.DEBUG)
557                   System.out.println("Deleting existing file " + resourcePath); //$NON-NLS-1$
558                 outputFile.delete(IResource.FORCE, null);
559               }
560               if (PHPBuilder.DEBUG)
561                 System.out.println("Copying changed file " + resourcePath); //$NON-NLS-1$
562               createFolder(resourcePath.removeLastSegments(1), md.binaryFolder); // ensure
563               // package
564               // exists
565               // in
566               // the
567               // output
568               // folder
569               resource.copy(outputFile.getFullPath(), IResource.FORCE, null);
570               outputFile.setDerived(true);
571           }
572           return;
573         }
574     }
575   }
576   protected void finishedWith(String sourceLocator, CompilationResult result,
577       char[] mainTypeName, ArrayList definedTypeNames,
578       ArrayList duplicateTypeNames) throws CoreException {
579 //    char[][] previousTypeNames = newState.getDefinedTypeNamesFor(sourceLocator);
580 //    if (previousTypeNames == null)
581 //      previousTypeNames = new char[][]{mainTypeName};
582 //    IPath packagePath = null;
583 //    next : for (int i = 0, l = previousTypeNames.length; i < l; i++) {
584 //      char[] previous = previousTypeNames[i];
585 //      for (int j = 0, m = definedTypeNames.size(); j < m; j++)
586 //        if (CharOperation.equals(previous, (char[]) definedTypeNames.get(j)))
587 //          continue next;
588 //      SourceFile sourceFile = (SourceFile) result.getCompilationUnit();
589 //      if (packagePath == null) {
590 //        int count = sourceFile.sourceLocation.sourceFolder.getFullPath()
591 //            .segmentCount();
592 //        packagePath = sourceFile.resource.getFullPath().removeFirstSegments(
593 //            count).removeLastSegments(1);
594 //      }
595 //      if (secondaryTypesToRemove == null)
596 //        this.secondaryTypesToRemove = new SimpleLookupTable();
597 //      ArrayList types = (ArrayList) secondaryTypesToRemove
598 //          .get(sourceFile.sourceLocation.binaryFolder);
599 //      if (types == null)
600 //        types = new ArrayList(definedTypeNames.size());
601 //      types.add(packagePath.append(new String(previous)));
602 //      secondaryTypesToRemove.put(sourceFile.sourceLocation.binaryFolder, types);
603 //    }
604     //  super.finishedWith(sourceLocator, result, mainTypeName,
605     // definedTypeNames, duplicateTypeNames);
606   }
607 //  protected void removeClassFile(IPath typePath, IContainer outputFolder)
608 //      throws CoreException {
609 //    if (typePath.lastSegment().indexOf('$') == -1) { // is not a nested type
610 //      newState.removeQualifiedTypeName(typePath.toString());
611 //      // add dependents even when the type thinks it does not exist to be on
612 //      // the safe side
613 //      if (PHPBuilder.DEBUG)
614 //        System.out.println("Found removed type " + typePath); //$NON-NLS-1$
615 //      addDependentsOf(typePath, true); // when member types are removed, their
616 //      // enclosing type is structurally
617 //      // changed
618 //    }
619 //    IFile classFile = outputFolder.getFile(typePath
620 //        .addFileExtension(PHPBuilder.CLASS_EXTENSION));
621 //    if (classFile.exists()) {
622 //      if (PHPBuilder.DEBUG)
623 //        System.out.println("Deleting class file of removed type " + typePath); //$NON-NLS-1$
624 //      classFile.delete(IResource.FORCE, null);
625 //    }
626 //  }
627 //  protected void removeSecondaryTypes() throws CoreException {
628 //    if (secondaryTypesToRemove != null) { // delayed deleting secondary types
629 //      // until the end of the compile loop
630 //      Object[] keyTable = secondaryTypesToRemove.keyTable;
631 //      Object[] valueTable = secondaryTypesToRemove.valueTable;
632 //      for (int i = 0, l = keyTable.length; i < l; i++) {
633 //        IContainer outputFolder = (IContainer) keyTable[i];
634 //        if (outputFolder != null) {
635 //          ArrayList paths = (ArrayList) valueTable[i];
636 //          for (int j = 0, m = paths.size(); j < m; j++)
637 //            removeClassFile((IPath) paths.get(j), outputFolder);
638 //        }
639 //      }
640 //      this.secondaryTypesToRemove = null;
641 //      if (previousSourceFiles != null && previousSourceFiles.size() > 1)
642 //        this.previousSourceFiles = null; // cannot optimize recompile case when
643 //      // a secondary type is deleted
644 //    }
645 //  }
646   protected void resetCollections() {
647     previousSourceFiles = sourceFiles.isEmpty()
648         ? null
649         : (ArrayList) sourceFiles.clone();
650     sourceFiles.clear();
651     qualifiedStrings.clear();
652     simpleStrings.clear();
653     workQueue.clear();
654   }
655   protected void updateProblemsFor(SourceFile sourceFile,
656       CompilationResult result) throws CoreException {
657     IMarker[] markers = PHPBuilder.getProblemsFor(sourceFile.resource);
658     IProblem[] problems = result.getProblems();
659     if (problems == null && markers.length == 0)
660       return;
661     notifier.updateProblemCounts(markers, problems);
662     PHPBuilder.removeProblemsFor(sourceFile.resource);
663     storeProblemsFor(sourceFile, problems);
664   }
665   protected void updateTasksFor(SourceFile sourceFile, CompilationResult result)
666       throws CoreException {
667     IMarker[] markers = PHPBuilder.getTasksFor(sourceFile.resource);
668     IProblem[] tasks = result.getTasks();
669     if (tasks == null && markers.length == 0)
670       return;
671     PHPBuilder.removeTasksFor(sourceFile.resource);
672     storeTasksFor(sourceFile, tasks);
673   }
674   //protected void writeClassFileBytes(byte[] bytes, IFile file, String
675   // qualifiedFileName, boolean isSecondaryType) throws CoreException {
676   //    // Before writing out the class file, compare it to the previous file
677   //    // If structural changes occured then add dependent source files
678   //    if (file.exists()) {
679   //            if (writeClassFileCheck(file, qualifiedFileName, bytes)) {
680   //                    if (JavaBuilder.DEBUG)
681   //                            System.out.println("Writing changed class file " +
682   // file.getName());//$NON-NLS-1$
683   //                    file.setContents(new ByteArrayInputStream(bytes), true, false, null);
684   //                    if (!file.isDerived())
685   //                            file.setDerived(true);
686   //            } else if (JavaBuilder.DEBUG) {
687   //                    System.out.println("Skipped over unchanged class file " +
688   // file.getName());//$NON-NLS-1$
689   //            }
690   //    } else {
691   //            if (isSecondaryType)
692   //                    addDependentsOf(new Path(qualifiedFileName), true); // new secondary type
693   //            if (JavaBuilder.DEBUG)
694   //                    System.out.println("Writing new class file " +
695   // file.getName());//$NON-NLS-1$
696   //            file.create(new ByteArrayInputStream(bytes), IResource.FORCE, null);
697   //            file.setDerived(true);
698   //    }
699   //}
700   //protected boolean writeClassFileCheck(IFile file, String fileName, byte[]
701   // newBytes) throws CoreException {
702   //    try {
703   //            byte[] oldBytes = Util.getResourceContentsAsByteArray(file);
704   //            if (this.compileLoop > 1) { // only optimize files which were recompiled
705   // during the dependent pass, see 33990
706   //                    notEqual : if (newBytes.length == oldBytes.length) {
707   //                            for (int i = newBytes.length; --i >= 0;)
708   //                                    if (newBytes[i] != oldBytes[i]) break notEqual;
709   //                            return false; // bytes are identical so skip them
710   //                    }
711   //            }
712   //            IPath location = file.getLocation();
713   //            if (location == null) return false; // unable to determine location of
714   // this class file
715   //            ClassFileReader reader = new ClassFileReader(oldBytes,
716   // location.toString().toCharArray());
717   //            // ignore local types since they're only visible inside a single method
718   //            if (!(reader.isLocal() || reader.isAnonymous()) &&
719   // reader.hasStructuralChanges(newBytes)) {
720   //                    if (JavaBuilder.DEBUG)
721   //                            System.out.println("Type has structural changes " + fileName);
722   // //$NON-NLS-1$
723   //                    addDependentsOf(new Path(fileName), true);
724   //            }
725   //    } catch (ClassFormatException e) {
726   //            addDependentsOf(new Path(fileName), true);
727   //    }
728   //    return true;
729   //}
730   public String toString() {
731     return "incremental image builder for:\n\tnew state: " + newState; //$NON-NLS-1$
732   }
733   /*
734    * Debug helper
735    * 
736    * static void dump(IResourceDelta delta) { StringBuffer buffer = new
737    * StringBuffer(); IPath path = delta.getFullPath(); for (int i =
738    * path.segmentCount(); --i > 0;) buffer.append(" "); switch
739    * (delta.getKind()) { case IResourceDelta.ADDED: buffer.append('+'); break;
740    * case IResourceDelta.REMOVED: buffer.append('-'); break; case
741    * IResourceDelta.CHANGED: '); break; case IResourceDelta.NO_CHANGE:
742    * buffer.append('='); break; default: buffer.append('?'); break; }
743    * buffer.append(path); System.out.println(buffer.toString());
744    * IResourceDelta[] children = delta.getAffectedChildren(); for (int i = 0, l =
745    * children.length; i < l; i++) dump(children[i]); }
746    */
747 }