Package org.aspectj.org.eclipse.jdt.internal.core.builder

Source Code of org.aspectj.org.eclipse.jdt.internal.core.builder.AbstractImageBuilder

/*******************************************************************************
* Copyright (c) 2000, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.core.builder;

import org.eclipse.core.runtime.*;
import org.eclipse.core.resources.*;

import org.aspectj.org.eclipse.jdt.core.*;
import org.aspectj.org.eclipse.jdt.core.compiler.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.Compiler;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.aspectj.org.eclipse.jdt.internal.compiler.problem.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.SimpleSet;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.aspectj.org.eclipse.jdt.internal.core.JavaModelManager;
import org.aspectj.org.eclipse.jdt.internal.core.util.Messages;
import org.aspectj.org.eclipse.jdt.internal.core.util.Util;

import java.io.*;
import java.util.*;

/**
* The abstract superclass of Java builders.
* Provides the building and compilation mechanism
* in common with the batch and incremental builders.
*/
public abstract class AbstractImageBuilder implements ICompilerRequestor, ICompilationUnitLocator {

protected JavaBuilder javaBuilder;
protected State newState;

// local copies
protected NameEnvironment nameEnvironment;
protected ClasspathMultiDirectory[] sourceLocations;
protected BuildNotifier notifier;

protected Compiler compiler;
protected WorkQueue workQueue;
protected ArrayList problemSourceFiles;
protected boolean compiledAllAtOnce;

private boolean inCompiler;

protected boolean keepStoringProblemMarkers;
protected SimpleSet filesWithAnnotations = null;

public static int MAX_AT_ONCE = 2000; // best compromise between space used and speed
public final static String[] JAVA_PROBLEM_MARKER_ATTRIBUTE_NAMES = {
  IMarker.MESSAGE,
  IMarker.SEVERITY,
  IJavaModelMarker.ID,
  IMarker.CHAR_START,
  IMarker.CHAR_END,
  IMarker.LINE_NUMBER,
  IJavaModelMarker.ARGUMENTS,
  IJavaModelMarker.CATEGORY_ID, 
};
public final static String[] JAVA_TASK_MARKER_ATTRIBUTE_NAMES = {
  IMarker.MESSAGE,
  IMarker.PRIORITY,
  IJavaModelMarker.ID,
  IMarker.CHAR_START,
  IMarker.CHAR_END,
  IMarker.LINE_NUMBER,
  IMarker.USER_EDITABLE,
  IMarker.SOURCE_ID,
};
public final static Integer S_ERROR = new Integer(IMarker.SEVERITY_ERROR);
public final static Integer S_WARNING = new Integer(IMarker.SEVERITY_WARNING);
public final static Integer P_HIGH = new Integer(IMarker.PRIORITY_HIGH);
public final static Integer P_NORMAL = new Integer(IMarker.PRIORITY_NORMAL);
public final static Integer P_LOW = new Integer(IMarker.PRIORITY_LOW);

protected AbstractImageBuilder(JavaBuilder javaBuilder, boolean buildStarting, State newState) {
  // local copies
  this.javaBuilder = javaBuilder;
  this.nameEnvironment = javaBuilder.nameEnvironment;
  this.sourceLocations = this.nameEnvironment.sourceLocations;
  this.notifier = javaBuilder.notifier;
  this.keepStoringProblemMarkers = true; // may get disabled when missing classfiles are encountered

  if (buildStarting) {
    this.newState = newState == null ? new State(javaBuilder) : newState;
    this.compiler = newCompiler();
    this.workQueue = new WorkQueue();
    this.problemSourceFiles = new ArrayList(3);

    if (this.javaBuilder.participants != null) {
      for (int i = 0, l = this.javaBuilder.participants.length; i < l; i++) {
        if (this.javaBuilder.participants[i].isAnnotationProcessor()) {
          // initialize this set so the builder knows to gather CUs that define Annotation types
          // each Annotation processor participant is then asked to process these files AFTER
          // the compile loop. The normal dependency loop will then recompile all affected types
          this.filesWithAnnotations = new SimpleSet(1);
          break;
        }
      }
    }
  }
}

public void acceptResult(CompilationResult result) {
  // In Batch mode, we write out the class files, hold onto the dependency info
  // & additional types and report problems.

  // In Incremental mode, when writing out a class file we need to compare it
  // against the previous file, remembering if structural changes occured.
  // Before reporting the new problems, we need to update the problem count &
  // remove the old problems. Plus delete additional class files that no longer exist.

  SourceFile compilationUnit = (SourceFile) result.getCompilationUnit(); // go directly back to the sourceFile
  if (!workQueue.isCompiled(compilationUnit)) {
    workQueue.finished(compilationUnit);

    try {
      updateProblemsFor(compilationUnit, result); // record compilation problems before potentially adding duplicate errors
      updateTasksFor(compilationUnit, result); // record tasks
    } catch (CoreException e) {
      throw internalException(e);
    }

    if (result.hasInconsistentToplevelHierarchies)
      // ensure that this file is always retrieved from source for the rest of the build
      if (!problemSourceFiles.contains(compilationUnit))
        problemSourceFiles.add(compilationUnit);

    IType mainType = null;
    String mainTypeName = null;
    String typeLocator = compilationUnit.typeLocator();
    ClassFile[] classFiles = result.getClassFiles();
    int length = classFiles.length;
    ArrayList duplicateTypeNames = null;
    ArrayList definedTypeNames = new ArrayList(length);
    for (int i = 0; i < length; i++) {
      ClassFile classFile = classFiles[i];

      char[][] compoundName = classFile.getCompoundName();
      char[] typeName = compoundName[compoundName.length - 1];
      boolean isNestedType = classFile.enclosingClassFile != null;

      // Look for a possible collision, if one exists, report an error but do not write the class file
      if (isNestedType) {
        String qualifiedTypeName = new String(classFile.outerMostEnclosingClassFile().fileName());
        if (newState.isDuplicateLocator(qualifiedTypeName, typeLocator))
          continue;
      } else {
        String qualifiedTypeName = new String(classFile.fileName()); // the qualified type name "p1/p2/A"
        if (newState.isDuplicateLocator(qualifiedTypeName, typeLocator)) {
          if (duplicateTypeNames == null)
            duplicateTypeNames = new ArrayList();
          duplicateTypeNames.add(compoundName);
          if (mainType == null) {
            try {
              mainTypeName = compilationUnit.initialTypeName; // slash separated qualified name "p1/p1/A"
              mainType = javaBuilder.javaProject.findType(mainTypeName.replace('/', '.'));
            } catch (JavaModelException e) {
              // ignore
            }
          }
          IType type;
          if (qualifiedTypeName.equals(mainTypeName)) {
            type = mainType;
          } else {
            String simpleName = qualifiedTypeName.substring(qualifiedTypeName.lastIndexOf('/')+1);
            type = mainType == null ? null : mainType.getCompilationUnit().getType(simpleName);
          }
          createProblemFor(compilationUnit.resource, type, Messages.bind(Messages.build_duplicateClassFile, new String(typeName)), JavaCore.ERROR);
          continue;
        }
        newState.recordLocatorForType(qualifiedTypeName, typeLocator);
        if (!qualifiedTypeName.equals(compilationUnit.initialTypeName))
          acceptSecondaryType(classFile);
      }
      try {
        definedTypeNames.add(writeClassFile(classFile, compilationUnit, !isNestedType));
      } catch (CoreException e) {
        Util.log(e, "JavaBuilder handling CoreException"); //$NON-NLS-1$
        if (e.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS)
          createProblemFor(compilationUnit.resource, null, Messages.bind(Messages.build_classFileCollision, e.getMessage()), JavaCore.ERROR);
        else
          createProblemFor(compilationUnit.resource, null, Messages.build_inconsistentClassFile, JavaCore.ERROR);
      }
    }
    if (result.hasAnnotations && this.filesWithAnnotations != null) // only initialized if an annotation processor is attached
      this.filesWithAnnotations.add(compilationUnit);

    finishedWith(typeLocator, result, compilationUnit.getMainTypeName(), definedTypeNames, duplicateTypeNames);
    notifier.compiled(compilationUnit);
  }
}

protected void acceptSecondaryType(ClassFile classFile) {
  // noop
}

protected void addAllSourceFiles(final ArrayList sourceFiles) throws CoreException {
  for (int i = 0, l = sourceLocations.length; i < l; i++) {
    final ClasspathMultiDirectory sourceLocation = sourceLocations[i];
    final char[][] exclusionPatterns = sourceLocation.exclusionPatterns;
    final char[][] inclusionPatterns = sourceLocation.inclusionPatterns;
    final boolean isAlsoProject = sourceLocation.sourceFolder.equals(javaBuilder.currentProject);
    final int segmentCount = sourceLocation.sourceFolder.getFullPath().segmentCount();
    final IContainer outputFolder = sourceLocation.binaryFolder;
    final boolean isOutputFolder = sourceLocation.sourceFolder.equals(outputFolder);
    sourceLocation.sourceFolder.accept(
      new IResourceProxyVisitor() {
        public boolean visit(IResourceProxy proxy) throws CoreException {
          switch(proxy.getType()) {
            case IResource.FILE :
              if (org.aspectj.org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(proxy.getName())) {
                IResource resource = proxy.requestResource();
                if (exclusionPatterns != null || inclusionPatterns != null)
                  if (Util.isExcluded(resource.getFullPath(), inclusionPatterns, exclusionPatterns, false))
                    return false;
                sourceFiles.add(new SourceFile((IFile) resource, sourceLocation));
              }
              return false;
            case IResource.FOLDER :
              IPath folderPath = null;
              if (isAlsoProject)
                if (isExcludedFromProject(folderPath = proxy.requestFullPath()))
                  return false;
              if (exclusionPatterns != null) {
                if (folderPath == null)
                  folderPath = proxy.requestFullPath();
                if (Util.isExcluded(folderPath, inclusionPatterns, exclusionPatterns, true)) {
                  // must walk children if inclusionPatterns != null, can skip them if == null
                  // but folder is excluded so do not create it in the output folder
                  return inclusionPatterns != null;
                }
              }
              if (!isOutputFolder) {
                if (folderPath == null)
                  folderPath = proxy.requestFullPath();
                String packageName = folderPath.lastSegment();
                if (packageName.length() > 0) {
                  String sourceLevel = javaBuilder.javaProject.getOption(JavaCore.COMPILER_SOURCE, true);
                  String complianceLevel = javaBuilder.javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true);
                  if (JavaConventions.validatePackageName(packageName, sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR)
                    createFolder(folderPath.removeFirstSegments(segmentCount), outputFolder);
                }
              }
          }
          return true;
        }
      },
      IResource.NONE
    );
    notifier.checkCancel();
  }
}

protected void cleanUp() {
  this.nameEnvironment.cleanup();

  this.javaBuilder = null;
  this.nameEnvironment = null;
  this.sourceLocations = null;
  this.notifier = null;
  this.compiler = null;
  this.workQueue = null;
  this.problemSourceFiles = null;
}

/* Compile the given elements, adding more elements to the work queue
* if they are affected by the changes.
*/
protected void compile(SourceFile[] units) {
  if (this.filesWithAnnotations != null && this.filesWithAnnotations.elementSize > 0)
    // will add files that have annotations in acceptResult() & then processAnnotations() before exitting this method
    this.filesWithAnnotations.clear();

  // notify CompilationParticipants which source files are about to be compiled
  BuildContext[] participantResults = this.javaBuilder.participants == null ? null : notifyParticipants(units);
  if (participantResults != null && participantResults.length > units.length) {
    units = new SourceFile[participantResults.length];
    for (int i = participantResults.length; --i >= 0;)
      units[i] = participantResults[i].sourceFile;
  }

  int unitsLength = units.length;
  this.compiledAllAtOnce = unitsLength <= MAX_AT_ONCE;
  if (this.compiledAllAtOnce) {
    // do them all now
    if (JavaBuilder.DEBUG)
      for (int i = 0; i < unitsLength; i++)
        System.out.println("About to compile " + units[i].typeLocator()); //$NON-NLS-1$
    compile(units, null, true);
  } else {
    SourceFile[] remainingUnits = new SourceFile[unitsLength]; // copy of units, removing units when about to compile
    System.arraycopy(units, 0, remainingUnits, 0, unitsLength);
    int doNow = unitsLength < MAX_AT_ONCE ? unitsLength : MAX_AT_ONCE;
    SourceFile[] toCompile = new SourceFile[doNow];
    int remainingIndex = 0;
    boolean compilingFirstGroup = true;
    while (remainingIndex < unitsLength) {
      int count = 0;
      while (remainingIndex < unitsLength && count < doNow) {
        // Although it needed compiling when this method was called, it may have
        // already been compiled when it was referenced by another unit.
        SourceFile unit = remainingUnits[remainingIndex];
        if (unit != null && (compilingFirstGroup || this.workQueue.isWaiting(unit))) {
          if (JavaBuilder.DEBUG)
            System.out.println("About to compile #" + remainingIndex + " : "+ unit.typeLocator()); //$NON-NLS-1$ //$NON-NLS-2$
          toCompile[count++] = unit;
        }
        remainingUnits[remainingIndex++] = null;
      }
      if (count < doNow)
        System.arraycopy(toCompile, 0, toCompile = new SourceFile[count], 0, count);
      if (!compilingFirstGroup)
        for (int a = remainingIndex; a < unitsLength; a++)
          if (remainingUnits[a] != null && this.workQueue.isCompiled(remainingUnits[a]))
            remainingUnits[a] = null; // use the class file for this source file since its been compiled
      compile(toCompile, remainingUnits, compilingFirstGroup);
      compilingFirstGroup = false;
    }
  }

  if (participantResults != null) {
    for (int i = participantResults.length; --i >= 0;)
      if (participantResults[i] != null)
        recordParticipantResult(participantResults[i]);

    processAnnotations(participantResults);
  }
}

protected void compile(SourceFile[] units, SourceFile[] additionalUnits, boolean compilingFirstGroup) {
  if (units.length == 0) return;
  notifier.aboutToCompile(units[0]); // just to change the message

  // extend additionalFilenames with all hierarchical problem types found during this entire build
  if (!problemSourceFiles.isEmpty()) {
    int toAdd = problemSourceFiles.size();
    int length = additionalUnits == null ? 0 : additionalUnits.length;
    if (length == 0)
      additionalUnits = new SourceFile[toAdd];
    else
      System.arraycopy(additionalUnits, 0, additionalUnits = new SourceFile[length + toAdd], 0, length);
    for (int i = 0; i < toAdd; i++)
      additionalUnits[length + i] = (SourceFile) problemSourceFiles.get(i);
  }
  String[] initialTypeNames = new String[units.length];
  for (int i = 0, l = units.length; i < l; i++)
    initialTypeNames[i] = units[i].initialTypeName;
  nameEnvironment.setNames(initialTypeNames, additionalUnits);
  notifier.checkCancel();
  try {
    inCompiler = true;
    compiler.compile(units);
  } catch (AbortCompilation ignored) {
    // ignore the AbortCompilcation coming from BuildNotifier.checkCancelWithinCompiler()
    // the Compiler failed after the user has chose to cancel... likely due to an OutOfMemory error
  } finally {
    inCompiler = false;
  }
  // Check for cancel immediately after a compile, because the compiler may
  // have been cancelled but without propagating the correct exception
  notifier.checkCancel();
}

protected void createProblemFor(IResource resource, IMember javaElement, String message, String problemSeverity) {
  try {
    IMarker marker = resource.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
    int severity = problemSeverity.equals(JavaCore.WARNING) ? IMarker.SEVERITY_WARNING : IMarker.SEVERITY_ERROR;

    ISourceRange range = javaElement == null ? null : javaElement.getNameRange();
    int start = range == null ? 0 : range.getOffset();
    int end = range == null ? 1 : start + range.getLength();
    marker.setAttributes(
      new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IMarker.CHAR_START, IMarker.CHAR_END, IMarker.SOURCE_ID},
      new Object[] {message, new Integer(severity), new Integer(start), new Integer(end), JavaBuilder.SOURCE_ID});
  } catch (CoreException e) {
    throw internalException(e);
  }
}

