package org.aspectj.weaver.patterns;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
import org.aspectj.weaver.AnnotationAJ;
import org.aspectj.weaver.CompressingDataOutputStream;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.VersionedDataInputStream;
import org.aspectj.weaver.WeaverMessages;
import org.aspectj.weaver.World;
public class DeclareAnnotation extends Declare {
public static final Kind AT_TYPE = new Kind(1, "type");
public static final Kind AT_FIELD = new Kind(2, "field");
public static final Kind AT_METHOD = new Kind(3, "method");
public static final Kind AT_CONSTRUCTOR = new Kind(4, "constructor");
public static final Kind AT_REMOVE_FROM_FIELD = new Kind(5, "removeFromField");
private Kind kind;
private TypePattern typePattern;
private ISignaturePattern signaturePattern;
private ResolvedType containingAspect;
private List<String> annotationMethods;
private List<String> annotationStrings;
private AnnotationAJ annotation;
private ResolvedType annotationType;
private int annotationStart;
private int annotationEnd;
public DeclareAnnotation(Kind kind, TypePattern typePattern) {
this.typePattern = typePattern;
this.kind = kind;
init();
}
public DeclareAnnotation(Kind kind, ISignaturePattern sigPattern) {
this.signaturePattern = sigPattern;
this.kind = kind;
init();
}
private void init() {
this.annotationMethods = new ArrayList<String>();
annotationMethods.add("unknown");
this.annotationStrings = new ArrayList<String>();
annotationStrings.add("@<annotation>");
}
public String getAnnotationString() {
return annotationStrings.get(0);
}
public boolean isExactPattern() {
return typePattern instanceof ExactTypePattern;
}
public String getAnnotationMethod() {
return annotationMethods.get(0);
}
@Override
public String toString() {
StringBuilder ret = new StringBuilder();
ret.append("declare @");
ret.append(kind);
ret.append(" : ");
ret.append(typePattern != null ? typePattern.toString() : signaturePattern.toString());
ret.append(" : ");
ret.append(annotationStrings.get(0));
return ret.toString();
}
@Override
public Object accept(PatternNodeVisitor visitor, Object data) {
return visitor.visit(this, data);
}
@Override
public void resolve(IScope scope) {
if (!scope.getWorld().isInJava5Mode()) {
String msg = null;
if (kind == AT_TYPE) {
msg = WeaverMessages.DECLARE_ATTYPE_ONLY_SUPPORTED_AT_JAVA5_LEVEL;
} else if (kind == AT_METHOD) {
msg = WeaverMessages.DECLARE_ATMETHOD_ONLY_SUPPORTED_AT_JAVA5_LEVEL;
} else if (kind == AT_FIELD) {
msg = WeaverMessages.DECLARE_ATFIELD_ONLY_SUPPORTED_AT_JAVA5_LEVEL;
} else if (kind == AT_CONSTRUCTOR) {
msg = WeaverMessages.DECLARE_ATCONS_ONLY_SUPPORTED_AT_JAVA5_LEVEL;
}
scope.message(MessageUtil.error(WeaverMessages.format(msg), getSourceLocation()));
return;
}
if (typePattern != null) {
typePattern = typePattern.resolveBindings(scope, Bindings.NONE, false, false);
}
if (signaturePattern != null) {
signaturePattern = signaturePattern.resolveBindings(scope, Bindings.NONE);
}
this.containingAspect = scope.getEnclosingType();
}
@Override
public Declare parameterizeWith(Map<String, UnresolvedType> typeVariableBindingMap, World w) {
DeclareAnnotation ret;
if (this.kind == AT_TYPE) {
ret = new DeclareAnnotation(kind, this.typePattern.parameterizeWith(typeVariableBindingMap, w));
} else {
ret = new DeclareAnnotation(kind, this.signaturePattern.parameterizeWith(typeVariableBindingMap, w));
}
ret.annotationMethods = this.annotationMethods;
ret.annotationStrings = this.annotationStrings;
ret.annotation = this.annotation;
ret.containingAspect = this.containingAspect;
ret.copyLocationFrom(this);
return ret;
}
@Override
public boolean isAdviceLike() {
return false;
}
public void setAnnotationString(String annotationString) {
this.annotationStrings.set(0, annotationString);
}
public void setAnnotationLocation(int start, int end) {
this.annotationStart = start;
this.annotationEnd = end;
}
public int getAnnotationSourceStart() {
return annotationStart;
}
public int getAnnotationSourceEnd() {
return annotationEnd;
}
public void setAnnotationMethod(String methodName) {
this.annotationMethods.set(0, methodName);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof DeclareAnnotation)) {
return false;
}
DeclareAnnotation other = (DeclareAnnotation) obj;
if (!this.kind.equals(other.kind)) {
return false;
}
if (!this.annotationStrings.get(0).equals(other.annotationStrings.get(0))) {
return false;
}
if (!this.annotationMethods.get(0).equals(other.annotationMethods.get(0))) {
return false;
}
if (this.typePattern != null) {
if (!typePattern.equals(other.typePattern)) {
return false;
}
}
if (this.signaturePattern != null) {
if (!signaturePattern.equals(other.signaturePattern)) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
int result = 19;
result = 37 * result + kind.hashCode();
result = 37 * result + annotationStrings.get(0).hashCode();
result = 37 * result + annotationMethods.get(0).hashCode();
if (typePattern != null) {
result = 37 * result + typePattern.hashCode();
}
if (signaturePattern != null) {
result = 37 * result + signaturePattern.hashCode();
}
return result;
}
@Override
public void write(CompressingDataOutputStream s) throws IOException {
s.writeByte(Declare.ANNOTATION);
if (kind.id == AT_FIELD.id && isRemover) {
s.writeInt(AT_REMOVE_FROM_FIELD.id);
} else {
s.writeInt(kind.id);
}
int max = 0;
s.writeByte(max = annotationStrings.size());
for (int i = 0; i < max; i++) {
s.writeUTF(annotationStrings.get(i));
}
s.writeByte(max = annotationMethods.size());
for (int i = 0; i < max; i++) {
s.writeUTF(annotationMethods.get(i));
}
if (typePattern != null) {
typePattern.write(s);
}
if (signaturePattern != null) {
AbstractSignaturePattern.writeCompoundSignaturePattern(s, signaturePattern);
}
writeLocation(s);
}
public static Declare read(VersionedDataInputStream s, ISourceContext context) throws IOException {
DeclareAnnotation ret = null;
boolean isRemover = false;
int kind = s.readInt();
if (kind == AT_REMOVE_FROM_FIELD.id) {
kind = AT_FIELD.id;
isRemover = true;
}
if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
s.readByte();
}
String annotationString = s.readUTF();
if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
s.readByte();
}
String annotationMethod = s.readUTF();
TypePattern tp = null;
SignaturePattern sp = null;
switch (kind) {
case 1:
tp = TypePattern.read(s, context);
ret = new DeclareAnnotation(AT_TYPE, tp);
break;
case 2:
if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
ret = new DeclareAnnotation(AT_FIELD, AbstractSignaturePattern.readCompoundSignaturePattern(s, context));
} else {
sp = SignaturePattern.read(s, context);
ret = new DeclareAnnotation(AT_FIELD, sp);
}
if (isRemover) {
ret.setRemover(true);
}
break;
case 3:
if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
ret = new DeclareAnnotation(AT_METHOD, AbstractSignaturePattern.readCompoundSignaturePattern(s, context));
} else {
sp = SignaturePattern.read(s, context);
ret = new DeclareAnnotation(AT_METHOD, sp);
}
break;
case 4:
if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
ret = new DeclareAnnotation(AT_CONSTRUCTOR, AbstractSignaturePattern.readCompoundSignaturePattern(s, context));
} else {
sp = SignaturePattern.read(s, context);
ret = new DeclareAnnotation(AT_CONSTRUCTOR, sp);
}
break;
}
ret.setAnnotationString(annotationString);
ret.setAnnotationMethod(annotationMethod);
ret.readLocation(context, s);
return ret;
}
public boolean matches(ResolvedMember resolvedmember, World world) {
if (kind == AT_METHOD || kind == AT_CONSTRUCTOR) {
if (resolvedmember != null && resolvedmember.getName().charAt(0) == '<') {
if (kind == AT_METHOD) {
return false;
}
}
}
return signaturePattern.matches(resolvedmember, world, false);
}
public boolean matches(ResolvedType type) {
if (!typePattern.matchesStatically(type)) {
return false;
}
if (type.getWorld().getLint().typeNotExposedToWeaver.isEnabled() && !type.isExposedToWeaver()) {
type.getWorld().getLint().typeNotExposedToWeaver.signal(type.getName(), getSourceLocation());
}
return true;
}
public void setAspect(ResolvedType typeX) {
containingAspect = typeX;
}
public UnresolvedType getAspect() {
return containingAspect;
}
public void copyAnnotationTo(ResolvedType onType) {
ensureAnnotationDiscovered();
if (!onType.hasAnnotation(annotation.getType())) {
onType.addAnnotation(annotation);
}
}
public AnnotationAJ getAnnotation() {
ensureAnnotationDiscovered();
return annotation;
}
private void ensureAnnotationDiscovered() {
if (annotation != null) {
return;
}
String annotationMethod = annotationMethods.get(0);
for (Iterator<ResolvedMember> iter = containingAspect.getMethods(true, true); iter.hasNext();) {
ResolvedMember member = iter.next();
if (member.getName().equals(annotationMethod)) {
AnnotationAJ[] annos = member.getAnnotations();
if (annos == null) {
return;
}
int idx = 0;
if (annos.length > 0
&& annos[0].getType().getSignature().equals("Lorg/aspectj/internal/lang/annotation/ajcDeclareAnnotation;")) {
idx = 1;
}
annotation = annos[idx];
break;
}
}
}
public TypePattern getTypePattern() {
return typePattern;
}
public ISignaturePattern getSignaturePattern() {
return signaturePattern;
}
public boolean isStarredAnnotationPattern() {
if (typePattern != null) {
return typePattern.isStarAnnotation();
} else {
return signaturePattern.isStarAnnotation();
}
}
public Kind getKind() {
return kind;
}
public boolean isDeclareAtConstuctor() {
return kind.equals(AT_CONSTRUCTOR);
}
public boolean isDeclareAtMethod() {
return kind.equals(AT_METHOD);
}
public boolean isDeclareAtType() {
return kind.equals(AT_TYPE);
}
public boolean isDeclareAtField() {
return kind.equals(AT_FIELD);
}
public ResolvedType getAnnotationType() {
if (annotationType == null) {
String annotationMethod = annotationMethods.get(0);
for (Iterator<ResolvedMember> iter = containingAspect.getMethods(true, true); iter.hasNext();) {
ResolvedMember member = iter.next();
if (member.getName().equals(annotationMethod)) {
ResolvedType[] annoTypes = member.getAnnotationTypes();
if (annoTypes == null) {
return null;
}
int idx = 0;
if (annoTypes[0].getSignature().equals("Lorg/aspectj/internal/lang/annotation/ajcDeclareAnnotation;")) {
idx = 1;
}
annotationType = annoTypes[idx];
break;
}
}
}
return annotationType;
}
public boolean isAnnotationAllowedOnField() {
ensureAnnotationDiscovered();
return annotation.allowedOnField();
}
public String getPatternAsString() {
if (signaturePattern != null) {
return signaturePattern.toString();
}
if (typePattern != null) {
return typePattern.toString();
}
return "DONT KNOW";
}
public boolean couldEverMatch(ResolvedType type) {
if (signaturePattern != null) {
return signaturePattern.couldEverMatch(type);
}
return true;
}
@Override
public String getNameSuffix() {
return getKind().toString();
}
public static class Kind {
private final int id;
private String s;
private Kind(int n, String name) {
id = n;
s = name;
}
@Override
public int hashCode() {
return (19 + 37 * id);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Kind)) {
return false;
}
Kind other = (Kind) obj;
return other.id == id;
}
@Override
public String toString() {
return "at_" + s;
}
}
boolean isRemover = false;
public void setRemover(boolean b) {
isRemover = b;
}
public boolean isRemover() {
return isRemover;
}
}