]> source.dussan.org Git - aspectj.git/commitdiff
pipeline changes: converts Eclipse annotations to AJ ones
authoraclement <aclement>
Fri, 28 Jul 2006 10:20:23 +0000 (10:20 +0000)
committeraclement <aclement>
Fri, 28 Jul 2006 10:20:23 +0000 (10:20 +0000)
org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceType.java

index e70a6f0ff75fe80e78acf70a4a27d870fb602ee7..8381f8834000e6c1b952df43e7ec3713bb96700e 100644 (file)
@@ -31,21 +31,34 @@ import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
 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;
@@ -53,6 +66,7 @@ import org.aspectj.weaver.ResolvedType;
 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;
@@ -82,6 +96,9 @@ public class EclipseSourceType extends AbstractReferenceTypeDelegate {
                
        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;
@@ -430,14 +447,206 @@ public class EclipseSourceType extends AbstractReferenceTypeDelegate {
                }
                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);
@@ -445,7 +654,7 @@ public class EclipseSourceType extends AbstractReferenceTypeDelegate {
                }
                
                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;