org.aspectj.ajdt.internal.compiler.ast.AdviceDeclaration 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 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.ArrayList;
import java.util.List;
import org.aspectj.ajdt.internal.compiler.lookup.AjTypeConstants;
import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
import org.aspectj.ajdt.internal.compiler.lookup.PrivilegedHandler;
import org.aspectj.bridge.context.CompilationAndWeavingContext;
import org.aspectj.bridge.context.ContextToken;
import org.aspectj.org.eclipse.jdt.core.Flags;
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.QualifiedTypeReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
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.codegen.CodeStream;
import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.Opcodes;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
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.MethodBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.aspectj.weaver.Advice;
import org.aspectj.weaver.AdviceKind;
import org.aspectj.weaver.AjAttribute;
import org.aspectj.weaver.NameMangler;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.UnresolvedType;
/**
* Represents before, after and around advice in an aspect. Will generate a method corresponding to the body of the advice with an
* attribute including additional information.
*
* @author Jim Hugunin
*/
public class AdviceDeclaration extends AjMethodDeclaration {
public PointcutDesignator pointcutDesignator; // set during parsing
int baseArgumentCount; // referenced by IfPseudoToken.makeArguments
public Argument extraArgument; // set during parsing, referenced by Proceed
public AdviceKind kind; // set during parsing, referenced by Proceed and AsmElementFormatter
private int extraArgumentFlags = 0;
public int adviceSequenceNumberInType;
public MethodBinding proceedMethodBinding; // set during this.resolveStaments, referenced by Proceed
public List proceedCalls = new ArrayList(2); // populated during Proceed.findEnclosingAround
private boolean proceedInInners;
private ResolvedMember[] proceedCallSignatures;
private boolean[] formalsUnchangedToProceed;
private UnresolvedType[] declaredExceptions;
public AdviceDeclaration(CompilationResult result, AdviceKind kind) {
super(result);
this.returnType = TypeReference.baseTypeReference(T_void, 0,null);
this.kind = kind;
}
// override
protected int generateInfoAttributes(ClassFile classFile) {
List l = new ArrayList(1);
l.add(new EclipseAttributeAdapter(makeAttribute()));
addDeclarationStartLineAttribute(l, classFile);
return classFile.generateMethodInfoAttributes(binding, l);
}
private AjAttribute makeAttribute() {
if (kind == AdviceKind.Around) {
return new AjAttribute.AdviceAttribute(kind, pointcutDesignator.getPointcut(), extraArgumentFlags, sourceStart,
sourceEnd, null, proceedInInners, proceedCallSignatures, formalsUnchangedToProceed, declaredExceptions);
} else {
return new AjAttribute.AdviceAttribute(kind, pointcutDesignator.getPointcut(), extraArgumentFlags, sourceStart,
sourceEnd, null);
}
}
// override
public void resolveStatements() {
if (binding == null || ignoreFurtherInvestigation)
return;
ClassScope upperScope = (ClassScope) scope.parent; // !!! safety
modifiers = checkAndSetModifiers(modifiers, upperScope);
int bindingModifiers = (modifiers | (binding.modifiers & ExtraCompilerModifiers.AccGenericSignature));
binding.modifiers = bindingModifiers;
if (kind == AdviceKind.AfterThrowing && extraArgument != null) {
TypeBinding argTb = extraArgument.binding.type;
TypeBinding expectedTb = upperScope.getJavaLangThrowable();
if (!argTb.isCompatibleWith(expectedTb)) {
scope.problemReporter().typeMismatchError(argTb, expectedTb, extraArgument,null);
ignoreFurtherInvestigation = true;
return;
}
}
pointcutDesignator.finishResolveTypes(this, this.binding, baseArgumentCount, upperScope.referenceContext.binding);
if (binding == null || ignoreFurtherInvestigation)
return;
if (kind == AdviceKind.Around) {
ReferenceBinding[] exceptions = new ReferenceBinding[] { upperScope.getJavaLangThrowable() };
proceedMethodBinding = new MethodBinding(Modifier.STATIC | Flags.AccSynthetic, "proceed".toCharArray(),
binding.returnType, resize(baseArgumentCount + 1, binding.parameters), exceptions, binding.declaringClass);
proceedMethodBinding.selector = CharOperation.concat(selector, proceedMethodBinding.selector);
}
super.resolveStatements(); // upperScope);
if (binding != null)
determineExtraArgumentFlags();
if (kind == AdviceKind.Around) {
int n = proceedCalls.size();
// EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(upperScope);
// System.err.println("access to: " + Arrays.asList(handler.getMembers()));
// XXX set these correctly
formalsUnchangedToProceed = new boolean[baseArgumentCount];
proceedCallSignatures = new ResolvedMember[0];
proceedInInners = false;
declaredExceptions = new UnresolvedType[0];
for (int i = 0; i < n; i++) {
Proceed call = (Proceed) proceedCalls.get(i);
if (call.inInner) {
// System.err.println("proceed in inner: " + call);
proceedInInners = true;
// XXX wrong
// proceedCallSignatures[i] = world.makeResolvedMember(call.binding);
}
}
// ??? should reorganize into AspectDeclaration
// if we have proceed in inners we won't ever be inlined so the code below is unneeded
if (!proceedInInners) {
PrivilegedHandler handler = (PrivilegedHandler) upperScope.referenceContext.binding.privilegedHandler;
if (handler == null) {
handler = new PrivilegedHandler((AspectDeclaration) upperScope.referenceContext);
// upperScope.referenceContext.binding.privilegedHandler = handler;
}
this.traverse(new MakeDeclsPublicVisitor(), (ClassScope) null);
AccessForInlineVisitor v = new AccessForInlineVisitor((AspectDeclaration) upperScope.referenceContext, handler);
ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.ACCESS_FOR_INLINE,
selector);
this.traverse(v, (ClassScope) null);
CompilationAndWeavingContext.leavingPhase(tok);
// ??? if we found a construct that we can't inline, set
// proceedInInners so that we won't try to inline this body
if (!v.isInlinable)
proceedInInners = true;
}
}
}
// called by Proceed.resolveType
public int getDeclaredParameterCount() {
// this only works before code generation
return this.arguments.length - 3 - ((extraArgument == null) ? 0 : 1);
// Advice.countOnes(extraArgumentFlags);
}
private void generateProceedMethod(ClassScope classScope, ClassFile classFile) {
MethodBinding binding = proceedMethodBinding;
classFile.generateMethodInfoHeader(binding);
int methodAttributeOffset = classFile.contentsOffset;
int attributeNumber = classFile.generateMethodInfoAttributes(binding, AstUtil.getAjSyntheticAttribute());
int codeAttributeOffset = classFile.contentsOffset;
classFile.generateCodeAttributeHeader();
CodeStream codeStream = classFile.codeStream;
codeStream.reset(this, classFile);
// push the closure
int nargs = binding.parameters.length;
int closureIndex = 0;
for (int i = 0; i < nargs - 1; i++) {
closureIndex += AstUtil.slotsNeeded(binding.parameters[i]);
}
codeStream.aload(closureIndex);
// build the Object[]
codeStream.generateInlinedValue(nargs - 1);
codeStream.newArray(new ArrayBinding(classScope.getType(TypeConstants.JAVA_LANG_OBJECT,
TypeConstants.JAVA_LANG_OBJECT.length), 1, classScope.environment()));
int index = 0;
for (int i = 0; i < nargs - 1; i++) {
TypeBinding type = binding.parameters[i];
codeStream.dup();
codeStream.generateInlinedValue(i);
codeStream.load(type, index);
index += AstUtil.slotsNeeded(type);
if (type.isBaseType()) {
codeStream.invoke(Opcodes.OPC_invokestatic, AjTypeConstants.getConversionMethodToObject(classScope, type), null);
}
codeStream.aastore();
}
// call run
ReferenceBinding closureType = (ReferenceBinding) binding.parameters[nargs - 1];
MethodBinding runMethod = closureType.getMethods("run".toCharArray())[0];
codeStream.invoke(Opcodes.OPC_invokevirtual, runMethod, null);
TypeBinding returnType = binding.returnType;
if (returnType.isBaseType()) {
codeStream.invoke(Opcodes.OPC_invokestatic, AjTypeConstants.getConversionMethodFromObject(classScope, returnType), null);
} else {
codeStream.checkcast(returnType);
}
AstUtil.generateReturn(returnType, codeStream);
codeStream.recordPositionsFrom(0, 1);
classFile.completeCodeAttribute(codeAttributeOffset);
attributeNumber++;
classFile.completeMethodInfo(binding,methodAttributeOffset, attributeNumber);
}
// override
public void generateCode(ClassScope classScope, ClassFile classFile) {
if (ignoreFurtherInvestigation)
return;
super.generateCode(classScope, classFile);
if (proceedMethodBinding != null) {
generateProceedMethod(classScope, classFile);
}
}
private void determineExtraArgumentFlags() {
if (extraArgument != null)
extraArgumentFlags |= Advice.ExtraArgument;
ThisJoinPointVisitor tjp = new ThisJoinPointVisitor(this);
extraArgumentFlags |= tjp.removeUnusedExtraArguments();
}
private static TypeBinding[] resize(int newSize, TypeBinding[] bindings) {
int len = bindings.length;
TypeBinding[] ret = new TypeBinding[newSize];
System.arraycopy(bindings, 0, ret, 0, Math.min(newSize, len));
return ret;
}
/**
* Add either the @Before, @After, @Around, @AfterReturning or @AfterThrowing annotation
*/
public void addAtAspectJAnnotations() {
Annotation adviceAnnotation = null;
String pointcutExpression = pointcutDesignator.getPointcut().toString();
String extraArgumentName = "";
if (extraArgument != null) {
extraArgumentName = new String(extraArgument.name);
}
String argNames = buildArgNameRepresentation();
if (kind == AdviceKind.Before) {
adviceAnnotation = AtAspectJAnnotationFactory.createBeforeAnnotation(pointcutExpression, argNames,
declarationSourceStart);
} else if (kind == AdviceKind.After) {
adviceAnnotation = AtAspectJAnnotationFactory.createAfterAnnotation(pointcutExpression, argNames,
declarationSourceStart);
} else if (kind == AdviceKind.AfterReturning) {
adviceAnnotation = AtAspectJAnnotationFactory.createAfterReturningAnnotation(pointcutExpression, argNames,
extraArgumentName, declarationSourceStart);
} else if (kind == AdviceKind.AfterThrowing) {
adviceAnnotation = AtAspectJAnnotationFactory.createAfterThrowingAnnotation(pointcutExpression, argNames,
extraArgumentName, declarationSourceStart);
} else if (kind == AdviceKind.Around) {
adviceAnnotation = AtAspectJAnnotationFactory.createAroundAnnotation(pointcutExpression, argNames,
declarationSourceStart);
}
AtAspectJAnnotationFactory.addAnnotation(this, adviceAnnotation, this.scope);
}
private String buildArgNameRepresentation() {
StringBuffer args = new StringBuffer();
int numArgsWeCareAbout = getDeclaredParameterCount();
if (this.arguments != null) {
for (int i = 0; i < numArgsWeCareAbout; i++) {
if (i != 0)
args.append(",");
args.append(new String(this.arguments[i].name));
}
}
if (extraArgument != null) {
if (numArgsWeCareAbout > 0) {
args.append(",");
}
args.append(new String(extraArgument.name));
}
return args.toString();
}
// override, Called by ClassScope.postParse
public void postParse(TypeDeclaration typeDec) {
AspectDeclaration aspectDecl = (AspectDeclaration) typeDec;
adviceSequenceNumberInType = aspectDecl.adviceCounter++;
StringBuffer stringifiedPointcut = new StringBuffer(30);
pointcutDesignator.print(0, stringifiedPointcut);
this.selector = NameMangler.adviceName(EclipseFactory.getName(typeDec.binding).replace('.', '_'), kind,
adviceSequenceNumberInType, stringifiedPointcut.toString().hashCode()).toCharArray();
if (arguments != null) {
baseArgumentCount = arguments.length;
}
if (kind == AdviceKind.Around) {
extraArgument = makeFinalArgument("ajc$aroundClosure", AjTypeConstants.getAroundClosureType());
}
int addedArguments = 3;
if (extraArgument != null) {
addedArguments += 1;
}
arguments = extendArgumentsLength(arguments, addedArguments);
int index = baseArgumentCount;
if (extraArgument != null) {
arguments[index++] = extraArgument;
}
arguments[index++] = makeFinalArgument("thisJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());
arguments[index++] = makeFinalArgument("thisJoinPoint", AjTypeConstants.getJoinPointType());
arguments[index++] = makeFinalArgument("thisEnclosingJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());
if (pointcutDesignator.isError()) {
this.ignoreFurtherInvestigation = true;
}
pointcutDesignator.postParse(typeDec, this);
}
private int checkAndSetModifiers(int modifiers, ClassScope scope) {
if (modifiers == 0)
return Modifier.PUBLIC;
else if (modifiers == Modifier.STRICT)
return Modifier.PUBLIC | Modifier.STRICT;
else {
tagAsHavingErrors();
scope.problemReporter().signalError(declarationSourceStart, sourceStart - 1,
"illegal modifier on advice, only strictfp is allowed");
return Modifier.PUBLIC;
}
}
// called by IfPseudoToken
public static Argument[] addTjpArguments(Argument[] arguments, TypeDeclaration containingTypeDec) {
int index = arguments.length;
arguments = extendArgumentsLength(arguments, 4);
arguments[index++] = makeFinalArgument("thisJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());
arguments[index++] = makeFinalArgument("thisJoinPoint", AjTypeConstants.getJoinPointType());
arguments[index++] = makeFinalArgument("thisEnclosingJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());
arguments[index++] = makeFinalArgument("thisAspectInstance", toReference(containingTypeDec.name));
return arguments;
}
private static TypeReference toReference(char[] typename) {
if (CharOperation.contains('.', typename)) {
char[][] compoundName = CharOperation.splitOn('.', typename);
return new QualifiedTypeReference(compoundName, new long[compoundName.length]);
} else {
return new SingleTypeReference(typename, 0);
}
}
private static Argument makeFinalArgument(String name, TypeReference typeRef) {
long pos = 0; // XXX encode start and end location
return new Argument(name.toCharArray(), pos, typeRef, Modifier.FINAL);
}
private static Argument[] extendArgumentsLength(Argument[] args, int addedArguments) {
if (args == null) {
return new Argument[addedArguments];
}
int len = args.length;
Argument[] ret = new Argument[len + addedArguments];
System.arraycopy(args, 0, ret, 0, len);
return ret;
}
// public String toString(int tab) {
// String s = tabString(tab);
// if (modifiers != AccDefault) {
// s += modifiersString(modifiers);
// }
//
// if (kind == AdviceKind.Around) {
// s += returnTypeToString(0);
// }
//
// s += new String(selector) + "("; //$NON-NLS-1$
// if (arguments != null) {
// for (int i = 0; i < arguments.length; i++) {
// s += arguments[i].toString(0);
// if (i != (arguments.length - 1))
// s = s + ", "; //$NON-NLS-1$
// };
// };
// s += ")"; //$NON-NLS-1$
//
// if (extraArgument != null) {
// s += "(" + extraArgument.toString(0) + ")";
// }
//
//
//
// if (thrownExceptions != null) {
// s += " throws "; //$NON-NLS-1$
// for (int i = 0; i < thrownExceptions.length; i++) {
// s += thrownExceptions[i].toString(0);
// if (i != (thrownExceptions.length - 1))
// s = s + ", "; //$NON-NLS-1$
// };
// };
//
// s += ": ";
// if (pointcutDesignator != null) {
// s += pointcutDesignator.toString(0);
// }
//
// s += toStringStatements(tab + 1);
// return s;
// }
public StringBuffer printBody(int indent, StringBuffer output) {
output.append(": ");
if (pointcutDesignator != null) {
output.append(pointcutDesignator.toString());
}
return super.printBody(indent, output);
}
public StringBuffer printReturnType(int indent, StringBuffer output) {
if (this.kind == AdviceKind.Around) {
return super.printReturnType(indent, output);
}
return output;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy