]> source.dussan.org Git - aspectj.git/blob
5c2e4d2c76058b7a318b153b710b333386cbc48a
[aspectj.git] /
1 /*******************************************************************************
2  * Copyright (c) 2006 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  *     Andy Clement    - initial implementation 26Jul06
10  *******************************************************************************/
11 package org.aspectj.ajdt.internal.compiler;
12
13 import java.io.IOException;
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.Hashtable;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.Map;
20
21 import org.aspectj.ajdt.internal.compiler.ast.AddAtAspectJAnnotationsVisitor;
22 import org.aspectj.ajdt.internal.compiler.ast.AspectDeclaration;
23 import org.aspectj.ajdt.internal.compiler.ast.InterTypeConstructorDeclaration;
24 import org.aspectj.ajdt.internal.compiler.ast.InterTypeFieldDeclaration;
25 import org.aspectj.ajdt.internal.compiler.ast.InterTypeMethodDeclaration;
26 import org.aspectj.ajdt.internal.compiler.ast.ValidateAtAspectJAnnotationsVisitor;
27 import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
28 import org.aspectj.ajdt.internal.core.builder.AjState;
29 import org.aspectj.asm.internal.CharOperation;
30 import org.aspectj.bridge.IMessage;
31 import org.aspectj.bridge.IMessageHandler;
32 import org.aspectj.bridge.IProgressListener;
33 import org.aspectj.bridge.context.CompilationAndWeavingContext;
34 import org.aspectj.bridge.context.ContextToken;
35 import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
36 import org.aspectj.org.eclipse.jdt.internal.compiler.Compiler;
37 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
38 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
39 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
40 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
41 import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
42 import org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
43 import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
44 import org.aspectj.weaver.bcel.BcelWeaver;
45 import org.aspectj.weaver.bcel.BcelWorld;
46 import org.aspectj.weaver.bcel.UnwovenClassFile;
47
48 /**
49  * Adapts standard JDT Compiler to add in AspectJ specific behaviours. This version implements pipelining - where files are compiled
50  * and then woven immediately, unlike AjCompilerAdapter which compiles everything then weaves everything. (One small note: because
51  * all aspects have to be known before weaving can take place, the weaving pipeline is 'stalled' until all aspects have been
52  * compiled).
53  * 
54  * The basic strategy is this:
55  * 
56  * 1. diet parse all input source files - this is enough for us to implement ITD matching - this enables us to determine which are
57  * aspects 2. sort the input files, aspects first - keep a note of how many files contain aspects 3. if there are aspects, mark the
58  * pipeline as 'stalled' 3. repeat 3a. compile a file 3b. have we now compiled all aspects? NO - put file in a weave pending queue
59  * YES- unstall the 'pipeline' 3c. is the pipeline stalled? NO - weave all pending files and this one YES- do nothing
60  * 
61  * Complexities arise because of: - what does -XterminateAfterCompilation mean? since there is no stage where everything is compiled
62  * and nothing is woven
63  * 
64  * 
65  * Here is the compiler loop difference when pipelining.
66  * 
67  * the old way: Finished diet parsing [C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java] Finished diet parsing
68  * [C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java] > AjLookupEnvironment.completeTypeBindings() <
69  * AjLookupEnvironment.completeTypeBindings() compiling C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java
70  * >Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java)
71  * <Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java) compiling
72  * C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java
73  * >Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java)
74  * <Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java) >AjCompilerAdapter.weave()
75  * >BcelWeaver.prepareForWeave <BcelWeaver.prepareForWeave woven class ClassOne (from
76  * C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java) woven class ClassTwo (from
77  * C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java) <AjCompilerAdapter.weave()
78  * 
79  * the new way (see the compiling/weaving mixed up): Finished diet parsing
80  * [C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java] Finished diet parsing
81  * [C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java] >AjLookupEnvironment.completeTypeBindings()
82  * <AjLookupEnvironment.completeTypeBindings() compiling C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java
83  * >Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java)
84  * <Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java) >AjCompilerAdapter.weave()
85  * >BcelWeaver.prepareForWeave <BcelWeaver.prepareForWeave woven class ClassOne (from
86  * C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassOne.java) <AjCompilerAdapter.weave() compiling
87  * C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java
88  * >Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java)
89  * <Compiler.process(C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java) >AjCompilerAdapter.weave() woven class ClassTwo
90  * (from C:\temp\ajcSandbox\aspectjhead\ajcTest23160.tmp\ClassTwo.java) <AjCompilerAdapter.weave()
91  * 
92  * 
93  */
94 public class AjPipeliningCompilerAdapter extends AbstractCompilerAdapter {
95
96         private Compiler compiler;
97         private BcelWeaver weaver;
98         private EclipseFactory eWorld;
99         private boolean isBatchCompile;
100         private boolean reportedErrors;
101         private boolean isXTerminateAfterCompilation;
102         private boolean proceedOnError;
103         private boolean inJava5Mode;
104         private boolean makeReflectable;
105         private boolean noAtAspectJAnnotationProcessing;
106         private IIntermediateResultsRequestor intermediateResultsRequestor;
107         private IProgressListener progressListener;
108         private IOutputClassFileNameProvider outputFileNameProvider;
109         private IBinarySourceProvider binarySourceProvider;
110         private WeaverMessageHandler weaverMessageHandler;
111         private Map<String, List<UnwovenClassFile>> binarySourceSetForFullWeave = new HashMap<>();
112
113         private ContextToken processingToken = null;
114         private ContextToken resolvingToken = null;
115         private ContextToken analysingToken = null;
116         private ContextToken generatingToken = null;
117
118         private AjState incrementalCompilationState;
119
120         // Maintains a list of whats weaving - whilst the pipeline is stalled, this accumulates aspects.
121         List<InterimCompilationResult> resultsPendingWeave = new ArrayList<>();
122
123         // pipelining info
124         private boolean pipelineStalled = true;
125         private boolean weaverInitialized = false;
126         private int toWaitFor;
127         // If we determine we are going to drop back to a full build - don't need to tell the weaver to report adviceDidNotMatch
128         private boolean droppingBackToFullBuild;
129
130         /**
131          * Create an adapter, and tell it everything it needs to now to drive the AspectJ parts of a compile cycle.
132          * 
133          * @param compiler the JDT compiler that produces class files from source
134          * @param isBatchCompile true if this is a full build (non-incremental)
135          * @param world the bcelWorld used for type resolution during weaving
136          * @param weaver the weaver
137          * @param intRequestor recipient of interim compilation results from compiler (pre-weave)
138          * @param outputFileNameProvider implementor of a strategy providing output file names for results
139          * @param binarySourceEntries binary source that we didn't compile, but that we need to weave
140          * @param resultSetForFullWeave if we are doing an incremental build, and the weaver determines that we need to weave the world,
141          *        this is the set of intermediate results that will be passed to the weaver.
142          */
143         public AjPipeliningCompilerAdapter(Compiler compiler, boolean isBatchCompile, BcelWorld world, BcelWeaver weaver,
144                         EclipseFactory eFactory, IIntermediateResultsRequestor intRequestor, IProgressListener progressListener,
145                         IOutputClassFileNameProvider outputFileNameProvider, IBinarySourceProvider binarySourceProvider,
146                         Map fullBinarySourceEntries, /* fileName |-> List<UnwovenClassFile> */
147                         boolean isXterminateAfterCompilation, boolean proceedOnError, boolean noAtAspectJProcessing, boolean makeReflectable,
148                         AjState incrementalCompilationState) {
149                 this.compiler = compiler;
150                 this.isBatchCompile = isBatchCompile;
151                 this.weaver = weaver;
152                 this.intermediateResultsRequestor = intRequestor;
153                 this.progressListener = progressListener;
154                 this.outputFileNameProvider = outputFileNameProvider;
155                 this.binarySourceProvider = binarySourceProvider;
156                 this.isXTerminateAfterCompilation = isXterminateAfterCompilation;
157                 this.proceedOnError = proceedOnError;
158                 this.binarySourceSetForFullWeave = fullBinarySourceEntries;
159                 this.eWorld = eFactory;
160                 this.inJava5Mode = false;
161                 this.makeReflectable = makeReflectable;
162                 this.noAtAspectJAnnotationProcessing = noAtAspectJProcessing;
163                 this.incrementalCompilationState = incrementalCompilationState;
164
165                 if (compiler.options.complianceLevel >= ClassFileConstants.JDK1_5) {
166                         inJava5Mode = true;
167                 }
168                 IMessageHandler msgHandler = world.getMessageHandler();
169                 // Do we need to reset the message handler or create a new one? (This saves a ton of memory lost on incremental compiles...)
170                 if (msgHandler instanceof WeaverMessageHandler) {
171                         ((WeaverMessageHandler) msgHandler).resetCompiler(compiler);
172                         weaverMessageHandler = (WeaverMessageHandler) msgHandler;
173                 } else {
174                         weaverMessageHandler = new WeaverMessageHandler(msgHandler, compiler);
175                         world.setMessageHandler(weaverMessageHandler);
176                 }
177         }
178
179         // the compilation lifecycle methods below are called in order as compilation progresses...
180
181         /**
182          * In a pipelining compilation system, we need to ensure aspects are through the pipeline first. Only when they are all through
183          * (and therefore we know about all static/dynamic crosscutting) can be proceed to weave anything. Effectively the weaving part
184          * of the pipeline stalls until all the aspects have been fully compiled. This method sorts the compilation units such that any
185          * containing aspects are fully compiled first and it keeps a note on how long it should stall the pipeline before commencing
186          * weaving.
187          */
188         public void afterDietParsing(CompilationUnitDeclaration[] units) {
189                 if (debugPipeline) {
190                         System.err.println("> afterDietParsing: there are " + (units == null ? 0 : units.length) + " units to sort");
191                 }
192
193                 if (!reportedErrors && units != null) {
194                         for (CompilationUnitDeclaration unit : units) {
195                                 if (unit != null && unit.compilationResult != null && unit.compilationResult.hasErrors()) {
196                                         reportedErrors = true;
197                                         break; // TODO break or exit here?
198                                 }
199                         }
200                 }
201
202                 // Break the units into two lists...
203                 List<CompilationUnitDeclaration> aspects = new ArrayList<>();
204                 List<CompilationUnitDeclaration> nonaspects = new ArrayList<>();
205                 for (CompilationUnitDeclaration unit : units) {
206                         if (containsAnAspect(unit)) {
207                                 aspects.add(unit);
208                         } else {
209                                 nonaspects.add(unit);
210                         }
211                 }
212
213                 // ...and put them back together, aspects first
214                 int posn = 0;
215                 for (CompilationUnitDeclaration aspect : aspects) {
216                         units[posn++] = aspect;
217                 }
218                 for (CompilationUnitDeclaration nonaspect : nonaspects) {
219                         units[posn++] = nonaspect;
220                 }
221
222                 // Work out how long to stall the pipeline
223                 toWaitFor = aspects.size();
224                 if (debugPipeline) {
225                         System.err.println("< afterDietParsing: stalling pipeline for " + toWaitFor + " source files");
226                 }
227
228                 // TESTING
229                 if (pipelineTesting) {
230                         if (pipelineOutput == null) {
231                                 pipelineOutput = new Hashtable();
232                         }
233                         pipelineOutput.put("filesContainingAspects", new Integer(toWaitFor).toString());
234                         StringBuffer order = new StringBuffer();
235                         order.append("[");
236                         for (int i = 0; i < units.length; i++) {
237                                 if (i != 0) {
238                                         order.append(",");
239                                 }
240                                 CompilationUnitDeclaration declaration = units[i];
241                                 String filename = new String(declaration.getFileName());
242                                 int idx = filename.lastIndexOf('/');
243                                 if (idx > 0) {
244                                         filename = filename.substring(idx + 1);
245                                 }
246                                 idx = filename.lastIndexOf('\\');
247                                 if (idx > 0) {
248                                         filename = filename.substring(idx + 1);
249                                 }
250                                 order.append(filename);
251                         }
252                         order.append("]");
253                         pipelineOutput.put("weaveOrder", order.toString());
254                 }
255         }
256
257         public void beforeCompiling(ICompilationUnit[] sourceUnits) {
258                 resultsPendingWeave = new ArrayList<>();
259                 reportedErrors = false;
260                 droppingBackToFullBuild = false;
261         }
262
263         public void beforeProcessing(CompilationUnitDeclaration unit) {
264                 if (debugPipeline) {
265                         System.err.println("compiling " + new String(unit.getFileName()));
266                 }
267                 eWorld.showMessage(IMessage.INFO, "compiling " + new String(unit.getFileName()), null, null);
268                 processingToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_COMPILATION_UNIT, unit
269                                 .getFileName());
270                 if (inJava5Mode && !noAtAspectJAnnotationProcessing) {
271                         ContextToken tok = CompilationAndWeavingContext.enteringPhase(
272                                         CompilationAndWeavingContext.ADDING_AT_ASPECTJ_ANNOTATIONS, unit.getFileName());
273                         AddAtAspectJAnnotationsVisitor atAspectJVisitor = new AddAtAspectJAnnotationsVisitor(unit, makeReflectable);
274                         unit.traverse(atAspectJVisitor, unit.scope);
275                         CompilationAndWeavingContext.leavingPhase(tok);
276                 }
277         }
278
279         public void beforeResolving(CompilationUnitDeclaration unit) {
280                 resolvingToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.RESOLVING_COMPILATION_UNIT, unit
281                                 .getFileName());
282         }
283
284         public void afterResolving(CompilationUnitDeclaration unit) {
285                 if (resolvingToken != null) {
286                         CompilationAndWeavingContext.leavingPhase(resolvingToken);
287                 }
288         }
289
290         public void beforeAnalysing(CompilationUnitDeclaration unit) {
291                 analysingToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.ANALYSING_COMPILATION_UNIT, unit
292                                 .getFileName());
293                 if (inJava5Mode && !noAtAspectJAnnotationProcessing) {
294                         ValidateAtAspectJAnnotationsVisitor atAspectJVisitor = new ValidateAtAspectJAnnotationsVisitor(unit);
295                         unit.traverse(atAspectJVisitor, unit.scope);
296                 }
297         }
298
299         public void afterAnalysing(CompilationUnitDeclaration unit) {
300                 if (analysingToken != null) {
301                         CompilationAndWeavingContext.leavingPhase(analysingToken);
302                 }
303         }
304
305         public void beforeGenerating(CompilationUnitDeclaration unit) {
306                 generatingToken = CompilationAndWeavingContext.enteringPhase(
307                                 CompilationAndWeavingContext.GENERATING_UNWOVEN_CODE_FOR_COMPILATION_UNIT, unit.getFileName());
308                 if (eWorld.pushinCollector != null) {
309                         if (unit.types != null && unit.types.length > 0) {
310                                 for (int t = 0; t < unit.types.length; t++) {
311                                         TypeDeclaration type = unit.types[t];
312                                         if (type.methods != null) {
313                                                 for (int m = 0; m < type.methods.length; m++) {
314                                                         AbstractMethodDeclaration md = type.methods[m];
315                                                         if (md instanceof InterTypeMethodDeclaration) {
316                                                                 InterTypeMethodDeclaration itmd = ((InterTypeMethodDeclaration) md);
317                                                                 ITDMethodPrinter printer = new ITDMethodPrinter(itmd, md.scope);
318                                                                 String s = printer.print();
319                                                                 eWorld.pushinCollector.recordInterTypeMethodDeclarationCode(md, s, getDeclarationLineNumber(md));
320                                                         } else if (md instanceof InterTypeFieldDeclaration) {
321                                                                 ITDFieldPrinter printer = new ITDFieldPrinter(((InterTypeFieldDeclaration) md), md.scope);
322                                                                 String s = printer.print();
323                                                                 eWorld.pushinCollector.recordInterTypeFieldDeclarationCode(md, s, getDeclarationLineNumber(md));
324                                                         } else if (md instanceof InterTypeConstructorDeclaration) {
325                                                                 ITDConstructorPrinter printer = new ITDConstructorPrinter(((InterTypeConstructorDeclaration) md),
326                                                                                 md.scope);
327                                                                 String s = printer.print();
328                                                                 eWorld.pushinCollector.recordInterTypeConstructorDeclarationCode(md, s,
329                                                                                 getDeclarationLineNumber(md));
330                                                                 // } else if (md instanceof DeclareAnnotationDeclaration) {
331                                                                 // DeclareAnnotationDeclaration dad = (DeclareAnnotationDeclaration) md;
332                                                                 // String value = new DeclareAnnotationsPrinter(dad, dad.scope).print();
333                                                                 // eWorld.pushinCollector.recordDeclareAnnotationDeclarationCode(md, value);
334                                                         }
335                                                 }
336                                         }
337                                 }
338                         }
339                         eWorld.pushinCollector.setOutputFileNameProvider(outputFileNameProvider);
340                 }
341         }
342
343         /**
344          * @return the line number for this declaration in the source code
345          */
346         private int getDeclarationLineNumber(AbstractMethodDeclaration md) {
347                 int sourceStart = md.sourceStart;
348                 int[] separators = md.compilationResult.lineSeparatorPositions;
349                 int declarationStartLine = 1;
350                 for (int separator : separators) {
351                         if (sourceStart < separator) {
352                                 break;
353                         }
354                         declarationStartLine++;
355                 }
356                 return declarationStartLine;
357         }
358
359         public void afterGenerating(CompilationUnitDeclaration unit) {
360                 if (generatingToken != null) {
361                         CompilationAndWeavingContext.leavingPhase(generatingToken);
362                 }
363                 if (eWorld.pushinCollector != null) {
364                         eWorld.pushinCollector.dump(unit);
365                 }
366         }
367
368         public void afterCompiling(CompilationUnitDeclaration[] units) {
369                 this.eWorld.cleanup();
370                 if (!weaverInitialized) { // nothing got compiled, doesnt mean there is nothing to do... (binary weaving)
371                         if (!(isXTerminateAfterCompilation || (reportedErrors && !proceedOnError))) {
372                                 // acceptResult(unit.compilationResult);
373                                 // } else {
374                                 try {
375                                         if (weaveQueuedEntries()) {
376                                                 droppingBackToFullBuild = true;
377                                         }
378                                 } catch (IOException ex) {
379                                         AbortCompilation ac = new AbortCompilation(null, ex);
380                                         throw ac;
381                                 }
382                         }
383                 }
384                 postWeave();
385                 try {
386                         // not great ... but one more check before we continue, see pr132314
387                         if (!reportedErrors && units != null) {
388                                 for (CompilationUnitDeclaration unit : units) {
389                                         if (unit != null && unit.compilationResult != null && unit.compilationResult.hasErrors()) {
390                                                 reportedErrors = true;
391                                                 break;
392                                         }
393                                 }
394                         }
395                         if (isXTerminateAfterCompilation || (reportedErrors && !proceedOnError)) {
396                                 // no point weaving... just tell the requestor we're done
397                                 notifyRequestor();
398                         } else {
399                                 // weave(); // notification happens as weave progresses...
400                                 // weaver.getWorld().flush(); // pr152257
401                         }
402                         // } catch (IOException ex) {
403                         // AbortCompilation ac = new AbortCompilation(null,ex);
404                         // throw ac;
405                 } catch (RuntimeException rEx) {
406                         if (rEx instanceof AbortCompilation) {
407                                 throw rEx; // Don't wrap AbortCompilation exceptions!
408                         }
409
410                         // This will be unwrapped in Compiler.handleInternalException() and the nested
411                         // RuntimeException thrown back to the original caller - which is AspectJ
412                         // which will then then log it as a compiler problem.
413                         throw new AbortCompilation(true, rEx);
414                 }
415         }
416
417         public void afterProcessing(CompilationUnitDeclaration unit, int unitIndex) {
418                 CompilationAndWeavingContext.leavingPhase(processingToken);
419                 eWorld.finishedCompilationUnit(unit);
420                 InterimCompilationResult intRes = new InterimCompilationResult(unit.compilationResult, outputFileNameProvider);
421                 if (unit.compilationResult.hasErrors()) {
422                         reportedErrors = true;
423                 }
424
425                 if (intermediateResultsRequestor != null) {
426                         intermediateResultsRequestor.acceptResult(intRes);
427                 }
428
429                 if (unit.compilationResult.hasErrors() || (isXTerminateAfterCompilation || (reportedErrors && !proceedOnError))) {
430                         acceptResult(unit.compilationResult);
431                 } else {
432                         queueForWeaving(intRes);
433                 }
434         }
435
436         private void queueForWeaving(InterimCompilationResult intRes) {
437                 resultsPendingWeave.add(intRes);
438                 if (pipelineStalled) {
439                         if (resultsPendingWeave.size() >= toWaitFor) {
440                                 pipelineStalled = false;
441                         }
442                 }
443                 if (pipelineStalled) {
444                         return;
445                 }
446                 try {
447                         if (weaveQueuedEntries()) {
448                                 droppingBackToFullBuild = true;
449                         }
450                 } catch (IOException ex) {
451                         AbortCompilation ac = new AbortCompilation(null, ex);
452                         throw ac;
453                 }
454         }
455
456         /*
457          * Called from the weaverAdapter once it has finished weaving the class files associated with a given compilation result.
458          */
459         public void acceptResult(CompilationResult result) {
460                 compiler.requestor.acceptResult(result.tagAsAccepted());
461                 if (compiler.unitsToProcess != null) {
462                         for (int i = 0; i < compiler.unitsToProcess.length; i++) {
463                                 if (compiler.unitsToProcess[i] != null) {
464                                         if (compiler.unitsToProcess[i].compilationResult == result) {
465                                                 compiler.unitsToProcess[i].cleanUp();
466                                                 compiler.unitsToProcess[i] = null;
467                                         }
468                                 }
469                         }
470                 }
471         }
472
473         // helper methods...
474         // ==================================================================================
475
476         private List<InterimCompilationResult> getBinarySourcesFrom(Map<String, List<UnwovenClassFile>> binarySourceEntries) {
477                 // Map is fileName |-> List<UnwovenClassFile>
478                 List<InterimCompilationResult> ret = new ArrayList<>();
479                 for (String sourceFileName : binarySourceEntries.keySet()) {
480                         List<UnwovenClassFile> unwovenClassFiles = binarySourceEntries.get(sourceFileName);
481                         // XXX - see bugs 57432,58679 - final parameter on next call should be "compiler.options.maxProblemsPerUnit"
482                         CompilationResult result = new CompilationResult(sourceFileName.toCharArray(), 0, 0, Integer.MAX_VALUE);
483                         result.noSourceAvailable();
484                         InterimCompilationResult binarySource = new InterimCompilationResult(result, unwovenClassFiles);
485                         ret.add(binarySource);
486                 }
487                 return ret;
488         }
489
490         private void notifyRequestor() {
491                 for (InterimCompilationResult iresult : resultsPendingWeave) {
492                         compiler.requestor.acceptResult(iresult.result().tagAsAccepted());
493                 }
494         }
495
496         /** Return true if we've decided to drop back to a full build (too much has changed) */
497         private boolean weaveQueuedEntries() throws IOException {
498                 if (debugPipeline) {
499                         System.err.println(">.weaveQueuedEntries()");
500                 }
501                 for (InterimCompilationResult iresult : resultsPendingWeave) {
502                         for (int i = 0; i < iresult.unwovenClassFiles().length; i++) {
503                                 weaver.addClassFile(iresult.unwovenClassFiles()[i], false);
504                         }
505                 }
506                 ensureWeaverInitialized(); // by doing this only once, are we saying needToReweaveWorld can't change once the aspects have
507                 // been stuffed into the weaver?
508                 if (weaver.needToReweaveWorld() && !isBatchCompile) {
509                         return true;
510                 }
511                 weaver.weave(new WeaverAdapter(this, weaverMessageHandler, progressListener));
512                 resultsPendingWeave.clear(); // dont need to do those again
513                 this.eWorld.minicleanup();
514                 if (debugPipeline) {
515                         System.err.println("<.weaveQueuedEntries()");
516                 }
517                 return false;
518         }
519
520         private void ensureWeaverInitialized() {
521                 if (weaverInitialized) {
522                         return;
523                 }
524                 weaverInitialized = true;
525                 weaver.setIsBatchWeave(isBatchCompile);
526                 weaver.prepareForWeave();
527                 if (weaver.needToReweaveWorld()) {
528                         if (!isBatchCompile) {
529                                 // force full recompilation from source
530                                 this.incrementalCompilationState.forceBatchBuildNextTimeAround();
531                                 return;
532                         }
533                         resultsPendingWeave.addAll(getBinarySourcesFrom(binarySourceSetForFullWeave));
534                 } else {
535                         Map binarySourcesToAdd = binarySourceProvider.getBinarySourcesForThisWeave();
536                         resultsPendingWeave.addAll(getBinarySourcesFrom(binarySourcesToAdd));
537                 }
538         }
539
540         // private void weave() throws IOException {
541         // if (debugPipeline)System.err.println("> weave()");
542         // // ensure weaver state is set up correctly
543         // for (Iterator iter = resultsPendingWeave.iterator(); iter.hasNext();) {
544         // InterimCompilationResult iresult = (InterimCompilationResult) iter.next();
545         // for (int i = 0; i < iresult.unwovenClassFiles().length; i++) {
546         // weaver.addClassFile(iresult.unwovenClassFiles()[i]);
547         // }
548         // }
549         //
550         // weaver.setIsBatchWeave(isBatchCompile);
551         // weaver.prepareForWeave();
552         // if (weaver.needToReweaveWorld()) {
553         // if (!isBatchCompile) {
554         // //force full recompilation from source
555         // this.incrementalCompilationState.forceBatchBuildNextTimeAround();
556         // return;
557         // }
558         // resultsPendingWeave.addAll(getBinarySourcesFrom(binarySourceSetForFullWeave));
559         // } else {
560         // Map binarySourcesToAdd = binarySourceProvider.getBinarySourcesForThisWeave();
561         // resultsPendingWeave.addAll(getBinarySourcesFrom(binarySourcesToAdd));
562         // }
563         //
564         // try {
565         // weaver.weave(new WeaverAdapter(this,weaverMessageHandler,progressListener));
566         // } finally {
567         // weaver.tidyUp();
568         // IMessageHandler imh = weaver.getWorld().getMessageHandler();
569         // if (imh instanceof WeaverMessageHandler)
570         // ((WeaverMessageHandler)imh).resetCompiler(null);
571         // }
572         // if (debugPipeline)System.err.println("< weave()");
573         // }
574
575         private void postWeave() {
576                 if (debugPipeline) {
577                         System.err.println("> postWeave()");
578                 }
579                 IMessageHandler imh = weaver.getWorld().getMessageHandler();
580                 if (imh instanceof WeaverMessageHandler) {
581                         ((WeaverMessageHandler) imh).setCurrentResult(null);
582                 }
583                 if (!droppingBackToFullBuild) {
584                         weaver.allWeavingComplete();
585                 }
586                 weaver.tidyUp();
587                 if (imh instanceof WeaverMessageHandler) {
588                         ((WeaverMessageHandler) imh).resetCompiler(null);
589                 }
590                 if (debugPipeline) {
591                         System.err.println("< postWeave()");
592                 }
593         }
594
595         /**
596          * Return true if the compilation unit declaration contains an aspect declaration (either code style or annotation style). It
597          * must inspect the multiple types that may be in a compilation unit declaration and any inner types.
598          */
599         private boolean containsAnAspect(CompilationUnitDeclaration cud) {
600                 TypeDeclaration[] typeDecls = cud.types;
601                 if (typeDecls != null) {
602                         for (TypeDeclaration declaration : typeDecls) { // loop through top level types in the file
603                                 if (isAspect(declaration)) {
604                                         return true;
605                                 }
606                                 if (declaration.memberTypes != null) {
607                                         TypeDeclaration[] memberTypes = declaration.memberTypes;
608                                         for (TypeDeclaration memberType : memberTypes) { // loop through inner types
609                                                 if (containsAnAspect(memberType)) {
610                                                         return true;
611                                                 }
612                                         }
613                                 }
614                         }
615                 }
616                 return false;
617         }
618
619         private boolean containsAnAspect(TypeDeclaration tDecl) {
620                 if (isAspect(tDecl)) {
621                         return true;
622                 }
623                 if (tDecl.memberTypes != null) {
624                         TypeDeclaration[] memberTypes = tDecl.memberTypes;
625                         for (TypeDeclaration memberType : memberTypes) { // loop through inner types
626                                 if (containsAnAspect(memberType)) {
627                                         return true;
628                                 }
629                         }
630                 }
631                 return false;
632         }
633
634         private static final char[] aspectSig = "Lorg/aspectj/lang/annotation/Aspect;".toCharArray();
635
636         private boolean isAspect(TypeDeclaration declaration) {
637                 // avoid an NPE when something else is wrong in this system ... the real problem will be reported elsewhere
638                 if (declaration.staticInitializerScope == null) {
639                         return false;
640                 }
641                 if (declaration instanceof AspectDeclaration) {
642                         return true; // code style
643                 } else if (declaration.annotations != null) { // check for annotation style
644                         for (int index = 0; index < declaration.annotations.length; index++) {
645                                 // Cause annotation resolution
646                                 declaration.binding.getAnnotationTagBits();
647                                 Annotation a = declaration.annotations[index];
648                                 if (a.resolvedType == null) {
649                                         continue; // another problem is being reported, so don't crash here
650                                 }
651                                 if (CharOperation.equals(a.resolvedType.signature(), aspectSig)) {
652                                         return true;
653                                 }
654                         }
655                 }
656                 return false;
657         }
658
659         // ---
660         /**
661          * SECRET: FOR TESTING - this can be used to collect information that tests can verify.
662          */
663         public static boolean pipelineTesting = false;
664         public static Hashtable<String, String> pipelineOutput = null;
665
666         // Keys into pipelineOutput:
667         // compileOrder "[XXX,YYY]" a list of the order in which files will be woven (aspects should be first)
668         // filesContainingAspects "NNN" how many input source files have aspects inside
669         // 
670
671         public static String getPipelineDebugOutput(String key) {
672                 if (pipelineOutput == null) {
673                         return "";
674                 }
675                 return pipelineOutput.get(key);
676         }
677
678         private final static boolean debugPipeline = false;
679
680         public List<InterimCompilationResult> getResultsPendingWeave() {
681                 return resultsPendingWeave;
682         }
683
684 }