mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
Create a constexpr function that recursively validates that [a portion of] the diagnostics tree is in proper depth-first order. Use this to ensure at compile time that the diagnostics are, in fact, in the correct order. This will make it harder to accidentally introduce order errors, since any C++17 build will throw a compile error if the list is not correctly ordered.
121 lines
3.1 KiB
C++
121 lines
3.1 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file LICENSE.rst or https://cmake.org/licensing for details. */
|
|
#include "cmDiagnostics.h"
|
|
|
|
#include <cassert>
|
|
#include <map>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include <cmext/string_view>
|
|
|
|
#include "cmStringAlgorithms.h"
|
|
|
|
namespace {
|
|
|
|
#if __cplusplus >= 201703L
|
|
constexpr unsigned validateDiagnosticsSubtree(unsigned parent, unsigned index)
|
|
{
|
|
// Ensure that all diagnostics, starting from the specified index, have the
|
|
// specified parent as an ancestor. Return the first index that violates
|
|
// this condition.
|
|
while (index < cmDiagnostics::CategoryCount &&
|
|
cmDiagnostics::CategoryInfo[index].Parent == parent) {
|
|
unsigned const child = index;
|
|
// For each diagnostic, 'consume' its children (if any).
|
|
index = validateDiagnosticsSubtree(child, ++index);
|
|
}
|
|
return index;
|
|
}
|
|
|
|
static_assert(validateDiagnosticsSubtree(cmDiagnostics::CMD_NONE, 1) ==
|
|
cmDiagnostics::CategoryCount,
|
|
"Diagnostics are not properly ordered"
|
|
" (hint: LHS is the index of the first misordered diagnostic)");
|
|
#endif
|
|
|
|
cm::optional<cmDiagnosticCategory> stringToCategory(cm::string_view input)
|
|
{
|
|
using Map = std::map<cm::string_view, cmDiagnosticCategory>;
|
|
static Map const mapping = {
|
|
#define CATEGORY_MAP(C) { #C ""_s, cmDiagnostics::C },
|
|
CM_FOR_EACH_DIAGNOSTIC_CATEGORY(CATEGORY_MAP)
|
|
#undef CATEGORY_MAP
|
|
};
|
|
|
|
assert(!input.empty());
|
|
if (input.size() >= 4 && cmHasLiteralPrefix(input, "CMD_")) {
|
|
auto const i = mapping.find(input);
|
|
if (i != mapping.end()) {
|
|
return i->second;
|
|
}
|
|
}
|
|
|
|
return cm::nullopt;
|
|
}
|
|
}
|
|
|
|
#if __cplusplus < 201703L
|
|
// Prior to C++17, the compiler is unhappy if this member doesn't have explicit
|
|
// storage... and clang-tidy is unhappy if it does.
|
|
// NOLINTNEXTLINE(*-redundant-declaration)
|
|
constexpr cmDiagnostics::DiagnosticCategoryInformation
|
|
cmDiagnostics::CategoryInfo[cmDiagnostics::CategoryCount];
|
|
#endif
|
|
|
|
cm::string_view cmDiagnostics::GetActionString(DiagnosticAction action)
|
|
{
|
|
switch (action) {
|
|
case Ignore:
|
|
return "IGNORE"_s;
|
|
case Warn:
|
|
return "WARN"_s;
|
|
case SendError:
|
|
return "SEND_ERROR"_s;
|
|
case FatalError:
|
|
return "FATAL_ERROR"_s;
|
|
default:
|
|
return {};
|
|
}
|
|
}
|
|
|
|
cm::string_view cmDiagnostics::GetCategoryString(DiagnosticCategory category)
|
|
{
|
|
static cm::string_view const names[CategoryCount] = {
|
|
{}, // CMD_NONE
|
|
#define CATEGORY_NAME(C) #C ""_s,
|
|
CM_FOR_EACH_DIAGNOSTIC_CATEGORY(CATEGORY_NAME)
|
|
#undef CATEGORY_MAP
|
|
};
|
|
|
|
if (category < CategoryCount) {
|
|
return names[category];
|
|
}
|
|
return {};
|
|
}
|
|
|
|
cm::optional<cmDiagnosticAction> cmDiagnostics::GetDiagnosticAction(
|
|
cm::string_view name)
|
|
{
|
|
if (name == "IGNORE"_s) {
|
|
return DiagnosticAction::Ignore;
|
|
}
|
|
if (name == "WARN"_s) {
|
|
return DiagnosticAction::Warn;
|
|
}
|
|
if (name == "SEND_ERROR"_s) {
|
|
return DiagnosticAction::SendError;
|
|
}
|
|
if (name == "FATAL_ERROR"_s) {
|
|
return DiagnosticAction::FatalError;
|
|
}
|
|
|
|
return cm::nullopt;
|
|
}
|
|
|
|
cm::optional<cmDiagnosticCategory> cmDiagnostics::GetDiagnosticCategory(
|
|
cm::string_view name)
|
|
{
|
|
return stringToCategory(name);
|
|
}
|