Logo Search packages:      
Sourcecode: aspectj version File versions

Advice.java

/* *******************************************************************
 * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
 * All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 *  
 * Contributors: 
 *     PARC     initial implementation 
 * ******************************************************************/

package org.aspectj.weaver;

import java.util.Collections;
import java.util.List;

import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.weaver.patterns.AndPointcut;
import org.aspectj.weaver.patterns.PerClause;
import org.aspectj.weaver.patterns.Pointcut;
import org.aspectj.weaver.patterns.TypePattern;

public abstract class Advice extends ShadowMunger {

      protected AjAttribute.AdviceAttribute attribute; // the pointcut field is
      // ignored

      protected AdviceKind kind; // alias of attribute.getKind()
      protected Member signature;
      protected boolean hasMatchedAtLeastOnce = false;

      // not necessarily declaring aspect, this is a semantics change from 1.0
      protected ResolvedType concreteAspect; // null until after concretize

      protected List innerCflowEntries = Collections.EMPTY_LIST; // just for
      // cflow*Entry
      // kinds
      protected int nFreeVars; // just for cflow*Entry kinds

      protected TypePattern exceptionType; // just for Softener kind

      // if we are parameterized, these type may be different to the advice
      // signature types
      protected UnresolvedType[] bindingParameterTypes;

      protected List/* Lint.Kind */suppressedLintKinds = null; // based on
      // annotations on
      // this advice

      public ISourceLocation lastReportedMonitorExitJoinpointLocation = null;

      public static Advice makeCflowEntry(World world, Pointcut entry, boolean isBelow, Member stackField, int nFreeVars,
                  List innerCflowEntries, ResolvedType inAspect) {
            Advice ret = world.createAdviceMunger(isBelow ? AdviceKind.CflowBelowEntry : AdviceKind.CflowEntry, entry, stackField, 0,
                        entry);
            // 0);
            ret.innerCflowEntries = innerCflowEntries;
            ret.nFreeVars = nFreeVars;
            ret.concreteAspect = inAspect;
            return ret;
      }

      public static Advice makePerCflowEntry(World world, Pointcut entry, boolean isBelow, Member stackField, ResolvedType inAspect,
                  List innerCflowEntries) {
            Advice ret = world.createAdviceMunger(isBelow ? AdviceKind.PerCflowBelowEntry : AdviceKind.PerCflowEntry, entry,
                        stackField, 0, entry);
            ret.innerCflowEntries = innerCflowEntries;
            ret.concreteAspect = inAspect;
            return ret;
      }

      public static Advice makePerObjectEntry(World world, Pointcut entry, boolean isThis, ResolvedType inAspect) {
            Advice ret = world.createAdviceMunger(isThis ? AdviceKind.PerThisEntry : AdviceKind.PerTargetEntry, entry, null, 0, entry);

            ret.concreteAspect = inAspect;
            return ret;
      }

      // PTWIMPL per type within entry advice is what initializes the aspect
      // instance in the matched type
      public static Advice makePerTypeWithinEntry(World world, Pointcut p, ResolvedType inAspect) {
            Advice ret = world.createAdviceMunger(AdviceKind.PerTypeWithinEntry, p, null, 0, p);
            ret.concreteAspect = inAspect;
            return ret;
      }

      public static Advice makeSoftener(World world, Pointcut entry, TypePattern exceptionType, ResolvedType inAspect,
                  IHasSourceLocation loc) {
            Advice ret = world.createAdviceMunger(AdviceKind.Softener, entry, null, 0, loc);

            ret.exceptionType = exceptionType;
            ret.concreteAspect = inAspect;
            // System.out.println("made ret: " + ret + " with " + exceptionType);
            return ret;
      }

      public Advice(AjAttribute.AdviceAttribute attribute, Pointcut pointcut, Member signature) {
            super(pointcut, attribute.getStart(), attribute.getEnd(), attribute.getSourceContext());
            this.attribute = attribute;
            kind = attribute.getKind(); // alias
            this.signature = signature;
            if (signature != null) {
                  bindingParameterTypes = signature.getParameterTypes();
            } else {
                  bindingParameterTypes = new UnresolvedType[0];
            }
      }

