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.

CompilerRun.java 73KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC),
  3. * 2003 Contributors.
  4. * All rights reserved.
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Public License v1.0
  7. * which accompanies this distribution and is available at
  8. * http://www.eclipse.org/legal/epl-v10.html
  9. *
  10. * Contributors:
  11. * Xerox/PARC initial implementation
  12. * Wes Isberg 2003 updates
  13. * ******************************************************************/
  14. package org.aspectj.testing.harness.bridge;
  15. import java.io.File;
  16. import java.io.FileFilter;
  17. import java.io.IOException;
  18. import java.io.PrintStream;
  19. import java.lang.reflect.Array;
  20. import java.util.ArrayList;
  21. import java.util.Arrays;
  22. import java.util.Collections;
  23. import java.util.Iterator;
  24. import java.util.List;
  25. import java.util.Map;
  26. import java.util.Set;
  27. import java.util.TreeMap;
  28. import org.aspectj.bridge.ICommand;
  29. import org.aspectj.bridge.IMessage;
  30. import org.aspectj.bridge.IMessageHandler;
  31. import org.aspectj.bridge.MessageHandler;
  32. import org.aspectj.bridge.MessageUtil;
  33. import org.aspectj.bridge.ReflectionFactory;
  34. import org.aspectj.testing.ajde.CompileCommand;
  35. import org.aspectj.testing.run.IRunIterator;
  36. import org.aspectj.testing.run.IRunStatus;
  37. import org.aspectj.testing.run.WrappedRunIterator;
  38. import org.aspectj.testing.taskdefs.AjcTaskCompileCommand;
  39. import org.aspectj.testing.util.options.Option;
  40. import org.aspectj.testing.util.options.Option.Family;
  41. import org.aspectj.testing.util.options.Option.InvalidInputException;
  42. import org.aspectj.testing.util.options.Options;
  43. import org.aspectj.testing.util.options.Values;
  44. import org.aspectj.testing.xml.SoftMessage;
  45. import org.aspectj.testing.xml.XMLWriter;
  46. import org.aspectj.util.FileUtil;
  47. import org.aspectj.util.LangUtil;
  48. /**
  49. * Run the compiler once.
  50. * The lifecycle is as follows:
  51. * <ul>
  52. * <li>Spec (specification) is created.</li>
  53. * <li>This is created using the Spec.</li>
  54. * <li>setupAjcRun(Sandbox, Validator) is invoked,
  55. * at which point this populates the shared sandbox
  56. * with values derived from the spec and also
  57. * sets up internal state based on both the sandbox
  58. * and the spec.</li>
  59. * <li>run(IRunStatus) is invoked, and this runs the compiler
  60. * based on internal state, the spec, and the sandbox.</li>
  61. * </ul>
  62. * Programmer notes:
  63. * <ul>
  64. * <li>Paths are resolved absolutely, which fails to test the
  65. * compiler's ability to find files relative to a source base</li>
  66. * <li>This does not enforce the lifecycle.</li>
  67. * <li>This must be used as the initial compile
  68. * before doing an incremental compile.
  69. * In that case, staging must be enabled.</li>
  70. * </ul>
  71. */
  72. public class CompilerRun implements IAjcRun {
  73. // static final String JAVAC_COMPILER
  74. // = JavacCompileCommand.class.getName();
  75. static final String[] RA_String = new String[0];
  76. static final String[] JAR_SUFFIXES = new String[] { ".jar", ".zip" };
  77. static final String[] SOURCE_SUFFIXES =
  78. (String[]) FileUtil.SOURCE_SUFFIXES.toArray(new String[0]);
  79. /** specifications, set on construction */
  80. Spec spec;
  81. //------------ calculated during setup
  82. /** get shared stuff during setup */
  83. Sandbox sandbox;
  84. /**
  85. * During run, these String are passed as the source and arg files to compile.
  86. * The list is set up in setupAjcRun(..), when arg files are prefixed with "@".
  87. */
  88. final List /*String*/
  89. arguments;
  90. /**
  91. * During run, these String are collapsed and passed as the injar option.
  92. * The list is set up in setupAjcRun(..).
  93. */
  94. final List /*String*/
  95. injars;
  96. /**
  97. * During run, these String are collapsed and passed as the inpath option.
  98. * The list is set up in setupAjcRun(..),
  99. * which extracts only directories from the files attribute.
  100. */
  101. final List inpaths;
  102. private CompilerRun(Spec spec) {
  103. if (null == spec) {
  104. throw new IllegalArgumentException("null spec");
  105. }
  106. this.spec = spec;
  107. arguments = new ArrayList();
  108. injars = new ArrayList();
  109. inpaths = new ArrayList();
  110. }
  111. /**
  112. * Select from input String[] if readable directories
  113. * @param inputs String[] of input - null ignored
  114. * @param baseDir the base directory of the input
  115. * @return String[] of input that end with any input
  116. */
  117. public static String[] selectDirectories(String[] inputs, File baseDir) {
  118. if (LangUtil.isEmpty(inputs)) {
  119. return new String[0];
  120. }
  121. ArrayList result = new ArrayList();
  122. for (int i = 0; i < inputs.length; i++) {
  123. String input = inputs[i];
  124. if (null == input) {
  125. continue;
  126. }
  127. File inputFile = new File(baseDir, input);
  128. if (inputFile.canRead() && inputFile.isDirectory()) {
  129. result.add(input);
  130. }
  131. }
  132. return (String[]) result.toArray(new String[0]);
  133. }
  134. /**
  135. * Select from input String[] based on suffix-matching
  136. * @param inputs String[] of input - null ignored
  137. * @param suffixes String[] of suffix selectors - null ignored
  138. * @param ignoreCase if true, ignore case
  139. * @return String[] of input that end with any input
  140. */
  141. public static String[] endsWith(String[] inputs, String[] suffixes, boolean ignoreCase) {
  142. if (LangUtil.isEmpty(inputs) || LangUtil.isEmpty(suffixes)) {
  143. return new String[0];
  144. }
  145. if (ignoreCase) {
  146. String[] temp = new String[suffixes.length];
  147. for (int i = 0; i < temp.length; i++) {
  148. String suff = suffixes[i];
  149. temp[i] = (null == suff ? null : suff.toLowerCase());
  150. }
  151. suffixes = temp;
  152. }
  153. ArrayList result = new ArrayList();
  154. for (int i = 0; i < inputs.length; i++) {
  155. String input = inputs[i];
  156. if (null == input) {
  157. continue;
  158. }
  159. if (!ignoreCase) {
  160. input = input.toLowerCase();
  161. }
  162. for (int j = 0; j < suffixes.length; j++) {
  163. String suffix = suffixes[j];
  164. if (null == suffix) {
  165. continue;
  166. }
  167. if (input.endsWith(suffix)) {
  168. result.add(input);
  169. break;
  170. }
  171. }
  172. }
  173. return (String[]) result.toArray(new String[0]);
  174. }
  175. /**
  176. * This checks that the spec is reasonable and does setup:
  177. * <ul>
  178. * <li>calculate and set sandbox testBaseSrcDir as {Sandbox.testBaseDir}/
  179. * {Spec.testSrcDirOffset}/<li>
  180. * <li>get the list of source File to compile as {Sandbox.testBaseSrcDir} /
  181. * {Spec.getPaths..}</li>
  182. * <li>get the list of extraClasspath entries to add to default classpath as
  183. * {Sandbox.testBaseSrcDir} / {Spec.classpath..}</li>
  184. * <li>get the list of aspectpath entries to use as the aspectpath as
  185. * {Sandbox. testBaseSrcDir} / {Spec.aspectpath..}</li>
  186. * </ul>
  187. * All sources must be readable at this time,
  188. * unless spec.badInput is true (for invalid-input tests).
  189. * If staging, the source files and source roots are copied
  190. * to a separate staging directory so they can be modified
  191. * for incremental tests. Note that (as of this writing) the
  192. * compiler only handles source roots for incremental tests.
  193. * @param classesDir the File
  194. * @see org.aspectj.testing.harness.bridge.AjcTest.IAjcRun#setup(File, File)
  195. * @throws AbortException containing IOException or IllegalArgumentException
  196. * if the staging operations fail
  197. */
  198. public boolean setupAjcRun(Sandbox sandbox, Validator validator) {
  199. if (!validator.nullcheck(spec.getOptionsArray(), "localOptions")
  200. || !validator.nullcheck(sandbox, "sandbox")
  201. || !validator.nullcheck(spec.compiler, "compilerName")
  202. || !validator.canRead(Globals.F_aspectjrt_jar, "aspectjrt.jar")
  203. || !validator.canRead(
  204. Globals.F_testingclient_jar,
  205. "testing-client.jar")) {
  206. return false;
  207. }
  208. this.sandbox = sandbox;
  209. String rdir = spec.testSrcDirOffset;
  210. File testBaseSrcDir;
  211. if ((null == rdir) || (0 == rdir.length())) {
  212. testBaseSrcDir = sandbox.testBaseDir;
  213. } else {
  214. testBaseSrcDir = new File(sandbox.testBaseDir, rdir);
  215. // XXX what if rdir is two levels deep?
  216. if (!validator
  217. .canReadDir(testBaseSrcDir, "sandbox.testBaseSrcDir")) {
  218. return false;
  219. }
  220. }
  221. // Sources come as relative paths - check read, copy if staging.
  222. // This renders paths absolute before run(RunStatusI) is called.
  223. // For a compile run to support relative paths + source base,
  224. // change so the run calculates the paths (differently when staging)
  225. final String[] inpathPaths;
  226. final String[] injarPaths;
  227. final String[] srcPaths;
  228. {
  229. final String[] paths = spec.getPathsArray();
  230. srcPaths =
  231. endsWith(
  232. paths,
  233. CompilerRun.SOURCE_SUFFIXES,
  234. true);
  235. injarPaths =
  236. endsWith(paths, CompilerRun.JAR_SUFFIXES, true);
  237. inpathPaths =
  238. selectDirectories(paths, testBaseSrcDir);
  239. if (!spec.badInput) {
  240. int found = inpathPaths.length + injarPaths.length + srcPaths.length;
  241. if (paths.length != found) {
  242. validator.fail("found " + found + " of " + paths.length + " sources");
  243. }
  244. }
  245. }
  246. // validate readable for sources
  247. if (!spec.badInput) {
  248. if (!validator.canRead(testBaseSrcDir, srcPaths, "sources")
  249. // see validation of inpathPaths below due to ambiguous base dir
  250. || !validator.canRead(
  251. testBaseSrcDir,
  252. spec.argfiles,
  253. "argfiles")
  254. || !validator.canRead(
  255. testBaseSrcDir,
  256. spec.classpath,
  257. "classpath")
  258. || !validator.canRead(
  259. testBaseSrcDir,
  260. spec.aspectpath,
  261. "aspectpath")
  262. || !validator.canRead(
  263. testBaseSrcDir,
  264. spec.sourceroots,
  265. "sourceroots")
  266. || !validator.canRead(
  267. testBaseSrcDir,
  268. spec.extdirs,
  269. "extdirs")) {
  270. return false;
  271. }
  272. }
  273. int numSources =
  274. srcPaths.length
  275. + injarPaths.length
  276. + inpathPaths.length
  277. + spec.argfiles.length
  278. + spec.sourceroots.length;
  279. if (!spec.badInput && (numSources < 1)) {
  280. validator.fail(
  281. "no input jars, arg files, or source files or roots");
  282. return false;
  283. }
  284. final File[] argFiles =
  285. FileUtil.getBaseDirFiles(testBaseSrcDir, spec.argfiles);
  286. final File[] injarFiles =
  287. FileUtil.getBaseDirFiles(testBaseSrcDir, injarPaths);
  288. final File[] inpathFiles =
  289. FileUtil.getBaseDirFiles(testBaseSrcDir, inpathPaths);
  290. final File[] aspectFiles =
  291. FileUtil.getBaseDirFiles(testBaseSrcDir, spec.aspectpath);
  292. final File[] extdirFiles =
  293. FileUtil.getBaseDirFiles(testBaseSrcDir, spec.extdirs);
  294. final File[] classFiles =
  295. FileUtil.getBaseDirFiles(testBaseSrcDir, spec.classpath);
  296. final File[] xlintFiles = (null == spec.xlintfile ? new File[0]
  297. : FileUtil.getBaseDirFiles(testBaseSrcDir, new String[] {spec.xlintfile}));
  298. // injars might be outjars in the classes dir...
  299. for (int i = 0; i < injarFiles.length; i++) {
  300. if (!injarFiles[i].exists()) {
  301. injarFiles[i] = new File(sandbox.classesDir, injarPaths[i]);
  302. }
  303. }
  304. for (int i = 0; i < inpathFiles.length; i++) {
  305. if (!inpathFiles[i].exists()) {
  306. inpathFiles[i] = new File(sandbox.classesDir, inpathPaths[i]);
  307. }
  308. }
  309. // moved after solving any injars that were outjars
  310. if (!validator.canRead(injarFiles, "injars")
  311. || !validator.canRead(injarFiles, "injars")) {
  312. return false;
  313. }
  314. // hmm - duplicates validation above, verifying getBaseDirFiles?
  315. if (!spec.badInput) {
  316. if (!validator.canRead(argFiles, "argFiles")
  317. || !validator.canRead(injarFiles, "injarFiles")
  318. || !validator.canRead(inpathFiles, "inpathFiles")
  319. || !validator.canRead(aspectFiles, "aspectFiles")
  320. || !validator.canRead(classFiles, "classFiles")
  321. || !validator.canRead(xlintFiles, "xlintFiles")) {
  322. return false;
  323. }
  324. }
  325. final File[] srcFiles;
  326. File[] sourcerootFiles = new File[0];
  327. // source text files are copied when staging incremental tests
  328. if (!spec.isStaging()) {
  329. // XXX why this? was always? || (testBaseSrcDir != sandbox.stagingDir))) {
  330. srcFiles =
  331. FileUtil.getBaseDirFiles(
  332. testBaseSrcDir,
  333. srcPaths,
  334. CompilerRun.SOURCE_SUFFIXES);
  335. if (!LangUtil.isEmpty(spec.sourceroots)) {
  336. sourcerootFiles =
  337. FileUtil.getBaseDirFiles(
  338. testBaseSrcDir,
  339. spec.sourceroots,
  340. null);
  341. }
  342. } else { // staging - copy files
  343. if (spec.badInput) {
  344. validator.info(
  345. "badInput ignored - files checked when staging");
  346. }
  347. try {
  348. // copy all files, then remove tagged ones
  349. // XXX make copyFiles support a filter?
  350. srcFiles =
  351. FileUtil.copyFiles(
  352. testBaseSrcDir,
  353. srcPaths,
  354. sandbox.stagingDir);
  355. if (!LangUtil.isEmpty(spec.sourceroots)) {
  356. sourcerootFiles =
  357. FileUtil.copyFiles(
  358. testBaseSrcDir,
  359. spec.sourceroots,
  360. sandbox.stagingDir);
  361. // delete incremental files in sourceroot after copying // XXX inefficient
  362. // an incremental file has an extra "." in name
  363. // most .java files don't, because they are named after
  364. // the principle type they contain, and simple type names
  365. // have no dots.
  366. FileFilter pickIncFiles = new FileFilter() {
  367. public boolean accept(File file) {
  368. if (file.isDirectory()) {
  369. // continue recursion
  370. return true;
  371. }
  372. String path = file.getPath();
  373. // only source files are relevant to staging
  374. if (!FileUtil.hasSourceSuffix(path)) {
  375. return false;
  376. }
  377. int first = path.indexOf(".");
  378. int last = path.lastIndexOf(".");
  379. return (first != last);
  380. }
  381. };
  382. for (int i = 0; i < sourcerootFiles.length; i++) {
  383. FileUtil.deleteContents(
  384. sourcerootFiles[i],
  385. pickIncFiles,
  386. false);
  387. }
  388. if (0 < sourcerootFiles.length) {
  389. FileUtil.sleepPastFinalModifiedTime(
  390. sourcerootFiles);
  391. }
  392. }
  393. File[] files =
  394. FileUtil.getBaseDirFiles(sandbox.stagingDir, srcPaths);
  395. if (0 < files.length) {
  396. FileUtil.sleepPastFinalModifiedTime(files);
  397. }
  398. } catch (IllegalArgumentException e) {
  399. validator.fail("staging - bad input", e);
  400. return false;
  401. } catch (IOException e) {
  402. validator.fail("staging - operations", e);
  403. return false;
  404. }
  405. }
  406. if (!spec.badInput
  407. && !validator.canRead(srcFiles, "copied paths")) {
  408. return false;
  409. }
  410. arguments.clear();
  411. if (!LangUtil.isEmpty(xlintFiles)) {
  412. arguments.add("-Xlintfile");
  413. String sr = FileUtil.flatten(xlintFiles, null);
  414. arguments.add(sr);
  415. }
  416. if (spec.outjar != null) {
  417. arguments.add("-outjar");
  418. arguments.add(new File(sandbox.classesDir,spec.outjar).getPath());
  419. }
  420. if (!LangUtil.isEmpty(extdirFiles)) {
  421. arguments.add("-extdirs");
  422. String sr = FileUtil.flatten(extdirFiles, null);
  423. arguments.add(sr);
  424. }
  425. if (!LangUtil.isEmpty(sourcerootFiles)) {
  426. arguments.add("-sourceroots");
  427. String sr = FileUtil.flatten(sourcerootFiles, null);
  428. arguments.add(sr);
  429. }
  430. if (!LangUtil.isEmpty(srcFiles)) {
  431. arguments.addAll(Arrays.asList(FileUtil.getPaths(srcFiles)));
  432. }
  433. injars.clear();
  434. if (!LangUtil.isEmpty(injarFiles)) {
  435. injars.addAll(Arrays.asList(FileUtil.getPaths(injarFiles)));
  436. }
  437. inpaths.clear();
  438. if (!LangUtil.isEmpty(inpathFiles)) {
  439. inpaths.addAll(Arrays.asList(FileUtil.getPaths(inpathFiles)));
  440. }
  441. if (!LangUtil.isEmpty(argFiles)) {
  442. String[] ra = FileUtil.getPaths(argFiles);
  443. for (int j = 0; j < ra.length; j++) {
  444. arguments.add("@" + ra[j]);
  445. }
  446. if (!spec.badInput && spec.isStaging) {
  447. validator.fail(
  448. "warning: files listed in argfiles not staged");
  449. }
  450. }
  451. // save classpath and aspectpath in sandbox for this and other clients
  452. final boolean checkReadable = !spec.badInput;
  453. int size = spec.includeClassesDir ? 3 : 2;
  454. File[] cp = new File[size + classFiles.length];
  455. System.arraycopy(classFiles, 0, cp, 0, classFiles.length);
  456. int index = classFiles.length;
  457. if (spec.includeClassesDir) {
  458. cp[index++] = sandbox.classesDir;
  459. }
  460. cp[index++] = Globals.F_aspectjrt_jar;
  461. cp[index++] = Globals.F_testingclient_jar;
  462. sandbox.compilerRunInit(this, testBaseSrcDir, aspectFiles,
  463. checkReadable, cp, checkReadable, null);
  464. // XXX todo set bootclasspath if set for forking?
  465. return true;
  466. }
  467. /**
  468. * Setup result evaluation and command line, run, and evaluate result.
  469. * <li>setup an AjcMessageHandler using the expected messages from
  470. * {@link Spec#getMessages()}.<li>
  471. * <li>heed any globals interpreted into a TestSetup by reading
  472. * {@link Spec@getOptions()}. For a list of supported globals, see
  473. * {@link setupArgs(ArrayList, IMessageHandler}.</li>
  474. * <li>construct a command line, using as classpath
  475. * {@link Sandbox.classpathToString()}<li>
  476. * <li>construct a compiler using {@link Spec#compiler}
  477. * or any overriding value set in TestSetup.<li>
  478. * <li>Just before running, set the compiler in the sandbox using
  479. * {@link Sandbox.setCompiler(ICommand)}.<li>
  480. * <li>After running, report AjcMessageHandler results to the status parameter.
  481. * If the AjcMessageHandler reports a failure, then send info messages
  482. * for the Spec, TestSetup, and command line.<li>
  483. * @see org.aspectj.testing.run.IRun#run(IRunStatus)
  484. */
  485. public boolean run(IRunStatus status) {
  486. if (null == spec.testSetup) {
  487. MessageUtil.abort(
  488. status,
  489. "no test setup - adoptParentValues not called");
  490. return false;
  491. } else if (!spec.testSetup.result) {
  492. MessageUtil.abort(status, spec.testSetup.failureReason);
  493. return false;
  494. }
  495. AjcMessageHandler handler =
  496. new AjcMessageHandler(spec.getMessages());
  497. handler.init();
  498. boolean handlerResult = false;
  499. boolean result = false;
  500. boolean commandResult = false;
  501. ArrayList argList = new ArrayList();
  502. final Spec.TestSetup setupResult = spec.testSetup;
  503. try {
  504. if (spec.outjar == null) {
  505. argList.add("-d");
  506. String outputDirPath = sandbox.classesDir.getAbsolutePath();
  507. try { // worth it to try for canonical?
  508. outputDirPath = sandbox.classesDir.getCanonicalPath();
  509. } catch (IOException e) {
  510. MessageUtil.abort(
  511. status,
  512. "canonical " + sandbox.classesDir,
  513. e);
  514. }
  515. argList.add(outputDirPath);
  516. }
  517. String path = sandbox.classpathToString(this);
  518. if (!LangUtil.isEmpty(path)) {
  519. argList.add("-classpath");
  520. argList.add(path);
  521. }
  522. path = sandbox.getBootclasspath(this);
  523. if (!LangUtil.isEmpty(path)) {
  524. argList.add("-bootclasspath");
  525. argList.add(path);
  526. }
  527. path = sandbox.aspectpathToString(this);
  528. if (!LangUtil.isEmpty(path)) {
  529. argList.add("-aspectpath");
  530. argList.add(path);
  531. }
  532. if (0 < injars.size()) {
  533. argList.add("-injars");
  534. argList.add(
  535. FileUtil.flatten(
  536. (String[]) injars.toArray(new String[0]),
  537. null));
  538. }
  539. if (0 < inpaths.size()) {
  540. argList.add("-inpath");
  541. argList.add(
  542. FileUtil.flatten(
  543. (String[]) inpaths.toArray(new String[0]),
  544. null));
  545. }
  546. // put specified arguments last, for better badInput tests
  547. argList.addAll(setupResult.commandOptions);
  548. // add both java/aspectj and argfiles
  549. argList.addAll(arguments);
  550. // XXX hack - seek on request as a side effect. reimplement as listener
  551. if (null != setupResult.seek) {
  552. String slopPrefix = Spec.SEEK_MESSAGE_PREFIX + " slop - ";
  553. PrintStream slop =
  554. MessageUtil.handlerPrintStream(
  555. status,
  556. IMessage.INFO,
  557. System.err,
  558. slopPrefix);
  559. List found =
  560. FileUtil.lineSeek(
  561. setupResult.seek,
  562. arguments,
  563. false,
  564. slop);
  565. if (!LangUtil.isEmpty(found)) {
  566. for (Iterator iter = found.iterator();
  567. iter.hasNext();
  568. ) {
  569. MessageUtil.info(
  570. status,
  571. Spec.SEEK_MESSAGE_PREFIX + iter.next());
  572. }
  573. }
  574. }
  575. ICommand compiler = spec.reuseCompiler
  576. // throws IllegalStateException if null
  577. ? sandbox.getCommand(this)
  578. : ReflectionFactory.makeCommand(setupResult.compilerName, status);
  579. DirChanges dirChanges = null;
  580. if (null == compiler) {
  581. MessageUtil.fail(
  582. status,
  583. "unable to make compiler " + setupResult.compilerName);
  584. return false;
  585. } else {
  586. if (setupResult.compilerName != Spec.DEFAULT_COMPILER) {
  587. MessageUtil.info(
  588. status,
  589. "compiler: " + setupResult.compilerName);
  590. }
  591. if (status.aborted()) {
  592. MessageUtil.debug(
  593. status,
  594. "aborted, but compiler valid?: " + compiler);
  595. } else {
  596. // same DirChanges handling for JavaRun, CompilerRun, IncCompilerRun
  597. // XXX around advice or template method/class
  598. if (!LangUtil.isEmpty(spec.dirChanges)) {
  599. LangUtil.throwIaxIfFalse(
  600. 1 == spec.dirChanges.size(),
  601. "expecting 0..1 dirChanges");
  602. dirChanges =
  603. new DirChanges(
  604. (DirChanges.Spec) spec.dirChanges.get(0));
  605. if (!dirChanges
  606. .start(status, sandbox.classesDir)) {
  607. return false; // setup failed
  608. }
  609. }
  610. MessageUtil.info(
  611. status,
  612. compiler + "(" + argList + ")");
  613. sandbox.setCommand(compiler, this);
  614. String[] args = (String[]) argList.toArray(RA_String);
  615. commandResult = compiler.runCommand(args, handler);
  616. }
  617. }
  618. handlerResult = handler.passed();
  619. if (!handlerResult) {
  620. return false;
  621. } else {
  622. result = (commandResult == handler.expectingCommandTrue());
  623. if (!result) {
  624. String m =
  625. commandResult
  626. ? "compile did not fail as expected"
  627. : "compile failed unexpectedly";
  628. MessageUtil.fail(status, m);
  629. } else if (null != dirChanges) {
  630. result = dirChanges.end(status, sandbox.testBaseDir);
  631. }
  632. }
  633. return result;
  634. } finally {
  635. if (!handlerResult) { // more debugging context in case of failure
  636. MessageUtil.info(handler, spec.toLongString());
  637. MessageUtil.info(handler, "" + argList);
  638. if (null != setupResult) {
  639. MessageUtil.info(handler, "" + setupResult);
  640. }
  641. }
  642. handler.report(status);
  643. // XXX weak - actual messages not reported in real-time, no fast-fail
  644. }
  645. }
  646. public String toString() {
  647. return "CompilerRun(" + spec + ")";
  648. }
  649. /**
  650. * Initializer/factory for CompilerRun
  651. * any path or file is relative to this test base dir
  652. */
  653. public static class Spec extends AbstractRunSpec {
  654. public static final String XMLNAME = "compile";
  655. public static final String DEFAULT_COMPILER =
  656. ReflectionFactory.ECLIPSE;
  657. static final String SEEK_PREFIX = "-seek:";
  658. static final String SEEK_MESSAGE_PREFIX = "found: ";
  659. private static final CRSOptions CRSOPTIONS = new CRSOptions();
  660. /**
  661. * Retitle description to title, paths to files, do comment,
  662. * staging, badInput,
  663. * do dirChanges, and print no chidren.
  664. */
  665. private static final AbstractRunSpec.XMLNames NAMES =
  666. new AbstractRunSpec.XMLNames(
  667. AbstractRunSpec.XMLNames.DEFAULT,
  668. "title",
  669. null,
  670. null,
  671. null,
  672. "files",
  673. null,
  674. null,
  675. null,
  676. false,
  677. false,
  678. true);
  679. /**
  680. * If the source version warrants, add a -bootclasspath
  681. * entry to the list of arguments to add.
  682. * This will fail and return an error String if the
  683. * required library is not found.
  684. * @param sourceVersion the String (if any) describing the -source option
  685. * (expecting one of [null, "1.3", "1.4", "1.5"].
  686. * @param compilerName the String name of the target compiler
  687. * @param toAdd the ArrayList to add -bootclasspath to
  688. * @return the String describing any errors, or null if no errors
  689. */
  690. private static String updateBootclasspathForSourceVersion(
  691. String sourceVersion,
  692. String compilerName,
  693. ArrayList toAdd) {
  694. if (null == sourceVersion) {
  695. return null;
  696. }
  697. if (3 != sourceVersion.length()) {
  698. throw new IllegalArgumentException(
  699. "bad version: " + sourceVersion);
  700. }
  701. if (null == toAdd) {
  702. throw new IllegalArgumentException("null toAdd");
  703. }
  704. int version = sourceVersion.charAt(2) - '0';
  705. switch (version) {
  706. case (3) :
  707. if (Globals.supportsJava("1.4")) {
  708. if (!FileUtil.canReadFile(Globals.J2SE13_RTJAR)) {
  709. return "no 1.3 libraries to handle -source 1.3";
  710. }
  711. toAdd.add("-bootclasspath");
  712. toAdd.add(Globals.J2SE13_RTJAR.getAbsolutePath());
  713. }
  714. break;
  715. case (4) :
  716. if (!Globals.supportsJava("1.4")) {
  717. if (ReflectionFactory
  718. .ECLIPSE
  719. .equals(compilerName)) {
  720. return "run eclipse under 1.4 to handle -source 1.4";
  721. }
  722. if (!FileUtil.canReadFile(Globals.J2SE14_RTJAR)) {
  723. return "no 1.4 libraries to handle -source 1.4";
  724. }
  725. toAdd.add("-bootclasspath");
  726. toAdd.add(Globals.J2SE14_RTJAR.getAbsolutePath());
  727. }
  728. break;
  729. case (5) :
  730. return "1.5 not supported in CompilerRun";
  731. case (0) :
  732. // ignore - no version specified
  733. break;
  734. default :
  735. throw new Error("unexpected version: " + version);
  736. }
  737. return null;
  738. }
  739. static CRSOptions testAccessToCRSOptions() {
  740. return CRSOPTIONS;
  741. }
  742. static Options testAccessToOptions() {
  743. return CRSOPTIONS.getOptions();
  744. }
  745. private static String[] copy(String[] input) {
  746. if (null == input) {
  747. return null;
  748. }
  749. String[] result = new String[input.length];
  750. System.arraycopy(input, 0, result, 0, input.length);
  751. return result;
  752. }
  753. protected String compiler;
  754. // use same command - see also IncCompiler.Spec.fresh
  755. protected boolean reuseCompiler;
  756. protected boolean permitAnyCompiler;
  757. protected boolean includeClassesDir;
  758. protected TestSetup testSetup;
  759. protected String[] argfiles = new String[0];
  760. protected String[] aspectpath = new String[0];
  761. protected String[] classpath = new String[0];
  762. protected String[] sourceroots = new String[0];
  763. protected String[] extdirs = new String[0];
  764. /** src path = {suiteParentDir}/{testBaseDirOffset}/{testSrcDirOffset}/{path} */
  765. protected String testSrcDirOffset;
  766. protected String xlintfile;
  767. protected String outjar;
  768. public Spec() {
  769. super(XMLNAME);
  770. setXMLNames(NAMES);
  771. compiler = DEFAULT_COMPILER;
  772. }
  773. protected void initClone(Spec spec)
  774. throws CloneNotSupportedException {
  775. super.initClone(spec);
  776. spec.argfiles = copy(argfiles);
  777. spec.aspectpath = copy(aspectpath);
  778. spec.classpath = copy(classpath);
  779. spec.compiler = compiler;
  780. spec.includeClassesDir = includeClassesDir;
  781. spec.reuseCompiler = reuseCompiler;
  782. spec.permitAnyCompiler = permitAnyCompiler;
  783. spec.sourceroots = copy(sourceroots);
  784. spec.extdirs = copy(extdirs);
  785. spec.outjar = outjar;
  786. spec.testSetup = null;
  787. if (null != testSetup) {
  788. spec.testSetup = (TestSetup) testSetup.clone();
  789. }
  790. spec.testSrcDirOffset = testSrcDirOffset;
  791. }
  792. public Object clone() throws CloneNotSupportedException {
  793. Spec result = new Spec();
  794. initClone(result);
  795. return result;
  796. }
  797. public void setIncludeClassesDir(boolean include) {
  798. this.includeClassesDir = include;
  799. }
  800. public void setReuseCompiler(boolean reuse) {
  801. this.reuseCompiler = reuse;
  802. }
  803. public void setPermitAnyCompiler(boolean permitAny) {
  804. this.permitAnyCompiler = permitAny;
  805. }
  806. public void setCompiler(String compilerName) {
  807. this.compiler = compilerName;
  808. }
  809. public void setTestSrcDirOffset(String s) {
  810. if (null != s) {
  811. testSrcDirOffset = s;
  812. }
  813. }
  814. /** override to set dirToken to Sandbox.CLASSES and default suffix to ".class" */
  815. public void addDirChanges(DirChanges.Spec spec) {
  816. if (null == spec) {
  817. return;
  818. }
  819. spec.setDirToken(Sandbox.CLASSES_DIR);
  820. spec.setDefaultSuffix(".class");
  821. super.addDirChanges(spec);
  822. }
  823. public String toLongString() {
  824. return getPrintName() + "(" + super.containedSummary() + ")";
  825. }
  826. public String toString() {
  827. return getPrintName() + "(" + super.containedSummary() + ")";
  828. }
  829. /** bean mapping for writers */
  830. public void setFiles(String paths) {
  831. addPaths(paths);
  832. }
  833. /**
  834. * Add to default classpath
  835. * (which includes aspectjrt.jar and testing-client.jar).
  836. * @param files comma-delimited list of classpath entries - ignored if
  837. * null or empty
  838. */
  839. public void setClasspath(String files) {
  840. if (!LangUtil.isEmpty(files)) {
  841. classpath = XMLWriter.unflattenList(files);
  842. }
  843. }
  844. /**
  845. * Set source roots, deleting any old ones
  846. * @param files comma-delimited list of directories
  847. * - ignored if null or empty
  848. */
  849. public void setSourceroots(String dirs) {
  850. if (!LangUtil.isEmpty(dirs)) {
  851. sourceroots = XMLWriter.unflattenList(dirs);
  852. }
  853. }
  854. public void setXlintfile(String path) {
  855. xlintfile = path;
  856. }
  857. public void setOutjar(String path) {
  858. outjar = path;
  859. }
  860. /**
  861. * Set extension dirs, deleting any old ones
  862. * @param files comma-delimited list of directories
  863. * - ignored if null or empty
  864. */
  865. public void setExtdirs(String dirs) {
  866. if (!LangUtil.isEmpty(dirs)) {
  867. extdirs = XMLWriter.unflattenList(dirs);
  868. }
  869. }
  870. /**
  871. * Set aspectpath, deleting any old ones
  872. * @param files comma-delimited list of aspect jars - ignored if null or
  873. * empty
  874. */
  875. public void setAspectpath(String files) {
  876. if (!LangUtil.isEmpty(files)) {
  877. aspectpath = XMLWriter.unflattenList(files);
  878. }
  879. }
  880. /**
  881. * Set argfiles, deleting any old ones
  882. * @param files comma-delimited list of argfiles - ignored if null or empty
  883. */
  884. public void setArgfiles(String files) {
  885. if (!LangUtil.isEmpty(files)) {
  886. argfiles = XMLWriter.unflattenList(files);
  887. }
  888. }
  889. /** @return String[] copy of argfiles array */
  890. public String[] getArgfilesArray() {
  891. String[] argfiles = this.argfiles;
  892. if (LangUtil.isEmpty(argfiles)) {
  893. return new String[0];
  894. }
  895. return (String[]) copy(argfiles);
  896. }
  897. /**
  898. * Make a copy of the array.
  899. * @return an array with the same component type as source
  900. * containing same elements, even if null.
  901. * @throws IllegalArgumentException if source is null
  902. */
  903. public static final Object[] copy(Object[] source) {
  904. LangUtil.throwIaxIfNull(source, "source");
  905. final Class c = source.getClass().getComponentType();
  906. Object[] result = (Object[]) Array.newInstance(c, source.length);
  907. System.arraycopy(source, 0, result, 0, result.length);
  908. return result;
  909. }
  910. /**
  911. * This implementation skips if:
  912. * <ul>
  913. * <li>incremental test, but using ajc (not eclipse)</li>
  914. * <li>usejavac, but javac is not available on the classpath</li>
  915. * <li>eclipse, but -usejavac or -preprocess test</li>
  916. * <li>-source 1.4, but running under 1.2 (XXX design)</li>
  917. * <li>local/global option conflicts (-lenient/-strict)</li>
  918. * <li>semantic conflicts (e.g., -lenient/-strict)</li>
  919. * </ul>
  920. * @return false if this wants to be skipped, true otherwise
  921. */
  922. protected boolean doAdoptParentValues(
  923. RT parentRuntime,
  924. IMessageHandler handler) {
  925. if (!super.doAdoptParentValues(parentRuntime, handler)) {
  926. return false;
  927. }
  928. testSetup = setupArgs(handler);
  929. if (!testSetup.result) {
  930. skipMessage(handler, testSetup.failureReason);
  931. }
  932. return testSetup.result;
  933. }
  934. private String getShortCompilerName() {
  935. String compilerClassName = compiler;
  936. if (null != testSetup) {
  937. compilerClassName = testSetup.compilerName;
  938. }
  939. if (null != compilerClassName) {
  940. int loc = compilerClassName.lastIndexOf(".");
  941. if (-1 != loc) {
  942. compilerClassName =
  943. compilerClassName.substring(loc + 1);
  944. }
  945. }
  946. return compilerClassName;
  947. }
  948. /** @return a CompilerRun with this as spec if setup completes successfully. */
  949. public IRunIterator makeRunIterator(
  950. Sandbox sandbox,
  951. Validator validator) {
  952. CompilerRun run = new CompilerRun(this);
  953. if (run.setupAjcRun(sandbox, validator)) {
  954. // XXX need name for compilerRun
  955. return new WrappedRunIterator(this, run);
  956. }
  957. return null;
  958. }
  959. protected String getPrintName() {
  960. return "CompilerRun.Spec " + getShortCompilerName();
  961. }
  962. /**
  963. * Each non-incremental run, fold the global flags in with
  964. * the run flags, which may involve adding or removing from
  965. * either list, depending on the flag prefix:
  966. * <ul>
  967. * <li>-foo: use -foo unless forced off.<li>
  968. * <li>^foo: (force off) remove any -foo option from the run flags</li>
  969. * <li>!foo: (force on) require the -foo flag </li>
  970. * </ul>
  971. * If there is a force conflict, then the test is skipped
  972. * ("skipping" info message, TestSetup.result is false).
  973. * This means an option local to the test which was specified
  974. * without forcing may be overridden by a globally-forced option.
  975. * <p>
  976. * There are some flags which are interpreted by the test
  977. * and removed from the list of flags passed to the command
  978. * (see testFlag()):
  979. * <ul>
  980. * <li>eclipse: use the new eclipse compiler (can force)</li>
  981. * <li>ajc: use the old ajc compiler (can force)</li>
  982. * <li>ignoreWarnings: ignore warnings in result evaluations (no force)</li>
  983. * </ul>
  984. * <p>
  985. * There are some flags which are inconsistent with each other.
  986. * These are treated as conflicts and the test is skipped:
  987. * <ul>
  988. * <li>lenient, strict</li>
  989. * </ul>
  990. * <p>
  991. * <p>
  992. * This also interprets any relevant System properties,
  993. * e.g., from <code>JavaRun.BOOTCLASSPATH_KEY</code>.
  994. * <p>
  995. * Finally, compiler limitations are enforced here by skipping
  996. * tests which the compiler cannot do:
  997. * <ul>
  998. * <li>eclipse does not do -lenient, -strict, -usejavac, -preprocess,
  999. * -XOcodeSize, -XSerializable, XaddSafePrefix,
  1000. * -XserializableAspects,-XtargetNearSource</li>
  1001. * <li>ajc does not run in incremental (staging) mode,
  1002. * nor with -usejavac if javac is not on the classpath</li>
  1003. * </ul>
  1004. * <u>Errors</u>:This will remove an arg not prefixed by [-|!|^] after
  1005. * providing an info message.
  1006. * <u>TestSetup Result</u>:
  1007. * If this completes successfully, then TestSetup.result is true,
  1008. * and commandOptions is not null, and any test flags (ignore warning,
  1009. * compiler) are reflected in the TestSetup.
  1010. * If this fails, then TestSetup.result is false,
  1011. * and a TestSetup.failreason is set.
  1012. * This means the test is skipped.
  1013. * @return TestSetup with results
  1014. * (TestSetup result=false if the run should not continue)
  1015. */
  1016. protected TestSetup setupArgs(IMessageHandler handler) {
  1017. // warning: HarnessSelectionTest checks for specific error wording
  1018. final Spec spec = this;
  1019. final TestSetup result = new TestSetup();
  1020. result.compilerName = spec.compiler;
  1021. // urk - s.b. null, but expected
  1022. Values values = gatherValues(result);
  1023. if ((null == values) || (null != result.failureReason)) {
  1024. return checkResult(result);
  1025. }
  1026. // send info messages about
  1027. // forced staging when -incremental
  1028. // or staging but no -incremental flag
  1029. Option.Family getFamily =
  1030. CRSOPTIONS.crsIncrementalOption.getFamily();
  1031. final boolean haveIncrementalFlag =
  1032. (null != values.firstInFamily(getFamily));
  1033. if (spec.isStaging()) {
  1034. if (!haveIncrementalFlag) {
  1035. MessageUtil.info(
  1036. handler,
  1037. "staging but no -incremental flag");
  1038. }
  1039. } else if (haveIncrementalFlag) {
  1040. spec.setStaging(true);
  1041. MessageUtil.info(handler, "-incremental forcing staging");
  1042. }
  1043. if (hasInvalidOptions(values, result)) {
  1044. return checkResult(result);
  1045. }
  1046. // set compiler in result
  1047. getFamily = CRSOPTIONS.ajccompilerOption.getFamily();
  1048. Option.Value compiler = values.firstInFamily(getFamily);
  1049. if (null != compiler) {
  1050. result.compilerName
  1051. = CRSOPTIONS.compilerClassName(compiler.option);
  1052. if (null == result.compilerName) {
  1053. result.failureReason =
  1054. "unable to get class name for " + compiler;
  1055. return checkResult(result);
  1056. }
  1057. }
  1058. String compilerName =
  1059. (null == result.compilerName
  1060. ? spec.compiler
  1061. : result.compilerName);
  1062. // check compiler semantics
  1063. if (hasCompilerSpecErrors(compilerName, values, result)) {
  1064. return checkResult(result);
  1065. }
  1066. // add toadd and finish result
  1067. ArrayList args = new ArrayList();
  1068. String[] rendered = values.render();
  1069. if (!LangUtil.isEmpty(rendered)) {
  1070. args.addAll(Arrays.asList(rendered));
  1071. }
  1072. // update bootclasspath
  1073. getFamily = CRSOPTIONS.crsSourceOption.getFamily();
  1074. Option.Value source = values.firstInFamily(getFamily);
  1075. if (null != source) {
  1076. String sourceVersion = source.unflatten()[1];
  1077. ArrayList toAdd = new ArrayList();
  1078. /*String err =*/
  1079. updateBootclasspathForSourceVersion(
  1080. sourceVersion,
  1081. spec.compiler,
  1082. toAdd);
  1083. args.addAll(toAdd);
  1084. }
  1085. result.commandOptions = args;
  1086. result.result = true;
  1087. return checkResult(result);
  1088. }
  1089. /**
  1090. * Ensure exit invariant:
  1091. * <code>result.result == (null == result.failureReason)
  1092. * == (null != result.commandOptions)</code>
  1093. * @param result the TestSetup to verify
  1094. * @return result
  1095. * @throws Error if invariant is not true
  1096. */
  1097. TestSetup checkResult(TestSetup result) {
  1098. String err = null;
  1099. if (null == result) {
  1100. err = "null result";
  1101. } else if (result.result != (null == result.failureReason)) {
  1102. err =
  1103. result.result
  1104. ? "expected no failure: " + result.failureReason
  1105. : "fail for no reason";
  1106. } else if (result.result != (null != result.commandOptions)) {
  1107. err =
  1108. result.result
  1109. ? "expected command options"
  1110. : "unexpected command options";
  1111. }
  1112. if (null != err) {
  1113. throw new Error(err);
  1114. }
  1115. return result;
  1116. }
  1117. boolean hasInvalidOptions(Values values, TestSetup result) {
  1118. // not supporting 1.0 options any more
  1119. for (Iterator iter = CRSOPTIONS.invalidOptions.iterator();
  1120. iter.hasNext();
  1121. ) {
  1122. Option option = (Option) iter.next();
  1123. if (null != values.firstOption(option)) {
  1124. result.failureReason =
  1125. "invalid option in harness: " + option;
  1126. return true;
  1127. }
  1128. }
  1129. return false;
  1130. }
  1131. boolean hasCompilerSpecErrors(
  1132. String compilerName,
  1133. Values values,
  1134. TestSetup result) {
  1135. /*
  1136. * Describe any semantic conflicts between options.
  1137. * This skips:
  1138. * - old 1.0 options, including lenient v. strict
  1139. * - old ajc options, include !incremental and usejavac w/o javac
  1140. * - invalid eclipse options (mostly ajc)
  1141. * @param compilerName the String name of the target compiler
  1142. * @return a String describing any conflicts, or null if none
  1143. */
  1144. if (!permitAnyCompiler
  1145. && (!(ReflectionFactory.ECLIPSE.equals(compilerName)
  1146. || ReflectionFactory.OLD_AJC.equals(compilerName)
  1147. || CRSOptions.AJDE_COMPILER.equals(compilerName)
  1148. || CRSOptions.AJCTASK_COMPILER.equals(compilerName)
  1149. || permitAnyCompiler
  1150. ))) {
  1151. //|| BUILDER_COMPILER.equals(compilerName))
  1152. result.failureReason =
  1153. "unrecognized compiler: " + compilerName;
  1154. return true;
  1155. }
  1156. // not supporting ajc right now
  1157. if (null
  1158. != values.firstOption(CRSOPTIONS.ajccompilerOption)) {
  1159. result.failureReason = "ajc not supported";
  1160. return true;
  1161. }
  1162. // not supporting 1.0 options any more
  1163. for (Iterator iter = CRSOPTIONS.ajc10Options.iterator();
  1164. iter.hasNext();
  1165. ) {
  1166. Option option = (Option) iter.next();
  1167. if (null != values.firstOption(option)) {
  1168. result.failureReason = "old ajc 1.0 option: " + option;
  1169. return true;
  1170. }
  1171. }
  1172. return false;
  1173. }
  1174. protected Values gatherValues(TestSetup result) {
  1175. final Spec spec = this;
  1176. // ---- local option values
  1177. final Values localValues;
  1178. final Options options = CRSOPTIONS.getOptions();
  1179. try {
  1180. String[] input = getOptionsArray();
  1181. // this handles reading options,
  1182. // flattening two-String options, etc.
  1183. localValues = options.acceptInput(input);
  1184. // all local values should be picked up
  1185. String err = Options.missedMatchError(input, localValues);
  1186. if (!LangUtil.isEmpty(err)) {
  1187. result.failureReason = err;
  1188. return null;
  1189. }
  1190. } catch (InvalidInputException e) {
  1191. result.failureReason = e.getFullMessage();
  1192. return null;
  1193. }
  1194. // ---- global option values
  1195. StringBuffer errs = new StringBuffer();
  1196. final Values globalValues =
  1197. spec.runtime.extractOptions(options, true, errs);
  1198. if (errs.length() > 0) {
  1199. result.failureReason = errs.toString();
  1200. return null;
  1201. }
  1202. final Values combined =
  1203. Values.wrapValues(
  1204. new Values[] { localValues, globalValues });
  1205. String err = combined.resolve();
  1206. if (null != err) {
  1207. result.failureReason = err;
  1208. return null;
  1209. }
  1210. return handleTestArgs(combined, result);
  1211. }
  1212. // final int len = globalValues.length() + localValues.length();
  1213. // final Option.Value[] combinedValues = new Option.Value[len];
  1214. // System.arraycopy(
  1215. // globalValues,
  1216. // 0,
  1217. // combinedValues,
  1218. // 0,
  1219. // globalValues.length());
  1220. // System.arraycopy(
  1221. // localValues,
  1222. // 0,
  1223. // combinedValues,
  1224. // globalValues.length(),
  1225. // localValues.length());
  1226. //
  1227. // result.compilerName = spec.compiler;
  1228. // if (0 < combinedValues.length) {
  1229. // // this handles option forcing, etc.
  1230. // String err = Options.resolve(combinedValues);
  1231. // if (null != err) {
  1232. // result.failureReason = err;
  1233. // return null;
  1234. // }
  1235. // if (!handleTestArgs(combinedValues, result)) {
  1236. // return null;
  1237. // }
  1238. // }
  1239. // return Values.wrapValues(combinedValues);
  1240. // }
  1241. /**
  1242. * This interprets and nullifies values for the test.
  1243. * @param values the Option.Value[] being processed
  1244. * @param result the TestSetup to modify
  1245. * @return false if error (caller should return), true otherwise
  1246. */
  1247. Values handleTestArgs(Values values, final TestSetup result) {
  1248. final Option.Family compilerFamily =
  1249. CRSOPTIONS.ajccompilerOption.getFamily();
  1250. Values.Selector selector = new Values.Selector() {
  1251. protected boolean accept(Option.Value value) {
  1252. if (null == value) {
  1253. return false;
  1254. }
  1255. Option option = value.option;
  1256. if (compilerFamily.sameFamily(option.getFamily())) {
  1257. if (value.prefix.isSet()) {
  1258. String compilerClass
  1259. = CRSOPTIONS.compilerClassName(option);
  1260. if (null == compilerClass) {
  1261. result.failureReason =
  1262. "unrecognized compiler: " + value;
  1263. throw Values.Selector.STOP;
  1264. }
  1265. if (!CRSOPTIONS.compilerIsLoadable(option)) {
  1266. result.failureReason =
  1267. "unable to load compiler: " + option;
  1268. throw Values.Selector.STOP;
  1269. }
  1270. result.compilerName = compilerClass;
  1271. }
  1272. return true;
  1273. } else if (
  1274. CRSOPTIONS.crsIgnoreWarnings.sameOptionIdentifier(
  1275. option)) {
  1276. result.ignoreWarnings = value.prefix.isSet();
  1277. result.ignoreWarningsSet = true;
  1278. return true;
  1279. }
  1280. return false;
  1281. }
  1282. };
  1283. return values.nullify(selector);
  1284. }
  1285. // /**
  1286. // * This interprets and nullifies values for the test.
  1287. // * @param values the Option.Value[] being processed
  1288. // * @param result the TestSetup to modify
  1289. // * @return false if error (caller should return), true otherwise
  1290. // */
  1291. // boolean handleTestArgs(Option.Value[] values, TestSetup result) {
  1292. // if (!LangUtil.isEmpty(values)) {
  1293. // for (int i = 0; i < values.length; i++) {
  1294. // Option.Value value = values[i];
  1295. // if (null == value) {
  1296. // continue;
  1297. // }
  1298. // Option option = value.option;
  1299. // if (option.sameOptionFamily(ECLIPSE_OPTION)) {
  1300. // if (!value.prefix.isSet()) {
  1301. // values[i] = null;
  1302. // continue;
  1303. // }
  1304. // String compilerClass =
  1305. // (String) COMPILER_OPTION_TO_CLASSNAME.get(
  1306. // option);
  1307. // if (null == compilerClass) {
  1308. // result.failureReason =
  1309. // "unrecognized compiler: " + value;
  1310. // return false;
  1311. // }
  1312. // result.compilerName = compilerClass;
  1313. // values[i] = null;
  1314. // } else if (
  1315. // option.sameOptionFamily(crsIgnoreWarnings)) {
  1316. // result.ignoreWarnings = value.prefix.isSet();
  1317. // result.ignoreWarningsSet = true;
  1318. // values[i] = null;
  1319. // }
  1320. // }
  1321. // }
  1322. // return true;
  1323. // }
  1324. // XXX need keys, cache...
  1325. /** @return index of global in argList, ignoring first char */
  1326. protected int indexOf(String global, ArrayList argList) {
  1327. int max = argList.size();
  1328. for (int i = 0; i < max; i++) {
  1329. if (global
  1330. .equals(((String) argList.get(i)).substring(1))) {
  1331. return i;
  1332. }
  1333. }
  1334. return -1;
  1335. }
  1336. /**
  1337. * Write this out as a compile element as defined in
  1338. * AjcSpecXmlReader.DOCTYPE.
  1339. * @see AjcSpecXmlReader#DOCTYPE
  1340. * @see IXmlWritable#writeXml(XMLWriter)
  1341. */
  1342. public void writeXml(XMLWriter out) {
  1343. out.startElement(xmlElementName, false);
  1344. if (!LangUtil.isEmpty(testSrcDirOffset)) {
  1345. out.printAttribute("dir", testSrcDirOffset);
  1346. }
  1347. super.writeAttributes(out);
  1348. if (!DEFAULT_COMPILER.equals(compiler)) {
  1349. out.printAttribute("compiler", compiler);
  1350. }
  1351. if (reuseCompiler) {
  1352. out.printAttribute("reuseCompiler", "true");
  1353. }
  1354. // test-only feature
  1355. // if (permitAnyCompiler) {
  1356. // out.printAttribute("permitAnyCompiler", "true");
  1357. // }
  1358. if (includeClassesDir) {
  1359. out.printAttribute("includeClassesDir", "true");
  1360. }
  1361. if (!LangUtil.isEmpty(argfiles)) {
  1362. out.printAttribute(
  1363. "argfiles",
  1364. XMLWriter.flattenFiles(argfiles));
  1365. }
  1366. if (!LangUtil.isEmpty(aspectpath)) {
  1367. out.printAttribute(
  1368. "aspectpath",
  1369. XMLWriter.flattenFiles(aspectpath));
  1370. }
  1371. if (!LangUtil.isEmpty(sourceroots)) {
  1372. out.printAttribute(
  1373. "sourceroots",
  1374. XMLWriter.flattenFiles(sourceroots));
  1375. }
  1376. if (!LangUtil.isEmpty(extdirs)) {
  1377. out.printAttribute(
  1378. "extdirs",
  1379. XMLWriter.flattenFiles(extdirs));
  1380. }
  1381. out.endAttributes();
  1382. if (!LangUtil.isEmpty(dirChanges)) {
  1383. DirChanges.Spec.writeXml(out, dirChanges);
  1384. }
  1385. SoftMessage.writeXml(out, getMessages());
  1386. out.endElement(xmlElementName);
  1387. }
  1388. /**
  1389. * Encapsulate the directives that can be set using
  1390. * global arguments supplied in {@link Spec.getOptions()}.
  1391. * This supports changing the compiler and ignoring warnings.
  1392. */
  1393. class TestSetup {
  1394. /** null unless overriding the compiler to be used */
  1395. String compilerName;
  1396. /**
  1397. * true if we should tell AjcMessageHandler whether
  1398. * to ignore warnings in its result evaluation
  1399. */
  1400. boolean ignoreWarningsSet;
  1401. /** if telling AjcMessageHandler, what we tell it */
  1402. boolean ignoreWarnings;
  1403. /** false if setup failed */
  1404. boolean result;
  1405. /** if setup failed, this has the reason why */
  1406. String failureReason;
  1407. /** beyond running test, also seek text in sources */
  1408. String seek;
  1409. /** if setup completed, this has the combined global/local options */
  1410. ArrayList commandOptions;
  1411. public Object clone() {
  1412. TestSetup testSetup = new TestSetup();
  1413. testSetup.compilerName = compilerName;
  1414. testSetup.ignoreWarnings = ignoreWarnings;
  1415. testSetup.ignoreWarningsSet = ignoreWarningsSet;
  1416. testSetup.result = result;
  1417. testSetup.failureReason = failureReason;
  1418. testSetup.seek = seek;
  1419. if (null != commandOptions) {
  1420. testSetup.commandOptions = new ArrayList();
  1421. testSetup.commandOptions.addAll(commandOptions);
  1422. }
  1423. return testSetup;
  1424. }
  1425. public String toString() {
  1426. return "TestSetup("
  1427. + (null == compilerName ? "" : compilerName + " ")
  1428. + (!ignoreWarningsSet
  1429. ? ""
  1430. : (ignoreWarnings ? "" : "do not ")
  1431. + "ignore warnings ")
  1432. + (result ? "" : "setup failed")
  1433. + ")";
  1434. }
  1435. }
  1436. /**
  1437. * Options-related stuff in the spec.
  1438. */
  1439. static class CRSOptions {
  1440. // static final String BUILDER_COMPILER =
  1441. // "org.aspectj.ajdt.internal.core.builder.Builder.Command";
  1442. static final String AJDE_COMPILER =
  1443. CompileCommand.class.getName();
  1444. static final String AJCTASK_COMPILER =
  1445. AjcTaskCompileCommand.class.getName();
  1446. private final Map compilerOptionToLoadable = new TreeMap();
  1447. /*
  1448. * The options field in a compiler test permits some arbitrary
  1449. * command-line options to be set. It does not permit things
  1450. * like classpath, aspectpath, files, etc. which are set
  1451. * using other fields in the test specification, so the options
  1452. * permitted are a subset of those permitted on the command-line.
  1453. *
  1454. * Global options specified on the harness command-line are
  1455. * adopted for the compiler command-line if they are permitted
  1456. * in the options field. That means we have to detect each
  1457. * permitted option, rather than just letting all through
  1458. * for the compiler.
  1459. *
  1460. * Conversely, some options are targeted not at the compiler,
  1461. * but at the test itself (e.g., to ignore warnings, or to
  1462. * select a compiler.
  1463. *
  1464. * The harness can run many compilers, and they differ in
  1465. * which options are permitted. You can specify a compiler
  1466. * as an option (e.g., -eclipse). So the set of constraints
  1467. * on the list of permitted options can differ from test to test.
  1468. *
  1469. * The following code sets up the lists of permitted options
  1470. * and breaks out subsets for different compiler-variant checks.
  1471. * Most options are created but not named, but some options
  1472. * are named to detect corresponding values for further
  1473. * processing. e.g., the compiler options are saved so
  1474. * we can do per-compiler option verification.
  1475. *
  1476. */
  1477. private final Options crsOptions;
  1478. private final Family compilerFamily;
  1479. private final Option crsIncrementalOption;
  1480. private final Option crsSourceOption;
  1481. // these are options handled/absorbed by CompilerRun
  1482. private final Option crsIgnoreWarnings;
  1483. private final Option eclipseOption;
  1484. private final Option buildercompilerOption;
  1485. private final Option ajdecompilerOption;
  1486. private final Option javacOption;
  1487. private final Option ajctaskcompilerOption;
  1488. private final Option ajccompilerOption;
  1489. private final Map compilerOptionToClassname;
  1490. private final Set compilerOptions;
  1491. // compiler verification - permit but flag ajc 1.0 options
  1492. private final List ajc10Options;
  1493. private final List invalidOptions;
  1494. private CRSOptions() {
  1495. crsOptions = new Options(true);
  1496. Option.Factory factory = new Option.Factory("CompilerRun");
  1497. // compiler options go in map
  1498. eclipseOption =
  1499. factory.create(
  1500. "eclipse",
  1501. "compiler",
  1502. Option.FORCE_PREFIXES,
  1503. false);
  1504. compilerFamily = eclipseOption.getFamily();
  1505. buildercompilerOption =
  1506. factory.create(
  1507. "builderCompiler",
  1508. "compiler",
  1509. Option.FORCE_PREFIXES,
  1510. false);
  1511. ajctaskcompilerOption =
  1512. factory.create(
  1513. "ajctaskCompiler",
  1514. "compiler",
  1515. Option.FORCE_PREFIXES,
  1516. false);
  1517. ajdecompilerOption =
  1518. factory.create(
  1519. "ajdeCompiler",
  1520. "compiler",
  1521. Option.FORCE_PREFIXES,
  1522. false);
  1523. ajccompilerOption =
  1524. factory.create(
  1525. "ajc",
  1526. "compiler",
  1527. Option.FORCE_PREFIXES,
  1528. false);
  1529. javacOption =
  1530. factory.create(
  1531. "javac",
  1532. "compiler",
  1533. Option.FORCE_PREFIXES,
  1534. false);
  1535. Map map = new TreeMap();
  1536. map.put(eclipseOption, ReflectionFactory.ECLIPSE);
  1537. //map.put(BUILDERCOMPILER_OPTION, BUILDER_COMPILER);
  1538. map.put(
  1539. ajctaskcompilerOption,
  1540. AJCTASK_COMPILER);
  1541. map.put(ajdecompilerOption, AJDE_COMPILER);
  1542. map.put(ajccompilerOption, ReflectionFactory.OLD_AJC);
  1543. //map.put(JAVAC_OPTION, "XXX javac option not supported");
  1544. compilerOptionToClassname =
  1545. Collections.unmodifiableMap(map);
  1546. compilerOptions =
  1547. Collections.unmodifiableSet(
  1548. compilerOptionToClassname.keySet());
  1549. // options not permitted in the harness
  1550. List list = new ArrayList();
  1551. list.add(factory.create("workingdir"));
  1552. list.add(factory.create("argfile"));
  1553. list.add(factory.create("sourceroots"));
  1554. list.add(factory.create("outjar"));
  1555. invalidOptions = Collections.unmodifiableList(list);
  1556. // other options added directly
  1557. crsIncrementalOption = factory.create("incremental");
  1558. crsIgnoreWarnings = factory.create("ignoreWarnings");
  1559. crsSourceOption =
  1560. factory
  1561. .create(
  1562. "source",
  1563. "source",
  1564. Option.FORCE_PREFIXES,
  1565. false,
  1566. new String[][] { new String[] { "1.3", "1.4", "1.5" }
  1567. });
  1568. // ajc 1.0 options
  1569. // workingdir above in invalid options
  1570. list = new ArrayList();
  1571. list.add(factory.create("usejavac"));
  1572. list.add(factory.create("preprocess"));
  1573. list.add(factory.create("nocomment"));
  1574. list.add(factory.create("porting"));
  1575. list.add(factory.create("XOcodeSize"));
  1576. list.add(factory.create("XTargetNearSource"));
  1577. list.add(factory.create("XaddSafePrefix"));
  1578. list.add(
  1579. factory.create(
  1580. "lenient",
  1581. "lenient",
  1582. Option.FORCE_PREFIXES,
  1583. false));
  1584. list.add(
  1585. factory.create(
  1586. "strict",
  1587. "lenient",
  1588. Option.FORCE_PREFIXES,
  1589. false));
  1590. ajc10Options = Collections.unmodifiableList(list);
  1591. // -warn:.. and -g/-g:.. are not exclusive
  1592. if (!(factory.setupFamily("debug", true)
  1593. && factory.setupFamily("warning", true))) {
  1594. System.err.println("CompilerRun debug/warning fail!");
  1595. }
  1596. Option[] options =
  1597. new Option[] {
  1598. crsIncrementalOption,
  1599. crsIgnoreWarnings,
  1600. crsSourceOption,
  1601. factory.create(
  1602. "Xlint",
  1603. "XLint",
  1604. Option.FORCE_PREFIXES,
  1605. true),
  1606. factory.create("verbose"),
  1607. factory.create("emacssym"),
  1608. factory.create("referenceInfo"),
  1609. factory.create("nowarn"),
  1610. factory.create("deprecation"),
  1611. factory.create("noImportError"),
  1612. factory.create("proceedOnError"),
  1613. factory.create("preserveAllLocals"),
  1614. factory.create(
  1615. "warn",
  1616. "warning",
  1617. Option.STANDARD_PREFIXES,
  1618. true),
  1619. factory.create(
  1620. "g",
  1621. "debug",
  1622. Option.STANDARD_PREFIXES,
  1623. false),
  1624. factory.create(
  1625. "g:",
  1626. "debug",
  1627. Option.STANDARD_PREFIXES,
  1628. true),
  1629. factory.create(
  1630. "1.3",
  1631. "compliance",
  1632. Option.FORCE_PREFIXES,
  1633. false),
  1634. factory.create(
  1635. "1.4",
  1636. "compliance",
  1637. Option.FORCE_PREFIXES,
  1638. false),
  1639. factory.create(
  1640. "1.5",
  1641. "compliance",
  1642. Option.FORCE_PREFIXES,
  1643. false),
  1644. factory
  1645. .create(
  1646. "target",
  1647. "target",
  1648. Option.FORCE_PREFIXES,
  1649. false,
  1650. new String[][] { new String[] {
  1651. "1.1",
  1652. "1.2",
  1653. "1.3",
  1654. "1.4",
  1655. "1.5" }}),
  1656. factory.create("XnoInline"),
  1657. factory.create("XterminateAfterCompilation"),
  1658. factory.create("Xreweavable"),
  1659. factory.create("XnotReweavable"),
  1660. factory.create("XserializableAspects")
  1661. };
  1662. // among options not permitted: extdirs...
  1663. for (int i = 0; i < options.length; i++) {
  1664. crsOptions.addOption(options[i]);
  1665. }
  1666. for (Iterator iter = compilerOptions.iterator();
  1667. iter.hasNext();
  1668. ) {
  1669. crsOptions.addOption((Option) iter.next());
  1670. }
  1671. // these are recognized but records with them are skipped
  1672. for (Iterator iter = ajc10Options.iterator();
  1673. iter.hasNext();
  1674. ) {
  1675. crsOptions.addOption((Option) iter.next());
  1676. }
  1677. crsOptions.freeze();
  1678. }
  1679. Options getOptions() {
  1680. return crsOptions;
  1681. }
  1682. /**
  1683. * @return unmodifiable Set of options sharing the
  1684. * family "compiler".
  1685. */
  1686. Set compilerOptions() {
  1687. return compilerOptions;
  1688. }
  1689. /**
  1690. * @param option the compiler Option to get name for
  1691. * @return null if option is null or not a compiler option,
  1692. * or the fully-qualified classname of the ICommand
  1693. * implementing the compiler.
  1694. */
  1695. String compilerClassName(Option option) {
  1696. if ((null == option)
  1697. || (!compilerFamily.sameFamily(option.getFamily()))) {
  1698. return null;
  1699. }
  1700. return (String) compilerOptionToClassname.get(option);
  1701. }
  1702. /**
  1703. * Check that the compiler class associated with a compiler
  1704. * option can be loaded. This check only happens once;
  1705. * the result is cached (by compilerOption key) for later calls.
  1706. * @param compilerOption the Option (family compiler) to check
  1707. * @return true if compiler class for this option can be loaded
  1708. */
  1709. boolean compilerIsLoadable(Option compilerOption) {
  1710. LangUtil.throwIaxIfNull(compilerOption, "compilerName");
  1711. synchronized (compilerOptionToLoadable) {
  1712. Boolean result =
  1713. (Boolean) compilerOptionToLoadable.get(
  1714. compilerOption);
  1715. if (null == result) {
  1716. MessageHandler sink = new MessageHandler();
  1717. String compilerClassname =
  1718. (String) compilerOptionToClassname.get(
  1719. compilerOption);
  1720. if (null == compilerClassname) {
  1721. result = Boolean.FALSE;
  1722. } else {
  1723. ICommand c =
  1724. ReflectionFactory.makeCommand(
  1725. compilerClassname,
  1726. sink);
  1727. if ((null == c)
  1728. || sink.hasAnyMessage(
  1729. IMessage.ERROR,
  1730. true)) {
  1731. result = Boolean.FALSE;
  1732. } else {
  1733. result = Boolean.TRUE;
  1734. }
  1735. }
  1736. compilerOptionToLoadable.put(
  1737. compilerOption,
  1738. result);
  1739. }
  1740. return result.booleanValue();
  1741. }
  1742. }
  1743. } // CompilerRun.Spec.CRSOptions
  1744. } // CompilerRun.Spec
  1745. } // CompilerRun