All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aspectj.ajdt.internal.compiler.ast.PointcutDeclaration Maven / Gradle / Ivy

/* *******************************************************************
 * 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.AnnotationBinding;
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.SourceTypeBinding;
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];
 * 
 * 

* No method will actually be generated for this node but an attribute will be added to the enclosing class. *

* * @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) && !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 (CharOperation.equals(annotation.resolvedType.signature(),ASPECT_CHARS)) { 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; } private static char[] ASPECT_CHARS = "Lorg/aspectj/lang/annotation/Aspect;".toCharArray(); 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); TypeDeclaration typeDec = upperScope.referenceContext; if (Modifier.isAbstract(this.declaredModifiers)) { if (!(typeDec instanceof AspectDeclaration)) { if (!isAtAspectJ(typeDec)) { typeDec.scope.problemReporter().signalError(sourceStart, sourceEnd, "The abstract pointcut " + new String(declaredName) + " can only be defined in an aspect"); ignoreFurtherInvestigation = true; return; } } } } // 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; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy