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.

BcelWorld.java 48KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v 2.0
  6. * which accompanies this distribution and is available at
  7. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * Alexandre Vasseur perClause support for @AJ aspects
  12. * ******************************************************************/
  13. package org.aspectj.weaver.bcel;
  14. import java.io.File;
  15. import java.io.IOException;
  16. import java.lang.reflect.Modifier;
  17. import java.net.MalformedURLException;
  18. import java.util.ArrayList;
  19. import java.util.Collections;
  20. import java.util.HashMap;
  21. import java.util.Iterator;
  22. import java.util.List;
  23. import java.util.Map;
  24. import java.util.StringTokenizer;
  25. import org.aspectj.apache.bcel.Constants;
  26. import org.aspectj.apache.bcel.classfile.ClassParser;
  27. import org.aspectj.apache.bcel.classfile.ConstantPool;
  28. import org.aspectj.apache.bcel.classfile.JavaClass;
  29. import org.aspectj.apache.bcel.generic.FieldInstruction;
  30. import org.aspectj.apache.bcel.generic.INVOKEINTERFACE;
  31. import org.aspectj.apache.bcel.generic.Instruction;
  32. import org.aspectj.apache.bcel.generic.InstructionHandle;
  33. import org.aspectj.apache.bcel.generic.InvokeInstruction;
  34. import org.aspectj.apache.bcel.generic.MULTIANEWARRAY;
  35. import org.aspectj.apache.bcel.generic.ObjectType;
  36. import org.aspectj.apache.bcel.generic.Type;
  37. import org.aspectj.apache.bcel.util.ClassLoaderReference;
  38. import org.aspectj.apache.bcel.util.ClassLoaderRepository;
  39. import org.aspectj.apache.bcel.util.ClassPath;
  40. import org.aspectj.apache.bcel.util.NonCachingClassLoaderRepository;
  41. import org.aspectj.apache.bcel.util.Repository;
  42. import org.aspectj.asm.AsmManager;
  43. import org.aspectj.asm.IRelationship;
  44. import org.aspectj.asm.internal.CharOperation;
  45. import org.aspectj.bridge.IMessage;
  46. import org.aspectj.bridge.IMessageHandler;
  47. import org.aspectj.bridge.ISourceLocation;
  48. import org.aspectj.bridge.Message;
  49. import org.aspectj.bridge.MessageUtil;
  50. import org.aspectj.bridge.WeaveMessage;
  51. import org.aspectj.weaver.Advice;
  52. import org.aspectj.weaver.AdviceKind;
  53. import org.aspectj.weaver.AnnotationAJ;
  54. import org.aspectj.weaver.AnnotationOnTypeMunger;
  55. import org.aspectj.weaver.BCException;
  56. import org.aspectj.weaver.Checker;
  57. import org.aspectj.weaver.ICrossReferenceHandler;
  58. import org.aspectj.weaver.IWeavingSupport;
  59. import org.aspectj.weaver.Member;
  60. import org.aspectj.weaver.MemberImpl;
  61. import org.aspectj.weaver.MemberKind;
  62. import org.aspectj.weaver.NewParentTypeMunger;
  63. import org.aspectj.weaver.ReferenceType;
  64. import org.aspectj.weaver.ReferenceTypeDelegate;
  65. import org.aspectj.weaver.ResolvedMember;
  66. import org.aspectj.weaver.ResolvedMemberImpl;
  67. import org.aspectj.weaver.ResolvedType;
  68. import org.aspectj.weaver.ResolvedTypeMunger;
  69. import org.aspectj.weaver.Shadow;
  70. import org.aspectj.weaver.ShadowMunger;
  71. import org.aspectj.weaver.UnresolvedType;
  72. import org.aspectj.weaver.World;
  73. import org.aspectj.weaver.loadtime.definition.Definition;
  74. import org.aspectj.weaver.loadtime.definition.DocumentParser;
  75. import org.aspectj.weaver.model.AsmRelationshipProvider;
  76. import org.aspectj.weaver.patterns.DeclareAnnotation;
  77. import org.aspectj.weaver.patterns.DeclareParents;
  78. import org.aspectj.weaver.patterns.ParserException;
  79. import org.aspectj.weaver.patterns.PatternParser;
  80. import org.aspectj.weaver.patterns.TypePattern;
  81. import org.aspectj.weaver.tools.Trace;
  82. import org.aspectj.weaver.tools.TraceFactory;
  83. public class BcelWorld extends World implements Repository {
  84. private final ClassPathManager classPath;
  85. protected Repository delegate;
  86. private BcelWeakClassLoaderReference loaderRef;
  87. private final BcelWeavingSupport bcelWeavingSupport = new BcelWeavingSupport();
  88. private boolean isXmlConfiguredWorld = false;
  89. private WeavingXmlConfig xmlConfiguration;
  90. private List<TypeDelegateResolver> typeDelegateResolvers;
  91. private static Trace trace = TraceFactory.getTraceFactory().getTrace(BcelWorld.class);
  92. public BcelWorld() {
  93. this("");
  94. }
  95. public BcelWorld(String cp) {
  96. this(makeDefaultClasspath(cp), IMessageHandler.THROW, null);
  97. }
  98. public IRelationship.Kind determineRelKind(ShadowMunger munger) {
  99. AdviceKind ak = ((Advice) munger).getKind();
  100. if (ak.getKey() == AdviceKind.Before.getKey()) {
  101. return IRelationship.Kind.ADVICE_BEFORE;
  102. } else if (ak.getKey() == AdviceKind.After.getKey()) {
  103. return IRelationship.Kind.ADVICE_AFTER;
  104. } else if (ak.getKey() == AdviceKind.AfterThrowing.getKey()) {
  105. return IRelationship.Kind.ADVICE_AFTERTHROWING;
  106. } else if (ak.getKey() == AdviceKind.AfterReturning.getKey()) {
  107. return IRelationship.Kind.ADVICE_AFTERRETURNING;
  108. } else if (ak.getKey() == AdviceKind.Around.getKey()) {
  109. return IRelationship.Kind.ADVICE_AROUND;
  110. } else if (ak.getKey() == AdviceKind.CflowEntry.getKey() || ak.getKey() == AdviceKind.CflowBelowEntry.getKey()
  111. || ak.getKey() == AdviceKind.InterInitializer.getKey() || ak.getKey() == AdviceKind.PerCflowEntry.getKey()
  112. || ak.getKey() == AdviceKind.PerCflowBelowEntry.getKey() || ak.getKey() == AdviceKind.PerThisEntry.getKey()
  113. || ak.getKey() == AdviceKind.PerTargetEntry.getKey() || ak.getKey() == AdviceKind.Softener.getKey()
  114. || ak.getKey() == AdviceKind.PerTypeWithinEntry.getKey()) {
  115. // System.err.println("Dont want a message about this: "+ak);
  116. return null;
  117. }
  118. throw new RuntimeException("Shadow.determineRelKind: What the hell is it? " + ak);
  119. }
  120. @Override
  121. public void reportMatch(ShadowMunger munger, Shadow shadow) {
  122. if (getCrossReferenceHandler() != null) {
  123. final IRelationship.Kind kind = determineRelKind(munger);
  124. getCrossReferenceHandler().addCrossReference(
  125. munger.getSourceLocation(), // What is being applied?
  126. shadow.getSourceLocation(), // Where is it being applied?
  127. kind == null ? null : kind.getName(), // What kind of advice?
  128. ((Advice) munger).hasDynamicTests() // Is a runtime test being stuffed in the code?
  129. );
  130. }
  131. if (!getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) {
  132. reportWeavingMessage(munger, shadow);
  133. }
  134. if (getModel() != null) {
  135. AsmRelationshipProvider.addAdvisedRelationship(getModelAsAsmManager(), shadow, munger);
  136. }
  137. }
  138. /*
  139. * Report a message about the advice weave that has occurred. Some messing about to make it pretty ! This code is just asking
  140. * for an NPE to occur ...
  141. */
  142. private void reportWeavingMessage(ShadowMunger munger, Shadow shadow) {
  143. Advice advice = (Advice) munger;
  144. AdviceKind aKind = advice.getKind();
  145. // Only report on interesting advice kinds ...
  146. if (aKind == null || advice.getConcreteAspect() == null) {
  147. // We suspect someone is programmatically driving the weaver
  148. // (e.g. IdWeaveTestCase in the weaver testcases)
  149. return;
  150. }
  151. if (!(aKind.equals(AdviceKind.Before) || aKind.equals(AdviceKind.After) || aKind.equals(AdviceKind.AfterReturning)
  152. || aKind.equals(AdviceKind.AfterThrowing) || aKind.equals(AdviceKind.Around) || aKind.equals(AdviceKind.Softener))) {
  153. return;
  154. }
  155. // synchronized blocks are implemented with multiple monitor_exit instructions in the bytecode
  156. // (one for normal exit from the method, one for abnormal exit), we only want to tell the user
  157. // once we have advised the end of the sync block, even though under the covers we will have
  158. // woven both exit points
  159. if (shadow.getKind() == Shadow.SynchronizationUnlock) {
  160. if (advice.lastReportedMonitorExitJoinpointLocation == null) {
  161. // this is the first time through, let's continue...
  162. advice.lastReportedMonitorExitJoinpointLocation = shadow.getSourceLocation();
  163. } else {
  164. if (areTheSame(shadow.getSourceLocation(), advice.lastReportedMonitorExitJoinpointLocation)) {
  165. // Don't report it again!
  166. advice.lastReportedMonitorExitJoinpointLocation = null;
  167. return;
  168. }
  169. // hmmm, this means some kind of nesting is going on, urgh
  170. advice.lastReportedMonitorExitJoinpointLocation = shadow.getSourceLocation();
  171. }
  172. }
  173. String description = advice.getKind().toString();
  174. String advisedType = shadow.getEnclosingType().getName();
  175. String advisingType = advice.getConcreteAspect().getName();
  176. Message msg = null;
  177. if (advice.getKind().equals(AdviceKind.Softener)) {
  178. msg = WeaveMessage.constructWeavingMessage(
  179. WeaveMessage.WEAVEMESSAGE_SOFTENS,
  180. new String[] {
  181. advisedType, beautifyLocation(shadow.getSourceLocation()),
  182. advisingType, beautifyLocation(munger.getSourceLocation())
  183. },
  184. advisedType, advisingType,
  185. shadow.getSourceLocation(), munger.getSourceLocation()
  186. );
  187. }
  188. else {
  189. boolean runtimeTest = advice.hasDynamicTests();
  190. String joinPointDescription = shadow.toString();
  191. msg = WeaveMessage.constructWeavingMessage(
  192. WeaveMessage.WEAVEMESSAGE_ADVISES,
  193. new String[] {
  194. joinPointDescription,
  195. advisedType, beautifyLocation(shadow.getSourceLocation()),
  196. description,
  197. advisingType, beautifyLocation(munger.getSourceLocation()),
  198. (runtimeTest ? " [with runtime test]" : "")
  199. },
  200. advisedType, advisingType,
  201. shadow.getSourceLocation(), munger.getSourceLocation()
  202. );
  203. // Boolean.toString(runtimeTest)});
  204. }
  205. getMessageHandler().handleMessage(msg);
  206. }
  207. private boolean areTheSame(ISourceLocation locA, ISourceLocation locB) {
  208. if (locA == null) {
  209. return locB == null;
  210. }
  211. if (locB == null) {
  212. return false;
  213. }
  214. if (locA.getLine() != locB.getLine()) {
  215. return false;
  216. }
  217. File fA = locA.getSourceFile();
  218. File fB = locA.getSourceFile();
  219. if (fA == null) {
  220. return fB == null;
  221. }
  222. if (fB == null) {
  223. return false;
  224. }
  225. return fA.getName().equals(fB.getName());
  226. }
  227. /*
  228. * Ensure we report a nice source location - particular in the case where the source info is missing (binary weave).
  229. */
  230. private String beautifyLocation(ISourceLocation isl) {
  231. StringBuilder nice = new StringBuilder();
  232. if (isl == null || isl.getSourceFile() == null || isl.getSourceFile().getName().contains("no debug info available")) {
  233. nice.append("no debug info available");
  234. } else {
  235. // can't use File.getName() as this fails when a Linux box encounters a path created on Windows and vice-versa
  236. int takeFrom = isl.getSourceFile().getPath().lastIndexOf('/');
  237. if (takeFrom == -1) {
  238. takeFrom = isl.getSourceFile().getPath().lastIndexOf('\\');
  239. }
  240. int binary = isl.getSourceFile().getPath().lastIndexOf('!');
  241. if (binary != -1 && binary < takeFrom) {
  242. // we have been woven by a binary aspect
  243. String pathToBinaryLoc = isl.getSourceFile().getPath().substring(0, binary + 1);
  244. if (pathToBinaryLoc.contains(".jar")) {
  245. // only want to add the extra info if we're from a jar file
  246. int lastSlash = pathToBinaryLoc.lastIndexOf('/');
  247. if (lastSlash == -1) {
  248. lastSlash = pathToBinaryLoc.lastIndexOf('\\');
  249. }
  250. nice.append(pathToBinaryLoc.substring(lastSlash + 1));
  251. }
  252. }
  253. nice.append(isl.getSourceFile().getPath().substring(takeFrom + 1));
  254. if (isl.getLine() != 0) {
  255. nice.append(":").append(isl.getLine());
  256. }
  257. // if it's a binary file then also want to give the file name
  258. if (isl.getSourceFileName() != null) {
  259. nice.append("(from " + isl.getSourceFileName() + ")");
  260. }
  261. }
  262. return nice.toString();
  263. }
  264. private static List<String> makeDefaultClasspath(String cp) {
  265. List<String> classPath = new ArrayList<>();
  266. classPath.addAll(getPathEntries(cp));
  267. classPath.addAll(getPathEntries(ClassPath.getClassPath()));
  268. return classPath;
  269. }
  270. private static List<String> getPathEntries(String s) {
  271. List<String> ret = new ArrayList<>();
  272. StringTokenizer tok = new StringTokenizer(s, File.pathSeparator);
  273. while (tok.hasMoreTokens()) {
  274. ret.add(tok.nextToken());
  275. }
  276. return ret;
  277. }
  278. public BcelWorld(List classPath, IMessageHandler handler, ICrossReferenceHandler xrefHandler) {
  279. // this.aspectPath = new ClassPathManager(aspectPath, handler);
  280. this.classPath = new ClassPathManager(classPath, handler);
  281. setMessageHandler(handler);
  282. setCrossReferenceHandler(xrefHandler);
  283. // Tell BCEL to use us for resolving any classes
  284. delegate = this;
  285. }
  286. public BcelWorld(ClassPathManager cpm, IMessageHandler handler, ICrossReferenceHandler xrefHandler) {
  287. classPath = cpm;
  288. setMessageHandler(handler);
  289. setCrossReferenceHandler(xrefHandler);
  290. // Tell BCEL to use us for resolving any classes
  291. delegate = this;
  292. }
  293. /**
  294. * Build a World from a ClassLoader, for LTW support
  295. *
  296. * @param loader
  297. * @param handler
  298. * @param xrefHandler
  299. */
  300. public BcelWorld(ClassLoader loader, IMessageHandler handler, ICrossReferenceHandler xrefHandler) {
  301. classPath = null;
  302. loaderRef = new BcelWeakClassLoaderReference(loader);
  303. setMessageHandler(handler);
  304. setCrossReferenceHandler(xrefHandler);
  305. // Tell BCEL to use us for resolving any classes
  306. // delegate = getClassLoaderRepositoryFor(loader);
  307. }
  308. public void ensureRepositorySetup() {
  309. if (delegate == null) {
  310. delegate = getClassLoaderRepositoryFor(loaderRef);
  311. }
  312. }
  313. public Repository getClassLoaderRepositoryFor(ClassLoaderReference loader) {
  314. if (bcelRepositoryCaching) {
  315. return new ClassLoaderRepository(loader);
  316. } else {
  317. return new NonCachingClassLoaderRepository(loader);
  318. }
  319. }
  320. public void addPath(String name) {
  321. classPath.addPath(name, this.getMessageHandler());
  322. }
  323. // ---- various interactions with bcel
  324. public static Type makeBcelType(UnresolvedType type) {
  325. return Type.getType(type.getErasureSignature());
  326. }
  327. static Type[] makeBcelTypes(UnresolvedType[] types) {
  328. Type[] ret = new Type[types.length];
  329. for (int i = 0, len = types.length; i < len; i++) {
  330. ret[i] = makeBcelType(types[i]);
  331. }
  332. return ret;
  333. }
  334. public static Type[] makeBcelTypes(String[] types) {
  335. if (types == null || types.length==0 ) {
  336. return null;
  337. }
  338. Type[] ret = new Type[types.length];
  339. for (int i=0, len=types.length; i<len; i++) {
  340. ret[i] = makeBcelType(types[i]);
  341. }
  342. return ret;
  343. }
  344. public static Type makeBcelType(String type) {
  345. return Type.getType(type);
  346. }
  347. static String[] makeBcelTypesAsClassNames(UnresolvedType[] types) {
  348. String[] ret = new String[types.length];
  349. for (int i = 0, len = types.length; i < len; i++) {
  350. ret[i] = types[i].getName();
  351. }
  352. return ret;
  353. }
  354. public static UnresolvedType fromBcel(Type t) {
  355. return UnresolvedType.forSignature(t.getSignature());
  356. }
  357. static UnresolvedType[] fromBcel(Type[] ts) {
  358. UnresolvedType[] ret = new UnresolvedType[ts.length];
  359. for (int i = 0, len = ts.length; i < len; i++) {
  360. ret[i] = fromBcel(ts[i]);
  361. }
  362. return ret;
  363. }
  364. public ResolvedType resolve(Type t) {
  365. return resolve(fromBcel(t));
  366. }
  367. @Override
  368. protected ReferenceTypeDelegate resolveDelegate(ReferenceType ty) {
  369. String name = ty.getName();
  370. ensureAdvancedConfigurationProcessed();
  371. JavaClass jc = lookupJavaClass(classPath, name);
  372. if (jc == null) {
  373. // Anyone else to ask?
  374. if (typeDelegateResolvers != null) {
  375. for (TypeDelegateResolver tdr : typeDelegateResolvers) {
  376. ReferenceTypeDelegate delegate = tdr.getDelegate(ty);
  377. if (delegate != null) {
  378. return delegate;
  379. }
  380. }
  381. }
  382. return null;
  383. } else {
  384. return buildBcelDelegate(ty, jc, false, false);
  385. }
  386. }
  387. public BcelObjectType buildBcelDelegate(ReferenceType type, JavaClass jc, boolean artificial, boolean exposedToWeaver) {
  388. BcelObjectType ret = new BcelObjectType(type, jc, artificial, exposedToWeaver);
  389. return ret;
  390. }
  391. private JavaClass lookupJavaClass(ClassPathManager classPath, String name) {
  392. if (classPath == null) {
  393. try {
  394. ensureRepositorySetup();
  395. JavaClass jc = delegate.loadClass(name);
  396. if (trace.isTraceEnabled()) {
  397. trace.event("lookupJavaClass", this, new Object[] { name, jc });
  398. }
  399. return jc;
  400. } catch (ClassNotFoundException e) {
  401. if (trace.isTraceEnabled()) {
  402. trace.error("Unable to find class '" + name + "' in repository", e);
  403. }
  404. return null;
  405. }
  406. }
  407. ClassPathManager.ClassFile file = null;
  408. try {
  409. file = classPath.find(UnresolvedType.forName(name));
  410. if (file == null) {
  411. return null;
  412. }
  413. ClassParser parser = new ClassParser(file.getInputStream(), file.getPath());
  414. JavaClass jc = parser.parse();
  415. return jc;
  416. } catch (IOException ioe) {
  417. if (trace.isTraceEnabled()) {
  418. trace.error("IOException whilst processing class",ioe);
  419. }
  420. return null;
  421. } finally {
  422. if (file != null) {
  423. file.close();
  424. }
  425. }
  426. }
  427. public BcelObjectType addSourceObjectType(JavaClass jc, boolean artificial) {
  428. return addSourceObjectType(jc.getClassName(), jc, artificial);
  429. }
  430. public BcelObjectType addSourceObjectType(String classname, JavaClass jc, boolean artificial) {
  431. BcelObjectType ret = null;
  432. if (!jc.getClassName().equals(classname)) {
  433. throw new RuntimeException(jc.getClassName() + "!=" + classname);
  434. }
  435. String signature = UnresolvedType.forName(jc.getClassName()).getSignature();
  436. ResolvedType resolvedTypeFromTypeMap = typeMap.get(signature);
  437. if (resolvedTypeFromTypeMap != null && !(resolvedTypeFromTypeMap instanceof ReferenceType)) {
  438. // what on earth is it then? See pr 112243
  439. StringBuilder exceptionText = new StringBuilder();
  440. exceptionText.append("Found invalid (not a ReferenceType) entry in the type map. ");
  441. exceptionText.append("Signature=[" + signature + "] Found=[" + resolvedTypeFromTypeMap + "] Class=[" + resolvedTypeFromTypeMap.getClass() + "]");
  442. throw new BCException(exceptionText.toString());
  443. }
  444. ReferenceType referenceTypeFromTypeMap = (ReferenceType) resolvedTypeFromTypeMap;
  445. if (referenceTypeFromTypeMap == null) {
  446. if (jc.isGeneric() && isInJava5Mode()) {
  447. ReferenceType rawType = ReferenceType.fromTypeX(UnresolvedType.forRawTypeName(jc.getClassName()), this);
  448. ret = buildBcelDelegate(rawType, jc, artificial, true);
  449. ReferenceType genericRefType = new ReferenceType(UnresolvedType.forGenericTypeSignature(signature,
  450. ret.getDeclaredGenericSignature()), this);
  451. rawType.setDelegate(ret);
  452. genericRefType.setDelegate(ret);
  453. rawType.setGenericType(genericRefType);
  454. typeMap.put(signature, rawType);
  455. } else {
  456. referenceTypeFromTypeMap = new ReferenceType(signature, this);
  457. ret = buildBcelDelegate(referenceTypeFromTypeMap, jc, artificial, true);
  458. typeMap.put(signature, referenceTypeFromTypeMap);
  459. }
  460. } else {
  461. ret = buildBcelDelegate(referenceTypeFromTypeMap, jc, artificial, true);
  462. }
  463. return ret;
  464. }
  465. public BcelObjectType addSourceObjectType(String classname, byte[] bytes, boolean artificial) {
  466. BcelObjectType retval = null;
  467. String signature = UnresolvedType.forName(classname).getSignature();
  468. ResolvedType resolvedTypeFromTypeMap = typeMap.get(signature);
  469. if (resolvedTypeFromTypeMap != null && !(resolvedTypeFromTypeMap instanceof ReferenceType)) {
  470. // what on earth is it then? See pr 112243
  471. StringBuilder exceptionText = new StringBuilder();
  472. exceptionText.append("Found invalid (not a ReferenceType) entry in the type map. ");
  473. exceptionText.append("Signature=[" + signature + "] Found=[" + resolvedTypeFromTypeMap + "] Class=[" + resolvedTypeFromTypeMap.getClass() + "]");
  474. throw new BCException(exceptionText.toString());
  475. }
  476. ReferenceType referenceTypeFromTypeMap = (ReferenceType) resolvedTypeFromTypeMap;
  477. if (referenceTypeFromTypeMap == null) {
  478. JavaClass jc = Utility.makeJavaClass(classname, bytes);
  479. if (jc.isGeneric() && isInJava5Mode()) {
  480. referenceTypeFromTypeMap = ReferenceType.fromTypeX(UnresolvedType.forRawTypeName(jc.getClassName()), this);
  481. retval = buildBcelDelegate(referenceTypeFromTypeMap, jc, artificial, true);
  482. ReferenceType genericRefType = new ReferenceType(UnresolvedType.forGenericTypeSignature(signature,
  483. retval.getDeclaredGenericSignature()), this);
  484. referenceTypeFromTypeMap.setDelegate(retval);
  485. genericRefType.setDelegate(retval);
  486. referenceTypeFromTypeMap.setGenericType(genericRefType);
  487. typeMap.put(signature, referenceTypeFromTypeMap);
  488. } else {
  489. referenceTypeFromTypeMap = new ReferenceType(signature, this);
  490. retval = buildBcelDelegate(referenceTypeFromTypeMap, jc, artificial, true);
  491. typeMap.put(signature, referenceTypeFromTypeMap);
  492. }
  493. } else {
  494. ReferenceTypeDelegate existingDelegate = referenceTypeFromTypeMap.getDelegate();
  495. if (!(existingDelegate instanceof BcelObjectType)) {
  496. throw new IllegalStateException("For " + classname + " should be BcelObjectType, but is " + existingDelegate.getClass());
  497. }
  498. retval = (BcelObjectType) existingDelegate;
  499. // Note1: If the type is already exposed to the weaver (retval.isExposedToWeaver()) then this is likely
  500. // to be a hotswap reweave so build a new delegate, don't accidentally use the old data.
  501. // Note2: Also seen when LTW and another agent precedes the AspectJ agent. Earlier in LTW
  502. // a type is resolved (and ends up in the typemap but not exposed to the weaver at that time)
  503. // then later LTW actually is attempted on this type. We end up here with different
  504. // bytes to the current delegate if the earlier agent has modified them. See PR488216
  505. // if (retval.isArtificial() || retval.isExposedToWeaver()) {
  506. retval = buildBcelDelegate(referenceTypeFromTypeMap, Utility.makeJavaClass(classname, bytes), artificial, true);
  507. // }
  508. }
  509. return retval;
  510. }
  511. void deleteSourceObjectType(UnresolvedType ty) {
  512. typeMap.remove(ty.getSignature());
  513. }
  514. public static Member makeFieldJoinPointSignature(LazyClassGen cg, FieldInstruction fi) {
  515. ConstantPool cpg = cg.getConstantPool();
  516. return MemberImpl.field(fi.getClassName(cpg),
  517. (fi.opcode == Constants.GETSTATIC || fi.opcode == Constants.PUTSTATIC) ? Modifier.STATIC : 0, fi.getName(cpg),
  518. fi.getSignature(cpg));
  519. }
  520. public Member makeJoinPointSignatureFromMethod(LazyMethodGen mg, MemberKind kind) {
  521. Member ret = mg.getMemberView();
  522. if (ret == null) {
  523. int mods = mg.getAccessFlags();
  524. if (mg.getEnclosingClass().isInterface()) {
  525. mods |= Modifier.INTERFACE;
  526. }
  527. return new ResolvedMemberImpl(kind, UnresolvedType.forName(mg.getClassName()), mods, fromBcel(mg.getReturnType()),
  528. mg.getName(), fromBcel(mg.getArgumentTypes()));
  529. } else {
  530. return ret;
  531. }
  532. }
  533. public Member makeJoinPointSignatureForMonitorEnter(LazyClassGen cg, InstructionHandle h) {
  534. return MemberImpl.monitorEnter();
  535. }
  536. public Member makeJoinPointSignatureForMonitorExit(LazyClassGen cg, InstructionHandle h) {
  537. return MemberImpl.monitorExit();
  538. }
  539. public Member makeJoinPointSignatureForArrayConstruction(LazyClassGen cg, InstructionHandle handle) {
  540. Instruction i = handle.getInstruction();
  541. ConstantPool cpg = cg.getConstantPool();
  542. Member retval = null;
  543. if (i.opcode == Constants.ANEWARRAY) {
  544. // ANEWARRAY arrayInstruction = (ANEWARRAY)i;
  545. Type ot = i.getType(cpg);
  546. UnresolvedType ut = fromBcel(ot);
  547. ut = UnresolvedType.makeArray(ut, 1);
  548. retval = MemberImpl.method(ut, Modifier.PUBLIC, UnresolvedType.VOID, "<init>", new ResolvedType[] { INT });
  549. } else if (i instanceof MULTIANEWARRAY) {
  550. MULTIANEWARRAY arrayInstruction = (MULTIANEWARRAY) i;
  551. UnresolvedType ut = null;
  552. short dimensions = arrayInstruction.getDimensions();
  553. ObjectType ot = arrayInstruction.getLoadClassType(cpg);
  554. if (ot != null) {
  555. ut = fromBcel(ot);
  556. ut = UnresolvedType.makeArray(ut, dimensions);
  557. } else {
  558. Type t = arrayInstruction.getType(cpg);
  559. ut = fromBcel(t);
  560. }
  561. ResolvedType[] parms = new ResolvedType[dimensions];
  562. for (int ii = 0; ii < dimensions; ii++) {
  563. parms[ii] = INT;
  564. }
  565. retval = MemberImpl.method(ut, Modifier.PUBLIC, UnresolvedType.VOID, "<init>", parms);
  566. } else if (i.opcode == Constants.NEWARRAY) {
  567. // NEWARRAY arrayInstruction = (NEWARRAY)i;
  568. Type ot = i.getType();
  569. UnresolvedType ut = fromBcel(ot);
  570. retval = MemberImpl.method(ut, Modifier.PUBLIC, UnresolvedType.VOID, "<init>", new ResolvedType[] { INT });
  571. } else {
  572. throw new BCException("Cannot create array construction signature for this non-array instruction:" + i);
  573. }
  574. return retval;
  575. }
  576. public Member makeJoinPointSignatureForMethodInvocation(LazyClassGen cg, InvokeInstruction ii) {
  577. ConstantPool cpg = cg.getConstantPool();
  578. String name = ii.getName(cpg);
  579. String declaring = ii.getClassName(cpg);
  580. UnresolvedType declaringType = null;
  581. String signature = ii.getSignature(cpg);
  582. // 307147
  583. if (name.startsWith("ajc$privMethod$")) {
  584. // The invoke is on a privileged accessor. These may be created for different
  585. // kinds of target, not necessarily just private methods. In bug 307147 it is
  586. // for a private method. This code is identifying the particular case in 307147
  587. try {
  588. declaringType = UnresolvedType.forName(declaring);
  589. String typeNameAsFoundInAccessorName = declaringType.getName().replace('.', '_');
  590. int indexInAccessorName = name.lastIndexOf(typeNameAsFoundInAccessorName);
  591. if (indexInAccessorName != -1) {
  592. String methodName = name.substring(indexInAccessorName+typeNameAsFoundInAccessorName.length()+1);
  593. ResolvedType resolvedDeclaringType = declaringType.resolve(this);
  594. ResolvedMember[] methods = resolvedDeclaringType.getDeclaredMethods();
  595. for (ResolvedMember method: methods) {
  596. if (method.getName().equals(methodName) && method.getSignature().equals(signature) && Modifier.isPrivate(method.getModifiers())) {
  597. return method;
  598. }
  599. }
  600. }
  601. } catch (Exception e) {
  602. // Remove this once confident above code isn't having unexpected side effects
  603. // Added 1.8.7
  604. e.printStackTrace();
  605. }
  606. }
  607. int modifier = (ii instanceof INVOKEINTERFACE) ? Modifier.INTERFACE
  608. : (ii.opcode == Constants.INVOKESTATIC) ? Modifier.STATIC : (ii.opcode == Constants.INVOKESPECIAL && !name
  609. .equals("<init>")) ? Modifier.PRIVATE : 0;
  610. // in Java 1.4 and after, static method call of super class within
  611. // subclass method appears
  612. // as declared by the subclass in the bytecode - but they are not
  613. // see #104212
  614. if (ii.opcode == Constants.INVOKESTATIC) {
  615. ResolvedType appearsDeclaredBy = resolve(declaring);
  616. // look for the method there
  617. for (Iterator<ResolvedMember> iterator = appearsDeclaredBy.getMethods(true, true); iterator.hasNext();) {
  618. ResolvedMember method = iterator.next();
  619. if (Modifier.isStatic(method.getModifiers())) {
  620. if (name.equals(method.getName()) && signature.equals(method.getSignature())) {
  621. // we found it
  622. declaringType = method.getDeclaringType();
  623. break;
  624. }
  625. }
  626. }
  627. }
  628. if (declaringType == null) {
  629. if (declaring.charAt(0) == '[') {
  630. declaringType = UnresolvedType.forSignature(declaring);
  631. } else {
  632. declaringType = UnresolvedType.forName(declaring);
  633. }
  634. }
  635. return MemberImpl.method(declaringType, modifier, name, signature);
  636. }
  637. @Override
  638. public String toString() {
  639. StringBuilder buf = new StringBuilder();
  640. buf.append("BcelWorld(");
  641. // buf.append(shadowMungerMap);
  642. buf.append(")");
  643. return buf.toString();
  644. }
  645. /**
  646. * Retrieve a bcel delegate for an aspect - this will return NULL if the delegate is an EclipseSourceType and not a
  647. * BcelObjectType - this happens quite often when incrementally compiling.
  648. */
  649. public static BcelObjectType getBcelObjectType(ResolvedType concreteAspect) {
  650. if (concreteAspect == null) {
  651. return null;
  652. }
  653. if (!(concreteAspect instanceof ReferenceType)) { // Might be Missing
  654. return null;
  655. }
  656. ReferenceTypeDelegate rtDelegate = ((ReferenceType) concreteAspect).getDelegate();
  657. if (rtDelegate instanceof BcelObjectType) {
  658. return (BcelObjectType) rtDelegate;
  659. } else {
  660. return null;
  661. }
  662. }
  663. public void tidyUp() {
  664. // At end of compile, close any open files so deletion of those archives
  665. // is possible
  666. classPath.closeArchives();
  667. typeMap.report();
  668. typeMap.demote(true);
  669. // ResolvedType.resetPrimitives();
  670. }
  671. // / The repository interface methods
  672. @Override
  673. public JavaClass findClass(String className) {
  674. return lookupJavaClass(classPath, className);
  675. }
  676. @Override
  677. public JavaClass loadClass(String className) throws ClassNotFoundException {
  678. return lookupJavaClass(classPath, className);
  679. }
  680. @Override
  681. public void storeClass(JavaClass clazz) {
  682. // doesn't need to do anything
  683. }
  684. @Override
  685. public void removeClass(JavaClass clazz) {
  686. throw new RuntimeException("Not implemented");
  687. }
  688. @Override
  689. public JavaClass loadClass(Class clazz) throws ClassNotFoundException {
  690. throw new RuntimeException("Not implemented");
  691. }
  692. @Override
  693. public void clear() {
  694. delegate.clear();
  695. // throw new RuntimeException("Not implemented");
  696. }
  697. /**
  698. * The aim of this method is to make sure a particular type is 'ok'. Some operations on the delegate for a type modify it and
  699. * this method is intended to undo that... see pr85132
  700. */
  701. @Override
  702. public void validateType(UnresolvedType type) {
  703. ResolvedType result = typeMap.get(type.getSignature());
  704. if (result == null) {
  705. return; // We haven't heard of it yet
  706. }
  707. if (!result.isExposedToWeaver()) {
  708. return; // cant need resetting
  709. }
  710. result.ensureConsistent();
  711. // If we want to rebuild it 'from scratch' then:
  712. // ClassParser cp = new ClassParser(new
  713. // ByteArrayInputStream(newbytes),new String(cs));
  714. // try {
  715. // rt.setDelegate(makeBcelObjectType(rt,cp.parse(),true));
  716. // } catch (ClassFormatException e) {
  717. // e.printStackTrace();
  718. // } catch (IOException e) {
  719. // e.printStackTrace();
  720. // }
  721. }
  722. /**
  723. * Apply a single declare parents - return true if we change the type
  724. */
  725. private boolean applyDeclareParents(DeclareParents p, ResolvedType onType) {
  726. boolean didSomething = false;
  727. List<ResolvedType> newParents = p.findMatchingNewParents(onType, true);
  728. if (!newParents.isEmpty()) {
  729. didSomething = true;
  730. BcelObjectType classType = BcelWorld.getBcelObjectType(onType);
  731. // System.err.println("need to do declare parents for: " + onType);
  732. for (ResolvedType newParent : newParents) {
  733. // We set it here so that the imminent matching for ITDs can
  734. // succeed - we still haven't done the necessary changes to the class file
  735. // itself (like transform super calls) - that is done in
  736. // BcelTypeMunger.mungeNewParent()
  737. // classType.addParent(newParent);
  738. onType.addParent(newParent);
  739. ResolvedTypeMunger newParentMunger = new NewParentTypeMunger(newParent, p.getDeclaringType());
  740. newParentMunger.setSourceLocation(p.getSourceLocation());
  741. onType.addInterTypeMunger(new BcelTypeMunger(newParentMunger, getCrosscuttingMembersSet()
  742. .findAspectDeclaringParents(p)), false);
  743. }
  744. }
  745. return didSomething;
  746. }
  747. /**
  748. * Apply a declare @type - return true if we change the type
  749. */
  750. private boolean applyDeclareAtType(DeclareAnnotation decA, ResolvedType onType, boolean reportProblems) {
  751. boolean didSomething = false;
  752. if (decA.matches(onType)) {
  753. if (onType.hasAnnotation(decA.getAnnotation().getType())) {
  754. // already has it
  755. return false;
  756. }
  757. AnnotationAJ annoX = decA.getAnnotation();
  758. // check the annotation is suitable for the target
  759. boolean isOK = checkTargetOK(decA, onType, annoX);
  760. if (isOK) {
  761. didSomething = true;
  762. ResolvedTypeMunger newAnnotationTM = new AnnotationOnTypeMunger(annoX);
  763. newAnnotationTM.setSourceLocation(decA.getSourceLocation());
  764. onType.addInterTypeMunger(new BcelTypeMunger(newAnnotationTM, decA.getAspect().resolve(this)), false);
  765. decA.copyAnnotationTo(onType);
  766. }
  767. }
  768. return didSomething;
  769. }
  770. /**
  771. * Apply the specified declare @field construct to any matching fields in the specified type.
  772. * @param deca the declare annotation targeting fields
  773. * @param type the type to check for members matching the declare annotation
  774. * @return true if something matched and the type was modified
  775. */
  776. private boolean applyDeclareAtField(DeclareAnnotation deca, ResolvedType type) {
  777. boolean changedType = false;
  778. ResolvedMember[] fields = type.getDeclaredFields();
  779. for (ResolvedMember field: fields) {
  780. if (deca.matches(field, this)) {
  781. AnnotationAJ anno = deca.getAnnotation();
  782. if (!field.hasAnnotation(anno.getType())) {
  783. field.addAnnotation(anno);
  784. changedType=true;
  785. }
  786. }
  787. }
  788. return changedType;
  789. }
  790. /**
  791. * Checks for an @target() on the annotation and if found ensures it allows the annotation to be attached to the target type
  792. * that matched.
  793. */
  794. private boolean checkTargetOK(DeclareAnnotation decA, ResolvedType onType, AnnotationAJ annoX) {
  795. if (annoX.specifiesTarget()) {
  796. if ((onType.isAnnotation() && !annoX.allowedOnAnnotationType()) || (!annoX.allowedOnRegularType())) {
  797. return false;
  798. }
  799. }
  800. return true;
  801. }
  802. // Hmmm - very similar to the code in BcelWeaver.weaveParentTypeMungers -
  803. // this code
  804. // doesn't need to produce errors/warnings though as it won't really be
  805. // weaving.
  806. protected void weaveInterTypeDeclarations(ResolvedType onType) {
  807. List<DeclareParents> declareParentsList = getCrosscuttingMembersSet().getDeclareParents();
  808. if (onType.isRawType()) {
  809. onType = onType.getGenericType();
  810. }
  811. onType.clearInterTypeMungers();
  812. List<DeclareParents> decpToRepeat = new ArrayList<>();
  813. boolean aParentChangeOccurred = false;
  814. boolean anAnnotationChangeOccurred = false;
  815. // First pass - apply all decp mungers
  816. for (DeclareParents decp : declareParentsList) {
  817. boolean typeChanged = applyDeclareParents(decp, onType);
  818. if (typeChanged) {
  819. aParentChangeOccurred = true;
  820. } else { // Perhaps it would have matched if a 'dec @type' had
  821. // modified the type
  822. if (!decp.getChild().isStarAnnotation()) {
  823. decpToRepeat.add(decp);
  824. }
  825. }
  826. }
  827. // Still first pass - apply all dec @type mungers
  828. for (DeclareAnnotation decA : getCrosscuttingMembersSet().getDeclareAnnotationOnTypes()) {
  829. boolean typeChanged = applyDeclareAtType(decA, onType, true);
  830. if (typeChanged) {
  831. anAnnotationChangeOccurred = true;
  832. }
  833. }
  834. // apply declare @field
  835. for (DeclareAnnotation deca: getCrosscuttingMembersSet().getDeclareAnnotationOnFields()) {
  836. if (applyDeclareAtField(deca,onType)) {
  837. anAnnotationChangeOccurred = true;
  838. }
  839. }
  840. while ((aParentChangeOccurred || anAnnotationChangeOccurred) && !decpToRepeat.isEmpty()) {
  841. anAnnotationChangeOccurred = aParentChangeOccurred = false;
  842. List<DeclareParents> decpToRepeatNextTime = new ArrayList<>();
  843. for (DeclareParents decp: decpToRepeat) {
  844. if (applyDeclareParents(decp, onType)) {
  845. aParentChangeOccurred = true;
  846. } else {
  847. decpToRepeatNextTime.add(decp);
  848. }
  849. }
  850. for (DeclareAnnotation deca: getCrosscuttingMembersSet().getDeclareAnnotationOnTypes()) {
  851. if (applyDeclareAtType(deca, onType, false)) {
  852. anAnnotationChangeOccurred = true;
  853. }
  854. }
  855. for (DeclareAnnotation deca: getCrosscuttingMembersSet().getDeclareAnnotationOnFields()) {
  856. if (applyDeclareAtField(deca, onType)) {
  857. anAnnotationChangeOccurred = true;
  858. }
  859. }
  860. decpToRepeat = decpToRepeatNextTime;
  861. }
  862. }
  863. @Override
  864. public IWeavingSupport getWeavingSupport() {
  865. return bcelWeavingSupport;
  866. }
  867. @Override
  868. public void reportCheckerMatch(Checker checker, Shadow shadow) {
  869. IMessage iMessage = new Message(checker.getMessage(shadow), shadow.toString(), checker.isError() ? IMessage.ERROR
  870. : IMessage.WARNING, shadow.getSourceLocation(), null, new ISourceLocation[] { checker.getSourceLocation() }, true,
  871. 0, -1, -1);
  872. getMessageHandler().handleMessage(iMessage);
  873. if (getCrossReferenceHandler() != null) {
  874. getCrossReferenceHandler()
  875. .addCrossReference(
  876. checker.getSourceLocation(),
  877. shadow.getSourceLocation(),
  878. (checker.isError() ? IRelationship.Kind.DECLARE_ERROR.getName() : IRelationship.Kind.DECLARE_WARNING
  879. .getName()), false);
  880. }
  881. if (getModel() != null) {
  882. AsmRelationshipProvider.addDeclareErrorOrWarningRelationship(getModelAsAsmManager(), shadow, checker);
  883. }
  884. }
  885. public AsmManager getModelAsAsmManager() {
  886. return (AsmManager) getModel(); // For now... always an AsmManager in a bcel environment
  887. }
  888. void raiseError(String message) {
  889. getMessageHandler().handleMessage(MessageUtil.error(message));
  890. }
  891. /**
  892. * These are aop.xml files that can be used to alter the aspects that actually apply from those passed in - and also their scope
  893. * of application to other files in the system.
  894. *
  895. * @param xmlFiles list of File objects representing any aop.xml files passed in to configure the build process
  896. */
  897. public void setXmlFiles(List<File> xmlFiles) {
  898. if (!isXmlConfiguredWorld && !xmlFiles.isEmpty()) {
  899. raiseError("xml configuration files only supported by the compiler when -xmlConfigured option specified");
  900. return;
  901. }
  902. if (!xmlFiles.isEmpty()) {
  903. xmlConfiguration = new WeavingXmlConfig(this, WeavingXmlConfig.MODE_COMPILE);
  904. }
  905. for (File xmlfile : xmlFiles) {
  906. try {
  907. Definition d = DocumentParser.parse(xmlfile.toURI().toURL());
  908. xmlConfiguration.add(d);
  909. } catch (MalformedURLException e) {
  910. raiseError("Unexpected problem processing XML config file '" + xmlfile.getName() + "' :" + e.getMessage());
  911. } catch (Exception e) {
  912. raiseError("Unexpected problem processing XML config file '" + xmlfile.getName() + "' :" + e.getMessage());
  913. }
  914. }
  915. }
  916. /**
  917. * Add a scoped aspects where the scoping was defined in an aop.xml file and this world is being used in a LTW configuration
  918. */
  919. public void addScopedAspect(String name, String scope) {
  920. this.isXmlConfiguredWorld = true;
  921. if (xmlConfiguration == null) {
  922. xmlConfiguration = new WeavingXmlConfig(this, WeavingXmlConfig.MODE_LTW);
  923. }
  924. xmlConfiguration.addScopedAspect(name, scope);
  925. }
  926. public void setXmlConfigured(boolean b) {
  927. this.isXmlConfiguredWorld = b;
  928. }
  929. @Override
  930. public boolean isXmlConfigured() {
  931. return isXmlConfiguredWorld && xmlConfiguration != null;
  932. }
  933. public WeavingXmlConfig getXmlConfiguration() {
  934. return xmlConfiguration;
  935. }
  936. @Override
  937. public boolean isAspectIncluded(ResolvedType aspectType) {
  938. if (!isXmlConfigured()) {
  939. return true;
  940. }
  941. return xmlConfiguration.specifiesInclusionOfAspect(aspectType.getName());
  942. }
  943. @Override
  944. public TypePattern getAspectScope(ResolvedType declaringType) {
  945. return xmlConfiguration.getScopeFor(declaringType.getName());
  946. }
  947. @Override
  948. public boolean hasUnsatisfiedDependency(ResolvedType aspectType) {
  949. String aspectName = aspectType.getName();
  950. if (aspectType.hasAnnotations()) {
  951. AnnotationAJ[] annos = aspectType.getAnnotations();
  952. for (AnnotationAJ anno: annos) {
  953. if (anno.getTypeName().equals("org.aspectj.lang.annotation.RequiredTypes")) {
  954. String values = anno.getStringFormOfValue("value"); // Example: "[A,org.foo.Bar]"
  955. if (values != null && values.length() > 2) {
  956. values = values.substring(1,values.length()-1);
  957. StringTokenizer tokenizer = new StringTokenizer(values,",");
  958. boolean anythingMissing = false;
  959. while (tokenizer.hasMoreElements()) {
  960. String requiredTypeName = tokenizer.nextToken();
  961. ResolvedType rt = resolve(UnresolvedType.forName(requiredTypeName));
  962. if (rt.isMissing()) {
  963. if (!getMessageHandler().isIgnoring(IMessage.INFO)) {
  964. getMessageHandler().handleMessage(
  965. MessageUtil.info("deactivating aspect '" + aspectName + "' as it requires type '"
  966. + requiredTypeName + "' which cannot be found on the classpath"));
  967. }
  968. anythingMissing = true;
  969. if (aspectRequiredTypes == null) {
  970. aspectRequiredTypes = new HashMap<>();
  971. }
  972. // Record that it has an invalid type reference
  973. aspectRequiredTypes.put(aspectName,requiredTypeName);
  974. }
  975. }
  976. if (anythingMissing) {
  977. return true;
  978. }
  979. else {
  980. return false;
  981. }
  982. }
  983. else {
  984. // no value specified for annotation
  985. return false;
  986. }
  987. }
  988. }
  989. }
  990. if (aspectRequiredTypes == null) {
  991. // no aspects require anything, so there can be no unsatisfied dependencies
  992. return false;
  993. }
  994. if (!aspectRequiredTypesProcessed.contains(aspectName)) {
  995. String requiredTypeName = aspectRequiredTypes.get(aspectName);
  996. if (requiredTypeName==null) {
  997. aspectRequiredTypesProcessed.add(aspectName);
  998. return false;
  999. } else {
  1000. ResolvedType rt = resolve(UnresolvedType.forName(requiredTypeName));
  1001. if (!rt.isMissing()) {
  1002. aspectRequiredTypesProcessed.add(aspectName);
  1003. aspectRequiredTypes.remove(aspectName);
  1004. return false;
  1005. } else {
  1006. if (!getMessageHandler().isIgnoring(IMessage.INFO)) {
  1007. getMessageHandler().handleMessage(
  1008. MessageUtil.info("deactivating aspect '" + aspectName + "' as it requires type '"
  1009. + requiredTypeName + "' which cannot be found on the classpath"));
  1010. }
  1011. aspectRequiredTypesProcessed.add(aspectName);
  1012. return true;
  1013. }
  1014. }
  1015. }
  1016. return aspectRequiredTypes.containsKey(aspectName);
  1017. }
  1018. private List<String> aspectRequiredTypesProcessed = new ArrayList<>();
  1019. private Map<String, String> aspectRequiredTypes = null;
  1020. public void addAspectRequires(String aspectClassName, String requiredType) {
  1021. if (aspectRequiredTypes == null) {
  1022. aspectRequiredTypes = new HashMap<>();
  1023. }
  1024. aspectRequiredTypes.put(aspectClassName,requiredType);
  1025. }
  1026. /**
  1027. * A WeavingXmlConfig is initially a collection of definitions from XML files - once the world is ready and weaving is running
  1028. * it will initialize and transform those definitions into an optimized set of values (eg. resolve type patterns and string
  1029. * names to real entities). It can then answer questions quickly: (1) is this aspect included in the weaving? (2) Is there a
  1030. * scope specified for this aspect and does it include type X?
  1031. *
  1032. */
  1033. static class WeavingXmlConfig {
  1034. final static int MODE_COMPILE = 1;
  1035. final static int MODE_LTW = 2;
  1036. private int mode;
  1037. private boolean initialized = false; // Lazily done
  1038. private List<Definition> definitions = new ArrayList<>();
  1039. private List<String> resolvedIncludedAspects = new ArrayList<>();
  1040. private Map<String, TypePattern> scopes = new HashMap<>();
  1041. // these are not set for LTW mode (exclusion of these fast match patterns is handled before the weaver/world are used)
  1042. private List<String> includedFastMatchPatterns = Collections.emptyList();
  1043. private List<TypePattern> includedPatterns = Collections.emptyList();
  1044. private List<String> excludedFastMatchPatterns = Collections.emptyList();
  1045. private List<TypePattern> excludedPatterns = Collections.emptyList();
  1046. private BcelWorld world;
  1047. public WeavingXmlConfig(BcelWorld bcelWorld, int mode) {
  1048. this.world = bcelWorld;
  1049. this.mode = mode;
  1050. }
  1051. public void add(Definition d) {
  1052. definitions.add(d);
  1053. }
  1054. public void addScopedAspect(String aspectName, String scope) {
  1055. ensureInitialized();
  1056. resolvedIncludedAspects.add(aspectName);
  1057. try {
  1058. TypePattern scopePattern = new PatternParser(scope).parseTypePattern();
  1059. scopePattern.resolve(world);
  1060. scopes.put(aspectName, scopePattern);
  1061. if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) {
  1062. world.getMessageHandler().handleMessage(
  1063. MessageUtil.info("Aspect '" + aspectName + "' is scoped to apply against types matching pattern '"
  1064. + scopePattern + "'"));
  1065. }
  1066. } catch (Exception e) {
  1067. world.getMessageHandler().handleMessage(
  1068. MessageUtil.error("Unable to parse scope as type pattern. Scope was '" + scope + "': " + e.getMessage()));
  1069. }
  1070. }
  1071. public void ensureInitialized() {
  1072. if (!initialized) {
  1073. try {
  1074. resolvedIncludedAspects = new ArrayList<>();
  1075. // Process the definitions into something more optimal
  1076. for (Definition definition : definitions) {
  1077. List<String> aspectNames = definition.getAspectClassNames();
  1078. for (String name : aspectNames) {
  1079. resolvedIncludedAspects.add(name);
  1080. // TODO check for existence?
  1081. // ResolvedType resolvedAspect = resolve(UnresolvedType.forName(name));
  1082. // if (resolvedAspect.isMissing()) {
  1083. // // ERROR
  1084. // } else {
  1085. // resolvedIncludedAspects.add(resolvedAspect);
  1086. // }
  1087. String scope = definition.getScopeForAspect(name);
  1088. if (scope != null) {
  1089. // Resolve the type pattern
  1090. try {
  1091. TypePattern scopePattern = new PatternParser(scope).parseTypePattern();
  1092. scopePattern.resolve(world);
  1093. scopes.put(name, scopePattern);
  1094. if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) {
  1095. world.getMessageHandler().handleMessage(
  1096. MessageUtil.info("Aspect '" + name
  1097. + "' is scoped to apply against types matching pattern '"
  1098. + scopePattern.toString() + "'"));
  1099. }
  1100. } catch (Exception e) {
  1101. // TODO definitions should remember which file they came from, for inclusion in this message
  1102. world.getMessageHandler().handleMessage(
  1103. MessageUtil.error("Unable to parse scope as type pattern. Scope was '" + scope + "': "
  1104. + e.getMessage()));
  1105. }
  1106. }
  1107. }
  1108. try {
  1109. List<String> includePatterns = definition.getIncludePatterns();
  1110. if (includePatterns.size() > 0) {
  1111. includedPatterns = new ArrayList<>();
  1112. includedFastMatchPatterns = new ArrayList<>();
  1113. }
  1114. for (String includePattern : includePatterns) {
  1115. if (includePattern.endsWith("..*")) {
  1116. // from 'blah.blah.blah..*' leave the 'blah.blah.blah.'
  1117. includedFastMatchPatterns.add(includePattern.substring(0, includePattern.length() - 2));
  1118. } else {
  1119. TypePattern includedPattern = new PatternParser(includePattern).parseTypePattern();
  1120. includedPatterns.add(includedPattern);
  1121. }
  1122. }
  1123. List<String> excludePatterns = definition.getExcludePatterns();
  1124. if (excludePatterns.size() > 0) {
  1125. excludedPatterns = new ArrayList<>();
  1126. excludedFastMatchPatterns = new ArrayList<>();
  1127. }
  1128. for (String excludePattern : excludePatterns) {
  1129. if (excludePattern.endsWith("..*")) {
  1130. // from 'blah.blah.blah..*' leave the 'blah.blah.blah.'
  1131. excludedFastMatchPatterns.add(excludePattern.substring(0, excludePattern.length() - 2));
  1132. } else {
  1133. TypePattern excludedPattern = new PatternParser(excludePattern).parseTypePattern();
  1134. excludedPatterns.add(excludedPattern);
  1135. }
  1136. }
  1137. } catch (ParserException pe) {
  1138. // TODO definitions should remember which file they came from, for inclusion in this message
  1139. world.getMessageHandler().handleMessage(
  1140. MessageUtil.error("Unable to parse type pattern: " + pe.getMessage()));
  1141. }
  1142. }
  1143. } finally {
  1144. initialized = true;
  1145. }
  1146. }
  1147. }
  1148. public boolean specifiesInclusionOfAspect(String name) {
  1149. ensureInitialized();
  1150. return resolvedIncludedAspects.contains(name);
  1151. }
  1152. public TypePattern getScopeFor(String name) {
  1153. return scopes.get(name);
  1154. }
  1155. /**
  1156. * Checks if a given type is to be excluded from weaving.
  1157. * <p>
  1158. * For LTW, the development guide (<i>docs/devguide/ltw.adoc</i>) says:
  1159. * <p>
  1160. * <i>"The set of types to be woven are those types matched by at least one weaver {@code include} element and not
  1161. * matched by any weaver {@code exclude} element. If there are no weaver include statements, then all non-excluded
  1162. * types are included."</i>
  1163. * <p>
  1164. * In CTW mode, we cannot quite follow the same rules for exclusion as used for LTW: If the weaver is seeing it
  1165. * during this kind of build, the type is implicitly included. So all we should check for is exclusion.
  1166. *
  1167. * @param type resolved type to be checked
  1168. *
  1169. * @return Always false in LTW mode. In CTW mode true for excluded types, false otherwise.
  1170. */
  1171. public boolean excludesType(ResolvedType type) {
  1172. if (mode == MODE_LTW) {
  1173. return false;
  1174. }
  1175. String typename = type.getName();
  1176. boolean excluded = false;
  1177. for (String excludedPattern : excludedFastMatchPatterns) {
  1178. if (typename.startsWith(excludedPattern)) {
  1179. excluded = true;
  1180. break;
  1181. }
  1182. }
  1183. if (!excluded) {
  1184. for (TypePattern excludedPattern : excludedPatterns) {
  1185. if (excludedPattern.matchesStatically(type)) {
  1186. excluded = true;
  1187. break;
  1188. }
  1189. }
  1190. }
  1191. return excluded;
  1192. }
  1193. }
  1194. @Override
  1195. public TypeMap getTypeMap() {
  1196. return typeMap;
  1197. }
  1198. @Override
  1199. public boolean isLoadtimeWeaving() {
  1200. return false;
  1201. }
  1202. public void addTypeDelegateResolver(TypeDelegateResolver typeDelegateResolver) {
  1203. if (typeDelegateResolvers == null) {
  1204. typeDelegateResolvers = new ArrayList<>();
  1205. }
  1206. typeDelegateResolvers.add(typeDelegateResolver);
  1207. }
  1208. @Override
  1209. public void classWriteEvent(char[][] compoundName) {
  1210. typeMap.classWriteEvent(new String(CharOperation.concatWith(compoundName, '.')));
  1211. }
  1212. /**
  1213. * Force demote a type.
  1214. */
  1215. public void demote(ResolvedType type) {
  1216. typeMap.demote(type);
  1217. }
  1218. }