P4C
The P4 Compiler
Loading...
Searching...
No Matches
error_reporter.h
1/*
2 * SPDX-FileCopyrightText: 2013 Barefoot Networks, Inc.
3 * Copyright 2013-present Barefoot Networks, Inc.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8#ifndef LIB_ERROR_REPORTER_H_
9#define LIB_ERROR_REPORTER_H_
10
11#include <iostream>
12#include <ostream>
13#include <set>
14#include <type_traits>
15#include <unordered_map>
16#include <utility>
17
18#include "absl/strings/str_cat.h"
19#include "absl/strings/str_format.h"
20#include "error_catalog.h"
21#include "error_helper.h"
22#include "exceptions.h"
23#include "lib/format.h"
24#include "lib/source_file.h"
25
26namespace P4 {
27
29enum class DiagnosticAction {
30 Ignore,
34};
35
36// Keeps track of compilation errors.
37// Errors are specified using the error() and warning() methods.
38// Supported formatting styles are boost-style (%1%, %2%, ...) and
39// printf/absl::StrFormat-style (%s, %d, ...).
40class ErrorReporter {
41 protected:
42 unsigned int infoCount;
43 unsigned int warningCount;
44 unsigned int errorCount;
45 unsigned int maxErrorCount;
46
47 std::ostream *outputstream;
48
50 std::set<std::pair<int, const Util::SourceInfo>> errorTracker;
51
53 virtual void emit_message(const ErrorMessage &msg) {
54 *outputstream << msg.toString();
55 outputstream->flush();
56 }
57
58 virtual void emit_message(const ParserErrorMessage &msg) {
59 *outputstream << msg.toString();
60 outputstream->flush();
61 }
62
67 bool error_reported(int err, const Util::SourceInfo source) {
68 if (!source.isValid()) return false;
69 auto p = errorTracker.emplace(err, source);
70 return !p.second; // if insertion took place, then we have not seen the error.
71 }
72
74 cstring get_error_name(int errorCode) { return ErrorCatalog::getCatalog().getName(errorCode); }
75
76 public:
78 : infoCount(0),
79 warningCount(0),
80 errorCount(0),
81 maxErrorCount(20),
82 outputstream(&std::cerr),
83 defaultInfoDiagnosticAction(DiagnosticAction::Info),
84 defaultWarningDiagnosticAction(DiagnosticAction::Warn) {
85 ErrorCatalog::getCatalog().initReporter(*this);
86 }
87 virtual ~ErrorReporter() = default;
88
89 // Error message for a bug.
90 template <typename... Args>
91 std::string bug_message(const char *format, Args &&...args) {
92 return createBugMessage(format, args...);
93 }
94
95 // Formats a message with a trailing newline and any source locations and excerpts.
96 template <typename... Args>
97 std::string format_message(const char *format, Args &&...args) {
98 return ::P4::error_helper(format, std::forward<Args>(args)...).toString();
99 }
100
101 template <class T, typename = decltype(std::declval<T>()->getSourceInfo()), typename... Args>
102 void diagnose(DiagnosticAction action, const int errorCode, const char *format,
103 const char *suffix, T node, Args &&...args) {
104 if (!node || error_reported(errorCode, node->getSourceInfo())) return;
105
106 if (cstring name = get_error_name(errorCode))
107 diagnose(getDiagnosticAction(errorCode, name, action), name.c_str(), format, suffix,
108 node, std::forward<Args>(args)...);
109 else
110 diagnose(action, nullptr, format, suffix, node, std::forward<Args>(args)...);
111 }
112
113 template <typename... Args>
114 void diagnose(DiagnosticAction action, const int errorCode, const char *format,
115 const char *suffix, Args &&...args) {
116 if (cstring name = get_error_name(errorCode))
117 diagnose(getDiagnosticAction(errorCode, name, action), name.c_str(), format, suffix,
118 std::forward<Args>(args)...);
119 else
120 diagnose(action, nullptr, format, suffix, std::forward<Args>(args)...);
121 }
122
125 template <typename... Args>
126 void diagnose(DiagnosticAction action, const char *diagnosticName, const char *format,
127 const char *suffix, Args &&...args) {
128 if (action == DiagnosticAction::Ignore) return;
129
130 ErrorMessage::MessageType msgType = ErrorMessage::MessageType::None;
131 if (action == DiagnosticAction::Info) {
132 // Avoid burying errors in a pile of info messages:
133 // don't emit any more info messages if we've emitted errors.
134 if (errorCount > 0) return;
135
136 infoCount++;
137 msgType = ErrorMessage::MessageType::Info;
138 } else if (action == DiagnosticAction::Warn) {
139 // Avoid burying errors in a pile of warnings: don't emit any more warnings if we've
140 // emitted errors.
141 if (errorCount > 0) return;
142
143 warningCount++;
144 msgType = ErrorMessage::MessageType::Warning;
145 } else if (action == DiagnosticAction::Error) {
146 errorCount++;
147 msgType = ErrorMessage::MessageType::Error;
148 }
149
150 ErrorMessage msg(msgType, diagnosticName ? diagnosticName : "", suffix);
151 msg = ::P4::error_helper(format, std::move(msg), std::forward<Args>(args)...);
152 emit_message(msg);
153
154 if (errorCount >= maxErrorCount)
155 FATAL_ERROR("Number of errors exceeded set maximum of %1%", maxErrorCount);
156 }
157
158 unsigned getErrorCount() const { return errorCount; }
159
160 unsigned getMaxErrorCount() const { return maxErrorCount; }
162 unsigned setMaxErrorCount(unsigned newMaxCount) {
163 auto r = maxErrorCount;
164 maxErrorCount = newMaxCount;
165 return r;
166 }
167
168 unsigned getWarningCount() const { return warningCount; }
169
170 unsigned getInfoCount() const { return infoCount; }
171
174 unsigned getDiagnosticCount() const { return errorCount + warningCount + infoCount; }
175
176 void setOutputStream(std::ostream *stream) { outputstream = stream; }
177
178 std::ostream *getOutputStream() const { return outputstream; }
179
182 template <typename T>
183 void parser_error(const Util::SourceInfo &location, const T &message) {
184 errorCount++;
185 std::stringstream ss;
186 ss << message;
187
188 emit_message(ParserErrorMessage(location, ss.str()));
189 }
190
197 template <typename... Args>
198 void parser_error(const Util::InputSources *sources, const char *fmt, Args &&...args) {
199 errorCount++;
200
201 Util::SourcePosition position = sources->getCurrentPosition();
202 position--;
203
204 // Unfortunately, we cannot go with statically checked format string
205 // here as it would require some changes to yyerror
206 std::string message;
207 if (!absl::FormatUntyped(&message, absl::UntypedFormatSpec(fmt),
208 {absl::FormatArg(args)...})) {
209 BUG("Failed to format string %s", fmt);
210 }
211
212 emit_message(ParserErrorMessage(Util::SourceInfo(sources, position), std::move(message)));
213 }
214
218 DiagnosticAction defaultAction) {
219 // Actions for errors can never be overridden.
220 if (ErrorCatalog::getCatalog().isError(errorCode)) return DiagnosticAction::Error;
221 auto it = diagnosticActions.find(diagnostic);
222 if (it != diagnosticActions.end()) return it->second;
223 // if we're dealing with warnings and they have been globally modified
224 // (ignored or turned into errors), then return the global default
225 if (defaultAction == DiagnosticAction::Warn &&
226 defaultWarningDiagnosticAction != DiagnosticAction::Warn)
227 return defaultWarningDiagnosticAction;
228 return defaultAction;
229 }
230
232 void setDiagnosticAction(std::string_view diagnostic, DiagnosticAction action) {
233 diagnosticActions[cstring(diagnostic)] = action;
234 }
235
237 DiagnosticAction getDefaultWarningDiagnosticAction() { return defaultWarningDiagnosticAction; }
238
241 defaultWarningDiagnosticAction = action;
242 }
243
245 DiagnosticAction getDefaultInfoDiagnosticAction() { return defaultInfoDiagnosticAction; }
246
249 defaultInfoDiagnosticAction = action;
250 }
251
252 private:
254 DiagnosticAction defaultInfoDiagnosticAction;
255
257 DiagnosticAction defaultWarningDiagnosticAction;
258
260 std::unordered_map<cstring, DiagnosticAction> diagnosticActions;
261};
262
263} // namespace P4
264
265#endif /* LIB_ERROR_REPORTER_H_ */
static ErrorCatalog & getCatalog()
Return the singleton object.
Definition error_catalog.h:103
cstring getName(int errorCode)
retrieve the name for errorCode
Definition error_catalog.h:129
Definition error_reporter.h:40
void setDefaultWarningDiagnosticAction(DiagnosticAction action)
set the default diagnostic action for calls to P4::warning().
Definition error_reporter.h:240
void setDiagnosticAction(std::string_view diagnostic, DiagnosticAction action)
Set the action to take for the given diagnostic.
Definition error_reporter.h:232
std::set< std::pair< int, const Util::SourceInfo > > errorTracker
Track errors or warnings that have already been issued for a particular source location.
Definition error_reporter.h:50
bool error_reported(int err, const Util::SourceInfo source)
Definition error_reporter.h:67
unsigned getDiagnosticCount() const
Definition error_reporter.h:174
DiagnosticAction getDefaultWarningDiagnosticAction()
Definition error_reporter.h:237
void diagnose(DiagnosticAction action, const char *diagnosticName, const char *format, const char *suffix, Args &&...args)
Definition error_reporter.h:126
DiagnosticAction getDefaultInfoDiagnosticAction()
Definition error_reporter.h:245
unsigned setMaxErrorCount(unsigned newMaxCount)
set maxErrorCount to a the @newMaxCount threshold and return the previous value
Definition error_reporter.h:162
cstring get_error_name(int errorCode)
retrieve the format from the error catalog
Definition error_reporter.h:74
virtual void emit_message(const ErrorMessage &msg)
Output the message and flush the stream.
Definition error_reporter.h:53
std::ostream * outputstream
the maximum number of errors that we print before fail
Definition error_reporter.h:47
void parser_error(const Util::SourceInfo &location, const T &message)
Definition error_reporter.h:183
void setDefaultInfoDiagnosticAction(DiagnosticAction action)
set the default diagnostic action for calls to P4::info().
Definition error_reporter.h:248
DiagnosticAction getDiagnosticAction(int errorCode, cstring diagnostic, DiagnosticAction defaultAction)
Definition error_reporter.h:217
void parser_error(const Util::InputSources *sources, const char *fmt, Args &&...args)
Definition error_reporter.h:198
Definition source_file.h:280
Definition source_file.h:123
Definition source_file.h:47
Definition cstring.h:76
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13
unsigned infoCount()
Definition lib/error.h:33
DiagnosticAction
An action to take when a diagnostic message is triggered.
Definition error_reporter.h:29
@ Info
Take no action and continue compilation.
Definition error_reporter.h:31
@ Warn
Print an info message and continue compilation.
Definition error_reporter.h:32
@ Error
Print a warning and continue compilation.
Definition error_reporter.h:33
unsigned warningCount()
Definition lib/error.h:28
unsigned errorCount()
Definition lib/error.h:25
STL namespace.
Definition error_message.h:29
Definition error_message.h:61