KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > builder > AbstractImageBuilder


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.core.builder;
12
13 import org.eclipse.core.runtime.*;
14 import org.eclipse.core.resources.*;
15
16 import org.eclipse.jdt.core.*;
17 import org.eclipse.jdt.core.compiler.*;
18 import org.eclipse.jdt.internal.compiler.*;
19 import org.eclipse.jdt.internal.compiler.Compiler;
20 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
21 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
22 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
23 import org.eclipse.jdt.internal.compiler.problem.*;
24 import org.eclipse.jdt.internal.compiler.util.SimpleSet;
25 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
26 import org.eclipse.jdt.internal.core.JavaModelManager;
27 import org.eclipse.jdt.internal.core.util.Messages;
28 import org.eclipse.jdt.internal.core.util.Util;
29
30 import java.io.*;
31 import java.util.*;
32
33 /**
34  * The abstract superclass of Java builders.
35  * Provides the building and compilation mechanism
36  * in common with the batch and incremental builders.
37  */

38 public abstract class AbstractImageBuilder implements ICompilerRequestor, ICompilationUnitLocator {
39
40 protected JavaBuilder javaBuilder;
41 protected State newState;
42
43 // local copies
44
protected NameEnvironment nameEnvironment;
45 protected ClasspathMultiDirectory[] sourceLocations;
46 protected BuildNotifier notifier;
47
48 protected Compiler JavaDoc compiler;
49 protected WorkQueue workQueue;
50 protected ArrayList problemSourceFiles;
51 protected boolean compiledAllAtOnce;
52
53 private boolean inCompiler;
54
55 protected boolean keepStoringProblemMarkers;
56 protected SimpleSet filesWithAnnotations = null;
57
58 public static int MAX_AT_ONCE = 2000; // best compromise between space used and speed
59
public final static String JavaDoc[] JAVA_PROBLEM_MARKER_ATTRIBUTE_NAMES = {
60     IMarker.MESSAGE,
61     IMarker.SEVERITY,
62     IJavaModelMarker.ID,
63     IMarker.CHAR_START,
64     IMarker.CHAR_END,
65     IMarker.LINE_NUMBER,
66     IJavaModelMarker.ARGUMENTS,
67     IJavaModelMarker.CATEGORY_ID,
68 };
69 public final static String JavaDoc[] JAVA_TASK_MARKER_ATTRIBUTE_NAMES = {
70     IMarker.MESSAGE,
71     IMarker.PRIORITY,
72     IJavaModelMarker.ID,
73     IMarker.CHAR_START,
74     IMarker.CHAR_END,
75     IMarker.LINE_NUMBER,
76     IMarker.USER_EDITABLE,
77     IMarker.SOURCE_ID,
78 };
79 public final static Integer JavaDoc S_ERROR = new Integer JavaDoc(IMarker.SEVERITY_ERROR);
80 public final static Integer JavaDoc S_WARNING = new Integer JavaDoc(IMarker.SEVERITY_WARNING);
81 public final static Integer JavaDoc P_HIGH = new Integer JavaDoc(IMarker.PRIORITY_HIGH);
82 public final static Integer JavaDoc P_NORMAL = new Integer JavaDoc(IMarker.PRIORITY_NORMAL);
83 public final static Integer JavaDoc P_LOW = new Integer JavaDoc(IMarker.PRIORITY_LOW);
84
85 protected AbstractImageBuilder(JavaBuilder javaBuilder, boolean buildStarting, State newState) {
86     // local copies
87
this.javaBuilder = javaBuilder;
88     this.nameEnvironment = javaBuilder.nameEnvironment;
89     this.sourceLocations = this.nameEnvironment.sourceLocations;
90     this.notifier = javaBuilder.notifier;
91     this.keepStoringProblemMarkers = true; // may get disabled when missing classfiles are encountered
92

93     if (buildStarting) {
94         this.newState = newState == null ? new State(javaBuilder) : newState;
95         this.compiler = newCompiler();
96         this.workQueue = new WorkQueue();
97         this.problemSourceFiles = new ArrayList(3);
98
99         if (this.javaBuilder.participants != null) {
100             for (int i = 0, l = this.javaBuilder.participants.length; i < l; i++) {
101                 if (this.javaBuilder.participants[i].isAnnotationProcessor()) {
102                     // initialize this set so the builder knows to gather CUs that define Annotation types
103
// each Annotation processor participant is then asked to process these files AFTER
104
// the compile loop. The normal dependency loop will then recompile all affected types
105
this.filesWithAnnotations = new SimpleSet(1);
106                     break;
107                 }
108             }
109         }
110     }
111 }
112
113 public void acceptResult(CompilationResult result) {
114     // In Batch mode, we write out the class files, hold onto the dependency info
115
// & additional types and report problems.
116

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

122     SourceFile compilationUnit = (SourceFile) result.getCompilationUnit(); // go directly back to the sourceFile
123
if (!workQueue.isCompiled(compilationUnit)) {
124         workQueue.finished(compilationUnit);
125
126         try {
127             updateProblemsFor(compilationUnit, result); // record compilation problems before potentially adding duplicate errors
128
updateTasksFor(compilationUnit, result); // record tasks
129
} catch (CoreException e) {
130             throw internalException(e);
131         }
132
133         if (result.hasInconsistentToplevelHierarchies)
134             // ensure that this file is always retrieved from source for the rest of the build
135
if (!problemSourceFiles.contains(compilationUnit))
136                 problemSourceFiles.add(compilationUnit);
137
138         IType mainType = null;
139         String JavaDoc mainTypeName = null;
140         String JavaDoc typeLocator = compilationUnit.typeLocator();
141         ClassFile[] classFiles = result.getClassFiles();
142         int length = classFiles.length;
143         ArrayList duplicateTypeNames = null;
144         ArrayList definedTypeNames = new ArrayList(length);
145         for (int i = 0; i < length; i++) {
146             ClassFile classFile = classFiles[i];
147
148             char[][] compoundName = classFile.getCompoundName();
149             char[] typeName = compoundName[compoundName.length - 1];
150             boolean isNestedType = classFile.enclosingClassFile != null;
151
152             // Look for a possible collision, if one exists, report an error but do not write the class file
153
if (isNestedType) {
154                 String JavaDoc qualifiedTypeName = new String JavaDoc(classFile.outerMostEnclosingClassFile().fileName());
155                 if (newState.isDuplicateLocator(qualifiedTypeName, typeLocator))
156                     continue;
157             } else {
158                 String JavaDoc qualifiedTypeName = new String JavaDoc(classFile.fileName()); // the qualified type name "p1/p2/A"
159
if (newState.isDuplicateLocator(qualifiedTypeName, typeLocator)) {
160                     if (duplicateTypeNames == null)
161                         duplicateTypeNames = new ArrayList();
162                     duplicateTypeNames.add(compoundName);
163                     if (mainType == null) {
164                         try {
165                             mainTypeName = compilationUnit.initialTypeName; // slash separated qualified name "p1/p1/A"
166
mainType = javaBuilder.javaProject.findType(mainTypeName.replace('/', '.'));
167                         } catch (JavaModelException e) {
168                             // ignore
169
}
170                     }
171                     IType type;
172                     if (qualifiedTypeName.equals(mainTypeName)) {
173                         type = mainType;
174                     } else {
175                         String JavaDoc simpleName = qualifiedTypeName.substring(qualifiedTypeName.lastIndexOf('/')+1);
176                         type = mainType == null ? null : mainType.getCompilationUnit().getType(simpleName);
177                     }
178                     createProblemFor(compilationUnit.resource, type, Messages.bind(Messages.build_duplicateClassFile, new String JavaDoc(typeName)), JavaCore.ERROR);
179                     continue;
180                 }
181                 newState.recordLocatorForType(qualifiedTypeName, typeLocator);
182                 if (!qualifiedTypeName.equals(compilationUnit.initialTypeName))
183                     acceptSecondaryType(classFile);
184             }
185             try {
186                 definedTypeNames.add(writeClassFile(classFile, compilationUnit, !isNestedType));
187             } catch (CoreException e) {
188                 Util.log(e, "JavaBuilder handling CoreException"); //$NON-NLS-1$
189
if (e.getStatus().getCode() == IResourceStatus.CASE_VARIANT_EXISTS)
190                     createProblemFor(compilationUnit.resource, null, Messages.bind(Messages.build_classFileCollision, e.getMessage()), JavaCore.ERROR);
191                 else
192                     createProblemFor(compilationUnit.resource, null, Messages.build_inconsistentClassFile, JavaCore.ERROR);
193             }
194         }
195         if (result.hasAnnotations && this.filesWithAnnotations != null) // only initialized if an annotation processor is attached
196
this.filesWithAnnotations.add(compilationUnit);
197
198         finishedWith(typeLocator, result, compilationUnit.getMainTypeName(), definedTypeNames, duplicateTypeNames);
199         notifier.compiled(compilationUnit);
200     }
201 }
202
203 protected void acceptSecondaryType(ClassFile classFile) {
204     // noop
205
}
206
207 protected void addAllSourceFiles(final ArrayList sourceFiles) throws CoreException {
208     for (int i = 0, l = sourceLocations.length; i < l; i++) {
209         final ClasspathMultiDirectory sourceLocation = sourceLocations[i];
210         final char[][] exclusionPatterns = sourceLocation.exclusionPatterns;
211         final char[][] inclusionPatterns = sourceLocation.inclusionPatterns;
212         final boolean isAlsoProject = sourceLocation.sourceFolder.equals(javaBuilder.currentProject);
213         final int segmentCount = sourceLocation.sourceFolder.getFullPath().segmentCount();
214         final IContainer outputFolder = sourceLocation.binaryFolder;
215         final boolean isOutputFolder = sourceLocation.sourceFolder.equals(outputFolder);
216         sourceLocation.sourceFolder.accept(
217             new IResourceProxyVisitor() {
218                 public boolean visit(IResourceProxy proxy) throws CoreException {
219                     switch(proxy.getType()) {
220                         case IResource.FILE :
221                             if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(proxy.getName())) {
222                                 IResource resource = proxy.requestResource();
223                                 if (exclusionPatterns != null || inclusionPatterns != null)
224                                     if (Util.isExcluded(resource.getFullPath(), inclusionPatterns, exclusionPatterns, false))
225                                         return false;
226                                 sourceFiles.add(new SourceFile((IFile) resource, sourceLocation));
227                             }
228                             return false;
229                         case IResource.FOLDER :
230                             IPath folderPath = null;
231                             if (isAlsoProject)
232                                 if (isExcludedFromProject(folderPath = proxy.requestFullPath()))
233                                     return false;
234                             if (exclusionPatterns != null) {
235                                 if (folderPath == null)
236                                     folderPath = proxy.requestFullPath();
237                                 if (Util.isExcluded(folderPath, inclusionPatterns, exclusionPatterns, true)) {
238                                     // must walk children if inclusionPatterns != null, can skip them if == null
239
// but folder is excluded so do not create it in the output folder
240
return inclusionPatterns != null;
241                                 }
242                             }
243                             if (!isOutputFolder) {
244                                 if (folderPath == null)
245                                     folderPath = proxy.requestFullPath();
246                                 String JavaDoc packageName = folderPath.lastSegment();
247                                 if (packageName.length() > 0) {
248                                     String JavaDoc sourceLevel = javaBuilder.javaProject.getOption(JavaCore.COMPILER_SOURCE, true);
249                                     String JavaDoc complianceLevel = javaBuilder.javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true);
250                                     if (JavaConventions.validatePackageName(packageName, sourceLevel, complianceLevel).getSeverity() != IStatus.ERROR)
251                                         createFolder(folderPath.removeFirstSegments(segmentCount), outputFolder);
252                                 }
253                             }
254                     }
255                     return true;
256                 }
257             },
258             IResource.NONE
259         );
260         notifier.checkCancel();
261     }
262 }
263
264 protected void cleanUp() {
265     this.nameEnvironment.cleanup();
266
267     this.javaBuilder = null;
268     this.nameEnvironment = null;
269     this.sourceLocations = null;
270     this.notifier = null;
271     this.compiler = null;
272     this.workQueue = null;
273     this.problemSourceFiles = null;
274 }
275
276 /* Compile the given elements, adding more elements to the work queue
277 * if they are affected by the changes.
278 */

