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);
  }
  private int initializeBuilder(int kind, boolean forBuild) throws CoreException {
    // some calls just need the nameEnvironment initialized so skip the rest
    this.javaProject = (JavaProject) JavaCore.create(this.currentProject);
    this.workspaceRoot = this.currentProject.getWorkspace().getRoot();

    if (forBuild) {
      // cache the known participants for this project
      this.participants =
          JavaModelManager.getJavaModelManager()
              .compilationParticipants
              .getCompilationParticipants(this.javaProject);
      if (this.participants != null)
        for (int i = 0, l = this.participants.length; i < l; i++)
          if (this.participants[i].aboutToBuild(this.javaProject)
              == CompilationParticipant.NEEDS_FULL_BUILD) kind = FULL_BUILD;

      // Flush the existing external files cache if this is the beginning of a build cycle
      String projectName = this.currentProject.getName();
      if (builtProjects == null || builtProjects.contains(projectName)) {
        builtProjects = new ArrayList();
      }
      builtProjects.add(projectName);
    }

    this.binaryLocationsPerProject = new SimpleLookupTable(3);
    this.nameEnvironment =
        new NameEnvironment(
            this.workspaceRoot, this.javaProject, this.binaryLocationsPerProject, this.notifier);

    if (forBuild) {
      String filterSequence =
          this.javaProject.getOption(JavaCore.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;
      } else {
        int fileCount = 0, folderCount = 0;
        for (int i = 0, l = filters.length; i < l; i++) {
          char[] f = filters[i];
          if (f.length == 0) continue;
          if (f[f.length - 1] == '/') folderCount++;
          else fileCount++;
        }
        this.extraResourceFileFilters = new char[fileCount][];
        this.extraResourceFolderFilters = new String[folderCount];
        for (int i = 0, l = filters.length; i < l; i++) {
          char[] f = filters[i];
          if (f.length == 0) continue;
          if (f[f.length - 1] == '/')
            this.extraResourceFolderFilters[--folderCount] = new String(f, 0, f.length - 1);
          else this.extraResourceFileFilters[--fileCount] = f;
        }
      }
    }
    return kind;
  }
 boolean filterExtraResource(IResource resource) {
   if (this.extraResourceFileFilters != null) {
     char[] name = resource.getName().toCharArray();
     for (int i = 0, l = this.extraResourceFileFilters.length; i < l; i++)
       if (CharOperation.match(this.extraResourceFileFilters[i], name, true)) return true;
   }
   if (this.extraResourceFolderFilters != null) {
     IPath path = resource.getProjectRelativePath();
     String pathName = path.toString();
     int count = path.segmentCount();
     if (resource.getType() == IResource.FILE) count--;
     for (int i = 0, l = this.extraResourceFolderFilters.length; i < l; i++)
       if (pathName.indexOf(this.extraResourceFolderFilters[i]) != -1)
         for (int j = 0; j < count; j++)
           if (this.extraResourceFolderFilters[i].equals(path.segment(j))) return true;
   }
   return false;
 }
  protected void addDependentsOf(
      IPath path,
      boolean isStructuralChange,
      StringSet qualifiedNames,
      StringSet simpleNames,
      StringSet rootNames) {
    path = path.setDevice(null);
    if (isStructuralChange) {
      String last = path.lastSegment();
      if (last.length() == TypeConstants.PACKAGE_INFO_NAME.length)
        if (CharOperation.equals(last.toCharArray(), TypeConstants.PACKAGE_INFO_NAME)) {
          path =
              path.removeLastSegments(
                  1); // the package-info file has changed so blame the package itself
          /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=323785, in the case of default package,
            there is no need to blame the package itself as there can be no annotations or documentation
            comment tags in the package-info file that can influence the rest of the package. Just bail out
            so we don't touch null objects below.
          */
          if (path.isEmpty()) return;
        }
    }

    if (isStructuralChange && !this.hasStructuralChanges) {
      this.newState.tagAsStructurallyChanged();
      this.hasStructuralChanges = true;
    }
    // the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
    rootNames.add(path.segment(0));
    String packageName = path.removeLastSegments(1).toString();
    boolean wasNew = qualifiedNames.add(packageName);
    String typeName = path.lastSegment();
    int memberIndex = typeName.indexOf('$');
    if (memberIndex > 0) typeName = typeName.substring(0, memberIndex);
    wasNew = simpleNames.add(typeName) | wasNew;
    if (wasNew && JavaBuilder.DEBUG)
      System.out.println(
          "  will look for dependents of " //$NON-NLS-1$
              + typeName
              + " in "
              + packageName); //$NON-NLS-1$
  }
 /**
  * @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
     }
   }
 }