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

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. }