/**
  * Sets the deltas to register the changes resulting from this operation for this source element
  * and its destination. If the operation is a cross project operation
  *
  * <ul>
  *   <li>On a copy, the delta should be rooted in the dest project
  *   <li>On a move, two deltas are generated
  *       <ul>
  *         <li>one rooted in the source project
  *         <li>one rooted in the destination project
  *       </ul>
  * </ul>
  *
  * If the operation is rooted in a single project, the delta is rooted in that project
  */
 protected void prepareDeltas(
     IJavaElement sourceElement, IJavaElement destinationElement, boolean isMove) {
   if (Util.isExcluded(sourceElement) || Util.isExcluded(destinationElement)) return;
   IJavaProject destProject = destinationElement.getJavaProject();
   if (isMove) {
     IJavaProject sourceProject = sourceElement.getJavaProject();
     getDeltaFor(sourceProject).movedFrom(sourceElement, destinationElement);
     getDeltaFor(destProject).movedTo(destinationElement, sourceElement);
   } else {
     getDeltaFor(destProject).added(destinationElement);
   }
 }
  protected boolean checkForClassFileChanges(
      IResourceDelta binaryDelta, ClasspathMultiDirectory md, int segmentCount)
      throws CoreException {
    IResource resource = binaryDelta.getResource();
    // remember that if inclusion & exclusion patterns change then a full build is done
    boolean isExcluded =
        (md.exclusionPatterns != null || md.inclusionPatterns != null)
            && Util.isExcluded(resource, md.inclusionPatterns, md.exclusionPatterns);
    switch (resource.getType()) {
      case IResource.FOLDER:
        if (isExcluded && md.inclusionPatterns == null)
          return true; // no need to go further with this delta since its children cannot be
        // included

        IResourceDelta[] children = binaryDelta.getAffectedChildren();
        for (int i = 0, l = children.length; i < l; i++)
          if (!checkForClassFileChanges(children[i], md, segmentCount)) return false;
        return true;
      case IResource.FILE:
        if (!isExcluded
            && org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(resource.getName())) {
          // perform full build if a managed class file has been changed
          IPath typePath =
              resource.getFullPath().removeFirstSegments(segmentCount).removeFileExtension();
          if (this.newState.isKnownType(typePath.toString())) {
            if (JavaBuilder.DEBUG)
              System.out.println(
                  "MUST DO FULL BUILD. Found change to class file " + typePath); // $NON-NLS-1$
            return false;
          }
          return true;
        }
    }
    return true;
  }
    public boolean visit(IResource resource) throws CoreException {
      if (resource.isDerived()) {
        return false;
      }

      handler.handleResourceStart(resource);

      if (resource.getType() == IResource.FILE
          && ContentTypeUtils.isGroovyLikeFileName(resource.getName())) {
        if (Util.isExcluded(resource, includes, excludes)) {
          return false;
        }

        GroovyCompilationUnit unit = (GroovyCompilationUnit) JavaCore.create((IFile) resource);
        if (unit != null && unit.isOnBuildPath()) {
          if (monitor.isCanceled()) {
            throw new OperationCanceledException();
          }
          monitor.subTask(resource.getName());
          handler.setResource((IFile) resource);
          Map<Integer, String> commentsMap = findComments(unit);
          StaticTypeCheckerRequestor requestor =
              new StaticTypeCheckerRequestor(handler, commentsMap, onlyAssertions);
          TypeInferencingVisitorWithRequestor visitor =
              new TypeInferencingVisitorFactory().createVisitor(unit);
          try {
            unit.becomeWorkingCopy(monitor);
            visitor.visitCompilationUnit(requestor);
          } finally {
            unit.discardWorkingCopy();
          }
        }
      }
      return true;
    }
  public boolean execute(IProgressMonitor progressMonitor) {

    if (this.isCancelled || progressMonitor != null && progressMonitor.isCanceled()) return true;

    /* ensure no concurrent write access to index */
    Index index =
        this.manager.getIndex(
            this.containerPath, true, /*reuse index file*/ false /*create if none*/);
    if (index == null) return true;
    ReadWriteMonitor monitor = index.monitor;
    if (monitor == null) return true; // index got deleted since acquired

    try {
      monitor.enterRead(); // ask permission to read
      String containerRelativePath =
          Util.relativePath(this.folderPath, this.containerPath.segmentCount());
      String[] paths = index.queryDocumentNames(containerRelativePath);
      // all file names belonging to the folder or its subfolders and that are not excluded (see
      // http://bugs.eclipse.org/bugs/show_bug.cgi?id=32607)
      if (paths != null) {
        if (this.exclusionPatterns == null && this.inclusionPatterns == null) {
          for (int i = 0, max = paths.length; i < max; i++) {
            manager.remove(
                paths[i],
                this.containerPath); // write lock will be acquired by the remove operation
          }
        } else {
          for (int i = 0, max = paths.length; i < max; i++) {
            String documentPath = this.containerPath.toString() + '/' + paths[i];
            if (!Util.isExcluded(
                new Path(documentPath), this.inclusionPatterns, this.exclusionPatterns, false))
              manager.remove(
                  paths[i],
                  this.containerPath); // write lock will be acquired by the remove operation
          }
        }
      }
    } catch (IOException e) {
      if (JobManager.VERBOSE) {
        Util.verbose(
            "-> failed to remove "
                + this.folderPath
                + " from index because of the following exception:",
            System.err); // $NON-NLS-1$ //$NON-NLS-2$
        e.printStackTrace();
      }
      return false;
    } finally {
      monitor.exitRead(); // free read lock
    }
    return true;
  }
 /**
  * Creates any destination package fragment(s) which do not exists yet. Return true if a read-only
  * package fragment has been found among package fragments, false otherwise
  */
 private boolean createNeededPackageFragments(
     IContainer sourceFolder, PackageFragmentRoot root, String[] newFragName, boolean moveFolder)
     throws JavaModelException {
   boolean containsReadOnlyPackageFragment = false;
   IContainer parentFolder = (IContainer) root.resource();
   JavaElementDelta projectDelta = null;
   String[] sideEffectPackageName = null;
   char[][] inclusionPatterns = root.fullInclusionPatternChars();
   char[][] exclusionPatterns = root.fullExclusionPatternChars();
   for (int i = 0; i < newFragName.length; i++) {
     String subFolderName = newFragName[i];
     sideEffectPackageName = Util.arrayConcat(sideEffectPackageName, subFolderName);
     IResource subFolder = parentFolder.findMember(subFolderName);
     if (subFolder == null) {
       // create deepest folder only if not a move (folder will be moved in
       // processPackageFragmentResource)
       if (!(moveFolder && i == newFragName.length - 1)) {
         createFolder(parentFolder, subFolderName, this.force);
       }
       parentFolder = parentFolder.getFolder(new Path(subFolderName));
       sourceFolder = sourceFolder.getFolder(new Path(subFolderName));
       if (Util.isReadOnly(sourceFolder)) {
         containsReadOnlyPackageFragment = true;
       }
       IPackageFragment sideEffectPackage = root.getPackageFragment(sideEffectPackageName);
       if (i < newFragName.length - 1 // all but the last one are side effect packages
           && !Util.isExcluded(parentFolder, inclusionPatterns, exclusionPatterns)) {
         if (projectDelta == null) {
           projectDelta = getDeltaFor(root.getJavaProject());
         }
         projectDelta.added(sideEffectPackage);
       }
       this.createdElements.add(sideEffectPackage);
     } else {
       parentFolder = (IContainer) subFolder;
     }
   }
   return containsReadOnlyPackageFragment;
 }
  protected boolean findSourceFiles(
      IResourceDelta sourceDelta, ClasspathMultiDirectory md, int segmentCount)
      throws CoreException {
    // When a package becomes a type or vice versa, expect 2 deltas,
    // one on the folder & one on the source file
    IResource resource = sourceDelta.getResource();
    // remember that if inclusion & exclusion patterns change then a full build is done
    boolean isExcluded =
        (md.exclusionPatterns != null || md.inclusionPatterns != null)
            && Util.isExcluded(resource, md.inclusionPatterns, md.exclusionPatterns);
    switch (resource.getType()) {
      case IResource.FOLDER:
        if (isExcluded && md.inclusionPatterns == null)
          return true; // no need to go further with this delta since its children cannot be
        // included

        switch (sourceDelta.getKind()) {
          case IResourceDelta.ADDED:
            if (!isExcluded) {
              IPath addedPackagePath = resource.getFullPath().removeFirstSegments(segmentCount);
              createFolder(
                  addedPackagePath, md.binaryFolder); // ensure package exists in the output folder
              // see if any known source file is from the same package... classpath already includes
              // new package
              if (this.sourceLocations.length > 1
                  && this.newState.isKnownPackage(addedPackagePath.toString())) {
                if (JavaBuilder.DEBUG)
                  System.out.println(
                      "Skipped dependents of added package " + addedPackagePath); // $NON-NLS-1$
              } else {
                if (JavaBuilder.DEBUG)
                  System.out.println("Found added package " + addedPackagePath); // $NON-NLS-1$
                addDependentsOf(addedPackagePath, true);
              }
            }
            // $FALL-THROUGH$ collect all the source files
          case IResourceDelta.CHANGED:
            IResourceDelta[] children = sourceDelta.getAffectedChildren();
            for (int i = 0, l = children.length; i < l; i++)
              if (!findSourceFiles(children[i], md, segmentCount)) return false;
            return true;
          case IResourceDelta.REMOVED:
            if (isExcluded) {
              // since this folder is excluded then there is nothing to delete (from this md), but
              // must walk any included subfolders
              children = sourceDelta.getAffectedChildren();
              for (int i = 0, l = children.length; i < l; i++)
                if (!findSourceFiles(children[i], md, segmentCount)) return false;
              return true;
            }
            IPath removedPackagePath = resource.getFullPath().removeFirstSegments(segmentCount);
            if (this.sourceLocations.length > 1) {
              for (int i = 0, l = this.sourceLocations.length; i < l; i++) {
                if (this.sourceLocations[i].sourceFolder.getFolder(removedPackagePath).exists()) {
                  // only a package fragment was removed, same as removing multiple source files
                  createFolder(
                      removedPackagePath,
                      md.binaryFolder); // ensure package exists in the output folder
                  IResourceDelta[] removedChildren = sourceDelta.getAffectedChildren();
                  for (int j = 0, m = removedChildren.length; j < m; j++)
                    if (!findSourceFiles(removedChildren[j], md, segmentCount)) return false;
                  return true;
                }
              }
            }
            if ((sourceDelta.getFlags() & IResourceDelta.MOVED_TO) != 0) {
              // same idea as moving a source file
              // see bug 163200
              IResource movedFolder =
                  this.javaBuilder.workspaceRoot.getFolder(sourceDelta.getMovedToPath());
              JavaBuilder.removeProblemsAndTasksFor(movedFolder);
            }
            IFolder removedPackageFolder = md.binaryFolder.getFolder(removedPackagePath);
            if (removedPackageFolder.exists()) removedPackageFolder.delete(IResource.FORCE, null);
            // add dependents even when the package thinks it does not exist to be on the safe side
            if (JavaBuilder.DEBUG)
              System.out.println("Found removed package " + removedPackagePath); // $NON-NLS-1$
            addDependentsOf(removedPackagePath, true);
            this.newState.removePackage(sourceDelta);
        }
        return true;
      case IResource.FILE:
        if (isExcluded) return true;

        String resourceName = resource.getName();
        // GROOVY start
        // determine if this is a Groovy project
        final boolean isInterestingProject =
            LanguageSupportFactory.isInterestingProject(this.javaBuilder.getProject());
        // GROOVY end

        // GROOVY start
        /* old {
        if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(resourceName)) {
        } new */
        // GRECLIPSE-404 must call 'isJavaLikeFile' directly in order to make the Scala-Eclipse
        // plugin's weaving happy
        if ((!isInterestingProject
                && org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(resourceName)
                && !LanguageSupportFactory.isInterestingSourceFile(resourceName))
            || (isInterestingProject
                && LanguageSupportFactory.isSourceFile(resourceName, isInterestingProject))) {
          // GROOVY end
          IPath typePath =
              resource.getFullPath().removeFirstSegments(segmentCount).removeFileExtension();
          String typeLocator = resource.getProjectRelativePath().toString();
          switch (sourceDelta.getKind()) {
            case IResourceDelta.ADDED:
              if (JavaBuilder.DEBUG)
                System.out.println("Compile this added source file " + typeLocator); // $NON-NLS-1$
              this.sourceFiles.add(new SourceFile((IFile) resource, md, true));
              String typeName = typePath.toString();
              if (!this.newState.isDuplicateLocator(
                  typeName, typeLocator)) { // adding dependents results in 2 duplicate errors
                if (JavaBuilder.DEBUG)
                  System.out.println("Found added source file " + typeName); // $NON-NLS-1$
                addDependentsOf(typePath, true);
              }
              return true;
            case IResourceDelta.REMOVED:
              char[][] definedTypeNames = this.newState.getDefinedTypeNamesFor(typeLocator);
              if (definedTypeNames == null) { // defined a single type matching typePath
                removeClassFile(typePath, md.binaryFolder);
                if ((sourceDelta.getFlags() & IResourceDelta.MOVED_TO) != 0) {
                  // remove problems and tasks for a compilation unit that is being moved (to
                  // another package or renamed)
                  // if the target file is a compilation unit, the new cu will be recompiled
                  // if the target file is a non-java resource, then markers are removed
                  // see bug 2857
                  IResource movedFile =
                      this.javaBuilder.workspaceRoot.getFile(sourceDelta.getMovedToPath());
                  JavaBuilder.removeProblemsAndTasksFor(movedFile);
                }
              } else {
                if (JavaBuilder.DEBUG)
                  System.out.println(
                      "Found removed source file " + typePath.toString()); // $NON-NLS-1$
                addDependentsOf(
                    typePath,
                    true); // add dependents of the source file since it may be involved in a name
                // collision
                if (definedTypeNames.length
                    > 0) { // skip it if it failed to successfully define a type
                  IPath packagePath = typePath.removeLastSegments(1);
                  for (int i = 0, l = definedTypeNames.length; i < l; i++)
                    removeClassFile(
                        packagePath.append(new String(definedTypeNames[i])), md.binaryFolder);
                }
              }
              this.newState.removeLocator(typeLocator);
              return true;
            case IResourceDelta.CHANGED:
              if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0
                  && (sourceDelta.getFlags() & IResourceDelta.ENCODING) == 0)
                return true; // skip it since it really isn't changed
              if (JavaBuilder.DEBUG)
                System.out.println(
                    "Compile this changed source file " + typeLocator); // $NON-NLS-1$
              this.sourceFiles.add(new SourceFile((IFile) resource, md, true));
          }
          return true;
        } else if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(resourceName)) {
          // perform full build if a managed class file has been changed
          if (this.makeOutputFolderConsistent) {
            IPath typePath =
                resource.getFullPath().removeFirstSegments(segmentCount).removeFileExtension();
            if (this.newState.isKnownType(typePath.toString())) {
              if (JavaBuilder.DEBUG)
                System.out.println(
                    "MUST DO FULL BUILD. Found change to class file " + typePath); // $NON-NLS-1$
              return false;
            }
          }
          return true;
        } else if (md.hasIndependentOutputFolder) {
          if (this.javaBuilder.filterExtraResource(resource)) return true;

          // copy all other resource deltas to the output folder
          IPath resourcePath = resource.getFullPath().removeFirstSegments(segmentCount);
          IResource outputFile = md.binaryFolder.getFile(resourcePath);
          switch (sourceDelta.getKind()) {
            case IResourceDelta.ADDED:
              if (outputFile.exists()) {
                if (JavaBuilder.DEBUG)
                  System.out.println("Deleting existing file " + resourcePath); // $NON-NLS-1$
                outputFile.delete(IResource.FORCE, null);
              }
              if (JavaBuilder.DEBUG)
                System.out.println("Copying added file " + resourcePath); // $NON-NLS-1$
              createFolder(
                  resourcePath.removeLastSegments(1),
                  md.binaryFolder); // ensure package exists in the output folder
              copyResource(resource, outputFile);
              return true;
            case IResourceDelta.REMOVED:
              if (outputFile.exists()) {
                if (JavaBuilder.DEBUG)
                  System.out.println("Deleting removed file " + resourcePath); // $NON-NLS-1$
                outputFile.delete(IResource.FORCE, null);
              }
              return true;
            case IResourceDelta.CHANGED:
              if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0
                  && (sourceDelta.getFlags() & IResourceDelta.ENCODING) == 0)
                return true; // skip it since it really isn't changed
              if (outputFile.exists()) {
                if (JavaBuilder.DEBUG)
                  System.out.println("Deleting existing file " + resourcePath); // $NON-NLS-1$
                outputFile.delete(IResource.FORCE, null);
              }
              if (JavaBuilder.DEBUG)
                System.out.println("Copying changed file " + resourcePath); // $NON-NLS-1$
              createFolder(
                  resourcePath.removeLastSegments(1),
                  md.binaryFolder); // ensure package exists in the output folder
              copyResource(resource, outputFile);
          }
          return true;
        }
    }
    return true;
  }
  /**
   * Copies/moves a package fragment with the name <code>newName</code> to the destination package.
   * <br>
   *
   * @exception JavaModelException if the operation is unable to complete
   */
  private void processPackageFragmentResource(
      PackageFragment source, PackageFragmentRoot root, String newName) throws JavaModelException {
    try {
      String[] newFragName = (newName == null) ? source.names : Util.getTrimmedSimpleNames(newName);
      PackageFragment newFrag = root.getPackageFragment(newFragName);
      IResource[] resources = collectResourcesOfInterest(source);

      // if isMove() can we move the folder itself ? (see
      // http://bugs.eclipse.org/bugs/show_bug.cgi?id=22458)
      boolean shouldMoveFolder =
          isMove() && !newFrag.resource().exists(); // if new pkg fragment exists, it is an override
      IFolder srcFolder = (IFolder) source.resource();
      IPath destPath = newFrag.getPath();
      if (shouldMoveFolder) {
        // check if destination is not included in source
        if (srcFolder.getFullPath().isPrefixOf(destPath)) {
          shouldMoveFolder = false;
        } else {
          // check if there are no sub-packages
          IResource[] members = srcFolder.members();
          for (int i = 0; i < members.length; i++) {
            if (members[i] instanceof IFolder) {
              shouldMoveFolder = false;
              break;
            }
          }
        }
      }
      boolean containsReadOnlySubPackageFragments =
          createNeededPackageFragments(
              (IContainer) source.parent.resource(), root, newFragName, shouldMoveFolder);
      boolean sourceIsReadOnly = Util.isReadOnly(srcFolder);

      // Process resources
      if (shouldMoveFolder) {
        // move underlying resource
        // TODO Revisit once bug 43044 is fixed
        if (sourceIsReadOnly) {
          Util.setReadOnly(srcFolder, false);
        }
        srcFolder.move(destPath, this.force, true /* keep history */, getSubProgressMonitor(1));
        if (sourceIsReadOnly) {
          Util.setReadOnly(srcFolder, true);
        }
        setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
      } else {
        // process the leaf resources
        if (resources.length > 0) {
          if (isRename()) {
            if (!destPath.equals(source.getPath())) {
              moveResources(resources, destPath);
            }
          } else if (isMove()) {
            // we need to delete this resource if this operation wants to override existing
            // resources
            for (int i = 0, max = resources.length; i < max; i++) {
              IResource destinationResource =
                  ResourcesPlugin.getWorkspace()
                      .getRoot()
                      .findMember(destPath.append(resources[i].getName()));
              if (destinationResource != null) {
                if (this.force) {
                  deleteResource(destinationResource, IResource.KEEP_HISTORY);
                } else {
                  throw new JavaModelException(
                      new JavaModelStatus(
                          IJavaModelStatusConstants.NAME_COLLISION,
                          Messages.bind(
                              Messages.status_nameCollision,
                              destinationResource.getFullPath().toString())));
                }
              }
            }
            moveResources(resources, destPath);
          } else {
            // we need to delete this resource if this operation wants to override existing
            // resources
            for (int i = 0, max = resources.length; i < max; i++) {
              IResource destinationResource =
                  ResourcesPlugin.getWorkspace()
                      .getRoot()
                      .findMember(destPath.append(resources[i].getName()));
              if (destinationResource != null) {
                if (this.force) {
                  // we need to delete this resource if this operation wants to override existing
                  // resources
                  deleteResource(destinationResource, IResource.KEEP_HISTORY);
                } else {
                  throw new JavaModelException(
                      new JavaModelStatus(
                          IJavaModelStatusConstants.NAME_COLLISION,
                          Messages.bind(
                              Messages.status_nameCollision,
                              destinationResource.getFullPath().toString())));
                }
              }
            }
            copyResources(resources, destPath);
          }
        }
      }

      // Update package statement in compilation unit if needed
      if (!Util.equalArraysOrNull(
          newFragName, source.names)) { // if package has been renamed, update the compilation units
        char[][] inclusionPatterns = root.fullInclusionPatternChars();
        char[][] exclusionPatterns = root.fullExclusionPatternChars();
        for (int i = 0; i < resources.length; i++) {
          String resourceName = resources[i].getName();
          if (Util.isJavaLikeFileName(resourceName)) {
            // we only consider potential compilation units
            ICompilationUnit cu = newFrag.getCompilationUnit(resourceName);
            if (Util.isExcluded(
                cu.getPath(), inclusionPatterns, exclusionPatterns, false /*not a folder*/))
              continue;
            this.parser.setSource(cu);
            CompilationUnit astCU = (CompilationUnit) this.parser.createAST(this.progressMonitor);
            AST ast = astCU.getAST();
            ASTRewrite rewrite = ASTRewrite.create(ast);
            updatePackageStatement(astCU, newFragName, rewrite, cu);
            TextEdit edits = rewrite.rewriteAST();
            applyTextEdit(cu, edits);
            cu.save(null, false);
          }
        }
      }

      // Discard empty old package (if still empty after the rename)
      boolean isEmpty = true;
      if (isMove()) {
        // delete remaining files in this package (.class file in the case where Proj=src=bin)
        // in case of a copy
        updateReadOnlyPackageFragmentsForMove(
            (IContainer) source.parent.resource(), root, newFragName, sourceIsReadOnly);
        if (srcFolder.exists()) {
          IResource[] remaining = srcFolder.members();
          for (int i = 0, length = remaining.length; i < length; i++) {
            IResource file = remaining[i];
            if (file instanceof IFile) {
              if (Util.isReadOnly(file)) {
                Util.setReadOnly(file, false);
              }
              deleteResource(file, IResource.FORCE | IResource.KEEP_HISTORY);
            } else {
              isEmpty = false;
            }
          }
        }
        if (isEmpty) {
          IResource rootResource;
          // check if source is included in destination
          if (destPath.isPrefixOf(srcFolder.getFullPath())) {
            rootResource = newFrag.resource();
          } else {
            rootResource = source.parent.resource();
          }

          // delete recursively empty folders
          deleteEmptyPackageFragment(source, false, rootResource);
        }
      } else if (containsReadOnlySubPackageFragments) {
        // in case of a copy
        updateReadOnlyPackageFragmentsForCopy(
            (IContainer) source.parent.resource(), root, newFragName);
      }
      // workaround for bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=24505
      if (isEmpty && isMove() && !(Util.isExcluded(source) || Util.isExcluded(newFrag))) {
        IJavaProject sourceProject = source.getJavaProject();
        getDeltaFor(sourceProject).movedFrom(source, newFrag);
        IJavaProject destProject = newFrag.getJavaProject();
        getDeltaFor(destProject).movedTo(newFrag, source);
      }
    } catch (JavaModelException e) {
      throw e;
    } catch (CoreException ce) {
      throw new JavaModelException(ce);
    }
  }
  /** @exception JavaModelException if setting the source of the original compilation unit fails */
  protected void executeOperation() throws JavaModelException {
    try {
      beginTask(Messages.workingCopy_commit, 2);
      CompilationUnit workingCopy = getCompilationUnit();

      if (ExternalJavaProject.EXTERNAL_PROJECT_NAME.equals(
          workingCopy.getJavaProject().getElementName())) {
        // case of a working copy without a resource
        workingCopy.getBuffer().save(this.progressMonitor, this.force);
        return;
      }

      ICompilationUnit primary = workingCopy.getPrimary();
      boolean isPrimary = workingCopy.isPrimary();

      JavaElementDeltaBuilder deltaBuilder = null;
      PackageFragmentRoot root =
          (PackageFragmentRoot) workingCopy.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
      boolean isIncluded = !Util.isExcluded(workingCopy);
      IFile resource = (IFile) workingCopy.getResource();
      IJavaProject project = root.getJavaProject();
      if (isPrimary
          || (root.validateOnClasspath().isOK()
              && isIncluded
              && resource.isAccessible()
              && Util.isValidCompilationUnitName(
                  workingCopy.getElementName(),
                  project.getOption(JavaCore.COMPILER_SOURCE, true),
                  project.getOption(JavaCore.COMPILER_COMPLIANCE, true)))) {

        // force opening so that the delta builder can get the old info
        if (!isPrimary && !primary.isOpen()) {
          primary.open(null);
        }

        // creates the delta builder (this remembers the content of the cu) if:
        // - it is not excluded
        // - and it is not a primary or it is a non-consistent primary
        if (isIncluded && (!isPrimary || !workingCopy.isConsistent())) {
          deltaBuilder = new JavaElementDeltaBuilder(primary);
        }

        // save the cu
        IBuffer primaryBuffer = primary.getBuffer();
        if (!isPrimary) {
          if (primaryBuffer == null) return;
          char[] primaryContents = primaryBuffer.getCharacters();
          boolean hasSaved = false;
          try {
            IBuffer workingCopyBuffer = workingCopy.getBuffer();
            if (workingCopyBuffer == null) return;
            primaryBuffer.setContents(workingCopyBuffer.getCharacters());
            primaryBuffer.save(this.progressMonitor, this.force);
            primary.makeConsistent(this);
            hasSaved = true;
          } finally {
            if (!hasSaved) {
              // restore original buffer contents since something went wrong
              primaryBuffer.setContents(primaryContents);
            }
          }
        } else {
          // for a primary working copy no need to set the content of the buffer again
          primaryBuffer.save(this.progressMonitor, this.force);
          primary.makeConsistent(this);
        }
      } else {
        // working copy on cu outside classpath OR resource doesn't exist yet
        String encoding = null;
        try {
          encoding = resource.getCharset();
        } catch (CoreException ce) {
          // use no encoding
        }
        String contents = workingCopy.getSource();
        if (contents == null) return;
        try {
          byte[] bytes = encoding == null ? contents.getBytes() : contents.getBytes(encoding);
          ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
          if (resource.exists()) {
            resource.setContents(
                stream,
                this.force ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY,
                null);
          } else {
            resource.create(stream, this.force, this.progressMonitor);
          }
        } catch (CoreException e) {
          throw new JavaModelException(e);
        } catch (UnsupportedEncodingException e) {
          throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
        }
      }

      setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);

      // make sure working copy is in sync
      workingCopy.updateTimeStamp((CompilationUnit) primary);
      workingCopy.makeConsistent(this);
      worked(1);

      // build the deltas
      if (deltaBuilder != null) {
        deltaBuilder.buildDeltas();

        // add the deltas to the list of deltas created during this operation
        if (deltaBuilder.delta != null) {
          addDelta(deltaBuilder.delta);
        }
      }
      worked(1);
    } finally {
      done();
    }
  }
  /** Compute the non-java resources contained in this java project. */
  private Object[] computeNonJavaResources(JavaProject project) {

    // determine if src == project and/or if bin == project
    IPath projectPath = project.getProject().getFullPath();
    boolean srcIsProject = false;
    boolean binIsProject = false;
    char[][] inclusionPatterns = null;
    char[][] exclusionPatterns = null;
    IPath projectOutput = null;
    boolean isClasspathResolved = true;
    try {
      IClasspathEntry entry = project.getClasspathEntryFor(projectPath);
      if (entry != null) {
        srcIsProject = true;
        inclusionPatterns = ((ClasspathEntry) entry).fullInclusionPatternChars();
        exclusionPatterns = ((ClasspathEntry) entry).fullExclusionPatternChars();
      }
      projectOutput = project.getOutputLocation();
      binIsProject = projectPath.equals(projectOutput);
    } catch (JavaModelException e) {
      isClasspathResolved = false;
    }

    Object[] resources = new IResource[5];
    int resourcesCounter = 0;
    try {
      IResource[] members = ((IContainer) project.getResource()).members();
      int length = members.length;
      if (length > 0) {
        String sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true);
        String complianceLevel = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
        IClasspathEntry[] classpath = project.getResolvedClasspath();
        for (int i = 0; i < length; i++) {
          IResource res = members[i];
          switch (res.getType()) {
            case IResource.FILE:
              IPath resFullPath = res.getFullPath();
              String resName = res.getName();

              // ignore a jar file on the classpath
              if (isClasspathResolved
                  && isClasspathEntryOrOutputLocation(
                      resFullPath,
                      res.getLocation() /* see https://bugs.eclipse
                                .org/bugs/show_bug.cgi?id=244406 */,
                      classpath,
                      projectOutput)) {
                break;
              }
              // ignore .java file if src == project
              if (srcIsProject
                  && Util.isValidCompilationUnitName(resName, sourceLevel, complianceLevel)
                  && !Util.isExcluded(res, inclusionPatterns, exclusionPatterns)) {
                break;
              }
              // ignore .class file if bin == project
              if (binIsProject
                  && Util.isValidClassFileName(resName, sourceLevel, complianceLevel)) {
                break;
              }
              // else add non java resource
              if (resources.length == resourcesCounter) {
                // resize
                System.arraycopy(
                    resources,
                    0,
                    (resources = new IResource[resourcesCounter * 2]),
                    0,
                    resourcesCounter);
              }
              resources[resourcesCounter++] = res;
              break;
            case IResource.FOLDER:
              resFullPath = res.getFullPath();

              // ignore non-excluded folders on the classpath or that correspond to an output
              // location
              if ((srcIsProject
                      && !Util.isExcluded(res, inclusionPatterns, exclusionPatterns)
                      && Util.isValidFolderNameForPackage(
                          res.getName(), sourceLevel, complianceLevel))
                  || (isClasspathResolved
                      && isClasspathEntryOrOutputLocation(
                          resFullPath, res.getLocation(), classpath, projectOutput))) {
                break;
              }
              // else add non java resource
              if (resources.length == resourcesCounter) {
                // resize
                System.arraycopy(
                    resources,
                    0,
                    (resources = new IResource[resourcesCounter * 2]),
                    0,
                    resourcesCounter);
              }
              resources[resourcesCounter++] = res;
          }
        }
      }
      if (resources.length != resourcesCounter) {
        System.arraycopy(
            resources, 0, (resources = new IResource[resourcesCounter]), 0, resourcesCounter);
      }
    } catch (CoreException e) {
      resources = NO_NON_JAVA_RESOURCES;
      resourcesCounter = 0;
    }
    return resources;
  }