llvm-project/clang/tools/diagtool/DiagnosticNames.cpp
Chandler Carruth bc6f84a2db
[StrTable] Switch diag group names to llvm::StringTable (#123302)
Previously, they used a hand-rolled Pascal-string encoding different
from all the other string tables produced from TableGen. This moves them
to use the newly introduced runtime abstraction, and enhances that
abstraction to support iterating over the string table as used in this
case.

From what I can tell the Pascal-string encoding isn't critical here to
avoid expensive `strlen` calls, so I think this is a simpler and more
consistent model. But if folks would prefer a Pascal-string style
encoding, I can instead work to switch the `StringTable` abstraction
towards that. It would require some tricky tradeoffs though to make it
reasonably general: either using 4 bytes instead of 1 byte to encode the
size, or having a fallback to `strlen` for long strings.
2025-01-22 00:41:27 -08:00

104 lines
3.5 KiB
C++

//===- DiagnosticNames.cpp - Defines a table of all builtin diagnostics ----==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "DiagnosticNames.h"
#include "clang/Basic/AllDiagnostics.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringTable.h"
using namespace clang;
using namespace diagtool;
static const DiagnosticRecord BuiltinDiagnosticsByName[] = {
#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
#include "clang/Basic/DiagnosticIndexName.inc"
#undef DIAG_NAME_INDEX
};
llvm::ArrayRef<DiagnosticRecord> diagtool::getBuiltinDiagnosticsByName() {
return llvm::ArrayRef(BuiltinDiagnosticsByName);
}
// FIXME: Is it worth having two tables, especially when this one can get
// out of sync easily?
static const DiagnosticRecord BuiltinDiagnosticsByID[] = {
#define DIAG(ENUM, CLASS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \
SHOWINSYSHEADER, SHOWINSYSMACRO, DEFER, CATEGORY) \
{#ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t)},
#include "clang/Basic/AllDiagnosticKinds.inc"
#undef DIAG
};
static bool orderByID(const DiagnosticRecord &Left,
const DiagnosticRecord &Right) {
return Left.DiagID < Right.DiagID;
}
const DiagnosticRecord &diagtool::getDiagnosticForID(short DiagID) {
DiagnosticRecord Key = {nullptr, DiagID, 0};
// The requirement for lower_bound to produce a valid result it is
// enough if the BuiltinDiagnosticsByID is partitioned (by DiagID),
// but as we want this function to work for all possible values of
// DiagID sent in as argument it is better to right away check if
// BuiltinDiagnosticsByID is sorted.
assert(llvm::is_sorted(BuiltinDiagnosticsByID, orderByID) &&
"IDs in BuiltinDiagnosticsByID must be sorted.");
const DiagnosticRecord *Result =
llvm::lower_bound(BuiltinDiagnosticsByID, Key, orderByID);
assert(Result && "diagnostic not found; table may be out of date");
return *Result;
}
#define GET_DIAG_ARRAYS
#include "clang/Basic/DiagnosticGroups.inc"
#undef GET_DIAG_ARRAYS
// Second the table of options, sorted by name for fast binary lookup.
static const GroupRecord OptionTable[] = {
#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups, Docs) \
{FlagNameOffset, Members, SubGroups},
#include "clang/Basic/DiagnosticGroups.inc"
#undef DIAG_ENTRY
};
llvm::StringRef GroupRecord::getName() const {
return DiagGroupNames[NameOffset];
}
GroupRecord::subgroup_iterator GroupRecord::subgroup_begin() const {
return DiagSubGroups + SubGroups;
}
GroupRecord::subgroup_iterator GroupRecord::subgroup_end() const {
return nullptr;
}
llvm::iterator_range<diagtool::GroupRecord::subgroup_iterator>
GroupRecord::subgroups() const {
return llvm::make_range(subgroup_begin(), subgroup_end());
}
GroupRecord::diagnostics_iterator GroupRecord::diagnostics_begin() const {
return DiagArrays + Members;
}
GroupRecord::diagnostics_iterator GroupRecord::diagnostics_end() const {
return nullptr;
}
llvm::iterator_range<diagtool::GroupRecord::diagnostics_iterator>
GroupRecord::diagnostics() const {
return llvm::make_range(diagnostics_begin(), diagnostics_end());
}
llvm::ArrayRef<GroupRecord> diagtool::getDiagnosticGroups() {
return llvm::ArrayRef(OptionTable);
}