279 protected void compile(SourceFile[] units) {
280     if (this.filesWithAnnotations != null && this.filesWithAnnotations.elementSize > 0)
281         // will add files that have annotations in acceptResult() & then processAnnotations() before exitting this method
282
this.filesWithAnnotations.clear();
283
284     // notify CompilationParticipants which source files are about to be compiled
285
BuildContext[] participantResults = this.javaBuilder.participants == null ? null : notifyParticipants(units);
286     if (participantResults != null && participantResults.length > units.length) {
287         units = new SourceFile[participantResults.length];
288         for (int i = participantResults.length; --i >= 0;)
289             units[i] = participantResults[i].sourceFile;
290     }
291
292     int unitsLength = units.length;
293     this.compiledAllAtOnce = unitsLength <= MAX_AT_ONCE;
294     if (this.compiledAllAtOnce) {
295         // do them all now
296
if (JavaBuilder.DEBUG)
297             for (int i = 0; i < unitsLength; i++)
298                 System.out.println("About to compile " + units[i].typeLocator()); //$NON-NLS-1$
299
compile(units, null, true);
300     } else {
301         SourceFile[] remainingUnits = new SourceFile[unitsLength]; // copy of units, removing units when about to compile
302
System.arraycopy(units, 0, remainingUnits, 0, unitsLength);
303         int doNow = unitsLength < MAX_AT_ONCE ? unitsLength : MAX_AT_ONCE;
304         SourceFile[] toCompile = new SourceFile[doNow];
305         int remainingIndex = 0;
306         boolean compilingFirstGroup = true;
307         while (remainingIndex < unitsLength) {
308             int count = 0;
309             while (remainingIndex < unitsLength && count < doNow) {
310                 // Although it needed compiling when this method was called, it may have
311
// already been compiled when it was referenced by another unit.
312
SourceFile unit = remainingUnits[remainingIndex];
313                 if (unit != null && (compilingFirstGroup || this.workQueue.isWaiting(unit))) {
314                     if (JavaBuilder.DEBUG)
315                         System.out.println("About to compile #" + remainingIndex + " : "+ unit.typeLocator()); //$NON-NLS-1$ //$NON-NLS-2$
316
toCompile[count++] = unit;
317                 }
318                 remainingUnits[remainingIndex++] = null;
319             }
320             if (count < doNow)
321                 System.arraycopy(toCompile, 0, toCompile = new SourceFile[count], 0, count);
322             if (!compilingFirstGroup)
323                 for (int a = remainingIndex; a < unitsLength; a++)
324                     if (remainingUnits[a] != null && this.workQueue.isCompiled(remainingUnits[a]))
325                         remainingUnits[a] = null; // use the class file for this source file since its been compiled
326
compile(toCompile, remainingUnits, compilingFirstGroup);
327             compilingFirstGroup = false;
328         }
329     }
330
331     if (participantResults != null) {
332         for (int i = participantResults.length; --i >= 0;)
333             if (participantResults[i] != null)
334                 recordParticipantResult(participantResults[i]);
335
336         processAnnotations(participantResults);
337     }
338 }
339
340 protected void compile(SourceFile[] units, SourceFile[] additionalUnits, boolean compilingFirstGroup) {
341     if (units.length == 0) return;
342     notifier.aboutToCompile(units[0]); // just to change the message
343

344     // extend additionalFilenames with all hierarchical problem types found during this entire build
345
if (!problemSourceFiles.isEmpty()) {
346         int toAdd = problemSourceFiles.size();
347         int length = additionalUnits == null ? 0 : additionalUnits.length;
348         if (length == 0)
349             additionalUnits = new SourceFile[toAdd];
350         else
351             System.arraycopy(additionalUnits, 0, additionalUnits = new SourceFile[length + toAdd], 0, length);
352         for (int i = 0; i < toAdd; i++)
353             additionalUnits[length + i] = (SourceFile) problemSourceFiles.get(i);
354     }
355     String JavaDoc[] initialTypeNames = new String JavaDoc[units.length];
356     for (int i = 0, l = units.length; i < l; i++)
357         initialTypeNames[i] = units[i].initialTypeName;
358     nameEnvironment.setNames(initialTypeNames, additionalUnits);
359     notifier.checkCancel();
360     try {
361         inCompiler = true;
362         compiler.compile(units);
363     } catch (AbortCompilation ignored) {
364         // ignore the AbortCompilcation coming from BuildNotifier.checkCancelWithinCompiler()
365
// the Compiler failed after the user has chose to cancel... likely due to an OutOfMemory error
366
} finally {
367         inCompiler = false;
368     }
369     // Check for cancel immediately after a compile, because the compiler may
370
// have been cancelled but without propagating the correct exception
371
notifier.checkCancel();
372 }
373
374 protected void createProblemFor(IResource resource, IMember javaElement, String JavaDoc message, String JavaDoc problemSeverity) {
375     try {
376         IMarker marker = resource.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
377         int severity = problemSeverity.equals(JavaCore.WARNING) ? IMarker.SEVERITY_WARNING : IMarker.SEVERITY_ERROR;
378
379         ISourceRange range = javaElement == null ? null : javaElement.getNameRange();
380         int start = range == null ? 0 : range.getOffset();
381         int end = range == null ? 1 : start + range.getLength();
382         marker.setAttributes(
383             new String JavaDoc[] {IMarker.MESSAGE, IMarker.SEVERITY, IMarker.CHAR_START, IMarker.CHAR_END, IMarker.SOURCE_ID},
384             new Object JavaDoc[] {message, new Integer JavaDoc(severity), new Integer JavaDoc(start), new Integer JavaDoc(end), JavaBuilder.SOURCE_ID});
385     } catch (CoreException e) {
386         throw internalException(e);
387     }
388 }
389
390 protected void deleteGeneratedFiles(IFile[] deletedGeneratedFiles) {
391     // no op by default
392
}
393
394 protected SourceFile findSourceFile(IFile file, boolean mustExist) {
395     if (mustExist && !file.exists()) return null;
396
397     // assumes the file exists in at least one of the source folders & is not excluded
398
ClasspathMultiDirectory md = sourceLocations[0];
399     if (sourceLocations.length > 1) {
400         IPath sourceFileFullPath = file.getFullPath();
401         for (int j = 0, m = sourceLocations.length; j < m; j++) {
402             if (sourceLocations[j].sourceFolder.getFullPath().isPrefixOf(sourceFileFullPath)) {
403                 md = sourceLocations[j];
404                 if (md.exclusionPatterns == null && md.inclusionPatterns == null)
405                     break;
406                 if (!Util.isExcluded(file, md.inclusionPatterns, md.exclusionPatterns))
407                     break;
408             }
409         }
410     }
411     return new SourceFile(file, md);
412 }
413
414 protected void finishedWith(String JavaDoc sourceLocator, CompilationResult result, char[] mainTypeName, ArrayList definedTypeNames, ArrayList duplicateTypeNames) {
415     if (duplicateTypeNames == null) {
416         newState.record(sourceLocator, result.qualifiedReferences, result.simpleNameReferences, mainTypeName, definedTypeNames);
417         return;
418     }
419
420     char[][][] qualifiedRefs = result.qualifiedReferences;
421     char[][] simpleRefs = result.simpleNameReferences;
422     // for each duplicate type p1.p2.A, add the type name A (package was already added)
423
next : for (int i = 0, l = duplicateTypeNames.size(); i < l; i++) {
424         char[][] compoundName = (char[][]) duplicateTypeNames.get(i);
425         char[] typeName = compoundName[compoundName.length - 1];
426         int sLength = simpleRefs.length;
427         for (int j = 0; j < sLength; j++)
428             if (CharOperation.equals(simpleRefs[j], typeName))
429                 continue next;
430         System.arraycopy(simpleRefs, 0, simpleRefs = new char[sLength + 1][], 0, sLength);
431         simpleRefs[sLength] = typeName;
432     }
433     newState.record(sourceLocator, qualifiedRefs, simpleRefs, mainTypeName, definedTypeNames);
434 }
435
436 protected IContainer createFolder(IPath packagePath, IContainer outputFolder) throws CoreException {
437     if (packagePath.isEmpty()) return outputFolder;
438     IFolder folder = outputFolder.getFolder(packagePath);
439     if (!folder.exists()) {
440         createFolder(packagePath.removeLastSegments(1), outputFolder);
441         folder.create(IResource.FORCE | IResource.DERIVED, true, null);
442     }
443     return folder;
444 }
445
446
447
448 /* (non-Javadoc)
449  * @see org.eclipse.jdt.internal.core.builder.ICompilationUnitLocator#fromIFile(org.eclipse.core.resources.IFile)
450  */

