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.

TypePatternList.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  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.patterns;
  13. import java.io.IOException;
  14. import java.util.ArrayList;
  15. import java.util.List;
  16. import java.util.Map;
  17. import org.aspectj.bridge.ISourceLocation;
  18. import org.aspectj.util.FuzzyBoolean;
  19. import org.aspectj.weaver.CompressingDataOutputStream;
  20. import org.aspectj.weaver.ISourceContext;
  21. import org.aspectj.weaver.IntMap;
  22. import org.aspectj.weaver.ResolvableTypeList;
  23. import org.aspectj.weaver.ResolvedType;
  24. import org.aspectj.weaver.UnresolvedType;
  25. import org.aspectj.weaver.VersionedDataInputStream;
  26. import org.aspectj.weaver.World;
  27. public class TypePatternList extends PatternNode {
  28. private TypePattern[] typePatterns;
  29. int ellipsisCount = 0;
  30. public static final TypePatternList EMPTY = new TypePatternList(new TypePattern[] {});
  31. public static final TypePatternList ANY = new TypePatternList(new TypePattern[] { new EllipsisTypePattern() }); // can't use
  32. // TypePattern.ELLIPSIS
  33. // because of
  34. // circular
  35. // static
  36. // dependency
  37. // that
  38. // introduces
  39. public TypePatternList() {
  40. typePatterns = new TypePattern[0];
  41. ellipsisCount = 0;
  42. }
  43. public TypePatternList(TypePattern[] arguments) {
  44. this.typePatterns = arguments;
  45. for (TypePattern argument : arguments) {
  46. if (argument == TypePattern.ELLIPSIS) {
  47. ellipsisCount++;
  48. }
  49. }
  50. }
  51. public TypePatternList(List<TypePattern> l) {
  52. this(l.toArray(new TypePattern[0]));
  53. }
  54. public int size() {
  55. return typePatterns.length;
  56. }
  57. public TypePattern get(int index) {
  58. return typePatterns[index];
  59. }
  60. @Override
  61. public String toString() {
  62. StringBuilder buf = new StringBuilder();
  63. buf.append("(");
  64. for (int i = 0, len = typePatterns.length; i < len; i++) {
  65. TypePattern type = typePatterns[i];
  66. if (i > 0) {
  67. buf.append(", ");
  68. }
  69. if (type == TypePattern.ELLIPSIS) {
  70. buf.append("..");
  71. } else {
  72. buf.append(type.toString());
  73. }
  74. }
  75. buf.append(")");
  76. return buf.toString();
  77. }
  78. /*
  79. * return true iff this pattern could ever match a signature with the given number of parameters
  80. */
  81. public boolean canMatchSignatureWithNParameters(int numParams) {
  82. if (ellipsisCount == 0) {
  83. return numParams == size();
  84. } else {
  85. return (size() - ellipsisCount) <= numParams;
  86. }
  87. }
  88. public FuzzyBoolean matches(ResolvedType[] types, TypePattern.MatchKind kind) {
  89. return matches(types, kind, null);
  90. }
  91. // XXX shares much code with WildTypePattern and with NamePattern
  92. /**
  93. * When called with TypePattern.STATIC this will always return either FuzzyBoolean.YES or FuzzyBoolean.NO.
  94. *
  95. * When called with TypePattern.DYNAMIC this could return MAYBE if at runtime it would be possible for arguments of the given
  96. * static types to dynamically match this, but it is not known for certain.
  97. *
  98. * This method will never return FuzzyBoolean.NEVER
  99. */
  100. public FuzzyBoolean matches(ResolvedType[] types, TypePattern.MatchKind kind, ResolvedType[][] parameterAnnotations) {
  101. int nameLength = types.length;
  102. int patternLength = typePatterns.length;
  103. int nameIndex = 0;
  104. int patternIndex = 0;
  105. if (ellipsisCount == 0) {
  106. if (nameLength != patternLength) {
  107. return FuzzyBoolean.NO;
  108. }
  109. FuzzyBoolean finalReturn = FuzzyBoolean.YES;
  110. while (patternIndex < patternLength) {
  111. ResolvedType t = types[nameIndex];
  112. FuzzyBoolean ret = null;
  113. try {
  114. if (parameterAnnotations != null) {
  115. t.temporaryAnnotationTypes = parameterAnnotations[nameIndex];
  116. }
  117. ret = typePatterns[patternIndex].matches(t, kind);
  118. } finally {
  119. t.temporaryAnnotationTypes = null;
  120. }
  121. patternIndex++;
  122. nameIndex++;
  123. if (ret == FuzzyBoolean.NO) {
  124. return ret;
  125. }
  126. if (ret == FuzzyBoolean.MAYBE) {
  127. finalReturn = ret;
  128. }
  129. }
  130. return finalReturn;
  131. } else if (ellipsisCount == 1) {
  132. if (nameLength < patternLength - 1) {
  133. return FuzzyBoolean.NO;
  134. }
  135. FuzzyBoolean finalReturn = FuzzyBoolean.YES;
  136. while (patternIndex < patternLength) {
  137. TypePattern p = typePatterns[patternIndex++];
  138. if (p == TypePattern.ELLIPSIS) {
  139. nameIndex = nameLength - (patternLength - patternIndex);
  140. } else {
  141. ResolvedType t = types[nameIndex];
  142. FuzzyBoolean ret = null;
  143. try {
  144. if (parameterAnnotations != null) {
  145. t.temporaryAnnotationTypes = parameterAnnotations[nameIndex];
  146. }
  147. ret = p.matches(t, kind);
  148. } finally {
  149. t.temporaryAnnotationTypes = null;
  150. }
  151. nameIndex++;
  152. if (ret == FuzzyBoolean.NO) {
  153. return ret;
  154. }
  155. if (ret == FuzzyBoolean.MAYBE) {
  156. finalReturn = ret;
  157. }
  158. }
  159. }
  160. return finalReturn;
  161. } else {
  162. // System.err.print("match(" + arguments + ", " + types + ") -> ");
  163. FuzzyBoolean b = outOfStar(typePatterns, types, 0, 0, patternLength - ellipsisCount, nameLength, ellipsisCount, kind,
  164. parameterAnnotations);
  165. // System.err.println(b);
  166. return b;
  167. }
  168. }
  169. private static FuzzyBoolean outOfStar(final TypePattern[] pattern, final ResolvedType[] target, int pi, int ti, int pLeft,
  170. int tLeft, final int starsLeft, TypePattern.MatchKind kind, ResolvedType[][] parameterAnnotations) {
  171. if (pLeft > tLeft) {
  172. return FuzzyBoolean.NO;
  173. }
  174. FuzzyBoolean finalReturn = FuzzyBoolean.YES;
  175. while (true) {
  176. // invariant: if (tLeft > 0) then (ti < target.length && pi < pattern.length)
  177. if (tLeft == 0) {
  178. return finalReturn;
  179. }
  180. if (pLeft == 0) {
  181. if (starsLeft > 0) {
  182. return finalReturn;
  183. } else {
  184. return FuzzyBoolean.NO;
  185. }
  186. }
  187. if (pattern[pi] == TypePattern.ELLIPSIS) {
  188. return inStar(pattern, target, pi + 1, ti, pLeft, tLeft, starsLeft - 1, kind, parameterAnnotations);
  189. }
  190. FuzzyBoolean ret = null;
  191. try {
  192. if (parameterAnnotations != null) {
  193. target[ti].temporaryAnnotationTypes = parameterAnnotations[ti];
  194. }
  195. ret = pattern[pi].matches(target[ti], kind);
  196. } finally {
  197. target[ti].temporaryAnnotationTypes = null;
  198. }
  199. if (ret == FuzzyBoolean.NO) {
  200. return ret;
  201. }
  202. if (ret == FuzzyBoolean.MAYBE) {
  203. finalReturn = ret;
  204. }
  205. pi++;
  206. ti++;
  207. pLeft--;
  208. tLeft--;
  209. }
  210. }
  211. private static FuzzyBoolean inStar(final TypePattern[] pattern, final ResolvedType[] target, int pi, int ti, final int pLeft,
  212. int tLeft, int starsLeft, TypePattern.MatchKind kind, ResolvedType[][] parameterAnnotations) {
  213. // invariant: pLeft > 0, so we know we'll run out of stars and find a real char in pattern
  214. TypePattern patternChar = pattern[pi];
  215. while (patternChar == TypePattern.ELLIPSIS) {
  216. starsLeft--;
  217. patternChar = pattern[++pi];
  218. }
  219. while (true) {
  220. // invariant: if (tLeft > 0) then (ti < target.length)
  221. if (pLeft > tLeft) {
  222. return FuzzyBoolean.NO;
  223. }
  224. FuzzyBoolean ff = null;
  225. try {
  226. if (parameterAnnotations != null) {
  227. target[ti].temporaryAnnotationTypes = parameterAnnotations[ti];
  228. }
  229. ff = patternChar.matches(target[ti], kind);
  230. } finally {
  231. target[ti].temporaryAnnotationTypes = null;
  232. }
  233. if (ff.maybeTrue()) {
  234. FuzzyBoolean xx = outOfStar(pattern, target, pi + 1, ti + 1, pLeft - 1, tLeft - 1, starsLeft, kind,
  235. parameterAnnotations);
  236. if (xx.maybeTrue()) {
  237. return ff.and(xx);
  238. }
  239. }
  240. ti++;
  241. tLeft--;
  242. }
  243. }
  244. public FuzzyBoolean matches(ResolvableTypeList types, TypePattern.MatchKind kind, ResolvedType[][] parameterAnnotations) {
  245. int nameLength = types.length;
  246. int patternLength = typePatterns.length;
  247. int nameIndex = 0;
  248. int patternIndex = 0;
  249. if (ellipsisCount == 0) {
  250. if (nameLength != patternLength) {
  251. return FuzzyBoolean.NO;
  252. }
  253. FuzzyBoolean finalReturn = FuzzyBoolean.YES;
  254. while (patternIndex < patternLength) {
  255. ResolvedType t = types.getResolved(nameIndex);
  256. FuzzyBoolean ret = null;
  257. try {
  258. if (parameterAnnotations != null) {
  259. t.temporaryAnnotationTypes = parameterAnnotations[nameIndex];
  260. }
  261. ret = typePatterns[patternIndex].matches(t, kind);
  262. } finally {
  263. t.temporaryAnnotationTypes = null;
  264. }
  265. patternIndex++;
  266. nameIndex++;
  267. if (ret == FuzzyBoolean.NO) {
  268. return ret;
  269. }
  270. if (ret == FuzzyBoolean.MAYBE) {
  271. finalReturn = ret;
  272. }
  273. }
  274. return finalReturn;
  275. } else if (ellipsisCount == 1) {
  276. if (nameLength < patternLength - 1) {
  277. return FuzzyBoolean.NO;
  278. }
  279. FuzzyBoolean finalReturn = FuzzyBoolean.YES;
  280. while (patternIndex < patternLength) {
  281. TypePattern p = typePatterns[patternIndex++];
  282. if (p == TypePattern.ELLIPSIS) {
  283. nameIndex = nameLength - (patternLength - patternIndex);
  284. } else {
  285. ResolvedType t = types.getResolved(nameIndex);
  286. FuzzyBoolean ret = null;
  287. try {
  288. if (parameterAnnotations != null) {
  289. t.temporaryAnnotationTypes = parameterAnnotations[nameIndex];
  290. }
  291. ret = p.matches(t, kind);
  292. } finally {
  293. t.temporaryAnnotationTypes = null;
  294. }
  295. nameIndex++;
  296. if (ret == FuzzyBoolean.NO) {
  297. return ret;
  298. }
  299. if (ret == FuzzyBoolean.MAYBE) {
  300. finalReturn = ret;
  301. }
  302. }
  303. }
  304. return finalReturn;
  305. } else {
  306. // System.err.print("match(" + arguments + ", " + types + ") -> ");
  307. FuzzyBoolean b = outOfStar(typePatterns, types, 0, 0, patternLength - ellipsisCount, nameLength, ellipsisCount, kind,
  308. parameterAnnotations);
  309. // System.err.println(b);
  310. return b;
  311. }
  312. }
  313. private static FuzzyBoolean outOfStar(final TypePattern[] pattern, ResolvableTypeList target, int pi, int ti, int pLeft,
  314. int tLeft, final int starsLeft, TypePattern.MatchKind kind, ResolvedType[][] parameterAnnotations) {
  315. if (pLeft > tLeft) {
  316. return FuzzyBoolean.NO;
  317. }
  318. FuzzyBoolean finalReturn = FuzzyBoolean.YES;
  319. while (true) {
  320. // invariant: if (tLeft > 0) then (ti < target.length && pi < pattern.length)
  321. if (tLeft == 0) {
  322. return finalReturn;
  323. }
  324. if (pLeft == 0) {
  325. if (starsLeft > 0) {
  326. return finalReturn;
  327. } else {
  328. return FuzzyBoolean.NO;
  329. }
  330. }
  331. if (pattern[pi] == TypePattern.ELLIPSIS) {
  332. return inStar(pattern, target, pi + 1, ti, pLeft, tLeft, starsLeft - 1, kind, parameterAnnotations);
  333. }
  334. FuzzyBoolean ret = null;
  335. ResolvedType type = target.getResolved(ti);
  336. try {
  337. if (parameterAnnotations != null) {
  338. type.temporaryAnnotationTypes = parameterAnnotations[ti];
  339. }
  340. ret = pattern[pi].matches(type, kind);
  341. } finally {
  342. type.temporaryAnnotationTypes = null;
  343. }
  344. if (ret == FuzzyBoolean.NO) {
  345. return ret;
  346. }
  347. if (ret == FuzzyBoolean.MAYBE) {
  348. finalReturn = ret;
  349. }
  350. pi++;
  351. ti++;
  352. pLeft--;
  353. tLeft--;
  354. }
  355. }
  356. private static FuzzyBoolean inStar(final TypePattern[] pattern, ResolvableTypeList target, int pi, int ti, final int pLeft,
  357. int tLeft, int starsLeft, TypePattern.MatchKind kind, ResolvedType[][] parameterAnnotations) {
  358. // invariant: pLeft > 0, so we know we'll run out of stars and find a real char in pattern
  359. TypePattern patternChar = pattern[pi];
  360. while (patternChar == TypePattern.ELLIPSIS) {
  361. starsLeft--;
  362. patternChar = pattern[++pi];
  363. }
  364. while (true) {
  365. // invariant: if (tLeft > 0) then (ti < target.length)
  366. if (pLeft > tLeft) {
  367. return FuzzyBoolean.NO;
  368. }
  369. ResolvedType type = target.getResolved(ti);
  370. FuzzyBoolean ff = null;
  371. try {
  372. if (parameterAnnotations != null) {
  373. type.temporaryAnnotationTypes = parameterAnnotations[ti];
  374. }
  375. ff = patternChar.matches(type, kind);
  376. } finally {
  377. type.temporaryAnnotationTypes = null;
  378. }
  379. if (ff.maybeTrue()) {
  380. FuzzyBoolean xx = outOfStar(pattern, target, pi + 1, ti + 1, pLeft - 1, tLeft - 1, starsLeft, kind,
  381. parameterAnnotations);
  382. if (xx.maybeTrue()) {
  383. return ff.and(xx);
  384. }
  385. }
  386. ti++;
  387. tLeft--;
  388. }
  389. }
  390. /**
  391. * Return a version of this type pattern list in which all type variable references are replaced by their corresponding entry in
  392. * the map
  393. *
  394. * @param typeVariableMap
  395. * @return
  396. */
  397. public TypePatternList parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
  398. TypePattern[] parameterizedPatterns = new TypePattern[typePatterns.length];
  399. for (int i = 0; i < parameterizedPatterns.length; i++) {
  400. parameterizedPatterns[i] = typePatterns[i].parameterizeWith(typeVariableMap, w);
  401. }
  402. return new TypePatternList(parameterizedPatterns);
  403. }
  404. public TypePatternList resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
  405. for (int i = 0; i < typePatterns.length; i++) {
  406. TypePattern p = typePatterns[i];
  407. if (p != null) {
  408. typePatterns[i] = typePatterns[i].resolveBindings(scope, bindings, allowBinding, requireExactType);
  409. }
  410. }
  411. return this;
  412. }
  413. public TypePatternList resolveReferences(IntMap bindings) {
  414. int len = typePatterns.length;
  415. TypePattern[] ret = new TypePattern[len];
  416. for (int i = 0; i < len; i++) {
  417. ret[i] = typePatterns[i].remapAdviceFormals(bindings);
  418. }
  419. return new TypePatternList(ret);
  420. }
  421. public void postRead(ResolvedType enclosingType) {
  422. for (TypePattern p : typePatterns) {
  423. p.postRead(enclosingType);
  424. }
  425. }
  426. @Override
  427. public boolean equals(Object other) {
  428. if (!(other instanceof TypePatternList)) {
  429. return false;
  430. }
  431. TypePatternList o = (TypePatternList) other;
  432. int len = o.typePatterns.length;
  433. if (len != this.typePatterns.length) {
  434. return false;
  435. }
  436. for (int i = 0; i < len; i++) {
  437. if (!this.typePatterns[i].equals(o.typePatterns[i])) {
  438. return false;
  439. }
  440. }
  441. return true;
  442. }
  443. @Override
  444. public int hashCode() {
  445. int result = 41;
  446. for (TypePattern typePattern : typePatterns) {
  447. result = 37 * result + typePattern.hashCode();
  448. }
  449. return result;
  450. }
  451. public static TypePatternList read(VersionedDataInputStream s, ISourceContext context) throws IOException {
  452. short len = s.readShort();
  453. TypePattern[] arguments = new TypePattern[len];
  454. for (int i = 0; i < len; i++) {
  455. arguments[i] = TypePattern.read(s, context);
  456. }
  457. TypePatternList ret = new TypePatternList(arguments);
  458. if (!s.isAtLeast169()) {
  459. ret.readLocation(context, s);
  460. }
  461. return ret;
  462. }
  463. @Override
  464. public int getEnd() {
  465. throw new IllegalStateException();
  466. }
  467. @Override
  468. public ISourceContext getSourceContext() {
  469. throw new IllegalStateException();
  470. }
  471. @Override
  472. public ISourceLocation getSourceLocation() {
  473. throw new IllegalStateException();
  474. }
  475. @Override
  476. public int getStart() {
  477. throw new IllegalStateException();
  478. }
  479. @Override
  480. public void write(CompressingDataOutputStream s) throws IOException {
  481. s.writeShort(typePatterns.length);
  482. for (TypePattern typePattern : typePatterns) {
  483. typePattern.write(s);
  484. }
  485. // writeLocation(s);
  486. }
  487. public TypePattern[] getTypePatterns() {
  488. return typePatterns;
  489. }
  490. public List<UnresolvedType> getExactTypes() {
  491. List<UnresolvedType> ret = new ArrayList<>();
  492. for (TypePattern typePattern : typePatterns) {
  493. UnresolvedType t = typePattern.getExactType();
  494. if (!ResolvedType.isMissing(t)) {
  495. ret.add(t);
  496. }
  497. }
  498. return ret;
  499. }
  500. @Override
  501. public Object accept(PatternNodeVisitor visitor, Object data) {
  502. return visitor.visit(this, data);
  503. }
  504. @Override
  505. public Object traverse(PatternNodeVisitor visitor, Object data) {
  506. Object ret = accept(visitor, data);
  507. if (typePatterns != null) {
  508. for (TypePattern typePattern : typePatterns) {
  509. typePattern.traverse(visitor, ret);
  510. }
  511. }
  512. return ret;
  513. }
  514. public boolean areAllExactWithNoSubtypesAllowed() {
  515. for (TypePattern array_element : typePatterns) {
  516. if (!(array_element instanceof ExactTypePattern)) {
  517. return false;
  518. } else {
  519. ExactTypePattern etp = (ExactTypePattern) array_element;
  520. if (etp.isIncludeSubtypes()) {
  521. return false;
  522. }
  523. }
  524. }
  525. return true;
  526. }
  527. public String[] maybeGetCleanNames() {
  528. String[] theParamNames = new String[typePatterns.length];
  529. for (int i = 0; i < typePatterns.length; i++) {
  530. TypePattern string = typePatterns[i];
  531. if (!(string instanceof ExactTypePattern)) {
  532. return null;
  533. }
  534. theParamNames[i] = ((ExactTypePattern) string).getExactType().getName();
  535. }
  536. return theParamNames;
  537. }
  538. }