org.aspectj.ajdt.internal.compiler.ast.IfPseudoToken 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.org.eclipse.jdt.core.compiler.CharOperation;
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.Expression;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Statement;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.StringLiteral;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TrueLiteral;
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.TypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
import org.aspectj.weaver.Member;
import org.aspectj.weaver.ResolvedMemberImpl;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.patterns.IfPointcut;
import org.aspectj.weaver.patterns.Pointcut;
/**
* (formals*): ... if(expr) ...
*
* generates the following: public static final boolean ajc$if_N(formals*,
* [thisJoinPoints as needed]) { return expr; }
*
* Here's the complicated bit, it deals with cflow: (a): ... this(a) && cflow(if
* (a == foo)) is an error. The way we capture this is: We generate the ajc$if
* method with an (a) parameter, we let eclipse do the proper name binding. We
* then, as a post pass (that we need to do anyway) look for the used
* parameters. If a is used, we signal an error because a was not one of the
* cflow variables. XXX we'll do this part after we do cflow
*
* The IfPointcut pcd then generates itself always as a dynamic test, it has to
* get the right parameters through any named pointcut references...
*/
public class IfPseudoToken extends PseudoToken {
public Expression expr;
public MethodDeclaration testMethod;
private IfPointcut pointcut;
public IfPseudoToken(Parser parser, Expression expr) {
super(parser, "if", false);
this.expr = expr;
}
public Pointcut maybeGetParsedPointcut() {
if (expr instanceof FalseLiteral) {
return IfPointcut.makeIfFalsePointcut(Pointcut.SYMBOLIC);
} else if (expr instanceof TrueLiteral) {
return IfPointcut.makeIfTruePointcut(Pointcut.SYMBOLIC);
} else {
pointcut = new IfPointcut(new ResolvedMemberImpl(Member.METHOD,
UnresolvedType.OBJECT, 0, "if_", "()V"), 0);
}
return pointcut;
}
/**
* enclosingDec is either AdviceDeclaration or PointcutDeclaration
*/
public int postParse(TypeDeclaration typeDec,
MethodDeclaration enclosingDec, int counter) {
// typeDec.scope.problemReporter().signalError(sourceStart, sourceEnd,
// "if pcd is not implemented in 1.1alpha1");
// XXX need to implement correctly
if (pointcut == null)
return 0;
testMethod = makeIfMethod(enclosingDec.compilationResult, enclosingDec, typeDec, counter);
AstUtil.addMethodDeclaration(typeDec, testMethod);
return 1;
}
private final static char[] CodeGenerationHint = "CodeGenerationHint".toCharArray();
private final static char[] FullyQualifiedCodeGenerationHint = "org.aspectj.lang.annotation.control.CodeGenerationHint".toCharArray();
private final static char[] IfNameSuffix = "ifNameSuffix".toCharArray();
// XXX todo: make sure that errors in Arguments only get displayed once
private MethodDeclaration makeIfMethod(CompilationResult result, MethodDeclaration enclosingDec, TypeDeclaration containingTypeDec, int counter) {
MethodDeclaration ret = new IfMethodDeclaration(result, pointcut);
ret.modifiers = ClassFileConstants.AccStatic | ClassFileConstants.AccFinal | ClassFileConstants.AccPublic;
ret.returnType = AstUtil.makeTypeReference(TypeBinding.BOOLEAN);
String nameSuffix = null;
if (enclosingDec!=null && enclosingDec.annotations!=null) {
NormalAnnotation interestingAnnotation = null;
Annotation[] as = enclosingDec.annotations;
if (as!=null) {
for (int a = 0; a < as.length && interestingAnnotation == null; a++) {
if (as[a] instanceof NormalAnnotation) {
TypeReference tr = as[a].type;
if (tr instanceof SingleTypeReference) {
if (CharOperation.equals(CodeGenerationHint,((SingleTypeReference)tr).token)) {
interestingAnnotation = (NormalAnnotation)as[a];
}
} else if (tr instanceof QualifiedTypeReference) {
char[] qualifiedName = CharOperation.concatWith(((QualifiedTypeReference)tr).tokens,'.');
if (CharOperation.equals(FullyQualifiedCodeGenerationHint,qualifiedName)) {
interestingAnnotation = (NormalAnnotation)as[a];
}
}
}
}
}
if (interestingAnnotation!=null) {
MemberValuePair[] memberValuePairs = interestingAnnotation.memberValuePairs;
for (MemberValuePair memberValuePair: memberValuePairs) {
if (CharOperation.equals(IfNameSuffix,memberValuePair.name) && (memberValuePair.value instanceof StringLiteral)) {
nameSuffix = new String(((StringLiteral)memberValuePair.value).source());
}
}
}
}
// create a more stable name 277508
StringBuilder ifSelector = new StringBuilder();
ifSelector.append("ajc$if$");
if (nameSuffix == null || nameSuffix.length()==0) {
boolean computedName = false;
try {
// possibly even better logic for more reliable name:
if (enclosingDec instanceof AdviceDeclaration) {
// name is ajc$if$[$]$
ifSelector.append(((AdviceDeclaration)enclosingDec).adviceSequenceNumberInType).append("$");
if (counter!=0) {
ifSelector.append(counter);
ifSelector.append("$");
}
ifSelector.append(Integer.toHexString(expr.toString().hashCode()));
computedName = true;
} else if (enclosingDec instanceof PointcutDeclaration) {
if (counter!=0) {
ifSelector.append(counter);
ifSelector.append("$");
}
StringBuilder toHash = new StringBuilder(((PointcutDeclaration) enclosingDec).getPointcutText());
toHash.append(expr.toString());
// name is pointcut selector then $if[$]$
ifSelector.append(Integer.toHexString(toHash.toString().hashCode()));
computedName = true;
}
} catch (Throwable t) {
throw new IllegalStateException(t);
// let it build a name the 'old way'
}
if (!computedName) {
ifSelector.append(Integer.toHexString(expr.sourceStart));
}
} else {
ifSelector.append(nameSuffix);
}
ret.selector = ifSelector.toString().toCharArray();
ret.arguments = makeArguments(enclosingDec, containingTypeDec);
ret.statements = new Statement[] { new ReturnStatement(expr,
expr.sourceStart, expr.sourceEnd) };
return ret;
}
private Argument[] makeArguments(MethodDeclaration enclosingDec,
TypeDeclaration containingTypeDec) {
Argument[] baseArguments = enclosingDec.arguments;
int len = baseArguments.length;
if (enclosingDec instanceof AdviceDeclaration) {
len = ((AdviceDeclaration) enclosingDec).baseArgumentCount;
}
Argument[] ret = new Argument[len];
for (int i = 0; i < len; i++) {
Argument a = baseArguments[i];
ret[i] = new Argument(a.name, AstUtil.makeLongPos(a.sourceStart,
a.sourceEnd), a.type, Modifier.FINAL);
}
ret = AdviceDeclaration.addTjpArguments(ret, containingTypeDec);
return ret;
}
}