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.

BoundedReferenceType.java 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /* *******************************************************************
  2. * Copyright (c) 2010 Contributors.
  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. package org.aspectj.weaver;
  10. import java.util.Map;
  11. /**
  12. * A BoundedReferenceType is the result of a generics wildcard expression ? extends String, ? super Foo etc..
  13. *
  14. * The "signature" for a bounded reference type follows the generic signature specification in section 4.4 of JVM spec: *,+,- plus
  15. * signature strings.
  16. *
  17. * The bound may be a type variable (e.g. ? super T)
  18. *
  19. * @author Adrian Colyer
  20. * @author Andy Clement
  21. */
  22. public class BoundedReferenceType extends ReferenceType {
  23. // possible kinds of BoundedReferenceType
  24. public static final int UNBOUND = 0;
  25. public static final int EXTENDS = 1;
  26. public static final int SUPER = 2;
  27. public int kind;
  28. private ResolvedType lowerBound;
  29. private ResolvedType upperBound;
  30. protected ReferenceType[] additionalInterfaceBounds = ReferenceType.EMPTY_ARRAY;
  31. public BoundedReferenceType(ReferenceType aBound, boolean isExtends, World world) {
  32. super((isExtends ? "+" : "-") + aBound.signature, aBound.signatureErasure, world);
  33. if (isExtends) {
  34. this.kind = EXTENDS;
  35. } else {
  36. this.kind = SUPER;
  37. }
  38. if (isExtends) {
  39. upperBound = aBound;
  40. } else {
  41. lowerBound = aBound;
  42. upperBound = world.resolve(UnresolvedType.OBJECT);
  43. }
  44. setDelegate(new BoundedReferenceTypeDelegate((ReferenceType) getUpperBound()));
  45. }
  46. public BoundedReferenceType(ReferenceType aBound, boolean isExtends, World world, ReferenceType[] additionalInterfaces) {
  47. this(aBound, isExtends, world);
  48. this.additionalInterfaceBounds = additionalInterfaces;
  49. }
  50. /**
  51. * only for use when resolving GenericsWildcardTypeX or a TypeVariableReferenceType
  52. */
  53. protected BoundedReferenceType(String signature, String erasedSignature, World world) {
  54. super(signature, erasedSignature, world);
  55. if (signature.equals("*")) {
  56. // pure wildcard
  57. this.kind = UNBOUND;
  58. upperBound = world.resolve(UnresolvedType.OBJECT);
  59. } else {
  60. upperBound = world.resolve(forSignature(erasedSignature));
  61. }
  62. setDelegate(new BoundedReferenceTypeDelegate((ReferenceType) upperBound));
  63. }
  64. /**
  65. * Constructs the BoundedReferenceType representing an unbounded wildcard '?'. In this situation the signature is '*' and the
  66. * erased signature is Ljava/lang/Object;
  67. */
  68. public BoundedReferenceType(World world) {
  69. super("*", "Ljava/lang/Object;", world);
  70. this.kind = UNBOUND;
  71. upperBound = world.resolve(UnresolvedType.OBJECT);
  72. setDelegate(new BoundedReferenceTypeDelegate((ReferenceType) upperBound));
  73. }
  74. public UnresolvedType getUpperBound() {
  75. return upperBound;
  76. }
  77. public UnresolvedType getLowerBound() {
  78. return lowerBound;
  79. }
  80. public ReferenceType[] getAdditionalBounds() {
  81. return additionalInterfaceBounds;
  82. }
  83. @Override
  84. public UnresolvedType parameterize(Map<String, UnresolvedType> typeBindings) {
  85. if (this.kind == UNBOUND) {
  86. return this;
  87. }
  88. ReferenceType[] parameterizedAdditionalInterfaces = new ReferenceType[additionalInterfaceBounds == null ? 0
  89. : additionalInterfaceBounds.length];
  90. for (int i = 0; i < parameterizedAdditionalInterfaces.length; i++) {
  91. parameterizedAdditionalInterfaces[i] = (ReferenceType) additionalInterfaceBounds[i].parameterize(typeBindings);
  92. }
  93. if (this.kind == EXTENDS) {
  94. UnresolvedType parameterizedUpperBound = getUpperBound().parameterize(typeBindings);
  95. if (!(parameterizedUpperBound instanceof ReferenceType)) {
  96. throw new IllegalStateException("DEBUG551732: Unexpected problem processing bounds. Parameterizing "+getUpperBound()+" produced "+parameterizedUpperBound+
  97. " (Type: "+parameterizedUpperBound==null?"null":parameterizedUpperBound.getClass().getName()+") (typeBindings="+typeBindings+")");
  98. }
  99. return new BoundedReferenceType((ReferenceType) parameterizedUpperBound, true, world,
  100. parameterizedAdditionalInterfaces);
  101. } else {
  102. // (this.kind == SUPER)
  103. UnresolvedType parameterizedLowerBound = getLowerBound().parameterize(typeBindings);
  104. if (!(parameterizedLowerBound instanceof ReferenceType)) {
  105. throw new IllegalStateException("PR543023: Unexpectedly found a non reference type: "+
  106. parameterizedLowerBound.getClass().getName()+" with signature "+parameterizedLowerBound.getSignature());
  107. }
  108. return new BoundedReferenceType((ReferenceType)parameterizedLowerBound , false, world,
  109. parameterizedAdditionalInterfaces);
  110. }
  111. }
  112. @Override
  113. public String getSignatureForAttribute() {
  114. StringBuilder ret = new StringBuilder();
  115. if (kind==SUPER){
  116. ret.append("-");
  117. ret.append(lowerBound.getSignatureForAttribute());
  118. for (ReferenceType additionalInterfaceBound : additionalInterfaceBounds) {
  119. ret.append(additionalInterfaceBound.getSignatureForAttribute());
  120. }
  121. } else if (kind==EXTENDS) {
  122. ret.append("+");
  123. ret.append(upperBound.getSignatureForAttribute());
  124. for (ReferenceType additionalInterfaceBound : additionalInterfaceBounds) {
  125. ret.append(additionalInterfaceBound.getSignatureForAttribute());
  126. }
  127. } else if (kind==UNBOUND) {
  128. ret.append("*");
  129. }
  130. return ret.toString();
  131. }
  132. public boolean hasLowerBound() {
  133. return lowerBound != null;
  134. }
  135. public boolean isExtends() {
  136. return this.kind == EXTENDS;
  137. }
  138. public boolean isSuper() {
  139. return this.kind == SUPER;
  140. }
  141. public boolean isUnbound() {
  142. return this.kind == UNBOUND;
  143. }
  144. public boolean alwaysMatches(ResolvedType aCandidateType) {
  145. if (isExtends()) {
  146. // aCandidateType must be a subtype of upperBound
  147. return ((ReferenceType) getUpperBound()).isAssignableFrom(aCandidateType);
  148. } else if (isSuper()) {
  149. // aCandidateType must be a supertype of lowerBound
  150. return aCandidateType.isAssignableFrom((ReferenceType) getLowerBound());
  151. } else {
  152. return true; // straight '?'
  153. }
  154. }
  155. // this "maybe matches" that
  156. public boolean canBeCoercedTo(ResolvedType aCandidateType) {
  157. if (alwaysMatches(aCandidateType)) {
  158. return true;
  159. }
  160. if (aCandidateType.isGenericWildcard()) {
  161. BoundedReferenceType boundedRT = (BoundedReferenceType) aCandidateType;
  162. ResolvedType myUpperBound = (ResolvedType) getUpperBound();
  163. ResolvedType myLowerBound = (ResolvedType) getLowerBound();
  164. if (isExtends()) {
  165. if (boundedRT.isExtends()) {
  166. return myUpperBound.isAssignableFrom((ResolvedType) boundedRT.getUpperBound());
  167. } else if (boundedRT.isSuper()) {
  168. return myUpperBound == boundedRT.getLowerBound();
  169. } else {
  170. return true; // it's '?'
  171. }
  172. } else if (isSuper()) {
  173. if (boundedRT.isSuper()) {
  174. return ((ResolvedType) boundedRT.getLowerBound()).isAssignableFrom(myLowerBound);
  175. } else if (boundedRT.isExtends()) {
  176. return myLowerBound == boundedRT.getUpperBound();
  177. } else {
  178. return true;
  179. }
  180. } else {
  181. return true;
  182. }
  183. } else {
  184. return false;
  185. }
  186. }
  187. @Override
  188. public String getSimpleName() {
  189. if (!isExtends() && !isSuper()) {
  190. return "?";
  191. }
  192. if (isExtends()) {
  193. return ("? extends " + getUpperBound().getSimpleName());
  194. } else {
  195. return ("? super " + getLowerBound().getSimpleName());
  196. }
  197. }
  198. // override to include additional interface bounds...
  199. @Override
  200. public ResolvedType[] getDeclaredInterfaces() {
  201. ResolvedType[] interfaces = super.getDeclaredInterfaces();
  202. if (additionalInterfaceBounds.length > 0) {
  203. ResolvedType[] allInterfaces = new ResolvedType[interfaces.length + additionalInterfaceBounds.length];
  204. System.arraycopy(interfaces, 0, allInterfaces, 0, interfaces.length);
  205. System.arraycopy(additionalInterfaceBounds, 0, allInterfaces, interfaces.length, additionalInterfaceBounds.length);
  206. return allInterfaces;
  207. } else {
  208. return interfaces;
  209. }
  210. }
  211. @Override
  212. public boolean isGenericWildcard() {
  213. return true;
  214. }
  215. }