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, 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(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(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 // Actions for errors can never be overridden.
230 if (defaultAction == DiagnosticAction::Error) return defaultAction;
231 auto it = diagnosticActions.find(diagnostic);
232 if (it != diagnosticActions.end()) return it->second;
233 // if we're dealing with warnings and they have been globally modified
234 // (ignored or turned into errors), then return the global default
235 if (defaultAction == DiagnosticAction::Warn &&
236 defaultWarningDiagnosticAction != DiagnosticAction::Warn)
237 return defaultWarningDiagnosticAction;
238 return defaultAction;
239 }
240
242 void setDiagnosticAction(std::string_view diagnostic, DiagnosticAction action) {
243 diagnosticActions[cstring(diagnostic)] = action;
244 }
245
247 DiagnosticAction getDefaultWarningDiagnosticAction() { return defaultWarningDiagnosticAction; }
248
251 defaultWarningDiagnosticAction = action;
252 }
253
255 DiagnosticAction getDefaultInfoDiagnosticAction() { return defaultInfoDiagnosticAction; }
256
259 defaultInfoDiagnosticAction = action;
260 }
261
262 private:
264 DiagnosticAction defaultInfoDiagnosticAction;
265
267 DiagnosticAction defaultWarningDiagnosticAction;
268
270 std::unordered_map<cstring, DiagnosticAction> diagnosticActions;
271};
272
273} // namespace P4
274
275#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:49
void setDefaultWarningDiagnosticAction(DiagnosticAction action)
set the default diagnostic action for calls to P4::warning().
Definition error_reporter.h:250
void setDiagnosticAction(std::string_view diagnostic, DiagnosticAction action)
Set the action to take for the given diagnostic.
Definition error_reporter.h:242
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, Util::SourceInfo source)
Definition error_reporter.h:76
unsigned getDiagnosticCount() const
Definition error_reporter.h:185
DiagnosticAction getDefaultWarningDiagnosticAction()
Definition error_reporter.h:247
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:255
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
DiagnosticAction getDiagnosticAction(cstring diagnostic, DiagnosticAction defaultAction)
Definition error_reporter.h:228
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:258
void parser_error(const Util::InputSources *sources, const char *fmt, Args &&...args)
Definition error_reporter.h:209
Definition source_file.h:276
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.
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 errorCount()
Definition error.h:35
Definition error_message.h:38
Definition error_message.h:70