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 }
95 virtual ~ErrorReporter() = default;
96
97 // error message for a bug
98 template <typename... Args>
99 std::string bug_message(const char *format, Args &&...args) {
100 boost::format fmt(format);
101 // FIXME: This will implicitly take location of the first argument having
102 // SourceInfo. Not sure if this always desireable or not.
103 return ::P4::bug_helper(fmt, "", "", std::forward<Args>(args)...);
104 }
105
106 template <typename... Args>
107 std::string format_message(const char *format, Args &&...args) {
108 boost::format fmt(format);
109 return ::P4::error_helper(fmt, std::forward<Args>(args)...).toString();
110 }
111
112 template <class T, typename = decltype(std::declval<T>()->getSourceInfo()), typename... Args>
113 void diagnose(DiagnosticAction action, const int errorCode, const char *format,
114 const char *suffix, T node, Args &&...args) {
115 if (!node || error_reported(errorCode, node->getSourceInfo())) return;
116
117 if (cstring name = get_error_name(errorCode))
118 diagnose(getDiagnosticAction(errorCode, name, action), name.c_str(), format, suffix,
119 node, std::forward<Args>(args)...);
120 else
121 diagnose(action, nullptr, format, suffix, node, std::forward<Args>(args)...);
122 }
123
124 template <typename... Args>
125 void diagnose(DiagnosticAction action, const int errorCode, const char *format,
126 const char *suffix, Args &&...args) {
127 if (cstring name = get_error_name(errorCode))
128 diagnose(getDiagnosticAction(errorCode, name, action), name.c_str(), format, suffix,
129 std::forward<Args>(args)...);
130 else
131 diagnose(action, nullptr, format, suffix, std::forward<Args>(args)...);
132 }
133
136 template <typename... Args>
137 void diagnose(DiagnosticAction action, const char *diagnosticName, const char *format,
138 const char *suffix, Args &&...args) {
139 if (action == DiagnosticAction::Ignore) return;
140
141 ErrorMessage::MessageType msgType = ErrorMessage::MessageType::None;
142 if (action == DiagnosticAction::Info) {
143 // Avoid burying errors in a pile of info messages:
144 // don't emit any more info messages if we've emitted errors.
145 if (errorCount > 0) return;
146
147 infoCount++;
148 msgType = ErrorMessage::MessageType::Info;
149 } else if (action == DiagnosticAction::Warn) {
150 // Avoid burying errors in a pile of warnings: don't emit any more warnings if we've
151 // emitted errors.
152 if (errorCount > 0) return;
153
154 warningCount++;
155 msgType = ErrorMessage::MessageType::Warning;
156 } else if (action == DiagnosticAction::Error) {
157 errorCount++;
158 msgType = ErrorMessage::MessageType::Error;
159 }
160
161 boost::format fmt(format);
162 ErrorMessage msg(msgType, diagnosticName ? diagnosticName : "", suffix);
163 msg = ::P4::error_helper(fmt, msg, std::forward<Args>(args)...);
164 emit_message(msg);
165
166 if (errorCount > maxErrorCount)
167 FATAL_ERROR("Number of errors exceeded set maximum of %1%", maxErrorCount);
168 }
169
170 unsigned getErrorCount() const { return errorCount; }
171
172 unsigned getMaxErrorCount() const { return maxErrorCount; }
174 unsigned setMaxErrorCount(unsigned newMaxCount) {
175 auto r = maxErrorCount;
176 maxErrorCount = newMaxCount;
177 return r;
178 }
179
180 unsigned getWarningCount() const { return warningCount; }
181
182 unsigned getInfoCount() const { return infoCount; }
183
186 unsigned getDiagnosticCount() const { return errorCount + warningCount + infoCount; }
187
188 void setOutputStream(std::ostream *stream) { outputstream = stream; }
189
190 std::ostream *getOutputStream() const { return outputstream; }
191
194 template <typename T>
195 void parser_error(const Util::SourceInfo &location, const T &message) {
196 errorCount++;
197 std::stringstream ss;
198 ss << message;
199
200 emit_message(ParserErrorMessage(location, ss.str()));
201 }
202
209 template <typename... Args>
210 void parser_error(const Util::InputSources *sources, const char *fmt, Args &&...args) {
211 errorCount++;
212
213 Util::SourcePosition position = sources->getCurrentPosition();
214 position--;
215
216 // Unfortunately, we cannot go with statically checked format string
217 // here as it would require some changes to yyerror
218 std::string message;
219 if (!absl::FormatUntyped(&message, absl::UntypedFormatSpec(fmt),
220 {absl::FormatArg(args)...})) {
221 BUG("Failed to format string %s", fmt);
222 }
223
224 emit_message(ParserErrorMessage(Util::SourceInfo(sources, position), std::move(message)));
225 }
226
230 DiagnosticAction defaultAction) {
231 // Actions for errors can never be overridden.
232 if (ErrorCatalog::getCatalog().isError(errorCode)) return DiagnosticAction::Error;
233 auto it = diagnosticActions.find(diagnostic);
234 if (it != diagnosticActions.end()) return it->second;
235 // if we're dealing with warnings and they have been globally modified
236 // (ignored or turned into errors), then return the global default
237 if (defaultAction == DiagnosticAction::Warn &&
238 defaultWarningDiagnosticAction != DiagnosticAction::Warn)
239 return defaultWarningDiagnosticAction;
240 return defaultAction;
241 }
242
244 void setDiagnosticAction(std::string_view diagnostic, DiagnosticAction action) {
245 diagnosticActions[cstring(diagnostic)] = action;
246 }
247
249 DiagnosticAction getDefaultWarningDiagnosticAction() { return defaultWarningDiagnosticAction; }
250
253 defaultWarningDiagnosticAction = action;
254 }
255
257 DiagnosticAction getDefaultInfoDiagnosticAction() { return defaultInfoDiagnosticAction; }
258
261 defaultInfoDiagnosticAction = action;
262 }
263
264 private:
266 DiagnosticAction defaultInfoDiagnosticAction;
267
269 DiagnosticAction defaultWarningDiagnosticAction;
270
272 std::unordered_map<cstring, DiagnosticAction> diagnosticActions;
273};
274
275} // namespace P4
276
277#endif /* LIB_ERROR_REPORTER_H_ */
static ErrorCatalog & getCatalog()
Return the singleton object.
Definition error_catalog.h:105
cstring getName(int errorCode)
retrieve the name for errorCode
Definition error_catalog.h:131
Definition error_reporter.h:49
void setDefaultWarningDiagnosticAction(DiagnosticAction action)
set the default diagnostic action for calls to P4::warning().
Definition error_reporter.h:252
void setDiagnosticAction(std::string_view diagnostic, DiagnosticAction action)
Set the action to take for the given diagnostic.
Definition error_reporter.h:244
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:186
DiagnosticAction getDefaultWarningDiagnosticAction()
Definition error_reporter.h:249
void diagnose(DiagnosticAction action, const char *diagnosticName, const char *format, const char *suffix, Args &&...args)
Definition error_reporter.h:137
DiagnosticAction getDefaultInfoDiagnosticAction()
Definition error_reporter.h:257
unsigned setMaxErrorCount(unsigned newMaxCount)
set maxErrorCount to a the @newMaxCount threshold and return the previous value
Definition error_reporter.h:174
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:195
void setDefaultInfoDiagnosticAction(DiagnosticAction action)
set the default diagnostic action for calls to P4::info().
Definition error_reporter.h:260
DiagnosticAction getDiagnosticAction(int errorCode, cstring diagnostic, DiagnosticAction defaultAction)
Definition error_reporter.h:229
void parser_error(const Util::InputSources *sources, const char *fmt, Args &&...args)
Definition error_reporter.h:210
Definition source_file.h:294
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