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

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403
  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 v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  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((NamePattern[]) names.toArray(new NamePattern[names.size()]), 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((NamePattern[]) names.toArray(new NamePattern[names.size()]), 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((NamePattern[]) names.toArray(new NamePattern[names.size()]), 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<char[]>();
  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.TypePattern#matchesExactly(IType)
  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 > 1;
  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<char[]>();
  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.TypePattern#matchesInstanceof(IType)
  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. StringBuffer buf = new StringBuffer();
  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. for (int i = 0; i < namePatterns.length; i++) {
  541. newNamePatterns[i] = namePatterns[i];
  542. }
  543. if (newNamePatterns.length == 1) {
  544. String simpleName = newNamePatterns[0].maybeGetSimpleName();
  545. if (simpleName != null) {
  546. if (typeVariableMap.containsKey(simpleName)) {
  547. String newName = ((ReferenceType) typeVariableMap.get(simpleName)).getName().replace('$', '.');
  548. StringTokenizer strTok = new StringTokenizer(newName, ".");
  549. newNamePatterns = new NamePattern[strTok.countTokens()];
  550. int index = 0;
  551. while (strTok.hasMoreTokens()) {
  552. newNamePatterns[index++] = new NamePattern(strTok.nextToken());
  553. }
  554. }
  555. }
  556. }
  557. WildTypePattern ret = new WildTypePattern(newNamePatterns, includeSubtypes, dim, isVarArgs, typeParameters
  558. .parameterizeWith(typeVariableMap, w));
  559. ret.annotationPattern = this.annotationPattern.parameterizeWith(typeVariableMap, w);
  560. if (additionalInterfaceBounds == null) {
  561. ret.additionalInterfaceBounds = null;
  562. } else {
  563. ret.additionalInterfaceBounds = new TypePattern[additionalInterfaceBounds.length];
  564. for (int i = 0; i < additionalInterfaceBounds.length; i++) {
  565. ret.additionalInterfaceBounds[i] = additionalInterfaceBounds[i].parameterizeWith(typeVariableMap, w);
  566. }
  567. }
  568. ret.upperBound = upperBound != null ? upperBound.parameterizeWith(typeVariableMap, w) : null;
  569. ret.lowerBound = lowerBound != null ? lowerBound.parameterizeWith(typeVariableMap, w) : null;
  570. ret.isGeneric = isGeneric;
  571. ret.knownMatches = knownMatches;
  572. ret.importedPrefixes = importedPrefixes;
  573. ret.copyLocationFrom(this);
  574. return ret;
  575. }
  576. /**
  577. * Need to determine if I'm really a pattern or a reference to a formal
  578. *
  579. * We may wish to further optimize the case of pattern vs. non-pattern
  580. *
  581. * We will be replaced by what we return
  582. */
  583. @Override
  584. public TypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
  585. if (isNamePatternStar()) {
  586. TypePattern anyPattern = maybeResolveToAnyPattern(scope, bindings, allowBinding, requireExactType);
  587. if (anyPattern != null) {
  588. if (requireExactType) {
  589. scope.getWorld().getMessageHandler().handleMessage(
  590. MessageUtil.error(WeaverMessages.format(WeaverMessages.WILDCARD_NOT_ALLOWED), getSourceLocation()));
  591. return NO;
  592. } else {
  593. return anyPattern;
  594. }
  595. }
  596. }
  597. TypePattern bindingTypePattern = maybeResolveToBindingTypePattern(scope, bindings, allowBinding, requireExactType);
  598. if (bindingTypePattern != null) {
  599. return bindingTypePattern;
  600. }
  601. annotationPattern = annotationPattern.resolveBindings(scope, bindings, allowBinding);
  602. // resolve any type parameters
  603. if (typeParameters != null && typeParameters.size() > 0) {
  604. typeParameters.resolveBindings(scope, bindings, allowBinding, requireExactType);
  605. isGeneric = false;
  606. }
  607. // resolve any bounds
  608. if (upperBound != null) {
  609. upperBound = upperBound.resolveBindings(scope, bindings, allowBinding, requireExactType);
  610. }
  611. if (lowerBound != null) {
  612. lowerBound = lowerBound.resolveBindings(scope, bindings, allowBinding, requireExactType);
  613. // amc - additional interface bounds only needed if we support type vars again.
  614. }
  615. String fullyQualifiedName = maybeGetCleanName();
  616. if (fullyQualifiedName != null) {
  617. return resolveBindingsFromFullyQualifiedTypeName(fullyQualifiedName, scope, bindings, allowBinding, requireExactType);
  618. } else {
  619. if (requireExactType) {
  620. scope.getWorld().getMessageHandler().handleMessage(
  621. MessageUtil.error(WeaverMessages.format(WeaverMessages.WILDCARD_NOT_ALLOWED), getSourceLocation()));
  622. return NO;
  623. }
  624. importedPrefixes = scope.getImportedPrefixes();
  625. knownMatches = preMatch(scope.getImportedNames());
  626. return this; // pattern contains wildcards so can't be resolved to an ExactTypePattern...
  627. // XXX need to implement behavior for Lint.invalidWildcardTypeName
  628. }
  629. }
  630. private TypePattern maybeResolveToAnyPattern(IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
  631. // If there is an annotation specified we have to
  632. // use a special variant of Any TypePattern called
  633. // AnyWithAnnotation
  634. if (annotationPattern == AnnotationTypePattern.ANY) {
  635. if (dim == 0 && !isVarArgs && upperBound == null && lowerBound == null
  636. && (additionalInterfaceBounds == null || additionalInterfaceBounds.length == 0)) { // pr72531
  637. return TypePattern.ANY; // ??? loses source location
  638. }
  639. } else if (!isVarArgs) {
  640. annotationPattern = annotationPattern.resolveBindings(scope, bindings, allowBinding);
  641. AnyWithAnnotationTypePattern ret = new AnyWithAnnotationTypePattern(annotationPattern);
  642. ret.setLocation(sourceContext, start, end);
  643. return ret;
  644. }
  645. return null; // can't resolve to a simple "any" pattern
  646. }
  647. private TypePattern maybeResolveToBindingTypePattern(IScope scope, Bindings bindings, boolean allowBinding,
  648. boolean requireExactType) {
  649. String simpleName = maybeGetSimpleName();
  650. if (simpleName != null) {
  651. FormalBinding formalBinding = scope.lookupFormal(simpleName);
  652. if (formalBinding != null) {
  653. if (bindings == null) {
  654. scope.message(IMessage.ERROR, this, "negation doesn't allow binding");
  655. return this;
  656. }
  657. if (!allowBinding) {
  658. scope.message(IMessage.ERROR, this, "name binding only allowed in target, this, and args pcds");
  659. return this;
  660. }
  661. BindingTypePattern binding = new BindingTypePattern(formalBinding, isVarArgs);
  662. binding.copyLocationFrom(this);
  663. bindings.register(binding, scope);
  664. return binding;
  665. }
  666. }
  667. return null; // not possible to resolve to a binding type pattern
  668. }
  669. private TypePattern resolveBindingsFromFullyQualifiedTypeName(String fullyQualifiedName, IScope scope, Bindings bindings,
  670. boolean allowBinding, boolean requireExactType) {
  671. String originalName = fullyQualifiedName;
  672. ResolvedType resolvedTypeInTheWorld = null;
  673. UnresolvedType type;
  674. // System.out.println("resolve: " + cleanName);
  675. // ??? this loop has too many inefficiencies to count
  676. resolvedTypeInTheWorld = lookupTypeInWorldIncludingPrefixes(scope.getWorld(), fullyQualifiedName, scope
  677. .getImportedPrefixes());
  678. if (resolvedTypeInTheWorld.isGenericWildcard()) {
  679. type = resolvedTypeInTheWorld;
  680. } else {
  681. type = lookupTypeInScope(scope, fullyQualifiedName, this);
  682. }
  683. if ((type instanceof ResolvedType) && ((ResolvedType) type).isMissing()) {
  684. return resolveBindingsForMissingType(resolvedTypeInTheWorld, originalName, scope, bindings, allowBinding,
  685. requireExactType);
  686. } else {
  687. return resolveBindingsForExactType(scope, type, fullyQualifiedName, requireExactType);
  688. }
  689. }
  690. private UnresolvedType lookupTypeInScope(IScope scope, String typeName, IHasPosition location) {
  691. UnresolvedType type = null;
  692. while (ResolvedType.isMissing(type = scope.lookupType(typeName, location))) {
  693. int lastDot = typeName.lastIndexOf('.');
  694. if (lastDot == -1) {
  695. break;
  696. }
  697. typeName = typeName.substring(0, lastDot) + '$' + typeName.substring(lastDot + 1);
  698. }
  699. return type;
  700. }
  701. /**
  702. * Searches the world for the ResolvedType with the given typeName. If one isn't found then for each of the supplied prefixes,
  703. * it prepends the typeName with the prefix and searches the world for the ResolvedType with this new name. If one still isn't
  704. * found then a MissingResolvedTypeWithKnownSignature is returned with the originally requested typeName (this ensures the
  705. * typeName makes sense).
  706. */
  707. private ResolvedType lookupTypeInWorldIncludingPrefixes(World world, String typeName, String[] prefixes) {
  708. ResolvedType ret = lookupTypeInWorld(world, typeName);
  709. if (!ret.isMissing()) {
  710. return ret;
  711. }
  712. ResolvedType retWithPrefix = ret;
  713. int counter = 0;
  714. while (retWithPrefix.isMissing() && (counter < prefixes.length)) {
  715. retWithPrefix = lookupTypeInWorld(world, prefixes[counter] + typeName);
  716. counter++;
  717. }
  718. if (!retWithPrefix.isMissing()) {
  719. return retWithPrefix;
  720. }
  721. return ret;
  722. }
  723. private ResolvedType lookupTypeInWorld(World world, String typeName) {
  724. UnresolvedType ut = UnresolvedType.forName(typeName);
  725. ResolvedType ret = world.resolve(ut, true);
  726. while (ret.isMissing()) {
  727. int lastDot = typeName.lastIndexOf('.');
  728. if (lastDot == -1) {
  729. break;
  730. }
  731. typeName = typeName.substring(0, lastDot) + '$' + typeName.substring(lastDot + 1);
  732. ret = world.resolve(UnresolvedType.forName(typeName), true);
  733. }
  734. return ret;
  735. }
  736. private TypePattern resolveBindingsForExactType(IScope scope, UnresolvedType aType, String fullyQualifiedName,
  737. boolean requireExactType) {
  738. TypePattern ret = null;
  739. if (aType.isTypeVariableReference()) {
  740. // we have to set the bounds on it based on the bounds of this pattern
  741. ret = resolveBindingsForTypeVariable(scope, (UnresolvedTypeVariableReferenceType) aType);
  742. } else if (typeParameters.size() > 0) {
  743. ret = resolveParameterizedType(scope, aType, requireExactType);
  744. } else if (upperBound != null || lowerBound != null) {
  745. // this must be a generic wildcard with bounds
  746. ret = resolveGenericWildcard(scope, aType);
  747. } else {
  748. if (dim != 0) {
  749. aType = UnresolvedType.makeArray(aType, dim);
  750. }
  751. ret = new ExactTypePattern(aType, includeSubtypes, isVarArgs);
  752. }
  753. ret.setAnnotationTypePattern(annotationPattern);
  754. ret.copyLocationFrom(this);
  755. return ret;
  756. }
  757. private TypePattern resolveGenericWildcard(IScope scope, UnresolvedType aType) {
  758. if (!aType.getSignature().equals(GENERIC_WILDCARD_SIGNATURE_CHARACTER)) {
  759. throw new IllegalStateException("Can only have bounds for a generic wildcard");
  760. }
  761. boolean canBeExact = true;
  762. if ((upperBound != null) && ResolvedType.isMissing(upperBound.getExactType())) {
  763. canBeExact = false;
  764. }
  765. if ((lowerBound != null) && ResolvedType.isMissing(lowerBound.getExactType())) {
  766. canBeExact = false;
  767. }
  768. if (canBeExact) {
  769. ResolvedType type = null;
  770. if (upperBound != null) {
  771. if (upperBound.isIncludeSubtypes()) {
  772. canBeExact = false;
  773. } else {
  774. ReferenceType upper = (ReferenceType) upperBound.getExactType().resolve(scope.getWorld());
  775. type = new BoundedReferenceType(upper, true, scope.getWorld());
  776. }
  777. } else {
  778. if (lowerBound.isIncludeSubtypes()) {
  779. canBeExact = false;
  780. } else {
  781. ReferenceType lower = (ReferenceType) lowerBound.getExactType().resolve(scope.getWorld());
  782. type = new BoundedReferenceType(lower, false, scope.getWorld());
  783. }
  784. }
  785. if (canBeExact) {
  786. // might have changed if we find out include subtypes is set on one of the bounds...
  787. return new ExactTypePattern(type, includeSubtypes, isVarArgs);
  788. }
  789. }
  790. // we weren't able to resolve to an exact type pattern...
  791. // leave as wild type pattern
  792. importedPrefixes = scope.getImportedPrefixes();
  793. knownMatches = preMatch(scope.getImportedNames());
  794. return this;
  795. }
  796. private TypePattern resolveParameterizedType(IScope scope, UnresolvedType aType, boolean requireExactType) {
  797. ResolvedType rt = aType.resolve(scope.getWorld());
  798. if (!verifyTypeParameters(rt, scope, requireExactType)) {
  799. return TypePattern.NO; // messages already isued
  800. }
  801. // Only if the type is exact *and* the type parameters are exact should we create an
  802. // ExactTypePattern for this WildTypePattern
  803. if (typeParameters.areAllExactWithNoSubtypesAllowed()) {
  804. TypePattern[] typePats = typeParameters.getTypePatterns();
  805. UnresolvedType[] typeParameterTypes = new UnresolvedType[typePats.length];
  806. for (int i = 0; i < typeParameterTypes.length; i++) {
  807. typeParameterTypes[i] = ((ExactTypePattern) typePats[i]).getExactType();
  808. }
  809. // rt could be a parameterized type 156058
  810. if (rt.isParameterizedType()) {
  811. rt = rt.getGenericType();
  812. }
  813. ResolvedType type = TypeFactory.createParameterizedType(rt, typeParameterTypes, scope.getWorld());
  814. if (isGeneric) {
  815. type = type.getGenericType();
  816. }
  817. // UnresolvedType tx = UnresolvedType.forParameterizedTypes(aType,typeParameterTypes);
  818. // UnresolvedType type = scope.getWorld().resolve(tx,true);
  819. if (dim != 0) {
  820. type = ResolvedType.makeArray(type, dim);
  821. }
  822. return new ExactTypePattern(type, includeSubtypes, isVarArgs);
  823. } else {
  824. // AMC... just leave it as a wild type pattern then?
  825. importedPrefixes = scope.getImportedPrefixes();
  826. knownMatches = preMatch(scope.getImportedNames());
  827. return this;
  828. }
  829. }
  830. private TypePattern resolveBindingsForMissingType(ResolvedType typeFoundInWholeWorldSearch, String nameWeLookedFor,
  831. IScope scope, Bindings bindings, boolean allowBinding, boolean requireExactType) {
  832. if (requireExactType) {
  833. if (!allowBinding) {
  834. scope.getWorld().getMessageHandler().handleMessage(
  835. MessageUtil.error(WeaverMessages.format(WeaverMessages.CANT_BIND_TYPE, nameWeLookedFor),
  836. getSourceLocation()));
  837. } else if (scope.getWorld().getLint().invalidAbsoluteTypeName.isEnabled()) {
  838. scope.getWorld().getLint().invalidAbsoluteTypeName.signal(nameWeLookedFor, getSourceLocation());
  839. }
  840. return NO;
  841. } else if (scope.getWorld().getLint().invalidAbsoluteTypeName.isEnabled()) {
  842. // Only put the lint warning out if we can't find it in the world
  843. if (typeFoundInWholeWorldSearch.isMissing()) {
  844. scope.getWorld().getLint().invalidAbsoluteTypeName.signal(nameWeLookedFor, getSourceLocation());
  845. this.failedResolution = true;
  846. }
  847. }
  848. importedPrefixes = scope.getImportedPrefixes();
  849. knownMatches = preMatch(scope.getImportedNames());
  850. return this;
  851. }
  852. /**
  853. * We resolved the type to a type variable declared in the pointcut designator. Now we have to create either an exact type
  854. * pattern or a wild type pattern for it, with upper and lower bounds set accordingly. XXX none of this stuff gets serialized
  855. * yet
  856. *
  857. * @param scope
  858. * @param tvrType
  859. * @return
  860. */
  861. private TypePattern resolveBindingsForTypeVariable(IScope scope, UnresolvedTypeVariableReferenceType tvrType) {
  862. Bindings emptyBindings = new Bindings(0);
  863. if (upperBound != null) {
  864. upperBound = upperBound.resolveBindings(scope, emptyBindings, false, false);
  865. }
  866. if (lowerBound != null) {
  867. lowerBound = lowerBound.resolveBindings(scope, emptyBindings, false, false);
  868. }
  869. if (additionalInterfaceBounds != null) {
  870. TypePattern[] resolvedIfBounds = new TypePattern[additionalInterfaceBounds.length];
  871. for (int i = 0; i < resolvedIfBounds.length; i++) {
  872. resolvedIfBounds[i] = additionalInterfaceBounds[i].resolveBindings(scope, emptyBindings, false, false);
  873. }
  874. additionalInterfaceBounds = resolvedIfBounds;
  875. }
  876. if (upperBound == null && lowerBound == null && additionalInterfaceBounds == null) {
  877. // no bounds to worry about...
  878. ResolvedType rType = tvrType.resolve(scope.getWorld());
  879. if (dim != 0) {
  880. rType = ResolvedType.makeArray(rType, dim);
  881. }
  882. return new ExactTypePattern(rType, includeSubtypes, isVarArgs);
  883. } else {
  884. // we have to set bounds on the TypeVariable held by tvrType before resolving it
  885. boolean canCreateExactTypePattern = true;
  886. if (upperBound != null && ResolvedType.isMissing(upperBound.getExactType())) {
  887. canCreateExactTypePattern = false;
  888. }
  889. if (lowerBound != null && ResolvedType.isMissing(lowerBound.getExactType())) {
  890. canCreateExactTypePattern = false;
  891. }
  892. if (additionalInterfaceBounds != null) {
  893. for (TypePattern additionalInterfaceBound : additionalInterfaceBounds) {
  894. if (ResolvedType.isMissing(additionalInterfaceBound.getExactType())) {
  895. canCreateExactTypePattern = false;
  896. }
  897. }
  898. }
  899. if (canCreateExactTypePattern) {
  900. TypeVariable tv = tvrType.getTypeVariable();
  901. if (upperBound != null) {
  902. tv.setSuperclass(upperBound.getExactType());
  903. }
  904. if (additionalInterfaceBounds != null) {
  905. UnresolvedType[] ifBounds = new UnresolvedType[additionalInterfaceBounds.length];
  906. for (int i = 0; i < ifBounds.length; i++) {
  907. ifBounds[i] = additionalInterfaceBounds[i].getExactType();
  908. }
  909. tv.setAdditionalInterfaceBounds(ifBounds);
  910. }
  911. ResolvedType rType = tvrType.resolve(scope.getWorld());
  912. if (dim != 0) {
  913. rType = ResolvedType.makeArray(rType, dim);
  914. }
  915. return new ExactTypePattern(rType, includeSubtypes, isVarArgs);
  916. }
  917. return this; // leave as wild type pattern then
  918. }
  919. }
  920. /**
  921. * 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
  922. * parameters. Time to perform some basic checks: - can the base type be parameterized? (is it generic) - can the type parameter
  923. * pattern list match the number of parameters on the base type - do all parameter patterns meet the bounds of the respective
  924. * type variables If any of these checks fail, a warning message is issued and we return false.
  925. *
  926. * @return
  927. */
  928. private boolean verifyTypeParameters(ResolvedType baseType, IScope scope, boolean requireExactType) {
  929. ResolvedType genericType = baseType.getGenericType();
  930. if (genericType == null) {
  931. // issue message "does not match because baseType.getName() is not generic"
  932. scope.message(MessageUtil.warn(WeaverMessages.format(WeaverMessages.NOT_A_GENERIC_TYPE, baseType.getName()),
  933. getSourceLocation()));
  934. return false;
  935. }
  936. int minRequiredTypeParameters = typeParameters.size();
  937. boolean foundEllipsis = false;
  938. TypePattern[] typeParamPatterns = typeParameters.getTypePatterns();
  939. for (TypePattern typeParamPattern : typeParamPatterns) {
  940. if (typeParamPattern instanceof WildTypePattern) {
  941. WildTypePattern wtp = (WildTypePattern) typeParamPattern;
  942. if (wtp.ellipsisCount > 0) {
  943. foundEllipsis = true;
  944. minRequiredTypeParameters--;
  945. }
  946. }
  947. }
  948. TypeVariable[] tvs = genericType.getTypeVariables();
  949. if ((tvs.length < minRequiredTypeParameters) || (!foundEllipsis && minRequiredTypeParameters != tvs.length)) {
  950. // issue message "does not match because wrong no of type params"
  951. String msg = WeaverMessages.format(WeaverMessages.INCORRECT_NUMBER_OF_TYPE_ARGUMENTS, genericType.getName(),
  952. new Integer(tvs.length));
  953. if (requireExactType) {
  954. scope.message(MessageUtil.error(msg, getSourceLocation()));
  955. } else {
  956. scope.message(MessageUtil.warn(msg, getSourceLocation()));
  957. }
  958. return false;
  959. }
  960. // now check that each typeParameter pattern, if exact, matches the bounds
  961. // of the type variable.
  962. // pr133307 - delay verification until type binding completion, these next few lines replace
  963. // the call to checkBoundsOK
  964. if (!boundscheckingoff) {
  965. VerifyBoundsForTypePattern verification = new VerifyBoundsForTypePattern(scope, genericType, requireExactType,
  966. typeParameters, getSourceLocation());
  967. scope.getWorld().getCrosscuttingMembersSet().recordNecessaryCheck(verification);
  968. }
  969. // return checkBoundsOK(scope,genericType,requireExactType);
  970. return true;
  971. }
  972. /**
  973. * By capturing the verification in this class, rather than performing it in verifyTypeParameters(), we can cope with situations
  974. * where the interactions between generics and declare parents would otherwise cause us problems. For example, if verifying as
  975. * 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
  976. * create and store a verification object, we can verify this later when the type system is considered 'complete'
  977. */
  978. static class VerifyBoundsForTypePattern implements IVerificationRequired {
  979. private final IScope scope;
  980. private final ResolvedType genericType;
  981. private final boolean requireExactType;
  982. private TypePatternList typeParameters = TypePatternList.EMPTY;
  983. private final ISourceLocation sLoc;
  984. public VerifyBoundsForTypePattern(IScope scope, ResolvedType genericType, boolean requireExactType,
  985. TypePatternList typeParameters, ISourceLocation sLoc) {
  986. this.scope = scope;
  987. this.genericType = genericType;
  988. this.requireExactType = requireExactType;
  989. this.typeParameters = typeParameters;
  990. this.sLoc = sLoc;
  991. }
  992. public void verify() {
  993. TypeVariable[] tvs = genericType.getTypeVariables();
  994. TypePattern[] typeParamPatterns = typeParameters.getTypePatterns();
  995. if (typeParameters.areAllExactWithNoSubtypesAllowed()) {
  996. for (int i = 0; i < tvs.length; i++) {
  997. UnresolvedType ut = typeParamPatterns[i].getExactType();
  998. boolean continueCheck = true;
  999. // FIXME asc dont like this but ok temporary measure. If the type parameter
  1000. // is itself a type variable (from the generic aspect) then assume it'll be
  1001. // ok... (see pr112105) Want to break this? Run GenericAspectK test.
  1002. if (ut.isTypeVariableReference()) {
  1003. continueCheck = false;
  1004. }
  1005. // System.err.println("Verifying "+ut.getName()+" meets bounds for "+tvs[i]);
  1006. if (continueCheck && !tvs[i].canBeBoundTo(ut.resolve(scope.getWorld()))) {
  1007. // issue message that type parameter does not meet specification
  1008. String parameterName = ut.getName();
  1009. if (ut.isTypeVariableReference()) {
  1010. parameterName = ((TypeVariableReference) ut).getTypeVariable().getDisplayName();
  1011. }
  1012. String msg = WeaverMessages.format(WeaverMessages.VIOLATES_TYPE_VARIABLE_BOUNDS, parameterName,
  1013. new Integer(i + 1), tvs[i].getDisplayName(), genericType.getName());
  1014. if (requireExactType) {
  1015. scope.message(MessageUtil.error(msg, sLoc));
  1016. } else {
  1017. scope.message(MessageUtil.warn(msg, sLoc));
  1018. }
  1019. }
  1020. }
  1021. }
  1022. }
  1023. }
  1024. // pr133307 - moved to verification object
  1025. // public boolean checkBoundsOK(IScope scope,ResolvedType genericType,boolean requireExactType) {
  1026. // if (boundscheckingoff) return true;
  1027. // TypeVariable[] tvs = genericType.getTypeVariables();
  1028. // TypePattern[] typeParamPatterns = typeParameters.getTypePatterns();
  1029. // if (typeParameters.areAllExactWithNoSubtypesAllowed()) {
  1030. // for (int i = 0; i < tvs.length; i++) {
  1031. // UnresolvedType ut = typeParamPatterns[i].getExactType();
  1032. // boolean continueCheck = true;
  1033. // // FIXME asc dont like this but ok temporary measure. If the type parameter
  1034. // // is itself a type variable (from the generic aspect) then assume it'll be
  1035. // // ok... (see pr112105) Want to break this? Run GenericAspectK test.
  1036. // if (ut.isTypeVariableReference()) {
  1037. // continueCheck = false;
  1038. // }
  1039. //
  1040. // if (continueCheck &&
  1041. // !tvs[i].canBeBoundTo(ut.resolve(scope.getWorld()))) {
  1042. // // issue message that type parameter does not meet specification
  1043. // String parameterName = ut.getName();
  1044. // if (ut.isTypeVariableReference()) parameterName = ((TypeVariableReference)ut).getTypeVariable().getDisplayName();
  1045. // String msg =
  1046. // WeaverMessages.format(
  1047. // WeaverMessages.VIOLATES_TYPE_VARIABLE_BOUNDS,
  1048. // parameterName,
  1049. // new Integer(i+1),
  1050. // tvs[i].getDisplayName(),
  1051. // genericType.getName());
  1052. // if (requireExactType) scope.message(MessageUtil.error(msg,getSourceLocation()));
  1053. // else scope.message(MessageUtil.warn(msg,getSourceLocation()));
  1054. // return false;
  1055. // }
  1056. // }
  1057. // }
  1058. // return true;
  1059. // }
  1060. @Override
  1061. public boolean isStar() {
  1062. boolean annPatternStar = annotationPattern == AnnotationTypePattern.ANY;
  1063. return (isNamePatternStar() && annPatternStar && dim == 0);
  1064. }
  1065. private boolean isNamePatternStar() {
  1066. return namePatterns.length == 1 && namePatterns[0].isAny();
  1067. }
  1068. /**
  1069. * @return those possible matches which I match exactly the last element of
  1070. */
  1071. private String[] preMatch(String[] possibleMatches) {
  1072. // if (namePatterns.length != 1) return CollectionUtil.NO_STRINGS;
  1073. List<String> ret = new ArrayList<String>();
  1074. for (String possibleMatch : possibleMatches) {
  1075. char[][] names = splitNames(possibleMatch, true); // ??? not most efficient
  1076. if (namePatterns[0].matches(names[names.length - 1])) {
  1077. ret.add(possibleMatch);
  1078. continue;
  1079. }
  1080. if (possibleMatch.contains("$")) {
  1081. names = splitNames(possibleMatch, false); // ??? not most efficient
  1082. if (namePatterns[0].matches(names[names.length - 1])) {
  1083. ret.add(possibleMatch);
  1084. }
  1085. }
  1086. }
  1087. return ret.toArray(new String[ret.size()]);
  1088. }
  1089. // public void postRead(ResolvedType enclosingType) {
  1090. // this.importedPrefixes = enclosingType.getImportedPrefixes();
  1091. // this.knownNames = prematch(enclosingType.getImportedNames());
  1092. // }
  1093. @Override
  1094. public String toString() {
  1095. StringBuffer buf = new StringBuffer();
  1096. if (annotationPattern != AnnotationTypePattern.ANY) {
  1097. buf.append('(');
  1098. buf.append(annotationPattern.toString());
  1099. buf.append(' ');
  1100. }
  1101. for (int i = 0, len = namePatterns.length; i < len; i++) {
  1102. NamePattern name = namePatterns[i];
  1103. if (name == null) {
  1104. buf.append(".");
  1105. } else {
  1106. if (i > 0) {
  1107. buf.append(".");
  1108. }
  1109. buf.append(name.toString());
  1110. }
  1111. }
  1112. if (upperBound != null) {
  1113. buf.append(" extends ");
  1114. buf.append(upperBound.toString());
  1115. }
  1116. if (lowerBound != null) {
  1117. buf.append(" super ");
  1118. buf.append(lowerBound.toString());
  1119. }
  1120. if (typeParameters != null && typeParameters.size() != 0) {
  1121. buf.append("<");
  1122. buf.append(typeParameters.toString());
  1123. buf.append(">");
  1124. }
  1125. if (includeSubtypes) {
  1126. buf.append('+');
  1127. }
  1128. if (isVarArgs) {
  1129. buf.append("...");
  1130. }
  1131. if (annotationPattern != AnnotationTypePattern.ANY) {
  1132. buf.append(')');
  1133. }
  1134. return buf.toString();
  1135. }
  1136. @Override
  1137. public boolean equals(Object other) {
  1138. if (!(other instanceof WildTypePattern)) {
  1139. return false;
  1140. }
  1141. WildTypePattern o = (WildTypePattern) other;
  1142. int len = o.namePatterns.length;
  1143. if (len != this.namePatterns.length) {
  1144. return false;
  1145. }
  1146. if (this.includeSubtypes != o.includeSubtypes) {
  1147. return false;
  1148. }
  1149. if (this.dim != o.dim) {
  1150. return false;
  1151. }
  1152. if (this.isVarArgs != o.isVarArgs) {
  1153. return false;
  1154. }
  1155. if (this.upperBound != null) {
  1156. if (o.upperBound == null) {
  1157. return false;
  1158. }
  1159. if (!this.upperBound.equals(o.upperBound)) {
  1160. return false;
  1161. }
  1162. } else {
  1163. if (o.upperBound != null) {
  1164. return false;
  1165. }
  1166. }
  1167. if (this.lowerBound != null) {
  1168. if (o.lowerBound == null) {
  1169. return false;
  1170. }
  1171. if (!this.lowerBound.equals(o.lowerBound)) {
  1172. return false;
  1173. }
  1174. } else {
  1175. if (o.lowerBound != null) {
  1176. return false;
  1177. }
  1178. }
  1179. if (!typeParameters.equals(o.typeParameters)) {
  1180. return false;
  1181. }
  1182. for (int i = 0; i < len; i++) {
  1183. if (!o.namePatterns[i].equals(this.namePatterns[i])) {
  1184. return false;
  1185. }
  1186. }
  1187. return (o.annotationPattern.equals(this.annotationPattern));
  1188. }
  1189. @Override
  1190. public int hashCode() {
  1191. int result = 17;
  1192. for (NamePattern namePattern : namePatterns) {
  1193. result = 37 * result + namePattern.hashCode();
  1194. }
  1195. result = 37 * result + annotationPattern.hashCode();
  1196. if (upperBound != null) {
  1197. result = 37 * result + upperBound.hashCode();
  1198. }
  1199. if (lowerBound != null) {
  1200. result = 37 * result + lowerBound.hashCode();
  1201. }
  1202. return result;
  1203. }
  1204. private static final byte VERSION = 1; // rev on change
  1205. @Override
  1206. public void write(CompressingDataOutputStream s) throws IOException {
  1207. s.writeByte(TypePattern.WILD);
  1208. s.writeByte(VERSION);
  1209. s.writeShort(namePatterns.length);
  1210. for (NamePattern namePattern : namePatterns) {
  1211. namePattern.write(s);
  1212. }
  1213. s.writeBoolean(includeSubtypes);
  1214. s.writeInt(dim);
  1215. s.writeBoolean(isVarArgs);
  1216. typeParameters.write(s); // ! change from M2
  1217. // ??? storing this information with every type pattern is wasteful of .class
  1218. // file size. Storing it on enclosing types would be more efficient
  1219. FileUtil.writeStringArray(knownMatches, s);
  1220. FileUtil.writeStringArray(importedPrefixes, s);
  1221. writeLocation(s);
  1222. annotationPattern.write(s);
  1223. // generics info, new in M3
  1224. s.writeBoolean(isGeneric);
  1225. s.writeBoolean(upperBound != null);
  1226. if (upperBound != null) {
  1227. upperBound.write(s);
  1228. }
  1229. s.writeBoolean(lowerBound != null);
  1230. if (lowerBound != null) {
  1231. lowerBound.write(s);
  1232. }
  1233. s.writeInt(additionalInterfaceBounds == null ? 0 : additionalInterfaceBounds.length);
  1234. if (additionalInterfaceBounds != null) {
  1235. for (TypePattern additionalInterfaceBound : additionalInterfaceBounds) {
  1236. additionalInterfaceBound.write(s);
  1237. }
  1238. }
  1239. }
  1240. public static TypePattern read(VersionedDataInputStream s, ISourceContext context) throws IOException {
  1241. if (s.getMajorVersion() >= AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
  1242. return readTypePattern150(s, context);
  1243. } else {
  1244. return readTypePatternOldStyle(s, context);
  1245. }
  1246. }
  1247. public static TypePattern readTypePattern150(VersionedDataInputStream s, ISourceContext context) throws IOException {
  1248. byte version = s.readByte();
  1249. if (version > VERSION) {
  1250. throw new BCException("WildTypePattern was written by a more recent version of AspectJ, cannot read");
  1251. }
  1252. int len = s.readShort();
  1253. NamePattern[] namePatterns = new NamePattern[len];
  1254. for (int i = 0; i < len; i++) {
  1255. namePatterns[i] = NamePattern.read(s);
  1256. }
  1257. boolean includeSubtypes = s.readBoolean();
  1258. int dim = s.readInt();
  1259. boolean varArg = s.readBoolean();
  1260. TypePatternList typeParams = TypePatternList.read(s, context);
  1261. WildTypePattern ret = new WildTypePattern(namePatterns, includeSubtypes, dim, varArg, typeParams);
  1262. ret.knownMatches = FileUtil.readStringArray(s);
  1263. ret.importedPrefixes = FileUtil.readStringArray(s);
  1264. ret.readLocation(context, s);
  1265. ret.setAnnotationTypePattern(AnnotationTypePattern.read(s, context));
  1266. // generics info, new in M3
  1267. ret.isGeneric = s.readBoolean();
  1268. if (s.readBoolean()) {
  1269. ret.upperBound = TypePattern.read(s, context);
  1270. }
  1271. if (s.readBoolean()) {
  1272. ret.lowerBound = TypePattern.read(s, context);
  1273. }
  1274. int numIfBounds = s.readInt();
  1275. if (numIfBounds > 0) {
  1276. ret.additionalInterfaceBounds = new TypePattern[numIfBounds];
  1277. for (int i = 0; i < numIfBounds; i++) {
  1278. ret.additionalInterfaceBounds[i] = TypePattern.read(s, context);
  1279. }
  1280. }
  1281. return ret;
  1282. }
  1283. public static TypePattern readTypePatternOldStyle(VersionedDataInputStream s, ISourceContext context) throws IOException {
  1284. int len = s.readShort();
  1285. NamePattern[] namePatterns = new NamePattern[len];
  1286. for (int i = 0; i < len; i++) {
  1287. namePatterns[i] = NamePattern.read(s);
  1288. }
  1289. boolean includeSubtypes = s.readBoolean();
  1290. int dim = s.readInt();
  1291. WildTypePattern ret = new WildTypePattern(namePatterns, includeSubtypes, dim, false, null);
  1292. ret.knownMatches = FileUtil.readStringArray(s);
  1293. ret.importedPrefixes = FileUtil.readStringArray(s);
  1294. ret.readLocation(context, s);
  1295. return ret;
  1296. }
  1297. @Override
  1298. public Object accept(PatternNodeVisitor visitor, Object data) {
  1299. return visitor.visit(this, data);
  1300. }
  1301. public boolean hasFailedResolution() {
  1302. return failedResolution;
  1303. }
  1304. }