Repository: carbon-language/carbon-lang
File: toolchain/check/import_cpp.cpp (C++)

Code before:

namespace {

// Used to convert Clang diagnostics to Carbon diagnostics.
//
// Handling of Clang notes is a little subtle: as far as Clang is concerned,
// notes are separate diagnostics, not connected to the error or warning that
// precedes them. But in Carbon's diagnostics system, notes are part of the
// enclosing diagnostic. To handle this, we buffer Clang diagnostics until we
// reach a point where we know we're not in the middle of a diagnostic, and then
// emit a diagnostic along with all of its notes. This is triggered when adding
// or removing a Carbon context note, which could otherwise get attached to the
// wrong C++ diagnostics, and at the end of the Carbon program.
class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer {
 public:
  // Creates an instance with the location that triggers calling Clang.
  // `context` must not be null.
  explicit CarbonClangDiagnosticConsumer(
      Context* context, std::shared_ptr<clang::CompilerInvocation> invocation)
      : context_(context),
        invocation_(std::move(invocation)),
        flusher_{.consumer_ = this} {
    context->emitter().AddFlushFn(flusher_);
  }

  ~CarbonClangDiagnosticConsumer() {
    CARBON_CHECK(diagnostic_infos_.empty(),
                 "Missing flush before destroying diagnostic consumer");
  }

  // Generates a Carbon warning for each Clang warning and a Carbon error for
  // each Clang error or fatal.
  auto HandleDiagnostic(clang::DiagnosticsEngine::Level diag_level,
                        const clang::Diagnostic& info) -> void override {
    DiagnosticConsumer::HandleDiagnostic(diag_level, info);

    SemIR::ImportIRInstId clang_import_ir_inst_id =
        AddImportIRInst(*context_, info.getLocation());

    llvm::SmallString<256> message;
    info.FormatDiagnostic(message);

    if (!info.hasSourceManager()) {
      // If we don't have a source manager, we haven't actually started
      // compiling yet, and this is an error from the driver or early in the
      // frontend. Pass it on directly.
      CARBON_CHECK(info.getLocation().isInvalid());
      diagnostic_infos_.push_back({.level = diag_level,
                                   .import_ir_inst_id = clang_import_ir_inst_id,
                                   .message = message.str().str()});
      return;

Review comment (suggestion):
```suggestion
  ~CarbonClangDiagnosticConsumer() override {
```

Code after:

namespace {

// Used to convert Clang diagnostics to Carbon diagnostics.
//
// Handling of Clang notes is a little subtle: as far as Clang is concerned,
// notes are separate diagnostics, not connected to the error or warning that
// precedes them. But in Carbon's diagnostics system, notes are part of the
// enclosing diagnostic. To handle this, we buffer Clang diagnostics until we
// reach a point where we know we're not in the middle of a diagnostic, and then
// emit a diagnostic along with all of its notes. This is triggered when adding
// or removing a Carbon context note, which could otherwise get attached to the
// wrong C++ diagnostics, and at the end of the Carbon program.
class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer {
 public:
  // Creates an instance with the location that triggers calling Clang.
  // `context` must not be null.
  explicit CarbonClangDiagnosticConsumer(
      Context* context, std::shared_ptr<clang::CompilerInvocation> invocation)
      : context_(context), invocation_(std::move(invocation)) {
    context->emitter().AddFlushFn([this] { EmitDiagnostics(); });
  }

  ~CarbonClangDiagnosticConsumer() override {
    CARBON_CHECK(diagnostic_infos_.empty(),
                 "Missing flush before destroying diagnostic consumer");
  }

  // Generates a Carbon warning for each Clang warning and a Carbon error for
  // each Clang error or fatal.
  auto HandleDiagnostic(clang::DiagnosticsEngine::Level diag_level,
                        const clang::Diagnostic& info) -> void override {
    DiagnosticConsumer::HandleDiagnostic(diag_level, info);

    SemIR::ImportIRInstId clang_import_ir_inst_id =
        AddImportIRInst(*context_, info.getLocation());

    llvm::SmallString<256> message;
    info.FormatDiagnostic(message);

    if (!info.hasSourceManager()) {
      // If we don't have a source manager, we haven't actually started
      // compiling yet, and this is an error from the driver or early in the
      // frontend. Pass it on directly.
      CARBON_CHECK(info.getLocation().isInvalid());
      diagnostic_infos_.push_back({.level = diag_level,
                                   .import_ir_inst_id = clang_import_ir_inst_id,
                                   .message = message.str().str()});
      return;
    }