docs: public static LinkedHashSet<VarSymbol> findAllIdents(VisitorState state) {
      ImmutableSet.Builder<VarSymbol> result = new ImmutableSet.Builder<>();
      Tree prev = state.getPath().getLeaf();
      for (Tree curr : state.getPath().getParentPath()) {
        switch (curr.getKind()) {
          case BLOCK:
            for (StatementTree stmt : ((BlockTree) curr).getStatements()) {
              if (stmt.equals(prev)) {
                break;
              }
              addIfVariable(stmt, result);
            }
            break;
          case METHOD:
            for (VariableTree param : ((MethodTree) curr).getParameters()) {
              result.add(ASTHelpers.getSymbol(param));
            }
            break;
          case CATCH:
            result.add(ASTHelpers.getSymbol(((CatchTree) curr).getParameter()));
            break;
          case CLASS:
          case INTERFACE:
          case ENUM:
          case ANNOTATION_TYPE:
            // Collect fields declared in this class.  If we are in a field initializer, only
            // include fields declared before this one. JLS 8.3.3 allows forward references if the
            // field is referred to by qualified name, but we don't support that.
            for (Tree member : ((ClassTree) curr).getMembers()) {
              if (member.equals(prev)) {
                break;
              }
              addIfVariable(member, result);
            }
  
            // Collect inherited fields.
            Type classType = ASTHelpers.getType(curr);
            List<Type> classTypeClosure = state.getTypes().closure(classType);
            List<Type> superTypes =
                classTypeClosure.size() <= 1
                    ? Collections.emptyList()
                    : classTypeClosure.subList(1, classTypeClosure.size());
            for (Type type : superTypes) {
              Scope scope = type.tsym.members();
              ImmutableList.Builder<VarSymbol> varsList = ImmutableList.builder();
              for (Symbol var : scope.getSymbols(VarSymbol.class::isInstance)) {
                varsList.add((VarSymbol) var);
              }
              result.addAll(varsList.build().reverse());
            }
            break;
          case FOR_LOOP:
            addAllIfVariable(((ForLoopTree) curr).getInitializer(), result);
            break;
          case ENHANCED_FOR_LOOP:
            result.add(ASTHelpers.getSymbol(((EnhancedForLoopTree) curr).getVariable()));
            break;
          case TRY:
            TryTree tryTree = (TryTree) curr;
            boolean inResources = false;
            for (Tree resource : tryTree.getResources()) {
              if (resource.equals(prev)) {
                inResources = true;
                break;
              }
            }
            if (inResources) {
              // Case 1: we're in one of the resource declarations
              for (Tree resource : tryTree.getResources()) {
                if (resource.equals(prev)) {
                  break;
                }
                addIfVariable(resource, result);
              }
            } else if (tryTree.getBlock().equals(prev)) {
              // Case 2: We're in the block (not a catch or finally)
              addAllIfVariable(tryTree.getResources(), result);
            }
            break;
          case COMPILATION_UNIT:
            for (ImportTree importTree : ((CompilationUnitTree) curr).getImports()) {
              if (importTree.isStatic()
                  && importTree.getQualifiedIdentifier().getKind() == Kind.MEMBER_SELECT) {
                MemberSelectTree memberSelectTree =
                    (MemberSelectTree) importTree.getQualifiedIdentifier();
                Scope scope =
                    state
                        .getTypes()
                        .membersClosure(
                            ASTHelpers.getType(memberSelectTree.getExpression()),
                            /* skipInterface= */ false);
                for (Symbol var :
                    scope.getSymbols(
                        sym ->
                            sym instanceof VarSymbol
                                && sym.getSimpleName().equals(memberSelectTree.getIdentifier()))) {
                  result.add((VarSymbol) var);
                }
              }
            }
            break;
          default:
            // other node types don't introduce variables
            break;
        }
  
        prev = curr;
      }
  
      // TODO(eaftan): switch out collector for ImmutableSet.toImmutableSet()
      return result.build().stream()
          .filter(var -> isVisible(var, state.getPath()))
          .collect(Collectors.toCollection(LinkedHashSet::new));
    }