P4C
The P4 Compiler
Loading...
Searching...
No Matches
error_reporter.h
1/*
2Copyright 2013-present Barefoot Networks, Inc.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#ifndef LIB_ERROR_REPORTER_H_
18#define LIB_ERROR_REPORTER_H_
19
20#include <iostream>
21#include <ostream>
22#include <set>
23#include <type_traits>
24#include <unordered_map>
25
26#include <boost/format.hpp>
27
28#include "absl/strings/str_format.h"
29#include "bug_helper.h"
30#include "error_catalog.h"
31#include "error_helper.h"
32#include "exceptions.h"
33
34namespace P4 {
35
37enum class DiagnosticAction {
38 Ignore,
42};
43
44// Keeps track of compilation errors.
45// Errors are specified using the error() and warning() methods,
46// that use boost::format format strings, i.e.,
47// %1%, %2%, etc (starting at 1, not at 0).
48// Some compatibility for printf-style arguments is also supported.
49class ErrorReporter {
50 protected:
51 unsigned int infoCount;
52 unsigned int warningCount;
53 unsigned int errorCount;
54 unsigned int maxErrorCount;
55
56 std::ostream *outputstream;
57
59 std::set<std::pair<int, const Util::SourceInfo>> errorTracker;
60
62 virtual void emit_message(const ErrorMessage &msg) {
63 *outputstream << msg.toString();
64 outputstream->flush();
65 }
66
67 virtual void emit_message(const ParserErrorMessage &msg) {
68 *outputstream << msg.toString();
69 outputstream->flush();
70 }
71
76 bool error_reported(int err, const Util::SourceInfo source) {
77 if (!source.isValid()) return false;
78 auto p = errorTracker.emplace(err, source);
79 return !p.second; // if insertion took place, then we have not seen the error.
80 }
81
83 cstring get_error_name(int errorCode) { return ErrorCatalog::getCatalog().getName(errorCode); }
84
85 public:
87 : infoCount(0),
88 warningCount(0),
89 errorCount(0),
90 maxErrorCount(20),
91 defaultInfoDiagnosticAction(DiagnosticAction::Info),
92 defaultWarningDiagnosticAction(DiagnosticAction::Warn) {
93 outputstream = &std::cerr;
94 ErrorCatalog::getCatalog().initReporter(*this);
95 }
96 virtual ~ErrorReporter() = default;
97
98 // error message for a bug
99 template <typename... Args>
100 std::string bug_message(const char *format, Args &&...args) {
101 boost::format fmt(format);
102 // FIXME: This will implicitly take location of the first argument having
103 // SourceInfo. Not sure if this always desireable or not.
104 return ::P4::bug_helper(fmt, "", "", std::forward<Args>(args)...);
105 }
106
107 template <typename... Args>
108 std::string format_message(const char *format, Args &&...args) {
109 boost::format fmt(format);
110 return ::P4::error_helper(fmt, std::forward<Args>(args)...).toString();
111 }
112
113 template <class T, typename = decltype(std::declval<T>()->getSourceInfo()), typename... Args>
114 void diagnose(DiagnosticAction action, const int errorCode, const char *format,
115 const char *suffix, T node, Args &&...args) {
116 if (!node || error_reported(errorCode, node->getSourceInfo())) return;
117
118 if (cstring name = get_error_name(errorCode))
119 diagnose(getDiagnosticAction(errorCode, name, action), name.c_str(), format, suffix,
120 node, std::forward<Args>(args)...);
121 else
122 diagnose(action, nullptr, format, suffix, node, std::forward<Args>(args)...);
123 }
124
125 template <typename... Args>
126 void diagnose(DiagnosticAction action, const int errorCode, const char *format,
127 const char *suffix, Args &&...args) {
128 if (cstring name = get_error_name(errorCode))
129 diagnose(getDiagnosticAction(errorCode, name, action), name.c_str(), format, suffix,
130 std::forward<Args>(args)...);
131 else
132 diagnose(action, nullptr, format, suffix, std::forward<Args>(args)...);
133 }
134
137 template <typename... Args>
138 void diagnose(DiagnosticAction action, const char *diagnosticName, const char *format,
139 const char *suffix, Args &&...args) {
140 if (action == DiagnosticAction::Ignore) return;
141
142 ErrorMessage::MessageType msgType = ErrorMessage::MessageType::None;
143 if (action == DiagnosticAction::Info) {
144 // Avoid burying errors in a pile of info messages:
145 // don't emit any more info messages if we've emitted errors.
146 if (errorCount > 0) return;
147
148 infoCount++;
149 msgType = ErrorMessage::MessageType::Info;
150 } else if (action == DiagnosticAction::Warn) {
151 // Avoid burying errors in a pile of warnings: don't emit any more warnings if we've
152 // emitted errors.
153 if (errorCount > 0) return;
154
155 warningCount++;
156 msgType = ErrorMessage::MessageType::Warning;
157 } else if (action == DiagnosticAction::Error) {
158 errorCount++;
159 msgType = ErrorMessage::MessageType::Error;
160 }
161
162 boost::format fmt(format);
163 ErrorMessage msg(msgType, diagnosticName ? diagnosticName : "", suffix);
164 msg = ::P4::error_helper(fmt, msg, std::forward<Args>(args)...);
165 emit_message(msg);
166
167 if (errorCount > maxErrorCount)
168 FATAL_ERROR("Number of errors exceeded set maximum of %1%", maxErrorCount);
169 }
170
171 unsigned getErrorCount() const { return errorCount; }
172
173 unsigned getMaxErrorCount() const { return maxErrorCount; }
175 unsigned setMaxErrorCount(unsigned newMaxCount) {
176 auto r = maxErrorCount;
177 maxErrorCount = newMaxCount;
178 return r;
179 }
180
181 unsigned getWarningCount() const { return warningCount; }
182
183 unsigned getInfoCount() const { return infoCount; }
184
187 unsigned getDiagnosticCount() const { return errorCount + warningCount + infoCount; }
188
189 void setOutputStream(std::ostream *stream) { outputstream = stream; }
190
191 std::ostream *getOutputStream() const { return outputstream; }
192
195 template <typename T>
196 void parser_error(const Util::SourceInfo &location, const T &message) {
197 errorCount++;
198 std::stringstream ss;
199 ss << message;
200
201 emit_message(ParserErrorMessage(location, ss.str()));
202 }
203
210 template <typename... Args>
211 void parser_error(const Util::InputSources *sources, const char *fmt, Args &&...args) {
212 errorCount++;
213
214 Util::SourcePosition position = sources->getCurrentPosition();
215 position--;
216
217 // Unfortunately, we cannot go with statically checked format string
218 // here as it would require some changes to yyerror
219 std::string message;
220 if (!absl::FormatUntyped(&message, absl::UntypedFormatSpec(fmt),
221 {absl::FormatArg(args)...})) {
222 BUG("Failed to format string %s", fmt);
223 }
224
225 emit_message(ParserErrorMessage(Util::SourceInfo(sources, position), std::move(message)));
226 }
227
231 DiagnosticAction defaultAction) {
232 // Actions for errors can never be overridden.
233 if (ErrorCatalog::getCatalog().isError(errorCode)) return DiagnosticAction::Error;
234 auto it = diagnosticActions.find(diagnostic);
235 if (it != diagnosticActions.end()) return it->second;
236 // if we're dealing with warnings and they have been globally modified
237 // (ignored or turned into errors), then return the global default
238 if (defaultAction == DiagnosticAction::Warn &&
239 defaultWarningDiagnosticAction != DiagnosticAction::Warn)
240 return defaultWarningDiagnosticAction;
241 return defaultAction;
242 }
243
245 void setDiagnosticAction(std::string_view diagnostic, DiagnosticAction action) {
246 diagnosticActions[cstring(diagnostic)] = action;
247 }
248
250 DiagnosticAction getDefaultWarningDiagnosticAction() { return defaultWarningDiagnosticAction; }
251
254 defaultWarningDiagnosticAction = action;
255 }
256
258 DiagnosticAction getDefaultInfoDiagnosticAction() { return defaultInfoDiagnosticAction; }
259
262 defaultInfoDiagnosticAction = action;
263 }
264
265 private:
267 DiagnosticAction defaultInfoDiagnosticAction;
268
270 DiagnosticAction defaultWarningDiagnosticAction;
271
273 std::unordered_map<cstring, DiagnosticAction> diagnosticActions;
274};
275
276} // namespace P4
277
278#endif /* LIB_ERROR_REPORTER_H_ */
static ErrorCatalog & getCatalog()
Return the singleton object.
Definition error_catalog.h:111
cstring getName(int errorCode)
retrieve the name for errorCode
Definition error_catalog.h:137
Definition error_reporter.h:49
void setDefaultWarningDiagnosticAction(DiagnosticAction action)
set the default diagnostic action for calls to P4::warning().
Definition error_reporter.h:253
void setDiagnosticAction(std::string_view diagnostic, DiagnosticAction action)
Set the action to take for the given diagnostic.
Definition error_reporter.h:245
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:59
bool error_reported(int err, const Util::SourceInfo source)
Definition error_reporter.h:76
unsigned getDiagnosticCount() const
Definition error_reporter.h:187
DiagnosticAction getDefaultWarningDiagnosticAction()
Definition error_reporter.h:250
void diagnose(DiagnosticAction action, const char *diagnosticName, const char *format, const char *suffix, Args &&...args)
Definition error_reporter.h:138
DiagnosticAction getDefaultInfoDiagnosticAction()
Definition error_reporter.h:258
unsigned setMaxErrorCount(unsigned newMaxCount)
set maxErrorCount to a the @newMaxCount threshold and return the previous value
Definition error_reporter.h:175
cstring get_error_name(int errorCode)
retrieve the format from the error catalog
Definition error_reporter.h:83
virtual void emit_message(const ErrorMessage &msg)
Output the message and flush the stream.
Definition error_reporter.h:62
std::ostream * outputstream
the maximum number of errors that we print before fail
Definition error_reporter.h:56
void parser_error(const Util::SourceInfo &location, const T &message)
Definition error_reporter.h:196
void setDefaultInfoDiagnosticAction(DiagnosticAction action)
set the default diagnostic action for calls to P4::info().
Definition error_reporter.h:261
DiagnosticAction getDiagnosticAction(int errorCode, cstring diagnostic, DiagnosticAction defaultAction)
Definition error_reporter.h:230
void parser_error(const Util::InputSources *sources, const char *fmt, Args &&...args)
Definition error_reporter.h:211
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:24
unsigned infoCount()
Definition lib/error.h:42
DiagnosticAction
An action to take when a diagnostic message is triggered.
Definition error_reporter.h:37
@ Info
Take no action and continue compilation.
Definition error_reporter.h:39
@ Warn
Print an info message and continue compilation.
Definition error_reporter.h:40
@ Error
Print a warning and continue compilation.
Definition error_reporter.h:41
unsigned warningCount()
Definition lib/error.h:37
unsigned errorCount()
Definition lib/error.h:34
Definition error_message.h:38
Definition error_message.h:70