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.

CrosscuttingMembers.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  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.util.ArrayList;
  14. import java.util.Collection;
  15. import java.util.HashSet;
  16. import java.util.Hashtable;
  17. import java.util.Iterator;
  18. import java.util.LinkedHashSet;
  19. import java.util.List;
  20. import java.util.Map;
  21. import java.util.Set;
  22. import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
  23. import org.aspectj.weaver.patterns.Declare;
  24. import org.aspectj.weaver.patterns.DeclareAnnotation;
  25. import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
  26. import org.aspectj.weaver.patterns.DeclareParents;
  27. import org.aspectj.weaver.patterns.DeclarePrecedence;
  28. import org.aspectj.weaver.patterns.DeclareSoft;
  29. import org.aspectj.weaver.patterns.DeclareTypeErrorOrWarning;
  30. import org.aspectj.weaver.patterns.PerClause;
  31. import org.aspectj.weaver.patterns.Pointcut;
  32. import org.aspectj.weaver.patterns.PointcutRewriter;
  33. /**
  34. * This holds on to all members that have an invasive effect outside of there own compilation unit. These members need to be all
  35. * gathered up and in a world before any weaving can take place.
  36. *
  37. * They are also important in the compilation process and need to be gathered up before the inter-type declaration weaving stage
  38. * (unsurprisingly).
  39. *
  40. * All members are concrete.
  41. *
  42. * @author Jim Hugunin
  43. */
  44. public class CrosscuttingMembers {
  45. private final ResolvedType inAspect;
  46. private final World world;
  47. private PerClause perClause;
  48. private List<ShadowMunger> shadowMungers = new ArrayList<>(4);
  49. private List<ConcreteTypeMunger> typeMungers = new ArrayList<>(4);
  50. private List<ConcreteTypeMunger> lateTypeMungers = new ArrayList<>(0);
  51. private Set<DeclareParents> declareParents = new HashSet<>();
  52. private Set<DeclareSoft> declareSofts = new HashSet<>();
  53. private List<Declare> declareDominates = new ArrayList<>(4);
  54. // These are like declare parents type mungers
  55. private Set<DeclareAnnotation> declareAnnotationsOnType = new LinkedHashSet<>();
  56. private Set<DeclareAnnotation> declareAnnotationsOnField = new LinkedHashSet<>();
  57. private Set<DeclareAnnotation> declareAnnotationsOnMethods = new LinkedHashSet<>();
  58. // declareAnnotationsOnMethods includes constructors too
  59. private Set<DeclareTypeErrorOrWarning> declareTypeEow = new HashSet<>();
  60. private boolean shouldConcretizeIfNeeded = true;
  61. public CrosscuttingMembers(ResolvedType inAspect, boolean shouldConcretizeIfNeeded) {
  62. this.inAspect = inAspect;
  63. world = inAspect.getWorld();
  64. this.shouldConcretizeIfNeeded = shouldConcretizeIfNeeded;
  65. }
  66. private final Map<String, Object> cflowFields = new Hashtable<>();
  67. private final Map<String, Object> cflowBelowFields = new Hashtable<>();
  68. // public void addConcreteShadowMungers(Collection c) {
  69. // shadowMungers.addAll(c);
  70. // }
  71. public void addConcreteShadowMunger(ShadowMunger m) {
  72. // assert m is concrete
  73. shadowMungers.add(m);
  74. }
  75. public void addShadowMungers(Collection<ShadowMunger> c) {
  76. for (ShadowMunger munger : c) {
  77. addShadowMunger(munger);
  78. }
  79. }
  80. private void addShadowMunger(ShadowMunger m) {
  81. if (inAspect.isAbstract()) {
  82. return; // mungers for abstract aspects are not added
  83. }
  84. addConcreteShadowMunger(m.concretize(inAspect, world, perClause));
  85. }
  86. public void addTypeMungers(Collection<ConcreteTypeMunger> c) {
  87. typeMungers.addAll(c);
  88. }
  89. public void addTypeMunger(ConcreteTypeMunger m) {
  90. if (m == null) {
  91. throw new Error("FIXME AV - should not happen or what ?");// return;
  92. }
  93. typeMungers.add(m);
  94. }
  95. public void addLateTypeMungers(Collection<ConcreteTypeMunger> c) {
  96. lateTypeMungers.addAll(c);
  97. }
  98. public void addLateTypeMunger(ConcreteTypeMunger m) {
  99. lateTypeMungers.add(m);
  100. }
  101. public void addDeclares(Collection<Declare> declares) {
  102. for (Declare declare : declares) {
  103. addDeclare(declare);
  104. }
  105. }
  106. public void addDeclare(Declare declare) {
  107. // this is not extensible, oh well
  108. if (declare instanceof DeclareErrorOrWarning) {
  109. ShadowMunger m = new Checker((DeclareErrorOrWarning) declare);
  110. m.setDeclaringType(declare.getDeclaringType());
  111. addShadowMunger(m);
  112. } else if (declare instanceof DeclarePrecedence) {
  113. declareDominates.add(declare);
  114. } else if (declare instanceof DeclareParents) {
  115. DeclareParents dp = (DeclareParents) declare;
  116. exposeTypes(dp.getParents().getExactTypes());
  117. declareParents.add(dp);
  118. } else if (declare instanceof DeclareSoft) {
  119. DeclareSoft d = (DeclareSoft) declare;
  120. // Ordered so that during concretization we can check the related
  121. // munger
  122. ShadowMunger m = Advice.makeSoftener(world, d.getPointcut(), d.getException(), inAspect, d);
  123. m.setDeclaringType(d.getDeclaringType());
  124. Pointcut concretePointcut = d.getPointcut().concretize(inAspect, d.getDeclaringType(), 0, m);
  125. m.pointcut = concretePointcut;
  126. declareSofts.add(new DeclareSoft(d.getException(), concretePointcut));
  127. addConcreteShadowMunger(m);
  128. } else if (declare instanceof DeclareAnnotation) {
  129. // FIXME asc perf Possible Improvement. Investigate why this is
  130. // called twice in a weave ?
  131. DeclareAnnotation da = (DeclareAnnotation) declare;
  132. if (da.getAspect() == null) {
  133. da.setAspect(inAspect);
  134. }
  135. if (da.isDeclareAtType()) {
  136. declareAnnotationsOnType.add(da);
  137. } else if (da.isDeclareAtField()) {
  138. declareAnnotationsOnField.add(da);
  139. } else if (da.isDeclareAtMethod() || da.isDeclareAtConstuctor()) {
  140. declareAnnotationsOnMethods.add(da);
  141. }
  142. } else if (declare instanceof DeclareTypeErrorOrWarning) {
  143. declareTypeEow.add((DeclareTypeErrorOrWarning) declare);
  144. } else {
  145. throw new RuntimeException("unimplemented");
  146. }
  147. }
  148. public void exposeTypes(List<UnresolvedType> typesToExpose) {
  149. for (UnresolvedType typeToExpose : typesToExpose) {
  150. exposeType(typeToExpose);
  151. }
  152. }
  153. public void exposeType(UnresolvedType typeToExpose) {
  154. if (ResolvedType.isMissing(typeToExpose)) {
  155. return;
  156. }
  157. if (typeToExpose.isParameterizedType() || typeToExpose.isRawType()) {
  158. if (typeToExpose instanceof ResolvedType) {
  159. typeToExpose = ((ResolvedType) typeToExpose).getGenericType();
  160. } else {
  161. typeToExpose = UnresolvedType.forSignature(typeToExpose.getErasureSignature());
  162. }
  163. }
  164. // Check we haven't already got a munger for this:
  165. String signatureToLookFor = typeToExpose.getSignature();
  166. for (ConcreteTypeMunger cTM : typeMungers) {
  167. ResolvedTypeMunger rTM = cTM.getMunger();
  168. if (rTM != null && rTM instanceof ExposeTypeMunger) {
  169. String exposedType = ((ExposeTypeMunger) rTM).getExposedTypeSignature();
  170. if (exposedType.equals(signatureToLookFor)) {
  171. return; // dont need to bother
  172. }
  173. }
  174. }
  175. addTypeMunger(world.getWeavingSupport().concreteTypeMunger(new ExposeTypeMunger(typeToExpose), inAspect));
  176. // ResolvedMember member = new ResolvedMemberImpl(
  177. // Member.STATIC_INITIALIZATION, typeToExpose, 0, UnresolvedType.VOID,
  178. // "<clinit>", UnresolvedType.NONE);
  179. // addTypeMunger(world.concreteTypeMunger(
  180. // new PrivilegedAccessMunger(member), inAspect));
  181. }
  182. public void addPrivilegedAccesses(Collection<ResolvedMember> accessedMembers) {
  183. int version = inAspect.getCompilerVersion();
  184. for (ResolvedMember member : accessedMembers) {
  185. // Looking it up ensures we get the annotations - the accessedMembers are just retrieved from the attribute and
  186. // don't have that information
  187. ResolvedMember resolvedMember = world.resolve(member);
  188. // pr333469
  189. // If the member is for an ITD (e.g. serialVersionUID) then during resolution we may resolve it on
  190. // a supertype because it doesn't yet exist on the target.
  191. // For example: MyList extends ArrayList<String> and the ITD is on MyList - after resolution it may be:
  192. // ArrayList<String>.serialVersionUID, we need to avoid that happening
  193. if (resolvedMember == null) {
  194. // can happen for ITDs - are there many privileged access ITDs??
  195. resolvedMember = member;
  196. if (resolvedMember.hasBackingGenericMember()) {
  197. resolvedMember = resolvedMember.getBackingGenericMember();
  198. }
  199. } else {
  200. UnresolvedType unresolvedDeclaringType = member.getDeclaringType().getRawType();
  201. UnresolvedType resolvedDeclaringType = resolvedMember.getDeclaringType().getRawType();
  202. if (!unresolvedDeclaringType.equals(resolvedDeclaringType)) {
  203. resolvedMember = member;
  204. }
  205. }
  206. PrivilegedAccessMunger privilegedAccessMunger = new PrivilegedAccessMunger(resolvedMember,
  207. version >= WeaverVersionInfo.WEAVER_VERSION_AJ169);
  208. ConcreteTypeMunger concreteTypeMunger = world.getWeavingSupport().concreteTypeMunger(privilegedAccessMunger, inAspect);
  209. addTypeMunger(concreteTypeMunger);
  210. }
  211. }
  212. public Collection<ShadowMunger> getCflowEntries() {
  213. List<ShadowMunger> ret = new ArrayList<>();
  214. for (ShadowMunger m : shadowMungers) {
  215. if (m instanceof Advice) {
  216. Advice a = (Advice) m;
  217. if (a.getKind().isCflow()) {
  218. ret.add(a);
  219. }
  220. }
  221. }
  222. return ret;
  223. }
  224. /**
  225. * Updates the records if something has changed. This is called at most twice, firstly whilst collecting ITDs and declares. At
  226. * this point the CrosscuttingMembers we're comparing ourselves with doesn't know about shadowmungers. Therefore a straight
  227. * comparison with the existing list of shadowmungers would return that something has changed even though it might not have, so
  228. * in this first round we ignore the shadowMungers. The second time this is called is whilst we're preparing to weave. At this
  229. * point we know everything in the system and so we're able to compare the shadowMunger list. (see bug 129163)
  230. *
  231. * @param other
  232. * @param careAboutShadowMungers
  233. * @return true if something has changed since the last time this method was called, false otherwise
  234. */
  235. public boolean replaceWith(CrosscuttingMembers other, boolean careAboutShadowMungers) {
  236. boolean changed = false;
  237. if (careAboutShadowMungers) {
  238. if (perClause == null || !perClause.equals(other.perClause)) {
  239. changed = true;
  240. perClause = other.perClause;
  241. }
  242. }
  243. // XXX all of the below should be set equality rather than list equality
  244. // System.err.println("old: " + shadowMungers + " new: " +
  245. // other.shadowMungers);
  246. if (careAboutShadowMungers) {
  247. // bug 129163: use set equality rather than list equality
  248. Set<ShadowMunger> theseShadowMungers = new HashSet<>();
  249. Set<ShadowMunger> theseInlinedAroundMungers = new HashSet<>();
  250. for (ShadowMunger munger : shadowMungers) {
  251. if (munger instanceof Advice) {
  252. Advice adviceMunger = (Advice) munger;
  253. // bug 154054: if we're around advice that has been inlined
  254. // then we need to do more checking than existing equals
  255. // methods allow
  256. if (!world.isXnoInline() && adviceMunger.getKind().equals(AdviceKind.Around)) {
  257. theseInlinedAroundMungers.add(adviceMunger);
  258. } else {
  259. theseShadowMungers.add(adviceMunger);
  260. }
  261. } else {
  262. theseShadowMungers.add(munger);
  263. }
  264. }
  265. Set<ShadowMunger> tempSet = new HashSet<>(other.shadowMungers);
  266. Set<ShadowMunger> otherShadowMungers = new HashSet<>();
  267. Set<ShadowMunger> otherInlinedAroundMungers = new HashSet<>();
  268. for (ShadowMunger munger : tempSet) {
  269. if (munger instanceof Advice) {
  270. Advice adviceMunger = (Advice) munger;
  271. // bug 154054: if we're around advice that has been inlined
  272. // then we need to do more checking than existing equals
  273. // methods allow
  274. if (!world.isXnoInline() && adviceMunger.getKind().equals(AdviceKind.Around)) {
  275. otherInlinedAroundMungers.add(rewritePointcutInMunger(adviceMunger));
  276. } else {
  277. otherShadowMungers.add(rewritePointcutInMunger(adviceMunger));
  278. }
  279. } else {
  280. otherShadowMungers.add(rewritePointcutInMunger(munger));
  281. }
  282. }
  283. if (!theseShadowMungers.equals(otherShadowMungers)) {
  284. changed = true;
  285. }
  286. if (!equivalent(theseInlinedAroundMungers, otherInlinedAroundMungers)) {
  287. changed = true;
  288. }
  289. // bug 158573 - if there are no changes then preserve whether
  290. // or not a particular shadowMunger has matched something.
  291. if (!changed) {
  292. for (ShadowMunger munger : shadowMungers) {
  293. int i = other.shadowMungers.indexOf(munger);
  294. ShadowMunger otherMunger = other.shadowMungers.get(i);
  295. if (munger instanceof Advice) {
  296. ((Advice) otherMunger).setHasMatchedSomething(((Advice) munger).hasMatchedSomething());
  297. }
  298. }
  299. }
  300. // replace the existing list of shadowmungers with the
  301. // new ones in case anything like the sourcelocation has
  302. // changed, however, don't want this flagged as a change
  303. // which will force a full build - bug 134541
  304. shadowMungers = other.shadowMungers;
  305. }
  306. // bug 129163: use set equality rather than list equality and
  307. // if we dont care about shadow mungers then ignore those
  308. // typeMungers which are created to help with the implementation
  309. // of shadowMungers
  310. Set<ConcreteTypeMunger> theseTypeMungers = new HashSet<>();
  311. Set<ConcreteTypeMunger> otherTypeMungers = new HashSet<>();
  312. if (!careAboutShadowMungers) {
  313. for (ConcreteTypeMunger typeMunger : typeMungers) {
  314. if (!typeMunger.existsToSupportShadowMunging()) {
  315. theseTypeMungers.add(typeMunger);
  316. }
  317. }
  318. for (ConcreteTypeMunger typeMunger : other.typeMungers) {
  319. if (!typeMunger.existsToSupportShadowMunging()) {
  320. otherTypeMungers.add(typeMunger);
  321. }
  322. }
  323. } else {
  324. theseTypeMungers.addAll(typeMungers);
  325. otherTypeMungers.addAll(other.typeMungers);
  326. }
  327. // initial go at equivalence logic rather than set compare (see
  328. // pr133532)
  329. if (theseTypeMungers.size() != otherTypeMungers.size()) {
  330. changed = true;
  331. typeMungers = other.typeMungers;
  332. } else {
  333. boolean shouldOverwriteThis = false;
  334. boolean foundInequality = false;
  335. for (Iterator<ConcreteTypeMunger> iter = theseTypeMungers.iterator(); iter.hasNext() && !foundInequality;) {
  336. ConcreteTypeMunger thisOne = iter.next();
  337. boolean foundInOtherSet = false;
  338. for (ConcreteTypeMunger otherOne : otherTypeMungers) {
  339. if (thisOne instanceof ConcreteTypeMunger) {
  340. if (thisOne.shouldOverwrite()) {
  341. shouldOverwriteThis = true;
  342. }
  343. }
  344. if (thisOne instanceof ConcreteTypeMunger && otherOne instanceof ConcreteTypeMunger) {
  345. if (thisOne.equivalentTo(otherOne)) {
  346. foundInOtherSet = true;
  347. } else if (thisOne.equals(otherOne)) {
  348. foundInOtherSet = true;
  349. }
  350. } else {
  351. if (thisOne.equals(otherOne)) {
  352. foundInOtherSet = true;
  353. }
  354. }
  355. }
  356. if (!foundInOtherSet) {
  357. foundInequality = true;
  358. }
  359. }
  360. if (foundInequality) {
  361. // System.out.println("type munger change");
  362. changed = true;
  363. }
  364. if (shouldOverwriteThis) {
  365. typeMungers = other.typeMungers;
  366. }
  367. }
  368. // if (!theseTypeMungers.equals(otherTypeMungers)) {
  369. // changed = true;
  370. // typeMungers = other.typeMungers;
  371. // }
  372. if (!lateTypeMungers.equals(other.lateTypeMungers)) {
  373. changed = true;
  374. lateTypeMungers = other.lateTypeMungers;
  375. }
  376. if (!declareDominates.equals(other.declareDominates)) {
  377. changed = true;
  378. declareDominates = other.declareDominates;
  379. }
  380. if (!declareParents.equals(other.declareParents)) {
  381. // Are the differences just because of a mixin? These are not created until weave time so should be gotten rid of for
  382. // the up front comparison
  383. if (!careAboutShadowMungers) {
  384. // this means we are in front end compilation and if the differences are purely mixin parents, we can continue OK
  385. Set<DeclareParents> trimmedThis = new HashSet<>();
  386. for (DeclareParents decp : declareParents) {
  387. if (!decp.isMixin()) {
  388. trimmedThis.add(decp);
  389. }
  390. }
  391. Set<DeclareParents> trimmedOther = new HashSet<>();
  392. for (DeclareParents decp : other.declareParents) {
  393. if (!decp.isMixin()) {
  394. trimmedOther.add(decp);
  395. }
  396. }
  397. if (!trimmedThis.equals(trimmedOther)) {
  398. changed = true;
  399. declareParents = other.declareParents;
  400. }
  401. } else {
  402. changed = true;
  403. declareParents = other.declareParents;
  404. }
  405. }
  406. if (!declareSofts.equals(other.declareSofts)) {
  407. changed = true;
  408. declareSofts = other.declareSofts;
  409. }
  410. // DECAT for when attempting to replace an aspect
  411. if (!declareAnnotationsOnType.equals(other.declareAnnotationsOnType)) {
  412. changed = true;
  413. declareAnnotationsOnType = other.declareAnnotationsOnType;
  414. }
  415. if (!declareAnnotationsOnField.equals(other.declareAnnotationsOnField)) {
  416. changed = true;
  417. declareAnnotationsOnField = other.declareAnnotationsOnField;
  418. }
  419. if (!declareAnnotationsOnMethods.equals(other.declareAnnotationsOnMethods)) {
  420. changed = true;
  421. declareAnnotationsOnMethods = other.declareAnnotationsOnMethods;
  422. }
  423. if (!declareTypeEow.equals(other.declareTypeEow)) {
  424. changed = true;
  425. declareTypeEow = other.declareTypeEow;
  426. }
  427. return changed;
  428. }
  429. private boolean equivalent(Set<ShadowMunger> theseInlinedAroundMungers, Set<ShadowMunger> otherInlinedAroundMungers) {
  430. if (theseInlinedAroundMungers.size() != otherInlinedAroundMungers.size()) {
  431. return false;
  432. }
  433. for (ShadowMunger theseInlinedAroundMunger : theseInlinedAroundMungers) {
  434. Advice thisAdvice = (Advice) theseInlinedAroundMunger;
  435. boolean foundIt = false;
  436. for (ShadowMunger otherInlinedAroundMunger : otherInlinedAroundMungers) {
  437. Advice otherAdvice = (Advice) otherInlinedAroundMunger;
  438. if (thisAdvice.equals(otherAdvice)) {
  439. if (thisAdvice.getSignature() instanceof ResolvedMemberImpl) {
  440. if (((ResolvedMemberImpl) thisAdvice.getSignature()).isEquivalentTo(otherAdvice.getSignature())) {
  441. foundIt = true;
  442. continue;
  443. }
  444. }
  445. return false;
  446. }
  447. }
  448. if (!foundIt) {
  449. return false;
  450. }
  451. }
  452. return true;
  453. }
  454. private ShadowMunger rewritePointcutInMunger(ShadowMunger munger) {
  455. PointcutRewriter pr = new PointcutRewriter();
  456. Pointcut p = munger.getPointcut();
  457. Pointcut newP = pr.rewrite(p);
  458. if (p.m_ignoreUnboundBindingForNames.length != 0) {
  459. // *sigh* dirty fix for dirty hacky implementation pr149305
  460. newP.m_ignoreUnboundBindingForNames = p.m_ignoreUnboundBindingForNames;
  461. }
  462. munger.setPointcut(newP);
  463. return munger;
  464. }
  465. public void setPerClause(PerClause perClause) {
  466. if (shouldConcretizeIfNeeded) {
  467. this.perClause = perClause.concretize(inAspect);
  468. } else {
  469. this.perClause = perClause;
  470. }
  471. }
  472. public List<Declare> getDeclareDominates() {
  473. return declareDominates;
  474. }
  475. public Collection<DeclareParents> getDeclareParents() {
  476. return declareParents;
  477. }
  478. public Collection<DeclareSoft> getDeclareSofts() {
  479. return declareSofts;
  480. }
  481. public List<ShadowMunger> getShadowMungers() {
  482. return shadowMungers;
  483. }
  484. public List<ConcreteTypeMunger> getTypeMungers() {
  485. return typeMungers;
  486. }
  487. public List<ConcreteTypeMunger> getLateTypeMungers() {
  488. return lateTypeMungers;
  489. }
  490. public Collection<DeclareAnnotation> getDeclareAnnotationOnTypes() {
  491. return declareAnnotationsOnType;
  492. }
  493. public Collection<DeclareAnnotation> getDeclareAnnotationOnFields() {
  494. return declareAnnotationsOnField;
  495. }
  496. /**
  497. * includes declare @method and @constructor
  498. */
  499. public Collection<DeclareAnnotation> getDeclareAnnotationOnMethods() {
  500. return declareAnnotationsOnMethods;
  501. }
  502. public Collection<DeclareTypeErrorOrWarning> getDeclareTypeErrorOrWarning() {
  503. return declareTypeEow;
  504. }
  505. public Map<String, Object> getCflowBelowFields() {
  506. return cflowBelowFields;
  507. }
  508. public Map<String, Object> getCflowFields() {
  509. return cflowFields;
  510. }
  511. public void clearCaches() {
  512. cflowFields.clear();
  513. cflowBelowFields.clear();
  514. }
  515. }