[clang-tools-extra] 35823d1 - [clang-doc] Use llvm RTTI over handrolled casting (#202059)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Jun 6 13:46:02 PDT 2026
Author: Paul Kirth
Date: 2026-06-06T13:45:58-07:00
New Revision: 35823d13a8460f57be6b73f3dc4f3b93acbcf79d
URL: https://github.com/llvm/llvm-project/commit/35823d13a8460f57be6b73f3dc4f3b93acbcf79d
DIFF: https://github.com/llvm/llvm-project/commit/35823d13a8460f57be6b73f3dc4f3b93acbcf79d.diff
LOG: [clang-doc] Use llvm RTTI over handrolled casting (#202059)
Clang-Doc has a limited amount of polymorphism over Info types.
Historically, these have just been cast directly in a few places, but we
can use the existing llvm RTTI implementation to more rigorously
dispatch and query the types involved with only limited extra code.
This should make future changes a bit harder to get wrong.
Added:
Modified:
clang-tools-extra/clang-doc/BitcodeWriter.cpp
clang-tools-extra/clang-doc/JSONGenerator.cpp
clang-tools-extra/clang-doc/MDGenerator.cpp
clang-tools-extra/clang-doc/Representation.cpp
clang-tools-extra/clang-doc/Representation.h
clang-tools-extra/clang-doc/Serialize.cpp
clang-tools-extra/clang-doc/YAMLGenerator.cpp
clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
index 2ab1bbf4a8a16..ee5114b1af880 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -768,28 +768,28 @@ void ClangDocBitcodeWriter::emitBlock(const VarInfo &I) {
bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
switch (I->IT) {
case InfoType::IT_namespace:
- emitBlock(*static_cast<NamespaceInfo *>(I));
+ emitBlock(*cast<NamespaceInfo>(I));
break;
case InfoType::IT_record:
- emitBlock(*static_cast<RecordInfo *>(I));
+ emitBlock(*cast<RecordInfo>(I));
break;
case InfoType::IT_enum:
- emitBlock(*static_cast<EnumInfo *>(I));
+ emitBlock(*cast<EnumInfo>(I));
break;
case InfoType::IT_function:
- emitBlock(*static_cast<FunctionInfo *>(I));
+ emitBlock(*cast<FunctionInfo>(I));
break;
case InfoType::IT_typedef:
- emitBlock(*static_cast<TypedefInfo *>(I));
+ emitBlock(*cast<TypedefInfo>(I));
break;
case InfoType::IT_concept:
- emitBlock(*static_cast<ConceptInfo *>(I));
+ emitBlock(*cast<ConceptInfo>(I));
break;
case InfoType::IT_variable:
- emitBlock(*static_cast<VarInfo *>(I));
+ emitBlock(*cast<VarInfo>(I));
break;
case InfoType::IT_friend:
- emitBlock(*static_cast<FriendInfo *>(I));
+ emitBlock(*cast<FriendInfo>(I));
break;
case InfoType::IT_default:
unsigned ID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp
index 0ab71b4a5b5c9..fc629dc8449e0 100644
--- a/clang-tools-extra/clang-doc/JSONGenerator.cpp
+++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp
@@ -451,7 +451,7 @@ void JSONGenerator::serializeCommonAttributes(const Info &I,
// Namespaces aren't SymbolInfos, so they dont have a DefLoc
if (I.IT != InfoType::IT_namespace) {
- const auto *Symbol = static_cast<const SymbolInfo *>(&I);
+ const auto *Symbol = cast<SymbolInfo>(&I);
if (Symbol->DefLoc)
Obj["Location"] = serializeLocation(Symbol->DefLoc.value());
}
@@ -491,7 +491,7 @@ void JSONGenerator::serializeClassSpecializations(SymbolID ClassUSR,
auto *Class = Infos->lookup(toHex(ClassUSR));
if (!Class || Class->IT != InfoType::IT_record)
return;
- RecordInfo *ClassInfo = static_cast<RecordInfo *>(Class);
+ RecordInfo *ClassInfo = cast<RecordInfo>(Class);
if (!ClassInfo->Template || !ClassInfo->Template->Specialization)
return;
serializeTemplateSpecialization(ClassInfo->Template.value(), ReferenceObj);
@@ -865,7 +865,7 @@ SmallString<16> JSONGenerator::determineFileName(Info *I,
SmallString<128> &Path) {
SmallString<16> FileName;
if (I->IT == InfoType::IT_record) {
- auto *RecordSymbolInfo = static_cast<SymbolInfo *>(I);
+ auto *RecordSymbolInfo = cast<SymbolInfo>(I);
FileName = RecordSymbolInfo->MangledName;
} else if (I->IT == InfoType::IT_namespace) {
FileName = "index";
@@ -1052,10 +1052,10 @@ Error JSONGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
switch (I->IT) {
case InfoType::IT_namespace:
- serializeInfo(*static_cast<NamespaceInfo *>(I), Obj);
+ serializeInfo(*cast<NamespaceInfo>(I), Obj);
break;
case InfoType::IT_record:
- serializeInfo(*static_cast<RecordInfo *>(I), Obj);
+ serializeInfo(*cast<RecordInfo>(I), Obj);
break;
case InfoType::IT_concept:
case InfoType::IT_enum:
diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp b/clang-tools-extra/clang-doc/MDGenerator.cpp
index df1ca6b868d43..4d412cde557ed 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -561,19 +561,19 @@ llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
const ClangDocContext &CDCtx) {
switch (I->IT) {
case InfoType::IT_namespace:
- genMarkdown(CDCtx, *static_cast<clang::doc::NamespaceInfo *>(I), OS);
+ genMarkdown(CDCtx, *cast<NamespaceInfo>(I), OS);
break;
case InfoType::IT_record:
- genMarkdown(CDCtx, *static_cast<clang::doc::RecordInfo *>(I), OS);
+ genMarkdown(CDCtx, *cast<RecordInfo>(I), OS);
break;
case InfoType::IT_enum:
- genMarkdown(CDCtx, *static_cast<clang::doc::EnumInfo *>(I), OS);
+ genMarkdown(CDCtx, *cast<EnumInfo>(I), OS);
break;
case InfoType::IT_function:
- genMarkdown(CDCtx, *static_cast<clang::doc::FunctionInfo *>(I), OS);
+ genMarkdown(CDCtx, *cast<FunctionInfo>(I), OS);
break;
case InfoType::IT_typedef:
- genMarkdown(CDCtx, *static_cast<clang::doc::TypedefInfo *>(I), OS);
+ genMarkdown(CDCtx, *cast<TypedefInfo>(I), OS);
break;
case InfoType::IT_concept:
case InfoType::IT_variable:
diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp
index bfa1150f9bc35..9c13f6bfa566d 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -108,7 +108,7 @@ static llvm::Expected<Info *> reduce(SmallVectorImpl<Info *> &Values) {
"no value to reduce");
T *Merged = allocateTransient<T>(Values[0]->USR);
for (auto &I : Values)
- Merged->merge(std::move(*static_cast<T *>(I)));
+ Merged->merge(std::move(*cast<T>(I)));
return Merged;
}
@@ -220,36 +220,29 @@ llvm::Error mergeSingleInfo(doc::Info *&Reduced, doc::Info *NewInfo,
switch (Reduced->IT) {
case InfoType::IT_namespace:
- static_cast<NamespaceInfo *>(Reduced)->merge(
- std::move(*static_cast<NamespaceInfo *>(NewInfo)));
+ cast<NamespaceInfo>(Reduced)->merge(
+ std::move(*cast<NamespaceInfo>(NewInfo)));
break;
case InfoType::IT_record:
- static_cast<RecordInfo *>(Reduced)->merge(
- std::move(*static_cast<RecordInfo *>(NewInfo)));
+ cast<RecordInfo>(Reduced)->merge(std::move(*cast<RecordInfo>(NewInfo)));
break;
case InfoType::IT_enum:
- static_cast<EnumInfo *>(Reduced)->merge(
- std::move(*static_cast<EnumInfo *>(NewInfo)));
+ cast<EnumInfo>(Reduced)->merge(std::move(*cast<EnumInfo>(NewInfo)));
break;
case InfoType::IT_function:
- static_cast<FunctionInfo *>(Reduced)->merge(
- std::move(*static_cast<FunctionInfo *>(NewInfo)));
+ cast<FunctionInfo>(Reduced)->merge(std::move(*cast<FunctionInfo>(NewInfo)));
break;
case InfoType::IT_typedef:
- static_cast<TypedefInfo *>(Reduced)->merge(
- std::move(*static_cast<TypedefInfo *>(NewInfo)));
+ cast<TypedefInfo>(Reduced)->merge(std::move(*cast<TypedefInfo>(NewInfo)));
break;
case InfoType::IT_concept:
- static_cast<ConceptInfo *>(Reduced)->merge(
- std::move(*static_cast<ConceptInfo *>(NewInfo)));
+ cast<ConceptInfo>(Reduced)->merge(std::move(*cast<ConceptInfo>(NewInfo)));
break;
case InfoType::IT_variable:
- static_cast<VarInfo *>(Reduced)->merge(
- std::move(*static_cast<VarInfo *>(NewInfo)));
+ cast<VarInfo>(Reduced)->merge(std::move(*cast<VarInfo>(NewInfo)));
break;
case InfoType::IT_friend:
- static_cast<FriendInfo *>(Reduced)->merge(
- std::move(*static_cast<FriendInfo *>(NewInfo)));
+ cast<FriendInfo>(Reduced)->merge(std::move(*cast<FriendInfo>(NewInfo)));
break;
default:
return llvm::createStringError(llvm::inconvertibleErrorCode(),
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index c7921ff9de875..e3ad7fa3f375d 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -23,6 +23,7 @@
#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/simple_ilist.h"
#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/StringSaver.h"
#include <array>
@@ -585,6 +586,8 @@ struct NamespaceInfo : public Info {
NamespaceInfo(SymbolID USR = SymbolID(), StringRef Name = StringRef(),
StringRef Path = StringRef());
+ static bool classof(const Info *I) { return I->IT == InfoType::IT_namespace; }
+
void merge(NamespaceInfo &&I);
ScopeChildren Children;
@@ -598,6 +601,24 @@ struct SymbolInfo : public Info {
SymbolInfo(const SymbolInfo &Other, llvm::BumpPtrAllocator &Arena);
+ // SymbolInfo is an intermediate base without its own InfoType. It covers
+ // every Info* kind that relates to symbols, which mostly just excludes
+ // Namespace in the current schema.
+ static bool classof(const Info *I) {
+ switch (I->IT) {
+ case InfoType::IT_record:
+ case InfoType::IT_function:
+ case InfoType::IT_enum:
+ case InfoType::IT_typedef:
+ case InfoType::IT_concept:
+ case InfoType::IT_variable:
+ case InfoType::IT_friend:
+ return true;
+ default:
+ return false;
+ }
+ }
+
void merge(SymbolInfo &&I);
bool operator<(const SymbolInfo &Other) const {
@@ -627,6 +648,9 @@ struct FriendInfo : public SymbolInfo {
const StringRef Name = StringRef())
: SymbolInfo(IT, USR, Name) {}
FriendInfo(const FriendInfo &Other, llvm::BumpPtrAllocator &Arena);
+
+ static bool classof(const Info *I) { return I->IT == InfoType::IT_friend; }
+
bool mergeable(const FriendInfo &Other);
void merge(FriendInfo &&Other);
@@ -641,6 +665,8 @@ struct VarInfo : public SymbolInfo {
VarInfo() : SymbolInfo(InfoType::IT_variable) {}
explicit VarInfo(SymbolID USR) : SymbolInfo(InfoType::IT_variable, USR) {}
+ static bool classof(const Info *I) { return I->IT == InfoType::IT_variable; }
+
void merge(VarInfo &&I);
TypeInfo Type;
@@ -652,6 +678,8 @@ struct FunctionInfo : public SymbolInfo {
FunctionInfo(SymbolID USR = SymbolID())
: SymbolInfo(InfoType::IT_function, USR) {}
+ static bool classof(const Info *I) { return I->IT == InfoType::IT_function; }
+
void merge(FunctionInfo &&I);
Reference Parent;
@@ -680,6 +708,8 @@ struct RecordInfo : public SymbolInfo {
RecordInfo(const RecordInfo &Other, llvm::BumpPtrAllocator &Arena);
+ static bool classof(const Info *I) { return I->IT == InfoType::IT_record; }
+
void merge(RecordInfo &&I);
// Type of this record (struct, class, union, interface).
@@ -715,6 +745,8 @@ struct TypedefInfo : public SymbolInfo {
TypedefInfo(SymbolID USR = SymbolID())
: SymbolInfo(InfoType::IT_typedef, USR) {}
+ static bool classof(const Info *I) { return I->IT == InfoType::IT_typedef; }
+
void merge(TypedefInfo &&I);
TypeInfo Underlying = {};
@@ -782,6 +814,8 @@ struct EnumInfo : public SymbolInfo {
EnumInfo() : SymbolInfo(InfoType::IT_enum) {}
EnumInfo(SymbolID USR) : SymbolInfo(InfoType::IT_enum, USR) {}
+ static bool classof(const Info *I) { return I->IT == InfoType::IT_enum; }
+
void merge(EnumInfo &&I);
// Indicates whether this enum is scoped (e.g. enum class).
@@ -799,6 +833,8 @@ struct ConceptInfo : public SymbolInfo {
ConceptInfo() : SymbolInfo(InfoType::IT_concept) {}
ConceptInfo(SymbolID USR) : SymbolInfo(InfoType::IT_concept, USR) {}
+ static bool classof(const Info *I) { return I->IT == InfoType::IT_concept; }
+
void merge(ConceptInfo &&I);
bool IsType = false;
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index c7481fa5bada6..50118e0472075 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -363,17 +363,17 @@ static std::string serialize(const T &I, DiagnosticsEngine &Diags) {
std::string serialize(const Info &I, DiagnosticsEngine &Diags) {
switch (I.IT) {
case InfoType::IT_namespace:
- return serialize(static_cast<const NamespaceInfo &>(I), Diags);
+ return serialize(cast<NamespaceInfo>(I), Diags);
case InfoType::IT_record:
- return serialize(static_cast<const RecordInfo &>(I), Diags);
+ return serialize(cast<RecordInfo>(I), Diags);
case InfoType::IT_enum:
- return serialize(static_cast<const EnumInfo &>(I), Diags);
+ return serialize(cast<EnumInfo>(I), Diags);
case InfoType::IT_function:
- return serialize(static_cast<const FunctionInfo &>(I), Diags);
+ return serialize(cast<FunctionInfo>(I), Diags);
case InfoType::IT_concept:
- return serialize(static_cast<const ConceptInfo &>(I), Diags);
+ return serialize(cast<ConceptInfo>(I), Diags);
case InfoType::IT_variable:
- return serialize(static_cast<const VarInfo &>(I), Diags);
+ return serialize(cast<VarInfo>(I), Diags);
case InfoType::IT_friend:
case InfoType::IT_typedef:
case InfoType::IT_default:
diff --git a/clang-tools-extra/clang-doc/YAMLGenerator.cpp b/clang-tools-extra/clang-doc/YAMLGenerator.cpp
index 3d2bb97335b6f..5a1d822526daa 100644
--- a/clang-tools-extra/clang-doc/YAMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/YAMLGenerator.cpp
@@ -567,19 +567,19 @@ llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
llvm::yaml::Output InfoYAML(OS);
switch (I->IT) {
case InfoType::IT_namespace:
- InfoYAML << *static_cast<clang::doc::NamespaceInfo *>(I);
+ InfoYAML << *cast<NamespaceInfo>(I);
break;
case InfoType::IT_record:
- InfoYAML << *static_cast<clang::doc::RecordInfo *>(I);
+ InfoYAML << *cast<RecordInfo>(I);
break;
case InfoType::IT_enum:
- InfoYAML << *static_cast<clang::doc::EnumInfo *>(I);
+ InfoYAML << *cast<EnumInfo>(I);
break;
case InfoType::IT_function:
- InfoYAML << *static_cast<clang::doc::FunctionInfo *>(I);
+ InfoYAML << *cast<FunctionInfo>(I);
break;
case InfoType::IT_typedef:
- InfoYAML << *static_cast<clang::doc::TypedefInfo *>(I);
+ InfoYAML << *cast<TypedefInfo>(I);
break;
case InfoType::IT_concept:
case InfoType::IT_variable:
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index 5d1d88a228cc6..38002f5111a9f 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -231,14 +231,10 @@ static llvm::Error getMdFiles(const char *Argv0,
static void sortUsrToInfo(llvm::StringMap<doc::Info *> &USRToInfo) {
for (auto &I : USRToInfo) {
auto &Info = I.second;
- if (Info->IT == doc::InfoType::IT_namespace) {
- auto *Namespace = static_cast<clang::doc::NamespaceInfo *>(Info);
+ if (auto *Namespace = dyn_cast<doc::NamespaceInfo>(Info))
Namespace->Children.sort();
- }
- if (Info->IT == doc::InfoType::IT_record) {
- auto *Record = static_cast<clang::doc::RecordInfo *>(Info);
+ else if (auto *Record = dyn_cast<doc::RecordInfo>(Info))
Record->Children.sort();
- }
}
}
More information about the cfe-commits
mailing list