// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/developer/debug/zxdb/expr/index_walker.h"

#include <ctype.h>
#include <lib/syslog/cpp/macros.h>
#include <string.h>

#include <string_view>

#include "src/developer/debug/zxdb/common/err.h"
#include "src/developer/debug/zxdb/expr/expr_parser.h"
#include "src/developer/debug/zxdb/symbols/index.h"
#include "src/developer/debug/zxdb/symbols/index_node.h"

namespace zxdb {

namespace {

// We don't expect to have identifiers with whitespace in them. If somebody does "Foo < Bar>" stop
// considering the name at the space.
inline bool IsNameEnd(char ch) { return isspace(ch) || ch == '<'; }

// Finds all anonymous children of the nodes in the given stage and appends them recursively until
// there are no more to add.
//
// In the future we may want an option to trigger whether this function is called or not.
void AddAnonymousChildrenToStage(IndexWalker::Stage* stage) {
  // This implements a breadth-first search, adding all unnamed items.
  const std::string kEmpty;

  size_t last_pass_begin = 0;
  while (last_pass_begin < stage->size()) {
    size_t last_pass_end = stage->size();
    for (size_t i = last_pass_begin; i < last_pass_end; i++) {
      const IndexNode* node = (*stage)[i];

      // Add unnamed items. The common case is anonymous namespaces but we might also have unnamed
      // types for anonymous enums and structs.
      if (auto found = node->namespaces().find(kEmpty); found != node->namespaces().end())
        stage->push_back(&found->second);
      if (auto found = node->types().find(kEmpty); found != node->types().end())
        stage->push_back(&found->second);
    }
    last_pass_begin = last_pass_end;
  }
}

}  // namespace

IndexWalker::IndexWalker(const Index* index) {
  // Prefer not to reallocate the vector-of-vectors. It is rare for C++ namespace hierarchies to
  // be more than a couple of components long, so this number should cover most cases.
  path_.reserve(8);

  path_.push_back({&index->root()});
  AddAnonymousChildrenToStage(&path_[0]);
}

IndexWalker::~IndexWalker() = default;

bool IndexWalker::WalkUp() {
  if (path_.size() > 1) {
    // Don't walk above the root.
    path_.pop_back();
    return true;
  }
  return false;
}

// TODO(bug 6410) When we encounter an "inline" namespace, implicitly walk into it here, or have
// that controllable as an option. Inline namespaces produce a namespace with an implicit "using"
// statement.
bool IndexWalker::WalkInto(const ParsedIdentifierComponent& comp) {
  const Stage& old_stage = path_.back();

  const std::string& comp_name = comp.name();
  if (comp_name.empty())
    return true;  // No-op.

  Stage new_stage;
  for (const auto* old_node : old_stage) {
    for (int i = 0; i < static_cast<int>(IndexNode::Kind::kEndPhysical); i++) {
      const IndexNode::Map& map = old_node->MapForKind(static_cast<IndexNode::Kind>(i));

      // This is complicated by templates which can't be string-compared for equality without
      // canonicalization. Search everything in the index with the same base (non-template-part)
      // name. With the index being sorted, we can start at the item that begins lexicographically
      // >= the input.
      auto iter = map.lower_bound(comp_name);
      if (iter == map.end())
        continue;  // Nothing can match of this kind.

      if (!comp.has_template()) {
        // In the common case there is no template in the input, so we can just check for exact
        // string equality and be done with this kind.
        if (iter->first == comp_name)
          new_stage.push_back(&iter->second);
        continue;
      }

      // Check all nodes until template canonicalization can't affect the comparison.
      while (iter != map.end() && !IsIndexStringBeyondName(iter->first, comp_name)) {
        if (ComponentMatches(iter->first, comp)) {
          // Found match.
          new_stage.push_back(&iter->second);
          break;
        }

        ++iter;
      }
    }
  }

  if (new_stage.empty())
    return false;  // No children found.

  AddAnonymousChildrenToStage(&new_stage);

  // Commit the new found stuff.
  path_.push_back(std::move(new_stage));
  return true;
}

bool IndexWalker::WalkInto(const ParsedIdentifier& ident) {
  IndexWalker sub(*this);
  if (!sub.WalkIntoClosest(ident))
    return false;

  // Full walk succeeded, commit.
  std::swap(path_, sub.path_);
  return true;
}

void IndexWalker::WalkIntoSpecific(const IndexNode* node) { path_.push_back(Stage{node}); }

bool IndexWalker::WalkIntoClosest(const ParsedIdentifier& ident) {
  if (ident.qualification() == IdentifierQualification::kGlobal)
    path_.resize(1);  // Only keep the root.

  for (const auto& comp : ident.components()) {
    if (!WalkInto(comp))
      return false;  // This component not found.
  }
  return true;
}

// static
bool IndexWalker::ComponentMatches(const std::string& index_string,
                                   const ParsedIdentifierComponent& comp) {
  if (!ComponentMatchesNameOnly(index_string, comp))
    return false;
  // Only bother with the expensive template comparison on demand.
  return ComponentMatchesTemplateOnly(index_string, comp);
}

// static
bool IndexWalker::ComponentMatchesNameOnly(const std::string& index_string,
                                           const ParsedIdentifierComponent& comp) {
  const std::string& comp_name = comp.name();
  if (comp_name.size() > index_string.size())
    return false;  // Index string can't contain the name.

  if (strncmp(comp_name.c_str(), index_string.c_str(), comp_name.size()) != 0)
    return false;  // Name prefix doesn't match.

  // The index string should be at the end or should have a template spec
  // following the name.
  return index_string.size() == comp_name.size() || IsNameEnd(index_string[comp_name.size()]);
}

// static
bool IndexWalker::ComponentMatchesTemplateOnly(const std::string& index_string,
                                               const ParsedIdentifierComponent& comp) {
  ParsedIdentifier index_ident;
  Err err = ExprParser::ParseIdentifier(index_string, &index_ident);
  if (err.has_error())
    return false;

  // Each namespaced component should be a different layer of the index so it should produce a
  // one-component identifier. But this depends how the symbols are structured which we don't want
  // to make assumptions about.
  if (index_ident.components().size() != 1)
    return false;
  const auto& index_comp = index_ident.components()[0];

  if (comp.has_template() != index_comp.has_template())
    return false;
  return comp.template_contents() == index_comp.template_contents();
}

// static
bool IndexWalker::IsIndexStringBeyondName(std::string_view index_name, std::string_view name) {
  if (index_name.size() <= name.size()) {
    // The |index_name| is too small to start with the name and have template stuff on it (which
    // requires special handling), so we can directly return the answer by string comparison.
    return index_name > name;
  }

  // When the first name.size() characters of the index string aren't the same as the name, we don't
  // need to worry about templates or anything and can just return that comparison.
  std::string_view index_prefix = index_name.substr(0, name.size());
  int prefix_compare = index_prefix.compare(name);
  if (prefix_compare != 0)
    return prefix_compare > 0;  // Index is beyond the name by prefix only.

  // |index_name| starts with |name|. For the index node to be after all possible templates of
  // |name|, compare against the template begin character. This does make the assumption that the
  // compiler won't write templates with a space after the name ("vector < int >").
  return index_name[name.size()] > '<';
}

}  // namespace zxdb
