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.

BcelMethod.java 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  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. * ******************************************************************/
  12. package org.aspectj.weaver.bcel;
  13. import java.lang.reflect.Modifier;
  14. import java.util.ArrayList;
  15. import java.util.List;
  16. import java.util.StringTokenizer;
  17. import org.aspectj.apache.bcel.classfile.AnnotationDefault;
  18. import org.aspectj.apache.bcel.classfile.Attribute;
  19. import org.aspectj.apache.bcel.classfile.ExceptionTable;
  20. import org.aspectj.apache.bcel.classfile.JavaClass;
  21. import org.aspectj.apache.bcel.classfile.LineNumber;
  22. import org.aspectj.apache.bcel.classfile.LineNumberTable;
  23. import org.aspectj.apache.bcel.classfile.LocalVariable;
  24. import org.aspectj.apache.bcel.classfile.LocalVariableTable;
  25. import org.aspectj.apache.bcel.classfile.Method;
  26. import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
  27. import org.aspectj.apache.bcel.classfile.annotation.NameValuePair;
  28. import org.aspectj.bridge.ISourceLocation;
  29. import org.aspectj.bridge.SourceLocation;
  30. import org.aspectj.util.GenericSignature;
  31. import org.aspectj.util.GenericSignature.TypeVariableSignature;
  32. import org.aspectj.util.GenericSignatureParser;
  33. import org.aspectj.weaver.AjAttribute;
  34. import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
  35. import org.aspectj.weaver.AnnotationAJ;
  36. import org.aspectj.weaver.BCException;
  37. import org.aspectj.weaver.ISourceContext;
  38. import org.aspectj.weaver.MemberKind;
  39. import org.aspectj.weaver.ResolvedMemberImpl;
  40. import org.aspectj.weaver.ResolvedPointcutDefinition;
  41. import org.aspectj.weaver.ResolvedType;
  42. import org.aspectj.weaver.ShadowMunger;
  43. import org.aspectj.weaver.TypeVariable;
  44. import org.aspectj.weaver.UnresolvedType;
  45. import org.aspectj.weaver.World;
  46. import org.aspectj.weaver.bcel.BcelGenericSignatureToTypeXConverter.GenericSignatureFormatException;
  47. //public final
  48. class BcelMethod extends ResolvedMemberImpl {
  49. private Method method;
  50. // these fields are not set for many BcelMethods...
  51. private ShadowMunger associatedShadowMunger;
  52. private ResolvedPointcutDefinition preResolvedPointcut; // used when ajc has
  53. // pre-resolved the
  54. // pointcut of some
  55. // @Advice
  56. private AjAttribute.EffectiveSignatureAttribute effectiveSignature;
  57. private AjAttribute.MethodDeclarationLineNumberAttribute declarationLineNumber;
  58. private final BcelObjectType bcelObjectType;
  59. private int bitflags;
  60. private static final int KNOW_IF_SYNTHETIC = 0x0001;
  61. private static final int PARAMETER_NAMES_INITIALIZED = 0x0002;
  62. private static final int CAN_BE_PARAMETERIZED = 0x0004;
  63. private static final int UNPACKED_GENERIC_SIGNATURE = 0x0008;
  64. private static final int IS_AJ_SYNTHETIC = 0x0040;
  65. private static final int IS_SYNTHETIC = 0x0080;
  66. private static final int IS_SYNTHETIC_INVERSE = 0x7f7f; // all bits but
  67. // IS_SYNTHETIC (and
  68. // topmost bit)
  69. private static final int HAS_ANNOTATIONS = 0x0400;
  70. private static final int HAVE_DETERMINED_ANNOTATIONS = 0x0800;
  71. // genericized version of return and parameter types
  72. private UnresolvedType genericReturnType = null;
  73. private UnresolvedType[] genericParameterTypes = null;
  74. BcelMethod(BcelObjectType declaringType, Method method) {
  75. super(method.getName().equals("<init>") ? CONSTRUCTOR : (method.getName().equals("<clinit>") ? STATIC_INITIALIZATION
  76. : METHOD), declaringType.getResolvedTypeX(), method.getModifiers(), method.getName(), method.getSignature());
  77. this.method = method;
  78. sourceContext = declaringType.getResolvedTypeX().getSourceContext();
  79. bcelObjectType = declaringType;
  80. unpackJavaAttributes();
  81. unpackAjAttributes(bcelObjectType.getWorld());
  82. }
  83. /**
  84. * This constructor expects to be passed the attributes, rather than deserializing them.
  85. */
  86. BcelMethod(BcelObjectType declaringType, Method method, List<AjAttribute> attributes) {
  87. super(method.getName().equals("<init>") ? CONSTRUCTOR : (method.getName().equals("<clinit>") ? STATIC_INITIALIZATION
  88. : METHOD), declaringType.getResolvedTypeX(), method.getModifiers(), method.getName(), method.getSignature());
  89. this.method = method;
  90. sourceContext = declaringType.getResolvedTypeX().getSourceContext();
  91. bcelObjectType = declaringType;
  92. unpackJavaAttributes();
  93. processAttributes(bcelObjectType.getWorld(), attributes);
  94. }
  95. // ----
  96. private void unpackJavaAttributes() {
  97. ExceptionTable exnTable = method.getExceptionTable();
  98. checkedExceptions = (exnTable == null) ? UnresolvedType.NONE : UnresolvedType.forNames(exnTable.getExceptionNames());
  99. }
  100. @Override
  101. public String[] getParameterNames() {
  102. determineParameterNames();
  103. return super.getParameterNames();
  104. }
  105. public int getLineNumberOfFirstInstruction() {
  106. LineNumberTable lnt = method.getLineNumberTable();
  107. if (lnt == null) {
  108. return -1;
  109. }
  110. LineNumber[] lns = lnt.getLineNumberTable();
  111. if (lns == null || lns.length == 0) {
  112. return -1;
  113. }
  114. return lns[0].getLineNumber();
  115. }
  116. public void determineParameterNames() {
  117. if ((bitflags & PARAMETER_NAMES_INITIALIZED) != 0) {
  118. return;
  119. }
  120. bitflags |= PARAMETER_NAMES_INITIALIZED;
  121. LocalVariableTable varTable = method.getLocalVariableTable();
  122. int len = getArity();
  123. if (varTable == null) {
  124. // do we have an annotation with the argNames value specified...
  125. AnnotationAJ[] annos = getAnnotations();
  126. if (annos != null && annos.length != 0) {
  127. AnnotationAJ[] axs = getAnnotations();
  128. for (int i = 0; i < axs.length; i++) {
  129. AnnotationAJ annotationX = axs[i];
  130. String typename = annotationX.getTypeName();
  131. if (typename.charAt(0) == 'o') {
  132. if (typename.equals("org.aspectj.lang.annotation.Pointcut")
  133. || typename.equals("org.aspectj.lang.annotation.Before")
  134. || typename.equals("org.aspectj.lang.annotation.Around")
  135. || typename.startsWith("org.aspectj.lang.annotation.After")) {
  136. AnnotationGen a = ((BcelAnnotation) annotationX).getBcelAnnotation();
  137. if (a != null) {
  138. List<NameValuePair> values = a.getValues();
  139. for (NameValuePair nvPair : values) {
  140. if (nvPair.getNameString().equals("argNames")) {
  141. String argNames = nvPair.getValue().stringifyValue();
  142. StringTokenizer argNameTokenizer = new StringTokenizer(argNames, " ,");
  143. List<String> argsList = new ArrayList<String>();
  144. while (argNameTokenizer.hasMoreTokens()) {
  145. argsList.add(argNameTokenizer.nextToken());
  146. }
  147. int requiredCount = getParameterTypes().length;
  148. while (argsList.size() < requiredCount) {
  149. argsList.add("arg" + argsList.size());
  150. }
  151. setParameterNames(argsList.toArray(new String[] {}));
  152. return;
  153. }
  154. }
  155. }
  156. }
  157. }
  158. }
  159. }
  160. setParameterNames(Utility.makeArgNames(len));
  161. } else {
  162. UnresolvedType[] paramTypes = getParameterTypes();
  163. String[] paramNames = new String[len];
  164. int index = Modifier.isStatic(modifiers) ? 0 : 1;
  165. for (int i = 0; i < len; i++) {
  166. LocalVariable lv = varTable.getLocalVariable(index);
  167. if (lv == null) {
  168. paramNames[i] = "arg" + i;
  169. } else {
  170. paramNames[i] = lv.getName();
  171. }
  172. index += paramTypes[i].getSize();
  173. }
  174. setParameterNames(paramNames);
  175. }
  176. }
  177. private void unpackAjAttributes(World world) {
  178. associatedShadowMunger = null;
  179. ResolvedType resolvedDeclaringType = getDeclaringType().resolve(world);
  180. WeaverVersionInfo wvinfo = bcelObjectType.getWeaverVersionAttribute();
  181. List<AjAttribute> as = Utility.readAjAttributes(resolvedDeclaringType.getClassName(), method.getAttributes(),
  182. resolvedDeclaringType.getSourceContext(), world, wvinfo, new BcelConstantPoolReader(method.getConstantPool()));
  183. processAttributes(world, as);
  184. as = AtAjAttributes.readAj5MethodAttributes(method, this, resolvedDeclaringType, preResolvedPointcut,
  185. resolvedDeclaringType.getSourceContext(), world.getMessageHandler());
  186. processAttributes(world, as);
  187. }
  188. private void processAttributes(World world, List<AjAttribute> as) {
  189. for (AjAttribute attr : as) {
  190. if (attr instanceof AjAttribute.MethodDeclarationLineNumberAttribute) {
  191. declarationLineNumber = (AjAttribute.MethodDeclarationLineNumberAttribute) attr;
  192. } else if (attr instanceof AjAttribute.AdviceAttribute) {
  193. associatedShadowMunger = ((AjAttribute.AdviceAttribute) attr).reify(this, world, (ResolvedType) getDeclaringType());
  194. } else if (attr instanceof AjAttribute.AjSynthetic) {
  195. bitflags |= IS_AJ_SYNTHETIC;
  196. } else if (attr instanceof AjAttribute.EffectiveSignatureAttribute) {
  197. effectiveSignature = (AjAttribute.EffectiveSignatureAttribute) attr;
  198. } else if (attr instanceof AjAttribute.PointcutDeclarationAttribute) {
  199. // this is an @AspectJ annotated advice method, with pointcut pre-resolved by ajc
  200. preResolvedPointcut = ((AjAttribute.PointcutDeclarationAttribute) attr).reify();
  201. } else {
  202. throw new BCException("weird method attribute " + attr);
  203. }
  204. }
  205. }
  206. //
  207. // // for testing - if we have this attribute, return it - will return null
  208. // if
  209. // // it doesnt know anything
  210. // public AjAttribute[] getAttributes(String name) {
  211. // List results = new ArrayList();
  212. // List l = Utility.readAjAttributes(getDeclaringType().getClassName(),
  213. // method.getAttributes(),
  214. // getSourceContext(bcelObjectType.getWorld()), bcelObjectType.getWorld(),
  215. // bcelObjectType.getWeaverVersionAttribute());
  216. // for (Iterator iter = l.iterator(); iter.hasNext();) {
  217. // AjAttribute element = (AjAttribute) iter.next();
  218. // if (element.getNameString().equals(name))
  219. // results.add(element);
  220. // }
  221. // if (results.size() > 0) {
  222. // return (AjAttribute[]) results.toArray(new AjAttribute[] {});
  223. // }
  224. // return null;
  225. // }
  226. @Override
  227. public String getAnnotationDefaultValue() {
  228. Attribute[] attrs = method.getAttributes();
  229. for (int i = 0; i < attrs.length; i++) {
  230. Attribute attribute = attrs[i];
  231. if (attribute.getName().equals("AnnotationDefault")) {
  232. AnnotationDefault def = (AnnotationDefault) attribute;
  233. return def.getElementValue().stringifyValue();
  234. }
  235. }
  236. return null;
  237. }
  238. // for testing - use with the method above
  239. public String[] getAttributeNames(boolean onlyIncludeAjOnes) {
  240. Attribute[] as = method.getAttributes();
  241. List<String> names = new ArrayList<String>();
  242. // String[] strs = new String[as.length];
  243. for (int j = 0; j < as.length; j++) {
  244. if (!onlyIncludeAjOnes || as[j].getName().startsWith(AjAttribute.AttributePrefix)) {
  245. names.add(as[j].getName());
  246. }
  247. }
  248. return names.toArray(new String[] {});
  249. }
  250. @Override
  251. public boolean isAjSynthetic() {
  252. return (bitflags & IS_AJ_SYNTHETIC) != 0;
  253. }
  254. @Override
  255. public ShadowMunger getAssociatedShadowMunger() {
  256. return associatedShadowMunger;
  257. }
  258. @Override
  259. public AjAttribute.EffectiveSignatureAttribute getEffectiveSignature() {
  260. return effectiveSignature;
  261. }
  262. public boolean hasDeclarationLineNumberInfo() {
  263. return declarationLineNumber != null;
  264. }
  265. public int getDeclarationLineNumber() {
  266. if (declarationLineNumber != null) {
  267. return declarationLineNumber.getLineNumber();
  268. } else {
  269. return -1;
  270. }
  271. }
  272. public int getDeclarationOffset() {
  273. if (declarationLineNumber != null) {
  274. return declarationLineNumber.getOffset();
  275. } else {
  276. return -1;
  277. }
  278. }
  279. @Override
  280. public ISourceLocation getSourceLocation() {
  281. ISourceLocation ret = super.getSourceLocation();
  282. if ((ret == null || ret.getLine() == 0) && hasDeclarationLineNumberInfo()) {
  283. // lets see if we can do better
  284. ISourceContext isc = getSourceContext();
  285. if (isc != null) {
  286. ret = isc.makeSourceLocation(getDeclarationLineNumber(), getDeclarationOffset());
  287. } else {
  288. ret = new SourceLocation(null, getDeclarationLineNumber());
  289. }
  290. }
  291. return ret;
  292. }
  293. @Override
  294. public MemberKind getKind() {
  295. if (associatedShadowMunger != null) {
  296. return ADVICE;
  297. } else {
  298. return super.getKind();
  299. }
  300. }
  301. @Override
  302. public boolean hasAnnotation(UnresolvedType ofType) {
  303. ensureAnnotationsRetrieved();
  304. for (ResolvedType aType : annotationTypes) {
  305. if (aType.equals(ofType)) {
  306. return true;
  307. }
  308. }
  309. return false;
  310. }
  311. @Override
  312. public AnnotationAJ[] getAnnotations() {
  313. ensureAnnotationsRetrieved();
  314. if ((bitflags & HAS_ANNOTATIONS) != 0) {
  315. return annotations;
  316. } else {
  317. return AnnotationAJ.EMPTY_ARRAY;
  318. }
  319. }
  320. @Override
  321. public ResolvedType[] getAnnotationTypes() {
  322. ensureAnnotationsRetrieved();
  323. return annotationTypes;
  324. }
  325. @Override
  326. public AnnotationAJ getAnnotationOfType(UnresolvedType ofType) {
  327. ensureAnnotationsRetrieved();
  328. if ((bitflags & HAS_ANNOTATIONS) == 0) {
  329. return null;
  330. }
  331. for (int i = 0; i < annotations.length; i++) {
  332. if (annotations[i].getTypeName().equals(ofType.getName())) {
  333. return annotations[i];
  334. }
  335. }
  336. return null;
  337. }
  338. @Override
  339. public void addAnnotation(AnnotationAJ annotation) {
  340. ensureAnnotationsRetrieved();
  341. if ((bitflags & HAS_ANNOTATIONS) == 0) {
  342. annotations = new AnnotationAJ[1];
  343. annotations[0] = annotation;
  344. annotationTypes = new ResolvedType[1];
  345. annotationTypes[0] = annotation.getType();
  346. } else {
  347. // Add it to the set of annotations
  348. int len = annotations.length;
  349. AnnotationAJ[] ret = new AnnotationAJ[len + 1];
  350. System.arraycopy(annotations, 0, ret, 0, len);
  351. ret[len] = annotation;
  352. annotations = ret;
  353. ResolvedType[] newAnnotationTypes = new ResolvedType[len + 1];
  354. System.arraycopy(annotationTypes, 0, newAnnotationTypes, 0, len);
  355. newAnnotationTypes[len] = annotation.getType();
  356. annotationTypes = newAnnotationTypes;
  357. }
  358. bitflags |= HAS_ANNOTATIONS;
  359. }
  360. public void removeAnnotation(ResolvedType annotationType) {
  361. ensureAnnotationsRetrieved();
  362. if ((bitflags & HAS_ANNOTATIONS) == 0) {
  363. // nothing to do, why did we get called?
  364. } else {
  365. int len = annotations.length;
  366. if (len == 1) {
  367. bitflags &= ~HAS_ANNOTATIONS;
  368. annotations = null;
  369. annotationTypes = null;
  370. return;
  371. }
  372. AnnotationAJ[] ret = new AnnotationAJ[len - 1];
  373. int p = 0;
  374. for (AnnotationAJ annotation : annotations) {
  375. if (!annotation.getType().equals(annotationType)) {
  376. ret[p++] = annotation;
  377. }
  378. }
  379. annotations = ret;
  380. ResolvedType[] newAnnotationTypes = new ResolvedType[len - 1];
  381. p = 0;
  382. for (AnnotationAJ annotation : annotations) {
  383. if (!annotation.getType().equals(annotationType)) {
  384. newAnnotationTypes[p++] = annotationType;
  385. }
  386. }
  387. annotationTypes = newAnnotationTypes;
  388. }
  389. bitflags |= HAS_ANNOTATIONS;
  390. }
  391. public static final AnnotationAJ[] NO_PARAMETER_ANNOTATIONS = new AnnotationAJ[] {};
  392. public void addParameterAnnotation(int param, AnnotationAJ anno) {
  393. ensureParameterAnnotationsRetrieved();
  394. if (parameterAnnotations == NO_PARAMETER_ANNOTATIONXS) {
  395. // First time we've added any, so lets set up the array
  396. parameterAnnotations = new AnnotationAJ[getArity()][];
  397. for (int i = 0; i < getArity(); i++) {
  398. parameterAnnotations[i] = NO_PARAMETER_ANNOTATIONS;
  399. }
  400. }
  401. int existingCount = parameterAnnotations[param].length;
  402. if (existingCount == 0) {
  403. AnnotationAJ[] annoArray = new AnnotationAJ[1];
  404. annoArray[0] = anno;
  405. parameterAnnotations[param] = annoArray;
  406. } else {
  407. AnnotationAJ[] newAnnoArray = new AnnotationAJ[existingCount + 1];
  408. System.arraycopy(parameterAnnotations[param], 0, newAnnoArray, 0, existingCount);
  409. newAnnoArray[existingCount] = anno;
  410. parameterAnnotations[param] = newAnnoArray;
  411. }
  412. }
  413. private void ensureAnnotationsRetrieved() {
  414. if (method == null) {
  415. return; // must be ok, we have evicted it
  416. }
  417. if ((bitflags & HAVE_DETERMINED_ANNOTATIONS) != 0) {
  418. return;
  419. }
  420. bitflags |= HAVE_DETERMINED_ANNOTATIONS;
  421. AnnotationGen annos[] = method.getAnnotations();
  422. if (annos.length == 0) {
  423. annotationTypes = ResolvedType.NONE;
  424. annotations = AnnotationAJ.EMPTY_ARRAY;
  425. } else {
  426. int annoCount = annos.length;
  427. annotationTypes = new ResolvedType[annoCount];
  428. annotations = new AnnotationAJ[annoCount];
  429. for (int i = 0; i < annoCount; i++) {
  430. AnnotationGen annotation = annos[i];
  431. annotations[i] = new BcelAnnotation(annotation, bcelObjectType.getWorld());
  432. annotationTypes[i] = annotations[i].getType();
  433. }
  434. bitflags |= HAS_ANNOTATIONS;
  435. }
  436. }
  437. private void ensureParameterAnnotationsRetrieved() {
  438. if (method == null) {
  439. return; // must be ok, we have evicted it
  440. }
  441. AnnotationGen[][] pAnns = method.getParameterAnnotations();
  442. if (parameterAnnotationTypes == null || pAnns.length != parameterAnnotationTypes.length) {
  443. if (pAnns == Method.NO_PARAMETER_ANNOTATIONS) {
  444. parameterAnnotationTypes = BcelMethod.NO_PARAMETER_ANNOTATION_TYPES;
  445. parameterAnnotations = BcelMethod.NO_PARAMETER_ANNOTATIONXS;
  446. } else {
  447. AnnotationGen annos[][] = method.getParameterAnnotations();
  448. parameterAnnotations = new AnnotationAJ[annos.length][];
  449. parameterAnnotationTypes = new ResolvedType[annos.length][];
  450. for (int i = 0; i < annos.length; i++) {
  451. AnnotationGen[] annosOnThisParam = annos[i];
  452. if (annos[i].length == 0) {
  453. parameterAnnotations[i] = AnnotationAJ.EMPTY_ARRAY;
  454. parameterAnnotationTypes[i] = ResolvedType.NONE;
  455. } else {
  456. parameterAnnotations[i] = new AnnotationAJ[annosOnThisParam.length];
  457. parameterAnnotationTypes[i] = new ResolvedType[annosOnThisParam.length];
  458. for (int j = 0; j < annosOnThisParam.length; j++) {
  459. parameterAnnotations[i][j] = new BcelAnnotation(annosOnThisParam[j], bcelObjectType.getWorld());
  460. parameterAnnotationTypes[i][j] = bcelObjectType.getWorld().resolve(
  461. UnresolvedType.forSignature(annosOnThisParam[j].getTypeSignature()));
  462. }
  463. }
  464. }
  465. }
  466. }
  467. }
  468. @Override
  469. public AnnotationAJ[][] getParameterAnnotations() {
  470. ensureParameterAnnotationsRetrieved();
  471. return parameterAnnotations;
  472. }
  473. @Override
  474. public ResolvedType[][] getParameterAnnotationTypes() {
  475. ensureParameterAnnotationsRetrieved();
  476. return parameterAnnotationTypes;
  477. }
  478. /**
  479. * A method can be parameterized if it has one or more generic parameters. A generic parameter (type variable parameter) is
  480. * identified by the prefix "T"
  481. */
  482. @Override
  483. public boolean canBeParameterized() {
  484. unpackGenericSignature();
  485. return (bitflags & CAN_BE_PARAMETERIZED) != 0;
  486. }
  487. @Override
  488. public UnresolvedType[] getGenericParameterTypes() {
  489. unpackGenericSignature();
  490. return genericParameterTypes;
  491. }
  492. /**
  493. * Return the parameterized/generic return type or the normal return type if the method is not generic.
  494. */
  495. @Override
  496. public UnresolvedType getGenericReturnType() {
  497. unpackGenericSignature();
  498. return genericReturnType;
  499. }
  500. /** For testing only */
  501. public Method getMethod() {
  502. return method;
  503. }
  504. private void unpackGenericSignature() {
  505. if ((bitflags & UNPACKED_GENERIC_SIGNATURE) != 0) {
  506. return;
  507. }
  508. bitflags |= UNPACKED_GENERIC_SIGNATURE;
  509. if (!bcelObjectType.getWorld().isInJava5Mode()) {
  510. genericReturnType = getReturnType();
  511. genericParameterTypes = getParameterTypes();
  512. return;
  513. }
  514. String gSig = method.getGenericSignature();
  515. if (gSig != null) {
  516. GenericSignature.MethodTypeSignature mSig = new GenericSignatureParser().parseAsMethodSignature(gSig);// method
  517. // .
  518. // getGenericSignature
  519. // ());
  520. if (mSig.formalTypeParameters.length > 0) {
  521. // generic method declaration
  522. bitflags |= CAN_BE_PARAMETERIZED;
  523. }
  524. typeVariables = new TypeVariable[mSig.formalTypeParameters.length];
  525. for (int i = 0; i < typeVariables.length; i++) {
  526. GenericSignature.FormalTypeParameter methodFtp = mSig.formalTypeParameters[i];
  527. try {
  528. typeVariables[i] = BcelGenericSignatureToTypeXConverter.formalTypeParameter2TypeVariable(methodFtp,
  529. mSig.formalTypeParameters, bcelObjectType.getWorld());
  530. } catch (GenericSignatureFormatException e) {
  531. // this is a development bug, so fail fast with good info
  532. throw new IllegalStateException("While getting the type variables for method " + this.toString()
  533. + " with generic signature " + mSig + " the following error condition was detected: " + e.getMessage());
  534. }
  535. }
  536. GenericSignature.FormalTypeParameter[] parentFormals = bcelObjectType.getAllFormals();
  537. GenericSignature.FormalTypeParameter[] formals = new GenericSignature.FormalTypeParameter[parentFormals.length
  538. + mSig.formalTypeParameters.length];
  539. // put method formal in front of type formals for overriding in
  540. // lookup
  541. System.arraycopy(mSig.formalTypeParameters, 0, formals, 0, mSig.formalTypeParameters.length);
  542. System.arraycopy(parentFormals, 0, formals, mSig.formalTypeParameters.length, parentFormals.length);
  543. GenericSignature.TypeSignature returnTypeSignature = mSig.returnType;
  544. try {
  545. genericReturnType = BcelGenericSignatureToTypeXConverter.typeSignature2TypeX(returnTypeSignature, formals,
  546. bcelObjectType.getWorld());
  547. } catch (GenericSignatureFormatException e) {
  548. // development bug, fail fast with good info
  549. throw new IllegalStateException("While determing the generic return type of " + this.toString()
  550. + " with generic signature " + gSig + " the following error was detected: " + e.getMessage());
  551. }
  552. GenericSignature.TypeSignature[] paramTypeSigs = mSig.parameters;
  553. if (paramTypeSigs.length == 0) {
  554. genericParameterTypes = UnresolvedType.NONE;
  555. } else {
  556. genericParameterTypes = new UnresolvedType[paramTypeSigs.length];
  557. }
  558. for (int i = 0; i < paramTypeSigs.length; i++) {
  559. try {
  560. genericParameterTypes[i] = BcelGenericSignatureToTypeXConverter.typeSignature2TypeX(paramTypeSigs[i], formals,
  561. bcelObjectType.getWorld());
  562. } catch (GenericSignatureFormatException e) {
  563. // development bug, fail fast with good info
  564. throw new IllegalStateException("While determining the generic parameter types of " + this.toString()
  565. + " with generic signature " + gSig + " the following error was detected: " + e.getMessage());
  566. }
  567. if (paramTypeSigs[i] instanceof TypeVariableSignature) {
  568. bitflags |= CAN_BE_PARAMETERIZED;
  569. }
  570. }
  571. } else {
  572. genericReturnType = getReturnType();
  573. genericParameterTypes = getParameterTypes();
  574. }
  575. }
  576. @Override
  577. public void evictWeavingState() {
  578. if (method != null) {
  579. unpackGenericSignature();
  580. unpackJavaAttributes();
  581. ensureAnnotationsRetrieved();
  582. ensureParameterAnnotationsRetrieved();
  583. determineParameterNames();
  584. // this.sourceContext = SourceContextImpl.UNKNOWN_SOURCE_CONTEXT;
  585. method = null;
  586. }
  587. }
  588. @Override
  589. public boolean isSynthetic() {
  590. if ((bitflags & KNOW_IF_SYNTHETIC) == 0) {
  591. workOutIfSynthetic();
  592. }
  593. return (bitflags & IS_SYNTHETIC) != 0;// isSynthetic;
  594. }
  595. // Pre Java5 synthetic is an attribute 'Synthetic', post Java5 it is a
  596. // modifier (4096 or 0x1000)
  597. private void workOutIfSynthetic() {
  598. if ((bitflags & KNOW_IF_SYNTHETIC) != 0) {
  599. return;
  600. }
  601. bitflags |= KNOW_IF_SYNTHETIC;
  602. JavaClass jc = bcelObjectType.getJavaClass();
  603. bitflags &= IS_SYNTHETIC_INVERSE; // unset the bit
  604. if (jc == null) {
  605. return; // what the hell has gone wrong?
  606. }
  607. if (jc.getMajor() < 49/* Java5 */) {
  608. // synthetic is an attribute
  609. String[] synthetics = getAttributeNames(false);
  610. if (synthetics != null) {
  611. for (int i = 0; i < synthetics.length; i++) {
  612. if (synthetics[i].equals("Synthetic")) {
  613. bitflags |= IS_SYNTHETIC;
  614. break;
  615. }
  616. }
  617. }
  618. } else {
  619. // synthetic is a modifier (4096)
  620. if ((modifiers & 4096) != 0) {
  621. bitflags |= IS_SYNTHETIC;
  622. }
  623. }
  624. }
  625. /**
  626. * Returns whether or not the given object is equivalent to the current one. Returns true if
  627. * getMethod().getCode().getCodeString() are equal. Allows for different line number tables.
  628. */
  629. // bug 154054: is similar to equals(Object) however
  630. // doesn't require implementing equals in Method and Code
  631. // which proved expensive. Currently used within
  632. // CrosscuttingMembers.replaceWith() to decide if we need
  633. // to do a full build
  634. @Override
  635. public boolean isEquivalentTo(Object other) {
  636. if (!(other instanceof BcelMethod)) {
  637. return false;
  638. }
  639. BcelMethod o = (BcelMethod) other;
  640. return getMethod().getCode().getCodeString().equals(o.getMethod().getCode().getCodeString());
  641. }
  642. /**
  643. * Return true if the method represents the default constructor. Hard to determine this from bytecode, but the existence of the
  644. * MethodDeclarationLineNumber attribute should tell us.
  645. *
  646. * @return true if this BcelMethod represents the default constructor
  647. */
  648. @Override
  649. public boolean isDefaultConstructor() {
  650. boolean mightBe = !hasDeclarationLineNumberInfo() && name.equals("<init>") && parameterTypes.length == 0;
  651. if (mightBe) {
  652. // TODO would be nice to do a check to see if the file was compiled with javac or ajc?
  653. // maybe by checking the constant pool for aspectj strings?
  654. return true;
  655. } else {
  656. return false;
  657. }
  658. }
  659. }