1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026 |
- /*******************************************************************************
- * 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:
- * initial implementation Alexandre Vasseur
- *******************************************************************************/
- package org.aspectj.weaver.bcel;
-
- import java.io.ByteArrayInputStream;
- import java.io.IOException;
- import java.lang.reflect.Modifier;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collections;
- import java.util.Comparator;
- import java.util.Iterator;
- import java.util.List;
- import java.util.StringTokenizer;
-
- import org.aspectj.apache.bcel.Constants;
- import org.aspectj.apache.bcel.classfile.Attribute;
- import org.aspectj.apache.bcel.classfile.Constant;
- import org.aspectj.apache.bcel.classfile.ConstantUtf8;
- import org.aspectj.apache.bcel.classfile.Field;
- import org.aspectj.apache.bcel.classfile.JavaClass;
- import org.aspectj.apache.bcel.classfile.LocalVariable;
- import org.aspectj.apache.bcel.classfile.LocalVariableTable;
- import org.aspectj.apache.bcel.classfile.Method;
- import org.aspectj.apache.bcel.classfile.Unknown;
- import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
- import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValue;
- import org.aspectj.apache.bcel.classfile.annotation.ClassElementValue;
- import org.aspectj.apache.bcel.classfile.annotation.ElementValue;
- import org.aspectj.apache.bcel.classfile.annotation.NameValuePair;
- import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnos;
- import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisAnnos;
- import org.aspectj.apache.bcel.generic.Type;
- import org.aspectj.asm.AsmManager;
- import org.aspectj.asm.IHierarchy;
- import org.aspectj.asm.IProgramElement;
- import org.aspectj.bridge.IMessage;
- import org.aspectj.bridge.IMessageHandler;
- import org.aspectj.bridge.ISourceLocation;
- import org.aspectj.bridge.Message;
- import org.aspectj.bridge.MessageUtil;
- import org.aspectj.weaver.Advice;
- import org.aspectj.weaver.AdviceKind;
- import org.aspectj.weaver.AjAttribute;
- import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
- import org.aspectj.weaver.AjcMemberMaker;
- import org.aspectj.weaver.BindingScope;
- import org.aspectj.weaver.ISourceContext;
- import org.aspectj.weaver.MethodDelegateTypeMunger;
- import org.aspectj.weaver.NameMangler;
- import org.aspectj.weaver.ReferenceType;
- import org.aspectj.weaver.ReferenceTypeDelegate;
- import org.aspectj.weaver.ResolvedMember;
- import org.aspectj.weaver.ResolvedPointcutDefinition;
- import org.aspectj.weaver.ResolvedType;
- import org.aspectj.weaver.UnresolvedType;
- import org.aspectj.weaver.VersionedDataInputStream;
- import org.aspectj.weaver.WeaverMessages;
- import org.aspectj.weaver.World;
- import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
- import org.aspectj.weaver.patterns.DeclareParents;
- import org.aspectj.weaver.patterns.DeclareParentsMixin;
- import org.aspectj.weaver.patterns.DeclarePrecedence;
- import org.aspectj.weaver.patterns.FormalBinding;
- import org.aspectj.weaver.patterns.IScope;
- import org.aspectj.weaver.patterns.ParserException;
- import org.aspectj.weaver.patterns.PatternParser;
- import org.aspectj.weaver.patterns.PerCflow;
- import org.aspectj.weaver.patterns.PerClause;
- import org.aspectj.weaver.patterns.PerFromSuper;
- import org.aspectj.weaver.patterns.PerObject;
- import org.aspectj.weaver.patterns.PerSingleton;
- import org.aspectj.weaver.patterns.PerTypeWithin;
- import org.aspectj.weaver.patterns.Pointcut;
- import org.aspectj.weaver.patterns.TypePattern;
-
- /**
- * Annotation defined aspect reader. Reads the Java 5 annotations and turns them into AjAttributes
- *
- * @author Alexandre Vasseur (alex AT gnilux DOT com)
- */
- public class AtAjAttributes {
-
- private final static List<AjAttribute> NO_ATTRIBUTES = Collections.emptyList();
- private final static String[] EMPTY_STRINGS = new String[0];
- private final static String VALUE = "value";
- private final static String ARGNAMES = "argNames";
- private final static String POINTCUT = "pointcut";
- private final static String THROWING = "throwing";
- private final static String RETURNING = "returning";
- private final static String STRING_DESC = "Ljava/lang/String;";
- private final static String ASPECTJ_ANNOTATION_PACKAGE = "org.aspectj.lang.annotation";
- private final static char PACKAGE_INITIAL_CHAR = ASPECTJ_ANNOTATION_PACKAGE.charAt(0);
-
- /**
- * A struct that allows to add extra arguments without always breaking the API
- */
- private static class AjAttributeStruct {
-
- /**
- * The list of AjAttribute.XXX that we are populating from the @AJ read
- */
- List<AjAttribute> ajAttributes = new ArrayList<>();
-
- /**
- * The resolved type (class) for which we are reading @AJ for (be it class, method, field annotations)
- */
- final ResolvedType enclosingType;
-
- final ISourceContext context;
- final IMessageHandler handler;
-
- public AjAttributeStruct(ResolvedType type, ISourceContext sourceContext, IMessageHandler messageHandler) {
- enclosingType = type;
- context = sourceContext;
- handler = messageHandler;
- }
- }
-
- /**
- * A struct when we read @AJ on method
- *
- * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
- */
- private static class AjAttributeMethodStruct extends AjAttributeStruct {
-
- // argument names used for formal binding
- private String[] m_argumentNamesLazy = null;
- public String unparsedArgumentNames = null; // Set only if discovered as
- // argNames attribute of
- // annotation
-
- final Method method;
- final BcelMethod bMethod;
-
- public AjAttributeMethodStruct(Method method, BcelMethod bMethod, ResolvedType type, ISourceContext sourceContext,
- IMessageHandler messageHandler) {
- super(type, sourceContext, messageHandler);
- this.method = method;
- this.bMethod = bMethod;
- }
-
- public String[] getArgumentNames() {
- if (m_argumentNamesLazy == null) {
- m_argumentNamesLazy = getMethodArgumentNames(method, unparsedArgumentNames, this);
- }
- return m_argumentNamesLazy;
- }
- }
-
- /**
- * A struct when we read @AJ on field
- */
- private static class AjAttributeFieldStruct extends AjAttributeStruct {
-
- final Field field;
-
- // final BcelField bField;
-
- public AjAttributeFieldStruct(Field field, BcelField bField, ResolvedType type, ISourceContext sourceContext,
- IMessageHandler messageHandler) {
- super(type, sourceContext, messageHandler);
- this.field = field;
- // this.bField = bField;
- }
- }
-
- /**
- * Annotations are RuntimeVisible only. This allow us to not visit RuntimeInvisible ones.
- *
- * @param attribute
- * @return true if runtime visible annotation
- */
- public static boolean acceptAttribute(Attribute attribute) {
- return (attribute instanceof RuntimeVisAnnos);
- }
-
- /**
- * Extract class level annotations and turn them into AjAttributes.
- *
- * @param javaClass
- * @param type
- * @param context
- * @param msgHandler
- * @return list of AjAttributes
- */
- public static List<AjAttribute> readAj5ClassAttributes(AsmManager model, JavaClass javaClass, ReferenceType type,
- ISourceContext context, IMessageHandler msgHandler, boolean isCodeStyleAspect) {
- boolean ignoreThisClass = javaClass.getClassName().charAt(0) == PACKAGE_INITIAL_CHAR
- && javaClass.getClassName().startsWith(ASPECTJ_ANNOTATION_PACKAGE);
- if (ignoreThisClass) {
- return NO_ATTRIBUTES;
- }
- boolean containsPointcut = false;
- boolean containsAnnotationClassReference = false;
- Constant[] cpool = javaClass.getConstantPool().getConstantPool();
- for (Constant constant : cpool) {
- if (constant != null && constant.getTag() == Constants.CONSTANT_Utf8) {
- String constantValue = ((ConstantUtf8) constant).getValue();
- if (constantValue.length() > 28 && constantValue.charAt(1) == PACKAGE_INITIAL_CHAR) {
- if (constantValue.startsWith("Lorg/aspectj/lang/annotation")) {
- containsAnnotationClassReference = true;
- if ("Lorg/aspectj/lang/annotation/DeclareAnnotation;".equals(constantValue)) {
- msgHandler.handleMessage(new Message(
- "Found @DeclareAnnotation while current release does not support it (see '" + type.getName()
- + "')", IMessage.WARNING, null, type.getSourceLocation()));
- }
- if ("Lorg/aspectj/lang/annotation/Pointcut;".equals(constantValue)) {
- containsPointcut = true;
- }
- }
-
- }
- }
- }
- if (!containsAnnotationClassReference) {
- return NO_ATTRIBUTES;
- }
-
- AjAttributeStruct struct = new AjAttributeStruct(type, context, msgHandler);
- Attribute[] attributes = javaClass.getAttributes();
- boolean hasAtAspectAnnotation = false;
- boolean hasAtPrecedenceAnnotation = false;
-
- WeaverVersionInfo wvinfo = null;
- for (Attribute attribute : attributes) {
- if (acceptAttribute(attribute)) {
- RuntimeAnnos rvs = (RuntimeAnnos) attribute;
- // we don't need to look for several attribute occurrences since
- // it cannot happen as per JSR175
- if (!isCodeStyleAspect && !javaClass.isInterface()) {
- hasAtAspectAnnotation = handleAspectAnnotation(rvs, struct);
- // TODO AV - if put outside the if isCodeStyleAspect then we
- // would enable mix style
- hasAtPrecedenceAnnotation = handlePrecedenceAnnotation(rvs, struct);
- }
- // there can only be one RuntimeVisible bytecode attribute
- break;
- }
- }
- for (int i = attributes.length - 1; i >= 0; i--) {
- Attribute attribute = attributes[i];
- if (attribute.getName().equals(WeaverVersionInfo.AttributeName)) {
- try {
- VersionedDataInputStream s = new VersionedDataInputStream(new ByteArrayInputStream(
- ((Unknown) attribute).getBytes()), null);
- wvinfo = WeaverVersionInfo.read(s);
- struct.ajAttributes.add(0, wvinfo);
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
- }
- if (wvinfo == null) {
- // If we are in here due to a resetState() call (presumably because of reweavable state processing), the
- // original type delegate will have been set with a version but that version will be missing from
- // the new set of attributes (looks like a bug where the version attribute was not included in the
- // data compressed into the attribute). So rather than 'defaulting' to current, we should use one
- // if it set on the delegate for the type.
- ReferenceTypeDelegate delegate = type.getDelegate();
- if (delegate instanceof BcelObjectType) {
- wvinfo = ((BcelObjectType) delegate).getWeaverVersionAttribute();
- if (wvinfo != null) {
- if (wvinfo.getMajorVersion() != WeaverVersionInfo.WEAVER_VERSION_MAJOR_UNKNOWN) {
- // use this one
- struct.ajAttributes.add(0, wvinfo);
- } else {
- wvinfo = null;
- }
- }
- }
- if (wvinfo == null) {
- struct.ajAttributes.add(0, wvinfo = new AjAttribute.WeaverVersionInfo());
- }
- }
-
- // basic semantic check
- if (hasAtPrecedenceAnnotation && !hasAtAspectAnnotation) {
- msgHandler.handleMessage(new Message("Found @DeclarePrecedence on a non @Aspect type '" + type.getName() + "'",
- IMessage.WARNING, null, type.getSourceLocation()));
- // bypass what we have read
- return NO_ATTRIBUTES;
- }
-
- // the following block will not detect @Pointcut in non @Aspect types
- // for optimization purpose
- if (!(hasAtAspectAnnotation || isCodeStyleAspect) && !containsPointcut) {
- return NO_ATTRIBUTES;
- }
-
- // FIXME AV - turn on when ajcMightHaveAspect
- // if (hasAtAspectAnnotation && type.isInterface()) {
- // msgHandler.handleMessage(
- // new Message(
- // "Found @Aspect on an interface type '" + type.getName() + "'",
- // IMessage.WARNING,
- // null,
- // type.getSourceLocation()
- // )
- // );
- // // bypass what we have read
- // return EMPTY_LIST;
- // }
-
- // semantic check: @Aspect must be public
- // FIXME AV - do we really want to enforce that?
- // if (hasAtAspectAnnotation && !javaClass.isPublic()) {
- // msgHandler.handleMessage(
- // new Message(
- // "Found @Aspect annotation on a non public class '" +
- // javaClass.getClassName() + "'",
- // IMessage.ERROR,
- // null,
- // type.getSourceLocation()
- // )
- // );
- // return EMPTY_LIST;
- // }
-
- // code style pointcuts are class attributes
- // we need to gather the @AJ pointcut right now and not at method level
- // annotation extraction time
- // in order to be able to resolve the pointcut references later on
- // we don't need to look in super class, the pointcut reference in the
- // grammar will do it
-
- for (int i = 0; i < javaClass.getMethods().length; i++) {
- Method method = javaClass.getMethods()[i];
- 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 = null;
- boolean processedPointcut = false;
- Attribute[] mattributes = method.getAttributes();
- for (Attribute mattribute : mattributes) {
- if (acceptAttribute(mattribute)) {
- // TODO speed all this nonsense up rather than looking
- // through all the annotations every time
- // same for fields
- mstruct = new AjAttributeMethodStruct(method, null, type, context, msgHandler);
- processedPointcut = handlePointcutAnnotation((RuntimeAnnos) mattribute, mstruct);
- if (!processedPointcut) {
- processedPointcut = handleDeclareMixinAnnotation((RuntimeAnnos) mattribute, mstruct);
- }
- // there can only be one RuntimeVisible bytecode attribute
- break;
- }
- }
- if (processedPointcut) {
- struct.ajAttributes.addAll(mstruct.ajAttributes);
- }
- }
-
- // code style declare error / warning / implements / parents are field
- // attributes
- Field[] fs = javaClass.getFields();
- for (Field field : fs) {
- if (field.getName().startsWith(NameMangler.PREFIX)) {
- continue; // already dealt with by ajc...
- }
- // FIXME alex optimize, this method struct will gets recreated for
- // advice extraction
- AjAttributeFieldStruct fstruct = new AjAttributeFieldStruct(field, null, type, context, msgHandler);
- Attribute[] fattributes = field.getAttributes();
-
- for (Attribute fattribute : fattributes) {
- if (acceptAttribute(fattribute)) {
- RuntimeAnnos frvs = (RuntimeAnnos) fattribute;
- if (handleDeclareErrorOrWarningAnnotation(model, frvs, fstruct)
- || handleDeclareParentsAnnotation(frvs, fstruct)) {
- // semantic check - must be in an @Aspect [remove if
- // previous block bypassed in advance]
- if (!type.isAnnotationStyleAspect() && !isCodeStyleAspect) {
- msgHandler.handleMessage(new Message("Found @AspectJ annotations in a non @Aspect type '"
- + type.getName() + "'", IMessage.WARNING, null, type.getSourceLocation()));
- // go ahead
- }
- }
- // there can only be one RuntimeVisible bytecode attribute
- break;
- }
- }
- struct.ajAttributes.addAll(fstruct.ajAttributes);
- }
-
- return struct.ajAttributes;
- }
-
- /**
- * Extract method level annotations and turn them into AjAttributes.
- *
- * @param method
- * @param type
- * @param context
- * @param msgHandler
- * @return list of AjAttributes
- */
- public static List<AjAttribute> readAj5MethodAttributes(Method method, BcelMethod bMethod, ResolvedType type,
- ResolvedPointcutDefinition preResolvedPointcut, ISourceContext context, IMessageHandler msgHandler) {
- if (method.getName().startsWith(NameMangler.PREFIX)) {
- return Collections.emptyList(); // already dealt with by ajc...
- }
-
- AjAttributeMethodStruct struct = new AjAttributeMethodStruct(method, bMethod, type, context, msgHandler);
- Attribute[] attributes = method.getAttributes();
-
- // we remember if we found one @AJ annotation for minimal semantic error
- // reporting
- // the real reporting beeing done thru AJDT and the compiler mapping @AJ
- // to AjAtttribute
- // or thru APT
- //
- // Note: we could actually skip the whole thing if type is not itself an
- // @Aspect
- // but then we would not see any warning. We do bypass for pointcut but
- // not for advice since it would
- // be too silent.
- boolean hasAtAspectJAnnotation = false;
- boolean hasAtAspectJAnnotationMustReturnVoid = false;
- for (Attribute attribute : attributes) {
- try {
- if (acceptAttribute(attribute)) {
- RuntimeAnnos rvs = (RuntimeAnnos) attribute;
- hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid
- || handleBeforeAnnotation(rvs, struct, preResolvedPointcut);
- hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid
- || handleAfterAnnotation(rvs, struct, preResolvedPointcut);
- hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid
- || handleAfterReturningAnnotation(rvs, struct, preResolvedPointcut, bMethod);
- hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid
- || handleAfterThrowingAnnotation(rvs, struct, preResolvedPointcut, bMethod);
- hasAtAspectJAnnotation = hasAtAspectJAnnotation || handleAroundAnnotation(rvs, struct, preResolvedPointcut);
- // there can only be one RuntimeVisible bytecode attribute
- break;
- }
- } catch (ReturningFormalNotDeclaredInAdviceSignatureException e) {
- msgHandler.handleMessage(new Message(WeaverMessages.format(WeaverMessages.RETURNING_FORMAL_NOT_DECLARED_IN_ADVICE,
- e.getFormalName()), IMessage.ERROR, null, bMethod.getSourceLocation()));
- } catch (ThrownFormalNotDeclaredInAdviceSignatureException e) {
- msgHandler.handleMessage(new Message(WeaverMessages.format(WeaverMessages.THROWN_FORMAL_NOT_DECLARED_IN_ADVICE,
- e.getFormalName()), IMessage.ERROR, null, bMethod.getSourceLocation()));
- }
- }
- hasAtAspectJAnnotation = hasAtAspectJAnnotation || hasAtAspectJAnnotationMustReturnVoid;
-
- // semantic check - must be in an @Aspect [remove if previous block
- // bypassed in advance]
- if (hasAtAspectJAnnotation && !type.isAspect()) { // isAnnotationStyleAspect())
- // {
- msgHandler.handleMessage(new Message("Found @AspectJ annotations in a non @Aspect type '" + type.getName() + "'",
- IMessage.WARNING, null, type.getSourceLocation()));
- // go ahead
- }
- // semantic check - advice must be public
- if (hasAtAspectJAnnotation && !struct.method.isPublic()) {
- msgHandler.handleMessage(new Message("Found @AspectJ annotation on a non public advice '"
- + methodToString(struct.method) + "'", IMessage.ERROR, null, type.getSourceLocation()));
- // go ahead
- }
-
- // semantic check - advice must not be static
- if (hasAtAspectJAnnotation && struct.method.isStatic()) {
- msgHandler.handleMessage(MessageUtil.error("Advice cannot be declared static '" + methodToString(struct.method) + "'",
- type.getSourceLocation()));
- // new Message(
- // "Advice cannot be declared static '" +
- // methodToString(struct.method) + "'",
- // IMessage.ERROR,
- // null,
- // type.getSourceLocation()
- // )
- // );
- // go ahead
- }
-
- // semantic check for non around advice must return void
- if (hasAtAspectJAnnotationMustReturnVoid && !Type.VOID.equals(struct.method.getReturnType())) {
- msgHandler.handleMessage(new Message("Found @AspectJ annotation on a non around advice not returning void '"
- + methodToString(struct.method) + "'", IMessage.ERROR, null, type.getSourceLocation()));
- // go ahead
- }
-
- return struct.ajAttributes;
- }
-
- /**
- * Extract field level annotations and turn them into AjAttributes.
- *
- * @param field
- * @param type
- * @param context
- * @param msgHandler
- * @return list of AjAttributes, always empty for now
- */
- public static List<AjAttribute> readAj5FieldAttributes(Field field, BcelField bField, ResolvedType type,
- ISourceContext context, IMessageHandler msgHandler) {
- // Note: field annotation are for ITD and DEOW - processed at class
- // level directly
- return Collections.emptyList();
- }
-
- /**
- * Read @Aspect
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handleAspectAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeStruct struct) {
- AnnotationGen aspect = getAnnotation(runtimeAnnotations, AjcMemberMaker.ASPECT_ANNOTATION);
- if (aspect != null) {
- // semantic check for inheritance (only one level up)
- boolean extendsAspect = false;
- if (!"java.lang.Object".equals(struct.enclosingType.getSuperclass().getName())) {
- if (!struct.enclosingType.getSuperclass().isAbstract() && struct.enclosingType.getSuperclass().isAspect()) {
- reportError("cannot extend a concrete aspect", struct);
- return false;
- }
- extendsAspect = struct.enclosingType.getSuperclass().isAspect();
- }
-
- NameValuePair aspectPerClause = getAnnotationElement(aspect, VALUE);
- final PerClause perClause;
- if (aspectPerClause == null) {
- // empty value means singleton unless inherited
- if (!extendsAspect) {
- perClause = new PerSingleton();
- } else {
- perClause = new PerFromSuper(struct.enclosingType.getSuperclass().getPerClause().getKind());
- }
- } else {
- String perX = aspectPerClause.getValue().stringifyValue();
- if (perX == null || perX.length() <= 0) {
- perClause = new PerSingleton();
- } else {
- perClause = parsePerClausePointcut(perX, struct);
- }
- }
- if (perClause == null) {
- // could not parse it, ignore the aspect
- return false;
- } else {
- perClause.setLocation(struct.context, -1, -1);// struct.context.getOffset(),
- // struct.context.getOffset()+1);//FIXME
- // AVASM
- // Not setting version here
- // struct.ajAttributes.add(new AjAttribute.WeaverVersionInfo());
- AjAttribute.Aspect aspectAttribute = new AjAttribute.Aspect(perClause);
- struct.ajAttributes.add(aspectAttribute);
- FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
- final IScope binding;
- binding = new BindingScope(struct.enclosingType, struct.context, bindings);
-
- // // we can't resolve here since the perclause typically refers
- // to pointcuts
- // // defined in the aspect that we haven't told the
- // BcelObjectType about yet.
- //
- // perClause.resolve(binding);
-
- // so we prepare to do it later...
- aspectAttribute.setResolutionScope(binding);
- return true;
- }
- }
- return false;
- }
-
- /**
- * Read a perClause, returns null on failure and issue messages
- *
- * @param perClauseString like "pertarget(.....)"
- * @param struct for which we are parsing the per clause
- * @return a PerClause instance
- */
- private static PerClause parsePerClausePointcut(String perClauseString, AjAttributeStruct struct) {
- final String pointcutString;
- Pointcut pointcut = null;
- TypePattern typePattern = null;
- final PerClause perClause;
- if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERCFLOW.getName())) {
- pointcutString = PerClause.KindAnnotationPrefix.PERCFLOW.extractPointcut(perClauseString);
- pointcut = parsePointcut(pointcutString, struct, false);
- perClause = new PerCflow(pointcut, false);
- } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERCFLOWBELOW.getName())) {
- pointcutString = PerClause.KindAnnotationPrefix.PERCFLOWBELOW.extractPointcut(perClauseString);
- pointcut = parsePointcut(pointcutString, struct, false);
- perClause = new PerCflow(pointcut, true);
- } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTARGET.getName())) {
- pointcutString = PerClause.KindAnnotationPrefix.PERTARGET.extractPointcut(perClauseString);
- pointcut = parsePointcut(pointcutString, struct, false);
- perClause = new PerObject(pointcut, false);
- } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTHIS.getName())) {
- pointcutString = PerClause.KindAnnotationPrefix.PERTHIS.extractPointcut(perClauseString);
- pointcut = parsePointcut(pointcutString, struct, false);
- perClause = new PerObject(pointcut, true);
- } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTYPEWITHIN.getName())) {
- pointcutString = PerClause.KindAnnotationPrefix.PERTYPEWITHIN.extractPointcut(perClauseString);
- typePattern = parseTypePattern(pointcutString, struct);
- perClause = new PerTypeWithin(typePattern);
- } else if (perClauseString.equalsIgnoreCase(PerClause.SINGLETON.getName() + "()")) {
- perClause = new PerSingleton();
- } else {
- // could not parse the @AJ perclause - fallback to singleton and
- // issue an error
- reportError("@Aspect per clause cannot be read '" + perClauseString + "'", struct);
- return null;
- }
-
- if (!PerClause.SINGLETON.equals(perClause.getKind()) && !PerClause.PERTYPEWITHIN.equals(perClause.getKind())
- && pointcut == null) {
- // we could not parse the pointcut
- return null;
- }
- if (PerClause.PERTYPEWITHIN.equals(perClause.getKind()) && typePattern == null) {
- // we could not parse the type pattern
- return null;
- }
- return perClause;
- }
-
- /**
- * Read @DeclarePrecedence
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handlePrecedenceAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeStruct struct) {
- AnnotationGen aspect = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREPRECEDENCE_ANNOTATION);
- if (aspect != null) {
- NameValuePair precedence = getAnnotationElement(aspect, VALUE);
- if (precedence != null) {
- String precedencePattern = precedence.getValue().stringifyValue();
- PatternParser parser = new PatternParser(precedencePattern);
- DeclarePrecedence ajPrecedence = parser.parseDominates();
- struct.ajAttributes.add(new AjAttribute.DeclareAttribute(ajPrecedence));
- return true;
- }
- }
- return false;
- }
-
- // /**
- // * Read @DeclareImplements
- // *
- // * @param runtimeAnnotations
- // * @param struct
- // * @return true if found
- // */
- // private static boolean
- // handleDeclareImplementsAnnotation(RuntimeAnnotations runtimeAnnotations,
- // AjAttributeFieldStruct
- // struct) {//, ResolvedPointcutDefinition preResolvedPointcut) {
- // Annotation deci = getAnnotation(runtimeAnnotations,
- // AjcMemberMaker.DECLAREIMPLEMENTS_ANNOTATION);
- // if (deci != null) {
- // ElementNameValuePairGen deciPatternNVP = getAnnotationElement(deci,
- // VALUE);
- // String deciPattern = deciPatternNVP.getValue().stringifyValue();
- // if (deciPattern != null) {
- // TypePattern typePattern = parseTypePattern(deciPattern, struct);
- // ResolvedType fieldType =
- // UnresolvedType.forSignature(struct.field.getSignature()).resolve(struct.enclosingType.getWorld());
- // if (fieldType.isPrimitiveType()) {
- // return false;
- // } else if (fieldType.isInterface()) {
- // TypePattern parent = new
- // ExactTypePattern(UnresolvedType.forSignature(struct.field.getSignature()),
- // false, false);
- // parent.resolve(struct.enclosingType.getWorld());
- // List parents = new ArrayList(1);
- // parents.add(parent);
- // //TODO kick ISourceLocation sl = struct.bField.getSourceLocation(); ??
- // struct.ajAttributes.add(
- // new AjAttribute.DeclareAttribute(
- // new DeclareParents(
- // typePattern,
- // parents,
- // false
- // )
- // )
- // );
- // return true;
- // } else {
- // reportError("@DeclareImplements: can only be used on field whose type is an interface",
- // struct);
- // return false;
- // }
- // }
- // }
- // return false;
- // }
-
- private static boolean handleDeclareParentsAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeFieldStruct struct) {
- AnnotationGen decpAnno = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREPARENTS_ANNOTATION);
- if (decpAnno != null) {
- NameValuePair decpPatternNameValuePair = getAnnotationElement(decpAnno, VALUE);
- String decpPattern = decpPatternNameValuePair.getValue().stringifyValue();
- System.out.println("decpPatterNVP = "+decpPattern);
- if (decpPattern != null) {
- TypePattern typePattern = parseTypePattern(decpPattern, struct);
- ResolvedType fieldType = UnresolvedType.forSignature(struct.field.getSignature()).resolve(
- struct.enclosingType.getWorld());
- if (fieldType.isParameterizedOrRawType()) {
- fieldType = fieldType.getGenericType();
- }
- if (fieldType.isInterface()) {
- TypePattern parent = parseTypePattern(fieldType.getName(), struct);
- FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
- IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings);
- // first add the declare implements like
- List<TypePattern> parents = new ArrayList<>(1);
- parents.add(parent);
- DeclareParents dp = new DeclareParents(typePattern, parents, false);
- dp.resolve(binding); // resolves the parent and child parts of the decp
-
- // resolve this so that we can use it for the
- // MethodDelegateMungers below.
- // eg. '@Coloured *' will change from a WildTypePattern to
- // an 'AnyWithAnnotationTypePattern' after this resolution
- typePattern = dp.getChild(); // this retrieves the resolved version
- // TODO kick ISourceLocation sl =
- // struct.bField.getSourceLocation(); ??
- // dp.setLocation(dp.getDeclaringType().getSourceContext(),
- // dp.getDeclaringType().getSourceLocation().getOffset(),
- // dp.getDeclaringType().getSourceLocation().getOffset());
- dp.setLocation(struct.context, -1, -1); // not ideal...
- struct.ajAttributes.add(new AjAttribute.DeclareAttribute(dp));
-
- // do we have a defaultImpl=xxx.class (ie implementation)
- String defaultImplClassName = null;
- NameValuePair defaultImplNVP = getAnnotationElement(decpAnno, "defaultImpl");
- if (defaultImplNVP != null) {
- ClassElementValue defaultImpl = (ClassElementValue) defaultImplNVP.getValue();
- defaultImplClassName = UnresolvedType.forSignature(defaultImpl.getClassString()).getName();
- if (defaultImplClassName.equals("org.aspectj.lang.annotation.DeclareParents")) {
- defaultImplClassName = null;
- } else {
- // check public no arg ctor
- ResolvedType impl = struct.enclosingType.getWorld().resolve(defaultImplClassName, false);
- ResolvedMember[] mm = impl.getDeclaredMethods();
- int implModifiers = impl.getModifiers();
- boolean defaultVisibilityImpl = !(Modifier.isPrivate(implModifiers)
- || Modifier.isProtected(implModifiers) || Modifier.isPublic(implModifiers));
- boolean hasNoCtorOrANoArgOne = true;
- ResolvedMember foundOneOfIncorrectVisibility = null;
- for (ResolvedMember resolvedMember : mm) {
- if (resolvedMember.getName().equals("<init>")) {
- hasNoCtorOrANoArgOne = false;
-
- if (resolvedMember.getParameterTypes().length == 0) {
- if (defaultVisibilityImpl) { // default visibility implementation
- if (resolvedMember.isPublic() || resolvedMember.isDefault()) {
- hasNoCtorOrANoArgOne = true;
- } else {
- foundOneOfIncorrectVisibility = resolvedMember;
- }
- } else if (Modifier.isPublic(implModifiers)) { // public
- // implementation
- if (resolvedMember.isPublic()) {
- hasNoCtorOrANoArgOne = true;
- } else {
- foundOneOfIncorrectVisibility = resolvedMember;
- }
- }
- }
- }
- if (hasNoCtorOrANoArgOne) {
- break;
- }
- }
- if (!hasNoCtorOrANoArgOne) {
- if (foundOneOfIncorrectVisibility != null) {
- reportError(
- "@DeclareParents: defaultImpl=\""
- + defaultImplClassName
- + "\" has a no argument constructor, but it is of incorrect visibility. It must be at least as visible as the type.",
- struct);
- } else {
- reportError("@DeclareParents: defaultImpl=\"" + defaultImplClassName
- + "\" has no public no-arg constructor", struct);
- }
- }
- if (!fieldType.isAssignableFrom(impl)) {
- reportError("@DeclareParents: defaultImpl=\"" + defaultImplClassName
- + "\" does not implement the interface '" + fieldType.toString() + "'", struct);
- }
- }
-
- }
- boolean hasAtLeastOneMethod = false;
- // then iterate on field interface hierarchy (not object)
- Iterator<ResolvedMember> methodIterator = fieldType.getMethodsIncludingIntertypeDeclarations(false, true);
- while (methodIterator.hasNext()) {
- ResolvedMember method = methodIterator.next();
- if (method.isAbstract()) {
- // moved to be detected at weave time if the target
- // doesnt implement the methods
- // if (defaultImplClassName == null) {
- // // non marker interface with no default impl
- // provided
- // reportError("@DeclareParents: used with a non marker interface and no defaultImpl=\"...\" provided",
- // struct);
- // return false;
- // }
- hasAtLeastOneMethod = true;
- // What we are saying here:
- // We have this method 'method' and we want to put a
- // forwarding method into a type that matches
- // typePattern that should delegate to the version
- // of the method in 'defaultImplClassName'
-
- // Now the method may be from a supertype but the
- // declaring type of the method we pass into the
- // type
- // munger is what is used to determine the type of
- // the field that hosts the delegate instance.
- // So here we create a modified method with an
- // alternative declaring type so that we lookup
- // the right field. See pr164016.
- MethodDelegateTypeMunger mdtm = new MethodDelegateTypeMunger(method, struct.enclosingType, defaultImplClassName, typePattern);
- mdtm.setFieldType(fieldType);
- mdtm.setSourceLocation(struct.enclosingType.getSourceLocation());
- struct.ajAttributes.add(new AjAttribute.TypeMunger(mdtm));
- }
- }
- // successful so far, we thus need a bcel type munger to have
- // a field hosting the mixin in the target type
- if (hasAtLeastOneMethod && defaultImplClassName != null) {
- ResolvedMember fieldHost = AjcMemberMaker.itdAtDeclareParentsField(null, fieldType, struct.enclosingType);
- struct.ajAttributes.add(new AjAttribute.TypeMunger(new MethodDelegateTypeMunger.FieldHostTypeMunger(
- fieldHost, struct.enclosingType, typePattern)));
- }
- return true;
- } else {
- reportError("@DeclareParents: can only be used on a field whose type is an interface", struct);
- return false;
- }
- }
- }
- return false;
- }
-
- /**
- * @return a nicely formatted method string, for example: int X.foo(java.lang.String)
- */
- public static String getMethodForMessage(AjAttributeMethodStruct methodstructure) {
- StringBuffer sb = new StringBuffer();
- sb.append("Method '");
- sb.append(methodstructure.method.getReturnType().toString());
- sb.append(" ").append(methodstructure.enclosingType).append(".").append(methodstructure.method.getName());
- sb.append("(");
- Type[] args = methodstructure.method.getArgumentTypes();
- if (args != null) {
- for (int t = 0; t < args.length; t++) {
- if (t > 0) {
- sb.append(",");
- }
- sb.append(args[t].toString());
- }
- }
- sb.append(")'");
- return sb.toString();
- }
-
- /**
- * Process any @DeclareMixin annotation.
- *
- * Example Declaration <br>
- *
- * @DeclareMixin("Foo+") public I createImpl(Object o) { return new Impl(o); }
- *
- * <br>
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handleDeclareMixinAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct) {
- AnnotationGen declareMixinAnnotation = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREMIXIN_ANNOTATION);
- if (declareMixinAnnotation == null) {
- // No annotation found
- return false;
- }
- Method annotatedMethod = struct.method;
- World world = struct.enclosingType.getWorld();
- NameValuePair declareMixinPatternNameValuePair = getAnnotationElement(declareMixinAnnotation, VALUE);
-
- // declareMixinPattern could be of the form "Bar*" or "A || B" or "Foo+"
- String declareMixinPattern = declareMixinPatternNameValuePair.getValue().stringifyValue();
- TypePattern targetTypePattern = parseTypePattern(declareMixinPattern, struct);
-
- // Return value of the annotated method is the interface or class that the mixin delegate should have
- ResolvedType methodReturnType = UnresolvedType.forSignature(annotatedMethod.getReturnType().getSignature()).resolve(world);
- if (methodReturnType.isParameterizedOrRawType()) {
- methodReturnType = methodReturnType.getGenericType();
- }
- if (methodReturnType.isPrimitiveType()) {
- reportError(getMethodForMessage(struct) + ": factory methods for a mixin cannot return void or a primitive type",
- struct);
- return false;
- }
-
- if (annotatedMethod.getArgumentTypes().length > 1) {
- reportError(getMethodForMessage(struct) + ": factory methods for a mixin can take a maximum of one parameter", struct);
- return false;
- }
-
- // The set of interfaces to be mixed in is either:
- // supplied as a list in the 'Class[] interfaces' value in the annotation value
- // supplied as just the interface return value of the annotated method
- // supplied as just the class return value of the annotated method
- NameValuePair interfaceListSpecified = getAnnotationElement(declareMixinAnnotation, "interfaces");
-
- List<TypePattern> newParents = new ArrayList<>(1);
- List<ResolvedType> newInterfaceTypes = new ArrayList<>(1);
- if (interfaceListSpecified != null) {
- ArrayElementValue arrayOfInterfaceTypes = (ArrayElementValue) interfaceListSpecified.getValue();
- int numberOfTypes = arrayOfInterfaceTypes.getElementValuesArraySize();
- ElementValue[] theTypes = arrayOfInterfaceTypes.getElementValuesArray();
- for (int i = 0; i < numberOfTypes; i++) {
- ClassElementValue interfaceType = (ClassElementValue) theTypes[i];
- // Check: needs to be resolvable
- // TODO crappy replace required
- ResolvedType ajInterfaceType = UnresolvedType.forSignature(interfaceType.getClassString().replace("/", "."))
- .resolve(world);
- if (ajInterfaceType.isMissing() || !ajInterfaceType.isInterface()) {
- reportError(
- "Types listed in the 'interfaces' DeclareMixin annotation value must be valid interfaces. This is invalid: "
- + ajInterfaceType.getName(), struct); // TODO better error location, use the method position
- return false;
- }
- if (!ajInterfaceType.isAssignableFrom(methodReturnType)) {
- reportError(getMethodForMessage(struct) + ": factory method does not return something that implements '"
- + ajInterfaceType.getName() + "'", struct);
- return false;
- }
- newInterfaceTypes.add(ajInterfaceType);
- // Checking that it is a superinterface of the methods return value is done at weave time
- TypePattern newParent = parseTypePattern(ajInterfaceType.getName(), struct);
- newParents.add(newParent);
- }
- } else {
- if (methodReturnType.isClass()) {
- reportError(
- getMethodForMessage(struct)
- + ": factory methods for a mixin must either return an interface type or specify interfaces in the annotation and return a class",
- struct);
- return false;
- }
- // Use the method return type: this might be a class or an interface
- TypePattern newParent = parseTypePattern(methodReturnType.getName(), struct);
- newInterfaceTypes.add(methodReturnType);
- newParents.add(newParent);
- }
- if (newParents.size() == 0) {
- // Warning: did they foolishly put @DeclareMixin(value="Bar+",interfaces={})
- // TODO output warning
- return false;
- }
-
- // Create the declare parents that will add the interfaces to matching targets
- FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
- IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings);
- // how do we mark this as a decp due to decmixin?
- DeclareParents dp = new DeclareParentsMixin(targetTypePattern, newParents);
- dp.resolve(binding);
- targetTypePattern = dp.getChild();
-
- dp.setLocation(struct.context, -1, -1); // not ideal...
- struct.ajAttributes.add(new AjAttribute.DeclareAttribute(dp));
-
- // The factory method for building the implementation is the
- // one attached to the annotation:
- // Method implementationFactory = struct.method;
-
- boolean hasAtLeastOneMethod = false;
-
- for (ResolvedType typeForDelegation : newInterfaceTypes) {
- // TODO check for overlapping interfaces. Eg. A implements I, I extends J - if they specify interfaces={I,J} we dont
- // want to do any methods twice
- ResolvedMember[] methods = typeForDelegation.getMethodsWithoutIterator(true, false, false).toArray(
- new ResolvedMember[0]);
- for (ResolvedMember resolvedMember : methods) {
- ResolvedMember method = resolvedMember;
- if (method.isAbstract()) {
- hasAtLeastOneMethod = true;
- if (method.hasBackingGenericMember()) {
- method = method.getBackingGenericMember();
- }
- MethodDelegateTypeMunger mdtm = new MethodDelegateTypeMunger(method, struct.enclosingType, "",
- targetTypePattern, struct.method.getName(), struct.method.getSignature());
- mdtm.setFieldType(methodReturnType);
- mdtm.setSourceLocation(struct.enclosingType.getSourceLocation());
- struct.ajAttributes.add(new AjAttribute.TypeMunger(mdtm));
- }
- }
- }
- // if any method delegate was created then a field to hold the delegate instance must also be added
- if (hasAtLeastOneMethod) {
- ResolvedMember fieldHost = AjcMemberMaker.itdAtDeclareParentsField(null, methodReturnType, struct.enclosingType);
- struct.ajAttributes.add(new AjAttribute.TypeMunger(new MethodDelegateTypeMunger.FieldHostTypeMunger(fieldHost,
- struct.enclosingType, targetTypePattern)));
- }
- return true;
- }
-
- /**
- * Read @Before
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handleBeforeAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct,
- ResolvedPointcutDefinition preResolvedPointcut) {
- AnnotationGen before = getAnnotation(runtimeAnnotations, AjcMemberMaker.BEFORE_ANNOTATION);
- if (before != null) {
- NameValuePair beforeAdvice = getAnnotationElement(before, VALUE);
- if (beforeAdvice != null) {
- // this/target/args binding
- String argumentNames = getArgNamesValue(before);
- if (argumentNames != null) {
- struct.unparsedArgumentNames = argumentNames;
- }
- FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
- try {
- bindings = extractBindings(struct);
- } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
- return false;
- }
- IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings);
-
- // joinpoint, staticJoinpoint binding
- int extraArgument = extractExtraArgument(struct.method);
-
- Pointcut pc = null;
- if (preResolvedPointcut != null) {
- pc = preResolvedPointcut.getPointcut();
- // pc.resolve(binding);
- } else {
- pc = parsePointcut(beforeAdvice.getValue().stringifyValue(), struct, false);
- if (pc == null) {
- return false;// parse error
- }
- pc = pc.resolve(binding);
- }
- setIgnoreUnboundBindingNames(pc, bindings);
-
- ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(),
- struct.bMethod.getDeclarationOffset());
- struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.Before, pc, extraArgument, sl.getOffset(), sl
- .getOffset() + 1,// FIXME AVASM
- struct.context));
- return true;
- }
- }
- return false;
- }
-
- /**
- * Read @After
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handleAfterAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct,
- ResolvedPointcutDefinition preResolvedPointcut) {
- AnnotationGen after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTER_ANNOTATION);
- if (after != null) {
- NameValuePair afterAdvice = getAnnotationElement(after, VALUE);
- if (afterAdvice != null) {
- // this/target/args binding
- FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
- String argumentNames = getArgNamesValue(after);
- if (argumentNames != null) {
- struct.unparsedArgumentNames = argumentNames;
- }
- try {
- bindings = extractBindings(struct);
- } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
- return false;
- }
- IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings);
-
- // joinpoint, staticJoinpoint binding
- int extraArgument = extractExtraArgument(struct.method);
-
- Pointcut pc = null;
- if (preResolvedPointcut != null) {
- pc = preResolvedPointcut.getPointcut();
- } else {
- pc = parsePointcut(afterAdvice.getValue().stringifyValue(), struct, false);
- if (pc == null) {
- return false;// parse error
- }
- pc.resolve(binding);
- }
- setIgnoreUnboundBindingNames(pc, bindings);
-
- ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(),
- struct.bMethod.getDeclarationOffset());
- struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.After, pc, extraArgument, sl.getOffset(), sl
- .getOffset() + 1,// FIXME AVASM
- struct.context));
- return true;
- }
- }
- return false;
- }
-
- /**
- * Read @AfterReturning
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handleAfterReturningAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct,
- ResolvedPointcutDefinition preResolvedPointcut, BcelMethod owningMethod)
- throws ReturningFormalNotDeclaredInAdviceSignatureException {
- AnnotationGen after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERRETURNING_ANNOTATION);
- if (after != null) {
- NameValuePair annValue = getAnnotationElement(after, VALUE);
- NameValuePair annPointcut = getAnnotationElement(after, POINTCUT);
- NameValuePair annReturned = getAnnotationElement(after, RETURNING);
-
- // extract the pointcut and returned type/binding - do some checks
- String pointcut = null;
- String returned = null;
- if ((annValue != null && annPointcut != null) || (annValue == null && annPointcut == null)) {
- reportError("@AfterReturning: either 'value' or 'poincut' must be provided, not both", struct);
- return false;
- }
- if (annValue != null) {
- pointcut = annValue.getValue().stringifyValue();
- } else {
- pointcut = annPointcut.getValue().stringifyValue();
- }
- if (isNullOrEmpty(pointcut)) {
- reportError("@AfterReturning: either 'value' or 'poincut' must be provided, not both", struct);
- return false;
- }
- if (annReturned != null) {
- returned = annReturned.getValue().stringifyValue();
- if (isNullOrEmpty(returned)) {
- returned = null;
- } else {
- // check that thrownFormal exists as the last parameter in
- // the advice
- String[] pNames = owningMethod.getParameterNames();
- if (pNames == null || pNames.length == 0 || !Arrays.asList(pNames).contains(returned)) {
- throw new ReturningFormalNotDeclaredInAdviceSignatureException(returned);
- }
- }
- }
- String argumentNames = getArgNamesValue(after);
- if (argumentNames != null) {
- struct.unparsedArgumentNames = argumentNames;
- }
- // this/target/args binding
- // exclude the return binding from the pointcut binding since it is
- // an extraArg binding
- FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
- try {
- bindings = (returned == null ? extractBindings(struct) : extractBindings(struct, returned));
- } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
- return false;
- }
- IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings);
-
- // joinpoint, staticJoinpoint binding
- int extraArgument = extractExtraArgument(struct.method);
-
- // return binding
- if (returned != null) {
- extraArgument |= Advice.ExtraArgument;
- }
-
- Pointcut pc = null;
- if (preResolvedPointcut != null) {
- pc = preResolvedPointcut.getPointcut();
- } else {
- pc = parsePointcut(pointcut, struct, false);
- if (pc == null) {
- return false;// parse error
- }
- pc.resolve(binding);
- }
- setIgnoreUnboundBindingNames(pc, bindings);
-
- ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(),
- struct.bMethod.getDeclarationOffset());
- struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.AfterReturning, pc, extraArgument, sl.getOffset(),
- sl.getOffset() + 1,// FIXME AVASM
- struct.context));
- return true;
- }
- return false;
- }
-
- /**
- * Read @AfterThrowing
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handleAfterThrowingAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct,
- ResolvedPointcutDefinition preResolvedPointcut, BcelMethod owningMethod)
- throws ThrownFormalNotDeclaredInAdviceSignatureException {
- AnnotationGen after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERTHROWING_ANNOTATION);
- if (after != null) {
- NameValuePair annValue = getAnnotationElement(after, VALUE);
- NameValuePair annPointcut = getAnnotationElement(after, POINTCUT);
- NameValuePair annThrown = getAnnotationElement(after, THROWING);
-
- // extract the pointcut and throwned type/binding - do some checks
- String pointcut = null;
- String thrownFormal = null;
- if ((annValue != null && annPointcut != null) || (annValue == null && annPointcut == null)) {
- reportError("@AfterThrowing: either 'value' or 'poincut' must be provided, not both", struct);
- return false;
- }
- if (annValue != null) {
- pointcut = annValue.getValue().stringifyValue();
- } else {
- pointcut = annPointcut.getValue().stringifyValue();
- }
- if (isNullOrEmpty(pointcut)) {
- reportError("@AfterThrowing: either 'value' or 'poincut' must be provided, not both", struct);
- return false;
- }
- if (annThrown != null) {
- thrownFormal = annThrown.getValue().stringifyValue();
- if (isNullOrEmpty(thrownFormal)) {
- thrownFormal = null;
- } else {
- // check that thrownFormal exists as the last parameter in
- // the advice
- String[] pNames = owningMethod.getParameterNames();
- if (pNames == null || pNames.length == 0 || !Arrays.asList(pNames).contains(thrownFormal)) {
- throw new ThrownFormalNotDeclaredInAdviceSignatureException(thrownFormal);
- }
- }
- }
- String argumentNames = getArgNamesValue(after);
- if (argumentNames != null) {
- struct.unparsedArgumentNames = argumentNames;
- }
- // this/target/args binding
- // exclude the throwned binding from the pointcut binding since it
- // is an extraArg binding
- FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
- try {
- bindings = (thrownFormal == null ? extractBindings(struct) : extractBindings(struct, thrownFormal));
- } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
- return false;
- }
- IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings);
-
- // joinpoint, staticJoinpoint binding
- int extraArgument = extractExtraArgument(struct.method);
-
- // return binding
- if (thrownFormal != null) {
- extraArgument |= Advice.ExtraArgument;
- }
-
- Pointcut pc = null;
- if (preResolvedPointcut != null) {
- pc = preResolvedPointcut.getPointcut();
- } else {
- pc = parsePointcut(pointcut, struct, false);
- if (pc == null) {
- return false;// parse error
- }
- pc.resolve(binding);
- }
- setIgnoreUnboundBindingNames(pc, bindings);
-
- ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(),
- struct.bMethod.getDeclarationOffset());
- struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.AfterThrowing, pc, extraArgument, sl.getOffset(), sl
- .getOffset() + 1, struct.context));
- return true;
- }
- return false;
- }
-
- /**
- * Read @Around
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handleAroundAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct,
- ResolvedPointcutDefinition preResolvedPointcut) {
- AnnotationGen around = getAnnotation(runtimeAnnotations, AjcMemberMaker.AROUND_ANNOTATION);
- if (around != null) {
- NameValuePair aroundAdvice = getAnnotationElement(around, VALUE);
- if (aroundAdvice != null) {
- // this/target/args binding
- String argumentNames = getArgNamesValue(around);
- if (argumentNames != null) {
- struct.unparsedArgumentNames = argumentNames;
- }
- FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0];
- try {
- bindings = extractBindings(struct);
- } catch (UnreadableDebugInfoException unreadableDebugInfoException) {
- return false;
- }
- IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings);
-
- // joinpoint, staticJoinpoint binding
- int extraArgument = extractExtraArgument(struct.method);
-
- Pointcut pc = null;
- if (preResolvedPointcut != null) {
- pc = preResolvedPointcut.getPointcut();
- } else {
- pc = parsePointcut(aroundAdvice.getValue().stringifyValue(), struct, false);
- if (pc == null) {
- return false;// parse error
- }
- pc.resolve(binding);
- }
- setIgnoreUnboundBindingNames(pc, bindings);
-
- ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(),
- struct.bMethod.getDeclarationOffset());
- struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.Around, pc, extraArgument, sl.getOffset(), sl
- .getOffset() + 1,// FIXME AVASM
- struct.context));
- return true;
- }
- }
- return false;
- }
-
- /**
- * Read @Pointcut and handle the resolving in a lazy way to deal with pointcut references
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if a pointcut was handled
- */
- private static boolean handlePointcutAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct) {
- AnnotationGen pointcut = getAnnotation(runtimeAnnotations, AjcMemberMaker.POINTCUT_ANNOTATION);
- if (pointcut == null) {
- return false;
- }
- NameValuePair pointcutExpr = getAnnotationElement(pointcut, VALUE);
-
- // semantic check: the method must return void, or be
- // "public static boolean" for if() support
- if (!(Type.VOID.equals(struct.method.getReturnType()) || (Type.BOOLEAN.equals(struct.method.getReturnType())
- && struct.method.isStatic() && struct.method.isPublic()))) {
- reportWarning("Found @Pointcut on a method not returning 'void' or not 'public static boolean'", struct);
- // no need to stop
- }
-
- // semantic check: the method must not throw anything
- if (struct.method.getExceptionTable() != null) {
- reportWarning("Found @Pointcut on a method throwing exception", struct);
- // no need to stop
- }
-
- String argumentNames = getArgNamesValue(pointcut);
- if (argumentNames != null) {
- struct.unparsedArgumentNames = argumentNames;
- }
- // this/target/args binding
- final IScope binding;
- try {
- if (struct.method.isAbstract()) {
- binding = null;
- } else {
- binding = new BindingScope(struct.enclosingType, struct.context, extractBindings(struct));
- }
- } catch (UnreadableDebugInfoException e) {
- return false;
- }
-
- UnresolvedType[] argumentTypes = new UnresolvedType[struct.method.getArgumentTypes().length];
- for (int i = 0; i < argumentTypes.length; i++) {
- argumentTypes[i] = UnresolvedType.forSignature(struct.method.getArgumentTypes()[i].getSignature());
- }
-
- Pointcut pc = null;
- if (struct.method.isAbstract()) {
- if ((pointcutExpr != null && isNullOrEmpty(pointcutExpr.getValue().stringifyValue())) || pointcutExpr == null) {
- // abstract pointcut
- // leave pc = null
- } else {
- reportError("Found defined @Pointcut on an abstract method", struct);
- return false;// stop
- }
- } else {
- if (pointcutExpr == null || isNullOrEmpty(pointcutExpr.getValue().stringifyValue())) {
- // the matches nothing pointcut (125475/125480) - perhaps not as
- // cleanly supported as it could be.
- } else {
- // if (pointcutExpr != null) {
- // use a LazyResolvedPointcutDefinition so that the pointcut is
- // resolved lazily
- // since for it to be resolved, we will need other pointcuts to
- // be registered as well
- pc = parsePointcut(pointcutExpr.getValue().stringifyValue(), struct, true);
- if (pc == null) {
- return false;// parse error
- }
- pc.setLocation(struct.context, -1, -1);// FIXME AVASM !! bMethod
- // is null here..
- // } else {
- // reportError("Found undefined @Pointcut on a non-abstract method",
- // struct);
- // return false;
- // }
- }
- }
- // do not resolve binding now but lazily
- struct.ajAttributes.add(new AjAttribute.PointcutDeclarationAttribute(new LazyResolvedPointcutDefinition(
- struct.enclosingType, struct.method.getModifiers(), struct.method.getName(), argumentTypes, UnresolvedType
- .forSignature(struct.method.getReturnType().getSignature()), pc,// can
- // be
- // null
- // for
- // abstract
- // pointcut
- binding // can be null for abstract pointcut
- )));
- return true;
- }
-
- /**
- * Read @DeclareError, @DeclareWarning
- *
- * @param runtimeAnnotations
- * @param struct
- * @return true if found
- */
- private static boolean handleDeclareErrorOrWarningAnnotation(AsmManager model, RuntimeAnnos runtimeAnnotations,
- AjAttributeFieldStruct struct) {
- AnnotationGen error = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREERROR_ANNOTATION);
- boolean hasError = false;
- if (error != null) {
- NameValuePair declareError = getAnnotationElement(error, VALUE);
- if (declareError != null) {
- if (!STRING_DESC.equals(struct.field.getSignature()) || struct.field.getConstantValue() == null) {
- reportError("@DeclareError used on a non String constant field", struct);
- return false;
- }
- Pointcut pc = parsePointcut(declareError.getValue().stringifyValue(), struct, false);
- if (pc == null) {
- hasError = false;// cannot parse pointcut
- } else {
- DeclareErrorOrWarning deow = new DeclareErrorOrWarning(true, pc, struct.field.getConstantValue().toString());
- setDeclareErrorOrWarningLocation(model, deow, struct);
- struct.ajAttributes.add(new AjAttribute.DeclareAttribute(deow));
- hasError = true;
- }
- }
- }
- AnnotationGen warning = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREWARNING_ANNOTATION);
- boolean hasWarning = false;
- if (warning != null) {
- NameValuePair declareWarning = getAnnotationElement(warning, VALUE);
- if (declareWarning != null) {
- if (!STRING_DESC.equals(struct.field.getSignature()) || struct.field.getConstantValue() == null) {
- reportError("@DeclareWarning used on a non String constant field", struct);
- return false;
- }
- Pointcut pc = parsePointcut(declareWarning.getValue().stringifyValue(), struct, false);
- if (pc == null) {
- hasWarning = false;// cannot parse pointcut
- } else {
- DeclareErrorOrWarning deow = new DeclareErrorOrWarning(false, pc, struct.field.getConstantValue().toString());
- setDeclareErrorOrWarningLocation(model, deow, struct);
- struct.ajAttributes.add(new AjAttribute.DeclareAttribute(deow));
- return hasWarning = true;
- }
- }
- }
- return hasError || hasWarning;
- }
-
- /**
- * Sets the location for the declare error / warning using the corresponding IProgramElement in the structure model. This will
- * only fix bug 120356 if compiled with -emacssym, however, it does mean that the cross references view in AJDT will show the
- * correct information.
- *
- * Other possibilities for fix: 1. using the information in ajcDeclareSoft (if this is set correctly) which will fix the problem
- * if compiled with ajc but not if compiled with javac. 2. creating an AjAttribute called FieldDeclarationLineNumberAttribute
- * (much like MethodDeclarationLineNumberAttribute) which we can ask for the offset. This will again only fix bug 120356 when
- * compiled with ajc.
- *
- * @param deow
- * @param struct
- */
- private static void setDeclareErrorOrWarningLocation(AsmManager model, DeclareErrorOrWarning deow, AjAttributeFieldStruct struct) {
- IHierarchy top = (model == null ? null : model.getHierarchy());
- if (top != null && top.getRoot() != null) {
- IProgramElement ipe = top.findElementForLabel(top.getRoot(), IProgramElement.Kind.FIELD, struct.field.getName());
- if (ipe != null && ipe.getSourceLocation() != null) {
- ISourceLocation sourceLocation = ipe.getSourceLocation();
- int start = sourceLocation.getOffset();
- int end = start + struct.field.getName().length();
- deow.setLocation(struct.context, start, end);
- return;
- }
- }
- deow.setLocation(struct.context, -1, -1);
- }
-
- /**
- * Returns a readable representation of a method. Method.toString() is not suitable.
- *
- * @param method
- * @return a readable representation of a method
- */
- private static String methodToString(Method method) {
- StringBuffer sb = new StringBuffer();
- sb.append(method.getName());
- sb.append(method.getSignature());
- return sb.toString();
- }
-
- /**
- * Build the bindings for a given method (pointcut / advice)
- *
- * @param struct
- * @return null if no debug info is available
- */
- private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct) throws UnreadableDebugInfoException {
- Method method = struct.method;
- String[] argumentNames = struct.getArgumentNames();
-
- // assert debug info was here
- if (argumentNames.length != method.getArgumentTypes().length) {
- reportError(
- "Cannot read debug info for @Aspect to handle formal binding in pointcuts (please compile with 'javac -g' or '<javac debug='true'.../>' in Ant)",
- struct);
- throw new UnreadableDebugInfoException();
- }
-
- List<FormalBinding> bindings = new ArrayList<>();
- for (int i = 0; i < argumentNames.length; i++) {
- String argumentName = argumentNames[i];
- UnresolvedType argumentType = UnresolvedType.forSignature(method.getArgumentTypes()[i].getSignature());
-
- // do not bind JoinPoint / StaticJoinPoint /
- // EnclosingStaticJoinPoint
- // TODO solve me : this means that the JP/SJP/ESJP cannot appear as
- // binding
- // f.e. when applying advice on advice etc
- if ((AjcMemberMaker.TYPEX_JOINPOINT.equals(argumentType)
- || AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.equals(argumentType)
- || AjcMemberMaker.TYPEX_STATICJOINPOINT.equals(argumentType)
- || AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.equals(argumentType) || AjcMemberMaker.AROUND_CLOSURE_TYPE
- .equals(argumentType))) {
- // continue;// skip
- bindings.add(new FormalBinding.ImplicitFormalBinding(argumentType, argumentName, i));
- } else {
- bindings.add(new FormalBinding(argumentType, argumentName, i));
- }
- }
-
- return bindings.toArray(new FormalBinding[] {});
- }
-
- // FIXME alex deal with exclude index
- private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct, String excludeFormal)
- throws UnreadableDebugInfoException {
- FormalBinding[] bindings = extractBindings(struct);
- // int excludeIndex = -1;
- for (int i = 0; i < bindings.length; i++) {
- FormalBinding binding = bindings[i];
- if (binding.getName().equals(excludeFormal)) {
- // excludeIndex = i;
- bindings[i] = new FormalBinding.ImplicitFormalBinding(binding.getType(), binding.getName(), binding.getIndex());
- break;
- }
- }
- return bindings;
- //
- // if (excludeIndex >= 0) {
- // FormalBinding[] bindingsFiltered = new
- // FormalBinding[bindings.length-1];
- // int k = 0;
- // for (int i = 0; i < bindings.length; i++) {
- // if (i == excludeIndex) {
- // ;
- // } else {
- // bindingsFiltered[k] = new FormalBinding(bindings[i].getType(),
- // bindings[i].getName(), k);
- // k++;
- // }
- // }
- // return bindingsFiltered;
- // } else {
- // return bindings;
- // }
- }
-
- /**
- * Compute the flag for the xxxJoinPoint extra argument
- *
- * @param method
- * @return extra arg flag
- */
- private static int extractExtraArgument(Method method) {
- Type[] methodArgs = method.getArgumentTypes();
- String[] sigs = new String[methodArgs.length];
- for (int i = 0; i < methodArgs.length; i++) {
- sigs[i] = methodArgs[i].getSignature();
- }
- return extractExtraArgument(sigs);
- }
-
- /**
- * Compute the flag for the xxxJoinPoint extra argument
- *
- * @param argumentSignatures
- * @return extra arg flag
- */
- public static int extractExtraArgument(String[] argumentSignatures) {
- int extraArgument = 0;
- for (String argumentSignature : argumentSignatures) {
- if (AjcMemberMaker.TYPEX_JOINPOINT.getSignature().equals(argumentSignature)) {
- extraArgument |= Advice.ThisJoinPoint;
- } else if (AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.getSignature().equals(argumentSignature)) {
- extraArgument |= Advice.ThisJoinPoint;
- } else if (AjcMemberMaker.TYPEX_STATICJOINPOINT.getSignature().equals(argumentSignature)) {
- extraArgument |= Advice.ThisJoinPointStaticPart;
- } else if (AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.getSignature().equals(argumentSignature)) {
- extraArgument |= Advice.ThisEnclosingJoinPointStaticPart;
- }
- }
- return extraArgument;
- }
-
- /**
- * Returns the runtime (RV/RIV) annotation of type annotationType or null if no such annotation
- *
- * @param rvs
- * @param annotationType
- * @return annotation
- */
- private static AnnotationGen getAnnotation(RuntimeAnnos rvs, UnresolvedType annotationType) {
- final String annotationTypeName = annotationType.getName();
- for (AnnotationGen rv : rvs.getAnnotations()) {
- if (annotationTypeName.equals(rv.getTypeName())) {
- return rv;
- }
- }
- return null;
- }
-
- /**
- * Returns the value of a given element of an annotation or null if not found Caution: Does not handles default value.
- *
- * @param annotation
- * @param elementName
- * @return annotation NVP
- */
- private static NameValuePair getAnnotationElement(AnnotationGen annotation, String elementName) {
- for (NameValuePair element : annotation.getValues()) {
- if (elementName.equals(element.getNameString())) {
- return element;
- }
- }
- return null;
- }
-
- /**
- * Return the argNames set for an annotation or null if it is not specified.
- */
- private static String getArgNamesValue(AnnotationGen anno) {
- List<NameValuePair> elements = anno.getValues();
- for (NameValuePair element : elements) {
- if (ARGNAMES.equals(element.getNameString())) {
- return element.getValue().stringifyValue();
- }
- }
- return null;
- }
-
- private static String lastbit(String fqname) {
- int i = fqname.lastIndexOf(".");
- if (i == -1) {
- return fqname;
- } else {
- return fqname.substring(i + 1);
- }
- }
-
- /**
- * Extract the method argument names. First we try the debug info attached to the method (the LocalVariableTable) - if we cannot
- * find that we look to use the argNames value that may have been supplied on the associated annotation. If that fails we just
- * don't know and return an empty string.
- *
- * @param method
- * @param argNamesFromAnnotation
- * @param methodStruct
- * @return method argument names
- */
- private static String[] getMethodArgumentNames(Method method, String argNamesFromAnnotation,
- AjAttributeMethodStruct methodStruct) {
- if (method.getArgumentTypes().length == 0) {
- return EMPTY_STRINGS;
- }
-
- final int startAtStackIndex = method.isStatic() ? 0 : 1;
- final List<MethodArgument> arguments = new ArrayList<>();
- LocalVariableTable lt = method.getLocalVariableTable();
- if (lt != null) {
- LocalVariable[] lvt = lt.getLocalVariableTable();
- for (LocalVariable localVariable : lvt) {
- if (localVariable != null) { // pr348488
- if (localVariable.getStartPC() == 0) {
- if (localVariable.getIndex() >= startAtStackIndex) {
- arguments.add(new MethodArgument(localVariable.getName(), localVariable.getIndex()));
- }
- }
- } else {
- String typename = (methodStruct.enclosingType != null ? methodStruct.enclosingType.getName() : "");
- System.err.println("AspectJ: 348488 debug: unusual local variable table for method " + typename + "."
- + method.getName());
- }
- }
- if (arguments.size() == 0) {
- // The local variable table is causing us trouble, try the annotation value
- // See 539121 for a jacoco variant of the cobertura issue below
- if (argNamesFromAnnotation != null) {
- String[] argNames = extractArgNamesFromAnnotationValue(method, argNamesFromAnnotation, methodStruct);
- if (argNames.length != 0) {
- return argNames;
- }
- }
- // could be cobertura code where some extra bytecode has been stuffed in at the start of the method
- // but the local variable table hasn't been repaired - for example:
- // LocalVariable(start_pc = 6, length = 40, index = 0:com.example.ExampleAspect this)
- // LocalVariable(start_pc = 6, length = 40, index = 1:org.aspectj.lang.ProceedingJoinPoint pjp)
- // LocalVariable(start_pc = 6, length = 40, index = 2:int __cobertura__line__number__)
- // LocalVariable(start_pc = 6, length = 40, index = 3:int __cobertura__branch__number__)
- LocalVariable localVariable = lvt[0];
- if (localVariable != null) { // pr348488
- if (localVariable.getStartPC() != 0) {
- // looks suspicious so let's use this information
- for (int j = 0; j < lvt.length && arguments.size() < method.getArgumentTypes().length; j++) {
- localVariable = lvt[j];
- if (localVariable.getIndex() >= startAtStackIndex) {
- arguments.add(new MethodArgument(localVariable.getName(), localVariable.getIndex()));
- }
- }
- }
- }
- }
- } else {
- if (argNamesFromAnnotation != null) {
- String[] argNames = extractArgNamesFromAnnotationValue(method, argNamesFromAnnotation, methodStruct);
- if (argNames != null) {
- return argNames;
- }
- }
- }
-
- if (arguments.size() != method.getArgumentTypes().length) {
- return EMPTY_STRINGS;
- }
-
- // sort by index
- arguments.sort(new Comparator<MethodArgument>() {
- public int compare(MethodArgument mo, MethodArgument mo1) {
- if (mo.indexOnStack == mo1.indexOnStack) {
- return 0;
- } else if (mo.indexOnStack > mo1.indexOnStack) {
- return 1;
- } else {
- return -1;
- }
- }
- });
- String[] argumentNames = new String[arguments.size()];
- int i = 0;
- for (MethodArgument methodArgument : arguments) {
- argumentNames[i++] = methodArgument.name;
- }
- return argumentNames;
- }
-
- private static String[] extractArgNamesFromAnnotationValue(Method method, String argNamesFromAnnotation,
- AjAttributeMethodStruct methodStruct) {
- StringTokenizer st = new StringTokenizer(argNamesFromAnnotation, " ,");
- List<String> args = new ArrayList<>();
- while (st.hasMoreTokens()) {
- args.add(st.nextToken());
- }
- if (args.size() != method.getArgumentTypes().length) {
- StringBuffer shortString = new StringBuffer().append(lastbit(method.getReturnType().toString())).append(" ")
- .append(method.getName());
- if (method.getArgumentTypes().length > 0) {
- shortString.append("(");
- for (int i = 0; i < method.getArgumentTypes().length; i++) {
- shortString.append(lastbit(method.getArgumentTypes()[i].toString()));
- if ((i + 1) < method.getArgumentTypes().length) {
- shortString.append(",");
- }
-
- }
- shortString.append(")");
- }
- reportError("argNames annotation value does not specify the right number of argument names for the method '"
- + shortString.toString() + "'", methodStruct);
- return EMPTY_STRINGS;
- }
- return args.toArray(new String[] {});
- }
-
- /**
- * A method argument, used for sorting by indexOnStack (ie order in signature)
- *
- * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
- */
- private static class MethodArgument {
- String name;
- int indexOnStack;
-
- public MethodArgument(String name, int indexOnStack) {
- this.name = name;
- this.indexOnStack = indexOnStack;
- }
- }
-
- /**
- * LazyResolvedPointcutDefinition lazyly resolve the pointcut so that we have time to register all pointcut referenced before
- * pointcut resolution happens
- *
- * @author Alexandre Vasseur (alex AT gnilux DOT com)
- */
- public static class LazyResolvedPointcutDefinition extends ResolvedPointcutDefinition {
- private final Pointcut m_pointcutUnresolved; // null for abstract
- // pointcut
- private final IScope m_binding;
-
- private Pointcut m_lazyPointcut = null;
-
- public LazyResolvedPointcutDefinition(UnresolvedType declaringType, int modifiers, String name,
- UnresolvedType[] parameterTypes, UnresolvedType returnType, Pointcut pointcut, IScope binding) {
- super(declaringType, modifiers, name, parameterTypes, returnType, Pointcut.makeMatchesNothing(Pointcut.RESOLVED));
- m_pointcutUnresolved = pointcut;
- m_binding = binding;
- }
-
- @Override
- public Pointcut getPointcut() {
- if (m_lazyPointcut == null && m_pointcutUnresolved == null) {
- m_lazyPointcut = Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
- }
- if (m_lazyPointcut == null && m_pointcutUnresolved != null) {
- m_lazyPointcut = m_pointcutUnresolved.resolve(m_binding);
- m_lazyPointcut.copyLocationFrom(m_pointcutUnresolved);
- }
- return m_lazyPointcut;
- }
- }
-
- /**
- * Helper to test empty strings
- *
- * @param s
- * @return true if empty or null
- */
- private static boolean isNullOrEmpty(String s) {
- return (s == null || s.length() <= 0);
- }
-
- /**
- * Set the pointcut bindings for which to ignore unbound issues, so that we can implicitly bind xxxJoinPoint for @AJ advices
- *
- * @param pointcut
- * @param bindings
- */
- private static void setIgnoreUnboundBindingNames(Pointcut pointcut, FormalBinding[] bindings) {
- // register ImplicitBindings as to be ignored since unbound
- // TODO is it likely to fail in a bad way if f.e. this(jp) etc ?
- List<String> ignores = new ArrayList<>();
- for (FormalBinding formalBinding : bindings) {
- if (formalBinding instanceof FormalBinding.ImplicitFormalBinding) {
- ignores.add(formalBinding.getName());
- }
- }
- pointcut.m_ignoreUnboundBindingForNames = ignores.toArray(new String[0]);
- }
-
- /**
- * A check exception when we cannot read debug info (needed for formal binding)
- */
- private static class UnreadableDebugInfoException extends Exception {
- }
-
- /**
- * Report an error
- *
- * @param message
- * @param location
- */
- private static void reportError(String message, AjAttributeStruct location) {
- if (!location.handler.isIgnoring(IMessage.ERROR)) {
- location.handler.handleMessage(new Message(message, location.enclosingType.getSourceLocation(), true));
- }
- }
-
- // private static void reportError(String message, IMessageHandler handler, ISourceLocation sourceLocation) {
- // if (!handler.isIgnoring(IMessage.ERROR)) {
- // handler.handleMessage(new Message(message, sourceLocation, true));
- // }
- // }
-
- /**
- * Report a warning
- *
- * @param message
- * @param location
- */
- private static void reportWarning(String message, AjAttributeStruct location) {
- if (!location.handler.isIgnoring(IMessage.WARNING)) {
- location.handler.handleMessage(new Message(message, location.enclosingType.getSourceLocation(), false));
- }
- }
-
- /**
- * Parse the given pointcut, return null on failure and issue an error
- *
- * @param pointcutString
- * @param struct
- * @param allowIf
- * @return pointcut, unresolved
- */
- private static Pointcut parsePointcut(String pointcutString, AjAttributeStruct struct, boolean allowIf) {
- try {
- PatternParser parser = new PatternParser(pointcutString, struct.context);
- Pointcut pointcut = parser.parsePointcut();
- parser.checkEof();
- pointcut.check(null, struct.enclosingType.getWorld());
- if (!allowIf && pointcutString.contains("if()") && hasIf(pointcut)) {
- reportError("if() pointcut is not allowed at this pointcut location '" + pointcutString + "'", struct);
- return null;
- }
- pointcut.setLocation(struct.context, -1, -1);// FIXME -1,-1 is not
- // good enough
- return pointcut;
- } catch (ParserException e) {
- reportError("Invalid pointcut '" + pointcutString + "': " + e.toString()
- + (e.getLocation() == null ? "" : " at position " + e.getLocation().getStart()), struct);
- return null;
- }
- }
-
- private static boolean hasIf(Pointcut pointcut) {
- IfFinder visitor = new IfFinder();
- pointcut.accept(visitor, null);
- return visitor.hasIf;
- }
-
- /**
- * Parse the given type pattern, return null on failure and issue an error
- *
- * @param patternString
- * @param location
- * @return type pattern
- */
- private static TypePattern parseTypePattern(String patternString, AjAttributeStruct location) {
- try {
- TypePattern typePattern = new PatternParser(patternString).parseTypePattern();
- typePattern.setLocation(location.context, -1, -1);// FIXME -1,-1 is
- // not good
- // enough
- return typePattern;
- } catch (ParserException e) {
- reportError("Invalid type pattern'" + patternString + "' : " + e.getLocation(), location);
- return null;
- }
- }
-
- static class ThrownFormalNotDeclaredInAdviceSignatureException extends Exception {
-
- private final String formalName;
-
- public ThrownFormalNotDeclaredInAdviceSignatureException(String formalName) {
- this.formalName = formalName;
- }
-
- public String getFormalName() {
- return formalName;
- }
- }
-
- static class ReturningFormalNotDeclaredInAdviceSignatureException extends Exception {
-
- private final String formalName;
-
- public ReturningFormalNotDeclaredInAdviceSignatureException(String formalName) {
- this.formalName = formalName;
- }
-
- public String getFormalName() {
- return formalName;
- }
- }
- }
|