/*******************************************************************************
* Copyright (c) 2000, 2009 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.eclipse.wst.jsdt.internal.core.builder;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceProxy;
import org.eclipse.core.resources.IResourceProxyVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.wst.jsdt.core.IJavaScriptModelMarker;
import org.eclipse.wst.jsdt.core.IMember;
import org.eclipse.wst.jsdt.core.ISourceRange;
import org.eclipse.wst.jsdt.core.JavaScriptCore;
import org.eclipse.wst.jsdt.core.JavaScriptModelException;
import org.eclipse.wst.jsdt.core.compiler.BuildContext;
import org.eclipse.wst.jsdt.core.compiler.CategorizedProblem;
import org.eclipse.wst.jsdt.core.compiler.CharOperation;
import org.eclipse.wst.jsdt.core.compiler.IProblem;
import org.eclipse.wst.jsdt.internal.compiler.CompilationResult;
import org.eclipse.wst.jsdt.internal.compiler.Compiler;
import org.eclipse.wst.jsdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.wst.jsdt.internal.compiler.ICompilerRequestor;
import org.eclipse.wst.jsdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.wst.jsdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.wst.jsdt.internal.compiler.problem.AbortCompilation;
import org.eclipse.wst.jsdt.internal.compiler.util.SimpleSet;
import org.eclipse.wst.jsdt.internal.core.JavaModelManager;
import org.eclipse.wst.jsdt.internal.core.util.Messages;
import org.eclipse.wst.jsdt.internal.core.util.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;
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,
IJavaScriptModelMarker.ID,
IMarker.CHAR_START,
IMarker.CHAR_END,
IMarker.LINE_NUMBER,
IJavaScriptModelMarker.ARGUMENTS,
IJavaScriptModelMarker.CATEGORY_ID,
};
public final static String[] JAVA_TASK_MARKER_ATTRIBUTE_NAMES = {
IMarker.MESSAGE,
IMarker.PRIORITY,
IJavaScriptModelMarker.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);
}
}
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);
String typeLocator = compilationUnit.typeLocator();
finishedWith(typeLocator, result, compilationUnit.getMainTypeName(), new ArrayList(), new ArrayList());
notifier.compiled(compilationUnit);
}
}
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 {
if (proxy.isDerived())
return false;
switch(proxy.getType()) {
case IResource.FILE :
if (org.eclipse.wst.jsdt.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 (JavaScriptCore.isReadOnly(proxy.requestResource()))
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;
}
}
}
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) {
// notify validationParticipants 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]);
}
}
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(IJavaScriptModelMarker.JAVASCRIPT_MODEL_PROBLEM_MARKER);
int severity = problemSeverity.equals(JavaScriptCore.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;
if (file.isDerived()) 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);
}
/* (non-Javadoc)
* @see org.eclipse.wst.jsdt.internal.core.builder.ICompilationUnitLocator#fromIFile(org.eclipse.core.resources.IFile)
*/
public ICompilationUnit fromIFile(IFile file) {
return findSourceFile(file, true);
}
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 JavaScriptModelException {
// 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(JavaScriptCore.COMPILER_PB_INVALID_JAVADOC);
if (option == null || option.equals(JavaScriptCore.IGNORE)) { // TODO (frederic) see why option is null sometimes while running model tests!?
option = (String) projectOptions.get(JavaScriptCore.COMPILER_PB_MISSING_JAVADOC_TAGS);
if (option == null || option.equals(JavaScriptCore.IGNORE)) {
option = (String) projectOptions.get(JavaScriptCore.COMPILER_PB_MISSING_JAVADOC_COMMENTS);
if (option == null || option.equals(JavaScriptCore.IGNORE)) {
option = (String) projectOptions.get(JavaScriptCore.COMPILER_PB_UNUSED_IMPORT);
if (option == null || option.equals(JavaScriptCore.IGNORE)) { // Unused import need also to look inside javadoc comment
projectOptions.put(JavaScriptCore.COMPILER_DOC_COMMENT_SUPPORT, JavaScriptCore.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;
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;
ValidationParticipantResult[] toAdd = null;
int added = 0;
for (int i = results.length; --i >= 0;) {
ValidationParticipantResult 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) {
ValidationParticipantResult newResult = new BuildContext(sourceFile);
// is there enough room to add all the addedGeneratedFiles.length ?
if (toAdd == null) {
toAdd = new ValidationParticipantResult[addedGeneratedFiles.length];
} else {
int length = toAdd.length;
if (added == length)
System.arraycopy(toAdd, 0, toAdd = new ValidationParticipantResult[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 void recordParticipantResult(ValidationParticipantResult 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;
IResource container=(resource instanceof IFile)? resource.getParent():resource;
if (JavaScriptCore.isReadOnly(container))
return;
HashSet managedMarkerTypes = JavaModelManager.getJavaModelManager().validationParticipants.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 = JavaScriptCore.ERROR.equals(javaBuilder.javaProject.getOption(JavaScriptCore.CORE_INCOMPLETE_CLASSPATH, true));
// insert extra classpath problem, and make it the only problem for this project (optional)
if (isInvalidClasspathError && JavaScriptCore.ABORT.equals(javaBuilder.javaProject.getOption(JavaScriptCore.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(IJavaScriptModelMarker.JAVASCRIPT_MODEL_PROBLEM_MARKER);
marker.setAttributes(
new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaScriptModelMarker.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 (IJavaScriptModelMarker.JAVASCRIPT_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(IJavaScriptModelMarker.TASK_MARKER);
Integer priority = P_NORMAL;
String compilerPriority = task.getArguments()[2];
if (JavaScriptCore.COMPILER_TASK_PRIORITY_HIGH.equals(compilerPriority))
priority = P_HIGH;
else if (JavaScriptCore.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);
}
}