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