Package org.aspectj.weaver.patterns

Source Code of org.aspectj.weaver.patterns.Pointcut$MatchesNothingPointcut

/* *******************************************************************
* 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.patterns;

import java.io.IOException;
import java.util.Map;

import org.aspectj.util.FuzzyBoolean;
import org.aspectj.util.TypeSafeEnum;
import org.aspectj.weaver.Advice;
import org.aspectj.weaver.AdviceKind;
import org.aspectj.weaver.BCException;
import org.aspectj.weaver.Checker;
import org.aspectj.weaver.CompressingDataOutputStream;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.IntMap;
import org.aspectj.weaver.PoliceExtensionUse;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.ShadowMunger;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.VersionedDataInputStream;
import org.aspectj.weaver.World;
import org.aspectj.weaver.ast.Literal;
import org.aspectj.weaver.ast.Test;

/**
* The lifecycle of Pointcuts is modeled by Pointcut.State. It has three things:
*
* <p>
* Creation -- SYMBOLIC -- then resolve(IScope) -- RESOLVED -- concretize(...) -- CONCRETE
*
* @author Erik Hilsdale
* @author Jim Hugunin
*
*         A day in the life of a pointcut.... - AMC. ==========================================
*
*         Pointcuts are created by the PatternParser, which is called by ajdt to parse a pointcut from the PseudoTokens AST node
*         (which in turn are part of a PointcutDesignator AST node).
*
*         Pointcuts are resolved by ajdt when an AdviceDeclaration or a PointcutDeclaration has its statements resolved. This
*         happens as part of completeTypeBindings in the AjLookupEnvironment which is called after the diet parse phase of the
*         compiler. Named pointcuts, and references to named pointcuts are instances of ReferencePointcut.
*
*         At the end of the compilation process, the pointcuts are serialized (write method) into attributes in the class file.
*
*         When the weaver loads the class files, it unpacks the attributes and deserializes the pointcuts (read). All aspects are
*         added to the world, by calling addOrReplaceAspect on the crosscutting members set of the world. When aspects are added or
*         replaced, the crosscutting members in the aspect are extracted as ShadowMungers (each holding a pointcut). The
*         ShadowMungers are concretized, which concretizes the pointcuts. At this stage ReferencePointcuts are replaced by their
*         declared content.
*
*         During weaving, the weaver processes type by type. It first culls potentially matching ShadowMungers by calling the
*         fastMatch method on their pointcuts. Only those that might match make it through to the next phase. At the next phase,
*         all of the shadows within the type are created and passed to the pointcut for matching (match).
*
*         When the actual munging happens, matched pointcuts are asked for their residue (findResidue) - the runtime test if any.
*         Because of negation, findResidue may be called on pointcuts that could never match the shadow.
*
*/
public abstract class Pointcut extends PatternNode {
  public static final class State extends TypeSafeEnum {
    public State(String name, int key) {
      super(name, key);
    }
  }

  /**
   * ATAJ the name of the formal for which we don't want any warning when unbound since we consider them as implicitly bound. f.e.
   * JoinPoint for @AJ advices
   */
  public String[] m_ignoreUnboundBindingForNames = EMPTY_STRING_ARRAY;

  public static final String[] EMPTY_STRING_ARRAY = new String[0];

  public static final State SYMBOLIC = new State("symbolic", 0);
  public static final State RESOLVED = new State("resolved", 1);
  public static final State CONCRETE = new State("concrete", 2);

  protected byte pointcutKind;

  public State state;

  protected int lastMatchedShadowId;
  private FuzzyBoolean lastMatchedShadowResult;
  private String[] typeVariablesInScope = EMPTY_STRING_ARRAY;

  protected boolean hasBeenParameterized = false;

  /**
   * Constructor for Pattern.
   */
  public Pointcut() {
    super();
    this.state = SYMBOLIC;
  }

  /**
   * Could I match any shadows in the code defined within this type?
   */
  public abstract FuzzyBoolean fastMatch(FastMatchInfo info);

  /**
   * The set of ShadowKinds that this Pointcut could possibly match - an int whose bits are set according to the Kinds specified
   * in Shadow.java
   */
  public abstract int couldMatchKinds();

  public String[] getTypeVariablesInScope() {
    return typeVariablesInScope;
  }

  public void setTypeVariablesInScope(String[] typeVars) {
    this.typeVariablesInScope = typeVars;
  }

  /**
   * Do I really match this shadow? XXX implementors need to handle state
   */
  public final FuzzyBoolean match(Shadow shadow) {
    if (shadow.shadowId == lastMatchedShadowId) {
      return lastMatchedShadowResult;
    }
    FuzzyBoolean ret;
    // this next test will prevent a lot of un-needed matching going on....
    if (shadow.getKind().isSet(couldMatchKinds())) {
      ret = matchInternal(shadow);
    } else {
      ret = FuzzyBoolean.NO;
    }
    lastMatchedShadowId = shadow.shadowId;
    lastMatchedShadowResult = ret;
    return ret;
  }

