[clang-tools-extra] 22e6a26 - Revert clang-doc arena merging patches (#191668)

via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 13 08:40:46 PDT 2026


Author: Paul Kirth
Date: 2026-04-13T15:40:40Z
New Revision: 22e6a261fae1eb57105cc131592026701f283e0e

URL: https://github.com/llvm/llvm-project/commit/22e6a261fae1eb57105cc131592026701f283e0e
DIFF: https://github.com/llvm/llvm-project/commit/22e6a261fae1eb57105cc131592026701f283e0e.diff

LOG: Revert clang-doc arena merging patches (#191668)

This is a set of squashed reverts of recent clang doc patches, since its
breaking something on Darwin builders:
https://lab.llvm.org/buildbot/#/builders/23/builds/19172

Revert "[clang-doc][nfc] Default initialize all StringRef members
(#191641)"

This reverts commit 155b9b354c1d91661be9f6d0432a96e47cfc2700.

Revert "[clang-doc] Initialize StringRef members in Info types
(#191637)"

This reverts commit 489dab3827b255d21ea38b1e3f45ddb08bd10a87.

Revert "[clang-doc] Initialize member variable (#191570)"

This reverts commit 5d64a44a84af31f9e99d42cccffa4f01c0be2e0b.

Revert "[clang-doc] Merge data into persistent memory (#190056)"

This reverts commit 21e0034c69489eff3b09929e5e13ea34b3dd0e5a.

Revert "[clang-doc] Support deep copy between arenas for merging
(#190055)"

This reverts commit c70dae8b0cee46af1411bc4e4ba6fc28e2babf3e.

Added: 
    

Modified: 
    clang-tools-extra/clang-doc/BitcodeReader.cpp
    clang-tools-extra/clang-doc/BitcodeReader.h
    clang-tools-extra/clang-doc/JSONGenerator.cpp
    clang-tools-extra/clang-doc/MDGenerator.cpp
    clang-tools-extra/clang-doc/Mapper.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/Serialize.h
    clang-tools-extra/clang-doc/YAMLGenerator.cpp
    clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp
    clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
    clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
    clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
    clang-tools-extra/unittests/clang-doc/ClangDocTest.h
    clang-tools-extra/unittests/clang-doc/GeneratorTest.cpp
    clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp
    clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
    clang-tools-extra/unittests/clang-doc/MergeTest.cpp
    clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
    clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp
index c5e848ae4c28d..b7f4d6aa7ba23 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -129,15 +129,14 @@ static llvm::Error decodeRecord(const Record &R, FieldId &Field,
                                  "invalid value for FieldId");
 }
 
-static llvm::Error decodeRecord(const Record &R, OwningVec<Location> &Field,
+static llvm::Error decodeRecord(const Record &R,
+                                llvm::SmallVectorImpl<Location> &Field,
                                 llvm::StringRef Blob) {
   if (R[0] > INT_MAX)
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                    "integer too large to parse");
-
-  Field.push_back(*allocatePtr<Location>(static_cast<int>(R[0]),
-                                         static_cast<int>(R[1]), Blob,
-                                         static_cast<bool>(R[2])));
+  Field.emplace_back(static_cast<int>(R[0]), static_cast<int>(R[1]), Blob,
+                     static_cast<bool>(R[2]));
   return llvm::Error::success();
 }
 
@@ -426,99 +425,6 @@ ClangDocBitcodeReader::parseBlock(unsigned ID, T I, BlockBeginHandler &&BBH,
   }
 }
 
-template <typename T, typename BlockBeginHandler, typename BlockEndHandler>
-llvm::Error ClangDocBitcodeReader::parseBlock(unsigned ID, T I,
-                                              BlockBeginHandler &&BBH,
-                                              BlockEndHandler &&BEH) {
-  return parseBlock(ID, I, std::forward<BlockBeginHandler>(BBH),
-                    std::forward<BlockEndHandler>(BEH),
-                    [&](unsigned Code) { return readRecord(Code, I); });
-}
-
-template <typename ChildType>
-llvm::Expected<bool> ClangDocBitcodeReader::readSubBlockIfMatch(
-    unsigned ID, unsigned TargetID, llvm::SmallVectorImpl<ChildType> &V) {
-  if (ID != TargetID)
-    return false;
-  ChildType Val;
-  if (auto Err = readBlock(ID, &Val))
-    return std::move(Err);
-  V.push_back(std::move(Val));
-  return true;
-}
-
-template <typename T>
-static llvm::Error addReference(T I, Reference &&R, FieldId F);
-
-template <> llvm::Error addReference(VarInfo *I, Reference &&R, FieldId F);
-template <> llvm::Error addReference(TypeInfo *I, Reference &&R, FieldId F);
-template <>
-llvm::Error addReference(FieldTypeInfo *I, Reference &&R, FieldId F);
-template <>
-llvm::Error addReference(MemberTypeInfo *I, Reference &&R, FieldId F);
-template <> llvm::Error addReference(EnumInfo *I, Reference &&R, FieldId F);
-template <> llvm::Error addReference(TypedefInfo *I, Reference &&R, FieldId F);
-template <>
-llvm::Error addReference(NamespaceInfo *I, Reference &&R, FieldId F);
-template <> llvm::Error addReference(FunctionInfo *I, Reference &&R, FieldId F);
-template <> llvm::Error addReference(RecordInfo *I, Reference &&R, FieldId F);
-template <>
-llvm::Error addReference(ConstraintInfo *I, Reference &&R, FieldId F);
-template <>
-llvm::Error addReference(FriendInfo *Friend, Reference &&R, FieldId F);
-
-template <typename InfoT>
-llvm::Expected<bool> ClangDocBitcodeReader::routeReferenceBlock(
-    unsigned ID, llvm::SmallVectorImpl<Reference> &Namespaces, InfoT *I,
-    std::initializer_list<ReferenceMap> Mappings) {
-  if (ID != BI_REFERENCE_BLOCK_ID)
-    return false;
-  Reference R;
-  if (auto Err = readBlock(ID, &R))
-    return std::move(Err);
-
-  for (const auto &Map : Mappings) {
-    if (CurrentReferenceField == Map.Field) {
-      Map.Vec->push_back(std::move(R));
-      return true;
-    }
-  }
-
-  if (CurrentReferenceField == FieldId::F_namespace) {
-    Namespaces.push_back(std::move(R));
-    return true;
-  }
-
-  if (auto Err = addReference(I, std::move(R), CurrentReferenceField))
-    return std::move(Err);
-
-  return true;
-}
-
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, CommentInfo *I);
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, FunctionInfo *I);
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, EnumInfo *I);
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, BaseRecordInfo *I);
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, RecordInfo *I);
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, TemplateInfo *I);
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID,
-                                             TemplateSpecializationInfo *I);
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, VarInfo *I);
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, TypedefInfo *I);
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, NamespaceInfo *I);
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, FriendInfo *I);
-
 template <>
 llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, CommentInfo *I) {
   llvm::SmallVector<CommentInfo> LocalChildren;
@@ -542,13 +448,25 @@ llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, CommentInfo *I) {
         if (!LocalChildren.empty())
           I->Children =
               allocateArray<CommentInfo>(LocalChildren, TransientArena);
-        if (!AttrKeys.empty())
-          I->AttrKeys = allocateArray(AttrKeys, TransientArena);
-        if (!AttrValues.empty())
-          I->AttrValues = allocateArray(AttrValues, TransientArena);
-        if (!Args.empty())
-          I->Args = allocateArray(Args, TransientArena);
-
+        if (!AttrKeys.empty()) {
+          StringRef *KeysMem =
+              TransientArena.Allocate<StringRef>(AttrKeys.size());
+          std::uninitialized_copy(AttrKeys.begin(), AttrKeys.end(), KeysMem);
+          I->AttrKeys = llvm::ArrayRef<StringRef>(KeysMem, AttrKeys.size());
+        }
+        if (!AttrValues.empty()) {
+          StringRef *ValuesMem =
+              TransientArena.Allocate<StringRef>(AttrValues.size());
+          std::uninitialized_copy(AttrValues.begin(), AttrValues.end(),
+                                  ValuesMem);
+          I->AttrValues =
+              llvm::ArrayRef<StringRef>(ValuesMem, AttrValues.size());
+        }
+        if (!Args.empty()) {
+          StringRef *ArgsMem = TransientArena.Allocate<StringRef>(Args.size());
+          std::uninitialized_copy(Args.begin(), Args.end(), ArgsMem);
+          I->Args = llvm::ArrayRef<StringRef>(ArgsMem, Args.size());
+        }
         return llvm::Error::success();
       },
       [&](unsigned BlockOrCode) -> llvm::Error {
@@ -563,219 +481,6 @@ llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, CommentInfo *I) {
       });
 }
 
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, FunctionInfo *I) {
-  llvm::SmallVector<FieldTypeInfo, 4> LocalParams;
-  llvm::SmallVector<Reference> LocalNamespaces;
-
-  return parseBlock(
-      ID, I,
-      [&](unsigned BlockOrCode) -> llvm::Expected<bool> {
-        auto B = readSubBlockIfMatch(BlockOrCode, BI_FIELD_TYPE_BLOCK_ID,
-                                     LocalParams);
-        if (!B)
-          return B.takeError();
-        if (*B)
-          return true;
-        return routeReferenceBlock(BlockOrCode, LocalNamespaces, I);
-      },
-      [&]() -> llvm::Error {
-        I->Params = allocateArray(LocalParams, TransientArena);
-        if (!LocalNamespaces.empty())
-          I->Namespace = allocateArray(LocalNamespaces, TransientArena);
-        return llvm::Error::success();
-      });
-}
-
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, EnumInfo *I) {
-  llvm::SmallVector<EnumValueInfo, 4> LocalMembers;
-  llvm::SmallVector<Reference> LocalNamespaces;
-
-  return parseBlock(
-      ID, I,
-      [&](unsigned BlockOrCode) -> llvm::Expected<bool> {
-        auto B = readSubBlockIfMatch(BlockOrCode, BI_ENUM_VALUE_BLOCK_ID,
-                                     LocalMembers);
-        if (!B)
-          return B.takeError();
-        if (*B)
-          return true;
-        return routeReferenceBlock(BlockOrCode, LocalNamespaces, I);
-      },
-      [&]() -> llvm::Error {
-        I->Members = allocateArray(LocalMembers, TransientArena);
-        if (!LocalNamespaces.empty())
-          I->Namespace = allocateArray(LocalNamespaces, TransientArena);
-        return llvm::Error::success();
-      });
-}
-
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, BaseRecordInfo *I) {
-  // BaseRecordInfo and FriendInfo are over 256 bytes and require a size.
-  llvm::SmallVector<BaseRecordInfo, 4> LocalBases;
-  llvm::SmallVector<FriendInfo, 4> LocalFriends;
-  llvm::SmallVector<MemberTypeInfo> LocalMembers;
-  llvm::SmallVector<Reference> LocalParents;
-  llvm::SmallVector<Reference> LocalVirtualParents;
-
-  return parseBlock(
-      ID, I,
-      [&](unsigned BlockOrCode) -> llvm::Expected<bool> {
-        auto B = readSubBlockIfMatch(BlockOrCode, BI_MEMBER_TYPE_BLOCK_ID,
-                                     LocalMembers);
-        if (!B)
-          return B.takeError();
-        if (*B)
-          return true;
-
-        B = readSubBlockIfMatch(BlockOrCode, BI_BASE_RECORD_BLOCK_ID,
-                                LocalBases);
-        if (!B)
-          return B.takeError();
-        if (*B)
-          return true;
-
-        B = readSubBlockIfMatch(BlockOrCode, BI_FRIEND_BLOCK_ID, LocalFriends);
-        if (!B)
-          return B.takeError();
-        if (*B)
-          return true;
-
-        llvm::SmallVector<Reference> Dummy;
-        return routeReferenceBlock(
-            BlockOrCode, Dummy, I,
-            {{FieldId::F_parent, &LocalParents},
-             {FieldId::F_vparent, &LocalVirtualParents}});
-      },
-      [&]() -> llvm::Error {
-        if (!LocalMembers.empty())
-          I->Members = allocateArray(LocalMembers, TransientArena);
-        if (!LocalParents.empty())
-          I->Parents = allocateArray(LocalParents, TransientArena);
-        if (!LocalVirtualParents.empty())
-          I->VirtualParents =
-              allocateArray(LocalVirtualParents, TransientArena);
-        I->Bases = allocateArray(LocalBases, TransientArena);
-        I->Friends = allocateArray(LocalFriends, TransientArena);
-        return llvm::Error::success();
-      });
-}
-
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, RecordInfo *I) {
-  llvm::SmallVector<BaseRecordInfo, 4> LocalBases;
-  llvm::SmallVector<FriendInfo, 4> LocalFriends;
-  llvm::SmallVector<MemberTypeInfo> LocalMembers;
-  llvm::SmallVector<Reference> LocalParents;
-  llvm::SmallVector<Reference> LocalVirtualParents;
-  llvm::SmallVector<Reference> LocalNamespaces;
-
-  return parseBlock(
-      ID, I,
-      [&](unsigned BlockOrCode) -> llvm::Expected<bool> {
-        auto B = readSubBlockIfMatch(BlockOrCode, BI_MEMBER_TYPE_BLOCK_ID,
-                                     LocalMembers);
-        if (!B)
-          return B.takeError();
-        if (*B)
-          return true;
-
-        B = readSubBlockIfMatch(BlockOrCode, BI_BASE_RECORD_BLOCK_ID,
-                                LocalBases);
-        if (!B)
-          return B.takeError();
-        if (*B)
-          return true;
-
-        B = readSubBlockIfMatch(BlockOrCode, BI_FRIEND_BLOCK_ID, LocalFriends);
-        if (!B)
-          return B.takeError();
-        if (*B)
-          return true;
-
-        return routeReferenceBlock(
-            BlockOrCode, LocalNamespaces, I,
-            {{FieldId::F_parent, &LocalParents},
-             {FieldId::F_vparent, &LocalVirtualParents}});
-      },
-      [&]() -> llvm::Error {
-        if (!LocalMembers.empty())
-          I->Members = allocateArray(LocalMembers, TransientArena);
-        if (!LocalParents.empty())
-          I->Parents = allocateArray(LocalParents, TransientArena);
-        if (!LocalVirtualParents.empty())
-          I->VirtualParents =
-              allocateArray(LocalVirtualParents, TransientArena);
-        if (!LocalNamespaces.empty())
-          I->Namespace = allocateArray(LocalNamespaces, TransientArena);
-        I->Bases = allocateArray(LocalBases, TransientArena);
-        I->Friends = allocateArray(LocalFriends, TransientArena);
-        return llvm::Error::success();
-      });
-}
-
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, TemplateInfo *I) {
-  llvm::SmallVector<TemplateParamInfo> LocalParams;
-  llvm::SmallVector<ConstraintInfo> LocalConstraints;
-
-  return parseBlock(
-      ID, I,
-      [&](unsigned BlockOrCode) -> llvm::Expected<bool> {
-        auto B = readSubBlockIfMatch(BlockOrCode, BI_TEMPLATE_PARAM_BLOCK_ID,
-                                     LocalParams);
-        if (!B)
-          return B.takeError();
-        if (*B)
-          return true;
-
-        B = readSubBlockIfMatch(BlockOrCode, BI_CONSTRAINT_BLOCK_ID,
-                                LocalConstraints);
-        if (!B)
-          return B.takeError();
-        if (*B)
-          return true;
-
-        return false;
-      },
-      [&]() -> llvm::Error {
-        I->Params = allocateArray(LocalParams, TransientArena);
-        I->Constraints = allocateArray(LocalConstraints, TransientArena);
-        return llvm::Error::success();
-      },
-      [&](unsigned BlockOrCode) -> llvm::Error {
-        return readRecord(BlockOrCode, I);
-      });
-}
-
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID,
-                                             TemplateSpecializationInfo *I) {
-  llvm::SmallVector<TemplateParamInfo> LocalParams;
-
-  return parseBlock(
-      ID, I,
-      [&](unsigned BlockOrCode) -> llvm::Expected<bool> {
-        auto B = readSubBlockIfMatch(BlockOrCode, BI_TEMPLATE_PARAM_BLOCK_ID,
-                                     LocalParams);
-        if (!B)
-          return B.takeError();
-        if (*B)
-          return true;
-
-        return false;
-      },
-      [&]() -> llvm::Error {
-        I->Params = allocateArray(LocalParams, TransientArena);
-        return llvm::Error::success();
-      },
-      [&](unsigned BlockOrCode) -> llvm::Error {
-        return readRecord(BlockOrCode, I);
-      });
-}
-
 static llvm::Error parseRecord(const Record &R, unsigned ID,
                                llvm::StringRef Blob, Reference *I, FieldId &F) {
   switch (ID) {
@@ -874,25 +579,51 @@ static llvm::Error parseRecord(const Record &R, unsigned ID, StringRef Blob,
                                  "invalid field for Friend");
 }
 
-template <typename, typename = void>
-struct has_description : std::false_type {};
-template <typename T>
-struct has_description<T, std::void_t<decltype(std::declval<T>().Description)>>
-    : std::true_type {};
-
 template <typename T> static llvm::Expected<CommentInfo *> getCommentInfo(T I) {
-  if constexpr (std::is_pointer_v<T>) {
-    using Pointee = std::remove_pointer_t<T>;
-    if constexpr (has_description<Pointee>::value) {
-      auto *NewComment = allocatePtr<CommentInfo>();
-      I->Description.push_back(*NewComment);
-      return NewComment;
-    }
-  }
   return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                  "invalid type cannot contain CommentInfo");
 }
 
+template <> llvm::Expected<CommentInfo *> getCommentInfo(FunctionInfo *I) {
+  return &I->Description.emplace_back();
+}
+
+template <> llvm::Expected<CommentInfo *> getCommentInfo(NamespaceInfo *I) {
+  return &I->Description.emplace_back();
+}
+
+template <> llvm::Expected<CommentInfo *> getCommentInfo(RecordInfo *I) {
+  return &I->Description.emplace_back();
+}
+
+template <> llvm::Expected<CommentInfo *> getCommentInfo(MemberTypeInfo *I) {
+  return &I->Description.emplace_back();
+}
+
+template <> llvm::Expected<CommentInfo *> getCommentInfo(EnumInfo *I) {
+  return &I->Description.emplace_back();
+}
+
+template <> llvm::Expected<CommentInfo *> getCommentInfo(TypedefInfo *I) {
+  return &I->Description.emplace_back();
+}
+
+template <> llvm::Expected<CommentInfo *> getCommentInfo(EnumValueInfo *I) {
+  return &I->Description.emplace_back();
+}
+
+template <> llvm::Expected<CommentInfo *> getCommentInfo(ConceptInfo *I) {
+  return &I->Description.emplace_back();
+}
+
+template <> Expected<CommentInfo *> getCommentInfo(VarInfo *I) {
+  return &I->Description.emplace_back();
+}
+
+template <> Expected<CommentInfo *> getCommentInfo(FriendInfo *I) {
+  return &I->Description.emplace_back();
+}
+
 // When readSubBlock encounters a TypeInfo sub-block, it calls addTypeInfo on
 // the parent block to set it. The template specializations define what to do
 // for each supported parent block.
@@ -902,11 +633,26 @@ static llvm::Error addTypeInfo(T I, TTypeInfo &&TI) {
                                  "invalid type cannot contain TypeInfo");
 }
 
+template <> llvm::Error addTypeInfo(RecordInfo *I, MemberTypeInfo &&T) {
+  I->Members.emplace_back(std::move(T));
+  return llvm::Error::success();
+}
+
+template <> llvm::Error addTypeInfo(BaseRecordInfo *I, MemberTypeInfo &&T) {
+  I->Members.emplace_back(std::move(T));
+  return llvm::Error::success();
+}
+
 template <> llvm::Error addTypeInfo(FunctionInfo *I, TypeInfo &&T) {
   I->ReturnType = std::move(T);
   return llvm::Error::success();
 }
 
