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 Common Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/cpl-v10.html
* Contributors:
*     PARC     initial implementation
* ******************************************************************/


package org.aspectj.weaver.patterns;

import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

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.ISourceContext;
import org.aspectj.weaver.IntMap;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.ShadowMunger;
import org.aspectj.weaver.VersionedDataInputStream;
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 = 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 = new String[0];
 
  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 
   */
  public abstract /*Enum*/Set/*<Shadow.Kind>*/ 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 (couldMatchKinds().contains(shadow.getKind())) {
      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 prepare(Shadow shadow) {}
   
    // ---- test method
   
    public static Pointcut fromString(String str) {
        PatternParser parser = new PatternParser(str);
        return parser.parsePointcut();
    }
   
    static class MatchesNothingPointcut extends Pointcut {
      protected Test findResidueInternal(Shadow shadow, ExposedState state) {
      return Literal.FALSE; // can only get here if an earlier error occurred
    }

    public Set couldMatchKinds() {
      return Collections.EMPTY_SET;
    }
   
    public FuzzyBoolean fastMatch(FastMatchInfo type) {
      return FuzzyBoolean.NO;
    }
   
    protected FuzzyBoolean matchInternal(Shadow shadow) {
      return FuzzyBoolean.NO;
    }
       
    public void resolveBindings(IScope scope, Bindings bindings) {
    }
   
    public void postRead(ResolvedType enclosingType) {
    }

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


    public void write(DataOutputStream s) throws IOException {
      s.writeByte(NONE);
    }
   
    public String toString() { return ""; }

        public Object accept(PatternNodeVisitor visitor, Object data) {
            return visitor.visit(this, data);
        }
       
        public Pointcut parameterizeWith(Map typeVariableMap) {
          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 typeVariableMap);

}
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.