protected void deleteGeneratedFiles(IFile[] deletedGeneratedFiles) {
  // no op by default
}

protected SourceFile findSourceFile(IFile file, boolean mustExist) {
  if (mustExist && !file.exists()) return null;

  // assumes the file exists in at least one of the source folders & is not excluded
  ClasspathMultiDirectory md = sourceLocations[0];
  if (sourceLocations.length > 1) {
    IPath sourceFileFullPath = file.getFullPath();
    for (int j = 0, m = sourceLocations.length; j < m; j++) {
      if (sourceLocations[j].sourceFolder.getFullPath().isPrefixOf(sourceFileFullPath)) {
        md = sourceLocations[j];
        if (md.exclusionPatterns == null && md.inclusionPatterns == null)
          break;
        if (!Util.isExcluded(file, md.inclusionPatterns, md.exclusionPatterns))
          break;
      }
    }
  }
  return new SourceFile(file, md);
}

protected void finishedWith(String sourceLocator, CompilationResult result, char[] mainTypeName, ArrayList definedTypeNames, ArrayList duplicateTypeNames) {
  if (duplicateTypeNames == null) {
    newState.record(sourceLocator, result.qualifiedReferences, result.simpleNameReferences, mainTypeName, definedTypeNames);
    return;
  }

  char[][][] qualifiedRefs = result.qualifiedReferences;
  char[][] simpleRefs = result.simpleNameReferences;
  // for each duplicate type p1.p2.A, add the type name A (package was already added)
  next : for (int i = 0, l = duplicateTypeNames.size(); i < l; i++) {
    char[][] compoundName = (char[][]) duplicateTypeNames.get(i);
    char[] typeName = compoundName[compoundName.length - 1];
    int sLength = simpleRefs.length;
    for (int j = 0; j < sLength; j++)
      if (CharOperation.equals(simpleRefs[j], typeName))
        continue next;
    System.arraycopy(simpleRefs, 0, simpleRefs = new char[sLength + 1][], 0, sLength);
    simpleRefs[sLength] = typeName;
  }
  newState.record(sourceLocator, qualifiedRefs, simpleRefs, mainTypeName, definedTypeNames);
}

