1 /*******************************************************************************
 
   2  * Copyright (c) 2000, 2008 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
 
   9  *     IBM Corporation - initial API and implementation
 
  10  *******************************************************************************/
 
  11 package net.sourceforge.phpdt.internal.compiler.ast;
 
  13 import net.sourceforge.phpdt.core.compiler.CharOperation;
 
  14 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
 
  15 import net.sourceforge.phpdt.internal.compiler.classfmt.ClassFileConstants;
 
  16 import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
 
  17 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
 
  18 import net.sourceforge.phpdt.internal.compiler.lookup.*;
 
  23 public abstract class Annotation extends Expression {
 
  25         final static MemberValuePair[] NoValuePairs = new MemberValuePair[0];
 
  26         public int declarationSourceEnd;
 
  27         public Binding recipient;
 
  29         public TypeReference type;
 
  31          *  The representation of this annotation in the type system. 
 
  33         private AnnotationBinding compilerAnnotation = null;
 
  35         public static long getRetentionPolicy(char[] policyName) {
 
  36                 if (policyName == null || policyName.length == 0)
 
  38                 switch(policyName[0]) {
 
  40                                 if (CharOperation.equals(policyName, TypeConstants.UPPER_CLASS)) 
 
  41                                         return TagBits.AnnotationClassRetention;
 
  44                                 if (CharOperation.equals(policyName, TypeConstants.UPPER_SOURCE)) 
 
  45                                         return TagBits.AnnotationSourceRetention;
 
  48                                 if (CharOperation.equals(policyName, TypeConstants.UPPER_RUNTIME)) 
 
  49                                         return TagBits.AnnotationRuntimeRetention;
 
  55         public static long getTargetElementType(char[] elementName) {
 
  56                 if (elementName == null || elementName.length == 0)
 
  58                 switch(elementName[0]) {
 
  60                                 if (CharOperation.equals(elementName, TypeConstants.UPPER_ANNOTATION_TYPE)) 
 
  61                                         return TagBits.AnnotationForAnnotationType;
 
  64                                 if (CharOperation.equals(elementName, TypeConstants.UPPER_CONSTRUCTOR)) 
 
  65                                         return TagBits.AnnotationForConstructor;
 
  68                                 if (CharOperation.equals(elementName, TypeConstants.UPPER_FIELD)) 
 
  69                                         return TagBits.AnnotationForField;
 
  72                                 if (CharOperation.equals(elementName, TypeConstants.UPPER_LOCAL_VARIABLE)) 
 
  73                                         return TagBits.AnnotationForLocalVariable;
 
  76                                 if (CharOperation.equals(elementName, TypeConstants.UPPER_METHOD)) 
 
  77                                         return TagBits.AnnotationForMethod;
 
  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;
 
  86                                 if (CharOperation.equals(elementName, TypeConstants.TYPE)) 
 
  87                                         return TagBits.AnnotationForType;
 
  93         public ElementValuePair[] computeElementValuePairs() {
 
  94                 return Binding.NO_ELEMENT_VALUE_PAIRS;
 
  98          * Compute the bit pattern for recognized standard annotations the compiler may need to act upon
 
 100         private long detectStandardAnnotation(Scope scope, ReferenceBinding annotationType, MemberValuePair valueAttribute) {
 
 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);
 
 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);
 
 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);
 
 147                         // marker annotations
 
 148                         case TypeIds.T_JavaLangDeprecated :
 
 149                                 tagBits |= TagBits.AnnotationDeprecated;
 
 151                         case TypeIds.T_JavaLangAnnotationDocumented :
 
 152                                 tagBits |= TagBits.AnnotationDocumented;
 
 154                         case TypeIds.T_JavaLangAnnotationInherited :
 
 155                                 tagBits |= TagBits.AnnotationInherited;
 
 157                         case TypeIds.T_JavaLangOverride :
 
 158                                 tagBits |= TagBits.AnnotationOverride;
 
 160                         case TypeIds.T_JavaLangSuppressWarnings :
 
 161                                 tagBits |= TagBits.AnnotationSuppressWarnings;
 
 167         public AnnotationBinding getCompilerAnnotation() {
 
 168                 return this.compilerAnnotation;
 
 171         public abstract MemberValuePair[] memberValuePairs();
 
 173         public StringBuffer printExpression(int indent, StringBuffer output) {
 
 175                 this.type.printExpression(0, output);
 
 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;
 
 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 irritants = CompilerOptions.warningTokenToIrritants(cst.stringValue());
 
 194                                                                 if (irritants != 0) {
 
 195                                                                         if ((suppressWarningIrritants & irritants) == irritants) {
 
 196                                                                                 scope.problemReporter().unusedWarningToken(inits[j]);
 
 198                                                                                 suppressWarningIrritants |= irritants;
 
 201                                                                         scope.problemReporter().unhandledWarningToken(inits[j]);
 
 207                                         Constant cst = value.constant;
 
 208                                         if (cst != Constant.NotAConstant && cst.typeID() == T_JavaLangString) {
 
 209                                                 long irritants = CompilerOptions.warningTokenToIrritants(cst.stringValue());
 
 210                                                 if (irritants != 0) {
 
 211                                                         suppressWarningIrritants |= irritants;
 
 213                                                         scope.problemReporter().unhandledWarningToken(value);
 
 220                 if (isSuppressingWarnings && suppressWarningIrritants != 0) {
 
 221                         scope.referenceCompilationUnit().recordSuppressWarnings(suppressWarningIrritants, this, startSuppresss, endSuppress);
 
 225         public TypeBinding resolveType(BlockScope scope) {
 
 227                 if (this.compilerAnnotation != null)
 
 228                         return this.resolvedType;
 
 229                 this.constant = Constant.NotAConstant;
 
 231                 TypeBinding typeBinding = this.type.resolveType(scope);
 
 232                 if (typeBinding == null) {
 
 235                 this.resolvedType = typeBinding;
 
 236                 // ensure type refers to an annotation type
 
 237                 if (!typeBinding.isAnnotationType() && typeBinding.isValidBinding()) {
 
 238                         scope.problemReporter().typeMismatchError(typeBinding, scope.getJavaLangAnnotationAnnotation(), this.type, null);
 
 242                 ReferenceBinding annotationType = (ReferenceBinding) this.resolvedType;
 
 243                 MethodBinding[] methods = annotationType.methods();
 
 244                 // clone valuePairs to keep track of unused ones
 
 245                 MemberValuePair[] originalValuePairs = memberValuePairs();
 
 246                 MemberValuePair valueAttribute = null; // remember the first 'value' pair
 
 247                 MemberValuePair[] pairs;
 
 248                 int pairsLength = originalValuePairs.length;
 
 249                 if (pairsLength > 0) {
 
 250                         System.arraycopy(originalValuePairs, 0, pairs = new MemberValuePair[pairsLength], 0, pairsLength);
 
 252                         pairs = originalValuePairs;
 
 255                 nextMember: for (int i = 0, requiredLength = methods.length; i < requiredLength; i++) {
 
 256                         MethodBinding method = methods[i];
 
 257                         char[] selector = method.selector;
 
 258                         boolean foundValue = false;
 
 259                         nextPair: for (int j = 0; j < pairsLength; j++) {
 
 260                                 MemberValuePair pair = pairs[j];
 
 261                                 if (pair == null) continue nextPair;
 
 262                                 char[] name = pair.name;
 
 263                                 if (CharOperation.equals(name, selector)) {
 
 264                                         if (valueAttribute == null && CharOperation.equals(name, TypeConstants.VALUE)) {
 
 265                                                 valueAttribute = pair;
 
 267                                         pair.binding = method;
 
 268                                         pair.resolveTypeExpecting(scope, method.returnType);
 
 269                                         pairs[j] = null; // consumed
 
 273                                         boolean foundDuplicate = false;
 
 274                                         for (int k = j+1; k < pairsLength; k++) {
 
 275                                                 MemberValuePair otherPair = pairs[k];
 
 276                                                 if (otherPair == null) continue;
 
 277                                                 if (CharOperation.equals(otherPair.name, selector)) {
 
 278                                                         foundDuplicate = true;
 
 279                                                         scope.problemReporter().duplicateAnnotationValue(annotationType, otherPair);
 
 280                                                         otherPair.binding = method;
 
 281                                                         otherPair.resolveTypeExpecting(scope, method.returnType);
 
 285                                         if (foundDuplicate) {
 
 286                                                 scope.problemReporter().duplicateAnnotationValue(annotationType, pair);
 
 292                                         (method.modifiers & ClassFileConstants.AccAnnotationDefault) == 0 &&
 
 293                                         (this.bits & IsRecovered) == 0) {
 
 294                                 scope.problemReporter().missingValueForAnnotationMember(this, selector);
 
 297                 // check unused pairs
 
 298                 for (int i = 0; i < pairsLength; i++) {
 
 299                         if (pairs[i] != null) {
 
 300                                 scope.problemReporter().undefinedAnnotationValue(annotationType, pairs[i]);
 
 301                                 pairs[i].resolveTypeExpecting(scope, null); // resilient
 
 304 //              if (scope.compilerOptions().storeAnnotations)
 
 305                 this.compilerAnnotation = scope.environment().createAnnotation((ReferenceBinding) this.resolvedType, this.computeElementValuePairs());
 
 306                 // recognize standard annotations ?
 
 307                 long tagBits = detectStandardAnnotation(scope, annotationType, valueAttribute);
 
 309                 // record annotation positions in the compilation result
 
 310                 scope.referenceCompilationUnit().recordSuppressWarnings(CompilerOptions.NonExternalizedString, null, this.sourceStart, this.declarationSourceEnd);
 
 311                 if (this.recipient != null) {
 
 313                                 // tag bits onto recipient
 
 314                                 switch (this.recipient.kind()) {
 
 315                                         case Binding.PACKAGE :
 
 316                                                 ((PackageBinding)this.recipient).tagBits |= tagBits;
 
 319                                         case Binding.GENERIC_TYPE :
 
 320                                                 SourceTypeBinding sourceType = (SourceTypeBinding) this.recipient;
 
 321                                                 sourceType.tagBits |= tagBits;
 
 322                                                 if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
 
 323                                                         TypeDeclaration typeDeclaration =  sourceType.scope.referenceContext;
 
 325                                                         if (scope.referenceCompilationUnit().types[0] == typeDeclaration) {
 
 328                                                                 start = typeDeclaration.declarationSourceStart;
 
 330                                                         recordSuppressWarnings(scope, start, typeDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
 
 333                                         case Binding.METHOD :
 
 334                                                 MethodBinding sourceMethod = (MethodBinding) this.recipient;
 
 335                                                 sourceMethod.tagBits |= tagBits;
 
 336                                                 if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
 
 337                                                         sourceType = (SourceTypeBinding) sourceMethod.declaringClass;
 
 338                                                         AbstractMethodDeclaration methodDeclaration = sourceType.scope.referenceContext.declarationOf(sourceMethod);
 
 339                                                         recordSuppressWarnings(scope, methodDeclaration.declarationSourceStart, methodDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
 
 343                                                 FieldBinding sourceField = (FieldBinding) this.recipient;
 
 344                                                 sourceField.tagBits |= tagBits;
 
 345                                                 if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
 
 346                                                         sourceType = (SourceTypeBinding) sourceField.declaringClass;
 
 347                                                         FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(sourceField);
 
 348                                                         recordSuppressWarnings(scope, fieldDeclaration.declarationSourceStart, fieldDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
 
 352                                                 LocalVariableBinding variable = (LocalVariableBinding) this.recipient;
 
 353                                                 variable.tagBits |= tagBits;
 
 354                                                 if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
 
 355                                                          LocalDeclaration localDeclaration = variable.declaration;
 
 356                                                         recordSuppressWarnings(scope, localDeclaration.declarationSourceStart, localDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
 
 361                         // check (meta)target compatibility
 
 362                         checkTargetCompatibility: {
 
 363                                 long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference
 
 364                                 if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) // does not specify any target restriction
 
 365                                         break checkTargetCompatibility;
 
 367                                 switch (recipient.kind()) {
 
 368                                         case Binding.PACKAGE :
 
 369                                                 if ((metaTagBits & TagBits.AnnotationForPackage) != 0)
 
 370                                                         break checkTargetCompatibility;
 
 373                                         case Binding.GENERIC_TYPE :
 
 374                                                 if (((ReferenceBinding)this.recipient).isAnnotationType()) {
 
 375                                                         if ((metaTagBits & (TagBits.AnnotationForAnnotationType|TagBits.AnnotationForType)) != 0)
 
 376                                                         break checkTargetCompatibility;
 
 377                                                 } else if ((metaTagBits & TagBits.AnnotationForType) != 0) 
 
 378                                                         break checkTargetCompatibility;
 
 380                                         case Binding.METHOD :
 
 381                                                 if (((MethodBinding)this.recipient).isConstructor()) {
 
 382                                                         if ((metaTagBits & TagBits.AnnotationForConstructor) != 0)
 
 383                                                                 break checkTargetCompatibility;
 
 384                                                 } else  if ((metaTagBits & TagBits.AnnotationForMethod) != 0)
 
 385                                                         break checkTargetCompatibility;
 
 388                                                 if ((metaTagBits & TagBits.AnnotationForField) != 0)
 
 389                                                         break checkTargetCompatibility;
 
 392                                                 if ((((LocalVariableBinding)this.recipient).tagBits & TagBits.IsArgument) != 0) {
 
 393                                                         if ((metaTagBits & TagBits.AnnotationForParameter) != 0)
 
 394                                                                 break checkTargetCompatibility;
 
 395                                                 } else  if ((annotationType.tagBits & TagBits.AnnotationForLocalVariable) != 0)
 
 396                                                         break checkTargetCompatibility;
 
 399                                 scope.problemReporter().disallowedTargetForAnnotation(this);
 
 402                 return this.resolvedType;
 
 405         public abstract void traverse(ASTVisitor visitor, BlockScope scope);