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.

ResolvedTypeMunger.java 17KB

15 years ago
15 years ago
14 years ago
15 years ago
14 years ago
15 years ago
14 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
14 years ago
15 years ago
14 years ago
15 years ago
15 years ago
14 years ago
15 years ago
14 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
14 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
14 years ago
15 years ago
15 years ago
15 years ago
15 years ago
14 years ago
15 years ago
14 years ago
15 years ago
14 years ago
15 years ago
15 years ago
15 years ago
15 years ago
15 years ago
14 years ago
15 years ago
14 years ago
15 years ago
15 years ago
15 years ago
15 years ago
14 years ago
15 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  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 @AspectJ ITDs
  12. * ******************************************************************/
  13. package org.aspectj.weaver;
  14. import java.io.DataInputStream;
  15. import java.io.DataOutputStream;
  16. import java.io.EOFException;
  17. import java.io.File;
  18. import java.io.IOException;
  19. import java.io.ObjectInputStream;
  20. import java.io.ObjectOutputStream;
  21. import java.util.ArrayList;
  22. import java.util.Collections;
  23. import java.util.HashSet;
  24. import java.util.List;
  25. import java.util.Map;
  26. import java.util.Set;
  27. import org.aspectj.bridge.ISourceLocation;
  28. import org.aspectj.bridge.SourceLocation;
  29. import org.aspectj.util.TypeSafeEnum;
  30. /**
  31. * This is an abstraction over method/field introduction. It might not have the chops to handle other inter-type declarations. This
  32. * is the thing that is used on the eclipse side and serialized into a ConcreteTypeMunger.
  33. */
  34. public abstract class ResolvedTypeMunger {
  35. protected Kind kind;
  36. protected ResolvedMember signature;
  37. /**
  38. * The declared signature is filled in when a type munger is parameterized for application to a particular type. It represents
  39. * the signature originally declared in the source file.
  40. */
  41. protected ResolvedMember declaredSignature;
  42. // This list records the occurences (in order) of any names specified in the <>
  43. // for a target type for the ITD. So for example, for List<C,B,A> this list
  44. // will be C,B,A - the list is used later to map other occurrences of C,B,A
  45. // across the intertype declaration to the right type variables in the generic
  46. // type upon which the itd is being made.
  47. // might need serializing the class file for binary weaving.
  48. protected List<String> typeVariableAliases;
  49. private Set<ResolvedMember> superMethodsCalled = Collections.emptySet();
  50. private ISourceLocation location;
  51. private ResolvedType onType = null;
  52. public ResolvedTypeMunger(Kind kind, ResolvedMember signature) {
  53. this.kind = kind;
  54. this.signature = signature;
  55. UnresolvedType declaringType = signature != null ? signature.getDeclaringType() : null;
  56. if (declaringType != null) {
  57. if (declaringType.isRawType()) {
  58. throw new IllegalStateException("Use generic type, not raw type");
  59. }
  60. if (declaringType.isParameterizedType()) {
  61. throw new IllegalStateException("Use generic type, not parameterized type");
  62. }
  63. }
  64. // boolean aChangeOccurred = false;
  65. //
  66. // UnresolvedType rt = signature.getReturnType();
  67. // if (rt.isParameterizedType() || rt.isGenericType()) {rt = rt.getRawType();aChangeOccurred=true;}
  68. // UnresolvedType[] pt = signature.getParameterTypes();
  69. // for (int i = 0; i < pt.length; i++) {
  70. // if (pt[i].isParameterizedType() || pt[i].isGenericType()) { pt[i] = pt[i].getRawType();aChangeOccurred=true;}
  71. // }
  72. // if (aChangeOccurred) {
  73. // this.signature = new
  74. // ResolvedMemberImpl(signature.getKind(),signature.getDeclaringType(),signature.getModifiers(),rt,signature
  75. // .getName(),pt,signature.getExceptions());
  76. // }
  77. }
  78. public void setSourceLocation(ISourceLocation isl) {
  79. location = isl;
  80. }
  81. public ISourceLocation getSourceLocation() {
  82. return location;
  83. }
  84. // ----
  85. // fromType is guaranteed to be a non-abstract aspect
  86. // public ConcreteTypeMunger concretize(World world, ResolvedType aspectType) {
  87. //
  88. // ConcreteTypeMunger munger = world.concreteTypeMunger(this, aspectType);
  89. // return munger;
  90. // }
  91. public boolean matches(ResolvedType matchType, ResolvedType aspectType) {
  92. if (onType == null) {
  93. onType = matchType.getWorld().resolve(getDeclaringType());
  94. if (onType.isRawType()) {
  95. onType = onType.getGenericType();
  96. }
  97. }
  98. // System.err.println("matching: " + this + " to " + matchType + " onType = " + onType);
  99. if (matchType.equals(onType)) {
  100. if (!onType.isExposedToWeaver()) {
  101. // if the onType is an interface, and it already has the member we are about
  102. // to munge, then this is ok...
  103. boolean ok = (onType.isInterface() && (onType.lookupMemberWithSupersAndITDs(getSignature()) != null));
  104. if (!ok && onType.getWeaverState() == null) {
  105. if (matchType.getWorld().getLint().typeNotExposedToWeaver.isEnabled()) {
  106. matchType.getWorld().getLint().typeNotExposedToWeaver.signal(matchType.getName(), signature
  107. .getSourceLocation());
  108. }
  109. }
  110. }
  111. return true;
  112. }
  113. // System.err.println("NO MATCH DIRECT");
  114. if (onType.isInterface()) {
  115. return matchType.isTopmostImplementor(onType);
  116. } else {
  117. return false;
  118. }
  119. }
  120. // ----
  121. @Override
  122. public String toString() {
  123. return "ResolvedTypeMunger(" + getKind() + ", " + getSignature() + ")";
  124. // .superMethodsCalled + ")";
  125. }
  126. // ----
  127. public static ResolvedTypeMunger read(VersionedDataInputStream s, ISourceContext context) throws IOException {
  128. Kind kind = Kind.read(s);
  129. if (kind == Field) {
  130. return NewFieldTypeMunger.readField(s, context);
  131. } else if (kind == Method) {
  132. return NewMethodTypeMunger.readMethod(s, context);
  133. } else if (kind == Constructor) {
  134. return NewConstructorTypeMunger.readConstructor(s, context);
  135. } else if (kind == MethodDelegate) {
  136. return MethodDelegateTypeMunger.readMethod(s, context, false);
  137. } else if (kind == FieldHost) {
  138. return MethodDelegateTypeMunger.FieldHostTypeMunger.readFieldHost(s, context);
  139. } else if (kind == MethodDelegate2) {
  140. return MethodDelegateTypeMunger.readMethod(s, context, true);
  141. } else if (kind == InnerClass) {
  142. return NewMemberClassTypeMunger.readInnerClass(s, context);
  143. } else {
  144. throw new RuntimeException("unimplemented");
  145. }
  146. }
  147. protected static Set<ResolvedMember> readSuperMethodsCalled(VersionedDataInputStream s) throws IOException {
  148. Set<ResolvedMember> ret = new HashSet<>();
  149. int n = -1;
  150. if (s.isAtLeast169()) {
  151. n = s.readByte();
  152. } else {
  153. n = s.readInt();
  154. }
  155. if (n < 0) {
  156. throw new BCException("Problem deserializing type munger");
  157. }
  158. for (int i = 0; i < n; i++) {
  159. ret.add(ResolvedMemberImpl.readResolvedMember(s, null));
  160. }
  161. return ret;
  162. }
  163. protected final void writeSuperMethodsCalled(CompressingDataOutputStream s) throws IOException {
  164. if (superMethodsCalled == null || superMethodsCalled.size() == 0) {
  165. s.writeByte(0);
  166. return;
  167. }
  168. List<ResolvedMember> ret = new ArrayList<>(superMethodsCalled);
  169. Collections.sort(ret);
  170. int n = ret.size();
  171. s.writeByte(n);
  172. for (ResolvedMember m : ret) {
  173. m.write(s);
  174. }
  175. }
  176. protected static ISourceLocation readSourceLocation(VersionedDataInputStream s) throws IOException {
  177. // Location persistence for type mungers was added after 1.2.1 was shipped...
  178. if (s.getMajorVersion() < AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
  179. return null;
  180. }
  181. SourceLocation ret = null;
  182. ObjectInputStream ois = null;
  183. try {
  184. // This logic copes with the location missing from the attribute - an EOFException will
  185. // occur on the next line and we ignore it.
  186. byte b = 0;
  187. // if we aren't on 1.6.9 or we are on 1.6.9 but not compressed, then read as object stream
  188. if (!s.isAtLeast169() || (b = s.readByte()) == 0) {
  189. ois = new ObjectInputStream(s);
  190. boolean validLocation = (Boolean) ois.readObject();
  191. if (validLocation) {
  192. File f = (File) ois.readObject();
  193. Integer ii = (Integer) ois.readObject();
  194. Integer offset = (Integer) ois.readObject();
  195. ret = new SourceLocation(f, ii);
  196. ret.setOffset(offset);
  197. }
  198. } else {
  199. boolean validLocation = b == 2;
  200. if (validLocation) {
  201. String path = s.readUtf8(s.readShort());
  202. File f = new File(path);
  203. ret = new SourceLocation(f, s.readInt());
  204. int offset = s.readInt();
  205. ret.setOffset(offset);
  206. }
  207. }
  208. } catch (EOFException eof) {
  209. return null; // This exception occurs if processing an 'old style' file where the
  210. // type munger attributes don't include the source location.
  211. } catch (IOException ioe) {
  212. // Something went wrong, maybe this is an 'old style' file that doesnt attach locations to mungers?
  213. // (but I thought that was just an EOFException?)
  214. ioe.printStackTrace();
  215. return null;
  216. } catch (ClassNotFoundException e) {
  217. } finally {
  218. if (ois != null) {
  219. ois.close();
  220. }
  221. }
  222. return ret;
  223. }
  224. protected final void writeSourceLocation(CompressingDataOutputStream s) throws IOException {
  225. if (s.canCompress()) {
  226. s.writeByte(1 + (location == null ? 0 : 1)); // 1==compressed no location 2==compressed with location
  227. if (location != null) {
  228. s.writeCompressedPath(location.getSourceFile().getPath());
  229. s.writeInt(location.getLine());
  230. s.writeInt(location.getOffset());
  231. }
  232. } else {
  233. s.writeByte(0);
  234. ObjectOutputStream oos = new ObjectOutputStream(s);
  235. oos.writeObject(location != null);
  236. if (location != null) {
  237. oos.writeObject(location.getSourceFile());
  238. oos.writeObject(location.getLine());
  239. oos.writeObject(location.getOffset());
  240. }
  241. oos.flush();
  242. oos.close();
  243. }
  244. }
  245. public abstract void write(CompressingDataOutputStream s) throws IOException;
  246. public Kind getKind() {
  247. return kind;
  248. }
  249. public static class Kind extends TypeSafeEnum {
  250. /* private */Kind(String name, int key) {
  251. super(name, key);
  252. }
  253. public static Kind read(DataInputStream s) throws IOException {
  254. int key = s.readByte();
  255. switch (key) {
  256. case 1:
  257. return Field;
  258. case 2:
  259. return Method;
  260. case 5:
  261. return Constructor;
  262. case 9:
  263. return MethodDelegate;
  264. case 10:
  265. return FieldHost;
  266. case 11:
  267. return MethodDelegate2;
  268. case 12:
  269. return InnerClass;
  270. }
  271. throw new BCException("bad kind: " + key);
  272. }
  273. @Override
  274. public String toString() {
  275. // we want MethodDelegate to appear as Method in WeaveInfo messages
  276. // TODO we may want something for fieldhost ?
  277. if (getName().startsWith(MethodDelegate.getName())) {// startsWith will cover MethodDelegate2 as well
  278. return Method.toString();
  279. } else {
  280. return super.toString();
  281. }
  282. }
  283. }
  284. // ---- fields
  285. public static final Kind Field = new Kind("Field", 1);
  286. public static final Kind Method = new Kind("Method", 2);
  287. public static final Kind Constructor = new Kind("Constructor", 5);
  288. // not serialized, only created during concretization of aspects
  289. public static final Kind PerObjectInterface = new Kind("PerObjectInterface", 3);
  290. public static final Kind PrivilegedAccess = new Kind("PrivilegedAccess", 4);
  291. public static final Kind Parent = new Kind("Parent", 6);
  292. // PTWIMPL not serialized, used during concretization of aspects
  293. public static final Kind PerTypeWithinInterface = new Kind("PerTypeWithinInterface", 7);
  294. public static final Kind AnnotationOnType = new Kind("AnnotationOnType", 8); // not serialized
  295. public static final Kind MethodDelegate = new Kind("MethodDelegate", 9);// serialized, @AJ ITDs
  296. public static final Kind FieldHost = new Kind("FieldHost", 10);// serialized, @AJ ITDs
  297. public static final Kind MethodDelegate2 = new Kind("MethodDelegate2", 11);// serialized, @AJ ITDs
  298. public static final Kind InnerClass = new Kind("InnerClass", 12);
  299. public static final String SUPER_DISPATCH_NAME = "superDispatch";
  300. public void setSuperMethodsCalled(Set<ResolvedMember> c) {
  301. this.superMethodsCalled = c;
  302. }
  303. public Set<ResolvedMember> getSuperMethodsCalled() {
  304. return superMethodsCalled;
  305. }
  306. public ResolvedMember getSignature() {
  307. return signature;
  308. }
  309. // ----
  310. public ResolvedMember getMatchingSyntheticMember(Member member, ResolvedType aspectType) {
  311. if ((getSignature() != null) && getSignature().isPublic() && member.equals(getSignature())) {
  312. return getSignature();
  313. }
  314. return null;
  315. }
  316. public boolean changesPublicSignature() {
  317. return kind == Field || kind == Method || kind == Constructor;
  318. }
  319. public boolean needsAccessToTopmostImplementor() {
  320. if (kind == Field) {
  321. return true;
  322. } else if (kind == Method) {
  323. return !signature.isAbstract();
  324. } else {
  325. return false;
  326. }
  327. }
  328. protected static List<String> readInTypeAliases(VersionedDataInputStream s) throws IOException {
  329. if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
  330. int count = -1;
  331. if (s.isAtLeast169()) {
  332. count = s.readByte();
  333. } else {
  334. count = s.readInt();
  335. }
  336. if (count != 0) {
  337. List<String> aliases = new ArrayList<>();
  338. for (int i = 0; i < count; i++) {
  339. aliases.add(s.readUTF());
  340. }
  341. return aliases;
  342. }
  343. }
  344. return null;
  345. }
  346. protected final void writeOutTypeAliases(DataOutputStream s) throws IOException {
  347. // Write any type variable aliases
  348. if (typeVariableAliases == null || typeVariableAliases.size() == 0) {
  349. s.writeByte(0);
  350. } else {
  351. s.writeByte(typeVariableAliases.size());
  352. for (String element : typeVariableAliases) {
  353. s.writeUTF(element);
  354. }
  355. }
  356. }
  357. public List<String> getTypeVariableAliases() {
  358. return typeVariableAliases;
  359. }
  360. protected void setTypeVariableAliases(List<String> typeVariableAliases) {
  361. this.typeVariableAliases = typeVariableAliases;
  362. }
  363. public boolean hasTypeVariableAliases() {
  364. return (typeVariableAliases != null && typeVariableAliases.size() > 0);
  365. }
  366. /**
  367. * return true if type variables are specified with the target type for this ITD. e.g. this would return true:
  368. * "int I&lt;A,B&gt;.m() { return 42; }"
  369. */
  370. public boolean sharesTypeVariablesWithGenericType() {
  371. return (typeVariableAliases != null && typeVariableAliases.size() > 0);
  372. }
  373. /**
  374. * Parameterizes a resolved type munger for a particular usage of its target type (this is used when the target type is generic
  375. * and the ITD shares type variables with the target) see ConcreteTypeMunger.parameterizedFor
  376. */
  377. public ResolvedTypeMunger parameterizedFor(ResolvedType target) {
  378. throw new BCException("Dont call parameterizedFor on a type munger of this kind: " + this.getClass());
  379. }
  380. // ResolvedType genericType = target;
  381. // if (target.isRawType() || target.isParameterizedType()) genericType = genericType.getGenericType();
  382. // ResolvedMember parameterizedSignature = null;
  383. // // If we are parameterizing it for a generic type, we just need to 'swap the letters' from the ones used
  384. // // in the original ITD declaration to the ones used in the actual target type declaration.
  385. // if (target.isGenericType()) {
  386. // TypeVariable vars[] = target.getTypeVariables();
  387. // UnresolvedTypeVariableReferenceType[] varRefs = new UnresolvedTypeVariableReferenceType[vars.length];
  388. // for (int i = 0; i < vars.length; i++) {
  389. // varRefs[i] = new UnresolvedTypeVariableReferenceType(vars[i]);
  390. // }
  391. // parameterizedSignature = getSignature().parameterizedWith(varRefs,genericType,true,typeVariableAliases);
  392. // } else {
  393. // // For raw and 'normal' parameterized targets (e.g. Interface, Interface<String>)
  394. // parameterizedSignature =
  395. // getSignature().parameterizedWith(target.getTypeParameters(),genericType,target.isParameterizedType(),typeVariableAliases);
  396. // }
  397. // return new NewMethodTypeMunger(parameterizedSignature,getSuperMethodsCalled(),typeVariableAliases);
  398. // }
  399. // /**
  400. // * see ResolvedTypeMunger.parameterizedFor(ResolvedType)
  401. // */
  402. // public ResolvedTypeMunger parameterizedFor(ResolvedType target) {
  403. // ResolvedType genericType = target;
  404. // if (target.isRawType() || target.isParameterizedType()) genericType = genericType.getGenericType();
  405. // ResolvedMember parameterizedSignature =
  406. // getSignature().parameterizedWith(target.getTypeParameters(),genericType,target.isParameterizedType(),typeVariableAliases);
  407. // return new NewFieldTypeMunger(parameterizedSignature,getSuperMethodsCalled(),typeVariableAliases);
  408. // }
  409. public void setDeclaredSignature(ResolvedMember rm) {
  410. declaredSignature = rm;
  411. }
  412. public ResolvedMember getDeclaredSignature() {
  413. return declaredSignature;
  414. }
  415. /**
  416. * A late munger has to be done after shadow munging since which shadows are matched can affect the operation of the late
  417. * munger. e.g. perobjectinterfacemunger
  418. */
  419. public boolean isLateMunger() {
  420. return false;
  421. }
  422. /**
  423. * Some type mungers are created purely to help with the implementation of shadow mungers. For example to support the cflow()
  424. * pointcut we create a new cflow field in the aspect, and that is added via a BcelCflowCounterFieldAdder.
  425. *
  426. * During compilation we need to compare sets of type mungers, and if some only come into existence after the 'shadowy' type
  427. * things have been processed, we need to ignore them during the comparison.
  428. *
  429. * Returning true from this method indicates the type munger exists to support 'shadowy' stuff - and so can be ignored in some
  430. * comparison.
  431. */
  432. public boolean existsToSupportShadowMunging() {
  433. return false;
  434. }
  435. public ResolvedTypeMunger parameterizeWith(Map<String, UnresolvedType> m, World w) {
  436. throw new BCException("Dont call parameterizeWith() on a type munger of this kind: " + this.getClass());
  437. }
  438. public UnresolvedType getDeclaringType() {
  439. return getSignature().getDeclaringType();
  440. }
  441. }