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.

PointcutDeclaration.java 11KB

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
11 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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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 v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-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.Iterator;
  15. import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
  16. import org.aspectj.ajdt.internal.core.builder.EclipseSourceContext;
  17. import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
  18. import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
  19. import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
  20. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
  21. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
  22. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
  23. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
  24. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
  25. import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
  26. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
  27. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
  28. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
  29. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TagBits;
  30. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
  31. import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
  32. import org.aspectj.weaver.AjAttribute;
  33. import org.aspectj.weaver.ResolvedPointcutDefinition;
  34. import org.aspectj.weaver.UnresolvedType;
  35. import org.aspectj.weaver.patterns.Pointcut;
  36. /**
  37. * pointcut [declaredModifiers] [declaredName]([arguments]): [pointcutDesignator];
  38. *
  39. * <p>
  40. * No method will actually be generated for this node but an attribute will be added to the enclosing class.
  41. * </p>
  42. *
  43. * @author Jim Hugunin
  44. */
  45. public class PointcutDeclaration extends AjMethodDeclaration {
  46. public static final char[] mangledPrefix = "ajc$pointcut$".toCharArray();
  47. public PointcutDesignator pointcutDesignator;
  48. private int declaredModifiers;
  49. private String declaredName;
  50. private boolean generateSyntheticPointcutMethod = false;
  51. private EclipseFactory world = null;
  52. // private boolean mangleSelector = true;
  53. private ResolvedPointcutDefinition resolvedPointcutDeclaration = null;
  54. public PointcutDeclaration(CompilationResult compilationResult) {
  55. super(compilationResult);
  56. this.returnType = TypeReference.baseTypeReference(T_void, 0, null);
  57. }
  58. private Pointcut getPointcut() {
  59. if (pointcutDesignator == null) {
  60. return Pointcut.makeMatchesNothing(Pointcut.RESOLVED);
  61. } else {
  62. return pointcutDesignator.getPointcut();
  63. }
  64. }
  65. public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
  66. // do nothing
  67. }
  68. public void postParse(TypeDeclaration typeDec) {
  69. if (arguments == null)
  70. arguments = new Argument[0];
  71. this.declaredModifiers = modifiers;
  72. this.declaredName = new String(selector);
  73. // amc - if we set mangle selector to false, then the generated bytecode has the
  74. // pointcut method name that the user of an @Pointcut would expect.
  75. // But then we will unpack it again in the weaver which may cause redundant
  76. // error messages to be issued. This seems the better trade-off...
  77. // if (mangleSelector) {
  78. selector = CharOperation.concat(mangledPrefix, '$', selector, '$', Integer.toHexString(sourceStart).toCharArray());
  79. // }
  80. if (Modifier.isAbstract(this.declaredModifiers)) {
  81. if (!(typeDec instanceof AspectDeclaration)) {
  82. // check for @Aspect
  83. if (isAtAspectJ(typeDec)) {
  84. // no need to check abstract class as JDT does that
  85. } else {
  86. typeDec.scope.problemReporter().signalError(sourceStart, sourceEnd,
  87. "The abstract pointcut " + new String(declaredName) + " can only be defined in an aspect");
  88. ignoreFurtherInvestigation = true;
  89. return;
  90. }
  91. } else if (!Modifier.isAbstract(typeDec.modifiers)) {
  92. typeDec.scope.problemReporter().signalError(sourceStart, sourceEnd,
  93. "The abstract pointcut " + new String(declaredName) + " can only be defined in an abstract aspect");
  94. ignoreFurtherInvestigation = true;
  95. return;
  96. }
  97. }
  98. if (pointcutDesignator != null) {
  99. pointcutDesignator.postParse(typeDec, this);
  100. }
  101. }
  102. private boolean isAtAspectJ(TypeDeclaration typeDec) {
  103. if (typeDec.annotations == null)
  104. return false;
  105. for (int i = 0; i < typeDec.annotations.length; i++) {
  106. Annotation annotation = typeDec.annotations[i];
  107. if ("Lorg/aspectj/lang/annotation/Aspect;".equals(new String(annotation.resolvedType.signature()))) {
  108. return true;
  109. }
  110. }
  111. return false;
  112. }
  113. /**
  114. * Called from the AtAspectJVisitor to create the @Pointcut annotation (and corresponding method) for this pointcut
  115. *
  116. */
  117. public void addAtAspectJAnnotations() {
  118. String argNames = buildArgNameRepresentation();
  119. Annotation pcutAnnotation = AtAspectJAnnotationFactory.createPointcutAnnotation(getPointcutText(), argNames,
  120. declarationSourceStart);
  121. if (annotations == null) {
  122. annotations = new Annotation[] { pcutAnnotation };
  123. } else {
  124. Annotation[] old = annotations;
  125. annotations = new Annotation[old.length + 1];
  126. System.arraycopy(old, 0, annotations, 0, old.length);
  127. annotations[old.length] = pcutAnnotation;
  128. }
  129. generateSyntheticPointcutMethod = true;
  130. }
  131. public String getPointcutText() {
  132. String text = getPointcut().toString();
  133. if (text.indexOf("BindingTypePattern") == -1)
  134. return text;
  135. // has been wrecked by resolution, try to reconstruct from tokens
  136. if (pointcutDesignator != null) {
  137. text = pointcutDesignator.getPointcutDeclarationText();
  138. }
  139. return text;
  140. }
  141. private String buildArgNameRepresentation() {
  142. StringBuffer args = new StringBuffer();
  143. if (this.arguments != null) {
  144. for (int i = 0; i < this.arguments.length; i++) {
  145. if (i != 0)
  146. args.append(",");
  147. args.append(new String(this.arguments[i].name));
  148. }
  149. }
  150. return args.toString();
  151. }
  152. // coming from an @Pointcut declaration
  153. public void setGenerateSyntheticPointcutMethod() {
  154. generateSyntheticPointcutMethod = true;
  155. // mangleSelector = false;
  156. }
  157. public void resolve(ClassScope upperScope) {
  158. // we attempted to resolve annotations below, but that was too early, so we do it again
  159. // now at the 'right' time.
  160. if (binding != null) {
  161. binding.tagBits -= TagBits.AnnotationResolved;
  162. resolveAnnotations(scope, this.annotations, this.binding);
  163. }
  164. // for the rest of the resolution process, this method should do nothing, use the entry point below...
  165. }
  166. public void resolvePointcut(ClassScope upperScope) {
  167. this.world = EclipseFactory.fromScopeLookupEnvironment(upperScope);
  168. super.resolve(upperScope);
  169. }
  170. public void resolveStatements() {
  171. if (isAbstract()) {
  172. this.modifiers |= ExtraCompilerModifiers.AccSemicolonBody;
  173. }
  174. if (binding == null || ignoreFurtherInvestigation)
  175. return;
  176. if (Modifier.isAbstract(this.declaredModifiers) && (pointcutDesignator != null)) {
  177. scope.problemReporter().signalError(sourceStart, sourceEnd, "abstract pointcut can't have body");
  178. ignoreFurtherInvestigation = true;
  179. return;
  180. }
  181. if (pointcutDesignator != null) {
  182. pointcutDesignator.finishResolveTypes(this, this.binding, arguments.length, scope.enclosingSourceType());
  183. }
  184. // System.out.println("resolved: " + getPointcut() + ", " + getPointcut().state);
  185. makeResolvedPointcutDefinition(world);
  186. resolvedPointcutDeclaration.setPointcut(getPointcut());
  187. super.resolveStatements();
  188. }
  189. public ResolvedPointcutDefinition makeResolvedPointcutDefinition(EclipseFactory inWorld) {
  190. if (resolvedPointcutDeclaration != null)
  191. return resolvedPointcutDeclaration;
  192. if (binding == null) {
  193. // other errors exist that will be reported separately
  194. return null;
  195. }
  196. // System.out.println("pc: " + getPointcut() + ", " + getPointcut().state);
  197. ReferenceBinding declaringClass = binding.declaringClass;
  198. TypeBinding[] parameters = binding.parameters;
  199. UnresolvedType utDeclaringClass = inWorld.fromBinding(declaringClass);
  200. UnresolvedType[] utParameters = inWorld.fromBindings(parameters);
  201. resolvedPointcutDeclaration = new ResolvedPointcutDefinition(utDeclaringClass, declaredModifiers, declaredName,
  202. utParameters, getPointcut()); // ??? might want to
  203. // use null
  204. resolvedPointcutDeclaration.setPosition(sourceStart, sourceEnd);
  205. resolvedPointcutDeclaration.setSourceContext(new EclipseSourceContext(compilationResult));
  206. return resolvedPointcutDeclaration;
  207. }
  208. public AjAttribute makeAttribute() {
  209. return new AjAttribute.PointcutDeclarationAttribute(makeResolvedPointcutDefinition(world));
  210. }
  211. /**
  212. * A pointcut declaration exists in a classfile only as an attibute on the class. Unlike advice and inter-type declarations, it
  213. * has no corresponding method.
  214. */
  215. public void generateCode(ClassScope classScope, ClassFile classFile) {
  216. this.world = EclipseFactory.fromScopeLookupEnvironment(classScope);
  217. if (ignoreFurtherInvestigation)
  218. return;
  219. classFile.extraAttributes.add(new EclipseAttributeAdapter(makeAttribute()));
  220. addVersionAttributeIfNecessary(classFile);
  221. if (generateSyntheticPointcutMethod) {
  222. this.binding.modifiers |= ClassFileConstants.AccSynthetic;
  223. super.generateCode(classScope, classFile);
  224. }
  225. return;
  226. }
  227. /**
  228. * Normally, pointcuts occur in aspects - aspects are always tagged with a weaver version attribute, see AspectDeclaration.
  229. * However, pointcuts can also occur in regular classes and in this case there is no AspectDeclaration to ensure the attribute
  230. * is added. So, this method adds the attribute if someone else hasn't already.
  231. */
  232. private void addVersionAttributeIfNecessary(ClassFile classFile) {
  233. for (Iterator iter = classFile.extraAttributes.iterator(); iter.hasNext();) {
  234. EclipseAttributeAdapter element = (EclipseAttributeAdapter) iter.next();
  235. if (CharOperation.equals(element.getNameChars(), weaverVersionChars))
  236. return;
  237. }
  238. classFile.extraAttributes.add(new EclipseAttributeAdapter(new AjAttribute.WeaverVersionInfo()));
  239. }
  240. private static char[] weaverVersionChars = "org.aspectj.weaver.WeaverVersion".toCharArray();
  241. protected int generateInfoAttributes(ClassFile classFile) {
  242. return super.generateInfoAttributes(classFile, true);
  243. }
  244. public StringBuffer printReturnType(int indent, StringBuffer output) {
  245. return output.append("pointcut");
  246. }
  247. /*
  248. * (non-Javadoc)
  249. *
  250. * @see org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration#printBody(int, java.lang.StringBuffer)
  251. */
  252. public StringBuffer printBody(int indent, StringBuffer output) {
  253. output.append(": ");
  254. output.append(getPointcut());
  255. output.append(";");
  256. return output;
  257. }
  258. }