mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
What this really does is avoids shadowing names, so that we can comfortable have things like `Check::DiagnosticEmitter` or `Check::DiagnosticLoc` without shadowing being a concern. Note, down this path I'm also thinking about: - Renaming misc DiagnosticConsumer/DiagnosticEmitter classes, possibly just to DiagnosticConsumer/DiagnosticEmitter (so `Check::DiagnosticEmitter` instead of `SemIRLocDiagnosticEmitter`). - Dropping `Diagnostic` from `Emitter::DiagnosticBuilder`. - But not for `Check::DiagnosticBuilder`, because `Check::Builder` would be ambiguous. - Renaming diagnostics/diagnostic_* to drop "diagnostic". [Discussion about SemIRLoc -> DiagnosticLoc](https://discord.com/channels/655572317891461132/655578254970716160/1353771570463768698) reminded me of this (in particular the older [Check::DiagnosticBuilder discussion](https://discord.com/channels/655572317891461132/655578254970716160/1344363562608627763)), but I'd only do that rename if there's matching consensus about a path forward where we keep SemIRLoc, and in a way that it's only ever used for diagnostics (the divergence from which is at the root of current LocId discussion). I'm trying to keep that separate from a namespace addition for clarity.
93 lines
3.1 KiB
C++
93 lines
3.1 KiB
C++
// 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_DIAGNOSTICS_DIAGNOSTIC_CONSUMER_H_
|
|
#define CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_CONSUMER_H_
|
|
|
|
#include "common/ostream.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "toolchain/diagnostics/diagnostic.h"
|
|
|
|
namespace Carbon::Diagnostics {
|
|
|
|
// Receives diagnostics as they are emitted.
|
|
class Consumer {
|
|
public:
|
|
virtual ~Consumer() = default;
|
|
|
|
// Handle a diagnostic.
|
|
//
|
|
// This relies on moves of the Diagnostic. At present, diagnostics are
|
|
// allocated on the stack, so their lifetime is that of HandleDiagnostic.
|
|
// However, SortingConsumer needs a longer lifetime, until all
|
|
// diagnostics have been produced. As a consequence, it needs to either copy
|
|
// or move the Diagnostic, and right now we're moving due to the overhead of
|
|
// notes.
|
|
//
|
|
// At present, there is no persistent storage of diagnostics because IDEs
|
|
// would be fine with diagnostics being printed immediately and discarded,
|
|
// without SortingConsumer. If this becomes a performance issue, we
|
|
// may want to investigate alternative ownership models that address both IDE
|
|
// and CLI user needs.
|
|
virtual auto HandleDiagnostic(Diagnostic diagnostic) -> void = 0;
|
|
|
|
// Flushes any buffered input.
|
|
virtual auto Flush() -> void {}
|
|
};
|
|
|
|
// A diagnostic consumer that prints to a stream.
|
|
class StreamConsumer : public Consumer {
|
|
public:
|
|
explicit StreamConsumer(llvm::raw_ostream* stream) : stream_(stream) {}
|
|
|
|
auto HandleDiagnostic(Diagnostic diagnostic) -> void override;
|
|
auto Flush() -> void override { stream_->flush(); }
|
|
|
|
auto set_stream(llvm::raw_ostream* stream) -> void { stream_ = stream; }
|
|
auto set_include_diagnostic_kind(bool value) -> void {
|
|
include_diagnostic_kind_ = value;
|
|
}
|
|
|
|
private:
|
|
auto Print(const Message& message, llvm::StringRef prefix) -> void;
|
|
|
|
llvm::raw_ostream* stream_;
|
|
|
|
// Whether to include the diagnostic kind when printing.
|
|
bool include_diagnostic_kind_ = false;
|
|
|
|
// Whethere we've printed a diagnostic. Used for printing separators.
|
|
bool printed_diagnostic_ = false;
|
|
};
|
|
|
|
// Returns a diagnostic consumer instance that prints to stderr.
|
|
auto ConsoleConsumer() -> Consumer&;
|
|
|
|
// Diagnostic consumer adaptor that tracks whether any errors have been
|
|
// produced.
|
|
class ErrorTrackingConsumer : public Consumer {
|
|
public:
|
|
explicit ErrorTrackingConsumer(Consumer& next_consumer)
|
|
: next_consumer_(&next_consumer) {}
|
|
|
|
auto HandleDiagnostic(Diagnostic diagnostic) -> void override {
|
|
seen_error_ |= diagnostic.level == Level::Error;
|
|
next_consumer_->HandleDiagnostic(std::move(diagnostic));
|
|
}
|
|
|
|
// Reset whether we've seen an error.
|
|
auto Reset() -> void { seen_error_ = false; }
|
|
|
|
// Returns whether we've seen an error since the last reset.
|
|
auto seen_error() const -> bool { return seen_error_; }
|
|
|
|
private:
|
|
Consumer* next_consumer_;
|
|
bool seen_error_ = false;
|
|
};
|
|
|
|
} // namespace Carbon::Diagnostics
|
|
|
|
#endif // CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_CONSUMER_H_
|