protected IContainer createFolder(IPath packagePath, IContainer outputFolder) throws CoreException {
  if (packagePath.isEmpty()) return outputFolder;
  IFolder folder = outputFolder.getFolder(packagePath);
  if (!folder.exists()) {
    createFolder(packagePath.removeLastSegments(1), outputFolder);
    folder.create(IResource.FORCE | IResource.DERIVED, true, null);
  }
  return folder;
}



/* (non-Javadoc)
* @see org.aspectj.org.eclipse.jdt.internal.core.builder.ICompilationUnitLocator#fromIFile(org.eclipse.core.resources.IFile)
*/
public ICompilationUnit fromIFile(IFile file) {
  return findSourceFile(file, true);
}

protected void initializeAnnotationProcessorManager(Compiler newCompiler) {
  AbstractAnnotationProcessorManager annotationManager = JavaModelManager.getJavaModelManager().createAnnotationProcessorManager();
  if (annotationManager != null) {
    annotationManager.configureFromPlatform(newCompiler, this, javaBuilder.javaProject);
    annotationManager.setErr(new PrintWriter(System.err));
    annotationManager.setOut(new PrintWriter(System.out));
  }
  newCompiler.annotationProcessorManager = annotationManager;
}

protected RuntimeException internalException(CoreException t) {
  ImageBuilderInternalException imageBuilderException = new ImageBuilderInternalException(t);
  if (inCompiler)
    return new AbortCompilation(true, imageBuilderException);
  return imageBuilderException;
}

