mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Swift: go back to explicit DIAGNOSE_ERROR macros
This commit is contained in:
@@ -8,12 +8,12 @@
|
||||
|
||||
namespace codeql {
|
||||
|
||||
nlohmann::json SwiftDiagnosticsSource::json(const std::chrono::system_clock::time_point& timestamp,
|
||||
std::string_view message) const {
|
||||
return {
|
||||
nlohmann::json SwiftDiagnostic::json(const std::chrono::system_clock::time_point& timestamp,
|
||||
std::string_view message) const {
|
||||
nlohmann::json ret{
|
||||
{"source",
|
||||
{
|
||||
{"id", sourceId()},
|
||||
{"id", absl::StrJoin({extractorName, programName, id}, "/")},
|
||||
{"name", name},
|
||||
{"extractorName", extractorName},
|
||||
}},
|
||||
@@ -28,26 +28,29 @@ nlohmann::json SwiftDiagnosticsSource::json(const std::chrono::system_clock::tim
|
||||
{"plaintextMessage", absl::StrCat(message, ".\n\n", action, ".")},
|
||||
{"timestamp", fmt::format("{:%FT%T%z}", timestamp)},
|
||||
};
|
||||
}
|
||||
|
||||
std::string SwiftDiagnosticsSource::sourceId() const {
|
||||
return absl::StrJoin({extractorName, programName, id}, "/");
|
||||
}
|
||||
|
||||
nlohmann::json SwiftDiagnosticsSourceWithLocation::json(
|
||||
const std::chrono::system_clock::time_point& timestamp,
|
||||
std::string_view message) const {
|
||||
auto ret = source.json(timestamp, message);
|
||||
auto& location = ret["location"] = {{"file", file}};
|
||||
if (startLine) location["startLine"] = startLine;
|
||||
if (startColumn) location["startColumn"] = startColumn;
|
||||
if (endLine) location["endLine"] = endLine;
|
||||
if (endColumn) location["endColumn"] = endColumn;
|
||||
if (location) {
|
||||
ret["location"] = location->json();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string SwiftDiagnosticsSourceWithLocation::str() const {
|
||||
return absl::StrCat(source.id, "@", file, ":", startLine, ":", startColumn, ":", endLine, ":",
|
||||
endColumn);
|
||||
std::string SwiftDiagnostic::abbreviation() const {
|
||||
if (location) {
|
||||
return absl::StrCat(id, "@", location->str());
|
||||
}
|
||||
return std::string{id};
|
||||
}
|
||||
|
||||
nlohmann::json SwiftDiagnosticsLocation::json() const {
|
||||
nlohmann::json ret{{"file", file}};
|
||||
if (startLine) ret["startLine"] = startLine;
|
||||
if (startColumn) ret["startColumn"] = startColumn;
|
||||
if (endLine) ret["endLine"] = endLine;
|
||||
if (endColumn) ret["endColumn"] = endColumn;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string SwiftDiagnosticsLocation::str() const {
|
||||
return absl::StrJoin(std::tuple{file, startLine, startColumn, endLine, endColumn}, ":");
|
||||
}
|
||||
} // namespace codeql
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <optional>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
@@ -17,19 +18,14 @@ namespace codeql {
|
||||
|
||||
extern const std::string_view programName;
|
||||
|
||||
struct SwiftDiagnosticsSource;
|
||||
|
||||
struct SwiftDiagnosticsSourceWithLocation {
|
||||
const SwiftDiagnosticsSource& source;
|
||||
struct SwiftDiagnosticsLocation {
|
||||
std::string_view file;
|
||||
unsigned startLine;
|
||||
unsigned startColumn;
|
||||
unsigned endLine;
|
||||
unsigned endColumn;
|
||||
|
||||
// see SwiftDiagnosticsSource::json
|
||||
nlohmann::json json(const std::chrono::system_clock::time_point& timestamp,
|
||||
std::string_view message) const;
|
||||
nlohmann::json json() const;
|
||||
|
||||
std::string str() const;
|
||||
};
|
||||
@@ -37,7 +33,7 @@ struct SwiftDiagnosticsSourceWithLocation {
|
||||
// Models a diagnostic source for Swift, holding static information that goes out into a diagnostic
|
||||
// These are internally stored into a map on id's. A specific error log can use binlog's category
|
||||
// as id, which will then be used to recover the diagnostic source while dumping.
|
||||
struct SwiftDiagnosticsSource {
|
||||
struct SwiftDiagnostic {
|
||||
std::string_view id;
|
||||
std::string_view name;
|
||||
static constexpr std::string_view extractorName = "swift";
|
||||
@@ -46,6 +42,7 @@ struct SwiftDiagnosticsSource {
|
||||
// TODO(C++20) with vector going constexpr this can be turned to `std::vector<std::string_view>`
|
||||
std::string_view helpLinks;
|
||||
|
||||
std::optional<SwiftDiagnosticsLocation> location;
|
||||
// for the moment, we only output errors, so no need to store the severity
|
||||
|
||||
// create a JSON diagnostics for this source with the given timestamp and message to out
|
||||
@@ -55,16 +52,18 @@ struct SwiftDiagnosticsSource {
|
||||
nlohmann::json json(const std::chrono::system_clock::time_point& timestamp,
|
||||
std::string_view message) const;
|
||||
|
||||
SwiftDiagnosticsSourceWithLocation withLocation(std::string_view file,
|
||||
unsigned startLine = 0,
|
||||
unsigned startColumn = 0,
|
||||
unsigned endLine = 0,
|
||||
unsigned endColumn = 0) const {
|
||||
return {*this, file, startLine, startColumn, endLine, endColumn};
|
||||
}
|
||||
// returns <id> or <id>@<location> if a location is present
|
||||
std::string abbreviation() const;
|
||||
|
||||
private:
|
||||
std::string sourceId() const;
|
||||
SwiftDiagnostic withLocation(std::string_view file,
|
||||
unsigned startLine = 0,
|
||||
unsigned startColumn = 0,
|
||||
unsigned endLine = 0,
|
||||
unsigned endColumn = 0) const {
|
||||
auto ret = *this;
|
||||
ret.location = SwiftDiagnosticsLocation{file, startLine, startColumn, endLine, endColumn};
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
class SwiftDiagnosticsDumper {
|
||||
@@ -77,8 +76,7 @@ class SwiftDiagnosticsDumper {
|
||||
|
||||
void flush() { output.flush(); }
|
||||
|
||||
template <typename Source>
|
||||
void write(const Source& source,
|
||||
void write(const SwiftDiagnostic& source,
|
||||
const std::chrono::system_clock::time_point& timestamp,
|
||||
std::string_view message) {
|
||||
if (output) {
|
||||
@@ -93,49 +91,9 @@ class SwiftDiagnosticsDumper {
|
||||
std::ofstream output;
|
||||
};
|
||||
|
||||
constexpr codeql::SwiftDiagnosticsSource internalError{
|
||||
constexpr SwiftDiagnostic internalError{
|
||||
"internal-error",
|
||||
"Internal error",
|
||||
"Contact us about this issue",
|
||||
};
|
||||
} // namespace codeql
|
||||
|
||||
namespace mserialize {
|
||||
// log diagnostic sources using just their id, using binlog/mserialize internal plumbing
|
||||
template <>
|
||||
struct CustomTag<codeql::SwiftDiagnosticsSource, void> : detail::BuiltinTag<std::string> {
|
||||
using T = codeql::SwiftDiagnosticsSource;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct CustomSerializer<codeql::SwiftDiagnosticsSource, void> {
|
||||
template <typename OutputStream>
|
||||
static void serialize(const codeql::SwiftDiagnosticsSource& source, OutputStream& out) {
|
||||
mserialize::serialize(source.id, out);
|
||||
}
|
||||
|
||||
static size_t serialized_size(const codeql::SwiftDiagnosticsSource& source) {
|
||||
return mserialize::serialized_size(source.id);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct CustomTag<codeql::SwiftDiagnosticsSourceWithLocation, void>
|
||||
: detail::BuiltinTag<std::string> {
|
||||
using T = codeql::SwiftDiagnosticsSourceWithLocation;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct CustomSerializer<codeql::SwiftDiagnosticsSourceWithLocation, void> {
|
||||
template <typename OutputStream>
|
||||
static void serialize(const codeql::SwiftDiagnosticsSourceWithLocation& source,
|
||||
OutputStream& out) {
|
||||
mserialize::serialize(source.str(), out);
|
||||
}
|
||||
|
||||
static size_t serialized_size(const codeql::SwiftDiagnosticsSourceWithLocation& source) {
|
||||
return mserialize::serialized_size(source.str());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mserialize
|
||||
|
||||
@@ -35,29 +35,31 @@
|
||||
#define LOG_DEBUG(...) LOG_WITH_LEVEL(debug, __VA_ARGS__)
|
||||
#define LOG_TRACE(...) LOG_WITH_LEVEL(trace, __VA_ARGS__)
|
||||
|
||||
#define CODEQL_GET_SECOND(...) CODEQL_GET_SECOND_I(__VA_ARGS__, 0, 0)
|
||||
#define CODEQL_GET_SECOND_I(X, Y, ...) Y
|
||||
|
||||
// only do the actual logging if the picked up `Logger` instance is configured to handle the
|
||||
// provided log level. `LEVEL` must be a compile-time constant. `logger()` is evaluated once
|
||||
// TODO(C++20) replace non-standard ##__VA_ARGS__ with __VA_OPT__(,) __VA_ARGS__
|
||||
#define LOG_WITH_LEVEL_AND_CATEGORY(LEVEL, CATEGORY, ...) \
|
||||
do { \
|
||||
static_assert(::codeql::detail::checkLogArgs<decltype(CODEQL_GET_SECOND(__VA_ARGS__))>( \
|
||||
MSERIALIZE_FIRST(__VA_ARGS__)), \
|
||||
"diagnostics logs must have format starting with \"[{}]\""); \
|
||||
constexpr auto _level = ::codeql::Log::Level::LEVEL; \
|
||||
::codeql::Logger& _logger = logger(); \
|
||||
if (_level >= _logger.level()) { \
|
||||
BINLOG_CREATE_SOURCE_AND_EVENT(_logger.writer(), _level, CATEGORY, ::binlog::clockNow(), \
|
||||
__VA_ARGS__); \
|
||||
} \
|
||||
if (_level >= ::codeql::Log::Level::error) { \
|
||||
::codeql::Log::flush(); \
|
||||
} \
|
||||
#define LOG_WITH_LEVEL(LEVEL, ...) \
|
||||
do { \
|
||||
constexpr auto _level = ::codeql::Log::Level::LEVEL; \
|
||||
::codeql::Logger& _logger = logger(); \
|
||||
if (_level >= _logger.level()) { \
|
||||
BINLOG_CREATE_SOURCE_AND_EVENT(_logger.writer(), _level, /*category*/, ::binlog::clockNow(), \
|
||||
__VA_ARGS__); \
|
||||
} \
|
||||
if (_level >= ::codeql::Log::Level::error) { \
|
||||
::codeql::Log::flush(); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define LOG_WITH_LEVEL(LEVEL, ...) LOG_WITH_LEVEL_AND_CATEGORY(LEVEL, , __VA_ARGS__)
|
||||
// Emit errors with a specified SwiftDiagnostic object. These will be both logged and outputted as
|
||||
// JSON DB diagnostics
|
||||
#define DIAGNOSE_CRITICAL(ID, ...) DIAGNOSE_WITH_LEVEL(critical, ID, __VA_ARGS__)
|
||||
#define DIAGNOSE_ERROR(ID, ...) DIAGNOSE_WITH_LEVEL(error, ID, __VA_ARGS__)
|
||||
|
||||
#define CODEQL_DIAGNOSTIC_LOG_FORMAT_PREFIX "[{}] "
|
||||
// TODO(C++20) replace non-standard , ##__VA_ARGS__ with __VA_OPT__(,) __VA_ARGS__
|
||||
#define DIAGNOSE_WITH_LEVEL(LEVEL, ID, FORMAT, ...) \
|
||||
LOG_WITH_LEVEL(LEVEL, CODEQL_DIAGNOSTIC_LOG_FORMAT_PREFIX FORMAT, \
|
||||
::codeql::detail::SwiftDiagnosticLogWrapper{ID}, ##__VA_ARGS__);
|
||||
|
||||
// avoid calling into binlog's original macros
|
||||
#undef BINLOG_CRITICAL
|
||||
@@ -126,8 +128,7 @@ class Log {
|
||||
return instance().getLoggerConfigurationImpl(name);
|
||||
}
|
||||
|
||||
template <typename Source>
|
||||
static void diagnose(const Source& source,
|
||||
static void diagnose(const SwiftDiagnostic& source,
|
||||
const std::chrono::system_clock::time_point& time,
|
||||
std::string_view message) {
|
||||
instance().diagnostics.write(source, time, message);
|
||||
@@ -224,31 +225,9 @@ class Logger {
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
constexpr std::string_view diagnosticsFormatPrefix = "[{}] ";
|
||||
|
||||
template <typename T>
|
||||
constexpr bool checkLogArgs(std::string_view format) {
|
||||
using Type = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
constexpr bool isDiagnostic = std::is_same_v<Type, SwiftDiagnosticsSource> ||
|
||||
std::is_same_v<Type, SwiftDiagnosticsSourceWithLocation>;
|
||||
return !isDiagnostic ||
|
||||
format.substr(0, diagnosticsFormatPrefix.size()) == diagnosticsFormatPrefix;
|
||||
}
|
||||
|
||||
template <typename Writer, typename Source, typename... T>
|
||||
void binlogAddEventIgnoreFirstOverload(Writer& writer,
|
||||
std::uint64_t eventSourceId,
|
||||
std::uint64_t clock,
|
||||
const char* format,
|
||||
const Source& source,
|
||||
T&&... t) {
|
||||
std::chrono::system_clock::time_point point{
|
||||
std::chrono::duration_cast<std::chrono::system_clock::duration>(
|
||||
std::chrono::nanoseconds{clock})};
|
||||
constexpr auto offset = ::codeql::detail::diagnosticsFormatPrefix.size();
|
||||
::codeql::Log::diagnose(source, point, fmt::format(format + offset, t...));
|
||||
writer.addEvent(eventSourceId, clock, source, std::forward<T>(t)...);
|
||||
}
|
||||
struct SwiftDiagnosticLogWrapper {
|
||||
const SwiftDiagnostic& value;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace codeql
|
||||
@@ -262,32 +241,37 @@ void addEventIgnoreFirst(Writer& writer,
|
||||
std::uint64_t eventSourceId,
|
||||
std::uint64_t clock,
|
||||
const char (&format)[N],
|
||||
const codeql::SwiftDiagnosticsSource& source,
|
||||
codeql::detail::SwiftDiagnosticLogWrapper&& source,
|
||||
T&&... t) {
|
||||
codeql::detail::binlogAddEventIgnoreFirstOverload(writer, eventSourceId, clock, format, source,
|
||||
std::forward<T>(t)...);
|
||||
std::chrono::system_clock::time_point point{
|
||||
std::chrono::duration_cast<std::chrono::system_clock::duration>(
|
||||
std::chrono::nanoseconds{clock})};
|
||||
constexpr std::string_view prefix = CODEQL_DIAGNOSTIC_LOG_FORMAT_PREFIX;
|
||||
::codeql::Log::diagnose(source.value, point, fmt::format(format + prefix.size(), t...));
|
||||
writer.addEvent(eventSourceId, clock, source, std::forward<T>(t)...);
|
||||
}
|
||||
|
||||
template <typename Writer, size_t N, typename... T>
|
||||
void addEventIgnoreFirst(Writer& writer,
|
||||
std::uint64_t eventSourceId,
|
||||
std::uint64_t clock,
|
||||
const char (&format)[N],
|
||||
codeql::SwiftDiagnosticsSourceWithLocation&& source,
|
||||
T&&... t) {
|
||||
codeql::detail::binlogAddEventIgnoreFirstOverload(writer, eventSourceId, clock, format, source,
|
||||
std::forward<T>(t)...);
|
||||
}
|
||||
|
||||
template <typename Writer, size_t N, typename... T>
|
||||
void addEventIgnoreFirst(Writer& writer,
|
||||
std::uint64_t eventSourceId,
|
||||
std::uint64_t clock,
|
||||
const char (&format)[N],
|
||||
const codeql::SwiftDiagnosticsSourceWithLocation& source,
|
||||
T&&... t) {
|
||||
codeql::detail::binlogAddEventIgnoreFirstOverload(writer, eventSourceId, clock, format, source,
|
||||
std::forward<T>(t)...);
|
||||
}
|
||||
|
||||
} // namespace binlog::detail
|
||||
|
||||
namespace mserialize {
|
||||
// log diagnostics wrapper using the abbreviation of the underlying diagnostic, using
|
||||
// binlog/mserialize internal plumbing
|
||||
template <>
|
||||
struct CustomTag<codeql::detail::SwiftDiagnosticLogWrapper, void>
|
||||
: detail::BuiltinTag<std::string> {
|
||||
using T = codeql::detail::SwiftDiagnosticLogWrapper;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct CustomSerializer<codeql::detail::SwiftDiagnosticLogWrapper, void> {
|
||||
template <typename OutputStream>
|
||||
static void serialize(const codeql::detail::SwiftDiagnosticLogWrapper& source,
|
||||
OutputStream& out) {
|
||||
mserialize::serialize(source.value.abbreviation(), out);
|
||||
}
|
||||
|
||||
static size_t serialized_size(const codeql::detail::SwiftDiagnosticLogWrapper& source) {
|
||||
return mserialize::serialized_size(source.value.abbreviation());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mserialize
|
||||
|
||||
Reference in New Issue
Block a user