org.aspectj.ajdt.internal.compiler.ast.PointcutDeclaration Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
Tools from the AspectJ project
/* *******************************************************************
* 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 v 2.0
* which accompanies this distribution and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
*
* Contributors:
* PARC initial implementation
* ******************************************************************/
package org.aspectj.ajdt.internal.compiler.ast;
import java.lang.reflect.Modifier;
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];
*
*
* 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.contains("BindingTypePattern"))
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 (Object o : classFile.extraAttributes) {
EclipseAttributeAdapter element = (EclipseAttributeAdapter) o;
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