protected boolean isExcludedFromProject(IPath childPath) throws JavaModelException {
  // answer whether the folder should be ignored when walking the project as a source folder
  if (childPath.segmentCount() > 2) return false; // is a subfolder of a package

  for (int j = 0, k = sourceLocations.length; j < k; j++) {
    if (childPath.equals(sourceLocations[j].binaryFolder.getFullPath())) return true;
    if (childPath.equals(sourceLocations[j].sourceFolder.getFullPath())) return true;
  }
  // skip default output folder which may not be used by any source folder
  return childPath.equals(javaBuilder.javaProject.getOutputLocation());
}

protected Compiler newCompiler() {
  // disable entire javadoc support if not interested in diagnostics
  Map projectOptions = javaBuilder.javaProject.getOptions(true);
  String option = (String) projectOptions.get(JavaCore.COMPILER_PB_INVALID_JAVADOC);
  if (option == null || option.equals(JavaCore.IGNORE)) { // TODO (frederic) see why option is null sometimes while running model tests!?
    option = (String) projectOptions.get(JavaCore.COMPILER_PB_MISSING_JAVADOC_TAGS);
    if (option == null || option.equals(JavaCore.IGNORE)) {
      option = (String) projectOptions.get(JavaCore.COMPILER_PB_MISSING_JAVADOC_COMMENTS);
      if (option == null || option.equals(JavaCore.IGNORE)) {
        option = (String) projectOptions.get(JavaCore.COMPILER_PB_UNUSED_IMPORT);
        if (option == null || option.equals(JavaCore.IGNORE)) { // Unused import need also to look inside javadoc comment
          projectOptions.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.DISABLED);
        }
      }
    }
  }
 
  // called once when the builder is initialized... can override if needed
  CompilerOptions compilerOptions = new CompilerOptions(projectOptions);
  compilerOptions.performMethodsFullRecovery = true;
  compilerOptions.performStatementsRecovery = true;
  Compiler newCompiler = new Compiler(
    nameEnvironment,
    DefaultErrorHandlingPolicies.proceedWithAllProblems(),
    compilerOptions,
    this,
    ProblemFactory.getProblemFactory(Locale.getDefault()));
  CompilerOptions options = newCompiler.options;
 
  // enable the compiler reference info support
  options.produceReferenceInfo = true;

  if (options.complianceLevel >= ClassFileConstants.JDK1_6
      && options.processAnnotations) {
    // support for Java 6 annotation processors
    initializeAnnotationProcessorManager(newCompiler);
  }
 
  return newCompiler;
}

