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
17#include <boost/format.hpp>
18
19#include "absl/strings/str_format.h"
20#include "bug_helper.h"
21#include "error_catalog.h"
22#include "error_helper.h"
23#include "exceptions.h"
24
25namespace P4 {
26
28enum class DiagnosticAction {
29 Ignore,
33};
34
35// Keeps track of compilation errors.
36// Errors are specified using the error() and warning() methods,
37// that use boost::format format strings, i.e.,
38// %1%, %2%, etc (starting at 1, not at 0).
39// Some compatibility for printf-style arguments is also supported.
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 defaultInfoDiagnosticAction(DiagnosticAction::Info),
83 defaultWarningDiagnosticAction(DiagnosticAction::Warn) {
84 outputstream = &std::cerr;
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 boost::format fmt(format);
93 // FIXME: This will implicitly take location of the first argument having
94 // SourceInfo. Not sure if this always desireable or not.
95 return ::P4::bug_helper(fmt, "", "", std::forward<Args>(args)...);
96 }
97
98 template <typename... Args>
99 std::string format_message(const char *format, Args &&...args) {
100 boost::format fmt(format);
101 return ::P4::error_helper(fmt, std::forward<Args>(args)...).toString();
102 }
103
104 template <class T, typename = decltype(std::declval<T>()->getSourceInfo()), typename... Args>
105 void diagnose(DiagnosticAction action, const int errorCode, const char *format,
106 const char *suffix, T node, Args &&...args) {
107 if (!node || error_reported(errorCode, node->getSourceInfo())) return;
108
109 if (cstring name = get_error_name(errorCode))
110 diagnose(getDiagnosticAction(errorCode, name, action), name.c_str(), format, suffix,
111 node, std::forward<Args>(args)...);
112 else
113 diagnose(action, nullptr, format, suffix, node, std::forward<Args>(args)...);
114 }
115
116 template <typename... Args>
117 void diagnose(DiagnosticAction action, const int errorCode, const char *format,
118 const char *suffix, Args &&...args) {
119 if (cstring name = get_error_name(errorCode))
120 diagnose(getDiagnosticAction(errorCode, name, action), name.c_str(), format, suffix,
121 std::forward<Args>(args)...);
122 else
123 diagnose(action, nullptr, format, suffix, std::forward<Args>(args)...);
124 }
125
128 template <typename... Args>
129 void diagnose(DiagnosticAction action, const char *diagnosticName, const char *format,
130 const char *suffix, Args &&...args) {
131 if (action == DiagnosticAction::Ignore) return;
132
133 ErrorMessage::MessageType msgType = ErrorMessage::MessageType::None;
134 if (action == DiagnosticAction::Info) {
135 // Avoid burying errors in a pile of info messages:
136 // don't emit any more info messages if we've emitted errors.
137 if (errorCount > 0) return;
138
139 infoCount++;
140 msgType = ErrorMessage::MessageType::Info;
141 } else if (action == DiagnosticAction::Warn) {
142 // Avoid burying errors in a pile of warnings: don't emit any more warnings if we've
143 // emitted errors.
144 if (errorCount > 0) return;
145
146 warningCount++;
147 msgType = ErrorMessage::MessageType::Warning;
148 } else if (action == DiagnosticAction::Error) {
149 errorCount++;
150 msgType = ErrorMessage::MessageType::Error;
151 }
152
153 boost::format fmt(format);
154 ErrorMessage msg(msgType, diagnosticName ? diagnosticName : "", suffix);
155 msg = ::P4::error_helper(fmt, msg, std::forward<Args>(args)...);
156 emit_message(msg);
157
158 if (errorCount > maxErrorCount)
159 FATAL_ERROR("Number of errors exceeded set maximum of %1%", maxErrorCount);
160 }
161
162 unsigned getErrorCount() const { return errorCount; }
163
164 unsigned getMaxErrorCount() const { return maxErrorCount; }
166 unsigned setMaxErrorCount(unsigned newMaxCount) {
167 auto r = maxErrorCount;
168 maxErrorCount = newMaxCount;
169 return r;
170 }
171
172 unsigned getWarningCount() const { return warningCount; }
173
174 unsigned getInfoCount() const { return infoCount; }
175
178 unsigned getDiagnosticCount() const { return errorCount + warningCount + infoCount; }
179
180 void setOutputStream(std::ostream *stream) { outputstream = stream; }
181
182 std::ostream *getOutputStream() const { return outputstream; }
183
186 template <typename T>
187 void parser_error(const Util::SourceInfo &location, const T &message) {
188 errorCount++;
189 std::stringstream ss;
190 ss << message;
191
192 emit_message(ParserErrorMessage(location, ss.str()));
193 }
194
201 template <typename... Args>
202 void parser_error(const Util::InputSources *sources, const char *fmt, Args &&...args) {
203 errorCount++;
204
205 Util::SourcePosition position = sources->getCurrentPosition();
206 position--;
207
208 // Unfortunately, we cannot go with statically checked format string
209 // here as it would require some changes to yyerror
210 std::string message;
211 if (!absl::FormatUntyped(&message, absl::UntypedFormatSpec(fmt),
212 {absl::FormatArg(args)...})) {
213 BUG("Failed to format string %s", fmt);
214 }
215
216 emit_message(ParserErrorMessage(Util::SourceInfo(sources, position), std::move(message)));
217 }
218
222 DiagnosticAction defaultAction) {
223 // Actions for errors can never be overridden.
224 if (ErrorCatalog::getCatalog().isError(errorCode)) return DiagnosticAction::Error;
225 auto it = diagnosticActions.find(diagnostic);
226 if (it != diagnosticActions.end()) return it->second;
227 // if we're dealing with warnings and they have been globally modified
228 // (ignored or turned into errors), then return the global default
229 if (defaultAction == DiagnosticAction::Warn &&
230 defaultWarningDiagnosticAction != DiagnosticAction::Warn)
231 return defaultWarningDiagnosticAction;
232 return defaultAction;
233 }
234
236 void setDiagnosticAction(std::string_view diagnostic, DiagnosticAction action) {
237 diagnosticActions[cstring(diagnostic)] = action;
238 }
239
241 DiagnosticAction getDefaultWarningDiagnosticAction() { return defaultWarningDiagnosticAction; }
242
245 defaultWarningDiagnosticAction = action;
246 }
247
249 DiagnosticAction getDefaultInfoDiagnosticAction() { return defaultInfoDiagnosticAction; }
250
253 defaultInfoDiagnosticAction = action;
254 }
255
256 private:
258 DiagnosticAction defaultInfoDiagnosticAction;
259
261 DiagnosticAction defaultWarningDiagnosticAction;
262
264 std::unordered_map<cstring, DiagnosticAction> diagnosticActions;
265};
266
267} // namespace P4
268
269#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:244
void setDiagnosticAction(std::string_view diagnostic, DiagnosticAction action)
Set the action to take for the given diagnostic.
Definition error_reporter.h:236
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:178
DiagnosticAction getDefaultWarningDiagnosticAction()
Definition error_reporter.h:241
void diagnose(DiagnosticAction action, const char *diagnosticName, const char *format, const char *suffix, Args &&...args)
Definition error_reporter.h:129
DiagnosticAction getDefaultInfoDiagnosticAction()
Definition error_reporter.h:249
unsigned setMaxErrorCount(unsigned newMaxCount)
set maxErrorCount to a the @newMaxCount threshold and return the previous value
Definition error_reporter.h:166
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:187
void setDefaultInfoDiagnosticAction(DiagnosticAction action)
set the default diagnostic action for calls to P4::info().
Definition error_reporter.h:252
DiagnosticAction getDiagnosticAction(int errorCode, cstring diagnostic, DiagnosticAction defaultAction)
Definition error_reporter.h:221
void parser_error(const Util::InputSources *sources, const char *fmt, Args &&...args)
Definition error_reporter.h:202
Definition source_file.h:289
Definition source_file.h:132
Definition source_file.h:56
Definition cstring.h:85
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13
unsigned infoCount()
Definition lib/error.h:42
DiagnosticAction
An action to take when a diagnostic message is triggered.
Definition error_reporter.h:28
@ Info
Take no action and continue compilation.
Definition error_reporter.h:30
@ Warn
Print an info message and continue compilation.
Definition error_reporter.h:31
@ Error
Print a warning and continue compilation.
Definition error_reporter.h:32
unsigned warningCount()
Definition lib/error.h:37
unsigned errorCount()
Definition lib/error.h:34
Definition error_message.h:29
Definition error_message.h:61