  protected abstract FuzzyBoolean matchInternal(Shadow shadow);

  public static final byte KINDED = 1;
  public static final byte WITHIN = 2;
  public static final byte THIS_OR_TARGET = 3;
  public static final byte ARGS = 4;
  public static final byte AND = 5;
  public static final byte OR = 6;
  public static final byte NOT = 7;
  public static final byte REFERENCE = 8;
  public static final byte IF = 9;
  public static final byte CFLOW = 10;
  public static final byte WITHINCODE = 12;
  public static final byte HANDLER = 13;
  public static final byte IF_TRUE = 14;
  public static final byte IF_FALSE = 15;
  public static final byte ANNOTATION = 16;
  public static final byte ATWITHIN = 17;
  public static final byte ATWITHINCODE = 18;
  public static final byte ATTHIS_OR_TARGET = 19;

  public static final byte NONE = 20; // DO NOT CHANGE OR REORDER THIS SEQUENCE, THIS VALUE CAN BE PUT OUT BY ASPECTJ1.2.1

  public static final byte ATARGS = 21;
  public static final byte USER_EXTENSION = 22;

  public byte getPointcutKind() {
    return pointcutKind;
  }

  // internal, only called from resolve
  protected abstract void resolveBindings(IScope scope, Bindings bindings);

  /**
   * Returns this pointcut mutated
   */
  public final Pointcut resolve(IScope scope) {
    assertState(SYMBOLIC);
    Bindings bindingTable = new Bindings(scope.getFormalCount());
    IScope bindingResolutionScope = scope;
    if (typeVariablesInScope.length > 0) {
      bindingResolutionScope = new ScopeWithTypeVariables(typeVariablesInScope, scope);
    }
    this.resolveBindings(bindingResolutionScope, bindingTable);
    bindingTable.checkAllBound(bindingResolutionScope);
    this.state = RESOLVED;
    return this;
  }

  /**
   * Returns a new pointcut Only used by test cases
   */
  public final Pointcut concretize(ResolvedType inAspect, ResolvedType declaringType, int arity) {
    Pointcut ret = concretize(inAspect, declaringType, IntMap.idMap(arity));
    // copy the unbound ignore list
    ret.m_ignoreUnboundBindingForNames = m_ignoreUnboundBindingForNames;
    return ret;
  }

  // XXX this is the signature we're moving to
  public final Pointcut concretize(ResolvedType inAspect, ResolvedType declaringType, int arity, ShadowMunger advice) {
    // if (state == CONCRETE) return this; //???
    IntMap map = IntMap.idMap(arity);
    map.setEnclosingAdvice(advice);
    map.setConcreteAspect(inAspect);
    return concretize(inAspect, declaringType, map);
  }

  public boolean isDeclare(ShadowMunger munger) {
    if (munger == null) {
      return false; // ??? Is it actually an error if we get a null munger into this method.
    }
    if (munger instanceof Checker) {
      return true;
    }
    if (((Advice) munger).getKind().equals(AdviceKind.Softener)) {
      return true;
    }
    return false;
  }

  public final Pointcut concretize(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
    // !!! add this test -- assertState(RESOLVED);
    Pointcut ret = this.concretize1(inAspect, declaringType, bindings);
    if (shouldCopyLocationForConcretize()) {
      ret.copyLocationFrom(this);
    }
    ret.state = CONCRETE;
    // copy the unbound ignore list
    ret.m_ignoreUnboundBindingForNames = m_ignoreUnboundBindingForNames;
    return ret;
  }

  protected boolean shouldCopyLocationForConcretize() {
    return true;
  }

