From: acolyer Date: Mon, 25 Apr 2005 16:07:25 +0000 (+0000) Subject: support in ajc for parsing and error reporting of @AspectJ style aspect definitions... X-Git-Tag: PRE_ANDY~443 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=75c1c3ea4d4cc5308cf3ba4490d18b8536b08dd2;p=aspectj.git support in ajc for parsing and error reporting of @AspectJ style aspect definitions (aspect, pointcut, advice only at this point). Also include the AddAtAspectJAnnotationsVisitor support. Switch off using -Xdev:NoAtAspectJProcessing. --- diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java index 0f8909585..af7cc30fa 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/ajc/BuildArgParser.java @@ -511,7 +511,9 @@ public class BuildArgParser extends Main { } else if (arg.equals("-XjavadocsInModel")) { buildConfig.setGenerateModelMode(true); buildConfig.setGenerateJavadocsInModelMode(true); - } else if (arg.equals("-noweave") || arg.equals( "-XnoWeave")) { + } else if (arg.equals("-Xdev:NoAtAspectJProcessing")) { + buildConfig.setNoAtAspectJAnnotationProcessing(true); + }else if (arg.equals("-noweave") || arg.equals( "-XnoWeave")) { buildConfig.setNoWeave(true); } else if (arg.equals("-XserializableAspects")) { buildConfig.setXserializableAspects(true); diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompilerAdapter.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompilerAdapter.java index 9091a8c15..8085a51f4 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompilerAdapter.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/AjCompilerAdapter.java @@ -19,20 +19,24 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import org.aspectj.ajdt.internal.compiler.ast.AddAtAspectJAnnotationsVisitor; +import org.aspectj.ajdt.internal.compiler.ast.ValidateAtAspectJAnnotationsVisitor; import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory; +import org.aspectj.ajdt.internal.core.builder.AjCompilerOptions; import org.aspectj.bridge.IMessage; import org.aspectj.bridge.IMessageHandler; import org.aspectj.bridge.IProgressListener; -import org.aspectj.weaver.bcel.BcelWeaver; -import org.aspectj.weaver.bcel.BcelWorld; -import org.aspectj.weaver.patterns.CflowPointcut; import org.aspectj.org.eclipse.jdt.core.compiler.IProblem; import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult; import org.aspectj.org.eclipse.jdt.internal.compiler.Compiler; import org.aspectj.org.eclipse.jdt.internal.compiler.ICompilerAdapter; import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit; +import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortCompilation; +import org.aspectj.weaver.bcel.BcelWeaver; +import org.aspectj.weaver.bcel.BcelWorld; +import org.aspectj.weaver.patterns.CflowPointcut; /** * @author colyer @@ -48,6 +52,8 @@ public class AjCompilerAdapter implements ICompilerAdapter { private boolean reportedErrors; private boolean isXNoWeave; private boolean proceedOnError; + private boolean inJava5Mode; + private boolean noAtAspectJAnnotationProcessing; private IIntermediateResultsRequestor intermediateResultsRequestor; private IProgressListener progressListener; private IOutputClassFileNameProvider outputFileNameProvider; @@ -55,7 +61,6 @@ public class AjCompilerAdapter implements ICompilerAdapter { private WeaverMessageHandler weaverMessageHandler; private Map /* fileName |-> List */ binarySourceSetForFullWeave = new HashMap(); private Collection /*InterimCompilationResult*/ resultSetForFullWeave = Collections.EMPTY_LIST; - List /*InterimResult*/ resultsPendingWeave = new ArrayList(); @@ -86,7 +91,8 @@ public class AjCompilerAdapter implements ICompilerAdapter { Map fullBinarySourceEntries, /* fileName |-> List */ Collection /* InterimCompilationResult */ resultSetForFullWeave, boolean isXNoWeave, - boolean proceedOnError) { + boolean proceedOnError, + boolean noAtAspectJProcessing) { this.compiler = compiler; this.isBatchCompile = isBatchCompile; this.weaver = weaver; @@ -99,6 +105,10 @@ public class AjCompilerAdapter implements ICompilerAdapter { this.binarySourceSetForFullWeave = fullBinarySourceEntries; this.resultSetForFullWeave = resultSetForFullWeave; this.eWorld = eFactory; + this.inJava5Mode = false; + this.noAtAspectJAnnotationProcessing = noAtAspectJProcessing; + + if (compiler.options.complianceLevel == CompilerOptions.JDK1_5) inJava5Mode = true; IMessageHandler msgHandler = world.getMessageHandler(); weaverMessageHandler = new WeaverMessageHandler(msgHandler, compiler); @@ -133,6 +143,17 @@ public class AjCompilerAdapter implements ICompilerAdapter { public void beforeProcessing(CompilationUnitDeclaration unit) { eWorld.showMessage(IMessage.INFO, "compiling " + new String(unit.getFileName()), null, null); + if (inJava5Mode && !noAtAspectJAnnotationProcessing) { + AddAtAspectJAnnotationsVisitor atAspectJVisitor = new AddAtAspectJAnnotationsVisitor(unit); + unit.traverse(atAspectJVisitor, unit.scope); + } + } + + public void beforeAnalysing(CompilationUnitDeclaration unit) { + if (inJava5Mode && !noAtAspectJAnnotationProcessing) { + ValidateAtAspectJAnnotationsVisitor atAspectJVisitor = new ValidateAtAspectJAnnotationsVisitor(unit); + unit.traverse(atAspectJVisitor, unit.scope); + } } public void afterProcessing(CompilationUnitDeclaration unit, int unitIndex) { diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AddAtAspectJAnnotationsVisitor.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AddAtAspectJAnnotationsVisitor.java new file mode 100644 index 000000000..8b4ade56e --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AddAtAspectJAnnotationsVisitor.java @@ -0,0 +1,61 @@ +/* ******************************************************************* + * Copyright (c) 2005 IBM Corporation Ltd + * 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: + * Adrian Colyer initial implementation + * ******************************************************************/ +package org.aspectj.ajdt.internal.compiler.ast; + +import org.aspectj.org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; +import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; + +public class AddAtAspectJAnnotationsVisitor extends ASTVisitor { + + private CompilationUnitDeclaration unit; + + public AddAtAspectJAnnotationsVisitor(CompilationUnitDeclaration unit) { + this.unit = unit; + } + + public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) { + if (localTypeDeclaration instanceof AspectDeclaration) { + ((AspectDeclaration) localTypeDeclaration).addAtAspectJAnnotations(); + } + return true; + } + + + public boolean visit(TypeDeclaration memberTypeDeclaration,ClassScope scope) { + if (memberTypeDeclaration instanceof AspectDeclaration) { + ((AspectDeclaration) memberTypeDeclaration).addAtAspectJAnnotations(); + } + return true; + } + + public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) { + if (typeDeclaration instanceof AspectDeclaration) { + ((AspectDeclaration) typeDeclaration).addAtAspectJAnnotations(); + } + return true; + } + public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) { + if (methodDeclaration instanceof AdviceDeclaration) { + ((AdviceDeclaration)methodDeclaration).addAtAspectJAnnotations(); + } else if (methodDeclaration instanceof PointcutDeclaration) { + ((PointcutDeclaration)methodDeclaration).addAtAspectJAnnotations(); + } + return false; + } + + +} diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AdviceDeclaration.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AdviceDeclaration.java index a81ad0abf..6e2d95591 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AdviceDeclaration.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AdviceDeclaration.java @@ -20,14 +20,10 @@ 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.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.TypeX; +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.TypeDeclaration; import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference; @@ -37,7 +33,12 @@ import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope; 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.core.compiler.CharOperation; +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.TypeX; /** * Represents before, after and around advice in an aspect. @@ -47,22 +48,21 @@ import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation; * @author Jim Hugunin */ public class AdviceDeclaration extends AjMethodDeclaration { - public PointcutDesignator pointcutDesignator; - int baseArgumentCount; + public PointcutDesignator pointcutDesignator; // set during parsing + int baseArgumentCount; // referenced by IfPseudoToken.makeArguments - public Argument extraArgument; + public Argument extraArgument; // set during parsing, referenced by Proceed - public AdviceKind kind; + public AdviceKind kind; // set during parsing, referenced by Proceed and AsmElementFormatter private int extraArgumentFlags = 0; - public MethodBinding proceedMethodBinding; - + public MethodBinding proceedMethodBinding; // set during this.resolveStaments, referenced by Proceed + public List proceedCalls = new ArrayList(2); // populated during Proceed.findEnclosingAround - public List proceedCalls = new ArrayList(2); - public boolean proceedInInners; - public ResolvedMember[] proceedCallSignatures; - public boolean[] formalsUnchangedToProceed; - public TypeX[] declaredExceptions; + private boolean proceedInInners; + private ResolvedMember[] proceedCallSignatures; + private boolean[] formalsUnchangedToProceed; + private TypeX[] declaredExceptions; public AdviceDeclaration(CompilationResult result, AdviceKind kind) { @@ -71,7 +71,7 @@ public class AdviceDeclaration extends AjMethodDeclaration { this.kind = kind; } - + // override protected int generateInfoAttributes(ClassFile classFile) { List l = new ArrayList(1); l.add(new EclipseAttributeAdapter(makeAttribute())); @@ -80,7 +80,7 @@ public class AdviceDeclaration extends AjMethodDeclaration { return classFile.generateMethodInfoAttribute(binding, false, l); } - public AjAttribute makeAttribute() { + private AjAttribute makeAttribute() { if (kind == AdviceKind.Around) { return new AjAttribute.AdviceAttribute(kind, pointcutDesignator.getPointcut(), extraArgumentFlags, sourceStart, sourceEnd, null, @@ -92,6 +92,7 @@ public class AdviceDeclaration extends AjMethodDeclaration { } } + // override public void resolveStatements() { if (binding == null || ignoreFurtherInvestigation) return; @@ -172,14 +173,14 @@ public class AdviceDeclaration extends AjMethodDeclaration { } } - + // 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); } - public void generateProceedMethod(ClassScope classScope, ClassFile classFile) { + private void generateProceedMethod(ClassScope classScope, ClassFile classFile) { MethodBinding binding = (MethodBinding)proceedMethodBinding; classFile.generateMethodInfoHeader(binding); @@ -243,7 +244,7 @@ public class AdviceDeclaration extends AjMethodDeclaration { } - + // override public void generateCode(ClassScope classScope, ClassFile classFile) { if (ignoreFurtherInvestigation) return; @@ -268,7 +269,39 @@ public class AdviceDeclaration extends AjMethodDeclaration { 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); + } + + if (kind == AdviceKind.Before) { + adviceAnnotation = AtAspectJAnnotationFactory.createBeforeAnnotation(pointcutExpression,declarationSourceStart); + } else if (kind == AdviceKind.After) { + adviceAnnotation = AtAspectJAnnotationFactory.createAfterAnnotation(pointcutExpression,declarationSourceStart); + } else if (kind == AdviceKind.AfterReturning) { + adviceAnnotation = AtAspectJAnnotationFactory.createAfterReturningAnnotation(pointcutExpression,extraArgumentName,declarationSourceStart); + } else if (kind == AdviceKind.AfterThrowing) { + adviceAnnotation = AtAspectJAnnotationFactory.createAfterThrowingAnnotation(pointcutExpression,extraArgumentName,declarationSourceStart); + } else if (kind == AdviceKind.Around) { + adviceAnnotation = AtAspectJAnnotationFactory.createAroundAnnotation(pointcutExpression,declarationSourceStart); + } + if (annotations == null) { + annotations = new Annotation[] { adviceAnnotation }; + } else { + Annotation[] old = annotations; + annotations = new Annotation[old.length +1]; + System.arraycopy(old,0,annotations,0,old.length); + annotations[old.length] = adviceAnnotation; + } + } + // override, Called by ClassScope.postParse public void postParse(TypeDeclaration typeDec) { int adviceSequenceNumberInType = ((AspectDeclaration)typeDec).adviceCounter++; @@ -321,7 +354,7 @@ public class AdviceDeclaration extends AjMethodDeclaration { } } - + // called by IfPseudoToken public static Argument[] addTjpArguments(Argument[] arguments) { int index = arguments.length; arguments = extendArgumentsLength(arguments, 3); diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AjMethodDeclaration.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AjMethodDeclaration.java index bb31f5e16..efaedf2b5 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AjMethodDeclaration.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AjMethodDeclaration.java @@ -25,6 +25,8 @@ import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; */ public class AjMethodDeclaration extends MethodDeclaration { + private List attributes = new ArrayList(); + /** * @param compilationResult */ @@ -32,12 +34,18 @@ public class AjMethodDeclaration extends MethodDeclaration { super(compilationResult); } + // general purpose hook to add an AjAttribute to this method + // used by @AspectJ visitor to add pointcut attribute to @Advice + protected void addAttribute(EclipseAttributeAdapter eaa) { + attributes.add(eaa); + } + /** * Overridden to add extra AJ stuff, also adds synthetic if boolean is true. */ protected int generateInfoAttributes(ClassFile classFile,boolean addAjSynthetic) { // add extra attributes into list then call 2-arg version of generateInfoAttributes... - List extras = new ArrayList(); + List extras = attributes; addDeclarationStartLineAttribute(extras,classFile); if (addAjSynthetic) { extras.add(new EclipseAttributeAdapter(new AjAttribute.AjSynthetic())); diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AspectDeclaration.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AspectDeclaration.java index 31eb13fe5..f9beb3f85 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AspectDeclaration.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AspectDeclaration.java @@ -14,23 +14,53 @@ package org.aspectj.ajdt.internal.compiler.ast; import java.lang.reflect.Modifier; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; -import org.aspectj.ajdt.internal.compiler.lookup.*; -import org.aspectj.weaver.*; -import org.aspectj.weaver.patterns.*; +import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory; +import org.aspectj.ajdt.internal.compiler.lookup.EclipseScope; +import org.aspectj.ajdt.internal.compiler.lookup.EclipseSourceType; +import org.aspectj.ajdt.internal.compiler.lookup.EclipseTypeMunger; +import org.aspectj.ajdt.internal.compiler.lookup.HelperInterfaceBinding; +import org.aspectj.ajdt.internal.compiler.lookup.InlineAccessFieldBinding; +import org.aspectj.ajdt.internal.compiler.lookup.PrivilegedHandler; 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.AbstractMethodDeclaration; +import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation; import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Clinit; import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; -//import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.CodeStream; import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.ExceptionLabel; import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.Label; import org.aspectj.org.eclipse.jdt.internal.compiler.env.IGenericType; -import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.*; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BaseTypes; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.InvocationSite; +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.Scope; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding; +import org.aspectj.weaver.AjAttribute; +import org.aspectj.weaver.AjcMemberMaker; +import org.aspectj.weaver.NameMangler; +import org.aspectj.weaver.ResolvedMember; +import org.aspectj.weaver.ResolvedTypeX; +import org.aspectj.weaver.Shadow; +import org.aspectj.weaver.TypeX; +import org.aspectj.weaver.patterns.Declare; +import org.aspectj.weaver.patterns.FormalBinding; +import org.aspectj.weaver.patterns.PerClause; +import org.aspectj.weaver.patterns.PerFromSuper; +import org.aspectj.weaver.patterns.PerSingleton; +import org.aspectj.weaver.patterns.TypePattern; //import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser; @@ -158,6 +188,28 @@ public class AspectDeclaration extends TypeDeclaration { private FieldBinding initFailureField= null; + /** + * AMC - this method is called by the AtAspectJVisitor during beforeCompilation processing in + * the AjCompiler adapter. We use this hook to add in the @AspectJ annotations. + */ + public void addAtAspectJAnnotations() { + Annotation atAspectAnnotation = AtAspectJAnnotationFactory.createAspectAnnotation(perClause.toDeclarationString(), declarationSourceStart); + Annotation privilegedAnnotation = null; + if (isPrivileged) privilegedAnnotation = AtAspectJAnnotationFactory.createPrivilegedAnnotation(declarationSourceStart); + Annotation[] toAdd = new Annotation[isPrivileged ? 2 : 1]; + toAdd[0] = atAspectAnnotation; + if (isPrivileged) toAdd[1] = privilegedAnnotation; + if (annotations == null) { + annotations = toAdd; + } else { + Annotation[] old = annotations; + annotations = new Annotation[annotations.length + toAdd.length]; + System.arraycopy(old,0,annotations,0,old.length); + System.arraycopy(toAdd,0,annotations,old.length,toAdd.length); + } + } + + public void generateCode(ClassFile enclosingClassFile) { if (ignoreFurtherInvestigation) { if (binding == null) diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AtAspectJAnnotationFactory.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AtAspectJAnnotationFactory.java new file mode 100644 index 000000000..304cd4761 --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/AtAspectJAnnotationFactory.java @@ -0,0 +1,146 @@ +/* ******************************************************************* + * Copyright (c) 2005 Contributors. + * 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://eclipse.org/legal/epl-v10.html + * + * Contributors: + * Adrian Colyer Initial implementation + * ******************************************************************/ +package org.aspectj.ajdt.internal.compiler.ast; + +import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Expression; +import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MemberValuePair; +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.StringLiteral; +import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference; + +/** + * @author colyer + * Creates @AspectJ annotations for use by AtAspectJVisitor + */ +public class AtAspectJAnnotationFactory { + + static final char[] org = "org".toCharArray(); + static final char[] aspectj = "aspectj".toCharArray(); + static final char[] lang = "lang".toCharArray(); + static final char[] internal = "internal".toCharArray(); + static final char[] annotation = "annotation".toCharArray(); + static final char[] value = "value".toCharArray(); + + static final char[] aspect = "Aspect".toCharArray(); + static final char[] privileged = "ajcPrivileged".toCharArray(); + static final char[] before = "Before".toCharArray(); + static final char[] after = "After".toCharArray(); + static final char[] afterReturning = "AfterReturning".toCharArray(); + static final char[] afterThrowing = "AfterThrowing".toCharArray(); + static final char[] around = "Around".toCharArray(); + static final char[] pointcut = "Pointcut".toCharArray(); + + /** + * Create an @Aspect annotation for a code style aspect declaration starting at + * the given position in the source file + */ + public static Annotation createAspectAnnotation(String perclause, int pos) { + char[][] typeName = new char[][] {org,aspectj,lang,annotation,aspect}; + long[] positions = new long[] {pos,pos,pos,pos,pos}; + TypeReference orgAspectJLangAnnotationAspect = new QualifiedTypeReference(typeName,positions); + NormalAnnotation atAspectAnnotation = new NormalAnnotation(orgAspectJLangAnnotationAspect,pos); + if (!perclause.equals("")) { + // we have to set the value + Expression perclauseExpr = new StringLiteral(perclause.toCharArray(),pos,pos); + MemberValuePair[] mvps = new MemberValuePair[1]; + mvps[0] = new MemberValuePair(value,pos,pos,perclauseExpr); + atAspectAnnotation.memberValuePairs = mvps; + } + return atAspectAnnotation; + } + + public static Annotation createPrivilegedAnnotation(int pos) { + char[][] typeName = new char[][] {org,aspectj,internal,lang,annotation,privileged}; + long[] positions = new long[] {pos,pos,pos,pos,pos,pos}; + TypeReference annType = new QualifiedTypeReference(typeName,positions); + NormalAnnotation ann = new NormalAnnotation(annType,pos); + return ann; + } + + public static Annotation createBeforeAnnotation(String pointcutExpression, int pos) { + char[][] typeName = new char[][] {org,aspectj,lang,annotation,before}; + long[] positions = new long[] {pos,pos,pos,pos,pos}; + TypeReference annType = new QualifiedTypeReference(typeName,positions); + NormalAnnotation ann = new NormalAnnotation(annType,pos); + Expression pcExpr = new StringLiteral(pointcutExpression.toCharArray(),pos,pos); + MemberValuePair[] mvps = new MemberValuePair[1]; + mvps[0] = new MemberValuePair(value,pos,pos,pcExpr); + ann.memberValuePairs = mvps; + return ann; + } + + public static Annotation createAfterAnnotation(String pointcutExpression, int pos) { + char[][] typeName = new char[][] {org,aspectj,lang,annotation,after}; + long[] positions = new long[] {pos,pos,pos,pos,pos}; + TypeReference annType = new QualifiedTypeReference(typeName,positions); + NormalAnnotation ann = new NormalAnnotation(annType,pos); + Expression pcExpr = new StringLiteral(pointcutExpression.toCharArray(),pos,pos); + MemberValuePair[] mvps = new MemberValuePair[1]; + mvps[0] = new MemberValuePair(value,pos,pos,pcExpr); + ann.memberValuePairs = mvps; + return ann; + } + + public static Annotation createAfterReturningAnnotation(String pointcutExpression, String extraArgumentName, int pos) { + char[][] typeName = new char[][] {org,aspectj,lang,annotation,afterReturning}; + long[] positions = new long[] {pos,pos,pos,pos,pos}; + TypeReference annType = new QualifiedTypeReference(typeName,positions); + NormalAnnotation ann = new NormalAnnotation(annType,pos); + Expression pcExpr = new StringLiteral(pointcutExpression.toCharArray(),pos,pos); + MemberValuePair[] mvps = new MemberValuePair[2]; + mvps[0] = new MemberValuePair("pointcut".toCharArray(),pos,pos,pcExpr); + Expression argExpr = new StringLiteral(extraArgumentName.toCharArray(),pos,pos); + mvps[1] = new MemberValuePair("returning".toCharArray(),pos,pos,argExpr); + ann.memberValuePairs = mvps; + return ann; + } + + public static Annotation createAfterThrowingAnnotation(String pointcutExpression, String extraArgumentName, int pos) { + char[][] typeName = new char[][] {org,aspectj,lang,annotation,afterThrowing}; + long[] positions = new long[] {pos,pos,pos,pos,pos}; + TypeReference annType = new QualifiedTypeReference(typeName,positions); + NormalAnnotation ann = new NormalAnnotation(annType,pos); + Expression pcExpr = new StringLiteral(pointcutExpression.toCharArray(),pos,pos); + MemberValuePair[] mvps = new MemberValuePair[2]; + mvps[0] = new MemberValuePair("pointcut".toCharArray(),pos,pos,pcExpr); + Expression argExpr = new StringLiteral(extraArgumentName.toCharArray(),pos,pos); + mvps[1] = new MemberValuePair("throwing".toCharArray(),pos,pos,argExpr); + ann.memberValuePairs = mvps; + return ann; + } + + public static Annotation createAroundAnnotation(String pointcutExpression, int pos) { + char[][] typeName = new char[][] {org,aspectj,lang,annotation,around}; + long[] positions = new long[] {pos,pos,pos,pos,pos}; + TypeReference annType = new QualifiedTypeReference(typeName,positions); + NormalAnnotation ann = new NormalAnnotation(annType,pos); + Expression pcExpr = new StringLiteral(pointcutExpression.toCharArray(),pos,pos); + MemberValuePair[] mvps = new MemberValuePair[1]; + mvps[0] = new MemberValuePair(value,pos,pos,pcExpr); + ann.memberValuePairs = mvps; + return ann; + } + + public static Annotation createPointcutAnnotation(String pointcutExpression, int pos) { + char[][] typeName = new char[][] {org,aspectj,lang,annotation,pointcut}; + long[] positions = new long[] {pos,pos,pos,pos,pos}; + TypeReference annType = new QualifiedTypeReference(typeName,positions); + NormalAnnotation ann = new NormalAnnotation(annType,pos); + Expression pcExpr = new StringLiteral(pointcutExpression.toCharArray(),pos,pos); + MemberValuePair[] mvps = new MemberValuePair[1]; + mvps[0] = new MemberValuePair(value,pos,pos,pcExpr); + ann.memberValuePairs = mvps; + return ann; + } +} diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/PointcutDeclaration.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/PointcutDeclaration.java index 870a5edc0..4c46411b8 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/PointcutDeclaration.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/PointcutDeclaration.java @@ -17,20 +17,22 @@ import java.lang.reflect.Modifier; import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory; import org.aspectj.ajdt.internal.core.builder.EclipseSourceContext; -import org.aspectj.weaver.AjAttribute; -import org.aspectj.weaver.ResolvedPointcutDefinition; -//import org.aspectj.weaver.ResolvedTypeX; -//import org.aspectj.weaver.TypeX; -import org.aspectj.weaver.patterns.Pointcut; +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.flow.FlowInfo; +import org.aspectj.org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext; import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TagBits; import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser; -import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation; +import org.aspectj.weaver.AjAttribute; +import org.aspectj.weaver.ResolvedPointcutDefinition; +import org.aspectj.weaver.patterns.Pointcut; /** * pointcut [declaredModifiers] [declaredName]([arguments]): [pointcutDesignator]; @@ -46,6 +48,8 @@ public class PointcutDeclaration extends AjMethodDeclaration { public PointcutDesignator pointcutDesignator; private int declaredModifiers; private String declaredName; + private boolean generateSyntheticPointcutMethod = false; + //private boolean mangleSelector = true; private ResolvedPointcutDefinition resolvedPointcutDeclaration = null; @@ -73,8 +77,14 @@ public class PointcutDeclaration extends AjMethodDeclaration { if (arguments == null) arguments = new Argument[0]; this.declaredModifiers = modifiers; this.declaredName = new String(selector); - selector = CharOperation.concat(mangledPrefix, '$', selector, '$', - Integer.toHexString(sourceStart).toCharArray()); + // 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)) { @@ -98,8 +108,39 @@ public class PointcutDeclaration extends AjMethodDeclaration { } } + + /** + * Called from the AtAspectJVisitor to create the @Pointcut annotation + * (and corresponding method) for this pointcut + * + */ + public void addAtAspectJAnnotations() { + Annotation pcutAnnotation = AtAspectJAnnotationFactory.createPointcutAnnotation(getPointcut().toString(),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; + } + + // coming from an @Pointcut declaration + public void setGenerateSyntheticPointcutMethod() { + generateSyntheticPointcutMethod = true; + //mangleSelector = false; + } + public void resolve(ClassScope upperScope) { - // this method should do nothing, use the entry point below... + // 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) { @@ -152,6 +193,7 @@ public class PointcutDeclaration extends AjMethodDeclaration { public AjAttribute makeAttribute() { return new AjAttribute.PointcutDeclarationAttribute(makeResolvedPointcutDefinition()); } + /** * A pointcut declaration exists in a classfile only as an attibute on the @@ -161,9 +203,16 @@ public class PointcutDeclaration extends AjMethodDeclaration { public void generateCode(ClassScope classScope, ClassFile classFile) { if (ignoreFurtherInvestigation) return ; classFile.extraAttributes.add(new EclipseAttributeAdapter(makeAttribute())); + if (generateSyntheticPointcutMethod) { + super.generateCode(classScope,classFile); + } return; } + protected int generateInfoAttributes(ClassFile classFile) { + return super.generateInfoAttributes(classFile,true); + } + public StringBuffer printReturnType(int indent, StringBuffer output) { return output.append("pointcut"); } diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/PointcutDesignator.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/PointcutDesignator.java index 9bede187a..9b3b2adfa 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/PointcutDesignator.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/PointcutDesignator.java @@ -13,20 +13,20 @@ package org.aspectj.ajdt.internal.compiler.ast; -import org.aspectj.ajdt.internal.compiler.lookup.EclipseScope; import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory; -import org.aspectj.weaver.TypeX; -import org.aspectj.weaver.patterns.FormalBinding; -import org.aspectj.weaver.patterns.Pointcut; +import org.aspectj.ajdt.internal.compiler.lookup.EclipseScope; +import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument; -import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser; +import org.aspectj.weaver.TypeX; +import org.aspectj.weaver.patterns.FormalBinding; +import org.aspectj.weaver.patterns.Pointcut; public class PointcutDesignator extends ASTNode { private Pointcut pointcut; @@ -46,8 +46,14 @@ public class PointcutDesignator extends ASTNode { pointcut = pc; } + // called by AtAspectJVisitor + public PointcutDesignator(Pointcut pc) { + this.pointcut = pc; + } + public void postParse(TypeDeclaration typeDec, MethodDeclaration enclosingDec) { - tokens.postParse(typeDec, enclosingDec); + if (tokens != null) + tokens.postParse(typeDec, enclosingDec); } diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/ValidateAtAspectJAnnotationsVisitor.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/ValidateAtAspectJAnnotationsVisitor.java new file mode 100644 index 000000000..6da29969f --- /dev/null +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/ast/ValidateAtAspectJAnnotationsVisitor.java @@ -0,0 +1,615 @@ +/* ******************************************************************* + * Copyright (c) 2005 IBM Corporation Ltd + * 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: + * Adrian Colyer initial implementation + * ******************************************************************/ +package org.aspectj.ajdt.internal.compiler.ast; + +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory; +import org.aspectj.ajdt.internal.compiler.lookup.EclipseScope; +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.ASTVisitor; +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.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.SingleMemberAnnotation; +import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; +import org.aspectj.org.eclipse.jdt.internal.compiler.ast.StringLiteral; +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.lookup.BlockScope; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; +import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding; +import org.aspectj.weaver.AdviceKind; +import org.aspectj.weaver.AjAttribute; +import org.aspectj.weaver.ISourceContext; +import org.aspectj.weaver.ResolvedPointcutDefinition; +import org.aspectj.weaver.TypeX; +import org.aspectj.weaver.patterns.FormalBinding; +import org.aspectj.weaver.patterns.ParserException; +import org.aspectj.weaver.patterns.PatternParser; +import org.aspectj.weaver.patterns.Pointcut; + +public class ValidateAtAspectJAnnotationsVisitor extends ASTVisitor { + + private static final char[] beforeAdviceSig = "Lorg/aspectj/lang/annotation/Before;".toCharArray(); + private static final char[] afterAdviceSig = "Lorg/aspectj/lang/annotation/After;".toCharArray(); + private static final char[] afterReturningAdviceSig = "Lorg/aspectj/lang/annotation/AfterReturning;".toCharArray(); + private static final char[] afterThrowingAdviceSig = "Lorg/aspectj/lang/annotation/AfterThrowing;".toCharArray(); + private static final char[] aroundAdviceSig = "Lorg/aspectj/lang/annotation/Around;".toCharArray(); + private static final char[] pointcutSig = "Lorg/aspectj/lang/annotation/Pointcut;".toCharArray(); + private static final char[] aspectSig = "Lorg/aspectj/lang/annotation/Aspect;".toCharArray(); + private static final char[] adviceNameSig = "Lorg/aspectj/lang/annotation/AdviceName;".toCharArray(); + private static final char[] orgAspectJLangAnnotation = "org/aspectj/lang/annotation/".toCharArray(); + private static final char[] voidType = "void".toCharArray(); + private static final char[] joinPoint = "Lorg/aspectj/lang/JoinPoint;".toCharArray(); + private static final char[] joinPointStaticPart = "Lorg/aspectj/lang/JoinPoint$StaticPart;".toCharArray(); + private static final char[] joinPointEnclosingStaticPart = "Lorg/aspectj/lang/JoinPoint$EnclosingStaticPart;".toCharArray(); + private static final char[] proceedingJoinPoint = "Lorg/aspectj/lang/ProceedingJoinPoint;".toCharArray(); + private static final char[][] adviceSigs = new char[][] {beforeAdviceSig,afterAdviceSig,afterReturningAdviceSig,afterThrowingAdviceSig,aroundAdviceSig}; + + + private CompilationUnitDeclaration unit; + private Stack typeStack = new Stack(); + + public ValidateAtAspectJAnnotationsVisitor(CompilationUnitDeclaration unit) { + this.unit = unit; + } + + public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) { + typeStack.push(localTypeDeclaration); + checkTypeDeclaration(localTypeDeclaration); + return true; + } + + public void endVisit(TypeDeclaration localTypeDeclaration,BlockScope scope) { + typeStack.pop(); + } + + public boolean visit(TypeDeclaration memberTypeDeclaration,ClassScope scope) { + typeStack.push(memberTypeDeclaration); + checkTypeDeclaration(memberTypeDeclaration); + return true; + } + + public void endVisit(TypeDeclaration memberTypeDeclaration,ClassScope scope) { + typeStack.pop(); + } + + public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) { + typeStack.push(typeDeclaration); + checkTypeDeclaration(typeDeclaration); + return true; + } + + public void endVisit(TypeDeclaration typeDeclaration,CompilationUnitScope scope) { + typeStack.pop(); + } + + private void checkTypeDeclaration(TypeDeclaration typeDecl) { + if (!(typeDecl instanceof AspectDeclaration)) { + if (insideAspect()) { + validateAspectDeclaration(typeDecl); + } else { + // check that class doesn't extend aspect + TypeReference parentRef = typeDecl.superclass; + if (parentRef != null) { + TypeBinding parentBinding = parentRef.resolvedType; + if (parentBinding instanceof SourceTypeBinding) { + SourceTypeBinding parentSTB = (SourceTypeBinding) parentBinding; + if (parentSTB.scope != null) { + TypeDeclaration parentDecl = parentSTB.scope.referenceContext; + if (isAspect(parentDecl)) { + typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"a class cannot extend an aspect"); + } + } + } + } + } + } else { + // check that aspect doesn't have @Aspect annotation + boolean foundAspectAnnotation = false; + for (int i = 0; i < typeDecl.annotations.length; i++) { + if (typeDecl.annotations[i].resolvedType == null) continue; + char[] sig = typeDecl.annotations[i].resolvedType.signature(); + if (CharOperation.equals(aspectSig,sig)) { + if (!foundAspectAnnotation) { + foundAspectAnnotation = true; // this is the one we added in the first visitor pass + } else { + //a second @Aspect annotation, user must have declared one... + typeDecl.scope.problemReporter().signalError( + typeDecl.sourceStart, + typeDecl.sourceEnd, + "aspects cannot have @Aspect annotation" + ); + } + } + } + } + } + + public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) { + if (!methodDeclaration.getClass().equals(AjMethodDeclaration.class)) { + // simply test for innapropriate use of annotations on code-style members + if (!hasAspectJAnnotation(methodDeclaration)) return false; + int numPointcutAnnotations = 0; + int numAdviceAnnotations = 0; + int numAdviceNameAnnotations = 0; + for (int i=0; i < methodDeclaration.annotations.length; i++) { + if (isAspectJAnnotation(methodDeclaration.annotations[i])) { + if (CharOperation.equals(adviceNameSig,methodDeclaration.annotations[i].resolvedType.signature())) { + numAdviceNameAnnotations++; + } else if (CharOperation.equals(pointcutSig,methodDeclaration.annotations[i].resolvedType.signature())) { + numPointcutAnnotations++; + } else { + for (int j = 0; j < adviceSigs.length; j++) { + if (CharOperation.equals(adviceSigs[j],methodDeclaration.annotations[i].resolvedType.signature())) { + numAdviceAnnotations++; + } + } + } + } + } + if (methodDeclaration instanceof PointcutDeclaration) { + if (numPointcutAnnotations > 1 || numAdviceAnnotations > 0 || numAdviceNameAnnotations > 0) { + methodDeclaration.scope.problemReporter().signalError( + methodDeclaration.sourceStart, + methodDeclaration.sourceEnd, + "@AspectJ annotations cannot be declared on this aspect member"); + } + } else if (methodDeclaration instanceof AdviceDeclaration) { + if (numPointcutAnnotations > 0 || numAdviceAnnotations > 1) { + methodDeclaration.scope.problemReporter().signalError( + methodDeclaration.sourceStart, + methodDeclaration.sourceEnd, + "Only @AdviceName AspectJ annotation allowed on advice"); + } + } else { + if (numPointcutAnnotations > 0 || numAdviceAnnotations > 0 || numAdviceNameAnnotations > 0) { + methodDeclaration.scope.problemReporter().signalError( + methodDeclaration.sourceStart, + methodDeclaration.sourceEnd, + "@AspectJ annotations cannot be declared on this aspect member"); + } + } + return false; + } + if (isAnnotationStyleAdvice(methodDeclaration.annotations)) { + validateAdvice(methodDeclaration); + } else if (isAnnotationStylePointcut(methodDeclaration.annotations)) { + convertToPointcutDeclaration(methodDeclaration,scope); + } + return false; + } + + + + private boolean isAnnotationStyleAdvice(Annotation[] annotations) { + if (annotations == null) return false; + for (int i = 0; i < annotations.length; i++) { + if (annotations[i].resolvedType == null) continue; + char[] sig = annotations[i].resolvedType.signature(); + if (CharOperation.equals(beforeAdviceSig,sig) || + CharOperation.equals(afterAdviceSig,sig) || + CharOperation.equals(afterReturningAdviceSig,sig) || + CharOperation.equals(aroundAdviceSig,sig) || + CharOperation.equals(afterThrowingAdviceSig,sig)) { + return true; + } + } + return false; + } + + private boolean isAnnotationStylePointcut(Annotation[] annotations) { + if (annotations == null) return false; + for (int i = 0; i < annotations.length; i++) { + if (annotations[i].resolvedType == null) continue; + char[] sig = annotations[i].resolvedType.signature(); + if (CharOperation.equals(pointcutSig,sig)) { + return true; + } + } + return false; + } + + private boolean hasAspectJAnnotation(MethodDeclaration methodDecl) { + if (methodDecl.annotations == null) return false; + for (int i=0; i < methodDecl.annotations.length; i++) { + if (isAspectJAnnotation(methodDecl.annotations[i])) return true; + } + return false; + } + + private boolean isAspectJAnnotation(Annotation ann) { + if (ann.resolvedType == null) return false; + char[] sig = ann.resolvedType.signature(); + return CharOperation.contains(orgAspectJLangAnnotation, sig); + } + + private boolean insideAspect() { + if (typeStack.empty()) return false; + TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek(); + return isAspect(typeDecl); + } + + private boolean isAspect(TypeDeclaration typeDecl) { + if (typeDecl instanceof AspectDeclaration) return true; + return hasAspectAnnotation(typeDecl); + } + + private boolean hasAspectAnnotation(TypeDeclaration typeDecl) { + if (typeDecl.annotations == null) return false; + for (int i = 0; i < typeDecl.annotations.length; i++) { + if (typeDecl.annotations[i].resolvedType == null) continue; + char[] sig = typeDecl.annotations[i].resolvedType.signature(); + if (CharOperation.equals(aspectSig,sig)) { + return true; + } + } + return false; + } + + /** + * nested aspect must be static + * cannot extend a concrete aspect + * pointcut in perclause must be good. + */ + private void validateAspectDeclaration(TypeDeclaration typeDecl) { + if (typeStack.size() > 1) { + // it's a nested aspect + if (!Modifier.isStatic(typeDecl.modifiers)) { + typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart, typeDecl.sourceEnd, "inner aspects must be static"); + return; + } + } + + SourceTypeBinding binding = typeDecl.binding; + if (binding != null) { + if (binding.isEnum() || binding.isInterface() || binding.isAnnotationType()) { + typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"only classes can have an @Aspect annotation"); + } + } + + TypeReference parentRef = typeDecl.superclass; + if (parentRef != null) { + TypeBinding parentBinding = parentRef.resolvedType; + if (parentBinding instanceof SourceTypeBinding) { + SourceTypeBinding parentSTB = (SourceTypeBinding) parentBinding; + TypeDeclaration parentDecl = parentSTB.scope.referenceContext; + if (isAspect(parentDecl) && !Modifier.isAbstract(parentDecl.modifiers)) { + typeDecl.scope.problemReporter().signalError(typeDecl.sourceStart,typeDecl.sourceEnd,"cannot extend a concrete aspect"); + } + } + } + + Annotation aspectAnnotation = null; + for (int i = 0; i < typeDecl.annotations.length; i++) { + if (typeDecl.annotations[i].resolvedType == null) continue; + char[] sig = typeDecl.annotations[i].resolvedType.signature(); + if (CharOperation.equals(aspectSig,sig)) { + aspectAnnotation = typeDecl.annotations[i]; + break; + } + } + + int[] pcLoc = new int[2]; + String perClause = getStringLiteralFor("value", aspectAnnotation, pcLoc); + AspectDeclaration aspectDecl = new AspectDeclaration(typeDecl.compilationResult); + + try { + if (perClause != null && !perClause.equals("")) { + ISourceContext context = new EclipseSourceContext(unit.compilationResult,pcLoc[0]); + Pointcut pc = new PatternParser(perClause,context).maybeParsePerClause(); + FormalBinding[] bindings = new FormalBinding[0]; + if (pc != null) pc.resolve(new EclipseScope(bindings,typeDecl.scope)); + } + } catch(ParserException pEx) { + typeDecl.scope.problemReporter().parseError( + pcLoc[0] + pEx.getLocation().getStart(), + pcLoc[0] + pEx.getLocation().getEnd() , + -1, + perClause.toCharArray(), + perClause, + new String[] {pEx.getMessage()}); + } + } + + /** + * 1) Advice must be public + * 2) Advice must have a void return type if not around advice + * 3) Advice must not have any other @AspectJ annotations + */ + private void validateAdvice(MethodDeclaration methodDeclaration) { + + if (!insideAspect()) { + methodDeclaration.scope.problemReporter().signalError(methodDeclaration.sourceStart, + methodDeclaration.sourceEnd, + "Advice must be declared inside an aspect type"); + } + + if (!Modifier.isPublic(methodDeclaration.modifiers)) { + methodDeclaration.scope.problemReporter() + .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"advice must be public"); + } + + AdviceKind kind = null; + Annotation adviceAnn = null; + Annotation duplicateAnn = null; + for(int i = 0; i < methodDeclaration.annotations.length; i++) { + Annotation ann = methodDeclaration.annotations[i]; + if (isAspectJAnnotation(ann)) { + if (adviceAnn != null) { + duplicateAnn = ann; + break; + } + if (CharOperation.equals(afterAdviceSig,ann.resolvedType.signature())) { + kind = AdviceKind.After; + adviceAnn = ann; + } else if (CharOperation.equals(afterReturningAdviceSig,ann.resolvedType.signature())) { + kind = AdviceKind.AfterReturning; + adviceAnn = ann; + } else if (CharOperation.equals(afterThrowingAdviceSig,ann.resolvedType.signature())) { + kind = AdviceKind.AfterThrowing; + adviceAnn = ann; + } else if (CharOperation.equals(beforeAdviceSig,ann.resolvedType.signature())) { + kind = AdviceKind.Before; + adviceAnn = ann; + } else if (CharOperation.equals(aroundAdviceSig,ann.resolvedType.signature())) { + kind = AdviceKind.Around; + adviceAnn = ann; + } else if (CharOperation.equals(adviceNameSig,ann.resolvedType.signature())) { + methodDeclaration.scope.problemReporter().signalError( + ann.sourceStart,ann.sourceEnd, "AdviceName annotation cannot be used for advice defined using annotation style"); + } + } + } + + if (duplicateAnn != null) { + methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(duplicateAnn); + } + + if (kind != AdviceKind.Around) { + ensureVoidReturnType(methodDeclaration); + } + + resolveAndSetPointcut(methodDeclaration, adviceAnn); + + } + + private void resolveAndSetPointcut(MethodDeclaration methodDeclaration, Annotation adviceAnn) { + int[] pcLocation = new int[2]; + String pointcutExpression = getStringLiteralFor("pointcut",adviceAnn,pcLocation); + if (pointcutExpression == null) pointcutExpression = getStringLiteralFor("value",adviceAnn,pcLocation); + try { + ISourceContext context = new EclipseSourceContext(unit.compilationResult,pcLocation[0]); + Pointcut pc = new PatternParser(pointcutExpression,context).parsePointcut(); + FormalBinding[] bindings = buildFormalAdviceBindingsFrom(methodDeclaration); + pc.resolve(new EclipseScope(bindings,methodDeclaration.scope)); + // now create a ResolvedPointcutDefinition,make an attribute out of it, and add it to the method + TypeX[] paramTypes = new TypeX[bindings.length]; + for (int i = 0; i < paramTypes.length; i++) paramTypes[i] = bindings[i].getType(); + ResolvedPointcutDefinition resPcutDef = + new ResolvedPointcutDefinition( + EclipseFactory.fromBinding(((TypeDeclaration)typeStack.peek()).binding), + methodDeclaration.modifiers, + "anonymous", + paramTypes, + pc + ); + AjAttribute attr = new AjAttribute.PointcutDeclarationAttribute(resPcutDef); + ((AjMethodDeclaration)methodDeclaration).addAttribute(new EclipseAttributeAdapter(attr)); + } catch(ParserException pEx) { + methodDeclaration.scope.problemReporter().parseError( + pcLocation[0] + pEx.getLocation().getStart(), + pcLocation[0] + pEx.getLocation().getEnd() , + -1, + pointcutExpression.toCharArray(), + pointcutExpression, + new String[] {pEx.getMessage()}); + } + } + + private void ensureVoidReturnType(MethodDeclaration methodDeclaration) { + boolean returnsVoid = true; + if ((methodDeclaration.returnType instanceof SingleTypeReference)) { + SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType; + if (!CharOperation.equals(voidType,retType.token)) { + returnsVoid = false; + } + } else { + returnsVoid = false; + } + if (!returnsVoid) { + methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart, + methodDeclaration.returnType.sourceEnd, + "This advice must return void"); + } + } + + private FormalBinding[] buildFormalAdviceBindingsFrom(MethodDeclaration mDecl) { + if (mDecl.arguments == null) return new FormalBinding[0]; + FormalBinding[] ret = new FormalBinding[mDecl.arguments.length]; + for (int i = 0; i < mDecl.arguments.length; i++) { + Argument arg = mDecl.arguments[i]; + String name = new String(arg.name); + TypeBinding argTypeBinding = mDecl.binding.parameters[i]; + TypeX type = EclipseFactory.fromBinding(argTypeBinding); + if (CharOperation.equals(joinPoint,argTypeBinding.signature()) || + CharOperation.equals(joinPointStaticPart,argTypeBinding.signature()) || + CharOperation.equals(joinPointEnclosingStaticPart,argTypeBinding.signature()) || + CharOperation.equals(proceedingJoinPoint,argTypeBinding.signature())) { + ret[i] = new FormalBinding.ImplicitFormalBinding(type,name,i); + } else { + ret[i] = new FormalBinding(type, name, i, arg.sourceStart, arg.sourceEnd, "unknown"); + } + } + return ret; + } + + private String getStringLiteralFor(String memberName, Annotation inAnnotation, int[] location) { + if (inAnnotation instanceof SingleMemberAnnotation && memberName.equals("value")) { + SingleMemberAnnotation sma = (SingleMemberAnnotation) inAnnotation; + if (sma.memberValue instanceof StringLiteral) { + StringLiteral sv = (StringLiteral) sma.memberValue; + location[0] = sv.sourceStart; + location[1] = sv.sourceEnd; + return new String(sv.source()); + } + } + if (! (inAnnotation instanceof NormalAnnotation)) return null; + NormalAnnotation ann = (NormalAnnotation) inAnnotation; + MemberValuePair[] mvps = ann.memberValuePairs; + if (mvps == null) return null; + for (int i = 0; i < mvps.length; i++) { + if (CharOperation.equals(memberName.toCharArray(),mvps[i].name)) { + if (mvps[i].value instanceof StringLiteral) { + StringLiteral sv = (StringLiteral) mvps[i].value; + location[0] = sv.sourceStart; + location[1] = sv.sourceEnd; + return new String(sv.source()); + } + } + } + return null; + } + + private void convertToPointcutDeclaration(MethodDeclaration methodDeclaration, ClassScope scope) { + TypeDeclaration typeDecl = (TypeDeclaration) typeStack.peek(); + if (typeDecl.binding != null) { + if (!typeDecl.binding.isClass()) { + methodDeclaration.scope.problemReporter() + .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"pointcuts can only be declared in a class or an aspect"); + } + } + + if (methodDeclaration.thrownExceptions != null && methodDeclaration.thrownExceptions.length > 0) { + methodDeclaration.scope.problemReporter() + .signalError(methodDeclaration.sourceStart,methodDeclaration.sourceEnd,"pointcuts cannot throw exceptions!"); + } + + PointcutDeclaration pcDecl = new PointcutDeclaration(unit.compilationResult); + copyAllFields(methodDeclaration,pcDecl); + + Annotation pcutAnn = null; + Annotation duplicateAnn = null; + for(int i = 0; i < methodDeclaration.annotations.length; i++) { + Annotation ann = methodDeclaration.annotations[i]; + if (isAspectJAnnotation(ann)) { + if (pcutAnn != null) { + duplicateAnn = ann; + break; + } + if (CharOperation.equals(pointcutSig,ann.resolvedType.signature())) { + pcutAnn = ann; + } + } + } + + if (duplicateAnn != null && !CharOperation.equals(pointcutSig,duplicateAnn.resolvedType.signature())) { + // (duplicate annotations of same type are already reported) + methodDeclaration.scope.problemReporter().disallowedTargetForAnnotation(duplicateAnn); + } + + boolean returnsVoid = true; + if ((methodDeclaration.returnType instanceof SingleTypeReference)) { + SingleTypeReference retType = (SingleTypeReference) methodDeclaration.returnType; + if (!CharOperation.equals(voidType,retType.token)) { + returnsVoid = false; + } + } else { + returnsVoid = false; + } + if (!returnsVoid) { + methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart, + methodDeclaration.returnType.sourceEnd, + "Methods annotated with @Pointcut must return void"); + } + + if (methodDeclaration.statements != null && methodDeclaration.statements.length > 0) { + methodDeclaration.scope.problemReporter().signalError(methodDeclaration.returnType.sourceStart, + methodDeclaration.returnType.sourceEnd, + "Pointcuts should have an empty method body"); + } + + int[] pcLocation = new int[2]; + String pointcutExpression = getStringLiteralFor("value",pcutAnn,pcLocation); + try { + ISourceContext context = new EclipseSourceContext(unit.compilationResult,pcLocation[0]); + Pointcut pc = new PatternParser(pointcutExpression,context).parsePointcut(); + pcDecl.pointcutDesignator = new PointcutDesignator(pc); + pcDecl.setGenerateSyntheticPointcutMethod(); + TypeDeclaration onType = (TypeDeclaration) typeStack.peek(); + pcDecl.postParse(onType); + int argsLength = methodDeclaration.arguments == null ? 0 : methodDeclaration.arguments.length; + FormalBinding[] bindings = new FormalBinding[argsLength]; + for (int i = 0, len = bindings.length; i < len; i++) { + Argument arg = methodDeclaration.arguments[i]; + String name = new String(arg.name); + TypeX type = EclipseFactory.fromBinding(methodDeclaration.binding.parameters[i]); + bindings[i] = new FormalBinding(type, name, i, arg.sourceStart, arg.sourceEnd, "unknown"); + } + swap(onType,methodDeclaration,pcDecl); + pc.resolve(new EclipseScope(bindings,methodDeclaration.scope)); + } catch(ParserException pEx) { + methodDeclaration.scope.problemReporter().parseError( + pcLocation[0] + pEx.getLocation().getStart(), + pcLocation[0] + pEx.getLocation().getEnd() , + -1, + pointcutExpression.toCharArray(), + pointcutExpression, + new String[] {pEx.getMessage()}); + } + } + + private void copyAllFields(MethodDeclaration from, MethodDeclaration to) { + to.annotations = from.annotations; + to.arguments = from.arguments; + to.binding = from.binding; + to.bits = from.bits; + to.bodyEnd = from.bodyEnd; + to.bodyStart = from.bodyStart; + to.declarationSourceEnd = from.declarationSourceEnd; + to.declarationSourceStart = from.declarationSourceStart; + to.errorInSignature = from.errorInSignature; + to.explicitDeclarations = from.explicitDeclarations; + to.ignoreFurtherInvestigation = from.ignoreFurtherInvestigation; + to.javadoc = from.javadoc; + to.modifiers = from.modifiers; + to.modifiersSourceStart = from.modifiersSourceStart; + to.needFreeReturn = from.needFreeReturn; + to.returnType = from.returnType; + to.scope = from.scope; + to.selector = from.selector; + to.sourceEnd = from.sourceEnd; + to.sourceStart = from.sourceStart; + to.statements = from.statements; + to.thrownExceptions = from.thrownExceptions; + to.typeParameters = from.typeParameters; + } + + private void swap(TypeDeclaration inType, MethodDeclaration thisDeclaration, MethodDeclaration forThatDeclaration) { + for (int i = 0; i < inType.methods.length; i++) { + if (inType.methods[i] == thisDeclaration) { + inType.methods[i] = forThatDeclaration; + break; + } + } + } +} diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java index 2365ef452..197fa3376 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/AjLookupEnvironment.java @@ -29,6 +29,8 @@ import org.aspectj.bridge.WeaveMessage; import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation; import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation; +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.env.AccessRestriction; import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryType; @@ -307,7 +309,7 @@ public class AjLookupEnvironment extends LookupEnvironment { // test classes don't extend aspects if (sourceType.superclass != null) { ResolvedTypeX parent = factory.fromEclipse(sourceType.superclass); - if (parent.isAspect() && !(dec instanceof AspectDeclaration)) { + if (parent.isAspect() && !isAspect(dec)) { factory.showMessage(IMessage.ERROR, "class \'" + new String(sourceType.sourceName) + "\' can not extend aspect \'" + parent.getName() + "\'", factory.fromEclipse(sourceType).getSourceLocation(), null); @@ -319,6 +321,31 @@ public class AjLookupEnvironment extends LookupEnvironment { buildInterTypeAndPerClause(((SourceTypeBinding) memberTypes[i]).scope); } } + + private boolean isAspect(TypeDeclaration decl) { + if ((decl instanceof AspectDeclaration)) { + return true; + } else if (decl.annotations == null) { + return false; + } else { + for (int i = 0; i < decl.annotations.length; i++) { + Annotation ann = decl.annotations[i]; + if (ann.type instanceof SingleTypeReference) { + if (CharOperation.equals("Aspect".toCharArray(),((SingleTypeReference)ann.type).token)) return true; + } else if (ann.type instanceof QualifiedTypeReference) { + QualifiedTypeReference qtr = (QualifiedTypeReference) ann.type; + if (qtr.tokens.length != 5) return false; + if (!CharOperation.equals("org".toCharArray(),qtr.tokens[0])) return false; + if (!CharOperation.equals("aspectj".toCharArray(),qtr.tokens[1])) return false; + if (!CharOperation.equals("lang".toCharArray(),qtr.tokens[2])) return false; + if (!CharOperation.equals("annotation".toCharArray(),qtr.tokens[3])) return false; + if (!CharOperation.equals("Aspect".toCharArray(),qtr.tokens[4])) return false; + return true; + } + } + } + return false; + } private void weaveInterTypeDeclarations(CompilationUnitScope unit, Collection typeMungers, Collection declareParents, Collection declareAnnotationOnTypes) { diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceType.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceType.java index 90ed87495..826e585f2 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceType.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceType.java @@ -34,6 +34,7 @@ import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.*; * @author Jim Hugunin */ public class EclipseSourceType extends ResolvedTypeX.ConcreteName { + private static final char[] pointcutSig = "Lorg/aspectj/lang/annotation/Pointcut;".toCharArray(); protected ResolvedPointcutDefinition[] declaredPointcuts = null; protected ResolvedMember[] declaredMethods = null; protected ResolvedMember[] declaredFields = null; @@ -83,6 +84,19 @@ public class EclipseSourceType extends ResolvedTypeX.ConcreteName { return false; } + private boolean isAnnotationStylePointcut(Annotation[] annotations) { + if (annotations == null) return false; + for (int i = 0; i < annotations.length; i++) { + if (annotations[i].resolvedType == null) continue; // XXX happens if we do this very early from buildInterTypeandPerClause + // may prevent us from resolving references made in @Pointcuts to + // an @Pointcut in a code-style aspect + char[] sig = annotations[i].resolvedType.signature(); + if (CharOperation.equals(pointcutSig,sig)) { + return true; + } + } + return false; + } public WeaverStateInfo getWeaverState() { return null; } @@ -113,7 +127,7 @@ public class EclipseSourceType extends ResolvedTypeX.ConcreteName { PointcutDeclaration d = (PointcutDeclaration)amd; ResolvedPointcutDefinition df = d.makeResolvedPointcutDefinition(); declaredPointcuts.add(df); - } else if (amd instanceof InterTypeDeclaration) { + } else if (amd instanceof InterTypeDeclaration) { // these are handled in a separate pass continue; } else if (amd instanceof DeclareDeclaration && @@ -123,6 +137,10 @@ public class EclipseSourceType extends ResolvedTypeX.ConcreteName { } else if (amd instanceof AdviceDeclaration) { // these are ignored during compilation and only used during weaving continue; + } else if ((amd.annotations != null) && isAnnotationStylePointcut(amd.annotations)) { + // consider pointcuts defined via annotations + ResolvedPointcutDefinition df = makeResolvedPointcutDefinition(amd); + declaredPointcuts.add(df); } else { if (amd.binding == null || !amd.binding.isValidBinding()) continue; declaredMethods.add(EclipseFactory.makeResolvedMember(amd.binding)); @@ -144,6 +162,18 @@ public class EclipseSourceType extends ResolvedTypeX.ConcreteName { declaredFields.toArray(new ResolvedMember[declaredFields.size()]); } + private ResolvedPointcutDefinition makeResolvedPointcutDefinition(AbstractMethodDeclaration md) { + ResolvedPointcutDefinition resolvedPointcutDeclaration = new ResolvedPointcutDefinition( + EclipseFactory.fromBinding(md.binding.declaringClass), + md.modifiers, + new String(md.selector), + EclipseFactory.fromBindings(md.binding.parameters), + null); //??? might want to use null + + resolvedPointcutDeclaration.setPosition(md.sourceStart, md.sourceEnd); + resolvedPointcutDeclaration.setSourceContext(new EclipseSourceContext(md.compilationResult)); + return resolvedPointcutDeclaration; + } public ResolvedMember[] getDeclaredFields() { if (declaredFields == null) fillDeclaredMembers(); diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java index 12ca5f606..cf5bcb5fb 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildConfig.java @@ -508,6 +508,13 @@ public class AjBuildConfig { options.generateModel = structureModelMode; } + public boolean isNoAtAspectJAnnotationProcessing() { + return options.noAtAspectJProcessing; + } + + public void setNoAtAspectJAnnotationProcessing(boolean noProcess) { + options.noAtAspectJProcessing = noProcess; + } public void setShowWeavingInformation(boolean b) { options.showWeavingInformation = true; diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java index c4223b8b4..1f550dd95 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjBuildManager.java @@ -974,7 +974,8 @@ public class AjBuildManager implements IOutputClassFileNameProvider,IBinarySourc state.binarySourceFiles, state.resultsFromFile.values(), buildConfig.isNoWeave(), - buildConfig.getProceedOnError()); + buildConfig.getProceedOnError(), + buildConfig.isNoAtAspectJAnnotationProcessing()); } /* (non-Javadoc) diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjCompilerOptions.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjCompilerOptions.java index 8553ed9df..0eeb1797f 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjCompilerOptions.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AjCompilerOptions.java @@ -41,8 +41,9 @@ public class AjCompilerOptions extends CompilerOptions { public static final String OPTION_XNoInline = "org.aspectj.ajdt.core.compiler.weaver.XNoInline"; public static final String OPTION_XReweavable = "org.aspectj.ajdt.core.compiler.weaver.XReweavable"; public static final String OPTION_XReweavableCompress = "org.aspectj.ajdt.core.compiler.weaver.XReweavableCompress"; - - // these next three not exposed by IDEs + + // these next four not exposed by IDEs + public static final String OPTION_XDevNoAtAspectJProcessing = "org.aspectj.ajdt.core.compiler.ast.NoAtAspectJProcessing"; public static final String OPTION_GenerateModel = "org.aspectj.ajdt.core.compiler.model.GenerateModel"; public static final String OPTION_GenerateJavaDocsInModel = "org.aspectj.ajdt.core.compiler.model.GenerateJavaDocsInModel"; public static final String OPTION_Emacssym = "org.aspectj.ajdt.core.compiler.model.Emacssym"; @@ -69,10 +70,12 @@ public class AjCompilerOptions extends CompilerOptions { // If true - autoboxing behaves differently ... public boolean behaveInJava5Way = false; - // these next three not exposed by IDEs + // these next four not exposed by IDEs public boolean generateModel = false; public boolean generateJavaDocsInModel = false; public boolean generateEmacsSymFiles = false; + public boolean noAtAspectJProcessing = false; + public boolean proceedOnError = false; @@ -119,6 +122,7 @@ public class AjCompilerOptions extends CompilerOptions { map.put(OPTION_GenerateModel,this.generateModel ? ENABLED : DISABLED); map.put(OPTION_GenerateJavaDocsInModel,this.generateJavaDocsInModel ? ENABLED : DISABLED); map.put(OPTION_Emacssym,this.generateEmacsSymFiles ? ENABLED : DISABLED); + map.put(OPTION_XDevNoAtAspectJProcessing,this.noAtAspectJProcessing ? ENABLED : DISABLED); return map; } @@ -203,6 +207,13 @@ public class AjCompilerOptions extends CompilerOptions { this.generateEmacsSymFiles = false; } } + if ((optionValue = optionsMap.get(OPTION_XDevNoAtAspectJProcessing)) != null) { + if (ENABLED.equals(optionValue)) { + this.noAtAspectJProcessing = true; + } else if (DISABLED.equals(optionValue)) { + this.noAtAspectJProcessing = false; + } + } } @@ -235,7 +246,8 @@ public class AjCompilerOptions extends CompilerOptions { buf.append("\n\t- generate AJDE model: ").append(this.generateModel ? ENABLED : DISABLED); //$NON-NLS-1$ buf.append("\n\t- generate Javadocs in AJDE model: ").append(this.generateJavaDocsInModel ? ENABLED : DISABLED); //$NON-NLS-1$ - buf.append("\n\t- generate Emacs symbol files: ").append(this.generateEmacsSymFiles ? ENABLED : DISABLED); //$NON-NLS-1$ + buf.append("\n\t- generate Emacs symbol files: ").append(this.generateEmacsSymFiles ? ENABLED : DISABLED); //$NON-NLS-1$ + buf.append("\n\t- suppress @AspectJ processing: ").append(this.noAtAspectJProcessing ? ENABLED : DISABLED); //$NON-NLS-1$ buf.append("\n\t- invalid absolute type name (XLint): ").append(getSeverityString(InvalidAbsoluteTypeName)); //$NON-NLS-1$ buf.append("\n\t- invalid wildcard type name (XLint): ").append(getSeverityString(InvalidWildCardTypeName)); //$NON-NLS-1$ diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AspectJBuilder.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AspectJBuilder.java index b91aed439..5407758ff 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AspectJBuilder.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/AspectJBuilder.java @@ -139,7 +139,7 @@ public class AspectJBuilder extends JavaBuilder implements ICompilerAdapterFacto return new AjCompilerAdapter(forCompiler,isBatchBuild,myBcelWorld, myWeaver,eFactory,unwovenResultCollector,ajNotifier,fileNameProvider,bsProvider, fullBinarySourceEntries,resultSetForFullWeave, - ajOptions.noWeave,ajOptions.proceedOnError); + ajOptions.noWeave,ajOptions.proceedOnError,ajOptions.noAtAspectJProcessing); } /* (non-Javadoc) diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/EclipseSourceContext.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/EclipseSourceContext.java index d8219bee1..056120373 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/EclipseSourceContext.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/core/builder/EclipseSourceContext.java @@ -27,11 +27,21 @@ import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult; public class EclipseSourceContext implements ISourceContext { CompilationResult result; + int offset = 0; public EclipseSourceContext(CompilationResult result) { this.result = result; } + public EclipseSourceContext(CompilationResult result, int offset) { + this.result = result; + this.offset = offset; + } + + public int getOffset() { + return offset; + } + private File getSourceFile() { return new File(new String(result.fileName)); } diff --git a/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/CommandTestCase.java b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/CommandTestCase.java index a508e512c..0c972cf40 100644 --- a/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/CommandTestCase.java +++ b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/compiler/batch/CommandTestCase.java @@ -166,7 +166,7 @@ public abstract class CommandTestCase extends TestCase { /** get the location of the org.aspectj.lang & runtime classes */ protected static String getRuntimeClasspath() { - return "../runtime/bin" + File.pathSeparator + + return "../runtime/bin" + File.pathSeparator + "../aspectj5rt/bin" + File.pathSeparator + System.getProperty("aspectjrt.path"); } diff --git a/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/core/builder/AjCompilerOptionsTest.java b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/core/builder/AjCompilerOptionsTest.java index 988209675..c19ecc33d 100644 --- a/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/core/builder/AjCompilerOptionsTest.java +++ b/org.aspectj.ajdt.core/testsrc/org/aspectj/ajdt/internal/core/builder/AjCompilerOptionsTest.java @@ -45,6 +45,7 @@ public class AjCompilerOptionsTest extends TestCase { assertFalse(options.generateModel); assertFalse(options.generateJavaDocsInModel); assertFalse(options.generateEmacsSymFiles); + assertFalse(options.noAtAspectJProcessing); Map map = options.getMap(); assertEquals(CompilerOptions.WARNING,map.get(AjCompilerOptions.OPTION_ReportInvalidAbsoluteTypeName)); @@ -68,6 +69,7 @@ public class AjCompilerOptionsTest extends TestCase { options.generateModel = true; options.generateJavaDocsInModel = true; options.generateEmacsSymFiles = true; + options.noAtAspectJProcessing = true; Map map = options.getMap(); assertEquals(CompilerOptions.ENABLED,map.get(AjCompilerOptions.OPTION_NoWeave)); @@ -79,6 +81,7 @@ public class AjCompilerOptionsTest extends TestCase { assertEquals(CompilerOptions.ENABLED,map.get(AjCompilerOptions.OPTION_GenerateModel)); assertEquals(CompilerOptions.ENABLED,map.get(AjCompilerOptions.OPTION_GenerateJavaDocsInModel)); assertEquals(CompilerOptions.ENABLED,map.get(AjCompilerOptions.OPTION_Emacssym)); + assertEquals(CompilerOptions.ENABLED,map.get(AjCompilerOptions.OPTION_XDevNoAtAspectJProcessing)); } @@ -103,6 +106,7 @@ public class AjCompilerOptionsTest extends TestCase { map.put(AjCompilerOptions.OPTION_GenerateModel,CompilerOptions.ENABLED); map.put(AjCompilerOptions.OPTION_GenerateJavaDocsInModel,CompilerOptions.ENABLED); map.put(AjCompilerOptions.OPTION_Emacssym,CompilerOptions.ENABLED); + map.put(AjCompilerOptions.OPTION_XDevNoAtAspectJProcessing,CompilerOptions.ENABLED); options.set(map); @@ -115,6 +119,7 @@ public class AjCompilerOptionsTest extends TestCase { assertTrue(options.generateModel); assertTrue(options.generateJavaDocsInModel); assertTrue(options.generateEmacsSymFiles); + assertTrue(options.noAtAspectJProcessing); Map newMap = options.getMap(); diff --git a/weaver/src/org/aspectj/weaver/ISourceContext.java b/weaver/src/org/aspectj/weaver/ISourceContext.java index 16cb3c8bc..d0c91a27b 100644 --- a/weaver/src/org/aspectj/weaver/ISourceContext.java +++ b/weaver/src/org/aspectj/weaver/ISourceContext.java @@ -18,4 +18,5 @@ import org.aspectj.bridge.ISourceLocation; public interface ISourceContext { public ISourceLocation makeSourceLocation(IHasPosition position); public ISourceLocation makeSourceLocation(int line); + public int getOffset(); } diff --git a/weaver/src/org/aspectj/weaver/ataspectj/Aj5Attributes.java b/weaver/src/org/aspectj/weaver/ataspectj/Aj5Attributes.java index f708b6f8f..2eb120ecd 100644 --- a/weaver/src/org/aspectj/weaver/ataspectj/Aj5Attributes.java +++ b/weaver/src/org/aspectj/weaver/ataspectj/Aj5Attributes.java @@ -27,7 +27,6 @@ import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair; import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnotations; import org.aspectj.apache.bcel.generic.Type; import org.aspectj.bridge.IMessageHandler; -import org.aspectj.bridge.IMessage; import org.aspectj.bridge.Message; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; @@ -36,6 +35,7 @@ import org.aspectj.weaver.AdviceKind; import org.aspectj.weaver.AjAttribute; import org.aspectj.weaver.AjcMemberMaker; import org.aspectj.weaver.ISourceContext; +import org.aspectj.weaver.NameMangler; import org.aspectj.weaver.ResolvedPointcutDefinition; import org.aspectj.weaver.ResolvedTypeX; import org.aspectj.weaver.TypeX; @@ -142,14 +142,14 @@ public class Aj5Attributes { * @param msgHandler * @return list of AjAttributes */ - public static List readAj5ClassAttributes(JavaClass javaClass, ResolvedTypeX type, ISourceContext context,IMessageHandler msgHandler) { + public static List readAj5ClassAttributes(JavaClass javaClass, ResolvedTypeX type, ISourceContext context,IMessageHandler msgHandler, boolean isCodeStyleAspect) { AjAttributeStruct struct = new AjAttributeStruct(type, context, msgHandler); Attribute[] attributes = javaClass.getAttributes(); for (int i = 0; i < attributes.length; i++) { Attribute attribute = attributes[i]; if (acceptAttribute(attribute)) { RuntimeAnnotations rvs = (RuntimeAnnotations) attribute; - handleAspectAnnotation(rvs, struct); + if (!isCodeStyleAspect) handleAspectAnnotation(rvs, struct); handlePrecedenceAnnotation(rvs, struct); } } @@ -161,6 +161,7 @@ public class Aj5Attributes { //FIXME alex can that be too slow ? for (int m = 0; m < javaClass.getMethods().length; m++) { Method method = javaClass.getMethods()[m]; + if (method.getName().startsWith(NameMangler.PREFIX)) continue; // already dealt with by ajc... //FIXME alex optimize, this method struct will gets recreated for advice extraction AjAttributeMethodStruct mstruct = new AjAttributeMethodStruct(method, type, context, msgHandler); Attribute[] mattributes = method.getAttributes(); @@ -187,19 +188,21 @@ public class Aj5Attributes { * @param msgHandler * @return list of AjAttributes */ - public static List readAj5MethodAttributes(Method method, ResolvedTypeX type, ISourceContext context,IMessageHandler msgHandler) { - AjAttributeMethodStruct struct = new AjAttributeMethodStruct(method, type, context, msgHandler); + public static List readAj5MethodAttributes(Method method, ResolvedTypeX type, ResolvedPointcutDefinition preResolvedPointcut, ISourceContext context,IMessageHandler msgHandler) { + if (method.getName().startsWith(NameMangler.PREFIX)) return Collections.EMPTY_LIST; // already dealt with by ajc... + + AjAttributeMethodStruct struct = new AjAttributeMethodStruct(method, type, context, msgHandler); Attribute[] attributes = method.getAttributes(); for (int i = 0; i < attributes.length; i++) { Attribute attribute = attributes[i]; if (acceptAttribute(attribute)) { RuntimeAnnotations rvs = (RuntimeAnnotations) attribute; - handleBeforeAnnotation(rvs, struct); - handleAfterAnnotation(rvs, struct); - handleAfterReturningAnnotation(rvs, struct); - handleAfterThrowingAnnotation(rvs, struct); - handleAroundAnnotation(rvs, struct); + handleBeforeAnnotation(rvs, struct, preResolvedPointcut); + handleAfterAnnotation(rvs, struct, preResolvedPointcut); + handleAfterReturningAnnotation(rvs, struct, preResolvedPointcut); + handleAfterThrowingAnnotation(rvs, struct, preResolvedPointcut); + handleAroundAnnotation(rvs, struct, preResolvedPointcut); } } return struct.ajAttributes; @@ -215,6 +218,7 @@ public class Aj5Attributes { * @return list of AjAttributes, always empty for now */ public static List readAj5FieldAttributes(Field field, ResolvedTypeX type, ISourceContext context,IMessageHandler msgHandler) { + if (field.getName().startsWith(NameMangler.PREFIX)) return Collections.EMPTY_LIST; // already dealt with by ajc... return EMPTY_LIST; } @@ -271,7 +275,7 @@ public class Aj5Attributes { } else if (perClause.startsWith(PerClause.KindAnnotationPrefix.PERTYPEWITHIN.getName())) { pointcut = PerClause.KindAnnotationPrefix.PERTYPEWITHIN.extractPointcut(perClause); return new PerTypeWithin(new PatternParser(pointcut).parseTypePattern()); - } else if (perClause.equalsIgnoreCase(PerClause.SINGLETON.getName())) { + } else if (perClause.equalsIgnoreCase(PerClause.SINGLETON.getName() + "()")) { return new PerSingleton(); } // could not parse the @AJ perclause @@ -310,7 +314,7 @@ public class Aj5Attributes { * @param runtimeAnnotations * @param struct */ - private static void handleBeforeAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct) { + private static void handleBeforeAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { Annotation before = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.Before"); if (before != null) { ElementNameValuePair beforeAdvice = getAnnotationElement(before, "value"); @@ -325,7 +329,12 @@ public class Aj5Attributes { // joinpoint, staticJoinpoint binding int extraArgument = extractExtraArgument(struct.method); - Pointcut pc = Pointcut.fromString(beforeAdvice.getValue().stringifyValue()).resolve(binding); + Pointcut pc = null; + if (preResolvedPointcut != null) { + pc = preResolvedPointcut.getPointcut(); + } else { + pc = Pointcut.fromString(beforeAdvice.getValue().stringifyValue()).resolve(binding); + } setIgnoreUnboundBindingNames(pc, bindings); struct.ajAttributes.add(new AjAttribute.AdviceAttribute( @@ -347,7 +356,7 @@ public class Aj5Attributes { * @param runtimeAnnotations * @param struct */ - private static void handleAfterAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct) { + private static void handleAfterAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { Annotation after = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.After"); if (after != null) { ElementNameValuePair afterAdvice = getAnnotationElement(after, "value"); @@ -362,7 +371,12 @@ public class Aj5Attributes { // joinpoint, staticJoinpoint binding int extraArgument = extractExtraArgument(struct.method); - Pointcut pc = Pointcut.fromString(afterAdvice.getValue().stringifyValue()).resolve(binding); + Pointcut pc = null; + if (preResolvedPointcut != null) { + pc = preResolvedPointcut.getPointcut(); + } else { + pc = Pointcut.fromString(afterAdvice.getValue().stringifyValue()).resolve(binding); + } setIgnoreUnboundBindingNames(pc, bindings); struct.ajAttributes.add(new AjAttribute.AdviceAttribute( @@ -384,7 +398,7 @@ public class Aj5Attributes { * @param runtimeAnnotations * @param struct */ - private static void handleAfterReturningAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct) { + private static void handleAfterReturningAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { Annotation after = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.AfterReturning"); if (after != null) { ElementNameValuePair annValue = getAnnotationElement(after, "value"); @@ -427,7 +441,12 @@ public class Aj5Attributes { extraArgument |= Advice.ExtraArgument; } - Pointcut pc = Pointcut.fromString(pointcut).resolve(binding); + Pointcut pc = null; + if (preResolvedPointcut != null) { + pc = preResolvedPointcut.getPointcut(); + } else { + pc = Pointcut.fromString(pointcut).resolve(binding); + } setIgnoreUnboundBindingNames(pc, bindings); struct.ajAttributes.add(new AjAttribute.AdviceAttribute( @@ -448,7 +467,7 @@ public class Aj5Attributes { * @param runtimeAnnotations * @param struct */ - private static void handleAfterThrowingAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct) { + private static void handleAfterThrowingAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { Annotation after = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.AfterThrowing"); if (after != null) { ElementNameValuePair annValue = getAnnotationElement(after, "value"); @@ -491,7 +510,12 @@ public class Aj5Attributes { extraArgument |= Advice.ExtraArgument; } - Pointcut pc = Pointcut.fromString(pointcut).resolve(binding); + Pointcut pc = null; + if (preResolvedPointcut != null) { + pc = preResolvedPointcut.getPointcut(); + } else { + pc = Pointcut.fromString(pointcut).resolve(binding); + } setIgnoreUnboundBindingNames(pc, bindings); struct.ajAttributes.add(new AjAttribute.AdviceAttribute( @@ -512,7 +536,7 @@ public class Aj5Attributes { * @param runtimeAnnotations * @param struct */ - private static void handleAroundAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct) { + private static void handleAroundAnnotation(RuntimeAnnotations runtimeAnnotations, AjAttributeMethodStruct struct, ResolvedPointcutDefinition preResolvedPointcut) { Annotation around = getAnnotation(runtimeAnnotations, "org.aspectj.lang.annotation.Around"); if (around != null) { ElementNameValuePair aroundAdvice = getAnnotationElement(around, "value"); @@ -527,7 +551,12 @@ public class Aj5Attributes { // joinpoint, staticJoinpoint binding int extraArgument = extractExtraArgument(struct.method); - Pointcut pc = Pointcut.fromString(aroundAdvice.getValue().stringifyValue()).resolve(binding); + Pointcut pc = null; + if (preResolvedPointcut != null) { + pc = preResolvedPointcut.getPointcut(); + } else { + pc = Pointcut.fromString(aroundAdvice.getValue().stringifyValue()).resolve(binding); + } setIgnoreUnboundBindingNames(pc, bindings); struct.ajAttributes.add(new AjAttribute.AdviceAttribute( diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelMethod.java b/weaver/src/org/aspectj/weaver/bcel/BcelMethod.java index 7de8b3735..a8c629992 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelMethod.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelMethod.java @@ -29,6 +29,7 @@ import org.aspectj.weaver.AnnotationX; import org.aspectj.weaver.BCException; import org.aspectj.weaver.ISourceContext; import org.aspectj.weaver.ResolvedMember; +import org.aspectj.weaver.ResolvedPointcutDefinition; import org.aspectj.weaver.ResolvedTypeX; import org.aspectj.weaver.ShadowMunger; import org.aspectj.weaver.TypeX; @@ -40,6 +41,7 @@ final class BcelMethod extends ResolvedMember { private Method method; private boolean isAjSynthetic; private ShadowMunger associatedShadowMunger; + private ResolvedPointcutDefinition preResolvedPointcut; // used when ajc has pre-resolved the pointcut of some @Advice private ResolvedTypeX[] annotationTypes = null; private AnnotationX[] annotations = null; @@ -96,27 +98,33 @@ final class BcelMethod extends ResolvedMember { } private void unpackAjAttributes(World world) { + associatedShadowMunger = null; List as = BcelAttributes.readAjAttributes(getDeclaringType().getClassName(),method.getAttributes(), getSourceContext(world),world.getMessageHandler()); - as.addAll(Aj5Attributes.readAj5MethodAttributes(method, world.resolve(getDeclaringType()), getSourceContext(world), world.getMessageHandler())); + processAttributes(world, as); + as = Aj5Attributes.readAj5MethodAttributes(method, world.resolve(getDeclaringType()), preResolvedPointcut,getSourceContext(world), world.getMessageHandler()); + processAttributes(world,as); + } - //System.out.println("unpack: " + this + ", " + as); + private void processAttributes(World world, List as) { for (Iterator iter = as.iterator(); iter.hasNext();) { AjAttribute a = (AjAttribute) iter.next(); if (a instanceof AjAttribute.MethodDeclarationLineNumberAttribute) { declarationLineNumber = (AjAttribute.MethodDeclarationLineNumberAttribute)a; } else if (a instanceof AjAttribute.AdviceAttribute) { associatedShadowMunger = ((AjAttribute.AdviceAttribute)a).reify(this, world); - return; + // return; } else if (a instanceof AjAttribute.AjSynthetic) { isAjSynthetic = true; } else if (a instanceof AjAttribute.EffectiveSignatureAttribute) { //System.out.println("found effective: " + this); effectiveSignature = (AjAttribute.EffectiveSignatureAttribute)a; + } else if (a instanceof AjAttribute.PointcutDeclarationAttribute) { + // this is an @AspectJ annotated advice method, with pointcut pre-resolved by ajc + preResolvedPointcut = ((AjAttribute.PointcutDeclarationAttribute)a).reify(); } else { throw new BCException("weird method attribute " + a); } } - associatedShadowMunger = null; } public boolean isAjSynthetic() { diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java b/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java index 46a7fe783..862b2a65b 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java @@ -66,6 +66,7 @@ public class BcelObjectType extends ResolvedTypeX.ConcreteName { private boolean discoveredWhetherAnnotationStyle = false; private boolean isAnnotationStyleAspect = false;// set upon construction + private boolean isCodeStyleAspect = false; // not redundant with field above! public Collection getTypeMungers() { @@ -185,7 +186,7 @@ public class BcelObjectType extends ResolvedTypeX.ConcreteName { public boolean isAnnotationStyleAspect() { if (!discoveredWhetherAnnotationStyle) { discoveredWhetherAnnotationStyle = true; - isAnnotationStyleAspect = hasAnnotation(Ajc5MemberMaker.ASPECT); + isAnnotationStyleAspect = !isCodeStyleAspect && hasAnnotation(Ajc5MemberMaker.ASPECT); } return isAnnotationStyleAspect; } @@ -196,13 +197,32 @@ public class BcelObjectType extends ResolvedTypeX.ConcreteName { declares = new ArrayList(); // Pass in empty list that can store things for readAj5 to process List l = BcelAttributes.readAjAttributes(javaClass.getClassName(),javaClass.getAttributes(), getResolvedTypeX().getSourceContext(),getResolvedTypeX().getWorld().getMessageHandler()); - l.addAll(Aj5Attributes.readAj5ClassAttributes(javaClass, getResolvedTypeX(), getResolvedTypeX().getSourceContext(), getResolvedTypeX().getWorld().getMessageHandler())); + processAttributes(l,pointcuts,false); + l = Aj5Attributes.readAj5ClassAttributes(javaClass, getResolvedTypeX(), getResolvedTypeX().getSourceContext(), getResolvedTypeX().getWorld().getMessageHandler(),isCodeStyleAspect); + processAttributes(l,pointcuts,true); + + this.pointcuts = (ResolvedPointcutDefinition[]) + pointcuts.toArray(new ResolvedPointcutDefinition[pointcuts.size()]); + // Test isn't quite right, leaving this out for now... +// if (isAspect() && wvInfo.getMajorVersion() == WeaverVersionInfo.UNKNOWN.getMajorVersion()) { +// throw new BCException("Unable to continue, this version of AspectJ cannot use aspects as input that were built "+ +// "with an AspectJ earlier than version 1.2.1. Please rebuild class: "+javaClass.getClassName()); +// } + +// this.typeMungers = (BcelTypeMunger[]) +// typeMungers.toArray(new BcelTypeMunger[typeMungers.size()]); +// this.declares = (Declare[]) +// declares.toArray(new Declare[declares.size()]); + } - for (Iterator iter = l.iterator(); iter.hasNext();) { + + private void processAttributes(List attributeList, List pointcuts, boolean fromAnnotations) { + for (Iterator iter = attributeList.iterator(); iter.hasNext();) { AjAttribute a = (AjAttribute) iter.next(); //System.err.println("unpacking: " + this + " and " + a); if (a instanceof AjAttribute.Aspect) { perClause = ((AjAttribute.Aspect)a).reify(this.getResolvedTypeX()); + if (!fromAnnotations) isCodeStyleAspect = true; } else if (a instanceof AjAttribute.PointcutDeclarationAttribute) { pointcuts.add(((AjAttribute.PointcutDeclarationAttribute)a).reify()); } else if (a instanceof AjAttribute.WeaverState) { @@ -223,18 +243,6 @@ public class BcelObjectType extends ResolvedTypeX.ConcreteName { throw new BCException("bad attribute " + a); } } - this.pointcuts = (ResolvedPointcutDefinition[]) - pointcuts.toArray(new ResolvedPointcutDefinition[pointcuts.size()]); - // Test isn't quite right, leaving this out for now... -// if (isAspect() && wvInfo.getMajorVersion() == WeaverVersionInfo.UNKNOWN.getMajorVersion()) { -// throw new BCException("Unable to continue, this version of AspectJ cannot use aspects as input that were built "+ -// "with an AspectJ earlier than version 1.2.1. Please rebuild class: "+javaClass.getClassName()); -// } - -// this.typeMungers = (BcelTypeMunger[]) -// typeMungers.toArray(new BcelTypeMunger[typeMungers.size()]); -// this.declares = (Declare[]) -// declares.toArray(new Declare[declares.size()]); } public PerClause getPerClause() { diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelSourceContext.java b/weaver/src/org/aspectj/weaver/bcel/BcelSourceContext.java index 8f7f4065a..8d313c4e7 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelSourceContext.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelSourceContext.java @@ -51,6 +51,8 @@ public class BcelSourceContext implements ISourceContext { return new File(fileName); } + + public int getOffset() { return 0; } /* // AMC - a temporary "fudge" to give as much information as possible about the identity of the diff --git a/weaver/src/org/aspectj/weaver/patterns/BasicTokenSource.java b/weaver/src/org/aspectj/weaver/patterns/BasicTokenSource.java index c8c215a3d..dad3bccd4 100644 --- a/weaver/src/org/aspectj/weaver/patterns/BasicTokenSource.java +++ b/weaver/src/org/aspectj/weaver/patterns/BasicTokenSource.java @@ -80,7 +80,7 @@ public class BasicTokenSource implements ITokenSource { ////////////////////////////////////////////////////// // Convenience, maybe just for testing - static ITokenSource makeTokenSource(String input) { + static ITokenSource makeTokenSource(String input, ISourceContext context) { char[] chars = input.toCharArray(); int i = 0; @@ -136,7 +136,7 @@ public class BasicTokenSource implements ITokenSource { //System.out.println(tokens); - return new BasicTokenSource((IToken[])tokens.toArray(new IToken[tokens.size()]), null); + return new BasicTokenSource((IToken[])tokens.toArray(new IToken[tokens.size()]), context); } private static String makeString(char ch) { @@ -153,5 +153,8 @@ public class BasicTokenSource implements ITokenSource { public ISourceContext getSourceContext() { return sourceContext; } + public void setSourceContext(ISourceContext context) { + this.sourceContext = context; + } } diff --git a/weaver/src/org/aspectj/weaver/patterns/PatternNode.java b/weaver/src/org/aspectj/weaver/patterns/PatternNode.java index c49b52923..0730538ca 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PatternNode.java +++ b/weaver/src/org/aspectj/weaver/patterns/PatternNode.java @@ -31,11 +31,11 @@ public abstract class PatternNode implements IHasSourceLocation { } public int getStart() { - return start; + return start + (sourceContext != null ? sourceContext.getOffset() : 0); } public int getEnd() { - return end; + return end + (sourceContext != null ? sourceContext.getOffset() : 0); } public ISourceContext getSourceContext() { diff --git a/weaver/src/org/aspectj/weaver/patterns/PatternParser.java b/weaver/src/org/aspectj/weaver/patterns/PatternParser.java index ffd4446ca..ea0be3fe2 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PatternParser.java +++ b/weaver/src/org/aspectj/weaver/patterns/PatternParser.java @@ -1160,6 +1160,10 @@ public class PatternParser { public PatternParser(String data) { - this(BasicTokenSource.makeTokenSource(data)); + this(BasicTokenSource.makeTokenSource(data,null)); + } + + public PatternParser(String data, ISourceContext context) { + this(BasicTokenSource.makeTokenSource(data,context)); } } diff --git a/weaver/src/org/aspectj/weaver/patterns/PerCflow.java b/weaver/src/org/aspectj/weaver/patterns/PerCflow.java index 97c06bc55..cded77643 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PerCflow.java +++ b/weaver/src/org/aspectj/weaver/patterns/PerCflow.java @@ -126,4 +126,9 @@ public class PerCflow extends PerClause { public String toString() { return "percflow(" + inAspect + " on " + entry + ")"; } + + public String toDeclarationString() { + if (isBelow) return "percflowbelow(" + entry + ")"; + return "percflow(" + entry + ")"; + } } diff --git a/weaver/src/org/aspectj/weaver/patterns/PerClause.java b/weaver/src/org/aspectj/weaver/patterns/PerClause.java index e8fbc834a..d410436b0 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PerClause.java +++ b/weaver/src/org/aspectj/weaver/patterns/PerClause.java @@ -41,6 +41,8 @@ public abstract class PerClause extends Pointcut { public abstract PerClause.Kind getKind(); + public abstract String toDeclarationString(); + public static class Kind extends TypeSafeEnum { public Kind(String name, int key) { super(name, key); } diff --git a/weaver/src/org/aspectj/weaver/patterns/PerFromSuper.java b/weaver/src/org/aspectj/weaver/patterns/PerFromSuper.java index d7841008e..87d6b61db 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PerFromSuper.java +++ b/weaver/src/org/aspectj/weaver/patterns/PerFromSuper.java @@ -97,6 +97,10 @@ public class PerFromSuper extends PerClause { public String toString() { return "perFromSuper(" + kind + ", " + inAspect + ")"; } + + public String toDeclarationString() { + return ""; + } public PerClause.Kind getKind() { return kind; diff --git a/weaver/src/org/aspectj/weaver/patterns/PerObject.java b/weaver/src/org/aspectj/weaver/patterns/PerObject.java index b4283bc0e..79426942e 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PerObject.java +++ b/weaver/src/org/aspectj/weaver/patterns/PerObject.java @@ -137,4 +137,8 @@ public class PerObject extends PerClause { return "per" + (isThis ? "this" : "target") + "(" + entry + ")"; } + + public String toDeclarationString() { + return toString(); + } } diff --git a/weaver/src/org/aspectj/weaver/patterns/PerSingleton.java b/weaver/src/org/aspectj/weaver/patterns/PerSingleton.java index 169e83962..f98d07980 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PerSingleton.java +++ b/weaver/src/org/aspectj/weaver/patterns/PerSingleton.java @@ -126,5 +126,9 @@ public class PerSingleton extends PerClause { public String toString() { return "persingleton(" + inAspect + ")"; } + + public String toDeclarationString() { + return ""; + } } diff --git a/weaver/src/org/aspectj/weaver/patterns/PerTypeWithin.java b/weaver/src/org/aspectj/weaver/patterns/PerTypeWithin.java index cdc7c3aa9..151e3f2d7 100644 --- a/weaver/src/org/aspectj/weaver/patterns/PerTypeWithin.java +++ b/weaver/src/org/aspectj/weaver/patterns/PerTypeWithin.java @@ -169,6 +169,10 @@ public class PerTypeWithin extends PerClause { return "pertypewithin("+typePattern+")"; } + public String toDeclarationString() { + return toString(); + } + private FuzzyBoolean isWithinType(ResolvedTypeX type) { while (type != null) { if (typePattern.matchesStatically(type)) { diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/NamePatternParserTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/NamePatternParserTestCase.java index b43526586..cd646b122 100644 --- a/weaver/testsrc/org/aspectj/weaver/patterns/NamePatternParserTestCase.java +++ b/weaver/testsrc/org/aspectj/weaver/patterns/NamePatternParserTestCase.java @@ -51,7 +51,7 @@ public class NamePatternParserTestCase extends TestCase { private void checkMatch(String[] patterns) { for (int i=0, len=patterns.length; i < len; i++) { String pattern = patterns[i]; - ITokenSource tokenSource = BasicTokenSource.makeTokenSource(pattern); + ITokenSource tokenSource = BasicTokenSource.makeTokenSource(pattern,null); NamePattern p1 = new PatternParser(tokenSource).parseNamePattern(); NamePattern p2 = new NamePattern(pattern); assertEquals("pattern: " + pattern, p2, p1);