org.aspectj.weaver.patterns.KindedPointcut.java Source code

Java tutorial

Introduction

Here is the source code for org.aspectj.weaver.patterns.KindedPointcut.java

Source

/* *******************************************************************
 * 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 static org.aspectj.util.FuzzyBoolean.MAYBE;

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

import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.util.FuzzyBoolean;
import org.aspectj.weaver.Checker;
import org.aspectj.weaver.CompressingDataOutputStream;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.IntMap;
import org.aspectj.weaver.Member;
import org.aspectj.weaver.ResolvedMember;
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.WeaverMessages;
import org.aspectj.weaver.World;
import org.aspectj.weaver.ast.Literal;
import org.aspectj.weaver.ast.Test;

public class KindedPointcut extends Pointcut {
    Shadow.Kind kind;
    private SignaturePattern signature;
    private int matchKinds;

    private ShadowMunger munger = null; // only set after concretization

    public KindedPointcut(Shadow.Kind kind, SignaturePattern signature) {
        this.kind = kind;
        this.signature = signature;
        this.pointcutKind = KINDED;
        this.matchKinds = kind.bit;
    }

    public KindedPointcut(Shadow.Kind kind, SignaturePattern signature, ShadowMunger munger) {
        this(kind, signature);
        this.munger = munger;
    }

    public SignaturePattern getSignature() {
        return signature;
    }

    @Override
    public int couldMatchKinds() {
        return matchKinds;
    }

    public boolean couldEverMatchSameJoinPointsAs(KindedPointcut other) {
        if (this.kind != other.kind) {
            return false;
        }
        String myName = signature.getName().maybeGetSimpleName();
        String yourName = other.signature.getName().maybeGetSimpleName();
        if (myName != null && yourName != null) {
            if (!myName.equals(yourName)) {
                return false;
            }
        }
        if (signature.getParameterTypes().ellipsisCount == 0) {
            if (other.signature.getParameterTypes().ellipsisCount == 0) {
                if (signature.getParameterTypes().getTypePatterns().length != other.signature.getParameterTypes()
                        .getTypePatterns().length) {
                    return false;
                }
            }
        }
        return true;
    }

    @Override
    public FuzzyBoolean fastMatch(FastMatchInfo info) {
        // info.getKind()==null means all kinds
        if (info.getKind() != null) {
            if (info.getKind() != kind) {
                return FuzzyBoolean.NO;
            }
        }

        // KindedPointcut represents these join points:
        // method-execution/ctor-execution/method-call/ctor-call/field-get/field-set/advice-execution/static-initialization
        // initialization/pre-initialization

        // Check if the global fastmatch flag is on - the flag can be removed (and this made default) once it proves stable!
        if (info.world.optimizedMatching) {

            // For now, just consider MethodExecution and Initialization
            if ((kind == Shadow.MethodExecution || kind == Shadow.Initialization) && info.getKind() == null) {
                boolean fastMatchingOnAspect = info.getType().isAspect();
                // an Aspect may define ITDs, and although our signature declaring type pattern may not match on the
                // aspect, the ITDs may have a different signature as we iterate through the members of the aspect. Let's not
                // try and work through that here and just say MAYBE
                if (fastMatchingOnAspect) {
                    return MAYBE;
                }
                // Aim here is to do the same test as is done for signature pattern declaring type pattern matching
                if (this.getSignature().isExactDeclaringTypePattern()) {
                    ExactTypePattern typePattern = (ExactTypePattern) this.getSignature().getDeclaringType();
                    // Interface checks are more expensive, they could be anywhere...
                    ResolvedType patternExactType = typePattern.getResolvedExactType(info.world);
                    if (patternExactType.isInterface()) {
                        ResolvedType curr = info.getType();
                        Iterator<ResolvedType> hierarchyWalker = curr.getHierarchy(true, true);
                        boolean found = false;
                        while (hierarchyWalker.hasNext()) {
                            curr = hierarchyWalker.next();
                            if (typePattern.matchesStatically(curr)) {
                                found = true;
                                break;
                            }
                        }
                        if (!found) {
                            return FuzzyBoolean.NO;
                        }
                    } else if (patternExactType.isClass()) {
                        ResolvedType curr = info.getType();
                        do {
                            if (typePattern.matchesStatically(curr)) {
                                break;
                            }
                            curr = curr.getSuperclass();
                        } while (curr != null);
                        if (curr == null) {
                            return FuzzyBoolean.NO;
                        }
                    }
                } else if (this.getSignature().getDeclaringType() instanceof AnyWithAnnotationTypePattern) {
                    // aim here is to say NO if the annotation is not possible in the hierarchy here
                    ResolvedType type = info.getType();
                    AnnotationTypePattern annotationTypePattern = ((AnyWithAnnotationTypePattern) getSignature()
                            .getDeclaringType()).getAnnotationPattern();
                    if (annotationTypePattern instanceof ExactAnnotationTypePattern) {
                        ExactAnnotationTypePattern exactAnnotationTypePattern = (ExactAnnotationTypePattern) annotationTypePattern;
                        if (exactAnnotationTypePattern.getAnnotationValues() == null
                                || exactAnnotationTypePattern.getAnnotationValues().size() == 0) {
                            ResolvedType annotationType = exactAnnotationTypePattern.getAnnotationType()
                                    .resolve(info.world);
                            if (type.hasAnnotation(annotationType)) {
                                return FuzzyBoolean.MAYBE;
                            }
                            if (annotationType.isInheritedAnnotation()) {
                                // ok - we may be picking it up from further up the hierarchy (but only a super*class*)
                                ResolvedType toMatchAgainst = type.getSuperclass();
                                boolean found = false;
                                while (toMatchAgainst != null) {
                                    if (toMatchAgainst.hasAnnotation(annotationType)) {
                                        found = true;
                                        break;
                                    }
                                    toMatchAgainst = toMatchAgainst.getSuperclass();
                                }
                                if (!found) {
                                    return FuzzyBoolean.NO;
                                }
                            } else {
                                return FuzzyBoolean.NO;
                            }
                        }
                    }
                    // Optimization from 532033: passes AspectJ tests but breaks Spring Framework
                    //            } else  if (this.getSignature().getDeclaringType() instanceof WildTypePattern) {
                    //               final WildTypePattern pattern = (WildTypePattern) this.getSignature().getDeclaringType();
                    //               final ResolvedType type = info.getType();
                    //               return pattern.matches(type, TypePattern.STATIC);
                }
            }
        }

        return FuzzyBoolean.MAYBE;
    }

    @Override
    protected FuzzyBoolean matchInternal(Shadow shadow) {
        if (shadow.getKind() != kind) {
            return FuzzyBoolean.NO;
        }

        if (shadow.getKind() == Shadow.SynchronizationLock && kind == Shadow.SynchronizationLock) {
            return FuzzyBoolean.YES;
        }
        if (shadow.getKind() == Shadow.SynchronizationUnlock && kind == Shadow.SynchronizationUnlock) {
            return FuzzyBoolean.YES;
        }

        if (!signature.matches(shadow.getMatchingSignature(), shadow.getIWorld(), this.kind == Shadow.MethodCall)) {

            if (kind == Shadow.MethodCall) {
                warnOnConfusingSig(shadow);
                // warnOnBridgeMethod(shadow);
            }
            return FuzzyBoolean.NO;
        }

        return FuzzyBoolean.YES;
    }

    // private void warnOnBridgeMethod(Shadow shadow) {
    // if (shadow.getIWorld().getLint().noJoinpointsForBridgeMethods.isEnabled()) {
    // ResolvedMember rm = shadow.getSignature().resolve(shadow.getIWorld());
    // if (rm!=null) {
    // int shadowModifiers = rm.getModifiers(); //shadow.getSignature().getModifiers(shadow.getIWorld());
    // if (ResolvedType.hasBridgeModifier(shadowModifiers)) {
    // shadow.getIWorld().getLint().noJoinpointsForBridgeMethods.signal(new String[]{},getSourceLocation(),
    // new ISourceLocation[]{shadow.getSourceLocation()});
    // }
    // }
    // }
    // }

    private void warnOnConfusingSig(Shadow shadow) {
        // Don't do all this processing if we don't need to !
        if (!shadow.getIWorld().getLint().unmatchedSuperTypeInCall.isEnabled()) {
            return;
        }

        // no warnings for declare error/warning
        if (munger instanceof Checker) {
            return;
        }

        World world = shadow.getIWorld();

        // warning never needed if the declaring type is any
        UnresolvedType exactDeclaringType = signature.getDeclaringType().getExactType();

        ResolvedType shadowDeclaringType = shadow.getSignature().getDeclaringType().resolve(world);

        if (signature.getDeclaringType().isStar() || ResolvedType.isMissing(exactDeclaringType)
                || exactDeclaringType.resolve(world).isMissing()) {
            return;
        }

        // warning not needed if match type couldn't ever be the declaring type
        if (!shadowDeclaringType.isAssignableFrom(exactDeclaringType.resolve(world))) {
            return;
        }

        // if the method in the declaring type is *not* visible to the
        // exact declaring type then warning not needed.
        ResolvedMember rm = shadow.getSignature().resolve(world);
        // rm can be null in the case where we are binary weaving, and looking at a class with a call to a method in another class,
        // but because of class incompatibilities, the method does not exist on the target class anymore.
        // this will be reported elsewhere.
        if (rm == null) {
            return;
        }

        int shadowModifiers = rm.getModifiers();
        if (!ResolvedType.isVisible(shadowModifiers, shadowDeclaringType, exactDeclaringType.resolve(world))) {
            return;
        }

        if (!signature.getReturnType().matchesStatically(shadow.getSignature().getReturnType().resolve(world))) {
            // Covariance issue...
            // The reason we didn't match is that the type pattern for the pointcut (Car) doesn't match the
            // return type for the specific declaration at the shadow. (FastCar Sub.getCar())
            // XXX Put out another XLINT in this case?
            return;
        }
        // PR60015 - Don't report the warning if the declaring type is object and 'this' is an interface
        if (exactDeclaringType.resolve(world).isInterface()
                && shadowDeclaringType.equals(world.resolve("java.lang.Object"))) {
            return;
        }

        SignaturePattern nonConfusingPattern = new SignaturePattern(signature.getKind(), signature.getModifiers(),
                signature.getReturnType(), TypePattern.ANY, signature.getName(), signature.getParameterTypes(),
                signature.getThrowsPattern(), signature.getAnnotationPattern());

        if (nonConfusingPattern.matches(shadow.getSignature(), shadow.getIWorld(), true)) {
            shadow.getIWorld().getLint().unmatchedSuperTypeInCall.signal(
                    new String[] { shadow.getSignature().getDeclaringType().toString(),
                            signature.getDeclaringType().toString() },
                    this.getSourceLocation(), new ISourceLocation[] { shadow.getSourceLocation() });
        }
    }

    @Override
    public boolean equals(Object other) {
        if (!(other instanceof KindedPointcut)) {
            return false;
        }
        KindedPointcut o = (KindedPointcut) other;
        return o.kind == this.kind && o.signature.equals(this.signature);
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 37 * result + kind.hashCode();
        result = 37 * result + signature.hashCode();
        return result;
    }

    @Override
    public String toString() {
        StringBuffer buf = new StringBuffer();
        buf.append(kind.getSimpleName());
        buf.append("(");
        buf.append(signature.toString());
        buf.append(")");
        return buf.toString();
    }

    @Override
    public void postRead(ResolvedType enclosingType) {
        signature.postRead(enclosingType);
    }

    @Override
    public void write(CompressingDataOutputStream s) throws IOException {
        s.writeByte(Pointcut.KINDED);
        kind.write(s);
        signature.write(s);
        writeLocation(s);
    }

    public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
        Shadow.Kind kind = Shadow.Kind.read(s);
        SignaturePattern sig = SignaturePattern.read(s, context);
        KindedPointcut ret = new KindedPointcut(kind, sig);
        ret.readLocation(context, s);
        return ret;
    }

    // XXX note: there is no namebinding in any kinded pointcut.
    // still might want to do something for better error messages
    // We want to do something here to make sure we don't sidestep the parameter
    // list in capturing type identifiers.
    @Override
    public void resolveBindings(IScope scope, Bindings bindings) {
        if (kind == Shadow.Initialization) {
            // scope.getMessageHandler().handleMessage(
            // MessageUtil.error(
            // "initialization unimplemented in 1.1beta1",
            // this.getSourceLocation()));
        }
        signature = signature.resolveBindings(scope, bindings);

        if (kind == Shadow.ConstructorExecution) { // Bug fix 60936
            if (signature.getDeclaringType() != null) {
                World world = scope.getWorld();
                UnresolvedType exactType = signature.getDeclaringType().getExactType();
                if (signature.getKind() == Member.CONSTRUCTOR && !ResolvedType.isMissing(exactType)
                        && exactType.resolve(world).isInterface()
                        && !signature.getDeclaringType().isIncludeSubtypes()) {
                    world.getLint().noInterfaceCtorJoinpoint.signal(exactType.toString(), getSourceLocation());
                }
            }
        }

        // no parameterized types
        if (kind == Shadow.StaticInitialization) {
            HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
            signature.getDeclaringType().traverse(visitor, null);
            if (visitor.wellHasItThen/* ? */()) {
                scope.message(MessageUtil.error(
                        WeaverMessages.format(WeaverMessages.NO_STATIC_INIT_JPS_FOR_PARAMETERIZED_TYPES),
                        getSourceLocation()));
            }
        }

        // no parameterized types in declaring type position
        if ((kind == Shadow.FieldGet) || (kind == Shadow.FieldSet)) {
            HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
            signature.getDeclaringType().traverse(visitor, null);
            if (visitor.wellHasItThen/* ? */()) {
                scope.message(MessageUtil.error(
                        WeaverMessages.format(WeaverMessages.GET_AND_SET_DONT_SUPPORT_DEC_TYPE_PARAMETERS),
                        getSourceLocation()));
            }

            // fields can't have a void type!
            UnresolvedType returnType = signature.getReturnType().getExactType();
            if (returnType.equals(UnresolvedType.VOID)) {
                scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.FIELDS_CANT_HAVE_VOID_TYPE),
                        getSourceLocation()));
            }
        }

        // no join points for initialization and preinitialization of parameterized types
        // no throwable parameterized types
        if ((kind == Shadow.Initialization) || (kind == Shadow.PreInitialization)) {
            HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
            signature.getDeclaringType().traverse(visitor, null);
            if (visitor.wellHasItThen/* ? */()) {
                scope.message(
                        MessageUtil.error(WeaverMessages.format(WeaverMessages.NO_INIT_JPS_FOR_PARAMETERIZED_TYPES),
                                getSourceLocation()));
            }

            visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
            signature.getThrowsPattern().traverse(visitor, null);
            if (visitor.wellHasItThen/* ? */()) {
                scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.NO_GENERIC_THROWABLES),
                        getSourceLocation()));
            }
        }

        // no parameterized types in declaring type position
        // no throwable parameterized types
        if ((kind == Shadow.MethodExecution) || (kind == Shadow.ConstructorExecution)) {
            HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
            signature.getDeclaringType().traverse(visitor, null);
            if (visitor.wellHasItThen/* ? */()) {
                scope.message(MessageUtil.error(
                        WeaverMessages
                                .format(WeaverMessages.EXECUTION_DOESNT_SUPPORT_PARAMETERIZED_DECLARING_TYPES),
                        getSourceLocation()));
            }

            visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
            signature.getThrowsPattern().traverse(visitor, null);
            if (visitor.wellHasItThen/* ? */()) {
                scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.NO_GENERIC_THROWABLES),
                        getSourceLocation()));
            }
        }

        // no parameterized types in declaring type position
        // no throwable parameterized types
        if ((kind == Shadow.MethodCall) || (kind == Shadow.ConstructorCall)) {
            HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
            signature.getDeclaringType().traverse(visitor, null);
            if (visitor.wellHasItThen/* ? */()) {
                scope.message(MessageUtil.error(
                        WeaverMessages.format(WeaverMessages.CALL_DOESNT_SUPPORT_PARAMETERIZED_DECLARING_TYPES),
                        getSourceLocation()));
            }

            visitor = new HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor();
            signature.getThrowsPattern().traverse(visitor, null);
            if (visitor.wellHasItThen/* ? */()) {
                scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.NO_GENERIC_THROWABLES),
                        getSourceLocation()));
            }
            if (!scope.getWorld().isJoinpointArrayConstructionEnabled() && kind == Shadow.ConstructorCall
                    && signature.getDeclaringType().isArray()) {
                scope.message(
                        MessageUtil.warn(WeaverMessages.format(WeaverMessages.NO_NEWARRAY_JOINPOINTS_BY_DEFAULT),
                                getSourceLocation()));
            }
        }
    }

    @Override
    protected Test findResidueInternal(Shadow shadow, ExposedState state) {
        return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE;
    }

    @Override
    public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
        Pointcut ret = new KindedPointcut(kind, signature, bindings.getEnclosingAdvice());
        ret.copyLocationFrom(this);
        return ret;
    }

    @Override
    public Pointcut parameterizeWith(Map<String, UnresolvedType> typeVariableMap, World w) {
        Pointcut ret = new KindedPointcut(kind, signature.parameterizeWith(typeVariableMap, w), munger);
        ret.copyLocationFrom(this);
        return ret;
    }

    public Shadow.Kind getKind() {
        return kind;
    }

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