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.

InterTypeDeclaration.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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 Common Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.ajdt.internal.compiler.ast;
  13. import java.lang.reflect.Modifier;
  14. import java.util.ArrayList;
  15. import java.util.List;
  16. import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
  17. import org.aspectj.ajdt.internal.compiler.lookup.EclipseTypeMunger;
  18. import org.aspectj.ajdt.internal.compiler.lookup.InterTypeScope;
  19. import org.aspectj.ajdt.internal.core.builder.EclipseSourceContext;
  20. import org.aspectj.bridge.context.CompilationAndWeavingContext;
  21. import org.aspectj.bridge.context.ContextToken;
  22. import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
  23. import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
  24. import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
  25. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
  26. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
  27. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
  28. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
  29. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope;
  30. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding;
  31. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
  32. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
  33. import org.aspectj.weaver.AjAttribute;
  34. import org.aspectj.weaver.ResolvedMember;
  35. import org.aspectj.weaver.ResolvedTypeMunger;
  36. import org.aspectj.weaver.Shadow;
  37. /**
  38. * Base type for all inter-type declarations including methods, fields and constructors.
  39. *
  40. * @author Jim Hugunin
  41. */
  42. public abstract class InterTypeDeclaration extends AjMethodDeclaration {
  43. protected TypeReference onType;
  44. protected ReferenceBinding onTypeBinding;
  45. protected ResolvedTypeMunger munger;
  46. protected int declaredModifiers;
  47. protected char[] declaredSelector;
  48. /**
  49. * If targetting a generic type and wanting to use its type variables, an ITD can use an alternative name for
  50. * them. This is a list of strings representing the alternative names - the position in the list is used to
  51. * match it to the real type variable in the target generic type.
  52. */
  53. protected List typeVariableAliases;
  54. /**
  55. * When set to true, the scope hierarchy for the field/method declaration has been correctly modified to
  56. * include an intertypescope which resolves things relative to the targetted type.
  57. */
  58. private boolean scopeSetup = false;
  59. // XXXAJ5 - When the compiler is changed, these will exist somewhere in it...
  60. private final static short ACC_ANNOTATION = 0x2000;
  61. private final static short ACC_ENUM = 0x4000;
  62. public InterTypeDeclaration(CompilationResult result, TypeReference onType) {
  63. super(result);
  64. setOnType(onType);
  65. modifiers = AccPublic | AccStatic;
  66. }
  67. public void setOnType(TypeReference onType) {
  68. this.onType = onType;
  69. determineTypeVariableAliases();
  70. }
  71. public void setDeclaredModifiers(int modifiers) {
  72. this.declaredModifiers = modifiers;
  73. }
  74. public void setSelector(char[] selector) {
  75. declaredSelector = selector;
  76. this.selector = CharOperation.concat(selector, Integer.toHexString(sourceStart).toCharArray());
  77. this.selector = CharOperation.concat(getPrefix(),this.selector);
  78. }
  79. // return the selector prefix for this itd that is to be used before resolution replaces it with a "proper" name
  80. protected abstract char[] getPrefix();
  81. /**
  82. * Checks that the target for the ITD is not an annotation. If it is, an error message
  83. * is signaled. We return true if it is annotation so the caller knows to stop processing.
  84. * kind is 'constructor', 'field', 'method'
  85. */
  86. public boolean isTargetAnnotation(ClassScope classScope,String kind) {
  87. if ((onTypeBinding.getAccessFlags() & ACC_ANNOTATION)!=0) {
  88. classScope.problemReporter().signalError(sourceStart,sourceEnd,
  89. "can't make inter-type "+kind+" declarations on annotation types.");
  90. ignoreFurtherInvestigation = true;
  91. return true;
  92. }
  93. return false;
  94. }
  95. /**
  96. * Checks that the target for the ITD is not an enum. If it is, an error message
  97. * is signaled. We return true if it is enum so the caller knows to stop processing.
  98. */
  99. public boolean isTargetEnum(ClassScope classScope,String kind) {
  100. if ((onTypeBinding.getAccessFlags() & ACC_ENUM)!=0) {
  101. classScope.problemReporter().signalError(sourceStart,sourceEnd,
  102. "can't make inter-type "+kind+" declarations on enum types.");
  103. ignoreFurtherInvestigation = true;
  104. return true;
  105. }
  106. return false;
  107. }
  108. public void resolve(ClassScope upperScope) {
  109. if (ignoreFurtherInvestigation) return;
  110. if (!scopeSetup) {
  111. ClassScope newParent = new InterTypeScope(upperScope, onTypeBinding,typeVariableAliases);
  112. scope.parent = newParent;
  113. this.scope.isStatic = Modifier.isStatic(declaredModifiers);
  114. scopeSetup = true;
  115. }
  116. fixSuperCallsForInterfaceContext(upperScope);
  117. if (ignoreFurtherInvestigation) return;
  118. super.resolve((ClassScope)scope.parent);//newParent);
  119. fixSuperCallsInBody();
  120. }
  121. private void fixSuperCallsForInterfaceContext(ClassScope scope) {
  122. if (onTypeBinding.isInterface()) {
  123. ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.FIXING_SUPER_CALLS, selector);
  124. InterSuperFixerVisitor v =
  125. new InterSuperFixerVisitor(this,
  126. EclipseFactory.fromScopeLookupEnvironment(scope), scope);
  127. this.traverse(v, scope);
  128. CompilationAndWeavingContext.leavingPhase(tok);
  129. }
  130. }
  131. /**
  132. * Called from AspectDeclarations.buildInterTypeAndPerClause
  133. */
  134. public abstract EclipseTypeMunger build(ClassScope classScope);
  135. public void fixSuperCallsInBody() {
  136. ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.FIXING_SUPER_CALLS_IN_ITDS, selector);
  137. SuperFixerVisitor v = new SuperFixerVisitor(this, onTypeBinding);
  138. this.traverse(v, (ClassScope)null);
  139. munger.setSuperMethodsCalled(v.superMethodsCalled);
  140. CompilationAndWeavingContext.leavingPhase(tok);
  141. }
  142. protected void resolveOnType(ClassScope classScope) {
  143. checkSpec();
  144. // If they did supply a parameterized single type reference, we need to do
  145. // some extra checks...
  146. if (onType instanceof ParameterizedSingleTypeReference) {
  147. resolveTypeParametersForITDOnGenericType(classScope);
  148. } else {
  149. onTypeBinding = (ReferenceBinding)onType.getTypeBindingPublic(classScope);
  150. if (!onTypeBinding.isValidBinding()) {
  151. classScope.problemReporter().invalidType(onType, onTypeBinding);
  152. ignoreFurtherInvestigation = true;
  153. }
  154. }
  155. }
  156. /**
  157. * Transform the parameterized type binding (e.g. SomeType<A,B,C>) to a
  158. * real type (e.g. SomeType). The only kind of parameterization allowed
  159. * is with type variables and those are references to type variables on
  160. * the target type. Once we have worked out the base generic type intended
  161. * then we do lots of checks to verify the declaration was well formed.
  162. */
  163. private void resolveTypeParametersForITDOnGenericType(ClassScope classScope) {
  164. // Collapse the parameterized reference to its generic type
  165. ParameterizedSingleTypeReference pref = (ParameterizedSingleTypeReference) onType;
  166. long pos = (((long)pref.sourceStart) << 32) | pref.sourceEnd;
  167. onType = new SingleTypeReference(pref.token,pos);
  168. onTypeBinding = (ReferenceBinding)onType.getTypeBindingPublic(classScope);
  169. if (!onTypeBinding.isValidBinding()) {
  170. classScope.problemReporter().invalidType(onType, onTypeBinding);
  171. ignoreFurtherInvestigation = true;
  172. }
  173. int aliasCount = (typeVariableAliases==null?0:typeVariableAliases.size());
  174. // Cannot specify a parameterized target type for the ITD if the target
  175. // type is not generic.
  176. if (aliasCount!=0 && !onTypeBinding.isGenericType()) {
  177. scope.problemReporter().signalError(sourceStart,sourceEnd,
  178. "Type parameters can not be specified in the ITD target type - the target type "+onTypeBinding.debugName()+" is not generic.");
  179. ignoreFurtherInvestigation = true;
  180. return;
  181. }
  182. // Check they have supplied the right number of type parameters on the ITD target type
  183. if (aliasCount>0) {
  184. if (onTypeBinding.typeVariables().length != aliasCount) { // typeParameters.length) { phantom contains the fake ones from the ontype, typeparameters will also include extra things if it is a generic method
  185. scope.problemReporter().signalError(sourceStart, sourceEnd,
  186. "Incorrect number of type parameters supplied. The generic type "+onTypeBinding.debugName()+" has "+
  187. onTypeBinding.typeVariables().length+" type parameters, not "+aliasCount+".");
  188. ignoreFurtherInvestigation = true;
  189. return;
  190. }
  191. }
  192. // check if they used stupid names for type variables
  193. if (aliasCount>0) {
  194. for (int i = 0; i < aliasCount; i++) {
  195. String array_element = (String)typeVariableAliases.get(i);
  196. SingleTypeReference str = new SingleTypeReference(array_element.toCharArray(),0);
  197. TypeBinding tb = str.getTypeBindingPublic(classScope);
  198. if (tb!=null && !(tb instanceof ProblemReferenceBinding)) {
  199. scope.problemReporter().signalError(sourceStart,sourceEnd,
  200. "Intertype declarations can only be made on the generic type, not on a parameterized type. The name '"+
  201. array_element+"' cannot be used as a type parameter, since it refers to a real type.");
  202. ignoreFurtherInvestigation = true;
  203. return;
  204. }
  205. }
  206. }
  207. // TypeVariableBinding[] tVarsInGenericType = onTypeBinding.typeVariables();
  208. // typeVariableAliases = new ArrayList(); /* Name>GenericTypeVariablePosition */ // FIXME ASC DONT THINK WE NEED TO BUILD IT HERE AS WELL...
  209. // TypeReference[] targs = pref.typeArguments;
  210. // if (targs!=null) {
  211. // for (int i = 0; i < targs.length; i++) {
  212. // TypeReference tref = targs[i];
  213. // typeVariableAliases.add(CharOperation.toString(tref.getTypeName()));//tVarsInGenericType[i]);
  214. // }
  215. // }
  216. }
  217. protected void checkSpec() {
  218. if (Modifier.isProtected(declaredModifiers)) {
  219. scope.problemReporter().signalError(sourceStart, sourceEnd,
  220. "protected inter-type declarations are not allowed");
  221. ignoreFurtherInvestigation = true;
  222. }
  223. }
  224. protected List makeEffectiveSignatureAttribute(
  225. ResolvedMember sig,
  226. Shadow.Kind kind,
  227. boolean weaveBody)
  228. {
  229. List l = new ArrayList(1);
  230. l.add(new EclipseAttributeAdapter(
  231. new AjAttribute.EffectiveSignatureAttribute(sig, kind, weaveBody)));
  232. return l;
  233. }
  234. protected void setMunger(ResolvedTypeMunger munger) {
  235. munger.getSignature().setPosition(sourceStart, sourceEnd);
  236. munger.getSignature().setSourceContext(new EclipseSourceContext(compilationResult));
  237. this.munger = munger;
  238. }
  239. protected int generateInfoAttributes(ClassFile classFile) {
  240. List l;
  241. Shadow.Kind kind = getShadowKindForBody();
  242. if (kind != null) {
  243. l = makeEffectiveSignatureAttribute(munger.getSignature(), kind, true);
  244. } else {
  245. l = new ArrayList(0);
  246. }
  247. addDeclarationStartLineAttribute(l,classFile);
  248. return classFile.generateMethodInfoAttribute(binding, false, l);
  249. }
  250. protected abstract Shadow.Kind getShadowKindForBody();
  251. public ResolvedMember getSignature() {
  252. if (munger==null) return null; // Can be null in an erroneous program I think
  253. return munger.getSignature();
  254. }
  255. public char[] getDeclaredSelector() {
  256. return declaredSelector;
  257. }
  258. public TypeReference getOnType() {
  259. return onType;
  260. }
  261. /**
  262. * Create the list of aliases based on what was supplied as parameters for the ontype.
  263. * For example, if the declaration is 'List<N> SomeType<N>.foo' then the alias list
  264. * will simply contain 'N' and 'N' will mean 'the first type variable declared for
  265. * type SomeType'
  266. */
  267. public void determineTypeVariableAliases() {
  268. if (onType!=null && onType instanceof ParameterizedSingleTypeReference) {
  269. ParameterizedSingleTypeReference paramRef = (ParameterizedSingleTypeReference) onType;
  270. TypeReference[] rb = paramRef.typeArguments;
  271. typeVariableAliases = new ArrayList();
  272. for (int i = 0; i < rb.length; i++) {
  273. typeVariableAliases.add(CharOperation.toString(rb[i].getTypeName()));
  274. }
  275. }
  276. }
  277. /**
  278. * Called just before the compiler is going to start resolving elements of a declaration, this method
  279. * adds an intertypescope between the methodscope and classscope so that elements of the type targetted
  280. * by the ITD can be resolved. For example, if type variables are referred to in the ontype for the ITD,
  281. * they have to be resolved against the ontype, not the aspect containing the ITD.
  282. */
  283. public void ensureScopeSetup() {
  284. if (scopeSetup) return; // don't do it agai
  285. MethodScope scope = this.scope;
  286. TypeReference ot = onType;
  287. // Work out the real base type
  288. if (ot instanceof ParameterizedSingleTypeReference) {
  289. ParameterizedSingleTypeReference pref = (ParameterizedSingleTypeReference) ot;
  290. long pos = (((long)pref.sourceStart) << 32) | pref.sourceEnd;
  291. ot = new SingleTypeReference(pref.token,pos);
  292. }
  293. // resolve it
  294. ReferenceBinding rb = (ReferenceBinding)ot.getTypeBindingPublic(scope.parent);
  295. // if resolution failed, give up - someone else is going to report an error
  296. if (rb instanceof ProblemReferenceBinding) return;
  297. ClassScope newParent = new InterTypeScope(scope.parent, rb, typeVariableAliases);
  298. // FIXME asc verify the choice of lines here...
  299. // Two versions of this next line.
  300. // First one tricks the JDT variable processing code so that it won't complain if
  301. // you refer to a type variable from a static ITD - it *is* a problem and it *will* be caught, but later and
  302. // by the AJDT code so we can put out a much nicer message.
  303. scope.isStatic = (typeVariableAliases!=null?false:Modifier.isStatic(declaredModifiers));
  304. // this is the original version in case tricking the JDT causes grief (if you reinstate this variant, you
  305. // will need to change the expected messages output for some of the generic ITD tests)
  306. // scope.isStatic = Modifier.isStatic(declaredModifiers);
  307. scope.parent = newParent;
  308. scopeSetup = true;
  309. }
  310. }