001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
011:
012: import org.eclipse.jdt.core.compiler.CharOperation;
013: import org.eclipse.jdt.internal.compiler.ASTVisitor;
014: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
015: import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
016: import org.eclipse.jdt.internal.compiler.impl.Constant;
017: import org.eclipse.jdt.internal.compiler.lookup.*;
018:
019: /**
020: * Annotation
021: */
022: public abstract class Annotation extends Expression {
023:
024: final static MemberValuePair[] NoValuePairs = new MemberValuePair[0];
025: public int declarationSourceEnd;
026: public Binding recipient;
027:
028: public TypeReference type;
029: /**
030: * The representation of this annotation in the type system.
031: */
032: private AnnotationBinding compilerAnnotation = null;
033:
034: public static long getRetentionPolicy(char[] policyName) {
035: if (policyName == null || policyName.length == 0)
036: return 0;
037: switch (policyName[0]) {
038: case 'C':
039: if (CharOperation.equals(policyName,
040: TypeConstants.UPPER_CLASS))
041: return TagBits.AnnotationClassRetention;
042: break;
043: case 'S':
044: if (CharOperation.equals(policyName,
045: TypeConstants.UPPER_SOURCE))
046: return TagBits.AnnotationSourceRetention;
047: break;
048: case 'R':
049: if (CharOperation.equals(policyName,
050: TypeConstants.UPPER_RUNTIME))
051: return TagBits.AnnotationRuntimeRetention;
052: break;
053: }
054: return 0; // unknown
055: }
056:
057: public static long getTargetElementType(char[] elementName) {
058: if (elementName == null || elementName.length == 0)
059: return 0;
060: switch (elementName[0]) {
061: case 'A':
062: if (CharOperation.equals(elementName,
063: TypeConstants.UPPER_ANNOTATION_TYPE))
064: return TagBits.AnnotationForAnnotationType;
065: break;
066: case 'C':
067: if (CharOperation.equals(elementName,
068: TypeConstants.UPPER_CONSTRUCTOR))
069: return TagBits.AnnotationForConstructor;
070: break;
071: case 'F':
072: if (CharOperation.equals(elementName,
073: TypeConstants.UPPER_FIELD))
074: return TagBits.AnnotationForField;
075: break;
076: case 'L':
077: if (CharOperation.equals(elementName,
078: TypeConstants.UPPER_LOCAL_VARIABLE))
079: return TagBits.AnnotationForLocalVariable;
080: break;
081: case 'M':
082: if (CharOperation.equals(elementName,
083: TypeConstants.UPPER_METHOD))
084: return TagBits.AnnotationForMethod;
085: break;
086: case 'P':
087: if (CharOperation.equals(elementName,
088: TypeConstants.UPPER_PARAMETER))
089: return TagBits.AnnotationForParameter;
090: else if (CharOperation.equals(elementName,
091: TypeConstants.UPPER_PACKAGE))
092: return TagBits.AnnotationForPackage;
093: break;
094: case 'T':
095: if (CharOperation.equals(elementName, TypeConstants.TYPE))
096: return TagBits.AnnotationForType;
097: break;
098: }
099: return 0; // unknown
100: }
101:
102: public ElementValuePair[] computeElementValuePairs() {
103: return Binding.NO_ELEMENT_VALUE_PAIRS;
104: }
105:
106: /**
107: * Compute the bit pattern for recognized standard annotations the compiler may need to act upon
108: */
109: private long detectStandardAnnotation(Scope scope,
110: ReferenceBinding annotationType,
111: MemberValuePair valueAttribute) {
112: long tagBits = 0;
113: switch (annotationType.id) {
114: // retention annotation
115: case TypeIds.T_JavaLangAnnotationRetention:
116: if (valueAttribute != null) {
117: Expression expr = valueAttribute.value;
118: if ((expr.bits & Binding.VARIABLE) == Binding.FIELD) {
119: FieldBinding field = ((Reference) expr)
120: .fieldBinding();
121: if (field != null
122: && field.declaringClass.id == T_JavaLangAnnotationRetentionPolicy) {
123: tagBits |= getRetentionPolicy(field.name);
124: }
125: }
126: }
127: break;
128: // target annotation
129: case TypeIds.T_JavaLangAnnotationTarget:
130: tagBits |= TagBits.AnnotationTarget; // target specified (could be empty)
131: if (valueAttribute != null) {
132: Expression expr = valueAttribute.value;
133: if (expr instanceof ArrayInitializer) {
134: ArrayInitializer initializer = (ArrayInitializer) expr;
135: final Expression[] expressions = initializer.expressions;
136: if (expressions != null) {
137: for (int i = 0, length = expressions.length; i < length; i++) {
138: Expression initExpr = expressions[i];
139: if ((initExpr.bits & Binding.VARIABLE) == Binding.FIELD) {
140: FieldBinding field = ((Reference) initExpr)
141: .fieldBinding();
142: if (field != null
143: && field.declaringClass.id == T_JavaLangAnnotationElementType) {
144: long element = getTargetElementType(field.name);
145: if ((tagBits & element) != 0) {
146: scope
147: .problemReporter()
148: .duplicateTargetInTargetAnnotation(
149: annotationType,
150: (NameReference) initExpr);
151: } else {
152: tagBits |= element;
153: }
154: }
155: }
156: }
157: }
158: } else if ((expr.bits & Binding.VARIABLE) == Binding.FIELD) {
159: FieldBinding field = ((Reference) expr)
160: .fieldBinding();
161: if (field != null
162: && field.declaringClass.id == T_JavaLangAnnotationElementType) {
163: tagBits |= getTargetElementType(field.name);
164: }
165: }
166: }
167: break;
168: // marker annotations
169: case TypeIds.T_JavaLangDeprecated:
170: tagBits |= TagBits.AnnotationDeprecated;
171: break;
172: case TypeIds.T_JavaLangAnnotationDocumented:
173: tagBits |= TagBits.AnnotationDocumented;
174: break;
175: case TypeIds.T_JavaLangAnnotationInherited:
176: tagBits |= TagBits.AnnotationInherited;
177: break;
178: case TypeIds.T_JavaLangOverride:
179: tagBits |= TagBits.AnnotationOverride;
180: break;
181: case TypeIds.T_JavaLangSuppressWarnings:
182: tagBits |= TagBits.AnnotationSuppressWarnings;
183: break;
184: }
185: return tagBits;
186: }
187:
188: public AnnotationBinding getCompilerAnnotation() {
189: return this .compilerAnnotation;
190: }
191:
192: public abstract MemberValuePair[] memberValuePairs();
193:
194: public StringBuffer printExpression(int indent, StringBuffer output) {
195: output.append('@');
196: this .type.printExpression(0, output);
197: return output;
198: }
199:
200: public void recordSuppressWarnings(Scope scope, int startSuppresss,
201: int endSuppress, boolean isSuppressingWarnings) {
202: long suppressWarningIrritants = 0;
203: MemberValuePair[] pairs = this .memberValuePairs();
204: pairLoop: for (int i = 0, length = pairs.length; i < length; i++) {
205: MemberValuePair pair = pairs[i];
206: if (CharOperation.equals(pair.name, TypeConstants.VALUE)) {
207: Expression value = pair.value;
208: if (value instanceof ArrayInitializer) {
209: ArrayInitializer initializer = (ArrayInitializer) value;
210: Expression[] inits = initializer.expressions;
211: if (inits != null) {
212: for (int j = 0, initsLength = inits.length; j < initsLength; j++) {
213: Constant cst = inits[j].constant;
214: if (cst != Constant.NotAConstant
215: && cst.typeID() == T_JavaLangString) {
216: long irritant = CompilerOptions
217: .warningTokenToIrritant(cst
218: .stringValue());
219: if (irritant != 0) {
220: suppressWarningIrritants |= irritant;
221: if (~suppressWarningIrritants == 0)
222: break pairLoop;
223: } else {
224: scope.problemReporter()
225: .unhandledWarningToken(
226: inits[j]);
227: }
228: }
229: }
230: }
231: } else {
232: Constant cst = value.constant;
233: if (cst != Constant.NotAConstant
234: && cst.typeID() == T_JavaLangString) {
235: long irritant = CompilerOptions
236: .warningTokenToIrritant(cst
237: .stringValue());
238: if (irritant != 0) {
239: suppressWarningIrritants |= irritant;
240: if (~suppressWarningIrritants == 0)
241: break pairLoop;
242: } else {
243: scope.problemReporter()
244: .unhandledWarningToken(value);
245: }
246: }
247: }
248: break pairLoop;
249: }
250: }
251: if (isSuppressingWarnings && suppressWarningIrritants != 0) {
252: scope.referenceCompilationUnit().compilationResult
253: .recordSuppressWarnings(suppressWarningIrritants,
254: startSuppresss, endSuppress);
255: }
256: }
257:
258: public TypeBinding resolveType(BlockScope scope) {
259:
260: if (this .compilerAnnotation != null)
261: return this .resolvedType;
262: this .constant = Constant.NotAConstant;
263:
264: TypeBinding typeBinding = this .type.resolveType(scope);
265: if (typeBinding == null) {
266: return null;
267: }
268: this .resolvedType = typeBinding;
269: // ensure type refers to an annotation type
270: if (!typeBinding.isAnnotationType()) {
271: scope.problemReporter().typeMismatchError(typeBinding,
272: scope.getJavaLangAnnotationAnnotation(), this .type);
273: return null;
274: }
275:
276: ReferenceBinding annotationType = (ReferenceBinding) this .resolvedType;
277: MethodBinding[] methods = annotationType.methods();
278: // clone valuePairs to keep track of unused ones
279: MemberValuePair[] originalValuePairs = memberValuePairs();
280: MemberValuePair valueAttribute = null; // remember the first 'value' pair
281: MemberValuePair[] pairs;
282: int pairsLength = originalValuePairs.length;
283: if (pairsLength > 0) {
284: System.arraycopy(originalValuePairs, 0,
285: pairs = new MemberValuePair[pairsLength], 0,
286: pairsLength);
287: } else {
288: pairs = originalValuePairs;
289: }
290:
291: nextMember: for (int i = 0, requiredLength = methods.length; i < requiredLength; i++) {
292: MethodBinding method = methods[i];
293: char[] selector = method.selector;
294: boolean foundValue = false;
295: nextPair: for (int j = 0; j < pairsLength; j++) {
296: MemberValuePair pair = pairs[j];
297: if (pair == null)
298: continue nextPair;
299: char[] name = pair.name;
300: if (CharOperation.equals(name, selector)) {
301: if (valueAttribute == null
302: && CharOperation.equals(name,
303: TypeConstants.VALUE)) {
304: valueAttribute = pair;
305: }
306: pair.binding = method;
307: pair.resolveTypeExpecting(scope, method.returnType);
308: pairs[j] = null; // consumed
309: foundValue = true;
310:
311: // check duplicates
312: boolean foundDuplicate = false;
313: for (int k = j + 1; k < pairsLength; k++) {
314: MemberValuePair otherPair = pairs[k];
315: if (otherPair == null)
316: continue;
317: if (CharOperation.equals(otherPair.name,
318: selector)) {
319: foundDuplicate = true;
320: scope.problemReporter()
321: .duplicateAnnotationValue(
322: annotationType, otherPair);
323: otherPair.binding = method;
324: otherPair.resolveTypeExpecting(scope,
325: method.returnType);
326: pairs[k] = null;
327: }
328: }
329: if (foundDuplicate) {
330: scope.problemReporter()
331: .duplicateAnnotationValue(
332: annotationType, pair);
333: continue nextMember;
334: }
335: }
336: }
337: if (!foundValue
338: && (method.modifiers & ClassFileConstants.AccAnnotationDefault) == 0) {
339: scope
340: .problemReporter()
341: .missingValueForAnnotationMember(this , selector);
342: }
343: }
344: // check unused pairs
345: for (int i = 0; i < pairsLength; i++) {
346: if (pairs[i] != null) {
347: scope.problemReporter().undefinedAnnotationValue(
348: annotationType, pairs[i]);
349: pairs[i].resolveTypeExpecting(scope, null); // resilient
350: }
351: }
352: // if (scope.compilerOptions().storeAnnotations)
353: this .compilerAnnotation = scope.environment().createAnnotation(
354: (ReferenceBinding) this .resolvedType,
355: this .computeElementValuePairs());
356: // recognize standard annotations ?
357: long tagBits = detectStandardAnnotation(scope, annotationType,
358: valueAttribute);
359:
360: // record annotation positions in the compilation result
361: scope.referenceCompilationUnit().compilationResult
362: .recordSuppressWarnings(
363: CompilerOptions.NonExternalizedString,
364: this .sourceStart, this .declarationSourceEnd);
365: if (this .recipient != null) {
366: if (tagBits != 0) {
367: // tag bits onto recipient
368: switch (this .recipient.kind()) {
369: case Binding.PACKAGE:
370: ((PackageBinding) this .recipient).tagBits |= tagBits;
371: break;
372: case Binding.TYPE:
373: case Binding.GENERIC_TYPE:
374: SourceTypeBinding sourceType = (SourceTypeBinding) this .recipient;
375: sourceType.tagBits |= tagBits;
376: if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
377: TypeDeclaration typeDeclaration = sourceType.scope.referenceContext;
378: int start;
379: if (scope.referenceCompilationUnit().types[0] == typeDeclaration) {
380: start = 0;
381: } else {
382: start = typeDeclaration.declarationSourceStart;
383: }
384: recordSuppressWarnings(
385: scope,
386: start,
387: typeDeclaration.declarationSourceEnd,
388: scope.compilerOptions().suppressWarnings);
389: }
390: break;
391: case Binding.METHOD:
392: MethodBinding sourceMethod = (MethodBinding) this .recipient;
393: sourceMethod.tagBits |= tagBits;
394: if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
395: sourceType = (SourceTypeBinding) sourceMethod.declaringClass;
396: AbstractMethodDeclaration methodDeclaration = sourceType.scope.referenceContext
397: .declarationOf(sourceMethod);
398: recordSuppressWarnings(
399: scope,
400: methodDeclaration.declarationSourceStart,
401: methodDeclaration.declarationSourceEnd,
402: scope.compilerOptions().suppressWarnings);
403: }
404: break;
405: case Binding.FIELD:
406: FieldBinding sourceField = (FieldBinding) this .recipient;
407: sourceField.tagBits |= tagBits;
408: if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
409: sourceType = (SourceTypeBinding) sourceField.declaringClass;
410: FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext
411: .declarationOf(sourceField);
412: recordSuppressWarnings(
413: scope,
414: fieldDeclaration.declarationSourceStart,
415: fieldDeclaration.declarationSourceEnd,
416: scope.compilerOptions().suppressWarnings);
417: }
418: break;
419: case Binding.LOCAL:
420: LocalVariableBinding variable = (LocalVariableBinding) this .recipient;
421: variable.tagBits |= tagBits;
422: if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
423: LocalDeclaration localDeclaration = variable.declaration;
424: recordSuppressWarnings(
425: scope,
426: localDeclaration.declarationSourceStart,
427: localDeclaration.declarationSourceEnd,
428: scope.compilerOptions().suppressWarnings);
429: }
430: break;
431: }
432: }
433: // check (meta)target compatibility
434: checkTargetCompatibility: {
435: long metaTagBits = annotationType
436: .getAnnotationTagBits(); // could be forward reference
437: if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) // does not specify any target restriction
438: break checkTargetCompatibility;
439:
440: switch (recipient.kind()) {
441: case Binding.PACKAGE:
442: if ((metaTagBits & TagBits.AnnotationForPackage) != 0)
443: break checkTargetCompatibility;
444: break;
445: case Binding.TYPE:
446: case Binding.GENERIC_TYPE:
447: if (((ReferenceBinding) this .recipient)
448: .isAnnotationType()) {
449: if ((metaTagBits & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType)) != 0)
450: break checkTargetCompatibility;
451: } else if ((metaTagBits & TagBits.AnnotationForType) != 0)
452: break checkTargetCompatibility;
453: break;
454: case Binding.METHOD:
455: if (((MethodBinding) this .recipient)
456: .isConstructor()) {
457: if ((metaTagBits & TagBits.AnnotationForConstructor) != 0)
458: break checkTargetCompatibility;
459: } else if ((metaTagBits & TagBits.AnnotationForMethod) != 0)
460: break checkTargetCompatibility;
461: break;
462: case Binding.FIELD:
463: if ((metaTagBits & TagBits.AnnotationForField) != 0)
464: break checkTargetCompatibility;
465: break;
466: case Binding.LOCAL:
467: if ((((LocalVariableBinding) this .recipient).tagBits & TagBits.IsArgument) != 0) {
468: if ((metaTagBits & TagBits.AnnotationForParameter) != 0)
469: break checkTargetCompatibility;
470: } else if ((annotationType.tagBits & TagBits.AnnotationForLocalVariable) != 0)
471: break checkTargetCompatibility;
472: break;
473: }
474: scope.problemReporter().disallowedTargetForAnnotation(
475: this );
476: }
477: }
478: return this .resolvedType;
479: }
480:
481: public abstract void traverse(ASTVisitor visitor, BlockScope scope);
482:
483: }
|