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.

Shadow.java 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  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. * ******************************************************************/
  12. package org.aspectj.weaver;
  13. import java.io.DataInputStream;
  14. import java.io.IOException;
  15. import java.lang.reflect.Modifier;
  16. import java.util.ArrayList;
  17. import java.util.Collections;
  18. import java.util.HashSet;
  19. import java.util.List;
  20. import java.util.Set;
  21. import org.aspectj.bridge.IMessage;
  22. import org.aspectj.bridge.ISourceLocation;
  23. import org.aspectj.bridge.MessageUtil;
  24. import org.aspectj.util.PartialOrder;
  25. import org.aspectj.util.TypeSafeEnum;
  26. import org.aspectj.weaver.ast.Var;
  27. /*
  28. * The superclass of anything representing a the shadow of a join point. A shadow represents
  29. * some bit of code, and encompasses both entry and exit from that code. All shadows have a kind
  30. * and a signature.
  31. */
  32. public abstract class Shadow {
  33. // every Shadow has a unique id, doesn't matter if it wraps...
  34. private static int nextShadowID = 100; // easier to spot than zero. // OPTIMIZE is this a bug? static?
  35. private final Kind kind;
  36. private final Member signature;
  37. private Member matchingSignature;
  38. private ResolvedMember resolvedSignature;
  39. protected final Shadow enclosingShadow;
  40. protected List<ShadowMunger> mungers = Collections.emptyList();
  41. protected boolean needAroundClosureStacking = false;
  42. public int shadowId = nextShadowID++; // every time we build a shadow, it gets a new id
  43. // ----
  44. protected Shadow(Kind kind, Member signature, Shadow enclosingShadow) {
  45. this.kind = kind;
  46. this.signature = signature;
  47. this.enclosingShadow = enclosingShadow;
  48. }
  49. // ----
  50. public abstract World getIWorld();
  51. public List<ShadowMunger> getMungers() {
  52. return mungers;
  53. }
  54. /**
  55. * could this(*) pcd ever match
  56. */
  57. public final boolean hasThis() {
  58. if (getKind().neverHasThis()) {
  59. return false;
  60. } else if (getKind().isEnclosingKind()) {
  61. return !Modifier.isStatic(getSignature().getModifiers());
  62. } else if (enclosingShadow == null) {
  63. return false;
  64. } else {
  65. return enclosingShadow.hasThis();
  66. }
  67. }
  68. /**
  69. * the type of the this object here
  70. *
  71. * @throws IllegalStateException if there is no this here
  72. */
  73. public final UnresolvedType getThisType() {
  74. if (!hasThis()) {
  75. throw new IllegalStateException("no this");
  76. }
  77. if (getKind().isEnclosingKind()) {
  78. return getSignature().getDeclaringType();
  79. } else {
  80. return enclosingShadow.getThisType();
  81. }
  82. }
  83. /**
  84. * a var referencing this
  85. *
  86. * @throws IllegalStateException if there is no target here
  87. */
  88. public abstract Var getThisVar();
  89. /**
  90. * could target(*) pcd ever match
  91. */
  92. public final boolean hasTarget() {
  93. if (getKind().neverHasTarget()) {
  94. return false;
  95. } else if (getKind().isTargetSameAsThis()) {
  96. return hasThis();
  97. } else {
  98. return !Modifier.isStatic(getSignature().getModifiers());
  99. }
  100. }
  101. /**
  102. * the type of the target object here
  103. *
  104. * @throws IllegalStateException if there is no target here
  105. */
  106. public final UnresolvedType getTargetType() {
  107. if (!hasTarget()) {
  108. throw new IllegalStateException("no target");
  109. }
  110. return getSignature().getDeclaringType();
  111. }
  112. /**
  113. * a var referencing the target
  114. *
  115. * @throws IllegalStateException if there is no target here
  116. */
  117. public abstract Var getTargetVar();
  118. public UnresolvedType[] getArgTypes() {
  119. if (getKind() == FieldSet) {
  120. return new UnresolvedType[] { getSignature().getReturnType() };
  121. }
  122. return getSignature().getParameterTypes();
  123. }
  124. public boolean isShadowForArrayConstructionJoinpoint() {
  125. return (getKind() == ConstructorCall && signature.getDeclaringType().isArray());
  126. }
  127. public boolean isShadowForMonitor() {
  128. return (getKind() == SynchronizationLock || getKind() == SynchronizationUnlock);
  129. }
  130. // will return the right length array of ints depending on how many dimensions the array has
  131. public ResolvedType[] getArgumentTypesForArrayConstructionShadow() {
  132. String s = signature.getDeclaringType().getSignature();
  133. int pos = s.indexOf("[");
  134. int dims = 1;
  135. while (pos < s.length()) {
  136. pos++;
  137. if (pos < s.length()) {
  138. dims += (s.charAt(pos) == '[' ? 1 : 0);
  139. }
  140. }
  141. ResolvedType intType = UnresolvedType.INT.resolve(this.getIWorld());
  142. if (dims == 1) {
  143. return new ResolvedType[] { intType };
  144. }
  145. ResolvedType[] someInts = new ResolvedType[dims];
  146. for (int i = 0; i < dims; i++) {
  147. someInts[i] = intType;
  148. }
  149. return someInts;
  150. }
  151. public UnresolvedType[] getGenericArgTypes() {
  152. if (isShadowForArrayConstructionJoinpoint()) {
  153. return getArgumentTypesForArrayConstructionShadow();
  154. }
  155. if (isShadowForMonitor()) {
  156. return UnresolvedType.ARRAY_WITH_JUST_OBJECT;
  157. }
  158. if (getKind() == FieldSet) {
  159. return new UnresolvedType[] { getResolvedSignature().getGenericReturnType() };
  160. }
  161. return getResolvedSignature().getGenericParameterTypes();
  162. }
  163. public UnresolvedType getArgType(int arg) {
  164. if (getKind() == FieldSet) {
  165. return getSignature().getReturnType();
  166. }
  167. return getSignature().getParameterTypes()[arg];
  168. }
  169. public int getArgCount() {
  170. if (getKind() == FieldSet) {
  171. return 1;
  172. }
  173. return getSignature().getParameterTypes().length;
  174. }
  175. // /**
  176. // * Return name of the argument at position 'i' at this shadow. This does not make sense for all shadows - but can be useful in
  177. // * the case of, for example, method-execution.
  178. // *
  179. // * @return null if it cannot be determined
  180. // */
  181. // public String getArgName(int i, World w) {
  182. // String[] names = getSignature().getParameterNames(w);
  183. // if (names == null || i >= names.length)
  184. // return null;
  185. // return names[i];
  186. // }
  187. public abstract UnresolvedType getEnclosingType();
  188. public abstract Var getArgVar(int i);
  189. public abstract Var getThisJoinPointVar();
  190. public abstract Var getThisJoinPointStaticPartVar();
  191. public abstract Var getThisEnclosingJoinPointStaticPartVar();
  192. public abstract Var getThisAspectInstanceVar(ResolvedType aspectType);
  193. // annotation variables
  194. public abstract Var getKindedAnnotationVar(UnresolvedType forAnnotationType);
  195. public abstract Var getWithinAnnotationVar(UnresolvedType forAnnotationType);
  196. public abstract Var getWithinCodeAnnotationVar(UnresolvedType forAnnotationType);
  197. public abstract Var getThisAnnotationVar(UnresolvedType forAnnotationType);
  198. public abstract Var getTargetAnnotationVar(UnresolvedType forAnnotationType);
  199. public abstract Var getArgAnnotationVar(int i, UnresolvedType forAnnotationType);
  200. public abstract Member getEnclosingCodeSignature();
  201. /**
  202. * returns the kind of shadow this is, representing what happens under this shadow
  203. */
  204. public Kind getKind() {
  205. return kind;
  206. }
  207. /**
  208. * returns the signature of the thing under this shadow
  209. */
  210. public Member getSignature() {
  211. return signature;
  212. }
  213. /**
  214. * returns the signature of the thing under this shadow, with any synthetic arguments removed
  215. */
  216. public Member getMatchingSignature() {
  217. return matchingSignature != null ? matchingSignature : signature;
  218. }
  219. public void setMatchingSignature(Member member) {
  220. this.matchingSignature = member;
  221. }
  222. /**
  223. * returns the resolved signature of the thing under this shadow
  224. *
  225. */
  226. public ResolvedMember getResolvedSignature() {
  227. if (resolvedSignature == null) {
  228. resolvedSignature = signature.resolve(getIWorld());
  229. }
  230. return resolvedSignature;
  231. }
  232. public UnresolvedType getReturnType() {
  233. if (kind == ConstructorCall) {
  234. return getSignature().getDeclaringType();
  235. } else if (kind == FieldSet) {
  236. return UnresolvedType.VOID;
  237. } else if (kind == SynchronizationLock || kind == SynchronizationUnlock) {
  238. return UnresolvedType.VOID;
  239. }
  240. return getResolvedSignature().getGenericReturnType();
  241. }
  242. public static String METHOD_EXECUTION = "method-execution";
  243. public static String METHOD_CALL = "method-call";
  244. public static String CONSTRUCTOR_EXECUTION = "constructor-execution";
  245. public static String CONSTRUCTOR_CALL = "constructor-call";
  246. public static String FIELD_GET = "field-get";
  247. public static String FIELD_SET = "field-set";
  248. public static String STATICINITIALIZATION = "staticinitialization";
  249. public static String PREINITIALIZATION = "preinitialization";
  250. public static String INITIALIZATION = "initialization";
  251. public static String EXCEPTION_HANDLER = "exception-handler";
  252. public static String SYNCHRONIZATION_LOCK = "lock";
  253. public static String SYNCHRONIZATION_UNLOCK = "unlock";
  254. public static String ADVICE_EXECUTION = "adviceexecution";
  255. /**
  256. * These names are the ones that will be returned by thisJoinPoint.getKind() Those need to be documented somewhere
  257. */
  258. public static final Kind MethodCall = new Kind(METHOD_CALL, 1, true);
  259. public static final Kind ConstructorCall = new Kind(CONSTRUCTOR_CALL, 2, true);
  260. public static final Kind MethodExecution = new Kind(METHOD_EXECUTION, 3, false);
  261. public static final Kind ConstructorExecution = new Kind(CONSTRUCTOR_EXECUTION, 4, false);
  262. public static final Kind FieldGet = new Kind(FIELD_GET, 5, true);
  263. public static final Kind FieldSet = new Kind(FIELD_SET, 6, true);
  264. public static final Kind StaticInitialization = new Kind(STATICINITIALIZATION, 7, false);
  265. public static final Kind PreInitialization = new Kind(PREINITIALIZATION, 8, false);
  266. public static final Kind AdviceExecution = new Kind(ADVICE_EXECUTION, 9, false);
  267. public static final Kind Initialization = new Kind(INITIALIZATION, 10, false);
  268. public static final Kind ExceptionHandler = new Kind(EXCEPTION_HANDLER, 11, true);
  269. public static final Kind SynchronizationLock = new Kind(SYNCHRONIZATION_LOCK, 12, true);
  270. public static final Kind SynchronizationUnlock = new Kind(SYNCHRONIZATION_UNLOCK, 13, true);
  271. // Bits here are 1<<(Kind.getKey()) - and unfortunately keys didn't start at zero so bits here start at 2
  272. public static final int MethodCallBit = 0x002;
  273. public static final int ConstructorCallBit = 0x004;
  274. public static final int MethodExecutionBit = 0x008;
  275. public static final int ConstructorExecutionBit = 0x010;
  276. public static final int FieldGetBit = 0x020;
  277. public static final int FieldSetBit = 0x040;
  278. public static final int StaticInitializationBit = 0x080;
  279. public static final int PreInitializationBit = 0x100;
  280. public static final int AdviceExecutionBit = 0x200;
  281. public static final int InitializationBit = 0x400;
  282. public static final int ExceptionHandlerBit = 0x800;
  283. public static final int SynchronizationLockBit = 0x1000;
  284. public static final int SynchronizationUnlockBit = 0x2000;
  285. public static final int MAX_SHADOW_KIND = 13;
  286. public static final Kind[] SHADOW_KINDS = new Kind[] { MethodCall, ConstructorCall, MethodExecution, ConstructorExecution,
  287. FieldGet, FieldSet, StaticInitialization, PreInitialization, AdviceExecution, Initialization, ExceptionHandler,
  288. SynchronizationLock, SynchronizationUnlock };
  289. public static final int ALL_SHADOW_KINDS_BITS;
  290. public static final int NO_SHADOW_KINDS_BITS;
  291. static {
  292. ALL_SHADOW_KINDS_BITS = 0x3ffe;
  293. NO_SHADOW_KINDS_BITS = 0x0000;
  294. }
  295. /**
  296. * Return count of how many bits set in the supplied parameter.
  297. */
  298. public static int howMany(int i) {
  299. int count = 0;
  300. for (Kind shadowKind : SHADOW_KINDS) {
  301. if ((i & shadowKind.bit) != 0) {
  302. count++;
  303. }
  304. }
  305. return count;
  306. }
  307. /**
  308. * A type-safe enum representing the kind of shadows
  309. */
  310. public static final class Kind extends TypeSafeEnum {
  311. // private boolean argsOnStack; //XXX unused
  312. public int bit;
  313. public Kind(String name, int key, boolean argsOnStack) {
  314. super(name, key);
  315. bit = 1 << key;
  316. // this.argsOnStack = argsOnStack;
  317. }
  318. public String toLegalJavaIdentifier() {
  319. return getName().replace('-', '_');
  320. }
  321. public boolean argsOnStack() {
  322. return !isTargetSameAsThis();
  323. }
  324. // false for handlers
  325. public boolean allowsExtraction() {
  326. return true;
  327. }
  328. public boolean isSet(int i) {
  329. return (i & bit) != 0;
  330. }
  331. // XXX revisit along with removal of priorities
  332. public boolean hasHighPriorityExceptions() {
  333. return !isTargetSameAsThis();
  334. }
  335. private final static int hasReturnValueFlag = MethodCallBit | ConstructorCallBit | MethodExecutionBit | FieldGetBit
  336. | AdviceExecutionBit;
  337. /**
  338. * These shadow kinds have return values that can be bound in after returning(Dooberry doo) advice.
  339. *
  340. * @return
  341. */
  342. public boolean hasReturnValue() {
  343. return (bit & hasReturnValueFlag) != 0;
  344. }
  345. private final static int isEnclosingKindFlag = MethodExecutionBit | ConstructorExecutionBit | AdviceExecutionBit
  346. | StaticInitializationBit | InitializationBit;
  347. /**
  348. * These are all the shadows that contains other shadows within them and are often directly associated with methods.
  349. */
  350. public boolean isEnclosingKind() {
  351. return (bit & isEnclosingKindFlag) != 0;
  352. }
  353. private final static int isTargetSameAsThisFlag = MethodExecutionBit | ConstructorExecutionBit | StaticInitializationBit
  354. | PreInitializationBit | AdviceExecutionBit | InitializationBit;
  355. public boolean isTargetSameAsThis() {
  356. return (bit & isTargetSameAsThisFlag) != 0;
  357. }
  358. private final static int neverHasTargetFlag = ConstructorCallBit | ExceptionHandlerBit | PreInitializationBit
  359. | StaticInitializationBit | SynchronizationLockBit | SynchronizationUnlockBit;
  360. public boolean neverHasTarget() {
  361. return (bit & neverHasTargetFlag) != 0;
  362. }
  363. private final static int neverHasThisFlag = PreInitializationBit | StaticInitializationBit;
  364. public boolean neverHasThis() {
  365. return (bit & neverHasThisFlag) != 0;
  366. }
  367. public String getSimpleName() {
  368. int dash = getName().lastIndexOf('-');
  369. if (dash == -1) {
  370. return getName();
  371. } else {
  372. return getName().substring(dash + 1);
  373. }
  374. }
  375. public static Kind read(DataInputStream s) throws IOException {
  376. int key = s.readByte();
  377. switch (key) {
  378. case 1:
  379. return MethodCall;
  380. case 2:
  381. return ConstructorCall;
  382. case 3:
  383. return MethodExecution;
  384. case 4:
  385. return ConstructorExecution;
  386. case 5:
  387. return FieldGet;
  388. case 6:
  389. return FieldSet;
  390. case 7:
  391. return StaticInitialization;
  392. case 8:
  393. return PreInitialization;
  394. case 9:
  395. return AdviceExecution;
  396. case 10:
  397. return Initialization;
  398. case 11:
  399. return ExceptionHandler;
  400. case 12:
  401. return SynchronizationLock;
  402. case 13:
  403. return SynchronizationUnlock;
  404. }
  405. throw new BCException("unknown kind: " + key);
  406. }
  407. }
  408. /**
  409. * Only does the check if the munger requires it (@AJ aspects don't)
  410. *
  411. * @param munger
  412. * @return
  413. */
  414. protected boolean checkMunger(ShadowMunger munger) {
  415. if (munger.mustCheckExceptions()) {
  416. for (ResolvedType resolvedType : munger.getThrownExceptions()) {
  417. if (!checkCanThrow(munger, resolvedType)) {
  418. return false;
  419. }
  420. }
  421. }
  422. return true;
  423. }
  424. protected boolean checkCanThrow(ShadowMunger munger, ResolvedType resolvedTypeX) {
  425. if (getKind() == ExceptionHandler) {
  426. // XXX much too lenient rules here, need to walk up exception handlers
  427. return true;
  428. }
  429. if (!isDeclaredException(resolvedTypeX, getSignature())) {
  430. getIWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.CANT_THROW_CHECKED, resolvedTypeX, this), // from
  431. // advice
  432. // in
  433. // \
  434. // '"
  435. // +
  436. // munger
  437. // .
  438. // +
  439. // "\'"
  440. // ,
  441. getSourceLocation(), munger.getSourceLocation());
  442. }
  443. return true;
  444. }
  445. private boolean isDeclaredException(ResolvedType resolvedTypeX, Member member) {
  446. ResolvedType[] excs = getIWorld().resolve(member.getExceptions(getIWorld()));
  447. for (ResolvedType exc : excs) {
  448. if (exc.isAssignableFrom(resolvedTypeX)) {
  449. return true;
  450. }
  451. }
  452. return false;
  453. }
  454. public void addMunger(ShadowMunger munger) {
  455. if (checkMunger(munger)) {
  456. if (mungers == Collections.EMPTY_LIST) {
  457. mungers = new ArrayList<>();
  458. }
  459. this.mungers.add(munger);
  460. }
  461. }
  462. public final void implement() {
  463. sortMungers();
  464. if (mungers == null) {
  465. return;
  466. }
  467. prepareForMungers();
  468. implementMungers();
  469. }
  470. private void sortMungers() {
  471. List<ShadowMunger> sorted = PartialOrder.sort(mungers);
  472. // Bunch of code to work out whether to report xlints for advice that isn't ordered at this Joinpoint
  473. possiblyReportUnorderedAdvice(sorted);
  474. if (sorted == null) {
  475. // this means that we have circular dependencies
  476. for (ShadowMunger m : mungers) {
  477. getIWorld().getMessageHandler().handleMessage(
  478. MessageUtil.error(WeaverMessages.format(WeaverMessages.CIRCULAR_DEPENDENCY, this), m.getSourceLocation()));
  479. }
  480. }
  481. mungers = sorted;
  482. }
  483. // not quite optimal... but the xlint is ignore by default
  484. private void possiblyReportUnorderedAdvice(List<ShadowMunger> sorted) {
  485. if (sorted != null && getIWorld().getLint().unorderedAdviceAtShadow.isEnabled() && mungers.size() > 1) {
  486. // Stores a set of strings of the form 'aspect1:aspect2' which indicates there is no
  487. // precedence specified between the two aspects at this shadow.
  488. Set<String> clashingAspects = new HashSet<>();
  489. int max = mungers.size();
  490. // Compare every pair of advice mungers
  491. for (int i = max - 1; i >= 0; i--) {
  492. for (int j = 0; j < i; j++) {
  493. ShadowMunger a = mungers.get(i);
  494. ShadowMunger b = mungers.get(j);
  495. // Make sure they are the right type
  496. if (a instanceof Advice && b instanceof Advice) {
  497. Advice adviceA = (Advice) a;
  498. Advice adviceB = (Advice) b;
  499. if (!adviceA.concreteAspect.equals(adviceB.concreteAspect)) {
  500. AdviceKind adviceKindA = adviceA.getKind();
  501. AdviceKind adviceKindB = adviceB.getKind();
  502. // make sure they are the nice ones (<6) and not any synthetic advice ones we
  503. // create to support other features of the language.
  504. if (adviceKindA.getKey() < (byte) 6 && adviceKindB.getKey() < (byte) 6
  505. && adviceKindA.getPrecedence() == adviceKindB.getPrecedence()) {
  506. // Ask the world if it knows about precedence between these
  507. Integer order = getIWorld().getPrecedenceIfAny(adviceA.concreteAspect, adviceB.concreteAspect);
  508. if (order != null && order.equals(0)) {
  509. String key = adviceA.getDeclaringAspect() + ":" + adviceB.getDeclaringAspect();
  510. String possibleExistingKey = adviceB.getDeclaringAspect() + ":" + adviceA.getDeclaringAspect();
  511. if (!clashingAspects.contains(possibleExistingKey)) {
  512. clashingAspects.add(key);
  513. }
  514. }
  515. }
  516. }
  517. }
  518. }
  519. }
  520. for (String element : clashingAspects) {
  521. String aspect1 = element.substring(0, element.indexOf(":"));
  522. String aspect2 = element.substring(element.indexOf(":") + 1);
  523. getIWorld().getLint().unorderedAdviceAtShadow.signal(new String[]{this.toString(), aspect1, aspect2},
  524. this.getSourceLocation(), null);
  525. }
  526. }
  527. }
  528. /**
  529. * Prepare the shadow for implementation. After this is done, the shadow should be in such a position that each munger simply
  530. * needs to be implemented.
  531. */
  532. protected void prepareForMungers() {
  533. throw new RuntimeException("Generic shadows cannot be prepared");
  534. }
  535. /** Actually implement the (non-empty) mungers associated with this shadow */
  536. private void implementMungers() {
  537. World world = getIWorld();
  538. needAroundClosureStacking = false;
  539. int annotationStyleWithAroundAndProceedCount = 0;
  540. for (ShadowMunger munger: mungers) {
  541. if (munger.getDeclaringType()!= null &&
  542. munger.getDeclaringType().isAnnotationStyleAspect() &&
  543. munger.isAroundAdvice() &&
  544. munger.bindsProceedingJoinPoint()) {
  545. annotationStyleWithAroundAndProceedCount++;
  546. if (annotationStyleWithAroundAndProceedCount>1) {
  547. needAroundClosureStacking = true;
  548. break;
  549. }
  550. }
  551. }
  552. for (ShadowMunger munger : mungers) {
  553. if (munger.implementOn(this)) {
  554. world.reportMatch(munger, this);
  555. }
  556. }
  557. }
  558. public abstract ISourceLocation getSourceLocation();
  559. // ---- utility
  560. public String toString() {
  561. return getKind() + "(" + getSignature() + ")"; // + getSourceLines();
  562. }
  563. public String toResolvedString(World world) {
  564. StringBuilder sb = new StringBuilder();
  565. sb.append(getKind());
  566. sb.append("(");
  567. Member m = getSignature();
  568. if (m == null) {
  569. sb.append("<<missing signature>>");
  570. } else {
  571. ResolvedMember rm = world.resolve(m);
  572. if (rm == null) {
  573. sb.append("<<unresolvableMember:").append(m).append(">>");
  574. } else {
  575. String genString = rm.toGenericString();
  576. if (genString == null) {
  577. sb.append("<<unableToGetGenericStringFor:").append(rm).append(">>");
  578. } else {
  579. sb.append(genString);
  580. }
  581. }
  582. }
  583. sb.append(")");
  584. return sb.toString();
  585. // was: return getKind() + "(" + world.resolve(getSignature()).toGenericString() + ")";
  586. }
  587. /**
  588. * Convert a bit array for the shadow kinds into a set of them... should only be used for testing - mainline code should do bit
  589. * manipulation!
  590. */
  591. public static Set<Kind> toSet(int i) {
  592. Set<Kind> results = new HashSet<>();
  593. for (int j = 0; j < Shadow.SHADOW_KINDS.length; j++) {
  594. Kind k = Shadow.SHADOW_KINDS[j];
  595. if (k.isSet(i)) {
  596. results.add(k);
  597. }
  598. }
  599. return results;
  600. }
  601. }