|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541 |
- /* *******************************************************************
- * Copyright (c) 2005 IBM Corporation
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v 2.0
- * which accompanies this distribution and is available at
- * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
- *
- * Contributors:
- * Adrian Colyer initial implementation
- * Andy Clement got it working
- * ******************************************************************/
- 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;
-
- /**
- * Represents a declare annotation statement, one of atField, atMethod, atConstructor or atType.
- *
- * @author Andy Clement
- */
- 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;
- // for declare @type
- private TypePattern typePattern;
- // for declare @field,@method,@constructor
- private ISignaturePattern signaturePattern;
- private ResolvedType containingAspect;
- private List<String> annotationMethods;
- private List<String> annotationStrings;
- private AnnotationAJ annotation; // discovered when required
- private ResolvedType annotationType; // discovered when required
-
- // not serialized:
- private int annotationStart;
- private int annotationEnd;
-
- /**
- * Constructor for declare atType.
- */
- public DeclareAnnotation(Kind kind, TypePattern typePattern) {
- this.typePattern = typePattern;
- this.kind = kind;
- init();
- }
-
- /**
- * Constructor for declare atMethod/atField/atConstructor.
- */
- public DeclareAnnotation(Kind kind, ISignaturePattern sigPattern) {
- this.signaturePattern = sigPattern;
- this.kind = kind;
- init();
- }
-
- private void init() {
- this.annotationMethods = new ArrayList<>();
- annotationMethods.add("unknown");
- this.annotationStrings = new ArrayList<>();
- annotationStrings.add("@<annotation>");
- }
-
- /**
- * Returns the string, useful before the real annotation has been resolved
- */
- 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;
- }
- // old format was just a single string and method
- if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
- // int numAnnotationStrings =
- s.readByte();
- }
- String annotationString = s.readUTF();
- if (s.getMajorVersion() >= WeaverVersionInfo.WEAVER_VERSION_AJ169) {
- // int numAnnotationMethods =
- 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;
- }
-
- /**
- * For declare atConstructor, atMethod, atField
- */
- public boolean matches(ResolvedMember resolvedmember, World world) {
- if (kind == AT_METHOD || kind == AT_CONSTRUCTOR) {
- if (resolvedmember != null && resolvedmember.getName().charAt(0) == '<') {
- // <clinit> or <init>
- if (kind == AT_METHOD) {
- return false;
- }
- }
- }
- return signaturePattern.matches(resolvedmember, world, false);
- }
-
- /**
- * For declare atType.
- */
- 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;
- }
-
- /**
- * The annotation specified in the declare @type is stored against a simple method of the form "ajc$declare_<NN>", this method
- * finds that method and retrieves the 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) {
- // if weaving broken code, this can happen
- return;
- }
- int idx = 0;
- if (annos.length > 0
- && annos[0].getType().getSignature().equals("Lorg/aspectj/internal/lang/annotation/ajcDeclareAnnotation;")) {
- if (annos.length < 2)
- continue;
- 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);
- }
-
- /**
- * @return the type of the annotation
- */
- 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) {
- // if weaving broken code, this can happen
- return null;
- }
- int idx = 0;
- if (annoTypes[0].getSignature().equals("Lorg/aspectj/internal/lang/annotation/ajcDeclareAnnotation;")) {
- idx = 1;
- if (annoTypes.length < 2)
- continue;
- }
- annotationType = annoTypes[idx];
- break;
- }
- }
- }
- return annotationType;
- }
-
- /**
- * @return true if the annotation specified is allowed on a field
- */
- 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";
- }
-
- /**
- * Return true if this declare annotation could ever match something in the specified type - only really able to make
- * intelligent decision if a type was specified in the sig/type pattern signature.
- */
- public boolean couldEverMatch(ResolvedType type) {
- // Haven't implemented variant for typePattern (doesn't seem worth it!)
- // BUGWARNING This test might not be sufficient for funny cases relating
- // to interfaces and the use of '+' - but it seems really important to
- // do something here so we don't iterate over all fields and all methods
- // in all types exposed to the weaver! So look out for bugs here and
- // we can update the test as appropriate.
- if (signaturePattern != null) {
- return signaturePattern.couldEverMatch(type);
- }
- return true;
- }
-
- /**
- * Provide a name suffix so that we can tell the different declare annotations forms apart in the AjProblemReporter
- */
- @Override
- public String getNameSuffix() {
- return getKind().toString();
- }
-
- /**
- * Captures type of declare annotation (method/type/field/constructor)
- */
- 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;
- }
- }
|