[llvm-branch-commits] [clang-tools-extra] [clang-doc] Introduce abstractions for pointer operations (PR #184872)

Paul Kirth via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Mar 6 14:49:19 PST 2026


https://github.com/ilovepi updated https://github.com/llvm/llvm-project/pull/184872

>From 00571fb58b05fcb517d88e9d311119383ebc629e Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Thu, 5 Mar 2026 00:28:30 +0000
Subject: [PATCH] [clang-doc] Introduce abstractions for pointer operations

Since we're migrating from std::unique_ptr to raw pointers via
arena allocation, we want to have some interfaces that abstract
these operations away, and can be changed to keep the system working
without introducing a lot of unnecessary chrun in the code.
---
 clang-tools-extra/clang-doc/BitcodeReader.cpp |  8 +++----
 clang-tools-extra/clang-doc/JSONGenerator.cpp |  2 +-
 clang-tools-extra/clang-doc/MDGenerator.cpp   |  2 +-
 .../clang-doc/Representation.cpp              |  6 ++---
 clang-tools-extra/clang-doc/Representation.h  | 11 +++++++++
 clang-tools-extra/clang-doc/Serialize.cpp     | 24 +++++++++----------
 clang-tools-extra/clang-doc/YAMLGenerator.cpp |  2 +-
 .../benchmarks/ClangDocBenchmark.cpp          |  8 +++----
 .../clang-doc/tool/ClangDocMain.cpp           |  6 ++---
 9 files changed, 40 insertions(+), 29 deletions(-)

diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp
index 6cd0cb06871de..1589e20064889 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -507,8 +507,8 @@ template <> llvm::Expected<CommentInfo *> getCommentInfo(EnumValueInfo *I) {
 }
 
 template <> llvm::Expected<CommentInfo *> getCommentInfo(CommentInfo *I) {
-  I->Children.emplace_back(std::make_unique<CommentInfo>());
-  return I->Children.back().get();
+  I->Children.emplace_back(allocatePtr<CommentInfo>());
+  return getPtr(I->Children.back());
 }
 
 template <> llvm::Expected<CommentInfo *> getCommentInfo(ConceptInfo *I) {
@@ -1078,8 +1078,8 @@ llvm::Error ClangDocBitcodeReader::readBlockInfoBlock() {
 template <typename T>
 llvm::Expected<OwnedPtr<Info>> ClangDocBitcodeReader::createInfo(unsigned ID) {
   llvm::TimeTraceScope("Reducing infos", "createInfo");
-  OwnedPtr<Info> I = std::make_unique<T>();
-  if (auto Err = readBlock(ID, static_cast<T *>(I.get())))
+  OwnedPtr<Info> I = doc::allocatePtr<T>();
+  if (auto Err = readBlock(ID, static_cast<T *>(getPtr(I))))
     return std::move(Err);
   return OwnedPtr<Info>{std::move(I)};
 }
diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp
index efdff7f5b2cb1..05ff399f4cebb 100644
--- a/clang-tools-extra/clang-doc/JSONGenerator.cpp
+++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp
@@ -953,7 +953,7 @@ Error JSONGenerator::generateDocumentation(
   StringSet<> CreatedDirs;
   StringMap<std::vector<doc::Info *>> FileToInfos;
   for (const auto &Group : Infos) {
-    Info *Info = Group.getValue().get();
+    Info *Info = getPtr(Group.getValue());
 
     SmallString<128> Path;
     auto RootDirStr = RootDir.str() + "/json";
diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp b/clang-tools-extra/clang-doc/MDGenerator.cpp
index c72dd11bc9df8..172ec9b524db8 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -423,7 +423,7 @@ llvm::Error MDGenerator::generateDocumentation(
   // Collect all output by file name and create the necessary directories.
   llvm::StringMap<std::vector<doc::Info *>> FileToInfos;
   for (const auto &Group : Infos) {
-    doc::Info *Info = Group.getValue().get();
+    doc::Info *Info = getPtr(Group.getValue());
 
     llvm::SmallString<128> Path;
     llvm::sys::path::native(RootDir, Path);
diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp
index c9bfd419d622b..a8b221f94f4b9 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -89,10 +89,10 @@ static llvm::Expected<OwnedPtr<Info>> reduce(OwningPtrArray<Info> &Values) {
   if (Values.empty() || !Values[0])
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                    "no value to reduce");
-  OwnedPtr<Info> Merged = std::make_unique<T>(Values[0]->USR);
-  T *Tmp = static_cast<T *>(Merged.get());
+  OwnedPtr<Info> Merged = allocatePtr<T>(Values[0]->USR);
+  T *Tmp = static_cast<T *>(getPtr(Merged));
   for (auto &I : Values)
-    Tmp->merge(std::move(*static_cast<T *>(I.get())));
+    Tmp->merge(std::move(*static_cast<T *>(getPtr(I))));
   return std::move(Merged);
 }
 
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index 6cae3c017d583..b09ee6dd7b36d 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -48,6 +48,17 @@ template <typename T> using OwningPtrVec = std::vector<OwnedPtr<T>>;
 // To be eventually transitioned to arena-allocated arrays of bare pointers.
 template <typename T> using OwningPtrArray = std::vector<OwnedPtr<T>>;
 
+// A helper function to create an owned pointer, abstracting away the memory
+// allocation mechanism.
+template <typename T, typename... Args>
+OwnedPtr<T> allocatePtr(Args &&...args) {
+  return std::make_unique<T>(std::forward<Args>(args)...);
+}
+
+// A helper function to access the underlying pointer from an owned pointer,
+// abstracting away the pointer dereferencing mechanism.
+template <typename T> T *getPtr(const OwnedPtr<T> &O) { return O.get(); }
+
 // SHA1'd hash of a USR.
 using SymbolID = std::array<uint8_t, 20>;
 
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index afd2ffd391ba9..b6e963bd5fd74 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -241,7 +241,7 @@ void ClangDocCommentVisitor::parseComment(const comments::Comment *C) {
   ConstCommentVisitor<ClangDocCommentVisitor>::visit(C);
   for (comments::Comment *Child :
        llvm::make_range(C->child_begin(), C->child_end())) {
-    CurrentCI.Children.emplace_back(std::make_unique<CommentInfo>());
+    CurrentCI.Children.emplace_back(allocatePtr<CommentInfo>());
     ClangDocCommentVisitor Visitor(*CurrentCI.Children.back());
     Visitor.parseComment(Child);
   }
@@ -349,17 +349,17 @@ static std::string serialize(T &I, DiagnosticsEngine &Diags) {
 std::string serialize(OwnedPtr<Info> &I, DiagnosticsEngine &Diags) {
   switch (I->IT) {
   case InfoType::IT_namespace:
-    return serialize(*static_cast<NamespaceInfo *>(I.get()), Diags);
+    return serialize(*static_cast<NamespaceInfo *>(getPtr(I)), Diags);
   case InfoType::IT_record:
-    return serialize(*static_cast<RecordInfo *>(I.get()), Diags);
+    return serialize(*static_cast<RecordInfo *>(getPtr(I)), Diags);
   case InfoType::IT_enum:
-    return serialize(*static_cast<EnumInfo *>(I.get()), Diags);
+    return serialize(*static_cast<EnumInfo *>(getPtr(I)), Diags);
   case InfoType::IT_function:
-    return serialize(*static_cast<FunctionInfo *>(I.get()), Diags);
+    return serialize(*static_cast<FunctionInfo *>(getPtr(I)), Diags);
   case InfoType::IT_concept:
-    return serialize(*static_cast<ConceptInfo *>(I.get()), Diags);
+    return serialize(*static_cast<ConceptInfo *>(getPtr(I)), Diags);
   case InfoType::IT_variable:
-    return serialize(*static_cast<VarInfo *>(I.get()), Diags);
+    return serialize(*static_cast<VarInfo *>(getPtr(I)), Diags);
   case InfoType::IT_friend:
   case InfoType::IT_typedef:
   case InfoType::IT_default:
@@ -491,20 +491,20 @@ template <typename ChildType>
 static OwnedPtr<Info> makeAndInsertIntoParent(ChildType Child) {
   if (Child.Namespace.empty()) {
     // Insert into unnamed parent namespace.
-    auto ParentNS = std::make_unique<NamespaceInfo>();
+    auto ParentNS = allocatePtr<NamespaceInfo>();
     InsertChild(ParentNS->Children, std::forward<ChildType>(Child));
     return ParentNS;
   }
 
   switch (Child.Namespace[0].RefType) {
   case InfoType::IT_namespace: {
-    auto ParentNS = std::make_unique<NamespaceInfo>();
+    auto ParentNS = allocatePtr<NamespaceInfo>();
     ParentNS->USR = Child.Namespace[0].USR;
     InsertChild(ParentNS->Children, std::forward<ChildType>(Child));
     return ParentNS;
   }
   case InfoType::IT_record: {
-    auto ParentRec = std::make_unique<RecordInfo>();
+    auto ParentRec = allocatePtr<RecordInfo>();
     ParentRec->USR = Child.Namespace[0].USR;
     InsertChild(ParentRec->Children, std::forward<ChildType>(Child));
     return ParentRec;
@@ -944,7 +944,7 @@ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const NamespaceDecl *D,
                                                    const FullComment *FC,
                                                    Location Loc,
                                                    bool PublicOnly) {
-  auto NSI = std::make_unique<NamespaceInfo>();
+  auto NSI = allocatePtr<NamespaceInfo>();
   bool IsInAnonymousNamespace = false;
   populateInfo(*NSI, D, FC, IsInAnonymousNamespace);
   if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
@@ -1017,7 +1017,7 @@ std::pair<OwnedPtr<Info>, OwnedPtr<Info>> emitInfo(const RecordDecl *D,
                                                    Location Loc,
                                                    bool PublicOnly) {
 
-  auto RI = std::make_unique<RecordInfo>();
+  auto RI = allocatePtr<RecordInfo>();
   bool IsInAnonymousNamespace = false;
 
   populateSymbolInfo(*RI, D, FC, Loc, IsInAnonymousNamespace);
diff --git a/clang-tools-extra/clang-doc/YAMLGenerator.cpp b/clang-tools-extra/clang-doc/YAMLGenerator.cpp
index ac2ef1d61e4f8..72e68b2c64206 100644
--- a/clang-tools-extra/clang-doc/YAMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/YAMLGenerator.cpp
@@ -358,7 +358,7 @@ llvm::Error YAMLGenerator::generateDocumentation(
     StringRef RootDir, llvm::StringMap<doc::OwnedPtr<doc::Info>> Infos,
     const ClangDocContext &CDCtx, std::string DirName) {
   for (const auto &Group : Infos) {
-    doc::Info *Info = Group.getValue().get();
+    doc::Info *Info = getPtr(Group.getValue());
 
     // Output file names according to the USR except the global namesapce.
     // Anonymous namespaces are taken care of in serialization, so here we can
diff --git a/clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp b/clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp
index 18e15de8129a1..be11cc80198e8 100644
--- a/clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp
+++ b/clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp
@@ -91,7 +91,7 @@ BENCHMARK(BM_Mapper_Scale)->Range(10, 10000);
 // --- Reducer Benchmarks ---
 
 static void BM_SerializeFunctionInfo(benchmark::State &State) {
-  auto I = std::make_unique<FunctionInfo>();
+  auto I = allocatePtr<FunctionInfo>();
   I->Name = "f";
   I->DefLoc = Location(0, 0, "test.cpp");
   I->ReturnType = TypeInfo("void");
@@ -119,7 +119,7 @@ static void BM_MergeInfos_Scale(benchmark::State &State) {
     OwningPtrArray<Info> Input;
     Input.reserve(State.range(0));
     for (int i = 0; i < State.range(0); ++i) {
-      auto I = std::make_unique<FunctionInfo>();
+      auto I = allocatePtr<FunctionInfo>();
       I->Name = "f";
       I->USR = USR;
       I->DefLoc = Location(10, i, "test.cpp");
@@ -181,7 +181,7 @@ static void BM_JSONGenerator_Scale(benchmark::State &State) {
   }
 
   int NumRecords = State.range(0);
-  auto NI = std::make_unique<NamespaceInfo>();
+  auto NI = allocatePtr<NamespaceInfo>();
   NI->Name = "GlobalNamespace";
   for (int i = 0; i < NumRecords; ++i) {
     NI->Children.Records.emplace_back(SymbolID{(uint8_t)(i & 0xFF)},
@@ -200,7 +200,7 @@ static void BM_JSONGenerator_Scale(benchmark::State &State) {
 
   for (auto _ : State) {
     Output.clear();
-    auto Err = (*G)->generateDocForInfo(NI.get(), OS, CDCtx);
+    auto Err = (*G)->generateDocForInfo(getPtr(NI), OS, CDCtx);
     if (Err) {
       State.SkipWithError("generateDocForInfo failed");
       llvm::consumeError(std::move(Err));
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index c189a414324c8..8ea1aa4b9e89f 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -228,11 +228,11 @@ sortUsrToInfo(llvm::StringMap<doc::OwnedPtr<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.get());
+      auto *Namespace = static_cast<clang::doc::NamespaceInfo *>(getPtr(Info));
       Namespace->Children.sort();
     }
     if (Info->IT == doc::InfoType::IT_record) {
-      auto *Record = static_cast<clang::doc::RecordInfo *>(Info.get());
+      auto *Record = static_cast<clang::doc::RecordInfo *>(getPtr(Info));
       Record->Children.sort();
     }
   }
@@ -400,7 +400,7 @@ Example usage for a project using a compile commands database:
           {
             llvm::TimeTraceScope Merge("addInfoToIndex");
             std::lock_guard<llvm::sys::Mutex> Guard(IndexMutex);
-            clang::doc::Generator::addInfoToIndex(CDCtx.Idx, Reduced.get());
+            clang::doc::Generator::addInfoToIndex(CDCtx.Idx, getPtr(Reduced));
           }
           // Save in the result map (needs a lock due to threaded access).
           {



More information about the llvm-branch-commits mailing list