451 public ICompilationUnit fromIFile(IFile file) {
452     return findSourceFile(file, true);
453 }
454
455 protected void initializeAnnotationProcessorManager(Compiler JavaDoc newCompiler) {
456     AbstractAnnotationProcessorManager annotationManager = JavaModelManager.getJavaModelManager().createAnnotationProcessorManager();
457     if (annotationManager != null) {
458         annotationManager.configureFromPlatform(newCompiler, this, javaBuilder.javaProject);
459         annotationManager.setErr(new PrintWriter(System.err));
460         annotationManager.setOut(new PrintWriter(System.out));
461     }
462     newCompiler.annotationProcessorManager = annotationManager;
463 }
464
465 protected RuntimeException JavaDoc internalException(CoreException t) {
466     ImageBuilderInternalException imageBuilderException = new ImageBuilderInternalException(t);
467     if (inCompiler)
468         return new AbortCompilation(true, imageBuilderException);
469     return imageBuilderException;
470 }
471
472 protected boolean isExcludedFromProject(IPath childPath) throws JavaModelException {
473     // answer whether the folder should be ignored when walking the project as a source folder
474
if (childPath.segmentCount() > 2) return false; // is a subfolder of a package
475

476     for (int j = 0, k = sourceLocations.length; j < k; j++) {
477         if (childPath.equals(sourceLocations[j].binaryFolder.getFullPath())) return true;
478         if (childPath.equals(sourceLocations[j].sourceFolder.getFullPath())) return true;
479     }
480     // skip default output folder which may not be used by any source folder
481
return childPath.equals(javaBuilder.javaProject.getOutputLocation());
482 }
483
484 protected Compiler JavaDoc newCompiler() {
485     // disable entire javadoc support if not interested in diagnostics
486
Map projectOptions = javaBuilder.javaProject.getOptions(true);
487     String JavaDoc option = (String JavaDoc) projectOptions.get(JavaCore.COMPILER_PB_INVALID_JAVADOC);
488     if (option == null || option.equals(JavaCore.IGNORE)) { // TODO (frederic) see why option is null sometimes while running model tests!?
489
option = (String JavaDoc) projectOptions.get(JavaCore.COMPILER_PB_MISSING_JAVADOC_TAGS);
490         if (option == null || option.equals(JavaCore.IGNORE)) {
491             option = (String JavaDoc) projectOptions.get(JavaCore.COMPILER_PB_MISSING_JAVADOC_COMMENTS);
492             if (option == null || option.equals(JavaCore.IGNORE)) {
493                 option = (String JavaDoc) projectOptions.get(JavaCore.COMPILER_PB_UNUSED_IMPORT);
494                 if (option == null || option.equals(JavaCore.IGNORE)) { // Unused import need also to look inside javadoc comment
495
projectOptions.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.DISABLED);
496                 }
497             }
498         }
499     }
500     
501     // called once when the builder is initialized... can override if needed
502
CompilerOptions compilerOptions = new CompilerOptions(projectOptions);
503     compilerOptions.performMethodsFullRecovery = true;
504     compilerOptions.performStatementsRecovery = true;
505     Compiler JavaDoc newCompiler = new Compiler JavaDoc(
506         nameEnvironment,
507         DefaultErrorHandlingPolicies.proceedWithAllProblems(),
508         compilerOptions,
509         this,
510         ProblemFactory.getProblemFactory(Locale.getDefault()));
511     CompilerOptions options = newCompiler.options;
512     
513     // enable the compiler reference info support
514
options.produceReferenceInfo = true;
515
516     if (options.complianceLevel >= ClassFileConstants.JDK1_6
517             && options.processAnnotations) {
518         // support for Java 6 annotation processors
519
initializeAnnotationProcessorManager(newCompiler);
520     }
521     
522     return newCompiler;
523 }
524
525 protected BuildContext[] notifyParticipants(SourceFile[] unitsAboutToCompile) {
526     BuildContext[] results = new BuildContext[unitsAboutToCompile.length];
527     for (int i = unitsAboutToCompile.length; --i >= 0;)
528         results[i] = new BuildContext(unitsAboutToCompile[i]);
529
530     // TODO (kent) do we expect to have more than one participant?
531
// and if so should we pass the generated files from the each processor to the others to process?
532
// and what happens if some participants do not expect to be called with only a few files, after seeing 'all' the files?
533
for (int i = 0, l = this.javaBuilder.participants.length; i < l; i++)
534         this.javaBuilder.participants[i].buildStarting(results, this instanceof BatchImageBuilder);
535
536     SimpleSet uniqueFiles = null;
537     CompilationParticipantResult[] toAdd = null;
538     int added = 0;
539     for (int i = results.length; --i >= 0;) {
540         CompilationParticipantResult result = results[i];
541         if (result == null) continue;
542
543         IFile[] deletedGeneratedFiles = result.deletedFiles;
544         if (deletedGeneratedFiles != null)
545             deleteGeneratedFiles(deletedGeneratedFiles);
546
547         IFile[] addedGeneratedFiles = result.addedFiles;
548         if (addedGeneratedFiles != null) {
549             for (int j = addedGeneratedFiles.length; --j >= 0;) {
550                 SourceFile sourceFile = findSourceFile(addedGeneratedFiles[j], true);
551                 if (sourceFile == null) continue;
552                 if (uniqueFiles == null) {
553                     uniqueFiles = new SimpleSet(unitsAboutToCompile.length + 3);
554                     for (int f = unitsAboutToCompile.length; --f >= 0;)
555                         uniqueFiles.add(unitsAboutToCompile[f]);
556                 }
557                 if (uniqueFiles.addIfNotIncluded(sourceFile) == sourceFile) {
558                     CompilationParticipantResult newResult = new BuildContext(sourceFile);
559                     // is there enough room to add all the addedGeneratedFiles.length ?
560
if (toAdd == null) {
561                         toAdd = new CompilationParticipantResult[addedGeneratedFiles.length];
562                     } else {
563                         int length = toAdd.length;
564                         if (added == length)
565                             System.arraycopy(toAdd, 0, toAdd = new CompilationParticipantResult[length + addedGeneratedFiles.length], 0, length);
566                     }
567                     toAdd[added++] = newResult;
568                 }
569             }
570         }
571     }
572
573     if (added >0 ) {
574         int length = results.length;
575         System.arraycopy(results, 0, results = new BuildContext[length + added], 0 , length);
576         System.arraycopy(toAdd, 0, results, length, added);
577     }
578     return results;
579 }
580
581 protected abstract void processAnnotationResults(CompilationParticipantResult[] results);
582
583 protected void processAnnotations(BuildContext[] results) {
584     boolean hasAnnotationProcessor = false;
585     for (int i = 0, l = this.javaBuilder.participants.length; !hasAnnotationProcessor && i < l; i++)
586         hasAnnotationProcessor = this.javaBuilder.participants[i].isAnnotationProcessor();
587     if (!hasAnnotationProcessor) return;
588
589     boolean foundAnnotations = this.filesWithAnnotations != null && this.filesWithAnnotations.elementSize > 0;
590     for (int i = results.length; --i >= 0;)
591         ((CompilationParticipantResult) results[i]).reset(foundAnnotations && this.filesWithAnnotations.includes(results[i].sourceFile));
592
593     // even if no files have annotations, must still tell every annotation processor in case the file used to have them
594
for (int i = 0, l = this.javaBuilder.participants.length; i < l; i++)
595         if (this.javaBuilder.participants[i].isAnnotationProcessor())
596             this.javaBuilder.participants[i].processAnnotations(results);
597     processAnnotationResults(results);
598 }
599
600 protected void recordParticipantResult(CompilationParticipantResult result) {
601     // any added/changed/deleted generated files have already been taken care
602
// just record the problems and dependencies - do not expect there to be many
603
// must be called after we're finished with the compilation unit results but before incremental loop adds affected files
604
CategorizedProblem[] problems = result.problems;
605     if (problems != null && problems.length > 0) {
606         // existing problems have already been removed so just add these as new problems
607
this.notifier.updateProblemCounts(problems);
608         try {
609             storeProblemsFor(result.sourceFile, problems);
610         } catch (CoreException e) {
611             // must continue with compile loop so just log the CoreException
612
e.printStackTrace();
613         }
614     }
615
616     String JavaDoc[] dependencies = result.dependencies;
617     if (dependencies != null) {
618         ReferenceCollection refs = (ReferenceCollection) this.newState.references.get(result.sourceFile.typeLocator());
619         if (refs != null)
620             refs.addDependencies(dependencies);
621     }
622 }
623
624 /**
625  * Creates a marker from each problem and adds it to the resource.
626  * The marker is as follows:
627  * - its type is T_PROBLEM
628  * - its plugin ID is the JavaBuilder's plugin ID
629  * - its message is the problem's message
630  * - its priority reflects the severity of the problem
631  * - its range is the problem's range
632  * - it has an extra attribute "ID" which holds the problem's id
633  * - it's GENERATED_BY attribute is positioned to JavaBuilder.GENERATED_BY if
634  * the problem was generated by JDT; else the GENERATED_BY attribute is
635  * carried from the problem to the marker in extra attributes, if present.
636  */