protected BuildContext[] notifyParticipants(SourceFile[] unitsAboutToCompile) {
  BuildContext[] results = new BuildContext[unitsAboutToCompile.length];
  for (int i = unitsAboutToCompile.length; --i >= 0;)
    results[i] = new BuildContext(unitsAboutToCompile[i]);

  // TODO (kent) do we expect to have more than one participant?
  // and if so should we pass the generated files from the each processor to the others to process?
  // and what happens if some participants do not expect to be called with only a few files, after seeing 'all' the files?
  for (int i = 0, l = this.javaBuilder.participants.length; i < l; i++)
    this.javaBuilder.participants[i].buildStarting(results, this instanceof BatchImageBuilder);

  SimpleSet uniqueFiles = null;
  CompilationParticipantResult[] toAdd = null;
  int added = 0;
  for (int i = results.length; --i >= 0;) {
    CompilationParticipantResult result = results[i];
    if (result == null) continue;

    IFile[] deletedGeneratedFiles = result.deletedFiles;
    if (deletedGeneratedFiles != null)
      deleteGeneratedFiles(deletedGeneratedFiles);

    IFile[] addedGeneratedFiles = result.addedFiles;
    if (addedGeneratedFiles != null) {
      for (int j = addedGeneratedFiles.length; --j >= 0;) {
        SourceFile sourceFile = findSourceFile(addedGeneratedFiles[j], true);
        if (sourceFile == null) continue;
        if (uniqueFiles == null) {
          uniqueFiles = new SimpleSet(unitsAboutToCompile.length + 3);
          for (int f = unitsAboutToCompile.length; --f >= 0;)
            uniqueFiles.add(unitsAboutToCompile[f]);
        }
        if (uniqueFiles.addIfNotIncluded(sourceFile) == sourceFile) {
          CompilationParticipantResult newResult = new BuildContext(sourceFile);
          // is there enough room to add all the addedGeneratedFiles.length ?
          if (toAdd == null) {
            toAdd = new CompilationParticipantResult[addedGeneratedFiles.length];
          } else {
            int length = toAdd.length;
            if (added == length)
              System.arraycopy(toAdd, 0, toAdd = new CompilationParticipantResult[length + addedGeneratedFiles.length], 0, length);
          }
          toAdd[added++] = newResult;
        }
      }
    }
  }

  if (added >0 ) {
    int length = results.length;
    System.arraycopy(results, 0, results = new BuildContext[length + added], 0 , length);
    System.arraycopy(toAdd, 0, results, length, added);
  }
  return results;
}

