/*
  * Set the focus type (i.e. the type that this resolver is computing the hierarch for.
  * Returns the binding of this focus type or null if it could not be found.
  */
 public ReferenceBinding setFocusType(char[][] compoundName) {
   if (compoundName == null || this.lookupEnvironment == null) return null;
   this.focusType = this.lookupEnvironment.getCachedType(compoundName);
   if (this.focusType == null) {
     this.focusType = this.lookupEnvironment.askForType(compoundName);
     if (this.focusType == null) {
       int length = compoundName.length;
       char[] typeName = compoundName[length - 1];
       int firstDollar = CharOperation.indexOf('$', typeName);
       if (firstDollar != -1) {
         compoundName[length - 1] = CharOperation.subarray(typeName, 0, firstDollar);
         this.focusType = this.lookupEnvironment.askForType(compoundName);
         if (this.focusType != null) {
           char[][] memberTypeNames =
               CharOperation.splitOn('$', typeName, firstDollar + 1, typeName.length);
           for (int i = 0; i < memberTypeNames.length; i++) {
             this.focusType = this.focusType.getMemberType(memberTypeNames[i]);
             if (this.focusType == null) return null;
           }
         }
       }
     }
   }
   return this.focusType;
 }
  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;
  }
  /*
   * Creates the super class handle of the given type.
   * Returns null if the type has no super class.
   * Adds the simple name to the hierarchy missing types if the class is not found and returns null.
   */
  private IType findSuperClass(IGenericType type, ReferenceBinding typeBinding) {
    ReferenceBinding superBinding = typeBinding.superclass();

    if (superBinding != null) {
      superBinding = (ReferenceBinding) superBinding.erasure();
      if (typeBinding.isHierarchyInconsistent()) {
        if (superBinding.problemId() == ProblemReasons.NotFound) {
          this.hasMissingSuperClass = true;
          this.builder.hierarchy.missingTypes.add(
              new String(superBinding.sourceName)); // note: this could be Map$Entry
          return null;
        } else if ((superBinding.id == TypeIds.T_JavaLangObject)) {
          char[] superclassName;
          char separator;
          if (type instanceof IBinaryType) {
            superclassName = ((IBinaryType) type).getSuperclassName();
            separator = '/';
          } else if (type instanceof ISourceType) {
            superclassName = ((ISourceType) type).getSuperclassName();
            separator = '.';
          } else if (type instanceof HierarchyType) {
            superclassName = ((HierarchyType) type).superclassName;
            separator = '.';
          } else {
            return null;
          }

          if (superclassName
              != null) { // check whether subclass of Object due to broken hierarchy (as opposed to
                         // explicitly extending it)
            int lastSeparator = CharOperation.lastIndexOf(separator, superclassName);
            char[] simpleName =
                lastSeparator == -1
                    ? superclassName
                    : CharOperation.subarray(
                        superclassName, lastSeparator + 1, superclassName.length);
            if (!CharOperation.equals(simpleName, TypeConstants.OBJECT)) {
              this.hasMissingSuperClass = true;
              this.builder.hierarchy.missingTypes.add(new String(simpleName));
              return null;
            }
          }
        }
      }
      for (int t = this.typeIndex; t >= 0; t--) {
        if (TypeBinding.equalsEquals(this.typeBindings[t], superBinding)) {
          return this.builder.getHandle(this.typeModels[t], superBinding);
        }
      }
    }
    return null;
  }
  private IAnnotation getAnnotation(
      final org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation annotation,
      JavaElement parentElement) {
    final int typeStart = annotation.type.sourceStart();
    final int typeEnd = annotation.type.sourceEnd();
    final int sourceStart = annotation.sourceStart();
    final int sourceEnd = annotation.declarationSourceEnd;
    class LocalVarAnnotation extends Annotation {
      IMemberValuePair[] memberValuePairs;

      public LocalVarAnnotation(JavaElement localVar, String elementName) {
        super(localVar, elementName);
      }

      public IMemberValuePair[] getMemberValuePairs() throws JavaModelException {
        return this.memberValuePairs;
      }

      public ISourceRange getNameRange() throws JavaModelException {
        return new SourceRange(typeStart, typeEnd - typeStart + 1);
      }

      public ISourceRange getSourceRange() throws JavaModelException {
        return new SourceRange(sourceStart, sourceEnd - sourceStart + 1);
      }

      public boolean exists() {
        return this.parent.exists();
      }
    }
    String annotationName =
        new String(CharOperation.concatWith(annotation.type.getTypeName(), '.'));
    LocalVarAnnotation localVarAnnotation = new LocalVarAnnotation(parentElement, annotationName);
    org.aspectj.org.eclipse.jdt.internal.compiler.ast.MemberValuePair[] astMemberValuePairs =
        annotation.memberValuePairs();
    int length;
    IMemberValuePair[] memberValuePairs;
    if (astMemberValuePairs == null || (length = astMemberValuePairs.length) == 0) {
      memberValuePairs = Annotation.NO_MEMBER_VALUE_PAIRS;
    } else {
      memberValuePairs = new IMemberValuePair[length];
      for (int i = 0; i < length; i++) {
        org.aspectj.org.eclipse.jdt.internal.compiler.ast.MemberValuePair astMemberValuePair =
            astMemberValuePairs[i];
        MemberValuePair memberValuePair = new MemberValuePair(new String(astMemberValuePair.name));
        memberValuePair.value =
            getAnnotationMemberValue(memberValuePair, astMemberValuePair.value, localVarAnnotation);
        memberValuePairs[i] = memberValuePair;
      }
    }
    localVarAnnotation.memberValuePairs = memberValuePairs;
    return localVarAnnotation;
  }
  /**
   * Validate the given Java type name, either simple or qualified, for the given source and
   * compliance levels.
   *
   * <p>For example, <code>"java.lang.Object"</code>, or <code>"Object"</code>.
   *
   * <p>The source level and compliance level values should be taken from the constant defined
   * inside {@link JavaCore} class. The constants are named <code>JavaCore#VERSION_1_x</code>, x
   * being set between '1' and '8'.
   *
   * @param name the name of a type
   * @param sourceLevel the source level
   * @param complianceLevel the compliance level
   * @return a status object with code <code>IStatus.OK</code> if the given name is valid as a Java
   *     type name, a status with code <code>IStatus.WARNING</code> indicating why the given name is
   *     discouraged, otherwise a status object indicating what is wrong with the name
   * @since 3.3
   * @see JavaCore#VERSION_1_1
   * @see JavaCore#VERSION_1_2
   * @see JavaCore#VERSION_1_3
   * @see JavaCore#VERSION_1_4
   * @see JavaCore#VERSION_1_5
   * @see JavaCore#VERSION_1_6
   * @see JavaCore#VERSION_1_7
   * @see JavaCore#VERSION_1_8
   */
  public static IStatus validateJavaTypeName(
      String name, String sourceLevel, String complianceLevel) {
    if (name == null) {
      return new Status(
          IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_type_nullName, null);
    }
    String trimmed = name.trim();
    if (!name.equals(trimmed)) {
      return new Status(
          IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_type_nameWithBlanks, null);
    }
    int index = name.lastIndexOf('.');
    char[] scannedID;
    if (index == -1) {
      // simple name
      scannedID = scannedIdentifier(name, sourceLevel, complianceLevel);
    } else {
      // qualified name
      String pkg = name.substring(0, index).trim();
      IStatus status = validatePackageName(pkg, sourceLevel, complianceLevel);
      if (!status.isOK()) {
        return status;
      }
      String type = name.substring(index + 1).trim();
      scannedID = scannedIdentifier(type, sourceLevel, complianceLevel);
    }

    if (scannedID != null) {
      IStatus status =
          ResourcesPlugin.getWorkspace().validateName(new String(scannedID), IResource.FILE);
      if (!status.isOK()) {
        return status;
      }
      if (CharOperation.contains('$', scannedID)) {
        return new Status(
            IStatus.WARNING, JavaCore.PLUGIN_ID, -1, Messages.convention_type_dollarName, null);
      }
      if ((scannedID.length > 0 && ScannerHelper.isLowerCase(scannedID[0]))) {
        return new Status(
            IStatus.WARNING, JavaCore.PLUGIN_ID, -1, Messages.convention_type_lowercaseName, null);
      }
      return JavaModelStatus.VERIFIED_OK;
    } else {
      return new Status(
          IStatus.ERROR,
          JavaCore.PLUGIN_ID,
          -1,
          Messages.bind(Messages.convention_type_invalidName, name),
          null);
    }
  }
  public int scanIdentifierOrKeyword() {
    int kind = super.scanIdentifierOrKeyword();
    if (kind != TerminalTokens.TokenNameIdentifier) return kind;

    char[] contents = getCurrentIdentifierSource();

    // XXX performance here is less than optimal, but code simplicity is pretty damn good
    if (CharOperation.equals(aspectV, contents)) return TerminalTokens.TokenNameaspect;
    else if (CharOperation.equals(pointcutV, contents)) return TerminalTokens.TokenNamepointcut;
    else if (CharOperation.equals(privilegedV, contents)) return TerminalTokens.TokenNameprivileged;
    else if (CharOperation.equals(beforeV, contents)) return TerminalTokens.TokenNamebefore;
    else if (CharOperation.equals(afterV, contents)) return TerminalTokens.TokenNameafter;
    else if (CharOperation.equals(aroundV, contents)) return TerminalTokens.TokenNamearound;
    else if (CharOperation.equals(declareV, contents)) return TerminalTokens.TokenNamedeclare;

    return kind;
  }
  public void storeDependencyInfo() {
    // add the type hierarchy of each referenced supertype
    // cannot do early since the hierarchy may not be fully resolved
    for (int i = 0; i < this.referencedSuperTypes.size; i++) { // grows as more types are added
      ReferenceBinding type = (ReferenceBinding) this.referencedSuperTypes.elementAt(i);
      if (!this.referencedTypes.containsIdentical(type)) this.referencedTypes.add(type);

      if (!type.isLocalType()) {
        ReferenceBinding enclosing = type.enclosingType();
        if (enclosing != null) recordSuperTypeReference(enclosing);
      }
      ReferenceBinding superclass = type.superclass();
      if (superclass != null) recordSuperTypeReference(superclass);
      ReferenceBinding[] interfaces = type.superInterfaces();
      if (interfaces != null)
        for (int j = 0, length = interfaces.length; j < length; j++)
          recordSuperTypeReference(interfaces[j]);
    }

    for (int i = 0, l = this.referencedTypes.size; i < l; i++) {
      ReferenceBinding type = (ReferenceBinding) this.referencedTypes.elementAt(i);
      if (!type.isLocalType())
        recordQualifiedReference(
            type.isMemberType()
                ? CharOperation.splitOn('.', type.readableName())
                : type.compoundName);
    }

    int size = this.qualifiedReferences.size;
    char[][][] qualifiedRefs = new char[size][][];
    for (int i = 0; i < size; i++) qualifiedRefs[i] = this.qualifiedReferences.elementAt(i);
    this.referenceContext.compilationResult.qualifiedReferences = qualifiedRefs;

    size = this.simpleNameReferences.size;
    char[][] simpleRefs = new char[size][];
    for (int i = 0; i < size; i++) simpleRefs[i] = this.simpleNameReferences.elementAt(i);
    this.referenceContext.compilationResult.simpleNameReferences = simpleRefs;

    size = this.rootReferences.size;
    char[][] rootRefs = new char[size][];
    for (int i = 0; i < size; i++) rootRefs[i] = this.rootReferences.elementAt(i);
    this.referenceContext.compilationResult.rootReferences = rootRefs;
  }
  /**
   * Resolve the supertypes for the types contained in the given openables (ICompilationUnits and/or
   * IClassFiles). Inform the requestor of the resolved supertypes for each supplied source type
   * using: connect(ISourceType suppliedType, IGenericType superclass, IGenericType[]
   * superinterfaces)
   *
   * <p>Also inform the requestor of the supertypes of each additional requested super type which is
   * also a source type instead of a binary type.
   *
   * @param openables
   * @param localTypes
   * @param monitor
   */
  public void resolve(Openable[] openables, HashSet localTypes, IProgressMonitor monitor) {
    try {
      int openablesLength = openables.length;
      CompilationUnitDeclaration[] parsedUnits = new CompilationUnitDeclaration[openablesLength];
      boolean[] hasLocalType = new boolean[openablesLength];
      org.aspectj.org.eclipse.jdt.core.ICompilationUnit[] cus =
          new org.aspectj.org.eclipse.jdt.core.ICompilationUnit[openablesLength];
      int unitsIndex = 0;

      CompilationUnitDeclaration focusUnit = null;
      ReferenceBinding focusBinaryBinding = null;
      IType focus = this.builder.getType();
      Openable focusOpenable = null;
      if (focus != null) {
        if (focus.isBinary()) {
          focusOpenable = (Openable) focus.getClassFile();
        } else {
          focusOpenable = (Openable) focus.getCompilationUnit();
        }
      }

      // build type bindings
      Parser parser = new Parser(this.lookupEnvironment.problemReporter, true);
      final boolean isJava8 = this.options.sourceLevel >= ClassFileConstants.JDK1_8;
      for (int i = 0; i < openablesLength; i++) {
        Openable openable = openables[i];
        if (openable instanceof org.aspectj.org.eclipse.jdt.core.ICompilationUnit) {
          org.aspectj.org.eclipse.jdt.core.ICompilationUnit cu =
              (org.aspectj.org.eclipse.jdt.core.ICompilationUnit) openable;

          // contains a potential subtype as a local or anonymous type?
          boolean containsLocalType = false;
          if (localTypes == null) { // case of hierarchy on region
            containsLocalType = true;
          } else {
            IPath path = cu.getPath();
            containsLocalType =
                cu.isWorkingCopy()
                    ? true /* presume conservatively */
                    : localTypes.contains(path.toString());
          }

          // build parsed unit
          CompilationUnitDeclaration parsedUnit = null;
          if (cu.isOpen()) {
            // create parsed unit from source element infos
            CompilationResult result =
                new CompilationResult(
                    (ICompilationUnit) cu, i, openablesLength, this.options.maxProblemsPerUnit);
            SourceTypeElementInfo[] typeInfos = null;
            try {
              IType[] topLevelTypes = cu.getTypes();
              int topLevelLength = topLevelTypes.length;
              if (topLevelLength == 0)
                continue; // empty cu: no need to parse (see
                          // https://bugs.eclipse.org/bugs/show_bug.cgi?id=65677)
              typeInfos = new SourceTypeElementInfo[topLevelLength];
              for (int j = 0; j < topLevelLength; j++) {
                IType topLevelType = topLevelTypes[j];
                typeInfos[j] =
                    (SourceTypeElementInfo) ((JavaElement) topLevelType).getElementInfo();
              }
            } catch (JavaModelException e) {
              // types/cu exist since cu is opened
            }
            int flags =
                !containsLocalType
                    ? SourceTypeConverter.MEMBER_TYPE | (isJava8 ? SourceTypeConverter.METHOD : 0)
                    : SourceTypeConverter.FIELD_AND_METHOD
                        | SourceTypeConverter.MEMBER_TYPE
                        | SourceTypeConverter.LOCAL_TYPE;
            parsedUnit =
                SourceTypeConverter.buildCompilationUnit(
                    typeInfos, flags, this.lookupEnvironment.problemReporter, result);

            // We would have got all the necessary local types by now and hence there is no further
            // need
            // to parse the method bodies. Parser.getMethodBodies, which is called latter in this
            // function,
            // will not parse the method statements if ASTNode.HasAllMethodBodies is set.
            if (containsLocalType) parsedUnit.bits |= ASTNode.HasAllMethodBodies;
          } else {
            // create parsed unit from file
            IFile file = (IFile) cu.getResource();
            ICompilationUnit sourceUnit =
                this.builder.createCompilationUnitFromPath(openable, file);
            CompilationResult unitResult =
                new CompilationResult(
                    sourceUnit, i, openablesLength, this.options.maxProblemsPerUnit);
            parsedUnit = parser.dietParse(sourceUnit, unitResult);
          }

          if (parsedUnit != null) {
            hasLocalType[unitsIndex] = containsLocalType;
            cus[unitsIndex] = cu;
            parsedUnits[unitsIndex++] = parsedUnit;
            try {
              this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
              if (openable.equals(focusOpenable)) {
                focusUnit = parsedUnit;
              }
            } catch (AbortCompilation e) {
              // classpath problem for this type: ignore
            }
          }
        } else {
          // cache binary type binding
          ClassFile classFile = (ClassFile) openable;
          IBinaryType binaryType =
              (IBinaryType) JavaModelManager.getJavaModelManager().getInfo(classFile.getType());
          if (binaryType == null) {
            // create binary type from file
            if (classFile.getPackageFragmentRoot().isArchive()) {
              binaryType = this.builder.createInfoFromClassFileInJar(classFile);
            } else {
              IResource file = classFile.resource();
              binaryType = this.builder.createInfoFromClassFile(classFile, file);
            }
          }
          if (binaryType != null) {
            try {
              BinaryTypeBinding binaryTypeBinding =
                  this.lookupEnvironment.cacheBinaryType(
                      binaryType,
                      false /*don't need field and method (bug 125067)*/,
                      null /*no access restriction*/);
              remember(binaryType, binaryTypeBinding);
              if (openable.equals(focusOpenable)) {
                focusBinaryBinding = binaryTypeBinding;
              }
            } catch (AbortCompilation e) {
              // classpath problem for this type: ignore
            }
          }
        }
      }

      // remember type declaration of focus if local/anonymous early (see
      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=210498)
      TypeDeclaration focusLocalType = null;
      if (focus != null
          && focusBinaryBinding == null
          && focusUnit != null
          && ((Member) focus).getOuterMostLocalContext() != null) {
        focusLocalType = new ASTNodeFinder(focusUnit).findType(focus);
      }

      for (int i = 0; i <= this.typeIndex; i++) {
        IGenericType suppliedType = this.typeModels[i];
        if (suppliedType != null && suppliedType.isBinaryType()) {
          CompilationUnitDeclaration previousUnitBeingCompleted =
              this.lookupEnvironment.unitBeingCompleted;
          // fault in its hierarchy...
          try {
            // ensure that unitBeingCompleted is set so that we don't get an AbortCompilation for a
            // missing type
            // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=213249 )
            if (previousUnitBeingCompleted == null) {
              this.lookupEnvironment.unitBeingCompleted = FakeUnit;
            }
            ReferenceBinding typeBinding = this.typeBindings[i];
            typeBinding.superclass();
            typeBinding.superInterfaces();
          } catch (AbortCompilation e) {
            // classpath problem for this type: ignore
          } finally {
            this.lookupEnvironment.unitBeingCompleted = previousUnitBeingCompleted;
          }
        }
      }

      // complete type bindings (i.e. connect super types)
      for (int i = 0; i < unitsIndex; i++) {
        CompilationUnitDeclaration parsedUnit = parsedUnits[i];
        if (parsedUnit != null) {
          try {
            if (hasLocalType[i]) { // NB: no-op if method bodies have been already parsed
              if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
              parser.getMethodBodies(parsedUnit);
            }
          } catch (AbortCompilation e) {
            // classpath problem for this type: don't try to resolve (see
            // https://bugs.eclipse.org/bugs/show_bug.cgi?id=49809)
            hasLocalType[i] = false;
          }
        }
      }
      // complete type bindings and build fields and methods only for local types
      // (in this case the constructor is needed when resolving local types)
      // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=145333)
      try {
        this.lookupEnvironment.completeTypeBindings(parsedUnits, hasLocalType, unitsIndex);
        // remember type bindings
        for (int i = 0; i < unitsIndex; i++) {
          CompilationUnitDeclaration parsedUnit = parsedUnits[i];
          if (parsedUnit != null && !parsedUnit.hasErrors()) {
            boolean containsLocalType = hasLocalType[i];
            if (containsLocalType) {
              if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
              parsedUnit.scope.faultInTypes();
              parsedUnit.resolve();
            }

            rememberAllTypes(parsedUnit, cus[i], containsLocalType);
          }
        }
      } catch (AbortCompilation e) {
        // skip it silently
      }
      worked(monitor, 1);

      // if no potential subtype was a real subtype of the binary focus type, no need to go further
      // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=54043)
      if (focusBinaryBinding == null && focus != null && focus.isBinary()) {
        char[] fullyQualifiedName = focus.getFullyQualifiedName().toCharArray();
        focusBinaryBinding =
            this.lookupEnvironment.getCachedType(CharOperation.splitOn('.', fullyQualifiedName));
        // https://bugs.eclipse.org/bugs/show_bug.cgi?id=436155
        // When local types are requested, it's likely a type is found from cache without
        // the hierarchy being resolved completely, so consider that factor too
        if (focusBinaryBinding == null
            || (focusBinaryBinding.tagBits & TagBits.HasUnresolvedSuperclass) != 0) return;
      }

      reportHierarchy(focus, focusLocalType, focusBinaryBinding);

    } catch (
        ClassCastException
            e) { // work-around for 1GF5W1S - can happen in case duplicates are fed to the hierarchy
                 // with binaries hiding sources
    } catch (
        AbortCompilation
            e) { // ignore this exception for now since it typically means we cannot find
                 // java.lang.Object
      if (TypeHierarchy.DEBUG) e.printStackTrace();
    } finally {
      reset();
    }
  }
  /*
   * Reports the hierarchy from the remembered bindings.
   * Note that 'binaryTypeBinding' is null if focus type is a source type.
   */
  private void reportHierarchy(
      IType focus, TypeDeclaration focusLocalType, ReferenceBinding binaryTypeBinding) {

    // set focus type binding
    if (focus != null) {
      if (binaryTypeBinding != null) {
        // binary type
        this.focusType = binaryTypeBinding;
      } else {
        // source type
        if (focusLocalType != null) {
          // anonymous or local type
          this.focusType = focusLocalType.binding;
        } else {
          // top level or member type
          char[] fullyQualifiedName = focus.getFullyQualifiedName().toCharArray();
          setFocusType(CharOperation.splitOn('.', fullyQualifiedName));
        }
      }
    }

    // be resilient and fix super type bindings
    fixSupertypeBindings();

    int objectIndex = -1;
    IProgressMonitor progressMonitor = this.builder.hierarchy.progressMonitor;
    for (int current = this.typeIndex; current >= 0; current--) {
      if (progressMonitor != null && progressMonitor.isCanceled())
        throw new OperationCanceledException();

      ReferenceBinding typeBinding = this.typeBindings[current];

      // java.lang.Object treated at the end
      if (typeBinding.id == TypeIds.T_JavaLangObject) {
        objectIndex = current;
        continue;
      }

      IGenericType suppliedType = this.typeModels[current];

      if (!subOrSuperOfFocus(typeBinding)) {
        continue; // ignore types outside of hierarchy
      }

      IType superclass;
      if (typeBinding.isInterface()) { // do not connect interfaces to Object
        superclass = null;
      } else {
        superclass = findSuperClass(suppliedType, typeBinding);
      }
      IType[] superinterfaces = findSuperInterfaces(suppliedType, typeBinding);

      this.builder.connect(
          suppliedType,
          this.builder.getHandle(suppliedType, typeBinding),
          superclass,
          superinterfaces);
    }
    // add java.lang.Object only if the super class is not missing
    if (objectIndex > -1 && (!this.hasMissingSuperClass || this.focusType == null)) {
      IGenericType objectType = this.typeModels[objectIndex];
      this.builder.connect(
          objectType,
          this.builder.getHandle(objectType, this.typeBindings[objectIndex]),
          null,
          null);
    }
  }
  /*
   * Returns the handles of the super interfaces of the given type.
   * Adds the simple name to the hierarchy missing types if an interface is not found (but don't put null in the returned array)
   */
  private IType[] findSuperInterfaces(IGenericType type, ReferenceBinding typeBinding) {
    char[][] superInterfaceNames;
    char separator;
    if (type instanceof IBinaryType) {
      superInterfaceNames = ((IBinaryType) type).getInterfaceNames();
      separator = '/';
    } else if (type instanceof ISourceType) {
      ISourceType sourceType = (ISourceType) type;
      if (sourceType.isAnonymous()) { // if anonymous type
        if (typeBinding.superInterfaces() != null && typeBinding.superInterfaces().length > 0) {
          superInterfaceNames = new char[][] {sourceType.getSuperclassName()};
        } else {
          superInterfaceNames = sourceType.getInterfaceNames();
        }
      } else {
        if (TypeDeclaration.kind(sourceType.getModifiers()) == TypeDeclaration.ANNOTATION_TYPE_DECL)
          superInterfaceNames =
              new char[][] {TypeConstants.CharArray_JAVA_LANG_ANNOTATION_ANNOTATION};
        else superInterfaceNames = sourceType.getInterfaceNames();
      }
      separator = '.';
    } else if (type instanceof HierarchyType) {
      HierarchyType hierarchyType = (HierarchyType) type;
      if (hierarchyType.isAnonymous()) { // if anonymous type
        if (typeBinding.superInterfaces() != null && typeBinding.superInterfaces().length > 0) {
          superInterfaceNames = new char[][] {hierarchyType.superclassName};
        } else {
          superInterfaceNames = hierarchyType.superInterfaceNames;
        }
      } else {
        superInterfaceNames = hierarchyType.superInterfaceNames;
      }
      separator = '.';
    } else {
      return null;
    }

    ReferenceBinding[] interfaceBindings = typeBinding.superInterfaces();
    int bindingIndex = 0;
    int bindingLength = interfaceBindings == null ? 0 : interfaceBindings.length;
    int length = superInterfaceNames == null ? 0 : superInterfaceNames.length;
    IType[] superinterfaces = new IType[length];
    int index = 0;
    next:
    for (int i = 0; i < length; i++) {
      char[] superInterfaceName = superInterfaceNames[i];
      int end = superInterfaceName.length;

      // find the end of simple name
      int genericStart = CharOperation.indexOf(Signature.C_GENERIC_START, superInterfaceName);
      if (genericStart != -1) end = genericStart;

      // find the start of simple name
      int lastSeparator = CharOperation.lastIndexOf(separator, superInterfaceName, 0, end);
      int start = lastSeparator + 1;

      // case of binary inner type -> take the last part
      int lastDollar = CharOperation.lastIndexOf('$', superInterfaceName, start);
      if (lastDollar != -1) start = lastDollar + 1;

      char[] simpleName = CharOperation.subarray(superInterfaceName, start, end);

      if (bindingIndex < bindingLength) {
        ReferenceBinding interfaceBinding =
            (ReferenceBinding) interfaceBindings[bindingIndex].erasure();

        // ensure that the binding corresponds to the interface defined by the user
        if (CharOperation.equals(simpleName, interfaceBinding.sourceName)) {
          bindingIndex++;
          for (int t = this.typeIndex; t >= 0; t--) {
            if (TypeBinding.equalsEquals(this.typeBindings[t], interfaceBinding)) {
              IType handle = this.builder.getHandle(this.typeModels[t], interfaceBinding);
              if (handle != null) {
                superinterfaces[index++] = handle;
                continue next;
              }
            }
          }
        }
      }
      this.builder.hierarchy.missingTypes.add(new String(simpleName));
    }
    if (index != length)
      System.arraycopy(superinterfaces, 0, superinterfaces = new IType[index], 0, index);
    return superinterfaces;
  }
  /*
   * INTERNAL USE-ONLY
   * Innerclasses get their name computed as they are generated, since some may not
   * be actually outputed if sitting inside unreachable code.
   */
  public char[] computeConstantPoolName(LocalTypeBinding localType) {
    if (localType.constantPoolName != null) {
      return localType.constantPoolName;
    }
    // delegates to the outermost enclosing classfile, since it is the only one with a global vision
    // of its innertypes.

    if (this.constantPoolNameUsage == null) this.constantPoolNameUsage = new HashtableOfType();

    ReferenceBinding outerMostEnclosingType =
        localType.scope.outerMostClassScope().enclosingSourceType();

    // ensure there is not already such a local type name defined by the user
    int index = 0;
    char[] candidateName;
    boolean isCompliant15 = compilerOptions().complianceLevel >= ClassFileConstants.JDK1_5;
    while (true) {
      if (localType.isMemberType()) {
        if (index == 0) {
          candidateName =
              CharOperation.concat(
                  localType.enclosingType().constantPoolName(), localType.sourceName, '$');
        } else {
          // in case of collision, then member name gets extra $1 inserted
          // e.g. class X { { class L{} new X(){ class L{} } } }
          candidateName =
              CharOperation.concat(
                  localType.enclosingType().constantPoolName(),
                  '$',
                  String.valueOf(index).toCharArray(),
                  '$',
                  localType.sourceName);
        }
      } else if (localType.isAnonymousType()) {
        if (isCompliant15) {
          // AspectJ Extension start
          char[] extraInsert = null;
          if (outerMostEnclosingType instanceof SourceTypeBinding) {
            SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) outerMostEnclosingType;
            ClassScope classScope = sourceTypeBinding.scope;
            if (classScope != null) {
              TypeDeclaration typeDeclaration = classScope.referenceContext;
              if (typeDeclaration != null) {
                extraInsert = typeDeclaration.getLocalTypeNameSuffix();
              }
            }
          }
          if (extraInsert != null) { // AspectJ Extension end
            candidateName =
                CharOperation.concat(
                    localType.enclosingType.constantPoolName(),
                    '$',
                    extraInsert,
                    '$',
                    String.valueOf(index + 1).toCharArray());
          } else {
            // from 1.5 on, use immediately enclosing type name
            candidateName =
                CharOperation.concat(
                    localType.enclosingType.constantPoolName(),
                    String.valueOf(index + 1).toCharArray(),
                    '$');
          } // AspectJ extension, closing }
        } else {
          candidateName =
              CharOperation.concat(
                  outerMostEnclosingType.constantPoolName(),
                  String.valueOf(index + 1).toCharArray(),
                  '$');
        }
      } else {
        // local type
        if (isCompliant15) {
          candidateName =
              CharOperation.concat(
                  CharOperation.concat(
                      localType.enclosingType().constantPoolName(),
                      String.valueOf(index + 1).toCharArray(),
                      '$'),
                  localType.sourceName);
        } else {
          candidateName =
              CharOperation.concat(
                  outerMostEnclosingType.constantPoolName(),
                  '$',
                  String.valueOf(index + 1).toCharArray(),
                  '$',
                  localType.sourceName);
        }
      }
      if (this.constantPoolNameUsage.get(candidateName) != null) {
        index++;
      } else {
        this.constantPoolNameUsage.put(candidateName, localType);
        break;
      }
    }
    return candidateName;
  }
  /**
   * 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 buildTypeBindings(AccessRestriction accessRestriction) {
    this.topLevelTypes =
        new SourceTypeBinding[0]; // want it initialized if the package cannot be resolved
    boolean firstIsSynthetic = false;
    if (this.referenceContext.compilationResult.compilationUnit != null) {
      char[][] expectedPackageName =
          this.referenceContext.compilationResult.compilationUnit.getPackageName();
      if (expectedPackageName != null
          && !CharOperation.equals(this.currentPackageName, expectedPackageName)) {

        // only report if the unit isn't structurally empty
        if (this.referenceContext.currentPackage != null
            || this.referenceContext.types != null
            || this.referenceContext.imports != null) {
          problemReporter().packageIsNotExpectedPackage(this.referenceContext);
        }
        this.currentPackageName =
            expectedPackageName.length == 0 ? CharOperation.NO_CHAR_CHAR : expectedPackageName;
      }
    }
    if (this.currentPackageName == CharOperation.NO_CHAR_CHAR) {
      // environment default package is never null
      this.fPackage = this.environment.defaultPackage;
    } else {
      if ((this.fPackage = this.environment.createPackage(this.currentPackageName)) == null) {
        if (this.referenceContext.currentPackage != null) {
          problemReporter()
              .packageCollidesWithType(
                  this.referenceContext); // only report when the unit has a package statement
        }
        // ensure fPackage is not null
        this.fPackage = this.environment.defaultPackage;
        return;
      } else if (this.referenceContext.isPackageInfo()) {
        // resolve package annotations now if this is "package-info.java".
        if (this.referenceContext.types == null || this.referenceContext.types.length == 0) {
          this.referenceContext.types = new TypeDeclaration[1];
          this.referenceContext.createPackageInfoType();
          firstIsSynthetic = true;
        }
        // ensure the package annotations are copied over before resolution
        if (this.referenceContext.currentPackage != null
            && this.referenceContext.currentPackage.annotations != null) {
          this.referenceContext.types[0].annotations =
              this.referenceContext.currentPackage.annotations;
        }
      }
      recordQualifiedReference(this.currentPackageName); // always dependent on your own package
    }

    // Skip typeDeclarations which know of previously reported errors
    TypeDeclaration[] types = this.referenceContext.types;
    int typeLength = (types == null) ? 0 : types.length;
    this.topLevelTypes = new SourceTypeBinding[typeLength];
    int count = 0;
    nextType:
    for (int i = 0; i < typeLength; i++) {
      TypeDeclaration typeDecl = types[i];
      if (this.environment.isProcessingAnnotations && this.environment.isMissingType(typeDecl.name))
        throw new SourceTypeCollisionException(); // resolved a type ref before APT generated the
      // type
      ReferenceBinding typeBinding = this.fPackage.getType0(typeDecl.name);
      recordSimpleReference(typeDecl.name); // needed to detect collision cases
      if (typeBinding != null
          && typeBinding.isValidBinding()
          && !(typeBinding instanceof UnresolvedReferenceBinding)) {
        // if its an unresolved binding - its fixed up whenever its needed, see
        // UnresolvedReferenceBinding.resolve()
        if (this.environment.isProcessingAnnotations)
          throw new SourceTypeCollisionException(); // resolved a type ref before APT generated the
        // type
        // if a type exists, check that its a valid type
        // it can be a NotFound problem type if its a secondary type referenced before its primary
        // type found in additional units
        // and it can be an unresolved type which is now being defined
        problemReporter().duplicateTypes(this.referenceContext, typeDecl);
        continue nextType;
      }
      if (this.fPackage != this.environment.defaultPackage
          && this.fPackage.getPackage(typeDecl.name) != null) {
        // if a package exists, it must be a valid package - cannot be a NotFound problem package
        // this is now a warning since a package does not really 'exist' until it contains a type,
        // see JLS v2, 7.4.3
        problemReporter().typeCollidesWithPackage(this.referenceContext, typeDecl);
      }

      if ((typeDecl.modifiers & ClassFileConstants.AccPublic) != 0) {
        char[] mainTypeName;
        if ((mainTypeName = this.referenceContext.getMainTypeName())
                != null // mainTypeName == null means that implementor of ICompilationUnit decided
            // to return null
            && !CharOperation.equals(mainTypeName, typeDecl.name)) {
          problemReporter().publicClassMustMatchFileName(this.referenceContext, typeDecl);
          // tolerate faulty main type name (91091), allow to proceed into type construction
        }
      }

      ClassScope child = new ClassScope(this, typeDecl);
      SourceTypeBinding type = child.buildType(null, this.fPackage, accessRestriction);
      if (firstIsSynthetic && i == 0) type.modifiers |= ClassFileConstants.AccSynthetic;
      if (type != null) this.topLevelTypes[count++] = type;
    }

    // shrink topLevelTypes... only happens if an error was reported
    if (count != this.topLevelTypes.length)
      System.arraycopy(
          this.topLevelTypes, 0, this.topLevelTypes = new SourceTypeBinding[count], 0, count);
  }
  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;
  }
  /**
   * Validate the given package name for the given source and compliance levels.
   *
   * <p>The syntax of a package name corresponds to PackageName as defined by PackageDeclaration
   * (JLS2 7.4). For example, <code>"java.lang"</code>.
   *
   * <p>Note that the given name must be a non-empty package name (that is, attempting to validate
   * the default package will return an error status.) Also it must not contain any characters or
   * substrings that are not valid on the file system on which workspace root is located.
   *
   * @param name the name of a package
   * @param sourceLevel the source level
   * @param complianceLevel the compliance level
   * @return a status object with code <code>IStatus.OK</code> if the given name is valid as a
   *     package name, otherwise a status object indicating what is wrong with the name
   * @since 3.3
   */
  public static IStatus validatePackageName(
      String name, String sourceLevel, String complianceLevel) {

    if (name == null) {
      return new Status(
          IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_package_nullName, null);
    }
    int length;
    if ((length = name.length()) == 0) {
      return new Status(
          IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_package_emptyName, null);
    }
    if (name.charAt(0) == DOT || name.charAt(length - 1) == DOT) {
      return new Status(
          IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_package_dotName, null);
    }
    if (CharOperation.isWhitespace(name.charAt(0))
        || CharOperation.isWhitespace(name.charAt(name.length() - 1))) {
      return new Status(
          IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.convention_package_nameWithBlanks, null);
    }
    int dot = 0;
    while (dot != -1 && dot < length - 1) {
      if ((dot = name.indexOf(DOT, dot + 1)) != -1
          && dot < length - 1
          && name.charAt(dot + 1) == DOT) {
        return new Status(
            IStatus.ERROR,
            JavaCore.PLUGIN_ID,
            -1,
            Messages.convention_package_consecutiveDotsName,
            null);
      }
    }
    IWorkspace workspace = ResourcesPlugin.getWorkspace();
    StringTokenizer st = new StringTokenizer(name, "."); // $NON-NLS-1$
    boolean firstToken = true;
    IStatus warningStatus = null;
    while (st.hasMoreTokens()) {
      String typeName = st.nextToken();
      typeName = typeName.trim(); // grammar allows spaces
      char[] scannedID = scannedIdentifier(typeName, sourceLevel, complianceLevel);
      if (scannedID == null) {
        return new Status(
            IStatus.ERROR,
            JavaCore.PLUGIN_ID,
            -1,
            Messages.bind(Messages.convention_illegalIdentifier, typeName),
            null);
      }
      IStatus status = workspace.validateName(new String(scannedID), IResource.FOLDER);
      if (!status.isOK()) {
        return status;
      }
      if (firstToken && scannedID.length > 0 && ScannerHelper.isUpperCase(scannedID[0])) {
        if (warningStatus == null) {
          warningStatus =
              new Status(
                  IStatus.WARNING,
                  JavaCore.PLUGIN_ID,
                  -1,
                  Messages.convention_package_uppercaseName,
                  null);
        }
      }
      firstToken = false;
    }
    if (warningStatus != null) {
      return warningStatus;
    }
    return JavaModelStatus.VERIFIED_OK;
  }
 /*
  * Creates the value wrapper from the given expression, and sets the valueKind on the given memberValuePair
  */
 private Object getAnnotationMemberValue(
     MemberValuePair memberValuePair, Expression expression, JavaElement parentElement) {
   if (expression instanceof NullLiteral) {
     return null;
   } else if (expression instanceof Literal) {
     ((Literal) expression).computeConstant();
     return Util.getAnnotationMemberValue(memberValuePair, expression.constant);
   } else if (expression instanceof org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation) {
     memberValuePair.valueKind = IMemberValuePair.K_ANNOTATION;
     return getAnnotation(
         (org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation) expression, parentElement);
   } else if (expression instanceof ClassLiteralAccess) {
     ClassLiteralAccess classLiteral = (ClassLiteralAccess) expression;
     char[] typeName = CharOperation.concatWith(classLiteral.type.getTypeName(), '.');
     memberValuePair.valueKind = IMemberValuePair.K_CLASS;
     return new String(typeName);
   } else if (expression instanceof QualifiedNameReference) {
     char[] qualifiedName =
         CharOperation.concatWith(((QualifiedNameReference) expression).tokens, '.');
     memberValuePair.valueKind = IMemberValuePair.K_QUALIFIED_NAME;
     return new String(qualifiedName);
   } else if (expression instanceof SingleNameReference) {
     char[] simpleName = ((SingleNameReference) expression).token;
     if (simpleName == RecoveryScanner.FAKE_IDENTIFIER) {
       memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN;
       return null;
     }
     memberValuePair.valueKind = IMemberValuePair.K_SIMPLE_NAME;
     return new String(simpleName);
   } else if (expression instanceof ArrayInitializer) {
     memberValuePair.valueKind = -1; // modified below by the first call to getMemberValue(...)
     Expression[] expressions = ((ArrayInitializer) expression).expressions;
     int length = expressions == null ? 0 : expressions.length;
     Object[] values = new Object[length];
     for (int i = 0; i < length; i++) {
       int previousValueKind = memberValuePair.valueKind;
       Object value = getAnnotationMemberValue(memberValuePair, expressions[i], parentElement);
       if (previousValueKind != -1 && memberValuePair.valueKind != previousValueKind) {
         // values are heterogeneous, value kind is thus unknown
         memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN;
       }
       values[i] = value;
     }
     if (memberValuePair.valueKind == -1) memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN;
     return values;
   } else if (expression
       instanceof UnaryExpression) { // to deal with negative numerals (see bug - 248312)
     UnaryExpression unaryExpression = (UnaryExpression) expression;
     if ((unaryExpression.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT
         == OperatorIds.MINUS) {
       if (unaryExpression.expression instanceof Literal) {
         Literal subExpression = (Literal) unaryExpression.expression;
         subExpression.computeConstant();
         return Util.getNegativeAnnotationMemberValue(memberValuePair, subExpression.constant);
       }
     }
     memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN;
     return null;
   } else {
     memberValuePair.valueKind = IMemberValuePair.K_UNKNOWN;
     return null;
   }
 }