KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > ast > Annotation


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.compiler.ast;
12
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.ASTVisitor;
15 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
16 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
17 import org.eclipse.jdt.internal.compiler.impl.Constant;
18 import org.eclipse.jdt.internal.compiler.lookup.*;
19
20 /**
21  * Annotation
22  */

23 public abstract class Annotation extends Expression {
24     
25     final static MemberValuePair[] NoValuePairs = new MemberValuePair[0];
26     public int declarationSourceEnd;
27     public Binding recipient;
28     
29     public TypeReference type;
30     /**
31      * The representation of this annotation in the type system.
32      */

33     private AnnotationBinding compilerAnnotation = null;
34     
35     public static long getRetentionPolicy(char[] policyName) {
36         if (policyName == null || policyName.length == 0)
37             return 0;
38         switch(policyName[0]) {
39             case 'C' :
40                 if (CharOperation.equals(policyName, TypeConstants.UPPER_CLASS))
41                     return TagBits.AnnotationClassRetention;
42                 break;
43             case 'S' :
44                 if (CharOperation.equals(policyName, TypeConstants.UPPER_SOURCE))
45                     return TagBits.AnnotationSourceRetention;
46                 break;
47             case 'R' :
48                 if (CharOperation.equals(policyName, TypeConstants.UPPER_RUNTIME))
49                     return TagBits.AnnotationRuntimeRetention;
50                 break;
51         }
52         return 0; // unknown
53
}
54     
55     public static long getTargetElementType(char[] elementName) {
56         if (elementName == null || elementName.length == 0)
57             return 0;
58         switch(elementName[0]) {
59             case 'A' :
60                 if (CharOperation.equals(elementName, TypeConstants.UPPER_ANNOTATION_TYPE))
61                     return TagBits.AnnotationForAnnotationType;
62                 break;
63             case 'C' :
64                 if (CharOperation.equals(elementName, TypeConstants.UPPER_CONSTRUCTOR))
65                     return TagBits.AnnotationForConstructor;
66                 break;
67             case 'F' :
68                 if (CharOperation.equals(elementName, TypeConstants.UPPER_FIELD))
69                     return TagBits.AnnotationForField;
70                 break;
71             case 'L' :
72                 if (CharOperation.equals(elementName, TypeConstants.UPPER_LOCAL_VARIABLE))
73                     return TagBits.AnnotationForLocalVariable;
74                 break;
75             case 'M' :
76                 if (CharOperation.equals(elementName, TypeConstants.UPPER_METHOD))
77                     return TagBits.AnnotationForMethod;
78                 break;
79             case 'P' :
80                 if (CharOperation.equals(elementName, TypeConstants.UPPER_PARAMETER))
81                     return TagBits.AnnotationForParameter;
82                 else if (CharOperation.equals(elementName, TypeConstants.UPPER_PACKAGE))
83                     return TagBits.AnnotationForPackage;
84                 break;
85             case 'T' :
86                 if (CharOperation.equals(elementName, TypeConstants.TYPE))
87                     return TagBits.AnnotationForType;
88                 break;
89         }
90         return 0; // unknown
91
}
92
93     public ElementValuePair[] computeElementValuePairs() {
94         return Binding.NO_ELEMENT_VALUE_PAIRS;
95     }
96
97     /**
98      * Compute the bit pattern for recognized standard annotations the compiler may need to act upon
99      */

100     private long detectStandardAnnotation(Scope scope, ReferenceBinding annotationType, MemberValuePair valueAttribute) {
101         long tagBits = 0;
102         switch (annotationType.id) {
103             // retention annotation
104
case TypeIds.T_JavaLangAnnotationRetention :
105                 if (valueAttribute != null) {
106                     Expression expr = valueAttribute.value;
107                     if ((expr.bits & Binding.VARIABLE) == Binding.FIELD) {
108                         FieldBinding field = ((Reference)expr).fieldBinding();
109                         if (field != null && field.declaringClass.id == T_JavaLangAnnotationRetentionPolicy) {
110                             tagBits |= getRetentionPolicy(field.name);
111                         }
112                     }
113                 }
114                 break;
115             // target annotation
116
case TypeIds.T_JavaLangAnnotationTarget :
117                 tagBits |= TagBits.AnnotationTarget; // target specified (could be empty)
118
if (valueAttribute != null) {
119                     Expression expr = valueAttribute.value;
120                     if (expr instanceof ArrayInitializer) {
121                         ArrayInitializer initializer = (ArrayInitializer) expr;
122                         final Expression[] expressions = initializer.expressions;
123                         if (expressions != null) {
124                             for (int i = 0, length = expressions.length; i < length; i++) {
125                                 Expression initExpr = expressions[i];
126                                 if ((initExpr.bits & Binding.VARIABLE) == Binding.FIELD) {
127                                     FieldBinding field = ((Reference) initExpr).fieldBinding();
128                                     if (field != null && field.declaringClass.id == T_JavaLangAnnotationElementType) {
129                                         long element = getTargetElementType(field.name);
130                                         if ((tagBits & element) != 0) {
131                                             scope.problemReporter().duplicateTargetInTargetAnnotation(annotationType, (NameReference)initExpr);
132                                         } else {
133                                             tagBits |= element;
134                                         }
135                                     }
136                                 }
137                             }
138                         }
139                     } else if ((expr.bits & Binding.VARIABLE) == Binding.FIELD) {
140                         FieldBinding field = ((Reference) expr).fieldBinding();
141                         if (field != null && field.declaringClass.id == T_JavaLangAnnotationElementType) {
142                             tagBits |= getTargetElementType(field.name);
143                         }
144                     }
145                 }
146                 break;
147             // marker annotations
148
case TypeIds.T_JavaLangDeprecated :
149                 tagBits |= TagBits.AnnotationDeprecated;
150                 break;
151             case TypeIds.T_JavaLangAnnotationDocumented :
152                 tagBits |= TagBits.AnnotationDocumented;
153                 break;
154             case TypeIds.T_JavaLangAnnotationInherited :
155                 tagBits |= TagBits.AnnotationInherited;
156                 break;
157             case TypeIds.T_JavaLangOverride :
158                 tagBits |= TagBits.AnnotationOverride;
159                 break;
160             case TypeIds.T_JavaLangSuppressWarnings :
161                 tagBits |= TagBits.AnnotationSuppressWarnings;
162                 break;
163         }
164         return tagBits;
165     }
166
167     public AnnotationBinding getCompilerAnnotation() {
168         return this.compilerAnnotation;
169     }
170
171     public abstract MemberValuePair[] memberValuePairs();
172     
173     public StringBuffer JavaDoc printExpression(int indent, StringBuffer JavaDoc output) {
174         output.append('@');
175         this.type.printExpression(0, output);
176         return output;
177     }
178     
179     public void recordSuppressWarnings(Scope scope, int startSuppresss, int endSuppress, boolean isSuppressingWarnings) {
180         long suppressWarningIrritants = 0;
181         MemberValuePair[] pairs = this.memberValuePairs();
182         pairLoop: for (int i = 0, length = pairs.length; i < length; i++) {
183             MemberValuePair pair = pairs[i];
184             if (CharOperation.equals(pair.name, TypeConstants.VALUE)) {
185                 Expression value = pair.value;
186                 if (value instanceof ArrayInitializer) {
187                     ArrayInitializer initializer = (ArrayInitializer) value;
188                     Expression[] inits = initializer.expressions;
189                     if (inits != null) {
190                         for (int j = 0, initsLength = inits.length; j < initsLength; j++) {
191                             Constant cst = inits[j].constant;
192                             if (cst != Constant.NotAConstant && cst.typeID() == T_JavaLangString) {
193                                 long irritant = CompilerOptions.warningTokenToIrritant(cst.stringValue());
194                                 if (irritant != 0) {
195                                     suppressWarningIrritants |= irritant;
196                                     if (~suppressWarningIrritants == 0) break pairLoop;
197                                 } else {
198                                     scope.problemReporter().unhandledWarningToken(inits[j]);
199                                 }
200                             }
201                         }
202                     }
203                 } else {
204                     Constant cst = value.constant;
205                     if (cst != Constant.NotAConstant && cst.typeID() == T_JavaLangString) {
206                         long irritant = CompilerOptions.warningTokenToIrritant(cst.stringValue());
207                         if (irritant != 0) {
208                             suppressWarningIrritants |= irritant;
209                             if (~suppressWarningIrritants == 0) break pairLoop;
210                         } else {
211                             scope.problemReporter().unhandledWarningToken(value);
212                         }
213                     }
214                 }
215                 break pairLoop;
216             }
217         }
218         if (isSuppressingWarnings && suppressWarningIrritants != 0) {
219             scope.referenceCompilationUnit().compilationResult.recordSuppressWarnings(suppressWarningIrritants, startSuppresss, endSuppress);
220         }
221     }
222     
223     public TypeBinding resolveType(BlockScope scope) {
224
225         if (this.compilerAnnotation != null)
226             return this.resolvedType;
227         this.constant = Constant.NotAConstant;
228         
229         TypeBinding typeBinding = this.type.resolveType(scope);
230         if (typeBinding == null) {
231             return null;
232         }
233         this.resolvedType = typeBinding;
234         // ensure type refers to an annotation type
235
if (!typeBinding.isAnnotationType()) {
236             scope.problemReporter().typeMismatchError(typeBinding, scope.getJavaLangAnnotationAnnotation(), this.type);
237             return null;
238         }
239
240         ReferenceBinding annotationType = (ReferenceBinding) this.resolvedType;
241         MethodBinding[] methods = annotationType.methods();
242         // clone valuePairs to keep track of unused ones
243
MemberValuePair[] originalValuePairs = memberValuePairs();
244         MemberValuePair valueAttribute = null; // remember the first 'value' pair
245
MemberValuePair[] pairs;
246         int pairsLength = originalValuePairs.length;
247         if (pairsLength > 0) {
248             System.arraycopy(originalValuePairs, 0, pairs = new MemberValuePair[pairsLength], 0, pairsLength);
249         } else {
250             pairs = originalValuePairs;
251         }
252         
253         nextMember: for (int i = 0, requiredLength = methods.length; i < requiredLength; i++) {
254             MethodBinding method = methods[i];
255             char[] selector = method.selector;
256             boolean foundValue = false;
257             nextPair: for (int j = 0; j < pairsLength; j++) {
258                 MemberValuePair pair = pairs[j];
259                 if (pair == null) continue nextPair;
260                 char[] name = pair.name;
261                 if (CharOperation.equals(name, selector)) {
262                     if (valueAttribute == null && CharOperation.equals(name, TypeConstants.VALUE)) {
263                         valueAttribute = pair;
264                     }
265                     pair.binding = method;
266                     pair.resolveTypeExpecting(scope, method.returnType);
267                     pairs[j] = null; // consumed
268
foundValue = true;
269                     
270                     // check duplicates
271
boolean foundDuplicate = false;
272                     for (int k = j+1; k < pairsLength; k++) {
273                         MemberValuePair otherPair = pairs[k];
274                         if (otherPair == null) continue;
275                         if (CharOperation.equals(otherPair.name, selector)) {
276                             foundDuplicate = true;
277                             scope.problemReporter().duplicateAnnotationValue(annotationType, otherPair);
278                             otherPair.binding = method;
279                             otherPair.resolveTypeExpecting(scope, method.returnType);
280                             pairs[k] = null;
281                         }
282                     }
283                     if (foundDuplicate) {
284                         scope.problemReporter().duplicateAnnotationValue(annotationType, pair);
285                         continue nextMember;
286                     }
287                 }
288             }
289             if (!foundValue && (method.modifiers & ClassFileConstants.AccAnnotationDefault) == 0) {
290                 scope.problemReporter().missingValueForAnnotationMember(this, selector);
291             }
292         }
293         // check unused pairs
294
for (int i = 0; i < pairsLength; i++) {
295             if (pairs[i] != null) {
296                 scope.problemReporter().undefinedAnnotationValue(annotationType, pairs[i]);
297                 pairs[i].resolveTypeExpecting(scope, null); // resilient
298
}
299         }
300 // if (scope.compilerOptions().storeAnnotations)
301
this.compilerAnnotation = scope.environment().createAnnotation((ReferenceBinding) this.resolvedType, this.computeElementValuePairs());
302         // recognize standard annotations ?
303
long tagBits = detectStandardAnnotation(scope, annotationType, valueAttribute);
304
305         // record annotation positions in the compilation result
306
scope.referenceCompilationUnit().compilationResult.recordSuppressWarnings(CompilerOptions.NonExternalizedString, this.sourceStart, this.declarationSourceEnd);
307         if (this.recipient != null) {
308             if (tagBits != 0) {
309                 // tag bits onto recipient
310
switch (this.recipient.kind()) {
311                     case Binding.PACKAGE :
312                         ((PackageBinding)this.recipient).tagBits |= tagBits;
313                         break;
314                     case Binding.TYPE :
315                     case Binding.GENERIC_TYPE :
316                         SourceTypeBinding sourceType = (SourceTypeBinding) this.recipient;
317                         sourceType.tagBits |= tagBits;
318                         if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
319                             TypeDeclaration typeDeclaration = sourceType.scope.referenceContext;
320                             int start;
321                             if (scope.referenceCompilationUnit().types[0] == typeDeclaration) {
322                                 start = 0;
323                             } else {
324                                 start = typeDeclaration.declarationSourceStart;
325                             }
326                             recordSuppressWarnings(scope, start, typeDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
327                         }
328                         break;
329                     case Binding.METHOD :
330                         MethodBinding sourceMethod = (MethodBinding) this.recipient;
331                         sourceMethod.tagBits |= tagBits;
332                         if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
333                             sourceType = (SourceTypeBinding) sourceMethod.declaringClass;
334                             AbstractMethodDeclaration methodDeclaration = sourceType.scope.referenceContext.declarationOf(sourceMethod);
335                             recordSuppressWarnings(scope, methodDeclaration.declarationSourceStart, methodDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
336                         }
337                         break;
338                     case Binding.FIELD :
339                         FieldBinding sourceField = (FieldBinding) this.recipient;
340                         sourceField.tagBits |= tagBits;
341                         if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
342                             sourceType = (SourceTypeBinding) sourceField.declaringClass;
343                             FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(sourceField);
344                             recordSuppressWarnings(scope, fieldDeclaration.declarationSourceStart, fieldDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
345                         }
346                         break;
347                     case Binding.LOCAL :
348                         LocalVariableBinding variable = (LocalVariableBinding) this.recipient;
349                         variable.tagBits |= tagBits;
350                         if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
351                              LocalDeclaration localDeclaration = variable.declaration;
352                             recordSuppressWarnings(scope, localDeclaration.declarationSourceStart, localDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
353                         }
354                         break;
355                 }
356             }
357             // check (meta)target compatibility
358
checkTargetCompatibility: {
359                 long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference
360
if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) // does not specify any target restriction
361
break checkTargetCompatibility;
362                     
363                 switch (recipient.kind()) {
364                     case Binding.PACKAGE :
365                         if ((metaTagBits & TagBits.AnnotationForPackage) != 0)
366                             break checkTargetCompatibility;
367                         break;
368                     case Binding.TYPE :
369                     case Binding.GENERIC_TYPE :
370                         if (((ReferenceBinding)this.recipient).isAnnotationType()) {
371                             if ((metaTagBits & (TagBits.AnnotationForAnnotationType|TagBits.AnnotationForType)) != 0)
372                             break checkTargetCompatibility;
373                         } else if ((metaTagBits & TagBits.AnnotationForType) != 0)
374                             break checkTargetCompatibility;
375                         break;
376                     case Binding.METHOD :
377                         if (((MethodBinding)this.recipient).isConstructor()) {
378                             if ((metaTagBits & TagBits.AnnotationForConstructor) != 0)
379                                 break checkTargetCompatibility;
380                         } else if ((metaTagBits & TagBits.AnnotationForMethod) != 0)
381                             break checkTargetCompatibility;
382                         break;
383                     case Binding.FIELD :
384                         if ((metaTagBits & TagBits.AnnotationForField) != 0)
385                             break checkTargetCompatibility;
386                         break;
387                     case Binding.LOCAL :
388                         if ((((LocalVariableBinding)this.recipient).tagBits & TagBits.IsArgument) != 0) {
389                             if ((metaTagBits & TagBits.AnnotationForParameter) != 0)
390                                 break checkTargetCompatibility;
391                         } else if ((annotationType.tagBits & TagBits.AnnotationForLocalVariable) != 0)
392                             break checkTargetCompatibility;
393                         break;
394                 }
395                 scope.problemReporter().disallowedTargetForAnnotation(this);
396             }
397         }
398         return this.resolvedType;
399     }
400     
401     public abstract void traverse(ASTVisitor visitor, BlockScope scope);
402     
403 }
404
Popular Tags