protected abstract void processAnnotationResults(CompilationParticipantResult[] results);

protected void processAnnotations(BuildContext[] results) {
  boolean hasAnnotationProcessor = false;
  for (int i = 0, l = this.javaBuilder.participants.length; !hasAnnotationProcessor && i < l; i++)
    hasAnnotationProcessor = this.javaBuilder.participants[i].isAnnotationProcessor();
  if (!hasAnnotationProcessor) return;

  boolean foundAnnotations = this.filesWithAnnotations != null && this.filesWithAnnotations.elementSize > 0;
  for (int i = results.length; --i >= 0;)
    ((CompilationParticipantResult) results[i]).reset(foundAnnotations && this.filesWithAnnotations.includes(results[i].sourceFile));

  // even if no files have annotations, must still tell every annotation processor in case the file used to have them
  for (int i = 0, l = this.javaBuilder.participants.length; i < l; i++)
    if (this.javaBuilder.participants[i].isAnnotationProcessor())
      this.javaBuilder.participants[i].processAnnotations(results);
  processAnnotationResults(results);
}

protected void recordParticipantResult(CompilationParticipantResult result) {
  // any added/changed/deleted generated files have already been taken care
  // just record the problems and dependencies - do not expect there to be many
  // must be called after we're finished with the compilation unit results but before incremental loop adds affected files
  CategorizedProblem[] problems = result.problems;
  if (problems != null && problems.length > 0) {
    // existing problems have already been removed so just add these as new problems
    this.notifier.updateProblemCounts(problems);
    try {
      storeProblemsFor(result.sourceFile, problems);
    } catch (CoreException e) {
      // must continue with compile loop so just log the CoreException
      e.printStackTrace();
    }
  }

  String[] dependencies = result.dependencies;
  if (dependencies != null) {
    ReferenceCollection refs = (ReferenceCollection) this.newState.references.get(result.sourceFile.typeLocator());
    if (refs != null)
      refs.addDependencies(dependencies);
  }
}