      public boolean match(Shadow shadow, World world) {
            if (super.match(shadow, world)) {
                  if (shadow.getKind() == Shadow.ExceptionHandler) {
                        if (kind.isAfter() || kind == AdviceKind.Around) {
                              world.showMessage(IMessage.WARNING, WeaverMessages.format(WeaverMessages.ONLY_BEFORE_ON_HANDLER),
                                          getSourceLocation(), shadow.getSourceLocation());
                              return false;
                        }
                  }
                  if (shadow.getKind() == Shadow.SynchronizationLock || shadow.getKind() == Shadow.SynchronizationUnlock) {
                        if (kind == AdviceKind.Around
                        // Don't work, see comments in SynchronizationTests
                        // && attribute.getProceedCallSignatures()!=null
                        // && attribute.getProceedCallSignatures().length!=0
                        ) {
                              world.showMessage(IMessage.WARNING, WeaverMessages.format(WeaverMessages.NO_AROUND_ON_SYNCHRONIZATION),
                                          getSourceLocation(), shadow.getSourceLocation());
                              return false;
                        }
                  }

                  if (hasExtraParameter() && kind == AdviceKind.AfterReturning) {
                        ResolvedType resolvedExtraParameterType = getExtraParameterType().resolve(world);
                        ResolvedType shadowReturnType = shadow.getReturnType().resolve(world);
                        boolean matches = (resolvedExtraParameterType.isConvertableFrom(shadowReturnType) && shadow.getKind()
                                    .hasReturnValue());
                        if (matches && resolvedExtraParameterType.isParameterizedType()) {
                              maybeIssueUncheckedMatchWarning(resolvedExtraParameterType, shadowReturnType, shadow, world);
                        }
                        return matches;
                  } else if (hasExtraParameter() && kind == AdviceKind.AfterThrowing) { // pr119749
                        ResolvedType exceptionType = getExtraParameterType().resolve(world);
                        if (!exceptionType.isCheckedException())
                              return true;
                        UnresolvedType[] shadowThrows = shadow.getSignature().getExceptions(world);
                        boolean matches = false;
                        for (int i = 0; i < shadowThrows.length && !matches; i++) {
                              ResolvedType type = shadowThrows[i].resolve(world);
                              if (exceptionType.isAssignableFrom(type))
                                    matches = true;
                        }
                        return matches;
                  } else if (kind == AdviceKind.PerTargetEntry) {
                        return shadow.hasTarget();
                  } else if (kind == AdviceKind.PerThisEntry) {
                        return shadow.hasThis();
                  } else if (kind == AdviceKind.Around) {
                        if (shadow.getKind() == Shadow.PreInitialization) {
                              world.showMessage(IMessage.WARNING, WeaverMessages.format(WeaverMessages.AROUND_ON_PREINIT),
                                          getSourceLocation(), shadow.getSourceLocation());
                              return false;
                        } else if (shadow.getKind() == Shadow.Initialization) {
                              world.showMessage(IMessage.WARNING, WeaverMessages.format(WeaverMessages.AROUND_ON_INIT), getSourceLocation(),
                                          shadow.getSourceLocation());
                              return false;
                        } else if (shadow.getKind() == Shadow.StaticInitialization
                                    && shadow.getEnclosingType().resolve(world).isInterface()) {
                              world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.AROUND_ON_INTERFACE_STATICINIT, shadow
                                          .getEnclosingType().getName()), getSourceLocation(), shadow.getSourceLocation());
                              return false;
                        } else {
                              // System.err.println(getSignature().getReturnType() +
                              // " from " + shadow.getReturnType());
                              if (getSignature().getReturnType() == ResolvedType.VOID) {
                                    if (shadow.getReturnType() != ResolvedType.VOID) {
                                          world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.NON_VOID_RETURN, shadow),
                                                      getSourceLocation(), shadow.getSourceLocation());
                                          return false;
                                    }
                              } else if (getSignature().getReturnType().equals(UnresolvedType.OBJECT)) {
                                    return true;
                              } else {
                                    ResolvedType shadowReturnType = shadow.getReturnType().resolve(world);
                                    ResolvedType adviceReturnType = getSignature().getGenericReturnType().resolve(world);

                                    if (shadowReturnType.isParameterizedType() && adviceReturnType.isRawType()) { // Set
                                          // <
                                          // Integer
                                          // >
                                          // and
                                          // Set
                                          ResolvedType shadowReturnGenericType = shadowReturnType.getGenericType(); // Set
                                          ResolvedType adviceReturnGenericType = adviceReturnType.getGenericType(); // Set
                                          if (shadowReturnGenericType.isAssignableFrom(adviceReturnGenericType)
                                                      && world.getLint().uncheckedAdviceConversion.isEnabled()) {
                                                world.getLint().uncheckedAdviceConversion.signal(new String[] { shadow.toString(),
                                                            shadowReturnType.getName(), adviceReturnType.getName() }, shadow.getSourceLocation(),
                                                            new ISourceLocation[] { getSourceLocation() });
                                          }
                                    } else if (!shadowReturnType.isAssignableFrom(adviceReturnType)) {
                                          // System.err.println(this + ", " + sourceContext +
                                          // ", " + start);
                                          world.showMessage(IMessage.ERROR, WeaverMessages
                                                      .format(WeaverMessages.INCOMPATIBLE_RETURN_TYPE, shadow), getSourceLocation(), shadow
                                                      .getSourceLocation());
                                          return false;
                                    }
                              }
                        }
                  }
                  return true;
            } else {
                  return false;
            }
      }

      /**
       * In after returning advice if we are binding the extra parameter to a parameterized type we may not be able to do a type-safe
       * conversion.
       * 
       * @param resolvedExtraParameterType the type in the after returning declaration
       * @param shadowReturnType the type at the shadow
       * @param world
       */
      private void maybeIssueUncheckedMatchWarning(ResolvedType afterReturningType, ResolvedType shadowReturnType, Shadow shadow,
                  World world) {
            boolean inDoubt = !afterReturningType.isAssignableFrom(shadowReturnType);
            if (inDoubt && world.getLint().uncheckedArgument.isEnabled()) {
                  String uncheckedMatchWith = afterReturningType.getSimpleBaseName();
                  if (shadowReturnType.isParameterizedType() && (shadowReturnType.getRawType() == afterReturningType.getRawType())) {
                        uncheckedMatchWith = shadowReturnType.getSimpleName();
                  }
                  if (!Utils.isSuppressing(getSignature().getAnnotations(), "uncheckedArgument")) {
                        world.getLint().uncheckedArgument.signal(new String[] { afterReturningType.getSimpleName(), uncheckedMatchWith,
                                    afterReturningType.getSimpleBaseName(), shadow.toResolvedString(world) }, getSourceLocation(),
                                    new ISourceLocation[] { shadow.getSourceLocation() });
                  }
            }
      }

      // ----

      public AdviceKind getKind() {
            return kind;
      }

      public Member getSignature() {
            return signature;
      }

      public boolean hasExtraParameter() {
            return (getExtraParameterFlags() & ExtraArgument) != 0;
      }

      protected int getExtraParameterFlags() {
            return attribute.getExtraParameterFlags();
      }

      protected int getExtraParameterCount() {
            return countOnes(getExtraParameterFlags() & ParameterMask);
      }

      public UnresolvedType[] getBindingParameterTypes() {
            return bindingParameterTypes;
      }

      public void setBindingParameterTypes(UnresolvedType[] types) {
            bindingParameterTypes = types;
      }

      public static int countOnes(int bits) {
            int ret = 0;
            while (bits != 0) {
                  if ((bits & 1) != 0)
                        ret += 1;
                  bits = bits >> 1;
            }
            return ret;
      }

      public int getBaseParameterCount() {
            return getSignature().getParameterTypes().length - getExtraParameterCount();
      }

      public String[] getBaseParameterNames(World world) {
            String[] allNames = getSignature().getParameterNames(world);
            int extras = getExtraParameterCount();
            if (extras == 0)
                  return allNames;
            String[] result = new String[getBaseParameterCount()];
            for (int i = 0; i < result.length; i++) {
                  result[i] = allNames[i];
            }
            return result;
      }

      /**
       * Return the type of the 'extra argument'. For either after returning or after throwing advice, the extra argument will be the
       * returned value or the thrown exception respectively. With annotation style the user may declare the parameters in any order,
       * whereas for code style they are in a well defined order. So there is some extra complexity in here for annotation style that
       * looks up the correct parameter in the advice signature by name, based on the name specified in the annotation. If this fails
       * then we 'fallback' to guessing at positions, where the extra argument is presumed to come at the end.
       * 
       * @return the type of the extraParameter
       */
      public UnresolvedType getExtraParameterType() {
            if (!hasExtraParameter()) {
                  return ResolvedType.MISSING;
            }
            if (signature instanceof ResolvedMember) {
                  ResolvedMember method = (ResolvedMember) signature;
                  UnresolvedType[] parameterTypes = method.getGenericParameterTypes();
                  if (getConcreteAspect().isAnnotationStyleAspect()) {

                        // Examine the annotation to determine the parameter name then look it up in the parameters for the method
                        String[] pnames = method.getParameterNames();
                        if (pnames != null) {
                              // It is worth attempting to look up the correct parameter
                              AnnotationAJ[] annos = getSignature().getAnnotations();
                              String parameterToLookup = null;
                              if (annos != null && (getKind() == AdviceKind.AfterThrowing || getKind() == AdviceKind.AfterReturning)) {
                                    for (int i = 0; i < annos.length && parameterToLookup == null; i++) {
                                          AnnotationAJ anno = annos[i];
                                          String annosig = anno.getType().getSignature();
                                          if (annosig.equals("Lorg/aspectj/lang/annotation/AfterThrowing;")) {
                                                // the 'throwing' value in the annotation will name the parameter to bind to
                                                parameterToLookup = anno.getStringFormOfValue("throwing");
                                          } else if (annosig.equals("Lorg/aspectj/lang/annotation/AfterReturning;")) {
                                                // the 'returning' value in the annotation will name the parameter to bind to
                                                parameterToLookup = anno.getStringFormOfValue("returning");
                                          }
                                    }
                              }
                              if (parameterToLookup != null) {
                                    for (int i = 0; i < pnames.length; i++) {
                                          if (pnames[i].equals(parameterToLookup)) {
                                                return parameterTypes[i];
                                          }
                                    }
                              }
                        }

                        // Don't think this code works so well... why isnt it getBaseParameterCount()-1 ?

                        int baseParmCnt = getBaseParameterCount();

                        // bug 122742 - if we're an annotation style aspect then one
                        // of the extra parameters could be JoinPoint which we want
                        // to ignore
                        while ((baseParmCnt + 1 < parameterTypes.length)
                                    && (parameterTypes[baseParmCnt].equals(AjcMemberMaker.TYPEX_JOINPOINT)
                                                || parameterTypes[baseParmCnt].equals(AjcMemberMaker.TYPEX_STATICJOINPOINT) || parameterTypes[baseParmCnt]
                                                .equals(AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT))) {
                              baseParmCnt++;
                        }
                        return parameterTypes[baseParmCnt];
                  } else {
                        return parameterTypes[getBaseParameterCount()];
                  }
            } else {
                  return signature.getParameterTypes()[getBaseParameterCount()];
            }
      }

      public UnresolvedType getDeclaringAspect() {
            return getOriginalSignature().getDeclaringType();
      }

      protected Member getOriginalSignature() {
            return signature;
      }

      protected String extraParametersToString() {
            if (getExtraParameterFlags() == 0) {
                  return "";
            } else {
                  return "(extraFlags: " + getExtraParameterFlags() + ")";
            }
      }

      public Pointcut getPointcut() {
            return pointcut;
      }

      // ----

      /**
       * @param fromType is guaranteed to be a non-abstract aspect
       * @param clause has been concretized at a higher level
       */
      public ShadowMunger concretize(ResolvedType fromType, World world, PerClause clause) {
            // assert !fromType.isAbstract();
            Pointcut p = pointcut.concretize(fromType, getDeclaringType(), signature.getArity(), this);
            if (clause != null) {
                  Pointcut oldP = p;
                  p = new AndPointcut(clause, p);
                  p.copyLocationFrom(oldP);
                  p.state = Pointcut.CONCRETE;

                  // FIXME ? ATAJ copy unbound bindings to ignore
                  p.m_ignoreUnboundBindingForNames = oldP.m_ignoreUnboundBindingForNames;
            }

            Advice munger = world.getWeavingSupport().createAdviceMunger(attribute, p, signature);
            munger.concreteAspect = fromType;
            munger.bindingParameterTypes = bindingParameterTypes;
            munger.setDeclaringType(getDeclaringType());
            // System.err.println("concretizing here " + p + " with clause " +
            // clause);
            return munger;
      }

      // ---- from object

      public String toString() {
            StringBuffer sb = new StringBuffer();
            sb.append("(").append(getKind()).append(extraParametersToString());
            sb.append(": ").append(pointcut).append("->").append(signature).append(")");
            return sb.toString();
            // return "("
            // + getKind()
            // + extraParametersToString()
            // + ": "
            // + pointcut
            // + "->"
            // + signature
            // + ")";
      }

      // XXX this perhaps ought to take account of the other fields in advice ...
      public boolean equals(Object other) {
            if (!(other instanceof Advice))
                  return false;
            Advice o = (Advice) other;
            return o.kind.equals(kind) && ((o.pointcut == null) ? (pointcut == null) : o.pointcut.equals(pointcut))
                        && ((o.signature == null) ? (signature == null) : o.signature.equals(signature));
            // && (AsmManager.getDefault().getHandleProvider().dependsOnLocation() ? ((o.getSourceLocation() == null) ?
            // (getSourceLocation() == null)
            // : o.getSourceLocation().equals(getSourceLocation()))
            // : true) // pr134471 - remove when handles are improved
            // // to be independent of location
            // ;

      }

      private volatile int hashCode = 0;

      public int hashCode() {
            if (hashCode == 0) {
                  int result = 17;
                  result = 37 * result + kind.hashCode();
                  result = 37 * result + ((pointcut == null) ? 0 : pointcut.hashCode());
                  result = 37 * result + ((signature == null) ? 0 : signature.hashCode());
                  hashCode = result;
            }
            return hashCode;
      }

      // ---- fields

      public static final int ExtraArgument = 0x01;
      public static final int ThisJoinPoint = 0x02;
      public static final int ThisJoinPointStaticPart = 0x04;
      public static final int ThisEnclosingJoinPointStaticPart = 0x08;
      public static final int ParameterMask = 0x0f;
      // For an if pointcut, this indicates it is hard wired to access a constant of either true or false
      public static final int ConstantReference = 0x10; 
      // When the above flag is set, this indicates whether it is true or false
      public static final int ConstantValue = 0x20; 
      public static final int CanInline = 0x40;

      // for testing only
      public void setLexicalPosition(int lexicalPosition) {
            start = lexicalPosition;
      }

      public ResolvedType getConcreteAspect() {
            return concreteAspect;
      }

      public boolean hasMatchedSomething() {
            return hasMatchedAtLeastOnce;
      }

      public void setHasMatchedSomething(boolean hasMatchedSomething) {
            hasMatchedAtLeastOnce = hasMatchedSomething;
      }

      public abstract boolean hasDynamicTests();

}

Generated by  Doxygen 1.6.0   Back to index