637 protected void storeProblemsFor(SourceFile sourceFile, CategorizedProblem[] problems) throws CoreException {
638     if (sourceFile == null || problems == null || problems.length == 0) return;
639      // once a classpath error is found, ignore all other problems for this project so the user can see the main error
640
// but still try to compile as many source files as possible to help the case when the base libraries are in source
641
if (!this.keepStoringProblemMarkers) return; // only want the one error recorded on this source file
642

643     IResource resource = sourceFile.resource;
644     HashSet managedMarkerTypes = JavaModelManager.getJavaModelManager().compilationParticipants.managedMarkerTypes();
645     for (int i = 0, l = problems.length; i < l; i++) {
646         CategorizedProblem problem = problems[i];
647         int id = problem.getID();
648
649         // handle missing classfile situation
650
if (id == IProblem.IsClassPathCorrect) {
651             String JavaDoc missingClassfileName = problem.getArguments()[0];
652             if (JavaBuilder.DEBUG)
653                 System.out.println(Messages.bind(Messages.build_incompleteClassPath, missingClassfileName));
654             boolean isInvalidClasspathError = JavaCore.ERROR.equals(javaBuilder.javaProject.getOption(JavaCore.CORE_INCOMPLETE_CLASSPATH, true));
655             // insert extra classpath problem, and make it the only problem for this project (optional)
656
if (isInvalidClasspathError && JavaCore.ABORT.equals(javaBuilder.javaProject.getOption(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, true))) {
657                 JavaBuilder.removeProblemsAndTasksFor(javaBuilder.currentProject); // make this the only problem for this project
658
this.keepStoringProblemMarkers = false;
659             }
660             IMarker marker = this.javaBuilder.currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
661             marker.setAttributes(
662                 new String JavaDoc[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.CATEGORY_ID, IMarker.SOURCE_ID},
663                 new Object JavaDoc[] {
664                     Messages.bind(Messages.build_incompleteClassPath, missingClassfileName),
665                     new Integer JavaDoc(isInvalidClasspathError ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING),
666                     new Integer JavaDoc(CategorizedProblem.CAT_BUILDPATH),
667                     JavaBuilder.SOURCE_ID
668                 }
669             );
670             // even if we're not keeping more markers, still fall through rest of the problem reporting, so that offending
671
// IsClassPathCorrect problem gets recorded since it may help locate the offending reference
672
}
673
674         String JavaDoc markerType = problem.getMarkerType();
675         boolean managedProblem = false;
676         if (IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER.equals(markerType)
677                 || (managedProblem = managedMarkerTypes.contains(markerType))) {
678             IMarker marker = resource.createMarker(markerType);
679
680             String JavaDoc[] attributeNames = JAVA_PROBLEM_MARKER_ATTRIBUTE_NAMES;
681             int standardLength = attributeNames.length;
682             String JavaDoc[] allNames = attributeNames;
683             int managedLength = managedProblem ? 0 : 1;
684             String JavaDoc[] extraAttributeNames = problem.getExtraMarkerAttributeNames();
685             int extraLength = extraAttributeNames == null ? 0 : extraAttributeNames.length;
686             if (managedLength > 0 || extraLength > 0) {
687                 allNames = new String JavaDoc[standardLength + managedLength + extraLength];
688                 System.arraycopy(attributeNames, 0, allNames, 0, standardLength);
689                 if (managedLength > 0)
690                     allNames[standardLength] = IMarker.SOURCE_ID;
691                 System.arraycopy(extraAttributeNames, 0, allNames, standardLength + managedLength, extraLength);
692             }
693
694             Object JavaDoc[] allValues = new Object JavaDoc[allNames.length];
695             // standard attributes
696
int index = 0;
697             allValues[index++] = problem.getMessage(); // message
698
allValues[index++] = problem.isError() ? S_ERROR : S_WARNING; // severity
699
allValues[index++] = new Integer JavaDoc(id); // ID
700
allValues[index++] = new Integer JavaDoc(problem.getSourceStart()); // start
701
allValues[index++] = new Integer JavaDoc(problem.getSourceEnd() + 1); // end
702
allValues[index++] = new Integer JavaDoc(problem.getSourceLineNumber()); // line
703
allValues[index++] = Util.getProblemArgumentsForMarker(problem.getArguments()); // arguments
704
allValues[index++] = new Integer JavaDoc(problem.getCategoryID()); // category ID
705
// GENERATED_BY attribute for JDT problems
706
if (managedLength > 0)
707                 allValues[index++] = JavaBuilder.SOURCE_ID;
708             // optional extra attributes
709
if (extraLength > 0)
710                 System.arraycopy(problem.getExtraMarkerAttributeValues(), 0, allValues, index, extraLength);
711
712             marker.setAttributes(allNames, allValues);
713
714             if (!this.keepStoringProblemMarkers) return; // only want the one error recorded on this source file
715
}
716     }
717 }
718
719 protected void storeTasksFor(SourceFile sourceFile, CategorizedProblem[] tasks) throws CoreException {
720     if (sourceFile == null || tasks == null || tasks.length == 0) return;
721
722     IResource resource = sourceFile.resource;
723     for (int i = 0, l = tasks.length; i < l; i++) {
724         CategorizedProblem task = tasks[i];
725         if (task.getID() == IProblem.Task) {
726             IMarker marker = resource.createMarker(IJavaModelMarker.TASK_MARKER);
727             Integer JavaDoc priority = P_NORMAL;
728             String JavaDoc compilerPriority = task.getArguments()[2];
729             if (JavaCore.COMPILER_TASK_PRIORITY_HIGH.equals(compilerPriority))
730                 priority = P_HIGH;
731             else if (JavaCore.COMPILER_TASK_PRIORITY_LOW.equals(compilerPriority))
732                 priority = P_LOW;
733
734             String JavaDoc[] attributeNames = JAVA_TASK_MARKER_ATTRIBUTE_NAMES;
735             int standardLength = attributeNames.length;
736             String JavaDoc[] allNames = attributeNames;
737             String JavaDoc[] extraAttributeNames = task.getExtraMarkerAttributeNames();
738             int extraLength = extraAttributeNames == null ? 0 : extraAttributeNames.length;
739             if (extraLength > 0) {
740                 allNames = new String JavaDoc[standardLength + extraLength];
741                 System.arraycopy(attributeNames, 0, allNames, 0, standardLength);
742                 System.arraycopy(extraAttributeNames, 0, allNames, standardLength, extraLength);
743             }
744
745             Object JavaDoc[] allValues = new Object JavaDoc[allNames.length];
746             // standard attributes
747
int index = 0;
748             allValues[index++] = task.getMessage();
749             allValues[index++] = priority;
750             allValues[index++] = new Integer JavaDoc(task.getID());
751             allValues[index++] = new Integer JavaDoc(task.getSourceStart());
752             allValues[index++] = new Integer JavaDoc(task.getSourceEnd() + 1);
753             allValues[index++] = new Integer JavaDoc(task.getSourceLineNumber());
754             allValues[index++] = Boolean.FALSE;
755             allValues[index++] = JavaBuilder.SOURCE_ID;
756             // optional extra attributes
757
if (extraLength > 0)
758                 System.arraycopy(task.getExtraMarkerAttributeValues(), 0, allValues, index, extraLength);
759
760             marker.setAttributes(allNames, allValues);
761         }
762     }
763 }
764
765 protected void updateProblemsFor(SourceFile sourceFile, CompilationResult result) throws CoreException {
766     CategorizedProblem[] problems = result.getProblems();
767     if (problems == null || problems.length == 0) return;
768
769     notifier.updateProblemCounts(problems);
770     storeProblemsFor(sourceFile, problems);
771 }
772
773 protected void updateTasksFor(SourceFile sourceFile, CompilationResult result) throws CoreException {
774     CategorizedProblem[] tasks = result.getTasks();
775     if (tasks == null || tasks.length == 0) return;
776
777     storeTasksFor(sourceFile, tasks);
778 }
779
780 protected char[] writeClassFile(ClassFile classFile, SourceFile compilationUnit, boolean isTopLevelType) throws CoreException {
781     String JavaDoc fileName = new String JavaDoc(classFile.fileName()); // the qualified type name "p1/p2/A"
782
IPath filePath = new Path(fileName);
783     IContainer outputFolder = compilationUnit.sourceLocation.binaryFolder;
784     IContainer container = outputFolder;
785     if (filePath.segmentCount() > 1) {
786         container = createFolder(filePath.removeLastSegments(1), outputFolder);
787         filePath = new Path(filePath.lastSegment());
788     }
789
790     IFile file = container.getFile(filePath.addFileExtension(SuffixConstants.EXTENSION_class));
791     writeClassFileBytes(classFile.getBytes(), file, fileName, isTopLevelType, compilationUnit);
792     if (classFile.isShared) {
793         this.compiler.lookupEnvironment.classFilePool.release(classFile);
794     }
795     // answer the name of the class file as in Y or Y$M
796
return filePath.lastSegment().toCharArray();
797 }
798
799 protected void writeClassFileBytes(byte[] bytes, IFile file, String JavaDoc qualifiedFileName, boolean isTopLevelType, SourceFile compilationUnit) throws CoreException {
800     if (file.exists()) {
801         // Deal with shared output folders... last one wins... no collision cases detected
802
if (JavaBuilder.DEBUG)
803             System.out.println("Writing changed class file " + file.getName());//$NON-NLS-1$
804
if (!file.isDerived())
805             file.setDerived(true);
806         file.setContents(new ByteArrayInputStream(bytes), true, false, null);
807     } else {
808         // Default implementation just writes out the bytes for the new class file...
809
if (JavaBuilder.DEBUG)
810             System.out.println("Writing new class file " + file.getName());//$NON-NLS-1$
811
file.create(new ByteArrayInputStream(bytes), IResource.FORCE | IResource.DERIVED, null);
812     }
813 }
814 }
815
Popular Tags