diff options
| -rw-r--r-- | include/cps/Diagnostics.h | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/include/cps/Diagnostics.h b/include/cps/Diagnostics.h index 4bcb877..9c9ea37 100644 --- a/include/cps/Diagnostics.h +++ b/include/cps/Diagnostics.h @@ -1,6 +1,7 @@ #pragma once #include <cstdarg> #include <cstdio> +#include <set> #include <string> namespace cps { @@ -30,14 +31,24 @@ inline std::string diagnosticPrefix(Severity S, const std::string &Locus = "cpsc return (Locus.empty() ? "" : Span("01", Locus + ":") + " ") + Span(Color, Label); } +// Every diagnostic line printed so far, to suppress exact repeats. +inline std::set<std::string> PrintedDiagnostics; + // Prints "<path>:<line>: <label>: <message>\n" (just "<path>:" when the line is // unknown, "cpsc:" when no source is set). inline void vsourceDiagnostic(Severity S, int Line, const char *Format, va_list Args) { std::string Locus = DiagnosticSource.empty() ? "cpsc" : DiagnosticSource; if (!DiagnosticSource.empty() && Line > 0) Locus += ":" + std::to_string(Line); - std::fputs(diagnosticPrefix(S, Locus).c_str(), stderr); - std::vfprintf(stderr, Format, Args); - std::fputc('\n', stderr); + va_list Copy; + va_copy(Copy, Args); + int Length = std::vsnprintf(nullptr, 0, Format, Copy); + va_end(Copy); + std::string Message(Length > 0 ? Length : 0, '\0'); + if (Length > 0) std::vsnprintf(Message.data(), Message.size() + 1, Format, Args); + std::string Text = diagnosticPrefix(S, Locus) + Message + '\n'; + // The same node can be diagnosed more than once; print each line once. + if (!PrintedDiagnostics.insert(Text).second) return; + std::fputs(Text.c_str(), stderr); } __attribute__((format(printf, 2, 3))) |
