protected void consumeSingleTypeImportDeclarationName() {
    // SingleTypeImportDeclarationName ::= 'import' Name
    /* push an ImportRef build from the last name
    stored in the identifier stack. */

    ImportReference impt;
    int length;
    char[][] tokens = new char[length = this.identifierLengthStack[this.identifierLengthPtr--]][];
    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);
    pushOnAstStack(
        impt = newImportReference(tokens, positions, false, ClassFileConstants.AccDefault));

    if (this.currentToken == TokenNameSEMICOLON) {
      impt.declarationSourceEnd = this.scanner.currentPosition - 1;
    } else {
      impt.declarationSourceEnd = impt.sourceEnd;
    }
    impt.declarationEnd = impt.declarationSourceEnd;
    // this.endPosition is just before the ;
    impt.declarationSourceStart = this.intStack[this.intPtr--];

    // recovery
    if (this.currentElement != null) {
      this.lastCheckPoint = impt.declarationSourceEnd + 1;
      this.currentElement = this.currentElement.add(impt, 0);
      this.lastIgnoredToken = -1;
      this.restartRecovery = true; // used to avoid branching back into the regular automaton
    }
    if (this.reportReferenceInfo) {
      this.requestor.acceptTypeReference(impt.tokens, impt.sourceStart, impt.sourceEnd);
    }
  }
  public StringBuffer print(int indent, StringBuffer output) {

    if (currentPackage != null) {
      printIndent(indent, output).append("package "); // $NON-NLS-1$
      currentPackage.print(0, output, false).append(";\n"); // $NON-NLS-1$
    }
    if (imports != null)
      for (int i = 0; i < imports.length; i++) {
        if (imports[i].isInternal()) continue;
        printIndent(indent, output).append("import "); // $NON-NLS-1$
        ImportReference currentImport = imports[i];
        currentImport.print(0, output).append(";\n"); // $NON-NLS-1$
      }

    if (types != null) {
      for (int i = 0; i < types.length; i++) {
        types[i].print(indent, output).append("\n"); // $NON-NLS-1$
      }
    }
    if (statements != null) {
      for (int i = 0; i < statements.length; i++) {
        statements[i].printStatement(indent, output).append("\n"); // $NON-NLS-1$
      }
    }
    return output;
  }
  public void checkAndSetImports() { // AspectJ Extension - raised to public
    if (this.referenceContext.imports == null) {
      this.imports = getDefaultImports();
      return;
    }

    // allocate the import array, add java.lang.* by default
    int numberOfStatements = this.referenceContext.imports.length;
    int numberOfImports = numberOfStatements + 1;
    for (int i = 0; i < numberOfStatements; i++) {
      ImportReference importReference = this.referenceContext.imports[i];
      if (((importReference.bits & ASTNode.OnDemand) != 0)
          && CharOperation.equals(TypeConstants.JAVA_LANG, importReference.tokens)
          && !importReference.isStatic()) {
        numberOfImports--;
        break;
      }
    }
    ImportBinding[] resolvedImports = new ImportBinding[numberOfImports];
    resolvedImports[0] = getDefaultImports()[0];
    int index = 1;

    nextImport:
    for (int i = 0; i < numberOfStatements; i++) {
      ImportReference importReference = this.referenceContext.imports[i];
      char[][] compoundName = importReference.tokens;

      // skip duplicates or imports of the current package
      for (int j = 0; j < index; j++) {
        ImportBinding resolved = resolvedImports[j];
        if (resolved.onDemand == ((importReference.bits & ASTNode.OnDemand) != 0)
            && resolved.isStatic() == importReference.isStatic())
          if (CharOperation.equals(compoundName, resolvedImports[j].compoundName))
            continue nextImport;
      }

      if ((importReference.bits & ASTNode.OnDemand) != 0) {
        if (CharOperation.equals(compoundName, this.currentPackageName)) continue nextImport;

        Binding importBinding = findImport(compoundName, compoundName.length);
        if (!importBinding.isValidBinding()
            || (importReference.isStatic() && importBinding instanceof PackageBinding))
          continue nextImport; // we report all problems in faultInImports()
        resolvedImports[index++] =
            new ImportBinding(compoundName, true, importBinding, importReference);
      } else {
        // resolve single imports only when the last name matches
        resolvedImports[index++] = new ImportBinding(compoundName, false, null, importReference);
      }
    }

    // shrink resolvedImports... only happens if an error was reported
    if (resolvedImports.length > index)
      System.arraycopy(resolvedImports, 0, resolvedImports = new ImportBinding[index], 0, index);
    this.imports = resolvedImports;
  }
  protected void consumeSingleStaticImportDeclarationName() {
    // SingleTypeImportDeclarationName ::= 'import' 'static' Name
    ImportReference impt;
    int length;
    char[][] tokens = new char[length = this.identifierLengthStack[this.identifierLengthPtr--]][];
    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);
    pushOnAstStack(
        impt = newImportReference(tokens, positions, false, ClassFileConstants.AccStatic));

    this.modifiers = ClassFileConstants.AccDefault;
    this.modifiersSourceStart = -1; // <-- see comment into modifiersFlag(int)

    if (this.currentToken == TokenNameSEMICOLON) {
      impt.declarationSourceEnd = this.scanner.currentPosition - 1;
    } else {
      impt.declarationSourceEnd = impt.sourceEnd;
    }
    impt.declarationEnd = impt.declarationSourceEnd;
    // this.endPosition is just before the ;
    impt.declarationSourceStart = this.intStack[this.intPtr--];

    if (!this.statementRecoveryActivated
        && this.options.sourceLevel < ClassFileConstants.JDK1_5
        && this.lastErrorEndPositionBeforeRecovery < this.scanner.currentPosition) {
      impt.modifiers =
          ClassFileConstants
              .AccDefault; // convert the static import reference to a non-static importe reference
      problemReporter().invalidUsageOfStaticImports(impt);
    }

    // recovery
    if (this.currentElement != null) {
      this.lastCheckPoint = impt.declarationSourceEnd + 1;
      this.currentElement = this.currentElement.add(impt, 0);
      this.lastIgnoredToken = -1;
      this.restartRecovery = true; // used to avoid branching back into the regular automaton
    }
    if (this.reportReferenceInfo) {
      // Name for static import is TypeName '.' Identifier
      // => accept unknown ref on identifier
      int tokensLength = impt.tokens.length - 1;
      int start = (int) (impt.sourcePositions[tokensLength] >>> 32);
      char[] last = impt.tokens[tokensLength];
      // accept all possible kind for last name, index users will have to select the right one...
      // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=86901
      this.requestor.acceptFieldReference(last, start);
      this.requestor.acceptMethodReference(last, 0, start);
      this.requestor.acceptTypeReference(last, start);
      // accept type name
      if (tokensLength > 0) {
        char[][] compoundName = new char[tokensLength][];
        System.arraycopy(impt.tokens, 0, compoundName, 0, tokensLength);
        int end = (int) impt.sourcePositions[tokensLength - 1];
        this.requestor.acceptTypeReference(compoundName, impt.sourceStart, end);
      }
    }
  }
  public StringBuffer print(int indent, StringBuffer output) {
    if (this.currentPackage != null) {
      printIndent(indent, output).append("package "); // $NON-NLS-1$
      this.currentPackage.print(0, output, false).append(";\n"); // $NON-NLS-1$
    }
    if (this.imports != null)
      for (int i = 0; i < this.imports.length; i++) {
        printIndent(indent, output).append("import "); // $NON-NLS-1$
        ImportReference currentImport = this.imports[i];
        if (currentImport.isStatic()) {
          output.append("static "); // $NON-NLS-1$
        }
        currentImport.print(0, output).append(";\n"); // $NON-NLS-1$
      }

    if (this.types != null) {
      for (int i = 0; i < this.types.length; i++) {
        this.types[i].print(indent, output).append("\n"); // $NON-NLS-1$
      }
    }
    return output;
  }
  protected void consumeStaticImportOnDemandDeclarationName() {
    // TypeImportOnDemandDeclarationName ::= 'import' 'static' Name '.' '*'
    /* push an ImportRef build from the last name
    stored in the identifier stack. */

    ImportReference impt;
    int length;
    char[][] tokens = new char[length = this.identifierLengthStack[this.identifierLengthPtr--]][];
    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);
    pushOnAstStack(
        impt = new ImportReference(tokens, positions, true, ClassFileConstants.AccStatic));

    // star end position
    impt.trailingStarPosition = this.intStack[this.intPtr--];
    this.modifiers = ClassFileConstants.AccDefault;
    this.modifiersSourceStart = -1; // <-- see comment into modifiersFlag(int)

    if (this.currentToken == TokenNameSEMICOLON) {
      impt.declarationSourceEnd = this.scanner.currentPosition - 1;
    } else {
      impt.declarationSourceEnd = impt.sourceEnd;
    }
    impt.declarationEnd = impt.declarationSourceEnd;
    // this.endPosition is just before the ;
    impt.declarationSourceStart = this.intStack[this.intPtr--];

    if (!this.statementRecoveryActivated
        && this.options.sourceLevel < ClassFileConstants.JDK1_5
        && this.lastErrorEndPositionBeforeRecovery < this.scanner.currentPosition) {
      impt.modifiers =
          ClassFileConstants
              .AccDefault; // convert the static import reference to a non-static importe reference
      problemReporter().invalidUsageOfStaticImports(impt);
    }

    // recovery
    if (this.currentElement != null) {
      this.lastCheckPoint = impt.declarationSourceEnd + 1;
      this.currentElement = this.currentElement.add(impt, 0);
      this.lastIgnoredToken = -1;
      this.restartRecovery = true; // used to avoid branching back into the regular automaton
    }
    if (this.reportReferenceInfo) {
      this.requestor.acceptTypeReference(impt.tokens, impt.sourceStart, impt.sourceEnd);
    }
  }
  /**
   * Checks for duplicates. If all ok, records the importBinding returns -1 when this import is
   * flagged as duplicate.
   *
   * @param importBinding
   * @param typesBySimpleNames
   * @param importReference
   * @param compoundName
   * @return -1 when this import is flagged as duplicate, importPtr otherwise.
   */
  private int checkAndRecordImportBinding(
      Binding importBinding,
      HashtableOfType typesBySimpleNames,
      ImportReference importReference,
      char[][] compoundName) {
    ReferenceBinding conflictingType = null;
    if (importBinding instanceof MethodBinding) {
      conflictingType = (ReferenceBinding) getType(compoundName, compoundName.length);
      if (!conflictingType.isValidBinding()
          || (importReference.isStatic() && !conflictingType.isStatic())) conflictingType = null;
    }
    // collisions between an imported static field & a type should be checked according to spec...
    // but currently not by javac
    final char[] name = compoundName[compoundName.length - 1];
    if (importBinding instanceof ReferenceBinding || conflictingType != null) {
      ReferenceBinding referenceBinding =
          conflictingType == null ? (ReferenceBinding) importBinding : conflictingType;
      ReferenceBinding typeToCheck =
          referenceBinding.problemId() == ProblemReasons.Ambiguous
              ? ((ProblemReferenceBinding) referenceBinding).closestMatch
              : referenceBinding;
      if (importReference.isTypeUseDeprecated(typeToCheck, this))
        problemReporter().deprecatedType(typeToCheck, importReference);

      ReferenceBinding existingType = typesBySimpleNames.get(name);
      if (existingType != null) {
        // duplicate test above should have caught this case, but make sure
        if (TypeBinding.equalsEquals(existingType, referenceBinding)) {
          // https://bugs.eclipse.org/bugs/show_bug.cgi?id=302865
          // Check all resolved imports to see if this import qualifies as a duplicate
          for (int j = 0; j < this.importPtr; j++) {
            ImportBinding resolved = this.tempImports[j];
            if (resolved instanceof ImportConflictBinding) {
              ImportConflictBinding importConflictBinding = (ImportConflictBinding) resolved;
              if (TypeBinding.equalsEquals(
                  importConflictBinding.conflictingTypeBinding, referenceBinding)) {
                if (!importReference.isStatic()) {
                  // resolved is implicitly static
                  problemReporter().duplicateImport(importReference);
                  recordImportBinding(
                      new ImportBinding(compoundName, false, importBinding, importReference));
                }
              }
            } else if (resolved.resolvedImport == referenceBinding) {
              if (importReference.isStatic() != resolved.isStatic()) {
                problemReporter().duplicateImport(importReference);
                recordImportBinding(
                    new ImportBinding(compoundName, false, importBinding, importReference));
              }
            }
          }
          return -1;
        }
        // either the type collides with a top level type or another imported type
        for (int j = 0, length = this.topLevelTypes.length; j < length; j++) {
          if (CharOperation.equals(this.topLevelTypes[j].sourceName, existingType.sourceName)) {
            problemReporter().conflictingImport(importReference);
            return -1;
          }
        }
        if (importReference.isStatic()
            && importBinding instanceof ReferenceBinding
            && compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8) {
          // 7.5.3 says nothing about collision of single static imports and JDK8 tolerates them,
          // though use is flagged.
          for (int j = 0; j < this.importPtr; j++) {
            ImportBinding resolved = this.tempImports[j];
            if (resolved.isStatic()
                && resolved.resolvedImport instanceof ReferenceBinding
                && importBinding != resolved.resolvedImport) {
              if (CharOperation.equals(
                  name, resolved.compoundName[resolved.compoundName.length - 1])) {
                ReferenceBinding type = (ReferenceBinding) resolved.resolvedImport;
                resolved.resolvedImport =
                    new ProblemReferenceBinding(
                        new char[][] {name}, type, ProblemReasons.Ambiguous);
                return -1;
              }
            }
          }
        }
        problemReporter().duplicateImport(importReference);
        return -1;
      }
      typesBySimpleNames.put(name, referenceBinding);
    } else if (importBinding instanceof FieldBinding) {
      for (int j = 0; j < this.importPtr; j++) {
        ImportBinding resolved = this.tempImports[j];
        // find other static fields with the same name
        if (resolved.isStatic()
            && resolved.resolvedImport instanceof FieldBinding
            && importBinding != resolved.resolvedImport) {
          if (CharOperation.equals(name, resolved.compoundName[resolved.compoundName.length - 1])) {
            if (compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8) {
              // 7.5.3 says nothing about collision of single static imports and JDK8 tolerates
              // them, though use is flagged.
              FieldBinding field = (FieldBinding) resolved.resolvedImport;
              resolved.resolvedImport =
                  new ProblemFieldBinding(
                      field, field.declaringClass, name, ProblemReasons.Ambiguous);
              return -1;
            } else {
              problemReporter().duplicateImport(importReference);
              return -1;
            }
          }
        }
      }
    }
    if (conflictingType == null) {
      recordImportBinding(new ImportBinding(compoundName, false, importBinding, importReference));
    } else {
      recordImportBinding(
          new ImportConflictBinding(compoundName, importBinding, conflictingType, importReference));
    }
    return this.importPtr;
  }
  void faultInImports() {
    boolean unresolvedFound = false;
    // should report unresolved only if we are not suppressing caching of failed resolutions
    boolean reportUnresolved = !this.suppressImportErrors;

    if (this.typeOrPackageCache != null && !this.skipCachingImports)
      return; // can be called when a field constant is resolved before static imports
    if (this.referenceContext.imports == null) {
      this.typeOrPackageCache = new HashtableOfObject(1);
      return;
    }

    // collect the top level type names if a single type import exists
    int numberOfStatements = this.referenceContext.imports.length;
    HashtableOfType typesBySimpleNames = null;
    for (int i = 0; i < numberOfStatements; i++) {
      if ((this.referenceContext.imports[i].bits & ASTNode.OnDemand) == 0) {
        typesBySimpleNames = new HashtableOfType(this.topLevelTypes.length + numberOfStatements);
        for (int j = 0, length = this.topLevelTypes.length; j < length; j++)
          typesBySimpleNames.put(this.topLevelTypes[j].sourceName, this.topLevelTypes[j]);
        break;
      }
    }

    // allocate the import array, add java.lang.* by default
    int numberOfImports = numberOfStatements + 1;
    for (int i = 0; i < numberOfStatements; i++) {
      ImportReference importReference = this.referenceContext.imports[i];
      if (((importReference.bits & ASTNode.OnDemand) != 0)
          && CharOperation.equals(TypeConstants.JAVA_LANG, importReference.tokens)
          && !importReference.isStatic()) {
        numberOfImports--;
        break;
      }
    }
    this.tempImports = new ImportBinding[numberOfImports];
    this.tempImports[0] = getDefaultImports()[0];
    this.importPtr = 1;

    // keep static imports with normal imports until there is a reason to split them up
    // on demand imports continue to be packages & types. need to check on demand type imports for
    // fields/methods
    // single imports change from being just types to types or fields
    nextImport:
    for (int i = 0; i < numberOfStatements; i++) {
      ImportReference importReference = this.referenceContext.imports[i];
      char[][] compoundName = importReference.tokens;

      // skip duplicates or imports of the current package
      for (int j = 0; j < this.importPtr; j++) {
        ImportBinding resolved = this.tempImports[j];
        if (resolved.onDemand == ((importReference.bits & ASTNode.OnDemand) != 0)
            && resolved.isStatic() == importReference.isStatic()) {
          if (CharOperation.equals(compoundName, resolved.compoundName)) {
            problemReporter().unusedImport(importReference); // since skipped, must be reported now
            continue nextImport;
          }
        }
      }
      if ((importReference.bits & ASTNode.OnDemand) != 0) {
        if (CharOperation.equals(compoundName, this.currentPackageName)) {
          problemReporter().unusedImport(importReference); // since skipped, must be reported now
          continue nextImport;
        }

        Binding importBinding = findImport(compoundName, compoundName.length);
        if (!importBinding.isValidBinding()) {
          problemReporter().importProblem(importReference, importBinding);
          continue nextImport;
        }
        if (importReference.isStatic() && importBinding instanceof PackageBinding) {
          problemReporter().cannotImportPackage(importReference);
          continue nextImport;
        }
        recordImportBinding(new ImportBinding(compoundName, true, importBinding, importReference));
      } else {
        Binding importBinding =
            findSingleImport(
                compoundName,
                Binding.TYPE | Binding.FIELD | Binding.METHOD,
                importReference.isStatic());
        if (!importBinding.isValidBinding()) {
          if (importBinding.problemId() == ProblemReasons.Ambiguous) {
            // keep it unless a duplicate can be found below
          } else {
            unresolvedFound = true;
            if (reportUnresolved) {
              problemReporter().importProblem(importReference, importBinding);
            }
            continue nextImport;
          }
        }
        if (importBinding instanceof PackageBinding) {
          problemReporter().cannotImportPackage(importReference);
          continue nextImport;
        }
        // all the code here which checks for valid bindings have been moved to the method
        // checkAndRecordImportBinding() since bug 361327
        if (checkAndRecordImportBinding(
                importBinding, typesBySimpleNames, importReference, compoundName)
            == -1) continue nextImport;
        if (importReference.isStatic()) {
          // look for more static bindings being imported by single static import(bug 361327).
          // findSingleImport() finds fields first, followed by method and then type
          // So if a type is found, no fields and methods are available anyway
          // similarly when method is found, type may be available but no field available for sure
          if (importBinding.kind() == Binding.FIELD) {
            checkMoreStaticBindings(
                compoundName, typesBySimpleNames, Binding.TYPE | Binding.METHOD, importReference);
          } else if (importBinding.kind() == Binding.METHOD) {
            checkMoreStaticBindings(
                compoundName, typesBySimpleNames, Binding.TYPE, importReference);
          }
        }
      }
    }

    // shrink resolvedImports... only happens if an error was reported
    if (this.tempImports.length > this.importPtr)
      System.arraycopy(
          this.tempImports,
          0,
          this.tempImports = new ImportBinding[this.importPtr],
          0,
          this.importPtr);
    this.imports = this.tempImports;
    int length = this.imports.length;
    this.typeOrPackageCache = new HashtableOfObject(length);
    for (int i = 0; i < length; i++) {
      ImportBinding binding = this.imports[i];
      if (!binding.onDemand && binding.resolvedImport instanceof ReferenceBinding
          || binding instanceof ImportConflictBinding)
        this.typeOrPackageCache.put(binding.compoundName[binding.compoundName.length - 1], binding);
    }
    this.skipCachingImports = this.suppressImportErrors && unresolvedFound;
  }