Package org.eclipse.jdt.internal.compiler.ast

Source Code of org.eclipse.jdt.internal.compiler.ast.LocationCollector

/*******************************************************************************
* Copyright (c) 2000, 2014 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
*     Stephan Herrmann - Contributions for
*                bug 186342 - [compiler][null] Using annotations for null checking
*                bug 365662 - [compiler][null] warn on contradictory and redundant null annotations
*                bug 331649 - [compiler][null] consider null annotations for fields
*                Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
*                Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099
*                Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations
*                Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled
*                Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings.
*                Bug 424728 - [1.8][null] Unexpected error: The nullness annotation 'XXXX' is not applicable at this location
*                Bug 392245 - [1.8][compiler][null] Define whether / how @NonNullByDefault applies to TYPE_USE locations
*                Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
*        Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
*                          Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work)
*                          Bug 409517 - [1.8][compiler] Type annotation problems on more elaborate array references
*                          Bug 415397 - [1.8][compiler] Type Annotations on wildcard type argument dropped
*                          Bug 414384 - [1.8] type annotation on abbreviated inner class is not marked as inner type
*      Jesper S Moller <jesper@selskabet.org> -  Contributions for
*                          Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
*                          Bug 412151 - [1.8][compiler] Check repeating annotation's collection type
*                          Bug 412149 - [1.8][compiler] Emit repeated annotations into the designated container
*                          Bug 419209 - [1.8] Repeating container annotations should be rejected in the presence of annotation it contains
*******************************************************************************/
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.env.EnumConstantSignature;
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
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public abstract class Annotation extends Expression {
 
  Annotation persistibleAnnotation = this// Emit this into class file, unless this is a repeating annotation, in which case package this into the designated container.
 
  /**
   * Return the location for the corresponding annotation inside the type reference, <code>null</code> if none.
   */
  public static int[] getLocations(
      final Expression reference,
      final Annotation annotation) {
 
    class LocationCollector extends ASTVisitor {
      Stack typePathEntries;
      Annotation searchedAnnotation;
      boolean continueSearch = true;
     
      public LocationCollector(Annotation currentAnnotation) {
        this.typePathEntries = new Stack();
        this.searchedAnnotation = currentAnnotation;
      }
     
      private int[] computeNestingDepth(TypeReference typeReference) {
        TypeBinding type = typeReference.resolvedType == null ? null : typeReference.resolvedType.leafComponentType();
        int[] nestingDepths = new int[typeReference.getAnnotatableLevels()];
        if (type != null && type.isNestedType()) {
          int depth = 0;
          TypeBinding currentType = type;
          while (currentType != null) {
            depth += (currentType.isStatic()) ? 0 : 1;
            currentType = currentType.enclosingType();
          }
          // Work backwards computing whether a INNER_TYPE entry is required for each level
          int counter = nestingDepths.length - 1;
          while (type != null && counter >= 0) {
            nestingDepths[counter--] = depth;
            depth -= type.isStatic() ? 0 : 1;
            type = type.enclosingType();
          }
        }
        return nestingDepths;
      }
     

      private void inspectAnnotations(Annotation [] annotations) {
        for (int i = 0, length = annotations == null ? 0 : annotations.length; this.continueSearch && i < length; i++) {
          if (annotations[i] == this.searchedAnnotation)
            this.continueSearch = false;
        }
      }

      private void inspectArrayDimensions(Annotation [][] annotationsOnDimensions, int dimensions) {
        for (int i = 0; this.continueSearch && i < dimensions; i++) {
          Annotation[] annotations = annotationsOnDimensions == null ? null : annotationsOnDimensions[i];
          inspectAnnotations(annotations);
          if (!this.continueSearch) return;
          this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY);
        }
      }
     
      private void inspectTypeArguments(TypeReference[] typeReferences) {
        for (int i = 0, length = typeReferences == null ? 0 : typeReferences.length; this.continueSearch && i < length; i++) {
          int size = this.typePathEntries.size();
          this.typePathEntries.add(new int[]{3,i});
          typeReferences[i].traverse(this, (BlockScope) null);
          if (!this.continueSearch) return;
          this.typePathEntries.setSize(size);
        }
      }
     
      public boolean visit(TypeReference typeReference, BlockScope scope) {
        if (this.continueSearch) {
          inspectArrayDimensions(typeReference.getAnnotationsOnDimensions(), typeReference.dimensions());
          if (this.continueSearch) {
            int[] nestingDepths = computeNestingDepth(typeReference);
            Annotation[][] annotations = typeReference.annotations;
            TypeReference [][] typeArguments = typeReference.getTypeArguments();
            int levels = typeReference.getAnnotatableLevels();
            int size = this.typePathEntries.size();
            for (int i = levels - 1; this.continueSearch && i >= 0; i--) {  // traverse outwards, see comment below about type annotations from SE7 locations.
              this.typePathEntries.setSize(size);
              for (int j = 0, depth = nestingDepths[i]; j < depth; j++)
                this.typePathEntries.add(TYPE_PATH_INNER_TYPE);
              if (annotations != null)
                inspectAnnotations(annotations[i]);
              if (this.continueSearch && typeArguments != null) {
                inspectTypeArguments(typeArguments[i]);
              }
            }
          }
        }
        return false; // if annotation is not found in the type reference, it must be one from SE7 location, typePathEntries captures the proper path entries for them.
     
      public boolean visit(SingleTypeReference typeReference, BlockScope scope) {
        return visit((TypeReference) typeReference, scope);
      }
     
      public boolean visit(ArrayTypeReference typeReference, BlockScope scope) {
        return visit((TypeReference) typeReference, scope);
      }
     
      public boolean visit(ParameterizedSingleTypeReference typeReference, BlockScope scope) {
        return visit((TypeReference) typeReference, scope);
      }

      public boolean visit(QualifiedTypeReference typeReference, BlockScope scope) {
        return visit((TypeReference) typeReference, scope);
      }
     
      public boolean visit(ArrayQualifiedTypeReference typeReference, BlockScope scope) {
        return visit((TypeReference) typeReference, scope);
      }
     
      public boolean visit(ParameterizedQualifiedTypeReference typeReference, BlockScope scope) {
        return visit((TypeReference) typeReference, scope);
      }
     
      public boolean visit(Wildcard typeReference, BlockScope scope) {
        visit((TypeReference) typeReference, scope);
        if (this.continueSearch) {
          TypeReference bound = typeReference.bound;
          if (bound != null) {
            int size = this.typePathEntries.size();
            this.typePathEntries.push(TYPE_PATH_ANNOTATION_ON_WILDCARD_BOUND);
            bound.traverse(this, scope);
            if (this.continueSearch)
              this.typePathEntries.setSize(size);
          }
        }
        return false;
      }

      public boolean visit(ArrayAllocationExpression allocationExpression, BlockScope scope) {
        if (this.continueSearch) {
          inspectArrayDimensions(allocationExpression.getAnnotationsOnDimensions(), allocationExpression.dimensions.length);
          if (this.continueSearch) {
            allocationExpression.type.traverse(this, scope);
          }
          if (this.continueSearch) throw new IllegalStateException();
        }
        return false;
      }
           
      public String toString() {
        StringBuffer buffer = new StringBuffer();
        buffer
          .append("search location for ") //$NON-NLS-1$
          .append(this.searchedAnnotation)
          .append("\ncurrent type_path entries : "); //$NON-NLS-1$
        for (int i = 0, maxi = this.typePathEntries.size(); i < maxi; i++) {
          int[] typePathEntry = (int[]) this.typePathEntries.get(i);
          buffer
            .append('(')
            .append(typePathEntry[0])
            .append(',')
            .append(typePathEntry[1])
            .append(')');
        }
        return String.valueOf(buffer);
      }
    }
    if (reference == null) return null;
    LocationCollector collector = new LocationCollector(annotation);
    reference.traverse(collector, (BlockScope) null);
    if (collector.typePathEntries.isEmpty()) {
      return null;
    }
    int size = collector.typePathEntries.size();
    int[] result = new int[size*2];
    int offset=0;
    for (int i = 0; i < size; i++) {
      int[] pathElement = (int[])collector.typePathEntries.get(i);
      result[offset++] = pathElement[0];
      result[offset++] = pathElement[1];
    }
    return result;
  }

  final static MemberValuePair[] NoValuePairs = new MemberValuePair[0];

  static final int[] TYPE_PATH_ELEMENT_ARRAY = new int[]{0,0};
  static final int[] TYPE_PATH_INNER_TYPE = new int[]{1,0};
  static final int[] TYPE_PATH_ANNOTATION_ON_WILDCARD_BOUND = new int[]{2,0};
 
  public int declarationSourceEnd;
  public Binding recipient;

  public TypeReference type;
  /**
   *  The representation of this annotation in the type system.
   */
  protected 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.
   * The lower bits (Binding.NullnessDefaultMASK) do not belong in tagBits, but in defaultNullness.
   */
  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_JavaLangFunctionalInterface :
        tagBits |= TagBits.AnnotationFunctionalInterface;
        break;
      case TypeIds.T_JavaLangAnnotationRepeatable:
        tagBits |= TagBits.AnnotationRepeatable;
        break;
      case TypeIds.T_JavaLangSuppressWarnings :
        tagBits |= TagBits.AnnotationSuppressWarnings;
        break;
      case TypeIds.T_JavaLangSafeVarargs :
        tagBits |= TagBits.AnnotationSafeVarargs;
        break;
      case TypeIds.T_JavaLangInvokeMethodHandlePolymorphicSignature :
        tagBits |= TagBits.AnnotationPolymorphicSignature;
        break;
      case TypeIds.T_ConfiguredAnnotationNullable :
        tagBits |= TagBits.AnnotationNullable;
        break;
      case TypeIds.T_ConfiguredAnnotationNonNull :
        tagBits |= TagBits.AnnotationNonNull;
        break;
      case TypeIds.T_ConfiguredAnnotationNonNullByDefault :
        // seeing this id implies that null annotation analysis is enabled
        Object value = null;
        if (valueAttribute != null) {
          if (valueAttribute.value instanceof FalseLiteral) {
            // parameter 'false' means: this annotation cancels any defaults
            tagBits |= TagBits.AnnotationNullUnspecifiedByDefault;
            break;
          } else if (valueAttribute.compilerElementPair != null) {
            value = valueAttribute.compilerElementPair.value;
          }
        } else if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8) { // fetch default value  - TODO: cache it?
          MethodBinding[] methods = annotationType.methods();
          if (methods != null && methods.length == 1) {
            Object defaultValue = methods[0].getDefaultValue();
            if (defaultValue instanceof Object[])
              value = defaultValue;
          }
        }
        if (value != null) {
          tagBits |= nullTagBitsFromAnnotationValue(value);
        } else {
          // neither explicit value, nor default value from DefaultLocation (1.8)
          tagBits |= TagBits.AnnotationNonNullByDefault;
        }
        break;
    }
    return tagBits;
  }

  /**
   * Convert the value() attribute of @NonNullByDefault into a bitvector a la {@link Binding#NullnessDefaultMASK}.
   * This method understands value encodings from source and binary types.
   *
   * <b>pre:</b> null annotation analysis is enabled
   */
  public static int nullTagBitsFromAnnotationValue(Object value) {
    if (value instanceof Object[]) {
      if (((Object[]) value).length == 0) {
        return Binding.NULL_UNSPECIFIED_BY_DEFAULT;
      } else {
        int bits = 0;
        for (Object single : (Object[])value)
          bits |= evaluateDefaultNullnessLocation(single);
        return bits;
      }
    } else {
      return evaluateDefaultNullnessLocation(value);
    }
  }

  private static int evaluateDefaultNullnessLocation(Object value) {
    char[] name = null;
    if (value instanceof FieldBinding) {
      name = ((FieldBinding) value).name;
    } else if (value instanceof EnumConstantSignature) {
      name = ((EnumConstantSignature) value).getEnumConstantName();
    } else if (value instanceof ElementValuePair.UnresolvedEnumConstant) {
      name = ((ElementValuePair.UnresolvedEnumConstant) value).getEnumConstantName();
    }
    if (name != null) {
      switch (name.length) {
        case 5:
          if (CharOperation.equals(name, TypeConstants.DEFAULT_LOCATION__FIELD))
            return Binding.DefaultLocationField;
          break;
        case 9:
          if (CharOperation.equals(name, TypeConstants.DEFAULT_LOCATION__PARAMETER))
            return Binding.DefaultLocationParameter;
          break;
        case 10:
          if (CharOperation.equals(name, TypeConstants.DEFAULT_LOCATION__TYPE_BOUND))
            return Binding.DefaultLocationTypeBound;
          break;
        case 11:
          if (CharOperation.equals(name, TypeConstants.DEFAULT_LOCATION__RETURN_TYPE))
            return Binding.DefaultLocationReturnType;
          break;
        case 13 :
          if (CharOperation.equals(name, TypeConstants.DEFAULT_LOCATION__TYPE_ARGUMENT))
            return Binding.DefaultLocationTypeArgument;
          break;
        case 14 :
          if (CharOperation.equals(name, TypeConstants.DEFAULT_LOCATION__TYPE_PARAMETER))
            return Binding.DefaultLocationTypeParameter;
          if (CharOperation.equals(name, TypeConstants.DEFAULT_LOCATION__ARRAY_CONTENTS))
            return Binding.DefaultLocationArrayContents;
          break;
      }
    }
    return 0;
  }
 
  static String getRetentionName(long tagBits) {
    if ((tagBits & TagBits.AnnotationRuntimeRetention) == TagBits.AnnotationRuntimeRetention) {
      // TagBits.AnnotationRuntimeRetention combines both TagBits.AnnotationClassRetention & TagBits.AnnotationSourceRetention
      return new String(UPPER_RUNTIME);
    } else if ((tagBits & TagBits.AnnotationSourceRetention) != 0) {
      return new String(UPPER_SOURCE);
    } else {
      return new String(TypeConstants.UPPER_CLASS);
    }
  }

  private static long getAnnotationRetention(ReferenceBinding binding) {
    long retention = binding.getAnnotationTagBits() & TagBits.AnnotationRetentionMASK;
    // Retention defaults to CLASS
    return retention != 0 ? retention : TagBits.AnnotationClassRetention;
  }

  public void checkRepeatableMetaAnnotation(BlockScope scope) {
   
    // `this' is the @Repeatable meta annotation, its recipient is the *repeatable* annotation type - we are at the declaration site, not the repeating use site.
   
    ReferenceBinding repeatableAnnotationType = (ReferenceBinding) this.recipient; // know it to be an annotation type. On target miss we don't get here
   
    MemberValuePair[] valuePairs = this.memberValuePairs();
    if (valuePairs == null || valuePairs.length != 1)
      return;
   
    Object value = valuePairs[0].compilerElementPair.value;
    if (!(value instanceof ReferenceBinding))
      return; // Has deeper problems, will bark elsewhere.
    ReferenceBinding containerAnnotationType = (ReferenceBinding) value;
    if (!containerAnnotationType.isAnnotationType())
      return; // Has deeper problems, will bark elsewhere.
   
    repeatableAnnotationType.setContainerAnnotationType(containerAnnotationType); // For now. May be reset later to PRB in case of problems.
    checkContainerAnnotationType(valuePairs[0], scope, containerAnnotationType, repeatableAnnotationType, false); // false => not use site, i.e declaration site error reporting requested.
  }

  public static void checkContainerAnnotationType(ASTNode culpritNode, BlockScope scope, ReferenceBinding containerAnnotationType, ReferenceBinding repeatableAnnotationType, boolean useSite) {
    MethodBinding[] annotationMethods = containerAnnotationType.methods();
    boolean sawValue = false;
    for (int i = 0, length = annotationMethods.length; i < length; ++i) {
      MethodBinding method = annotationMethods[i];
      if (CharOperation.equals(method.selector, TypeConstants.VALUE)) {
        sawValue = true;
        if (method.returnType.isArrayType() && method.returnType.dimensions() == 1) {
          ArrayBinding array = (ArrayBinding) method.returnType;
          if (TypeBinding.equalsEquals(array.elementsType(), repeatableAnnotationType)) continue;
        }
        repeatableAnnotationType.tagAsHavingDefectiveContainerType();
        scope.problemReporter().containerAnnotationTypeHasWrongValueType(culpritNode, containerAnnotationType, repeatableAnnotationType, method.returnType);
      } else {
        // Not the value() - must have default (or else isn't suitable as container)
        if ((method.modifiers & ClassFileConstants.AccAnnotationDefault) == 0) {
          repeatableAnnotationType.tagAsHavingDefectiveContainerType();
          scope.problemReporter().containerAnnotationTypeHasNonDefaultMembers(culpritNode, containerAnnotationType, method.selector);
        }
      }
    }
    if (!sawValue) {
      repeatableAnnotationType.tagAsHavingDefectiveContainerType();
      scope.problemReporter().containerAnnotationTypeMustHaveValue(culpritNode, containerAnnotationType);
    }

    if (useSite)
      checkContainingAnnotationTargetAtUse((Annotation) culpritNode, scope, containerAnnotationType, repeatableAnnotationType);
    else
      checkContainerAnnotationTypeTarget(culpritNode, scope, containerAnnotationType, repeatableAnnotationType);
   
    long annotationTypeBits = getAnnotationRetention(repeatableAnnotationType);
    long containerTypeBits = getAnnotationRetention(containerAnnotationType);
    // Due to clever layout of the bits, we can compare the absolute value directly
    if (containerTypeBits < annotationTypeBits) {
      repeatableAnnotationType.tagAsHavingDefectiveContainerType();
      scope.problemReporter().containerAnnotationTypeHasShorterRetention(culpritNode, repeatableAnnotationType, getRetentionName(annotationTypeBits), containerAnnotationType, getRetentionName(containerTypeBits));
    }
   
    if ((repeatableAnnotationType.getAnnotationTagBits() & TagBits.AnnotationDocumented) != 0 && (containerAnnotationType.getAnnotationTagBits() & TagBits.AnnotationDocumented) == 0) {
      repeatableAnnotationType.tagAsHavingDefectiveContainerType();
      scope.problemReporter().repeatableAnnotationTypeIsDocumented(culpritNode, repeatableAnnotationType, containerAnnotationType);
    }
   
    if ((repeatableAnnotationType.getAnnotationTagBits() & TagBits.AnnotationInherited) != 0 && (containerAnnotationType.getAnnotationTagBits() & TagBits.AnnotationInherited) == 0) {
      repeatableAnnotationType.tagAsHavingDefectiveContainerType();
      scope.problemReporter().repeatableAnnotationTypeIsInherited(culpritNode, repeatableAnnotationType, containerAnnotationType);
    }
  }
 
  // This is for error reporting for bad targets at annotation type declaration site (as opposed to the repeat site)
  private static void checkContainerAnnotationTypeTarget(ASTNode culpritNode, Scope scope, ReferenceBinding containerType, ReferenceBinding repeatableAnnotationType) {
    long tagBits = repeatableAnnotationType.getAnnotationTagBits();
    if ((tagBits & TagBits.AnnotationTargetMASK) == 0)
      tagBits = TagBits.SE7AnnotationTargetMASK; // absence of @Target meta-annotation implies all SE7 targets not all targets.
   
    long containerAnnotationTypeTypeTagBits = containerType.getAnnotationTagBits();
    if ((containerAnnotationTypeTypeTagBits & TagBits.AnnotationTargetMASK) == 0)
      containerAnnotationTypeTypeTagBits = TagBits.SE7AnnotationTargetMASK;

    final long targets = tagBits & TagBits.AnnotationTargetMASK;
    final long containerAnnotationTypeTargets = containerAnnotationTypeTypeTagBits & TagBits.AnnotationTargetMASK;

    if ((containerAnnotationTypeTargets & ~targets) != 0) {
      class MissingTargetBuilder {
        StringBuffer targetBuffer = new StringBuffer();
        void check(long targetMask, char[] targetName) {
          if ((containerAnnotationTypeTargets & targetMask & ~targets) != 0) {
             // if targetMask equals TagBits.AnnotationForType implies
             // TagBits.AnnotationForType is part of containerAnnotationTypeTargets
            if (targetMask == TagBits.AnnotationForType &&
                (targets & TagBits.AnnotationForTypeUse) != 0) {
              return;
            }
            add(targetName);
          }
        }
        void checkAnnotationType(char[] targetName) {
          if ((containerAnnotationTypeTargets & TagBits.AnnotationForAnnotationType) != 0 &&
              ((targets & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType))) == 0) {
            add(targetName);
          }
        }
        private void add(char[] targetName) {
          if (this.targetBuffer.length() != 0) {
            this.targetBuffer.append(", "); //$NON-NLS-1$
          }
          this.targetBuffer.append(targetName);
        }
        public String toString() {
          return this.targetBuffer.toString();
        }
        public boolean hasError() {
          return this.targetBuffer.length() != 0;
        }
      }
      MissingTargetBuilder builder = new MissingTargetBuilder();

      builder.check(TagBits.AnnotationForType, TypeConstants.TYPE);
      builder.check(TagBits.AnnotationForField, TypeConstants.UPPER_FIELD);
      builder.check(TagBits.AnnotationForMethod, TypeConstants.UPPER_METHOD);
      builder.check(TagBits.AnnotationForParameter, TypeConstants.UPPER_PARAMETER);
      builder.check(TagBits.AnnotationForConstructor, TypeConstants.UPPER_CONSTRUCTOR);
      builder.check(TagBits.AnnotationForLocalVariable, TypeConstants.UPPER_LOCAL_VARIABLE);
      builder.checkAnnotationType(TypeConstants.UPPER_ANNOTATION_TYPE);
      builder.check(TagBits.AnnotationForPackage, TypeConstants.UPPER_PACKAGE);
      builder.check(TagBits.AnnotationForTypeParameter, TypeConstants.TYPE_PARAMETER_TARGET);
      builder.check(TagBits.AnnotationForTypeUse, TypeConstants.TYPE_USE_TARGET);
      if (builder.hasError()) {
        repeatableAnnotationType.tagAsHavingDefectiveContainerType();
        scope.problemReporter().repeatableAnnotationTypeTargetMismatch(culpritNode, repeatableAnnotationType, containerType, builder.toString());
      }
    }
  }
 
  // This is for error reporting for bad targets at the repeated annotation use site (as opposed to repeatable annotation type declaration site) - Leads to better message.
  public static void checkContainingAnnotationTargetAtUse(Annotation repeatingAnnotation, BlockScope scope, TypeBinding containerAnnotationType, TypeBinding repeatingAnnotationType) {
    // check (meta)target compatibility
    if (!repeatingAnnotationType.isValidBinding()) {
      // no need to check annotation usage if missing
      return;
    }
    if (! isAnnotationTargetAllowed(repeatingAnnotation, scope, containerAnnotationType, repeatingAnnotation.recipient.kind())) {
      scope.problemReporter().disallowedTargetForContainerAnnotation(repeatingAnnotation, containerAnnotationType);
    }
  }

  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

    // we need to filter out only "pure" type use and type parameter annotations, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=392119
    if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) != 0) {
      if ((metaTagBits & TagBits.SE7AnnotationTargetMASK) == 0) {  // not a hybrid target.
        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

    if ((metaTagBits & (TagBits.AnnotationTargetMASK)) == 0) { // explicit target required for JSR308 style annotations.
      return false;
    }
    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 isRuntimeTypeVisible() {
    final TypeBinding annotationBinding = this.resolvedType;
    if (annotationBinding == null) {
      return false;
    }
    long metaTagBits = annotationBinding.getAnnotationTagBits();

    if ((metaTagBits & (TagBits.AnnotationTargetMASK)) == 0) { // explicit target required for JSR308 style annotations.
      return false;
    }
    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 boolean isRuntimeVisible() {
    final TypeBinding annotationBinding = this.resolvedType;
    if (annotationBinding == null) {
      return false;
    }
    long metaTagBits = annotationBinding.getAnnotationTagBits();
    // we need to filter out only "pure" type use and type parameter annotations, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=392119
    if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) != 0) {
      if ((metaTagBits & TagBits.SE7AnnotationTargetMASK) == 0) { // not a hybrid target.
        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);
    int defaultNullness = (int)(tagBits & Binding.NullnessDefaultMASK);
    tagBits &= ~Binding.NullnessDefaultMASK;

    // record annotation positions in the compilation result
    scope.referenceCompilationUnit().recordSuppressWarnings(IrritantSet.NLS, null, this.sourceStart, this.declarationSourceEnd);
    if (this.recipient != null) {
      int kind = this.recipient.kind();
      if (tagBits != 0 || defaultNullness != 0) {
        // tag bits onto recipient
        switch (kind) {
          case Binding.PACKAGE :
            ((PackageBinding)this.recipient).tagBits |= tagBits;
            break;
          case Binding.TYPE :
          case Binding.GENERIC_TYPE :
            SourceTypeBinding sourceType = (SourceTypeBinding) this.recipient;
            if ((tagBits & TagBits.AnnotationRepeatable) == 0 || sourceType.isAnnotationType()) // don't set AnnotationRepeatable on non-annotation types.
              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);
            }
            sourceType.defaultNullness |= defaultNullness;
            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);
            }
            long nullBits = sourceMethod.tagBits & TagBits.AnnotationNullMASK;
            if (nullBits == TagBits.AnnotationNullMASK) {
              scope.problemReporter().contradictoryNullAnnotations(this);
              sourceMethod.tagBits &= ~TagBits.AnnotationNullMASK; // avoid secondary problems
            }
            if (nullBits != 0 && sourceMethod.isConstructor()) {
              if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8)
                scope.problemReporter().nullAnnotationUnsupportedLocation(this);
              // for declaration annotations the inapplicability will be reported below
              sourceMethod.tagBits &= ~TagBits.AnnotationNullMASK;
            }
            sourceMethod.defaultNullness |= defaultNullness;
            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);
            }
            // fields don't yet have their type resolved, in 1.8 null annotations
            // will be transfered from the field to its type during STB.resolveTypeFor().
            if ((sourceField.tagBits & TagBits.AnnotationNullMASK) == TagBits.AnnotationNullMASK) {
              scope.problemReporter().contradictoryNullAnnotations(this);
              sourceField.tagBits &= ~TagBits.AnnotationNullMASK; // avoid secondary problems
            }
            break;
          case Binding.LOCAL :
            LocalVariableBinding variable = (LocalVariableBinding) this.recipient;
            variable.tagBits |= tagBits;
            if ((variable.tagBits & TagBits.AnnotationNullMASK) == TagBits.AnnotationNullMASK) {
              scope.problemReporter().contradictoryNullAnnotations(this);
              variable.tagBits &= ~TagBits.AnnotationNullMASK; // avoid secondary problems
            }
            if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
              LocalDeclaration localDeclaration = variable.declaration;
              recordSuppressWarnings(scope, localDeclaration.declarationSourceStart, localDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
            }
            break;
        }
      }
      checkAnnotationTarget(this, scope, annotationType, kind);
    }
    return this.resolvedType;
  }

  static boolean isAnnotationTargetAllowed(Annotation annotation, BlockScope scope, TypeBinding annotationType, int kind) {
    long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference
    if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) {
      // does not specify any target restriction - all locations supported in Java 7 and before are possible
      if (kind == Binding.TYPE_PARAMETER || kind == Binding.TYPE_USE) {
        scope.problemReporter().explitAnnotationTargetRequired(annotation);
      }
      return true;
    }

    // https://bugs.eclipse.org/bugs/show_bug.cgi?id=391201
    if ((metaTagBits & TagBits.SE7AnnotationTargetMASK) == 0
        && (metaTagBits & (TagBits.AnnotationForTypeUse | TagBits.AnnotationForTypeParameter)) != 0) {
      if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) {
        switch (kind) {
          case Binding.PACKAGE :
          case Binding.TYPE :
          case Binding.GENERIC_TYPE :
          case Binding.METHOD :
          case Binding.FIELD :
          case Binding.LOCAL :
            scope.problemReporter().invalidUsageOfTypeAnnotations(annotation);
        }
      }
    }
    switch (kind) {
      case Binding.PACKAGE :
        if ((metaTagBits & TagBits.AnnotationForPackage) != 0)
          return true;
        break;
      case Binding.TYPE_USE :
        if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
          // jsr 308
          return true;
        }
        if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) {
          // already reported as syntax error; don't report secondary problems
          return true;
        }
        break;
      case Binding.TYPE :
      case Binding.GENERIC_TYPE :
        if (((ReferenceBinding)annotation.recipient).isAnnotationType()) {
          if ((metaTagBits & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0)
          return true;
        } else if ((metaTagBits & (TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0) {
          return true;
        } else if ((metaTagBits & TagBits.AnnotationForPackage) != 0) {
          if (CharOperation.equals(((ReferenceBinding) annotation.recipient).sourceName, TypeConstants.PACKAGE_INFO_NAME))
            return true;
        }
        break;
      case Binding.METHOD :
        MethodBinding methodBinding = (MethodBinding) annotation.recipient;
        if (methodBinding.isConstructor()) {
          if ((metaTagBits & (TagBits.AnnotationForConstructor | TagBits.AnnotationForTypeUse)) != 0)
            return true;
        } else if ((metaTagBits & TagBits.AnnotationForMethod) != 0) {
          return true;
        } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
          SourceTypeBinding sourceType = (SourceTypeBinding) methodBinding.declaringClass;
          MethodDeclaration methodDecl = (MethodDeclaration) sourceType.scope.referenceContext.declarationOf(methodBinding);
          if (isTypeUseCompatible(methodDecl.returnType, scope)) {
            return true;
          }
        }
        break;
      case Binding.FIELD :
        if ((metaTagBits & TagBits.AnnotationForField) != 0) {
          return true;
        } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
          FieldBinding sourceField = (FieldBinding) annotation.recipient;
          SourceTypeBinding sourceType = (SourceTypeBinding) sourceField.declaringClass;
          FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(sourceField);
          if (isTypeUseCompatible(fieldDeclaration.type, scope)) {
            return true;
          }
        }
        break;
      case Binding.LOCAL :
        LocalVariableBinding localVariableBinding = (LocalVariableBinding) annotation.recipient;
        if ((localVariableBinding.tagBits & TagBits.IsArgument) != 0) {
          if ((metaTagBits & TagBits.AnnotationForParameter) != 0) {
            return true;
          } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
            if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) {
              return true;
            }
          }
        } else if ((annotationType.tagBits & TagBits.AnnotationForLocalVariable) != 0) {
          return true;
        } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
          if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) {
            return true;
          }
        }
        break;
      case Binding.TYPE_PARAMETER : // jsr308
        // https://bugs.eclipse.org/bugs/show_bug.cgi?id=391196
        if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) != 0) {
          return true;
        }
    }
    return false;
  }

  static void checkAnnotationTarget(Annotation annotation, BlockScope scope, ReferenceBinding annotationType, int kind) {
    // check (meta)target compatibility
    if (!annotationType.isValidBinding()) {
      // no need to check annotation usage if missing
      return;
    }
    if (! isAnnotationTargetAllowed(annotation, scope, annotationType, kind)) {
      scope.problemReporter().disallowedTargetForAnnotation(annotation);
    }
  }

  /**
   * Check to see if a repeating annotation is in fact of a container annotation type for an annotation which is also present at the same target.
   * @param scope The scope (for error reporting)
   * @param repeatedAnnotationType Type of annotation which has been repeated (to check for possibly being a container for a repeatable annotation)
   * @param sourceAnnotations The annotations to check
   */
  public static void checkForInstancesOfRepeatableWithRepeatingContainerAnnotation(BlockScope scope, ReferenceBinding repeatedAnnotationType, Annotation[] sourceAnnotations) {
    // Fail fast if the repeating annotation type can't be a container, anyway
    MethodBinding[] valueMethods = repeatedAnnotationType.getMethods(TypeConstants.VALUE);
    if (valueMethods.length != 1) return; // No violations possible
   
    TypeBinding methodReturnType = valueMethods[0].returnType;
    // value must be an array
    if (! methodReturnType.isArrayType() || methodReturnType.dimensions() != 1) return;
   
    ArrayBinding array = (ArrayBinding) methodReturnType;
    TypeBinding elementsType = array.elementsType();
    if (! elementsType.isRepeatableAnnotationType()) return; // Can't be a problem, then
   
    for (int i= 0; i < sourceAnnotations.length; ++i) {
      Annotation annotation = sourceAnnotations[i];
      if (TypeBinding.equalsEquals(elementsType, annotation.resolvedType)) {
        scope.problemReporter().repeatableAnnotationWithRepeatingContainer(annotation, repeatedAnnotationType);
        return; // One is enough for this annotation type
      }
    }
  }

  // Check and answer if an attempt to annotate a package is being made. Error should be reported by caller.
  public static boolean isTypeUseCompatible(TypeReference reference, Scope scope) {
    if (reference != null && !(reference instanceof SingleTypeReference)) {
      Binding binding = scope.getPackage(reference.getTypeName());
      // In case of ProblemReferenceBinding, don't report additional error
      if (binding instanceof PackageBinding) {
        return false;
      }
    }
    return true;
  }
 
  // Complain if an attempt to annotate the enclosing type of a static member type is being made.
  public static void isTypeUseCompatible(TypeReference reference, Scope scope, Annotation[] annotations) {
    if (annotations == null || reference == null || reference.getAnnotatableLevels() == 1)
      return;
    if (scope.environment().globalOptions.sourceLevel < ClassFileConstants.JDK1_8)
      return;

    TypeBinding resolvedType = reference.resolvedType == null ? null : reference.resolvedType.leafComponentType();
    if (resolvedType == null || !resolvedType.isNestedType())
      return;

    nextAnnotation:
      for (int i = 0, annotationsLength = annotations.length; i < annotationsLength; i++) {
        Annotation annotation = annotations[i];
        long metaTagBits = annotation.resolvedType.getAnnotationTagBits();
        if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0 && (metaTagBits & TagBits.SE7AnnotationTargetMASK) == 0) {
          ReferenceBinding currentType = (ReferenceBinding) resolvedType;
          while (currentType.isNestedType()) {
            if (currentType.isStatic()) {
              QualifiedTypeReference.rejectAnnotationsOnStaticMemberQualififer(scope, currentType, new Annotation [] { annotation });
              continue nextAnnotation;
            } else {
              int id = annotation.resolvedType.id;
              if (id == TypeIds.T_ConfiguredAnnotationNonNull || id == TypeIds.T_ConfiguredAnnotationNullable) {
                scope.problemReporter().nullAnnotationUnsupportedLocation(annotation);
                continue nextAnnotation;
              }
            }
            currentType = currentType.enclosingType();
          }
        }
      }
  }

  public abstract void traverse(ASTVisitor visitor, BlockScope scope);

  public abstract void traverse(ASTVisitor visitor, ClassScope scope);

  public Annotation getPersistibleAnnotation() {
    return this.persistibleAnnotation;      // will be this for non-repeating annotation, the container for the first of the repeating ones and null for the followers.
  }
 
  public void setPersistibleAnnotation(ContainerAnnotation container) {
    this.persistibleAnnotation = container; // will be a legitimate container for the first of the repeating ones and null for the followers.
  }
}
TOP

Related Classes of org.eclipse.jdt.internal.compiler.ast.LocationCollector

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.