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 void deleteGeneratedFiles(IFile[] deletedGeneratedFiles) {
    // delete generated files and recompile any affected source files
    try {
      for (int j = deletedGeneratedFiles.length; --j >= 0; ) {
        IFile deletedFile = deletedGeneratedFiles[j];
        if (deletedFile.exists())
          continue; // only delete .class files for source files that were actually deleted

        SourceFile sourceFile = findSourceFile(deletedFile, false);
        String typeLocator = sourceFile.typeLocator();
        int mdSegmentCount = sourceFile.sourceLocation.sourceFolder.getFullPath().segmentCount();
        IPath typePath =
            sourceFile
                .resource
                .getFullPath()
                .removeFirstSegments(mdSegmentCount)
                .removeFileExtension();
        addDependentsOf(typePath, true); // add dependents of the source file since its now deleted
        this.previousSourceFiles =
            null; // existing source files did not see it as deleted since they were compiled before
        // it was
        char[][] definedTypeNames = this.newState.getDefinedTypeNamesFor(typeLocator);
        if (definedTypeNames == null) { // defined a single type matching typePath
          removeClassFile(typePath, sourceFile.sourceLocation.binaryFolder);
        } else {
          if (definedTypeNames.length > 0) { // skip it if it failed to successfully define a type
            IPath packagePath = typePath.removeLastSegments(1);
            for (int d = 0, l = definedTypeNames.length; d < l; d++)
              removeClassFile(
                  packagePath.append(new String(definedTypeNames[d])),
                  sourceFile.sourceLocation.binaryFolder);
          }
        }
        this.newState.removeLocator(typeLocator);
      }
    } catch (CoreException e) {
      // must continue with compile loop so just log the CoreException
      Util.log(
          e,
          "JavaBuilder logging CompilationParticipant's CoreException to help debugging"); //$NON-NLS-1$
    }
  }
  protected void storeProblemsFor(SourceFile sourceFile, CategorizedProblem[] problems)
      throws CoreException {
    if (sourceFile == null || problems == null || problems.length == 0) return;

    for (int i = problems.length; --i >= 0; ) {
      CategorizedProblem problem = problems[i];
      if (problem != null && problem.getID() == IProblem.UndefinedType) {
        if (this.typeLocatorsWithUndefinedTypes == null)
          this.typeLocatorsWithUndefinedTypes = new StringSet(3);
        this.typeLocatorsWithUndefinedTypes.add(sourceFile.typeLocator());
        break;
      }
    }

    super.storeProblemsFor(sourceFile, problems);
  }
 /**
  * @see
  *     org.eclipse.jdt.internal.core.builder.AbstractImageBuilder#writeClassFileContents(org.eclipse.jdt.internal.compiler.ClassFile,
  *     org.eclipse.core.resources.IFile, java.lang.String, boolean,
  *     org.eclipse.jdt.internal.core.builder.SourceFile)
  */
 protected void writeClassFileContents(
     ClassFile classfile,
     IFile file,
     String qualifiedFileName,
     boolean isTopLevelType,
     SourceFile compilationUnit)
     throws CoreException {
   // Before writing out the class file, compare it to the previous file
   // If structural changes occurred then add dependent source files
   byte[] bytes = classfile.getBytes();
   if (file.exists()) {
     if (writeClassFileCheck(file, qualifiedFileName, bytes)
         || compilationUnit.updateClassFile) { // see 46093
       if (JavaBuilder.DEBUG)
         System.out.println("Writing changed class file " + file.getName()); // $NON-NLS-1$
       if (!file.isDerived()) file.setDerived(true, null);
       file.setContents(new ByteArrayInputStream(bytes), true, false, null);
     } else if (JavaBuilder.DEBUG) {
       System.out.println("Skipped over unchanged class file " + file.getName()); // $NON-NLS-1$
     }
   } else {
     if (isTopLevelType) addDependentsOf(new Path(qualifiedFileName), true); // new type
     if (JavaBuilder.DEBUG)
       System.out.println("Writing new class file " + file.getName()); // $NON-NLS-1$
     try {
       file.create(new ByteArrayInputStream(bytes), IResource.FORCE | IResource.DERIVED, null);
     } catch (CoreException e) {
       if (e.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS) {
         IStatus status = e.getStatus();
         if (status instanceof IResourceStatus) {
           IPath oldFilePath = ((IResourceStatus) status).getPath();
           char[] oldTypeName = oldFilePath.removeFileExtension().lastSegment().toCharArray();
           char[][] previousTypeNames =
               this.newState.getDefinedTypeNamesFor(compilationUnit.typeLocator());
           boolean fromSameFile = false;
           if (previousTypeNames == null) {
             fromSameFile = CharOperation.equals(compilationUnit.getMainTypeName(), oldTypeName);
           } else {
             for (int i = 0, l = previousTypeNames.length; i < l; i++) {
               if (CharOperation.equals(previousTypeNames[i], oldTypeName)) {
                 fromSameFile = true;
                 break;
               }
             }
           }
           if (fromSameFile) {
             // file is defined by the same compilationUnit, but won't be deleted until later so do
             // it now
             IFile collision = file.getParent().getFile(new Path(oldFilePath.lastSegment()));
             collision.delete(true, false, null);
             boolean success = false;
             try {
               file.create(
                   new ByteArrayInputStream(bytes), IResource.FORCE | IResource.DERIVED, null);
               success = true;
             } catch (CoreException ignored) {
               // ignore the second exception
             }
             if (success) return;
           }
         }
         // catch the case that a type has been renamed and collides on disk with an
         // as-yet-to-be-deleted type
         throw new AbortCompilation(true, new AbortIncrementalBuildException(qualifiedFileName));
       }
       throw e; // rethrow
     }
   }
 }