/**
* Creates a marker from each problem and adds it to the resource.
* The marker is as follows:
*   - its type is T_PROBLEM
*   - its plugin ID is the JavaBuilder's plugin ID
*   - its message is the problem's message
*   - its priority reflects the severity of the problem
*   - its range is the problem's range
*   - it has an extra attribute "ID" which holds the problem's id
*   - it's GENERATED_BY attribute is positioned to JavaBuilder.GENERATED_BY if
*     the problem was generated by JDT; else the GENERATED_BY attribute is
*     carried from the problem to the marker in extra attributes, if present.
*/
protected void storeProblemsFor(SourceFile sourceFile, CategorizedProblem[] problems) throws CoreException {
  if (sourceFile == null || problems == null || problems.length == 0) return;
   // once a classpath error is found, ignore all other problems for this project so the user can see the main error
  // but still try to compile as many source files as possible to help the case when the base libraries are in source
  if (!this.keepStoringProblemMarkers) return; // only want the one error recorded on this source file

  IResource resource = sourceFile.resource;
  HashSet managedMarkerTypes = JavaModelManager.getJavaModelManager().compilationParticipants.managedMarkerTypes();
  for (int i = 0, l = problems.length; i < l; i++) {
    CategorizedProblem problem = problems[i];
    int id = problem.getID();

    // handle missing classfile situation
    if (id == IProblem.IsClassPathCorrect) {
      String missingClassfileName = problem.getArguments()[0];
      if (JavaBuilder.DEBUG)
        System.out.println(Messages.bind(Messages.build_incompleteClassPath, missingClassfileName));
      boolean isInvalidClasspathError = JavaCore.ERROR.equals(javaBuilder.javaProject.getOption(JavaCore.CORE_INCOMPLETE_CLASSPATH, true));
      // insert extra classpath problem, and make it the only problem for this project (optional)
      if (isInvalidClasspathError && JavaCore.ABORT.equals(javaBuilder.javaProject.getOption(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, true))) {
        JavaBuilder.removeProblemsAndTasksFor(javaBuilder.currentProject); // make this the only problem for this project
        this.keepStoringProblemMarkers = false;
      }
      IMarker marker = this.javaBuilder.currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
      marker.setAttributes(
        new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.CATEGORY_ID, IMarker.SOURCE_ID},
        new Object[] {
          Messages.bind(Messages.build_incompleteClassPath, missingClassfileName),
          new Integer(isInvalidClasspathError ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING),
          new Integer(CategorizedProblem.CAT_BUILDPATH),
          JavaBuilder.SOURCE_ID
        }
      );
      // even if we're not keeping more markers, still fall through rest of the problem reporting, so that offending
      // IsClassPathCorrect problem gets recorded since it may help locate the offending reference
    }

    String markerType = problem.getMarkerType();
    boolean managedProblem = false;
    if (IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER.equals(markerType)
        || (managedProblem = managedMarkerTypes.contains(markerType))) {
      IMarker marker = resource.createMarker(markerType);

      String[] attributeNames = JAVA_PROBLEM_MARKER_ATTRIBUTE_NAMES;
      int standardLength = attributeNames.length;
      String[] allNames = attributeNames;
      int managedLength = managedProblem ? 0 : 1;
      String[] extraAttributeNames = problem.getExtraMarkerAttributeNames();
      int extraLength = extraAttributeNames == null ? 0 : extraAttributeNames.length;
      if (managedLength > 0 || extraLength > 0) {
        allNames = new String[standardLength + managedLength + extraLength];
        System.arraycopy(attributeNames, 0, allNames, 0, standardLength);
        if (managedLength > 0)
          allNames[standardLength] = IMarker.SOURCE_ID;
        System.arraycopy(extraAttributeNames, 0, allNames, standardLength + managedLength, extraLength);
      }

      Object[] allValues = new Object[allNames.length];
      // standard attributes
      int index = 0;
      allValues[index++] = problem.getMessage(); // message
      allValues[index++] = problem.isError() ? S_ERROR : S_WARNING; // severity
      allValues[index++] = new Integer(id); // ID
      allValues[index++] = new Integer(problem.getSourceStart()); // start
      allValues[index++] = new Integer(problem.getSourceEnd() + 1); // end
      allValues[index++] = new Integer(problem.getSourceLineNumber()); // line
      allValues[index++] = Util.getProblemArgumentsForMarker(problem.getArguments()); // arguments
      allValues[index++] = new Integer(problem.getCategoryID()); // category ID
      // GENERATED_BY attribute for JDT problems
      if (managedLength > 0)
        allValues[index++] = JavaBuilder.SOURCE_ID;
      // optional extra attributes
      if (extraLength > 0)
        System.arraycopy(problem.getExtraMarkerAttributeValues(), 0, allValues, index, extraLength);

      marker.setAttributes(allNames, allValues);

      if (!this.keepStoringProblemMarkers) return; // only want the one error recorded on this source file
    }
  }
}

