diagnostic_emitter.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef DIAGNOSTICS_DIAGNOSTICEMITTER_H_
  5. #define DIAGNOSTICS_DIAGNOSTICEMITTER_H_
  6. #include <functional>
  7. #include <string>
  8. #include <type_traits>
  9. #include "llvm/ADT/Any.h"
  10. #include "llvm/ADT/STLExtras.h"
  11. #include "llvm/ADT/SmallVector.h"
  12. #include "llvm/ADT/StringRef.h"
  13. #include "llvm/Support/raw_ostream.h"
  14. namespace Carbon {
  15. // An instance of a single error or warning. Information about the diagnostic
  16. // can be recorded into it for more complex consumers.
  17. //
  18. // TODO: turn this into a much more reasonable API when we add some actual
  19. // uses of it.
  20. struct Diagnostic {
  21. llvm::StringRef short_name;
  22. std::string message;
  23. };
  24. // Manages the creation of reports, the testing if diagnostics are enabled, and
  25. // the collection of reports.
  26. class DiagnosticEmitter {
  27. public:
  28. using Callback = std::function<void(const Diagnostic&)>;
  29. explicit DiagnosticEmitter(Callback callback)
  30. : callback_(std::move(callback)) {}
  31. ~DiagnosticEmitter() = default;
  32. // Emits an error unconditionally after applying the provided `substitutions`.
  33. template <typename DiagnosticT>
  34. void EmitError(typename DiagnosticT::Substitutions substitutions) {
  35. callback_({.short_name = DiagnosticT::ShortName,
  36. .message = DiagnosticT::Format(substitutions)});
  37. }
  38. // Emits an error unconditionally when there are no substitutions.
  39. template <typename DiagnosticT>
  40. std::enable_if_t<std::is_empty_v<typename DiagnosticT::Substitutions>>
  41. EmitError() {
  42. EmitError<DiagnosticT>({});
  43. }
  44. // Emits a warning if `F` returns true. `F` may or may not be called if the
  45. // warning is disabled.
  46. template <typename DiagnosticT>
  47. void EmitWarningIf(
  48. llvm::function_ref<bool(typename DiagnosticT::Substitutions&)> f) {
  49. // TODO(kfm): check if this warning is enabled
  50. typename DiagnosticT::Substitutions substitutions;
  51. if (f(substitutions)) {
  52. callback_({.short_name = DiagnosticT::ShortName,
  53. .message = DiagnosticT::Format(substitutions)});
  54. }
  55. }
  56. private:
  57. Callback callback_;
  58. };
  59. inline auto ConsoleDiagnosticEmitter() -> DiagnosticEmitter& {
  60. static auto* emitter = new DiagnosticEmitter(
  61. [](const Diagnostic& d) { llvm::errs() << d.message << "\n"; });
  62. return *emitter;
  63. }
  64. inline auto NullDiagnosticEmitter() -> DiagnosticEmitter& {
  65. static auto* emitter = new DiagnosticEmitter([](const Diagnostic&) {});
  66. return *emitter;
  67. }
  68. // CRTP base class for diagnostics with no substitutions.
  69. template <typename Derived>
  70. struct SimpleDiagnostic {
  71. struct Substitutions {};
  72. static auto Format(const Substitutions&) -> std::string {
  73. return Derived::Message.str();
  74. }
  75. };
  76. } // namespace Carbon
  77. #endif // DIAGNOSTICS_DIAGNOSTICEMITTER_H_