+template <> llvm::Error addTypeInfo(FunctionInfo *I, FieldTypeInfo &&T) {
+  I->Params.emplace_back(std::move(T));
+  return llvm::Error::success();
+}
+
 template <> llvm::Error addTypeInfo(FriendInfo *I, TypeInfo &&T) {
   I->ReturnType.emplace(std::move(T));
   return llvm::Error::success();
@@ -935,6 +681,9 @@ static llvm::Error addReference(T I, Reference &&R, FieldId F) {
 
 template <> llvm::Error addReference(VarInfo *I, Reference &&R, FieldId F) {
   switch (F) {
+  case FieldId::F_namespace:
+    I->Namespace.emplace_back(std::move(R));
+    return llvm::Error::success();
   default:
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                    "VarInfo cannot contain this Reference");
@@ -978,6 +727,9 @@ llvm::Error addReference(MemberTypeInfo *I, Reference &&R, FieldId F) {
 
 template <> llvm::Error addReference(EnumInfo *I, Reference &&R, FieldId F) {
   switch (F) {
+  case FieldId::F_namespace:
+    I->Namespace.emplace_back(std::move(R));
+    return llvm::Error::success();
   default:
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                    "invalid type cannot contain Reference");
@@ -986,6 +738,9 @@ template <> llvm::Error addReference(EnumInfo *I, Reference &&R, FieldId F) {
 
 template <> llvm::Error addReference(TypedefInfo *I, Reference &&R, FieldId F) {
   switch (F) {
+  case FieldId::F_namespace:
+    I->Namespace.emplace_back(std::move(R));
+    return llvm::Error::success();
   default:
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                    "invalid type cannot contain Reference");
@@ -995,13 +750,16 @@ template <> llvm::Error addReference(TypedefInfo *I, Reference &&R, FieldId F) {
 template <>
 llvm::Error addReference(NamespaceInfo *I, Reference &&R, FieldId F) {
   switch (F) {
-  case FieldId::F_child_namespace:
-    I->Children.Namespaces.push_back(
-        *allocatePtr<Reference>(TransientArena, std::move(R)));
+  case FieldId::F_namespace:
+    I->Namespace.emplace_back(std::move(R));
     return llvm::Error::success();
+  case FieldId::F_child_namespace: {
+    Reference *NewR = allocatePtr<Reference>(TransientArena, std::move(R));
+    I->Children.Namespaces.push_back(*NewR);
+    return llvm::Error::success();
+  }
   case FieldId::F_child_record:
-    I->Children.Records.push_back(
-        *allocatePtr<Reference>(TransientArena, std::move(R)));
+    I->Children.Records.emplace_back(std::move(R));
     return llvm::Error::success();
   default:
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -1012,6 +770,9 @@ llvm::Error addReference(NamespaceInfo *I, Reference &&R, FieldId F) {
 template <>
 llvm::Error addReference(FunctionInfo *I, Reference &&R, FieldId F) {
   switch (F) {
+  case FieldId::F_namespace:
+    I->Namespace.emplace_back(std::move(R));
+    return llvm::Error::success();
   case FieldId::F_parent:
     I->Parent = std::move(R);
     return llvm::Error::success();
@@ -1023,9 +784,17 @@ llvm::Error addReference(FunctionInfo *I, Reference &&R, FieldId F) {
 
 template <> llvm::Error addReference(RecordInfo *I, Reference &&R, FieldId F) {
   switch (F) {
+  case FieldId::F_namespace:
+    I->Namespace.emplace_back(std::move(R));
+    return llvm::Error::success();
+  case FieldId::F_parent:
+    I->Parents.emplace_back(std::move(R));
+    return llvm::Error::success();
+  case FieldId::F_vparent:
+    I->VirtualParents.emplace_back(std::move(R));
+    return llvm::Error::success();
   case FieldId::F_child_record:
-    I->Children.Records.push_back(
-        *allocatePtr<Reference>(TransientArena, std::move(R)));
+    I->Children.Records.emplace_back(std::move(R));
     return llvm::Error::success();
   default:
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -1054,42 +823,54 @@ llvm::Error addReference(FriendInfo *Friend, Reference &&R, FieldId F) {
                                  "Friend cannot contain this Reference");
 }
 
-static auto &getList(ScopeChildren &C, FunctionInfo *) { return C.Functions; }
-static auto &getList(ScopeChildren &C, EnumInfo *) { return C.Enums; }
-static auto &getList(ScopeChildren &C, TypedefInfo *) { return C.Typedefs; }
-static auto &getList(ScopeChildren &C, ConceptInfo *) { return C.Concepts; }
-static auto &getList(ScopeChildren &C, VarInfo *) { return C.Variables; }
-
-template <typename T, typename = void> struct has_children : std::false_type {};
-template <typename T>
-struct has_children<T, std::void_t<decltype(std::declval<T>().Children)>>
-    : std::is_same<decltype(std::declval<T>().Children), ScopeChildren> {};
-
-template <typename TargetChild, typename = void>
-struct is_valid_child : std::false_type {};
-template <typename TargetChild>
-struct is_valid_child<
-    TargetChild, std::void_t<decltype(getList(std::declval<ScopeChildren &>(),
-                                              std::declval<TargetChild *>()))>>
-    : std::true_type {};
-
-template <typename Target, typename Child>
-static void addChild(Target I, Child &&R) {
-  if constexpr (std::is_pointer_v<Target>) {
-    using Pointee = std::remove_pointer_t<Target>;
-    if constexpr (has_children<Pointee>::value) {
-      using BareChild = std::remove_cv_t<std::remove_reference_t<Child>>;
-      if constexpr (is_valid_child<BareChild>::value) {
-        auto *Node = allocatePtr<BareChild>(std::move(R));
-        getList(I->Children, Node).push_back(*Node);
-        return;
-      }
-    }
-  }
+template <typename T, typename ChildInfoType>
+static void addChild(T I, ChildInfoType &&R) {
   ExitOnErr(llvm::createStringError(llvm::inconvertibleErrorCode(),
                                     "invalid child type for info"));
 }
 
+// Namespace children:
+template <> void addChild(NamespaceInfo *I, FunctionInfo &&R) {
+  I->Children.Functions.emplace_back(std::move(R));
+}
+template <> void addChild(NamespaceInfo *I, EnumInfo &&R) {
+  I->Children.Enums.emplace_back(std::move(R));
+}
+template <> void addChild(NamespaceInfo *I, TypedefInfo &&R) {
+  I->Children.Typedefs.emplace_back(std::move(R));
+}
+template <> void addChild(NamespaceInfo *I, ConceptInfo &&R) {
+  I->Children.Concepts.emplace_back(std::move(R));
+}
+template <> void addChild(NamespaceInfo *I, VarInfo &&R) {
+  I->Children.Variables.emplace_back(std::move(R));
+}
+
+// Record children:
+template <> void addChild(RecordInfo *I, FunctionInfo &&R) {
+  I->Children.Functions.emplace_back(std::move(R));
+}
+template <> void addChild(RecordInfo *I, EnumInfo &&R) {
+  I->Children.Enums.emplace_back(std::move(R));
+}
+template <> void addChild(RecordInfo *I, TypedefInfo &&R) {
+  I->Children.Typedefs.emplace_back(std::move(R));
+}
+template <> void addChild(RecordInfo *I, FriendInfo &&R) {
+  I->Friends.emplace_back(std::move(R));
+}
+
+// Other types of children:
+template <> void addChild(EnumInfo *I, EnumValueInfo &&R) {
+  I->Members.emplace_back(std::move(R));
+}
+template <> void addChild(RecordInfo *I, BaseRecordInfo &&R) {
+  I->Bases.emplace_back(std::move(R));
+}
+template <> void addChild(BaseRecordInfo *I, FunctionInfo &&R) {
+  I->Children.Functions.emplace_back(std::move(R));
+}
+
 // TemplateParam children. These go into either a TemplateInfo (for template
 // parameters) or TemplateSpecializationInfo (for the specialization's
 // parameters).
@@ -1098,6 +879,13 @@ template <typename T> static void addTemplateParam(T I, TemplateParamInfo &&P) {
       llvm::createStringError(llvm::inconvertibleErrorCode(),
                               "invalid container for template parameter"));
 }
+template <> void addTemplateParam(TemplateInfo *I, TemplateParamInfo &&P) {
+  I->Params.emplace_back(std::move(P));
+}
+template <>
+void addTemplateParam(TemplateSpecializationInfo *I, TemplateParamInfo &&P) {
+  I->Params.emplace_back(std::move(P));
+}
 
 // Template info. These apply to either records or functions.
 template <typename T> static void addTemplate(T I, TemplateInfo &&P) {
@@ -1137,6 +925,9 @@ template <typename T> static void addConstraint(T I, ConstraintInfo &&C) {
   ExitOnErr(llvm::createStringError(llvm::inconvertibleErrorCode(),
                                     "invalid container for constraint info"));
 }
+template <> void addConstraint(TemplateInfo *I, ConstraintInfo &&C) {
+  I->Constraints.emplace_back(std::move(C));
+}
 
 // Read records from bitcode into a given info.
 template <typename T>
@@ -1161,37 +952,6 @@ llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, Reference *I) {
 }
 
 // Read a block of records into a single info.
-
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, VarInfo *I) {
-  return readBlockWithNamespace(ID, I);
-}
-
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, TypedefInfo *I) {
-  return readBlockWithNamespace(ID, I);
-}
-
-template <>
-llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, NamespaceInfo *I) {
-  return readBlockWithNamespace(ID, I);
-}
-
-template <typename T>
-llvm::Error ClangDocBitcodeReader::readBlockWithNamespace(unsigned ID, T I) {
-  llvm::SmallVector<Reference> LocalNamespaces;
-  return parseBlock(
-      ID, I,
-      [&](unsigned BlockOrCode) -> llvm::Expected<bool> {
-        return routeReferenceBlock(BlockOrCode, LocalNamespaces, I);
-      },
-      [&]() -> llvm::Error {
-        if (!LocalNamespaces.empty())
-          I->Namespace = allocateArray(LocalNamespaces, TransientArena);
-        return llvm::Error::success();
-      });
-}
-
 template <typename T>
 llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, T I) {
   return parseBlock(
@@ -1209,13 +969,13 @@ llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, FriendInfo *I) {
   return parseBlock(
       ID, I,
       [&](unsigned BlockOrCode) -> llvm::Expected<bool> {
-        auto B = readSubBlockIfMatch(BlockOrCode, BI_FIELD_TYPE_BLOCK_ID,
-                                     LocalParams);
-        if (!B)
-          return B.takeError();
-        if (*B)
+        if (BlockOrCode == BI_FIELD_TYPE_BLOCK_ID) {
+          FieldTypeInfo FI;
+          if (auto Err = readBlock(BlockOrCode, &FI))
+            return std::move(Err);
+          LocalParams.push_back(std::move(FI));
           return true;
-
+        }
         return false;
       },
       [&]() -> llvm::Error {
@@ -1228,19 +988,27 @@ llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, FriendInfo *I) {
       });
 }
 
+// TODO: fix inconsistentent returning of errors in add callbacks.
+// Once that's fixed, we only need one handleSubBlock.
 template <typename InfoType, typename T, typename Callback>
 llvm::Error ClangDocBitcodeReader::handleSubBlock(unsigned ID, T Parent,
                                                   Callback Function) {
   InfoType Info;
   if (auto Err = readBlock(ID, &Info))
     return Err;
-  if constexpr (std::is_void_v<
-                    std::invoke_result_t<Callback, T, InfoType &&>>) {
-    Function(Parent, std::move(Info));
-    return llvm::Error::success();
-  } else {
-    return Function(Parent, std::move(Info));
-  }
+  Function(Parent, std::move(Info));
+  return llvm::Error::success();
+}
+
+template <typename InfoType, typename T, typename Callback>
+llvm::Error ClangDocBitcodeReader::handleTypeSubBlock(unsigned ID, T Parent,
+                                                      Callback Function) {
+  InfoType Info;
+  if (auto Err = readBlock(ID, &Info))
+    return Err;
+  if (auto Err = Function(Parent, std::move(Info)))
+    return Err;
+  return llvm::Error::success();
 }
 
 template <typename T>
@@ -1264,15 +1032,15 @@ llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) {
     return llvm::Error::success();
   }
   case BI_TYPE_BLOCK_ID: {
-    return handleSubBlock<TypeInfo>(ID, I,
-                                    CreateAddFunc(addTypeInfo<T, TypeInfo>));
+    return handleTypeSubBlock<TypeInfo>(
+        ID, I, CreateAddFunc(addTypeInfo<T, TypeInfo>));
   }
   case BI_FIELD_TYPE_BLOCK_ID: {
-    return handleSubBlock<FieldTypeInfo>(
+    return handleTypeSubBlock<FieldTypeInfo>(
         ID, I, CreateAddFunc(addTypeInfo<T, FieldTypeInfo>));
   }
   case BI_MEMBER_TYPE_BLOCK_ID: {
-    return handleSubBlock<MemberTypeInfo>(
+    return handleTypeSubBlock<MemberTypeInfo>(
         ID, I, CreateAddFunc(addTypeInfo<T, MemberTypeInfo>));
   }
   case BI_REFERENCE_BLOCK_ID: {

diff  --git a/clang-tools-extra/clang-doc/BitcodeReader.h b/clang-tools-extra/clang-doc/BitcodeReader.h
index 4585cb454f408..d3499fdee0f5d 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.h
+++ b/clang-tools-extra/clang-doc/BitcodeReader.h
@@ -44,32 +44,12 @@ class ClangDocBitcodeReader {
   // Read a block of records into a single Info struct, calls readRecord on each
   // record found.
   template <typename T> llvm::Error readBlock(unsigned ID, T I);
-  template <typename T> llvm::Error readBlockWithNamespace(unsigned ID, T I);
 
   template <typename T, typename BlockBeginHandler, typename BlockEndHandler,
             typename RecordHandler>
   llvm::Error parseBlock(unsigned ID, T I, BlockBeginHandler &&BBH,
                          BlockEndHandler &&BEH, RecordHandler &&RH);
 
-  template <typename T, typename BlockBeginHandler, typename BlockEndHandler>
-  llvm::Error parseBlock(unsigned ID, T I, BlockBeginHandler &&BBH,
-                         BlockEndHandler &&BEH);
-
-  template <typename ChildType>
-  llvm::Expected<bool> readSubBlockIfMatch(unsigned ID, unsigned TargetID,
-                                           llvm::SmallVectorImpl<ChildType> &V);
-
-  struct ReferenceMap {
-    FieldId Field;
-    llvm::SmallVectorImpl<Reference> *Vec;
-  };
-
-  template <typename InfoT>
-  llvm::Expected<bool>
-  routeReferenceBlock(unsigned ID, llvm::SmallVectorImpl<Reference> &Namespaces,
-                      InfoT *I,
-                      std::initializer_list<ReferenceMap> Mappings = {});
-
   // Step through a block of records to find the next data field.
   template <typename T> llvm::Error readSubBlock(unsigned ID, T I);
 

diff  --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp
index 4854c6114b760..e895d641a6000 100644
--- a/clang-tools-extra/clang-doc/JSONGenerator.cpp
+++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp
@@ -27,7 +27,6 @@ class JSONGenerator : public Generator {
   void serializeCommonChildren(
       const ScopeChildren &Children, json::Object &Obj,
       std::optional<ReferenceFunc> MDReferenceLambda = std::nullopt);
-  void serializeContexts(Info *I, llvm::StringMap<OwnedPtr<Info>> &Infos);
   void serializeInfo(const ConstraintInfo &I, Object &Obj);
   void serializeInfo(const TemplateInfo &Template, Object &Obj);
   void serializeInfo(const ConceptInfo &I, Object &Obj);
@@ -62,12 +61,10 @@ class JSONGenerator : public Generator {
     };
   }
 
-  llvm::DenseMap<const Info *, SmallVector<Context, 4>> ContextsMap;
-  const ClangDocContext *CDCtx;
-  bool Markdown;
-
 public:
   static const char *Format;
+  const ClangDocContext *CDCtx;
+  bool Markdown;
 
   Error generateDocumentation(StringRef RootDir,
                               llvm::StringMap<OwnedPtr<doc::Info>> Infos,
@@ -323,20 +320,13 @@ static Object serializeComment(const CommentInfo &I, Object &Description) {
 
 /// Creates Contexts for namespaces and records to allow for navigation.
 void JSONGenerator::generateContext(const Info &I, Object &Obj) {
-  Obj["Contexts"] = json::Array();
-  Obj["HasContexts"] = true;
-
-  auto It = ContextsMap.find(&I);
-  if (It == ContextsMap.end() || It->second.empty())
-    return;
-
-  auto &ContextArrayRef = *Obj["Contexts"].getAsArray();
-  const auto &Contexts = It->second;
-  ContextArrayRef.reserve(Contexts.size());
+  json::Value ContextArray = json::Array();
+  auto &ContextArrayRef = *ContextArray.getAsArray();
+  ContextArrayRef.reserve(I.Contexts.size());
 
   std::string CurrentRelativePath;
   bool PreviousRecord = false;
-  for (const auto &Current : Contexts) {
+  for (const auto &Current : I.Contexts) {
     json::Value ContextVal = Object();
     Object &Context = *ContextVal.getAsObject();
     serializeReference(Current, Context);
@@ -382,9 +372,11 @@ void JSONGenerator::generateContext(const Info &I, Object &Obj) {
   }
 
   ContextArrayRef.back().getAsObject()->insert({"End", true});
+  Obj["Contexts"] = ContextArray;
+  Obj["HasContexts"] = true;
 }
 
-static void serializeDescription(const OwningVec<CommentInfo> &Description,
+static void serializeDescription(llvm::ArrayRef<CommentInfo> Description,
                                  json::Object &Obj, StringRef Key = "") {
   if (Description.empty())
     return;
@@ -437,8 +429,7 @@ void JSONGenerator::serializeCommonAttributes(const Info &I,
       Obj["Location"] = serializeLocation(Symbol->DefLoc.value());
   }
 
-  auto It = ContextsMap.find(&I);
-  if (It != ContextsMap.end() && !It->second.empty())
+  if (!I.Contexts.empty())
     generateContext(I, Obj);
 }
 
@@ -835,9 +826,9 @@ SmallString<16> JSONGenerator::determineFileName(Info *I,
 
 /// \param CDCtxIndex Passed by copy since clang-doc's context is passed to the
 /// generator as `const`
-static std::vector<Index> preprocessCDCtxIndex(Index CDCtxIndex) {
+static OwningVec<Index> preprocessCDCtxIndex(Index CDCtxIndex) {
   CDCtxIndex.sort();
-  std::vector<Index> Processed;
+  OwningVec<Index> Processed;
   Processed.reserve(CDCtxIndex.Children.size());
   for (const auto *Idx : CDCtxIndex.getSortedChildren()) {
     Index NewIdx = *Idx;
@@ -857,7 +848,7 @@ Error JSONGenerator::serializeAllFiles(const ClangDocContext &CDCtx,
                                        StringRef RootDir) {
   json::Value ObjVal = Object();
   Object &Obj = *ObjVal.getAsObject();
-  std::vector<Index> IndexCopy = preprocessCDCtxIndex(CDCtx.Idx);
+  OwningVec<Index> IndexCopy = preprocessCDCtxIndex(CDCtx.Idx);
   serializeArray(IndexCopy, Obj, "Index", serializeReferenceLambda());
   SmallString<128> Path;
   sys::path::append(Path, RootDir, "json", "all_files.json");
@@ -920,12 +911,10 @@ Error JSONGenerator::serializeIndex(StringRef RootDir) {
   return Error::success();
 }
 
-void JSONGenerator::serializeContexts(Info *I,
-                                      StringMap<OwnedPtr<Info>> &Infos) {
+static void serializeContexts(Info *I, StringMap<OwnedPtr<Info>> &Infos) {
   if (I->USR == GlobalNamespaceID)
     return;
   auto ParentUSR = I->ParentUSR;
-  auto &LocalContexts = ContextsMap[I];
 
   while (true) {
     // Infos may not have the ParentUSR, if its been filtered (public or path),
@@ -939,12 +928,12 @@ void JSONGenerator::serializeContexts(Info *I,
       Context GlobalRef(ParentInfo->USR, "Global Namespace",
                         InfoType::IT_namespace, "GlobalNamespace", "",
                         SmallString<16>("index"));
-      LocalContexts.push_back(GlobalRef);
-      break;
+      I->Contexts.push_back(GlobalRef);
+      return;
     }
 
     Context ParentRef(*ParentInfo);
-    LocalContexts.push_back(ParentRef);
+    I->Contexts.push_back(ParentRef);
     ParentUSR = ParentInfo->ParentUSR;
   }
 }

diff  --git a/clang-tools-extra/clang-doc/MDGenerator.cpp b/clang-tools-extra/clang-doc/MDGenerator.cpp
index 9ccb7a8ccd633..b0253c5d71bfc 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -31,7 +31,8 @@ static std::string genEmphasis(const Twine &Text) {
   return "**" + Text.str() + "**";
 }
 
-static std::string genReferenceList(llvm::ArrayRef<Reference> Refs) {
+static std::string
+genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs) {
   std::string Buffer;
   llvm::raw_string_ostream Stream(Buffer);
   for (const auto &R : Refs) {
@@ -81,7 +82,7 @@ class TableCommentWriter {
 public:
   explicit TableCommentWriter(llvm::raw_ostream &OS) : OS(OS) {}
 
-  void write(const OwningVec<CommentInfo> &Comments) {
+  void write(llvm::ArrayRef<CommentInfo> Comments) {
     for (const auto &C : Comments)
       writeTableSafeComment(C);
 
@@ -435,7 +436,7 @@ static llvm::Error serializeIndex(ClangDocContext &CDCtx) {
     OS << " for " << CDCtx.ProjectName;
   OS << "\n\n";
 
-  std::vector<const Index *> Children = CDCtx.Idx.getSortedChildren();
+  OwningVec<const Index *> Children = CDCtx.Idx.getSortedChildren();
   for (const auto *C : Children)
     serializeReference(OS, *C, 0);
 
@@ -454,7 +455,7 @@ static llvm::Error genIndex(ClangDocContext &CDCtx) {
                                        FileErr.message());
   CDCtx.Idx.sort();
   OS << "# " << CDCtx.ProjectName << " C/C++ Reference\n\n";
-  std::vector<const Index *> Children = CDCtx.Idx.getSortedChildren();
+  OwningVec<const Index *> Children = CDCtx.Idx.getSortedChildren();
   for (const auto *C : Children) {
     if (!C->Children.empty()) {
       const char *Type;

diff  --git a/clang-tools-extra/clang-doc/Mapper.cpp b/clang-tools-extra/clang-doc/Mapper.cpp
index 499ab5638b34e..583a0fe43b40c 100644
--- a/clang-tools-extra/clang-doc/Mapper.cpp
+++ b/clang-tools-extra/clang-doc/Mapper.cpp
@@ -43,9 +43,6 @@ void MapASTVisitor::HandleTranslationUnit(ASTContext &Context) {
   if (CDCtx.FTimeTrace)
     llvm::timeTraceProfilerInitialize(200, "clang-doc");
   TraverseDecl(Context.getTranslationUnitDecl());
-
-  TransientArena.Reset();
-
   if (CDCtx.FTimeTrace)
     llvm::timeTraceProfilerFinishThread();
 }

diff  --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp
index 50c5f9bb1d071..42f85c39655dd 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -105,6 +105,17 @@ static llvm::Expected<OwnedPtr<Info>> reduce(OwningPtrArray<Info> &Values) {
   return std::move(Merged);
 }
 
+// Return the index of the matching child in the vector, or -1 if merge is not
+// necessary.
+template <typename T>
+static int getChildIndexIfExists(OwningVec<T> &Children, T &ChildToMerge) {
+  for (unsigned long I = 0; I < Children.size(); I++) {
+    if (ChildToMerge.USR == Children[I].USR)
+      return I;
+  }
+  return -1;
+}
+
 template <typename T>
 static void reduceChildren(llvm::simple_ilist<T> &Children,
                            llvm::simple_ilist<T> &&ChildrenToMerge) {
@@ -115,145 +126,34 @@ static void reduceChildren(llvm::simple_ilist<T> &Children,
     auto It = llvm::find_if(
         Children, [&](const T &C) { return C.USR == ChildToMerge->USR; });
     if (It == Children.end()) {
-      T *NewChild = allocatePtr<T>(PersistentArena, ChildToMerge->USR);
-      NewChild->merge(std::move(*ChildToMerge));
-      Children.push_back(*NewChild);
+      Children.push_back(*ChildToMerge);
     } else {
       It->merge(std::move(*ChildToMerge));
     }
   }
 }
 
-template <>
-void reduceChildren<Reference>(
-    llvm::simple_ilist<Reference> &Children,
-    llvm::simple_ilist<Reference> &&ChildrenToMerge) {
-  while (!ChildrenToMerge.empty()) {
-    Reference *ChildToMerge = &ChildrenToMerge.front();
-    ChildrenToMerge.pop_front();
-
-    auto It = llvm::find_if(Children, [&](const Reference &C) {
-      return C.USR == ChildToMerge->USR;
-    });
-    if (It == Children.end()) {
-      Reference *NewChild = allocatePtr<Reference>(PersistentArena);
-      NewChild->USR = ChildToMerge->USR;
-      NewChild->RefType = ChildToMerge->RefType;
-      NewChild->merge(std::move(*ChildToMerge));
-      Children.push_back(*NewChild);
-    } else {
-      It->merge(std::move(*ChildToMerge));
+template <typename T>
+static void reduceChildren(OwningVec<T> &Children,
+                           OwningVec<T> &&ChildrenToMerge) {
+  for (auto &ChildToMerge : ChildrenToMerge) {
+    int MergeIdx = getChildIndexIfExists(Children, ChildToMerge);
+    if (MergeIdx == -1) {
+      Children.push_back(std::move(ChildToMerge));
+      continue;
     }
+    Children[MergeIdx].merge(std::move(ChildToMerge));
   }
 }
 
 template <typename Container>
 static void mergeUnkeyed(Container &Target, Container &&Source) {
-  using T = typename Container::value_type;
-  while (!Source.empty()) {
-    auto &Item = Source.front();
-    Source.pop_front();
-    if (llvm::none_of(Target, [&](const auto &E) { return E == Item; })) {
-      T *NewItem = allocatePtr<T>(PersistentArena, Item);
-      Target.push_back(*NewItem);
-    }
-  }
-}
-
-template <>
-void mergeUnkeyed<OwningVec<CommentInfo>>(OwningVec<CommentInfo> &Target,
-                                          OwningVec<CommentInfo> &&Source) {
-  while (!Source.empty()) {
-    auto &Item = Source.front();
-    Source.pop_front();
-    if (llvm::none_of(Target, [&](const auto &E) { return E == Item; })) {
-      CommentInfo *NewItem =
-          allocatePtr<CommentInfo>(PersistentArena, Item, PersistentArena);
-      Target.push_back(*NewItem);
-    }
+  for (auto &Item : Source) {
+    if (llvm::none_of(Target, [&](const auto &E) { return E == Item; }))
+      Target.push_back(std::move(Item));
   }
 }
 
-llvm::Error mergeSingleInfo(doc::OwnedPtr<doc::Info> &Reduced,
-                            doc::OwnedPtr<doc::Info> &&NewInfo,
-                            llvm::BumpPtrAllocator &Arena) {
-  if (!Reduced) {
-    switch (NewInfo->IT) {
-    case InfoType::IT_namespace:
-      Reduced = allocatePtr<NamespaceInfo>(Arena, NewInfo->USR);
-      break;
-    case InfoType::IT_record:
-      Reduced = allocatePtr<RecordInfo>(Arena, NewInfo->USR);
-      break;
-    case InfoType::IT_enum:
-      Reduced = allocatePtr<EnumInfo>(Arena, NewInfo->USR);
-      break;
-    case InfoType::IT_function:
-      Reduced = allocatePtr<FunctionInfo>(Arena, NewInfo->USR);
-      break;
-    case InfoType::IT_typedef:
-      Reduced = allocatePtr<TypedefInfo>(Arena, NewInfo->USR);
-      break;
-    case InfoType::IT_concept:
-      Reduced = allocatePtr<ConceptInfo>(Arena, NewInfo->USR);
-      break;
-    case InfoType::IT_variable:
-      Reduced = allocatePtr<VarInfo>(Arena, NewInfo->USR);
-      break;
-    case InfoType::IT_friend:
-      Reduced = allocatePtr<FriendInfo>(Arena, NewInfo->USR);
-      break;
-    default:
-      return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                     "unknown info type");
-    }
-  }
-
-  if (Reduced->IT != NewInfo->IT)
-    return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                   "info types mismatch");
-
-  switch (Reduced->IT) {
-  case InfoType::IT_namespace:
-    static_cast<NamespaceInfo *>(getPtr(Reduced))
-        ->merge(std::move(*static_cast<NamespaceInfo *>(getPtr(NewInfo))));
-    break;
-  case InfoType::IT_record:
-    static_cast<RecordInfo *>(getPtr(Reduced))
-        ->merge(std::move(*static_cast<RecordInfo *>(getPtr(NewInfo))));
-    break;
-  case InfoType::IT_enum:
-    static_cast<EnumInfo *>(getPtr(Reduced))
-        ->merge(std::move(*static_cast<EnumInfo *>(getPtr(NewInfo))));
-    break;
-  case InfoType::IT_function:
-    static_cast<FunctionInfo *>(getPtr(Reduced))
-        ->merge(std::move(*static_cast<FunctionInfo *>(getPtr(NewInfo))));
-    break;
-  case InfoType::IT_typedef:
-    static_cast<TypedefInfo *>(getPtr(Reduced))
-        ->merge(std::move(*static_cast<TypedefInfo *>(getPtr(NewInfo))));
-    break;
-  case InfoType::IT_concept:
-    static_cast<ConceptInfo *>(getPtr(Reduced))
-        ->merge(std::move(*static_cast<ConceptInfo *>(getPtr(NewInfo))));
-    break;
-  case InfoType::IT_variable:
-    static_cast<VarInfo *>(getPtr(Reduced))
-        ->merge(std::move(*static_cast<VarInfo *>(getPtr(NewInfo))));
-    break;
-  case InfoType::IT_friend:
-    static_cast<FriendInfo *>(getPtr(Reduced))
-        ->merge(std::move(*static_cast<FriendInfo *>(getPtr(NewInfo))));
-    break;
-  default:
-    return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                   "unknown info type");
-  }
-
-  return llvm::Error::success();
-}
-
 // Dispatch function.
 llvm::Expected<OwnedPtr<Info>> mergeInfos(OwningPtrArray<Info> &Values) {
   if (Values.empty() || !Values[0])
@@ -284,20 +184,6 @@ llvm::Expected<OwnedPtr<Info>> mergeInfos(OwningPtrArray<Info> &Values) {
   llvm_unreachable("unhandled enumerator");
 }
 
-TemplateSpecializationInfo::TemplateSpecializationInfo(
-    const TemplateSpecializationInfo &Other, llvm::BumpPtrAllocator &Arena)
-    : SpecializationOf(Other.SpecializationOf) {
-  Params = allocateArray(Other.Params, Arena);
-}
-
-TemplateInfo::TemplateInfo(const TemplateInfo &Other,
-                           llvm::BumpPtrAllocator &Arena) {
-  Params = allocateArray(Other.Params, Arena);
-  if (Other.Specialization)
-    Specialization = TemplateSpecializationInfo(*Other.Specialization, Arena);
-  Constraints = allocateArray(Other.Constraints, Arena);
-}
-
 bool CommentInfo::operator==(const CommentInfo &Other) const {
   auto FirstCI = std::tie(Kind, Text, Name, Direction, ParamName, CloseName,
                           SelfClosing, Explicit, AttrKeys, AttrValues, Args);
@@ -333,28 +219,6 @@ bool CommentInfo::operator<(const CommentInfo &Other) const {
   return false;
 }
 
-CommentInfo::CommentInfo(const CommentInfo &Other,
-                         llvm::BumpPtrAllocator &Arena) {
-  Kind = Other.Kind;
-  Direction = Other.Direction;
-  Name = Other.Name;
-  ParamName = Other.ParamName;
-  CloseName = Other.CloseName;
-  SelfClosing = Other.SelfClosing;
-  Explicit = Other.Explicit;
-  Text = Other.Text;
-  AttrKeys = allocateArray(Other.AttrKeys, Arena);
-  AttrValues = allocateArray(Other.AttrValues, Arena);
-  Args = allocateArray(Other.Args, Arena);
-  if (!Other.Children.empty()) {
-    CommentInfo *NewArray = Arena.Allocate<CommentInfo>(Other.Children.size());
-    for (size_t Idx = 0; Idx < Other.Children.size(); ++Idx) {
-      new (NewArray + Idx) CommentInfo(Other.Children[Idx], Arena);
-    }
-    Children = llvm::ArrayRef<CommentInfo>(NewArray, Other.Children.size());
-  }
-}
-
 static llvm::SmallString<64>
 calculateRelativeFilePath(const InfoType &Type, const StringRef &Path,
                           const StringRef &Name, const StringRef &CurrentPath) {
@@ -411,8 +275,6 @@ void Reference::merge(Reference &&Other) {
     Name = Other.Name;
   if (Path.empty())
     Path = Other.Path;
-  if (QualName.empty())
-    QualName = Other.QualName;
   if (DocumentationFileName.empty())
     DocumentationFileName = Other.DocumentationFileName;
 }
@@ -427,31 +289,6 @@ void FriendInfo::merge(FriendInfo &&Other) {
   SymbolInfo::merge(std::move(Other));
 }
 
-FriendInfo::FriendInfo(const FriendInfo &Other, llvm::BumpPtrAllocator &Arena)
-    : SymbolInfo(Other, Arena) {
-  Ref = Other.Ref;
-  if (Other.Template)
-    Template.emplace(*Other.Template, Arena);
-  if (Other.ReturnType)
-    ReturnType = Other.ReturnType;
-  if (!Other.Params.empty())
-    Params = allocateArray(Other.Params, Arena);
-  IsClass = Other.IsClass;
-}
-
-Info::Info(const Info &Other, llvm::BumpPtrAllocator &Arena)
-    : Path(Other.Path), Name(Other.Name),
-      DocumentationFileName(Other.DocumentationFileName), USR(Other.USR),
-      ParentUSR(Other.ParentUSR), IT(Other.IT) {
-  Namespace = allocateArray(Other.Namespace, Arena);
-  if (!Other.Description.empty()) {
-    for (const auto &Desc : Other.Description) {
-      CommentInfo *NewDesc = allocatePtr<CommentInfo>(Arena, Desc, Arena);
-      Description.push_back(*NewDesc);
-    }
-  }
-}
-
 void Info::mergeBase(Info &&Other) {
   assert(mergeable(Other));
   if (USR == EmptySID)
@@ -460,8 +297,8 @@ void Info::mergeBase(Info &&Other) {
     Name = Other.Name;
   if (Path == "")
     Path = Other.Path;
-  if (Namespace.empty() && !Other.Namespace.empty())
-    Namespace = allocateArray(Other.Namespace, PersistentArena);
+  if (Namespace.empty())
+    Namespace = std::move(Other.Namespace);
   // Unconditionally extend the description, since each decl may have a comment.
   mergeUnkeyed(Description, std::move(Other.Description));
   if (ParentUSR == EmptySID)
@@ -474,17 +311,6 @@ bool Info::mergeable(const Info &Other) {
   return IT == Other.IT && USR == Other.USR;
 }
 
-SymbolInfo::SymbolInfo(const SymbolInfo &Other, llvm::BumpPtrAllocator &Arena)
-    : Info(Other, Arena), DefLoc(Other.DefLoc), MangledName(Other.MangledName),
-      IsStatic(Other.IsStatic) {
-  if (!Other.Loc.empty()) {
-    for (const auto &L : Other.Loc) {
-      Location *NewL = allocatePtr<Location>(Arena, L);
-      Loc.push_back(*NewL);
-    }
-  }
-}
-
 void SymbolInfo::merge(SymbolInfo &&Other) {
   assert(mergeable(Other));
   if (!DefLoc)
@@ -494,8 +320,6 @@ void SymbolInfo::merge(SymbolInfo &&Other) {
   mergeBase(std::move(Other));
   if (MangledName.empty())
     MangledName = std::move(Other.MangledName);
-  if (!IsStatic)
-    IsStatic = Other.IsStatic;
 }
 
 NamespaceInfo::NamespaceInfo(SymbolID USR, StringRef Name, StringRef Path)
@@ -517,76 +341,37 @@ void NamespaceInfo::merge(NamespaceInfo &&Other) {
 RecordInfo::RecordInfo(SymbolID USR, StringRef Name, StringRef Path)
     : SymbolInfo(InfoType::IT_record, USR, Name, Path) {}
 
-// FIXME: This constructor is currently unsafe for cross-arena copies of
-// populated records. Because a default copy of ScopeChildren will shallow-copy
-// the intrusive pointers, leading to a use-after-free when the TransientArena
-// is reset. Subsequent patches will address this by deep-copying children
-// individually via reduceChildren.
-RecordInfo::RecordInfo(const RecordInfo &Other, llvm::BumpPtrAllocator &Arena)
-    : SymbolInfo(Other, Arena), TagType(Other.TagType),
-      IsTypeDef(Other.IsTypeDef) {
-  Members = deepCopyArray(Other.Members, Arena);
-  Parents = allocateArray(Other.Parents, Arena);
-  VirtualParents = allocateArray(Other.VirtualParents, Arena);
-  Bases = deepCopyArray(Other.Bases, Arena);
-  Friends = deepCopyArray(Other.Friends, Arena);
-}
-
-MemberTypeInfo::MemberTypeInfo(const MemberTypeInfo &Other,
-                               llvm::BumpPtrAllocator &Arena)
-    : FieldTypeInfo(Other), Access(Other.Access), IsStatic(Other.IsStatic) {
-  if (!Other.Description.empty()) {
-    for (const auto &Desc : Other.Description) {
-      CommentInfo *NewDesc = allocatePtr<CommentInfo>(Arena, Desc, Arena);
-      Description.push_back(*NewDesc);
-    }
-  }
-}
-
 void RecordInfo::merge(RecordInfo &&Other) {
   assert(mergeable(Other));
   if (!llvm::to_underlying(TagType))
     TagType = Other.TagType;
   IsTypeDef = IsTypeDef || Other.IsTypeDef;
-  if (Members.empty() && !Other.Members.empty())
-    Members = deepCopyArray(Other.Members, PersistentArena);
-  if (Bases.empty() && !Other.Bases.empty())
-    Bases = deepCopyArray(Other.Bases, PersistentArena);
-  if (Parents.empty() && !Other.Parents.empty())
-    Parents = allocateArray(Other.Parents, PersistentArena);
-  if (VirtualParents.empty() && !Other.VirtualParents.empty())
-    VirtualParents = allocateArray(Other.VirtualParents, PersistentArena);
-  if (Friends.empty() && !Other.Friends.empty())
-    Friends = deepCopyArray(Other.Friends, PersistentArena);
+  if (Members.empty())
+    Members = std::move(Other.Members);
+  if (Bases.empty())
+    Bases = std::move(Other.Bases);
+  if (Parents.empty())
+    Parents = std::move(Other.Parents);
+  if (VirtualParents.empty())
+    VirtualParents = std::move(Other.VirtualParents);
+  if (Friends.empty())
+    Friends = std::move(Other.Friends);
   // Reduce children if necessary.
   reduceChildren(Children.Records, std::move(Other.Children.Records));
   reduceChildren(Children.Functions, std::move(Other.Children.Functions));
   reduceChildren(Children.Enums, std::move(Other.Children.Enums));
   reduceChildren(Children.Typedefs, std::move(Other.Children.Typedefs));
   SymbolInfo::merge(std::move(Other));
-  if (!Template && Other.Template)
-    Template = TemplateInfo(*Other.Template, PersistentArena);
-}
-
-EnumValueInfo::EnumValueInfo(const EnumValueInfo &Other,
-                             llvm::BumpPtrAllocator &Arena)
-    : Name(Other.Name), Value(Other.Value), ValueExpr(Other.ValueExpr) {
-  if (!Other.Description.empty()) {
-    for (const auto &Desc : Other.Description) {
-      CommentInfo *NewDesc = allocatePtr<CommentInfo>(Arena, Desc, Arena);
-      Description.push_back(*NewDesc);
-    }
-  }
+  if (!Template)
+    Template = Other.Template;
 }
 
 void EnumInfo::merge(EnumInfo &&Other) {
   assert(mergeable(Other));
   if (!Scoped)
     Scoped = Other.Scoped;
-  if (!BaseType && Other.BaseType)
-    BaseType = std::move(Other.BaseType);
-  if (Members.empty() && !Other.Members.empty())
-    Members = deepCopyArray(Other.Members, PersistentArena);
+  if (Members.empty())
+    Members = std::move(Other.Members);
   SymbolInfo::merge(std::move(Other));
 }
 
@@ -600,11 +385,11 @@ void FunctionInfo::merge(FunctionInfo &&Other) {
     ReturnType = std::move(Other.ReturnType);
   if (Parent.USR == EmptySID && Parent.Name == "")
     Parent = std::move(Other.Parent);
-  if (Params.empty() && !Other.Params.empty())
-    Params = allocateArray(Other.Params, PersistentArena);
+  if (Params.empty())
+    Params = std::move(Other.Params);
   SymbolInfo::merge(std::move(Other));
-  if (!Template && Other.Template)
-    Template = TemplateInfo(*Other.Template, PersistentArena);
+  if (!Template)
+    Template = Other.Template;
 }
 
 void TypedefInfo::merge(TypedefInfo &&Other) {
@@ -613,8 +398,8 @@ void TypedefInfo::merge(TypedefInfo &&Other) {
     IsUsing = Other.IsUsing;
   if (Underlying.Type.Name == "")
     Underlying = Other.Underlying;
-  if (!Template && Other.Template)
-    Template = TemplateInfo(*Other.Template, PersistentArena);
+  if (!Template)
+    Template = Other.Template;
   SymbolInfo::merge(std::move(Other));
 }
 
@@ -624,11 +409,10 @@ void ConceptInfo::merge(ConceptInfo &&Other) {
     IsType = Other.IsType;
   if (ConstraintExpression.empty())
     ConstraintExpression = std::move(Other.ConstraintExpression);
-  if (Template.Constraints.empty() && !Other.Template.Constraints.empty())
-    Template.Constraints =
-        allocateArray(Other.Template.Constraints, PersistentArena);
-  if (Template.Params.empty() && !Other.Template.Params.empty())
-    Template.Params = allocateArray(Other.Template.Params, PersistentArena);
+  if (Template.Constraints.empty())
+    Template.Constraints = std::move(Other.Template.Constraints);
+  if (Template.Params.empty())
+    Template.Params = std::move(Other.Template.Params);
   SymbolInfo::merge(std::move(Other));
 }
 
@@ -643,11 +427,6 @@ void VarInfo::merge(VarInfo &&Other) {
 
 BaseRecordInfo::BaseRecordInfo() : RecordInfo() {}
 
-BaseRecordInfo::BaseRecordInfo(const BaseRecordInfo &Other,
-                               llvm::BumpPtrAllocator &Arena)
-    : RecordInfo(Other, Arena), Access(Other.Access),
-      IsVirtual(Other.IsVirtual), IsParent(Other.IsParent) {}
-
 BaseRecordInfo::BaseRecordInfo(SymbolID USR, StringRef Name, StringRef Path,
                                bool IsVirtual, AccessSpecifier Access,
                                bool IsParent)
@@ -705,8 +484,8 @@ bool Index::operator<(const Index &Other) const {
   return Name < Other.Name;
 }
 
-std::vector<const Index *> Index::getSortedChildren() const {
-  std::vector<const Index *> SortedChildren;
+OwningVec<const Index *> Index::getSortedChildren() const {
+  OwningVec<const Index *> SortedChildren;
   SortedChildren.reserve(Children.size());
   for (const auto &[_, C] : Children)
     SortedChildren.push_back(&C);
@@ -750,12 +529,12 @@ ClangDocContext::ClangDocContext(tooling::ExecutionContext *ECtx,
 
 void ScopeChildren::sort() {
   Namespaces.sort();
-  Records.sort();
-  Functions.sort();
-  Enums.sort();
-  Typedefs.sort();
-  Concepts.sort();
-  Variables.sort();
+  llvm::sort(Records);
+  llvm::sort(Functions);
+  llvm::sort(Enums);
+  llvm::sort(Typedefs);
+  llvm::sort(Concepts);
+  llvm::sort(Variables);
 }
 } // namespace doc
 } // namespace clang

diff  --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index 5f404463b012e..9208b77fc8606 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -52,7 +52,6 @@ class ConcurrentStringPool {
 ConcurrentStringPool &getGlobalStringPool();
 
 extern thread_local llvm::BumpPtrAllocator TransientArena;
-extern thread_local llvm::BumpPtrAllocator PersistentArena;
 
 inline StringRef internString(const Twine &T) {
   if (T.isTriviallyEmpty())
@@ -73,8 +72,8 @@ inline StringRef internString(const Twine &T) {
 }
 
 template <typename T>
-llvm::ArrayRef<T> allocateArray(llvm::SmallVectorImpl<T> &V,
-                                llvm::BumpPtrAllocator &Alloc) {
+inline llvm::ArrayRef<T> allocateArray(llvm::ArrayRef<T> V,
+                                       llvm::BumpPtrAllocator &Alloc) {
   if (V.empty())
     return llvm::ArrayRef<T>();
   T *Allocated = (T *)Alloc.Allocate<T>(V.size());
@@ -82,31 +81,9 @@ llvm::ArrayRef<T> allocateArray(llvm::SmallVectorImpl<T> &V,
   return llvm::ArrayRef<T>(Allocated, V.size());
 }
 
-template <typename T>
-llvm::ArrayRef<T> allocateArray(llvm::ArrayRef<T> V,
-                                llvm::BumpPtrAllocator &Alloc) {
-  if (V.empty())
-    return llvm::ArrayRef<T>();
-  T *Allocated = (T *)Alloc.Allocate<T>(V.size());
-  std::uninitialized_copy(V.begin(), V.end(), Allocated);
-  return llvm::ArrayRef<T>(Allocated, V.size());
-}
-
-template <typename T>
-llvm::ArrayRef<T> deepCopyArray(llvm::ArrayRef<T> V,
-                                llvm::BumpPtrAllocator &Alloc) {
-  if (V.empty())
-    return llvm::ArrayRef<T>();
-  T *Allocated = (T *)Alloc.Allocate<T>(V.size());
-  for (size_t Idx = 0; Idx < V.size(); ++Idx) {
-    new (Allocated + Idx) T(V[Idx], Alloc);
-  }
-  return llvm::ArrayRef<T>(Allocated, V.size());
-}
-
 // An abstraction for owned pointers. Initially mapped to OwnedPtr,
 // to be eventually transitioned to bare pointers in an arena.
-template <typename T> using OwnedPtr = T *;
+template <typename T> using OwnedPtr = std::unique_ptr<T>;
 
 // An abstraction for vectors that are populated and read sequentially.
 // To be eventually transitioned to llvm::ArrayRef for arena storage.
@@ -114,7 +91,7 @@ template <typename T> using OwningArray = std::vector<T>;
 
 // An abstraction for lists that are dynamically managed (inserted/removed).
 // To be eventually transitioned to llvm::simple_ilist.
-template <typename T> using OwningVec = llvm::simple_ilist<T>;
+template <typename T> using OwningVec = std::vector<T>;
 
 // An abstraction for dynamic lists of owned pointers.
 // To be eventually transitioned to llvm::simple_ilist<T*> or similar.
@@ -128,10 +105,9 @@ template <typename T> using OwningPtrArray = std::vector<OwnedPtr<T>>;
 // allocation mechanism.
 template <typename T, typename... Args>
 OwnedPtr<T> allocatePtr(Args &&...args) {
-  return new (TransientArena.Allocate<T>()) T(std::forward<Args>(args)...);
+  return std::make_unique<T>(std::forward<Args>(args)...);
 }
 
-// An overload to explicitly allocate on an arena, returning a bare pointer.
 template <typename T, typename... Args>
 T *allocatePtr(llvm::BumpPtrAllocator &Alloc, Args &&...args) {
   return new (Alloc.Allocate<T>()) T(std::forward<Args>(args)...);
@@ -139,7 +115,7 @@ T *allocatePtr(llvm::BumpPtrAllocator &Alloc, 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; }
+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>;
@@ -193,7 +169,6 @@ struct CommentInfo : public llvm::ilist_node<CommentInfo> {
   CommentInfo() = default;
   CommentInfo(const CommentInfo &Other) = default;
   CommentInfo &operator=(const CommentInfo &Other) = default;
-  CommentInfo(const CommentInfo &Other, llvm::BumpPtrAllocator &Arena);
   CommentInfo(CommentInfo &&Other) = default;
   CommentInfo &operator=(CommentInfo &&Other) = default;
 
@@ -219,11 +194,11 @@ struct CommentInfo : public llvm::ilist_node<CommentInfo> {
 
   llvm::ArrayRef<CommentInfo>
       Children;              // List of child comments for this CommentInfo.
-  StringRef Direction = {};  // Parameter direction (for (T)ParamCommand).
-  StringRef Name = {};       // Name of the comment (for Verbatim and HTML).
-  StringRef ParamName = {};  // Parameter name (for (T)ParamCommand).
-  StringRef CloseName = {};  // Closing tag name (for VerbatimBlock).
-  StringRef Text = {};       // Text of the comment.
+  StringRef Direction;       // Parameter direction (for (T)ParamCommand).
+  StringRef Name;            // Name of the comment (for Verbatim and HTML).
+  StringRef ParamName;       // Parameter name (for (T)ParamCommand).
+  StringRef CloseName;       // Closing tag name (for VerbatimBlock).
+  StringRef Text;            // Text of the comment.
   llvm::ArrayRef<StringRef> AttrKeys; // List of attribute keys (for HTML).
   llvm::ArrayRef<StringRef>
       AttrValues; // List of attribute values for each key (for HTML).
@@ -285,17 +260,17 @@ struct Reference : public llvm::ilist_node<Reference> {
   // Name of type (possibly unresolved). Not including namespaces or template
   // parameters (so for a std::vector<int> this would be "vector"). See also
   // QualName.
-  StringRef Name = {};
+  StringRef Name;
 
   // Full qualified name of this type, including namespaces and template
   // parameter (for example this could be "std::vector<int>"). Contrast to
   // Name.
-  StringRef QualName = {};
+  StringRef QualName;
 
   // Path of directory where the clang-doc generated file will be saved
   // (possibly unresolved)
-  StringRef Path = {};
-  StringRef DocumentationFileName = {};
+  StringRef Path;
+  StringRef DocumentationFileName;
 };
 
 // A Context is a reference that holds a relative path from a certain Info's
@@ -305,7 +280,7 @@ struct Context : public Reference {
           StringRef Path, StringRef DocumentationFileName)
       : Reference(USR, Name, IT, QualName, Path, DocumentationFileName) {}
   explicit Context(const Info &I);
-  StringRef RelativePath = {};
+  StringRef RelativePath;
 };
 
 // Holds the children of a record or namespace.
@@ -317,7 +292,7 @@ struct ScopeChildren {
   //
   // Namespaces are not syntactically valid as children of records, but making
   // this general for all possible container types reduces code complexity.
-  OwningVec<Reference> Namespaces;
+  llvm::simple_ilist<Reference> Namespaces;
   OwningVec<Reference> Records;
   OwningVec<FunctionInfo> Functions;
   OwningVec<EnumInfo> Enums;
@@ -359,19 +334,15 @@ struct TemplateParamInfo {
   // The literal contents of the code for that specifies this template parameter
   // for this declaration. Typical values will be "class T" and
   // "typename T = int".
-  StringRef Contents = {};
+  StringRef Contents;
 };
 
 struct TemplateSpecializationInfo {
-  TemplateSpecializationInfo() = default;
-  TemplateSpecializationInfo(const TemplateSpecializationInfo &Other,
-                             llvm::BumpPtrAllocator &Arena);
-
   // Indicates the declaration that this specializes.
   SymbolID SpecializationOf;
 
   // Template parameters applying to the specialized record/function.
-  llvm::ArrayRef<TemplateParamInfo> Params;
+  OwningVec<TemplateParamInfo> Params;
 };
 
 struct ConstraintInfo {
@@ -380,21 +351,18 @@ struct ConstraintInfo {
       : ConceptRef(USR, Name, InfoType::IT_concept) {}
   Reference ConceptRef;
 
-  StringRef ConstraintExpr = {};
+  StringRef ConstraintExpr;
 };
 
 // Records the template information for a struct or function that is a template
 // or an explicit template specialization.
 struct TemplateInfo {
-  TemplateInfo() = default;
-  TemplateInfo(const TemplateInfo &Other, llvm::BumpPtrAllocator &Arena);
-
   // May be empty for non-partial specializations.
-  llvm::ArrayRef<TemplateParamInfo> Params;
+  OwningVec<TemplateParamInfo> Params;
 
   // Set when this is a specialization of another record/function.
   std::optional<TemplateSpecializationInfo> Specialization;
-  llvm::ArrayRef<ConstraintInfo> Constraints;
+  OwningVec<ConstraintInfo> Constraints;
 };
 
 // Info for field types.
@@ -410,27 +378,24 @@ struct FieldTypeInfo : public TypeInfo {
            std::tie(Other.Type, Other.Name, Other.DefaultValue);
   }
 
-  StringRef Name = {}; // Name associated with this info.
+  StringRef Name; // Name associated with this info.
 
   // When used for function parameters, contains the string representing the
   // expression of the default value, if any.
-  StringRef DefaultValue = {};
+  StringRef DefaultValue;
 };
 
 // Info for member types.
 struct MemberTypeInfo : public FieldTypeInfo {
   MemberTypeInfo() = default;
-  MemberTypeInfo(const MemberTypeInfo &Other, llvm::BumpPtrAllocator &Arena);
   MemberTypeInfo(const TypeInfo &TI, StringRef Name, AccessSpecifier Access,
                  bool IsStatic = false)
       : FieldTypeInfo(TI, Name), Access(Access), IsStatic(IsStatic) {}
 
   bool operator==(const MemberTypeInfo &Other) const {
-    if (std::tie(Type, Name, Access, IsStatic) !=
-        std::tie(Other.Type, Other.Name, Other.Access, Other.IsStatic))
-      return false;
-    return std::equal(Description.begin(), Description.end(),
-                      Other.Description.begin(), Other.Description.end());
+    return std::tie(Type, Name, Access, IsStatic, Description) ==
+           std::tie(Other.Type, Other.Name, Other.Access, Other.IsStatic,
+                    Other.Description);
   }
 
   OwningVec<CommentInfo> Description;
@@ -465,7 +430,7 @@ struct Location : public llvm::ilist_node<Location> {
            std::tie(Other.StartLineNumber, Other.EndLineNumber, Other.Filename);
   }
 
-  StringRef Filename = {};
+  StringRef Filename;
   int StartLineNumber = 0;
   int EndLineNumber = 0;
   bool IsFileInRootDir = false;
@@ -477,9 +442,9 @@ struct Info {
        StringRef Name = StringRef(), StringRef Path = StringRef())
       : Path(internString(Path)), Name(internString(Name)), USR(USR), IT(IT) {}
 
-  Info(const Info &Other, llvm::BumpPtrAllocator &Arena);
   Info(const Info &Other) = delete;
   Info(Info &&Other) = default;
+  virtual ~Info() = default;
 
   Info &operator=(Info &&Other) = default;
 
@@ -495,18 +460,18 @@ struct Info {
   StringRef getFileBaseName() const;
 
   // Path of directory where the clang-doc generated file will be saved.
-  StringRef Path = {};
+  StringRef Path;
 
   // Unqualified name of the decl.
-  StringRef Name = {};
+  StringRef Name;
 
   // The name used for the file that this info is documented in.
   // In the JSON generator, infos are documented in files with mangled names.
   // Thus, we keep track of the physical filename for linking purposes.
-  StringRef DocumentationFileName = {};
+  StringRef DocumentationFileName;
 
   // List of parent namespaces for this decl.
-  llvm::ArrayRef<Reference> Namespace;
+  llvm::SmallVector<Reference, 4> Namespace;
 
   // Unique identifier for the decl described by this Info.
   SymbolID USR = SymbolID();
@@ -519,6 +484,8 @@ struct Info {
 
   // Comment description of this decl.
   OwningVec<CommentInfo> Description;
+
+  SmallVector<Context, 4> Contexts;
 };
 
 inline Context::Context(const Info &I)
@@ -540,8 +507,6 @@ struct SymbolInfo : public Info {
              StringRef Name = StringRef(), StringRef Path = StringRef())
       : Info(IT, USR, Name, Path) {}
 
-  SymbolInfo(const SymbolInfo &Other, llvm::BumpPtrAllocator &Arena);
-
   void merge(SymbolInfo &&I);
 
   bool operator<(const SymbolInfo &Other) const {
@@ -549,9 +514,8 @@ struct SymbolInfo : public Info {
     // generated in the order of the source code.
     // If the declaration location is the same, or not present
     // we sort by defined location otherwise fallback to the extracted name
-    if (Loc.size() > 0 && Other.Loc.size() > 0 &&
-        Loc.front() != Other.Loc.front())
-      return Loc.front() < Other.Loc.front();
+    if (Loc.size() > 0 && Other.Loc.size() > 0 && Loc[0] != Other.Loc[0])
+      return Loc[0] < Other.Loc[0];
 
     if (DefLoc && Other.DefLoc && *DefLoc != *Other.DefLoc)
       return *DefLoc < *Other.DefLoc;
@@ -560,8 +524,8 @@ struct SymbolInfo : public Info {
   }
 
   std::optional<Location> DefLoc;     // Location where this decl is defined.
-  OwningVec<Location> Loc;            // Locations where this decl is declared.
-  StringRef MangledName = {};
+  llvm::SmallVector<Location, 2> Loc; // Locations where this decl is declared.
+  StringRef MangledName;
   bool IsStatic = false;
 };
 
@@ -571,7 +535,6 @@ struct FriendInfo : public SymbolInfo, public llvm::ilist_node<FriendInfo> {
   FriendInfo(const InfoType IT, const SymbolID &USR,
              const StringRef Name = StringRef())
       : SymbolInfo(IT, USR, Name) {}
-  FriendInfo(const FriendInfo &Other, llvm::BumpPtrAllocator &Arena);
   bool mergeable(const FriendInfo &Other);
   void merge(FriendInfo &&Other);
 
@@ -601,8 +564,8 @@ struct FunctionInfo : public SymbolInfo, public llvm::ilist_node<FunctionInfo> {
 
   Reference Parent;
   TypeInfo ReturnType;
-  llvm::ArrayRef<FieldTypeInfo> Params;
-  StringRef Prototype = {};
+  llvm::SmallVector<FieldTypeInfo, 4> Params;
+  StringRef Prototype;
 
   // When present, this function is a template or specialization.
   std::optional<TemplateInfo> Template;
@@ -623,8 +586,6 @@ struct RecordInfo : public SymbolInfo {
   RecordInfo(SymbolID USR = SymbolID(), StringRef Name = StringRef(),
              StringRef Path = StringRef());
 
-  RecordInfo(const RecordInfo &Other, llvm::BumpPtrAllocator &Arena);
-
   void merge(RecordInfo &&I);
 
   // Type of this record (struct, class, union, interface).
@@ -639,18 +600,18 @@ struct RecordInfo : public SymbolInfo {
   // When present, this record is a template or specialization.
   std::optional<TemplateInfo> Template;
 
-  llvm::ArrayRef<MemberTypeInfo> Members; // List of info about record members.
-  llvm::ArrayRef<Reference> Parents;      // List of base/parent records
-                                          // (does not include virtual
-                                          // parents).
-  llvm::ArrayRef<Reference>
+  llvm::SmallVector<MemberTypeInfo, 4>
+      Members;                             // List of info about record members.
+  llvm::SmallVector<Reference, 4> Parents; // List of base/parent records
+                                           // (does not include virtual
+                                           // parents).
+  llvm::SmallVector<Reference, 4>
       VirtualParents; // List of virtual base/parent records.
 
-  llvm::ArrayRef<BaseRecordInfo>
-      Bases; // List of base/parent records; this includes
-             // inherited methods and attributes
+  OwningVec<BaseRecordInfo> Bases; // List of base/parent records; this includes
+                                   // inherited methods and attributes
 
-  llvm::ArrayRef<FriendInfo> Friends;
+  OwningVec<FriendInfo> Friends;
 
   ScopeChildren Children;
 };
@@ -668,7 +629,7 @@ struct TypedefInfo : public SymbolInfo, public llvm::ilist_node<TypedefInfo> {
   std::optional<TemplateInfo> Template;
 
   // Underlying type declaration
-  StringRef TypeDeclaration = {};
+  StringRef TypeDeclaration;
 
   // Indicates if this is a new C++ "using"-style typedef:
   //   using MyVector = std::vector<int>
@@ -677,10 +638,8 @@ struct TypedefInfo : public SymbolInfo, public llvm::ilist_node<TypedefInfo> {
   bool IsUsing = false;
 };
 
-struct BaseRecordInfo : public RecordInfo,
-                        public llvm::ilist_node<BaseRecordInfo> {
+struct BaseRecordInfo : public RecordInfo {
   BaseRecordInfo();
-  BaseRecordInfo(const BaseRecordInfo &Other, llvm::BumpPtrAllocator &Arena);
   BaseRecordInfo(SymbolID USR, StringRef Name, StringRef Path, bool IsVirtual,
                  AccessSpecifier Access, bool IsParent);
 
@@ -700,8 +659,6 @@ struct EnumValueInfo {
       : Name(internString(Name)), Value(internString(Value)),
         ValueExpr(internString(ValueExpr)) {}
 
-  EnumValueInfo(const EnumValueInfo &Other, llvm::BumpPtrAllocator &Arena);
-
   bool operator==(const EnumValueInfo &Other) const {
     return std::tie(Name, Value, ValueExpr) ==
            std::tie(Other.Name, Other.Value, Other.ValueExpr);
@@ -738,7 +695,7 @@ struct EnumInfo : public SymbolInfo, public llvm::ilist_node<EnumInfo> {
   // this will be "short".
   std::optional<TypeInfo> BaseType;
 
-  llvm::ArrayRef<EnumValueInfo> Members; // List of enum members.
+  llvm::SmallVector<EnumValueInfo, 4> Members; // List of enum members.
 };
 
 struct ConceptInfo : public SymbolInfo, public llvm::ilist_node<ConceptInfo> {
@@ -747,9 +704,9 @@ struct ConceptInfo : public SymbolInfo, public llvm::ilist_node<ConceptInfo> {
 
   void merge(ConceptInfo &&I);
 
-  bool IsType = false;
+  bool IsType;
   TemplateInfo Template;
-  StringRef ConstraintExpression = {};
+  StringRef ConstraintExpression;
 };
 
 struct Index : public Reference {
@@ -766,7 +723,7 @@ struct Index : public Reference {
   std::optional<StringRef> JumpToSection;
   llvm::StringMap<Index> Children;
 
-  std::vector<const Index *> getSortedChildren() const;
+  OwningVec<const Index *> getSortedChildren() const;
   void sort();
 };
 
@@ -777,12 +734,6 @@ struct Index : public Reference {
 // if they are 
diff erent.
 llvm::Expected<OwnedPtr<Info>> mergeInfos(OwningPtrArray<Info> &Values);
 
-// Merges a single new Info into an existing Reduced Info (allocating it if
-// needed).
-llvm::Error mergeSingleInfo(doc::OwnedPtr<doc::Info> &Reduced,
-                            doc::OwnedPtr<doc::Info> &&NewInfo,
-                            llvm::BumpPtrAllocator &Arena);
-
 struct ClangDocContext {
   ClangDocContext(tooling::ExecutionContext *ECtx, StringRef ProjectName,
                   bool PublicOnly, StringRef OutDirectory, StringRef SourceRoot,
@@ -822,26 +773,28 @@ struct ClangDocContext {
 // Ensure arena allocated types remain safe to allocate in the arena.
 // Only trivially destructible types are safe, so enforce that at compile-time.
 static_assert(std::is_trivially_destructible_v<CommentInfo>);
-static_assert(std::is_trivially_destructible_v<ConceptInfo>);
 static_assert(std::is_trivially_destructible_v<ConstraintInfo>);
-static_assert(std::is_trivially_destructible_v<EnumInfo>);
 static_assert(std::is_trivially_destructible_v<FieldTypeInfo>);
-static_assert(std::is_trivially_destructible_v<FriendInfo>);
-static_assert(std::is_trivially_destructible_v<FunctionInfo>);
-static_assert(std::is_trivially_destructible_v<Info>);
 static_assert(std::is_trivially_destructible_v<Location>);
-static_assert(std::is_trivially_destructible_v<MemberTypeInfo>);
-static_assert(std::is_trivially_destructible_v<NamespaceInfo>);
-static_assert(std::is_trivially_destructible_v<RecordInfo>);
 static_assert(std::is_trivially_destructible_v<Reference>);
-static_assert(std::is_trivially_destructible_v<ScopeChildren>);
-static_assert(std::is_trivially_destructible_v<SymbolInfo>);
-static_assert(std::is_trivially_destructible_v<TemplateInfo>);
 static_assert(std::is_trivially_destructible_v<TemplateParamInfo>);
-static_assert(std::is_trivially_destructible_v<TemplateSpecializationInfo>);
 static_assert(std::is_trivially_destructible_v<TypeInfo>);
-static_assert(std::is_trivially_destructible_v<TypedefInfo>);
-static_assert(std::is_trivially_destructible_v<VarInfo>);
+
+// FIXME: These types need to be trivially destructible for arena allocation.
+static_assert(!std::is_trivially_destructible_v<ConceptInfo>);
+static_assert(!std::is_trivially_destructible_v<EnumInfo>);
+static_assert(!std::is_trivially_destructible_v<FriendInfo>);
+static_assert(!std::is_trivially_destructible_v<FunctionInfo>);
+static_assert(!std::is_trivially_destructible_v<Info>);
+static_assert(!std::is_trivially_destructible_v<MemberTypeInfo>);
+static_assert(!std::is_trivially_destructible_v<NamespaceInfo>);
+static_assert(!std::is_trivially_destructible_v<RecordInfo>);
+static_assert(!std::is_trivially_destructible_v<ScopeChildren>);
+static_assert(!std::is_trivially_destructible_v<SymbolInfo>);
+static_assert(!std::is_trivially_destructible_v<TemplateInfo>);
+static_assert(!std::is_trivially_destructible_v<TemplateSpecializationInfo>);
+static_assert(!std::is_trivially_destructible_v<TypedefInfo>);
+static_assert(!std::is_trivially_destructible_v<VarInfo>);
 
 } // namespace doc
 } // namespace clang

diff  --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index 4b2f0b5eac3a4..ef7fed6cc8501 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -182,8 +182,8 @@ StringRef Serializer::getTypeAlias(const TypeAliasDecl *Alias) {
 //
 // }
 // }
-StringRef
-Serializer::getInfoRelativePath(llvm::ArrayRef<doc::Reference> Namespaces) {
+StringRef 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);
@@ -258,7 +258,9 @@ void ClangDocCommentVisitor::visitInlineCommandComment(
   for (unsigned I = 0, E = C->getNumArgs(); I != E; ++I)
     Args.push_back(internString(C->getArgText(I).trim()));
   if (!Args.empty()) {
-    CurrentCI.Args = allocateArray(Args, TransientArena);
+    StringRef *ArgsMem = TransientArena.Allocate<StringRef>(Args.size());
+    std::uninitialized_copy(Args.begin(), Args.end(), ArgsMem);
+    CurrentCI.Args = llvm::ArrayRef<StringRef>(ArgsMem, Args.size());
   }
 }
 
@@ -274,10 +276,16 @@ void ClangDocCommentVisitor::visitHTMLStartTagComment(
     AttrValues.push_back(internString(Attr.Value));
   }
   if (!AttrKeys.empty()) {
-    CurrentCI.AttrKeys = allocateArray(AttrKeys, TransientArena);
+    StringRef *KeysMem = TransientArena.Allocate<StringRef>(AttrKeys.size());
+    std::uninitialized_copy(AttrKeys.begin(), AttrKeys.end(), KeysMem);
+    CurrentCI.AttrKeys = llvm::ArrayRef<StringRef>(KeysMem, AttrKeys.size());
   }
   if (!AttrValues.empty()) {
-    CurrentCI.AttrValues = allocateArray(AttrValues, TransientArena);
+    StringRef *ValuesMem =
+        TransientArena.Allocate<StringRef>(AttrValues.size());
+    std::uninitialized_copy(AttrValues.begin(), AttrValues.end(), ValuesMem);
+    CurrentCI.AttrValues =
+        llvm::ArrayRef<StringRef>(ValuesMem, AttrValues.size());
   }
 }
 
@@ -294,7 +302,9 @@ void ClangDocCommentVisitor::visitBlockCommandComment(
   for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
     Args.push_back(internString(C->getArgText(I).trim()));
   if (!Args.empty()) {
-    CurrentCI.Args = allocateArray(Args, TransientArena);
+    StringRef *ArgsMem = TransientArena.Allocate<StringRef>(Args.size());
+    std::uninitialized_copy(Args.begin(), Args.end(), ArgsMem);
+    CurrentCI.Args = llvm::ArrayRef<StringRef>(ArgsMem, Args.size());
   }
 }
 
@@ -465,35 +475,29 @@ void Serializer::InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info) {
 }
 
 void Serializer::InsertChild(ScopeChildren &Scope, const RecordInfo &Info) {
-  Reference *R = allocatePtr<Reference>(
-      Info.USR, Info.Name, InfoType::IT_record, Info.Name,
-      getInfoRelativePath(Info.Namespace), Info.MangledName);
-  Scope.Records.push_back(*R);
+  Scope.Records.emplace_back(Info.USR, Info.Name, InfoType::IT_record,
+                             Info.Name, getInfoRelativePath(Info.Namespace),
+                             Info.MangledName);
 }
 
 void Serializer::InsertChild(ScopeChildren &Scope, EnumInfo Info) {
-  EnumInfo *E = allocatePtr<EnumInfo>(std::move(Info));
-  Scope.Enums.push_back(*E);
+  Scope.Enums.push_back(std::move(Info));
 }
 
 void Serializer::InsertChild(ScopeChildren &Scope, FunctionInfo Info) {
-  FunctionInfo *F = allocatePtr<FunctionInfo>(std::move(Info));
-  Scope.Functions.push_back(*F);
+  Scope.Functions.push_back(std::move(Info));
 }
 
 void Serializer::InsertChild(ScopeChildren &Scope, TypedefInfo Info) {
-  TypedefInfo *T = allocatePtr<TypedefInfo>(std::move(Info));
-  Scope.Typedefs.push_back(*T);
+  Scope.Typedefs.push_back(std::move(Info));
 }
 
 void Serializer::InsertChild(ScopeChildren &Scope, ConceptInfo Info) {
-  ConceptInfo *C = allocatePtr<ConceptInfo>(std::move(Info));
-  Scope.Concepts.push_back(*C);
+  Scope.Concepts.push_back(std::move(Info));
 }
 
 void Serializer::InsertChild(ScopeChildren &Scope, VarInfo Info) {
-  VarInfo *V = allocatePtr<VarInfo>(std::move(Info));
-  Scope.Variables.push_back(*V);
+  Scope.Variables.push_back(std::move(Info));
 }
 
 // Creates a parent of the correct type for the given child and inserts it into
@@ -577,18 +581,14 @@ AccessSpecifier Serializer::getFinalAccessSpecifier(AccessSpecifier FirstAS,
 // record, the access specification of the field depends on the inheritance mode
 void Serializer::parseFields(RecordInfo &I, const RecordDecl *D,
                              bool PublicOnly, AccessSpecifier Access) {
-  SmallVector<MemberTypeInfo, 4> Members;
   for (const FieldDecl *F : D->fields()) {
     if (!shouldSerializeInfo(PublicOnly, /*IsInAnonymousNamespace=*/false, F))
       continue;
-    populateMemberTypeInfo(Members, Access, F);
+    populateMemberTypeInfo(I, Access, F);
   }
   const auto *CxxRD = dyn_cast<CXXRecordDecl>(D);
-  if (!CxxRD) {
-    if (!Members.empty())
-      I.Members = allocateArray<MemberTypeInfo>(Members, TransientArena);
+  if (!CxxRD)
     return;
-  }
   for (Decl *CxxDecl : CxxRD->decls()) {
     auto *VD = dyn_cast<VarDecl>(CxxDecl);
     if (!VD ||
@@ -596,49 +596,40 @@ void Serializer::parseFields(RecordInfo &I, const RecordDecl *D,
       continue;
 
     if (VD->isStaticDataMember())
-      populateMemberTypeInfo(Members, Access, VD, /*IsStatic=*/true);
+      populateMemberTypeInfo(I, Access, VD, /*IsStatic=*/true);
   }
-  if (!Members.empty())
-    I.Members = allocateArray<MemberTypeInfo>(Members, TransientArena);
 }
 
 void Serializer::parseEnumerators(EnumInfo &I, const EnumDecl *D) {
-  llvm::SmallVector<EnumValueInfo, 4> LocalMembers;
   for (const EnumConstantDecl *E : D->enumerators()) {
     std::string ValueExpr;
     if (const Expr *InitExpr = E->getInitExpr())
       ValueExpr = getSourceCode(D, InitExpr->getSourceRange());
     SmallString<16> ValueStr;
     E->getInitVal().toString(ValueStr);
-    EnumValueInfo &Member = LocalMembers.emplace_back(
-        E->getNameAsString(), ValueStr.str(), ValueExpr);
+    I.Members.emplace_back(E->getNameAsString(), ValueStr.str(), ValueExpr);
     ASTContext &Context = E->getASTContext();
     if (RawComment *Comment =
             E->getASTContext().getRawCommentForDeclNoCache(E)) {
       Comment->setAttached();
       if (comments::FullComment *Fc = Comment->parse(Context, nullptr, E)) {
-        CommentInfo *NewCI = allocatePtr<CommentInfo>();
-        Member.Description.push_back(*NewCI);
+        EnumValueInfo &Member = I.Members.back();
+        Member.Description.emplace_back();
         parseFullComment(Fc, Member.Description.back());
       }
     }
   }
-  if (!LocalMembers.empty())
-    I.Members = allocateArray<EnumValueInfo>(LocalMembers, TransientArena);
 }
 
 void Serializer::parseParameters(FunctionInfo &I, const FunctionDecl *D) {
-  llvm::SmallVector<FieldTypeInfo, 4> LocalParams;
   auto &LO = D->getLangOpts();
   for (const ParmVarDecl *P : D->parameters()) {
-    FieldTypeInfo &FieldInfo = LocalParams.emplace_back(
+    FieldTypeInfo &FieldInfo = I.Params.emplace_back(
         getTypeInfoForType(P->getOriginalType(), LO), P->getNameAsString());
     if (std::optional<StringRef> DefaultValue =
             getSourceCode(D, P->getDefaultArgRange()))
       FieldInfo.DefaultValue = *DefaultValue;
   }
-  if (!LocalParams.empty())
-    I.Params = allocateArray<FieldTypeInfo>(LocalParams, TransientArena);
 }
 
 // TODO: Remove the serialization of Parents and VirtualParents, this
@@ -648,36 +639,28 @@ void Serializer::parseBases(RecordInfo &I, const CXXRecordDecl *D) {
   if (!D->isThisDeclarationADefinition())
     return;
 
-  llvm::SmallVector<Reference, 4> LocalParents;
   for (const CXXBaseSpecifier &B : D->bases()) {
     if (B.isVirtual())
       continue;
     if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
       const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
-      LocalParents.emplace_back(getUSRForDecl(D), B.getType().getAsString(),
-                                InfoType::IT_record, B.getType().getAsString());
+      I.Parents.emplace_back(getUSRForDecl(D), B.getType().getAsString(),
+                             InfoType::IT_record, B.getType().getAsString());
     } else if (const RecordDecl *P = getRecordDeclForType(B.getType()))
-      LocalParents.emplace_back(
-          getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record,
-          P->getQualifiedNameAsString(), internString(getInfoRelativePath(P)));
+      I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
+                             InfoType::IT_record, P->getQualifiedNameAsString(),
+                             internString(getInfoRelativePath(P)));
     else
-      LocalParents.emplace_back(SymbolID(), B.getType().getAsString());
+      I.Parents.emplace_back(SymbolID(), B.getType().getAsString());
   }
-  if (!LocalParents.empty())
-    I.Parents = allocateArray<Reference>(LocalParents, TransientArena);
-
-  llvm::SmallVector<Reference, 4> LocalVirtualParents;
   for (const CXXBaseSpecifier &B : D->vbases()) {
     if (const RecordDecl *P = getRecordDeclForType(B.getType()))
-      LocalVirtualParents.emplace_back(
+      I.VirtualParents.emplace_back(
           getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record,
           P->getQualifiedNameAsString(), internString(getInfoRelativePath(P)));
     else
-      LocalVirtualParents.emplace_back(SymbolID(), B.getType().getAsString());
+      I.VirtualParents.emplace_back(SymbolID(), B.getType().getAsString());
   }
-  if (!LocalVirtualParents.empty())
-    I.VirtualParents =
-        allocateArray<Reference>(LocalVirtualParents, TransientArena);
 }
 
 template <typename T>
@@ -725,13 +708,10 @@ void Serializer::populateTemplateParameters(
     if (!TemplateInfo) {
       TemplateInfo.emplace();
     }
-    llvm::SmallVector<TemplateParamInfo, 4> LocalParams;
     for (const NamedDecl *ND : *ParamList) {
-      LocalParams.emplace_back(getSourceCode(ND, ND->getSourceRange()));
+      TemplateInfo->Params.emplace_back(
+          getSourceCode(ND, ND->getSourceRange()));
     }
-    if (!LocalParams.empty())
-      TemplateInfo->Params =
-          allocateArray<TemplateParamInfo>(LocalParams, TransientArena);
   }
 }
 
@@ -794,14 +774,9 @@ void Serializer::populateInfo(Info &I, const T *D, const FullComment *C,
                           ConversionDecl->getConversionType().getAsString());
   else
     I.Name = internString(D->getNameAsString());
-  llvm::SmallVector<Reference, 4> LocalNamespaces;
-  populateParentNamespaces(LocalNamespaces, D, IsInAnonymousNamespace);
-  if (!LocalNamespaces.empty())
-    I.Namespace = allocateArray<Reference>(LocalNamespaces, TransientArena);
+  populateParentNamespaces(I.Namespace, D, IsInAnonymousNamespace);
   if (C) {
-
-    CommentInfo *NewCI = allocatePtr<CommentInfo>();
-    I.Description.push_back(*NewCI);
+    I.Description.emplace_back();
     parseFullComment(C, I.Description.back());
   }
 }
@@ -813,10 +788,8 @@ void Serializer::populateSymbolInfo(SymbolInfo &I, const T *D,
   populateInfo(I, D, C, IsInAnonymousNamespace);
   if (D->isThisDeclarationADefinition())
     I.DefLoc = Loc;
-  else {
-    Location *NewL = allocatePtr<Location>(Loc);
-    I.Loc.push_back(*NewL);
-  }
+  else
+    I.Loc.emplace_back(Loc);
 
   auto *Mangler = ItaniumMangleContext::create(
       D->getASTContext(), D->getASTContext().getDiagnostics());
@@ -838,8 +811,7 @@ void Serializer::populateSymbolInfo(SymbolInfo &I, const T *D,
 }
 
 void Serializer::handleCompoundConstraints(
-    const Expr *Constraint,
-    llvm::SmallVectorImpl<ConstraintInfo> &ConstraintInfos) {
+    const Expr *Constraint, OwningVec<ConstraintInfo> &ConstraintInfos) {
   if (Constraint->getStmtClass() == Stmt::ParenExprClass) {
     handleCompoundConstraints(dyn_cast<ParenExpr>(Constraint)->getSubExpr(),
                               ConstraintInfos);
@@ -863,7 +835,6 @@ void Serializer::populateConstraints(TemplateInfo &I, const TemplateDecl *D) {
 
   SmallVector<AssociatedConstraint> AssociatedConstraints;
   D->getAssociatedConstraints(AssociatedConstraints);
-  SmallVector<ConstraintInfo, 4> LocalConstraints;
   for (const auto &Constraint : AssociatedConstraints) {
     if (!Constraint)
       continue;
@@ -875,14 +846,11 @@ void Serializer::populateConstraints(TemplateInfo &I, const TemplateDecl *D) {
       ConstraintInfo CI(getUSRForDecl(ConstraintExpr->getNamedConcept()),
                         ConstraintExpr->getNamedConcept()->getNameAsString());
       CI.ConstraintExpr = internString(exprToString(ConstraintExpr));
-      LocalConstraints.push_back(std::move(CI));
+      I.Constraints.push_back(std::move(CI));
     } else {
-      handleCompoundConstraints(Constraint.ConstraintExpr, LocalConstraints);
+      handleCompoundConstraints(Constraint.ConstraintExpr, I.Constraints);
     }
   }
-  if (!LocalConstraints.empty())
-    I.Constraints =
-        allocateArray<ConstraintInfo>(LocalConstraints, TransientArena);
 }
 
 void Serializer::populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
@@ -911,13 +879,9 @@ void Serializer::populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
 
     // Template parameters to the specialization.
     if (FTSI->TemplateArguments) {
-      SmallVector<TemplateParamInfo, 4> LocalParams;
       for (const TemplateArgument &Arg : FTSI->TemplateArguments->asArray()) {
-        LocalParams.push_back(convertTemplateArgToInfo(D, Arg));
+        Specialization.Params.push_back(convertTemplateArgToInfo(D, Arg));
       }
-      if (!LocalParams.empty())
-        Specialization.Params =
-            allocateArray<TemplateParamInfo>(LocalParams, TransientArena);
     }
   }
 }
@@ -937,28 +901,26 @@ void Serializer::populateMemberTypeInfo(T &I, const Decl *D) {
 
   Comment->setAttached();
   if (comments::FullComment *Fc = Comment->parse(Context, nullptr, D)) {
-    CommentInfo *NewCI = allocatePtr<CommentInfo>();
-    I.Description.push_back(*NewCI);
+    I.Description.emplace_back();
     parseFullComment(Fc, I.Description.back());
   }
 }
 
-void Serializer::populateMemberTypeInfo(
-    SmallVectorImpl<MemberTypeInfo> &Members, 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 = Members.emplace_back(
+  MemberTypeInfo &NewMember = I.Members.emplace_back(
       getTypeInfoForType(D->getTypeSourceInfo()->getType(), D->getLangOpts()),
       D->getNameAsString(),
       getFinalAccessSpecifier(Access, D->getAccessUnsafe()), IsStatic);
   populateMemberTypeInfo(NewMember, D);
 }
 
-void Serializer::parseBases(llvm::SmallVectorImpl<BaseRecordInfo> &Bases,
-                            const CXXRecordDecl *D, bool IsFileInRootDir,
-                            bool PublicOnly, bool IsParent,
-                            AccessSpecifier ParentAccess) {
+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;
@@ -997,15 +959,14 @@ void Serializer::parseBases(llvm::SmallVectorImpl<BaseRecordInfo> &Bases,
                                  IsInAnonymousNamespace);
             FI.Access =
                 getFinalAccessSpecifier(BI.Access, MD->getAccessUnsafe());
-            FunctionInfo *FIPtr = allocatePtr<FunctionInfo>(std::move(FI));
-            BI.Children.Functions.push_back(*FIPtr);
+            BI.Children.Functions.emplace_back(std::move(FI));
           }
-        Bases.emplace_back(std::move(BI));
+        I.Bases.emplace_back(std::move(BI));
         // Call this function recursively to get the inherited classes of
         // this base; these new bases will also get stored in the original
         // RecordInfo: I.
-        parseBases(Bases, Base, IsFileInRootDir, PublicOnly, false,
-                   Bases.back().Access);
+        parseBases(I, Base, IsFileInRootDir, PublicOnly, false,
+                   I.Bases.back().Access);
       }
     }
   }
@@ -1034,8 +995,6 @@ void Serializer::parseFriends(RecordInfo &RI, const CXXRecordDecl *D) {
   if (!D->hasDefinition() || !D->hasFriends())
     return;
 
-  llvm::SmallVector<FriendInfo, 4> LocalFriends;
-
   for (const FriendDecl *FD : D->friends()) {
     if (FD->isUnsupportedFriend())
       continue;
@@ -1057,12 +1016,9 @@ void Serializer::parseFriends(RecordInfo &RI, const CXXRecordDecl *D) {
       if (isa<RecordDecl>(ActualTD->getTemplatedDecl()))
         F.IsClass = true;
       F.Template.emplace();
-      llvm::SmallVector<TemplateParamInfo, 4> LocalParams;
       for (const auto *Param : ActualTD->getTemplateParameters()->asArray())
-        LocalParams.emplace_back(getSourceCode(Param, Param->getSourceRange()));
-      if (!LocalParams.empty())
-        F.Template->Params =
-            allocateArray<TemplateParamInfo>(LocalParams, TransientArena);
+        F.Template->Params.emplace_back(
+            getSourceCode(Param, Param->getSourceRange()));
       ActualDecl = ActualTD->getTemplatedDecl();
     }
 
@@ -1080,10 +1036,8 @@ void Serializer::parseFriends(RecordInfo &RI, const CXXRecordDecl *D) {
                   getInfoRelativePath(ActualDecl));
 
     populateMemberTypeInfo(F, ActualDecl);
-    LocalFriends.push_back(std::move(F));
+    RI.Friends.push_back(std::move(F));
   }
-  if (!LocalFriends.empty())
-    RI.Friends = allocateArray<FriendInfo>(LocalFriends, TransientArena);
 }
 
 std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
@@ -1107,11 +1061,7 @@ Serializer::emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
     }
     // TODO: remove first call to parseBases, that function should be deleted
     parseBases(*RI, C);
-    llvm::SmallVector<BaseRecordInfo, 4> LocalBases;
-    parseBases(LocalBases, C, /*IsFileInRootDir=*/true, PublicOnly,
-               /*IsParent=*/true);
-    if (!LocalBases.empty())
-      RI->Bases = allocateArray<BaseRecordInfo>(LocalBases, TransientArena);
+    parseBases(*RI, C, /*IsFileInRootDir=*/true, PublicOnly, /*IsParent=*/true);
     parseFriends(*RI, C);
   }
   RI->Path = internString(getInfoRelativePath(RI->Namespace));
@@ -1144,23 +1094,15 @@ Serializer::emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
             dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
       if (const ASTTemplateArgumentListInfo *AsWritten =
               CTPSD->getTemplateArgsAsWritten()) {
-        llvm::SmallVector<TemplateParamInfo, 4> LocalParams;
         for (unsigned Idx = 0; Idx < AsWritten->getNumTemplateArgs(); Idx++) {
-          LocalParams.emplace_back(
+          Specialization.Params.emplace_back(
               getSourceCode(D, (*AsWritten)[Idx].getSourceRange()));
         }
-        if (!LocalParams.empty())
-          Specialization.Params =
-              allocateArray<TemplateParamInfo>(LocalParams, TransientArena);
       }
     } else {
-      llvm::SmallVector<TemplateParamInfo, 4> LocalParams;
       for (const TemplateArgument &Arg : CTSD->getTemplateArgs().asArray()) {
-        LocalParams.push_back(convertTemplateArgToInfo(D, Arg));
+        Specialization.Params.push_back(convertTemplateArgToInfo(D, Arg));
       }
-      if (!LocalParams.empty())
-        Specialization.Params =
-            allocateArray<TemplateParamInfo>(LocalParams, TransientArena);
     }
   }
 
@@ -1222,9 +1164,8 @@ void Serializer::extractCommentFromDecl(const Decl *D, TypedefInfo &Info) {
 
   Comment->setAttached();
   if (comments::FullComment *Fc = Comment->parse(Context, nullptr, D)) {
-    CommentInfo *NewCI = allocatePtr<CommentInfo>();
-    Info.Description.push_back(*NewCI);
-    parseFullComment(Fc, *NewCI);
+    Info.Description.emplace_back();
+    parseFullComment(Fc, Info.Description.back());
   }
 }
 
@@ -1317,13 +1258,10 @@ Serializer::emitInfo(const ConceptDecl *D, const FullComment *FC,
   Concept.ConstraintExpression = exprToString(D->getConstraintExpr());
 
   if (auto *ConceptParams = D->getTemplateParameters()) {
-    llvm::SmallVector<TemplateParamInfo, 4> LocalParams;
     for (const auto *Param : ConceptParams->asArray()) {
-      LocalParams.emplace_back(getSourceCode(Param, Param->getSourceRange()));
+      Concept.Template.Params.emplace_back(
+          getSourceCode(Param, Param->getSourceRange()));
     }
-    if (!LocalParams.empty())
-      Concept.Template.Params =
-          allocateArray<TemplateParamInfo>(LocalParams, TransientArena);
   }
 
   if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))

diff  --git a/clang-tools-extra/clang-doc/Serialize.h b/clang-tools-extra/clang-doc/Serialize.h
index 3d53514d0756a..04891bea33220 100644
--- a/clang-tools-extra/clang-doc/Serialize.h
+++ b/clang-tools-extra/clang-doc/Serialize.h
@@ -94,7 +94,8 @@ class Serializer {
 
   StringRef getTypeAlias(const TypeAliasDecl *Alias);
 
-  StringRef getInfoRelativePath(llvm::ArrayRef<doc::Reference> Namespaces);
+  StringRef
+  getInfoRelativePath(const llvm::SmallVectorImpl<doc::Reference> &Namespaces);
 
   StringRef getInfoRelativePath(const Decl *D);
 
@@ -138,9 +139,8 @@ class Serializer {
 
   void parseBases(RecordInfo &I, const CXXRecordDecl *D);
 
-  void parseBases(llvm::SmallVectorImpl<BaseRecordInfo> &Bases,
-                  const CXXRecordDecl *D, bool IsFileInRootDir, bool PublicOnly,
-                  bool IsParent,
+  void parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir,
+                  bool PublicOnly, bool IsParent,
                   AccessSpecifier ParentAccess = AccessSpecifier::AS_public);
 
   template <typename T>
@@ -165,9 +165,8 @@ class Serializer {
   void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
                           Location Loc, bool &IsInAnonymousNamespace);
 
-  void handleCompoundConstraints(
-      const Expr *Constraint,
-      llvm::SmallVectorImpl<ConstraintInfo> &ConstraintInfos);
+  void handleCompoundConstraints(const Expr *Constraint,
+                                 OwningVec<ConstraintInfo> &ConstraintInfos);
 
   void populateConstraints(TemplateInfo &I, const TemplateDecl *D);
 
@@ -177,9 +176,8 @@ class Serializer {
 
   template <typename T> void populateMemberTypeInfo(T &I, const Decl *D);
 
-  void populateMemberTypeInfo(llvm::SmallVectorImpl<MemberTypeInfo> &Members,
-                              AccessSpecifier &Access, const DeclaratorDecl *D,
-                              bool IsStatic = false);
+  void populateMemberTypeInfo(RecordInfo &I, AccessSpecifier &Access,
+                              const DeclaratorDecl *D, bool IsStatic = false);
 
   void parseFriends(RecordInfo &RI, const CXXRecordDecl *D);
 

diff  --git a/clang-tools-extra/clang-doc/YAMLGenerator.cpp b/clang-tools-extra/clang-doc/YAMLGenerator.cpp
index b5c43837f9505..9e3bca84877e0 100644
--- a/clang-tools-extra/clang-doc/YAMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/YAMLGenerator.cpp
@@ -31,70 +31,9 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(BaseRecordInfo)
 LLVM_YAML_IS_SEQUENCE_VECTOR(OwnedPtr<CommentInfo>)
 
 namespace llvm {
-
-template <typename T>
-bool operator==(const llvm::simple_ilist<T> &LHS,
-                const llvm::simple_ilist<T> &RHS) {
-  auto LIt = LHS.begin(), LEnd = LHS.end();
-  auto RIt = RHS.begin(), REnd = RHS.end();
-  for (; LIt != LEnd && RIt != REnd; ++LIt, ++RIt) {
-    if (!(*LIt == *RIt))
-      return false;
-  }
-  return LIt == LEnd && RIt == REnd;
-}
-
-template <typename T>
-bool operator!=(const llvm::simple_ilist<T> &LHS,
-                const llvm::simple_ilist<T> &RHS) {
-  return !(LHS == RHS);
-}
-
 namespace yaml {
 
-// Provide SequenceTraits for ArrayRef<T*> since YAMLTraits only provides it for
-// MutableArrayRef
-template <typename T> struct SequenceTraits<ArrayRef<T *>> {
-  static size_t size(IO &io, ArrayRef<T *> &seq) { return seq.size(); }
-  static T *&element(IO &io, ArrayRef<T *> &seq, size_t index) {
-    // ArrayRef is not mutable, but YAML output only reads the value.
-    return const_cast<T *&>(seq[index]);
-  }
-};
-
-template <typename T> struct SequenceTraits<llvm::simple_ilist<T>> {
-  static size_t size(IO &io, llvm::simple_ilist<T> &seq) { return seq.size(); }
-  static T &element(IO &io, llvm::simple_ilist<T> &seq, size_t index) {
-    return *std::next(seq.begin(), index);
-  }
-};
-
-// Map pointers to the value mappings as clang-doc only does output
-// serialization.
-template <typename T> struct PointerMappingTraits {
-  static void mapping(IO &IO, T *&Val) {
-    if (Val)
-      MappingTraits<T>::mapping(IO, *Val);
-  }
-};
-
-template <>
-struct MappingTraits<clang::doc::Reference *>
-    : PointerMappingTraits<clang::doc::Reference> {};
-template <>
-struct MappingTraits<clang::doc::CommentInfo *>
-    : PointerMappingTraits<clang::doc::CommentInfo> {};
-template <>
-struct MappingTraits<clang::doc::FunctionInfo *>
-    : PointerMappingTraits<clang::doc::FunctionInfo> {};
-template <>
-struct MappingTraits<clang::doc::EnumInfo *>
-    : PointerMappingTraits<clang::doc::EnumInfo> {};
-template <>
-struct MappingTraits<clang::doc::TemplateParamInfo *>
-    : PointerMappingTraits<clang::doc::TemplateParamInfo> {};
-
-template <typename T> struct SequenceTraits<ArrayRef<T>> {
+template <typename T> struct SequenceTraits<llvm::ArrayRef<T>> {
   static size_t size(IO &io, llvm::ArrayRef<T> &seq) { return seq.size(); }
   static T &element(IO &io, llvm::ArrayRef<T> &seq, size_t index) {
     return const_cast<T &>(seq[index]);
@@ -252,7 +191,7 @@ static void infoMapping(IO &IO, Info &I) {
 static void symbolInfoMapping(IO &IO, SymbolInfo &I) {
   infoMapping(IO, I);
   IO.mapOptional("DefLocation", I.DefLoc, std::optional<Location>());
-  IO.mapOptional("Location", I.Loc);
+  IO.mapOptional("Location", I.Loc, llvm::SmallVector<Location, 2>());
 }
 
 static void recordInfoMapping(IO &IO, RecordInfo &I) {
@@ -261,10 +200,10 @@ static void recordInfoMapping(IO &IO, RecordInfo &I) {
   IO.mapOptional("IsTypeDef", I.IsTypeDef, false);
   IO.mapOptional("Members", I.Members);
   IO.mapOptional("Bases", I.Bases);
-  IO.mapOptional("Parents", I.Parents, SmallVector<Reference, 4>());
+  IO.mapOptional("Parents", I.Parents, llvm::SmallVector<Reference, 4>());
   IO.mapOptional("VirtualParents", I.VirtualParents,
                  llvm::SmallVector<Reference, 4>());
-  IO.mapOptional("ChildRecords", I.Children.Records);
+  IO.mapOptional("ChildRecords", I.Children.Records, OwningVec<Reference>());
   IO.mapOptional("ChildFunctions", I.Children.Functions);
   IO.mapOptional("ChildEnums", I.Children.Enums);
   IO.mapOptional("ChildTypedefs", I.Children.Typedefs);
@@ -400,7 +339,7 @@ template <> struct MappingTraits<NamespaceInfo> {
     for (const auto &N : I.Children.Namespaces)
       TempNamespaces.push_back(N);
     IO.mapOptional("ChildNamespaces", TempNamespaces, std::vector<Reference>());
-    IO.mapOptional("ChildRecords", I.Children.Records);
+    IO.mapOptional("ChildRecords", I.Children.Records, OwningVec<Reference>());
     IO.mapOptional("ChildFunctions", I.Children.Functions);
     IO.mapOptional("ChildEnums", I.Children.Enums);
     IO.mapOptional("ChildTypedefs", I.Children.Typedefs);
@@ -502,6 +441,13 @@ template <> struct MappingTraits<CommentInfo> {
   static void mapping(IO &IO, CommentInfo &I) { commentInfoMapping(IO, I); }
 };
 
+template <> struct MappingTraits<OwnedPtr<CommentInfo>> {
+  static void mapping(IO &IO, OwnedPtr<CommentInfo> &I) {
+    if (I)
+      commentInfoMapping(IO, *I);
+  }
+};
+
 } // end namespace yaml
 } // end namespace llvm
 

diff  --git a/clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp b/clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp
index c610c57722649..f96cfc9426f1a 100644
--- a/clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp
+++ b/clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp
@@ -184,10 +184,9 @@ static void BM_JSONGenerator_Scale(benchmark::State &State) {
   auto NI = allocatePtr<NamespaceInfo>();
   NI->Name = "GlobalNamespace";
   for (int i = 0; i < NumRecords; ++i) {
-    Reference *R = new (TransientArena.Allocate<Reference>())
-        Reference(SymbolID{(uint8_t)(i & 0xFF)}, "Record" + std::to_string(i),
-                  InfoType::IT_record);
-    NI->Children.Records.push_back(*R);
+    NI->Children.Records.emplace_back(SymbolID{(uint8_t)(i & 0xFF)},
+                                      "Record" + std::to_string(i),
+                                      InfoType::IT_record);
   }
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());

diff  --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index 3c38901f4a0f9..f627ee5887528 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -29,7 +29,6 @@
 #include "clang/Tooling/CommonOptionsParser.h"
 #include "clang/Tooling/Execution.h"
 #include "llvm/ADT/APFloat.h"
-#include "llvm/ADT/ScopeExit.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
@@ -359,22 +358,15 @@ Example usage for a project using a compile commands database:
         llvm::hardware_concurrency(ExecutorConcurrency));
     {
       llvm::TimeTraceScope TS("Reduce");
-      for (const auto &Group : USRToBitcode) {
-        StringRef Key = Group.getKey();
-        std::vector<StringRef> Bitcodes = Group.getValue();
-        Pool.async([Key, Bitcodes, &CDCtx, &Diags, &USRToInfo, &USRToInfoMutex,
-                    &IndexMutex, &DiagMutex, &Error, DiagIDBitcodeReading,
-                    DiagIDBitcodeMerging]() {
-          if (CDCtx.FTimeTrace)
+      for (auto &Group : USRToBitcode) {
+        Pool.async([&, &Diags = Diags]() { // time trace decoding bitcode
+          if (FTimeTrace)
             llvm::timeTraceProfilerInitialize(200, "clang-doc");
 
-          doc::OwnedPtr<doc::Info> Reduced = nullptr;
+          doc::OwningPtrVec<doc::Info> Infos;
           {
-            llvm::TimeTraceScope Red("decoding and merging bitcode");
-            for (const auto &Bitcode : Bitcodes) {
-
-              llvm::scope_exit ArenaGuard(
-                  [] { clang::doc::TransientArena.Reset(); });
+            llvm::TimeTraceScope Red("decoding bitcode");
+            for (auto &Bitcode : Group.getValue()) {
               llvm::BitstreamCursor Stream(Bitcode);
               doc::ClangDocBitcodeReader Reader(Stream, Diags);
               auto ReadInfos = Reader.readBitcode();
@@ -386,17 +378,25 @@ Example usage for a project using a compile commands database:
                 Error = true;
                 return;
               }
-              for (auto &I : *ReadInfos) {
-                if (auto Err = doc::mergeSingleInfo(
-                        Reduced, std::move(I), clang::doc::PersistentArena)) {
-                  std::lock_guard<llvm::sys::Mutex> Guard(DiagMutex);
-                  Diags.Report(DiagIDBitcodeMerging)
-                      << toString(std::move(Err));
-                  return;
-                }
-              }
+              std::move(ReadInfos->begin(), ReadInfos->end(),
+                        std::back_inserter(Infos));
+            }
+          } // time trace decoding bitcode
+
+          doc::OwnedPtr<doc::Info> Reduced;
+
+          {
+            llvm::TimeTraceScope Merge("merging bitcode");
+            auto ExpReduced = doc::mergeInfos(Infos);
+
+            if (!ExpReduced) {
+              std::lock_guard<llvm::sys::Mutex> Guard(DiagMutex);
+              Diags.Report(DiagIDBitcodeMerging)
+                  << toString(ExpReduced.takeError());
+              return;
             }
-          } // time trace decoding and merging bitcode
+            Reduced = std::move(*ExpReduced);
+          } // time trace merging bitcode
 
           // Add a reference to this Info in the Index
           {
@@ -408,7 +408,7 @@ Example usage for a project using a compile commands database:
           {
             llvm::TimeTraceScope Merge("USRToInfo");
             std::lock_guard<llvm::sys::Mutex> Guard(USRToInfoMutex);
-            USRToInfo[Key] = std::move(Reduced);
+            USRToInfo[Group.getKey()] = std::move(Reduced);
           }
 
           if (CDCtx.FTimeTrace)

diff  --git a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
index 81de4ff2f6381..6bdf538012303 100644
--- a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
@@ -56,6 +56,7 @@ static OwningPtrVec<Info> readInfo(StringRef Bitcode, size_t NumInfos,
   llvm::BitstreamCursor Stream(Bitcode);
   doc::ClangDocBitcodeReader Reader(Stream, Diags);
   auto Infos = Reader.readBitcode();
+
   // Check that there was no error in the read.
   assert(Infos);
   EXPECT_EQ(Infos.get().size(), NumInfos);
@@ -67,43 +68,39 @@ class BitcodeTest : public ClangDocContextTest {};
 TEST_F(BitcodeTest, emitNamespaceInfoBitcode) {
   NamespaceInfo I;
   I.Name = "r";
-  Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   Reference NewNamespace(EmptySID, "ChildNamespace", InfoType::IT_namespace);
   I.Children.Namespaces.push_back(NewNamespace);
-  Reference ChildStruct(EmptySID, "ChildStruct", InfoType::IT_record);
-  I.Children.Records.push_back(ChildStruct);
-  FunctionInfo FI;
-  I.Children.Functions.push_back(FI);
-  EnumInfo EI;
-  I.Children.Enums.push_back(EI);
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
+  I.Children.Functions.emplace_back();
+  I.Children.Enums.emplace_back();
 
   std::string WriteResult = writeInfo(&I, this->Diags);
   EXPECT_TRUE(WriteResult.size() > 0);
   OwningPtrVec<Info> ReadResults = readInfo(WriteResult, 1, this->Diags);
 
-  CheckNamespaceInfo(&I, InfoAsNamespace(ReadResults[0]));
+  CheckNamespaceInfo(&I, InfoAsNamespace(ReadResults[0].get()));
 }
 
 TEST_F(BitcodeTest, emitRecordInfoBitcode) {
   RecordInfo I;
   I.Name = "r";
-  Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   I.DefLoc = Location(10, 10, "test.cpp");
-  Location Loc1(12, 12, "test.cpp");
-  I.Loc.push_back(Loc1);
+  I.Loc.emplace_back(12, 12, "test.cpp");
 
-  MemberTypeInfo M(TypeInfo("int"), "X", AccessSpecifier::AS_private);
+  I.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private);
   I.TagType = TagTypeKind::Class;
   I.IsTypeDef = true;
-  BaseRecordInfo B(EmptySID, "F", "path/to/F", true, AccessSpecifier::AS_public,
-                   true);
-  FunctionInfo FI;
-  B.Children.Functions.push_back(FI);
-  MemberTypeInfo BM(TypeInfo("int"), "X", AccessSpecifier::AS_private);
+  I.Bases.emplace_back(EmptySID, "F", "path/to/F", true,
+                       AccessSpecifier::AS_public, true);
+  I.Bases.back().Children.Functions.emplace_back();
+  I.Bases.back().Members.emplace_back(TypeInfo("int"), "X",
+                                      AccessSpecifier::AS_private);
+  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
+  I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
 
   // Documentation for the data member.
   CommentInfo BriefChildren[] = {CommentInfo(CommentKind::CK_TextComment, {},
@@ -112,47 +109,29 @@ TEST_F(BitcodeTest, emitRecordInfoBitcode) {
   CommentInfo TopCommentChildren[] = {
       CommentInfo(CommentKind::CK_ParagraphComment, BriefChildren)};
   CommentInfo TopComment(CommentKind::CK_FullComment, TopCommentChildren);
-  BM.Description.push_back(TopComment);
-  MemberTypeInfo BMem[] = {std::move(BM)};
-  B.Members = llvm::ArrayRef(BMem);
-  BaseRecordInfo Bases[] = {std::move(B)};
-  I.Bases = llvm::ArrayRef(Bases);
-
-  MemberTypeInfo Mem[] = {std::move(M)};
-  I.Members = llvm::ArrayRef(Mem);
-  Reference Parents[] = {Reference(EmptySID, "F", InfoType::IT_record)};
-  I.Parents = llvm::ArrayRef(Parents);
-  Reference VParents[] = {Reference(EmptySID, "G", InfoType::IT_record)};
-  I.VirtualParents = llvm::ArrayRef(VParents);
-
-  Reference ChildStruct(EmptySID, "ChildStruct", InfoType::IT_record);
-  I.Children.Records.push_back(ChildStruct);
-  FunctionInfo FI2;
-  I.Children.Functions.push_back(FI2);
-  EnumInfo EI;
-  I.Children.Enums.push_back(EI);
+  I.Bases.back().Members.back().Description.emplace_back(std::move(TopComment));
+
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
+  I.Children.Functions.emplace_back();
+  I.Children.Enums.emplace_back();
 
   std::string WriteResult = writeInfo(&I, this->Diags);
   EXPECT_TRUE(WriteResult.size() > 0);
   OwningPtrVec<Info> ReadResults = readInfo(WriteResult, 1, this->Diags);
 
-  CheckRecordInfo(&I, InfoAsRecord(ReadResults[0]));
+  CheckRecordInfo(&I, InfoAsRecord(ReadResults[0].get()));
 }
 
 TEST_F(BitcodeTest, emitFunctionInfoBitcode) {
   FunctionInfo I;
   I.Name = "f";
-  Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   I.DefLoc = Location(10, 10, "test.cpp");
-  Location Loc1(12, 12, "test.cpp");
-  I.Loc.push_back(Loc1);
+  I.Loc.emplace_back(12, 12, "test.cpp");
 
   I.ReturnType = TypeInfo("void");
-  FieldTypeInfo P(TypeInfo("int"), "P");
-  FieldTypeInfo Params[] = {std::move(P)};
-  I.Params = llvm::ArrayRef(Params);
+  I.Params.emplace_back(TypeInfo("int"), "P");
 
   I.Access = AccessSpecifier::AS_none;
 
@@ -160,23 +139,19 @@ TEST_F(BitcodeTest, emitFunctionInfoBitcode) {
   EXPECT_TRUE(WriteResult.size() > 0);
   OwningPtrVec<Info> ReadResults = readInfo(WriteResult, 1, this->Diags);
 
-  CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0]));
+  CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0].get()));
 }
 
 TEST_F(BitcodeTest, emitMethodInfoBitcode) {
   FunctionInfo I;
   I.Name = "f";
-  Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   I.DefLoc = Location(10, 10, "test.cpp");
-  Location Loc1(12, 12, "test.cpp");
-  I.Loc.push_back(Loc1);
+  I.Loc.emplace_back(12, 12, "test.cpp");
 
   I.ReturnType = TypeInfo("void");
-  FieldTypeInfo P(TypeInfo("int"), "P");
-  FieldTypeInfo Params[] = {std::move(P)};
-  I.Params = llvm::ArrayRef(Params);
+  I.Params.emplace_back(TypeInfo("int"), "P");
   I.IsMethod = true;
   I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
 
@@ -186,36 +161,31 @@ TEST_F(BitcodeTest, emitMethodInfoBitcode) {
   EXPECT_TRUE(WriteResult.size() > 0);
   OwningPtrVec<Info> ReadResults = readInfo(WriteResult, 1, this->Diags);
 
-  CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0]));
+  CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0].get()));
 }
 
 TEST_F(BitcodeTest, emitEnumInfoBitcode) {
   EnumInfo I;
   I.Name = "e";
-  Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   I.DefLoc = Location(10, 10, "test.cpp");
-  Location Loc1(12, 12, "test.cpp");
-  I.Loc.push_back(Loc1);
+  I.Loc.emplace_back(12, 12, "test.cpp");
 
-  EnumValueInfo EV("X");
-  EnumValueInfo Mems[] = {std::move(EV)};
-  I.Members = llvm::ArrayRef(Mems);
+  I.Members.emplace_back("X");
   I.Scoped = true;
 
   std::string WriteResult = writeInfo(&I, this->Diags);
   EXPECT_TRUE(WriteResult.size() > 0);
   OwningPtrVec<Info> ReadResults = readInfo(WriteResult, 1, this->Diags);
 
-  CheckEnumInfo(&I, InfoAsEnum(ReadResults[0]));
+  CheckEnumInfo(&I, InfoAsEnum(ReadResults[0].get()));
 }
 
 TEST_F(BitcodeTest, emitTypedefInfoBitcode) {
   TypedefInfo I;
   I.Name = "MyInt";
-  Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   I.DefLoc = Location(10, 10, "test.cpp");
   I.Underlying = TypeInfo("unsigned");
@@ -226,13 +196,13 @@ TEST_F(BitcodeTest, emitTypedefInfoBitcode) {
       CommentInfo(CommentKind::CK_ParagraphComment, BlankChildren)};
   CommentInfo Top(CommentKind::CK_FullComment, TopChildren);
 
-  I.Description.push_back(Top);
+  I.Description.emplace_back(std::move(Top));
 
   std::string WriteResult = writeInfo(&I, this->Diags);
   EXPECT_TRUE(WriteResult.size() > 0);
   OwningPtrVec<Info> ReadResults = readInfo(WriteResult, 1, this->Diags);
 
-  CheckTypedefInfo(&I, InfoAsTypedef(ReadResults[0]));
+  CheckTypedefInfo(&I, InfoAsTypedef(ReadResults[0].get()));
 
   // Check one with no IsUsing set, no description, and no definition location.
   TypedefInfo I2;
@@ -243,7 +213,7 @@ TEST_F(BitcodeTest, emitTypedefInfoBitcode) {
   WriteResult = writeInfo(&I2, this->Diags);
   EXPECT_TRUE(WriteResult.size() > 0);
   ReadResults = readInfo(WriteResult, 1, this->Diags);
-  CheckTypedefInfo(&I2, InfoAsTypedef(ReadResults[0]));
+  CheckTypedefInfo(&I2, InfoAsTypedef(ReadResults[0].get()));
 }
 
 TEST_F(BitcodeTest, emitInfoWithCommentBitcode) {
@@ -251,8 +221,7 @@ TEST_F(BitcodeTest, emitInfoWithCommentBitcode) {
   F.Name = "F";
   F.ReturnType = TypeInfo("void");
   F.DefLoc = Location(0, 0, "test.cpp");
-  FieldTypeInfo PI[] = {FieldTypeInfo(TypeInfo("int"), "I")};
-  F.Params = llvm::ArrayRef(PI);
+  F.Params.emplace_back(TypeInfo("int"), "I");
 
   // BlankLine
   CommentInfo BlankChildren[] = {CommentInfo(CommentKind::CK_TextComment)};
@@ -324,13 +293,13 @@ TEST_F(BitcodeTest, emitInfoWithCommentBitcode) {
                                Verbatim,  ParamOut, ParamIn,  Return};
   CommentInfo Top(CommentKind::CK_FullComment, TopChildren);
 
-  F.Description.push_back(Top);
+  F.Description.emplace_back(std::move(Top));
 
   std::string WriteResult = writeInfo(&F, this->Diags);
   EXPECT_TRUE(WriteResult.size() > 0);
   OwningPtrVec<Info> ReadResults = readInfo(WriteResult, 1, this->Diags);
 
-  CheckFunctionInfo(&F, InfoAsFunction(ReadResults[0]));
+  CheckFunctionInfo(&F, InfoAsFunction(ReadResults[0].get()));
 }
 
 } // namespace doc

diff  --git a/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp b/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
index 2e5466c172a18..92127da53b7bb 100644
--- a/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
@@ -54,10 +54,10 @@ TypedefInfo *InfoAsTypedef(Info *I) {
   return static_cast<TypedefInfo *>(I);
 }
 
-void CheckCommentInfo(ArrayRef<CommentInfo> Expected,
-                      ArrayRef<CommentInfo> Actual);
-void CheckCommentInfo(const OwningVec<CommentInfo> &Expected,
-                      const OwningVec<CommentInfo> &Actual);
+void CheckCommentInfo(const std::vector<CommentInfo> &Expected,
+                      const std::vector<CommentInfo> &Actual);
+void CheckCommentInfo(const std::vector<OwnedPtr<CommentInfo>> &Expected,
+                      const std::vector<OwnedPtr<CommentInfo>> &Actual);
 
 void CheckCommentInfo(const CommentInfo &Expected, const CommentInfo &Actual) {
   EXPECT_EQ(Expected.Kind, Actual.Kind);
@@ -84,71 +84,52 @@ void CheckCommentInfo(const CommentInfo &Expected, const CommentInfo &Actual) {
   CheckCommentInfo(Expected.Children, Actual.Children);
 }
 
-void CheckCommentInfo(ArrayRef<CommentInfo> Expected,
-                      ArrayRef<CommentInfo> Actual) {
-  auto ItE = Expected.begin();
-  auto ItA = Actual.begin();
-  while (ItE != Expected.end() && ItA != Actual.end()) {
-    CheckCommentInfo(*ItE, *ItA);
-    ++ItE;
-    ++ItA;
-  }
-  EXPECT_TRUE(ItE == Expected.end() && ItA == Actual.end());
+void CheckCommentInfo(const std::vector<CommentInfo> &Expected,
+                      const std::vector<CommentInfo> &Actual) {
+  ASSERT_EQ(Expected.size(), Actual.size());
+  for (size_t Idx = 0; Idx < Actual.size(); ++Idx)
+    CheckCommentInfo(Expected[Idx], Actual[Idx]);
 }
 
-void CheckCommentInfo(const OwningVec<CommentInfo> &Expected,
-                      const OwningVec<CommentInfo> &Actual) {
-  auto ItE = Expected.begin();
-  auto ItA = Actual.begin();
-  while (ItE != Expected.end() && ItA != Actual.end()) {
-    CheckCommentInfo(*ItE, *ItA);
-    ++ItE;
-    ++ItA;
-  }
-  EXPECT_TRUE(ItE == Expected.end() && ItA == Actual.end());
+void CheckCommentInfo(const std::vector<OwnedPtr<CommentInfo>> &Expected,
+                      const std::vector<OwnedPtr<CommentInfo>> &Actual) {
+  ASSERT_EQ(Expected.size(), Actual.size());
+  for (size_t Idx = 0; Idx < Actual.size(); ++Idx)
+    CheckCommentInfo(*Expected[Idx], *Actual[Idx]);
 }
 
-void CheckReference(const Reference &Expected, const Reference &Actual) {
+void CheckReference(Reference &Expected, Reference &Actual) {
   EXPECT_EQ(Expected.Name, Actual.Name);
   EXPECT_EQ(Expected.RefType, Actual.RefType);
   EXPECT_EQ(Expected.Path, Actual.Path);
 }
 
-void CheckTypeInfo(const TypeInfo *Expected, const TypeInfo *Actual) {
+void CheckTypeInfo(TypeInfo *Expected, TypeInfo *Actual) {
   CheckReference(Expected->Type, Actual->Type);
 }
 
-void CheckFieldTypeInfo(const FieldTypeInfo *Expected,
-                        const FieldTypeInfo *Actual) {
+void CheckFieldTypeInfo(FieldTypeInfo *Expected, FieldTypeInfo *Actual) {
   CheckTypeInfo(Expected, Actual);
   EXPECT_EQ(Expected->Name, Actual->Name);
 }
 
-void CheckMemberTypeInfo(const MemberTypeInfo *Expected,
-                         const MemberTypeInfo *Actual) {
+void CheckMemberTypeInfo(MemberTypeInfo *Expected, MemberTypeInfo *Actual) {
   CheckFieldTypeInfo(Expected, Actual);
   EXPECT_EQ(Expected->Access, Actual->Access);
   CheckCommentInfo(Expected->Description, Actual->Description);
 }
 
-void CheckBaseInfo(const Info *Expected, const Info *Actual) {
+void CheckBaseInfo(Info *Expected, Info *Actual) {
   EXPECT_EQ(size_t(20), Actual->USR.size());
   EXPECT_EQ(Expected->Name, Actual->Name);
   EXPECT_EQ(Expected->Path, Actual->Path);
-  auto ItN_E = Expected->Namespace.begin();
-  auto ItN_A = Actual->Namespace.begin();
-  while (ItN_E != Expected->Namespace.end() &&
-         ItN_A != Actual->Namespace.end()) {
-    CheckReference(*ItN_E, *ItN_A);
-    ++ItN_E;
-    ++ItN_A;
-  }
-  EXPECT_TRUE(ItN_E == Expected->Namespace.end() &&
-              ItN_A == Actual->Namespace.end());
+  ASSERT_EQ(Expected->Namespace.size(), Actual->Namespace.size());
+  for (size_t Idx = 0; Idx < Actual->Namespace.size(); ++Idx)
+    CheckReference(Expected->Namespace[Idx], Actual->Namespace[Idx]);
   CheckCommentInfo(Expected->Description, Actual->Description);
 }
 
-void CheckSymbolInfo(const SymbolInfo *Expected, const SymbolInfo *Actual) {
+void CheckSymbolInfo(SymbolInfo *Expected, SymbolInfo *Actual) {
   CheckBaseInfo(Expected, Actual);
   EXPECT_EQ(Expected->DefLoc.has_value(), Actual->DefLoc.has_value());
   if (Expected->DefLoc && Actual->DefLoc.has_value()) {
@@ -157,186 +138,109 @@ void CheckSymbolInfo(const SymbolInfo *Expected, const SymbolInfo *Actual) {
     EXPECT_EQ(Expected->DefLoc->EndLineNumber, Actual->DefLoc->EndLineNumber);
     EXPECT_EQ(Expected->DefLoc->Filename, Actual->DefLoc->Filename);
   }
-  auto ItE = Expected->Loc.begin();
-  auto ItA = Actual->Loc.begin();
-  while (ItE != Expected->Loc.end() && ItA != Actual->Loc.end()) {
-    EXPECT_EQ(*ItE, *ItA);
-    ++ItE;
-    ++ItA;
-  }
-  EXPECT_TRUE(ItE == Expected->Loc.end() && ItA == Actual->Loc.end());
+  ASSERT_EQ(Expected->Loc.size(), Actual->Loc.size());
+  for (size_t Idx = 0; Idx < Actual->Loc.size(); ++Idx)
+    EXPECT_EQ(Expected->Loc[Idx], Actual->Loc[Idx]);
 }
 
-void CheckFunctionInfo(const FunctionInfo *Expected,
-                       const FunctionInfo *Actual) {
+void CheckFunctionInfo(FunctionInfo *Expected, FunctionInfo *Actual) {
   CheckSymbolInfo(Expected, Actual);
 
   EXPECT_EQ(Expected->IsMethod, Actual->IsMethod);
   CheckReference(Expected->Parent, Actual->Parent);
   CheckTypeInfo(&Expected->ReturnType, &Actual->ReturnType);
 
-  for (size_t Idx = 0; Idx < Expected->Params.size(); ++Idx) {
+  ASSERT_EQ(Expected->Params.size(), Actual->Params.size());
+  for (size_t Idx = 0; Idx < Actual->Params.size(); ++Idx)
     EXPECT_EQ(Expected->Params[Idx], Actual->Params[Idx]);
-  }
 
   EXPECT_EQ(Expected->Access, Actual->Access);
 }
 
-void CheckEnumInfo(const EnumInfo *Expected, const EnumInfo *Actual) {
+void CheckEnumInfo(EnumInfo *Expected, EnumInfo *Actual) {
   CheckSymbolInfo(Expected, Actual);
 
   EXPECT_EQ(Expected->Scoped, Actual->Scoped);
-  auto ItM_E = Expected->Members.begin();
-  auto ItM_A = Actual->Members.begin();
-  while (ItM_E != Expected->Members.end() && ItM_A != Actual->Members.end()) {
-    EXPECT_EQ(*ItM_E, *ItM_A);
-    ++ItM_E;
-    ++ItM_A;
-  }
-  EXPECT_TRUE(ItM_E == Expected->Members.end() &&
-              ItM_A == Actual->Members.end());
+  ASSERT_EQ(Expected->Members.size(), Actual->Members.size());
+  for (size_t Idx = 0; Idx < Actual->Members.size(); ++Idx)
+    EXPECT_EQ(Expected->Members[Idx], Actual->Members[Idx]);
 }
 
-void CheckTypedefInfo(const TypedefInfo *Expected, const TypedefInfo *Actual) {
+void CheckTypedefInfo(TypedefInfo *Expected, TypedefInfo *Actual) {
   CheckSymbolInfo(Expected, Actual);
   EXPECT_EQ(Expected->IsUsing, Actual->IsUsing);
   CheckTypeInfo(&Expected->Underlying, &Actual->Underlying);
 }
 
-void CheckNamespaceInfo(const NamespaceInfo *Expected,
-                        const NamespaceInfo *Actual) {
+void CheckNamespaceInfo(NamespaceInfo *Expected, NamespaceInfo *Actual) {
   CheckBaseInfo(Expected, Actual);
 
   ASSERT_EQ(Expected->Children.Namespaces.size(),
             Actual->Children.Namespaces.size());
-  auto ItN_E = Expected->Children.Namespaces.begin();
-  auto ItN_A = Actual->Children.Namespaces.begin();
-  while (ItN_E != Expected->Children.Namespaces.end() &&
-         ItN_A != Actual->Children.Namespaces.end()) {
-    CheckReference(*ItN_E, *ItN_A);
-    ++ItN_E;
-    ++ItN_A;
-  }
-  EXPECT_TRUE(ItN_E == Expected->Children.Namespaces.end() &&
-              ItN_A == Actual->Children.Namespaces.end());
-
-  auto ItR_E = Expected->Children.Records.begin();
-  auto ItR_A = Actual->Children.Records.begin();
-  while (ItR_E != Expected->Children.Records.end() &&
-         ItR_A != Actual->Children.Records.end()) {
-    CheckReference(*ItR_E, *ItR_A);
-    ++ItR_E;
-    ++ItR_A;
+  auto ItExpected = Expected->Children.Namespaces.begin();
+  auto ItActual = Actual->Children.Namespaces.begin();
+  while (ItExpected != Expected->Children.Namespaces.end()) {
+    CheckReference(*ItExpected, *ItActual);
+    ++ItExpected;
+    ++ItActual;
   }
-  EXPECT_TRUE(ItR_E == Expected->Children.Records.end() &&
-              ItR_A == Actual->Children.Records.end());
-
-  auto ItF_E = Expected->Children.Functions.begin();
-  auto ItF_A = Actual->Children.Functions.begin();
-  while (ItF_E != Expected->Children.Functions.end() &&
-         ItF_A != Actual->Children.Functions.end()) {
-    CheckFunctionInfo(&(*ItF_E), &(*ItF_A));
-    ++ItF_E;
-    ++ItF_A;
-  }
-  EXPECT_TRUE(ItF_E == Expected->Children.Functions.end() &&
-              ItF_A == Actual->Children.Functions.end());
-
-  auto ItEnum_E = Expected->Children.Enums.begin();
-  auto ItEnum_A = Actual->Children.Enums.begin();
-  while (ItEnum_E != Expected->Children.Enums.end() &&
-         ItEnum_A != Actual->Children.Enums.end()) {
-    CheckEnumInfo(&(*ItEnum_E), &(*ItEnum_A));
-    ++ItEnum_E;
-    ++ItEnum_A;
-  }
-  EXPECT_TRUE(ItEnum_E == Expected->Children.Enums.end() &&
-              ItEnum_A == Actual->Children.Enums.end());
+
+  ASSERT_EQ(Expected->Children.Records.size(), Actual->Children.Records.size());
+  for (size_t Idx = 0; Idx < Actual->Children.Records.size(); ++Idx)
+    CheckReference(Expected->Children.Records[Idx],
+                   Actual->Children.Records[Idx]);
+
+  ASSERT_EQ(Expected->Children.Functions.size(),
+            Actual->Children.Functions.size());
+  for (size_t Idx = 0; Idx < Actual->Children.Functions.size(); ++Idx)
+    CheckFunctionInfo(&Expected->Children.Functions[Idx],
+                      &Actual->Children.Functions[Idx]);
+
+  ASSERT_EQ(Expected->Children.Enums.size(), Actual->Children.Enums.size());
+  for (size_t Idx = 0; Idx < Actual->Children.Enums.size(); ++Idx)
+    CheckEnumInfo(&Expected->Children.Enums[Idx], &Actual->Children.Enums[Idx]);
 }
 
-void CheckRecordInfo(const RecordInfo *Expected, const RecordInfo *Actual) {
+void CheckRecordInfo(RecordInfo *Expected, RecordInfo *Actual) {
   CheckSymbolInfo(Expected, Actual);
 
   EXPECT_EQ(Expected->TagType, Actual->TagType);
 
   EXPECT_EQ(Expected->IsTypeDef, Actual->IsTypeDef);
 
-  auto ItM_E = Expected->Members.begin();
-  auto ItM_A = Actual->Members.begin();
-  while (ItM_E != Expected->Members.end() && ItM_A != Actual->Members.end()) {
-    EXPECT_EQ(*ItM_E, *ItM_A);
-    ++ItM_E;
-    ++ItM_A;
-  }
-  EXPECT_TRUE(ItM_E == Expected->Members.end() &&
-              ItM_A == Actual->Members.end());
-
-  auto ItP_E = Expected->Parents.begin();
-  auto ItP_A = Actual->Parents.begin();
-  while (ItP_E != Expected->Parents.end() && ItP_A != Actual->Parents.end()) {
-    CheckReference(*ItP_E, *ItP_A);
-    ++ItP_E;
-    ++ItP_A;
-  }
-  EXPECT_TRUE(ItP_E == Expected->Parents.end() &&
-              ItP_A == Actual->Parents.end());
-
-  auto ItVP_E = Expected->VirtualParents.begin();
-  auto ItVP_A = Actual->VirtualParents.begin();
-  while (ItVP_E != Expected->VirtualParents.end() &&
-         ItVP_A != Actual->VirtualParents.end()) {
-    CheckReference(*ItVP_E, *ItVP_A);
-    ++ItVP_E;
-    ++ItVP_A;
-  }
-  EXPECT_TRUE(ItVP_E == Expected->VirtualParents.end() &&
-              ItVP_A == Actual->VirtualParents.end());
-
-  auto ItB_E = Expected->Bases.begin();
-  auto ItB_A = Actual->Bases.begin();
-  while (ItB_E != Expected->Bases.end() && ItB_A != Actual->Bases.end()) {
-    CheckBaseRecordInfo(&(*ItB_E), &(*ItB_A));
-    ++ItB_E;
-    ++ItB_A;
-  }
-  EXPECT_TRUE(ItB_E == Expected->Bases.end() && ItB_A == Actual->Bases.end());
-
-  auto ItR_E = Expected->Children.Records.begin();
-  auto ItR_A = Actual->Children.Records.begin();
-  while (ItR_E != Expected->Children.Records.end() &&
-         ItR_A != Actual->Children.Records.end()) {
-    CheckReference(*ItR_E, *ItR_A);
-    ++ItR_E;
-    ++ItR_A;
-  }
-  EXPECT_TRUE(ItR_E == Expected->Children.Records.end() &&
-              ItR_A == Actual->Children.Records.end());
-
-  auto ItF_E = Expected->Children.Functions.begin();
-  auto ItF_A = Actual->Children.Functions.begin();
-  while (ItF_E != Expected->Children.Functions.end() &&
-         ItF_A != Actual->Children.Functions.end()) {
-    CheckFunctionInfo(&(*ItF_E), &(*ItF_A));
-    ++ItF_E;
-    ++ItF_A;
-  }
-  EXPECT_TRUE(ItF_E == Expected->Children.Functions.end() &&
-              ItF_A == Actual->Children.Functions.end());
-
-  auto ItEnum_E = Expected->Children.Enums.begin();
-  auto ItEnum_A = Actual->Children.Enums.begin();
-  while (ItEnum_E != Expected->Children.Enums.end() &&
-         ItEnum_A != Actual->Children.Enums.end()) {
-    CheckEnumInfo(&(*ItEnum_E), &(*ItEnum_A));
-    ++ItEnum_E;
-    ++ItEnum_A;
-  }
-  EXPECT_TRUE(ItEnum_E == Expected->Children.Enums.end() &&
-              ItEnum_A == Actual->Children.Enums.end());
+  ASSERT_EQ(Expected->Members.size(), Actual->Members.size());
+  for (size_t Idx = 0; Idx < Actual->Members.size(); ++Idx)
+    EXPECT_EQ(Expected->Members[Idx], Actual->Members[Idx]);
+
+  ASSERT_EQ(Expected->Parents.size(), Actual->Parents.size());
+  for (size_t Idx = 0; Idx < Actual->Parents.size(); ++Idx)
+    CheckReference(Expected->Parents[Idx], Actual->Parents[Idx]);
+
+  ASSERT_EQ(Expected->VirtualParents.size(), Actual->VirtualParents.size());
+  for (size_t Idx = 0; Idx < Actual->VirtualParents.size(); ++Idx)
+    CheckReference(Expected->VirtualParents[Idx], Actual->VirtualParents[Idx]);
+
+  ASSERT_EQ(Expected->Bases.size(), Actual->Bases.size());
+  for (size_t Idx = 0; Idx < Actual->Bases.size(); ++Idx)
+    CheckBaseRecordInfo(&Expected->Bases[Idx], &Actual->Bases[Idx]);
+
+  ASSERT_EQ(Expected->Children.Records.size(), Actual->Children.Records.size());
+  for (size_t Idx = 0; Idx < Actual->Children.Records.size(); ++Idx)
+    CheckReference(Expected->Children.Records[Idx],
+                   Actual->Children.Records[Idx]);
+
+  ASSERT_EQ(Expected->Children.Functions.size(),
+            Actual->Children.Functions.size());
+  for (size_t Idx = 0; Idx < Actual->Children.Functions.size(); ++Idx)
+    CheckFunctionInfo(&Expected->Children.Functions[Idx],
+                      &Actual->Children.Functions[Idx]);
+
+  ASSERT_EQ(Expected->Children.Enums.size(), Actual->Children.Enums.size());
+  for (size_t Idx = 0; Idx < Actual->Children.Enums.size(); ++Idx)
+    CheckEnumInfo(&Expected->Children.Enums[Idx], &Actual->Children.Enums[Idx]);
 }
 
-void CheckBaseRecordInfo(const BaseRecordInfo *Expected,
-                         const BaseRecordInfo *Actual) {
+void CheckBaseRecordInfo(BaseRecordInfo *Expected, BaseRecordInfo *Actual) {
   CheckRecordInfo(Expected, Actual);
 
   EXPECT_EQ(Expected->IsVirtual, Actual->IsVirtual);
@@ -344,7 +248,7 @@ void CheckBaseRecordInfo(const BaseRecordInfo *Expected,
   EXPECT_EQ(Expected->IsParent, Actual->IsParent);
 }
 
-void CheckIndex(const Index &Expected, const Index &Actual) {
+void CheckIndex(Index &Expected, Index &Actual) {
   CheckReference(Expected, Actual);
   ASSERT_EQ(Expected.Children.size(), Actual.Children.size());
   for (auto &[_, C] : Expected.Children)

diff  --git a/clang-tools-extra/unittests/clang-doc/ClangDocTest.h b/clang-tools-extra/unittests/clang-doc/ClangDocTest.h
index 1525b1ed382ce..9b1a26af0cdf6 100644
--- a/clang-tools-extra/unittests/clang-doc/ClangDocTest.h
+++ b/clang-tools-extra/unittests/clang-doc/ClangDocTest.h
@@ -31,32 +31,25 @@ FunctionInfo *InfoAsFunction(Info *I);
 EnumInfo *InfoAsEnum(Info *I);
 TypedefInfo *InfoAsTypedef(Info *I);
 
-void CheckCommentInfo(ArrayRef<CommentInfo> Expected,
-                      ArrayRef<CommentInfo> Actual);
-void CheckCommentInfo(const OwningVec<CommentInfo> &Expected,
-                      const OwningVec<CommentInfo> &Actual);
-void CheckReference(const Reference &Expected, const Reference &Actual);
-void CheckTypeInfo(const TypeInfo *Expected, const TypeInfo *Actual);
-void CheckFieldTypeInfo(const FieldTypeInfo *Expected,
-                        const FieldTypeInfo *Actual);
-void CheckMemberTypeInfo(const MemberTypeInfo *Expected,
-                         const MemberTypeInfo *Actual);
+// Unlike the operator==, these functions explicitly does not check USRs, as
+// that may change and it would be better to not rely on its implementation.
+void CheckReference(Reference &Expected, Reference &Actual);
+void CheckTypeInfo(TypeInfo *Expected, TypeInfo *Actual);
+void CheckFieldTypeInfo(FieldTypeInfo *Expected, FieldTypeInfo *Actual);
+void CheckMemberTypeInfo(MemberTypeInfo *Expected, MemberTypeInfo *Actual);
 
 // This function explicitly does not check USRs, as that may change and it would
 // be better to not rely on its implementation.
-void CheckBaseInfo(const Info *Expected, const Info *Actual);
-void CheckSymbolInfo(const SymbolInfo *Expected, const SymbolInfo *Actual);
-void CheckFunctionInfo(const FunctionInfo *Expected,
-                       const FunctionInfo *Actual);
-void CheckEnumInfo(const EnumInfo *Expected, const EnumInfo *Actual);
-void CheckTypedefInfo(const TypedefInfo *Expected, const TypedefInfo *Actual);
-void CheckNamespaceInfo(const NamespaceInfo *Expected,
-                        const NamespaceInfo *Actual);
-void CheckRecordInfo(const RecordInfo *Expected, const RecordInfo *Actual);
-void CheckBaseRecordInfo(const BaseRecordInfo *Expected,
-                         const BaseRecordInfo *Actual);
+void CheckBaseInfo(Info *Expected, Info *Actual);
+void CheckSymbolInfo(SymbolInfo *Expected, SymbolInfo *Actual);
+void CheckFunctionInfo(FunctionInfo *Expected, FunctionInfo *Actual);
+void CheckEnumInfo(EnumInfo *Expected, EnumInfo *Actual);
+void CheckTypedefInfo(TypedefInfo *Expected, TypedefInfo *Actual);
+void CheckNamespaceInfo(NamespaceInfo *Expected, NamespaceInfo *Actual);
+void CheckRecordInfo(RecordInfo *Expected, RecordInfo *Actual);
+void CheckBaseRecordInfo(BaseRecordInfo *Expected, BaseRecordInfo *Actual);
 
-void CheckIndex(const Index &Expected, const Index &Actual);
+void CheckIndex(Index &Expected, Index &Actual);
 
 class ClangDocContextTest : public ::testing::Test {
 protected:

diff  --git a/clang-tools-extra/unittests/clang-doc/GeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/GeneratorTest.cpp
index e352abbe0801f..38f37bd535239 100644
--- a/clang-tools-extra/unittests/clang-doc/GeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/GeneratorTest.cpp
@@ -28,8 +28,7 @@ TEST_F(GeneratorTest, emitIndex) {
   InfoC->USR = serialize::hashUSR("3");
   Reference RefB = Reference(SymbolID(), "B");
   RefB.USR = serialize::hashUSR("2");
-  Reference NsC[] = {std::move(RefB)};
-  InfoC->Namespace = llvm::ArrayRef(NsC);
+  InfoC->Namespace = {std::move(RefB)};
   Generator::addInfoToIndex(Idx, InfoC.get());
   auto InfoD = std::make_unique<Info>();
   InfoD->Name = "D";
@@ -41,8 +40,7 @@ TEST_F(GeneratorTest, emitIndex) {
   RefD.USR = serialize::hashUSR("4");
   Reference RefE = Reference(SymbolID(), "E");
   RefE.USR = serialize::hashUSR("5");
-  Reference NsF[] = {std::move(RefE), std::move(RefD)};
-  InfoF->Namespace = llvm::ArrayRef(NsF);
+  InfoF->Namespace = {std::move(RefE), std::move(RefD)};
   Generator::addInfoToIndex(Idx, InfoF.get());
   auto InfoG = std::make_unique<Info>(InfoType::IT_namespace);
   Generator::addInfoToIndex(Idx, InfoG.get());

diff  --git a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp
index 509699f20aa09..6edd303dbc326 100644
--- a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp
@@ -19,54 +19,39 @@ TEST_F(JSONGeneratorTest, emitRecordJSON) {
   RecordInfo I;
   I.Name = "Foo";
   I.IsTypeDef = false;
-  Reference Ns[] = {
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "GlobalNamespace", InfoType::IT_namespace);
   I.Path = "GlobalNamespace";
   I.DefLoc = Location(1, 1, "main.cpp");
   I.TagType = TagTypeKind::Class;
 
   I.Template = TemplateInfo();
-  TemplateParamInfo TParams[] = {TemplateParamInfo("class T")};
-  I.Template->Params = llvm::ArrayRef(TParams);
+  I.Template->Params.emplace_back("class T");
 
-  EnumInfo E;
-  E.Name = "Color";
-  E.Scoped = false;
-  EnumValueInfo EV[] = {EnumValueInfo("RED", "0")};
-  E.Members = llvm::ArrayRef(EV);
-  I.Children.Enums.push_back(E);
+  I.Children.Enums.emplace_back();
+  I.Children.Enums.back().Name = "Color";
+  I.Children.Enums.back().Scoped = false;
+  I.Children.Enums.back().Members.emplace_back();
+  I.Children.Enums.back().Members.back().Name = "RED";
+  I.Children.Enums.back().Members.back().Value = "0";
 
-  MemberTypeInfo M[] = {
-      MemberTypeInfo(TypeInfo("int"), "X", AccessSpecifier::AS_protected)};
-  I.Members = llvm::ArrayRef(M);
+  I.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_protected);
 
-  BaseRecordInfo B(EmptySID, "F", "path/to/F", true, AccessSpecifier::AS_public,
-                   true);
-  FunctionInfo F;
-  F.Name = "InheritedFunctionOne";
-  B.Children.Functions.push_back(F);
-  MemberTypeInfo BM[] = {
-      MemberTypeInfo(TypeInfo("int"), "N", AccessSpecifier::AS_public)};
-  B.Members = llvm::ArrayRef(BM);
-
-  BaseRecordInfo Bases[] = {std::move(B)};
-  I.Bases = llvm::ArrayRef(Bases);
+  I.Bases.emplace_back(EmptySID, "F", "path/to/F", true,
+                       AccessSpecifier::AS_public, true);
+  I.Bases.back().Children.Functions.emplace_back();
+  I.Bases.back().Children.Functions.back().Name = "InheritedFunctionOne";
+  I.Bases.back().Members.emplace_back(TypeInfo("int"), "N",
+                                      AccessSpecifier::AS_public);
 
   // F is in the global namespace
-  Reference Parents[] = {Reference(EmptySID, "F", InfoType::IT_record, "")};
-  I.Parents = llvm::ArrayRef(Parents);
-  Reference VParents[] = {Reference(EmptySID, "G", InfoType::IT_record,
-                                    "path::to::G::G", "path/to/G")};
-  I.VirtualParents = llvm::ArrayRef(VParents);
-
-  Reference ChildStruct(EmptySID, "ChildStruct", InfoType::IT_record,
-                        "path::to::A::r::ChildStruct", "path/to/A/r");
-  I.Children.Records.push_back(ChildStruct);
+  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, "");
+  I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record,
+                                "path::to::G::G", "path/to/G");
 
-  FunctionInfo F2;
-  F2.Name = "OneFunction";
-  I.Children.Functions.push_back(F2);
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
+                                  "path::to::A::r::ChildStruct", "path/to/A/r");
+  I.Children.Functions.emplace_back();
+  I.Children.Functions.back().Name = "OneFunction";
 
   auto G = getJSONGenerator();
   assert(G);
@@ -212,26 +197,20 @@ TEST_F(JSONGeneratorTest, emitNamespaceJSON) {
   NamespaceInfo I;
   I.Name = "Namespace";
   I.Path = "path/to/A";
-  Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   Reference NewNamespace(EmptySID, "ChildNamespace", InfoType::IT_namespace,
                          "path::to::A::Namespace::ChildNamespace",
                          "path/to/A/Namespace");
   I.Children.Namespaces.push_back(NewNamespace);
-
-  Reference ChildStruct(EmptySID, "ChildStruct", InfoType::IT_record,
-                        "path::to::A::Namespace::ChildStruct",
-                        "path/to/A/Namespace");
-  I.Children.Records.push_back(ChildStruct);
-  FunctionInfo F;
-  F.Name = "OneFunction";
-  F.Access = AccessSpecifier::AS_none;
-  I.Children.Functions.push_back(F);
-
-  EnumInfo E;
-  E.Name = "OneEnum";
-  I.Children.Enums.push_back(E);
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
+                                  "path::to::A::Namespace::ChildStruct",
+                                  "path/to/A/Namespace");
+  I.Children.Functions.emplace_back();
+  I.Children.Functions.back().Name = "OneFunction";
+  I.Children.Functions.back().Access = AccessSpecifier::AS_none;
+  I.Children.Enums.emplace_back();
+  I.Children.Enums.back().Name = "OneEnum";
 
   auto G = getJSONGenerator();
   assert(G);

diff  --git a/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
index 2dc472a352fd8..6661360049881 100644
--- a/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
@@ -26,22 +26,16 @@ class MDGeneratorTest : public ClangDocContextTest {};
 TEST_F(MDGeneratorTest, emitNamespaceMD) {
   NamespaceInfo I;
   I.Name = "Namespace";
-  Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   Reference NewNamespace(EmptySID, "ChildNamespace", InfoType::IT_namespace);
   I.Children.Namespaces.push_back(NewNamespace);
-  Reference ChildStruct(EmptySID, "ChildStruct", InfoType::IT_record);
-  I.Children.Records.push_back(ChildStruct);
-
-  FunctionInfo F;
-  F.Name = "OneFunction";
-  F.Access = AccessSpecifier::AS_none;
-  I.Children.Functions.push_back(F);
-
-  EnumInfo E;
-  E.Name = "OneEnum";
-  I.Children.Enums.push_back(E);
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
+  I.Children.Functions.emplace_back();
+  I.Children.Functions.back().Name = "OneFunction";
+  I.Children.Functions.back().Access = AccessSpecifier::AS_none;
+  I.Children.Enums.emplace_back();
+  I.Children.Enums.back().Name = "OneEnum";
 
   auto G = getMDGenerator();
   assert(G);
@@ -85,31 +79,21 @@ TEST_F(MDGeneratorTest, emitNamespaceMD) {
 TEST_F(MDGeneratorTest, emitRecordMD) {
   RecordInfo I;
   I.Name = "r";
-  Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   I.DefLoc = Location(10, 10, "test.cpp");
-  Location Loc1(12, 12, "test.cpp");
-  I.Loc.push_back(Loc1);
+  I.Loc.emplace_back(12, 12, "test.cpp");
 
-  MemberTypeInfo M[] = {
-      MemberTypeInfo(TypeInfo("int"), "X", AccessSpecifier::AS_private)};
-  I.Members = llvm::ArrayRef(M);
+  I.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private);
   I.TagType = TagTypeKind::Class;
-  Reference Parents[] = {Reference(EmptySID, "F", InfoType::IT_record)};
-  I.Parents = llvm::ArrayRef(Parents);
-  Reference VParents[] = {Reference(EmptySID, "G", InfoType::IT_record)};
-  I.VirtualParents = llvm::ArrayRef(VParents);
-
-  Reference ChildStruct(EmptySID, "ChildStruct", InfoType::IT_record);
-  I.Children.Records.push_back(ChildStruct);
-  FunctionInfo F;
-  F.Name = "OneFunction";
-  I.Children.Functions.push_back(F);
+  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
+  I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
 
-  EnumInfo E;
-  E.Name = "OneEnum";
-  I.Children.Enums.push_back(E);
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
+  I.Children.Functions.emplace_back();
+  I.Children.Functions.back().Name = "OneFunction";
+  I.Children.Enums.emplace_back();
+  I.Children.Enums.back().Name = "OneEnum";
 
   auto G = getMDGenerator();
   assert(G);
@@ -159,18 +143,15 @@ ChildStruct
 TEST_F(MDGeneratorTest, emitFunctionMD) {
   FunctionInfo I;
   I.Name = "f";
-  Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   I.DefLoc = Location(10, 10, "test.cpp");
-  Location Loc1(12, 12, "test.cpp");
-  I.Loc.push_back(Loc1);
+  I.Loc.emplace_back(12, 12, "test.cpp");
 
   I.Access = AccessSpecifier::AS_none;
 
   I.ReturnType = TypeInfo("void");
-  FieldTypeInfo P[] = {FieldTypeInfo(TypeInfo("int"), "P")};
-  I.Params = llvm::ArrayRef(P);
+  I.Params.emplace_back(TypeInfo("int"), "P");
   I.IsMethod = true;
   I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
 
@@ -194,15 +175,12 @@ TEST_F(MDGeneratorTest, emitFunctionMD) {
 TEST_F(MDGeneratorTest, emitEnumMD) {
   EnumInfo I;
   I.Name = "e";
-  Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   I.DefLoc = Location(10, 10, "test.cpp");
-  Location Loc1(12, 12, "test.cpp");
-  I.Loc.push_back(Loc1);
+  I.Loc.emplace_back(12, 12, "test.cpp");
 
-  EnumValueInfo EV[] = {EnumValueInfo("X")};
-  I.Members = llvm::ArrayRef(EV);
+  I.Members.emplace_back("X");
   I.Scoped = true;
 
   auto G = getMDGenerator();
@@ -230,9 +208,8 @@ TEST_F(MDGeneratorTest, emitCommentMD) {
 
   I.DefLoc = Location(10, 10, "test.cpp");
   I.ReturnType = TypeInfo("void");
-  FieldTypeInfo PI[] = {FieldTypeInfo(TypeInfo("int"), "I"),
-                        FieldTypeInfo(TypeInfo("int"), "J")};
-  I.Params = llvm::ArrayRef(PI);
+  I.Params.emplace_back(TypeInfo("int"), "I");
+  I.Params.emplace_back(TypeInfo("int"), "J");
   I.Access = AccessSpecifier::AS_none;
 
   CommentInfo Top;

diff  --git a/clang-tools-extra/unittests/clang-doc/MergeTest.cpp b/clang-tools-extra/unittests/clang-doc/MergeTest.cpp
index 50374743681e3..15b791a044d2d 100644
--- a/clang-tools-extra/unittests/clang-doc/MergeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/MergeTest.cpp
@@ -18,200 +18,150 @@ class MergeTest : public ClangDocContextTest {};
 TEST_F(MergeTest, mergeNamespaceInfos) {
   NamespaceInfo One;
   One.Name = "Namespace";
-  Reference Ns1[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  One.Namespace = llvm::ArrayRef(Ns1);
+  One.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   Reference RA(NonEmptySID, "ChildNamespace", InfoType::IT_namespace);
   One.Children.Namespaces.push_back(RA);
-  Reference RC1(NonEmptySID, "ChildStruct", InfoType::IT_record);
-  One.Children.Records.push_back(RC1);
-
-  FunctionInfo F1;
-  F1.Name = "OneFunction";
-  F1.USR = NonEmptySID;
-  One.Children.Functions.push_back(F1);
-
-  EnumInfo E1;
-  E1.Name = "OneEnum";
-  E1.USR = NonEmptySID;
-  One.Children.Enums.push_back(E1);
+  One.Children.Records.emplace_back(NonEmptySID, "ChildStruct",
+                                    InfoType::IT_record);
+  One.Children.Functions.emplace_back();
+  One.Children.Functions.back().Name = "OneFunction";
+  One.Children.Functions.back().USR = NonEmptySID;
+  One.Children.Enums.emplace_back();
+  One.Children.Enums.back().Name = "OneEnum";
+  One.Children.Enums.back().USR = NonEmptySID;
 
   NamespaceInfo Two;
   Two.Name = "Namespace";
-  Reference Ns2[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  Two.Namespace = llvm::ArrayRef(Ns2);
+  Two.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   Reference RB(EmptySID, "OtherChildNamespace", InfoType::IT_namespace);
   Two.Children.Namespaces.push_back(RB);
-  Reference RC2(EmptySID, "OtherChildStruct", InfoType::IT_record);
-  Two.Children.Records.push_back(RC2);
-
-  FunctionInfo F2;
-  F2.Name = "TwoFunction";
-  Two.Children.Functions.push_back(F2);
-
-  EnumInfo E2;
-  E2.Name = "TwoEnum";
-  Two.Children.Enums.push_back(E2);
+  Two.Children.Records.emplace_back(EmptySID, "OtherChildStruct",
+                                    InfoType::IT_record);
+  Two.Children.Functions.emplace_back();
+  Two.Children.Functions.back().Name = "TwoFunction";
+  Two.Children.Enums.emplace_back();
+  Two.Children.Enums.back().Name = "TwoEnum";
 
   OwningPtrVec<Info> Infos;
-  Infos.push_back(&One);
-  Infos.push_back(&Two);
+  Infos.emplace_back(allocatePtr<NamespaceInfo>(std::move(One)));
+  Infos.emplace_back(allocatePtr<NamespaceInfo>(std::move(Two)));
 
-  NamespaceInfo Expected;
-  Expected.Name = "Namespace";
-  Reference NsExpected[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  Expected.Namespace = llvm::ArrayRef(NsExpected);
+  auto Expected = allocatePtr<NamespaceInfo>();
+  Expected->Name = "Namespace";
+  Expected->Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   Reference RC(NonEmptySID, "ChildNamespace", InfoType::IT_namespace);
-  Expected.Children.Namespaces.push_back(RC);
-  Reference RCE1(NonEmptySID, "ChildStruct", InfoType::IT_record);
-  Expected.Children.Records.push_back(RCE1);
+  Expected->Children.Namespaces.push_back(RC);
+  Expected->Children.Records.emplace_back(NonEmptySID, "ChildStruct",
+                                          InfoType::IT_record);
   Reference RD(EmptySID, "OtherChildNamespace", InfoType::IT_namespace);
-  Expected.Children.Namespaces.push_back(RD);
-  Reference RCE2(EmptySID, "OtherChildStruct", InfoType::IT_record);
-  Expected.Children.Records.push_back(RCE2);
-
-  FunctionInfo FE1;
-  FE1.Name = "OneFunction";
-  FE1.USR = NonEmptySID;
-  Expected.Children.Functions.push_back(FE1);
-
-  FunctionInfo FE2;
-  FE2.Name = "TwoFunction";
-  Expected.Children.Functions.push_back(FE2);
-
-  EnumInfo EE1;
-  EE1.Name = "OneEnum";
-  EE1.USR = NonEmptySID;
-  Expected.Children.Enums.push_back(EE1);
-
-  EnumInfo EE2;
-  EE2.Name = "TwoEnum";
-  Expected.Children.Enums.push_back(EE2);
+  Expected->Children.Namespaces.push_back(RD);
+  Expected->Children.Records.emplace_back(EmptySID, "OtherChildStruct",
+                                          InfoType::IT_record);
+  Expected->Children.Functions.emplace_back();
+  Expected->Children.Functions.back().Name = "OneFunction";
+  Expected->Children.Functions.back().USR = NonEmptySID;
+  Expected->Children.Functions.emplace_back();
+  Expected->Children.Functions.back().Name = "TwoFunction";
+  Expected->Children.Enums.emplace_back();
+  Expected->Children.Enums.back().Name = "OneEnum";
+  Expected->Children.Enums.back().USR = NonEmptySID;
+  Expected->Children.Enums.emplace_back();
+  Expected->Children.Enums.back().Name = "TwoEnum";
 
   auto Actual = mergeInfos(Infos);
   assert(Actual);
-  CheckNamespaceInfo(InfoAsNamespace(&Expected), InfoAsNamespace(Actual.get()));
+  CheckNamespaceInfo(InfoAsNamespace(Expected.get()),
+                     InfoAsNamespace(Actual.get().get()));
 }
 
 TEST_F(MergeTest, mergeRecordInfos) {
   RecordInfo One;
   One.Name = "r";
   One.IsTypeDef = true;
-  Reference Ns1[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  One.Namespace = llvm::ArrayRef(Ns1);
+  One.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   One.DefLoc = Location(10, 10, "test.cpp");
 
-  MemberTypeInfo M1[] = {
-      MemberTypeInfo(TypeInfo("int"), "X", AccessSpecifier::AS_private)};
-  One.Members = llvm::ArrayRef(M1);
+  One.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private);
   One.TagType = TagTypeKind::Class;
-  Reference P1[] = {Reference(EmptySID, "F", InfoType::IT_record)};
-  One.Parents = llvm::ArrayRef(P1);
-  Reference VP1[] = {Reference(EmptySID, "G", InfoType::IT_record)};
-  One.VirtualParents = llvm::ArrayRef(VP1);
-
-  BaseRecordInfo B1[] = {BaseRecordInfo(EmptySID, "F", "path/to/F", true,
-                                        AccessSpecifier::AS_protected, true)};
-  One.Bases = llvm::ArrayRef(B1);
-  Reference RCShared1(NonEmptySID, "SharedChildStruct", InfoType::IT_record);
-  One.Children.Records.push_back(RCShared1);
-
-  FunctionInfo F1;
-  F1.Name = "OneFunction";
-  F1.USR = NonEmptySID;
-  One.Children.Functions.push_back(F1);
-
-  EnumInfo E1;
-  E1.Name = "OneEnum";
-  E1.USR = NonEmptySID;
-  One.Children.Enums.push_back(E1);
+  One.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
+  One.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
+
+  One.Bases.emplace_back(EmptySID, "F", "path/to/F", true,
+                         AccessSpecifier::AS_protected, true);
+  One.Children.Records.emplace_back(NonEmptySID, "SharedChildStruct",
+                                    InfoType::IT_record);
+  One.Children.Functions.emplace_back();
+  One.Children.Functions.back().Name = "OneFunction";
+  One.Children.Functions.back().USR = NonEmptySID;
+  One.Children.Enums.emplace_back();
+  One.Children.Enums.back().Name = "OneEnum";
+  One.Children.Enums.back().USR = NonEmptySID;
 
   RecordInfo Two;
   Two.Name = "r";
-  Reference Ns2[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  Two.Namespace = llvm::ArrayRef(Ns2);
+  Two.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
-  Location Loc2(12, 12, "test.cpp");
-  Two.Loc.push_back(Loc2);
+  Two.Loc.emplace_back(12, 12, "test.cpp");
 
   Two.TagType = TagTypeKind::Class;
 
-  Reference RCShared2(NonEmptySID, "SharedChildStruct", InfoType::IT_record,
-                      "path");
-  Two.Children.Records.push_back(RCShared2);
-
-  FunctionInfo F2;
-  F2.Name = "TwoFunction";
-  Two.Children.Functions.push_back(F2);
-
-  EnumInfo E2;
-  E2.Name = "TwoEnum";
-  Two.Children.Enums.push_back(E2);
+  Two.Children.Records.emplace_back(NonEmptySID, "SharedChildStruct",
+                                    InfoType::IT_record, "path");
+  Two.Children.Functions.emplace_back();
+  Two.Children.Functions.back().Name = "TwoFunction";
+  Two.Children.Enums.emplace_back();
+  Two.Children.Enums.back().Name = "TwoEnum";
 
   OwningPtrVec<Info> Infos;
-  Infos.push_back(&One);
-  Infos.push_back(&Two);
-
-  RecordInfo Expected;
-  Expected.Name = "r";
-  Expected.IsTypeDef = true;
-  Reference NsE[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  Expected.Namespace = llvm::ArrayRef(NsE);
-
-  Expected.DefLoc = Location(10, 10, "test.cpp");
-  Location LocE(12, 12, "test.cpp");
-  Expected.Loc.push_back(LocE);
-
-  MemberTypeInfo ME[] = {
-      MemberTypeInfo(TypeInfo("int"), "X", AccessSpecifier::AS_private)};
-  Expected.Members = llvm::ArrayRef(ME);
-  Expected.TagType = TagTypeKind::Class;
-  Reference PE[] = {Reference(EmptySID, "F", InfoType::IT_record)};
-  Expected.Parents = llvm::ArrayRef(PE);
-  Reference VPE[] = {Reference(EmptySID, "G", InfoType::IT_record)};
-  Expected.VirtualParents = llvm::ArrayRef(VPE);
-  BaseRecordInfo BE[] = {BaseRecordInfo(EmptySID, "F", "path/to/F", true,
-                                        AccessSpecifier::AS_protected, true)};
-  Expected.Bases = llvm::ArrayRef(BE);
-
-  Reference RCSharedE(NonEmptySID, "SharedChildStruct", InfoType::IT_record,
-                      "path");
-  Expected.Children.Records.push_back(RCSharedE);
-  FunctionInfo FE1;
-  FE1.Name = "OneFunction";
-  FE1.USR = NonEmptySID;
-  Expected.Children.Functions.push_back(FE1);
-
-  FunctionInfo FE2;
-  FE2.Name = "TwoFunction";
-  Expected.Children.Functions.push_back(FE2);
-
-  EnumInfo EE1;
-  EE1.Name = "OneEnum";
-  EE1.USR = NonEmptySID;
-  Expected.Children.Enums.push_back(EE1);
-
-  EnumInfo EE2;
-  EE2.Name = "TwoEnum";
-  Expected.Children.Enums.push_back(EE2);
+  Infos.emplace_back(allocatePtr<RecordInfo>(std::move(One)));
+  Infos.emplace_back(allocatePtr<RecordInfo>(std::move(Two)));
+
+  auto Expected = allocatePtr<RecordInfo>();
+  Expected->Name = "r";
+  Expected->IsTypeDef = true;
+  Expected->Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+
+  Expected->DefLoc = Location(10, 10, "test.cpp");
+  Expected->Loc.emplace_back(12, 12, "test.cpp");
+
+  Expected->Members.emplace_back(TypeInfo("int"), "X",
+                                 AccessSpecifier::AS_private);
+  Expected->TagType = TagTypeKind::Class;
+  Expected->Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
+  Expected->VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
+  Expected->Bases.emplace_back(EmptySID, "F", "path/to/F", true,
+                               AccessSpecifier::AS_protected, true);
+
+  Expected->Children.Records.emplace_back(NonEmptySID, "SharedChildStruct",
+                                          InfoType::IT_record, "path");
+  Expected->Children.Functions.emplace_back();
+  Expected->Children.Functions.back().Name = "OneFunction";
+  Expected->Children.Functions.back().USR = NonEmptySID;
+  Expected->Children.Functions.emplace_back();
+  Expected->Children.Functions.back().Name = "TwoFunction";
+  Expected->Children.Enums.emplace_back();
+  Expected->Children.Enums.back().Name = "OneEnum";
+  Expected->Children.Enums.back().USR = NonEmptySID;
+  Expected->Children.Enums.emplace_back();
+  Expected->Children.Enums.back().Name = "TwoEnum";
 
   auto Actual = mergeInfos(Infos);
   assert(Actual);
-  CheckRecordInfo(InfoAsRecord(&Expected), InfoAsRecord(Actual.get()));
+  CheckRecordInfo(InfoAsRecord(Expected.get()),
+                  InfoAsRecord(Actual.get().get()));
 }
 
 TEST_F(MergeTest, mergeFunctionInfos) {
   FunctionInfo One;
   One.Name = "f";
-  Reference Ns1[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  One.Namespace = llvm::ArrayRef(Ns1);
+  One.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   One.DefLoc = Location(10, 10, "test.cpp");
-  Location Loc1(12, 12, "test.cpp");
-  One.Loc.push_back(Loc1);
+  One.Loc.emplace_back(12, 12, "test.cpp");
 
   One.IsMethod = true;
   One.Parent = Reference(EmptySID, "Parent", InfoType::IT_namespace);
@@ -220,106 +170,89 @@ TEST_F(MergeTest, mergeFunctionInfos) {
       CommentInfo(CommentKind::CK_TextComment, {}, "This is a text comment.")};
   CommentInfo OnePara[] = {
       CommentInfo(CommentKind::CK_ParagraphComment, OneText)};
-  CommentInfo TopOne(CommentKind::CK_FullComment, OnePara);
-  One.Description.push_back(TopOne);
+  One.Description.emplace_back(CommentKind::CK_FullComment, OnePara);
 
   FunctionInfo Two;
   Two.Name = "f";
-  Reference Ns2[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  Two.Namespace = llvm::ArrayRef(Ns2);
+  Two.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
-  Location Loc2(12, 12, "test.cpp");
-  Two.Loc.push_back(Loc2);
+  Two.Loc.emplace_back(12, 12, "test.cpp");
 
   Two.ReturnType = TypeInfo("void");
-  FieldTypeInfo P2(TypeInfo("int"), "P");
-  FieldTypeInfo Params2[] = {std::move(P2)};
-  Two.Params = llvm::ArrayRef(Params2);
+  Two.Params.emplace_back(TypeInfo("int"), "P");
 
   CommentInfo TwoText[] = {
       CommentInfo(CommentKind::CK_TextComment, {}, "This is a text comment.")};
   CommentInfo TwoPara[] = {
       CommentInfo(CommentKind::CK_ParagraphComment, TwoText)};
-  CommentInfo TopTwo(CommentKind::CK_FullComment, TwoPara);
-  Two.Description.push_back(TopTwo);
+  Two.Description.emplace_back(CommentKind::CK_FullComment, TwoPara);
 
   OwningPtrVec<Info> Infos;
-  Infos.push_back(&One);
-  Infos.push_back(&Two);
+  Infos.emplace_back(allocatePtr<FunctionInfo>(std::move(One)));
+  Infos.emplace_back(allocatePtr<FunctionInfo>(std::move(Two)));
 
-  FunctionInfo Expected;
-  Expected.Name = "f";
-  Reference NsE[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  Expected.Namespace = llvm::ArrayRef(NsE);
+  auto Expected = allocatePtr<FunctionInfo>();
+  Expected->Name = "f";
+  Expected->Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
-  Expected.DefLoc = Location(10, 10, "test.cpp");
-  Location LocE(12, 12, "test.cpp");
-  Expected.Loc.push_back(LocE);
+  Expected->DefLoc = Location(10, 10, "test.cpp");
+  Expected->Loc.emplace_back(12, 12, "test.cpp");
 
-  Expected.ReturnType = TypeInfo("void");
-  FieldTypeInfo PE(TypeInfo("int"), "P");
-  FieldTypeInfo ParamsE[] = {std::move(PE)};
-  Expected.Params = llvm::ArrayRef(ParamsE);
-  Expected.IsMethod = true;
-  Expected.Parent = Reference(EmptySID, "Parent", InfoType::IT_namespace);
+  Expected->ReturnType = TypeInfo("void");
+  Expected->Params.emplace_back(TypeInfo("int"), "P");
+  Expected->IsMethod = true;
+  Expected->Parent = Reference(EmptySID, "Parent", InfoType::IT_namespace);
 
   CommentInfo ExpectedText[] = {
       CommentInfo(CommentKind::CK_TextComment, {}, "This is a text comment.")};
   CommentInfo ExpectedPara[] = {
       CommentInfo(CommentKind::CK_ParagraphComment, ExpectedText)};
-  CommentInfo TopE(CommentKind::CK_FullComment, ExpectedPara);
-  Expected.Description.push_back(TopE);
+  Expected->Description.emplace_back(CommentKind::CK_FullComment, ExpectedPara);
 
   auto Actual = mergeInfos(Infos);
   assert(Actual);
-  CheckFunctionInfo(InfoAsFunction(&Expected), InfoAsFunction(Actual.get()));
+  CheckFunctionInfo(InfoAsFunction(Expected.get()),
+                    InfoAsFunction(Actual.get().get()));
 }
 
 TEST_F(MergeTest, mergeEnumInfos) {
   EnumInfo One;
   One.Name = "e";
-  Reference Ns1[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  One.Namespace = llvm::ArrayRef(Ns1);
+  One.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   One.DefLoc = Location(10, 10, "test.cpp");
-  Location Loc1(12, 12, "test.cpp");
-  One.Loc.push_back(Loc1);
+  One.Loc.emplace_back(12, 12, "test.cpp");
 
   One.Scoped = true;
 
   EnumInfo Two;
   Two.Name = "e";
-  Reference Ns2[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  Two.Namespace = llvm::ArrayRef(Ns2);
+  Two.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
-  Location Loc2(20, 20, "test.cpp");
-  Two.Loc.push_back(Loc2);
+  Two.Loc.emplace_back(20, 20, "test.cpp");
 
-  EnumValueInfo EV2[] = {EnumValueInfo("X"), EnumValueInfo("Y")};
-  Two.Members = llvm::ArrayRef(EV2);
+  Two.Members.emplace_back("X");
+  Two.Members.emplace_back("Y");
 
   OwningPtrVec<Info> Infos;
-  Infos.push_back(&One);
-  Infos.push_back(&Two);
+  Infos.emplace_back(allocatePtr<EnumInfo>(std::move(One)));
+  Infos.emplace_back(allocatePtr<EnumInfo>(std::move(Two)));
 
-  EnumInfo Expected;
-  Expected.Name = "e";
-  Reference NsE[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  Expected.Namespace = llvm::ArrayRef(NsE);
+  auto Expected = allocatePtr<EnumInfo>();
+  Expected->Name = "e";
+  Expected->Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
-  Expected.DefLoc = Location(10, 10, "test.cpp");
-  Location LocE1(12, 12, "test.cpp");
-  Expected.Loc.push_back(LocE1);
-  Location LocE2(20, 20, "test.cpp");
-  Expected.Loc.push_back(LocE2);
+  Expected->DefLoc = Location(10, 10, "test.cpp");
+  Expected->Loc.emplace_back(12, 12, "test.cpp");
+  Expected->Loc.emplace_back(20, 20, "test.cpp");
 
-  EnumValueInfo EV_E[] = {EnumValueInfo("X"), EnumValueInfo("Y")};
-  Expected.Members = llvm::ArrayRef(EV_E);
-  Expected.Scoped = true;
+  Expected->Members.emplace_back("X");
+  Expected->Members.emplace_back("Y");
+  Expected->Scoped = true;
 
   auto Actual = mergeInfos(Infos);
   assert(Actual);
-  CheckEnumInfo(InfoAsEnum(&Expected), InfoAsEnum(Actual.get()));
+  CheckEnumInfo(InfoAsEnum(Expected.get()), InfoAsEnum(Actual.get().get()));
 }
 
 } // namespace doc

diff  --git a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
index 371efab1b3081..4e963fd64f11b 100644
--- a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
@@ -117,27 +117,25 @@ TEST_F(SerializeTest, emitNamespaceInfo) {
   extractInfosFromCode("namespace A { namespace B { void f() {} } }", 5,
                        /*Public=*/false, Infos, this->Diags);
 
-  NamespaceInfo *A = InfoAsNamespace(Infos[0]);
+  NamespaceInfo *A = InfoAsNamespace(Infos[0].get());
   NamespaceInfo ExpectedA(EmptySID, "A");
   CheckNamespaceInfo(&ExpectedA, A);
 
-  NamespaceInfo *B = InfoAsNamespace(Infos[2]);
+  NamespaceInfo *B = InfoAsNamespace(Infos[2].get());
   NamespaceInfo ExpectedB(EmptySID, /*Name=*/"B", /*Path=*/"A");
-  Reference NsB[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  ExpectedB.Namespace = llvm::ArrayRef(NsB);
+  ExpectedB.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
   CheckNamespaceInfo(&ExpectedB, B);
 
-  NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[4]);
+  NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[4].get());
   NamespaceInfo ExpectedBWithFunction(EmptySID);
   FunctionInfo F;
   F.Name = "f";
   F.ReturnType = TypeInfo("void");
   F.DefLoc = Location(0, 0, "test.cpp");
-  Reference NsF[] = {Reference(EmptySID, "B", InfoType::IT_namespace),
-                     Reference(EmptySID, "A", InfoType::IT_namespace)};
-  F.Namespace = llvm::ArrayRef(NsF);
+  F.Namespace.emplace_back(EmptySID, "B", InfoType::IT_namespace);
+  F.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
   F.Access = AccessSpecifier::AS_none;
-  ExpectedBWithFunction.Children.Functions.push_back(F);
+  ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));
   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
 }
 
@@ -146,7 +144,7 @@ TEST_F(SerializeTest, emitAnonymousNamespaceInfo) {
   extractInfosFromCode("namespace { }", 2, /*Public=*/false, Infos,
                        this->Diags);
 
-  NamespaceInfo *A = InfoAsNamespace(Infos[0]);
+  NamespaceInfo *A = InfoAsNamespace(Infos[0].get());
   NamespaceInfo ExpectedA(EmptySID);
   ExpectedA.Name = "@nonymous_namespace";
   CheckNamespaceInfo(&ExpectedA, A);
@@ -172,103 +170,95 @@ void F<int>::TemplateMethod();
 typedef struct {} G;)raw",
                        10, /*Public=*/false, Infos, this->Diags);
 
-  RecordInfo *E = InfoAsRecord(Infos[0]);
+  RecordInfo *E = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
-  Reference NsE[] = {
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  ExpectedE.Namespace = llvm::ArrayRef(NsE);
+  ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                   InfoType::IT_namespace);
   ExpectedE.TagType = TagTypeKind::Class;
   ExpectedE.DefLoc = Location(0, 0, "test.cpp");
-  MemberTypeInfo MemE[] = {
-      MemberTypeInfo(TypeInfo("int"), "value", AccessSpecifier::AS_public)};
-  ExpectedE.Members = llvm::ArrayRef(MemE);
+  ExpectedE.Members.emplace_back(TypeInfo("int"), "value",
+                                 AccessSpecifier::AS_public);
   // TODO the data member should have the docstring on it:
   //ExpectedE.Members.back().Description.push_back(MakeOneLineCommentInfo(" Some docs"));
   CheckRecordInfo(&ExpectedE, E);
 
-  RecordInfo *RecordWithEConstructor = InfoAsRecord(Infos[2]);
+  RecordInfo *RecordWithEConstructor = InfoAsRecord(Infos[2].get());
   RecordInfo ExpectedRecordWithEConstructor(EmptySID);
   FunctionInfo EConstructor;
   EConstructor.Name = "E";
   EConstructor.Parent = Reference(EmptySID, "E", InfoType::IT_record);
   EConstructor.ReturnType = TypeInfo("void");
   EConstructor.DefLoc = Location(0, 0, "test.cpp");
-  Reference NsEC[] = {
-      Reference(EmptySID, "E", InfoType::IT_record),
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  EConstructor.Namespace = llvm::ArrayRef(NsEC);
+  EConstructor.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record);
+  EConstructor.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                      InfoType::IT_namespace);
   EConstructor.Access = AccessSpecifier::AS_public;
   EConstructor.IsMethod = true;
-  ExpectedRecordWithEConstructor.Children.Functions.push_back(EConstructor);
+  ExpectedRecordWithEConstructor.Children.Functions.emplace_back(
+      std::move(EConstructor));
   CheckRecordInfo(&ExpectedRecordWithEConstructor, RecordWithEConstructor);
 
-  RecordInfo *RecordWithMethod = InfoAsRecord(Infos[3]);
+  RecordInfo *RecordWithMethod = InfoAsRecord(Infos[3].get());
   RecordInfo ExpectedRecordWithMethod(EmptySID);
   FunctionInfo Method;
   Method.Name = "ProtectedMethod";
   Method.Parent = Reference(EmptySID, "E", InfoType::IT_record);
   Method.ReturnType = TypeInfo("void");
-  Location LMethod(0, 0, "test.cpp");
-  Method.Loc.push_back(LMethod);
-  Reference NsMethod[] = {
-      Reference(EmptySID, "E", InfoType::IT_record),
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  Method.Namespace = llvm::ArrayRef(NsMethod);
+  Method.Loc.emplace_back(0, 0, "test.cpp");
+  Method.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record);
+  Method.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                InfoType::IT_namespace);
   Method.Access = AccessSpecifier::AS_protected;
   Method.IsMethod = true;
-  ExpectedRecordWithMethod.Children.Functions.push_back(Method);
+  ExpectedRecordWithMethod.Children.Functions.emplace_back(std::move(Method));
   CheckRecordInfo(&ExpectedRecordWithMethod, RecordWithMethod);
 
-  RecordInfo *F = InfoAsRecord(Infos[4]);
+  RecordInfo *F = InfoAsRecord(Infos[4].get());
   RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace");
-  Reference NsF3[] = {
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  ExpectedF.Namespace = llvm::ArrayRef(NsF3);
+  ExpectedF.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                   InfoType::IT_namespace);
   ExpectedF.TagType = TagTypeKind::Struct;
   ExpectedF.DefLoc = Location(0, 0, "test.cpp");
   CheckRecordInfo(&ExpectedF, F);
 
-  RecordInfo *RecordWithTemplateMethod = InfoAsRecord(Infos[6]);
+  RecordInfo *RecordWithTemplateMethod = InfoAsRecord(Infos[6].get());
   RecordInfo ExpectedRecordWithTemplateMethod(EmptySID);
   FunctionInfo TemplateMethod;
   TemplateMethod.Name = "TemplateMethod";
   TemplateMethod.Parent = Reference(EmptySID, "F", InfoType::IT_record);
   TemplateMethod.ReturnType = TypeInfo("void");
-  Location LTemp1(0, 0, "test.cpp");
-  TemplateMethod.Loc.push_back(LTemp1);
-  Reference NsT1[] = {
-      Reference(EmptySID, "F", InfoType::IT_record),
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  TemplateMethod.Namespace = llvm::ArrayRef(NsT1);
+  TemplateMethod.Loc.emplace_back(0, 0, "test.cpp");
+  TemplateMethod.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record);
+  TemplateMethod.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                        InfoType::IT_namespace);
   TemplateMethod.Access = AccessSpecifier::AS_public;
   TemplateMethod.IsMethod = true;
-  ExpectedRecordWithTemplateMethod.Children.Functions.push_back(TemplateMethod);
+  ExpectedRecordWithTemplateMethod.Children.Functions.emplace_back(
+      std::move(TemplateMethod));
   CheckRecordInfo(&ExpectedRecordWithTemplateMethod, RecordWithTemplateMethod);
 
-  RecordInfo *TemplatedRecord = InfoAsRecord(Infos[7]);
+  RecordInfo *TemplatedRecord = InfoAsRecord(Infos[7].get());
   RecordInfo ExpectedTemplatedRecord(EmptySID);
   FunctionInfo SpecializedTemplateMethod;
   SpecializedTemplateMethod.Name = "TemplateMethod";
   SpecializedTemplateMethod.Parent =
       Reference(EmptySID, "F", InfoType::IT_record);
   SpecializedTemplateMethod.ReturnType = TypeInfo("void");
-  Location LTemp2(0, 0, "test.cpp");
-  SpecializedTemplateMethod.Loc.push_back(LTemp2);
-  Reference NsT2[] = {
-      Reference(EmptySID, "F", InfoType::IT_record),
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  SpecializedTemplateMethod.Namespace = llvm::ArrayRef(NsT2);
+  SpecializedTemplateMethod.Loc.emplace_back(0, 0, "test.cpp");
+  SpecializedTemplateMethod.Namespace.emplace_back(EmptySID, "F",
+                                                   InfoType::IT_record);
+  SpecializedTemplateMethod.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                                   InfoType::IT_namespace);
   SpecializedTemplateMethod.Access = AccessSpecifier::AS_public;
   SpecializedTemplateMethod.IsMethod = true;
-  ExpectedTemplatedRecord.Children.Functions.push_back(
-      SpecializedTemplateMethod);
+  ExpectedTemplatedRecord.Children.Functions.emplace_back(
+      std::move(SpecializedTemplateMethod));
   CheckRecordInfo(&ExpectedTemplatedRecord, TemplatedRecord);
 
-  RecordInfo *G = InfoAsRecord(Infos[8]);
+  RecordInfo *G = InfoAsRecord(Infos[8].get());
   RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace");
-  Reference NsG[] = {
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  ExpectedG.Namespace = llvm::ArrayRef(NsG);
+  ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                   InfoType::IT_namespace);
   ExpectedG.TagType = TagTypeKind::Struct;
   ExpectedG.DefLoc = Location(0, 0, "test.cpp");
   ExpectedG.IsTypeDef = true;
@@ -281,25 +271,25 @@ TEST_F(SerializeTest, emitEnumInfo) {
   extractInfosFromCode("enum E { X, Y }; enum class G { A, B };", 2,
                        /*Public=*/false, Infos, this->Diags);
 
-  NamespaceInfo *NamespaceWithEnum = InfoAsNamespace(Infos[0]);
+  NamespaceInfo *NamespaceWithEnum = InfoAsNamespace(Infos[0].get());
   NamespaceInfo ExpectedNamespaceWithEnum(EmptySID);
   EnumInfo E;
   E.Name = "E";
   E.DefLoc = Location(0, 0, "test.cpp");
-  EnumValueInfo EMem[] = {EnumValueInfo("X", "0"), EnumValueInfo("Y", "1")};
-  E.Members = llvm::ArrayRef(EMem);
-  ExpectedNamespaceWithEnum.Children.Enums.push_back(E);
+  E.Members.emplace_back("X", "0");
+  E.Members.emplace_back("Y", "1");
+  ExpectedNamespaceWithEnum.Children.Enums.emplace_back(std::move(E));
   CheckNamespaceInfo(&ExpectedNamespaceWithEnum, NamespaceWithEnum);
 
-  NamespaceInfo *NamespaceWithScopedEnum = InfoAsNamespace(Infos[1]);
+  NamespaceInfo *NamespaceWithScopedEnum = InfoAsNamespace(Infos[1].get());
   NamespaceInfo ExpectedNamespaceWithScopedEnum(EmptySID);
   EnumInfo G;
   G.Name = "G";
   G.Scoped = true;
   G.DefLoc = Location(0, 0, "test.cpp");
-  EnumValueInfo GMem[] = {EnumValueInfo("A", "0"), EnumValueInfo("B", "1")};
-  G.Members = llvm::ArrayRef(GMem);
-  ExpectedNamespaceWithScopedEnum.Children.Enums.push_back(G);
+  G.Members.emplace_back("A", "0");
+  G.Members.emplace_back("B", "1");
+  ExpectedNamespaceWithScopedEnum.Children.Enums.emplace_back(std::move(G));
   CheckNamespaceInfo(&ExpectedNamespaceWithScopedEnum, NamespaceWithScopedEnum);
 }
 
@@ -307,14 +297,12 @@ TEST_F(SerializeTest, emitUndefinedRecordInfo) {
   EmittedInfoList Infos;
   extractInfosFromCode("class E;", 2, /*Public=*/false, Infos, this->Diags);
 
-  RecordInfo *E = InfoAsRecord(Infos[0]);
+  RecordInfo *E = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
-  Reference NsE[] = {
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  ExpectedE.Namespace = llvm::ArrayRef(NsE);
+  ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                   InfoType::IT_namespace);
   ExpectedE.TagType = TagTypeKind::Class;
-  Location LE(0, 0, "test.cpp");
-  ExpectedE.Loc.push_back(LE);
+  ExpectedE.Loc.emplace_back(0, 0, "test.cpp");
   CheckRecordInfo(&ExpectedE, E);
 }
 
@@ -323,16 +311,14 @@ TEST_F(SerializeTest, emitRecordMemberInfo) {
   extractInfosFromCode("struct E { int I; };", 2, /*Public=*/false, Infos,
                        this->Diags);
 
-  RecordInfo *E = InfoAsRecord(Infos[0]);
+  RecordInfo *E = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
-  Reference NsE[] = {
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  ExpectedE.Namespace = llvm::ArrayRef(NsE);
+  ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                   InfoType::IT_namespace);
   ExpectedE.TagType = TagTypeKind::Struct;
   ExpectedE.DefLoc = Location(0, 0, "test.cpp");
-  MemberTypeInfo MemE[] = {
-      MemberTypeInfo(TypeInfo("int"), "I", AccessSpecifier::AS_public)};
-  ExpectedE.Members = llvm::ArrayRef(MemE);
+  ExpectedE.Members.emplace_back(TypeInfo("int"), "I",
+                                 AccessSpecifier::AS_public);
   CheckRecordInfo(&ExpectedE, E);
 }
 
@@ -341,25 +327,23 @@ TEST_F(SerializeTest, emitInternalRecordInfo) {
   extractInfosFromCode("class E { class G {}; };", 4, /*Public=*/false, Infos,
                        this->Diags);
 
-  RecordInfo *E = InfoAsRecord(Infos[0]);
+  RecordInfo *E = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
-  Reference NsE[] = {
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  ExpectedE.Namespace = llvm::ArrayRef(NsE);
+  ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                   InfoType::IT_namespace);
   ExpectedE.DefLoc = Location(0, 0, "test.cpp");
   ExpectedE.TagType = TagTypeKind::Class;
   CheckRecordInfo(&ExpectedE, E);
 
-  RecordInfo *G = InfoAsRecord(Infos[2]);
+  RecordInfo *G = InfoAsRecord(Infos[2].get());
   llvm::SmallString<128> ExpectedGPath("GlobalNamespace/E");
   llvm::sys::path::native(ExpectedGPath);
   RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/ExpectedGPath);
   ExpectedG.DefLoc = Location(0, 0, "test.cpp");
   ExpectedG.TagType = TagTypeKind::Class;
-  Reference NsG[] = {
-      Reference(EmptySID, "E", InfoType::IT_record),
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  ExpectedG.Namespace = llvm::ArrayRef(NsG);
+  ExpectedG.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record);
+  ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                   InfoType::IT_namespace);
   CheckRecordInfo(&ExpectedG, G);
 }
 
@@ -374,14 +358,14 @@ TEST_F(SerializeTest, emitPublicFunctionInternalInfo) {
   extractInfosFromCode("int F() { class G {}; return 0; };", 1, /*Public=*/true,
                        Infos, this->Diags);
 
-  NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0]);
+  NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());
   NamespaceInfo ExpectedBWithFunction(EmptySID);
   FunctionInfo F;
   F.Name = "F";
   F.ReturnType = TypeInfo("int");
   F.DefLoc = Location(0, 0, "test.cpp");
   F.Access = AccessSpecifier::AS_none;
-  ExpectedBWithFunction.Children.Functions.push_back(F);
+  ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));
   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
 }
 
@@ -390,16 +374,15 @@ TEST_F(SerializeTest, emitInlinedFunctionInfo) {
   extractInfosFromCode("inline void F(int I) { };", 1, /*Public=*/true, Infos,
                        this->Diags);
 
-  NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0]);
+  NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());
   NamespaceInfo ExpectedBWithFunction(EmptySID);
   FunctionInfo F;
   F.Name = "F";
   F.ReturnType = TypeInfo("void");
   F.DefLoc = Location(0, 0, "test.cpp");
-  FieldTypeInfo Params[] = {FieldTypeInfo(TypeInfo("int"), "I")};
-  F.Params = llvm::ArrayRef(Params);
+  F.Params.emplace_back(TypeInfo("int"), "I");
   F.Access = AccessSpecifier::AS_none;
-  ExpectedBWithFunction.Children.Functions.push_back(F);
+  ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));
   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
 }
 
@@ -414,169 +397,132 @@ class I {} ;
 class J : public I<int> {} ;)raw",
                        14, /*Public=*/false, Infos, this->Diags);
 
-  RecordInfo *F = InfoAsRecord(Infos[0]);
+  RecordInfo *F = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace");
-  Reference NsF[] = {
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  ExpectedF.Namespace = llvm::ArrayRef(NsF);
+  ExpectedF.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                   InfoType::IT_namespace, "");
   ExpectedF.TagType = TagTypeKind::Class;
   ExpectedF.DefLoc = Location(0, 0, "test.cpp");
   CheckRecordInfo(&ExpectedF, F);
 
-  RecordInfo *G = InfoAsRecord(Infos[3]);
+  RecordInfo *G = InfoAsRecord(Infos[3].get());
   RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace");
-  Reference NsG[] = {
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  ExpectedG.Namespace = llvm::ArrayRef(NsG);
+  ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                   InfoType::IT_namespace);
   ExpectedG.TagType = TagTypeKind::Class;
   ExpectedG.DefLoc = Location(0, 0, "test.cpp");
-  MemberTypeInfo MemG[] = {
-      MemberTypeInfo(TypeInfo("int"), "I", AccessSpecifier::AS_protected)};
-  ExpectedG.Members = llvm::ArrayRef(MemG);
+  ExpectedG.Members.emplace_back(TypeInfo("int"), "I",
+                                 AccessSpecifier::AS_protected);
   CheckRecordInfo(&ExpectedG, G);
 
-  RecordInfo *E = InfoAsRecord(Infos[6]);
+  RecordInfo *E = InfoAsRecord(Infos[6].get());
   RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
-  Reference NsE[] = {
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  ExpectedE.Namespace = llvm::ArrayRef(NsE);
-  Reference ParE[] = {Reference(EmptySID, /*Name=*/"F", InfoType::IT_record,
-                                /*QualName=*/"", /*Path=*/"GlobalNamespace")};
-  ExpectedE.Parents = llvm::ArrayRef(ParE);
-  Reference VParE[] = {Reference(EmptySID, /*Name=*/"G", InfoType::IT_record,
-                                 /*QualName=*/"G",
-                                 /*Path=*/"GlobalNamespace")};
-  ExpectedE.VirtualParents = llvm::ArrayRef(VParE);
-  BaseRecordInfo BaseF(EmptySID, /*Name=*/"F",
-                       /*Path=*/"GlobalNamespace", false,
-                       AccessSpecifier::AS_public, true);
+  ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                   InfoType::IT_namespace);
+  ExpectedE.Parents.emplace_back(EmptySID, /*Name=*/"F", InfoType::IT_record,
+                                 /*QualName=*/"", /*Path*=*/"GlobalNamespace");
+  ExpectedE.VirtualParents.emplace_back(EmptySID, /*Name=*/"G",
+                                        InfoType::IT_record, /*QualName=*/"G",
+                                        /*Path*=*/"GlobalNamespace");
+  ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"F",
+                               /*Path=*/"GlobalNamespace", false,
+                               AccessSpecifier::AS_public, true);
   FunctionInfo FunctionSet;
   FunctionSet.Name = "set";
   FunctionSet.ReturnType = TypeInfo("void");
-  Location LSet;
-  FunctionSet.Loc.push_back(LSet);
-  FieldTypeInfo ParamsSet[] = {FieldTypeInfo(TypeInfo("int"), "N")};
-  FunctionSet.Params = llvm::ArrayRef(ParamsSet);
-  Reference NsSet[] = {
-      Reference(EmptySID, "F", InfoType::IT_record),
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  FunctionSet.Namespace = llvm::ArrayRef(NsSet);
-  FunctionSet.Access =
-      AccessSpecifier::AS_none; // Wait, previous had AS_protected, but wait,
-                                // F.Access was AS_protected. FunctionSet.Access
-                                // should be AS_protected if it was so. In the
-                                // original it was AS_protected.
+  FunctionSet.Loc.emplace_back();
+  FunctionSet.Params.emplace_back(TypeInfo("int"), "N");
+  FunctionSet.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record);
+  FunctionSet.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                     InfoType::IT_namespace);
   FunctionSet.Access = AccessSpecifier::AS_protected;
   FunctionSet.IsMethod = true;
-  BaseF.Children.Functions.push_back(FunctionSet);
-
-  BaseRecordInfo BaseG(EmptySID, /*Name=*/"G",
-                       /*Path=*/"GlobalNamespace", true,
-                       AccessSpecifier::AS_private, true);
+  ExpectedE.Bases.back().Children.Functions.emplace_back(
+      std::move(FunctionSet));
+  ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"G",
+                               /*Path=*/"GlobalNamespace", true,
+                               AccessSpecifier::AS_private, true);
   FunctionInfo FunctionGet;
   FunctionGet.Name = "get";
   FunctionGet.ReturnType = TypeInfo("int");
-  Location LGet;
-  FunctionGet.DefLoc = LGet;
-  Reference NsGet[] = {
-      Reference(EmptySID, "G", InfoType::IT_record),
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  FunctionGet.Namespace = llvm::ArrayRef(NsGet);
+  FunctionGet.DefLoc = Location();
+  FunctionGet.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record);
+  FunctionGet.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                     InfoType::IT_namespace);
   FunctionGet.Access = AccessSpecifier::AS_private;
   FunctionGet.IsMethod = true;
-  BaseG.Children.Functions.push_back(FunctionGet);
-  MemberTypeInfo MemG2[] = {
-      MemberTypeInfo(TypeInfo("int"), "I", AccessSpecifier::AS_private)};
-  BaseG.Members = llvm::ArrayRef(MemG2);
-
-  BaseRecordInfo BasesE[] = {std::move(BaseF), std::move(BaseG)};
-  ExpectedE.Bases = llvm::ArrayRef(BasesE);
+  ExpectedE.Bases.back().Children.Functions.emplace_back(
+      std::move(FunctionGet));
+  ExpectedE.Bases.back().Members.emplace_back(TypeInfo("int"), "I",
+                                              AccessSpecifier::AS_private);
   ExpectedE.DefLoc = Location(0, 0, "test.cpp");
   ExpectedE.TagType = TagTypeKind::Class;
   CheckRecordInfo(&ExpectedE, E);
 
-  RecordInfo *H = InfoAsRecord(Infos[8]);
+  RecordInfo *H = InfoAsRecord(Infos[8].get());
   RecordInfo ExpectedH(EmptySID, /*Name=*/"H", /*Path=*/"GlobalNamespace");
-  Reference NsH[] = {
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  ExpectedH.Namespace = llvm::ArrayRef(NsH);
+  ExpectedH.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                   InfoType::IT_namespace);
   ExpectedH.TagType = TagTypeKind::Class;
   ExpectedH.DefLoc = Location(0, 0, "test.cpp");
-  Reference ParH[] = {Reference(EmptySID, /*Name=*/"E", InfoType::IT_record,
-                                /*QualName=*/"E", /*Path=*/"GlobalNamespace")};
-  ExpectedH.Parents = llvm::ArrayRef(ParH);
-  Reference VParH[] = {Reference(EmptySID, /*Name=*/"G", InfoType::IT_record,
-                                 /*QualName=*/"G",
-                                 /*Path=*/"GlobalNamespace")};
-  ExpectedH.VirtualParents = llvm::ArrayRef(VParH);
-
-  BaseRecordInfo BaseHE(EmptySID, /*Name=*/"E",
-                        /*Path=*/"GlobalNamespace", false,
-                        AccessSpecifier::AS_private, true);
-
-  BaseRecordInfo BaseHF(EmptySID, /*Name=*/"F",
-                        /*Path=*/"GlobalNamespace", false,
-                        AccessSpecifier::AS_private, false);
+  ExpectedH.Parents.emplace_back(EmptySID, /*Name=*/"E", InfoType::IT_record,
+                                 /*QualName=*/"E", /*Path=*/"GlobalNamespace");
+  ExpectedH.VirtualParents.emplace_back(EmptySID, /*Name=*/"G",
+                                        InfoType::IT_record, /*QualName=*/"G",
+                                        /*Path=*/"GlobalNamespace");
+  ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"E",
+                               /*Path=*/"GlobalNamespace", false,
+                               AccessSpecifier::AS_private, true);
+  ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"F",
+                               /*Path=*/"GlobalNamespace", false,
+                               AccessSpecifier::AS_private, false);
   FunctionInfo FunctionSetNew;
   FunctionSetNew.Name = "set";
   FunctionSetNew.ReturnType = TypeInfo("void");
-  Location LSetNew;
-  FunctionSetNew.Loc.push_back(LSetNew);
-  FieldTypeInfo ParamsSetNew[] = {FieldTypeInfo(TypeInfo("int"), "N")};
-  FunctionSetNew.Params = llvm::ArrayRef(ParamsSetNew);
-  Reference NsSetNew[] = {
-      Reference(EmptySID, "F", InfoType::IT_record),
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  FunctionSetNew.Namespace = llvm::ArrayRef(NsSetNew);
+  FunctionSetNew.Loc.emplace_back();
+  FunctionSetNew.Params.emplace_back(TypeInfo("int"), "N");
+  FunctionSetNew.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record);
+  FunctionSetNew.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                        InfoType::IT_namespace);
   FunctionSetNew.Access = AccessSpecifier::AS_private;
   FunctionSetNew.IsMethod = true;
-  BaseHF.Children.Functions.push_back(FunctionSetNew);
-  BaseRecordInfo BaseHG(EmptySID, /*Name=*/"G",
-                        /*Path=*/"GlobalNamespace", true,
-                        AccessSpecifier::AS_private, false);
+  ExpectedH.Bases.back().Children.Functions.emplace_back(
+      std::move(FunctionSetNew));
+  ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"G",
+                               /*Path=*/"GlobalNamespace", true,
+                               AccessSpecifier::AS_private, false);
   FunctionInfo FunctionGetNew;
   FunctionGetNew.Name = "get";
   FunctionGetNew.ReturnType = TypeInfo("int");
-  Location LGetNew;
-  FunctionGetNew.DefLoc = LGetNew;
-  Reference NsGetNew[] = {
-      Reference(EmptySID, "G", InfoType::IT_record),
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  FunctionGetNew.Namespace = llvm::ArrayRef(NsGetNew);
+  FunctionGetNew.DefLoc = Location();
+  FunctionGetNew.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record);
+  FunctionGetNew.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                        InfoType::IT_namespace);
   FunctionGetNew.Access = AccessSpecifier::AS_private;
   FunctionGetNew.IsMethod = true;
-  BaseHG.Children.Functions.push_back(FunctionGetNew);
-  MemberTypeInfo MemHG[] = {
-      MemberTypeInfo(TypeInfo("int"), "I", AccessSpecifier::AS_private)};
-  BaseHG.Members = llvm::ArrayRef(MemHG);
-
-  BaseRecordInfo BasesH[] = {std::move(BaseHE), std::move(BaseHF),
-                             std::move(BaseHG)};
-  ExpectedH.Bases = llvm::ArrayRef(BasesH);
-
+  ExpectedH.Bases.back().Children.Functions.emplace_back(
+      std::move(FunctionGetNew));
+  ExpectedH.Bases.back().Members.emplace_back(TypeInfo("int"), "I",
+                                              AccessSpecifier::AS_private);
   CheckRecordInfo(&ExpectedH, H);
 
-  RecordInfo *I = InfoAsRecord(Infos[10]);
+  RecordInfo *I = InfoAsRecord(Infos[10].get());
   RecordInfo ExpectedI(EmptySID, /*Name=*/"I", /*Path=*/"GlobalNamespace");
-  Reference NsI[] = {
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  ExpectedI.Namespace = llvm::ArrayRef(NsI);
+  ExpectedI.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                   InfoType::IT_namespace);
   ExpectedI.TagType = TagTypeKind::Class;
   ExpectedI.DefLoc = Location(0, 0, "test.cpp");
   CheckRecordInfo(&ExpectedI, I);
 
-  RecordInfo *J = InfoAsRecord(Infos[12]);
+  RecordInfo *J = InfoAsRecord(Infos[12].get());
   RecordInfo ExpectedJ(EmptySID, /*Name=*/"J", /*Path=*/"GlobalNamespace");
-  Reference NsJ[] = {
-      Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
-  ExpectedJ.Namespace = llvm::ArrayRef(NsJ);
-  Reference ParJ[] = {
-      Reference(EmptySID, /*Name=*/"I<int>", InfoType::IT_record)};
-  ExpectedJ.Parents = llvm::ArrayRef(ParJ);
-  BaseRecordInfo BasesJ[] = {BaseRecordInfo(EmptySID, /*Name=*/"I<int>",
-                                            /*Path=*/"GlobalNamespace", false,
-                                            AccessSpecifier::AS_public, true)};
-  ExpectedJ.Bases = llvm::ArrayRef(BasesJ);
+  ExpectedJ.Namespace.emplace_back(EmptySID, "GlobalNamespace",
+                                   InfoType::IT_namespace);
+  ExpectedJ.Parents.emplace_back(EmptySID, /*Name=*/"I<int>",
+                                 InfoType::IT_record);
+  ExpectedJ.Bases.emplace_back(EmptySID, /*Name=*/"I<int>",
+                               /*Path=*/"GlobalNamespace", false,
+                               AccessSpecifier::AS_public, true);
   ExpectedJ.DefLoc = Location(0, 0, "test.cpp");
   ExpectedJ.TagType = TagTypeKind::Class;
   CheckRecordInfo(&ExpectedJ, J);
@@ -592,33 +538,30 @@ static int staticModuleFunction(int x);
 export double exportedModuleFunction(double y);)raw",
                                2, /*Public=*/true, Infos, Args, this->Diags);
 
-  NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0]);
+  NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());
   NamespaceInfo ExpectedBWithFunction(EmptySID);
   FunctionInfo F;
   F.Name = "moduleFunction";
   F.ReturnType = TypeInfo("int");
-  Location LF1(0, 0, "test.cpp");
-  F.Loc.push_back(LF1);
-  FieldTypeInfo ParamsF[] = {FieldTypeInfo(TypeInfo("int"), "x"),
-                             FieldTypeInfo(TypeInfo("double"), "d")};
-  ParamsF[1].DefaultValue = "3.2 - 1.0";
-  F.Params = llvm::ArrayRef(ParamsF);
+  F.Loc.emplace_back(0, 0, "test.cpp");
+  F.Params.emplace_back(TypeInfo("int"), "x");
+  F.Params.emplace_back(TypeInfo("double"), "d");
+  F.Params.back().DefaultValue = "3.2 - 1.0";
   F.Access = AccessSpecifier::AS_none;
-  ExpectedBWithFunction.Children.Functions.push_back(F);
+  ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));
   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
 
-  NamespaceInfo *BWithExportedFunction = InfoAsNamespace(Infos[1]);
+  NamespaceInfo *BWithExportedFunction = InfoAsNamespace(Infos[1].get());
   NamespaceInfo ExpectedBWithExportedFunction(EmptySID);
   FunctionInfo ExportedF;
   ExportedF.Name = "exportedModuleFunction";
   ExportedF.ReturnType =
       TypeInfo(Reference(EmptySID, "double", InfoType::IT_default));
-  Location LF2(0, 0, "test.cpp");
-  ExportedF.Loc.push_back(LF2);
-  FieldTypeInfo ParamsExportedF[] = {FieldTypeInfo(TypeInfo("double"), "y")};
-  ExportedF.Params = llvm::ArrayRef(ParamsExportedF);
+  ExportedF.Loc.emplace_back(0, 0, "test.cpp");
+  ExportedF.Params.emplace_back(TypeInfo("double"), "y");
   ExportedF.Access = AccessSpecifier::AS_none;
-  ExpectedBWithExportedFunction.Children.Functions.push_back(ExportedF);
+  ExpectedBWithExportedFunction.Children.Functions.emplace_back(
+      std::move(ExportedF));
   CheckNamespaceInfo(&ExpectedBWithExportedFunction, BWithExportedFunction);
 }
 
@@ -628,24 +571,24 @@ TEST_F(SerializeTest, emitChildRecords) {
   extractInfosFromCode("class A { class B {}; }; namespace { class C {}; } ", 8,
                        /*Public=*/false, Infos, this->Diags);
 
-  NamespaceInfo *ParentA = InfoAsNamespace(Infos[1]);
+  NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());
   NamespaceInfo ExpectedParentA(EmptySID);
-  Reference RA(EmptySID, "A", InfoType::IT_record, "A", "GlobalNamespace");
-  ExpectedParentA.Children.Records.push_back(RA);
+  ExpectedParentA.Children.Records.emplace_back(
+      EmptySID, "A", InfoType::IT_record, "A", "GlobalNamespace");
   CheckNamespaceInfo(&ExpectedParentA, ParentA);
 
-  RecordInfo *ParentB = InfoAsRecord(Infos[3]);
+  RecordInfo *ParentB = InfoAsRecord(Infos[3].get());
   RecordInfo ExpectedParentB(EmptySID);
   llvm::SmallString<128> ExpectedParentBPath("GlobalNamespace/A");
   llvm::sys::path::native(ExpectedParentBPath);
-  Reference RB(EmptySID, "B", InfoType::IT_record, "A::B", ExpectedParentBPath);
-  ExpectedParentB.Children.Records.push_back(RB);
+  ExpectedParentB.Children.Records.emplace_back(
+      EmptySID, "B", InfoType::IT_record, "A::B", ExpectedParentBPath);
   CheckRecordInfo(&ExpectedParentB, ParentB);
 
-  NamespaceInfo *ParentC = InfoAsNamespace(Infos[7]);
+  NamespaceInfo *ParentC = InfoAsNamespace(Infos[7].get());
   NamespaceInfo ExpectedParentC(EmptySID);
-  Reference RC(EmptySID, "C", InfoType::IT_record, "C", "@nonymous_namespace");
-  ExpectedParentC.Children.Records.push_back(RC);
+  ExpectedParentC.Children.Records.emplace_back(
+      EmptySID, "C", InfoType::IT_record, "C", "@nonymous_namespace");
   CheckNamespaceInfo(&ExpectedParentC, ParentC);
 }
 
@@ -655,13 +598,13 @@ TEST_F(SerializeTest, emitChildNamespaces) {
   extractInfosFromCode("namespace A { namespace B { } }", 4, /*Public=*/false,
                        Infos, this->Diags);
 
-  NamespaceInfo *ParentA = InfoAsNamespace(Infos[1]);
+  NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());
   NamespaceInfo ExpectedParentA(EmptySID);
   Reference RA(EmptySID, "A", InfoType::IT_namespace);
   ExpectedParentA.Children.Namespaces.push_back(RA);
   CheckNamespaceInfo(&ExpectedParentA, ParentA);
 
-  NamespaceInfo *ParentB = InfoAsNamespace(Infos[3]);
+  NamespaceInfo *ParentB = InfoAsNamespace(Infos[3].get());
   NamespaceInfo ExpectedParentB(EmptySID);
   Reference RB(EmptySID, "B", InfoType::IT_namespace, "A::B", "A");
   ExpectedParentB.Children.Namespaces.push_back(RB);
@@ -674,10 +617,10 @@ TEST_F(SerializeTest, emitTypedefs) {
                        /*Public=*/false, Infos, this->Diags);
 
   // First info will be the global namespace with the typedef in it.
-  NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0]);
+  NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0].get());
   ASSERT_EQ(1u, GlobalNS1->Children.Typedefs.size());
 
-  const TypedefInfo &FirstTD = *GlobalNS1->Children.Typedefs.begin();
+  const TypedefInfo &FirstTD = GlobalNS1->Children.Typedefs[0];
   EXPECT_EQ("MyInt", FirstTD.Name);
   EXPECT_FALSE(FirstTD.IsUsing);
   EXPECT_EQ("int", FirstTD.Underlying.Type.Name);
@@ -685,11 +628,11 @@ TEST_F(SerializeTest, emitTypedefs) {
   // The second will be another global namespace with the using in it (the
   // global namespace is duplicated because the items haven't been merged at the
   // serialization phase of processing).
-  NamespaceInfo *GlobalNS2 = InfoAsNamespace(Infos[1]);
+  NamespaceInfo *GlobalNS2 = InfoAsNamespace(Infos[1].get());
   ASSERT_EQ(1u, GlobalNS2->Children.Typedefs.size());
 
   // Second is the "using" typedef.
-  const TypedefInfo &SecondTD = *GlobalNS2->Children.Typedefs.begin();
+  const TypedefInfo &SecondTD = GlobalNS2->Children.Typedefs[0];
   EXPECT_EQ("MyDouble", SecondTD.Name);
   EXPECT_TRUE(SecondTD.IsUsing);
   EXPECT_EQ("double", SecondTD.Underlying.Type.Name);
@@ -704,10 +647,10 @@ TEST_F(SerializeTest, emitFunctionTemplate) {
                        /*Public=*/false, Infos, this->Diags);
 
   // First info will be the global namespace.
-  NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0]);
+  NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0].get());
   ASSERT_EQ(1u, GlobalNS1->Children.Functions.size());
 
-  const FunctionInfo &Func1 = *GlobalNS1->Children.Functions.begin();
+  const FunctionInfo &Func1 = GlobalNS1->Children.Functions[0];
   EXPECT_EQ("GetFoo", Func1.Name);
   ASSERT_TRUE(Func1.Template);
   EXPECT_FALSE(Func1.Template->Specialization); // Not a specialization.
@@ -719,11 +662,11 @@ TEST_F(SerializeTest, emitFunctionTemplate) {
   // The second will be another global namespace with the function in it (the
   // global namespace is duplicated because the items haven't been merged at the
   // serialization phase of processing).
-  NamespaceInfo *GlobalNS2 = InfoAsNamespace(Infos[1]);
+  NamespaceInfo *GlobalNS2 = InfoAsNamespace(Infos[1].get());
   ASSERT_EQ(1u, GlobalNS2->Children.Functions.size());
 
   // This one is a template specialization.
-  const FunctionInfo &Func2 = *GlobalNS2->Children.Functions.begin();
+  const FunctionInfo &Func2 = GlobalNS2->Children.Functions[0];
   EXPECT_EQ("GetFoo", Func2.Name);
   ASSERT_TRUE(Func2.Template);
   EXPECT_TRUE(Func2.Template->Params.empty()); // No template params.
@@ -751,7 +694,7 @@ TEST_F(SerializeTest, emitClassTemplate) {
       /*Public=*/false, Infos, this->Diags);
 
   // First record.
-  const RecordInfo *Rec1 = InfoAsRecord(Infos[0]);
+  const RecordInfo *Rec1 = InfoAsRecord(Infos[0].get());
   EXPECT_EQ("MyTemplate", Rec1->Name);
   ASSERT_TRUE(Rec1->Template);
   EXPECT_FALSE(Rec1->Template->Specialization); // Not a specialization.
@@ -761,7 +704,7 @@ TEST_F(SerializeTest, emitClassTemplate) {
   EXPECT_EQ("int I", Rec1->Template->Params[0].Contents);
 
   // Second record.
-  const RecordInfo *Rec2 = InfoAsRecord(Infos[2]);
+  const RecordInfo *Rec2 = InfoAsRecord(Infos[2].get());
   EXPECT_EQ("MyTemplate", Rec2->Name);
   ASSERT_TRUE(Rec2->Template);
   EXPECT_TRUE(Rec2->Template->Params.empty()); // No template params.
@@ -773,7 +716,7 @@ TEST_F(SerializeTest, emitClassTemplate) {
   EXPECT_EQ(Rec1->USR, Rec2->Template->Specialization->SpecializationOf);
 
   // Third record.
-  const RecordInfo *Rec3 = InfoAsRecord(Infos[4]);
+  const RecordInfo *Rec3 = InfoAsRecord(Infos[4].get());
   EXPECT_EQ("OtherTemplate", Rec3->Name);
   ASSERT_TRUE(Rec3->Template);
 
@@ -783,7 +726,7 @@ TEST_F(SerializeTest, emitClassTemplate) {
   EXPECT_EQ("int U = 1", Rec3->Template->Params[1].Contents);
 
   // Fourth record.
-  const RecordInfo *Rec4 = InfoAsRecord(Infos[6]);
+  const RecordInfo *Rec4 = InfoAsRecord(Infos[6].get());
   EXPECT_EQ("OtherTemplate", Rec3->Name);
   ASSERT_TRUE(Rec4->Template);
   ASSERT_TRUE(Rec4->Template->Specialization);

diff  --git a/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
index 6f4b724bd9427..a7f8629b926c1 100644
--- a/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
@@ -28,25 +28,20 @@ TEST_F(YAMLGeneratorTest, emitNamespaceYAML) {
   NamespaceInfo I;
   I.Name = "Namespace";
   I.Path = "path/to/A";
-  Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   Reference NewNamespace(EmptySID, "ChildNamespace", InfoType::IT_namespace,
                          "path::to::A::Namespace::ChildNamespace",
                          "path/to/A/Namespace");
   I.Children.Namespaces.push_back(NewNamespace);
-  Reference ChildStruct(EmptySID, "ChildStruct", InfoType::IT_record,
-                        "path::to::A::Namespace::ChildStruct",
-                        "path/to/A/Namespace");
-  I.Children.Records.push_back(ChildStruct);
-  FunctionInfo F;
-  F.Name = "OneFunction";
-  F.Access = AccessSpecifier::AS_none;
-  I.Children.Functions.push_back(F);
-
-  EnumInfo E;
-  E.Name = "OneEnum";
-  I.Children.Enums.push_back(E);
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
+                                  "path::to::A::Namespace::ChildStruct",
+                                  "path/to/A/Namespace");
+  I.Children.Functions.emplace_back();
+  I.Children.Functions.back().Name = "OneFunction";
+  I.Children.Functions.back().Access = AccessSpecifier::AS_none;
+  I.Children.Enums.emplace_back();
+  I.Children.Enums.back().Name = "OneEnum";
 
   auto G = getYAMLGenerator();
   assert(G);
@@ -90,14 +85,12 @@ TEST_F(YAMLGeneratorTest, emitRecordYAML) {
   I.Name = "r";
   I.Path = "path/to/A";
   I.IsTypeDef = true;
-  Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   I.DefLoc = Location(10, 10, "test.cpp");
-  Location Loc1(12, 12, "test.cpp");
-  I.Loc.push_back(Loc1);
+  I.Loc.emplace_back(12, 12, "test.cpp");
 
-  MemberTypeInfo M(TypeInfo("int"), "X", AccessSpecifier::AS_private);
+  I.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private);
 
   // Member documentation.
   CommentInfo BriefChildren[] = {CommentInfo(CommentKind::CK_TextComment, {},
@@ -106,39 +99,26 @@ TEST_F(YAMLGeneratorTest, emitRecordYAML) {
   CommentInfo TopCommentChildren[] = {
       CommentInfo(CommentKind::CK_ParagraphComment, BriefChildren)};
   CommentInfo TopComment(CommentKind::CK_FullComment, TopCommentChildren);
-  M.Description.push_back(TopComment);
-  MemberTypeInfo MemArr[] = {std::move(M)};
-  I.Members = llvm::ArrayRef(MemArr);
+  I.Members.back().Description.push_back(std::move(TopComment));
 
   I.TagType = TagTypeKind::Class;
-  BaseRecordInfo B(EmptySID, "F", "path/to/F", true, AccessSpecifier::AS_public,
-                   true);
-  FunctionInfo F;
-  F.Name = "InheritedFunctionOne";
-  B.Children.Functions.push_back(F);
-  MemberTypeInfo BMem[] = {
-      MemberTypeInfo(TypeInfo("int"), "N", AccessSpecifier::AS_private)};
-  B.Members = llvm::ArrayRef(BMem);
-  BaseRecordInfo Bases[] = {std::move(B)};
-  I.Bases = llvm::ArrayRef(Bases);
-
+  I.Bases.emplace_back(EmptySID, "F", "path/to/F", true,
+                       AccessSpecifier::AS_public, true);
+  I.Bases.back().Children.Functions.emplace_back();
+  I.Bases.back().Children.Functions.back().Name = "InheritedFunctionOne";
+  I.Bases.back().Members.emplace_back(TypeInfo("int"), "N",
+                                      AccessSpecifier::AS_private);
   // F is in the global namespace
-  Reference Parents[] = {Reference(EmptySID, "F", InfoType::IT_record, "")};
-  I.Parents = llvm::ArrayRef(Parents);
-  Reference VParents[] = {Reference(EmptySID, "G", InfoType::IT_record,
-                                    "path::to::G::G", "path/to/G")};
-  I.VirtualParents = llvm::ArrayRef(VParents);
-
-  Reference ChildStruct(EmptySID, "ChildStruct", InfoType::IT_record,
-                        "path::to::A::r::ChildStruct", "path/to/A/r");
-  I.Children.Records.push_back(ChildStruct);
-  FunctionInfo F2;
-  F2.Name = "OneFunction";
-  I.Children.Functions.push_back(F2);
-
-  EnumInfo E;
-  E.Name = "OneEnum";
-  I.Children.Enums.push_back(E);
+  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, "");
+  I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record,
+                                "path::to::G::G", "path/to/G");
+
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
+                                  "path::to::A::r::ChildStruct", "path/to/A/r");
+  I.Children.Functions.emplace_back();
+  I.Children.Functions.back().Name = "OneFunction";
+  I.Children.Enums.emplace_back();
+  I.Children.Enums.back().Name = "OneEnum";
 
   auto G = getYAMLGenerator();
   assert(G);
@@ -225,22 +205,17 @@ IsTypeDef:       true
 TEST_F(YAMLGeneratorTest, emitFunctionYAML) {
   FunctionInfo I;
   I.Name = "f";
-  Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   I.DefLoc = Location(10, 10, "test.cpp");
-  Location Loc1(12, 12, "test.cpp");
-  I.Loc.push_back(Loc1);
+  I.Loc.emplace_back(12, 12, "test.cpp");
 
   I.Access = AccessSpecifier::AS_none;
 
   I.ReturnType = TypeInfo(Reference(EmptySID, "void", InfoType::IT_default));
-
-  FieldTypeInfo P1(TypeInfo("int"), "P");
-  FieldTypeInfo D(TypeInfo("double"), "D");
-  D.DefaultValue = "2.0 * M_PI";
-  FieldTypeInfo Params[] = {std::move(P1), std::move(D)};
-  I.Params = llvm::ArrayRef(Params);
+  I.Params.emplace_back(TypeInfo("int"), "P");
+  I.Params.emplace_back(TypeInfo("double"), "D");
+  I.Params.back().DefaultValue = "2.0 * M_PI";
   I.IsMethod = true;
   I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
 
@@ -295,15 +270,12 @@ IsMethod:        true
 TEST_F(YAMLGeneratorTest, emitSimpleEnumYAML) {
   EnumInfo I;
   I.Name = "e";
-  Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
-  I.Namespace = llvm::ArrayRef(Ns);
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   I.DefLoc = Location(10, 10, "test.cpp");
-  Location Loc1(12, 12, "test.cpp");
-  I.Loc.push_back(Loc1);
+  I.Loc.emplace_back(12, 12, "test.cpp");
 
-  EnumValueInfo EV[] = {EnumValueInfo("X")};
-  I.Members = llvm::ArrayRef(EV);
+  I.Members.emplace_back("X");
   I.Scoped = false;
 
   auto G = getYAMLGenerator();
@@ -340,8 +312,7 @@ TEST_F(YAMLGeneratorTest, enumTypedScopedEnumYAML) {
   EnumInfo I;
   I.Name = "e";
 
-  EnumValueInfo EV[] = {EnumValueInfo("X", "-9876", "FOO_BAR + 2")};
-  I.Members = llvm::ArrayRef(EV);
+  I.Members.emplace_back("X", "-9876", "FOO_BAR + 2");
   I.Scoped = true;
   I.BaseType = TypeInfo("short");
 
@@ -399,9 +370,8 @@ TEST_F(YAMLGeneratorTest, emitCommentYAML) {
   I.Name = "f";
   I.DefLoc = Location(10, 10, "test.cpp");
   I.ReturnType = TypeInfo("void");
-  FieldTypeInfo Params[] = {FieldTypeInfo(TypeInfo("int"), "I"),
-                            FieldTypeInfo(TypeInfo("int"), "J")};
-  I.Params = llvm::ArrayRef(Params);
+  I.Params.emplace_back(TypeInfo("int"), "I");
+  I.Params.emplace_back(TypeInfo("int"), "J");
   I.Access = AccessSpecifier::AS_none;
 
   // BlankLine
@@ -474,7 +444,7 @@ TEST_F(YAMLGeneratorTest, emitCommentYAML) {
                                Verbatim,  ParamOut, ParamIn,  Return};
   CommentInfo Top(CommentKind::CK_FullComment, TopChildren);
 
-  I.Description.push_back(Top);
+  I.Description.emplace_back(std::move(Top));
 
   auto G = getYAMLGenerator();
   assert(G);


        


More information about the cfe-commits mailing list