diff options
Diffstat (limited to 'org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java')
-rw-r--r-- | org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java | 385 |
1 files changed, 239 insertions, 146 deletions
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java index 64709c909..538c3ee7d 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java @@ -17,6 +17,8 @@ * bug 186342 - [compiler][null] Using annotations for null checking * bug 365662 - [compiler][null] warn on contradictory and redundant null annotations * bug 331649 - [compiler][null] consider null annotations for fields + * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for + * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -47,47 +49,44 @@ public abstract class Annotation extends Expression { final TypeReference reference, final Annotation[] primaryAnnotation, final Annotation annotation, - final Annotation[][] annotationsOnDimensionsOnExpression) { + final Annotation[][] annotationsOnDimensionsOnExpression, + final int dimensions) { + class LocationCollector extends ASTVisitor { - Stack currentIndexes; + Stack typePathEntries; Annotation currentAnnotation; boolean search = true; public LocationCollector(Annotation currentAnnotation) { - this.currentIndexes = new Stack(); + this.typePathEntries = new Stack(); this.currentAnnotation = currentAnnotation; } - public boolean visit(ArrayTypeReference typeReference, BlockScope scope) { + + public boolean visit(ParameterizedSingleTypeReference typeReference, BlockScope scope) { if (!this.search) return false; + Annotation[][] annotationsOnDimensions = typeReference.annotationsOnDimensions; if (annotationsOnDimensions != null) { - // check if the annotation is located on the first dimension - Annotation[] annotations = annotationsOnDimensions[0]; - if (annotations != null) { - for (int j = 0, max2 = annotations.length; j < max2; j++) { - Annotation current = annotations[j]; - if (current == this.currentAnnotation) { - this.search = false; - return false; - } - } - } - - this.currentIndexes.push(new Integer(0)); - for (int i = 1, max = annotationsOnDimensions.length; i < max; i++) { - annotations = annotationsOnDimensions[i]; + for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { + Annotation[] annotations = annotationsOnDimensions[i]; if (annotations != null) { for (int j = 0, max2 = annotations.length; j < max2; j++) { Annotation current = annotations[j]; if (current == this.currentAnnotation) { + // found it, push any relevant type path entries + for (int k = 0; k < i; k++) { + this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); + } this.search = false; return false; } } } - this.currentIndexes.push(new Integer(((Integer) this.currentIndexes.pop()).intValue() + 1)); + } } + + // Example cases handled here: @B(1) List<String>[] Annotation[][] annotations = typeReference.annotations; if (annotations == null) { annotations = new Annotation[][] { primaryAnnotation }; @@ -99,91 +98,99 @@ public abstract class Annotation extends Expression { for (int j = 0; j < annotationsLength; j++) { if (current[j] == this.currentAnnotation) { this.search = false; + // Found it, insert any necessary type path elements + for (int k = 0; k < typeReference.dimensions; k++) { + this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); + } return false; } } } - this.currentIndexes.pop(); + + // If a type argument is annotated it is necessary jump past the array elements + if (typeReference.dimensions != 0) { + for (int k = 0, maxk = typeReference.dimensions; k < maxk; k++) { + this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); + } + } + TypeReference[] typeReferences = typeReference.typeArguments; + for (int i = 0, max = typeReferences.length; i < max; i++) { + this.typePathEntries.add(new int[]{3,i}); + typeReferences[i].traverse(this, scope); + if (!this.search) { + return false; + } else { + this.typePathEntries.pop(); + } + } + if (typeReference.dimensions != 0) { + for (int k = 0, maxk = typeReference.dimensions; k < maxk; k++) { + this.typePathEntries.pop(); + } + } return true; } - public boolean visit(ArrayQualifiedTypeReference typeReference, BlockScope scope) { + + public boolean visit(SingleTypeReference typeReference, BlockScope scope) { if (!this.search) return false; - Annotation[][] annotationsOnDimensions = typeReference.annotationsOnDimensions; - if (annotationsOnDimensions != null) { - // check if the annotation is located on the first dimension - Annotation[] annotations = annotationsOnDimensions[0]; - if (annotations != null) { - for (int j = 0, max2 = annotations.length; j < max2; j++) { - Annotation current = annotations[j]; - if (current == this.currentAnnotation) { - this.search = false; - return false; - } - } - } - this.currentIndexes.push(new Integer(0)); - for (int i = 1, max = annotationsOnDimensions.length; i < max; i++) { - annotations = annotationsOnDimensions[i]; - if (annotations != null) { - for (int j = 0, max2 = annotations.length; j < max2; j++) { - Annotation current = annotations[j]; - if (current == this.currentAnnotation) { - this.search = false; - return false; - } - } - } - this.currentIndexes.push(new Integer(((Integer) this.currentIndexes.pop()).intValue() + 1)); + // depth allows for the syntax "outerInstance.new @A InnerType();" + int depth = 0; + if (typeReference.resolvedType instanceof ReferenceBinding) { + depth = getInnerDepth((ReferenceBinding)typeReference.resolvedType); + } + + if (dimensions != 0) { + for (int k = 0; k < dimensions; k++) { + this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); } } Annotation[][] annotations = typeReference.annotations; - if (annotations == null) { - annotations = new Annotation[][] { primaryAnnotation }; - } - int annotationsLevels = annotations.length; + int annotationsLevels = annotations == null ? 0 : annotations.length; for (int i = 0; i < annotationsLevels; i++) { Annotation [] current = annotations[i]; int annotationsLength = current == null ? 0 : current.length; for (int j = 0; j < annotationsLength; j++) { if (current[j] == this.currentAnnotation) { + // Found this.search = false; + if (depth != 0) { + for (int k = 0; k<depth; k++) { + this.typePathEntries.add(TYPE_PATH_INNER_TYPE); + } + } return false; } } } - this.currentIndexes.pop(); - return true; + if (dimensions != 0) { + for (int k = 0; k < dimensions; k++) { + this.typePathEntries.pop(); + } + } + return false; } - public boolean visit(ParameterizedSingleTypeReference typeReference, BlockScope scope) { + + public boolean visit(ArrayTypeReference typeReference, BlockScope scope) { if (!this.search) return false; + Annotation[][] annotationsOnDimensions = typeReference.annotationsOnDimensions; if (annotationsOnDimensions != null) { - // check if the annotation is located on the first dimension - Annotation[] annotations = annotationsOnDimensions[0]; - if (annotations != null) { - for (int j = 0, max2 = annotations.length; j < max2; j++) { - Annotation current = annotations[j]; - if (current == this.currentAnnotation) { - this.search = false; - return false; - } - } - } - - this.currentIndexes.push(new Integer(0)); - for (int i = 1, max = annotationsOnDimensions.length; i < max; i++) { - annotations = annotationsOnDimensions[i]; + for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { + Annotation[] annotations = annotationsOnDimensions[i]; if (annotations != null) { for (int j = 0, max2 = annotations.length; j < max2; j++) { Annotation current = annotations[j]; if (current == this.currentAnnotation) { + for (int k = 0; k < i; k++) { + this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); + } this.search = false; return false; } } } - this.currentIndexes.push(new Integer(((Integer) this.currentIndexes.pop()).intValue() + 1)); + } } Annotation[][] annotations = typeReference.annotations; @@ -196,50 +203,36 @@ public abstract class Annotation extends Expression { int annotationsLength = current == null ? 0 : current.length; for (int j = 0; j < annotationsLength; j++) { if (current[j] == this.currentAnnotation) { + for (int k = 0, maxk=typeReference.dimensions; k < maxk; k++) { + this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); + } this.search = false; return false; } } } - TypeReference[] typeReferences = typeReference.typeArguments; - this.currentIndexes.push(new Integer(0)); - for (int i = 0, max = typeReferences.length; i < max; i++) { - typeReferences[i].traverse(this, scope); - if (!this.search) return false; - this.currentIndexes.push(new Integer(((Integer) this.currentIndexes.pop()).intValue() + 1)); - } - this.currentIndexes.pop(); return true; } - public boolean visit(ParameterizedQualifiedTypeReference typeReference, BlockScope scope) { + + public boolean visit(ArrayQualifiedTypeReference typeReference, BlockScope scope) { if (!this.search) return false; Annotation[][] annotationsOnDimensions = typeReference.annotationsOnDimensions; if (annotationsOnDimensions != null) { - // check if the annotation is located on the first dimension - Annotation[] annotations = annotationsOnDimensions[0]; - if (annotations != null) { - for (int j = 0, max2 = annotations.length; j < max2; j++) { - Annotation current = annotations[j]; - if (current == this.currentAnnotation) { - this.search = false; - return false; - } - } - } - - this.currentIndexes.push(new Integer(0)); - for (int i = 1, max = annotationsOnDimensions.length; i < max; i++) { - annotations = annotationsOnDimensions[i]; + for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { + Annotation[] annotations = annotationsOnDimensions[i]; if (annotations != null) { for (int j = 0, max2 = annotations.length; j < max2; j++) { Annotation current = annotations[j]; if (current == this.currentAnnotation) { this.search = false; + // Found it, insert relevant type path elements + for (int k = 0, maxk = i; k < maxk; k++) { + this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); + } return false; } } } - this.currentIndexes.push(new Integer(((Integer) this.currentIndexes.pop()).intValue() + 1)); } } Annotation[][] annotations = typeReference.annotations; @@ -253,130 +246,230 @@ public abstract class Annotation extends Expression { for (int j = 0; j < annotationsLength; j++) { if (current[j] == this.currentAnnotation) { this.search = false; + for (int k = 0, maxk=typeReference.dimensions; k < maxk; k++) { + this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); + } return false; } } } - //TODO it is unclear how to manage annotations located in the first type arguments - TypeReference[] typeReferences = typeReference.typeArguments[typeReference.typeArguments.length - 1]; - this.currentIndexes.push(new Integer(0)); - for (int i = 0, max = typeReferences.length; i < max; i++) { - typeReferences[i].traverse(this, scope); - if (!this.search) return false; - this.currentIndexes.push(new Integer(((Integer) this.currentIndexes.pop()).intValue() + 1)); - } - this.currentIndexes.pop(); return true; } - public boolean visit(SingleTypeReference typeReference, BlockScope scope) { + + public boolean visit(ParameterizedQualifiedTypeReference typeReference, BlockScope scope) { if (!this.search) return false; - Annotation[][] annotationsOnDimensions = annotationsOnDimensionsOnExpression; + + // Example case handled by this block: java.util.List<String>[]@A[] + Annotation[][] annotationsOnDimensions = typeReference.annotationsOnDimensions; if (annotationsOnDimensions != null) { - // check if the annotation is located on the first dimension - Annotation[] annotations = annotationsOnDimensions[0]; - if (annotations != null) { - for (int j = 0, max2 = annotations.length; j < max2; j++) { - Annotation current = annotations[j]; - if (current == this.currentAnnotation) { - this.search = false; - return false; - } - } - } - - this.currentIndexes.push(new Integer(0)); - for (int i = 1, max = annotationsOnDimensions.length; i < max; i++) { - annotations = annotationsOnDimensions[i]; + for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { + Annotation[] annotations = annotationsOnDimensions[i]; if (annotations != null) { for (int j = 0, max2 = annotations.length; j < max2; j++) { Annotation current = annotations[j]; if (current == this.currentAnnotation) { this.search = false; + // Found it, insert relevant type path elements + for (int k = 0, maxk = i; k < maxk; k++) { + this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); + } return false; } } } - this.currentIndexes.push(new Integer(((Integer) this.currentIndexes.pop()).intValue() + 1)); } } + + boolean[] needsInnerEntryInfo = computeInnerEntryInfo(typeReference); + + // Example cases handled by this block: + // java.util.@A List<String>[][], com.demo.@A Outer.@B Inner<String>, java.util.Map.@A Entry<String,String> Annotation[][] annotations = typeReference.annotations; - int annotationsLevels = annotations == null ? 0 : annotations.length; + if (annotations == null) { + annotations = new Annotation[][] { primaryAnnotation }; + } + int annotationsLevels = annotations.length; for (int i = 0; i < annotationsLevels; i++) { Annotation [] current = annotations[i]; int annotationsLength = current == null ? 0 : current.length; for (int j = 0; j < annotationsLength; j++) { if (current[j] == this.currentAnnotation) { this.search = false; + // Found, insert any relevant type path elements + for (int k = 0, maxk = typeReference.dimensions; k < maxk; k++) { + this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); + } + // Found, insert any relevant type path elements + if (needsInnerEntryInfo != null) { + for (int k = 0; k <= i; k++) { + if (needsInnerEntryInfo[k]) { + this.typePathEntries.push(TYPE_PATH_INNER_TYPE); + } + } + } return false; } } } - return false; + + // Example cases handled by this block: + // java.util.List<@A String> + if (typeReference.dimensions != 0) { + for (int k = 0, maxk = typeReference.dimensions; k < maxk; k++) { + this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); + } + } + int toPop = 0; + for (int i = 0, max = typeReference.typeArguments.length; i < max; i++) { + TypeReference[] typeArgumentsForComponent = typeReference.typeArguments[i]; + if (needsInnerEntryInfo != null && needsInnerEntryInfo[i]) { + this.typePathEntries.push(TYPE_PATH_INNER_TYPE); + toPop++; + } + if (typeArgumentsForComponent != null) { + for (int j = 0, max2 = typeArgumentsForComponent.length; j < max2; j++) { + this.typePathEntries.push(new int[]{3,j}); + typeArgumentsForComponent[j].traverse(this,scope); + if (!this.search) return false; + this.typePathEntries.pop(); + } + } + } + toPop += typeReference.dimensions; + for (int k = 0, maxk = toPop; k < maxk; k++) { + this.typePathEntries.pop(); + } + return true; } + public boolean visit(Wildcard typeReference, BlockScope scope) { if (!this.search) return false; TypeReference bound = typeReference.bound; + this.typePathEntries.push(TYPE_PATH_ANNOTATION_ON_WILDCARD_BOUND); bound.traverse(this, scope); + if (!this.search) { + return false; + } + this.typePathEntries.pop(); return true; } + + private boolean[] computeInnerEntryInfo(QualifiedTypeReference typeReference) { + ReferenceBinding resolvedType = (ReferenceBinding) + (typeReference.resolvedType instanceof ArrayBinding ? typeReference.resolvedType.leafComponentType() : typeReference.resolvedType); + boolean[] needsInnerEntryInfo = null; + if (resolvedType != null && resolvedType.isNestedType()) { + // Work backwards computing whether a INNER_TYPE entry is required for each level + needsInnerEntryInfo = new boolean[typeReference.tokens.length]; + int counter = needsInnerEntryInfo.length - 1; + ReferenceBinding type = resolvedType;//resolvedType.enclosingType(); + while (type != null) { + needsInnerEntryInfo[counter--] = !type.isStatic(); + type = type.enclosingType(); + } + } + return needsInnerEntryInfo; + } + + private int getInnerDepth(ReferenceBinding resolvedType) { + int depth = 0; + ReferenceBinding type = resolvedType; + while (type != null) { + depth += (type.isStatic())?0:1; + type = type.enclosingType(); + } + return depth; + } + public boolean visit(QualifiedTypeReference typeReference, BlockScope scope) { if (!this.search) return false; + boolean[] needsInnerEntryInfo = computeInnerEntryInfo(typeReference); + + // Example cases handled by this block: + // java.util.@A List, com.demo.@A Outer.@B Inner, java.util.Map.@A Entry Annotation[][] annotations = typeReference.annotations; - int annotationsLevels = annotations == null ? 0 : annotations.length; + if (annotations == null) { + annotations = new Annotation[][] { primaryAnnotation }; + } + int annotationsLevels = annotations.length; for (int i = 0; i < annotationsLevels; i++) { Annotation [] current = annotations[i]; int annotationsLength = current == null ? 0 : current.length; for (int j = 0; j < annotationsLength; j++) { if (current[j] == this.currentAnnotation) { this.search = false; + // Found, insert any relevant type path elements + if (needsInnerEntryInfo != null) { + for (int k = 0; k <= i; k++) { + if (needsInnerEntryInfo[k]) { + this.typePathEntries.push(TYPE_PATH_INNER_TYPE); + } + } + } return false; } } } return true; } + public String toString() { StringBuffer buffer = new StringBuffer(); buffer .append("search location for ") //$NON-NLS-1$ .append(this.currentAnnotation) - .append("\ncurrent indexes : ") //$NON-NLS-1$ - .append(this.currentIndexes); + .append("\ncurrent type_path entries : "); //$NON-NLS-1$ + for (int i = 0, maxi = this.typePathEntries.size(); i < maxi; i++) { + int[] typePathEntry = (int[]) this.typePathEntries.get(i); + buffer + .append('(') + .append(typePathEntry[0]) + .append(',') + .append(typePathEntry[1]) + .append(')'); + } return String.valueOf(buffer); } } if (reference == null) return null; LocationCollector collector = new LocationCollector(annotation); reference.traverse(collector, (BlockScope) null); - if (collector.currentIndexes.isEmpty()) { + if (collector.typePathEntries.isEmpty()) { return null; } - int size = collector.currentIndexes.size(); - int[] result = new int[size]; + int size = collector.typePathEntries.size(); + int[] result = new int[size*2]; + int offset=0; for (int i = 0; i < size; i++) { - result[size - i - 1] = ((Integer) collector.currentIndexes.pop()).intValue(); + int[] pathElement = (int[])collector.typePathEntries.get(i); + result[offset++] = pathElement[0]; + result[offset++] = pathElement[1]; } return result; } - - // jsr 308 - public static class TypeUseBinding extends ReferenceBinding { - private int kind; - public TypeUseBinding(int kind) { - this.tagBits = 0L; - this.kind = kind; - } - public int kind() { - return this.kind; - } - public boolean hasTypeBit(int bit) { - return false; - } + + // jsr 308 + public static class TypeUseBinding extends ReferenceBinding { + private int kind; + public TypeUseBinding(int kind) { + this.tagBits = 0L; + this.kind = kind; + } + public int kind() { + return this.kind; } + public boolean hasTypeBit(int bit) { + return false; + } + } final static MemberValuePair[] NoValuePairs = new MemberValuePair[0]; private static final long TAGBITS_NULLABLE_OR_NONNULL = TagBits.AnnotationNullable|TagBits.AnnotationNonNull; + static final int[] TYPE_PATH_ELEMENT_ARRAY = new int[]{0,0}; + static final int[] TYPE_PATH_INNER_TYPE = new int[]{1,0}; + static final int[] TYPE_PATH_ANNOTATION_ON_WILDCARD_BOUND = new int[]{2,0}; + public int declarationSourceEnd; public Binding recipient; |