blob: 594474d7a14980704b6ca7593f8244d22005307d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
import java.util.Stack;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.impl.IrritantSet;
import org.eclipse.jdt.internal.compiler.lookup.*;
/**
* Annotation
*/
public abstract class Annotation extends Expression {
/**
* Return the location for the corresponding annotation inside the type reference, <code>null</code> if none.
*/
public static int[] getLocations(
final TypeReference reference,
final Annotation[] primaryAnnotation,
final Annotation annotation,
final Annotation[][] annotationsOnDimensionsOnExpression) {
class LocationCollector extends ASTVisitor {
Stack currentIndexes;
Annotation currentAnnotation;
boolean search = true;
public LocationCollector(Annotation currentAnnotation) {
this.currentIndexes = new Stack();
this.currentAnnotation = currentAnnotation;
}
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];
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));
}
}
Annotation[] annotations = typeReference.annotations;
if (annotations == null) {
annotations = primaryAnnotation;
}
if (annotations != null) {
for (int i = 0; i < annotations.length; i++) {
Annotation current = annotations[i];
if (current == this.currentAnnotation) {
this.search = false;
return false;
}
}
}
this.currentIndexes.pop();
return true;
}
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];
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));
}
}
Annotation[] annotations = typeReference.annotations;
if (annotations == null) {
annotations = primaryAnnotation;
}
if (annotations != null) {
for (int i = 0; i < annotations.length; i++) {
Annotation current = annotations[i];
if (current == this.currentAnnotation) {
this.search = false;
return false;
}
}
}
this.currentIndexes.pop();
return true;
}
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];
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));
}
}
Annotation[] annotations = typeReference.annotations;
if (annotations == null) {
annotations = primaryAnnotation;
}
if (annotations != null) {
for (int i = 0; i < annotations.length; i++) {
Annotation current = annotations[i];
if (current == this.currentAnnotation) {
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) {
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));
}
}
Annotation[] annotations = typeReference.annotations;
if (annotations == null) {
annotations = primaryAnnotation;
}
if (annotations != null) {
for (int i = 0; i < annotations.length; i++) {
Annotation current = annotations[i];
if (current == this.currentAnnotation) {
this.search = false;
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) {
if (!this.search) return false;
Annotation[][] annotationsOnDimensions = annotationsOnDimensionsOnExpression;
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));
}
}
Annotation[] annotations = typeReference.annotations;
if (annotations != null) {
for (int i = 0; i < annotations.length; i++) {
Annotation current = annotations[i];
if (current == this.currentAnnotation) {
this.search = false;
return false;
}
}
}
return false;
}
public boolean visit(Wildcard typeReference, BlockScope scope) {
if (!this.search) return false;
TypeReference bound = typeReference.bound;
bound.traverse(this, scope);
return true;
}
public boolean visit(QualifiedTypeReference typeReference, BlockScope scope) {
if (!this.search) return false;
Annotation[] annotations = typeReference.annotations;
if (annotations != null) {
for (int i = 0; i < annotations.length; i++) {
Annotation current = annotations[i];
if (current == this.currentAnnotation) {
this.search = false;
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);
return String.valueOf(buffer);
}
}
if (reference == null) return null;
LocationCollector collector = new LocationCollector(annotation);
reference.traverse(collector, (BlockScope) null);
if (collector.currentIndexes.isEmpty()) {
return null;
}
int size = collector.currentIndexes.size();
int[] result = new int[size];
for (int i = 0; i < size; i++) {
result[size - i - 1] = ((Integer) collector.currentIndexes.pop()).intValue();
}
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;
}
}
final static MemberValuePair[] NoValuePairs = new MemberValuePair[0];
public int declarationSourceEnd;
public Binding recipient;
public TypeReference type;
/**
* The representation of this annotation in the type system.
*/
private AnnotationBinding compilerAnnotation = null;
public static long getRetentionPolicy(char[] policyName) {
if (policyName == null || policyName.length == 0)
return 0;
switch(policyName[0]) {
case 'C' :
if (CharOperation.equals(policyName, TypeConstants.UPPER_CLASS))
return TagBits.AnnotationClassRetention;
break;
case 'S' :
if (CharOperation.equals(policyName, TypeConstants.UPPER_SOURCE))
return TagBits.AnnotationSourceRetention;
break;
case 'R' :
if (CharOperation.equals(policyName, TypeConstants.UPPER_RUNTIME))
return TagBits.AnnotationRuntimeRetention;
break;
}
return 0; // unknown
}
public static long getTargetElementType(char[] elementName) {
if (elementName == null || elementName.length == 0)
return 0;
switch(elementName[0]) {
case 'A' :
if (CharOperation.equals(elementName, TypeConstants.UPPER_ANNOTATION_TYPE))
return TagBits.AnnotationForAnnotationType;
break;
case 'C' :
if (CharOperation.equals(elementName, TypeConstants.UPPER_CONSTRUCTOR))
return TagBits.AnnotationForConstructor;
break;
case 'F' :
if (CharOperation.equals(elementName, TypeConstants.UPPER_FIELD))
return TagBits.AnnotationForField;
break;
case 'L' :
if (CharOperation.equals(elementName, TypeConstants.UPPER_LOCAL_VARIABLE))
return TagBits.AnnotationForLocalVariable;
break;
case 'M' :
if (CharOperation.equals(elementName, TypeConstants.UPPER_METHOD))
return TagBits.AnnotationForMethod;
break;
case 'P' :
if (CharOperation.equals(elementName, TypeConstants.UPPER_PARAMETER))
return TagBits.AnnotationForParameter;
else if (CharOperation.equals(elementName, TypeConstants.UPPER_PACKAGE))
return TagBits.AnnotationForPackage;
break;
case 'T' :
if (CharOperation.equals(elementName, TypeConstants.TYPE))
return TagBits.AnnotationForType;
if (CharOperation.equals(elementName, TypeConstants.TYPE_USE_TARGET))
return TagBits.AnnotationForTypeUse;
if (CharOperation.equals(elementName, TypeConstants.TYPE_PARAMETER_TARGET))
return TagBits.AnnotationForTypeParameter;
break;
}
return 0; // unknown
}
public ElementValuePair[] computeElementValuePairs() {
return Binding.NO_ELEMENT_VALUE_PAIRS;
}
/**
* Compute the bit pattern for recognized standard annotations the compiler may need to act upon
*/
private long detectStandardAnnotation(Scope scope, ReferenceBinding annotationType, MemberValuePair valueAttribute) {
long tagBits = 0;
switch (annotationType.id) {
// retention annotation
case TypeIds.T_JavaLangAnnotationRetention :
if (valueAttribute != null) {
Expression expr = valueAttribute.value;
if ((expr.bits & Binding.VARIABLE) == Binding.FIELD) {
FieldBinding field = ((Reference)expr).fieldBinding();
if (field != null && field.declaringClass.id == T_JavaLangAnnotationRetentionPolicy) {
tagBits |= getRetentionPolicy(field.name);
}
}
}
break;
// target annotation
case TypeIds.T_JavaLangAnnotationTarget :
tagBits |= TagBits.AnnotationTarget; // target specified (could be empty)
if (valueAttribute != null) {
Expression expr = valueAttribute.value;
if (expr instanceof ArrayInitializer) {
ArrayInitializer initializer = (ArrayInitializer) expr;
final Expression[] expressions = initializer.expressions;
if (expressions != null) {
for (int i = 0, length = expressions.length; i < length; i++) {
Expression initExpr = expressions[i];
if ((initExpr.bits & Binding.VARIABLE) == Binding.FIELD) {
FieldBinding field = ((Reference) initExpr).fieldBinding();
if (field != null && field.declaringClass.id == T_JavaLangAnnotationElementType) {
long element = getTargetElementType(field.name);
if ((tagBits & element) != 0) {
scope.problemReporter().duplicateTargetInTargetAnnotation(annotationType, (NameReference)initExpr);
} else {
tagBits |= element;
}
}
}
}
}
} else if ((expr.bits & Binding.VARIABLE) == Binding.FIELD) {
FieldBinding field = ((Reference) expr).fieldBinding();
if (field != null && field.declaringClass.id == T_JavaLangAnnotationElementType) {
tagBits |= getTargetElementType(field.name);
}
}
}
break;
// marker annotations
case TypeIds.T_JavaLangDeprecated :
tagBits |= TagBits.AnnotationDeprecated;
break;
case TypeIds.T_JavaLangAnnotationDocumented :
tagBits |= TagBits.AnnotationDocumented;
break;
case TypeIds.T_JavaLangAnnotationInherited :
tagBits |= TagBits.AnnotationInherited;
break;
case TypeIds.T_JavaLangOverride :
tagBits |= TagBits.AnnotationOverride;
break;
case TypeIds.T_JavaLangSuppressWarnings :
tagBits |= TagBits.AnnotationSuppressWarnings;
break;
}
return tagBits;
}
public AnnotationBinding getCompilerAnnotation() {
return this.compilerAnnotation;
}
public boolean isRuntimeInvisible() {
final TypeBinding annotationBinding = this.resolvedType;
if (annotationBinding == null) {
return false;
}
long metaTagBits = annotationBinding.getAnnotationTagBits(); // could be forward reference
// jsr 308
// we need to filter out type use and type parameter annotations
if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) != 0) {
return false;
}
if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0)
return true; // by default the retention is CLASS
return (metaTagBits & TagBits.AnnotationRetentionMASK) == TagBits.AnnotationClassRetention;
}
public boolean isRuntimeTypeInvisible() {
final TypeBinding annotationBinding = this.resolvedType;
if (annotationBinding == null) {
return false;
}
long metaTagBits = annotationBinding.getAnnotationTagBits(); // could be forward reference
// jsr 308
// we need to filter out type use and type parameter annotations
if ((metaTagBits & (TagBits.AnnotationTargetMASK)) != 0
&& ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) == 0)) {
return false;
}
if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0)
return true; // by default the retention is CLASS
return (metaTagBits & TagBits.AnnotationRetentionMASK) == TagBits.AnnotationClassRetention;
}
public boolean isRuntimeTypeVisible() {
final TypeBinding annotationBinding = this.resolvedType;
if (annotationBinding == null) {
return false;
}
long metaTagBits = annotationBinding.getAnnotationTagBits();
if ((metaTagBits & (TagBits.AnnotationTargetMASK)) != 0
&& ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) == 0)) {
return false;
}
if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0)
return false; // by default the retention is CLASS
return (metaTagBits & TagBits.AnnotationRetentionMASK) == TagBits.AnnotationRuntimeRetention;
}
public boolean isRuntimeVisible() {
final TypeBinding annotationBinding = this.resolvedType;
if (annotationBinding == null) {
return false;
}
long metaTagBits = annotationBinding.getAnnotationTagBits();
if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) != 0) {
return false;
}
if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0)
return false; // by default the retention is CLASS
return (metaTagBits & TagBits.AnnotationRetentionMASK) == TagBits.AnnotationRuntimeRetention;
}
public abstract MemberValuePair[] memberValuePairs();
public StringBuffer printExpression(int indent, StringBuffer output) {
output.append('@');
this.type.printExpression(0, output);
return output;
}
public void recordSuppressWarnings(Scope scope, int startSuppresss, int endSuppress, boolean isSuppressingWarnings) {
IrritantSet suppressWarningIrritants = null;
MemberValuePair[] pairs = memberValuePairs();
pairLoop: for (int i = 0, length = pairs.length; i < length; i++) {
MemberValuePair pair = pairs[i];
if (CharOperation.equals(pair.name, TypeConstants.VALUE)) {
Expression value = pair.value;
if (value instanceof ArrayInitializer) {
ArrayInitializer initializer = (ArrayInitializer) value;
Expression[] inits = initializer.expressions;
if (inits != null) {
for (int j = 0, initsLength = inits.length; j < initsLength; j++) {
Constant cst = inits[j].constant;
if (cst != Constant.NotAConstant && cst.typeID() == T_JavaLangString) {
IrritantSet irritants = CompilerOptions.warningTokenToIrritants(cst.stringValue());
if (irritants != null) {
if (suppressWarningIrritants == null) {
suppressWarningIrritants = new IrritantSet(irritants);
} else if (suppressWarningIrritants.set(irritants) == null) {
scope.problemReporter().unusedWarningToken(inits[j]);
}
} else {
scope.problemReporter().unhandledWarningToken(inits[j]);
}
}
}
}
} else {
Constant cst = value.constant;
if (cst != Constant.NotAConstant && cst.typeID() == T_JavaLangString) {
IrritantSet irritants = CompilerOptions.warningTokenToIrritants(cst.stringValue());
if (irritants != null) {
suppressWarningIrritants = new IrritantSet(irritants);
// TODO: should check for unused warning token against enclosing annotation as well ?
} else {
scope.problemReporter().unhandledWarningToken(value);
}
}
}
break pairLoop;
}
}
if (isSuppressingWarnings && suppressWarningIrritants != null) {
scope.referenceCompilationUnit().recordSuppressWarnings(suppressWarningIrritants, this, startSuppresss, endSuppress);
}
}
public TypeBinding resolveType(BlockScope scope) {
if (this.compilerAnnotation != null)
return this.resolvedType;
this.constant = Constant.NotAConstant;
TypeBinding typeBinding = this.type.resolveType(scope);
if (typeBinding == null) {
return null;
}
this.resolvedType = typeBinding;
// ensure type refers to an annotation type
if (!typeBinding.isAnnotationType() && typeBinding.isValidBinding()) {
scope.problemReporter().typeMismatchError(typeBinding, scope.getJavaLangAnnotationAnnotation(), this.type, null);
return null;
}
ReferenceBinding annotationType = (ReferenceBinding) this.resolvedType;
MethodBinding[] methods = annotationType.methods();
// clone valuePairs to keep track of unused ones
MemberValuePair[] originalValuePairs = memberValuePairs();
MemberValuePair valueAttribute = null; // remember the first 'value' pair
MemberValuePair[] pairs;
int pairsLength = originalValuePairs.length;
if (pairsLength > 0) {
System.arraycopy(originalValuePairs, 0, pairs = new MemberValuePair[pairsLength], 0, pairsLength);
} else {
pairs = originalValuePairs;
}
nextMember: for (int i = 0, requiredLength = methods.length; i < requiredLength; i++) {
MethodBinding method = methods[i];
char[] selector = method.selector;
boolean foundValue = false;
nextPair: for (int j = 0; j < pairsLength; j++) {
MemberValuePair pair = pairs[j];
if (pair == null) continue nextPair;
char[] name = pair.name;
if (CharOperation.equals(name, selector)) {
if (valueAttribute == null && CharOperation.equals(name, TypeConstants.VALUE)) {
valueAttribute = pair;
}
pair.binding = method;
pair.resolveTypeExpecting(scope, method.returnType);
pairs[j] = null; // consumed
foundValue = true;
// check duplicates
boolean foundDuplicate = false;
for (int k = j+1; k < pairsLength; k++) {
MemberValuePair otherPair = pairs[k];
if (otherPair == null) continue;
if (CharOperation.equals(otherPair.name, selector)) {
foundDuplicate = true;
scope.problemReporter().duplicateAnnotationValue(annotationType, otherPair);
otherPair.binding = method;
otherPair.resolveTypeExpecting(scope, method.returnType);
pairs[k] = null;
}
}
if (foundDuplicate) {
scope.problemReporter().duplicateAnnotationValue(annotationType, pair);
continue nextMember;
}
}
}
if (!foundValue
&& (method.modifiers & ClassFileConstants.AccAnnotationDefault) == 0
&& (this.bits & IsRecovered) == 0
&& annotationType.isValidBinding()) {
scope.problemReporter().missingValueForAnnotationMember(this, selector);
}
}
// check unused pairs
for (int i = 0; i < pairsLength; i++) {
if (pairs[i] != null) {
if (annotationType.isValidBinding()) {
scope.problemReporter().undefinedAnnotationValue(annotationType, pairs[i]);
}
pairs[i].resolveTypeExpecting(scope, null); // resilient
}
}
// if (scope.compilerOptions().storeAnnotations)
this.compilerAnnotation = scope.environment().createAnnotation((ReferenceBinding) this.resolvedType, computeElementValuePairs());
// recognize standard annotations ?
long tagBits = detectStandardAnnotation(scope, annotationType, valueAttribute);
// record annotation positions in the compilation result
scope.referenceCompilationUnit().recordSuppressWarnings(IrritantSet.NLS, null, this.sourceStart, this.declarationSourceEnd);
if (this.recipient != null) {
if (tagBits != 0) {
// tag bits onto recipient
switch (this.recipient.kind()) {
case Binding.PACKAGE :
((PackageBinding)this.recipient).tagBits |= tagBits;
break;
case Binding.TYPE :
case Binding.GENERIC_TYPE :
SourceTypeBinding sourceType = (SourceTypeBinding) this.recipient;
sourceType.tagBits |= tagBits;
if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
TypeDeclaration typeDeclaration = sourceType.scope.referenceContext;
int start;
if (scope.referenceCompilationUnit().types[0] == typeDeclaration) {
start = 0;
} else {
start = typeDeclaration.declarationSourceStart;
}
recordSuppressWarnings(scope, start, typeDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
}
break;
case Binding.METHOD :
MethodBinding sourceMethod = (MethodBinding) this.recipient;
sourceMethod.tagBits |= tagBits;
if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
sourceType = (SourceTypeBinding) sourceMethod.declaringClass;
AbstractMethodDeclaration methodDeclaration = sourceType.scope.referenceContext.declarationOf(sourceMethod);
recordSuppressWarnings(scope, methodDeclaration.declarationSourceStart, methodDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
}
break;
case Binding.FIELD :
FieldBinding sourceField = (FieldBinding) this.recipient;
sourceField.tagBits |= tagBits;
if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
sourceType = (SourceTypeBinding) sourceField.declaringClass;
FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(sourceField);
recordSuppressWarnings(scope, fieldDeclaration.declarationSourceStart, fieldDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
}
break;
case Binding.LOCAL :
LocalVariableBinding variable = (LocalVariableBinding) this.recipient;
variable.tagBits |= tagBits;
if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
LocalDeclaration localDeclaration = variable.declaration;
recordSuppressWarnings(scope, localDeclaration.declarationSourceStart, localDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
}
break;
}
}
// check (meta)target compatibility
checkTargetCompatibility: {
if (!annotationType.isValidBinding()) {
// no need to check annotation usage if missing
break checkTargetCompatibility;
}
long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference
if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) {
// does not specify any target restriction - all locations are possible including type annotations
break checkTargetCompatibility;
}
switch (this.recipient.kind()) {
case Binding.PACKAGE :
if ((metaTagBits & TagBits.AnnotationForPackage) != 0)
break checkTargetCompatibility;
break;
case Binding.TYPE_USE :
if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
// jsr 308
break checkTargetCompatibility;
}
break;
case Binding.TYPE :
case Binding.GENERIC_TYPE :
if (((ReferenceBinding)this.recipient).isAnnotationType()) {
if ((metaTagBits & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType)) != 0)
break checkTargetCompatibility;
} else if ((metaTagBits & TagBits.AnnotationForType) != 0) {
break checkTargetCompatibility;
} else if ((metaTagBits & TagBits.AnnotationForPackage) != 0) {
if (CharOperation.equals(((ReferenceBinding)this.recipient).sourceName, TypeConstants.PACKAGE_INFO_NAME))
break checkTargetCompatibility;
}
break;
case Binding.METHOD :
MethodBinding methodBinding = (MethodBinding) this.recipient;
if (methodBinding.isConstructor()) {
if ((metaTagBits & TagBits.AnnotationForConstructor) != 0)
break checkTargetCompatibility;
} else if ((metaTagBits & TagBits.AnnotationForMethod) != 0) {
break checkTargetCompatibility;
} else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
// jsr 308 - annotation on method return type
if (methodBinding.returnType != null && methodBinding.returnType.id == T_void) {
scope.problemReporter().illegalUsageOfTypeAnnotations(this);
}
break checkTargetCompatibility;
}
break;
case Binding.FIELD :
if ((metaTagBits & TagBits.AnnotationForField) != 0) {
break checkTargetCompatibility;
} else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
// jsr 308 - annotation on field type
break checkTargetCompatibility;
}
break;
case Binding.LOCAL :
if ((((LocalVariableBinding)this.recipient).tagBits & TagBits.IsArgument) != 0) {
if ((metaTagBits & TagBits.AnnotationForParameter) != 0) {
break checkTargetCompatibility;
} else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
// jsr 308 - annotation on method parameter type
break checkTargetCompatibility;
}
} else if ((annotationType.tagBits & TagBits.AnnotationForLocalVariable) != 0) {
break checkTargetCompatibility;
} else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
// jsr 308 - annotation on local type
break checkTargetCompatibility;
}
break;
case Binding.TYPE_PARAMETER : // jsr308
if ((metaTagBits & TagBits.AnnotationForTypeParameter) != 0) {
break checkTargetCompatibility;
}
}
scope.problemReporter().disallowedTargetForAnnotation(this);
}
}
return this.resolvedType;
}
public abstract void traverse(ASTVisitor visitor, BlockScope scope);
public abstract void traverse(ASTVisitor visitor, ClassScope scope);
}