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.

WildTypePattern.java 49KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398
  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 java.util.StringTokenizer;
  18. import org.aspectj.bridge.IMessage;
  19. import org.aspectj.bridge.ISourceLocation;
  20. import org.aspectj.bridge.Message;
  21. import org.aspectj.bridge.MessageUtil;
  22. import org.aspectj.util.FileUtil;
  23. import org.aspectj.util.FuzzyBoolean;
  24. import org.aspectj.weaver.AjAttribute;
  25. import org.aspectj.weaver.BCException;
  26. import org.aspectj.weaver.BoundedReferenceType;
  27. import org.aspectj.weaver.CompressingDataOutputStream;
  28. import org.aspectj.weaver.IHasPosition;
  29. import org.aspectj.weaver.ISourceContext;
  30. import org.aspectj.weaver.ReferenceType;
  31. import org.aspectj.weaver.ResolvedType;
  32. import org.aspectj.weaver.TypeFactory;
  33. import org.aspectj.weaver.TypeVariable;
  34. import org.aspectj.weaver.TypeVariableReference;
  35. import org.aspectj.weaver.UnresolvedType;
  36. import org.aspectj.weaver.UnresolvedTypeVariableReferenceType;
  37. import org.aspectj.weaver.VersionedDataInputStream;
  38. import org.aspectj.weaver.WeaverMessages;
  39. import org.aspectj.weaver.World;
  40. /**
  41. * The PatternParser always creates WildTypePatterns for type patterns in pointcut expressions (apart from *, which is sometimes
  42. * directly turned into TypePattern.ANY). resolveBindings() tries to work out what we've really got and turn it into a type pattern
  43. * that we can use for matching. This will normally be either an ExactTypePattern or a WildTypePattern.
  44. *
  45. * Here's how the process pans out for various generic and parameterized patterns: (see GenericsWildTypePatternResolvingTestCase)
  46. *
  47. * Foo where Foo exists and is generic Parser creates WildTypePattern namePatterns={Foo} resolveBindings resolves Foo to RT(Foo -
  48. * raw) return ExactTypePattern(LFoo;)
  49. *
  50. * Foo<String> where Foo exists and String meets the bounds Parser creates WildTypePattern namePatterns = {Foo},
  51. * typeParameters=WTP{String} resolveBindings resolves typeParameters to ExactTypePattern(String) resolves Foo to RT(Foo) returns
  52. * ExactTypePattern(PFoo<String>; - parameterized)
  53. *
  54. * Foo<Str*> where Foo exists and takes one bound Parser creates WildTypePattern namePatterns = {Foo}, typeParameters=WTP{Str*}
  55. * resolveBindings resolves typeParameters to WTP{Str*} resolves Foo to RT(Foo) returns WildTypePattern(name = Foo, typeParameters =
  56. * WTP{Str*} isGeneric=false)
  57. *
  58. * Fo*<String> Parser creates WildTypePattern namePatterns = {Fo*}, typeParameters=WTP{String} resolveBindings resolves
  59. * typeParameters to ETP{String} returns WildTypePattern(name = Fo*, typeParameters = ETP{String} isGeneric=false)
  60. *
  61. *
  62. * Foo<?>
  63. *
  64. * Foo<? extends Number>
  65. *
  66. * Foo<? extends Number+>
  67. *
  68. * Foo<? super Number>
  69. *
  70. */
  71. public class WildTypePattern extends TypePattern {
  72. private static final String GENERIC_WILDCARD_CHARACTER = "?"; // signature of ? is *
  73. private static final String GENERIC_WILDCARD_SIGNATURE_CHARACTER = "*"; // signature of ? is *
  74. private NamePattern[] namePatterns;
  75. private boolean failedResolution = false;
  76. int ellipsisCount;
  77. String[] importedPrefixes;
  78. String[] knownMatches;
  79. int dim;
  80. // SECRETAPI - just for testing, turns off boundschecking temporarily...
  81. public static boolean boundscheckingoff = false;
  82. // these next three are set if the type pattern is constrained by extends or super clauses, in which case the
  83. // namePatterns must have length 1
  84. // TODO AMC: read/write/resolve of these fields
  85. TypePattern upperBound; // extends Foo
  86. TypePattern[] additionalInterfaceBounds; // extends Foo & A,B,C
  87. TypePattern lowerBound; // super Foo
  88. // if we have type parameters, these fields indicate whether we should be a generic type pattern or a parameterized
  89. // type pattern. We can only tell during resolve bindings.
  90. private boolean isGeneric = true;
  91. WildTypePattern(NamePattern[] namePatterns, boolean includeSubtypes, int dim, boolean isVarArgs, TypePatternList typeParams) {
  92. super(includeSubtypes, isVarArgs, typeParams);
  93. this.namePatterns = namePatterns;
  94. this.dim = dim;
  95. ellipsisCount = 0;
  96. for (NamePattern namePattern : namePatterns) {
  97. if (namePattern == NamePattern.ELLIPSIS) {
  98. ellipsisCount++;
  99. }
  100. }
  101. setLocation(namePatterns[0].getSourceContext(), namePatterns[0].getStart(), namePatterns[namePatterns.length - 1].getEnd());
  102. }
  103. public WildTypePattern(List<NamePattern> names, boolean includeSubtypes, int dim) {
  104. this(names.toArray(new NamePattern[0]), includeSubtypes, dim, false, TypePatternList.EMPTY);
  105. }
  106. public WildTypePattern(List<NamePattern> names, boolean includeSubtypes, int dim, int endPos) {
  107. this(names, includeSubtypes, dim);
  108. this.end = endPos;
  109. }
  110. public WildTypePattern(List<NamePattern> names, boolean includeSubtypes, int dim, int endPos, boolean isVarArg) {
  111. this(names, includeSubtypes, dim);
  112. this.end = endPos;
  113. this.isVarArgs = isVarArg;
  114. }
  115. public WildTypePattern(List<NamePattern> names, boolean includeSubtypes, int dim, int endPos, boolean isVarArg, TypePatternList typeParams,
  116. TypePattern upperBound, TypePattern[] additionalInterfaceBounds, TypePattern lowerBound) {
  117. this(names.toArray(new NamePattern[0]), includeSubtypes, dim, isVarArg, typeParams);
  118. this.end = endPos;
  119. this.upperBound = upperBound;
  120. this.lowerBound = lowerBound;
  121. this.additionalInterfaceBounds = additionalInterfaceBounds;
  122. }
  123. public WildTypePattern(List<NamePattern> names, boolean includeSubtypes, int dim, int endPos, boolean isVarArg, TypePatternList typeParams) {
  124. this(names.toArray(new NamePattern[0]), includeSubtypes, dim, isVarArg, typeParams);
  125. this.end = endPos;
  126. }
  127. public NamePattern[] getNamePatterns() {
  128. return namePatterns;
  129. }
  130. public TypePattern getUpperBound() {
  131. return upperBound;
  132. }
  133. public TypePattern getLowerBound() {
  134. return lowerBound;
  135. }
  136. public TypePattern[] getAdditionalIntefaceBounds() {
  137. return additionalInterfaceBounds;
  138. }
  139. // called by parser after parsing a type pattern, must bump dim as well as setting flag
  140. @Override
  141. public void setIsVarArgs(boolean isVarArgs) {
  142. this.isVarArgs = isVarArgs;
  143. if (isVarArgs) {
  144. this.dim += 1;
  145. }
  146. }
  147. /*
  148. * (non-Javadoc)
  149. *
  150. * @see org.aspectj.weaver.patterns.TypePattern#couldEverMatchSameTypesAs(org.aspectj.weaver.patterns.TypePattern)
  151. */
  152. @Override
  153. protected boolean couldEverMatchSameTypesAs(TypePattern other) {
  154. if (super.couldEverMatchSameTypesAs(other)) {
  155. return true;
  156. }
  157. // false is necessary but not sufficient
  158. UnresolvedType otherType = other.getExactType();
  159. if (!ResolvedType.isMissing(otherType)) {
  160. if (namePatterns.length > 0) {
  161. if (!namePatterns[0].matches(otherType.getName())) {
  162. return false;
  163. }
  164. }
  165. }
  166. if (other instanceof WildTypePattern) {
  167. WildTypePattern owtp = (WildTypePattern) other;
  168. String mySimpleName = namePatterns[0].maybeGetSimpleName();
  169. String yourSimpleName = owtp.namePatterns[0].maybeGetSimpleName();
  170. if (mySimpleName != null && yourSimpleName != null) {
  171. return (mySimpleName.startsWith(yourSimpleName) || yourSimpleName.startsWith(mySimpleName));
  172. }
  173. }
  174. return true;
  175. }
  176. // XXX inefficient implementation
  177. // we don't know whether $ characters are from nested types, or were
  178. // part of the declared type name (generated code often uses $s in type
  179. // names). More work required on our part to get this right...
  180. public static char[][] splitNames(String s, boolean convertDollar) {
  181. List<char[]> ret = new ArrayList<>();
  182. int startIndex = 0;
  183. while (true) {
  184. int breakIndex = s.indexOf('.', startIndex); // what about /
  185. if (convertDollar && (breakIndex == -1)) {
  186. breakIndex = s.indexOf('$', startIndex); // we treat $ like . here
  187. }
  188. if (breakIndex == -1) {
  189. break;
  190. }
  191. char[] name = s.substring(startIndex, breakIndex).toCharArray();
  192. ret.add(name);
  193. startIndex = breakIndex + 1;
  194. }
  195. ret.add(s.substring(startIndex).toCharArray());
  196. return ret.toArray(new char[ret.size()][]);
  197. }
  198. /**
  199. * @see org.aspectj.weaver.patterns.TypePattern#matchesExactly(ResolvedType)
  200. */
  201. @Override
  202. protected boolean matchesExactly(ResolvedType type) {
  203. return matchesExactly(type, type);
  204. }
  205. @Override
  206. protected boolean matchesExactly(ResolvedType type, ResolvedType annotatedType) {
  207. String targetTypeName = type.getName();
  208. // System.err.println("match: " + targetTypeName + ", " + knownMatches); //Arrays.asList(importedPrefixes));
  209. // Ensure the annotation pattern is resolved
  210. annotationPattern.resolve(type.getWorld());
  211. return matchesExactlyByName(targetTypeName.replaceFirst("(\\[\\])+$", ""), type.isAnonymous(), type.isNested()) && matchesParameters(type, STATIC)
  212. && matchesArray(type)
  213. && matchesBounds(type, STATIC)
  214. && annotationPattern.matches(annotatedType, type.temporaryAnnotationTypes).alwaysTrue();
  215. }
  216. // we've matched against the base (or raw) type, but if this type pattern specifies parameters or
  217. // type variables we need to make sure we match against them too
  218. private boolean matchesParameters(ResolvedType aType, MatchKind staticOrDynamic) {
  219. if (!isGeneric && typeParameters.size() > 0) {
  220. if (!aType.isParameterizedType()) {
  221. return false;
  222. }
  223. // we have to match type parameters
  224. return typeParameters.matches(aType.getResolvedTypeParameters(), staticOrDynamic).alwaysTrue();
  225. }
  226. return true;
  227. }
  228. @Override
  229. protected boolean matchesArray(UnresolvedType type) {
  230. return type.getDimensions() == getDimensions() ||
  231. getDimensions() == 0 && namePatterns.length > 0 && namePatterns[namePatterns.length-1].toString().endsWith("*");
  232. }
  233. // we've matched against the base (or raw) type, but if this type pattern specifies bounds because
  234. // it is a ? extends or ? super deal then we have to match them too.
  235. private boolean matchesBounds(ResolvedType aType, MatchKind staticOrDynamic) {
  236. if (!(aType instanceof BoundedReferenceType)) {
  237. return true;
  238. }
  239. BoundedReferenceType boundedRT = (BoundedReferenceType) aType;
  240. if (upperBound == null && boundedRT.getUpperBound() != null) {
  241. // for upper bound, null can also match against Object - but anything else and we're out.
  242. if (!boundedRT.getUpperBound().getName().equals(UnresolvedType.OBJECT.getName())) {
  243. return false;
  244. }
  245. }
  246. if (lowerBound == null && boundedRT.getLowerBound() != null) {
  247. return false;
  248. }
  249. if (upperBound != null) {
  250. // match ? extends
  251. if (aType.isGenericWildcard() && boundedRT.isSuper()) {
  252. return false;
  253. }
  254. if (boundedRT.getUpperBound() == null) {
  255. return false;
  256. }
  257. return upperBound.matches((ResolvedType) boundedRT.getUpperBound(), staticOrDynamic).alwaysTrue();
  258. }
  259. if (lowerBound != null) {
  260. // match ? super
  261. if (!(boundedRT.isGenericWildcard() && boundedRT.isSuper())) {
  262. return false;
  263. }
  264. return lowerBound.matches((ResolvedType) boundedRT.getLowerBound(), staticOrDynamic).alwaysTrue();
  265. }
  266. return true;
  267. }
  268. /**
  269. * Used in conjunction with checks on 'isStar()' to tell you if this pattern represents '*' or '*[]' which are different !
  270. */
  271. public int getDimensions() {
  272. return dim;
  273. }
  274. @Override
  275. public boolean isArray() {
  276. return dim > 0;
  277. }
  278. /**
  279. * @param targetTypeName
  280. * @return
  281. */
  282. private boolean matchesExactlyByName(String targetTypeName, boolean isAnonymous, boolean isNested) {
  283. // we deal with parameter matching separately...
  284. if (targetTypeName.indexOf('<') != -1) {
  285. targetTypeName = targetTypeName.substring(0, targetTypeName.indexOf('<'));
  286. }
  287. // we deal with bounds matching separately too...
  288. if (targetTypeName.startsWith(GENERIC_WILDCARD_CHARACTER)) {
  289. targetTypeName = GENERIC_WILDCARD_CHARACTER;
  290. }
  291. // XXX hack
  292. if (knownMatches == null && importedPrefixes == null) {
  293. return innerMatchesExactly(targetTypeName, isAnonymous, isNested);
  294. }
  295. // if our pattern is length 1, then known matches are exact matches
  296. // if it's longer than that, then known matches are prefixes of a sort
  297. if (namePatterns.length == 1) {
  298. if (isAnonymous) {
  299. // we've already ruled out "*", and no other name pattern should match an anonymous type
  300. return false;
  301. }
  302. for (String knownMatch : knownMatches) {
  303. if (knownMatch.equals(targetTypeName)) {
  304. return true;
  305. }
  306. }
  307. } else {
  308. for (String knownMatch : knownMatches) {
  309. // String knownPrefix = knownMatches[i] + "$";
  310. // if (targetTypeName.startsWith(knownPrefix)) {
  311. if (targetTypeName.startsWith(knownMatch) && targetTypeName.length() > knownMatch.length()
  312. && targetTypeName.charAt(knownMatch.length()) == '$') {
  313. int pos = lastIndexOfDotOrDollar(knownMatch);
  314. if (innerMatchesExactly(targetTypeName.substring(pos + 1), isAnonymous, isNested)) {
  315. return true;
  316. }
  317. }
  318. }
  319. }
  320. // if any prefixes match, strip the prefix and check that the rest matches
  321. // assumes that prefixes have a dot at the end
  322. for (String prefix : importedPrefixes) {
  323. // System.err.println("prefix match? " + prefix + " to " + targetTypeName);
  324. if (targetTypeName.startsWith(prefix)) {
  325. if (innerMatchesExactly(targetTypeName.substring(prefix.length()), isAnonymous, isNested)) {
  326. return true;
  327. }
  328. }
  329. }
  330. return innerMatchesExactly(targetTypeName, isAnonymous, isNested);
  331. }
  332. private int lastIndexOfDotOrDollar(String string) {
  333. for (int pos = string.length() - 1; pos > -1; pos--) {
  334. char ch = string.charAt(pos);
  335. if (ch == '.' || ch == '$') {
  336. return pos;
  337. }
  338. }
  339. return -1;
  340. }
  341. private boolean innerMatchesExactly(String s, boolean isAnonymous, boolean convertDollar /* isNested */) {
  342. List<char[]> ret = new ArrayList<>();
  343. int startIndex = 0;
  344. while (true) {
  345. int breakIndex = s.indexOf('.', startIndex); // what about /
  346. if (convertDollar && (breakIndex == -1)) {
  347. breakIndex = s.indexOf('$', startIndex); // we treat $ like . here
  348. }
  349. if (breakIndex == -1) {
  350. break;
  351. }
  352. char[] name = s.substring(startIndex, breakIndex).toCharArray();
  353. ret.add(name);
  354. startIndex = breakIndex + 1;
  355. }
  356. ret.add(s.substring(startIndex).toCharArray());
  357. int namesLength = ret.size();
  358. int patternsLength = namePatterns.length;
  359. int namesIndex = 0;
  360. int patternsIndex = 0;
  361. if ((!namePatterns[patternsLength - 1].isAny()) && isAnonymous) {
  362. return false;
  363. }
  364. if (ellipsisCount == 0) {
  365. if (namesLength != patternsLength) {
  366. return false;
  367. }
  368. while (patternsIndex < patternsLength) {
  369. if (!namePatterns[patternsIndex++].matches(ret.get(namesIndex++))) {
  370. return false;
  371. }
  372. }
  373. return true;
  374. } else if (ellipsisCount == 1) {
  375. if (namesLength < patternsLength - 1) {
  376. return false;
  377. }
  378. while (patternsIndex < patternsLength) {
  379. NamePattern p = namePatterns[patternsIndex++];
  380. if (p == NamePattern.ELLIPSIS) {
  381. namesIndex = namesLength - (patternsLength - patternsIndex);
  382. } else {
  383. if (!p.matches(ret.get(namesIndex++))) {
  384. return false;
  385. }
  386. }
  387. }
  388. return true;
  389. } else {
  390. // System.err.print("match(\"" + Arrays.asList(namePatterns) + "\", \"" + Arrays.asList(names) + "\") -> ");
  391. boolean b = outOfStar(namePatterns, ret.toArray(new char[ret.size()][]), 0, 0, patternsLength - ellipsisCount,
  392. namesLength, ellipsisCount);
  393. // System.err.println(b);
  394. return b;
  395. }
  396. }
  397. private static boolean outOfStar(final NamePattern[] pattern, final char[][] target, int pi, int ti, int pLeft, int tLeft,
  398. final int starsLeft) {
  399. if (pLeft > tLeft) {
  400. return false;
  401. }
  402. while (true) {
  403. // invariant: if (tLeft > 0) then (ti < target.length && pi < pattern.length)
  404. if (tLeft == 0) {
  405. return true;
  406. }
  407. if (pLeft == 0) {
  408. return (starsLeft > 0);
  409. }
  410. if (pattern[pi] == NamePattern.ELLIPSIS) {
  411. return inStar(pattern, target, pi + 1, ti, pLeft, tLeft, starsLeft - 1);
  412. }
  413. if (!pattern[pi].matches(target[ti])) {
  414. return false;
  415. }
  416. pi++;
  417. ti++;
  418. pLeft--;
  419. tLeft--;
  420. }
  421. }
  422. private static boolean inStar(final NamePattern[] pattern, final char[][] target, int pi, int ti, final int pLeft, int tLeft,
  423. int starsLeft) {
  424. // invariant: pLeft > 0, so we know we'll run out of stars and find a real char in pattern
  425. // of course, we probably can't parse multiple ..'s in a row, but this keeps the algorithm
  426. // exactly parallel with that in NamePattern
  427. NamePattern patternChar = pattern[pi];
  428. while (patternChar == NamePattern.ELLIPSIS) {
  429. starsLeft--;
  430. patternChar = pattern[++pi];
  431. }
  432. while (true) {
  433. // invariant: if (tLeft > 0) then (ti < target.length)
  434. if (pLeft > tLeft) {
  435. return false;
  436. }
  437. if (patternChar.matches(target[ti])) {
  438. if (outOfStar(pattern, target, pi + 1, ti + 1, pLeft - 1, tLeft - 1, starsLeft)) {
  439. return true;
  440. }
  441. }
  442. ti++;
  443. tLeft--;
  444. }
  445. }
  446. /**
  447. * @see org.aspectj.weaver.patterns.TypePattern#matchesInstanceof(ResolvedType)
  448. */
  449. @Override
  450. public FuzzyBoolean matchesInstanceof(ResolvedType type) {
  451. // XXX hack to let unmatched types just silently remain so
  452. if (maybeGetSimpleName() != null) {
  453. return FuzzyBoolean.NO;
  454. }
  455. type.getWorld().getMessageHandler().handleMessage(
  456. new Message("can't do instanceof matching on patterns with wildcards", IMessage.ERROR, null, getSourceLocation()));
  457. return FuzzyBoolean.NO;
  458. }
  459. public NamePattern extractName() {
  460. if (isIncludeSubtypes() || isVarArgs() || isArray() || (typeParameters.size() > 0)) {
  461. // we can't extract a name, the pattern is something like Foo+ and therefore
  462. // it is not ok to treat Foo as a method name!
  463. return null;
  464. }
  465. // System.err.println("extract from : " + Arrays.asList(namePatterns));
  466. int len = namePatterns.length;
  467. if (len == 1 && !annotationPattern.isAny()) {
  468. return null; // can't extract
  469. }
  470. NamePattern ret = namePatterns[len - 1];
  471. NamePattern[] newNames = new NamePattern[len - 1];
  472. System.arraycopy(namePatterns, 0, newNames, 0, len - 1);
  473. namePatterns = newNames;
  474. // System.err.println(" left : " + Arrays.asList(namePatterns));
  475. return ret;
  476. }
  477. /**
  478. * Method maybeExtractName.
  479. *
  480. * @param string
  481. * @return boolean
  482. */
  483. public boolean maybeExtractName(String string) {
  484. int len = namePatterns.length;
  485. NamePattern ret = namePatterns[len - 1];
  486. String simple = ret.maybeGetSimpleName();
  487. if (simple != null && simple.equals(string)) {
  488. extractName();
  489. return true;
  490. }
  491. return false;
  492. }
  493. /**
  494. * If this type pattern has no '.' or '*' in it, then return a simple string
  495. *
  496. * otherwise, this will return null;
  497. */
  498. public String maybeGetSimpleName() {
  499. if (namePatterns.length == 1) {
  500. return namePatterns[0].maybeGetSimpleName();
  501. }
  502. return null;
  503. }
  504. /**
  505. * If this type pattern has no '*' or '..' in it
  506. */
  507. public String maybeGetCleanName() {
  508. if (namePatterns.length == 0) {
  509. throw new RuntimeException("bad name: " + namePatterns);
  510. }
  511. // System.out.println("get clean: " + this);
  512. StringBuilder buf = new StringBuilder();
  513. for (int i = 0, len = namePatterns.length; i < len; i++) {
  514. NamePattern p = namePatterns[i];
  515. String simpleName = p.maybeGetSimpleName();
  516. if (simpleName == null) {
  517. return null;
  518. }
  519. if (i > 0) {
  520. buf.append(".");
  521. }
  522. buf.append(simpleName);
  523. }
  524. // System.out.println(buf);
  525. return buf.toString();
  526. }
  527. @Override
  528. public TypePattern parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
  529. NamePattern[] newNamePatterns = new NamePattern[namePatterns.length];
  530. System.arraycopy(namePatterns, 0, newNamePatterns, 0, namePatterns.length);
  531. if (newNamePatterns.length == 1) {
  532. String simpleName = newNamePatterns[0].maybeGetSimpleName();
  533. if (simpleName != null) {
  534. if (typeVariableMap.containsKey(simpleName)) {
  535. String newName = ((ReferenceType) typeVariableMap.get(simpleName)).getName().replace('$', '.');
  536. StringTokenizer strTok = new StringTokenizer(newName, ".");
  537. newNamePatterns = new NamePattern[strTok.countTokens()];
  538. int index = 0;
  539. while (strTok.hasMoreTokens()) {
  540. newNamePatterns[index++] = new NamePattern(strTok.nextToken());
  541. }
  542. }
  543. }
  544. }
  545. WildTypePattern ret = new WildTypePattern(newNamePatterns, includeSubtypes, dim, isVarArgs, typeParameters
  546. .parameterizeWith(typeVariableMap, w));
  547. ret.annotationPattern = this.annotationPattern.parameterizeWith(typeVariableMap, w);
  548. if (additionalInterfaceBounds == null) {
  549. ret.additionalInterfaceBounds = null;
  550. } else {
  551. ret.additionalInterfaceBounds = new TypePattern[additionalInterfaceBounds.length];
  552. for (int i = 0; i < additionalInterfaceBounds.length; i++) {
  553. ret.additionalInterfaceBounds[i] = additionalInterfaceBounds[i].parameterizeWith(typeVariableMap, w);
  554. }
  555. }
  556. ret.upperBound = upperBound != null ? upperBound.parameterizeWith(typeVariableMap, w) : null;
  557. ret.lowerBound = lowerBound != null ? lowerBound.parameterizeWith(typeVariableMap, w) : null;
  558. ret.isGeneric = isGeneric;
  559. ret.knownMatches = knownMatches;
  560. ret.importedPrefixes = importedPrefixes;
  561. ret.copyLocationFrom(this);
  562. return ret;
  563. }
  564. /**
  565. * Need to determine if I'm really a pattern or a reference to a formal
  566. *
  567. * We may wish to further optimize the case of pattern vs. non-pattern
  568. *
  569. * We will be replaced by what we return
  570. */
  571. @Override
  572. public TypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
  573. if (isNamePatternStar()) {
  574. TypePattern anyPattern = maybeResolveToAnyPattern(scope, bindings, allowBinding, requireExactType);
  575. if (anyPattern != null) {
  576. if (requireExactType) {
  577. scope.getWorld().getMessageHandler().handleMessage(
  578. MessageUtil.error(WeaverMessages.format(WeaverMessages.WILDCARD_NOT_ALLOWED), getSourceLocation()));
  579. return NO;
  580. } else {
  581. return anyPattern;
  582. }
  583. }
  584. }
  585. TypePattern bindingTypePattern = maybeResolveToBindingTypePattern(scope, bindings, allowBinding, requireExactType);
  586. if (bindingTypePattern != null) {
  587. return bindingTypePattern;
  588. }
  589. annotationPattern = annotationPattern.resolveBindings(scope, bindings, allowBinding);
  590. // resolve any type parameters
  591. if (typeParameters != null && typeParameters.size() > 0) {
  592. typeParameters.resolveBindings(scope, bindings, allowBinding, requireExactType);
  593. isGeneric = false;
  594. }
  595. // resolve any bounds
  596. if (upperBound != null) {
  597. upperBound = upperBound.resolveBindings(scope, bindings, allowBinding, requireExactType);
  598. }
  599. if (lowerBound != null) {
  600. lowerBound = lowerBound.resolveBindings(scope, bindings, allowBinding, requireExactType);
  601. // amc - additional interface bounds only needed if we support type vars again.
  602. }
  603. String fullyQualifiedName = maybeGetCleanName();
  604. if (fullyQualifiedName != null) {
  605. return resolveBindingsFromFullyQualifiedTypeName(fullyQualifiedName, scope, bindings, allowBinding, requireExactType);
  606. } else {
  607. if (requireExactType) {
  608. scope.getWorld().getMessageHandler().handleMessage(
  609. MessageUtil.error(WeaverMessages.format(WeaverMessages.WILDCARD_NOT_ALLOWED), getSourceLocation()));
  610. return NO;
  611. }
  612. importedPrefixes = scope.getImportedPrefixes();
  613. knownMatches = preMatch(scope.getImportedNames());
  614. return this; // pattern contains wildcards so can't be resolved to an ExactTypePattern...
  615. // XXX need to implement behavior for Lint.invalidWildcardTypeName
  616. }
  617. }
  618. private TypePattern maybeResolveToAnyPattern(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
  619. // If there is an annotation specified we have to
  620. // use a special variant of Any TypePattern called
  621. // AnyWithAnnotation
  622. if (annotationPattern == AnnotationTypePattern.ANY) {
  623. if (dim == 0 && !isVarArgs && upperBound == null && lowerBound == null
  624. && (additionalInterfaceBounds == null || additionalInterfaceBounds.length == 0)) { // pr72531
  625. return TypePattern.ANY; // ??? loses source location
  626. }
  627. } else if (!isVarArgs) {
  628. annotationPattern = annotationPattern.resolveBindings(scope, bindings, allowBinding);
  629. AnyWithAnnotationTypePattern ret = new AnyWithAnnotationTypePattern(annotationPattern);
  630. ret.setLocation(sourceContext, start, end);
  631. return ret;
  632. }
  633. return null; // can't resolve to a simple "any" pattern
  634. }
  635. private TypePattern maybeResolveToBindingTypePattern(IScope scope, Bindings bindings, boolean allowBinding,
  636. boolean requireExactType) {
  637. String simpleName = maybeGetSimpleName();
  638. if (simpleName != null) {
  639. FormalBinding formalBinding = scope.lookupFormal(simpleName);
  640. if (formalBinding != null) {
  641. if (bindings == null) {
  642. scope.message(IMessage.ERROR, this, "negation doesn't allow binding");
  643. return this;
  644. }
  645. if (!allowBinding) {
  646. scope.message(IMessage.ERROR, this, "name binding only allowed in target, this, and args pcds");
  647. return this;
  648. }
  649. BindingTypePattern binding = new BindingTypePattern(formalBinding, isVarArgs);
  650. binding.copyLocationFrom(this);
  651. bindings.register(binding, scope);
  652. return binding;
  653. }
  654. }
  655. return null; // not possible to resolve to a binding type pattern
  656. }
  657. private TypePattern resolveBindingsFromFullyQualifiedTypeName(String fullyQualifiedName, IScope scope, Bindings bindings,
  658. boolean allowBinding, boolean requireExactType) {
  659. String originalName = fullyQualifiedName;
  660. ResolvedType resolvedTypeInTheWorld = null;
  661. UnresolvedType type;
  662. // System.out.println("resolve: " + cleanName);
  663. // ??? this loop has too many inefficiencies to count
  664. resolvedTypeInTheWorld = lookupTypeInWorldIncludingPrefixes(scope.getWorld(), fullyQualifiedName, scope
  665. .getImportedPrefixes());
  666. if (resolvedTypeInTheWorld.isGenericWildcard()) {
  667. type = resolvedTypeInTheWorld;
  668. } else {
  669. type = lookupTypeInScope(scope, fullyQualifiedName, this);
  670. }
  671. if ((type instanceof ResolvedType) && ((ResolvedType) type).isMissing()) {
  672. return resolveBindingsForMissingType(resolvedTypeInTheWorld, originalName, scope, bindings, allowBinding,
  673. requireExactType);
  674. } else {
  675. return resolveBindingsForExactType(scope, type, fullyQualifiedName, requireExactType);
  676. }
  677. }
  678. private UnresolvedType lookupTypeInScope(IScope scope, String typeName, IHasPosition location) {
  679. UnresolvedType type = null;
  680. while (ResolvedType.isMissing(type = scope.lookupType(typeName, location))) {
  681. int lastDot = typeName.lastIndexOf('.');
  682. if (lastDot == -1) {
  683. break;
  684. }
  685. typeName = typeName.substring(0, lastDot) + '$' + typeName.substring(lastDot + 1);
  686. }
  687. return type;
  688. }
  689. /**
  690. * Searches the world for the ResolvedType with the given typeName. If one isn't found then for each of the supplied prefixes,
  691. * it prepends the typeName with the prefix and searches the world for the ResolvedType with this new name. If one still isn't
  692. * found then a MissingResolvedTypeWithKnownSignature is returned with the originally requested typeName (this ensures the
  693. * typeName makes sense).
  694. */
  695. private ResolvedType lookupTypeInWorldIncludingPrefixes(World world, String typeName, String[] prefixes) {
  696. ResolvedType ret = lookupTypeInWorld(world, typeName);
  697. if (!ret.isMissing()) {
  698. return ret;
  699. }
  700. ResolvedType retWithPrefix = ret;
  701. int counter = 0;
  702. while (retWithPrefix.isMissing() && (counter < prefixes.length)) {
  703. retWithPrefix = lookupTypeInWorld(world, prefixes[counter] + typeName);
  704. counter++;
  705. }
  706. if (!retWithPrefix.isMissing()) {
  707. return retWithPrefix;
  708. }
  709. return ret;
  710. }
  711. private ResolvedType lookupTypeInWorld(World world, String typeName) {
  712. UnresolvedType ut = UnresolvedType.forName(typeName);
  713. ResolvedType ret = world.resolve(ut, true);
  714. while (ret.isMissing()) {
  715. int lastDot = typeName.lastIndexOf('.');
  716. if (lastDot == -1) {
  717. break;
  718. }
  719. typeName = typeName.substring(0, lastDot) + '$' + typeName.substring(lastDot + 1);
  720. ret = world.resolve(UnresolvedType.forName(typeName), true);
  721. }
  722. return ret;
  723. }
  724. private TypePattern resolveBindingsForExactType(IScope scope, UnresolvedType aType, String fullyQualifiedName,
  725. boolean requireExactType) {
  726. TypePattern ret = null;
  727. if (aType.isTypeVariableReference()) {
  728. // we have to set the bounds on it based on the bounds of this pattern
  729. ret = resolveBindingsForTypeVariable(scope, (UnresolvedTypeVariableReferenceType) aType);
  730. } else if (typeParameters.size() > 0) {
  731. ret = resolveParameterizedType(scope, aType, requireExactType);
  732. } else if (upperBound != null || lowerBound != null) {
  733. // this must be a generic wildcard with bounds
  734. ret = resolveGenericWildcard(scope, aType);
  735. } else {
  736. if (dim != 0) {
  737. aType = UnresolvedType.makeArray(aType, dim);
  738. }
  739. ret = new ExactTypePattern(aType, includeSubtypes, isVarArgs, typeParameters);
  740. }
  741. ret.setAnnotationTypePattern(annotationPattern);
  742. ret.copyLocationFrom(this);
  743. return ret;
  744. }
  745. private TypePattern resolveGenericWildcard(IScope scope, UnresolvedType aType) {
  746. if (!aType.getSignature().equals(GENERIC_WILDCARD_SIGNATURE_CHARACTER)) {
  747. throw new IllegalStateException("Can only have bounds for a generic wildcard");
  748. }
  749. boolean canBeExact = true;
  750. if ((upperBound != null) && ResolvedType.isMissing(upperBound.getExactType())) {
  751. canBeExact = false;
  752. }
  753. if ((lowerBound != null) && ResolvedType.isMissing(lowerBound.getExactType())) {
  754. canBeExact = false;
  755. }
  756. if (canBeExact) {
  757. ResolvedType type = null;
  758. if (upperBound != null) {
  759. if (upperBound.isIncludeSubtypes()) {
  760. canBeExact = false;
  761. } else {
  762. ReferenceType upper = (ReferenceType) upperBound.getExactType().resolve(scope.getWorld());
  763. type = new BoundedReferenceType(upper, true, scope.getWorld());
  764. }
  765. } else {
  766. if (lowerBound.isIncludeSubtypes()) {
  767. canBeExact = false;
  768. } else {
  769. ReferenceType lower = (ReferenceType) lowerBound.getExactType().resolve(scope.getWorld());
  770. type = new BoundedReferenceType(lower, false, scope.getWorld());
  771. }
  772. }
  773. if (canBeExact) {
  774. // might have changed if we find out include subtypes is set on one of the bounds...
  775. return new ExactTypePattern(type, includeSubtypes, isVarArgs, typeParameters);
  776. }
  777. }
  778. // we weren't able to resolve to an exact type pattern...
  779. // leave as wild type pattern
  780. importedPrefixes = scope.getImportedPrefixes();
  781. knownMatches = preMatch(scope.getImportedNames());
  782. return this;
  783. }
  784. private TypePattern resolveParameterizedType(IScope scope, UnresolvedType aType, boolean requireExactType) {
  785. ResolvedType rt = aType.resolve(scope.getWorld());
  786. if (!verifyTypeParameters(rt, scope, requireExactType)) {
  787. return TypePattern.NO; // messages already isued
  788. }
  789. // Only if the type is exact *and* the type parameters are exact should we create an
  790. // ExactTypePattern for this WildTypePattern
  791. if (typeParameters.areAllExactWithNoSubtypesAllowed()) {
  792. TypePattern[] typePats = typeParameters.getTypePatterns();
  793. UnresolvedType[] typeParameterTypes = new UnresolvedType[typePats.length];
  794. for (int i = 0; i < typeParameterTypes.length; i++) {
  795. typeParameterTypes[i] = ((ExactTypePattern) typePats[i]).getExactType();
  796. }
  797. // rt could be a parameterized type 156058
  798. if (rt.isParameterizedType()) {
  799. rt = rt.getGenericType();
  800. }
  801. ResolvedType type = TypeFactory.createParameterizedType(rt, typeParameterTypes, scope.getWorld());
  802. if (isGeneric) {
  803. type = type.getGenericType();
  804. }
  805. // UnresolvedType tx = UnresolvedType.forParameterizedTypes(aType,typeParameterTypes);
  806. // UnresolvedType type = scope.getWorld().resolve(tx,true);
  807. if (dim != 0) {
  808. type = ResolvedType.makeArray(type, dim);
  809. }
  810. return new ExactTypePattern(type, includeSubtypes, isVarArgs, typeParameters);
  811. } else {
  812. // AMC... just leave it as a wild type pattern then?
  813. importedPrefixes = scope.getImportedPrefixes();
  814. knownMatches = preMatch(scope.getImportedNames());
  815. return this;
  816. }
  817. }
  818. private TypePattern resolveBindingsForMissingType(ResolvedType typeFoundInWholeWorldSearch, String nameWeLookedFor,
  819. IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
  820. if (requireExactType) {
  821. if (!allowBinding) {
  822. scope.getWorld().getMessageHandler().handleMessage(
  823. MessageUtil.error(WeaverMessages.format(WeaverMessages.CANT_BIND_TYPE, nameWeLookedFor),
  824. getSourceLocation()));
  825. } else if (scope.getWorld().getLint().invalidAbsoluteTypeName.isEnabled()) {
  826. scope.getWorld().getLint().invalidAbsoluteTypeName.signal(nameWeLookedFor, getSourceLocation());
  827. }
  828. return NO;
  829. } else if (scope.getWorld().getLint().invalidAbsoluteTypeName.isEnabled()) {
  830. // Only put the lint warning out if we can't find it in the world
  831. if (typeFoundInWholeWorldSearch.isMissing()) {
  832. scope.getWorld().getLint().invalidAbsoluteTypeName.signal(nameWeLookedFor, getSourceLocation());
  833. this.failedResolution = true;
  834. }
  835. }
  836. importedPrefixes = scope.getImportedPrefixes();
  837. knownMatches = preMatch(scope.getImportedNames());
  838. return this;
  839. }
  840. /**
  841. * We resolved the type to a type variable declared in the pointcut designator. Now we have to create either an exact type
  842. * pattern or a wild type pattern for it, with upper and lower bounds set accordingly. XXX none of this stuff gets serialized
  843. * yet
  844. *
  845. * @param scope
  846. * @param tvrType
  847. * @return
  848. */
  849. private TypePattern resolveBindingsForTypeVariable(IScope scope, UnresolvedTypeVariableReferenceType tvrType) {
  850. Bindings emptyBindings = new Bindings(0);
  851. if (upperBound != null) {
  852. upperBound = upperBound.resolveBindings(scope, emptyBindings, false, false);
  853. }
  854. if (lowerBound != null) {
  855. lowerBound = lowerBound.resolveBindings(scope, emptyBindings, false, false);
  856. }
  857. if (additionalInterfaceBounds != null) {
  858. TypePattern[] resolvedIfBounds = new TypePattern[additionalInterfaceBounds.length];
  859. for (int i = 0; i < resolvedIfBounds.length; i++) {
  860. resolvedIfBounds[i] = additionalInterfaceBounds[i].resolveBindings(scope, emptyBindings, false, false);
  861. }
  862. additionalInterfaceBounds = resolvedIfBounds;
  863. }
  864. if (upperBound == null && lowerBound == null && additionalInterfaceBounds == null) {
  865. // no bounds to worry about...
  866. ResolvedType rType = tvrType.resolve(scope.getWorld());
  867. if (dim != 0) {
  868. rType = ResolvedType.makeArray(rType, dim);
  869. }
  870. return new ExactTypePattern(rType, includeSubtypes, isVarArgs, typeParameters);
  871. } else {
  872. // we have to set bounds on the TypeVariable held by tvrType before resolving it
  873. boolean canCreateExactTypePattern = true;
  874. if (upperBound != null && ResolvedType.isMissing(upperBound.getExactType())) {
  875. canCreateExactTypePattern = false;
  876. }
  877. if (lowerBound != null && ResolvedType.isMissing(lowerBound.getExactType())) {
  878. canCreateExactTypePattern = false;
  879. }
  880. if (additionalInterfaceBounds != null) {
  881. for (TypePattern additionalInterfaceBound : additionalInterfaceBounds) {
  882. if (ResolvedType.isMissing(additionalInterfaceBound.getExactType())) {
  883. canCreateExactTypePattern = false;
  884. }
  885. }
  886. }
  887. if (canCreateExactTypePattern) {
  888. TypeVariable tv = tvrType.getTypeVariable();
  889. if (upperBound != null) {
  890. tv.setSuperclass(upperBound.getExactType());
  891. }
  892. if (additionalInterfaceBounds != null) {
  893. UnresolvedType[] ifBounds = new UnresolvedType[additionalInterfaceBounds.length];
  894. for (int i = 0; i < ifBounds.length; i++) {
  895. ifBounds[i] = additionalInterfaceBounds[i].getExactType();
  896. }
  897. tv.setAdditionalInterfaceBounds(ifBounds);
  898. }
  899. ResolvedType rType = tvrType.resolve(scope.getWorld());
  900. if (dim != 0) {
  901. rType = ResolvedType.makeArray(rType, dim);
  902. }
  903. return new ExactTypePattern(rType, includeSubtypes, isVarArgs, typeParameters);
  904. }
  905. return this; // leave as wild type pattern then
  906. }
  907. }
  908. /**
  909. * When this method is called, we have resolved the base type to an exact type. We also have a set of type patterns for the
  910. * parameters. Time to perform some basic checks: - can the base type be parameterized? (is it generic) - can the type parameter
  911. * pattern list match the number of parameters on the base type - do all parameter patterns meet the bounds of the respective
  912. * type variables If any of these checks fail, a warning message is issued and we return false.
  913. *
  914. * @return
  915. */
  916. private boolean verifyTypeParameters(ResolvedType baseType, IScope scope, boolean requireExactType) {
  917. ResolvedType genericType = baseType.getGenericType();
  918. if (genericType == null) {
  919. // issue message "does not match because baseType.getName() is not generic"
  920. scope.message(MessageUtil.warn(WeaverMessages.format(WeaverMessages.NOT_A_GENERIC_TYPE, baseType.getName()),
  921. getSourceLocation()));
  922. return false;
  923. }
  924. int minRequiredTypeParameters = typeParameters.size();
  925. boolean foundEllipsis = false;
  926. TypePattern[] typeParamPatterns = typeParameters.getTypePatterns();
  927. for (TypePattern typeParamPattern : typeParamPatterns) {
  928. if (typeParamPattern instanceof WildTypePattern) {
  929. WildTypePattern wtp = (WildTypePattern) typeParamPattern;
  930. if (wtp.ellipsisCount > 0) {
  931. foundEllipsis = true;
  932. minRequiredTypeParameters--;
  933. }
  934. }
  935. }
  936. TypeVariable[] tvs = genericType.getTypeVariables();
  937. if ((tvs.length < minRequiredTypeParameters) || (!foundEllipsis && minRequiredTypeParameters != tvs.length)) {
  938. // issue message "does not match because wrong no of type params"
  939. String msg = WeaverMessages.format(WeaverMessages.INCORRECT_NUMBER_OF_TYPE_ARGUMENTS, genericType.getName(),
  940. tvs.length);
  941. if (requireExactType) {
  942. scope.message(MessageUtil.error(msg, getSourceLocation()));
  943. } else {
  944. scope.message(MessageUtil.warn(msg, getSourceLocation()));
  945. }
  946. return false;
  947. }
  948. // now check that each typeParameter pattern, if exact, matches the bounds
  949. // of the type variable.
  950. // pr133307 - delay verification until type binding completion, these next few lines replace
  951. // the call to checkBoundsOK
  952. if (!boundscheckingoff) {
  953. VerifyBoundsForTypePattern verification = new VerifyBoundsForTypePattern(scope, genericType, requireExactType,
  954. typeParameters, getSourceLocation());
  955. scope.getWorld().getCrosscuttingMembersSet().recordNecessaryCheck(verification);
  956. }
  957. // return checkBoundsOK(scope,genericType,requireExactType);
  958. return true;
  959. }
  960. /**
  961. * By capturing the verification in this class, rather than performing it in verifyTypeParameters(), we can cope with situations
  962. * where the interactions between generics and declare parents would otherwise cause us problems. For example, if verifying as
  963. * we go along we may report a problem which would have been fixed by a declare parents that we haven't looked at yet. If we
  964. * create and store a verification object, we can verify this later when the type system is considered 'complete'
  965. */
  966. static class VerifyBoundsForTypePattern implements IVerificationRequired {
  967. private final IScope scope;
  968. private final ResolvedType genericType;
  969. private final boolean requireExactType;
  970. private TypePatternList typeParameters = TypePatternList.EMPTY;
  971. private final ISourceLocation sLoc;
  972. public VerifyBoundsForTypePattern(IScope scope, ResolvedType genericType, boolean requireExactType,
  973. TypePatternList typeParameters, ISourceLocation sLoc) {
  974. this.scope = scope;
  975. this.genericType = genericType;
  976. this.requireExactType = requireExactType;
  977. this.typeParameters = typeParameters;
  978. this.sLoc = sLoc;
  979. }
  980. public void verify() {
  981. TypeVariable[] tvs = genericType.getTypeVariables();
  982. TypePattern[] typeParamPatterns = typeParameters.getTypePatterns();
  983. if (typeParameters.areAllExactWithNoSubtypesAllowed()) {
  984. for (int i = 0; i < tvs.length; i++) {
  985. UnresolvedType ut = typeParamPatterns[i].getExactType();
  986. boolean continueCheck = true;
  987. // FIXME asc dont like this but ok temporary measure. If the type parameter
  988. // is itself a type variable (from the generic aspect) then assume it'll be
  989. // ok... (see pr112105) Want to break this? Run GenericAspectK test.
  990. if (ut.isTypeVariableReference()) {
  991. continueCheck = false;
  992. }
  993. // System.err.println("Verifying "+ut.getName()+" meets bounds for "+tvs[i]);
  994. if (continueCheck && !tvs[i].canBeBoundTo(ut.resolve(scope.getWorld()))) {
  995. // issue message that type parameter does not meet specification
  996. String parameterName = ut.getName();
  997. if (ut.isTypeVariableReference()) {
  998. parameterName = ((TypeVariableReference) ut).getTypeVariable().getDisplayName();
  999. }
  1000. String msg = WeaverMessages.format(WeaverMessages.VIOLATES_TYPE_VARIABLE_BOUNDS, parameterName,
  1001. i + 1, tvs[i].getDisplayName(), genericType.getName());
  1002. if (requireExactType) {
  1003. scope.message(MessageUtil.error(msg, sLoc));
  1004. } else {
  1005. scope.message(MessageUtil.warn(msg, sLoc));
  1006. }
  1007. }
  1008. }
  1009. }
  1010. }
  1011. }
  1012. // pr133307 - moved to verification object
  1013. // public boolean checkBoundsOK(IScope scope,ResolvedType genericType,boolean requireExactType) {
  1014. // if (boundscheckingoff) return true;
  1015. // TypeVariable[] tvs = genericType.getTypeVariables();
  1016. // TypePattern[] typeParamPatterns = typeParameters.getTypePatterns();
  1017. // if (typeParameters.areAllExactWithNoSubtypesAllowed()) {
  1018. // for (int i = 0; i < tvs.length; i++) {
  1019. // UnresolvedType ut = typeParamPatterns[i].getExactType();
  1020. // boolean continueCheck = true;
  1021. // // FIXME asc dont like this but ok temporary measure. If the type parameter
  1022. // // is itself a type variable (from the generic aspect) then assume it'll be
  1023. // // ok... (see pr112105) Want to break this? Run GenericAspectK test.
  1024. // if (ut.isTypeVariableReference()) {
  1025. // continueCheck = false;
  1026. // }
  1027. //
  1028. // if (continueCheck &&
  1029. // !tvs[i].canBeBoundTo(ut.resolve(scope.getWorld()))) {
  1030. // // issue message that type parameter does not meet specification
  1031. // String parameterName = ut.getName();
  1032. // if (ut.isTypeVariableReference()) parameterName = ((TypeVariableReference)ut).getTypeVariable().getDisplayName();
  1033. // String msg =
  1034. // WeaverMessages.format(
  1035. // WeaverMessages.VIOLATES_TYPE_VARIABLE_BOUNDS,
  1036. // parameterName,
  1037. // new Integer(i+1),
  1038. // tvs[i].getDisplayName(),
  1039. // genericType.getName());
  1040. // if (requireExactType) scope.message(MessageUtil.error(msg,getSourceLocation()));
  1041. // else scope.message(MessageUtil.warn(msg,getSourceLocation()));
  1042. // return false;
  1043. // }
  1044. // }
  1045. // }
  1046. // return true;
  1047. // }
  1048. @Override
  1049. public boolean isStar() {
  1050. boolean annPatternStar = annotationPattern == AnnotationTypePattern.ANY;
  1051. return (isNamePatternStar() && annPatternStar && dim == 0);
  1052. }
  1053. private boolean isNamePatternStar() {
  1054. return namePatterns.length == 1 && namePatterns[0].isAny();
  1055. }
  1056. /**
  1057. * @return those possible matches which I match exactly the last element of
  1058. */
  1059. private String[] preMatch(String[] possibleMatches) {
  1060. // if (namePatterns.length != 1) return CollectionUtil.NO_STRINGS;
  1061. List<String> ret = new ArrayList<>();
  1062. for (String possibleMatch : possibleMatches) {
  1063. char[][] names = splitNames(possibleMatch, true); // ??? not most efficient
  1064. if (namePatterns[0].matches(names[names.length - 1])) {
  1065. ret.add(possibleMatch);
  1066. continue;
  1067. }
  1068. if (possibleMatch.contains("$")) {
  1069. names = splitNames(possibleMatch, false); // ??? not most efficient
  1070. if (namePatterns[0].matches(names[names.length - 1])) {
  1071. ret.add(possibleMatch);
  1072. }
  1073. }
  1074. }
  1075. return ret.toArray(new String[0]);
  1076. }
  1077. // public void postRead(ResolvedType enclosingType) {
  1078. // this.importedPrefixes = enclosingType.getImportedPrefixes();
  1079. // this.knownNames = prematch(enclosingType.getImportedNames());
  1080. // }
  1081. @Override
  1082. public String toString() {
  1083. StringBuilder buf = new StringBuilder();
  1084. if (annotationPattern != AnnotationTypePattern.ANY) {
  1085. buf.append('(');
  1086. buf.append(annotationPattern);
  1087. buf.append(' ');
  1088. }
  1089. for (int i = 0, len = namePatterns.length; i < len; i++) {
  1090. NamePattern name = namePatterns[i];
  1091. if (name == null) {
  1092. buf.append(".");
  1093. } else {
  1094. if (i > 0) {
  1095. buf.append(".");
  1096. }
  1097. buf.append(name);
  1098. }
  1099. }
  1100. if (upperBound != null) {
  1101. buf.append(" extends ");
  1102. buf.append(upperBound);
  1103. }
  1104. if (lowerBound != null) {
  1105. buf.append(" super ");
  1106. buf.append(lowerBound);
  1107. }
  1108. if (typeParameters != null && typeParameters.size() != 0) {
  1109. buf.append("<");
  1110. buf.append(typeParameters.toString());
  1111. buf.append(">");
  1112. }
  1113. if (includeSubtypes) {
  1114. buf.append('+');
  1115. }
  1116. for (int i = 0; i < getDimensions(); i++) {
  1117. buf.append("[]");
  1118. }
  1119. if (isVarArgs) {
  1120. buf.append("...");
  1121. }
  1122. if (annotationPattern != AnnotationTypePattern.ANY) {
  1123. buf.append(')');
  1124. }
  1125. return buf.toString();
  1126. }
  1127. @Override
  1128. public boolean equals(Object other) {
  1129. if (!(other instanceof WildTypePattern)) {
  1130. return false;
  1131. }
  1132. WildTypePattern o = (WildTypePattern) other;
  1133. int len = o.namePatterns.length;
  1134. if (len != this.namePatterns.length) {
  1135. return false;
  1136. }
  1137. if (this.includeSubtypes != o.includeSubtypes) {
  1138. return false;
  1139. }
  1140. if (this.dim != o.dim) {
  1141. return false;
  1142. }
  1143. if (this.isVarArgs != o.isVarArgs) {
  1144. return false;
  1145. }
  1146. if (this.upperBound != null) {
  1147. if (o.upperBound == null) {
  1148. return false;
  1149. }
  1150. if (!this.upperBound.equals(o.upperBound)) {
  1151. return false;
  1152. }
  1153. } else {
  1154. if (o.upperBound != null) {
  1155. return false;
  1156. }
  1157. }
  1158. if (this.lowerBound != null) {
  1159. if (o.lowerBound == null) {
  1160. return false;
  1161. }
  1162. if (!this.lowerBound.equals(o.lowerBound)) {
  1163. return false;
  1164. }
  1165. } else {
  1166. if (o.lowerBound != null) {
  1167. return false;
  1168. }
  1169. }
  1170. if (!typeParameters.equals(o.typeParameters)) {
  1171. return false;
  1172. }
  1173. for (int i = 0; i < len; i++) {
  1174. if (!o.namePatterns[i].equals(this.namePatterns[i])) {
  1175. return false;
  1176. }
  1177. }
  1178. return (o.annotationPattern.equals(this.annotationPattern));
  1179. }
  1180. @Override
  1181. public int hashCode() {
  1182. int result = 17;
  1183. for (NamePattern namePattern : namePatterns) {
  1184. result = 37 * result + namePattern.hashCode();
  1185. }
  1186. result = 37 * result + (includeSubtypes ? 1 : 0);
  1187. result = 37 * result + dim;
  1188. result = 37 * result + (isVarArgs ? 1 : 0);
  1189. result = 37 * result + annotationPattern.hashCode();
  1190. result = 37 * result + typeParameters.hashCode();
  1191. if (upperBound != null) {
  1192. result = 37 * result + upperBound.hashCode();
  1193. }
  1194. if (lowerBound != null) {
  1195. result = 37 * result + lowerBound.hashCode();
  1196. }
  1197. return result;
  1198. }
  1199. private static final byte VERSION = 1; // rev on change
  1200. @Override
  1201. public void write(CompressingDataOutputStream s) throws IOException {
  1202. s.writeByte(TypePattern.WILD);
  1203. s.writeByte(VERSION);
  1204. s.writeShort(namePatterns.length);
  1205. for (NamePattern namePattern : namePatterns) {
  1206. namePattern.write(s);
  1207. }
  1208. s.writeBoolean(includeSubtypes);
  1209. s.writeInt(dim);
  1210. s.writeBoolean(isVarArgs);
  1211. typeParameters.write(s); // ! change from M2
  1212. // ??? storing this information with every type pattern is wasteful of .class
  1213. // file size. Storing it on enclosing types would be more efficient
  1214. FileUtil.writeStringArray(knownMatches, s);
  1215. FileUtil.writeStringArray(importedPrefixes, s);
  1216. writeLocation(s);
  1217. annotationPattern.write(s);
  1218. // generics info, new in M3
  1219. s.writeBoolean(isGeneric);
  1220. s.writeBoolean(upperBound != null);
  1221. if (upperBound != null) {
  1222. upperBound.write(s);
  1223. }
  1224. s.writeBoolean(lowerBound != null);
  1225. if (lowerBound != null) {
  1226. lowerBound.write(s);
  1227. }
  1228. s.writeInt(additionalInterfaceBounds == null ? 0 : additionalInterfaceBounds.length);
  1229. if (additionalInterfaceBounds != null) {
  1230. for (TypePattern additionalInterfaceBound : additionalInterfaceBounds) {
  1231. additionalInterfaceBound.write(s);
  1232. }
  1233. }
  1234. }
  1235. public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
  1236. if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
  1237. return readTypePattern150(s, context);
  1238. } else {
  1239. return readTypePatternOldStyle(s, context);
  1240. }
  1241. }
  1242. public static TypePattern readTypePattern150(VersionedDataInputStream s, ISourceContext context) throws IOException {
  1243. byte version = s.readByte();
  1244. if (version > VERSION) {
  1245. throw new BCException("WildTypePattern was written by a more recent version of AspectJ, cannot read");
  1246. }
  1247. int len = s.readShort();
  1248. NamePattern[] namePatterns = new NamePattern[len];
  1249. for (int i = 0; i < len; i++) {
  1250. namePatterns[i] = NamePattern.read(s);
  1251. }
  1252. boolean includeSubtypes = s.readBoolean();
  1253. int dim = s.readInt();
  1254. boolean varArg = s.readBoolean();
  1255. TypePatternList typeParams = TypePatternList.read(s, context);
  1256. WildTypePattern ret = new WildTypePattern(namePatterns, includeSubtypes, dim, varArg, typeParams);
  1257. ret.knownMatches = FileUtil.readStringArray(s);
  1258. ret.importedPrefixes = FileUtil.readStringArray(s);
  1259. ret.readLocation(context, s);
  1260. ret.setAnnotationTypePattern(AnnotationTypePattern.read(s, context));
  1261. // generics info, new in M3
  1262. ret.isGeneric = s.readBoolean();
  1263. if (s.readBoolean()) {
  1264. ret.upperBound = TypePattern.read(s, context);
  1265. }
  1266. if (s.readBoolean()) {
  1267. ret.lowerBound = TypePattern.read(s, context);
  1268. }
  1269. int numIfBounds = s.readInt();
  1270. if (numIfBounds > 0) {
  1271. ret.additionalInterfaceBounds = new TypePattern[numIfBounds];
  1272. for (int i = 0; i < numIfBounds; i++) {
  1273. ret.additionalInterfaceBounds[i] = TypePattern.read(s, context);
  1274. }
  1275. }
  1276. return ret;
  1277. }
  1278. public static TypePattern readTypePatternOldStyle(VersionedDataInputStream s, ISourceContext context) throws IOException {
  1279. int len = s.readShort();
  1280. NamePattern[] namePatterns = new NamePattern[len];
  1281. for (int i = 0; i < len; i++) {
  1282. namePatterns[i] = NamePattern.read(s);
  1283. }
  1284. boolean includeSubtypes = s.readBoolean();
  1285. int dim = s.readInt();
  1286. WildTypePattern ret = new WildTypePattern(namePatterns, includeSubtypes, dim, false, null);
  1287. ret.knownMatches = FileUtil.readStringArray(s);
  1288. ret.importedPrefixes = FileUtil.readStringArray(s);
  1289. ret.readLocation(context, s);
  1290. return ret;
  1291. }
  1292. @Override
  1293. public Object accept(PatternNodeVisitor visitor, Object data) {
  1294. return visitor.visit(this, data);
  1295. }
  1296. public boolean hasFailedResolution() {
  1297. return failedResolution;
  1298. }
  1299. }