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