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 19KB

21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v 2.0
  6. * which accompanies this distribution and is available at
  7. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.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.IAttribute;
  26. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
  27. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
  28. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
  29. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
  30. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
  31. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
  32. import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
  33. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
  34. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodScope;
  35. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
  36. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding;
  37. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding;
  38. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
  39. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
  40. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
  41. import org.aspectj.weaver.AjAttribute;
  42. import org.aspectj.weaver.ResolvedMember;
  43. import org.aspectj.weaver.ResolvedTypeMunger;
  44. import org.aspectj.weaver.Shadow;
  45. /**
  46. * Base type for all inter-type declarations including methods, fields and constructors.
  47. *
  48. * @author Jim Hugunin
  49. */
  50. public abstract class InterTypeDeclaration extends AjMethodDeclaration {
  51. protected TypeReference onType;
  52. protected ReferenceBinding onTypeBinding;
  53. protected ResolvedTypeMunger munger;
  54. public int declaredModifiers; // so others can see (these differ from the modifiers in the superclass)
  55. protected char[] declaredSelector;
  56. /**
  57. * If targetting a generic type and wanting to use its type variables, an ITD can use an alternative name for
  58. * them. This is a list of strings representing the alternative names - the position in the list is used to
  59. * match it to the real type variable in the target generic type.
  60. */
  61. protected List<String> typeVariableAliases;
  62. protected InterTypeScope interTypeScope;
  63. /**
  64. * When set to true, the scope hierarchy for the field/method declaration has been correctly modified to
  65. * include an intertypescope which resolves things relative to the targetted type.
  66. */
  67. private boolean scopeSetup = false;
  68. // XXXAJ5 - When the compiler is changed, these will exist somewhere in it...
  69. private final static short ACC_ANNOTATION = 0x2000;
  70. private final static short ACC_ENUM = 0x4000;
  71. public InterTypeDeclaration(CompilationResult result, TypeReference onType) {
  72. super(result);
  73. setOnType(onType);
  74. modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic;
  75. }
  76. public void setOnType(TypeReference onType) {
  77. this.onType = onType;
  78. determineTypeVariableAliases();
  79. }
  80. public void setDeclaredModifiers(int modifiers) {
  81. this.declaredModifiers = modifiers;
  82. }
  83. public void setSelector(char[] selector) {
  84. declaredSelector = selector;
  85. this.selector = CharOperation.concat(selector, Integer.toHexString(sourceStart).toCharArray());
  86. this.selector = CharOperation.concat(getPrefix(),this.selector);
  87. }
  88. // return the selector prefix for this itd that is to be used before resolution replaces it with a "proper" name
  89. protected abstract char[] getPrefix();
  90. public void addAtAspectJAnnotations() {
  91. if (munger == null) return;
  92. Annotation ann = AtAspectJAnnotationFactory.createITDAnnotation(
  93. munger.getSignature().getDeclaringType().getName().toCharArray(),
  94. declaredModifiers,declaredSelector,declarationSourceStart);
  95. AtAspectJAnnotationFactory.addAnnotation(this,ann,this.scope);
  96. }
  97. /**
  98. * Checks that the target for the ITD is not an annotation. If it is, an error message
  99. * is signaled. We return true if it is annotation so the caller knows to stop processing.
  100. * kind is 'constructor', 'field', 'method'
  101. */
  102. public boolean isTargetAnnotation(ClassScope classScope,String kind) {
  103. if ((onTypeBinding.getAccessFlags() & ACC_ANNOTATION)!=0) {
  104. classScope.problemReporter().signalError(sourceStart,sourceEnd,
  105. "can't make inter-type "+kind+" declarations on annotation types.");
  106. ignoreFurtherInvestigation = true;
  107. return true;
  108. }
  109. return false;
  110. }
  111. /**
  112. * Checks that the target for the ITD is not an enum. If it is, an error message
  113. * is signaled. We return true if it is enum so the caller knows to stop processing.
  114. */
  115. public boolean isTargetEnum(ClassScope classScope,String kind) {
  116. if ((onTypeBinding.getAccessFlags() & ACC_ENUM)!=0) {
  117. classScope.problemReporter().signalError(sourceStart,sourceEnd,
  118. "can't make inter-type "+kind+" declarations on enum types.");
  119. ignoreFurtherInvestigation = true;
  120. return true;
  121. }
  122. return false;
  123. }
  124. @Override
  125. public void resolve(ClassScope upperScope) {
  126. if (ignoreFurtherInvestigation) return;
  127. if (!scopeSetup) {
  128. interTypeScope = new InterTypeScope(upperScope, onTypeBinding,typeVariableAliases);
  129. // Use setter in order to also update member 'compilationUnitScope'
  130. scope.setParent(interTypeScope);
  131. this.scope.isStatic = Modifier.isStatic(declaredModifiers);
  132. scopeSetup = true;
  133. }
  134. fixSuperCallsForInterfaceContext(upperScope);
  135. if (ignoreFurtherInvestigation) return;
  136. super.resolve((ClassScope)scope.parent);//newParent);
  137. fixSuperCallsInBody();
  138. }
  139. private void fixSuperCallsForInterfaceContext(ClassScope scope) {
  140. if (onTypeBinding.isInterface()) {
  141. ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.FIXING_SUPER_CALLS, selector);
  142. InterSuperFixerVisitor v =
  143. new InterSuperFixerVisitor(this,
  144. EclipseFactory.fromScopeLookupEnvironment(scope), scope);
  145. this.traverse(v, scope);
  146. CompilationAndWeavingContext.leavingPhase(tok);
  147. }
  148. }
  149. /**
  150. * Called from AspectDeclarations.buildInterTypeAndPerClause
  151. */
  152. public abstract EclipseTypeMunger build(ClassScope classScope);
  153. public void fixSuperCallsInBody() {
  154. ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.FIXING_SUPER_CALLS_IN_ITDS, selector);
  155. SuperFixerVisitor v = new SuperFixerVisitor(this, onTypeBinding);
  156. this.traverse(v, (ClassScope)null);
  157. munger.setSuperMethodsCalled(v.superMethodsCalled);
  158. CompilationAndWeavingContext.leavingPhase(tok);
  159. }
  160. protected void resolveOnType(ClassScope classScope) {
  161. checkSpec();
  162. if (onType==null) return; // error reported elsewhere.
  163. // If they did supply a parameterized single type reference, we need to do
  164. // some extra checks...
  165. if (onType instanceof ParameterizedSingleTypeReference || onType instanceof ParameterizedQualifiedTypeReference) {
  166. resolveTypeParametersForITDOnGenericType(classScope);
  167. } else {
  168. onTypeBinding = (ReferenceBinding)onType.getTypeBindingPublic(classScope);
  169. if (!onTypeBinding.isValidBinding()) {
  170. classScope.problemReporter().invalidType(onType, onTypeBinding);
  171. ignoreFurtherInvestigation = true;
  172. }
  173. if (onTypeBinding.isParameterizedType()) {
  174. // might be OK... pr132349
  175. ParameterizedTypeBinding ptb = (ParameterizedTypeBinding)onTypeBinding;
  176. if (ptb.isNestedType()) {
  177. if (ptb.typeVariables()==null || ptb.typeVariables().length==0) {
  178. if (ptb.enclosingType().isRawType()) onTypeBinding = ptb.type;
  179. }
  180. }
  181. }
  182. }
  183. }
  184. /**
  185. * Transform the parameterized type binding (e.g. SomeType<A,B,C>) to a
  186. * real type (e.g. SomeType). The only kind of parameterization allowed
  187. * is with type variables and those are references to type variables on
  188. * the target type. Once we have worked out the base generic type intended
  189. * then we do lots of checks to verify the declaration was well formed.
  190. */
  191. private void resolveTypeParametersForITDOnGenericType(ClassScope classScope) {
  192. // Collapse the parameterized reference to its generic type
  193. if (onType instanceof ParameterizedSingleTypeReference) {
  194. ParameterizedSingleTypeReference pref = (ParameterizedSingleTypeReference) onType;
  195. long pos = (((long)pref.sourceStart) << 32) | pref.sourceEnd;
  196. onType = new SingleTypeReference(pref.token,pos);
  197. } else {
  198. ParameterizedQualifiedTypeReference pref = (ParameterizedQualifiedTypeReference) onType;
  199. long pos = (((long)pref.sourceStart) << 32) | pref.sourceEnd;
  200. onType = new QualifiedTypeReference(pref.tokens,new long[]{pos});
  201. }
  202. onTypeBinding = (ReferenceBinding)onType.getTypeBindingPublic(classScope);
  203. if (!onTypeBinding.isValidBinding()) {
  204. classScope.problemReporter().invalidType(onType, onTypeBinding);
  205. ignoreFurtherInvestigation = true;
  206. }
  207. if (onTypeBinding.isRawType()) {
  208. onTypeBinding = ((RawTypeBinding)onTypeBinding).type;
  209. }
  210. int aliasCount = (typeVariableAliases==null?0:typeVariableAliases.size());
  211. // Cannot specify a parameterized target type for the ITD if the target
  212. // type is not generic.
  213. if (aliasCount!=0 && !onTypeBinding.isGenericType()) {
  214. scope.problemReporter().signalError(sourceStart,sourceEnd,
  215. "Type parameters can not be specified in the ITD target type - the target type "+onTypeBinding.debugName()+" is not generic.");
  216. ignoreFurtherInvestigation = true;
  217. return;
  218. }
  219. // Check they have supplied the right number of type parameters on the ITD target type
  220. if (aliasCount>0) {
  221. 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
  222. scope.problemReporter().signalError(sourceStart, sourceEnd,
  223. "Incorrect number of type parameters supplied. The generic type "+onTypeBinding.debugName()+" has "+
  224. onTypeBinding.typeVariables().length+" type parameters, not "+aliasCount+".");
  225. ignoreFurtherInvestigation = true;
  226. return;
  227. }
  228. }
  229. // check if they used stupid names for type variables
  230. if (aliasCount>0) {
  231. for (int i = 0; i < aliasCount; i++) {
  232. String array_element = typeVariableAliases.get(i);
  233. SingleTypeReference str = new SingleTypeReference(array_element.toCharArray(),0);
  234. TypeBinding tb = str.getTypeBindingPublic(classScope);
  235. if (tb!=null && !(tb instanceof ProblemReferenceBinding)) {// && !(tb instanceof TypeVariableBinding)) {
  236. scope.problemReporter().signalError(sourceStart,sourceEnd,
  237. "Intertype declarations can only be made on the generic type, not on a parameterized type. The name '"+
  238. array_element+"' cannot be used as a type parameter, since it refers to a real type.");
  239. ignoreFurtherInvestigation = true;
  240. return;
  241. }
  242. }
  243. }
  244. // TypeVariableBinding[] tVarsInGenericType = onTypeBinding.typeVariables();
  245. // typeVariableAliases = new ArrayList(); /* Name>GenericTypeVariablePosition */ // FIXME ASC DONT THINK WE NEED TO BUILD IT HERE AS WELL...
  246. // TypeReference[] targs = pref.typeArguments;
  247. // if (targs!=null) {
  248. // for (int i = 0; i < targs.length; i++) {
  249. // TypeReference tref = targs[i];
  250. // typeVariableAliases.add(CharOperation.toString(tref.getTypeName()));//tVarsInGenericType[i]);
  251. // }
  252. // }
  253. }
  254. protected void checkSpec() {
  255. if (Modifier.isProtected(declaredModifiers)) {
  256. scope.problemReporter().signalError(sourceStart, sourceEnd,
  257. "protected inter-type declarations are not allowed");
  258. ignoreFurtherInvestigation = true;
  259. }
  260. }
  261. protected List makeEffectiveSignatureAttribute(
  262. ResolvedMember sig,
  263. Shadow.Kind kind,
  264. boolean weaveBody)
  265. {
  266. List<IAttribute> l = new ArrayList<>(1);
  267. l.add(new EclipseAttributeAdapter(
  268. new AjAttribute.EffectiveSignatureAttribute(sig, kind, weaveBody)));
  269. return l;
  270. }
  271. protected void setMunger(ResolvedTypeMunger munger) {
  272. munger.getSignature().setPosition(sourceStart, sourceEnd);
  273. munger.getSignature().setSourceContext(new EclipseSourceContext(compilationResult));
  274. this.munger = munger;
  275. }
  276. @Override
  277. protected int generateInfoAttributes(ClassFile classFile) {
  278. List<IAttribute> l;
  279. Shadow.Kind kind = getShadowKindForBody();
  280. if (kind != null) {
  281. l = makeEffectiveSignatureAttribute(munger.getSignature(), kind, true);
  282. } else {
  283. l = new ArrayList<>(0);
  284. }
  285. addDeclarationStartLineAttribute(l,classFile);
  286. return classFile.generateMethodInfoAttributes(binding, l);
  287. }
  288. protected abstract Shadow.Kind getShadowKindForBody();
  289. public ResolvedMember getSignature() {
  290. if (munger==null) return null; // Can be null in an erroneous program I think
  291. return munger.getSignature();
  292. }
  293. public char[] getDeclaredSelector() {
  294. return declaredSelector;
  295. }
  296. public TypeReference getOnType() {
  297. return onType;
  298. }
  299. /**
  300. * Create the list of aliases based on what was supplied as parameters for the ontype.
  301. * For example, if the declaration is 'List&lt;N&gt; SomeType&lt;N&gt;.foo' then the alias list
  302. * will simply contain 'N' and 'N' will mean 'the first type variable declared for
  303. * type SomeType'
  304. */
  305. public void determineTypeVariableAliases() {
  306. if (onType!=null) {
  307. // TODO loses distinction about which level the type variables are at... is that a problem?
  308. if (onType instanceof ParameterizedSingleTypeReference) {
  309. ParameterizedSingleTypeReference paramRef = (ParameterizedSingleTypeReference) onType;
  310. TypeReference[] rb = paramRef.typeArguments;
  311. typeVariableAliases = new ArrayList<>();
  312. for (TypeReference typeReference : rb) {
  313. typeVariableAliases.add(CharOperation.toString(typeReference.getTypeName()));
  314. }
  315. } else if (onType instanceof ParameterizedQualifiedTypeReference) {
  316. ParameterizedQualifiedTypeReference paramRef = (ParameterizedQualifiedTypeReference) onType;
  317. typeVariableAliases = new ArrayList<>();
  318. for (int j = 0; j < paramRef.typeArguments.length; j++) {
  319. TypeReference[] rb = paramRef.typeArguments[j];
  320. for (int i = 0; rb!=null && i < rb.length; i++) {
  321. typeVariableAliases.add(CharOperation.toString(rb[i].getTypeName()));
  322. }
  323. }
  324. }
  325. }
  326. }
  327. /**
  328. * Called just before the compiler is going to start resolving elements of a declaration, this method
  329. * adds an intertypescope between the methodscope and classscope so that elements of the type targetted
  330. * by the ITD can be resolved. For example, if type variables are referred to in the ontype for the ITD,
  331. * they have to be resolved against the ontype, not the aspect containing the ITD.
  332. */
  333. @Override
  334. public void ensureScopeSetup() {
  335. if (scopeSetup) return; // don't do it again
  336. MethodScope scope = this.scope;
  337. TypeReference ot = onType;
  338. ReferenceBinding rb = null;
  339. if (ot instanceof ParameterizedQualifiedTypeReference) { // pr132349
  340. ParameterizedQualifiedTypeReference pref = (ParameterizedQualifiedTypeReference) ot;
  341. if (pref.typeArguments!=null && pref.typeArguments.length!=0) {
  342. boolean usingNonTypeVariableInITD = false;
  343. // Check if any of them are not type variables
  344. for (int i = 0; i < pref.typeArguments.length; i++) {
  345. TypeReference[] refs = pref.typeArguments[i];
  346. for (int j = 0; refs!=null && j < refs.length; j++) {
  347. TypeBinding tb = refs[j].getTypeBindingPublic(scope.parent);
  348. if (!tb.isTypeVariable() && !(tb instanceof ProblemReferenceBinding)) {
  349. usingNonTypeVariableInITD = true;
  350. }
  351. }
  352. }
  353. if (usingNonTypeVariableInITD) {
  354. scope.problemReporter().signalError(sourceStart,sourceEnd,
  355. "Cannot make inter-type declarations on parameterized types");
  356. // to prevent disgusting cascading errors after this problem - lets null out what leads to them (pr105038)
  357. this.arguments=null;
  358. this.returnType=new SingleTypeReference(TypeReference.VOID,0L);
  359. this.ignoreFurtherInvestigation=true;
  360. ReferenceBinding closestMatch = null;
  361. rb = new ProblemReferenceBinding(ot.getParameterizedTypeName(),closestMatch,0);
  362. onType=null;
  363. }
  364. }
  365. }
  366. // Work out the real base type
  367. if (ot instanceof ParameterizedSingleTypeReference) {
  368. ParameterizedSingleTypeReference pref = (ParameterizedSingleTypeReference) ot;
  369. long pos = (((long)pref.sourceStart) << 32) | pref.sourceEnd;
  370. ot = new SingleTypeReference(pref.token,pos);
  371. } else if (ot instanceof ParameterizedQualifiedTypeReference) {
  372. ParameterizedQualifiedTypeReference pref = (ParameterizedQualifiedTypeReference) ot;
  373. long pos = (((long)pref.sourceStart) << 32) | pref.sourceEnd;
  374. ot = new QualifiedTypeReference(pref.tokens,new long[]{pos});//SingleTypeReference(pref.Quatoken,pos);
  375. }
  376. // resolve it
  377. if (rb==null) {
  378. rb = (ReferenceBinding)ot.getTypeBindingPublic(scope.parent);
  379. }
  380. // pr203646 - if we have ended up with the raw type, get back to the underlying generic one.
  381. if (rb.isRawType() && rb.isMemberType()) {
  382. // if the real target type used a type variable alias then we can do this OK, but need to switch things around, we want the generic type
  383. rb = ((RawTypeBinding)rb).type;
  384. }
  385. if (rb instanceof TypeVariableBinding) {
  386. scope.problemReporter().signalError(sourceStart,sourceEnd,
  387. "Cannot make inter-type declarations on type variables, use an interface and declare parents");
  388. // to prevent disgusting cascading errors after this problem - lets null out what leads to them (pr105038)
  389. this.arguments=null;
  390. this.returnType=new SingleTypeReference(TypeReference.VOID,0L);
  391. this.ignoreFurtherInvestigation=true;
  392. ReferenceBinding closestMatch = null;
  393. if (((TypeVariableBinding)rb).firstBound!=null) {
  394. closestMatch = ((TypeVariableBinding)rb).firstBound.enclosingType();
  395. }
  396. rb = new ProblemReferenceBinding(rb.compoundName,closestMatch,0);
  397. }
  398. // if resolution failed, give up - someone else is going to report an error
  399. if (rb instanceof ProblemReferenceBinding) return;
  400. interTypeScope = new InterTypeScope(scope.parent, rb, typeVariableAliases);
  401. // FIXME asc verify the choice of lines here...
  402. // Two versions of this next line.
  403. // First one tricks the JDT variable processing code so that it won't complain if
  404. // you refer to a type variable from a static ITD - it *is* a problem and it *will* be caught, but later and
  405. // by the AJDT code so we can put out a much nicer message.
  406. scope.isStatic = (typeVariableAliases!=null?false:Modifier.isStatic(declaredModifiers));
  407. // this is the original version in case tricking the JDT causes grief (if you reinstate this variant, you
  408. // will need to change the expected messages output for some of the generic ITD tests)
  409. // scope.isStatic = Modifier.isStatic(declaredModifiers);
  410. scope.parent = interTypeScope;
  411. scopeSetup = true;
  412. }
  413. }