[clang-tools-extra] 80c7133 - [clang-doc] Introduce Serializer class (#184873)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 6 20:23:03 PST 2026
Author: Paul Kirth
Date: 2026-03-06T20:22:58-08:00
New Revision: 80c7133915c2886e7aa093b4842e2910bc96c82e
URL: https://github.com/llvm/llvm-project/commit/80c7133915c2886e7aa093b4842e2910bc96c82e
DIFF: https://github.com/llvm/llvm-project/commit/80c7133915c2886e7aa093b4842e2910bc96c82e.diff
LOG: [clang-doc] Introduce Serializer class (#184873)
Serialization has mostly been done with static functions, but soon we
will need to share state, like alocator references. To avoid blowing up
our parameter lists, we can just wrap the local functions within a
class.
Added:
Modified:
clang-tools-extra/clang-doc/Mapper.cpp
clang-tools-extra/clang-doc/Serialize.cpp
clang-tools-extra/clang-doc/Serialize.h
clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp
clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-doc/Mapper.cpp b/clang-tools-extra/clang-doc/Mapper.cpp
index d567fd28acfc4..bedf4f766c8b0 100644
--- a/clang-tools-extra/clang-doc/Mapper.cpp
+++ b/clang-tools-extra/clang-doc/Mapper.cpp
@@ -83,7 +83,8 @@ bool MapASTVisitor::mapDecl(const T *D, bool IsDefinition) {
bool IsFileInRootDir;
llvm::SmallString<128> File =
getFile(D, D->getASTContext(), CDCtx.SourceRoot, IsFileInRootDir);
- CP = serialize::emitInfo(D, getComment(D, D->getASTContext()),
+ serialize::Serializer Serializer;
+ CP = Serializer.emitInfo(D, getComment(D, D->getASTContext()),
getDeclLocation(D), CDCtx.PublicOnly);
}
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index 6487d0e969065..f6b3c088425fc 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -41,18 +41,8 @@ SymbolID hashUSR(llvm::StringRef USR) {
return llvm::SHA1::hash(arrayRefFromStringRef(USR));
}
-template <typename T>
-static void
-populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
- const T *D, bool &IsAnonymousNamespace);
-
-template <typename T> static void populateMemberTypeInfo(T &I, const Decl *D);
-static void populateMemberTypeInfo(RecordInfo &I, AccessSpecifier &Access,
- const DeclaratorDecl *D,
- bool IsStatic = false);
-
-static void getTemplateParameters(const TemplateParameterList *TemplateParams,
- llvm::raw_ostream &Stream) {
+void Serializer::getTemplateParameters(
+ const TemplateParameterList *TemplateParams, llvm::raw_ostream &Stream) {
Stream << "template <";
for (unsigned i = 0; i < TemplateParams->size(); ++i) {
@@ -96,8 +86,8 @@ static void getTemplateParameters(const TemplateParameterList *TemplateParams,
// Extract the full function prototype from a FunctionDecl including
// Full Decl
-static llvm::SmallString<256>
-getFunctionPrototype(const FunctionDecl *FuncDecl) {
+llvm::SmallString<256>
+Serializer::getFunctionPrototype(const FunctionDecl *FuncDecl) {
llvm::SmallString<256> Result;
llvm::raw_svector_ostream Stream(Result);
const ASTContext &Ctx = FuncDecl->getASTContext();
@@ -167,7 +157,7 @@ getFunctionPrototype(const FunctionDecl *FuncDecl) {
return Result; // Convert SmallString to std::string for return
}
-static llvm::SmallString<16> getTypeAlias(const TypeAliasDecl *Alias) {
+llvm::SmallString<16> Serializer::getTypeAlias(const TypeAliasDecl *Alias) {
llvm::SmallString<16> Result;
llvm::raw_svector_ostream Stream(Result);
const ASTContext &Ctx = Alias->getASTContext();
@@ -193,15 +183,15 @@ static llvm::SmallString<16> getTypeAlias(const TypeAliasDecl *Alias) {
//
// }
// }
-static llvm::SmallString<128>
-getInfoRelativePath(const llvm::SmallVectorImpl<doc::Reference> &Namespaces) {
+llvm::SmallString<128> Serializer::getInfoRelativePath(
+ const llvm::SmallVectorImpl<doc::Reference> &Namespaces) {
llvm::SmallString<128> Path;
for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)
llvm::sys::path::append(Path, R->Name);
return Path;
}
-static llvm::SmallString<128> getInfoRelativePath(const Decl *D) {
+llvm::SmallString<128> Serializer::getInfoRelativePath(const Decl *D) {
llvm::SmallVector<Reference, 4> Namespaces;
// The third arg in populateParentNamespaces is a boolean passed by reference,
// its value is not relevant in here so it's not used anywhere besides the
@@ -330,7 +320,7 @@ std::string ClangDocCommentVisitor::getCommandName(unsigned CommandID) const {
// Serializing functions.
-static std::string getSourceCode(const Decl *D, const SourceRange &R) {
+std::string Serializer::getSourceCode(const Decl *D, const SourceRange &R) {
return Lexer::getSourceText(CharSourceRange::getTokenRange(R),
D->getASTContext().getSourceManager(),
D->getASTContext().getLangOpts())
@@ -368,32 +358,32 @@ std::string serialize(OwnedPtr<Info> &I, DiagnosticsEngine &Diags) {
llvm_unreachable("unhandled enumerator");
}
-static void parseFullComment(const FullComment *C, CommentInfo &CI) {
+void Serializer::parseFullComment(const FullComment *C, CommentInfo &CI) {
ClangDocCommentVisitor Visitor(CI);
Visitor.parseComment(C);
}
-static SymbolID getUSRForDecl(const Decl *D) {
+SymbolID Serializer::getUSRForDecl(const Decl *D) {
llvm::SmallString<128> USR;
if (index::generateUSRForDecl(D, USR))
return SymbolID();
return hashUSR(USR);
}
-static TagDecl *getTagDeclForType(const QualType &T) {
+TagDecl *Serializer::getTagDeclForType(const QualType &T) {
if (const TagDecl *D = T->getAsTagDecl())
return D->getDefinition();
return nullptr;
}
-static RecordDecl *getRecordDeclForType(const QualType &T) {
+RecordDecl *Serializer::getRecordDeclForType(const QualType &T) {
if (const RecordDecl *D = T->getAsRecordDecl())
return D->getDefinition();
return nullptr;
}
-static TypeInfo getTypeInfoForType(const QualType &T,
- const PrintingPolicy &Policy) {
+TypeInfo Serializer::getTypeInfoForType(const QualType &T,
+ const PrintingPolicy &Policy) {
const TagDecl *TD = getTagDeclForType(T);
if (!TD) {
TypeInfo TI = TypeInfo(Reference(SymbolID(), T.getAsString(Policy)));
@@ -417,8 +407,8 @@ static TypeInfo getTypeInfoForType(const QualType &T,
return TI;
}
-static bool isPublic(const clang::AccessSpecifier AS,
- const clang::Linkage Link) {
+bool Serializer::isPublic(const clang::AccessSpecifier AS,
+ const clang::Linkage Link) {
if (AS == clang::AccessSpecifier::AS_private)
return false;
if ((Link == clang::Linkage::Module) || (Link == clang::Linkage::External))
@@ -426,8 +416,9 @@ static bool isPublic(const clang::AccessSpecifier AS,
return false; // otherwise, linkage is some form of internal linkage
}
-static bool shouldSerializeInfo(bool PublicOnly, bool IsInAnonymousNamespace,
- const NamedDecl *D) {
+bool Serializer::shouldSerializeInfo(bool PublicOnly,
+ bool IsInAnonymousNamespace,
+ const NamedDecl *D) {
bool IsAnonymousNamespace = false;
if (const auto *N = dyn_cast<NamespaceDecl>(D))
IsAnonymousNamespace = N->isAnonymousNamespace();
@@ -442,34 +433,34 @@ static bool shouldSerializeInfo(bool PublicOnly, bool IsInAnonymousNamespace,
// refer to them.
//
// See MakeAndInsertIntoParent().
-static void InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info) {
+void Serializer::InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info) {
Scope.Namespaces.emplace_back(Info.USR, Info.Name, InfoType::IT_namespace,
Info.Name, getInfoRelativePath(Info.Namespace));
}
-static void InsertChild(ScopeChildren &Scope, const RecordInfo &Info) {
+void Serializer::InsertChild(ScopeChildren &Scope, const RecordInfo &Info) {
Scope.Records.emplace_back(Info.USR, Info.Name, InfoType::IT_record,
Info.Name, getInfoRelativePath(Info.Namespace),
Info.MangledName);
}
-static void InsertChild(ScopeChildren &Scope, EnumInfo Info) {
+void Serializer::InsertChild(ScopeChildren &Scope, EnumInfo Info) {
Scope.Enums.push_back(std::move(Info));
}
-static void InsertChild(ScopeChildren &Scope, FunctionInfo Info) {
+void Serializer::InsertChild(ScopeChildren &Scope, FunctionInfo Info) {
Scope.Functions.push_back(std::move(Info));
}
-static void InsertChild(ScopeChildren &Scope, TypedefInfo Info) {
+void Serializer::InsertChild(ScopeChildren &Scope, TypedefInfo Info) {
Scope.Typedefs.push_back(std::move(Info));
}
-static void InsertChild(ScopeChildren &Scope, ConceptInfo Info) {
+void Serializer::InsertChild(ScopeChildren &Scope, ConceptInfo Info) {
Scope.Concepts.push_back(std::move(Info));
}
-static void InsertChild(ScopeChildren &Scope, VarInfo Info) {
+void Serializer::InsertChild(ScopeChildren &Scope, VarInfo Info) {
Scope.Variables.push_back(std::move(Info));
}
@@ -488,7 +479,7 @@ static void InsertChild(ScopeChildren &Scope, VarInfo Info) {
// parameter. Since each variant is used once, it's not worth having a more
// elaborate system to automatically deduce this information.
template <typename ChildType>
-static OwnedPtr<Info> makeAndInsertIntoParent(ChildType Child) {
+OwnedPtr<Info> Serializer::makeAndInsertIntoParent(ChildType Child) {
if (Child.Namespace.empty()) {
// Insert into unnamed parent namespace.
auto ParentNS = allocatePtr<NamespaceInfo>();
@@ -536,8 +527,8 @@ static OwnedPtr<Info> makeAndInsertIntoParent(ChildType Child) {
// will be private because the inheritance is private. This is the AS that
// this function calculates. FirstAS is the inheritance mode and SecondAS is
// the AS of the attribute / method.
-static AccessSpecifier getFinalAccessSpecifier(AccessSpecifier FirstAS,
- AccessSpecifier SecondAS) {
+AccessSpecifier Serializer::getFinalAccessSpecifier(AccessSpecifier FirstAS,
+ AccessSpecifier SecondAS) {
if (FirstAS == AccessSpecifier::AS_none ||
SecondAS == AccessSpecifier::AS_none)
return AccessSpecifier::AS_none;
@@ -552,8 +543,8 @@ static AccessSpecifier getFinalAccessSpecifier(AccessSpecifier FirstAS,
// The Access parameter is only provided when parsing the field of an inherited
// record, the access specification of the field depends on the inheritance mode
-static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly,
- AccessSpecifier Access = AccessSpecifier::AS_public) {
+void Serializer::parseFields(RecordInfo &I, const RecordDecl *D,
+ bool PublicOnly, AccessSpecifier Access) {
for (const FieldDecl *F : D->fields()) {
if (!shouldSerializeInfo(PublicOnly, /*IsInAnonymousNamespace=*/false, F))
continue;
@@ -573,7 +564,7 @@ static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly,
}
}
-static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
+void Serializer::parseEnumerators(EnumInfo &I, const EnumDecl *D) {
for (const EnumConstantDecl *E : D->enumerators()) {
std::string ValueExpr;
if (const Expr *InitExpr = E->getInitExpr())
@@ -594,7 +585,7 @@ static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
}
}
-static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
+void Serializer::parseParameters(FunctionInfo &I, const FunctionDecl *D) {
auto &LO = D->getLangOpts();
for (const ParmVarDecl *P : D->parameters()) {
FieldTypeInfo &FieldInfo = I.Params.emplace_back(
@@ -605,7 +596,7 @@ static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
// TODO: Remove the serialization of Parents and VirtualParents, this
// information is also extracted in the other definition of parseBases.
-static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
+void Serializer::parseBases(RecordInfo &I, const CXXRecordDecl *D) {
// Don't parse bases if this isn't a definition.
if (!D->isThisDeclarationADefinition())
return;
@@ -635,9 +626,9 @@ static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
}
template <typename T>
-static void
-populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
- const T *D, bool &IsInAnonymousNamespace) {
+void Serializer::populateParentNamespaces(
+ llvm::SmallVector<Reference, 4> &Namespaces, const T *D,
+ bool &IsInAnonymousNamespace) {
const DeclContext *DC = D->getDeclContext();
do {
if (const auto *N = dyn_cast<NamespaceDecl>(DC)) {
@@ -672,9 +663,8 @@ populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
InfoType::IT_namespace);
}
-static void
-populateTemplateParameters(std::optional<TemplateInfo> &TemplateInfo,
- const clang::Decl *D) {
+void Serializer::populateTemplateParameters(
+ std::optional<TemplateInfo> &TemplateInfo, const clang::Decl *D) {
if (const TemplateParameterList *ParamList =
D->getDescribedTemplateParams()) {
if (!TemplateInfo) {
@@ -687,8 +677,9 @@ populateTemplateParameters(std::optional<TemplateInfo> &TemplateInfo,
}
}
-static TemplateParamInfo convertTemplateArgToInfo(const clang::Decl *D,
- const TemplateArgument &Arg) {
+TemplateParamInfo
+Serializer::convertTemplateArgToInfo(const clang::Decl *D,
+ const TemplateArgument &Arg) {
// The TemplateArgument's pretty printing handles all the normal cases
// well enough for our requirements.
std::string Str;
@@ -700,7 +691,7 @@ static TemplateParamInfo convertTemplateArgToInfo(const clang::Decl *D,
// Check if the DeclKind is one for which we support contextual relationships.
// There might be other ContextDecls, like blocks, that we currently don't
// handle at all.
-static bool isSupportedContext(Decl::Kind DeclKind) {
+bool Serializer::isSupportedContext(Decl::Kind DeclKind) {
switch (DeclKind) {
case Decl::Kind::Record:
case Decl::Kind::CXXRecord:
@@ -713,7 +704,7 @@ static bool isSupportedContext(Decl::Kind DeclKind) {
}
}
-static void findParent(Info &I, const Decl *D) {
+void Serializer::findParent(Info &I, const Decl *D) {
assert(D && "Invalid Decl");
// Only walk up contexts if D is a record or namespace.
@@ -732,8 +723,8 @@ static void findParent(Info &I, const Decl *D) {
}
template <typename T>
-static void populateInfo(Info &I, const T *D, const FullComment *C,
- bool &IsInAnonymousNamespace) {
+void Serializer::populateInfo(Info &I, const T *D, const FullComment *C,
+ bool &IsInAnonymousNamespace) {
I.USR = getUSRForDecl(D);
findParent(I, D);
@@ -752,8 +743,9 @@ static void populateInfo(Info &I, const T *D, const FullComment *C,
}
template <typename T>
-static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
- Location Loc, bool &IsInAnonymousNamespace) {
+void Serializer::populateSymbolInfo(SymbolInfo &I, const T *D,
+ const FullComment *C, Location Loc,
+ bool &IsInAnonymousNamespace) {
populateInfo(I, D, C, IsInAnonymousNamespace);
if (D->isThisDeclarationADefinition())
I.DefLoc = Loc;
@@ -778,9 +770,8 @@ static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
delete Mangler;
}
-static void
-handleCompoundConstraints(const Expr *Constraint,
- OwningVec<ConstraintInfo> &ConstraintInfos) {
+void Serializer::handleCompoundConstraints(
+ const Expr *Constraint, OwningVec<ConstraintInfo> &ConstraintInfos) {
if (Constraint->getStmtClass() == Stmt::ParenExprClass) {
handleCompoundConstraints(dyn_cast<ParenExpr>(Constraint)->getSubExpr(),
ConstraintInfos);
@@ -798,7 +789,7 @@ handleCompoundConstraints(const Expr *Constraint,
}
}
-static void populateConstraints(TemplateInfo &I, const TemplateDecl *D) {
+void Serializer::populateConstraints(TemplateInfo &I, const TemplateDecl *D) {
if (!D || !D->hasAssociatedConstraints())
return;
@@ -822,9 +813,9 @@ static void populateConstraints(TemplateInfo &I, const TemplateDecl *D) {
}
}
-static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
- const FullComment *FC, Location Loc,
- bool &IsInAnonymousNamespace) {
+void Serializer::populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
+ const FullComment *FC, Location Loc,
+ bool &IsInAnonymousNamespace) {
populateSymbolInfo(I, D, FC, Loc, IsInAnonymousNamespace);
auto &LO = D->getLangOpts();
I.ReturnType = getTypeInfoForType(D->getReturnType(), LO);
@@ -857,7 +848,8 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
// TODO: Rename this, since this doesn't populate anything besides comments and
// isn't exclusive to members
-template <typename T> static void populateMemberTypeInfo(T &I, const Decl *D) {
+template <typename T>
+void Serializer::populateMemberTypeInfo(T &I, const Decl *D) {
assert(D && "Expect non-null FieldDecl in populateMemberTypeInfo");
ASTContext &Context = D->getASTContext();
@@ -874,8 +866,9 @@ template <typename T> static void populateMemberTypeInfo(T &I, const Decl *D) {
}
}
-static void populateMemberTypeInfo(RecordInfo &I, AccessSpecifier &Access,
- const DeclaratorDecl *D, bool IsStatic) {
+void Serializer::populateMemberTypeInfo(RecordInfo &I, AccessSpecifier &Access,
+ const DeclaratorDecl *D,
+ bool IsStatic) {
// Use getAccessUnsafe so that we just get the default AS_none if it's not
// valid, as opposed to an assert.
MemberTypeInfo &NewMember = I.Members.emplace_back(
@@ -885,10 +878,9 @@ static void populateMemberTypeInfo(RecordInfo &I, AccessSpecifier &Access,
populateMemberTypeInfo(NewMember, D);
}
-static void
-parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir,
- bool PublicOnly, bool IsParent,
- AccessSpecifier ParentAccess = AccessSpecifier::AS_public) {
+void Serializer::parseBases(RecordInfo &I, const CXXRecordDecl *D,
+ bool IsFileInRootDir, bool PublicOnly,
+ bool IsParent, AccessSpecifier ParentAccess) {
// Don't parse bases if this isn't a definition.
if (!D->isThisDeclarationADefinition())
return;
@@ -940,10 +932,9 @@ parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir,
}
}
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const NamespaceDecl *D,
- const FullComment *FC,
- Location Loc,
- bool PublicOnly) {
+std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
+Serializer::emitInfo(const NamespaceDecl *D, const FullComment *FC,
+ Location Loc, bool PublicOnly) {
auto NSI = allocatePtr<NamespaceInfo>();
bool IsInAnonymousNamespace = false;
populateInfo(*NSI, D, FC, IsInAnonymousNamespace);
@@ -962,7 +953,7 @@ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const NamespaceDecl *D,
return {std::move(NSI), makeAndInsertIntoParent<const NamespaceInfo &>(*NSI)};
}
-static void parseFriends(RecordInfo &RI, const CXXRecordDecl *D) {
+void Serializer::parseFriends(RecordInfo &RI, const CXXRecordDecl *D) {
if (!D->hasDefinition() || !D->hasFriends())
return;
@@ -1012,10 +1003,9 @@ static void parseFriends(RecordInfo &RI, const CXXRecordDecl *D) {
}
}
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const RecordDecl *D,
- const FullComment *FC,
- Location Loc,
- bool PublicOnly) {
+std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
+Serializer::emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
+ bool PublicOnly) {
auto RI = allocatePtr<RecordInfo>();
bool IsInAnonymousNamespace = false;
@@ -1085,10 +1075,9 @@ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const RecordDecl *D,
return {std::move(RI), std::move(Parent)};
}
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const FunctionDecl *D,
- const FullComment *FC,
- Location Loc,
- bool PublicOnly) {
+std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
+Serializer::emitInfo(const FunctionDecl *D, const FullComment *FC, Location Loc,
+ bool PublicOnly) {
FunctionInfo Func;
bool IsInAnonymousNamespace = false;
populateFunctionInfo(Func, D, FC, Loc, IsInAnonymousNamespace);
@@ -1100,10 +1089,9 @@ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const FunctionDecl *D,
return {nullptr, makeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))};
}
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const CXXMethodDecl *D,
- const FullComment *FC,
- Location Loc,
- bool PublicOnly) {
+std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
+Serializer::emitInfo(const CXXMethodDecl *D, const FullComment *FC,
+ Location Loc, bool PublicOnly) {
FunctionInfo Func;
bool IsInAnonymousNamespace = false;
populateFunctionInfo(Func, D, FC, Loc, IsInAnonymousNamespace);
@@ -1130,7 +1118,7 @@ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const CXXMethodDecl *D,
return {nullptr, makeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))};
}
-static void extractCommentFromDecl(const Decl *D, TypedefInfo &Info) {
+void Serializer::extractCommentFromDecl(const Decl *D, TypedefInfo &Info) {
assert(D && "Invalid Decl when extracting comment");
ASTContext &Context = D->getASTContext();
RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
@@ -1144,10 +1132,9 @@ static void extractCommentFromDecl(const Decl *D, TypedefInfo &Info) {
}
}
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const TypedefDecl *D,
- const FullComment *FC,
- Location Loc,
- bool PublicOnly) {
+std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
+Serializer::emitInfo(const TypedefDecl *D, const FullComment *FC, Location Loc,
+ bool PublicOnly) {
TypedefInfo Info;
bool IsInAnonymousNamespace = false;
populateInfo(Info, D, FC, IsInAnonymousNamespace);
@@ -1177,10 +1164,9 @@ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const TypedefDecl *D,
// A type alias is a C++ "using" declaration for a type. It gets mapped to a
// TypedefInfo with the IsUsing flag set.
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const TypeAliasDecl *D,
- const FullComment *FC,
- Location Loc,
- bool PublicOnly) {
+std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
+Serializer::emitInfo(const TypeAliasDecl *D, const FullComment *FC,
+ Location Loc, bool PublicOnly) {
TypedefInfo Info;
bool IsInAnonymousNamespace = false;
populateInfo(Info, D, FC, IsInAnonymousNamespace);
@@ -1202,10 +1188,9 @@ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const TypeAliasDecl *D,
return {nullptr, makeAndInsertIntoParent<TypedefInfo &&>(std::move(Info))};
}
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const EnumDecl *D,
- const FullComment *FC,
- Location Loc,
- bool PublicOnly) {
+std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
+Serializer::emitInfo(const EnumDecl *D, const FullComment *FC, Location Loc,
+ bool PublicOnly) {
EnumInfo Enum;
bool IsInAnonymousNamespace = false;
populateSymbolInfo(Enum, D, FC, Loc, IsInAnonymousNamespace);
@@ -1224,10 +1209,9 @@ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const EnumDecl *D,
return {nullptr, makeAndInsertIntoParent<EnumInfo &&>(std::move(Enum))};
}
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const ConceptDecl *D,
- const FullComment *FC,
- const Location &Loc,
- bool PublicOnly) {
+std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
+Serializer::emitInfo(const ConceptDecl *D, const FullComment *FC,
+ const Location &Loc, bool PublicOnly) {
ConceptInfo Concept;
bool IsInAnonymousNamespace = false;
@@ -1249,10 +1233,9 @@ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const ConceptDecl *D,
return {nullptr, makeAndInsertIntoParent<ConceptInfo &&>(std::move(Concept))};
}
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const VarDecl *D,
- const FullComment *FC,
- const Location &Loc,
- bool PublicOnly) {
+std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
+Serializer::emitInfo(const VarDecl *D, const FullComment *FC,
+ const Location &Loc, bool PublicOnly) {
VarInfo Var;
bool IsInAnonymousNamespace = false;
populateSymbolInfo(Var, D, FC, Loc, IsInAnonymousNamespace);
diff --git a/clang-tools-extra/clang-doc/Serialize.h b/clang-tools-extra/clang-doc/Serialize.h
index 4a27927d568f1..e6b1e6954279c 100644
--- a/clang-tools-extra/clang-doc/Serialize.h
+++ b/clang-tools-extra/clang-doc/Serialize.h
@@ -33,54 +33,156 @@ namespace serialize {
// EnumDecl, FunctionDecl and CXXMethodDecl; they are only returned wrapped in
// its parent scope. For NamespaceDecl and RecordDecl both elements are not
// nullptr.
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const NamespaceDecl *D,
- const FullComment *FC,
- Location Loc,
- bool PublicOnly);
-
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const RecordDecl *D,
- const FullComment *FC,
- Location Loc,
- bool PublicOnly);
-
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const EnumDecl *D,
- const FullComment *FC,
- Location Loc,
- bool PublicOnly);
-
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const FunctionDecl *D,
- const FullComment *FC,
- Location Loc,
- bool PublicOnly);
-
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
-emitInfo(const VarDecl *D, const FullComment *FC, int LineNumber,
- StringRef File, bool IsFileInRootDir, bool PublicOnly);
-
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const CXXMethodDecl *D,
- const FullComment *FC,
- Location Loc,
- bool PublicOnly);
-
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const TypedefDecl *D,
- const FullComment *FC,
- Location Loc,
- bool PublicOnly);
-
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const TypeAliasDecl *D,
- const FullComment *FC,
- Location Loc,
- bool PublicOnly);
-
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const ConceptDecl *D,
- const FullComment *FC,
- const Location &Loc,
- bool PublicOnly);
-
-std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const VarDecl *D,
- const FullComment *FC,
- const Location &Loc,
- bool PublicOnly);
+class Serializer {
+public:
+ Serializer() = default;
+
+ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const NamespaceDecl *D,
+ const FullComment *FC,
+ Location Loc,
+ bool PublicOnly);
+
+ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const RecordDecl *D,
+ const FullComment *FC,
+ Location Loc,
+ bool PublicOnly);
+
+ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const EnumDecl *D,
+ const FullComment *FC,
+ Location Loc,
+ bool PublicOnly);
+
+ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const FunctionDecl *D,
+ const FullComment *FC,
+ Location Loc,
+ bool PublicOnly);
+
+ std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
+ emitInfo(const VarDecl *D, const FullComment *FC, int LineNumber,
+ StringRef File, bool IsFileInRootDir, bool PublicOnly);
+
+ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const CXXMethodDecl *D,
+ const FullComment *FC,
+ Location Loc,
+ bool PublicOnly);
+
+ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const TypedefDecl *D,
+ const FullComment *FC,
+ Location Loc,
+ bool PublicOnly);
+
+ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const TypeAliasDecl *D,
+ const FullComment *FC,
+ Location Loc,
+ bool PublicOnly);
+
+ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const ConceptDecl *D,
+ const FullComment *FC,
+ const Location &Loc,
+ bool PublicOnly);
+
+ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const VarDecl *D,
+ const FullComment *FC,
+ const Location &Loc,
+ bool PublicOnly);
+
+private:
+ void getTemplateParameters(const TemplateParameterList *TemplateParams,
+ llvm::raw_ostream &Stream);
+
+ llvm::SmallString<256> getFunctionPrototype(const FunctionDecl *FuncDecl);
+
+ llvm::SmallString<16> getTypeAlias(const TypeAliasDecl *Alias);
+
+ llvm::SmallString<128>
+ getInfoRelativePath(const llvm::SmallVectorImpl<doc::Reference> &Namespaces);
+
+ llvm::SmallString<128> getInfoRelativePath(const Decl *D);
+
+ std::string getSourceCode(const Decl *D, const SourceRange &R);
+
+ void parseFullComment(const FullComment *C, CommentInfo &CI);
+
+ SymbolID getUSRForDecl(const Decl *D);
+
+ TagDecl *getTagDeclForType(const QualType &T);
+
+ RecordDecl *getRecordDeclForType(const QualType &T);
+
+ TypeInfo getTypeInfoForType(const QualType &T, const PrintingPolicy &Policy);
+
+ bool isPublic(const clang::AccessSpecifier AS, const clang::Linkage Link);
+
+ bool shouldSerializeInfo(bool PublicOnly, bool IsInAnonymousNamespace,
+ const NamedDecl *D);
+
+ void InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info);
+ void InsertChild(ScopeChildren &Scope, const RecordInfo &Info);
+ void InsertChild(ScopeChildren &Scope, EnumInfo Info);
+ void InsertChild(ScopeChildren &Scope, FunctionInfo Info);
+ void InsertChild(ScopeChildren &Scope, TypedefInfo Info);
+ void InsertChild(ScopeChildren &Scope, ConceptInfo Info);
+ void InsertChild(ScopeChildren &Scope, VarInfo Info);
+
+ template <typename ChildType>
+ OwnedPtr<Info> makeAndInsertIntoParent(ChildType Child);
+
+ AccessSpecifier getFinalAccessSpecifier(AccessSpecifier FirstAS,
+ AccessSpecifier SecondAS);
+
+ void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly,
+ AccessSpecifier Access = AccessSpecifier::AS_public);
+
+ void parseEnumerators(EnumInfo &I, const EnumDecl *D);
+
+ void parseParameters(FunctionInfo &I, const FunctionDecl *D);
+
+ void parseBases(RecordInfo &I, const CXXRecordDecl *D);
+
+ void parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir,
+ bool PublicOnly, bool IsParent,
+ AccessSpecifier ParentAccess = AccessSpecifier::AS_public);
+
+ template <typename T>
+ void populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
+ const T *D, bool &IsInAnonymousNamespace);
+
+ void populateTemplateParameters(std::optional<TemplateInfo> &TemplateInfo,
+ const clang::Decl *D);
+
+ TemplateParamInfo convertTemplateArgToInfo(const clang::Decl *D,
+ const TemplateArgument &Arg);
+
+ bool isSupportedContext(Decl::Kind DeclKind);
+
+ void findParent(Info &I, const Decl *D);
+
+ template <typename T>
+ void populateInfo(Info &I, const T *D, const FullComment *C,
+ bool &IsInAnonymousNamespace);
+
+ template <typename T>
+ void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
+ Location Loc, bool &IsInAnonymousNamespace);
+
+ void handleCompoundConstraints(const Expr *Constraint,
+ OwningVec<ConstraintInfo> &ConstraintInfos);
+
+ void populateConstraints(TemplateInfo &I, const TemplateDecl *D);
+
+ void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
+ const FullComment *FC, Location Loc,
+ bool &IsInAnonymousNamespace);
+
+ template <typename T> void populateMemberTypeInfo(T &I, const Decl *D);
+
+ void populateMemberTypeInfo(RecordInfo &I, AccessSpecifier &Access,
+ const DeclaratorDecl *D, bool IsStatic = false);
+
+ void parseFriends(RecordInfo &RI, const CXXRecordDecl *D);
+
+ void extractCommentFromDecl(const Decl *D, TypedefInfo &Info);
+};
// Function to hash a given USR value for storage.
// As USRs (Unified Symbol Resolution) could be large, especially for functions
diff --git a/clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp b/clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp
index be11cc80198e8..87cf08116c6d4 100644
--- a/clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp
+++ b/clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp
@@ -60,7 +60,8 @@ static void BM_EmitInfoFunction(benchmark::State &State) {
Location Loc;
for (auto _ : State) {
- auto Result = serialize::emitInfo(Func, FC, Loc, /*PublicOnly=*/false);
+ serialize::ClangDocSerializer Serializer;
+ auto Result = Serializer.emitInfo(Func, FC, Loc, /*PublicOnly=*/false);
benchmark::DoNotOptimize(Result);
}
}
diff --git a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
index 33fb0e634564b..5612e55343382 100644
--- a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
@@ -40,7 +40,8 @@ class ClangDocSerializeTestVisitor
template <typename T> bool mapDecl(const T *D) {
Location Loc(0, 0, "test.cpp");
- auto [Child, Parent] = serialize::emitInfo(D, getComment(D), Loc, Public);
+ serialize::Serializer S;
+ auto [Child, Parent] = S.emitInfo(D, getComment(D), Loc, Public);
if (Child)
EmittedInfos.emplace_back(std::move(Child));
if (Parent)
More information about the cfe-commits
mailing list