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.

AjBuildManager.java 60KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v 2.0
  6. * which accompanies this distribution and is available at
  7. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.ajdt.internal.core.builder;
  13. import java.io.BufferedOutputStream;
  14. import java.io.ByteArrayOutputStream;
  15. import java.io.File;
  16. import java.io.FileFilter;
  17. import java.io.FileInputStream;
  18. import java.io.FileNotFoundException;
  19. import java.io.IOException;
  20. import java.io.OutputStream;
  21. import java.io.PrintStream;
  22. import java.util.ArrayList;
  23. import java.util.Collection;
  24. import java.util.Collections;
  25. import java.util.HashMap;
  26. import java.util.List;
  27. import java.util.Locale;
  28. import java.util.Map;
  29. import java.util.Set;
  30. import java.util.jar.Attributes;
  31. import java.util.jar.JarFile;
  32. import java.util.jar.JarInputStream;
  33. import java.util.jar.JarOutputStream;
  34. import java.util.jar.Manifest;
  35. import java.util.zip.ZipEntry;
  36. import org.aspectj.ajdt.ajc.BuildArgParser;
  37. import org.aspectj.ajdt.internal.compiler.AjCompilerAdapter;
  38. import org.aspectj.ajdt.internal.compiler.AjPipeliningCompilerAdapter;
  39. import org.aspectj.ajdt.internal.compiler.CompilationResultDestinationManager;
  40. import org.aspectj.ajdt.internal.compiler.IBinarySourceProvider;
  41. import org.aspectj.ajdt.internal.compiler.ICompilerAdapter;
  42. import org.aspectj.ajdt.internal.compiler.ICompilerAdapterFactory;
  43. import org.aspectj.ajdt.internal.compiler.IIntermediateResultsRequestor;
  44. import org.aspectj.ajdt.internal.compiler.IOutputClassFileNameProvider;
  45. import org.aspectj.ajdt.internal.compiler.InterimCompilationResult;
  46. import org.aspectj.ajdt.internal.compiler.lookup.AjLookupEnvironment;
  47. import org.aspectj.ajdt.internal.compiler.lookup.AnonymousClassPublisher;
  48. import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
  49. import org.aspectj.ajdt.internal.compiler.problem.AjProblemReporter;
  50. import org.aspectj.asm.AsmManager;
  51. import org.aspectj.asm.IHierarchy;
  52. import org.aspectj.asm.IProgramElement;
  53. import org.aspectj.asm.internal.ProgramElement;
  54. import org.aspectj.bridge.AbortException;
  55. import org.aspectj.bridge.CountingMessageHandler;
  56. import org.aspectj.bridge.ILifecycleAware;
  57. import org.aspectj.bridge.IMessage;
  58. import org.aspectj.bridge.IMessageHandler;
  59. import org.aspectj.bridge.IProgressListener;
  60. import org.aspectj.bridge.ISourceLocation;
  61. import org.aspectj.bridge.Message;
  62. import org.aspectj.bridge.MessageUtil;
  63. import org.aspectj.bridge.SourceLocation;
  64. import org.aspectj.bridge.Version;
  65. import org.aspectj.bridge.context.CompilationAndWeavingContext;
  66. import org.aspectj.bridge.context.ContextFormatter;
  67. import org.aspectj.bridge.context.ContextToken;
  68. import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
  69. import org.aspectj.org.eclipse.jdt.core.compiler.IProblem;
  70. import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
  71. import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
  72. import org.aspectj.org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
  73. import org.aspectj.org.eclipse.jdt.internal.compiler.ICompilerRequestor;
  74. import org.aspectj.org.eclipse.jdt.internal.compiler.IProblemFactory;
  75. import org.aspectj.org.eclipse.jdt.internal.compiler.batch.ClasspathLocation;
  76. import org.aspectj.org.eclipse.jdt.internal.compiler.batch.CompilationUnit;
  77. import org.aspectj.org.eclipse.jdt.internal.compiler.batch.FileSystem;
  78. import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
  79. import org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
  80. import org.aspectj.org.eclipse.jdt.internal.compiler.env.IModule;
  81. import org.aspectj.org.eclipse.jdt.internal.compiler.env.INameEnvironment;
  82. import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
  83. import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
  84. import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
  85. import org.aspectj.org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
  86. import org.aspectj.tools.ajc.Main;
  87. import org.aspectj.util.FileUtil;
  88. import org.aspectj.weaver.CustomMungerFactory;
  89. import org.aspectj.weaver.Dump;
  90. import org.aspectj.weaver.ResolvedType;
  91. import org.aspectj.weaver.World;
  92. import org.aspectj.weaver.bcel.BcelWeaver;
  93. import org.aspectj.weaver.bcel.BcelWorld;
  94. import org.aspectj.weaver.bcel.UnwovenClassFile;
  95. import org.eclipse.core.runtime.OperationCanceledException;
  96. public class AjBuildManager implements IOutputClassFileNameProvider, IBinarySourceProvider, ICompilerAdapterFactory {
  97. private static final String CROSSREFS_FILE_NAME = "build.lst";
  98. private static final String CANT_WRITE_RESULT = "unable to write compilation result";
  99. private static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
  100. public static boolean COPY_INPATH_DIR_RESOURCES = false;
  101. // AJDT doesn't want this check, so Main enables it.
  102. private static boolean DO_RUNTIME_VERSION_CHECK = false;
  103. // If runtime version check fails, warn or fail? (unset?)
  104. static final boolean FAIL_IF_RUNTIME_NOT_FOUND = false;
  105. private static final FileFilter binarySourceFilter = new FileFilter() {
  106. @Override
  107. public boolean accept(File f) {
  108. return f.getName().endsWith(".class");
  109. }
  110. };
  111. /**
  112. * This builder is static so that it can be subclassed and reset. However, note that there is only one builder present, so if
  113. * two extendsion reset it, only the latter will get used.
  114. */
  115. public static AsmHierarchyBuilder asmHierarchyBuilder = new AsmHierarchyBuilder();
  116. static {
  117. // CompilationAndWeavingContext.setMultiThreaded(false);
  118. CompilationAndWeavingContext.registerFormatter(CompilationAndWeavingContext.BATCH_BUILD, new AjBuildContexFormatter());
  119. CompilationAndWeavingContext
  120. .registerFormatter(CompilationAndWeavingContext.INCREMENTAL_BUILD, new AjBuildContexFormatter());
  121. }
  122. private IProgressListener progressListener = null;
  123. private boolean environmentSupportsIncrementalCompilation = false;
  124. private int compiledCount;
  125. private int sourceFileCount;
  126. private JarOutputStream zos;
  127. private boolean batchCompile = true;
  128. private INameEnvironment environment;
  129. private Map<String, List<UnwovenClassFile>> /* String -> List<UCF> */binarySourcesForTheNextCompile = new HashMap<>();
  130. // FIXME asc should this really be in here?
  131. // private AsmManager structureModel;
  132. public AjBuildConfig buildConfig;
  133. private boolean ignoreOutxml;
  134. private boolean wasFullBuild = true; // true if last build was a full build rather than an incremental build
  135. AjState state = new AjState(this);
  136. /**
  137. * Enable check for runtime version, used only by Ant/command-line Main.
  138. *
  139. * @param caller Main unused except to limit to non-null clients.
  140. */
  141. public static void enableRuntimeVersionCheck(Main caller) {
  142. DO_RUNTIME_VERSION_CHECK = null != caller;
  143. }
  144. public BcelWeaver getWeaver() {
  145. return state.getWeaver();
  146. }
  147. public BcelWorld getBcelWorld() {
  148. return state.getBcelWorld();
  149. }
  150. public CountingMessageHandler handler;
  151. private CustomMungerFactory customMungerFactory;
  152. public AjBuildManager(IMessageHandler holder) {
  153. super();
  154. this.handler = CountingMessageHandler.makeCountingMessageHandler(holder);
  155. }
  156. public void environmentSupportsIncrementalCompilation(boolean itDoes) {
  157. this.environmentSupportsIncrementalCompilation = itDoes;
  158. if (itDoes) {
  159. org.aspectj.weaver.loadtime.definition.DocumentParser.deactivateCaching();
  160. }
  161. }
  162. /** @return true if we should generate a model as a side-effect */
  163. public boolean doGenerateModel() {
  164. return buildConfig.isGenerateModelMode();
  165. }
  166. public boolean batchBuild(AjBuildConfig buildConfig, IMessageHandler baseHandler) throws IOException, AbortException {
  167. return performBuild(buildConfig, baseHandler, true);
  168. }
  169. public boolean incrementalBuild(AjBuildConfig buildConfig, IMessageHandler baseHandler) throws IOException, AbortException {
  170. return performBuild(buildConfig, baseHandler, false);
  171. }
  172. /**
  173. * Perform a build.
  174. *
  175. * @return true if the build was successful (ie. no errors)
  176. */
  177. private boolean performBuild(AjBuildConfig buildConfig, IMessageHandler baseHandler, boolean isFullBuild) throws IOException,
  178. AbortException {
  179. boolean ret = true;
  180. batchCompile = isFullBuild;
  181. wasFullBuild = isFullBuild;
  182. if (baseHandler instanceof ILifecycleAware) {
  183. ((ILifecycleAware) baseHandler).buildStarting(!isFullBuild);
  184. }
  185. CompilationAndWeavingContext.reset();
  186. final int phase = isFullBuild ? CompilationAndWeavingContext.BATCH_BUILD : CompilationAndWeavingContext.INCREMENTAL_BUILD;
  187. final ContextToken ct = CompilationAndWeavingContext.enteringPhase(phase, buildConfig);
  188. try {
  189. if (isFullBuild) {
  190. this.state = new AjState(this);
  191. }
  192. this.state.setCouldBeSubsequentIncrementalBuild(this.environmentSupportsIncrementalCompilation);
  193. final boolean canIncremental = state.prepareForNextBuild(buildConfig);
  194. if (!canIncremental && !isFullBuild) { // retry as batch?
  195. CompilationAndWeavingContext.leavingPhase(ct);
  196. if (state.listenerDefined()) {
  197. state.getListener().recordDecision("Falling back to batch compilation");
  198. }
  199. return performBuild(buildConfig, baseHandler, true);
  200. }
  201. this.handler = CountingMessageHandler.makeCountingMessageHandler(baseHandler);
  202. if (buildConfig == null || buildConfig.isCheckRuntimeVersion()) {
  203. if (DO_RUNTIME_VERSION_CHECK) {
  204. final String check = checkRtJar(buildConfig);
  205. if (check != null) {
  206. if (FAIL_IF_RUNTIME_NOT_FOUND) {
  207. MessageUtil.error(handler, check);
  208. CompilationAndWeavingContext.leavingPhase(ct);
  209. return false;
  210. } else {
  211. MessageUtil.warn(handler, check);
  212. }
  213. }
  214. }
  215. }
  216. // if (batch) {
  217. setBuildConfig(buildConfig);
  218. // }
  219. if (isFullBuild || !AsmManager.attemptIncrementalModelRepairs) {
  220. // if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {
  221. setupModel(buildConfig);
  222. // }
  223. }
  224. if (isFullBuild) {
  225. initBcelWorld(handler);
  226. }
  227. if (handler.hasErrors()) {
  228. CompilationAndWeavingContext.leavingPhase(ct);
  229. return false;
  230. }
  231. if (buildConfig.getOutputJar() != null) {
  232. if (!openOutputStream(buildConfig.getOutputJar())) {
  233. CompilationAndWeavingContext.leavingPhase(ct);
  234. return false;
  235. }
  236. }
  237. if (isFullBuild) {
  238. // System.err.println("XXXX batch: " + buildConfig.getFiles());
  239. if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {
  240. AsmManager.setLastActiveStructureModel(state.getStructureModel());
  241. getWorld().setModel(state.getStructureModel());
  242. // in incremental build, only get updated model?
  243. }
  244. binarySourcesForTheNextCompile = state.getBinaryFilesToCompile(true);
  245. performCompilation(buildConfig.getFiles());
  246. state.clearBinarySourceFiles(); // we don't want these hanging around...
  247. if (!proceedOnError() && handler.hasErrors()) {
  248. CompilationAndWeavingContext.leavingPhase(ct);
  249. if (AsmManager.isReporting()) {
  250. state.getStructureModel().reportModelInfo("After a batch build");
  251. }
  252. return false;
  253. }
  254. if (AsmManager.isReporting()) {
  255. state.getStructureModel().reportModelInfo("After a batch build");
  256. }
  257. } else {
  258. // done already?
  259. // if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {
  260. // bcelWorld.setModel(StructureModelManager.INSTANCE.getStructureModel());
  261. // }
  262. // System.err.println("XXXX start inc ");
  263. AsmManager.setLastActiveStructureModel(state.getStructureModel());
  264. binarySourcesForTheNextCompile = state.getBinaryFilesToCompile(true);
  265. Set<File> files = state.getFilesToCompile(true);
  266. if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {
  267. if (AsmManager.attemptIncrementalModelRepairs) {
  268. state.getStructureModel().resetDeltaProcessing();
  269. state.getStructureModel().processDelta(files, state.getAddedFiles(), state.getDeletedFiles());
  270. }
  271. }
  272. boolean hereWeGoAgain = !(files.isEmpty() && binarySourcesForTheNextCompile.isEmpty());
  273. for (int i = 0; (i < 5) && hereWeGoAgain; i++) {
  274. if (state.listenerDefined()) {
  275. state.getListener()
  276. .recordInformation("Starting incremental compilation loop " + (i + 1) + " of possibly 5");
  277. // System.err.println("XXXX inc: " + files);
  278. }
  279. performCompilation(files);
  280. if ((!proceedOnError() && handler.hasErrors())
  281. || (progressListener != null && progressListener.isCancelledRequested())) {
  282. CompilationAndWeavingContext.leavingPhase(ct);
  283. return false;
  284. }
  285. if (state.requiresFullBatchBuild()) {
  286. if (state.listenerDefined()) {
  287. state.getListener().recordInformation(" Dropping back to full build");
  288. }
  289. return batchBuild(buildConfig, baseHandler);
  290. }
  291. binarySourcesForTheNextCompile = state.getBinaryFilesToCompile(false);
  292. files = state.getFilesToCompile(false);
  293. hereWeGoAgain = !(files.isEmpty() && binarySourcesForTheNextCompile.isEmpty());
  294. // TODO Andy - Needs some thought here...
  295. // I think here we might want to pass empty addedFiles/deletedFiles as they were
  296. // dealt with on the first call to processDelta - we are going through this loop
  297. // again because in compiling something we found something else we needed to
  298. // rebuild. But what case causes this?
  299. if (hereWeGoAgain) {
  300. if (buildConfig.isEmacsSymMode() || buildConfig.isGenerateModelMode()) {
  301. if (AsmManager.attemptIncrementalModelRepairs) {
  302. state.getStructureModel().processDelta(files, state.getAddedFiles(), state.getDeletedFiles());
  303. }
  304. }
  305. }
  306. }
  307. if (!files.isEmpty()) {
  308. CompilationAndWeavingContext.leavingPhase(ct);
  309. return batchBuild(buildConfig, baseHandler);
  310. } else {
  311. if (AsmManager.isReporting()) {
  312. state.getStructureModel().reportModelInfo("After an incremental build");
  313. }
  314. }
  315. }
  316. // XXX not in Mik's incremental
  317. if (buildConfig.isEmacsSymMode()) {
  318. new org.aspectj.ajdt.internal.core.builder.EmacsStructureModelManager().externalizeModel(state.getStructureModel());
  319. }
  320. // for bug 113554: support ajsym file generation for command line builds
  321. if (buildConfig.isGenerateCrossRefsMode()) {
  322. final File configFileProxy = new File(buildConfig.getOutputDir(), CROSSREFS_FILE_NAME);
  323. state.getStructureModel().writeStructureModel(configFileProxy.getAbsolutePath());
  324. }
  325. // have to tell state we succeeded or next is not incremental
  326. state.successfulCompile(buildConfig, isFullBuild);
  327. // For a full compile, copy resources to the destination
  328. // - they should not get deleted on incremental and AJDT
  329. // will handle changes to them that require a recopying
  330. if (isFullBuild) {
  331. copyResourcesToDestination();
  332. }
  333. if (buildConfig.getOutxmlName() != null) {
  334. writeOutxmlFile();
  335. }
  336. /* boolean weaved = */// weaveAndGenerateClassFiles();
  337. // if not weaved, then no-op build, no model changes
  338. // but always returns true
  339. // XXX weaved not in Mik's incremental
  340. if (buildConfig.isGenerateModelMode()) {
  341. state.getStructureModel().fireModelUpdated();
  342. }
  343. CompilationAndWeavingContext.leavingPhase(ct);
  344. } finally {
  345. if (baseHandler instanceof ILifecycleAware) {
  346. ((ILifecycleAware) baseHandler).buildFinished(!isFullBuild);
  347. }
  348. if (zos != null) {
  349. closeOutputStream(buildConfig.getOutputJar());
  350. }
  351. ret = !handler.hasErrors();
  352. if (getBcelWorld() != null) {
  353. final BcelWorld bcelWorld = getBcelWorld();
  354. bcelWorld.reportTimers();
  355. bcelWorld.tidyUp();
  356. }
  357. if (getWeaver() != null) {
  358. getWeaver().tidyUp();
  359. // bug 59895, don't release reference to handler as may be needed by a nested call
  360. // handler = null;
  361. }
  362. }
  363. return ret;
  364. }
  365. /**
  366. * Open an output jar file in which to write the compiler output.
  367. *
  368. * @param outJar the jar file to open
  369. * @return true if successful
  370. */
  371. private boolean openOutputStream(File outJar) {
  372. try {
  373. OutputStream os = FileUtil.makeOutputStream(buildConfig.getOutputJar());
  374. zos = new JarOutputStream(os, getWeaver().getManifest(true));
  375. } catch (IOException ex) {
  376. IMessage message = new Message("Unable to open outjar " + outJar.getPath() + "(" + ex.getMessage() + ")",
  377. new SourceLocation(outJar, 0), true);
  378. handler.handleMessage(message);
  379. return false;
  380. }
  381. return true;
  382. }
  383. private void closeOutputStream(File outJar) {
  384. try {
  385. if (zos != null) {
  386. zos.close();
  387. if (buildConfig.getCompilationResultDestinationManager() != null) {
  388. buildConfig.getCompilationResultDestinationManager().reportFileWrite(outJar.getPath(),
  389. CompilationResultDestinationManager.FILETYPE_OUTJAR);
  390. }
  391. }
  392. zos = null;
  393. /* Ensure we don't write an incomplete JAR bug-71339 */
  394. if (handler.hasErrors()) {
  395. outJar.delete();
  396. if (buildConfig.getCompilationResultDestinationManager() != null) {
  397. buildConfig.getCompilationResultDestinationManager().reportFileRemove(outJar.getPath(),
  398. CompilationResultDestinationManager.FILETYPE_OUTJAR);
  399. }
  400. }
  401. } catch (IOException ex) {
  402. IMessage message = new Message("Unable to write outjar " + outJar.getPath() + "(" + ex.getMessage() + ")",
  403. new SourceLocation(outJar, 0), true);
  404. handler.handleMessage(message);
  405. }
  406. }
  407. private void copyResourcesToDestination() throws IOException {
  408. // resources that we need to copy are contained in the injars and inpath only
  409. for (File inJar : buildConfig.getInJars()) {
  410. copyResourcesFromJarFile(inJar);
  411. }
  412. for (File inPathElement : buildConfig.getInpath()) {
  413. if (inPathElement.isDirectory()) {
  414. copyResourcesFromDirectory(inPathElement);
  415. }
  416. else {
  417. copyResourcesFromJarFile(inPathElement);
  418. }
  419. }
  420. if (buildConfig.getSourcePathResources() != null) {
  421. for (String resource : buildConfig.getSourcePathResources().keySet()) {
  422. File from = buildConfig.getSourcePathResources().get(resource);
  423. copyResourcesFromFile(from, resource, from);
  424. }
  425. }
  426. writeManifest();
  427. }
  428. private void copyResourcesFromJarFile(File jarFile) throws IOException {
  429. try (JarInputStream inStream = new JarInputStream(new FileInputStream(jarFile))) {
  430. while (true) {
  431. ZipEntry entry = inStream.getNextEntry();
  432. if (entry == null) {
  433. break;
  434. }
  435. String filename = entry.getName();
  436. // System.out.println("? copyResourcesFromJarFile() filename='" + filename +"'");
  437. if (entry.isDirectory()) {
  438. writeDirectory(filename, jarFile);
  439. } else if (acceptResource(filename, false)) {
  440. byte[] bytes = FileUtil.readAsByteArray(inStream);
  441. writeResource(filename, bytes, jarFile);
  442. }
  443. inStream.closeEntry();
  444. }
  445. }
  446. }
  447. private void copyResourcesFromDirectory(File dir) throws IOException {
  448. if (!COPY_INPATH_DIR_RESOURCES) {
  449. return;
  450. }
  451. // Get a list of all files (i.e. everything that isnt a directory)
  452. File[] files = FileUtil.listFiles(dir, new FileFilter() {
  453. @Override
  454. public boolean accept(File f) {
  455. boolean accept = !(f.isDirectory() || f.getName().endsWith(".class"));
  456. return accept;
  457. }
  458. });
  459. // For each file, add it either as a real .class file or as a resource
  460. for (File file : files) {
  461. // ASSERT: files[i].getAbsolutePath().startsWith(inFile.getAbsolutePath()
  462. // or we are in trouble...
  463. String filename = file.getAbsolutePath().substring(dir.getAbsolutePath().length() + 1);
  464. copyResourcesFromFile(file, filename, dir);
  465. }
  466. }
  467. private void copyResourcesFromFile(File f, String filename, File src) throws IOException {
  468. if (!acceptResource(filename, true)) {
  469. return;
  470. }
  471. FileInputStream fis = null;
  472. try {
  473. fis = new FileInputStream(f);
  474. byte[] bytes = FileUtil.readAsByteArray(fis);
  475. // String relativePath = files[i].getPath();
  476. writeResource(filename, bytes, src);
  477. } catch (FileNotFoundException fnfe) {
  478. // pr359332: looks like the file moved (refactoring?) just as this copy was starting
  479. // that is OK
  480. } finally {
  481. if (fis != null) {
  482. fis.close();
  483. }
  484. }
  485. }
  486. /**
  487. * Add a directory entry to the output zip file. Don't do anything if not writing out to a zip file. A directory entry is one
  488. * whose filename ends with '/'
  489. *
  490. * @param directory the directory path
  491. * @param srcloc the src of the directory entry, for use when creating a warning message
  492. * @throws IOException if something goes wrong creating the new zip entry
  493. */
  494. private void writeDirectory(String directory, File srcloc) throws IOException {
  495. if (state.hasResource(directory)) {
  496. IMessage msg = new Message("duplicate resource: '" + directory + "'", IMessage.WARNING, null, new SourceLocation(
  497. srcloc, 0));
  498. handler.handleMessage(msg);
  499. return;
  500. }
  501. if (zos != null) {
  502. ZipEntry newEntry = new ZipEntry(directory);
  503. zos.putNextEntry(newEntry);
  504. zos.closeEntry();
  505. state.recordResource(directory, srcloc);
  506. }
  507. // Nothing to do if not writing to a zip file
  508. }
  509. private void writeResource(String filename, byte[] content, File srcLocation) throws IOException {
  510. if (state.hasResource(filename)) {
  511. IMessage msg = new Message("duplicate resource: '" + filename + "'", IMessage.WARNING, null, new SourceLocation(
  512. srcLocation, 0));
  513. handler.handleMessage(msg);
  514. return;
  515. }
  516. if (filename.equals(buildConfig.getOutxmlName())) {
  517. ignoreOutxml = true;
  518. IMessage msg = new Message("-outxml/-outxmlfile option ignored because resource already exists: '" + filename + "'",
  519. IMessage.WARNING, null, new SourceLocation(srcLocation, 0));
  520. handler.handleMessage(msg);
  521. }
  522. if (zos != null) {
  523. ZipEntry newEntry = new ZipEntry(filename); // ??? get compression scheme right
  524. zos.putNextEntry(newEntry);
  525. zos.write(content);
  526. zos.closeEntry();
  527. } else {
  528. File destDir = buildConfig.getOutputDir();
  529. if (buildConfig.getCompilationResultDestinationManager() != null) {
  530. destDir = buildConfig.getCompilationResultDestinationManager().getOutputLocationForResource(srcLocation);
  531. }
  532. try {
  533. File outputLocation = new File(destDir, filename);
  534. OutputStream fos = FileUtil.makeOutputStream(outputLocation);
  535. fos.write(content);
  536. fos.close();
  537. if (buildConfig.getCompilationResultDestinationManager() != null) {
  538. buildConfig.getCompilationResultDestinationManager().reportFileWrite(outputLocation.getPath(),
  539. CompilationResultDestinationManager.FILETYPE_RESOURCE);
  540. }
  541. } catch (FileNotFoundException fnfe) {
  542. IMessage msg = new Message("unable to copy resource to output folder: '" + filename + "' - reason: "
  543. + fnfe.getMessage(), IMessage.ERROR, null, new SourceLocation(srcLocation, 0));
  544. handler.handleMessage(msg);
  545. }
  546. }
  547. state.recordResource(filename, srcLocation);
  548. }
  549. /*
  550. * If we are writing to an output directory copy the manifest but only if we already have one
  551. */
  552. private void writeManifest() throws IOException {
  553. Manifest manifest = getWeaver().getManifest(false);
  554. if (manifest != null && zos == null) {
  555. File outputDir = buildConfig.getOutputDir();
  556. if (buildConfig.getCompilationResultDestinationManager() != null) {
  557. // Manifests are only written if we have a jar on the inpath. Therefore,
  558. // we write the manifest to the defaultOutputLocation because this is
  559. // where we sent the classes that were on the inpath
  560. outputDir = buildConfig.getCompilationResultDestinationManager().getDefaultOutputLocation();
  561. }
  562. if (outputDir == null) {
  563. return;
  564. }
  565. File outputLocation = new File(outputDir, MANIFEST_NAME);
  566. OutputStream fos = FileUtil.makeOutputStream(outputLocation);
  567. manifest.write(fos);
  568. fos.close();
  569. if (buildConfig.getCompilationResultDestinationManager() != null) {
  570. buildConfig.getCompilationResultDestinationManager().reportFileWrite(outputLocation.getPath(),
  571. CompilationResultDestinationManager.FILETYPE_RESOURCE);
  572. }
  573. }
  574. }
  575. private boolean acceptResource(String resourceName, boolean fromFile) {
  576. if ((resourceName.startsWith("CVS/")) || (resourceName.contains("/CVS/")) || (resourceName.endsWith("/CVS"))
  577. || (resourceName.endsWith(".class")) || (resourceName.startsWith(".svn/"))
  578. || (resourceName.contains("/.svn/")) || (resourceName.endsWith("/.svn")) ||
  579. // Do not copy manifests if either they are coming from a jar or we are writing to a jar
  580. (resourceName.toUpperCase().equals(MANIFEST_NAME) && (!fromFile || zos != null))) {
  581. return false;
  582. } else {
  583. return true;
  584. }
  585. }
  586. private void writeOutxmlFile() throws IOException {
  587. if (ignoreOutxml) {
  588. return;
  589. }
  590. String filename = buildConfig.getOutxmlName();
  591. // System.err.println("? AjBuildManager.writeOutxmlFile() outxml=" + filename);
  592. Map<File, List<String>> outputDirsAndAspects = findOutputDirsForAspects();
  593. Set<Map.Entry<File, List<String>>> outputDirs = outputDirsAndAspects.entrySet();
  594. for (Map.Entry<File, List<String>> entry : outputDirs) {
  595. File outputDir = entry.getKey();
  596. List<String> aspects = entry.getValue();
  597. ByteArrayOutputStream baos = getOutxmlContents(aspects);
  598. if (zos != null) {
  599. ZipEntry newEntry = new ZipEntry(filename);
  600. zos.putNextEntry(newEntry);
  601. zos.write(baos.toByteArray());
  602. zos.closeEntry();
  603. }
  604. else {
  605. File outputFile = new File(outputDir, filename);
  606. OutputStream fos = FileUtil.makeOutputStream(outputFile);
  607. fos.write(baos.toByteArray());
  608. fos.close();
  609. if (buildConfig.getCompilationResultDestinationManager() != null) {
  610. buildConfig.getCompilationResultDestinationManager().reportFileWrite(outputFile.getPath(),
  611. CompilationResultDestinationManager.FILETYPE_RESOURCE);
  612. }
  613. }
  614. }
  615. }
  616. private ByteArrayOutputStream getOutxmlContents(List aspectNames) {
  617. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  618. PrintStream ps = new PrintStream(baos);
  619. ps.println("<aspectj>");
  620. ps.println("<aspects>");
  621. if (aspectNames != null) {
  622. for (Object aspectName : aspectNames) {
  623. String name = (String) aspectName;
  624. ps.println("<aspect name=\"" + name + "\"/>");
  625. }
  626. }
  627. ps.println("</aspects>");
  628. ps.println("</aspectj>");
  629. ps.println();
  630. ps.close();
  631. return baos;
  632. }
  633. /**
  634. * Returns a map where the keys are File objects corresponding to all the output directories and the values are a list of
  635. * aspects which are sent to that ouptut directory
  636. */
  637. private Map<File, List<String>> findOutputDirsForAspects() {
  638. Map<File, List<String>> outputDirsToAspects = new HashMap<>();
  639. Map<String, char[]> aspectNamesToFileNames = state.getAspectNamesToFileNameMap();
  640. if (buildConfig.getCompilationResultDestinationManager() == null
  641. || buildConfig.getCompilationResultDestinationManager().getAllOutputLocations().size() == 1) {
  642. // we only have one output directory...which simplifies things
  643. File outputDir = buildConfig.getOutputDir();
  644. if (buildConfig.getCompilationResultDestinationManager() != null) {
  645. outputDir = buildConfig.getCompilationResultDestinationManager().getDefaultOutputLocation();
  646. }
  647. List<String> aspectNames = new ArrayList<>();
  648. if (aspectNamesToFileNames != null) {
  649. Set<String> keys = aspectNamesToFileNames.keySet();
  650. for (String name : keys) {
  651. aspectNames.add(name);
  652. }
  653. }
  654. outputDirsToAspects.put(outputDir, aspectNames);
  655. } else {
  656. List outputDirs = buildConfig.getCompilationResultDestinationManager().getAllOutputLocations();
  657. for (Object dir : outputDirs) {
  658. File outputDir = (File) dir;
  659. outputDirsToAspects.put(outputDir, new ArrayList<>());
  660. }
  661. if (aspectNamesToFileNames != null) {
  662. Set<Map.Entry<String, char[]>> entrySet = aspectNamesToFileNames.entrySet();
  663. for (Map.Entry<String, char[]> entry : entrySet) {
  664. String aspectName = entry.getKey();
  665. char[] fileName = entry.getValue();
  666. File outputDir = buildConfig.getCompilationResultDestinationManager().getOutputLocationForClass(
  667. new File(new String(fileName)));
  668. if (!outputDirsToAspects.containsKey(outputDir)) {
  669. outputDirsToAspects.put(outputDir, new ArrayList<>());
  670. }
  671. ((List) outputDirsToAspects.get(outputDir)).add(aspectName);
  672. }
  673. }
  674. }
  675. return outputDirsToAspects;
  676. }
  677. // public static void dumprels() {
  678. // IRelationshipMap irm = AsmManager.getDefault().getRelationshipMap();
  679. // int ctr = 1;
  680. // Set entries = irm.getEntries();
  681. // for (Iterator iter = entries.iterator(); iter.hasNext();) {
  682. // String hid = (String) iter.next();
  683. // List rels = irm.get(hid);
  684. // for (Iterator iterator = rels.iterator(); iterator.hasNext();) {
  685. // IRelationship ir = (IRelationship) iterator.next();
  686. // List targets = ir.getTargets();
  687. // for (Iterator iterator2 = targets.iterator();
  688. // iterator2.hasNext();
  689. // ) {
  690. // String thid = (String) iterator2.next();
  691. // System.err.println("Hid:"+(ctr++)+":(targets="+targets.size()+") "+hid+" ("+ir.getName()+") "+thid);
  692. // }
  693. // }
  694. // }
  695. // }
  696. /**
  697. * Responsible for managing the ASM model between builds. Contains the policy for maintaining the persistance of elements in the
  698. * model.
  699. *
  700. * This code is driven before each 'fresh' (batch) build to create a new model.
  701. */
  702. private void setupModel(AjBuildConfig config) {
  703. if (!(config.isEmacsSymMode() || config.isGenerateModelMode())) {
  704. return;
  705. }
  706. // AsmManager.setCreatingModel(config.isEmacsSymMode() || config.isGenerateModelMode());
  707. // if (!AsmManager.isCreatingModel())
  708. // return;
  709. CompilationResultDestinationManager crdm = config.getCompilationResultDestinationManager();
  710. AsmManager structureModel = AsmManager.createNewStructureModel(crdm == null ? Collections.EMPTY_MAP : crdm.getInpathMap());
  711. // AsmManager.getDefault().getRelationshipMap().clear();
  712. IHierarchy model = structureModel.getHierarchy();
  713. String rootLabel = "<root>";
  714. IProgramElement.Kind kind = IProgramElement.Kind.FILE_JAVA;
  715. if (buildConfig.getConfigFile() != null) {
  716. rootLabel = buildConfig.getConfigFile().getName();
  717. model.setConfigFile(buildConfig.getConfigFile().getAbsolutePath());
  718. kind = IProgramElement.Kind.FILE_LST;
  719. }
  720. model.setRoot(new ProgramElement(structureModel, rootLabel, kind, new ArrayList()));
  721. model.setFileMap(new HashMap<>());
  722. // setStructureModel(model);
  723. state.setStructureModel(structureModel);
  724. // state.setRelationshipMap(AsmManager.getDefault().getRelationshipMap());
  725. }
  726. //
  727. // private void dumplist(List l) {
  728. // System.err.println("---- "+l.size());
  729. // for (int i =0 ;i<l.size();i++) System.err.println(i+"\t "+l.get(i));
  730. // }
  731. // private void accumulateFileNodes(IProgramElement ipe,List store) {
  732. // if (ipe.getKind()==IProgramElement.Kind.FILE_JAVA ||
  733. // ipe.getKind()==IProgramElement.Kind.FILE_ASPECTJ) {
  734. // if (!ipe.getName().equals("<root>")) {
  735. // store.add(ipe);
  736. // return;
  737. // }
  738. // }
  739. // for (Iterator i = ipe.getChildren().iterator();i.hasNext();) {
  740. // accumulateFileNodes((IProgramElement)i.next(),store);
  741. // }
  742. // }
  743. // LTODO delegate to BcelWeaver?
  744. // XXX hideous, should not be Object
  745. public void setCustomMungerFactory(Object o) {
  746. customMungerFactory = (CustomMungerFactory) o;
  747. }
  748. public Object getCustomMungerFactory() {
  749. return customMungerFactory;
  750. }
  751. /** init only on initial batch compile? no file-specific options */
  752. private void initBcelWorld(IMessageHandler handler) throws IOException {
  753. List cp = buildConfig.getFullClasspath(); // pr145693
  754. // buildConfig.getBootclasspath();
  755. // cp.addAll(buildConfig.getClasspath());
  756. BcelWorld bcelWorld = new BcelWorld(cp, handler, null);
  757. bcelWorld.setBehaveInJava5Way(buildConfig.getBehaveInJava5Way());
  758. bcelWorld.setTiming(buildConfig.isTiming(), false);
  759. bcelWorld.setAddSerialVerUID(buildConfig.isAddSerialVerUID());
  760. bcelWorld.setXmlConfigured(buildConfig.isXmlConfigured());
  761. bcelWorld.setXmlFiles(buildConfig.getXmlFiles());
  762. bcelWorld.performExtraConfiguration(buildConfig.getXconfigurationInfo());
  763. bcelWorld.setTargetAspectjRuntimeLevel(buildConfig.getTargetAspectjRuntimeLevel());
  764. bcelWorld.setOptionalJoinpoints(buildConfig.getXJoinpoints());
  765. bcelWorld.setXnoInline(buildConfig.isXnoInline());
  766. bcelWorld.setXlazyTjp(buildConfig.isXlazyTjp());
  767. bcelWorld.setXHasMemberSupportEnabled(buildConfig.isXHasMemberEnabled());
  768. bcelWorld.setPinpointMode(buildConfig.isXdevPinpoint());
  769. bcelWorld.setErrorAndWarningThreshold(buildConfig.getOptions().errorThreshold.isSet(24), buildConfig.getOptions().warningThreshold.isSet(24));
  770. BcelWeaver bcelWeaver = new BcelWeaver(bcelWorld);
  771. bcelWeaver.setCustomMungerFactory(customMungerFactory);
  772. state.setWorld(bcelWorld);
  773. state.setWeaver(bcelWeaver);
  774. state.clearBinarySourceFiles();
  775. if (buildConfig.getLintMode().equals(AjBuildConfig.AJLINT_DEFAULT)) {
  776. bcelWorld.getLint().loadDefaultProperties();
  777. } else {
  778. bcelWorld.getLint().setAll(buildConfig.getLintMode());
  779. }
  780. if (buildConfig.getLintOptionsMap() != null) {
  781. bcelWorld.getLint().setFromMap(buildConfig.getLintOptionsMap());
  782. }
  783. if (buildConfig.getLintSpecFile() != null) {
  784. bcelWorld.getLint().setFromProperties(buildConfig.getLintSpecFile());
  785. }
  786. for (File f: buildConfig.getAspectpath()) {
  787. if (!f.exists()) {
  788. IMessage message = new Message("invalid aspectpath entry: " + f.getName(), null, true);
  789. handler.handleMessage(message);
  790. } else {
  791. bcelWeaver.addLibraryJarFile(f);
  792. }
  793. }
  794. // String lintMode = buildConfig.getLintMode();
  795. File outputDir = buildConfig.getOutputDir();
  796. if (outputDir == null && buildConfig.getCompilationResultDestinationManager() != null) {
  797. // send all output from injars and inpath to the default output location
  798. // (will also later send the manifest there too)
  799. outputDir = buildConfig.getCompilationResultDestinationManager().getDefaultOutputLocation();
  800. }
  801. // ??? incremental issues
  802. for (File inJar : buildConfig.getInJars()) {
  803. List<UnwovenClassFile> unwovenClasses = bcelWeaver.addJarFile(inJar, outputDir, false);
  804. state.recordBinarySource(inJar.getPath(), unwovenClasses);
  805. }
  806. for (File inPathElement : buildConfig.getInpath()) {
  807. if (!inPathElement.isDirectory()) {
  808. // its a jar file on the inpath
  809. // the weaver method can actually handle dirs, but we don't call it, see next block
  810. List<UnwovenClassFile> unwovenClasses = bcelWeaver.addJarFile(inPathElement, outputDir, true);
  811. state.recordBinarySource(inPathElement.getPath(), unwovenClasses);
  812. } else {
  813. // add each class file in an in-dir individually, this gives us the best error reporting
  814. // (they are like 'source' files then), and enables a cleaner incremental treatment of
  815. // class file changes in indirs.
  816. File[] binSrcs = FileUtil.listFiles(inPathElement, binarySourceFilter);
  817. for (File binSrc : binSrcs) {
  818. UnwovenClassFile ucf = bcelWeaver.addClassFile(binSrc, inPathElement, outputDir);
  819. List<UnwovenClassFile> ucfl = new ArrayList<>();
  820. ucfl.add(ucf);
  821. state.recordBinarySource(binSrc.getPath(), ucfl);
  822. }
  823. }
  824. }
  825. bcelWeaver.setReweavableMode(buildConfig.isXNotReweavable());
  826. // check for org.aspectj.runtime.JoinPoint
  827. ResolvedType joinPoint = bcelWorld.resolve("org.aspectj.lang.JoinPoint");
  828. if (joinPoint.isMissing()) {
  829. IMessage message = new Message(
  830. "classpath error: unable to find org.aspectj.lang.JoinPoint (check that aspectjrt.jar is in your classpath)",
  831. null, true);
  832. handler.handleMessage(message);
  833. }
  834. }
  835. public World getWorld() {
  836. return getBcelWorld();
  837. }
  838. // void addAspectClassFilesToWeaver(List addedClassFiles) throws IOException {
  839. // for (Iterator i = addedClassFiles.iterator(); i.hasNext();) {
  840. // UnwovenClassFile classFile = (UnwovenClassFile) i.next();
  841. // getWeaver().addClassFile(classFile);
  842. // }
  843. // }
  844. public FileSystem getLibraryAccess(String[] classpaths, String[] filenames) {
  845. String defaultEncoding = buildConfig.getOptions().defaultEncoding;
  846. if ("".equals(defaultEncoding)) {//$NON-NLS-1$
  847. defaultEncoding = null;
  848. }
  849. // Bug 46671: We need an array as long as the number of elements in the classpath - *even though* not every
  850. // element of the classpath is likely to be a directory. If we ensure every element of the array is set to
  851. // only look for BINARY, then we make sure that for any classpath element that is a directory, we won't build
  852. // a classpathDirectory object that will attempt to look for source when it can't find binary.
  853. // int[] classpathModes = new int[classpaths.length];
  854. // for (int i =0 ;i<classpaths.length;i++) classpathModes[i]=ClasspathDirectory.BINARY;
  855. FileSystem nameEnvironment = null;
  856. // TODO J9 The compiler likes to work in terms of checked classpath objects - these will be different
  857. // depending on where the code came from (classpath, modulepath). If working with just the raw
  858. // 'classpaths' object it isn't recording where the code came from. This will be an issue later for
  859. // weaving, the distinction will need to be maintained for proper 'module aware/respecting' weaving.
  860. if (buildConfig.getCheckedClasspaths() == null) {
  861. nameEnvironment = new FileSystem(classpaths, filenames, defaultEncoding, ClasspathLocation.BINARY, null);
  862. } else {
  863. nameEnvironment = new FileSystem(buildConfig.getCheckedClasspaths(), filenames, false, null);
  864. }
  865. nameEnvironment.module = buildConfig.getModuleDesc();
  866. return nameEnvironment;
  867. }
  868. public IProblemFactory getProblemFactory() {
  869. return new DefaultProblemFactory(Locale.getDefault());
  870. }
  871. /*
  872. * Build the set of compilation source units
  873. */
  874. public CompilationUnit[] getCompilationUnits(String[] filenames) {
  875. int fileCount = filenames.length;
  876. CompilationUnit[] units = new CompilationUnit[fileCount];
  877. // HashtableOfObject knownFileNames = new HashtableOfObject(fileCount);
  878. String defaultEncoding = buildConfig.getOptions().defaultEncoding;
  879. if ("".equals(defaultEncoding)) {//$NON-NLS-1$
  880. defaultEncoding = null;
  881. }
  882. CompilationUnit moduleCU = null;
  883. // TODO building with multiple module-infos?
  884. int moduleIndex = -1;
  885. IModule moduleDesc = buildConfig.getModuleDesc();
  886. String moduleName = moduleDesc == null? null: new String(moduleDesc.name());
  887. for (int i=0;i<fileCount;i++) {
  888. if (filenames[i].endsWith("module-info.java")) {
  889. moduleIndex = i;
  890. moduleCU = new CompilationUnit(null, filenames[i], defaultEncoding, null, false, moduleName);
  891. }
  892. }
  893. for (int i = 0; i < fileCount; i++) {
  894. // units[i] = new CompilationUnit(null, filenames[i], defaultEncoding);
  895. if (i == moduleIndex) {
  896. units[i] = moduleCU;
  897. } else {
  898. units[i] = new CompilationUnit(null, filenames[i], defaultEncoding, null, false, moduleName);
  899. // With Java 10 changes the modulebinding is fetched from the rootenvironment
  900. // this.moduleBinding = rootEnvironment.getModule(this.module);
  901. // rather than using the moduleCU:
  902. // if (this.modCU != null)
  903. // return this.moduleBinding = this.modCU.module(rootEnvironment);
  904. // units[i].setModule(moduleCU);
  905. }
  906. // new CompilationUnit(null, fileName, encoding, this.destinationPaths[i],
  907. // shouldIgnoreOptionalProblems(this.ignoreOptionalProblemsFromFolders, fileName.toCharArray()),
  908. // this.modNames[i]);
  909. }
  910. return units;
  911. }
  912. public String extractDestinationPathFromSourceFile(CompilationResult result) {
  913. ICompilationUnit compilationUnit = result.compilationUnit;
  914. if (compilationUnit != null) {
  915. char[] fileName = compilationUnit.getFileName();
  916. int lastIndex = CharOperation.lastIndexOf(java.io.File.separatorChar, fileName);
  917. if (lastIndex == -1) {
  918. return System.getProperty("user.dir"); //$NON-NLS-1$
  919. }
  920. return new String(CharOperation.subarray(fileName, 0, lastIndex));
  921. }
  922. return System.getProperty("user.dir"); //$NON-NLS-1$
  923. }
  924. public void performCompilation(Collection<File> files) {
  925. if (progressListener != null) {
  926. compiledCount = 0;
  927. sourceFileCount = files.size();
  928. progressListener.setText("compiling source files");
  929. }
  930. // Translate from strings to File objects
  931. String[] filenames = new String[files.size()];
  932. int idx = 0;
  933. for (File f : files) {
  934. filenames[idx++] = f.getPath();
  935. }
  936. environment = state.getNameEnvironment();
  937. boolean environmentNeedsRebuilding = false;
  938. // Might be a bit too cautious, but let us see how it goes
  939. if (buildConfig.getChanged() != AjBuildConfig.NO_CHANGES) {
  940. environmentNeedsRebuilding = true;
  941. }
  942. if (environment == null || environmentNeedsRebuilding) {
  943. List<String> cps = buildConfig.getFullClasspath();
  944. Dump.saveFullClasspath(cps);
  945. String[] classpaths = new String[cps.size()];
  946. for (int i = 0; i < cps.size(); i++) {
  947. classpaths[i] = cps.get(i);
  948. }
  949. FileSystem fileSystem = getLibraryAccess(classpaths, filenames);
  950. environment = new StatefulNameEnvironment(fileSystem, state.getClassNameToFileMap(), state);
  951. state.setFileSystem(fileSystem);
  952. state.setNameEnvironment(environment);
  953. } else {
  954. ((StatefulNameEnvironment) environment).update(state.getClassNameToFileMap(), state.deltaAddedClasses);
  955. state.deltaAddedClasses.clear();
  956. }
  957. org.aspectj.ajdt.internal.compiler.CompilerAdapter.setCompilerAdapterFactory(this);
  958. final Map<String, String> settings = buildConfig.getOptions().getMap();
  959. final BuildArgParser bMain = buildConfig.getBuildArgParser();
  960. final org.aspectj.org.eclipse.jdt.internal.compiler.Compiler compiler = new org.aspectj.org.eclipse.jdt.internal.compiler.Compiler(
  961. environment, DefaultErrorHandlingPolicies.proceedWithAllProblems(), settings,
  962. getBatchRequestor(), getProblemFactory());
  963. bMain.compilerOptions = compiler.options;
  964. bMain.batchCompiler = compiler;
  965. bMain.initializeAnnotationProcessorManager();
  966. compiler.options.produceReferenceInfo = true; // TODO turn off when not needed
  967. if (bMain.compilerOptions.complianceLevel >= ClassFileConstants.JDK1_6
  968. && bMain.compilerOptions.processAnnotations) {
  969. // need this too?
  970. // if (bMain.checkVMVersion(ClassFileConstants.JDK1_6)) {
  971. // initializeAnnotationProcessorManager();
  972. // if (this.classNames != null) {
  973. // this.batchCompiler.setBinaryTypes(processClassNames(this.batchCompiler.lookupEnvironment));
  974. // }
  975. // } else {
  976. // // report a warning
  977. // this.logger.logIncorrectVMVersionForAnnotationProcessing();
  978. // }
  979. if (bMain.checkVMVersion(ClassFileConstants.JDK9)) {
  980. try {
  981. bMain.initRootModules(bMain.batchCompiler.lookupEnvironment, state.getFileSystem());
  982. } catch (IllegalArgumentException iae) {
  983. ISourceLocation location = null;
  984. if (buildConfig.getConfigFile() != null) {
  985. location = new SourceLocation(buildConfig.getConfigFile(), 0);
  986. }
  987. IMessage m = new Message(iae.getMessage(), IMessage.ERROR, null, location);
  988. handler.handleMessage(m);
  989. }
  990. }
  991. }
  992. try {
  993. compiler.compile(getCompilationUnits(filenames));
  994. } catch (OperationCanceledException oce) {
  995. handler.handleMessage(new Message("build cancelled:" + oce.getMessage(), IMessage.WARNING, null, null));
  996. }
  997. // cleanup
  998. org.aspectj.ajdt.internal.compiler.CompilerAdapter.setCompilerAdapterFactory(null);
  999. AnonymousClassPublisher.aspectOf().setAnonymousClassCreationListener(null);
  1000. environment.cleanup();
  1001. // environment = null;
  1002. }
  1003. public void cleanupEnvironment() {
  1004. if (environment != null) {
  1005. environment.cleanup();
  1006. environment = null;
  1007. // le = null;
  1008. }
  1009. }
  1010. /*
  1011. * Answer the component to which will be handed back compilation results from the compiler
  1012. */
  1013. public IIntermediateResultsRequestor getInterimResultRequestor() {
  1014. return new IIntermediateResultsRequestor() {
  1015. @Override
  1016. public void acceptResult(InterimCompilationResult result) {
  1017. if (progressListener != null) {
  1018. compiledCount++;
  1019. progressListener.setProgress((compiledCount / 2.0) / sourceFileCount);
  1020. progressListener.setText("compiled: " + result.fileName());
  1021. }
  1022. state.noteResult(result);
  1023. if (progressListener != null && progressListener.isCancelledRequested()) {
  1024. throw new AbortCompilation(true, new OperationCanceledException("Compilation cancelled as requested"));
  1025. }
  1026. }
  1027. };
  1028. }
  1029. public ICompilerRequestor getBatchRequestor() {
  1030. return new ICompilerRequestor() {
  1031. @Override
  1032. public void acceptResult(CompilationResult unitResult) {
  1033. // end of compile, must now write the results to the output destination
  1034. // this is either a jar file or a file in a directory
  1035. boolean hasErrors = unitResult.hasErrors();
  1036. if (!hasErrors || proceedOnError()) {
  1037. Collection<ClassFile> classFiles = unitResult.compiledTypes.values();
  1038. boolean shouldAddAspectName = (buildConfig.getOutxmlName() != null);
  1039. for (ClassFile classFile : classFiles) {
  1040. String filename = new String(classFile.fileName());
  1041. String classname = filename.replace('/', '.');
  1042. filename = filename.replace('/', File.separatorChar) + ".class";
  1043. try {
  1044. if (buildConfig.getOutputJar() == null) {
  1045. String outfile = writeDirectoryEntry(unitResult, classFile, filename);
  1046. getWorld().classWriteEvent(classFile.getCompoundName());
  1047. if (environmentSupportsIncrementalCompilation) {
  1048. if (!classname.endsWith("$ajcMightHaveAspect")) {
  1049. ResolvedType type = getBcelWorld().resolve(classname);
  1050. if (type.isAspect()) {
  1051. state.recordAspectClassFile(outfile);
  1052. }
  1053. }
  1054. }
  1055. }
  1056. else {
  1057. writeZipEntry(classFile, filename);
  1058. }
  1059. if (shouldAddAspectName && !classname.endsWith("$ajcMightHaveAspect")) {
  1060. addAspectName(classname, unitResult.getFileName());
  1061. }
  1062. } catch (IOException ex) {
  1063. IMessage message = EclipseAdapterUtils.makeErrorMessage(new String(unitResult.fileName),
  1064. CANT_WRITE_RESULT, ex);
  1065. handler.handleMessage(message);
  1066. }
  1067. }
  1068. state.noteNewResult(unitResult);
  1069. unitResult.compiledTypes.clear(); // free up references to AjClassFile instances
  1070. }
  1071. if (unitResult.hasProblems() || unitResult.hasTasks()) {
  1072. IProblem[] problems = unitResult.getAllProblems();
  1073. for (IProblem problem : problems) {
  1074. IMessage message = EclipseAdapterUtils.makeMessage(unitResult.compilationUnit, problem, getBcelWorld(),
  1075. progressListener);
  1076. handler.handleMessage(message);
  1077. }
  1078. }
  1079. }
  1080. private String writeDirectoryEntry(CompilationResult unitResult, ClassFile classFile, String filename)
  1081. throws IOException {
  1082. File destinationPath = buildConfig.getOutputDir();
  1083. if (buildConfig.getCompilationResultDestinationManager() != null) {
  1084. destinationPath = buildConfig.getCompilationResultDestinationManager().getOutputLocationForClass(
  1085. new File(new String(unitResult.fileName)));
  1086. }
  1087. String outFile;
  1088. if (destinationPath == null) {
  1089. outFile = new File(filename).getName();
  1090. outFile = new File(extractDestinationPathFromSourceFile(unitResult), outFile).getPath();
  1091. } else {
  1092. outFile = new File(destinationPath, filename).getPath();
  1093. }
  1094. try {
  1095. BufferedOutputStream os = FileUtil.makeOutputStream(new File(outFile));
  1096. os.write(classFile.getBytes());
  1097. os.close();
  1098. } catch (FileNotFoundException fnfe) {
  1099. IMessage msg = new Message("unable to write out class file: '" + filename + "' - reason: " + fnfe.getMessage(),
  1100. IMessage.ERROR, null, new SourceLocation(new File(outFile), 0));
  1101. handler.handleMessage(msg);
  1102. }
  1103. if (buildConfig.getCompilationResultDestinationManager() != null) {
  1104. buildConfig.getCompilationResultDestinationManager().reportFileWrite(outFile,
  1105. CompilationResultDestinationManager.FILETYPE_CLASS);
  1106. }
  1107. return outFile;
  1108. }
  1109. private void writeZipEntry(ClassFile classFile, String name) throws IOException {
  1110. name = name.replace(File.separatorChar, '/');
  1111. ZipEntry newEntry = new ZipEntry(name); // ??? get compression scheme right
  1112. zos.putNextEntry(newEntry);
  1113. zos.write(classFile.getBytes());
  1114. zos.closeEntry();
  1115. }
  1116. private void addAspectName(String name, char[] fileContainingAspect) {
  1117. BcelWorld world = getBcelWorld();
  1118. ResolvedType type = world.resolve(name);
  1119. // System.err.println("? writeAspectName() type=" + type);
  1120. if (type.isAspect()) {
  1121. if (state.getAspectNamesToFileNameMap() == null) {
  1122. state.initializeAspectNamesToFileNameMap();
  1123. }
  1124. if (!state.getAspectNamesToFileNameMap().containsKey(name)) {
  1125. state.getAspectNamesToFileNameMap().put(name, fileContainingAspect);
  1126. }
  1127. }
  1128. }
  1129. };
  1130. }
  1131. protected boolean proceedOnError() {
  1132. return buildConfig.getProceedOnError();
  1133. }
  1134. // public void noteClassFiles(AjCompiler.InterimResult result) {
  1135. // if (result == null) return;
  1136. // CompilationResult unitResult = result.result;
  1137. // String sourceFileName = result.fileName();
  1138. // if (!(unitResult.hasErrors() && !proceedOnError())) {
  1139. // List unwovenClassFiles = new ArrayList();
  1140. // Enumeration classFiles = unitResult.compiledTypes.elements();
  1141. // while (classFiles.hasMoreElements()) {
  1142. // ClassFile classFile = (ClassFile) classFiles.nextElement();
  1143. // String filename = new String(classFile.fileName());
  1144. // filename = filename.replace('/', File.separatorChar) + ".class";
  1145. //
  1146. // File destinationPath = buildConfig.getOutputDir();
  1147. // if (destinationPath == null) {
  1148. // filename = new File(filename).getName();
  1149. // filename = new File(extractDestinationPathFromSourceFile(unitResult), filename).getPath();
  1150. // } else {
  1151. // filename = new File(destinationPath, filename).getPath();
  1152. // }
  1153. //
  1154. // //System.out.println("classfile: " + filename);
  1155. // unwovenClassFiles.add(new UnwovenClassFile(filename, classFile.getBytes()));
  1156. // }
  1157. // state.noteClassesFromFile(unitResult, sourceFileName, unwovenClassFiles);
  1158. // // System.out.println("file: " + sourceFileName);
  1159. // // for (int i=0; i < unitResult.simpleNameReferences.length; i++) {
  1160. // // System.out.println("simple: " + new String(unitResult.simpleNameReferences[i]));
  1161. // // }
  1162. // // for (int i=0; i < unitResult.qualifiedReferences.length; i++) {
  1163. // // System.out.println("qualified: " +
  1164. // // new String(CharOperation.concatWith(unitResult.qualifiedReferences[i], '/')));
  1165. // // }
  1166. // } else {
  1167. // state.noteClassesFromFile(null, sourceFileName, Collections.EMPTY_LIST);
  1168. // }
  1169. // }
  1170. //
  1171. private void setBuildConfig(AjBuildConfig buildConfig) {
  1172. this.buildConfig = buildConfig;
  1173. if (!this.environmentSupportsIncrementalCompilation) {
  1174. this.environmentSupportsIncrementalCompilation = (buildConfig.isIncrementalMode() || buildConfig
  1175. .isIncrementalFileMode());
  1176. }
  1177. handler.reset();
  1178. }
  1179. String makeClasspathString(AjBuildConfig buildConfig) {
  1180. if (buildConfig == null || buildConfig.getFullClasspath() == null) {
  1181. return "";
  1182. }
  1183. StringBuilder buf = new StringBuilder();
  1184. boolean first = true;
  1185. for (String s : buildConfig.getFullClasspath()) {
  1186. if (first) {
  1187. first = false;
  1188. }
  1189. else {
  1190. buf.append(File.pathSeparator);
  1191. }
  1192. buf.append(s.toString());
  1193. }
  1194. return buf.toString();
  1195. }
  1196. /**
  1197. * This will return null if aspectjrt.jar is present and has the correct version. Otherwise it will return a string message
  1198. * indicating the problem.
  1199. */
  1200. private String checkRtJar(AjBuildConfig buildConfig) {
  1201. // omitting dev info
  1202. if (Version.getText().equals(Version.DEVELOPMENT) || Version.getText().endsWith("BUILD-SNAPSHOT")) {
  1203. // in the development version we can't do this test usefully
  1204. // MessageUtil.info(holder, "running development version of aspectj compiler");
  1205. return null;
  1206. }
  1207. if (buildConfig == null || buildConfig.getFullClasspath() == null) {
  1208. return "no classpath specified";
  1209. }
  1210. for (String s: buildConfig.getFullClasspath()) {
  1211. if (s.endsWith("runtime/target/classes") || s.endsWith("runtime\\target\\classes")) {
  1212. // doing an AspectJ build
  1213. return null;
  1214. }
  1215. }
  1216. String ret = null;
  1217. for (String s : buildConfig.getFullClasspath()) {
  1218. File p = new File(s);
  1219. // pr112830, allow variations on aspectjrt.jar of the form aspectjrtXXXXXX.jar
  1220. if (p.isFile() && p.getName().startsWith("aspectjrt") && p.getName().endsWith(".jar")) {
  1221. try {
  1222. String version = null;
  1223. Manifest manifest = new JarFile(p).getManifest();
  1224. if (manifest == null) {
  1225. ret = "no manifest found in " + p.getAbsolutePath() + ", expected " + Version.getText();
  1226. continue;
  1227. }
  1228. Attributes attr = manifest.getAttributes("org/aspectj/lang/");
  1229. if (null != attr) {
  1230. version = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
  1231. if (null != version) {
  1232. version = version.trim();
  1233. }
  1234. }
  1235. // assume that users of development aspectjrt.jar know what they're doing
  1236. if (version != null && (Version.DEVELOPMENT.equals(version) || version.endsWith("BUILD-SNAPSHOT"))) {
  1237. // MessageUtil.info(holder,
  1238. // "running with development version of aspectjrt.jar in " +
  1239. // p.getAbsolutePath());
  1240. return null;
  1241. }
  1242. else if (!Version.getText().equals(version)) {
  1243. ret = "bad version number found in " + p.getAbsolutePath() + " expected " + Version.getText() + " found "
  1244. + version;
  1245. continue;
  1246. }
  1247. } catch (IOException ioe) {
  1248. ret = "bad jar file found in " + p.getAbsolutePath() + " error: " + ioe;
  1249. }
  1250. return null; // this is the "OK" return value!
  1251. }
  1252. else if (p.isFile() && p.getName().contains("org.aspectj.runtime")) {
  1253. // likely to be a variant from the springsource bundle repo b272591
  1254. return null;
  1255. }
  1256. else {
  1257. // might want to catch other classpath errors
  1258. }
  1259. }
  1260. if (ret != null) {
  1261. return ret; // last error found in potentially matching jars...
  1262. }
  1263. return "couldn't find aspectjrt.jar on classpath, checked: " + makeClasspathString(buildConfig);
  1264. }
  1265. @Override
  1266. public String toString() {
  1267. StringBuilder buf = new StringBuilder();
  1268. buf.append("AjBuildManager(");
  1269. buf.append(")");
  1270. return buf.toString();
  1271. }
  1272. //
  1273. // public void setStructureModel(IHierarchy structureModel) {
  1274. // this.structureModel = structureModel;
  1275. // }
  1276. /**
  1277. * Returns null if there is no structure model
  1278. */
  1279. public AsmManager getStructureModel() {
  1280. return (state == null ? null : state.getStructureModel());
  1281. }
  1282. public IProgressListener getProgressListener() {
  1283. return progressListener;
  1284. }
  1285. public void setProgressListener(IProgressListener progressListener) {
  1286. this.progressListener = progressListener;
  1287. }
  1288. /*
  1289. * (non-Javadoc)
  1290. *
  1291. * @see org.aspectj.ajdt.internal.compiler.AjCompiler.IOutputClassFileNameProvider#getOutputClassFileName(char[])
  1292. */
  1293. @Override
  1294. public String getOutputClassFileName(char[] eclipseClassFileName, CompilationResult result) {
  1295. String filename = new String(eclipseClassFileName);
  1296. filename = filename.replace('/', File.separatorChar) + ".class";
  1297. File destinationPath = buildConfig.getOutputDir();
  1298. if (buildConfig.getCompilationResultDestinationManager() != null) {
  1299. File f = new File(new String(result.getFileName()));
  1300. destinationPath = buildConfig.getCompilationResultDestinationManager().getOutputLocationForClass(f);
  1301. }
  1302. String outFile;
  1303. if (destinationPath == null) {
  1304. outFile = new File(filename).getName();
  1305. outFile = new File(extractDestinationPathFromSourceFile(result), outFile).getPath();
  1306. } else {
  1307. outFile = new File(destinationPath, filename).getPath();
  1308. }
  1309. return outFile;
  1310. }
  1311. /*
  1312. * (non-Javadoc)
  1313. *
  1314. * @see org.eclipse.jdt.internal.compiler.ICompilerAdapterFactory#getAdapter(org.eclipse.jdt.internal.compiler.Compiler)
  1315. */
  1316. @Override
  1317. public ICompilerAdapter getAdapter(org.aspectj.org.eclipse.jdt.internal.compiler.Compiler forCompiler) {
  1318. // complete compiler config and return a suitable adapter...
  1319. populateCompilerOptionsFromLintSettings(forCompiler);
  1320. AjProblemReporter pr = new AjProblemReporter(DefaultErrorHandlingPolicies.proceedWithAllProblems(), forCompiler.options,
  1321. getProblemFactory());
  1322. forCompiler.problemReporter = pr;
  1323. AjLookupEnvironment le = new AjLookupEnvironment(forCompiler, forCompiler.options, pr, environment);
  1324. EclipseFactory factory = new EclipseFactory(le, this);
  1325. le.factory = factory;
  1326. pr.factory = factory;
  1327. forCompiler.lookupEnvironment = le;
  1328. forCompiler.parser = new Parser(pr, forCompiler.options.parseLiteralExpressionsAsConstants);
  1329. if (getBcelWorld().shouldPipelineCompilation()) {
  1330. IMessage message = MessageUtil.info("Pipelining compilation");
  1331. handler.handleMessage(message);
  1332. return new AjPipeliningCompilerAdapter(forCompiler, batchCompile, getBcelWorld(), getWeaver(), factory,
  1333. getInterimResultRequestor(), progressListener,
  1334. this, // IOutputFilenameProvider
  1335. this, // IBinarySourceProvider
  1336. state.getBinarySourceMap(), buildConfig.isTerminateAfterCompilation(), buildConfig.getProceedOnError(),
  1337. buildConfig.isNoAtAspectJAnnotationProcessing(), buildConfig.isMakeReflectable(), state);
  1338. } else {
  1339. return new AjCompilerAdapter(forCompiler, batchCompile, getBcelWorld(), getWeaver(), factory,
  1340. getInterimResultRequestor(), progressListener,
  1341. this, // IOutputFilenameProvider
  1342. this, // IBinarySourceProvider
  1343. state.getBinarySourceMap(), buildConfig.isTerminateAfterCompilation(), buildConfig.getProceedOnError(),
  1344. buildConfig.isNoAtAspectJAnnotationProcessing(), buildConfig.isMakeReflectable(), state);
  1345. }
  1346. }
  1347. /**
  1348. * Some AspectJ lint options need to be known about in the compiler. This is how we pass them over...
  1349. *
  1350. * @param forCompiler
  1351. */
  1352. private void populateCompilerOptionsFromLintSettings(org.aspectj.org.eclipse.jdt.internal.compiler.Compiler forCompiler) {
  1353. BcelWorld world = this.state.getBcelWorld();
  1354. IMessage.Kind swallowedExceptionKind = world.getLint().swallowedExceptionInCatchBlock.getKind();
  1355. Map optionsMap = new HashMap();
  1356. optionsMap.put(CompilerOptions.OPTION_ReportSwallowedExceptionInCatchBlock, swallowedExceptionKind == null ? "ignore"
  1357. : swallowedExceptionKind.toString());
  1358. forCompiler.options.set(optionsMap);
  1359. }
  1360. /*
  1361. * (non-Javadoc)
  1362. *
  1363. * @see org.aspectj.ajdt.internal.compiler.IBinarySourceProvider#getBinarySourcesForThisWeave()
  1364. */
  1365. @Override
  1366. public Map<String, List<UnwovenClassFile>> getBinarySourcesForThisWeave() {
  1367. return binarySourcesForTheNextCompile;
  1368. }
  1369. public static AsmHierarchyBuilder getAsmHierarchyBuilder() {
  1370. return asmHierarchyBuilder;
  1371. }
  1372. /**
  1373. * Override the the default hierarchy builder.
  1374. */
  1375. public static void setAsmHierarchyBuilder(AsmHierarchyBuilder newBuilder) {
  1376. asmHierarchyBuilder = newBuilder;
  1377. }
  1378. public AjState getState() {
  1379. return state;
  1380. }
  1381. public void setState(AjState buildState) {
  1382. state = buildState;
  1383. }
  1384. private static class AjBuildContexFormatter implements ContextFormatter {
  1385. @Override
  1386. public String formatEntry(int phaseId, Object data) {
  1387. StringBuilder sb = new StringBuilder();
  1388. if (phaseId == CompilationAndWeavingContext.BATCH_BUILD) {
  1389. sb.append("batch building ");
  1390. } else {
  1391. sb.append("incrementally building ");
  1392. }
  1393. AjBuildConfig config = (AjBuildConfig) data;
  1394. List classpath = config.getClasspath();
  1395. sb.append("with classpath: ");
  1396. for (Object o : classpath) {
  1397. sb.append(o.toString());
  1398. sb.append(File.pathSeparator);
  1399. }
  1400. return sb.toString();
  1401. }
  1402. }
  1403. public boolean wasFullBuild() {
  1404. return wasFullBuild;
  1405. }
  1406. }