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.

TypeVariable.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /* *******************************************************************
  2. * Copyright (c) 2005 Contributors.
  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://eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * Adrian Colyer Initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver;
  13. import java.io.DataOutputStream;
  14. import java.io.IOException;
  15. import java.util.HashSet;
  16. import java.util.Set;
  17. /**
  18. * Represents a type variable with bounds
  19. */
  20. public class TypeVariable {
  21. /**
  22. * whether or not the bounds of this type variable have been
  23. * resolved
  24. */
  25. private boolean isResolved = false;
  26. private boolean beingResolved = false;
  27. /**
  28. * the name of the type variable as recorded in the generic signature
  29. */
  30. private String name;
  31. private int rank;
  32. // It would be nice to push this field onto the TypeVariableDeclaringElement
  33. // interface (a getKind()) but at the moment we don't always guarantee
  34. // to set the declaring element (eclipse seems to utilise the knowledge of
  35. // what declared the type variable, but we dont yet...)
  36. /**
  37. * What kind of element declared this type variable?
  38. */
  39. private int declaringElementKind = UNKNOWN;
  40. public static final int UNKNOWN = -1;
  41. public static final int METHOD = 1;
  42. public static final int TYPE = 2;
  43. private TypeVariableDeclaringElement declaringElement;
  44. /**
  45. * the upper bound of the type variable (default to Object).
  46. * From the extends clause, eg. T extends Number.
  47. */
  48. private UnresolvedType upperBound = UnresolvedType.OBJECT;
  49. /**
  50. * any additional upper (interface) bounds.
  51. * from the extends clause, e.g. T extends Number & Comparable
  52. */
  53. private UnresolvedType[] additionalInterfaceBounds = new UnresolvedType[0];
  54. /**
  55. * any lower bound.
  56. * from the super clause, eg T super Foo
  57. */
  58. private UnresolvedType lowerBound = null;
  59. public TypeVariable(String aName) {
  60. this.name = aName;
  61. }
  62. public TypeVariable(String aName, UnresolvedType anUpperBound) {
  63. this(aName);
  64. this.upperBound = anUpperBound;
  65. }
  66. public TypeVariable(String aName, UnresolvedType anUpperBound,
  67. UnresolvedType[] someAdditionalInterfaceBounds) {
  68. this(aName,anUpperBound);
  69. this.additionalInterfaceBounds = someAdditionalInterfaceBounds;
  70. }
  71. public TypeVariable(String aName, UnresolvedType anUpperBound,
  72. UnresolvedType[] someAdditionalInterfaceBounds, UnresolvedType aLowerBound) {
  73. this(aName,anUpperBound,someAdditionalInterfaceBounds);
  74. this.lowerBound = aLowerBound;
  75. }
  76. public UnresolvedType getUpperBound() {
  77. return upperBound;
  78. }
  79. public UnresolvedType[] getAdditionalInterfaceBounds() {
  80. return additionalInterfaceBounds;
  81. }
  82. public UnresolvedType getLowerBound() {
  83. return lowerBound;
  84. }
  85. public String getName() {
  86. return name;
  87. }
  88. /**
  89. * resolve all the bounds of this type variable
  90. */
  91. public TypeVariable resolve(World inSomeWorld) {
  92. if (beingResolved) { return this; } // avoid spiral of death
  93. beingResolved = true;
  94. if (isResolved) return this;
  95. TypeVariable resolvedTVar = null;
  96. if (declaringElement != null) {
  97. // resolve by finding the real type var that we refer to...
  98. if (declaringElementKind == TYPE) {
  99. UnresolvedType declaring = (UnresolvedType) declaringElement;
  100. ReferenceType rd = (ReferenceType) declaring.resolve(inSomeWorld);
  101. TypeVariable[] tVars = rd.getTypeVariables();
  102. for (int i = 0; i < tVars.length; i++) {
  103. if (tVars[i].getName().equals(getName())) {
  104. resolvedTVar = tVars[i];
  105. break;
  106. }
  107. }
  108. } else {
  109. // look for type variable on method...
  110. ResolvedMember declaring = (ResolvedMember) declaringElement;
  111. TypeVariable[] tvrts = declaring.getTypeVariables();
  112. for (int i = 0; i < tvrts.length; i++) {
  113. if (tvrts[i].getName().equals(getName())) resolvedTVar = tvrts[i];
  114. // if (tvrts[i].isTypeVariableReference()) {
  115. // TypeVariableReferenceType tvrt = (TypeVariableReferenceType) tvrts[i].resolve(inSomeWorld);
  116. // TypeVariable tv = tvrt.getTypeVariable();
  117. // if (tv.getName().equals(getName())) resolvedTVar = tv;
  118. // }
  119. }
  120. }
  121. if (resolvedTVar == null) {
  122. // well, this is bad... we didn't find the type variable on the member
  123. // could be a separate compilation issue...
  124. // should issue message, this is a workaround to get us going...
  125. resolvedTVar = this;
  126. }
  127. } else {
  128. resolvedTVar = this;
  129. }
  130. upperBound = resolvedTVar.upperBound;
  131. lowerBound = resolvedTVar.lowerBound;
  132. additionalInterfaceBounds = resolvedTVar.additionalInterfaceBounds;
  133. upperBound = upperBound.resolve(inSomeWorld);
  134. if (lowerBound != null) lowerBound = lowerBound.resolve(inSomeWorld);
  135. if (additionalInterfaceBounds!=null) {
  136. for (int i = 0; i < additionalInterfaceBounds.length; i++) {
  137. additionalInterfaceBounds[i] = additionalInterfaceBounds[i].resolve(inSomeWorld);
  138. }
  139. }
  140. isResolved = true;
  141. beingResolved = false;
  142. return this;
  143. }
  144. /**
  145. * answer true if the given type satisfies all of the bound constraints of this
  146. * type variable.
  147. * If type variable has not been resolved then throws IllegalStateException
  148. */
  149. public boolean canBeBoundTo(ResolvedType aCandidateType) {
  150. if (!isResolved) throw new IllegalStateException("Can't answer binding questions prior to resolving");
  151. if (aCandidateType.isTypeVariableReference()) {
  152. return matchingBounds((TypeVariableReferenceType)aCandidateType);
  153. }
  154. // wildcard can accept any binding
  155. if (aCandidateType.isGenericWildcard()) { // AMC - need a more robust test!
  156. return true;
  157. }
  158. // otherwise can be bound iff...
  159. // aCandidateType is a subtype of upperBound
  160. if (!isASubtypeOf(upperBound,aCandidateType)) {
  161. return false;
  162. }
  163. // aCandidateType is a subtype of all additionalInterfaceBounds
  164. for (int i = 0; i < additionalInterfaceBounds.length; i++) {
  165. if (!isASubtypeOf(additionalInterfaceBounds[i], aCandidateType)) {
  166. return false;
  167. }
  168. }
  169. // lowerBound is a subtype of aCandidateType
  170. if ((lowerBound != null) && (!isASubtypeOf(aCandidateType,lowerBound))) {
  171. return false;
  172. }
  173. return true;
  174. }
  175. // can match any type in the range of the type variable...
  176. // XXX what about interfaces?
  177. private boolean matchingBounds(TypeVariableReferenceType tvrt) {
  178. if (tvrt.getUpperBound() != getUpperBound()) return false;
  179. if (tvrt.hasLowerBound() != (getLowerBound() != null)) return false;
  180. if (tvrt.hasLowerBound() && tvrt.getLowerBound() != getLowerBound()) return false;
  181. // either we both have bounds, or neither of us have bounds
  182. if ((tvrt.additionalInterfaceBounds != null) != (additionalInterfaceBounds != null)) return false;
  183. if (additionalInterfaceBounds != null) {
  184. // we both have bounds, compare
  185. if (tvrt.additionalInterfaceBounds.length != additionalInterfaceBounds.length) return false;
  186. Set aAndNotB = new HashSet();
  187. Set bAndNotA = new HashSet();
  188. for (int i = 0; i < additionalInterfaceBounds.length; i++) {
  189. aAndNotB.add(additionalInterfaceBounds[i]);
  190. }
  191. for (int i = 0; i < tvrt.additionalInterfaceBounds.length; i++) {
  192. bAndNotA.add(tvrt.additionalInterfaceBounds[i]);
  193. }
  194. for (int i = 0; i < additionalInterfaceBounds.length; i++) {
  195. bAndNotA.remove(additionalInterfaceBounds[i]);
  196. }
  197. for (int i = 0; i < tvrt.additionalInterfaceBounds.length; i++) {
  198. aAndNotB.remove(tvrt.additionalInterfaceBounds[i]);
  199. }
  200. if (! (aAndNotB.isEmpty() && bAndNotA.isEmpty()) ) return false;
  201. }
  202. return true;
  203. }
  204. private boolean isASubtypeOf(UnresolvedType candidateSuperType, UnresolvedType candidateSubType) {
  205. ResolvedType superType = (ResolvedType) candidateSuperType;
  206. ResolvedType subType = (ResolvedType) candidateSubType;
  207. return superType.isAssignableFrom(subType);
  208. }
  209. // only used when resolving
  210. public void setUpperBound(UnresolvedType aTypeX) {
  211. this.upperBound = aTypeX;
  212. }
  213. // only used when resolving
  214. public void setLowerBound(UnresolvedType aTypeX) {
  215. this.lowerBound = aTypeX;
  216. }
  217. // only used when resolving
  218. public void setAdditionalInterfaceBounds(UnresolvedType[] someTypeXs) {
  219. this.additionalInterfaceBounds = someTypeXs;
  220. }
  221. public String getDisplayName() {
  222. StringBuffer ret = new StringBuffer();
  223. ret.append(name);
  224. if (!upperBound.getName().equals("java.lang.Object")) {
  225. ret.append(" extends ");
  226. ret.append(upperBound.getName());
  227. if (additionalInterfaceBounds != null) {
  228. for (int i = 0; i < additionalInterfaceBounds.length; i++) {
  229. ret.append(" & ");
  230. ret.append(additionalInterfaceBounds[i].getName());
  231. }
  232. }
  233. }
  234. if (lowerBound != null) {
  235. ret.append(" super ");
  236. ret.append(lowerBound.getName());
  237. }
  238. return ret.toString();
  239. }
  240. // good enough approximation
  241. public String toString() {
  242. return "TypeVar " + getDisplayName();
  243. }
  244. /**
  245. * Return *full* signature for insertion in signature attribute, e.g. "T extends Number" would return "T:Ljava/lang/Number;"
  246. */
  247. public String getSignature() {
  248. StringBuffer sb = new StringBuffer();
  249. sb.append(name);
  250. sb.append(":");
  251. sb.append(upperBound.getSignature());
  252. if (additionalInterfaceBounds!=null) {
  253. for (int i = 0; i < additionalInterfaceBounds.length; i++) {
  254. UnresolvedType iBound = additionalInterfaceBounds[i];
  255. sb.append(iBound.getSignature());
  256. }
  257. }
  258. return sb.toString();
  259. }
  260. public void setRank(int rank) {
  261. this.rank=rank;
  262. }
  263. public int getRank() {
  264. return rank;
  265. }
  266. public void setDeclaringElement(TypeVariableDeclaringElement element) {
  267. this.declaringElement = element;
  268. if (element instanceof UnresolvedType) {
  269. this.declaringElementKind = TYPE;
  270. } else {
  271. this.declaringElementKind = METHOD;
  272. }
  273. }
  274. public TypeVariableDeclaringElement getDeclaringElement() {
  275. return declaringElement;
  276. }
  277. public void setDeclaringElementKind(int kind) {
  278. this.declaringElementKind = kind;
  279. }
  280. public int getDeclaringElementKind() {
  281. // if (declaringElementKind==UNKNOWN) throw new RuntimeException("Dont know declarer of this tvar : "+this);
  282. return declaringElementKind;
  283. }
  284. public void write(DataOutputStream s) throws IOException {
  285. // name, upperbound, additionalInterfaceBounds, lowerbound
  286. s.writeUTF(name);
  287. upperBound.write(s);
  288. if (additionalInterfaceBounds==null || additionalInterfaceBounds.length==0) {
  289. s.writeInt(0);
  290. } else {
  291. s.writeInt(additionalInterfaceBounds.length);
  292. for (int i = 0; i < additionalInterfaceBounds.length; i++) {
  293. UnresolvedType ibound = additionalInterfaceBounds[i];
  294. ibound.write(s);
  295. }
  296. }
  297. }
  298. public static TypeVariable read(VersionedDataInputStream s) throws IOException {
  299. //if (s.getMajorVersion()>=AjAttribute.WeaverVersionInfo.WEAVER_VERSION_MAJOR_AJ150) {
  300. String name = s.readUTF();
  301. UnresolvedType ubound = UnresolvedType.read(s);
  302. int iboundcount = s.readInt();
  303. UnresolvedType[] ibounds = null;
  304. if (iboundcount>0) {
  305. ibounds = new UnresolvedType[iboundcount];
  306. for (int i=0; i<iboundcount; i++) {
  307. ibounds[i] = UnresolvedType.read(s);
  308. }
  309. }
  310. TypeVariable newVariable = new TypeVariable(name,ubound,ibounds);
  311. return newVariable;
  312. }
  313. }