/**
   * Collects all elements available in a type: its hierarchy and its outer scopes.
   *
   * @param binding The type binding
   * @param flags Flags defining the elements to report
   * @param requestor the requestor to which all results are reported
   * @return return <code>true</code> if the requestor has reported the binding as found and no
   *     further results are required
   */
  private boolean addTypeDeclarations(
      ITypeBinding binding, int flags, IBindingRequestor requestor) {
    if (hasFlag(TYPES, flags) && !binding.isAnonymous()) {
      if (requestor.acceptBinding(binding)) return true;

      ITypeBinding[] typeParameters = binding.getTypeParameters();
      for (int i = 0; i < typeParameters.length; i++) {
        if (requestor.acceptBinding(typeParameters[i])) return true;
      }
    }

    addInherited(binding, flags, requestor); // add inherited

    if (binding.isLocal()) {
      addOuterDeclarationsForLocalType(binding, flags, requestor);
    } else {
      ITypeBinding declaringClass = binding.getDeclaringClass();
      if (declaringClass != null) {
        if (addTypeDeclarations(declaringClass, flags, requestor)) // Recursively add inherited
        return true;
      } else if (hasFlag(TYPES, flags)) {
        if (fRoot.findDeclaringNode(binding) != null) {
          List<AbstractTypeDeclaration> types = fRoot.types();
          for (int i = 0; i < types.size(); i++) {
            if (requestor.acceptBinding(types.get(i).resolveBinding())) return true;
          }
        }
      }
    }
    return false;
  }
 @Override
 public boolean visit(TypeDeclarationStatement node) {
   if (hasFlag(TYPES, fFlags) && fPosition < node.getStartPosition()) {
     fBreak = fRequestor.acceptBinding(node.resolveBinding());
   }
   return false;
 }
 @Override
 public boolean visit(VariableDeclaration node) {
   if (hasFlag(VARIABLES, fFlags) && fPosition < node.getStartPosition()) {
     fBreak = fRequestor.acceptBinding(node.resolveBinding());
   }
   return false;
 }
 /*
  * (non-Javadoc)
  * @see org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor#visit(org.eclipse.jdt.core.dom.TypeParameter)
  */
 @Override
 public boolean visit(TypeParameter node) {
   if (hasFlag(TYPES, fFlags) && node.getStartPosition() < fPosition) {
     fBreak = fRequestor.acceptBinding(node.getName().resolveBinding());
   }
   return !fBreak;
 }
  /**
   * Collects all elements available in a type and its hierarchy
   *
   * @param binding The type binding
   * @param flags Flags defining the elements to report
   * @param requestor the requestor to which all results are reported
   * @return return <code>true</code> if the requestor has reported the binding as found and no
   *     further results are required
   */
  private boolean addInherited(ITypeBinding binding, int flags, IBindingRequestor requestor) {
    if (!fTypesVisited.add(binding)) {
      return false;
    }
    if (hasFlag(VARIABLES, flags)) {
      IVariableBinding[] variableBindings = binding.getDeclaredFields();
      for (int i = 0; i < variableBindings.length; i++) {
        if (requestor.acceptBinding(variableBindings[i])) return true;
      }
    }

    if (hasFlag(METHODS, flags)) {
      IMethodBinding[] methodBindings = binding.getDeclaredMethods();
      for (int i = 0; i < methodBindings.length; i++) {
        IMethodBinding curr = methodBindings[i];
        if (!curr.isSynthetic() && !curr.isConstructor()) {
          if (requestor.acceptBinding(curr)) return true;
        }
      }
    }

    if (hasFlag(TYPES, flags)) {
      ITypeBinding[] typeBindings = binding.getDeclaredTypes();
      for (int i = 0; i < typeBindings.length; i++) {
        ITypeBinding curr = typeBindings[i];
        if (requestor.acceptBinding(curr)) return true;
      }
    }

    ITypeBinding superClass = binding.getSuperclass();
    if (superClass != null) {
      if (addInherited(superClass, flags, requestor)) // recursive
      return true;
    } else if (binding.isArray()) {
      if (addInherited(
          fRoot.getAST().resolveWellKnownType("java.lang.Object"), flags, requestor)) // $NON-NLS-1$
      return true;
    }

    ITypeBinding[] interfaces =
        binding.getInterfaces(); // includes looking for methods: abstract, unimplemented methods
    for (int i = 0; i < interfaces.length; i++) {
      if (addInherited(interfaces[i], flags, requestor)) // recursive
      return true;
    }
    return false;
  }
 @Override
 public boolean visit(TypeDeclarationStatement node) {
   if (hasFlag(TYPES, fFlags) && node.getStartPosition() + node.getLength() < fPosition) {
     fBreak = fRequestor.acceptBinding(node.resolveBinding());
     return false;
   }
   return !fBreak && isInside(node);
 }
 @Override
 public boolean visit(SwitchCase node) {
   // switch on enum allows to use enum constants without qualification
   if (hasFlag(VARIABLES, fFlags) && !node.isDefault() && isInside(node.getExpression())) {
     SwitchStatement switchStatement = (SwitchStatement) node.getParent();
     ITypeBinding binding = switchStatement.getExpression().resolveTypeBinding();
     if (binding != null && binding.isEnum()) {
       IVariableBinding[] declaredFields = binding.getDeclaredFields();
       for (int i = 0; i < declaredFields.length; i++) {
         IVariableBinding curr = declaredFields[i];
         if (curr.isEnumConstant()) {
           fBreak = fRequestor.acceptBinding(curr);
           if (fBreak) return false;
         }
       }
     }
   }
   return false;
 }