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;
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) {
if (info.getKind() != null) {
if (info.getKind() != kind) {
return FuzzyBoolean.NO;
}
}
if (info.world.optimizedMatching) {
if ((kind == Shadow.MethodExecution || kind == Shadow.Initialization) && info.getKind() == null) {
boolean fastMatchingOnAspect = info.getType().isAspect();
if (fastMatchingOnAspect) {
return MAYBE;
}
if (this.getSignature().isExactDeclaringTypePattern()) {
ExactTypePattern typePattern = (ExactTypePattern) this.getSignature().getDeclaringType();
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) {
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()) {
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;
}
}
}
}
}
}
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);
}
return FuzzyBoolean.NO;
}
return FuzzyBoolean.YES;
}
private void warnOnConfusingSig(Shadow shadow) {
if (!shadow.getIWorld().getLint().unmatchedSuperTypeInCall.isEnabled()) {
return;
}
if (munger instanceof Checker) {
return;
}
World world = shadow.getIWorld();
UnresolvedType exactDeclaringType = signature.getDeclaringType().getExactType();
ResolvedType shadowDeclaringType = shadow.getSignature().getDeclaringType().resolve(world);
if (signature.getDeclaringType().isStar() || ResolvedType.isMissing(exactDeclaringType)
|| exactDeclaringType.resolve(world).isMissing()) {
return;
}
if (!shadowDeclaringType.isAssignableFrom(exactDeclaringType.resolve(world))) {
return;
}
ResolvedMember rm = shadow.getSignature().resolve(world);
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))) {
return;
}
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;
}
@Override
public void resolveBindings(IScope scope, Bindings bindings) {
if (kind == Shadow.Initialization) {
}
signature = signature.resolveBindings(scope, bindings);
if (kind == Shadow.ConstructorExecution) {
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());
}
}
}
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()));
}
}
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()));
}
UnresolvedType returnType = signature.getReturnType().getExactType();
if (returnType.equals(UnresolvedType.VOID)) {
scope.message(MessageUtil.error(WeaverMessages.format(WeaverMessages.FIELDS_CANT_HAVE_VOID_TYPE),
getSourceLocation()));
}
}
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()));
}
}
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()));
}
}
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);
}
}