You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AjPipeliningCompilerAdapter.java 28KB

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