Repository: carbon-language/carbon-lang
File: toolchain/sem_ir/formatter.cpp (C++)

Code before:
  if (!decl_id.has_value()) {
    return true;
  }
  if (!should_format_entity_(decl_id)) {
    return false;
  }

  if (!sem_ir_->parse_tree().tokens().has_dump_sem_ir_ranges()) {
    return true;
  }

  // When there are dump ranges, ignore imported instructions.
  auto loc_id = sem_ir_->insts().GetCanonicalLocId(decl_id);
  if (loc_id.kind() != LocId::Kind::NodeId) {
    return false;
  }

  const auto& tree_and_subtrees = get_tree_and_subtrees_();

  // This takes the earliest token from either the node or its first postorder
  // child. The first postorder child isn't necessarily the earliest token in
  // the subtree (for example, it can miss modifiers), but finding the earliest
  // token requires walking *all* children, whereas this approach is
  // constant-time.
  auto begin = sem_ir_->parse_tree().node_token(
      *tree_and_subtrees.postorder(loc_id.node_id()).begin());

  // Non-defining declarations will be associated with a `Decl` node.
  // Definitions will have a `DefinitionStart` for which we can use the parent
  // to find the `Definition`, giving a range that includes the definition's
  // body.
  auto end_node_id = loc_id.node_id();
  if (is_definition_start) {
    end_node_id = node_parents_[end_node_id.index];
  }
  auto inclusive_end = sem_ir_->parse_tree().node_token(end_node_id);

  return sem_ir_->parse_tree().tokens().OverlapsWithDumpSemIRRange(
      begin, inclusive_end);
}

auto Formatter::ShouldFormatEntity(const EntityWithParamsBase& entity) -> bool {
  return ShouldFormatEntity(entity.latest_decl_id(),
                            entity.definition_id.has_value());
}

auto Formatter::ShouldFormatInst(InstId inst_id) -> bool {
  if (!sem_ir_->parse_tree().tokens().has_dump_sem_ir_ranges()) {
    return true;
  }


Review comment (suggestion):
Is it possible for the location to refer to `NodeId::None`? I think that would cause problems in the array indexing below.

Code after:
    auto& chunk = output_chunks_[to_add.pop_back_val()];
    if (chunk.include_in_output) {
      continue;
    }
    chunk.include_in_output = true;
    to_add.append(chunk.dependencies);
    chunk.dependencies.clear();
  }
}

auto Formatter::ShouldFormatEntity(InstId decl_id, bool is_definition_start)
    -> bool {
  if (!decl_id.has_value()) {
    return true;
  }
  if (!should_format_entity_(decl_id)) {
    return false;
  }

  if (!sem_ir_->parse_tree().tokens().has_dump_sem_ir_ranges()) {
    return true;
  }

  // When there are dump ranges, ignore imported instructions.
  auto loc_id = sem_ir_->insts().GetCanonicalLocId(decl_id);
  if (loc_id.kind() != LocId::Kind::NodeId) {
    return false;
  }

  const auto& tree_and_subtrees = get_tree_and_subtrees_();

  // This takes the earliest token from either the node or its first postorder
  // child. The first postorder child isn't necessarily the earliest token in
  // the subtree (for example, it can miss modifiers), but finding the earliest
  // token requires walking *all* children, whereas this approach is
  // constant-time.
  auto begin = sem_ir_->parse_tree().node_token(
      *tree_and_subtrees.postorder(loc_id.node_id()).begin());

  // Non-defining declarations will be associated with a `Decl` node.
  // Definitions will have a `DefinitionStart` for which we can use the parent
  // to find the `Definition`, giving a range that includes the definition's
  // body.
  auto end_node_id = loc_id.node_id();
  if (is_definition_start) {
    end_node_id = node_parents_[end_node_id.index];
  }
  auto inclusive_end = sem_ir_->parse_tree().node_token(end_node_id);

  return sem_ir_->parse_tree().tokens().OverlapsWithDumpSemIRRange(
      begin, inclusive_end);