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

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