  /**
   * Resolves and removes ReferencePointcuts, replacing with basic ones
   *
   * @param inAspect the aspect to resolve relative to
   * @param bindings a Map from formal index in the current lexical context -> formal index in the concrete advice that will run
   *
   *        This must always return a new Pointcut object (even if the concretized Pointcut is identical to the resolved one).
   *        That behavior is assumed in many places. XXX fix implementors to handle state
   */
  protected abstract Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings);

  // XXX implementors need to handle state
  /**
   * This can be called from NotPointcut even for Pointcuts that don't match the shadow
   */
  public final Test findResidue(Shadow shadow, ExposedState state) {
    // if (shadow.shadowId == lastMatchedShadowId) return lastMatchedShadowResidue;
    Test ret = findResidueInternal(shadow, state);
    // lastMatchedShadowResidue = ret;
    lastMatchedShadowId = shadow.shadowId;
    return ret;
  }

  protected abstract Test findResidueInternal(Shadow shadow, ExposedState state);

  // XXX we're not sure whether or not this is needed
  // XXX currently it's unused we're keeping it around as a stub
  public void postRead(ResolvedType enclosingType) {
  }

  public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
    byte kind = s.readByte();
    Pointcut ret;

    switch (kind) {
    case KINDED:
      ret = KindedPointcut.read(s, context);
      break;
    case WITHIN:
      ret = WithinPointcut.read(s, context);
      break;
    case THIS_OR_TARGET:
      ret = ThisOrTargetPointcut.read(s, context);
      break;
    case ARGS:
      ret = ArgsPointcut.read(s, context);
      break;
    case AND:
      ret = AndPointcut.read(s, context);
      break;
    case OR:
      ret = OrPointcut.read(s, context);
      break;
    case NOT:
      ret = NotPointcut.read(s, context);
      break;
    case REFERENCE:
      ret = ReferencePointcut.read(s, context);
      break;
    case IF:
      ret = IfPointcut.read(s, context);
      break;
    case CFLOW:
      ret = CflowPointcut.read(s, context);
      break;
    case WITHINCODE:
      ret = WithincodePointcut.read(s, context);
      break;
    case HANDLER:
      ret = HandlerPointcut.read(s, context);
      break;
    case IF_TRUE:
      ret = IfPointcut.makeIfTruePointcut(RESOLVED);
      break;
    case IF_FALSE:
      ret = IfPointcut.makeIfFalsePointcut(RESOLVED);
      break;
    case ANNOTATION:
      ret = AnnotationPointcut.read(s, context);
      break;
    case ATWITHIN:
      ret = WithinAnnotationPointcut.read(s, context);
      break;
    case ATWITHINCODE:
      ret = WithinCodeAnnotationPointcut.read(s, context);
      break;
    case ATTHIS_OR_TARGET:
      ret = ThisOrTargetAnnotationPointcut.read(s, context);
      break;
    case ATARGS:
      ret = ArgsAnnotationPointcut.read(s, context);
      break;
    case NONE:
      ret = makeMatchesNothing(RESOLVED);
      break;
    default:
      throw new BCException("unknown kind: " + kind);
    }
    ret.state = RESOLVED;
    ret.pointcutKind = kind;
    return ret;

  }

  public void check(ISourceContext ctx, World world) {
    // this is a quick visitor...
    PoliceExtensionUse pointcutPolice = new PoliceExtensionUse(world, this);
    this.accept(pointcutPolice, null);
    if (pointcutPolice.synchronizationDesignatorEncountered()) {
      world.setSynchronizationPointcutsInUse();
    }
  }

  // public void prepare(Shadow shadow) {}

  // ---- test method

  public static Pointcut fromString(String str) {
    PatternParser parser = new PatternParser(str);
    return parser.parsePointcut();
  }

  static class MatchesNothingPointcut extends Pointcut {
    @Override
    protected Test findResidueInternal(Shadow shadow, ExposedState state) {
      return Literal.FALSE; // can only get here if an earlier error occurred
    }

    @Override
    public int couldMatchKinds() {
      return Shadow.NO_SHADOW_KINDS_BITS;
    }

    @Override
    public FuzzyBoolean fastMatch(FastMatchInfo type) {
      return FuzzyBoolean.NO;
    }

    @Override
    protected FuzzyBoolean matchInternal(Shadow shadow) {
      return FuzzyBoolean.NO;
    }

    @Override
    public void resolveBindings(IScope scope, Bindings bindings) {
    }

    @Override
    public void postRead(ResolvedType enclosingType) {
    }

    @Override
    public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
      return makeMatchesNothing(state);
    }

    @Override
    public void write(CompressingDataOutputStream s) throws IOException {
      s.writeByte(NONE);
    }

    @Override
    public String toString() {
      return "";
    }

    @Override
    public Object accept(PatternNodeVisitor visitor, Object data) {
      return visitor.visit(this, data);
    }

    @Override
    public Pointcut parameterizeWith(Map<String, UnresolvedType> typeVariableMap, World w) {
      return this;
    }
  }

  // public static Pointcut MatchesNothing = new MatchesNothingPointcut();
  // ??? there could possibly be some good optimizations to be done at this point
  public static Pointcut makeMatchesNothing(State state) {
    Pointcut ret = new MatchesNothingPointcut();
    ret.state = state;
    return ret;
  }

  public void assertState(State state) {
    if (this.state != state) {
      throw new BCException("expected state: " + state + " got: " + this.state);
    }
  }

  public abstract Pointcut parameterizeWith(Map<String, UnresolvedType> typeVariableMap, World w);

}
TOP

Related Classes of org.aspectj.weaver.patterns.Pointcut$MatchesNothingPointcut

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.