您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

PointcutDeclaration.java 11KB

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