|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- /* *******************************************************************
- * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * PARC initial implementation
- * ******************************************************************/
-
- package org.aspectj.ajdt.internal.compiler.ast;
-
- import java.lang.reflect.Modifier;
- import java.util.Iterator;
-
- import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
- import org.aspectj.ajdt.internal.core.builder.EclipseSourceContext;
- import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
- import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
- import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
- import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TagBits;
- import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
- import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
- import org.aspectj.weaver.AjAttribute;
- import org.aspectj.weaver.ResolvedPointcutDefinition;
- import org.aspectj.weaver.UnresolvedType;
- import org.aspectj.weaver.patterns.Pointcut;
-
- /**
- * pointcut [declaredModifiers] [declaredName]([arguments]): [pointcutDesignator];
- *
- * <p>
- * No method will actually be generated for this node but an attribute will be added to the enclosing class.
- * </p>
- *
- * @author Jim Hugunin
- */
- public class PointcutDeclaration extends AjMethodDeclaration {
- public static final char[] mangledPrefix = "ajc$pointcut$".toCharArray();
-
- public PointcutDesignator pointcutDesignator;
- private int declaredModifiers;
- private String declaredName;
- private boolean generateSyntheticPointcutMethod = false;
- private EclipseFactory world = null;
- // private boolean mangleSelector = true;
-
- private ResolvedPointcutDefinition resolvedPointcutDeclaration = null;
-
- public PointcutDeclaration(CompilationResult compilationResult) {
- super(compilationResult);
- this.returnType = TypeReference.baseTypeReference(T_void, 0, null);
- }
-
- private Pointcut getPointcut() {
- if (pointcutDesignator == null) {
- return Pointcut.makeMatchesNothing(Pointcut.RESOLVED);
- } else {
- return pointcutDesignator.getPointcut();
- }
- }
-
- public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
- // do nothing
- }
-
- public void postParse(TypeDeclaration typeDec) {
- if (arguments == null)
- arguments = new Argument[0];
- this.declaredModifiers = modifiers;
- this.declaredName = new String(selector);
- // amc - if we set mangle selector to false, then the generated bytecode has the
- // pointcut method name that the user of an @Pointcut would expect.
- // But then we will unpack it again in the weaver which may cause redundant
- // error messages to be issued. This seems the better trade-off...
- // if (mangleSelector) {
- selector = CharOperation.concat(mangledPrefix, '$', selector, '$', Integer.toHexString(sourceStart).toCharArray());
- // }
-
- if (Modifier.isAbstract(this.declaredModifiers)) {
- if (!(typeDec instanceof AspectDeclaration)) {
- // check for @Aspect
- if (isAtAspectJ(typeDec)) {
- // no need to check abstract class as JDT does that
- } else {
- typeDec.scope.problemReporter().signalError(sourceStart, sourceEnd,
- "The abstract pointcut " + new String(declaredName) + " can only be defined in an aspect");
- ignoreFurtherInvestigation = true;
- return;
- }
- } else if (!Modifier.isAbstract(typeDec.modifiers)) {
- typeDec.scope.problemReporter().signalError(sourceStart, sourceEnd,
- "The abstract pointcut " + new String(declaredName) + " can only be defined in an abstract aspect");
-
- ignoreFurtherInvestigation = true;
- return;
- }
- }
-
- if (pointcutDesignator != null) {
- pointcutDesignator.postParse(typeDec, this);
- }
- }
-
- private boolean isAtAspectJ(TypeDeclaration typeDec) {
- if (typeDec.annotations == null)
- return false;
-
- for (int i = 0; i < typeDec.annotations.length; i++) {
- Annotation annotation = typeDec.annotations[i];
- if ("Lorg/aspectj/lang/annotation/Aspect;".equals(new String(annotation.resolvedType.signature()))) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Called from the AtAspectJVisitor to create the @Pointcut annotation (and corresponding method) for this pointcut
- *
- */
- public void addAtAspectJAnnotations() {
- String argNames = buildArgNameRepresentation();
- Annotation pcutAnnotation = AtAspectJAnnotationFactory.createPointcutAnnotation(getPointcutText(), argNames,
- declarationSourceStart);
-
- if (annotations == null) {
- annotations = new Annotation[] { pcutAnnotation };
- } else {
- Annotation[] old = annotations;
- annotations = new Annotation[old.length + 1];
- System.arraycopy(old, 0, annotations, 0, old.length);
- annotations[old.length] = pcutAnnotation;
- }
- generateSyntheticPointcutMethod = true;
- }
-
- public String getPointcutText() {
- String text = getPointcut().toString();
- if (text.indexOf("BindingTypePattern") == -1)
- return text;
- // has been wrecked by resolution, try to reconstruct from tokens
- if (pointcutDesignator != null) {
- text = pointcutDesignator.getPointcutDeclarationText();
- }
- return text;
- }
-
- private String buildArgNameRepresentation() {
- StringBuffer args = new StringBuffer();
- if (this.arguments != null) {
- for (int i = 0; i < this.arguments.length; i++) {
- if (i != 0)
- args.append(",");
- args.append(new String(this.arguments[i].name));
- }
- }
- return args.toString();
- }
-
- // coming from an @Pointcut declaration
- public void setGenerateSyntheticPointcutMethod() {
- generateSyntheticPointcutMethod = true;
- // mangleSelector = false;
- }
-
- public void resolve(ClassScope upperScope) {
- // we attempted to resolve annotations below, but that was too early, so we do it again
- // now at the 'right' time.
- if (binding != null) {
- binding.tagBits -= TagBits.AnnotationResolved;
- resolveAnnotations(scope, this.annotations, this.binding);
- }
- // for the rest of the resolution process, this method should do nothing, use the entry point below...
- }
-
- public void resolvePointcut(ClassScope upperScope) {
- this.world = EclipseFactory.fromScopeLookupEnvironment(upperScope);
- super.resolve(upperScope);
- }
-
- public void resolveStatements() {
- if (isAbstract()) {
- this.modifiers |= ExtraCompilerModifiers.AccSemicolonBody;
- }
-
- if (binding == null || ignoreFurtherInvestigation)
- return;
-
- if (Modifier.isAbstract(this.declaredModifiers) && (pointcutDesignator != null)) {
- scope.problemReporter().signalError(sourceStart, sourceEnd, "abstract pointcut can't have body");
- ignoreFurtherInvestigation = true;
- return;
- }
-
- if (pointcutDesignator != null) {
- pointcutDesignator.finishResolveTypes(this, this.binding, arguments.length, scope.enclosingSourceType());
- }
-
- // System.out.println("resolved: " + getPointcut() + ", " + getPointcut().state);
- makeResolvedPointcutDefinition(world);
- resolvedPointcutDeclaration.setPointcut(getPointcut());
- super.resolveStatements();
- }
-
- public ResolvedPointcutDefinition makeResolvedPointcutDefinition(EclipseFactory inWorld) {
- if (resolvedPointcutDeclaration != null)
- return resolvedPointcutDeclaration;
- if (binding == null) {
- // other errors exist that will be reported separately
- return null;
- }
- // System.out.println("pc: " + getPointcut() + ", " + getPointcut().state);
- ReferenceBinding declaringClass = binding.declaringClass;
- TypeBinding[] parameters = binding.parameters;
- UnresolvedType utDeclaringClass = inWorld.fromBinding(declaringClass);
- UnresolvedType[] utParameters = inWorld.fromBindings(parameters);
- resolvedPointcutDeclaration = new ResolvedPointcutDefinition(utDeclaringClass, declaredModifiers, declaredName,
- utParameters, getPointcut()); // ??? might want to
- // use null
-
- resolvedPointcutDeclaration.setPosition(sourceStart, sourceEnd);
- resolvedPointcutDeclaration.setSourceContext(new EclipseSourceContext(compilationResult));
- return resolvedPointcutDeclaration;
- }
-
- public AjAttribute makeAttribute() {
- return new AjAttribute.PointcutDeclarationAttribute(makeResolvedPointcutDefinition(world));
- }
-
- /**
- * A pointcut declaration exists in a classfile only as an attibute on the class. Unlike advice and inter-type declarations, it
- * has no corresponding method.
- */
- public void generateCode(ClassScope classScope, ClassFile classFile) {
- this.world = EclipseFactory.fromScopeLookupEnvironment(classScope);
- if (ignoreFurtherInvestigation)
- return;
- classFile.extraAttributes.add(new EclipseAttributeAdapter(makeAttribute()));
- addVersionAttributeIfNecessary(classFile);
-
- if (generateSyntheticPointcutMethod) {
- this.binding.modifiers |= ClassFileConstants.AccSynthetic;
- super.generateCode(classScope, classFile);
- }
- return;
- }
-
- /**
- * Normally, pointcuts occur in aspects - aspects are always tagged with a weaver version attribute, see AspectDeclaration.
- * However, pointcuts can also occur in regular classes and in this case there is no AspectDeclaration to ensure the attribute
- * is added. So, this method adds the attribute if someone else hasn't already.
- */
- private void addVersionAttributeIfNecessary(ClassFile classFile) {
- for (Iterator iter = classFile.extraAttributes.iterator(); iter.hasNext();) {
- EclipseAttributeAdapter element = (EclipseAttributeAdapter) iter.next();
- if (CharOperation.equals(element.getNameChars(), weaverVersionChars))
- return;
- }
- classFile.extraAttributes.add(new EclipseAttributeAdapter(new AjAttribute.WeaverVersionInfo()));
- }
-
- private static char[] weaverVersionChars = "org.aspectj.weaver.WeaverVersion".toCharArray();
-
- protected int generateInfoAttributes(ClassFile classFile) {
- return super.generateInfoAttributes(classFile, true);
- }
-
- public StringBuffer printReturnType(int indent, StringBuffer output) {
- return output.append("pointcut");
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration#printBody(int, java.lang.StringBuffer)
- */
- public StringBuffer printBody(int indent, StringBuffer output) {
- output.append(": ");
- output.append(getPointcut());
- output.append(";");
- return output;
- }
-
- }
|