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 16KB

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