import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ArrayInitializer;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
+import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.StringLiteral;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeParameter;
+import org.aspectj.org.eclipse.jdt.internal.compiler.impl.Constant;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.CompilerModifiers;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TagBits;
+import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.aspectj.weaver.AbstractReferenceTypeDelegate;
+import org.aspectj.weaver.AnnotationAJ;
+import org.aspectj.weaver.AnnotationNameValuePair;
import org.aspectj.weaver.AnnotationTargetKind;
+import org.aspectj.weaver.AnnotationValue;
import org.aspectj.weaver.AnnotationX;
+import org.aspectj.weaver.ArrayAnnotationValue;
+import org.aspectj.weaver.EnumAnnotationValue;
import org.aspectj.weaver.ReferenceType;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedPointcutDefinition;
import org.aspectj.weaver.TypeVariable;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.WeaverStateInfo;
+import org.aspectj.weaver.World;
import org.aspectj.weaver.patterns.PerClause;
import org.aspectj.weaver.patterns.PerFromSuper;
import org.aspectj.weaver.patterns.PerSingleton;
private boolean discoveredAnnotationTargetKinds = false;
private AnnotationTargetKind[] annotationTargetKinds;
+ private AnnotationX[] annotations = null;
+ private final static ResolvedType[] NO_ANNOTATION_TYPES = new ResolvedType[0];
+ private final static AnnotationX[] NO_ANNOTATIONS = new AnnotationX[0];
protected EclipseFactory eclipseWorld() {
return factory;
}
return false;
}
-
+
+ /**
+ * WARNING: This method does not have a complete implementation.
+ *
+ * The aim is that it converts Eclipse annotation objects to the AspectJ form of
+ * annotations (the type AnnotationAJ). The AnnotationX objects returned are wrappers
+ * over either a Bcel annotation type or the AspectJ AnnotationAJ type.
+ * The minimal implementation provided here is for processing the RetentionPolicy and
+ * Target annotation types - these are the only ones which the weaver will attempt to
+ * process from an EclipseSourceType.
+ *
+ * More notes:
+ * The pipeline has required us to implement this. With the pipeline we can be weaving
+ * a type and asking questions of annotations before they have been turned into Bcel
+ * objects - ie. when they are still in EclipseSourceType form. Without the pipeline we
+ * would have converted everything to Bcel objects before proceeding with weaving.
+ * Because the pipeline won't start weaving until all aspects have been compiled and
+ * the fact that no AspectJ constructs match on the values within annotations, this code
+ * only needs to deal with converting system annotations that the weaver needs to process
+ * (RetentionPolicy, Target).
+ */
public AnnotationX[] getAnnotations() {
- throw new RuntimeException("Missing implementation");
-
+ if (annotations!=null) return annotations; // only do this once
+ getAnnotationTypes(); // forces resolution and sets resolvedAnnotations
+ Annotation[] as = declaration.annotations;
+ if (as==null || as.length==0) {
+ annotations = NO_ANNOTATIONS;
+ } else {
+ annotations = new AnnotationX[as.length];
+ for (int i = 0; i < as.length; i++) {
+ annotations[i]=convertEclipseAnnotation(as[i],factory.getWorld());
+ }
+ }
+ return annotations;
+ }
+
+ /**
+ * Convert one eclipse annotation into an AnnotationX object containing an AnnotationAJ object.
+ *
+ * This code and the helper methods used by it will go *BANG* if they encounter anything
+ * not currently supported - this is safer than limping along with a malformed annotation. When
+ * the *BANG* is encountered the bug reporter should indicate the kind of annotation they
+ * were working with and this code can be enhanced to support it.
+ */
+ public AnnotationX convertEclipseAnnotation(Annotation eclipseAnnotation,World w) {
+ // TODO if it is sourcevisible, we shouldn't let it through!!!!!!!!! testcase!
+ ResolvedType annotationType = factory.fromTypeBindingToRTX(eclipseAnnotation.type.resolvedType);
+ long bs = (eclipseAnnotation.bits & TagBits.AnnotationRetentionMASK);
+ boolean isRuntimeVisible = (eclipseAnnotation.bits & TagBits.AnnotationRetentionMASK) == TagBits.AnnotationRuntimeRetention;
+ AnnotationAJ annotationAJ = new AnnotationAJ(annotationType.getSignature(),isRuntimeVisible);
+ generateAnnotation(eclipseAnnotation,annotationAJ);
+ return new AnnotationX(annotationAJ,w);
}
+
+ static class MissingImplementationException extends RuntimeException {
+ MissingImplementationException(String reason) {
+ super(reason);
+ }
+ }
+
+ private void generateAnnotation(Annotation annotation,AnnotationAJ annotationAJ) {
+ if (annotation instanceof NormalAnnotation) {
+ NormalAnnotation normalAnnotation = (NormalAnnotation) annotation;
+ MemberValuePair[] memberValuePairs = normalAnnotation.memberValuePairs;
+ if (memberValuePairs != null) {
+ int memberValuePairsLength = memberValuePairs.length;
+ for (int i = 0; i < memberValuePairsLength; i++) {
+ MemberValuePair memberValuePair = memberValuePairs[i];
+ MethodBinding methodBinding = memberValuePair.binding;
+ if (methodBinding == null) {
+ // is this just a marker annotation?
+ throw new MissingImplementationException(
+ "Please raise an AspectJ bug. AspectJ does not know how to convert this annotation ["+annotation+"]");
+ } else {
+ AnnotationValue av = generateElementValue(memberValuePair.value, methodBinding.returnType);
+ AnnotationNameValuePair anvp = new AnnotationNameValuePair(new String(memberValuePair.name),av);
+ annotationAJ.addNameValuePair(anvp);
+ }
+ }
+ } else {
+ throw new MissingImplementationException(
+ "Please raise an AspectJ bug. AspectJ does not know how to convert this annotation ["+annotation+"]");
+ }
+ } else if (annotation instanceof SingleMemberAnnotation) {
+ // this is a single member annotation (one member value)
+ SingleMemberAnnotation singleMemberAnnotation = (SingleMemberAnnotation) annotation;
+ MethodBinding methodBinding = singleMemberAnnotation.memberValuePairs()[0].binding;
+ if (methodBinding == null) {
+ throw new MissingImplementationException(
+ "Please raise an AspectJ bug. AspectJ does not know how to convert this annotation ["+annotation+"]");
+ } else {
+ AnnotationValue av = generateElementValue(singleMemberAnnotation.memberValue, methodBinding.returnType);
+ annotationAJ.addNameValuePair(
+ new AnnotationNameValuePair(new String(singleMemberAnnotation.memberValuePairs()[0].name),av));
+ }
+ } else {
+ // this is a marker annotation (no member value pairs)
+ throw new MissingImplementationException(
+ "Please raise an AspectJ bug. AspectJ does not know how to convert this annotation ["+annotation+"]");
+ }
+ }
+
+ private AnnotationValue generateElementValue(Expression defaultValue,TypeBinding memberValuePairReturnType) {
+ Constant constant = defaultValue.constant;
+ TypeBinding defaultValueBinding = defaultValue.resolvedType;
+ if (defaultValueBinding == null) {
+ throw new MissingImplementationException(
+ "Please raise an AspectJ bug. AspectJ does not know how to convert this annotation value ["+defaultValue+"]");
+ } else {
+ if (memberValuePairReturnType.isArrayType() && !defaultValueBinding.isArrayType()) {
+ if (constant != null && constant != Constant.NotAConstant) {
+ throw new MissingImplementationException(
+ "Please raise an AspectJ bug. AspectJ does not know how to convert this annotation value ["+defaultValue+"]");
+// generateElementValue(attributeOffset, defaultValue, constant, memberValuePairReturnType.leafComponentType());
+ } else {
+ AnnotationValue av = generateElementValueForNonConstantExpression(defaultValue, defaultValueBinding);
+ return new ArrayAnnotationValue(new AnnotationValue[]{av});
+ }
+ } else {
+ if (constant != null && constant != Constant.NotAConstant) {
+ throw new MissingImplementationException(
+ "Please raise an AspectJ bug. AspectJ does not know how to convert this annotation value ["+defaultValue+"]");
+// generateElementValue(attributeOffset, defaultValue, constant, memberValuePairReturnType.leafComponentType());
+ } else {
+ AnnotationValue av = generateElementValueForNonConstantExpression(defaultValue, defaultValueBinding);
+ return av;
+ }
+ }
+ }
+ }
+
+ private AnnotationValue generateElementValueForNonConstantExpression(Expression defaultValue, TypeBinding defaultValueBinding) {
+ if (defaultValueBinding != null) {
+ if (defaultValueBinding.isEnum()) {
+ FieldBinding fieldBinding = null;
+ if (defaultValue instanceof QualifiedNameReference) {
+ QualifiedNameReference nameReference = (QualifiedNameReference) defaultValue;
+ fieldBinding = (FieldBinding) nameReference.binding;
+ } else if (defaultValue instanceof SingleNameReference) {
+ SingleNameReference nameReference = (SingleNameReference) defaultValue;
+ fieldBinding = (FieldBinding) nameReference.binding;
+ } else {
+ throw new MissingImplementationException(
+ "Please raise an AspectJ bug. AspectJ does not know how to convert this annotation value ["+defaultValue+"]");
+ }
+ if (fieldBinding != null) {
+ String sig = new String(fieldBinding.type.signature());
+ AnnotationValue enumValue = new EnumAnnotationValue(sig,new String(fieldBinding.name));
+ return enumValue;
+ }
+ throw new MissingImplementationException(
+ "Please raise an AspectJ bug. AspectJ does not know how to convert this annotation value ["+defaultValue+"]");
+ } else if (defaultValueBinding.isAnnotationType()) {
+ throw new MissingImplementationException(
+ "Please raise an AspectJ bug. AspectJ does not know how to convert this annotation value ["+defaultValue+"]");
+// contents[contentsOffset++] = (byte) '@';
+// generateAnnotation((Annotation) defaultValue, attributeOffset);
+ } else if (defaultValueBinding.isArrayType()) {
+ // array type
+ if (defaultValue instanceof ArrayInitializer) {
+ ArrayInitializer arrayInitializer = (ArrayInitializer) defaultValue;
+ int arrayLength = arrayInitializer.expressions != null ? arrayInitializer.expressions.length : 0;
+ AnnotationValue[] values = new AnnotationValue[arrayLength];
+ for (int i = 0; i < arrayLength; i++) {
+ values[i] = generateElementValue(arrayInitializer.expressions[i], defaultValueBinding.leafComponentType());//, attributeOffset);
+ }
+ ArrayAnnotationValue aav = new ArrayAnnotationValue(values);
+ return aav;
+ } else {
+ throw new MissingImplementationException(
+ "Please raise an AspectJ bug. AspectJ does not know how to convert this annotation value ["+defaultValue+"]");
+ }
+ } else {
+ // class type
+ throw new MissingImplementationException(
+ "Please raise an AspectJ bug. AspectJ does not know how to convert this annotation value ["+defaultValue+"]");
+// if (contentsOffset + 3 >= this.contents.length) {
+// resizeContents(3);
+// }
+// contents[contentsOffset++] = (byte) 'c';
+// if (defaultValue instanceof ClassLiteralAccess) {
+// ClassLiteralAccess classLiteralAccess = (ClassLiteralAccess) defaultValue;
+// final int classInfoIndex = constantPool.literalIndex(classLiteralAccess.targetType.signature());
+// contents[contentsOffset++] = (byte) (classInfoIndex >> 8);
+// contents[contentsOffset++] = (byte) classInfoIndex;
+// } else {
+// contentsOffset = attributeOffset;
+// }
+ }
+ } else {
+ throw new MissingImplementationException(
+ "Please raise an AspectJ bug. AspectJ does not know how to convert this annotation value ["+defaultValue+"]");
+// contentsOffset = attributeOffset;
+ }
+ }
+
+ // ---------------------------------
+
public ResolvedType[] getAnnotationTypes() {
if (resolvedAnnotations!=null) return resolvedAnnotations;
-
// Make sure they are resolved
if (!annotationsResolved) {
TypeDeclaration.resolveAnnotations(declaration.staticInitializerScope, declaration.annotations, binding);
}
if (declaration.annotations == null) {
- resolvedAnnotations = new ResolvedType[0];
+ resolvedAnnotations = NO_ANNOTATION_TYPES;//new ResolvedType[0];
} else {
resolvedAnnotations = new ResolvedType[declaration.annotations.length];
Annotation[] as = declaration.annotations;