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.

BcelWeaver.java 70KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756
  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 v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * Alexandre Vasseur support for @AJ aspects
  12. * ******************************************************************/
  13. package org.aspectj.weaver.bcel;
  14. import java.io.ByteArrayInputStream;
  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.InputStream;
  21. import java.io.OutputStream;
  22. import java.util.ArrayList;
  23. import java.util.Collection;
  24. import java.util.Collections;
  25. import java.util.Comparator;
  26. import java.util.Enumeration;
  27. import java.util.HashMap;
  28. import java.util.HashSet;
  29. import java.util.Iterator;
  30. import java.util.List;
  31. import java.util.Map;
  32. import java.util.Set;
  33. import java.util.jar.Attributes;
  34. import java.util.jar.JarEntry;
  35. import java.util.jar.JarFile;
  36. import java.util.jar.Manifest;
  37. import java.util.jar.Attributes.Name;
  38. import java.util.zip.ZipEntry;
  39. import java.util.zip.ZipInputStream;
  40. import java.util.zip.ZipOutputStream;
  41. import org.aspectj.apache.bcel.classfile.ClassParser;
  42. import org.aspectj.apache.bcel.classfile.JavaClass;
  43. import org.aspectj.asm.AsmManager;
  44. import org.aspectj.bridge.IMessage;
  45. import org.aspectj.bridge.IProgressListener;
  46. import org.aspectj.bridge.ISourceLocation;
  47. import org.aspectj.bridge.Message;
  48. import org.aspectj.bridge.MessageUtil;
  49. import org.aspectj.bridge.SourceLocation;
  50. import org.aspectj.bridge.WeaveMessage;
  51. import org.aspectj.bridge.context.CompilationAndWeavingContext;
  52. import org.aspectj.bridge.context.ContextToken;
  53. import org.aspectj.util.FileUtil;
  54. import org.aspectj.util.FuzzyBoolean;
  55. import org.aspectj.weaver.Advice;
  56. import org.aspectj.weaver.AnnotationOnTypeMunger;
  57. import org.aspectj.weaver.AnnotationX;
  58. import org.aspectj.weaver.AsmRelationshipProvider;
  59. import org.aspectj.weaver.BCException;
  60. import org.aspectj.weaver.ConcreteTypeMunger;
  61. import org.aspectj.weaver.CrosscuttingMembersSet;
  62. import org.aspectj.weaver.IClassFileProvider;
  63. import org.aspectj.weaver.IWeaveRequestor;
  64. import org.aspectj.weaver.IWeaver;
  65. import org.aspectj.weaver.NewParentTypeMunger;
  66. import org.aspectj.weaver.ReferenceType;
  67. import org.aspectj.weaver.ReferenceTypeDelegate;
  68. import org.aspectj.weaver.ResolvedTypeMunger;
  69. import org.aspectj.weaver.ResolvedType;
  70. import org.aspectj.weaver.Shadow;
  71. import org.aspectj.weaver.ShadowMunger;
  72. import org.aspectj.weaver.UnresolvedType;
  73. import org.aspectj.weaver.WeaverMessages;
  74. import org.aspectj.weaver.WeaverMetrics;
  75. import org.aspectj.weaver.WeaverStateInfo;
  76. import org.aspectj.weaver.World;
  77. import org.aspectj.weaver.patterns.AndPointcut;
  78. import org.aspectj.weaver.patterns.BindingAnnotationTypePattern;
  79. import org.aspectj.weaver.patterns.BindingTypePattern;
  80. import org.aspectj.weaver.patterns.CflowPointcut;
  81. import org.aspectj.weaver.patterns.ConcreteCflowPointcut;
  82. import org.aspectj.weaver.patterns.DeclareAnnotation;
  83. import org.aspectj.weaver.patterns.DeclareParents;
  84. import org.aspectj.weaver.patterns.FastMatchInfo;
  85. import org.aspectj.weaver.patterns.IfPointcut;
  86. import org.aspectj.weaver.patterns.KindedPointcut;
  87. import org.aspectj.weaver.patterns.NameBindingPointcut;
  88. import org.aspectj.weaver.patterns.NotPointcut;
  89. import org.aspectj.weaver.patterns.OrPointcut;
  90. import org.aspectj.weaver.patterns.Pointcut;
  91. import org.aspectj.weaver.patterns.PointcutRewriter;
  92. import org.aspectj.weaver.patterns.WithinPointcut;
  93. import org.aspectj.weaver.tools.Trace;
  94. import org.aspectj.weaver.tools.TraceFactory;
  95. public class BcelWeaver implements IWeaver {
  96. private BcelWorld world;
  97. private CrosscuttingMembersSet xcutSet;
  98. private IProgressListener progressListener = null;
  99. private double progressMade;
  100. private double progressPerClassFile;
  101. private boolean inReweavableMode = false;
  102. private static Trace trace = TraceFactory.getTraceFactory().getTrace(BcelWeaver.class);
  103. public BcelWeaver(BcelWorld world) {
  104. super();
  105. if (trace.isTraceEnabled()) trace.enter("<init>",this,world);
  106. WeaverMetrics.reset();
  107. this.world = world;
  108. this.xcutSet = world.getCrosscuttingMembersSet();
  109. if (trace.isTraceEnabled()) trace.exit("<init>");
  110. }
  111. public BcelWeaver() {
  112. this(new BcelWorld());
  113. }
  114. // ---- fields
  115. // private Map sourceJavaClasses = new HashMap(); /* String -> UnwovenClassFile */
  116. private List addedClasses = new ArrayList(); /* List<UnovenClassFile> */
  117. private List deletedTypenames = new ArrayList(); /* List<String> */
  118. // private Map resources = new HashMap(); /* String -> UnwovenClassFile */
  119. private Manifest manifest = null;
  120. private boolean needToReweaveWorld = false;
  121. private boolean isBatchWeave = true;
  122. private List shadowMungerList = null; // setup by prepareForWeave
  123. private List typeMungerList = null; // setup by prepareForWeave
  124. private List lateTypeMungerList = null; // setup by prepareForWeave
  125. private List declareParentsList = null; // setup by prepareForWeave
  126. private ZipOutputStream zipOutputStream;
  127. // ----
  128. // only called for testing
  129. public void setShadowMungers(List l) {
  130. shadowMungerList = l;
  131. }
  132. /**
  133. * Add the given aspect to the weaver.
  134. * The type is resolved to support DOT for static inner classes as well as DOLLAR
  135. *
  136. * @param aspectName
  137. * @return aspect
  138. */
  139. public ResolvedType addLibraryAspect(String aspectName) {
  140. if (trace.isTraceEnabled()) trace.enter("addLibraryAspect",this,aspectName);
  141. // 1 - resolve as is
  142. UnresolvedType unresolvedT = UnresolvedType.forName(aspectName);
  143. unresolvedT.setNeedsModifiableDelegate(true);
  144. ResolvedType type = world.resolve(unresolvedT, true);
  145. if (type.isMissing()) {
  146. // fallback on inner class lookup mechanism
  147. String fixedName = aspectName;
  148. int hasDot = fixedName.lastIndexOf('.');
  149. while (hasDot > 0) {
  150. //System.out.println("BcelWeaver.addLibraryAspect " + fixedName);
  151. char[] fixedNameChars = fixedName.toCharArray();
  152. fixedNameChars[hasDot] = '$';
  153. fixedName = new String(fixedNameChars);
  154. hasDot = fixedName.lastIndexOf('.');
  155. UnresolvedType ut = UnresolvedType.forName(fixedName);
  156. ut.setNeedsModifiableDelegate(true);
  157. type = world.resolve(ut, true);
  158. if (!type.isMissing()) {
  159. break;
  160. }
  161. }
  162. }
  163. //System.out.println("type: " + type + " for " + aspectName);
  164. if (type.isAspect()) {
  165. // Bug 119657 ensure we use the unwoven aspect
  166. WeaverStateInfo wsi = type.getWeaverState();
  167. if (wsi != null && wsi.isReweavable()) {
  168. BcelObjectType classType = getClassType(type.getName());
  169. JavaClass wovenJavaClass = classType.getJavaClass();
  170. JavaClass unwovenJavaClass = Utility.makeJavaClass(wovenJavaClass.getFileName(),
  171. wsi.getUnwovenClassFileData(wovenJavaClass.getBytes()));
  172. world.storeClass(unwovenJavaClass);
  173. classType.setJavaClass(unwovenJavaClass);
  174. // classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData(classType.getJavaClass().getBytes())));
  175. }
  176. //TODO AV - happens to reach that a lot of time: for each type flagged reweavable X for each aspect in the weaverstate
  177. //=> mainly for nothing for LTW - pbly for something in incremental build...
  178. xcutSet.addOrReplaceAspect(type);
  179. if (trace.isTraceEnabled()) trace.exit("addLibraryAspect",type);
  180. return type;
  181. } else {
  182. // FIXME AV - better warning upon no such aspect from aop.xml
  183. RuntimeException ex = new RuntimeException("Cannot register non aspect: " + type.getName() + " , " + aspectName);
  184. if (trace.isTraceEnabled()) trace.exit("addLibraryAspect",ex);
  185. throw ex;
  186. }
  187. }
  188. /**
  189. *
  190. * @param inFile File path to class directory or zip/jar class archive
  191. * @throws IOException
  192. */
  193. public void addLibraryJarFile(File inFile) throws IOException {
  194. List addedAspects = null;
  195. if (inFile.isDirectory()) {
  196. addedAspects = addAspectsFromDirectory(inFile);
  197. } else {
  198. addedAspects = addAspectsFromJarFile(inFile);
  199. }
  200. for (Iterator i = addedAspects.iterator(); i.hasNext();) {
  201. ResolvedType aspectX = (ResolvedType) i.next();
  202. xcutSet.addOrReplaceAspect(aspectX);
  203. }
  204. }
  205. private List addAspectsFromJarFile(File inFile) throws FileNotFoundException, IOException {
  206. ZipInputStream inStream = new ZipInputStream(new FileInputStream(inFile)); //??? buffered
  207. List addedAspects = new ArrayList();
  208. while (true) {
  209. ZipEntry entry = inStream.getNextEntry();
  210. if (entry == null) break;
  211. if (entry.isDirectory() || !entry.getName().endsWith(".class")) {
  212. continue;
  213. }
  214. // FIXME ASC performance? of this alternative soln.
  215. ClassParser parser = new ClassParser(new ByteArrayInputStream(FileUtil.readAsByteArray(inStream)), entry.getName());
  216. JavaClass jc = parser.parse();
  217. inStream.closeEntry();
  218. ResolvedType type = world.addSourceObjectType(jc).getResolvedTypeX();
  219. type.setBinaryPath(inFile.getAbsolutePath());
  220. if (type.isAspect()) {
  221. addedAspects.add(type);
  222. }
  223. }
  224. inStream.close();
  225. return addedAspects;
  226. }
  227. private List addAspectsFromDirectory(File dir) throws FileNotFoundException, IOException{
  228. List addedAspects = new ArrayList();
  229. File[] classFiles = FileUtil.listFiles(dir,new FileFilter(){
  230. public boolean accept(File pathname) {
  231. return pathname.getName().endsWith(".class");
  232. }
  233. });
  234. for (int i = 0; i < classFiles.length; i++) {
  235. FileInputStream fis = new FileInputStream(classFiles[i]);
  236. byte[] bytes = FileUtil.readAsByteArray(fis);
  237. addIfAspect(bytes,classFiles[i].getAbsolutePath(),addedAspects);
  238. }
  239. return addedAspects;
  240. }
  241. private void addIfAspect(byte[] bytes, String name, List toList) throws IOException {
  242. ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes),name);
  243. JavaClass jc = parser.parse();
  244. ResolvedType type = world.addSourceObjectType(jc).getResolvedTypeX();
  245. String typeName = type.getName().replace('.', File.separatorChar);
  246. int end = name.indexOf(typeName);
  247. String binaryPath = name.substring(0,end-1);
  248. type.setBinaryPath(binaryPath);
  249. if (type.isAspect()) {
  250. toList.add(type);
  251. }
  252. }
  253. // // The ANT copy task should be used to copy resources across.
  254. // private final static boolean CopyResourcesFromInpathDirectoriesToOutput=false;
  255. /**
  256. * Add any .class files in the directory to the outdir. Anything other than .class files in
  257. * the directory (or its subdirectories) are considered resources and are also copied.
  258. *
  259. */
  260. public List addDirectoryContents(File inFile,File outDir) throws IOException {
  261. List addedClassFiles = new ArrayList();
  262. // Get a list of all files (i.e. everything that isnt a directory)
  263. File[] files = FileUtil.listFiles(inFile,new FileFilter() {
  264. public boolean accept(File f) {
  265. boolean accept = !f.isDirectory();
  266. return accept;
  267. }
  268. });
  269. // For each file, add it either as a real .class file or as a resource
  270. for (int i = 0; i < files.length; i++) {
  271. addedClassFiles.add(addClassFile(files[i],inFile,outDir));
  272. }
  273. return addedClassFiles;
  274. }
  275. /** Adds all class files in the jar
  276. */
  277. public List addJarFile(File inFile, File outDir, boolean canBeDirectory){
  278. // System.err.println("? addJarFile(" + inFile + ", " + outDir + ")");
  279. List addedClassFiles = new ArrayList();
  280. needToReweaveWorld = true;
  281. JarFile inJar = null;
  282. try {
  283. // Is this a directory we are looking at?
  284. if (inFile.isDirectory() && canBeDirectory) {
  285. addedClassFiles.addAll(addDirectoryContents(inFile,outDir));
  286. } else {
  287. inJar = new JarFile(inFile);
  288. addManifest(inJar.getManifest());
  289. Enumeration entries = inJar.entries();
  290. while (entries.hasMoreElements()) {
  291. JarEntry entry = (JarEntry)entries.nextElement();
  292. InputStream inStream = inJar.getInputStream(entry);
  293. byte[] bytes = FileUtil.readAsByteArray(inStream);
  294. String filename = entry.getName();
  295. // System.out.println("? addJarFile() filename='" + filename + "'");
  296. UnwovenClassFile classFile = new UnwovenClassFile(new File(outDir, filename).getAbsolutePath(), bytes);
  297. if (filename.endsWith(".class")) {
  298. this.addClassFile(classFile);
  299. addedClassFiles.add(classFile);
  300. }
  301. // else if (!entry.isDirectory()) {
  302. //
  303. // /* bug-44190 Copy meta-data */
  304. // addResource(filename,classFile);
  305. // }
  306. inStream.close();
  307. }
  308. inJar.close();
  309. }
  310. } catch (FileNotFoundException ex) {
  311. IMessage message = new Message(
  312. "Could not find input jar file " + inFile.getPath() + ", ignoring",
  313. new SourceLocation(inFile,0),
  314. false);
  315. world.getMessageHandler().handleMessage(message);
  316. } catch (IOException ex) {
  317. IMessage message = new Message(
  318. "Could not read input jar file " + inFile.getPath() + "(" + ex.getMessage() + ")",
  319. new SourceLocation(inFile,0),
  320. true);
  321. world.getMessageHandler().handleMessage(message);
  322. } finally {
  323. if (inJar != null) {
  324. try {inJar.close();}
  325. catch (IOException ex) {
  326. IMessage message = new Message(
  327. "Could not close input jar file " + inFile.getPath() + "(" + ex.getMessage() + ")",
  328. new SourceLocation(inFile,0),
  329. true);
  330. world.getMessageHandler().handleMessage(message);
  331. }
  332. }
  333. }
  334. return addedClassFiles;
  335. }
  336. // public void addResource(String name, File inPath, File outDir) throws IOException {
  337. //
  338. // /* Eliminate CVS files. Relative paths use "/" */
  339. // if (!name.startsWith("CVS/") && (-1 == name.indexOf("/CVS/")) && !name.endsWith("/CVS")) {
  340. //// System.err.println("? addResource('" + name + "')");
  341. //// BufferedInputStream inStream = new BufferedInputStream(new FileInputStream(inPath));
  342. //// byte[] bytes = new byte[(int)inPath.length()];
  343. //// inStream.read(bytes);
  344. //// inStream.close();
  345. // byte[] bytes = FileUtil.readAsByteArray(inPath);
  346. // UnwovenClassFile resourceFile = new UnwovenClassFile(new File(outDir, name).getAbsolutePath(), bytes);
  347. // addResource(name,resourceFile);
  348. // }
  349. // }
  350. public boolean needToReweaveWorld() {
  351. return needToReweaveWorld;
  352. }
  353. /** Should be addOrReplace
  354. */
  355. public void addClassFile(UnwovenClassFile classFile) {
  356. addedClasses.add(classFile);
  357. // if (null != sourceJavaClasses.put(classFile.getClassName(), classFile)) {
  358. //// throw new RuntimeException(classFile.getClassName());
  359. // }
  360. world.addSourceObjectType(classFile.getJavaClass());
  361. }
  362. public UnwovenClassFile addClassFile(File classFile, File inPathDir, File outDir) throws IOException {
  363. FileInputStream fis = new FileInputStream(classFile);
  364. byte[] bytes = FileUtil.readAsByteArray(fis);
  365. // String relativePath = files[i].getPath();
  366. // ASSERT: files[i].getAbsolutePath().startsWith(inFile.getAbsolutePath()
  367. // or we are in trouble...
  368. String filename = classFile.getAbsolutePath().substring(
  369. inPathDir.getAbsolutePath().length()+1);
  370. UnwovenClassFile ucf = new UnwovenClassFile(new File(outDir,filename).getAbsolutePath(),bytes);
  371. if (filename.endsWith(".class")) {
  372. // System.err.println("BCELWeaver: processing class from input directory "+classFile);
  373. this.addClassFile(ucf);
  374. }
  375. fis.close();
  376. return ucf;
  377. }
  378. public void deleteClassFile(String typename) {
  379. deletedTypenames.add(typename);
  380. // sourceJavaClasses.remove(typename);
  381. world.deleteSourceObjectType(UnresolvedType.forName(typename));
  382. }
  383. // public void addResource (String name, UnwovenClassFile resourceFile) {
  384. // /* bug-44190 Change error to warning and copy first resource */
  385. // if (!resources.containsKey(name)) {
  386. // resources.put(name, resourceFile);
  387. // }
  388. // else {
  389. // world.showMessage(IMessage.WARNING, "duplicate resource: '" + name + "'",
  390. // null, null);
  391. // }
  392. // }
  393. // ---- weave preparation
  394. public void setIsBatchWeave(boolean b) {
  395. isBatchWeave=b;
  396. }
  397. public void prepareForWeave() {
  398. if (trace.isTraceEnabled()) trace.enter("prepareForWeave",this);
  399. needToReweaveWorld = xcutSet.hasChangedSinceLastReset();
  400. CflowPointcut.clearCaches();
  401. // update mungers
  402. for (Iterator i = addedClasses.iterator(); i.hasNext(); ) {
  403. UnwovenClassFile jc = (UnwovenClassFile)i.next();
  404. String name = jc.getClassName();
  405. ResolvedType type = world.resolve(name);
  406. //System.err.println("added: " + type + " aspect? " + type.isAspect());
  407. if (type.isAspect()) {
  408. needToReweaveWorld |= xcutSet.addOrReplaceAspect(type);
  409. }
  410. }
  411. for (Iterator i = deletedTypenames.iterator(); i.hasNext(); ) {
  412. String name = (String)i.next();
  413. if (xcutSet.deleteAspect(UnresolvedType.forName(name))) needToReweaveWorld = true;
  414. }
  415. shadowMungerList = xcutSet.getShadowMungers();
  416. // world.debug("shadow mungers=" + shadowMungerList);
  417. rewritePointcuts(shadowMungerList);
  418. // Sometimes an error occurs during rewriting pointcuts (for example, if ambiguous bindings
  419. // are detected) - we ought to fail the prepare when this happens because continuing with
  420. // inconsistent pointcuts could lead to problems
  421. typeMungerList = xcutSet.getTypeMungers();
  422. lateTypeMungerList = xcutSet.getLateTypeMungers();
  423. declareParentsList = xcutSet.getDeclareParents();
  424. // The ordering here used to be based on a string compare on toString() for the two mungers -
  425. // that breaks for the @AJ style where advice names aren't programmatically generated. So we
  426. // have changed the sorting to be based on source location in the file - this is reliable, in
  427. // the case of source locations missing, we assume they are 'sorted' - i.e. the order in
  428. // which they were added to the collection is correct, this enables the @AJ stuff to work properly.
  429. // When @AJ processing starts filling in source locations for mungers, this code may need
  430. // a bit of alteration...
  431. Collections.sort(
  432. shadowMungerList,
  433. new Comparator() {
  434. public int compare(Object o1, Object o2) {
  435. ShadowMunger sm1 = (ShadowMunger)o1;
  436. ShadowMunger sm2 = (ShadowMunger)o2;
  437. if (sm1.getSourceLocation()==null) return (sm2.getSourceLocation()==null?0:1);
  438. if (sm2.getSourceLocation()==null) return -1;
  439. return (sm2.getSourceLocation().getOffset()-sm1.getSourceLocation().getOffset());
  440. }
  441. });
  442. if (inReweavableMode)
  443. world.showMessage(IMessage.INFO,
  444. WeaverMessages.format(WeaverMessages.REWEAVABLE_MODE),
  445. null, null);
  446. if (trace.isTraceEnabled()) trace.exit("prepareForWeave");
  447. }
  448. /*
  449. * Rewrite all of the pointcuts in the world into their most efficient
  450. * form for subsequent matching. Also ensure that if pc1.equals(pc2)
  451. * then pc1 == pc2 (for non-binding pcds) by making references all
  452. * point to the same instance.
  453. * Since pointcuts remember their match decision on the last shadow,
  454. * this makes matching faster when many pointcuts share common elements,
  455. * or even when one single pointcut has one common element (which can
  456. * be a side-effect of DNF rewriting).
  457. */
  458. private void rewritePointcuts(List/*ShadowMunger*/ shadowMungers) {
  459. PointcutRewriter rewriter = new PointcutRewriter();
  460. for (Iterator iter = shadowMungers.iterator(); iter.hasNext();) {
  461. ShadowMunger munger = (ShadowMunger) iter.next();
  462. Pointcut p = munger.getPointcut();
  463. Pointcut newP = rewriter.rewrite(p);
  464. // validateBindings now whilst we still have around the pointcut
  465. // that resembles what the user actually wrote in their program
  466. // text.
  467. if (munger instanceof Advice) {
  468. Advice advice = (Advice) munger;
  469. if (advice.getSignature() != null) {
  470. final int numFormals;
  471. final String names[];
  472. // If the advice is being concretized in a @AJ aspect *and* the advice was declared in
  473. // an @AJ aspect (it could have been inherited from a code style aspect) then
  474. // evaluate the alternative set of formals. pr125699
  475. if (advice.getConcreteAspect().isAnnotationStyleAspect()
  476. && advice.getDeclaringAspect()!=null
  477. && advice.getDeclaringAspect().resolve(world).isAnnotationStyleAspect()) {
  478. numFormals = advice.getBaseParameterCount();
  479. int numArgs = advice.getSignature().getParameterTypes().length;
  480. if (numFormals > 0) {
  481. names = advice.getSignature().getParameterNames(world);
  482. validateBindings(newP,p,numArgs,names);
  483. }
  484. } else {
  485. numFormals = advice.getBaseParameterCount();
  486. if (numFormals > 0) {
  487. names = advice.getBaseParameterNames(world);
  488. validateBindings(newP,p,numFormals,names);
  489. }
  490. }
  491. }
  492. }
  493. munger.setPointcut(newP);
  494. }
  495. // now that we have optimized individual pointcuts, optimize
  496. // across the set of pointcuts....
  497. // Use a map from key based on pc equality, to value based on
  498. // pc identity.
  499. Map/*<Pointcut,Pointcut>*/ pcMap = new HashMap();
  500. for (Iterator iter = shadowMungers.iterator(); iter.hasNext();) {
  501. ShadowMunger munger = (ShadowMunger) iter.next();
  502. Pointcut p = munger.getPointcut();
  503. munger.setPointcut(shareEntriesFromMap(p,pcMap));
  504. }
  505. }
  506. private Pointcut shareEntriesFromMap(Pointcut p,Map pcMap) {
  507. // some things cant be shared...
  508. if (p instanceof NameBindingPointcut) return p;
  509. if (p instanceof IfPointcut) return p;
  510. if (p instanceof ConcreteCflowPointcut) return p;
  511. if (p instanceof AndPointcut) {
  512. AndPointcut apc = (AndPointcut) p;
  513. Pointcut left = shareEntriesFromMap(apc.getLeft(),pcMap);
  514. Pointcut right = shareEntriesFromMap(apc.getRight(),pcMap);
  515. return new AndPointcut(left,right);
  516. } else if (p instanceof OrPointcut) {
  517. OrPointcut opc = (OrPointcut) p;
  518. Pointcut left = shareEntriesFromMap(opc.getLeft(),pcMap);
  519. Pointcut right = shareEntriesFromMap(opc.getRight(),pcMap);
  520. return new OrPointcut(left,right);
  521. } else if (p instanceof NotPointcut) {
  522. NotPointcut npc = (NotPointcut) p;
  523. Pointcut not = shareEntriesFromMap(npc.getNegatedPointcut(),pcMap);
  524. return new NotPointcut(not);
  525. } else {
  526. // primitive pcd
  527. if (pcMap.containsKey(p)) { // based on equality
  528. return (Pointcut) pcMap.get(p); // same instance (identity)
  529. } else {
  530. pcMap.put(p,p);
  531. return p;
  532. }
  533. }
  534. }
  535. // userPointcut is the pointcut that the user wrote in the program text.
  536. // dnfPointcut is the same pointcut rewritten in DNF
  537. // numFormals is the number of formal parameters in the pointcut
  538. // if numFormals > 0 then every branch of a disjunction must bind each formal once and only once.
  539. // in addition, the left and right branches of a disjunction must hold on join point kinds in
  540. // common.
  541. private void validateBindings(Pointcut dnfPointcut, Pointcut userPointcut, int numFormals, String[] names) {
  542. if (numFormals == 0) return; // nothing to check
  543. if (dnfPointcut.couldMatchKinds()==Shadow.NO_SHADOW_KINDS_BITS) return; // cant have problems if you dont match!
  544. if (dnfPointcut instanceof OrPointcut) {
  545. OrPointcut orBasedDNFPointcut = (OrPointcut) dnfPointcut;
  546. Pointcut[] leftBindings = new Pointcut[numFormals];
  547. Pointcut[] rightBindings = new Pointcut[numFormals];
  548. validateOrBranch(orBasedDNFPointcut,userPointcut,numFormals,names,leftBindings,rightBindings);
  549. } else {
  550. Pointcut[] bindings = new Pointcut[numFormals];
  551. validateSingleBranch(dnfPointcut, userPointcut, numFormals, names,bindings);
  552. }
  553. }
  554. private void validateOrBranch(OrPointcut pc, Pointcut userPointcut, int numFormals,
  555. String[] names, Pointcut[] leftBindings, Pointcut[] rightBindings) {
  556. Pointcut left = pc.getLeft();
  557. Pointcut right = pc.getRight();
  558. if (left instanceof OrPointcut) {
  559. Pointcut[] newRightBindings = new Pointcut[numFormals];
  560. validateOrBranch((OrPointcut)left,userPointcut,numFormals,names,leftBindings,newRightBindings);
  561. } else {
  562. if (left.couldMatchKinds()!=Shadow.NO_SHADOW_KINDS_BITS)
  563. validateSingleBranch(left, userPointcut, numFormals, names, leftBindings);
  564. }
  565. if (right instanceof OrPointcut) {
  566. Pointcut[] newLeftBindings = new Pointcut[numFormals];
  567. validateOrBranch((OrPointcut)right,userPointcut,numFormals,names,newLeftBindings,rightBindings);
  568. } else {
  569. if (right.couldMatchKinds()!=Shadow.NO_SHADOW_KINDS_BITS)
  570. validateSingleBranch(right, userPointcut, numFormals, names, rightBindings);
  571. }
  572. int kindsInCommon = left.couldMatchKinds() & right.couldMatchKinds();
  573. if (kindsInCommon!=Shadow.NO_SHADOW_KINDS_BITS && couldEverMatchSameJoinPoints(left,right)) {
  574. // we know that every branch binds every formal, so there is no ambiguity
  575. // if each branch binds it in exactly the same way...
  576. List ambiguousNames = new ArrayList();
  577. for (int i = 0; i < numFormals; i++) {
  578. if (leftBindings[i] == null) {
  579. if (rightBindings[i] != null) {
  580. ambiguousNames.add(names[i]);
  581. }
  582. } else if (!leftBindings[i].equals(rightBindings[i])) {
  583. ambiguousNames.add(names[i]);
  584. }
  585. }
  586. if (!ambiguousNames.isEmpty())
  587. raiseAmbiguityInDisjunctionError(userPointcut,ambiguousNames);
  588. }
  589. }
  590. // pc is a pointcut that does not contain any disjunctions
  591. // check that every formal is bound (negation doesn't count).
  592. // we know that numFormals > 0 or else we would not be called
  593. private void validateSingleBranch(Pointcut pc, Pointcut userPointcut, int numFormals, String[] names, Pointcut[] bindings) {
  594. boolean[] foundFormals = new boolean[numFormals];
  595. for (int i = 0; i < foundFormals.length; i++) {
  596. foundFormals[i] = false;
  597. }
  598. validateSingleBranchRecursion(pc, userPointcut, foundFormals, names, bindings);
  599. for (int i = 0; i < foundFormals.length; i++) {
  600. if (!foundFormals[i]) {
  601. boolean ignore = false;
  602. // ATAJ soften the unbound error for implicit bindings like JoinPoint in @AJ style
  603. for (int j = 0; j < userPointcut.m_ignoreUnboundBindingForNames.length; j++) {
  604. if (names[i] != null && names[i].equals(userPointcut.m_ignoreUnboundBindingForNames[j])) {
  605. ignore = true;
  606. break;
  607. }
  608. }
  609. if (!ignore) {
  610. raiseUnboundFormalError(names[i],userPointcut);
  611. }
  612. }
  613. }
  614. }
  615. // each formal must appear exactly once
  616. private void validateSingleBranchRecursion(Pointcut pc, Pointcut userPointcut, boolean[] foundFormals, String[] names, Pointcut[] bindings) {
  617. if (pc instanceof NotPointcut) {
  618. // nots can only appear at leaves in DNF
  619. NotPointcut not = (NotPointcut) pc;
  620. if (not.getNegatedPointcut() instanceof NameBindingPointcut) {
  621. NameBindingPointcut nnbp = (NameBindingPointcut) not.getNegatedPointcut();
  622. if (!nnbp.getBindingAnnotationTypePatterns().isEmpty() && !nnbp.getBindingTypePatterns().isEmpty())
  623. raiseNegationBindingError(userPointcut);
  624. }
  625. } else if (pc instanceof AndPointcut) {
  626. AndPointcut and = (AndPointcut) pc;
  627. validateSingleBranchRecursion(and.getLeft(), userPointcut,foundFormals,names,bindings);
  628. validateSingleBranchRecursion(and.getRight(),userPointcut,foundFormals,names,bindings);
  629. } else if (pc instanceof NameBindingPointcut) {
  630. List/*BindingTypePattern*/ btps = ((NameBindingPointcut)pc).getBindingTypePatterns();
  631. for (Iterator iter = btps.iterator(); iter.hasNext();) {
  632. BindingTypePattern btp = (BindingTypePattern) iter.next();
  633. int index = btp.getFormalIndex();
  634. bindings[index] = pc;
  635. if (foundFormals[index]) {
  636. raiseAmbiguousBindingError(names[index],userPointcut);
  637. } else {
  638. foundFormals[index] = true;
  639. }
  640. }
  641. List/*BindingAnnotationTypePattern*/ baps = ((NameBindingPointcut)pc).getBindingAnnotationTypePatterns();
  642. for (Iterator iter = baps.iterator(); iter.hasNext();) {
  643. BindingAnnotationTypePattern bap = (BindingAnnotationTypePattern) iter.next();
  644. int index = bap.getFormalIndex();
  645. bindings[index] = pc;
  646. if (foundFormals[index]) {
  647. raiseAmbiguousBindingError(names[index],userPointcut);
  648. } else {
  649. foundFormals[index] = true;
  650. }
  651. }
  652. } else if (pc instanceof ConcreteCflowPointcut) {
  653. ConcreteCflowPointcut cfp = (ConcreteCflowPointcut) pc;
  654. int[] slots = cfp.getUsedFormalSlots();
  655. for (int i = 0; i < slots.length; i++) {
  656. bindings[slots[i]] = cfp;
  657. if (foundFormals[slots[i]]) {
  658. raiseAmbiguousBindingError(names[slots[i]],userPointcut);
  659. } else {
  660. foundFormals[slots[i]] = true;
  661. }
  662. }
  663. }
  664. }
  665. // By returning false from this method, we are allowing binding of the same
  666. // variable on either side of an or.
  667. // Be conservative :- have to consider overriding, varargs, autoboxing,
  668. // the effects of itds (on within for example), interfaces, the fact that
  669. // join points can have multiple signatures and so on.
  670. private boolean couldEverMatchSameJoinPoints(Pointcut left, Pointcut right) {
  671. if (left instanceof OrPointcut) {
  672. OrPointcut leftOrPointcut = (OrPointcut)left;
  673. if (couldEverMatchSameJoinPoints(leftOrPointcut.getLeft(),right)) return true;
  674. if (couldEverMatchSameJoinPoints(leftOrPointcut.getRight(),right)) return true;
  675. return false;
  676. }
  677. if (right instanceof OrPointcut) {
  678. OrPointcut rightOrPointcut = (OrPointcut)right;
  679. if (couldEverMatchSameJoinPoints(left,rightOrPointcut.getLeft())) return true;
  680. if (couldEverMatchSameJoinPoints(left,rightOrPointcut.getRight())) return true;
  681. return false;
  682. }
  683. // look for withins
  684. WithinPointcut leftWithin = (WithinPointcut) findFirstPointcutIn(left,WithinPointcut.class);
  685. WithinPointcut rightWithin = (WithinPointcut) findFirstPointcutIn(right,WithinPointcut.class);
  686. if ((leftWithin != null) && (rightWithin != null)) {
  687. if (!leftWithin.couldEverMatchSameJoinPointsAs(rightWithin)) return false;
  688. }
  689. // look for kinded
  690. KindedPointcut leftKind = (KindedPointcut) findFirstPointcutIn(left,KindedPointcut.class);
  691. KindedPointcut rightKind = (KindedPointcut) findFirstPointcutIn(right,KindedPointcut.class);
  692. if ((leftKind != null) && (rightKind != null)) {
  693. if (!leftKind.couldEverMatchSameJoinPointsAs(rightKind)) return false;
  694. }
  695. return true;
  696. }
  697. private Pointcut findFirstPointcutIn(Pointcut toSearch, Class toLookFor) {
  698. if (toSearch instanceof NotPointcut) return null;
  699. if (toLookFor.isInstance(toSearch)) return toSearch;
  700. if (toSearch instanceof AndPointcut) {
  701. AndPointcut apc = (AndPointcut) toSearch;
  702. Pointcut left = findFirstPointcutIn(apc.getLeft(),toLookFor);
  703. if (left != null) return left;
  704. return findFirstPointcutIn(apc.getRight(),toLookFor);
  705. }
  706. return null;
  707. }
  708. /**
  709. * @param userPointcut
  710. */
  711. private void raiseNegationBindingError(Pointcut userPointcut) {
  712. world.showMessage(IMessage.ERROR,
  713. WeaverMessages.format(WeaverMessages.NEGATION_DOESNT_ALLOW_BINDING),
  714. userPointcut.getSourceContext().makeSourceLocation(userPointcut),null);
  715. }
  716. /**
  717. * @param name
  718. * @param userPointcut
  719. */
  720. private void raiseAmbiguousBindingError(String name, Pointcut userPointcut) {
  721. world.showMessage(IMessage.ERROR,
  722. WeaverMessages.format(WeaverMessages.AMBIGUOUS_BINDING,
  723. name),
  724. userPointcut.getSourceContext().makeSourceLocation(userPointcut),null);
  725. }
  726. /**
  727. * @param userPointcut
  728. */
  729. private void raiseAmbiguityInDisjunctionError(Pointcut userPointcut, List names) {
  730. StringBuffer formalNames = new StringBuffer(names.get(0).toString());
  731. for (int i = 1; i < names.size(); i++) {
  732. formalNames.append(", ");
  733. formalNames.append(names.get(i));
  734. }
  735. world.showMessage(IMessage.ERROR,
  736. WeaverMessages.format(WeaverMessages.AMBIGUOUS_BINDING_IN_OR,formalNames),
  737. userPointcut.getSourceContext().makeSourceLocation(userPointcut),null);
  738. }
  739. /**
  740. * @param name
  741. * @param userPointcut
  742. */
  743. private void raiseUnboundFormalError(String name, Pointcut userPointcut) {
  744. world.showMessage(IMessage.ERROR,
  745. WeaverMessages.format(WeaverMessages.UNBOUND_FORMAL,
  746. name),
  747. userPointcut.getSourceContext().makeSourceLocation(userPointcut),null);
  748. }
  749. // public void dumpUnwoven(File file) throws IOException {
  750. // BufferedOutputStream os = FileUtil.makeOutputStream(file);
  751. // this.zipOutputStream = new ZipOutputStream(os);
  752. // dumpUnwoven();
  753. // /* BUG 40943*/
  754. // dumpResourcesToOutJar();
  755. // zipOutputStream.close(); //this flushes and closes the acutal file
  756. // }
  757. //
  758. //
  759. // public void dumpUnwoven() throws IOException {
  760. // Collection filesToDump = new HashSet(sourceJavaClasses.values());
  761. // for (Iterator i = filesToDump.iterator(); i.hasNext(); ) {
  762. // UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  763. // dumpUnchanged(classFile);
  764. // }
  765. // }
  766. // public void dumpResourcesToOutPath() throws IOException {
  767. //// System.err.println("? dumpResourcesToOutPath() resources=" + resources.keySet());
  768. // Iterator i = resources.keySet().iterator();
  769. // while (i.hasNext()) {
  770. // UnwovenClassFile res = (UnwovenClassFile)resources.get(i.next());
  771. // dumpUnchanged(res);
  772. // }
  773. // //resources = new HashMap();
  774. // }
  775. //
  776. /* BUG #40943 */
  777. // public void dumpResourcesToOutJar() throws IOException {
  778. //// System.err.println("? dumpResourcesToOutJar() resources=" + resources.keySet());
  779. // Iterator i = resources.keySet().iterator();
  780. // while (i.hasNext()) {
  781. // String name = (String)i.next();
  782. // UnwovenClassFile res = (UnwovenClassFile)resources.get(name);
  783. // writeZipEntry(name,res.getBytes());
  784. // }
  785. // resources = new HashMap();
  786. // }
  787. //
  788. // // halfway house for when the jar is managed outside of the weaver, but the resources
  789. // // to be copied are known in the weaver.
  790. // public void dumpResourcesToOutJar(ZipOutputStream zos) throws IOException {
  791. // this.zipOutputStream = zos;
  792. // dumpResourcesToOutJar();
  793. // }
  794. public void addManifest (Manifest newManifest) {
  795. // System.out.println("? addManifest() newManifest=" + newManifest);
  796. if (manifest == null) {
  797. manifest = newManifest;
  798. }
  799. }
  800. public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
  801. private static final String WEAVER_MANIFEST_VERSION = "1.0";
  802. private static final Attributes.Name CREATED_BY = new Name("Created-By");
  803. private static final String WEAVER_CREATED_BY = "AspectJ Compiler";
  804. public Manifest getManifest (boolean shouldCreate) {
  805. if (manifest == null && shouldCreate) {
  806. manifest = new Manifest();
  807. Attributes attributes = manifest.getMainAttributes();
  808. attributes.put(Name.MANIFEST_VERSION,WEAVER_MANIFEST_VERSION);
  809. attributes.put(CREATED_BY,WEAVER_CREATED_BY);
  810. }
  811. return manifest;
  812. }
  813. // ---- weaving
  814. // Used by some test cases only...
  815. public Collection weave(File file) throws IOException {
  816. OutputStream os = FileUtil.makeOutputStream(file);
  817. this.zipOutputStream = new ZipOutputStream(os);
  818. prepareForWeave();
  819. Collection c = weave( new IClassFileProvider() {
  820. public boolean isApplyAtAspectJMungersOnly() {
  821. return false;
  822. }
  823. public Iterator getClassFileIterator() {
  824. return addedClasses.iterator();
  825. }
  826. public IWeaveRequestor getRequestor() {
  827. return new IWeaveRequestor() {
  828. public void acceptResult(UnwovenClassFile result) {
  829. try {
  830. writeZipEntry(result.filename, result.bytes);
  831. } catch(IOException ex) {}
  832. }
  833. public void processingReweavableState() {}
  834. public void addingTypeMungers() {}
  835. public void weavingAspects() {}
  836. public void weavingClasses() {}
  837. public void weaveCompleted() {}
  838. };
  839. }
  840. });
  841. // /* BUG 40943*/
  842. // dumpResourcesToOutJar();
  843. zipOutputStream.close(); //this flushes and closes the acutal file
  844. return c;
  845. }
  846. // public Collection weave() throws IOException {
  847. // prepareForWeave();
  848. // Collection filesToWeave;
  849. //
  850. // if (needToReweaveWorld) {
  851. // filesToWeave = sourceJavaClasses.values();
  852. // } else {
  853. // filesToWeave = addedClasses;
  854. // }
  855. //
  856. // Collection wovenClassNames = new ArrayList();
  857. // world.showMessage(IMessage.INFO, "might need to weave " + filesToWeave +
  858. // "(world=" + needToReweaveWorld + ")", null, null);
  859. //
  860. //
  861. // //System.err.println("typeMungers: " + typeMungerList);
  862. //
  863. // prepareToProcessReweavableState();
  864. // // clear all state from files we'll be reweaving
  865. // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
  866. // UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  867. // String className = classFile.getClassName();
  868. // BcelObjectType classType = getClassType(className);
  869. // processReweavableStateIfPresent(className, classType);
  870. // }
  871. //
  872. //
  873. //
  874. // //XXX this isn't quite the right place for this...
  875. // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
  876. // UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  877. // String className = classFile.getClassName();
  878. // addTypeMungers(className);
  879. // }
  880. //
  881. // // first weave into aspects
  882. // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
  883. // UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  884. // String className = classFile.getClassName();
  885. // BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className));
  886. // if (classType.isAspect()) {
  887. // weave(classFile, classType);
  888. // wovenClassNames.add(className);
  889. // }
  890. // }
  891. //
  892. // // then weave into non-aspects
  893. // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) {
  894. // UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  895. // String className = classFile.getClassName();
  896. // BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className));
  897. // if (! classType.isAspect()) {
  898. // weave(classFile, classType);
  899. // wovenClassNames.add(className);
  900. // }
  901. // }
  902. //
  903. // if (zipOutputStream != null && !needToReweaveWorld) {
  904. // Collection filesToDump = new HashSet(sourceJavaClasses.values());
  905. // filesToDump.removeAll(filesToWeave);
  906. // for (Iterator i = filesToDump.iterator(); i.hasNext(); ) {
  907. // UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  908. // dumpUnchanged(classFile);
  909. // }
  910. // }
  911. //
  912. // addedClasses = new ArrayList();
  913. // deletedTypenames = new ArrayList();
  914. //
  915. // return wovenClassNames;
  916. // }
  917. // variation of "weave" that sources class files from an external source.
  918. public Collection weave(IClassFileProvider input) throws IOException {
  919. if (trace.isTraceEnabled()) trace.enter("weave",this,input);
  920. ContextToken weaveToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING, "");
  921. Collection wovenClassNames = new ArrayList();
  922. IWeaveRequestor requestor = input.getRequestor();
  923. for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) {
  924. UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  925. if (AsmManager.isCreatingModel() && !isBatchWeave) {
  926. // remove all relationships where this file being woven is the target of the relationship
  927. AsmManager.getDefault().removeRelationshipsTargettingThisType(classFile.getClassName());
  928. }
  929. }
  930. // special case for AtAspectJMungerOnly - see #113587
  931. if (input.isApplyAtAspectJMungersOnly()) {
  932. ContextToken atAspectJMungersOnly = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_ATASPECTJTYPE_MUNGERS_ONLY, "");
  933. requestor.weavingAspects();
  934. ContextToken aspectToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_ASPECTS, "");
  935. for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) {
  936. UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  937. String className = classFile.getClassName();
  938. ResolvedType theType = world.resolve(className);
  939. if (theType.isAnnotationStyleAspect()) {
  940. BcelObjectType classType = BcelWorld.getBcelObjectType(theType);
  941. if (classType==null) {
  942. throw new BCException("Can't find bcel delegate for "+className+" type="+theType.getClass());
  943. }
  944. LazyClassGen clazz = classType.getLazyClassGen();
  945. BcelPerClauseAspectAdder selfMunger = new BcelPerClauseAspectAdder(theType, theType.getPerClause().getKind());
  946. selfMunger.forceMunge(clazz, true);
  947. classType.finishedWith();
  948. UnwovenClassFile[] newClasses = getClassFilesFor(clazz);
  949. for (int news = 0; news < newClasses.length; news++) {
  950. requestor.acceptResult(newClasses[news]);
  951. }
  952. wovenClassNames.add(classFile.getClassName());
  953. }
  954. }
  955. requestor.weaveCompleted();
  956. CompilationAndWeavingContext.leavingPhase(atAspectJMungersOnly);
  957. return wovenClassNames;
  958. }
  959. requestor.processingReweavableState();
  960. ContextToken reweaveToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_REWEAVABLE_STATE,"");
  961. prepareToProcessReweavableState();
  962. // clear all state from files we'll be reweaving
  963. for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) {
  964. UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  965. String className = classFile.getClassName();
  966. BcelObjectType classType = getClassType(className);
  967. // null return from getClassType() means the delegate is an eclipse source type - so
  968. // there *cant* be any reweavable state... (he bravely claimed...)
  969. if (classType !=null) {
  970. ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_REWEAVABLE_STATE, className);
  971. processReweavableStateIfPresent(className, classType);
  972. CompilationAndWeavingContext.leavingPhase(tok);
  973. }
  974. }
  975. CompilationAndWeavingContext.leavingPhase(reweaveToken);
  976. ContextToken typeMungingToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_TYPE_MUNGERS,"");
  977. requestor.addingTypeMungers();
  978. // We process type mungers in two groups, first mungers that change the type
  979. // hierarchy, then 'normal' ITD type mungers.
  980. // Process the types in a predictable order (rather than the order encountered).
  981. // For class A, the order is superclasses of A then superinterfaces of A
  982. // (and this mechanism is applied recursively)
  983. List typesToProcess = new ArrayList();
  984. for (Iterator iter = input.getClassFileIterator(); iter.hasNext();) {
  985. UnwovenClassFile clf = (UnwovenClassFile) iter.next();
  986. typesToProcess.add(clf.getClassName());
  987. }
  988. while (typesToProcess.size()>0) {
  989. weaveParentsFor(typesToProcess,(String)typesToProcess.get(0));
  990. }
  991. for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) {
  992. UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  993. String className = classFile.getClassName();
  994. addNormalTypeMungers(className);
  995. }
  996. CompilationAndWeavingContext.leavingPhase(typeMungingToken);
  997. requestor.weavingAspects();
  998. ContextToken aspectToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_ASPECTS, "");
  999. // first weave into aspects
  1000. for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) {
  1001. UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  1002. String className = classFile.getClassName();
  1003. ResolvedType theType = world.resolve(className);
  1004. if (theType.isAspect()) {
  1005. BcelObjectType classType = BcelWorld.getBcelObjectType(theType);
  1006. if (classType==null) {
  1007. // Sometimes.. if the Bcel Delegate couldn't be found then a problem occurred at compile time - on
  1008. // a previous compiler run. In this case I assert the delegate will still be an EclipseSourceType
  1009. // and we can ignore the problem here (the original compile error will be reported again from
  1010. // the eclipse source type) - pr113531
  1011. ReferenceTypeDelegate theDelegate = ((ReferenceType)theType).getDelegate();
  1012. if (theDelegate.getClass().getName().endsWith("EclipseSourceType")) continue;
  1013. throw new BCException("Can't find bcel delegate for "+className+" type="+theType.getClass());
  1014. }
  1015. weaveAndNotify(classFile, classType,requestor);
  1016. wovenClassNames.add(className);
  1017. }
  1018. }
  1019. CompilationAndWeavingContext.leavingPhase(aspectToken);
  1020. requestor.weavingClasses();
  1021. ContextToken classToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_CLASSES, "");
  1022. // then weave into non-aspects
  1023. for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) {
  1024. UnwovenClassFile classFile = (UnwovenClassFile)i.next();
  1025. String className = classFile.getClassName();
  1026. ResolvedType theType = world.resolve(className);
  1027. if (!theType.isAspect()) {
  1028. BcelObjectType classType = BcelWorld.getBcelObjectType(theType);
  1029. if (classType==null) {
  1030. // bug 119882 - see above comment for bug 113531
  1031. ReferenceTypeDelegate theDelegate = ((ReferenceType)theType).getDelegate();
  1032. // TODO urgh - put a method on the interface to check this, string compare is hideous
  1033. if (theDelegate.getClass().getName().endsWith("EclipseSourceType")) continue;
  1034. throw new BCException("Can't find bcel delegate for "+className+" type="+theType.getClass());
  1035. }
  1036. weaveAndNotify(classFile, classType, requestor);
  1037. wovenClassNames.add(className);
  1038. }
  1039. }
  1040. CompilationAndWeavingContext.leavingPhase(classToken);
  1041. addedClasses = new ArrayList();
  1042. deletedTypenames = new ArrayList();
  1043. requestor.weaveCompleted();
  1044. CompilationAndWeavingContext.leavingPhase(weaveToken);
  1045. if (trace.isTraceEnabled()) trace.exit("weave",wovenClassNames);
  1046. return wovenClassNames;
  1047. }
  1048. public void allWeavingComplete() {
  1049. warnOnUnmatchedAdvice();
  1050. }
  1051. /**
  1052. * In 1.5 mode and with XLint:adviceDidNotMatch enabled, put out messages for any
  1053. * mungers that did not match anything.
  1054. */
  1055. private void warnOnUnmatchedAdvice() {
  1056. class AdviceLocation {
  1057. private int lineNo;
  1058. private UnresolvedType inAspect;
  1059. public AdviceLocation(BcelAdvice advice) {
  1060. this.lineNo = advice.getSourceLocation().getLine();
  1061. this.inAspect = advice.getDeclaringAspect();
  1062. }
  1063. public boolean equals(Object obj) {
  1064. if (!(obj instanceof AdviceLocation)) return false;
  1065. AdviceLocation other = (AdviceLocation) obj;
  1066. if (this.lineNo != other.lineNo) return false;
  1067. if (!this.inAspect.equals(other.inAspect)) return false;
  1068. return true;
  1069. }
  1070. public int hashCode() {
  1071. return 37 + 17*lineNo + 17*inAspect.hashCode();
  1072. };
  1073. }
  1074. // FIXME asc Should be factored out into Xlint code and done automatically for all xlint messages, ideally.
  1075. // if a piece of advice hasn't matched anywhere and we are in -1.5 mode, put out a warning
  1076. if (world.isInJava5Mode() &&
  1077. world.getLint().adviceDidNotMatch.isEnabled()) {
  1078. List l = world.getCrosscuttingMembersSet().getShadowMungers();
  1079. Set alreadyWarnedLocations = new HashSet();
  1080. for (Iterator iter = l.iterator(); iter.hasNext();) {
  1081. ShadowMunger element = (ShadowMunger) iter.next();
  1082. if (element instanceof BcelAdvice) { // This will stop us incorrectly reporting deow Checkers
  1083. BcelAdvice ba = (BcelAdvice)element;
  1084. if (!ba.hasMatchedSomething()) {
  1085. // Because we implement some features of AJ itself by creating our own kind of mungers, you sometimes
  1086. // find that ba.getSignature() is not a BcelMethod - for example it might be a cflow entry munger.
  1087. if (ba.getSignature()!=null) {
  1088. // check we haven't already warned on this advice and line
  1089. // (cflow creates multiple mungers for the same advice)
  1090. AdviceLocation loc = new AdviceLocation(ba);
  1091. if (alreadyWarnedLocations.contains(loc)) {
  1092. continue;
  1093. } else {
  1094. alreadyWarnedLocations.add(loc);
  1095. }
  1096. if (!(ba.getSignature() instanceof BcelMethod)
  1097. || !Utility.isSuppressing((AnnotationX[])ba.getSignature().getAnnotations(),"adviceDidNotMatch")) {
  1098. world.getLint().adviceDidNotMatch.signal(ba.getDeclaringAspect().toString(),
  1099. new SourceLocation(element.getSourceLocation().getSourceFile(),element.getSourceLocation().getLine()));//element.getSourceLocation());
  1100. }
  1101. }
  1102. }
  1103. }
  1104. }
  1105. }
  1106. }
  1107. /**
  1108. * 'typeToWeave' is one from the 'typesForWeaving' list. This routine ensures we process
  1109. * supertypes (classes/interfaces) of 'typeToWeave' that are in the
  1110. * 'typesForWeaving' list before 'typeToWeave' itself. 'typesToWeave' is then removed from
  1111. * the 'typesForWeaving' list.
  1112. *
  1113. * Note: Future gotcha in here ... when supplying partial hierarchies, this algorithm may
  1114. * break down. If you have a hierarchy A>B>C and only give A and C to the weaver, it
  1115. * may choose to weave them in either order - but you'll probably have other problems if
  1116. * you are supplying partial hierarchies like that !
  1117. */
  1118. private void weaveParentsFor(List typesForWeaving,String typeToWeave) {
  1119. // Look at the supertype first
  1120. ResolvedType rtx = world.resolve(typeToWeave);
  1121. ResolvedType superType = rtx.getSuperclass();
  1122. if (superType!=null && typesForWeaving.contains(superType.getName())) {
  1123. weaveParentsFor(typesForWeaving,superType.getName());
  1124. }
  1125. // Then look at the superinterface list
  1126. ResolvedType[] interfaceTypes = rtx.getDeclaredInterfaces();
  1127. for (int i = 0; i < interfaceTypes.length; i++) {
  1128. ResolvedType rtxI = interfaceTypes[i];
  1129. if (typesForWeaving.contains(rtxI.getName())) {
  1130. weaveParentsFor(typesForWeaving,rtxI.getName());
  1131. }
  1132. }
  1133. ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_DECLARE_PARENTS,rtx.getName());
  1134. weaveParentTypeMungers(rtx); // Now do this type
  1135. CompilationAndWeavingContext.leavingPhase(tok);
  1136. typesForWeaving.remove(typeToWeave); // and remove it from the list of those to process
  1137. }
  1138. public void prepareToProcessReweavableState() {
  1139. }
  1140. public void processReweavableStateIfPresent(String className, BcelObjectType classType) {
  1141. // If the class is marked reweavable, check any aspects around when it was built are in this world
  1142. WeaverStateInfo wsi = classType.getWeaverState();
  1143. if (wsi!=null && wsi.isReweavable()) { // Check all necessary types are around!
  1144. world.showMessage(IMessage.INFO,
  1145. WeaverMessages.format(WeaverMessages.PROCESSING_REWEAVABLE,className,classType.getSourceLocation().getSourceFile()),
  1146. null,null);
  1147. Set aspectsPreviouslyInWorld = wsi.getAspectsAffectingType();
  1148. if (aspectsPreviouslyInWorld!=null) {
  1149. // keep track of them just to ensure unique missing aspect error reporting
  1150. Set alreadyConfirmedReweavableState = new HashSet();
  1151. for (Iterator iter = aspectsPreviouslyInWorld.iterator(); iter.hasNext();) {
  1152. String requiredTypeName = (String) iter.next();
  1153. if (!alreadyConfirmedReweavableState.contains(requiredTypeName)) {
  1154. ResolvedType rtx = world.resolve(UnresolvedType.forName(requiredTypeName),true);
  1155. boolean exists = !rtx.isMissing();
  1156. if (!exists) {
  1157. world.showMessage(IMessage.ERROR,
  1158. WeaverMessages.format(WeaverMessages.MISSING_REWEAVABLE_TYPE,requiredTypeName,className),
  1159. classType.getSourceLocation(), null);
  1160. } else {
  1161. // weaved in aspect that are not declared in aop.xml trigger an error for now
  1162. // may cause headhache for LTW and packaged lib without aop.xml in
  1163. // see #104218
  1164. if(!xcutSet.containsAspect(rtx)){
  1165. world.showMessage(
  1166. IMessage.ERROR,
  1167. WeaverMessages.format(
  1168. WeaverMessages.REWEAVABLE_ASPECT_NOT_REGISTERED,
  1169. requiredTypeName,
  1170. className
  1171. ),
  1172. null,
  1173. null
  1174. );
  1175. } else if (!world.getMessageHandler().isIgnoring(IMessage.INFO))
  1176. world.showMessage(IMessage.INFO,
  1177. WeaverMessages.format(WeaverMessages.VERIFIED_REWEAVABLE_TYPE,requiredTypeName,rtx.getSourceLocation().getSourceFile()),
  1178. null,null);
  1179. alreadyConfirmedReweavableState.add(requiredTypeName);
  1180. }
  1181. }
  1182. }
  1183. }
  1184. // old:
  1185. //classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData()));
  1186. // new: reweavable default with clever diff
  1187. classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData(classType.getJavaClass().getBytes())));
  1188. // } else {
  1189. // classType.resetState();
  1190. }
  1191. }
  1192. private void weaveAndNotify(UnwovenClassFile classFile, BcelObjectType classType,
  1193. IWeaveRequestor requestor) throws IOException {
  1194. trace.enter("weaveAndNotify",this,new Object[] {classFile,classType,requestor});
  1195. ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_TYPE, classType.getResolvedTypeX().getName());
  1196. LazyClassGen clazz = weaveWithoutDump(classFile,classType);
  1197. classType.finishedWith();
  1198. //clazz is null if the classfile was unchanged by weaving...
  1199. if (clazz != null) {
  1200. UnwovenClassFile[] newClasses = getClassFilesFor(clazz);
  1201. for (int i = 0; i < newClasses.length; i++) {
  1202. requestor.acceptResult(newClasses[i]);
  1203. }
  1204. } else {
  1205. requestor.acceptResult(classFile);
  1206. }
  1207. classType.weavingCompleted();
  1208. CompilationAndWeavingContext.leavingPhase(tok);
  1209. trace.exit("weaveAndNotify");
  1210. }
  1211. /** helper method - will return NULL if the underlying delegate is an EclipseSourceType and not a BcelObjectType */
  1212. public BcelObjectType getClassType(String forClass) {
  1213. return BcelWorld.getBcelObjectType(world.resolve(forClass));
  1214. }
  1215. public void addParentTypeMungers(String typeName) {
  1216. weaveParentTypeMungers(world.resolve(typeName));
  1217. }
  1218. public void addNormalTypeMungers(String typeName) {
  1219. weaveNormalTypeMungers(world.resolve(typeName));
  1220. }
  1221. public UnwovenClassFile[] getClassFilesFor(LazyClassGen clazz) {
  1222. List childClasses = clazz.getChildClasses(world);
  1223. UnwovenClassFile[] ret = new UnwovenClassFile[1 + childClasses.size()];
  1224. ret[0] = new UnwovenClassFile(clazz.getFileName(),clazz.getJavaClassBytesIncludingReweavable(world));
  1225. int index = 1;
  1226. for (Iterator iter = childClasses.iterator(); iter.hasNext();) {
  1227. UnwovenClassFile.ChildClass element = (UnwovenClassFile.ChildClass) iter.next();
  1228. UnwovenClassFile childClass = new UnwovenClassFile(clazz.getFileName() + "$" + element.name, element.bytes);
  1229. ret[index++] = childClass;
  1230. }
  1231. return ret;
  1232. }
  1233. /**
  1234. * Weaves new parents and annotations onto a type ("declare parents" and "declare @type")
  1235. *
  1236. * Algorithm:
  1237. * 1. First pass, do parents then do annotations. During this pass record:
  1238. * - any parent mungers that don't match but have a non-wild annotation type pattern
  1239. * - any annotation mungers that don't match
  1240. * 2. Multiple subsequent passes which go over the munger lists constructed in the first
  1241. * pass, repeatedly applying them until nothing changes.
  1242. * FIXME asc confirm that algorithm is optimal ??
  1243. */
  1244. public void weaveParentTypeMungers(ResolvedType onType) {
  1245. if (onType.isRawType()) onType = onType.getGenericType();
  1246. onType.clearInterTypeMungers();
  1247. List decpToRepeat = new ArrayList();
  1248. boolean aParentChangeOccurred = false;
  1249. boolean anAnnotationChangeOccurred = false;
  1250. // First pass - apply all decp mungers
  1251. for (Iterator i = declareParentsList.iterator(); i.hasNext(); ) {
  1252. DeclareParents decp = (DeclareParents)i.next();
  1253. boolean typeChanged = applyDeclareParents(decp,onType);
  1254. if (typeChanged) {
  1255. aParentChangeOccurred = true;
  1256. } else { // Perhaps it would have matched if a 'dec @type' had modified the type
  1257. if (!decp.getChild().isStarAnnotation()) decpToRepeat.add(decp);
  1258. }
  1259. }
  1260. // Still first pass - apply all dec @type mungers
  1261. for (Iterator i = xcutSet.getDeclareAnnotationOnTypes().iterator();i.hasNext();) {
  1262. DeclareAnnotation decA = (DeclareAnnotation)i.next();
  1263. boolean typeChanged = applyDeclareAtType(decA,onType,true);
  1264. if (typeChanged) {
  1265. anAnnotationChangeOccurred = true;
  1266. }
  1267. }
  1268. while ((aParentChangeOccurred || anAnnotationChangeOccurred) && !decpToRepeat.isEmpty()) {
  1269. anAnnotationChangeOccurred = aParentChangeOccurred = false;
  1270. List decpToRepeatNextTime = new ArrayList();
  1271. for (Iterator iter = decpToRepeat.iterator(); iter.hasNext();) {
  1272. DeclareParents decp = (DeclareParents) iter.next();
  1273. boolean typeChanged = applyDeclareParents(decp,onType);
  1274. if (typeChanged) {
  1275. aParentChangeOccurred = true;
  1276. } else {
  1277. decpToRepeatNextTime.add(decp);
  1278. }
  1279. }
  1280. for (Iterator iter = xcutSet.getDeclareAnnotationOnTypes().iterator(); iter.hasNext();) {
  1281. DeclareAnnotation decA = (DeclareAnnotation) iter.next();
  1282. boolean typeChanged = applyDeclareAtType(decA,onType,false);
  1283. if (typeChanged) {
  1284. anAnnotationChangeOccurred = true;
  1285. }
  1286. }
  1287. decpToRepeat = decpToRepeatNextTime;
  1288. }
  1289. }
  1290. /**
  1291. * Apply a declare @type - return true if we change the type
  1292. */
  1293. private boolean applyDeclareAtType(DeclareAnnotation decA, ResolvedType onType,boolean reportProblems) {
  1294. boolean didSomething = false;
  1295. if (decA.matches(onType)) {
  1296. if (onType.hasAnnotation(decA.getAnnotationX().getSignature())) {
  1297. // Could put out a lint here for an already annotated type ...
  1298. // if (reportProblems) {
  1299. // world.getLint().elementAlreadyAnnotated.signal(
  1300. // new String[]{onType.toString(),decA.getAnnotationTypeX().toString()},
  1301. // onType.getSourceLocation(),new ISourceLocation[]{decA.getSourceLocation()});
  1302. // }
  1303. return false;
  1304. }
  1305. AnnotationX annoX = decA.getAnnotationX();
  1306. // check the annotation is suitable for the target
  1307. boolean problemReported = verifyTargetIsOK(decA, onType, annoX,reportProblems);
  1308. if (!problemReported) {
  1309. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decA.getSourceLocation(),onType.getSourceLocation());
  1310. // TAG: WeavingMessage
  1311. if (!getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)){
  1312. getWorld().getMessageHandler().handleMessage(
  1313. WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ANNOTATES,
  1314. new String[]{
  1315. onType.toString(),
  1316. Utility.beautifyLocation(onType.getSourceLocation()),
  1317. decA.getAnnotationString(),
  1318. "type",
  1319. decA.getAspect().toString(),
  1320. Utility.beautifyLocation(decA.getSourceLocation())
  1321. }));
  1322. }
  1323. didSomething = true;
  1324. ResolvedTypeMunger newAnnotationTM = new AnnotationOnTypeMunger(annoX);
  1325. newAnnotationTM.setSourceLocation(decA.getSourceLocation());
  1326. onType.addInterTypeMunger(new BcelTypeMunger(newAnnotationTM,decA.getAspect().resolve(world)));
  1327. decA.copyAnnotationTo(onType);
  1328. }
  1329. }
  1330. return didSomething;
  1331. }
  1332. /**
  1333. * Checks for an @target() on the annotation and if found ensures it allows the annotation
  1334. * to be attached to the target type that matched.
  1335. */
  1336. private boolean verifyTargetIsOK(DeclareAnnotation decA, ResolvedType onType, AnnotationX annoX,boolean outputProblems) {
  1337. boolean problemReported = false;
  1338. if (annoX.specifiesTarget()) {
  1339. if ( (onType.isAnnotation() && !annoX.allowedOnAnnotationType()) ||
  1340. (!annoX.allowedOnRegularType())) {
  1341. if (outputProblems) {
  1342. if (decA.isExactPattern()) {
  1343. world.getMessageHandler().handleMessage(MessageUtil.error(
  1344. WeaverMessages.format(WeaverMessages.INCORRECT_TARGET_FOR_DECLARE_ANNOTATION,
  1345. onType.getName(),annoX.stringify(),annoX.getValidTargets()),decA.getSourceLocation()));
  1346. } else {
  1347. if (world.getLint().invalidTargetForAnnotation.isEnabled()) {
  1348. world.getLint().invalidTargetForAnnotation.signal(
  1349. new String[]{onType.getName(),annoX.stringify(),annoX.getValidTargets()},decA.getSourceLocation(),new ISourceLocation[]{onType.getSourceLocation()});
  1350. }
  1351. }
  1352. }
  1353. problemReported = true;
  1354. }
  1355. }
  1356. return problemReported;
  1357. }
  1358. /**
  1359. * Apply a single declare parents - return true if we change the type
  1360. */
  1361. private boolean applyDeclareParents(DeclareParents p, ResolvedType onType) {
  1362. boolean didSomething = false;
  1363. List newParents = p.findMatchingNewParents(onType,true);
  1364. if (!newParents.isEmpty()) {
  1365. didSomething=true;
  1366. BcelObjectType classType = BcelWorld.getBcelObjectType(onType);
  1367. //System.err.println("need to do declare parents for: " + onType);
  1368. for (Iterator j = newParents.iterator(); j.hasNext(); ) {
  1369. ResolvedType newParent = (ResolvedType)j.next();
  1370. // We set it here so that the imminent matching for ITDs can succeed - we
  1371. // still haven't done the necessary changes to the class file itself
  1372. // (like transform super calls) - that is done in BcelTypeMunger.mungeNewParent()
  1373. classType.addParent(newParent);
  1374. ResolvedTypeMunger newParentMunger = new NewParentTypeMunger(newParent);
  1375. newParentMunger.setSourceLocation(p.getSourceLocation());
  1376. onType.addInterTypeMunger(new BcelTypeMunger(newParentMunger, xcutSet.findAspectDeclaringParents(p)));
  1377. }
  1378. }
  1379. return didSomething;
  1380. }
  1381. public void weaveNormalTypeMungers(ResolvedType onType) {
  1382. ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_TYPE_MUNGERS, onType.getName());
  1383. if (onType.isRawType() || onType.isParameterizedType()) onType = onType.getGenericType();
  1384. for (Iterator i = typeMungerList.iterator(); i.hasNext(); ) {
  1385. ConcreteTypeMunger m = (ConcreteTypeMunger)i.next();
  1386. if (!m.isLateMunger() && m.matches(onType)) {
  1387. onType.addInterTypeMunger(m);
  1388. }
  1389. }
  1390. CompilationAndWeavingContext.leavingPhase(tok);
  1391. }
  1392. // exposed for ClassLoader dynamic weaving
  1393. public LazyClassGen weaveWithoutDump(UnwovenClassFile classFile, BcelObjectType classType) throws IOException {
  1394. return weave(classFile, classType, false);
  1395. }
  1396. // non-private for testing
  1397. LazyClassGen weave(UnwovenClassFile classFile, BcelObjectType classType) throws IOException {
  1398. LazyClassGen ret = weave(classFile, classType, true);
  1399. if (progressListener != null) {
  1400. progressMade += progressPerClassFile;
  1401. progressListener.setProgress(progressMade);
  1402. progressListener.setText("woven: " + classFile.getFilename());
  1403. }
  1404. return ret;
  1405. }
  1406. private LazyClassGen weave(UnwovenClassFile classFile, BcelObjectType classType, boolean dump) throws IOException {
  1407. if (classType.isSynthetic()) { // Don't touch synthetic classes
  1408. if (dump) dumpUnchanged(classFile);
  1409. return null;
  1410. }
  1411. List shadowMungers = fastMatch(shadowMungerList, classType.getResolvedTypeX());
  1412. List typeMungers = classType.getResolvedTypeX().getInterTypeMungers();
  1413. classType.getResolvedTypeX().checkInterTypeMungers();
  1414. // Decide if we need to do actual weaving for this class
  1415. boolean mightNeedToWeave =
  1416. shadowMungers.size() > 0 ||
  1417. typeMungers.size() > 0 ||
  1418. classType.isAspect() ||
  1419. world.getDeclareAnnotationOnMethods().size()>0 ||
  1420. world.getDeclareAnnotationOnFields().size()>0;
  1421. // May need bridge methods if on 1.5 and something in our hierarchy is affected by ITDs
  1422. boolean mightNeedBridgeMethods =
  1423. world.isInJava5Mode() &&
  1424. !classType.isInterface() &&
  1425. classType.getResolvedTypeX().getInterTypeMungersIncludingSupers().size()>0;
  1426. LazyClassGen clazz = null;
  1427. if (mightNeedToWeave || mightNeedBridgeMethods) {
  1428. clazz = classType.getLazyClassGen();
  1429. //System.err.println("got lazy gen: " + clazz + ", " + clazz.getWeaverState());
  1430. try {
  1431. boolean isChanged = false;
  1432. if (mightNeedToWeave)
  1433. isChanged = BcelClassWeaver.weave(world, clazz, shadowMungers, typeMungers, lateTypeMungerList);
  1434. if (mightNeedBridgeMethods)
  1435. isChanged = BcelClassWeaver.calculateAnyRequiredBridgeMethods(world,clazz) || isChanged;
  1436. if (isChanged) {
  1437. if (dump) dump(classFile, clazz);
  1438. return clazz;
  1439. }
  1440. } catch (RuntimeException re) {
  1441. String classDebugInfo = null;
  1442. try {
  1443. classDebugInfo = clazz.toLongString();
  1444. } catch (Exception e) {
  1445. // recover from crash whilst producing debug string
  1446. classDebugInfo = clazz.getClassName();
  1447. }
  1448. String messageText = "trouble in: \n" + classDebugInfo;
  1449. getWorld().getMessageHandler().handleMessage(
  1450. new Message(messageText,IMessage.ABORT,re,null)
  1451. );
  1452. } catch (Error re) {
  1453. String classDebugInfo = null;
  1454. try {
  1455. classDebugInfo = clazz.toLongString();
  1456. } catch (Exception e) {
  1457. // recover from crash whilst producing debug string
  1458. classDebugInfo = clazz.getClassName();
  1459. }
  1460. String messageText = "trouble in: \n" + classDebugInfo;
  1461. getWorld().getMessageHandler().handleMessage(
  1462. new Message(messageText,IMessage.ABORT,re,null)
  1463. );
  1464. }
  1465. }
  1466. // this is very odd return behavior trying to keep everyone happy
  1467. if (dump) {
  1468. dumpUnchanged(classFile);
  1469. return clazz;
  1470. } else {
  1471. // ATAJ: the class was not weaved, but since it gets there early it may have new generated inner classes
  1472. // attached to it to support LTW perX aspectOf support (see BcelPerClauseAspectAdder)
  1473. // that aggressively defines the inner <aspect>$mayHaveAspect interface.
  1474. if (clazz != null && !clazz.getChildClasses(world).isEmpty()) {
  1475. return clazz;
  1476. }
  1477. return null;
  1478. }
  1479. }
  1480. // ---- writing
  1481. private void dumpUnchanged(UnwovenClassFile classFile) throws IOException {
  1482. if (zipOutputStream != null) {
  1483. writeZipEntry(getEntryName(classFile.getJavaClass().getClassName()), classFile.getBytes());
  1484. } else {
  1485. classFile.writeUnchangedBytes();
  1486. }
  1487. }
  1488. private String getEntryName(String className) {
  1489. //XXX what does bcel's getClassName do for inner names
  1490. return className.replace('.', '/') + ".class";
  1491. }
  1492. private void dump(UnwovenClassFile classFile, LazyClassGen clazz) throws IOException {
  1493. if (zipOutputStream != null) {
  1494. String mainClassName = classFile.getJavaClass().getClassName();
  1495. writeZipEntry(getEntryName(mainClassName),
  1496. clazz.getJavaClass(world).getBytes());
  1497. if (!clazz.getChildClasses(world).isEmpty()) {
  1498. for (Iterator i = clazz.getChildClasses(world).iterator(); i.hasNext();) {
  1499. UnwovenClassFile.ChildClass c = (UnwovenClassFile.ChildClass) i.next();
  1500. writeZipEntry(getEntryName(mainClassName + "$" + c.name), c.bytes);
  1501. }
  1502. }
  1503. } else {
  1504. classFile.writeWovenBytes(
  1505. clazz.getJavaClass(world).getBytes(),
  1506. clazz.getChildClasses(world)
  1507. );
  1508. }
  1509. }
  1510. private void writeZipEntry(String name, byte[] bytes) throws IOException {
  1511. ZipEntry newEntry = new ZipEntry(name); //??? get compression scheme right
  1512. zipOutputStream.putNextEntry(newEntry);
  1513. zipOutputStream.write(bytes);
  1514. zipOutputStream.closeEntry();
  1515. }
  1516. private List fastMatch(List list, ResolvedType type) {
  1517. if (list == null) return Collections.EMPTY_LIST;
  1518. // here we do the coarsest grained fast match with no kind constraints
  1519. // this will remove all obvious non-matches and see if we need to do any weaving
  1520. FastMatchInfo info = new FastMatchInfo(type, null);
  1521. List result = new ArrayList();
  1522. Iterator iter = list.iterator();
  1523. while (iter.hasNext()) {
  1524. ShadowMunger munger = (ShadowMunger)iter.next();
  1525. FuzzyBoolean fb = munger.getPointcut().fastMatch(info);
  1526. WeaverMetrics.recordFastMatchTypeResult(fb); // Could pass: munger.getPointcut().toString(),info
  1527. if (fb.maybeTrue()) {
  1528. result.add(munger);
  1529. }
  1530. }
  1531. return result;
  1532. }
  1533. public void setProgressListener(IProgressListener listener, double previousProgress, double progressPerClassFile) {
  1534. progressListener = listener;
  1535. this.progressMade = previousProgress;
  1536. this.progressPerClassFile = progressPerClassFile;
  1537. }
  1538. public void setReweavableMode(boolean xNotReweavable) {
  1539. if (trace.isTraceEnabled()) trace.enter("setReweavableMode",this,xNotReweavable);
  1540. inReweavableMode = !xNotReweavable;
  1541. WeaverStateInfo.setReweavableModeDefaults(!xNotReweavable,false,true);
  1542. BcelClassWeaver.setReweavableMode(!xNotReweavable);
  1543. if (trace.isTraceEnabled()) trace.exit("setReweavableMode");
  1544. }
  1545. public boolean isReweavable() {
  1546. return inReweavableMode;
  1547. }
  1548. public World getWorld() {
  1549. return world;
  1550. }
  1551. public void tidyUp() {
  1552. if (trace.isTraceEnabled()) trace.enter("tidyUp",this);
  1553. shadowMungerList = null; // setup by prepareForWeave
  1554. typeMungerList = null; // setup by prepareForWeave
  1555. lateTypeMungerList = null; // setup by prepareForWeave
  1556. declareParentsList = null; // setup by prepareForWeave
  1557. if (trace.isTraceEnabled()) trace.exit("tidyUp");
  1558. }
  1559. }