protected void finishedWith(
      String sourceLocator,
      CompilationResult result,
      char[] mainTypeName,
      ArrayList definedTypeNames,
      ArrayList duplicateTypeNames) {
    char[][] previousTypeNames = this.newState.getDefinedTypeNamesFor(sourceLocator);
    if (previousTypeNames == null) previousTypeNames = new char[][] {mainTypeName};
    IPath packagePath = null;
    next:
    for (int i = 0, l = previousTypeNames.length; i < l; i++) {
      char[] previous = previousTypeNames[i];
      for (int j = 0, m = definedTypeNames.size(); j < m; j++)
        if (CharOperation.equals(previous, (char[]) definedTypeNames.get(j))) continue next;

      SourceFile sourceFile = (SourceFile) result.getCompilationUnit();
      if (packagePath == null) {
        int count = sourceFile.sourceLocation.sourceFolder.getFullPath().segmentCount();
        packagePath =
            sourceFile.resource.getFullPath().removeFirstSegments(count).removeLastSegments(1);
      }
      if (this.secondaryTypesToRemove == null)
        this.secondaryTypesToRemove = new SimpleLookupTable();
      ArrayList types =
          (ArrayList) this.secondaryTypesToRemove.get(sourceFile.sourceLocation.binaryFolder);
      if (types == null) types = new ArrayList(definedTypeNames.size());
      types.add(packagePath.append(new String(previous)));
      this.secondaryTypesToRemove.put(sourceFile.sourceLocation.binaryFolder, types);
    }
    super.finishedWith(sourceLocator, result, mainTypeName, definedTypeNames, duplicateTypeNames);
  }
 protected void compile(
     SourceFile[] units, SourceFile[] additionalUnits, boolean compilingFirstGroup) {
   if (compilingFirstGroup && additionalUnits != null) {
     // add any source file from additionalUnits to units if it defines secondary types
     // otherwise its possible during testing with MAX_AT_ONCE == 1 that a secondary type
     // can cause an infinite loop as it alternates between not found and defined, see bug 146324
     ArrayList extras = null;
     for (int i = 0, l = additionalUnits.length; i < l; i++) {
       SourceFile unit = additionalUnits[i];
       if (unit != null && this.newState.getDefinedTypeNamesFor(unit.typeLocator()) != null) {
         if (JavaBuilder.DEBUG)
           System.out.println(
               "About to compile file with secondary types " + unit.typeLocator()); // $NON-NLS-1$
         if (extras == null) extras = new ArrayList(3);
         extras.add(unit);
       }
     }
     if (extras != null) {
       int oldLength = units.length;
       int toAdd = extras.size();
       System.arraycopy(units, 0, units = new SourceFile[oldLength + toAdd], 0, oldLength);
       for (int i = 0; i < toAdd; i++) units[oldLength++] = (SourceFile) extras.get(i);
     }
   }
   super.compile(units, additionalUnits, compilingFirstGroup);
 }
 protected boolean findSourceFiles(IResourceDelta delta) throws CoreException {
   ArrayList visited =
       this.makeOutputFolderConsistent ? new ArrayList(this.sourceLocations.length) : null;
   for (int i = 0, l = this.sourceLocations.length; i < l; i++) {
     ClasspathMultiDirectory md = this.sourceLocations[i];
     if (this.makeOutputFolderConsistent
         && md.hasIndependentOutputFolder
         && !visited.contains(md.binaryFolder)) {
       // even a project which acts as its own source folder can have an independent/nested output
       // folder
       visited.add(md.binaryFolder);
       IResourceDelta binaryDelta = delta.findMember(md.binaryFolder.getProjectRelativePath());
       if (binaryDelta != null) {
         int segmentCount = binaryDelta.getFullPath().segmentCount();
         IResourceDelta[] children = binaryDelta.getAffectedChildren();
         for (int j = 0, m = children.length; j < m; j++)
           if (!checkForClassFileChanges(children[j], md, segmentCount)) return false;
       }
     }
     if (md.sourceFolder.equals(this.javaBuilder.currentProject)) {
       // skip nested source & output folders when the project is a source folder
       int segmentCount = delta.getFullPath().segmentCount();
       IResourceDelta[] children = delta.getAffectedChildren();
       for (int j = 0, m = children.length; j < m; j++)
         if (!isExcludedFromProject(children[j].getFullPath()))
           if (!findSourceFiles(children[j], md, segmentCount)) return false;
     } else {
       IResourceDelta sourceDelta = delta.findMember(md.sourceFolder.getProjectRelativePath());
       if (sourceDelta != null) {
         if (sourceDelta.getKind() == IResourceDelta.REMOVED) {
           if (JavaBuilder.DEBUG)
             System.out.println(
                 "ABORTING incremental build... found removed source folder"); //$NON-NLS-1$
           return false; // removed source folder should not make it here, but handle anyways
           // (ADDED is supported)
         }
         int segmentCount = sourceDelta.getFullPath().segmentCount();
         IResourceDelta[] children = sourceDelta.getAffectedChildren();
         try {
           for (int j = 0, m = children.length; j < m; j++)
             if (!findSourceFiles(children[j], md, segmentCount)) return false;
         } catch (CoreException e) {
           // catch the case that a package has been renamed and collides on disk with an
           // as-yet-to-be-deleted package
           if (e.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) {
             if (JavaBuilder.DEBUG)
               System.out.println(
                   "ABORTING incremental build... found renamed package"); //$NON-NLS-1$
             return false;
           }
           throw e; // rethrow
         }
       }
     }
     this.notifier.checkCancel();
   }
   return true;
 }