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
35enum class DiagnosticAction {
36 Ignore,
37 Info,
38 Warn,
39 Error
40};
41
42// Keeps track of compilation errors.
43// Errors are specified using the error() and warning() methods,
44// that use boost::format format strings, i.e.,
45// %1%, %2%, etc (starting at 1, not at 0).
46// Some compatibility for printf-style arguments is also supported.
48 protected:
49 unsigned int infoCount;
50 unsigned int warningCount;
51 unsigned int errorCount;
52 unsigned int maxErrorCount;
53
54 std::ostream *outputstream;
55
57 std::set<std::pair<int, const Util::SourceInfo>> errorTracker;
58
60 virtual void emit_message(const ErrorMessage &msg) {
61 *outputstream << msg.toString();
62 outputstream->flush();
63 }
64
65 virtual void emit_message(const ParserErrorMessage &msg) {
66 *outputstream << msg.toString();
67 outputstream->flush();
68 }
69
74 bool error_reported(int err, const Util::SourceInfo source) {
75 if (!source.isValid()) return false;
76 auto p = errorTracker.emplace(err, source);
77 return !p.second; // if insertion took place, then we have not seen the error.
78 }
79
81 cstring get_error_name(int errorCode) { return ErrorCatalog::getCatalog().getName(errorCode); }
82
83 public:
85 : infoCount(0),
86 warningCount(0),
87 errorCount(0),
88 maxErrorCount(20),
89 defaultInfoDiagnosticAction(DiagnosticAction::Info),
90 defaultWarningDiagnosticAction(DiagnosticAction::Warn) {
91 outputstream = &std::cerr;
92 }
93
94 // error message for a bug
95 template <typename... Args>
96 std::string bug_message(const char *format, Args &&...args) {
97 boost::format fmt(format);
98 // FIXME: This will implicitly take location of the first argument having
99 // SourceInfo. Not sure if this always desireable or not.
100 return ::bug_helper(fmt, "", "", std::forward<Args>(args)...);
101 }
102
103 template <typename... Args>
104 std::string format_message(const char *format, Args &&...args) {
105 boost::format fmt(format);
106 return ::error_helper(fmt, std::forward<Args>(args)...).toString();
107 }
108
109 template <class T, typename = std::enable_if_t<Util::has_SourceInfo_v<T>>, typename... Args>
110 void diagnose(DiagnosticAction action, const int errorCode, const char *format,
111 const char *suffix, const T *node, Args &&...args) {
112 if (node && !error_reported(errorCode, node->getSourceInfo())) {
113 cstring name = get_error_name(errorCode);
114 auto da = getDiagnosticAction(name, action);
115 if (name)
116 diagnose(da, name, format, suffix, node, std::forward<Args>(args)...);
117 else
118 diagnose(action, nullptr, format, suffix, node, std::forward<Args>(args)...);
119 }
120 }
121
122 template <class T, typename = std::enable_if_t<Util::has_SourceInfo_v<T>>, typename... Args>
123 void diagnose(DiagnosticAction action, const int errorCode, const char *format,
124 const char *suffix, const T &node, Args &&...args) {
125 diagnose(action, errorCode, format, suffix, &node, std::forward<Args>(args)...);
126 }
127
128 template <typename... Args>
129 void diagnose(DiagnosticAction action, const int errorCode, const char *format,
130 const char *suffix, Args &&...args) {
131 cstring name = get_error_name(errorCode);
132 auto da = getDiagnosticAction(name, action);
133 if (name)
134 diagnose(da, name, format, suffix, std::forward<Args>(args)...);
135 else
136 diagnose(action, nullptr, format, suffix, std::forward<Args>(args)...);
137 }
138
141 template <typename... Args>
142 void diagnose(DiagnosticAction action, const char *diagnosticName, const char *format,
143 const char *suffix, Args &&...args) {
144 if (action == DiagnosticAction::Ignore) return;
145
146 ErrorMessage::MessageType msgType = ErrorMessage::MessageType::None;
147 if (action == DiagnosticAction::Info) {
148 // Avoid burying errors in a pile of info messages:
149 // don't emit any more info messages if we've emitted errors.
150 if (errorCount > 0) return;
151
152 infoCount++;
153 msgType = ErrorMessage::MessageType::Info;
154 } else if (action == DiagnosticAction::Warn) {
155 // Avoid burying errors in a pile of warnings: don't emit any more warnings if we've
156 // emitted errors.
157 if (errorCount > 0) return;
158
159 warningCount++;
160 msgType = ErrorMessage::MessageType::Warning;
161 } else if (action == DiagnosticAction::Error) {
162 errorCount++;
163 msgType = ErrorMessage::MessageType::Error;
164 }
165
166 boost::format fmt(format);
167 ErrorMessage msg(msgType, diagnosticName ? diagnosticName : "", suffix);
168 msg = ::error_helper(fmt, msg, std::forward<Args>(args)...);
169 emit_message(msg);
170
171 if (errorCount > maxErrorCount)
172 FATAL_ERROR("Number of errors exceeded set maximum of %1%", maxErrorCount);
173 }
174
175 unsigned getErrorCount() const { return errorCount; }
176
177 unsigned getMaxErrorCount() const { return maxErrorCount; }
179 unsigned setMaxErrorCount(unsigned newMaxCount) {
180 auto r = maxErrorCount;
181 maxErrorCount = newMaxCount;
182 return r;
183 }
184
185 unsigned getWarningCount() const { return warningCount; }
186
187 unsigned getInfoCount() const { return infoCount; }
188
191 unsigned getDiagnosticCount() const { return errorCount + warningCount + infoCount; }
192
193 void setOutputStream(std::ostream *stream) { outputstream = stream; }
194
195 std::ostream *getOutputStream() const { return outputstream; }
196
199 template <typename T>
200 void parser_error(const Util::SourceInfo &location, const T &message) {
201 errorCount++;
202 std::stringstream ss;
203 ss << message;
204
205 emit_message(ParserErrorMessage(location, ss.str()));
206 }
207
214 template <typename... Args>
215 void parser_error(const Util::InputSources *sources, const char *fmt, Args &&...args) {
216 errorCount++;
217
218 Util::SourcePosition position = sources->getCurrentPosition();
219 position--;
220
221 // Unfortunately, we cannot go with statically checked format string
222 // here as it would require some changes to yyerror
223 std::string message;
224 if (!absl::FormatUntyped(&message, absl::UntypedFormatSpec(fmt),
225 {absl::FormatArg(args)...})) {
226 BUG("Failed to format string");
227 }
228
229 emit_message(ParserErrorMessage(Util::SourceInfo(sources, position), std::move(message)));
230 }
231
234 DiagnosticAction getDiagnosticAction(cstring diagnostic, DiagnosticAction defaultAction) {
235 // Actions for errors can never be overridden.
236 if (defaultAction == DiagnosticAction::Error) return defaultAction;
237 auto it = diagnosticActions.find(diagnostic);
238 if (it != diagnosticActions.end()) return it->second;
239 // if we're dealing with warnings and they have been globally modified
240 // (ignored or turned into errors), then return the global default
241 if (defaultAction == DiagnosticAction::Warn &&
242 defaultWarningDiagnosticAction != DiagnosticAction::Warn)
243 return defaultWarningDiagnosticAction;
244 return defaultAction;
245 }
246
248 void setDiagnosticAction(std::string_view diagnostic, DiagnosticAction action) {
249 diagnosticActions[cstring(diagnostic)] = action;
250 }
251
253 DiagnosticAction getDefaultWarningDiagnosticAction() { return defaultWarningDiagnosticAction; }
254
256 void setDefaultWarningDiagnosticAction(DiagnosticAction action) {
257 defaultWarningDiagnosticAction = action;
258 }
259
261 DiagnosticAction getDefaultInfoDiagnosticAction() { return defaultInfoDiagnosticAction; }
262
264 void setDefaultInfoDiagnosticAction(DiagnosticAction action) {
265 defaultInfoDiagnosticAction = action;
266 }
267
268 private:
270 DiagnosticAction defaultInfoDiagnosticAction;
271
273 DiagnosticAction defaultWarningDiagnosticAction;
274
276 std::unordered_map<cstring, DiagnosticAction> diagnosticActions;
277};
278
279#endif /* LIB_ERROR_REPORTER_H_ */
cstring getName(int errorCode)
retrieve the name for errorCode
Definition error_catalog.h:127
static ErrorCatalog & getCatalog()
Return the singleton object.
Definition error_catalog.h:101
Definition error_reporter.h:47
std::ostream * outputstream
the maximum number of errors that we print before fail
Definition error_reporter.h:54
void setDefaultWarningDiagnosticAction(DiagnosticAction action)
set the default diagnostic action for calls to warning().
Definition error_reporter.h:256
void setDefaultInfoDiagnosticAction(DiagnosticAction action)
set the default diagnostic action for calls to info().
Definition error_reporter.h:264
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:57
void setDiagnosticAction(std::string_view diagnostic, DiagnosticAction action)
Set the action to take for the given diagnostic.
Definition error_reporter.h:248
void diagnose(DiagnosticAction action, const char *diagnosticName, const char *format, const char *suffix, Args &&...args)
Definition error_reporter.h:142
DiagnosticAction getDiagnosticAction(cstring diagnostic, DiagnosticAction defaultAction)
Definition error_reporter.h:234
void parser_error(const Util::InputSources *sources, const char *fmt, Args &&...args)
Definition error_reporter.h:215
DiagnosticAction getDefaultInfoDiagnosticAction()
Definition error_reporter.h:261
cstring get_error_name(int errorCode)
retrieve the format from the error catalog
Definition error_reporter.h:81
bool error_reported(int err, const Util::SourceInfo source)
Definition error_reporter.h:74
virtual void emit_message(const ErrorMessage &msg)
Output the message and flush the stream.
Definition error_reporter.h:60
void parser_error(const Util::SourceInfo &location, const T &message)
Definition error_reporter.h:200
unsigned setMaxErrorCount(unsigned newMaxCount)
set maxErrorCount to a the @newMaxCount threshold and return the previous value
Definition error_reporter.h:179
DiagnosticAction getDefaultWarningDiagnosticAction()
Definition error_reporter.h:253
unsigned getDiagnosticCount() const
Definition error_reporter.h:191
Definition source_file.h:263
Definition source_file.h:123
Definition source_file.h:53
Definition cstring.h:80
Definition error_message.h:36
Definition error_message.h:68