/**
  * Checks additional bindings (methods or types) imported from a single static import. Method is
  * tried first, followed by type. If found, records them. If in the process, import is flagged as
  * duplicate, -1 is returned.
  *
  * @param compoundName
  * @param typesBySimpleNames
  * @param mask
  * @param importReference
  */
 private void checkMoreStaticBindings(
     char[][] compoundName,
     HashtableOfType typesBySimpleNames,
     int mask,
     ImportReference importReference) {
   Binding importBinding = findSingleStaticImport(compoundName, mask);
   if (!importBinding.isValidBinding()) {
     // only continue if the same kind's ambiguous binding is returned
     // may have found an ambiguous type when looking for field or method. Don't continue in that
     // case
     if (importBinding.problemId() == ProblemReasons.Ambiguous) {
       // keep it unless a duplicate can be found below
       checkAndRecordImportBinding(
           importBinding, typesBySimpleNames, importReference, compoundName);
     }
   } else {
     checkAndRecordImportBinding(importBinding, typesBySimpleNames, importReference, compoundName);
   }
   if (((mask & Binding.METHOD) != 0) && (importBinding.kind() == Binding.METHOD)) {
     // found method
     // type is left to be looked for
     // reset METHOD bit to enable lookup for only type
     mask &= ~Binding.METHOD;
     // now search for a type binding
     checkMoreStaticBindings(compoundName, typesBySimpleNames, mask, importReference);
   }
 }
  private Binding findImport(char[][] compoundName, int length) {
    recordQualifiedReference(compoundName);

    Binding binding = this.environment.getTopLevelPackage(compoundName[0]);
    int i = 1;
    foundNothingOrType:
    if (binding != null) {
      PackageBinding packageBinding = (PackageBinding) binding;
      while (i < length) {
        binding = packageBinding.getTypeOrPackage(compoundName[i++]);
        if (binding == null || !binding.isValidBinding()) {
          binding = null;
          break foundNothingOrType;
        }
        if (!(binding instanceof PackageBinding)) break foundNothingOrType;

        packageBinding = (PackageBinding) binding;
      }
      return packageBinding;
    }

    ReferenceBinding type;
    if (binding == null) {
      if (compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4)
        return new ProblemReferenceBinding(
            CharOperation.subarray(compoundName, 0, i), null, ProblemReasons.NotFound);
      type =
          findType(
              compoundName[0], this.environment.defaultPackage, this.environment.defaultPackage);
      if (type == null || !type.isValidBinding())
        return new ProblemReferenceBinding(
            CharOperation.subarray(compoundName, 0, i), null, ProblemReasons.NotFound);
      i = 1; // reset to look for member types inside the default package type
    } else {
      type = (ReferenceBinding) binding;
    }

    while (i < length) {
      type =
          (ReferenceBinding)
              this.environment.convertToRawType(
                  type, false /*do not force conversion of enclosing types*/); // type imports are
      // necessarily raw for all
      // except last
      if (!type.canBeSeenBy(this.fPackage))
        return new ProblemReferenceBinding(
            CharOperation.subarray(compoundName, 0, i), type, ProblemReasons.NotVisible);

      char[] name = compoundName[i++];
      // does not look for inherited member types on purpose, only immediate members
      type = type.getMemberType(name);
      if (type == null)
        return new ProblemReferenceBinding(
            CharOperation.subarray(compoundName, 0, i), null, ProblemReasons.NotFound);
    }
    if (!type.canBeSeenBy(this.fPackage))
      return new ProblemReferenceBinding(compoundName, type, ProblemReasons.NotVisible);
    return type;
  }
  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;
  }
  private Binding findSingleStaticImport(char[][] compoundName, int mask) {
    Binding binding = findImport(compoundName, compoundName.length - 1);
    if (!binding.isValidBinding()) return binding;

    char[] name = compoundName[compoundName.length - 1];
    if (binding instanceof PackageBinding) {
      Binding temp = ((PackageBinding) binding).getTypeOrPackage(name);
      if (temp != null
          && temp
              instanceof
              ReferenceBinding) // must resolve to a member type or field, not a top level type
      return new ProblemReferenceBinding(
            compoundName, (ReferenceBinding) temp, ProblemReasons.InvalidTypeForStaticImport);
      return binding; // cannot be a package, error is caught in sender
    }

    // look to see if its a static field first
    ReferenceBinding type = (ReferenceBinding) binding;
    FieldBinding field = (mask & Binding.FIELD) != 0 ? findField(type, name, null, true) : null;
    if (field != null) {
      if (field.problemId() == ProblemReasons.Ambiguous
          && ((ProblemFieldBinding) field).closestMatch.isStatic())
        return field; // keep the ambiguous field instead of a possible method match
      if (field.isValidBinding() && field.isStatic() && field.canBeSeenBy(type, null, this))
        return field;
    }

    // look to see if there is a static method with the same selector
    MethodBinding method = (mask & Binding.METHOD) != 0 ? findStaticMethod(type, name) : null;
    if (method != null) return method;

    type = findMemberType(name, type);
    if (type == null || !type.isStatic()) {
      if (field != null && !field.isValidBinding() && field.problemId() != ProblemReasons.NotFound)
        return field;
      return new ProblemReferenceBinding(compoundName, type, ProblemReasons.NotFound);
    }
    if (type.isValidBinding() && !type.canBeSeenBy(this.fPackage))
      return new ProblemReferenceBinding(compoundName, type, ProblemReasons.NotVisible);
    if (type.problemId() == ProblemReasons.NotVisible) // ensure compoundName is correct
    return new ProblemReferenceBinding(
          compoundName, ((ProblemReferenceBinding) type).closestMatch, ProblemReasons.NotVisible);
    return type;
  }
  ImportBinding[] getDefaultImports() {
    // initialize the default imports if necessary... share the default java.lang.* import
    if (this.environment.defaultImports != null) return this.environment.defaultImports;

    Binding importBinding = this.environment.getTopLevelPackage(TypeConstants.JAVA);
    if (importBinding != null)
      importBinding = ((PackageBinding) importBinding).getTypeOrPackage(TypeConstants.JAVA_LANG[1]);

    if (importBinding == null || !importBinding.isValidBinding()) {
      // create a proxy for the missing BinaryType
      problemReporter()
          .isClassPathCorrect(
              TypeConstants.JAVA_LANG_OBJECT,
              this.referenceContext,
              this.environment.missingClassFileLocation);
      BinaryTypeBinding missingObject =
          this.environment.createMissingType(null, TypeConstants.JAVA_LANG_OBJECT);
      importBinding = missingObject.fPackage;
    }

    return this.environment.defaultImports =
        new ImportBinding[] {new ImportBinding(TypeConstants.JAVA_LANG, true, importBinding, null)};
  }
  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;
  }