protected void storeTasksFor(SourceFile sourceFile, CategorizedProblem[] tasks) throws CoreException {
  if (sourceFile == null || tasks == null || tasks.length == 0) return;

  IResource resource = sourceFile.resource;
  for (int i = 0, l = tasks.length; i < l; i++) {
    CategorizedProblem task = tasks[i];
    if (task.getID() == IProblem.Task) {
      IMarker marker = resource.createMarker(IJavaModelMarker.TASK_MARKER);
      Integer priority = P_NORMAL;
      String compilerPriority = task.getArguments()[2];
      if (JavaCore.COMPILER_TASK_PRIORITY_HIGH.equals(compilerPriority))
        priority = P_HIGH;
      else if (JavaCore.COMPILER_TASK_PRIORITY_LOW.equals(compilerPriority))
        priority = P_LOW;

      String[] attributeNames = JAVA_TASK_MARKER_ATTRIBUTE_NAMES;
      int standardLength = attributeNames.length;
      String[] allNames = attributeNames;
      String[] extraAttributeNames = task.getExtraMarkerAttributeNames();
      int extraLength = extraAttributeNames == null ? 0 : extraAttributeNames.length;
      if (extraLength > 0) {
        allNames = new String[standardLength + extraLength];
        System.arraycopy(attributeNames, 0, allNames, 0, standardLength);
        System.arraycopy(extraAttributeNames, 0, allNames, standardLength, extraLength);
      }

      Object[] allValues = new Object[allNames.length];
      // standard attributes
      int index = 0;
      allValues[index++] = task.getMessage();
      allValues[index++] = priority;
      allValues[index++] = new Integer(task.getID());
      allValues[index++] = new Integer(task.getSourceStart());
      allValues[index++] = new Integer(task.getSourceEnd() + 1);
      allValues[index++] = new Integer(task.getSourceLineNumber());
      allValues[index++] = Boolean.FALSE;
      allValues[index++] = JavaBuilder.SOURCE_ID;
      // optional extra attributes
      if (extraLength > 0)
        System.arraycopy(task.getExtraMarkerAttributeValues(), 0, allValues, index, extraLength);

      marker.setAttributes(allNames, allValues);
    }
  }
}

protected void updateProblemsFor(SourceFile sourceFile, CompilationResult result) throws CoreException {
  CategorizedProblem[] problems = result.getProblems();
  if (problems == null || problems.length == 0) return;

  notifier.updateProblemCounts(problems);
  storeProblemsFor(sourceFile, problems);
}

protected void updateTasksFor(SourceFile sourceFile, CompilationResult result) throws CoreException {
  CategorizedProblem[] tasks = result.getTasks();
  if (tasks == null || tasks.length == 0) return;

  storeTasksFor(sourceFile, tasks);
}

protected char[] writeClassFile(ClassFile classFile, SourceFile compilationUnit, boolean isTopLevelType) throws CoreException {
  String fileName = new String(classFile.fileName()); // the qualified type name "p1/p2/A"
  IPath filePath = new Path(fileName);
  IContainer outputFolder = compilationUnit.sourceLocation.binaryFolder;
  IContainer container = outputFolder;
  if (filePath.segmentCount() > 1) {
    container = createFolder(filePath.removeLastSegments(1), outputFolder);
    filePath = new Path(filePath.lastSegment());
  }

  IFile file = container.getFile(filePath.addFileExtension(SuffixConstants.EXTENSION_class));
  writeClassFileBytes(classFile.getBytes(), file, fileName, isTopLevelType, compilationUnit);
  if (classFile.isShared) {
    this.compiler.lookupEnvironment.classFilePool.release(classFile);
  }
  // answer the name of the class file as in Y or Y$M
  return filePath.lastSegment().toCharArray();
}

protected void writeClassFileBytes(byte[] bytes, IFile file, String qualifiedFileName, boolean isTopLevelType, SourceFile compilationUnit) throws CoreException {
  if (file.exists()) {
    // Deal with shared output folders... last one wins... no collision cases detected
    if (JavaBuilder.DEBUG)
      System.out.println("Writing changed class file " + file.getName());//$NON-NLS-1$
    if (!file.isDerived())
      file.setDerived(true);
    file.setContents(new ByteArrayInputStream(bytes), true, false, null);
  } else {
    // Default implementation just writes out the bytes for the new class file...
    if (JavaBuilder.DEBUG)
      System.out.println("Writing new class file " + file.getName());//$NON-NLS-1$
    file.create(new ByteArrayInputStream(bytes), IResource.FORCE | IResource.DERIVED, null);
  }
}
}
TOP

Related Classes of org.aspectj.org.eclipse.jdt.internal.core.builder.AbstractImageBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.