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

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. }