1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.ASTVisitor;
15 import org.eclipse.jdt.internal.compiler.lookup.*;
20 public abstract class Annotation extends Expression {
22 public TypeReference type;
23 public int declarationSourceEnd;
24 public Binding recipient;
26 final static MemberValuePair[] NoValuePairs = new MemberValuePair[0];
28 public static long getRetentionPolicy(char[] policyName) {
29 if (policyName == null || policyName.length == 0)
31 switch(policyName[0]) {
33 if (CharOperation.equals(policyName, TypeConstants.UPPER_CLASS))
34 return TagBits.AnnotationClassRetention;
37 if (CharOperation.equals(policyName, TypeConstants.UPPER_SOURCE))
38 return TagBits.AnnotationSourceRetention;
41 if (CharOperation.equals(policyName, TypeConstants.UPPER_RUNTIME))
42 return TagBits.AnnotationRuntimeRetention;
48 public static long getTargetElementType(char[] elementName) {
49 if (elementName == null || elementName.length == 0)
51 switch(elementName[0]) {
53 if (CharOperation.equals(elementName, TypeConstants.UPPER_ANNOTATION_TYPE))
54 return TagBits.AnnotationForAnnotationType;
57 if (CharOperation.equals(elementName, TypeConstants.UPPER_CONSTRUCTOR))
58 return TagBits.AnnotationForConstructor;
61 if (CharOperation.equals(elementName, TypeConstants.UPPER_FIELD))
62 return TagBits.AnnotationForField;
65 if (CharOperation.equals(elementName, TypeConstants.UPPER_LOCAL_VARIABLE))
66 return TagBits.AnnotationForLocalVariable;
69 if (CharOperation.equals(elementName, TypeConstants.UPPER_METHOD))
70 return TagBits.AnnotationForMethod;
73 if (CharOperation.equals(elementName, TypeConstants.UPPER_PARAMETER))
74 return TagBits.AnnotationForParameter;
75 else if (CharOperation.equals(elementName, TypeConstants.UPPER_PACKAGE))
76 return TagBits.AnnotationForPackage;
79 if (CharOperation.equals(elementName, TypeConstants.TYPE))
80 return TagBits.AnnotationForType;
87 * Compute the bit pattern for recognized standard annotations the compiler may need to act upon
89 private long detectStandardAnnotation(Scope scope, ReferenceBinding annotationType, MemberValuePair valueAttribute) {
91 switch (annotationType.id) {
92 // retention annotation
93 case TypeIds.T_JavaLangAnnotationRetention :
94 if (valueAttribute != null) {
95 Expression expr = valueAttribute.value;
96 if ((expr.bits & Binding.VARIABLE) == Binding.FIELD) {
97 FieldBinding field = ((Reference)expr).fieldBinding();
98 if (field != null && field.declaringClass.id == T_JavaLangAnnotationRetentionPolicy) {
99 tagBits |= getRetentionPolicy(field.name);
105 case TypeIds.T_JavaLangAnnotationTarget :
106 tagBits |= TagBits.AnnotationTarget; // target specified (could be empty)
107 if (valueAttribute != null) {
108 Expression expr = valueAttribute.value;
109 if (expr instanceof ArrayInitializer) {
110 ArrayInitializer initializer = (ArrayInitializer) expr;
111 final Expression[] expressions = initializer.expressions;
112 if (expressions != null) {
113 for (int i = 0, length = expressions.length; i < length; i++) {
114 Expression initExpr = expressions[i];
115 if ((initExpr.bits & Binding.VARIABLE) == Binding.FIELD) {
116 FieldBinding field = ((Reference) initExpr).fieldBinding();
117 if (field != null && field.declaringClass.id == T_JavaLangAnnotationElementType) {
118 long element = getTargetElementType(field.name);
119 if ((tagBits & element) != 0) {
120 scope.problemReporter().duplicateTargetInTargetAnnotation(annotationType, (NameReference)initExpr);
128 } else if ((expr.bits & Binding.VARIABLE) == Binding.FIELD) {
129 FieldBinding field = ((Reference) expr).fieldBinding();
130 if (field != null && field.declaringClass.id == T_JavaLangAnnotationElementType) {
131 tagBits |= getTargetElementType(field.name);
136 // marker annotations
137 case TypeIds.T_JavaLangDeprecated :
138 tagBits |= TagBits.AnnotationDeprecated;
140 case TypeIds.T_JavaLangAnnotationDocumented :
141 tagBits |= TagBits.AnnotationDocumented;
143 case TypeIds.T_JavaLangAnnotationInherited :
144 tagBits |= TagBits.AnnotationInherited;
146 case TypeIds.T_JavaLangOverride :
147 tagBits |= TagBits.AnnotationOverride;
149 case TypeIds.T_JavaLangSuppressWarnings :
150 tagBits |= TagBits.AnnotationSuppressWarnings;
156 public StringBuffer printExpression(int indent, StringBuffer output) {
158 this.type.printExpression(0, output);
162 public abstract MemberValuePair[] memberValuePairs();
164 public TypeBinding resolveType(BlockScope scope) {
166 this.constant = NotAConstant;
168 TypeBinding typeBinding = this.type.resolveType(scope);
169 if (typeBinding == null)
171 this.resolvedType = typeBinding;
172 // ensure type refers to an annotation type
173 if (!typeBinding.isAnnotationType()) {
174 scope.problemReporter().typeMismatchError(typeBinding, scope.getJavaLangAnnotationAnnotation(), this.type);
178 ReferenceBinding annotationType = (ReferenceBinding) this.resolvedType;
179 MethodBinding[] methods = annotationType.methods();
180 // clone valuePairs to keep track of unused ones
181 MemberValuePair[] valuePairs = memberValuePairs();
182 MemberValuePair valueAttribute = null; // remember the first 'value' pair
183 MemberValuePair[] usedValuePairs;
184 int pairsLength = valuePairs.length;
185 System.arraycopy(valuePairs, 0, usedValuePairs = new MemberValuePair[pairsLength], 0, pairsLength);
187 nextMember: for (int i = 0, requiredLength = methods.length; i < requiredLength; i++) {
188 MethodBinding method = methods[i];
189 char[] selector = method.selector;
190 boolean foundValue = false;
191 nextPair: for (int j = 0; j < pairsLength; j++) {
192 MemberValuePair valuePair = usedValuePairs[j];
193 if (valuePair == null) continue nextPair;
194 char[] memberName = valuePair.name;
195 if (CharOperation.equals(memberName, selector)) {
196 if (valueAttribute == null && CharOperation.equals(memberName, TypeConstants.VALUE)) {
197 valueAttribute = valuePair;
199 valuePair.binding = method;
200 usedValuePairs[j] = null; // consumed
202 boolean foundDuplicate = false;
203 for (int k = j+1; k < pairsLength; k++) {
204 if (CharOperation.equals(usedValuePairs[k].name, selector)) {
205 foundDuplicate = true;
206 scope.problemReporter().duplicateAnnotationValue(annotationType, usedValuePairs[k]);
207 usedValuePairs[k].binding = method;
208 usedValuePairs[k] = null;
211 if (foundDuplicate) {
212 scope.problemReporter().duplicateAnnotationValue(annotationType, valuePair);
215 valuePair.resolveTypeExpecting(scope, method.returnType);
218 if (!foundValue && (method.modifiers & AccAnnotationDefault) == 0) {
219 scope.problemReporter().missingValueForAnnotationMember(this, method.selector);
222 // check unused pairs
223 for (int i = 0; i < pairsLength; i++) {
224 if (usedValuePairs[i] != null) {
225 scope.problemReporter().undefinedAnnotationValue(annotationType, usedValuePairs[i]);
228 // recognize standard annotations ?
229 long tagBits = detectStandardAnnotation(scope, annotationType, valueAttribute);
230 if (this.recipient != null) {
232 // tag bits onto recipient
233 switch (this.recipient.kind()) {
234 case Binding.PACKAGE :
235 // TODO (philippe) need support for package annotations
238 case Binding.GENERIC_TYPE :
239 case Binding.TYPE_PARAMETER :
240 ((ReferenceBinding)this.recipient).tagBits |= tagBits;
242 case Binding.METHOD :
243 ((MethodBinding)this.recipient).tagBits |= tagBits;
246 ((FieldBinding)this.recipient).tagBits |= tagBits;
249 ((LocalVariableBinding)this.recipient).tagBits |= tagBits;
253 // check (meta)target compatibility
254 checkTargetCompatibility: {
255 long metaTagBits = annotationType.getAnnotationTagBits();
256 if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) // does not specify any target restriction
257 break checkTargetCompatibility;
259 switch (recipient.kind()) {
260 case Binding.PACKAGE :
261 if ((metaTagBits & TagBits.AnnotationForPackage) != 0)
262 break checkTargetCompatibility;
265 case Binding.GENERIC_TYPE :
266 if (((ReferenceBinding)this.recipient).isAnnotationType()) {
267 if ((metaTagBits & (TagBits.AnnotationForAnnotationType|TagBits.AnnotationForType)) != 0)
268 break checkTargetCompatibility;
269 } else if ((metaTagBits & TagBits.AnnotationForType) != 0)
270 break checkTargetCompatibility;
272 case Binding.METHOD :
273 if (((MethodBinding)this.recipient).isConstructor()) {
274 if ((metaTagBits & TagBits.AnnotationForConstructor) != 0)
275 break checkTargetCompatibility;
276 } else if ((metaTagBits & TagBits.AnnotationForMethod) != 0)
277 break checkTargetCompatibility;
280 if ((metaTagBits & TagBits.AnnotationForField) != 0)
281 break checkTargetCompatibility;
284 if (((LocalVariableBinding)this.recipient).isArgument) {
285 if ((metaTagBits & TagBits.AnnotationForParameter) != 0)
286 break checkTargetCompatibility;
287 } else if ((annotationType.tagBits & TagBits.AnnotationForLocalVariable) != 0)
288 break checkTargetCompatibility;
291 scope.problemReporter().disallowedTargetForAnnotation(this);
294 return this.resolvedType;
297 public abstract void traverse(ASTVisitor visitor, BlockScope scope);
298 public abstract void traverse(ASTVisitor visitor, CompilationUnitScope scope);