| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- // 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_H_
- #define CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_H_
- #include <cstdint>
- #include <functional>
- #include <string>
- #include "common/check.h"
- #include "llvm/ADT/Any.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/StringRef.h"
- #include "toolchain/diagnostics/kind.h"
- namespace Carbon::Diagnostics {
- enum class Level : int8_t {
- // Information about the location of another diagnostic, showing how we
- // reached that location. This is currently only used for the "in import"
- // message.
- LocationInfo,
- // A note, not indicating an error on its own, but possibly providing
- // additional information for an error or warning.
- Note,
- // A Context that will be discarded if another Context precedes it in the
- // diagnostic, as the Context is assumed to provide better information. Used
- // as a fallback for when no better Context is provided.
- SoftContext,
- // Describes the high level operation being performed. If a diagnostic is
- // issued, the first Context message will steal its level and be displayed as
- // if it is the top-level diagnostic, and the rest are treated as Note
- // messages. The diagnostic message also becomes a Note of the first Context
- // message.
- Context,
- // A warning diagnostic, indicating a likely problem with the program.
- Warning,
- // An error diagnostic, indicating that the program is not valid.
- Error,
- };
- // Provides a definition of a diagnostic. For example:
- // CARBON_DIAGNOSTIC(MyDiagnostic, Error, "invalid code!");
- // CARBON_DIAGNOSTIC(MyDiagnostic, Warning, "found {0}, expected {1}",
- // std::string, std::string);
- //
- // Arguments are passed to llvm::formatv; see:
- // https://llvm.org/doxygen/FormatVariadic_8h_source.html
- //
- // See `Diagnostics::Emitter::Emit` for comments about argument lifetimes.
- #define CARBON_DIAGNOSTIC(DiagnosticName, LevelValue, Format, ...) \
- static constexpr auto DiagnosticName = \
- ::Carbon::Diagnostics::DiagnosticBase<__VA_ARGS__>( \
- ::Carbon::Diagnostics::Kind::DiagnosticName, \
- ::Carbon::Diagnostics::Level::LevelValue, /*is_on_scope=*/false, \
- Format)
- // Similar to `CARBON_DIAGNOSTIC`, but for diagnostics that are generated on a
- // scope; see `Diagnostic::is_on_scope` for details.
- #define CARBON_DIAGNOSTIC_ON_SCOPE(DiagnosticName, LevelValue, Format, ...) \
- static_assert(::Carbon::Diagnostics::Level::LevelValue == \
- ::Carbon::Diagnostics::Level::Warning || \
- ::Carbon::Diagnostics::Level::LevelValue == \
- ::Carbon::Diagnostics::Level::Error, \
- "Only use CARBON_DIAGNOSTIC_ON_SCOPE for the main " \
- "diagnostic, not notes"); \
- static constexpr auto DiagnosticName = \
- ::Carbon::Diagnostics::DiagnosticBase<__VA_ARGS__>( \
- ::Carbon::Diagnostics::Kind::DiagnosticName, \
- ::Carbon::Diagnostics::Level::LevelValue, /*is_on_scope=*/true, \
- Format)
- // A location for a diagnostic in a file. The lifetime of a Loc
- // is required to be less than SourceBuffer that it refers to due to the
- // contained filename and line references.
- struct Loc {
- // Writes the location to the given stream. It will be formatted as
- // `<filename>:<line_number>:<column_number>: ` with parts dropped when
- // unknown.
- auto FormatLocation(llvm::raw_ostream& out) const -> void;
- // Write the source snippet corresponding to this location to the given
- // stream.
- auto FormatSnippet(llvm::raw_ostream& out, int indent = 0) const -> void;
- // Name of the file or buffer that this diagnostic refers to.
- llvm::StringRef filename;
- // A reference to the line of the error.
- llvm::StringRef line;
- // A full snippet to print. If non-empty, this is used instead of `line` when
- // printing a snippet. Should contain both the quoted text and the caret line.
- std::string snippet;
- // 1-based line number. -1 indicates unknown; other values are unused.
- int32_t line_number = -1;
- // 1-based column number. -1 indicates unknown; other values are unused.
- int32_t column_number = -1;
- // The number of characters corresponding to the location in the line,
- // starting at column_number. Should always be at least 1.
- int32_t length = 1;
- };
- // A message composing a diagnostic. This may be the main message, but can also
- // be notes providing more information.
- struct Message {
- // Helper for calling `format_fn`.
- auto Format() const -> std::string { return format_fn(*this); }
- // The diagnostic's kind.
- Kind kind;
- // The message's level. This may be different from, but should not be more
- // severe than, the diagnostic's level.
- Level level;
- // The calculated location of the diagnostic.
- Loc loc;
- // The diagnostic's format string. This, along with format_args, will be
- // passed to format_fn.
- llvm::StringLiteral format;
- // A list of format arguments.
- //
- // These may be used by non-standard consumers to inspect diagnostic details
- // without needing to parse the formatted string; however, it should be
- // understood that diagnostic formats are subject to change and the llvm::Any
- // offers limited compile-time type safety. Integration tests are required.
- llvm::SmallVector<llvm::Any> format_args;
- // Returns the formatted string. By default, this uses llvm::formatv.
- std::function<auto(const Message&)->std::string> format_fn;
- };
- // An instance of a single error or warning. Information about the diagnostic
- // can be recorded into it for more complex consumers.
- struct Diagnostic {
- // The diagnostic's level.
- Level level;
- // Whether a diagnostic should only sort by `last_byte_offset` (which is
- // normal), or if it's generated on a scope and should be sorted based on the
- // first message's line and column when the `last_byte_offset` is equal.
- // This is used by `SortingConsumer`.
- bool is_on_scope;
- // The byte offset of the final token which is associated with the diagnostic.
- // This is used by `SortingConsumer`. This is separate from the
- // `Loc` because it must refer to a position in the primary file
- // being processed by a consumer, and has no use cross-file or in notes.
- //
- // This will usually be the start position (not end) of the last lexed token
- // processed before the diagnostic; it could also be `-1` when no source code
- // needs to be processed for a diagnostic, or an appropriate byte offset when
- // we specifically want a different diagnostic ordering than when a diagnostic
- // is issued.
- int32_t last_byte_offset = -1;
- // Messages related to the diagnostic. Only one should be a warning or error;
- // other messages provide context.
- llvm::SmallVector<Message> messages;
- };
- // Use the DIAGNOSTIC macro to instantiate this.
- // This stores static information about a diagnostic category.
- template <typename... Args>
- struct DiagnosticBase {
- explicit constexpr DiagnosticBase(Kind kind, Level level, bool is_on_scope,
- llvm::StringLiteral format)
- : Kind(kind), Level(level), IsOnScope(is_on_scope), Format(format) {
- static_assert((... && !(std::is_same_v<Args, llvm::StringRef> ||
- std::is_same_v<Args, llvm::StringLiteral>)),
- "String type disallowed in diagnostics. See "
- "https://github.com/carbon-language/carbon-lang/blob/trunk/"
- "toolchain/docs/diagnostics.md#diagnostic-parameter-types");
- }
- // The diagnostic's kind.
- Kind Kind;
- // The diagnostic's level.
- Level Level;
- // See `Diagnostic::is_on_scope`.
- bool IsOnScope;
- // The diagnostic's format for llvm::formatv.
- llvm::StringLiteral Format;
- };
- } // namespace Carbon::Diagnostics
- #endif // CARBON_TOOLCHAIN_DIAGNOSTICS_DIAGNOSTIC_H_
|