Repository: carbon-language/carbon-lang
File: toolchain/check/diagnostic_helpers.h (C/C++)

Code before:
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef CARBON_TOOLCHAIN_CHECK_DIAGNOSTIC_HELPERS_H_
#define CARBON_TOOLCHAIN_CHECK_DIAGNOSTIC_HELPERS_H_

#include <concepts>

#include "llvm/ADT/APSInt.h"
#include "toolchain/parse/node_ids.h"
#include "toolchain/sem_ir/ids.h"

namespace Carbon::Check {

// The `DiagnosticEmitterBase` is templated on this type so that
// diagnostics can be passed an `InstId` as a location, without having to
// explicitly construct a `LocId` from it first.
class LocIdForDiagnostics {
 public:
  // Constructs a token-only location for a diagnostic.
  //
  // This means the displayed location will include only the location's specific
  // parse node, instead of also including its descendants. As such, this can
  // only be true for locations backed by a `NodeId`.
  template <class LocT>
    requires std::constructible_from<SemIR::LocId, LocT>
  static auto TokenOnly(LocT loc_id) -> LocIdForDiagnostics {
    return LocIdForDiagnostics(SemIR::LocId(loc_id), true);
  }

  template <class LocT>
    requires std::constructible_from<SemIR::LocId, LocT>
  // NOLINTNEXTLINE(google-explicit-constructor)
  LocIdForDiagnostics(LocT loc_id)
      : LocIdForDiagnostics(SemIR::LocId(loc_id), false) {}

  auto loc_id() const -> SemIR::LocId { return loc_id_; }

  auto is_token_only() const -> bool { return is_token_only_; }

 private:
  explicit LocIdForDiagnostics(SemIR::LocId loc_id, bool is_token_only)
      : loc_id_(loc_id), is_token_only_(is_token_only) {}

  SemIR::LocId loc_id_;
  bool is_token_only_;
};

// We define the emitter separately for dependencies, so only provide a base

Review comment (suggestion):
It wasn't clear to me which cases "backed by a `NodeId`" might cover without reading the implementation, but it looks like the only case this is excluding is a location imported from C++. Would it be worth mentioning that here? Maybe:
```suggestion
  // parse node, instead of also including its descendants. This has no effect
  // for locations that refer to C++ source files.
```
(We could make `token_only` mode highlight the token in C++ diagnostics too, so maybe even this restriction could be lifted eventually.)

Code after:
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef CARBON_TOOLCHAIN_CHECK_DIAGNOSTIC_HELPERS_H_
#define CARBON_TOOLCHAIN_CHECK_DIAGNOSTIC_HELPERS_H_

#include <concepts>

#include "llvm/ADT/APSInt.h"
#include "toolchain/parse/node_ids.h"
#include "toolchain/sem_ir/ids.h"

namespace Carbon::Check {

// The `DiagnosticEmitterBase` is templated on this type so that
// diagnostics can be passed an `InstId` as a location, without having to
// explicitly construct a `LocId` from it first.
class LocIdForDiagnostics {
 public:
  // Constructs a token-only location for a diagnostic.
  //
  // This means the displayed location will include only the location's specific
  // parse node, instead of also including its descendants.
  static auto TokenOnly(Parse::NodeId node_id) -> LocIdForDiagnostics {
    return LocIdForDiagnostics(SemIR::LocId(node_id), true);
  }

  template <class LocT>
    requires std::constructible_from<SemIR::LocId, LocT>
  // NOLINTNEXTLINE(google-explicit-constructor)
  LocIdForDiagnostics(LocT loc_id)
      : LocIdForDiagnostics(SemIR::LocId(loc_id), false) {}

  auto loc_id() const -> SemIR::LocId { return loc_id_; }

  auto is_token_only() const -> bool { return is_token_only_; }

 private:
  explicit LocIdForDiagnostics(SemIR::LocId loc_id, bool is_token_only)
      : loc_id_(loc_id), is_token_only_(is_token_only) {}

  SemIR::LocId loc_id_;
  bool is_token_only_;
};

// We define the emitter separately for dependencies, so only provide a base
// here.
using DiagnosticEmitterBase = Diagnostics::Emitter<LocIdForDiagnostics>;