From 2719757a9231f54c8634ee0df316894dd2e47667 Mon Sep 17 00:00:00 2001 From: aclement Date: Fri, 28 Jul 2006 10:20:23 +0000 Subject: [PATCH] pipeline changes: converts Eclipse annotations to AJ ones --- .../compiler/lookup/EclipseSourceType.java | 219 +++++++++++++++++- 1 file changed, 214 insertions(+), 5 deletions(-) diff --git a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceType.java b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceType.java index e70a6f0ff..8381f8834 100644 --- a/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceType.java +++ b/org.aspectj.ajdt.core/src/org/aspectj/ajdt/internal/compiler/lookup/EclipseSourceType.java @@ -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; -- 2.39.5