xref: /llvm-project/mlir/include/mlir/Tools/PDLL/AST/Diagnostic.h (revision db791b278a414fb6df1acc1799adcf11d8fb9169)
1 //===- Diagnostic.h - PDLL AST Diagnostics ----------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef MLIR_TOOLS_PDLL_AST_DIAGNOSTIC_H
10 #define MLIR_TOOLS_PDLL_AST_DIAGNOSTIC_H
11 
12 #include <string>
13 #include <optional>
14 
15 #include "mlir/Support/LLVM.h"
16 #include "llvm/ADT/FunctionExtras.h"
17 #include "llvm/Support/SourceMgr.h"
18 
19 namespace mlir {
20 namespace pdll {
21 namespace ast {
22 class DiagnosticEngine;
23 
24 //===----------------------------------------------------------------------===//
25 // Diagnostic
26 //===----------------------------------------------------------------------===//
27 
28 /// This class provides a simple implementation of a PDLL diagnostic.
29 class Diagnostic {
30 public:
31   using Severity = llvm::SourceMgr::DiagKind;
32 
33   /// Return the severity of this diagnostic.
getSeverity()34   Severity getSeverity() const { return severity; }
35 
36   /// Return the message of this diagnostic.
getMessage()37   StringRef getMessage() const { return message; }
38 
39   /// Return the location of this diagnostic.
getLocation()40   SMRange getLocation() const { return location; }
41 
42   /// Return the notes of this diagnostic.
getNotes()43   auto getNotes() const { return llvm::make_pointee_range(notes); }
44 
45   /// Attach a note to this diagnostic.
46   Diagnostic &attachNote(const Twine &msg,
47                          std::optional<SMRange> noteLoc = std::nullopt) {
48     assert(getSeverity() != Severity::DK_Note &&
49            "cannot attach a Note to a Note");
50     notes.emplace_back(
51         new Diagnostic(Severity::DK_Note, noteLoc.value_or(location), msg));
52     return *notes.back();
53   }
54 
55   /// Allow an inflight diagnostic to be converted to 'failure', otherwise
56   /// 'success' if this is an empty diagnostic.
LogicalResult()57   operator LogicalResult() const { return failure(); }
58 
59 private:
Diagnostic(Severity severity,SMRange loc,const Twine & msg)60   Diagnostic(Severity severity, SMRange loc, const Twine &msg)
61       : severity(severity), message(msg.str()), location(loc) {}
62 
63   // Allow access to the constructor.
64   friend DiagnosticEngine;
65 
66   /// The severity of this diagnostic.
67   Severity severity;
68   /// The message held by this diagnostic.
69   std::string message;
70   /// The raw location of this diagnostic.
71   SMRange location;
72   /// Any additional note diagnostics attached to this diagnostic.
73   std::vector<std::unique_ptr<Diagnostic>> notes;
74 };
75 
76 //===----------------------------------------------------------------------===//
77 // InFlightDiagnostic
78 //===----------------------------------------------------------------------===//
79 
80 /// This class represents a diagnostic that is inflight and set to be reported.
81 /// This allows for last minute modifications of the diagnostic before it is
82 /// emitted by a DiagnosticEngine.
83 class InFlightDiagnostic {
84 public:
85   InFlightDiagnostic() = default;
InFlightDiagnostic(InFlightDiagnostic && rhs)86   InFlightDiagnostic(InFlightDiagnostic &&rhs)
87       : owner(rhs.owner), impl(std::move(rhs.impl)) {
88     // Reset the rhs diagnostic.
89     rhs.impl.reset();
90     rhs.abandon();
91   }
~InFlightDiagnostic()92   ~InFlightDiagnostic() {
93     if (isInFlight())
94       report();
95   }
96 
97   /// Access the internal diagnostic.
98   Diagnostic &operator*() { return *impl; }
99   Diagnostic *operator->() { return &*impl; }
100 
101   /// Reports the diagnostic to the engine.
102   void report();
103 
104   /// Abandons this diagnostic so that it will no longer be reported.
abandon()105   void abandon() { owner = nullptr; }
106 
107   /// Allow an inflight diagnostic to be converted to 'failure', otherwise
108   /// 'success' if this is an empty diagnostic.
LogicalResult()109   operator LogicalResult() const { return failure(isActive()); }
110 
111 private:
112   InFlightDiagnostic &operator=(const InFlightDiagnostic &) = delete;
113   InFlightDiagnostic &operator=(InFlightDiagnostic &&) = delete;
InFlightDiagnostic(DiagnosticEngine * owner,Diagnostic && rhs)114   InFlightDiagnostic(DiagnosticEngine *owner, Diagnostic &&rhs)
115       : owner(owner), impl(std::move(rhs)) {}
116 
117   /// Returns true if the diagnostic is still active, i.e. it has a live
118   /// diagnostic.
isActive()119   bool isActive() const { return impl.has_value(); }
120 
121   /// Returns true if the diagnostic is still in flight to be reported.
isInFlight()122   bool isInFlight() const { return owner; }
123 
124   // Allow access to the constructor.
125   friend DiagnosticEngine;
126 
127   /// The engine that this diagnostic is to report to.
128   DiagnosticEngine *owner = nullptr;
129 
130   /// The raw diagnostic that is inflight to be reported.
131   std::optional<Diagnostic> impl;
132 };
133 
134 //===----------------------------------------------------------------------===//
135 // DiagnosticEngine
136 //===----------------------------------------------------------------------===//
137 
138 /// This class manages the construction and emission of PDLL diagnostics.
139 class DiagnosticEngine {
140 public:
141   /// A function used to handle diagnostics emitted by the engine.
142   using HandlerFn = llvm::unique_function<void(Diagnostic &)>;
143 
144   /// Emit an error to the diagnostic engine.
emitError(SMRange loc,const Twine & msg)145   InFlightDiagnostic emitError(SMRange loc, const Twine &msg) {
146     return InFlightDiagnostic(
147         this, Diagnostic(Diagnostic::Severity::DK_Error, loc, msg));
148   }
emitWarning(SMRange loc,const Twine & msg)149   InFlightDiagnostic emitWarning(SMRange loc, const Twine &msg) {
150     return InFlightDiagnostic(
151         this, Diagnostic(Diagnostic::Severity::DK_Warning, loc, msg));
152   }
153 
154   /// Report the given diagnostic.
report(Diagnostic && diagnostic)155   void report(Diagnostic &&diagnostic) {
156     if (handler)
157       handler(diagnostic);
158   }
159 
160   /// Get the current handler function of this diagnostic engine.
getHandlerFn()161   const HandlerFn &getHandlerFn() const { return handler; }
162 
163   /// Take the current handler function, resetting the current handler to null.
takeHandlerFn()164   HandlerFn takeHandlerFn() {
165     HandlerFn oldHandler = std::move(handler);
166     handler = {};
167     return oldHandler;
168   }
169 
170   /// Set the handler function for this diagnostic engine.
setHandlerFn(HandlerFn && newHandler)171   void setHandlerFn(HandlerFn &&newHandler) { handler = std::move(newHandler); }
172 
173 private:
174   /// The registered diagnostic handler function.
175   HandlerFn handler;
176 };
177 
178 } // namespace ast
179 } // namespace pdll
180 } // namespace mlir
181 
182 #endif // MLIR_TOOLS_PDLL_AST_DIAGNOSTIC_H
183