public void traverse(ASTVisitor visitor, BlockScope scope) {

    if (visitor.visit(this, scope)) {
      int dimensionsLength = dimensions.length;
      type.traverse(visitor, scope);
      for (int i = 0; i < dimensionsLength; i++) {
        if (dimensions[i] != null) dimensions[i].traverse(visitor, scope);
      }
      if (initializer != null) initializer.traverse(visitor, scope);
    }
    visitor.endVisit(this, scope);
  }
  /** Record the thrown exception type bindings in the corresponding type references. */
  public void bindThrownExceptions() {

    if (this.thrownExceptions != null
        && this.binding != null
        && this.binding.thrownExceptions != null) {
      int thrownExceptionLength = this.thrownExceptions.length;
      int length = this.binding.thrownExceptions.length;
      if (length == thrownExceptionLength) {
        for (int i = 0; i < length; i++) {
          this.thrownExceptions[i].resolvedType = this.binding.thrownExceptions[i];
        }
      } else {
        int bindingIndex = 0;
        for (int i = 0; i < thrownExceptionLength && bindingIndex < length; i++) {
          TypeReference thrownException = this.thrownExceptions[i];
          ReferenceBinding thrownExceptionBinding = this.binding.thrownExceptions[bindingIndex];
          char[][] bindingCompoundName = thrownExceptionBinding.compoundName;
          if (bindingCompoundName == null) continue; // skip problem case
          if (thrownException instanceof SingleTypeReference) {
            // single type reference
            int lengthName = bindingCompoundName.length;
            char[] thrownExceptionTypeName = thrownException.getTypeName()[0];
            if (CharOperation.equals(
                thrownExceptionTypeName, bindingCompoundName[lengthName - 1])) {
              thrownException.resolvedType = thrownExceptionBinding;
              bindingIndex++;
            }
          } else {
            // qualified type reference
            if (CharOperation.equals(thrownException.getTypeName(), bindingCompoundName)) {
              thrownException.resolvedType = thrownExceptionBinding;
              bindingIndex++;
            }
          }
        }
      }
    }
  }
  public StringBuffer printExpression(int indent, StringBuffer output) {

    output.append("new "); // $NON-NLS-1$
    type.print(0, output);
    for (int i = 0; i < dimensions.length; i++) {
      if (dimensions[i] == null) output.append("[]"); // $NON-NLS-1$
      else {
        output.append('[');
        dimensions[i].printExpression(0, output);
        output.append(']');
      }
    }
    if (initializer != null) initializer.printExpression(0, output);
    return output;
  }
  public TypeBinding resolveType(BlockScope scope) {

    // Build an array type reference using the current dimensions
    // The parser does not check for the fact that dimension may be null
    // only at the -end- like new int [4][][]. The parser allows new int[][4][]
    // so this must be checked here......(this comes from a reduction to LL1 grammar)

    TypeBinding referenceType = type.resolveType(scope, true /* check bounds*/);

    // will check for null after dimensions are checked
    constant = Constant.NotAConstant;
    if (referenceType == VoidBinding) {
      scope.problemReporter().cannotAllocateVoidArray(this);
      referenceType = null;
    }

    // check the validity of the dimension syntax (and test for all null dimensions)
    int explicitDimIndex = -1;
    loop:
    for (int i = dimensions.length; --i >= 0; ) {
      if (dimensions[i] != null) {
        if (explicitDimIndex < 0) explicitDimIndex = i;
      } else if (explicitDimIndex > 0) {
        // should not have an empty dimension before an non-empty one
        scope.problemReporter().incorrectLocationForNonEmptyDimension(this, explicitDimIndex);
        break loop;
      }
    }

    // explicitDimIndex < 0 says if all dimensions are nulled
    // when an initializer is given, no dimension must be specified
    if (initializer == null) {
      if (explicitDimIndex < 0) {
        scope.problemReporter().mustDefineDimensionsOrInitializer(this);
      }
      // allow new List<?>[5] - only check for generic array when no initializer, since also checked
      // inside initializer resolution
      if (referenceType != null && !referenceType.isReifiable()) {
        scope.problemReporter().illegalGenericArray(referenceType, this);
      }
    } else if (explicitDimIndex >= 0) {
      scope.problemReporter().cannotDefineDimensionsAndInitializer(this);
    }

    // dimensions resolution
    for (int i = 0; i <= explicitDimIndex; i++) {
      if (dimensions[i] != null) {
        TypeBinding dimensionType = dimensions[i].resolveTypeExpecting(scope, IntBinding);
        if (dimensionType != null) {
          dimensions[i].computeConversion(scope, IntBinding, dimensionType);
        }
      }
    }

    // building the array binding
    if (referenceType != null) {
      if (dimensions.length > 255) {
        scope.problemReporter().tooManyDimensions(this);
      }
      this.resolvedType = scope.createArrayType(referenceType, dimensions.length);

      // check the initializer
      if (initializer != null) {
        if ((initializer.resolveTypeExpecting(scope, this.resolvedType)) != null)
          initializer.binding = (ArrayBinding) this.resolvedType;
      }
    }
    return this.resolvedType;
  }
 public TypeReference getTypeReference(int dim) {
   /* build a Reference on a variable that may be qualified or not
    * This variable is a type reference and dim will be its dimensions
    */
   Annotation[][] annotationsOnDimensions = null;
   TypeReference ref;
   int length = this.identifierLengthStack[this.identifierLengthPtr--];
   if (length < 0) { // flag for precompiled type reference on base types
     annotationsOnDimensions = getAnnotationsOnDimensions(dim);
     ref = TypeReference.baseTypeReference(-length, dim, annotationsOnDimensions);
     ref.sourceStart = this.intStack[this.intPtr--];
     if (dim == 0) {
       ref.sourceEnd = this.intStack[this.intPtr--];
     } else {
       this.intPtr--; // no need to use this position as it is an array
       ref.sourceEnd = this.rBracketPosition;
     }
     if (this.reportReferenceInfo) {
       this.requestor.acceptTypeReference(
           ref.getParameterizedTypeName(), ref.sourceStart, ref.sourceEnd);
     }
   } else {
     int numberOfIdentifiers =
         this.genericsIdentifiersLengthStack[this.genericsIdentifiersLengthPtr--];
     if (length != numberOfIdentifiers || this.genericsLengthStack[this.genericsLengthPtr] != 0) {
       // generic type
       ref = getTypeReferenceForGenericType(dim, length, numberOfIdentifiers);
       if (this.reportReferenceInfo) {
         if (length == 1 && numberOfIdentifiers == 1) {
           ParameterizedSingleTypeReference parameterizedSingleTypeReference =
               (ParameterizedSingleTypeReference) ref;
           this.requestor.acceptTypeReference(
               parameterizedSingleTypeReference.token,
               parameterizedSingleTypeReference.sourceStart);
         } else {
           ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference =
               (ParameterizedQualifiedTypeReference) ref;
           this.requestor.acceptTypeReference(
               parameterizedQualifiedTypeReference.tokens,
               parameterizedQualifiedTypeReference.sourceStart,
               parameterizedQualifiedTypeReference.sourceEnd);
         }
       }
     } else if (length == 1) {
       // single type reference
       this.genericsLengthPtr--; // pop the 0
       if (dim == 0) {
         ref =
             new SingleTypeReference(
                 this.identifierStack[this.identifierPtr],
                 this.identifierPositionStack[this.identifierPtr--]);
         if (this.reportReferenceInfo) {
           this.requestor.acceptTypeReference(((SingleTypeReference) ref).token, ref.sourceStart);
         }
       } else {
         annotationsOnDimensions = getAnnotationsOnDimensions(dim);
         ref =
             new ArrayTypeReference(
                 this.identifierStack[this.identifierPtr],
                 dim,
                 annotationsOnDimensions,
                 this.identifierPositionStack[this.identifierPtr--]);
         ref.sourceEnd = this.endPosition;
         if (annotationsOnDimensions != null) {
           ref.bits |= ASTNode.HasTypeAnnotations;
         }
         if (this.reportReferenceInfo) {
           this.requestor.acceptTypeReference(((ArrayTypeReference) ref).token, ref.sourceStart);
         }
       }
     } else { // Qualified type reference
       this.genericsLengthPtr--;
       char[][] tokens = new char[length][];
       this.identifierPtr -= length;
       long[] positions = new long[length];
       System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length);
       System.arraycopy(
           this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length);
       if (dim == 0) {
         ref = new QualifiedTypeReference(tokens, positions);
         if (this.reportReferenceInfo) {
           this.requestor.acceptTypeReference(
               ((QualifiedTypeReference) ref).tokens, ref.sourceStart, ref.sourceEnd);
         }
       } else {
         annotationsOnDimensions = getAnnotationsOnDimensions(dim);
         ref = new ArrayQualifiedTypeReference(tokens, dim, annotationsOnDimensions, positions);
         ref.sourceEnd = this.endPosition;
         if (annotationsOnDimensions != null) {
           ref.bits |= ASTNode.HasTypeAnnotations;
         }
         if (this.reportReferenceInfo) {
           this.requestor.acceptTypeReference(
               ((ArrayQualifiedTypeReference) ref).tokens, ref.sourceStart, ref.sourceEnd);
         }
       }
     }
   }
   int levels = ref.getAnnotatableLevels();
   for (int i = levels - 1; i >= 0; i--) {
     if ((length = this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr--]) != 0) {
       if (ref.annotations == null) ref.annotations = new Annotation[levels][];
       System.arraycopy(
           this.typeAnnotationStack,
           (this.typeAnnotationPtr -= length) + 1,
           ref.annotations[i] = new Annotation[length],
           0,
           length);
       if (i == 0) {
         ref.sourceStart = ref.annotations[0][0].sourceStart;
       }
       ref.bits |= ASTNode.HasTypeAnnotations;
     }
   }
   return ref;
 }
 public TypeReference getTypeReference(int dim) {
   /* build a Reference on a variable that may be qualified or not
    * This variable is a type reference and dim will be its dimensions
    */
   int length = this.identifierLengthStack[this.identifierLengthPtr--];
   if (length < 0) { // flag for precompiled type reference on base types
     TypeReference ref = TypeReference.baseTypeReference(-length, dim);
     ref.sourceStart = this.intStack[this.intPtr--];
     if (dim == 0) {
       ref.sourceEnd = this.intStack[this.intPtr--];
     } else {
       this.intPtr--; // no need to use this position as it is an array
       ref.sourceEnd = this.endPosition;
     }
     if (this.reportReferenceInfo) {
       this.requestor.acceptTypeReference(
           ref.getParameterizedTypeName(), ref.sourceStart, ref.sourceEnd);
     }
     return ref;
   } else {
     int numberOfIdentifiers =
         this.genericsIdentifiersLengthStack[this.genericsIdentifiersLengthPtr--];
     if (length != numberOfIdentifiers || this.genericsLengthStack[this.genericsLengthPtr] != 0) {
       // generic type
       TypeReference ref = getTypeReferenceForGenericType(dim, length, numberOfIdentifiers);
       if (this.reportReferenceInfo) {
         if (length == 1 && numberOfIdentifiers == 1) {
           ParameterizedSingleTypeReference parameterizedSingleTypeReference =
               (ParameterizedSingleTypeReference) ref;
           this.requestor.acceptTypeReference(
               parameterizedSingleTypeReference.token,
               parameterizedSingleTypeReference.sourceStart);
         } else {
           ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference =
               (ParameterizedQualifiedTypeReference) ref;
           this.requestor.acceptTypeReference(
               parameterizedQualifiedTypeReference.tokens,
               parameterizedQualifiedTypeReference.sourceStart,
               parameterizedQualifiedTypeReference.sourceEnd);
         }
       }
       return ref;
     } else if (length == 1) {
       // single variable reference
       this.genericsLengthPtr--; // pop the 0
       if (dim == 0) {
         SingleTypeReference ref =
             new SingleTypeReference(
                 this.identifierStack[this.identifierPtr],
                 this.identifierPositionStack[this.identifierPtr--]);
         if (this.reportReferenceInfo) {
           this.requestor.acceptTypeReference(ref.token, ref.sourceStart);
         }
         return ref;
       } else {
         ArrayTypeReference ref =
             new ArrayTypeReference(
                 this.identifierStack[this.identifierPtr],
                 dim,
                 this.identifierPositionStack[this.identifierPtr--]);
         ref.sourceEnd = this.endPosition;
         if (this.reportReferenceInfo) {
           this.requestor.acceptTypeReference(ref.token, ref.sourceStart);
         }
         return ref;
       }
     } else { // Qualified variable reference
       this.genericsLengthPtr--;
       char[][] tokens = new char[length][];
       this.identifierPtr -= length;
       long[] positions = new long[length];
       System.arraycopy(this.identifierStack, this.identifierPtr + 1, tokens, 0, length);
       System.arraycopy(
           this.identifierPositionStack, this.identifierPtr + 1, positions, 0, length);
       if (dim == 0) {
         QualifiedTypeReference ref = new QualifiedTypeReference(tokens, positions);
         if (this.reportReferenceInfo) {
           this.requestor.acceptTypeReference(ref.tokens, ref.sourceStart, ref.sourceEnd);
         }
         return ref;
       } else {
         ArrayQualifiedTypeReference ref = new ArrayQualifiedTypeReference(tokens, dim, positions);
         ref.sourceEnd = this.endPosition;
         if (this.reportReferenceInfo) {
           this.requestor.acceptTypeReference(ref.tokens, ref.sourceStart, ref.sourceEnd);
         }
         return ref;
       }
     }
   }
 }