[clang-tools-extra] Reapply "[clang-doc] Move Info types into arenas (#190054)" (PR #192495)
Paul Kirth via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 24 13:53:05 PDT 2026
https://github.com/ilovepi updated https://github.com/llvm/llvm-project/pull/192495
>From d415e124c858167ee5ed92f5923fbb221ab11c94 Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Mon, 13 Apr 2026 15:28:08 +0000
Subject: [PATCH 01/11] Reapply "[clang-doc] Move Info types into arenas
(#190054)"
This reverts commit e0caad9178d7e8c7c9551a466de7fd4a5d5e447d.
---
clang-tools-extra/clang-doc/BitcodeReader.cpp | 606 ++++++++++++------
clang-tools-extra/clang-doc/BitcodeReader.h | 20 +
clang-tools-extra/clang-doc/JSONGenerator.cpp | 45 +-
clang-tools-extra/clang-doc/MDGenerator.cpp | 9 +-
clang-tools-extra/clang-doc/Mapper.cpp | 3 +
.../clang-doc/Representation.cpp | 46 +-
clang-tools-extra/clang-doc/Representation.h | 110 ++--
clang-tools-extra/clang-doc/Serialize.cpp | 204 ++++--
clang-tools-extra/clang-doc/Serialize.h | 18 +-
clang-tools-extra/clang-doc/YAMLGenerator.cpp | 78 ++-
.../benchmarks/ClangDocBenchmark.cpp | 7 +-
.../unittests/clang-doc/BitcodeTest.cpp | 113 ++--
.../unittests/clang-doc/ClangDocTest.cpp | 274 +++++---
.../unittests/clang-doc/ClangDocTest.h | 37 +-
.../unittests/clang-doc/GeneratorTest.cpp | 6 +-
.../unittests/clang-doc/JSONGeneratorTest.cpp | 83 ++-
.../unittests/clang-doc/MDGeneratorTest.cpp | 73 ++-
.../unittests/clang-doc/MergeTest.cpp | 335 ++++++----
.../unittests/clang-doc/SerializeTest.cpp | 435 +++++++------
.../unittests/clang-doc/YAMLGeneratorTest.cpp | 112 ++--
20 files changed, 1660 insertions(+), 954 deletions(-)
diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp
index b7f4d6aa7ba23..c5e848ae4c28d 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -129,14 +129,15 @@ static llvm::Error decodeRecord(const Record &R, FieldId &Field,
"invalid value for FieldId");
}
-static llvm::Error decodeRecord(const Record &R,
- llvm::SmallVectorImpl<Location> &Field,
+static llvm::Error decodeRecord(const Record &R, OwningVec<Location> &Field,
llvm::StringRef Blob) {
if (R[0] > INT_MAX)
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"integer too large to parse");
- Field.emplace_back(static_cast<int>(R[0]), static_cast<int>(R[1]), Blob,
- static_cast<bool>(R[2]));
+
+ Field.push_back(*allocatePtr<Location>(static_cast<int>(R[0]),
+ static_cast<int>(R[1]), Blob,
+ static_cast<bool>(R[2])));
return llvm::Error::success();
}
@@ -425,6 +426,99 @@ 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;
@@ -448,25 +542,13 @@ llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, CommentInfo *I) {
if (!LocalChildren.empty())
I->Children =
allocateArray<CommentInfo>(LocalChildren, 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());
- }
+ if (!AttrKeys.empty())
+ I->AttrKeys = allocateArray(AttrKeys, TransientArena);
+ if (!AttrValues.empty())
+ I->AttrValues = allocateArray(AttrValues, TransientArena);
+ if (!Args.empty())
+ I->Args = allocateArray(Args, TransientArena);
+
return llvm::Error::success();
},
[&](unsigned BlockOrCode) -> llvm::Error {
@@ -481,6 +563,219 @@ 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) {
@@ -579,51 +874,25 @@ 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.
@@ -633,26 +902,11 @@ 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();
@@ -681,9 +935,6 @@ 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");
@@ -727,9 +978,6 @@ 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");
@@ -738,9 +986,6 @@ 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");
@@ -750,16 +995,13 @@ 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_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);
+ case FieldId::F_child_namespace:
+ I->Children.Namespaces.push_back(
+ *allocatePtr<Reference>(TransientArena, std::move(R)));
return llvm::Error::success();
- }
case FieldId::F_child_record:
- I->Children.Records.emplace_back(std::move(R));
+ I->Children.Records.push_back(
+ *allocatePtr<Reference>(TransientArena, std::move(R)));
return llvm::Error::success();
default:
return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -770,9 +1012,6 @@ 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();
@@ -784,17 +1023,9 @@ 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.emplace_back(std::move(R));
+ I->Children.Records.push_back(
+ *allocatePtr<Reference>(TransientArena, std::move(R)));
return llvm::Error::success();
default:
return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -823,54 +1054,42 @@ llvm::Error addReference(FriendInfo *Friend, Reference &&R, FieldId F) {
"Friend cannot contain this Reference");
}
-template <typename T, typename ChildInfoType>
-static void addChild(T I, ChildInfoType &&R) {
+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;
+ }
+ }
+ }
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).
@@ -879,13 +1098,6 @@ 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) {
@@ -925,9 +1137,6 @@ 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>
@@ -952,6 +1161,37 @@ 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(
@@ -969,13 +1209,13 @@ llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, FriendInfo *I) {
return parseBlock(
ID, I,
[&](unsigned BlockOrCode) -> llvm::Expected<bool> {
- 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));
+ auto B = readSubBlockIfMatch(BlockOrCode, BI_FIELD_TYPE_BLOCK_ID,
+ LocalParams);
+ if (!B)
+ return B.takeError();
+ if (*B)
return true;
- }
+
return false;
},
[&]() -> llvm::Error {
@@ -988,27 +1228,19 @@ 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;
- 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();
+ 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));
+ }
}
template <typename T>
@@ -1032,15 +1264,15 @@ llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) {
return llvm::Error::success();
}
case BI_TYPE_BLOCK_ID: {
- return handleTypeSubBlock<TypeInfo>(
- ID, I, CreateAddFunc(addTypeInfo<T, TypeInfo>));
+ return handleSubBlock<TypeInfo>(ID, I,
+ CreateAddFunc(addTypeInfo<T, TypeInfo>));
}
case BI_FIELD_TYPE_BLOCK_ID: {
- return handleTypeSubBlock<FieldTypeInfo>(
+ return handleSubBlock<FieldTypeInfo>(
ID, I, CreateAddFunc(addTypeInfo<T, FieldTypeInfo>));
}
case BI_MEMBER_TYPE_BLOCK_ID: {
- return handleTypeSubBlock<MemberTypeInfo>(
+ return handleSubBlock<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 d3499fdee0f5d..4585cb454f408 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.h
+++ b/clang-tools-extra/clang-doc/BitcodeReader.h
@@ -44,12 +44,32 @@ 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 e895d641a6000..4854c6114b760 100644
--- a/clang-tools-extra/clang-doc/JSONGenerator.cpp
+++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp
@@ -27,6 +27,7 @@ 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);
@@ -61,11 +62,13 @@ class JSONGenerator : public Generator {
};
}
-public:
- static const char *Format;
+ llvm::DenseMap<const Info *, SmallVector<Context, 4>> ContextsMap;
const ClangDocContext *CDCtx;
bool Markdown;
+public:
+ static const char *Format;
+
Error generateDocumentation(StringRef RootDir,
llvm::StringMap<OwnedPtr<doc::Info>> Infos,
const ClangDocContext &CDCtx,
@@ -320,13 +323,20 @@ 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) {
- json::Value ContextArray = json::Array();
- auto &ContextArrayRef = *ContextArray.getAsArray();
- ContextArrayRef.reserve(I.Contexts.size());
+ 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());
std::string CurrentRelativePath;
bool PreviousRecord = false;
- for (const auto &Current : I.Contexts) {
+ for (const auto &Current : Contexts) {
json::Value ContextVal = Object();
Object &Context = *ContextVal.getAsObject();
serializeReference(Current, Context);
@@ -372,11 +382,9 @@ void JSONGenerator::generateContext(const Info &I, Object &Obj) {
}
ContextArrayRef.back().getAsObject()->insert({"End", true});
- Obj["Contexts"] = ContextArray;
- Obj["HasContexts"] = true;
}
-static void serializeDescription(llvm::ArrayRef<CommentInfo> Description,
+static void serializeDescription(const OwningVec<CommentInfo> &Description,
json::Object &Obj, StringRef Key = "") {
if (Description.empty())
return;
@@ -429,7 +437,8 @@ void JSONGenerator::serializeCommonAttributes(const Info &I,
Obj["Location"] = serializeLocation(Symbol->DefLoc.value());
}
- if (!I.Contexts.empty())
+ auto It = ContextsMap.find(&I);
+ if (It != ContextsMap.end() && !It->second.empty())
generateContext(I, Obj);
}
@@ -826,9 +835,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 OwningVec<Index> preprocessCDCtxIndex(Index CDCtxIndex) {
+static std::vector<Index> preprocessCDCtxIndex(Index CDCtxIndex) {
CDCtxIndex.sort();
- OwningVec<Index> Processed;
+ std::vector<Index> Processed;
Processed.reserve(CDCtxIndex.Children.size());
for (const auto *Idx : CDCtxIndex.getSortedChildren()) {
Index NewIdx = *Idx;
@@ -848,7 +857,7 @@ Error JSONGenerator::serializeAllFiles(const ClangDocContext &CDCtx,
StringRef RootDir) {
json::Value ObjVal = Object();
Object &Obj = *ObjVal.getAsObject();
- OwningVec<Index> IndexCopy = preprocessCDCtxIndex(CDCtx.Idx);
+ std::vector<Index> IndexCopy = preprocessCDCtxIndex(CDCtx.Idx);
serializeArray(IndexCopy, Obj, "Index", serializeReferenceLambda());
SmallString<128> Path;
sys::path::append(Path, RootDir, "json", "all_files.json");
@@ -911,10 +920,12 @@ Error JSONGenerator::serializeIndex(StringRef RootDir) {
return Error::success();
}
-static void serializeContexts(Info *I, StringMap<OwnedPtr<Info>> &Infos) {
+void JSONGenerator::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),
@@ -928,12 +939,12 @@ static void serializeContexts(Info *I, StringMap<OwnedPtr<Info>> &Infos) {
Context GlobalRef(ParentInfo->USR, "Global Namespace",
InfoType::IT_namespace, "GlobalNamespace", "",
SmallString<16>("index"));
- I->Contexts.push_back(GlobalRef);
- return;
+ LocalContexts.push_back(GlobalRef);
+ break;
}
Context ParentRef(*ParentInfo);
- I->Contexts.push_back(ParentRef);
+ LocalContexts.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 b0253c5d71bfc..9ccb7a8ccd633 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -31,8 +31,7 @@ static std::string genEmphasis(const Twine &Text) {
return "**" + Text.str() + "**";
}
-static std::string
-genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs) {
+static std::string genReferenceList(llvm::ArrayRef<Reference> Refs) {
std::string Buffer;
llvm::raw_string_ostream Stream(Buffer);
for (const auto &R : Refs) {
@@ -82,7 +81,7 @@ class TableCommentWriter {
public:
explicit TableCommentWriter(llvm::raw_ostream &OS) : OS(OS) {}
- void write(llvm::ArrayRef<CommentInfo> Comments) {
+ void write(const OwningVec<CommentInfo> &Comments) {
for (const auto &C : Comments)
writeTableSafeComment(C);
@@ -436,7 +435,7 @@ static llvm::Error serializeIndex(ClangDocContext &CDCtx) {
OS << " for " << CDCtx.ProjectName;
OS << "\n\n";
- OwningVec<const Index *> Children = CDCtx.Idx.getSortedChildren();
+ std::vector<const Index *> Children = CDCtx.Idx.getSortedChildren();
for (const auto *C : Children)
serializeReference(OS, *C, 0);
@@ -455,7 +454,7 @@ static llvm::Error genIndex(ClangDocContext &CDCtx) {
FileErr.message());
CDCtx.Idx.sort();
OS << "# " << CDCtx.ProjectName << " C/C++ Reference\n\n";
- OwningVec<const Index *> Children = CDCtx.Idx.getSortedChildren();
+ std::vector<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 583a0fe43b40c..499ab5638b34e 100644
--- a/clang-tools-extra/clang-doc/Mapper.cpp
+++ b/clang-tools-extra/clang-doc/Mapper.cpp
@@ -43,6 +43,9 @@ 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 42f85c39655dd..1f01169b4c638 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -105,17 +105,6 @@ 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) {
@@ -133,24 +122,13 @@ static void reduceChildren(llvm::simple_ilist<T> &Children,
}
}
-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) {
- for (auto &Item : Source) {
+ while (!Source.empty()) {
+ auto &Item = Source.front();
+ Source.pop_front();
if (llvm::none_of(Target, [&](const auto &E) { return E == Item; }))
- Target.push_back(std::move(Item));
+ Target.push_back(Item);
}
}
@@ -484,8 +462,8 @@ bool Index::operator<(const Index &Other) const {
return Name < Other.Name;
}
-OwningVec<const Index *> Index::getSortedChildren() const {
- OwningVec<const Index *> SortedChildren;
+std::vector<const Index *> Index::getSortedChildren() const {
+ std::vector<const Index *> SortedChildren;
SortedChildren.reserve(Children.size());
for (const auto &[_, C] : Children)
SortedChildren.push_back(&C);
@@ -529,12 +507,12 @@ ClangDocContext::ClangDocContext(tooling::ExecutionContext *ECtx,
void ScopeChildren::sort() {
Namespaces.sort();
- llvm::sort(Records);
- llvm::sort(Functions);
- llvm::sort(Enums);
- llvm::sort(Typedefs);
- llvm::sort(Concepts);
- llvm::sort(Variables);
+ Records.sort();
+ Functions.sort();
+ Enums.sort();
+ Typedefs.sort();
+ Concepts.sort();
+ Variables.sort();
}
} // namespace doc
} // namespace clang
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index 9208b77fc8606..fd790d66c98fe 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -72,18 +72,28 @@ inline StringRef internString(const Twine &T) {
}
template <typename T>
-inline llvm::ArrayRef<T> allocateArray(llvm::ArrayRef<T> V,
- llvm::BumpPtrAllocator &Alloc) {
+llvm::ArrayRef<T> allocateArray(llvm::SmallVectorImpl<T> &V,
+ llvm::BumpPtrAllocator &Alloc) {
if (V.empty())
return llvm::ArrayRef<T>();
- T *Allocated = (T *)Alloc.Allocate<T>(V.size());
+ T *Allocated = static_cast<T *>(Alloc.Allocate<T>(V.size()));
std::uninitialized_move(V.begin(), V.end(), Allocated);
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 = static_cast<T *>(Alloc.Allocate<T>(V.size()));
+ std::uninitialized_copy(V.begin(), V.end(), Allocated);
+ 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 = std::unique_ptr<T>;
+template <typename T> using OwnedPtr = T *;
// An abstraction for vectors that are populated and read sequentially.
// To be eventually transitioned to llvm::ArrayRef for arena storage.
@@ -91,7 +101,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 = std::vector<T>;
+template <typename T> using OwningVec = llvm::simple_ilist<T>;
// An abstraction for dynamic lists of owned pointers.
// To be eventually transitioned to llvm::simple_ilist<T*> or similar.
@@ -105,9 +115,10 @@ template <typename T> using OwningPtrArray = std::vector<OwnedPtr<T>>;
// allocation mechanism.
template <typename T, typename... Args>
OwnedPtr<T> allocatePtr(Args &&...args) {
- return std::make_unique<T>(std::forward<Args>(args)...);
+ return new (TransientArena.Allocate<T>()) 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)...);
@@ -115,7 +126,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.get(); }
+template <typename T> T *getPtr(const OwnedPtr<T> &O) { return O; }
// SHA1'd hash of a USR.
using SymbolID = std::array<uint8_t, 20>;
@@ -292,7 +303,7 @@ struct ScopeChildren {
//
// Namespaces are not syntactically valid as children of records, but making
// this general for all possible container types reduces code complexity.
- llvm::simple_ilist<Reference> Namespaces;
+ OwningVec<Reference> Namespaces;
OwningVec<Reference> Records;
OwningVec<FunctionInfo> Functions;
OwningVec<EnumInfo> Enums;
@@ -342,7 +353,7 @@ struct TemplateSpecializationInfo {
SymbolID SpecializationOf;
// Template parameters applying to the specialized record/function.
- OwningVec<TemplateParamInfo> Params;
+ llvm::ArrayRef<TemplateParamInfo> Params;
};
struct ConstraintInfo {
@@ -358,11 +369,11 @@ struct ConstraintInfo {
// or an explicit template specialization.
struct TemplateInfo {
// May be empty for non-partial specializations.
- OwningVec<TemplateParamInfo> Params;
+ llvm::ArrayRef<TemplateParamInfo> Params;
// Set when this is a specialization of another record/function.
std::optional<TemplateSpecializationInfo> Specialization;
- OwningVec<ConstraintInfo> Constraints;
+ llvm::ArrayRef<ConstraintInfo> Constraints;
};
// Info for field types.
@@ -393,9 +404,11 @@ struct MemberTypeInfo : public FieldTypeInfo {
: FieldTypeInfo(TI, Name), Access(Access), IsStatic(IsStatic) {}
bool operator==(const MemberTypeInfo &Other) const {
- return std::tie(Type, Name, Access, IsStatic, Description) ==
- std::tie(Other.Type, Other.Name, Other.Access, Other.IsStatic,
- Other.Description);
+ 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());
}
OwningVec<CommentInfo> Description;
@@ -444,7 +457,6 @@ struct Info {
Info(const Info &Other) = delete;
Info(Info &&Other) = default;
- virtual ~Info() = default;
Info &operator=(Info &&Other) = default;
@@ -471,7 +483,7 @@ struct Info {
StringRef DocumentationFileName;
// List of parent namespaces for this decl.
- llvm::SmallVector<Reference, 4> Namespace;
+ llvm::ArrayRef<Reference> Namespace;
// Unique identifier for the decl described by this Info.
SymbolID USR = SymbolID();
@@ -484,8 +496,6 @@ struct Info {
// Comment description of this decl.
OwningVec<CommentInfo> Description;
-
- SmallVector<Context, 4> Contexts;
};
inline Context::Context(const Info &I)
@@ -514,8 +524,9 @@ 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[0] != Other.Loc[0])
- return Loc[0] < Other.Loc[0];
+ if (Loc.size() > 0 && Other.Loc.size() > 0 &&
+ Loc.front() != Other.Loc.front())
+ return Loc.front() < Other.Loc.front();
if (DefLoc && Other.DefLoc && *DefLoc != *Other.DefLoc)
return *DefLoc < *Other.DefLoc;
@@ -524,7 +535,7 @@ struct SymbolInfo : public Info {
}
std::optional<Location> DefLoc; // Location where this decl is defined.
- llvm::SmallVector<Location, 2> Loc; // Locations where this decl is declared.
+ OwningVec<Location> Loc; // Locations where this decl is declared.
StringRef MangledName;
bool IsStatic = false;
};
@@ -564,7 +575,7 @@ struct FunctionInfo : public SymbolInfo, public llvm::ilist_node<FunctionInfo> {
Reference Parent;
TypeInfo ReturnType;
- llvm::SmallVector<FieldTypeInfo, 4> Params;
+ llvm::ArrayRef<FieldTypeInfo> Params;
StringRef Prototype;
// When present, this function is a template or specialization.
@@ -600,18 +611,18 @@ struct RecordInfo : public SymbolInfo {
// When present, this record is a template or specialization.
std::optional<TemplateInfo> Template;
- 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>
+ 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>
VirtualParents; // List of virtual base/parent records.
- OwningVec<BaseRecordInfo> Bases; // List of base/parent records; this includes
- // inherited methods and attributes
+ llvm::ArrayRef<BaseRecordInfo>
+ Bases; // List of base/parent records; this includes
+ // inherited methods and attributes
- OwningVec<FriendInfo> Friends;
+ llvm::ArrayRef<FriendInfo> Friends;
ScopeChildren Children;
};
@@ -638,7 +649,8 @@ struct TypedefInfo : public SymbolInfo, public llvm::ilist_node<TypedefInfo> {
bool IsUsing = false;
};
-struct BaseRecordInfo : public RecordInfo {
+struct BaseRecordInfo : public RecordInfo,
+ public llvm::ilist_node<BaseRecordInfo> {
BaseRecordInfo();
BaseRecordInfo(SymbolID USR, StringRef Name, StringRef Path, bool IsVirtual,
AccessSpecifier Access, bool IsParent);
@@ -695,7 +707,7 @@ struct EnumInfo : public SymbolInfo, public llvm::ilist_node<EnumInfo> {
// this will be "short".
std::optional<TypeInfo> BaseType;
- llvm::SmallVector<EnumValueInfo, 4> Members; // List of enum members.
+ llvm::ArrayRef<EnumValueInfo> Members; // List of enum members.
};
struct ConceptInfo : public SymbolInfo, public llvm::ilist_node<ConceptInfo> {
@@ -723,7 +735,7 @@ struct Index : public Reference {
std::optional<StringRef> JumpToSection;
llvm::StringMap<Index> Children;
- OwningVec<const Index *> getSortedChildren() const;
+ std::vector<const Index *> getSortedChildren() const;
void sort();
};
@@ -773,28 +785,26 @@ 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>);
-
-// 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>);
+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 ef7fed6cc8501..4b2f0b5eac3a4 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(
- const llvm::SmallVectorImpl<doc::Reference> &Namespaces) {
+StringRef
+Serializer::getInfoRelativePath(llvm::ArrayRef<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,9 +258,7 @@ void ClangDocCommentVisitor::visitInlineCommandComment(
for (unsigned I = 0, E = C->getNumArgs(); I != E; ++I)
Args.push_back(internString(C->getArgText(I).trim()));
if (!Args.empty()) {
- StringRef *ArgsMem = TransientArena.Allocate<StringRef>(Args.size());
- std::uninitialized_copy(Args.begin(), Args.end(), ArgsMem);
- CurrentCI.Args = llvm::ArrayRef<StringRef>(ArgsMem, Args.size());
+ CurrentCI.Args = allocateArray(Args, TransientArena);
}
}
@@ -276,16 +274,10 @@ void ClangDocCommentVisitor::visitHTMLStartTagComment(
AttrValues.push_back(internString(Attr.Value));
}
if (!AttrKeys.empty()) {
- StringRef *KeysMem = TransientArena.Allocate<StringRef>(AttrKeys.size());
- std::uninitialized_copy(AttrKeys.begin(), AttrKeys.end(), KeysMem);
- CurrentCI.AttrKeys = llvm::ArrayRef<StringRef>(KeysMem, AttrKeys.size());
+ CurrentCI.AttrKeys = allocateArray(AttrKeys, TransientArena);
}
if (!AttrValues.empty()) {
- StringRef *ValuesMem =
- TransientArena.Allocate<StringRef>(AttrValues.size());
- std::uninitialized_copy(AttrValues.begin(), AttrValues.end(), ValuesMem);
- CurrentCI.AttrValues =
- llvm::ArrayRef<StringRef>(ValuesMem, AttrValues.size());
+ CurrentCI.AttrValues = allocateArray(AttrValues, TransientArena);
}
}
@@ -302,9 +294,7 @@ void ClangDocCommentVisitor::visitBlockCommandComment(
for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
Args.push_back(internString(C->getArgText(I).trim()));
if (!Args.empty()) {
- StringRef *ArgsMem = TransientArena.Allocate<StringRef>(Args.size());
- std::uninitialized_copy(Args.begin(), Args.end(), ArgsMem);
- CurrentCI.Args = llvm::ArrayRef<StringRef>(ArgsMem, Args.size());
+ CurrentCI.Args = allocateArray(Args, TransientArena);
}
}
@@ -475,29 +465,35 @@ void Serializer::InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info) {
}
void Serializer::InsertChild(ScopeChildren &Scope, const RecordInfo &Info) {
- Scope.Records.emplace_back(Info.USR, Info.Name, InfoType::IT_record,
- Info.Name, getInfoRelativePath(Info.Namespace),
- Info.MangledName);
+ Reference *R = allocatePtr<Reference>(
+ Info.USR, Info.Name, InfoType::IT_record, Info.Name,
+ getInfoRelativePath(Info.Namespace), Info.MangledName);
+ Scope.Records.push_back(*R);
}
void Serializer::InsertChild(ScopeChildren &Scope, EnumInfo Info) {
- Scope.Enums.push_back(std::move(Info));
+ EnumInfo *E = allocatePtr<EnumInfo>(std::move(Info));
+ Scope.Enums.push_back(*E);
}
void Serializer::InsertChild(ScopeChildren &Scope, FunctionInfo Info) {
- Scope.Functions.push_back(std::move(Info));
+ FunctionInfo *F = allocatePtr<FunctionInfo>(std::move(Info));
+ Scope.Functions.push_back(*F);
}
void Serializer::InsertChild(ScopeChildren &Scope, TypedefInfo Info) {
- Scope.Typedefs.push_back(std::move(Info));
+ TypedefInfo *T = allocatePtr<TypedefInfo>(std::move(Info));
+ Scope.Typedefs.push_back(*T);
}
void Serializer::InsertChild(ScopeChildren &Scope, ConceptInfo Info) {
- Scope.Concepts.push_back(std::move(Info));
+ ConceptInfo *C = allocatePtr<ConceptInfo>(std::move(Info));
+ Scope.Concepts.push_back(*C);
}
void Serializer::InsertChild(ScopeChildren &Scope, VarInfo Info) {
- Scope.Variables.push_back(std::move(Info));
+ VarInfo *V = allocatePtr<VarInfo>(std::move(Info));
+ Scope.Variables.push_back(*V);
}
// Creates a parent of the correct type for the given child and inserts it into
@@ -581,14 +577,18 @@ 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(I, Access, F);
+ populateMemberTypeInfo(Members, Access, F);
}
const auto *CxxRD = dyn_cast<CXXRecordDecl>(D);
- if (!CxxRD)
+ if (!CxxRD) {
+ if (!Members.empty())
+ I.Members = allocateArray<MemberTypeInfo>(Members, TransientArena);
return;
+ }
for (Decl *CxxDecl : CxxRD->decls()) {
auto *VD = dyn_cast<VarDecl>(CxxDecl);
if (!VD ||
@@ -596,40 +596,49 @@ void Serializer::parseFields(RecordInfo &I, const RecordDecl *D,
continue;
if (VD->isStaticDataMember())
- populateMemberTypeInfo(I, Access, VD, /*IsStatic=*/true);
+ populateMemberTypeInfo(Members, 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);
- I.Members.emplace_back(E->getNameAsString(), ValueStr.str(), ValueExpr);
+ EnumValueInfo &Member = LocalMembers.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)) {
- EnumValueInfo &Member = I.Members.back();
- Member.Description.emplace_back();
+ CommentInfo *NewCI = allocatePtr<CommentInfo>();
+ Member.Description.push_back(*NewCI);
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 = I.Params.emplace_back(
+ FieldTypeInfo &FieldInfo = LocalParams.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
@@ -639,28 +648,36 @@ 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();
- I.Parents.emplace_back(getUSRForDecl(D), B.getType().getAsString(),
- InfoType::IT_record, B.getType().getAsString());
+ LocalParents.emplace_back(getUSRForDecl(D), B.getType().getAsString(),
+ InfoType::IT_record, B.getType().getAsString());
} else if (const RecordDecl *P = getRecordDeclForType(B.getType()))
- I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
- InfoType::IT_record, P->getQualifiedNameAsString(),
- internString(getInfoRelativePath(P)));
+ LocalParents.emplace_back(
+ getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record,
+ P->getQualifiedNameAsString(), internString(getInfoRelativePath(P)));
else
- I.Parents.emplace_back(SymbolID(), B.getType().getAsString());
+ LocalParents.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()))
- I.VirtualParents.emplace_back(
+ LocalVirtualParents.emplace_back(
getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record,
P->getQualifiedNameAsString(), internString(getInfoRelativePath(P)));
else
- I.VirtualParents.emplace_back(SymbolID(), B.getType().getAsString());
+ LocalVirtualParents.emplace_back(SymbolID(), B.getType().getAsString());
}
+ if (!LocalVirtualParents.empty())
+ I.VirtualParents =
+ allocateArray<Reference>(LocalVirtualParents, TransientArena);
}
template <typename T>
@@ -708,10 +725,13 @@ void Serializer::populateTemplateParameters(
if (!TemplateInfo) {
TemplateInfo.emplace();
}
+ llvm::SmallVector<TemplateParamInfo, 4> LocalParams;
for (const NamedDecl *ND : *ParamList) {
- TemplateInfo->Params.emplace_back(
- getSourceCode(ND, ND->getSourceRange()));
+ LocalParams.emplace_back(getSourceCode(ND, ND->getSourceRange()));
}
+ if (!LocalParams.empty())
+ TemplateInfo->Params =
+ allocateArray<TemplateParamInfo>(LocalParams, TransientArena);
}
}
@@ -774,9 +794,14 @@ void Serializer::populateInfo(Info &I, const T *D, const FullComment *C,
ConversionDecl->getConversionType().getAsString());
else
I.Name = internString(D->getNameAsString());
- populateParentNamespaces(I.Namespace, D, IsInAnonymousNamespace);
+ llvm::SmallVector<Reference, 4> LocalNamespaces;
+ populateParentNamespaces(LocalNamespaces, D, IsInAnonymousNamespace);
+ if (!LocalNamespaces.empty())
+ I.Namespace = allocateArray<Reference>(LocalNamespaces, TransientArena);
if (C) {
- I.Description.emplace_back();
+
+ CommentInfo *NewCI = allocatePtr<CommentInfo>();
+ I.Description.push_back(*NewCI);
parseFullComment(C, I.Description.back());
}
}
@@ -788,8 +813,10 @@ void Serializer::populateSymbolInfo(SymbolInfo &I, const T *D,
populateInfo(I, D, C, IsInAnonymousNamespace);
if (D->isThisDeclarationADefinition())
I.DefLoc = Loc;
- else
- I.Loc.emplace_back(Loc);
+ else {
+ Location *NewL = allocatePtr<Location>(Loc);
+ I.Loc.push_back(*NewL);
+ }
auto *Mangler = ItaniumMangleContext::create(
D->getASTContext(), D->getASTContext().getDiagnostics());
@@ -811,7 +838,8 @@ void Serializer::populateSymbolInfo(SymbolInfo &I, const T *D,
}
void Serializer::handleCompoundConstraints(
- const Expr *Constraint, OwningVec<ConstraintInfo> &ConstraintInfos) {
+ const Expr *Constraint,
+ llvm::SmallVectorImpl<ConstraintInfo> &ConstraintInfos) {
if (Constraint->getStmtClass() == Stmt::ParenExprClass) {
handleCompoundConstraints(dyn_cast<ParenExpr>(Constraint)->getSubExpr(),
ConstraintInfos);
@@ -835,6 +863,7 @@ 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;
@@ -846,11 +875,14 @@ void Serializer::populateConstraints(TemplateInfo &I, const TemplateDecl *D) {
ConstraintInfo CI(getUSRForDecl(ConstraintExpr->getNamedConcept()),
ConstraintExpr->getNamedConcept()->getNameAsString());
CI.ConstraintExpr = internString(exprToString(ConstraintExpr));
- I.Constraints.push_back(std::move(CI));
+ LocalConstraints.push_back(std::move(CI));
} else {
- handleCompoundConstraints(Constraint.ConstraintExpr, I.Constraints);
+ handleCompoundConstraints(Constraint.ConstraintExpr, LocalConstraints);
}
}
+ if (!LocalConstraints.empty())
+ I.Constraints =
+ allocateArray<ConstraintInfo>(LocalConstraints, TransientArena);
}
void Serializer::populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
@@ -879,9 +911,13 @@ 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()) {
- Specialization.Params.push_back(convertTemplateArgToInfo(D, Arg));
+ LocalParams.push_back(convertTemplateArgToInfo(D, Arg));
}
+ if (!LocalParams.empty())
+ Specialization.Params =
+ allocateArray<TemplateParamInfo>(LocalParams, TransientArena);
}
}
}
@@ -901,26 +937,28 @@ void Serializer::populateMemberTypeInfo(T &I, const Decl *D) {
Comment->setAttached();
if (comments::FullComment *Fc = Comment->parse(Context, nullptr, D)) {
- I.Description.emplace_back();
+ CommentInfo *NewCI = allocatePtr<CommentInfo>();
+ I.Description.push_back(*NewCI);
parseFullComment(Fc, I.Description.back());
}
}
-void Serializer::populateMemberTypeInfo(RecordInfo &I, AccessSpecifier &Access,
- const DeclaratorDecl *D,
- bool IsStatic) {
+void Serializer::populateMemberTypeInfo(
+ SmallVectorImpl<MemberTypeInfo> &Members, AccessSpecifier &Access,
+ const DeclaratorDecl *D, bool IsStatic) {
// Use getAccessUnsafe so that we just get the default AS_none if it's not
// valid, as opposed to an assert.
- MemberTypeInfo &NewMember = I.Members.emplace_back(
+ MemberTypeInfo &NewMember = Members.emplace_back(
getTypeInfoForType(D->getTypeSourceInfo()->getType(), D->getLangOpts()),
D->getNameAsString(),
getFinalAccessSpecifier(Access, D->getAccessUnsafe()), IsStatic);
populateMemberTypeInfo(NewMember, D);
}
-void Serializer::parseBases(RecordInfo &I, const CXXRecordDecl *D,
- bool IsFileInRootDir, bool PublicOnly,
- bool IsParent, AccessSpecifier ParentAccess) {
+void Serializer::parseBases(llvm::SmallVectorImpl<BaseRecordInfo> &Bases,
+ 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;
@@ -959,14 +997,15 @@ void Serializer::parseBases(RecordInfo &I, const CXXRecordDecl *D,
IsInAnonymousNamespace);
FI.Access =
getFinalAccessSpecifier(BI.Access, MD->getAccessUnsafe());
- BI.Children.Functions.emplace_back(std::move(FI));
+ FunctionInfo *FIPtr = allocatePtr<FunctionInfo>(std::move(FI));
+ BI.Children.Functions.push_back(*FIPtr);
}
- I.Bases.emplace_back(std::move(BI));
+ 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(I, Base, IsFileInRootDir, PublicOnly, false,
- I.Bases.back().Access);
+ parseBases(Bases, Base, IsFileInRootDir, PublicOnly, false,
+ Bases.back().Access);
}
}
}
@@ -995,6 +1034,8 @@ 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;
@@ -1016,9 +1057,12 @@ 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())
- F.Template->Params.emplace_back(
- getSourceCode(Param, Param->getSourceRange()));
+ LocalParams.emplace_back(getSourceCode(Param, Param->getSourceRange()));
+ if (!LocalParams.empty())
+ F.Template->Params =
+ allocateArray<TemplateParamInfo>(LocalParams, TransientArena);
ActualDecl = ActualTD->getTemplatedDecl();
}
@@ -1036,8 +1080,10 @@ void Serializer::parseFriends(RecordInfo &RI, const CXXRecordDecl *D) {
getInfoRelativePath(ActualDecl));
populateMemberTypeInfo(F, ActualDecl);
- RI.Friends.push_back(std::move(F));
+ LocalFriends.push_back(std::move(F));
}
+ if (!LocalFriends.empty())
+ RI.Friends = allocateArray<FriendInfo>(LocalFriends, TransientArena);
}
std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
@@ -1061,7 +1107,11 @@ Serializer::emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
}
// TODO: remove first call to parseBases, that function should be deleted
parseBases(*RI, C);
- parseBases(*RI, C, /*IsFileInRootDir=*/true, PublicOnly, /*IsParent=*/true);
+ llvm::SmallVector<BaseRecordInfo, 4> LocalBases;
+ parseBases(LocalBases, C, /*IsFileInRootDir=*/true, PublicOnly,
+ /*IsParent=*/true);
+ if (!LocalBases.empty())
+ RI->Bases = allocateArray<BaseRecordInfo>(LocalBases, TransientArena);
parseFriends(*RI, C);
}
RI->Path = internString(getInfoRelativePath(RI->Namespace));
@@ -1094,15 +1144,23 @@ 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++) {
- Specialization.Params.emplace_back(
+ LocalParams.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()) {
- Specialization.Params.push_back(convertTemplateArgToInfo(D, Arg));
+ LocalParams.push_back(convertTemplateArgToInfo(D, Arg));
}
+ if (!LocalParams.empty())
+ Specialization.Params =
+ allocateArray<TemplateParamInfo>(LocalParams, TransientArena);
}
}
@@ -1164,8 +1222,9 @@ void Serializer::extractCommentFromDecl(const Decl *D, TypedefInfo &Info) {
Comment->setAttached();
if (comments::FullComment *Fc = Comment->parse(Context, nullptr, D)) {
- Info.Description.emplace_back();
- parseFullComment(Fc, Info.Description.back());
+ CommentInfo *NewCI = allocatePtr<CommentInfo>();
+ Info.Description.push_back(*NewCI);
+ parseFullComment(Fc, *NewCI);
}
}
@@ -1258,10 +1317,13 @@ 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()) {
- Concept.Template.Params.emplace_back(
- getSourceCode(Param, Param->getSourceRange()));
+ LocalParams.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 04891bea33220..3d53514d0756a 100644
--- a/clang-tools-extra/clang-doc/Serialize.h
+++ b/clang-tools-extra/clang-doc/Serialize.h
@@ -94,8 +94,7 @@ class Serializer {
StringRef getTypeAlias(const TypeAliasDecl *Alias);
- StringRef
- getInfoRelativePath(const llvm::SmallVectorImpl<doc::Reference> &Namespaces);
+ StringRef getInfoRelativePath(llvm::ArrayRef<doc::Reference> Namespaces);
StringRef getInfoRelativePath(const Decl *D);
@@ -139,8 +138,9 @@ class Serializer {
void parseBases(RecordInfo &I, const CXXRecordDecl *D);
- void parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir,
- bool PublicOnly, bool IsParent,
+ void parseBases(llvm::SmallVectorImpl<BaseRecordInfo> &Bases,
+ const CXXRecordDecl *D, bool IsFileInRootDir, bool PublicOnly,
+ bool IsParent,
AccessSpecifier ParentAccess = AccessSpecifier::AS_public);
template <typename T>
@@ -165,8 +165,9 @@ class Serializer {
void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
Location Loc, bool &IsInAnonymousNamespace);
- void handleCompoundConstraints(const Expr *Constraint,
- OwningVec<ConstraintInfo> &ConstraintInfos);
+ void handleCompoundConstraints(
+ const Expr *Constraint,
+ llvm::SmallVectorImpl<ConstraintInfo> &ConstraintInfos);
void populateConstraints(TemplateInfo &I, const TemplateDecl *D);
@@ -176,8 +177,9 @@ class Serializer {
template <typename T> void populateMemberTypeInfo(T &I, const Decl *D);
- void populateMemberTypeInfo(RecordInfo &I, AccessSpecifier &Access,
- const DeclaratorDecl *D, bool IsStatic = false);
+ void populateMemberTypeInfo(llvm::SmallVectorImpl<MemberTypeInfo> &Members,
+ 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 9e3bca84877e0..b5c43837f9505 100644
--- a/clang-tools-extra/clang-doc/YAMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/YAMLGenerator.cpp
@@ -31,9 +31,70 @@ 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 {
-template <typename T> struct SequenceTraits<llvm::ArrayRef<T>> {
+// 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>> {
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]);
@@ -191,7 +252,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, llvm::SmallVector<Location, 2>());
+ IO.mapOptional("Location", I.Loc);
}
static void recordInfoMapping(IO &IO, RecordInfo &I) {
@@ -200,10 +261,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, llvm::SmallVector<Reference, 4>());
+ IO.mapOptional("Parents", I.Parents, SmallVector<Reference, 4>());
IO.mapOptional("VirtualParents", I.VirtualParents,
llvm::SmallVector<Reference, 4>());
- IO.mapOptional("ChildRecords", I.Children.Records, OwningVec<Reference>());
+ IO.mapOptional("ChildRecords", I.Children.Records);
IO.mapOptional("ChildFunctions", I.Children.Functions);
IO.mapOptional("ChildEnums", I.Children.Enums);
IO.mapOptional("ChildTypedefs", I.Children.Typedefs);
@@ -339,7 +400,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, OwningVec<Reference>());
+ IO.mapOptional("ChildRecords", I.Children.Records);
IO.mapOptional("ChildFunctions", I.Children.Functions);
IO.mapOptional("ChildEnums", I.Children.Enums);
IO.mapOptional("ChildTypedefs", I.Children.Typedefs);
@@ -441,13 +502,6 @@ 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 f96cfc9426f1a..c610c57722649 100644
--- a/clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp
+++ b/clang-tools-extra/clang-doc/benchmarks/ClangDocBenchmark.cpp
@@ -184,9 +184,10 @@ static void BM_JSONGenerator_Scale(benchmark::State &State) {
auto NI = allocatePtr<NamespaceInfo>();
NI->Name = "GlobalNamespace";
for (int i = 0; i < NumRecords; ++i) {
- NI->Children.Records.emplace_back(SymbolID{(uint8_t)(i & 0xFF)},
- "Record" + std::to_string(i),
- InfoType::IT_record);
+ 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);
}
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
diff --git a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
index 6bdf538012303..81de4ff2f6381 100644
--- a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
@@ -56,7 +56,6 @@ 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);
@@ -68,39 +67,43 @@ class BitcodeTest : public ClangDocContextTest {};
TEST_F(BitcodeTest, emitNamespaceInfoBitcode) {
NamespaceInfo I;
I.Name = "r";
- I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
Reference NewNamespace(EmptySID, "ChildNamespace", InfoType::IT_namespace);
I.Children.Namespaces.push_back(NewNamespace);
- I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
- I.Children.Functions.emplace_back();
- I.Children.Enums.emplace_back();
+ 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);
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].get()));
+ CheckNamespaceInfo(&I, InfoAsNamespace(ReadResults[0]));
}
TEST_F(BitcodeTest, emitRecordInfoBitcode) {
RecordInfo I;
I.Name = "r";
- I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
I.DefLoc = Location(10, 10, "test.cpp");
- I.Loc.emplace_back(12, 12, "test.cpp");
+ Location Loc1(12, 12, "test.cpp");
+ I.Loc.push_back(Loc1);
- I.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private);
+ MemberTypeInfo M(TypeInfo("int"), "X", AccessSpecifier::AS_private);
I.TagType = TagTypeKind::Class;
I.IsTypeDef = true;
- 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);
+ 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);
// Documentation for the data member.
CommentInfo BriefChildren[] = {CommentInfo(CommentKind::CK_TextComment, {},
@@ -109,29 +112,47 @@ TEST_F(BitcodeTest, emitRecordInfoBitcode) {
CommentInfo TopCommentChildren[] = {
CommentInfo(CommentKind::CK_ParagraphComment, BriefChildren)};
CommentInfo TopComment(CommentKind::CK_FullComment, TopCommentChildren);
- 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();
+ 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);
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].get()));
+ CheckRecordInfo(&I, InfoAsRecord(ReadResults[0]));
}
TEST_F(BitcodeTest, emitFunctionInfoBitcode) {
FunctionInfo I;
I.Name = "f";
- I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
I.DefLoc = Location(10, 10, "test.cpp");
- I.Loc.emplace_back(12, 12, "test.cpp");
+ Location Loc1(12, 12, "test.cpp");
+ I.Loc.push_back(Loc1);
I.ReturnType = TypeInfo("void");
- I.Params.emplace_back(TypeInfo("int"), "P");
+ FieldTypeInfo P(TypeInfo("int"), "P");
+ FieldTypeInfo Params[] = {std::move(P)};
+ I.Params = llvm::ArrayRef(Params);
I.Access = AccessSpecifier::AS_none;
@@ -139,19 +160,23 @@ TEST_F(BitcodeTest, emitFunctionInfoBitcode) {
EXPECT_TRUE(WriteResult.size() > 0);
OwningPtrVec<Info> ReadResults = readInfo(WriteResult, 1, this->Diags);
- CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0].get()));
+ CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0]));
}
TEST_F(BitcodeTest, emitMethodInfoBitcode) {
FunctionInfo I;
I.Name = "f";
- I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
I.DefLoc = Location(10, 10, "test.cpp");
- I.Loc.emplace_back(12, 12, "test.cpp");
+ Location Loc1(12, 12, "test.cpp");
+ I.Loc.push_back(Loc1);
I.ReturnType = TypeInfo("void");
- I.Params.emplace_back(TypeInfo("int"), "P");
+ FieldTypeInfo P(TypeInfo("int"), "P");
+ FieldTypeInfo Params[] = {std::move(P)};
+ I.Params = llvm::ArrayRef(Params);
I.IsMethod = true;
I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
@@ -161,31 +186,36 @@ TEST_F(BitcodeTest, emitMethodInfoBitcode) {
EXPECT_TRUE(WriteResult.size() > 0);
OwningPtrVec<Info> ReadResults = readInfo(WriteResult, 1, this->Diags);
- CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0].get()));
+ CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0]));
}
TEST_F(BitcodeTest, emitEnumInfoBitcode) {
EnumInfo I;
I.Name = "e";
- I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
I.DefLoc = Location(10, 10, "test.cpp");
- I.Loc.emplace_back(12, 12, "test.cpp");
+ Location Loc1(12, 12, "test.cpp");
+ I.Loc.push_back(Loc1);
- I.Members.emplace_back("X");
+ EnumValueInfo EV("X");
+ EnumValueInfo Mems[] = {std::move(EV)};
+ I.Members = llvm::ArrayRef(Mems);
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].get()));
+ CheckEnumInfo(&I, InfoAsEnum(ReadResults[0]));
}
TEST_F(BitcodeTest, emitTypedefInfoBitcode) {
TypedefInfo I;
I.Name = "MyInt";
- I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
I.DefLoc = Location(10, 10, "test.cpp");
I.Underlying = TypeInfo("unsigned");
@@ -196,13 +226,13 @@ TEST_F(BitcodeTest, emitTypedefInfoBitcode) {
CommentInfo(CommentKind::CK_ParagraphComment, BlankChildren)};
CommentInfo Top(CommentKind::CK_FullComment, TopChildren);
- I.Description.emplace_back(std::move(Top));
+ I.Description.push_back(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].get()));
+ CheckTypedefInfo(&I, InfoAsTypedef(ReadResults[0]));
// Check one with no IsUsing set, no description, and no definition location.
TypedefInfo I2;
@@ -213,7 +243,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].get()));
+ CheckTypedefInfo(&I2, InfoAsTypedef(ReadResults[0]));
}
TEST_F(BitcodeTest, emitInfoWithCommentBitcode) {
@@ -221,7 +251,8 @@ TEST_F(BitcodeTest, emitInfoWithCommentBitcode) {
F.Name = "F";
F.ReturnType = TypeInfo("void");
F.DefLoc = Location(0, 0, "test.cpp");
- F.Params.emplace_back(TypeInfo("int"), "I");
+ FieldTypeInfo PI[] = {FieldTypeInfo(TypeInfo("int"), "I")};
+ F.Params = llvm::ArrayRef(PI);
// BlankLine
CommentInfo BlankChildren[] = {CommentInfo(CommentKind::CK_TextComment)};
@@ -293,13 +324,13 @@ TEST_F(BitcodeTest, emitInfoWithCommentBitcode) {
Verbatim, ParamOut, ParamIn, Return};
CommentInfo Top(CommentKind::CK_FullComment, TopChildren);
- F.Description.emplace_back(std::move(Top));
+ F.Description.push_back(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].get()));
+ CheckFunctionInfo(&F, InfoAsFunction(ReadResults[0]));
}
} // namespace doc
diff --git a/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp b/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
index 92127da53b7bb..2e5466c172a18 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(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(ArrayRef<CommentInfo> Expected,
+ ArrayRef<CommentInfo> Actual);
+void CheckCommentInfo(const OwningVec<CommentInfo> &Expected,
+ const OwningVec<CommentInfo> &Actual);
void CheckCommentInfo(const CommentInfo &Expected, const CommentInfo &Actual) {
EXPECT_EQ(Expected.Kind, Actual.Kind);
@@ -84,52 +84,71 @@ void CheckCommentInfo(const CommentInfo &Expected, const CommentInfo &Actual) {
CheckCommentInfo(Expected.Children, Actual.Children);
}
-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(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<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 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 CheckReference(Reference &Expected, Reference &Actual) {
+void CheckReference(const Reference &Expected, const Reference &Actual) {
EXPECT_EQ(Expected.Name, Actual.Name);
EXPECT_EQ(Expected.RefType, Actual.RefType);
EXPECT_EQ(Expected.Path, Actual.Path);
}
-void CheckTypeInfo(TypeInfo *Expected, TypeInfo *Actual) {
+void CheckTypeInfo(const TypeInfo *Expected, const TypeInfo *Actual) {
CheckReference(Expected->Type, Actual->Type);
}
-void CheckFieldTypeInfo(FieldTypeInfo *Expected, FieldTypeInfo *Actual) {
+void CheckFieldTypeInfo(const FieldTypeInfo *Expected,
+ const FieldTypeInfo *Actual) {
CheckTypeInfo(Expected, Actual);
EXPECT_EQ(Expected->Name, Actual->Name);
}
-void CheckMemberTypeInfo(MemberTypeInfo *Expected, MemberTypeInfo *Actual) {
+void CheckMemberTypeInfo(const MemberTypeInfo *Expected,
+ const MemberTypeInfo *Actual) {
CheckFieldTypeInfo(Expected, Actual);
EXPECT_EQ(Expected->Access, Actual->Access);
CheckCommentInfo(Expected->Description, Actual->Description);
}
-void CheckBaseInfo(Info *Expected, Info *Actual) {
+void CheckBaseInfo(const Info *Expected, const Info *Actual) {
EXPECT_EQ(size_t(20), Actual->USR.size());
EXPECT_EQ(Expected->Name, Actual->Name);
EXPECT_EQ(Expected->Path, Actual->Path);
- 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]);
+ 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());
CheckCommentInfo(Expected->Description, Actual->Description);
}
-void CheckSymbolInfo(SymbolInfo *Expected, SymbolInfo *Actual) {
+void CheckSymbolInfo(const SymbolInfo *Expected, const SymbolInfo *Actual) {
CheckBaseInfo(Expected, Actual);
EXPECT_EQ(Expected->DefLoc.has_value(), Actual->DefLoc.has_value());
if (Expected->DefLoc && Actual->DefLoc.has_value()) {
@@ -138,109 +157,186 @@ void CheckSymbolInfo(SymbolInfo *Expected, SymbolInfo *Actual) {
EXPECT_EQ(Expected->DefLoc->EndLineNumber, Actual->DefLoc->EndLineNumber);
EXPECT_EQ(Expected->DefLoc->Filename, Actual->DefLoc->Filename);
}
- 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]);
+ 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());
}
-void CheckFunctionInfo(FunctionInfo *Expected, FunctionInfo *Actual) {
+void CheckFunctionInfo(const FunctionInfo *Expected,
+ const FunctionInfo *Actual) {
CheckSymbolInfo(Expected, Actual);
EXPECT_EQ(Expected->IsMethod, Actual->IsMethod);
CheckReference(Expected->Parent, Actual->Parent);
CheckTypeInfo(&Expected->ReturnType, &Actual->ReturnType);
- ASSERT_EQ(Expected->Params.size(), Actual->Params.size());
- for (size_t Idx = 0; Idx < Actual->Params.size(); ++Idx)
+ for (size_t Idx = 0; Idx < Expected->Params.size(); ++Idx) {
EXPECT_EQ(Expected->Params[Idx], Actual->Params[Idx]);
+ }
EXPECT_EQ(Expected->Access, Actual->Access);
}
-void CheckEnumInfo(EnumInfo *Expected, EnumInfo *Actual) {
+void CheckEnumInfo(const EnumInfo *Expected, const EnumInfo *Actual) {
CheckSymbolInfo(Expected, Actual);
EXPECT_EQ(Expected->Scoped, Actual->Scoped);
- 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]);
+ 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());
}
-void CheckTypedefInfo(TypedefInfo *Expected, TypedefInfo *Actual) {
+void CheckTypedefInfo(const TypedefInfo *Expected, const TypedefInfo *Actual) {
CheckSymbolInfo(Expected, Actual);
EXPECT_EQ(Expected->IsUsing, Actual->IsUsing);
CheckTypeInfo(&Expected->Underlying, &Actual->Underlying);
}
-void CheckNamespaceInfo(NamespaceInfo *Expected, NamespaceInfo *Actual) {
+void CheckNamespaceInfo(const NamespaceInfo *Expected,
+ const NamespaceInfo *Actual) {
CheckBaseInfo(Expected, Actual);
ASSERT_EQ(Expected->Children.Namespaces.size(),
Actual->Children.Namespaces.size());
- auto ItExpected = Expected->Children.Namespaces.begin();
- auto ItActual = Actual->Children.Namespaces.begin();
- while (ItExpected != Expected->Children.Namespaces.end()) {
- CheckReference(*ItExpected, *ItActual);
- ++ItExpected;
- ++ItActual;
+ 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;
}
-
- 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]);
+ 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;
+ }
+ 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());
}
-void CheckRecordInfo(RecordInfo *Expected, RecordInfo *Actual) {
+void CheckRecordInfo(const RecordInfo *Expected, const RecordInfo *Actual) {
CheckSymbolInfo(Expected, Actual);
EXPECT_EQ(Expected->TagType, Actual->TagType);
EXPECT_EQ(Expected->IsTypeDef, Actual->IsTypeDef);
- 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]);
+ 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());
}
-void CheckBaseRecordInfo(BaseRecordInfo *Expected, BaseRecordInfo *Actual) {
+void CheckBaseRecordInfo(const BaseRecordInfo *Expected,
+ const BaseRecordInfo *Actual) {
CheckRecordInfo(Expected, Actual);
EXPECT_EQ(Expected->IsVirtual, Actual->IsVirtual);
@@ -248,7 +344,7 @@ void CheckBaseRecordInfo(BaseRecordInfo *Expected, BaseRecordInfo *Actual) {
EXPECT_EQ(Expected->IsParent, Actual->IsParent);
}
-void CheckIndex(Index &Expected, Index &Actual) {
+void CheckIndex(const Index &Expected, const 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 9b1a26af0cdf6..1525b1ed382ce 100644
--- a/clang-tools-extra/unittests/clang-doc/ClangDocTest.h
+++ b/clang-tools-extra/unittests/clang-doc/ClangDocTest.h
@@ -31,25 +31,32 @@ FunctionInfo *InfoAsFunction(Info *I);
EnumInfo *InfoAsEnum(Info *I);
TypedefInfo *InfoAsTypedef(Info *I);
-// 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);
+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);
// This function explicitly does not check USRs, as that may change and it would
// be better to not rely on its implementation.
-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 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 CheckIndex(Index &Expected, Index &Actual);
+void CheckIndex(const Index &Expected, const 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 38f37bd535239..e352abbe0801f 100644
--- a/clang-tools-extra/unittests/clang-doc/GeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/GeneratorTest.cpp
@@ -28,7 +28,8 @@ TEST_F(GeneratorTest, emitIndex) {
InfoC->USR = serialize::hashUSR("3");
Reference RefB = Reference(SymbolID(), "B");
RefB.USR = serialize::hashUSR("2");
- InfoC->Namespace = {std::move(RefB)};
+ Reference NsC[] = {std::move(RefB)};
+ InfoC->Namespace = llvm::ArrayRef(NsC);
Generator::addInfoToIndex(Idx, InfoC.get());
auto InfoD = std::make_unique<Info>();
InfoD->Name = "D";
@@ -40,7 +41,8 @@ TEST_F(GeneratorTest, emitIndex) {
RefD.USR = serialize::hashUSR("4");
Reference RefE = Reference(SymbolID(), "E");
RefE.USR = serialize::hashUSR("5");
- InfoF->Namespace = {std::move(RefE), std::move(RefD)};
+ Reference NsF[] = {std::move(RefE), std::move(RefD)};
+ InfoF->Namespace = llvm::ArrayRef(NsF);
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 6edd303dbc326..509699f20aa09 100644
--- a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp
@@ -19,39 +19,54 @@ TEST_F(JSONGeneratorTest, emitRecordJSON) {
RecordInfo I;
I.Name = "Foo";
I.IsTypeDef = false;
- I.Namespace.emplace_back(EmptySID, "GlobalNamespace", InfoType::IT_namespace);
+ Reference Ns[] = {
+ Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
I.Path = "GlobalNamespace";
I.DefLoc = Location(1, 1, "main.cpp");
I.TagType = TagTypeKind::Class;
I.Template = TemplateInfo();
- I.Template->Params.emplace_back("class T");
+ TemplateParamInfo TParams[] = {TemplateParamInfo("class T")};
+ I.Template->Params = llvm::ArrayRef(TParams);
- 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";
+ 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.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_protected);
+ MemberTypeInfo M[] = {
+ MemberTypeInfo(TypeInfo("int"), "X", AccessSpecifier::AS_protected)};
+ I.Members = llvm::ArrayRef(M);
- 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);
+ 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);
// F is in the global namespace
- 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");
+ 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.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";
+ FunctionInfo F2;
+ F2.Name = "OneFunction";
+ I.Children.Functions.push_back(F2);
auto G = getJSONGenerator();
assert(G);
@@ -197,20 +212,26 @@ TEST_F(JSONGeneratorTest, emitNamespaceJSON) {
NamespaceInfo I;
I.Name = "Namespace";
I.Path = "path/to/A";
- I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
Reference NewNamespace(EmptySID, "ChildNamespace", InfoType::IT_namespace,
"path::to::A::Namespace::ChildNamespace",
"path/to/A/Namespace");
I.Children.Namespaces.push_back(NewNamespace);
- 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";
+
+ 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);
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 6661360049881..2dc472a352fd8 100644
--- a/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
@@ -26,16 +26,22 @@ class MDGeneratorTest : public ClangDocContextTest {};
TEST_F(MDGeneratorTest, emitNamespaceMD) {
NamespaceInfo I;
I.Name = "Namespace";
- I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
Reference NewNamespace(EmptySID, "ChildNamespace", InfoType::IT_namespace);
I.Children.Namespaces.push_back(NewNamespace);
- 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";
+ 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);
auto G = getMDGenerator();
assert(G);
@@ -79,21 +85,31 @@ TEST_F(MDGeneratorTest, emitNamespaceMD) {
TEST_F(MDGeneratorTest, emitRecordMD) {
RecordInfo I;
I.Name = "r";
- I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
I.DefLoc = Location(10, 10, "test.cpp");
- I.Loc.emplace_back(12, 12, "test.cpp");
+ Location Loc1(12, 12, "test.cpp");
+ I.Loc.push_back(Loc1);
- I.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private);
+ MemberTypeInfo M[] = {
+ MemberTypeInfo(TypeInfo("int"), "X", AccessSpecifier::AS_private)};
+ I.Members = llvm::ArrayRef(M);
I.TagType = TagTypeKind::Class;
- I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
- I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
+ 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.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";
+ EnumInfo E;
+ E.Name = "OneEnum";
+ I.Children.Enums.push_back(E);
auto G = getMDGenerator();
assert(G);
@@ -143,15 +159,18 @@ ChildStruct
TEST_F(MDGeneratorTest, emitFunctionMD) {
FunctionInfo I;
I.Name = "f";
- I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
I.DefLoc = Location(10, 10, "test.cpp");
- I.Loc.emplace_back(12, 12, "test.cpp");
+ Location Loc1(12, 12, "test.cpp");
+ I.Loc.push_back(Loc1);
I.Access = AccessSpecifier::AS_none;
I.ReturnType = TypeInfo("void");
- I.Params.emplace_back(TypeInfo("int"), "P");
+ FieldTypeInfo P[] = {FieldTypeInfo(TypeInfo("int"), "P")};
+ I.Params = llvm::ArrayRef(P);
I.IsMethod = true;
I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
@@ -175,12 +194,15 @@ TEST_F(MDGeneratorTest, emitFunctionMD) {
TEST_F(MDGeneratorTest, emitEnumMD) {
EnumInfo I;
I.Name = "e";
- I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
I.DefLoc = Location(10, 10, "test.cpp");
- I.Loc.emplace_back(12, 12, "test.cpp");
+ Location Loc1(12, 12, "test.cpp");
+ I.Loc.push_back(Loc1);
- I.Members.emplace_back("X");
+ EnumValueInfo EV[] = {EnumValueInfo("X")};
+ I.Members = llvm::ArrayRef(EV);
I.Scoped = true;
auto G = getMDGenerator();
@@ -208,8 +230,9 @@ TEST_F(MDGeneratorTest, emitCommentMD) {
I.DefLoc = Location(10, 10, "test.cpp");
I.ReturnType = TypeInfo("void");
- I.Params.emplace_back(TypeInfo("int"), "I");
- I.Params.emplace_back(TypeInfo("int"), "J");
+ FieldTypeInfo PI[] = {FieldTypeInfo(TypeInfo("int"), "I"),
+ FieldTypeInfo(TypeInfo("int"), "J")};
+ I.Params = llvm::ArrayRef(PI);
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 15b791a044d2d..50374743681e3 100644
--- a/clang-tools-extra/unittests/clang-doc/MergeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/MergeTest.cpp
@@ -18,150 +18,200 @@ class MergeTest : public ClangDocContextTest {};
TEST_F(MergeTest, mergeNamespaceInfos) {
NamespaceInfo One;
One.Name = "Namespace";
- One.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns1[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ One.Namespace = llvm::ArrayRef(Ns1);
Reference RA(NonEmptySID, "ChildNamespace", InfoType::IT_namespace);
One.Children.Namespaces.push_back(RA);
- 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;
+ 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);
NamespaceInfo Two;
Two.Name = "Namespace";
- Two.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns2[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ Two.Namespace = llvm::ArrayRef(Ns2);
Reference RB(EmptySID, "OtherChildNamespace", InfoType::IT_namespace);
Two.Children.Namespaces.push_back(RB);
- 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";
+ 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);
OwningPtrVec<Info> Infos;
- Infos.emplace_back(allocatePtr<NamespaceInfo>(std::move(One)));
- Infos.emplace_back(allocatePtr<NamespaceInfo>(std::move(Two)));
+ Infos.push_back(&One);
+ Infos.push_back(&Two);
- auto Expected = allocatePtr<NamespaceInfo>();
- Expected->Name = "Namespace";
- Expected->Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ NamespaceInfo Expected;
+ Expected.Name = "Namespace";
+ Reference NsExpected[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ Expected.Namespace = llvm::ArrayRef(NsExpected);
Reference RC(NonEmptySID, "ChildNamespace", InfoType::IT_namespace);
- Expected->Children.Namespaces.push_back(RC);
- Expected->Children.Records.emplace_back(NonEmptySID, "ChildStruct",
- InfoType::IT_record);
+ Expected.Children.Namespaces.push_back(RC);
+ Reference RCE1(NonEmptySID, "ChildStruct", InfoType::IT_record);
+ Expected.Children.Records.push_back(RCE1);
Reference RD(EmptySID, "OtherChildNamespace", InfoType::IT_namespace);
- 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";
+ 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);
auto Actual = mergeInfos(Infos);
assert(Actual);
- CheckNamespaceInfo(InfoAsNamespace(Expected.get()),
- InfoAsNamespace(Actual.get().get()));
+ CheckNamespaceInfo(InfoAsNamespace(&Expected), InfoAsNamespace(Actual.get()));
}
TEST_F(MergeTest, mergeRecordInfos) {
RecordInfo One;
One.Name = "r";
One.IsTypeDef = true;
- One.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns1[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ One.Namespace = llvm::ArrayRef(Ns1);
One.DefLoc = Location(10, 10, "test.cpp");
- One.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private);
+ MemberTypeInfo M1[] = {
+ MemberTypeInfo(TypeInfo("int"), "X", AccessSpecifier::AS_private)};
+ One.Members = llvm::ArrayRef(M1);
One.TagType = TagTypeKind::Class;
- 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;
+ 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);
RecordInfo Two;
Two.Name = "r";
- Two.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns2[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ Two.Namespace = llvm::ArrayRef(Ns2);
- Two.Loc.emplace_back(12, 12, "test.cpp");
+ Location Loc2(12, 12, "test.cpp");
+ Two.Loc.push_back(Loc2);
Two.TagType = TagTypeKind::Class;
- 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";
+ 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);
OwningPtrVec<Info> Infos;
- 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";
+ 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);
auto Actual = mergeInfos(Infos);
assert(Actual);
- CheckRecordInfo(InfoAsRecord(Expected.get()),
- InfoAsRecord(Actual.get().get()));
+ CheckRecordInfo(InfoAsRecord(&Expected), InfoAsRecord(Actual.get()));
}
TEST_F(MergeTest, mergeFunctionInfos) {
FunctionInfo One;
One.Name = "f";
- One.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns1[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ One.Namespace = llvm::ArrayRef(Ns1);
One.DefLoc = Location(10, 10, "test.cpp");
- One.Loc.emplace_back(12, 12, "test.cpp");
+ Location Loc1(12, 12, "test.cpp");
+ One.Loc.push_back(Loc1);
One.IsMethod = true;
One.Parent = Reference(EmptySID, "Parent", InfoType::IT_namespace);
@@ -170,89 +220,106 @@ TEST_F(MergeTest, mergeFunctionInfos) {
CommentInfo(CommentKind::CK_TextComment, {}, "This is a text comment.")};
CommentInfo OnePara[] = {
CommentInfo(CommentKind::CK_ParagraphComment, OneText)};
- One.Description.emplace_back(CommentKind::CK_FullComment, OnePara);
+ CommentInfo TopOne(CommentKind::CK_FullComment, OnePara);
+ One.Description.push_back(TopOne);
FunctionInfo Two;
Two.Name = "f";
- Two.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns2[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ Two.Namespace = llvm::ArrayRef(Ns2);
- Two.Loc.emplace_back(12, 12, "test.cpp");
+ Location Loc2(12, 12, "test.cpp");
+ Two.Loc.push_back(Loc2);
Two.ReturnType = TypeInfo("void");
- Two.Params.emplace_back(TypeInfo("int"), "P");
+ FieldTypeInfo P2(TypeInfo("int"), "P");
+ FieldTypeInfo Params2[] = {std::move(P2)};
+ Two.Params = llvm::ArrayRef(Params2);
CommentInfo TwoText[] = {
CommentInfo(CommentKind::CK_TextComment, {}, "This is a text comment.")};
CommentInfo TwoPara[] = {
CommentInfo(CommentKind::CK_ParagraphComment, TwoText)};
- Two.Description.emplace_back(CommentKind::CK_FullComment, TwoPara);
+ CommentInfo TopTwo(CommentKind::CK_FullComment, TwoPara);
+ Two.Description.push_back(TopTwo);
OwningPtrVec<Info> Infos;
- Infos.emplace_back(allocatePtr<FunctionInfo>(std::move(One)));
- Infos.emplace_back(allocatePtr<FunctionInfo>(std::move(Two)));
+ Infos.push_back(&One);
+ Infos.push_back(&Two);
- auto Expected = allocatePtr<FunctionInfo>();
- Expected->Name = "f";
- Expected->Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ FunctionInfo Expected;
+ Expected.Name = "f";
+ Reference NsE[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ Expected.Namespace = llvm::ArrayRef(NsE);
- Expected->DefLoc = Location(10, 10, "test.cpp");
- Expected->Loc.emplace_back(12, 12, "test.cpp");
+ Expected.DefLoc = Location(10, 10, "test.cpp");
+ Location LocE(12, 12, "test.cpp");
+ Expected.Loc.push_back(LocE);
- Expected->ReturnType = TypeInfo("void");
- Expected->Params.emplace_back(TypeInfo("int"), "P");
- Expected->IsMethod = true;
- Expected->Parent = Reference(EmptySID, "Parent", InfoType::IT_namespace);
+ 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);
CommentInfo ExpectedText[] = {
CommentInfo(CommentKind::CK_TextComment, {}, "This is a text comment.")};
CommentInfo ExpectedPara[] = {
CommentInfo(CommentKind::CK_ParagraphComment, ExpectedText)};
- Expected->Description.emplace_back(CommentKind::CK_FullComment, ExpectedPara);
+ CommentInfo TopE(CommentKind::CK_FullComment, ExpectedPara);
+ Expected.Description.push_back(TopE);
auto Actual = mergeInfos(Infos);
assert(Actual);
- CheckFunctionInfo(InfoAsFunction(Expected.get()),
- InfoAsFunction(Actual.get().get()));
+ CheckFunctionInfo(InfoAsFunction(&Expected), InfoAsFunction(Actual.get()));
}
TEST_F(MergeTest, mergeEnumInfos) {
EnumInfo One;
One.Name = "e";
- One.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns1[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ One.Namespace = llvm::ArrayRef(Ns1);
One.DefLoc = Location(10, 10, "test.cpp");
- One.Loc.emplace_back(12, 12, "test.cpp");
+ Location Loc1(12, 12, "test.cpp");
+ One.Loc.push_back(Loc1);
One.Scoped = true;
EnumInfo Two;
Two.Name = "e";
- Two.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns2[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ Two.Namespace = llvm::ArrayRef(Ns2);
- Two.Loc.emplace_back(20, 20, "test.cpp");
+ Location Loc2(20, 20, "test.cpp");
+ Two.Loc.push_back(Loc2);
- Two.Members.emplace_back("X");
- Two.Members.emplace_back("Y");
+ EnumValueInfo EV2[] = {EnumValueInfo("X"), EnumValueInfo("Y")};
+ Two.Members = llvm::ArrayRef(EV2);
OwningPtrVec<Info> Infos;
- Infos.emplace_back(allocatePtr<EnumInfo>(std::move(One)));
- Infos.emplace_back(allocatePtr<EnumInfo>(std::move(Two)));
+ Infos.push_back(&One);
+ Infos.push_back(&Two);
- auto Expected = allocatePtr<EnumInfo>();
- Expected->Name = "e";
- Expected->Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ EnumInfo Expected;
+ Expected.Name = "e";
+ Reference NsE[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ Expected.Namespace = llvm::ArrayRef(NsE);
- Expected->DefLoc = Location(10, 10, "test.cpp");
- Expected->Loc.emplace_back(12, 12, "test.cpp");
- Expected->Loc.emplace_back(20, 20, "test.cpp");
+ 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->Members.emplace_back("X");
- Expected->Members.emplace_back("Y");
- Expected->Scoped = true;
+ EnumValueInfo EV_E[] = {EnumValueInfo("X"), EnumValueInfo("Y")};
+ Expected.Members = llvm::ArrayRef(EV_E);
+ Expected.Scoped = true;
auto Actual = mergeInfos(Infos);
assert(Actual);
- CheckEnumInfo(InfoAsEnum(Expected.get()), InfoAsEnum(Actual.get().get()));
+ CheckEnumInfo(InfoAsEnum(&Expected), InfoAsEnum(Actual.get()));
}
} // namespace doc
diff --git a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
index 4e963fd64f11b..371efab1b3081 100644
--- a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
@@ -117,25 +117,27 @@ TEST_F(SerializeTest, emitNamespaceInfo) {
extractInfosFromCode("namespace A { namespace B { void f() {} } }", 5,
/*Public=*/false, Infos, this->Diags);
- NamespaceInfo *A = InfoAsNamespace(Infos[0].get());
+ NamespaceInfo *A = InfoAsNamespace(Infos[0]);
NamespaceInfo ExpectedA(EmptySID, "A");
CheckNamespaceInfo(&ExpectedA, A);
- NamespaceInfo *B = InfoAsNamespace(Infos[2].get());
+ NamespaceInfo *B = InfoAsNamespace(Infos[2]);
NamespaceInfo ExpectedB(EmptySID, /*Name=*/"B", /*Path=*/"A");
- ExpectedB.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference NsB[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ ExpectedB.Namespace = llvm::ArrayRef(NsB);
CheckNamespaceInfo(&ExpectedB, B);
- NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[4].get());
+ NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[4]);
NamespaceInfo ExpectedBWithFunction(EmptySID);
FunctionInfo F;
F.Name = "f";
F.ReturnType = TypeInfo("void");
F.DefLoc = Location(0, 0, "test.cpp");
- F.Namespace.emplace_back(EmptySID, "B", InfoType::IT_namespace);
- F.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference NsF[] = {Reference(EmptySID, "B", InfoType::IT_namespace),
+ Reference(EmptySID, "A", InfoType::IT_namespace)};
+ F.Namespace = llvm::ArrayRef(NsF);
F.Access = AccessSpecifier::AS_none;
- ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));
+ ExpectedBWithFunction.Children.Functions.push_back(F);
CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
}
@@ -144,7 +146,7 @@ TEST_F(SerializeTest, emitAnonymousNamespaceInfo) {
extractInfosFromCode("namespace { }", 2, /*Public=*/false, Infos,
this->Diags);
- NamespaceInfo *A = InfoAsNamespace(Infos[0].get());
+ NamespaceInfo *A = InfoAsNamespace(Infos[0]);
NamespaceInfo ExpectedA(EmptySID);
ExpectedA.Name = "@nonymous_namespace";
CheckNamespaceInfo(&ExpectedA, A);
@@ -170,95 +172,103 @@ void F<int>::TemplateMethod();
typedef struct {} G;)raw",
10, /*Public=*/false, Infos, this->Diags);
- RecordInfo *E = InfoAsRecord(Infos[0].get());
+ RecordInfo *E = InfoAsRecord(Infos[0]);
RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
- ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
- InfoType::IT_namespace);
+ Reference NsE[] = {
+ Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
+ ExpectedE.Namespace = llvm::ArrayRef(NsE);
ExpectedE.TagType = TagTypeKind::Class;
ExpectedE.DefLoc = Location(0, 0, "test.cpp");
- ExpectedE.Members.emplace_back(TypeInfo("int"), "value",
- AccessSpecifier::AS_public);
+ MemberTypeInfo MemE[] = {
+ MemberTypeInfo(TypeInfo("int"), "value", AccessSpecifier::AS_public)};
+ ExpectedE.Members = llvm::ArrayRef(MemE);
// 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].get());
+ RecordInfo *RecordWithEConstructor = InfoAsRecord(Infos[2]);
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");
- EConstructor.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record);
- EConstructor.Namespace.emplace_back(EmptySID, "GlobalNamespace",
- InfoType::IT_namespace);
+ Reference NsEC[] = {
+ Reference(EmptySID, "E", InfoType::IT_record),
+ Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
+ EConstructor.Namespace = llvm::ArrayRef(NsEC);
EConstructor.Access = AccessSpecifier::AS_public;
EConstructor.IsMethod = true;
- ExpectedRecordWithEConstructor.Children.Functions.emplace_back(
- std::move(EConstructor));
+ ExpectedRecordWithEConstructor.Children.Functions.push_back(EConstructor);
CheckRecordInfo(&ExpectedRecordWithEConstructor, RecordWithEConstructor);
- RecordInfo *RecordWithMethod = InfoAsRecord(Infos[3].get());
+ RecordInfo *RecordWithMethod = InfoAsRecord(Infos[3]);
RecordInfo ExpectedRecordWithMethod(EmptySID);
FunctionInfo Method;
Method.Name = "ProtectedMethod";
Method.Parent = Reference(EmptySID, "E", InfoType::IT_record);
Method.ReturnType = TypeInfo("void");
- 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);
+ 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.Access = AccessSpecifier::AS_protected;
Method.IsMethod = true;
- ExpectedRecordWithMethod.Children.Functions.emplace_back(std::move(Method));
+ ExpectedRecordWithMethod.Children.Functions.push_back(Method);
CheckRecordInfo(&ExpectedRecordWithMethod, RecordWithMethod);
- RecordInfo *F = InfoAsRecord(Infos[4].get());
+ RecordInfo *F = InfoAsRecord(Infos[4]);
RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace");
- ExpectedF.Namespace.emplace_back(EmptySID, "GlobalNamespace",
- InfoType::IT_namespace);
+ Reference NsF3[] = {
+ Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
+ ExpectedF.Namespace = llvm::ArrayRef(NsF3);
ExpectedF.TagType = TagTypeKind::Struct;
ExpectedF.DefLoc = Location(0, 0, "test.cpp");
CheckRecordInfo(&ExpectedF, F);
- RecordInfo *RecordWithTemplateMethod = InfoAsRecord(Infos[6].get());
+ RecordInfo *RecordWithTemplateMethod = InfoAsRecord(Infos[6]);
RecordInfo ExpectedRecordWithTemplateMethod(EmptySID);
FunctionInfo TemplateMethod;
TemplateMethod.Name = "TemplateMethod";
TemplateMethod.Parent = Reference(EmptySID, "F", InfoType::IT_record);
TemplateMethod.ReturnType = TypeInfo("void");
- 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);
+ 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.Access = AccessSpecifier::AS_public;
TemplateMethod.IsMethod = true;
- ExpectedRecordWithTemplateMethod.Children.Functions.emplace_back(
- std::move(TemplateMethod));
+ ExpectedRecordWithTemplateMethod.Children.Functions.push_back(TemplateMethod);
CheckRecordInfo(&ExpectedRecordWithTemplateMethod, RecordWithTemplateMethod);
- RecordInfo *TemplatedRecord = InfoAsRecord(Infos[7].get());
+ RecordInfo *TemplatedRecord = InfoAsRecord(Infos[7]);
RecordInfo ExpectedTemplatedRecord(EmptySID);
FunctionInfo SpecializedTemplateMethod;
SpecializedTemplateMethod.Name = "TemplateMethod";
SpecializedTemplateMethod.Parent =
Reference(EmptySID, "F", InfoType::IT_record);
SpecializedTemplateMethod.ReturnType = TypeInfo("void");
- 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);
+ 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.Access = AccessSpecifier::AS_public;
SpecializedTemplateMethod.IsMethod = true;
- ExpectedTemplatedRecord.Children.Functions.emplace_back(
- std::move(SpecializedTemplateMethod));
+ ExpectedTemplatedRecord.Children.Functions.push_back(
+ SpecializedTemplateMethod);
CheckRecordInfo(&ExpectedTemplatedRecord, TemplatedRecord);
- RecordInfo *G = InfoAsRecord(Infos[8].get());
+ RecordInfo *G = InfoAsRecord(Infos[8]);
RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace");
- ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace",
- InfoType::IT_namespace);
+ Reference NsG[] = {
+ Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
+ ExpectedG.Namespace = llvm::ArrayRef(NsG);
ExpectedG.TagType = TagTypeKind::Struct;
ExpectedG.DefLoc = Location(0, 0, "test.cpp");
ExpectedG.IsTypeDef = true;
@@ -271,25 +281,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].get());
+ NamespaceInfo *NamespaceWithEnum = InfoAsNamespace(Infos[0]);
NamespaceInfo ExpectedNamespaceWithEnum(EmptySID);
EnumInfo E;
E.Name = "E";
E.DefLoc = Location(0, 0, "test.cpp");
- E.Members.emplace_back("X", "0");
- E.Members.emplace_back("Y", "1");
- ExpectedNamespaceWithEnum.Children.Enums.emplace_back(std::move(E));
+ EnumValueInfo EMem[] = {EnumValueInfo("X", "0"), EnumValueInfo("Y", "1")};
+ E.Members = llvm::ArrayRef(EMem);
+ ExpectedNamespaceWithEnum.Children.Enums.push_back(E);
CheckNamespaceInfo(&ExpectedNamespaceWithEnum, NamespaceWithEnum);
- NamespaceInfo *NamespaceWithScopedEnum = InfoAsNamespace(Infos[1].get());
+ NamespaceInfo *NamespaceWithScopedEnum = InfoAsNamespace(Infos[1]);
NamespaceInfo ExpectedNamespaceWithScopedEnum(EmptySID);
EnumInfo G;
G.Name = "G";
G.Scoped = true;
G.DefLoc = Location(0, 0, "test.cpp");
- G.Members.emplace_back("A", "0");
- G.Members.emplace_back("B", "1");
- ExpectedNamespaceWithScopedEnum.Children.Enums.emplace_back(std::move(G));
+ EnumValueInfo GMem[] = {EnumValueInfo("A", "0"), EnumValueInfo("B", "1")};
+ G.Members = llvm::ArrayRef(GMem);
+ ExpectedNamespaceWithScopedEnum.Children.Enums.push_back(G);
CheckNamespaceInfo(&ExpectedNamespaceWithScopedEnum, NamespaceWithScopedEnum);
}
@@ -297,12 +307,14 @@ TEST_F(SerializeTest, emitUndefinedRecordInfo) {
EmittedInfoList Infos;
extractInfosFromCode("class E;", 2, /*Public=*/false, Infos, this->Diags);
- RecordInfo *E = InfoAsRecord(Infos[0].get());
+ RecordInfo *E = InfoAsRecord(Infos[0]);
RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
- ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
- InfoType::IT_namespace);
+ Reference NsE[] = {
+ Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
+ ExpectedE.Namespace = llvm::ArrayRef(NsE);
ExpectedE.TagType = TagTypeKind::Class;
- ExpectedE.Loc.emplace_back(0, 0, "test.cpp");
+ Location LE(0, 0, "test.cpp");
+ ExpectedE.Loc.push_back(LE);
CheckRecordInfo(&ExpectedE, E);
}
@@ -311,14 +323,16 @@ TEST_F(SerializeTest, emitRecordMemberInfo) {
extractInfosFromCode("struct E { int I; };", 2, /*Public=*/false, Infos,
this->Diags);
- RecordInfo *E = InfoAsRecord(Infos[0].get());
+ RecordInfo *E = InfoAsRecord(Infos[0]);
RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
- ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
- InfoType::IT_namespace);
+ Reference NsE[] = {
+ Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
+ ExpectedE.Namespace = llvm::ArrayRef(NsE);
ExpectedE.TagType = TagTypeKind::Struct;
ExpectedE.DefLoc = Location(0, 0, "test.cpp");
- ExpectedE.Members.emplace_back(TypeInfo("int"), "I",
- AccessSpecifier::AS_public);
+ MemberTypeInfo MemE[] = {
+ MemberTypeInfo(TypeInfo("int"), "I", AccessSpecifier::AS_public)};
+ ExpectedE.Members = llvm::ArrayRef(MemE);
CheckRecordInfo(&ExpectedE, E);
}
@@ -327,23 +341,25 @@ TEST_F(SerializeTest, emitInternalRecordInfo) {
extractInfosFromCode("class E { class G {}; };", 4, /*Public=*/false, Infos,
this->Diags);
- RecordInfo *E = InfoAsRecord(Infos[0].get());
+ RecordInfo *E = InfoAsRecord(Infos[0]);
RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
- ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
- InfoType::IT_namespace);
+ Reference NsE[] = {
+ Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
+ ExpectedE.Namespace = llvm::ArrayRef(NsE);
ExpectedE.DefLoc = Location(0, 0, "test.cpp");
ExpectedE.TagType = TagTypeKind::Class;
CheckRecordInfo(&ExpectedE, E);
- RecordInfo *G = InfoAsRecord(Infos[2].get());
+ RecordInfo *G = InfoAsRecord(Infos[2]);
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;
- ExpectedG.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record);
- ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace",
- InfoType::IT_namespace);
+ Reference NsG[] = {
+ Reference(EmptySID, "E", InfoType::IT_record),
+ Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
+ ExpectedG.Namespace = llvm::ArrayRef(NsG);
CheckRecordInfo(&ExpectedG, G);
}
@@ -358,14 +374,14 @@ TEST_F(SerializeTest, emitPublicFunctionInternalInfo) {
extractInfosFromCode("int F() { class G {}; return 0; };", 1, /*Public=*/true,
Infos, this->Diags);
- NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());
+ NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0]);
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.emplace_back(std::move(F));
+ ExpectedBWithFunction.Children.Functions.push_back(F);
CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
}
@@ -374,15 +390,16 @@ TEST_F(SerializeTest, emitInlinedFunctionInfo) {
extractInfosFromCode("inline void F(int I) { };", 1, /*Public=*/true, Infos,
this->Diags);
- NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());
+ NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0]);
NamespaceInfo ExpectedBWithFunction(EmptySID);
FunctionInfo F;
F.Name = "F";
F.ReturnType = TypeInfo("void");
F.DefLoc = Location(0, 0, "test.cpp");
- F.Params.emplace_back(TypeInfo("int"), "I");
+ FieldTypeInfo Params[] = {FieldTypeInfo(TypeInfo("int"), "I")};
+ F.Params = llvm::ArrayRef(Params);
F.Access = AccessSpecifier::AS_none;
- ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));
+ ExpectedBWithFunction.Children.Functions.push_back(F);
CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
}
@@ -397,132 +414,169 @@ class I {} ;
class J : public I<int> {} ;)raw",
14, /*Public=*/false, Infos, this->Diags);
- RecordInfo *F = InfoAsRecord(Infos[0].get());
+ RecordInfo *F = InfoAsRecord(Infos[0]);
RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace");
- ExpectedF.Namespace.emplace_back(EmptySID, "GlobalNamespace",
- InfoType::IT_namespace, "");
+ Reference NsF[] = {
+ Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
+ ExpectedF.Namespace = llvm::ArrayRef(NsF);
ExpectedF.TagType = TagTypeKind::Class;
ExpectedF.DefLoc = Location(0, 0, "test.cpp");
CheckRecordInfo(&ExpectedF, F);
- RecordInfo *G = InfoAsRecord(Infos[3].get());
+ RecordInfo *G = InfoAsRecord(Infos[3]);
RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace");
- ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace",
- InfoType::IT_namespace);
+ Reference NsG[] = {
+ Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
+ ExpectedG.Namespace = llvm::ArrayRef(NsG);
ExpectedG.TagType = TagTypeKind::Class;
ExpectedG.DefLoc = Location(0, 0, "test.cpp");
- ExpectedG.Members.emplace_back(TypeInfo("int"), "I",
- AccessSpecifier::AS_protected);
+ MemberTypeInfo MemG[] = {
+ MemberTypeInfo(TypeInfo("int"), "I", AccessSpecifier::AS_protected)};
+ ExpectedG.Members = llvm::ArrayRef(MemG);
CheckRecordInfo(&ExpectedG, G);
- RecordInfo *E = InfoAsRecord(Infos[6].get());
+ RecordInfo *E = InfoAsRecord(Infos[6]);
RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
- 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);
+ 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);
FunctionInfo FunctionSet;
FunctionSet.Name = "set";
FunctionSet.ReturnType = TypeInfo("void");
- 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);
+ 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.Access = AccessSpecifier::AS_protected;
FunctionSet.IsMethod = 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);
+ BaseF.Children.Functions.push_back(FunctionSet);
+
+ BaseRecordInfo BaseG(EmptySID, /*Name=*/"G",
+ /*Path=*/"GlobalNamespace", true,
+ AccessSpecifier::AS_private, true);
FunctionInfo FunctionGet;
FunctionGet.Name = "get";
FunctionGet.ReturnType = TypeInfo("int");
- FunctionGet.DefLoc = Location();
- FunctionGet.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record);
- FunctionGet.Namespace.emplace_back(EmptySID, "GlobalNamespace",
- InfoType::IT_namespace);
+ 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.Access = AccessSpecifier::AS_private;
FunctionGet.IsMethod = true;
- ExpectedE.Bases.back().Children.Functions.emplace_back(
- std::move(FunctionGet));
- ExpectedE.Bases.back().Members.emplace_back(TypeInfo("int"), "I",
- AccessSpecifier::AS_private);
+ 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.DefLoc = Location(0, 0, "test.cpp");
ExpectedE.TagType = TagTypeKind::Class;
CheckRecordInfo(&ExpectedE, E);
- RecordInfo *H = InfoAsRecord(Infos[8].get());
+ RecordInfo *H = InfoAsRecord(Infos[8]);
RecordInfo ExpectedH(EmptySID, /*Name=*/"H", /*Path=*/"GlobalNamespace");
- ExpectedH.Namespace.emplace_back(EmptySID, "GlobalNamespace",
- InfoType::IT_namespace);
+ Reference NsH[] = {
+ Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
+ ExpectedH.Namespace = llvm::ArrayRef(NsH);
ExpectedH.TagType = TagTypeKind::Class;
ExpectedH.DefLoc = Location(0, 0, "test.cpp");
- 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);
+ 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);
FunctionInfo FunctionSetNew;
FunctionSetNew.Name = "set";
FunctionSetNew.ReturnType = TypeInfo("void");
- 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);
+ 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.Access = AccessSpecifier::AS_private;
FunctionSetNew.IsMethod = true;
- ExpectedH.Bases.back().Children.Functions.emplace_back(
- std::move(FunctionSetNew));
- ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"G",
- /*Path=*/"GlobalNamespace", true,
- AccessSpecifier::AS_private, false);
+ BaseHF.Children.Functions.push_back(FunctionSetNew);
+ BaseRecordInfo BaseHG(EmptySID, /*Name=*/"G",
+ /*Path=*/"GlobalNamespace", true,
+ AccessSpecifier::AS_private, false);
FunctionInfo FunctionGetNew;
FunctionGetNew.Name = "get";
FunctionGetNew.ReturnType = TypeInfo("int");
- FunctionGetNew.DefLoc = Location();
- FunctionGetNew.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record);
- FunctionGetNew.Namespace.emplace_back(EmptySID, "GlobalNamespace",
- InfoType::IT_namespace);
+ 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.Access = AccessSpecifier::AS_private;
FunctionGetNew.IsMethod = true;
- ExpectedH.Bases.back().Children.Functions.emplace_back(
- std::move(FunctionGetNew));
- ExpectedH.Bases.back().Members.emplace_back(TypeInfo("int"), "I",
- AccessSpecifier::AS_private);
+ 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);
+
CheckRecordInfo(&ExpectedH, H);
- RecordInfo *I = InfoAsRecord(Infos[10].get());
+ RecordInfo *I = InfoAsRecord(Infos[10]);
RecordInfo ExpectedI(EmptySID, /*Name=*/"I", /*Path=*/"GlobalNamespace");
- ExpectedI.Namespace.emplace_back(EmptySID, "GlobalNamespace",
- InfoType::IT_namespace);
+ Reference NsI[] = {
+ Reference(EmptySID, "GlobalNamespace", InfoType::IT_namespace)};
+ ExpectedI.Namespace = llvm::ArrayRef(NsI);
ExpectedI.TagType = TagTypeKind::Class;
ExpectedI.DefLoc = Location(0, 0, "test.cpp");
CheckRecordInfo(&ExpectedI, I);
- RecordInfo *J = InfoAsRecord(Infos[12].get());
+ RecordInfo *J = InfoAsRecord(Infos[12]);
RecordInfo ExpectedJ(EmptySID, /*Name=*/"J", /*Path=*/"GlobalNamespace");
- 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);
+ 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.DefLoc = Location(0, 0, "test.cpp");
ExpectedJ.TagType = TagTypeKind::Class;
CheckRecordInfo(&ExpectedJ, J);
@@ -538,30 +592,33 @@ static int staticModuleFunction(int x);
export double exportedModuleFunction(double y);)raw",
2, /*Public=*/true, Infos, Args, this->Diags);
- NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());
+ NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0]);
NamespaceInfo ExpectedBWithFunction(EmptySID);
FunctionInfo F;
F.Name = "moduleFunction";
F.ReturnType = TypeInfo("int");
- 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";
+ 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.Access = AccessSpecifier::AS_none;
- ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));
+ ExpectedBWithFunction.Children.Functions.push_back(F);
CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
- NamespaceInfo *BWithExportedFunction = InfoAsNamespace(Infos[1].get());
+ NamespaceInfo *BWithExportedFunction = InfoAsNamespace(Infos[1]);
NamespaceInfo ExpectedBWithExportedFunction(EmptySID);
FunctionInfo ExportedF;
ExportedF.Name = "exportedModuleFunction";
ExportedF.ReturnType =
TypeInfo(Reference(EmptySID, "double", InfoType::IT_default));
- ExportedF.Loc.emplace_back(0, 0, "test.cpp");
- ExportedF.Params.emplace_back(TypeInfo("double"), "y");
+ Location LF2(0, 0, "test.cpp");
+ ExportedF.Loc.push_back(LF2);
+ FieldTypeInfo ParamsExportedF[] = {FieldTypeInfo(TypeInfo("double"), "y")};
+ ExportedF.Params = llvm::ArrayRef(ParamsExportedF);
ExportedF.Access = AccessSpecifier::AS_none;
- ExpectedBWithExportedFunction.Children.Functions.emplace_back(
- std::move(ExportedF));
+ ExpectedBWithExportedFunction.Children.Functions.push_back(ExportedF);
CheckNamespaceInfo(&ExpectedBWithExportedFunction, BWithExportedFunction);
}
@@ -571,24 +628,24 @@ TEST_F(SerializeTest, emitChildRecords) {
extractInfosFromCode("class A { class B {}; }; namespace { class C {}; } ", 8,
/*Public=*/false, Infos, this->Diags);
- NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());
+ NamespaceInfo *ParentA = InfoAsNamespace(Infos[1]);
NamespaceInfo ExpectedParentA(EmptySID);
- ExpectedParentA.Children.Records.emplace_back(
- EmptySID, "A", InfoType::IT_record, "A", "GlobalNamespace");
+ Reference RA(EmptySID, "A", InfoType::IT_record, "A", "GlobalNamespace");
+ ExpectedParentA.Children.Records.push_back(RA);
CheckNamespaceInfo(&ExpectedParentA, ParentA);
- RecordInfo *ParentB = InfoAsRecord(Infos[3].get());
+ RecordInfo *ParentB = InfoAsRecord(Infos[3]);
RecordInfo ExpectedParentB(EmptySID);
llvm::SmallString<128> ExpectedParentBPath("GlobalNamespace/A");
llvm::sys::path::native(ExpectedParentBPath);
- ExpectedParentB.Children.Records.emplace_back(
- EmptySID, "B", InfoType::IT_record, "A::B", ExpectedParentBPath);
+ Reference RB(EmptySID, "B", InfoType::IT_record, "A::B", ExpectedParentBPath);
+ ExpectedParentB.Children.Records.push_back(RB);
CheckRecordInfo(&ExpectedParentB, ParentB);
- NamespaceInfo *ParentC = InfoAsNamespace(Infos[7].get());
+ NamespaceInfo *ParentC = InfoAsNamespace(Infos[7]);
NamespaceInfo ExpectedParentC(EmptySID);
- ExpectedParentC.Children.Records.emplace_back(
- EmptySID, "C", InfoType::IT_record, "C", "@nonymous_namespace");
+ Reference RC(EmptySID, "C", InfoType::IT_record, "C", "@nonymous_namespace");
+ ExpectedParentC.Children.Records.push_back(RC);
CheckNamespaceInfo(&ExpectedParentC, ParentC);
}
@@ -598,13 +655,13 @@ TEST_F(SerializeTest, emitChildNamespaces) {
extractInfosFromCode("namespace A { namespace B { } }", 4, /*Public=*/false,
Infos, this->Diags);
- NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());
+ NamespaceInfo *ParentA = InfoAsNamespace(Infos[1]);
NamespaceInfo ExpectedParentA(EmptySID);
Reference RA(EmptySID, "A", InfoType::IT_namespace);
ExpectedParentA.Children.Namespaces.push_back(RA);
CheckNamespaceInfo(&ExpectedParentA, ParentA);
- NamespaceInfo *ParentB = InfoAsNamespace(Infos[3].get());
+ NamespaceInfo *ParentB = InfoAsNamespace(Infos[3]);
NamespaceInfo ExpectedParentB(EmptySID);
Reference RB(EmptySID, "B", InfoType::IT_namespace, "A::B", "A");
ExpectedParentB.Children.Namespaces.push_back(RB);
@@ -617,10 +674,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].get());
+ NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0]);
ASSERT_EQ(1u, GlobalNS1->Children.Typedefs.size());
- const TypedefInfo &FirstTD = GlobalNS1->Children.Typedefs[0];
+ const TypedefInfo &FirstTD = *GlobalNS1->Children.Typedefs.begin();
EXPECT_EQ("MyInt", FirstTD.Name);
EXPECT_FALSE(FirstTD.IsUsing);
EXPECT_EQ("int", FirstTD.Underlying.Type.Name);
@@ -628,11 +685,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].get());
+ NamespaceInfo *GlobalNS2 = InfoAsNamespace(Infos[1]);
ASSERT_EQ(1u, GlobalNS2->Children.Typedefs.size());
// Second is the "using" typedef.
- const TypedefInfo &SecondTD = GlobalNS2->Children.Typedefs[0];
+ const TypedefInfo &SecondTD = *GlobalNS2->Children.Typedefs.begin();
EXPECT_EQ("MyDouble", SecondTD.Name);
EXPECT_TRUE(SecondTD.IsUsing);
EXPECT_EQ("double", SecondTD.Underlying.Type.Name);
@@ -647,10 +704,10 @@ TEST_F(SerializeTest, emitFunctionTemplate) {
/*Public=*/false, Infos, this->Diags);
// First info will be the global namespace.
- NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0].get());
+ NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0]);
ASSERT_EQ(1u, GlobalNS1->Children.Functions.size());
- const FunctionInfo &Func1 = GlobalNS1->Children.Functions[0];
+ const FunctionInfo &Func1 = *GlobalNS1->Children.Functions.begin();
EXPECT_EQ("GetFoo", Func1.Name);
ASSERT_TRUE(Func1.Template);
EXPECT_FALSE(Func1.Template->Specialization); // Not a specialization.
@@ -662,11 +719,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].get());
+ NamespaceInfo *GlobalNS2 = InfoAsNamespace(Infos[1]);
ASSERT_EQ(1u, GlobalNS2->Children.Functions.size());
// This one is a template specialization.
- const FunctionInfo &Func2 = GlobalNS2->Children.Functions[0];
+ const FunctionInfo &Func2 = *GlobalNS2->Children.Functions.begin();
EXPECT_EQ("GetFoo", Func2.Name);
ASSERT_TRUE(Func2.Template);
EXPECT_TRUE(Func2.Template->Params.empty()); // No template params.
@@ -694,7 +751,7 @@ TEST_F(SerializeTest, emitClassTemplate) {
/*Public=*/false, Infos, this->Diags);
// First record.
- const RecordInfo *Rec1 = InfoAsRecord(Infos[0].get());
+ const RecordInfo *Rec1 = InfoAsRecord(Infos[0]);
EXPECT_EQ("MyTemplate", Rec1->Name);
ASSERT_TRUE(Rec1->Template);
EXPECT_FALSE(Rec1->Template->Specialization); // Not a specialization.
@@ -704,7 +761,7 @@ TEST_F(SerializeTest, emitClassTemplate) {
EXPECT_EQ("int I", Rec1->Template->Params[0].Contents);
// Second record.
- const RecordInfo *Rec2 = InfoAsRecord(Infos[2].get());
+ const RecordInfo *Rec2 = InfoAsRecord(Infos[2]);
EXPECT_EQ("MyTemplate", Rec2->Name);
ASSERT_TRUE(Rec2->Template);
EXPECT_TRUE(Rec2->Template->Params.empty()); // No template params.
@@ -716,7 +773,7 @@ TEST_F(SerializeTest, emitClassTemplate) {
EXPECT_EQ(Rec1->USR, Rec2->Template->Specialization->SpecializationOf);
// Third record.
- const RecordInfo *Rec3 = InfoAsRecord(Infos[4].get());
+ const RecordInfo *Rec3 = InfoAsRecord(Infos[4]);
EXPECT_EQ("OtherTemplate", Rec3->Name);
ASSERT_TRUE(Rec3->Template);
@@ -726,7 +783,7 @@ TEST_F(SerializeTest, emitClassTemplate) {
EXPECT_EQ("int U = 1", Rec3->Template->Params[1].Contents);
// Fourth record.
- const RecordInfo *Rec4 = InfoAsRecord(Infos[6].get());
+ const RecordInfo *Rec4 = InfoAsRecord(Infos[6]);
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 a7f8629b926c1..6f4b724bd9427 100644
--- a/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
@@ -28,20 +28,25 @@ TEST_F(YAMLGeneratorTest, emitNamespaceYAML) {
NamespaceInfo I;
I.Name = "Namespace";
I.Path = "path/to/A";
- I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
Reference NewNamespace(EmptySID, "ChildNamespace", InfoType::IT_namespace,
"path::to::A::Namespace::ChildNamespace",
"path/to/A/Namespace");
I.Children.Namespaces.push_back(NewNamespace);
- 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";
+ 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);
auto G = getYAMLGenerator();
assert(G);
@@ -85,12 +90,14 @@ TEST_F(YAMLGeneratorTest, emitRecordYAML) {
I.Name = "r";
I.Path = "path/to/A";
I.IsTypeDef = true;
- I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
I.DefLoc = Location(10, 10, "test.cpp");
- I.Loc.emplace_back(12, 12, "test.cpp");
+ Location Loc1(12, 12, "test.cpp");
+ I.Loc.push_back(Loc1);
- I.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private);
+ MemberTypeInfo M(TypeInfo("int"), "X", AccessSpecifier::AS_private);
// Member documentation.
CommentInfo BriefChildren[] = {CommentInfo(CommentKind::CK_TextComment, {},
@@ -99,26 +106,39 @@ TEST_F(YAMLGeneratorTest, emitRecordYAML) {
CommentInfo TopCommentChildren[] = {
CommentInfo(CommentKind::CK_ParagraphComment, BriefChildren)};
CommentInfo TopComment(CommentKind::CK_FullComment, TopCommentChildren);
- I.Members.back().Description.push_back(std::move(TopComment));
+ M.Description.push_back(TopComment);
+ MemberTypeInfo MemArr[] = {std::move(M)};
+ I.Members = llvm::ArrayRef(MemArr);
I.TagType = TagTypeKind::Class;
- 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
- 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");
+ 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.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";
+ // 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);
auto G = getYAMLGenerator();
assert(G);
@@ -205,17 +225,22 @@ IsTypeDef: true
TEST_F(YAMLGeneratorTest, emitFunctionYAML) {
FunctionInfo I;
I.Name = "f";
- I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
I.DefLoc = Location(10, 10, "test.cpp");
- I.Loc.emplace_back(12, 12, "test.cpp");
+ Location Loc1(12, 12, "test.cpp");
+ I.Loc.push_back(Loc1);
I.Access = AccessSpecifier::AS_none;
I.ReturnType = TypeInfo(Reference(EmptySID, "void", InfoType::IT_default));
- I.Params.emplace_back(TypeInfo("int"), "P");
- I.Params.emplace_back(TypeInfo("double"), "D");
- I.Params.back().DefaultValue = "2.0 * M_PI";
+
+ 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.IsMethod = true;
I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
@@ -270,12 +295,15 @@ IsMethod: true
TEST_F(YAMLGeneratorTest, emitSimpleEnumYAML) {
EnumInfo I;
I.Name = "e";
- I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+ Reference Ns[] = {Reference(EmptySID, "A", InfoType::IT_namespace)};
+ I.Namespace = llvm::ArrayRef(Ns);
I.DefLoc = Location(10, 10, "test.cpp");
- I.Loc.emplace_back(12, 12, "test.cpp");
+ Location Loc1(12, 12, "test.cpp");
+ I.Loc.push_back(Loc1);
- I.Members.emplace_back("X");
+ EnumValueInfo EV[] = {EnumValueInfo("X")};
+ I.Members = llvm::ArrayRef(EV);
I.Scoped = false;
auto G = getYAMLGenerator();
@@ -312,7 +340,8 @@ TEST_F(YAMLGeneratorTest, enumTypedScopedEnumYAML) {
EnumInfo I;
I.Name = "e";
- I.Members.emplace_back("X", "-9876", "FOO_BAR + 2");
+ EnumValueInfo EV[] = {EnumValueInfo("X", "-9876", "FOO_BAR + 2")};
+ I.Members = llvm::ArrayRef(EV);
I.Scoped = true;
I.BaseType = TypeInfo("short");
@@ -370,8 +399,9 @@ TEST_F(YAMLGeneratorTest, emitCommentYAML) {
I.Name = "f";
I.DefLoc = Location(10, 10, "test.cpp");
I.ReturnType = TypeInfo("void");
- I.Params.emplace_back(TypeInfo("int"), "I");
- I.Params.emplace_back(TypeInfo("int"), "J");
+ FieldTypeInfo Params[] = {FieldTypeInfo(TypeInfo("int"), "I"),
+ FieldTypeInfo(TypeInfo("int"), "J")};
+ I.Params = llvm::ArrayRef(Params);
I.Access = AccessSpecifier::AS_none;
// BlankLine
@@ -444,7 +474,7 @@ TEST_F(YAMLGeneratorTest, emitCommentYAML) {
Verbatim, ParamOut, ParamIn, Return};
CommentInfo Top(CommentKind::CK_FullComment, TopChildren);
- I.Description.emplace_back(std::move(Top));
+ I.Description.push_back(Top);
auto G = getYAMLGenerator();
assert(G);
>From d9d484ccbe2ce87d8e7ac1aaca9b7588ff39c5ea Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Sat, 18 Apr 2026 01:23:52 +0000
Subject: [PATCH 02/11] Try alternate allocation strategy
---
clang-tools-extra/clang-doc/Representation.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index fd790d66c98fe..1687c517f1aeb 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -87,7 +87,7 @@ llvm::ArrayRef<T> allocateArray(llvm::ArrayRef<T> V,
if (V.empty())
return llvm::ArrayRef<T>();
T *Allocated = static_cast<T *>(Alloc.Allocate<T>(V.size()));
- std::uninitialized_copy(V.begin(), V.end(), Allocated);
+ std::uninitialized_move(V.begin(), V.end(), Allocated);
return llvm::ArrayRef<T>(Allocated, V.size());
}
>From fbb26e9b88ce11a67f22017ad4a9a97280068f9d Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Mon, 20 Apr 2026 22:03:17 +0000
Subject: [PATCH 03/11] Always allocate Info types in the arena
---
clang-tools-extra/clang-doc/Serialize.cpp | 135 +++++++++++-----------
clang-tools-extra/clang-doc/Serialize.h | 12 +-
2 files changed, 71 insertions(+), 76 deletions(-)
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index 4b2f0b5eac3a4..e6ec6dee58939 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -471,29 +471,24 @@ void Serializer::InsertChild(ScopeChildren &Scope, const RecordInfo &Info) {
Scope.Records.push_back(*R);
}
-void Serializer::InsertChild(ScopeChildren &Scope, EnumInfo Info) {
- EnumInfo *E = allocatePtr<EnumInfo>(std::move(Info));
- Scope.Enums.push_back(*E);
+void Serializer::InsertChild(ScopeChildren &Scope, EnumInfo &Info) {
+ Scope.Enums.push_back(Info);
}
-void Serializer::InsertChild(ScopeChildren &Scope, FunctionInfo Info) {
- FunctionInfo *F = allocatePtr<FunctionInfo>(std::move(Info));
- Scope.Functions.push_back(*F);
+void Serializer::InsertChild(ScopeChildren &Scope, FunctionInfo &Info) {
+ Scope.Functions.push_back(Info);
}
-void Serializer::InsertChild(ScopeChildren &Scope, TypedefInfo Info) {
- TypedefInfo *T = allocatePtr<TypedefInfo>(std::move(Info));
- Scope.Typedefs.push_back(*T);
+void Serializer::InsertChild(ScopeChildren &Scope, TypedefInfo &Info) {
+ Scope.Typedefs.push_back(Info);
}
-void Serializer::InsertChild(ScopeChildren &Scope, ConceptInfo Info) {
- ConceptInfo *C = allocatePtr<ConceptInfo>(std::move(Info));
- Scope.Concepts.push_back(*C);
+void Serializer::InsertChild(ScopeChildren &Scope, ConceptInfo &Info) {
+ Scope.Concepts.push_back(Info);
}
-void Serializer::InsertChild(ScopeChildren &Scope, VarInfo Info) {
- VarInfo *V = allocatePtr<VarInfo>(std::move(Info));
- Scope.Variables.push_back(*V);
+void Serializer::InsertChild(ScopeChildren &Scope, VarInfo &Info) {
+ Scope.Variables.push_back(Info);
}
// Creates a parent of the correct type for the given child and inserts it into
@@ -511,11 +506,11 @@ void Serializer::InsertChild(ScopeChildren &Scope, VarInfo Info) {
// parameter. Since each variant is used once, it's not worth having a more
// elaborate system to automatically deduce this information.
template <typename ChildType>
-OwnedPtr<Info> Serializer::makeAndInsertIntoParent(ChildType Child) {
+OwnedPtr<Info> Serializer::makeAndInsertIntoParent(ChildType &Child) {
if (Child.Namespace.empty()) {
// Insert into unnamed parent namespace.
auto ParentNS = allocatePtr<NamespaceInfo>();
- InsertChild(ParentNS->Children, std::forward<ChildType>(Child));
+ InsertChild(ParentNS->Children, Child);
return ParentNS;
}
@@ -523,13 +518,13 @@ OwnedPtr<Info> Serializer::makeAndInsertIntoParent(ChildType Child) {
case InfoType::IT_namespace: {
auto ParentNS = allocatePtr<NamespaceInfo>();
ParentNS->USR = Child.Namespace[0].USR;
- InsertChild(ParentNS->Children, std::forward<ChildType>(Child));
+ InsertChild(ParentNS->Children, Child);
return ParentNS;
}
case InfoType::IT_record: {
auto ParentRec = allocatePtr<RecordInfo>();
ParentRec->USR = Child.Namespace[0].USR;
- InsertChild(ParentRec->Children, std::forward<ChildType>(Child));
+ InsertChild(ParentRec->Children, Child);
return ParentRec;
}
case InfoType::IT_default:
@@ -1173,28 +1168,28 @@ Serializer::emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
Serializer::emitInfo(const FunctionDecl *D, const FullComment *FC, Location Loc,
bool PublicOnly) {
- FunctionInfo Func;
+ FunctionInfo *Func = allocatePtr<FunctionInfo>();
bool IsInAnonymousNamespace = false;
- populateFunctionInfo(Func, D, FC, Loc, IsInAnonymousNamespace);
- Func.Access = clang::AccessSpecifier::AS_none;
+ populateFunctionInfo(*Func, D, FC, Loc, IsInAnonymousNamespace);
+ Func->Access = clang::AccessSpecifier::AS_none;
if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
return {};
// Info is wrapped in its parent scope so is returned in the second position.
- return {nullptr, makeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))};
+ return {nullptr, makeAndInsertIntoParent(*Func)};
}
std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
Serializer::emitInfo(const CXXMethodDecl *D, const FullComment *FC,
Location Loc, bool PublicOnly) {
- FunctionInfo Func;
+ FunctionInfo *Func = allocatePtr<FunctionInfo>();
bool IsInAnonymousNamespace = false;
- populateFunctionInfo(Func, D, FC, Loc, IsInAnonymousNamespace);
+ populateFunctionInfo(*Func, D, FC, Loc, IsInAnonymousNamespace);
if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
return {};
- Func.IsMethod = true;
- Func.IsStatic = D->isStatic();
+ Func->IsMethod = true;
+ Func->IsStatic = D->isStatic();
const NamedDecl *Parent = nullptr;
if (const auto *SD =
@@ -1204,13 +1199,13 @@ Serializer::emitInfo(const CXXMethodDecl *D, const FullComment *FC,
Parent = D->getParent();
SymbolID ParentUSR = getUSRForDecl(Parent);
- Func.Parent =
+ Func->Parent =
Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record,
Parent->getQualifiedNameAsString()};
- Func.Access = D->getAccess();
+ Func->Access = D->getAccess();
// Info is wrapped in its parent scope so is returned in the second position.
- return {nullptr, makeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))};
+ return {nullptr, makeAndInsertIntoParent(*Func)};
}
void Serializer::extractCommentFromDecl(const Decl *D, TypedefInfo &Info) {
@@ -1231,31 +1226,31 @@ void Serializer::extractCommentFromDecl(const Decl *D, TypedefInfo &Info) {
std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
Serializer::emitInfo(const TypedefDecl *D, const FullComment *FC, Location Loc,
bool PublicOnly) {
- TypedefInfo Info;
+ TypedefInfo *Info = allocatePtr<TypedefInfo>();
bool IsInAnonymousNamespace = false;
- populateInfo(Info, D, FC, IsInAnonymousNamespace);
+ populateInfo(*Info, D, FC, IsInAnonymousNamespace);
if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
return {};
- Info.DefLoc = Loc;
+ Info->DefLoc = Loc;
auto &LO = D->getLangOpts();
- Info.Underlying = getTypeInfoForType(D->getUnderlyingType(), LO);
- populateTemplateParameters(Info.Template, D);
- if (Info.Template)
- populateConstraints(Info.Template.value(), D->getDescribedTemplate());
+ Info->Underlying = getTypeInfoForType(D->getUnderlyingType(), LO);
+ populateTemplateParameters(Info->Template, D);
+ if (Info->Template)
+ populateConstraints(Info->Template.value(), D->getDescribedTemplate());
- if (Info.Underlying.Type.Name.empty()) {
+ if (Info->Underlying.Type.Name.empty()) {
// Typedef for an unnamed type. This is like "typedef struct { } Foo;"
// The record serializer explicitly checks for this syntax and constructs
// a record with that name, so we don't want to emit a duplicate here.
return {};
}
- Info.IsUsing = false;
- extractCommentFromDecl(D, Info);
+ Info->IsUsing = false;
+ extractCommentFromDecl(D, *Info);
// Info is wrapped in its parent scope so is returned in the second position.
- return {nullptr, makeAndInsertIntoParent<TypedefInfo &&>(std::move(Info))};
+ return {nullptr, makeAndInsertIntoParent(*Info)};
}
// A type alias is a C++ "using" declaration for a type. It gets mapped to a
@@ -1263,58 +1258,58 @@ Serializer::emitInfo(const TypedefDecl *D, const FullComment *FC, Location Loc,
std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
Serializer::emitInfo(const TypeAliasDecl *D, const FullComment *FC,
Location Loc, bool PublicOnly) {
- TypedefInfo Info;
+ TypedefInfo *Info = allocatePtr<TypedefInfo>();
bool IsInAnonymousNamespace = false;
- populateInfo(Info, D, FC, IsInAnonymousNamespace);
+ populateInfo(*Info, D, FC, IsInAnonymousNamespace);
if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
return {};
- Info.DefLoc = Loc;
+ Info->DefLoc = Loc;
const LangOptions &LO = D->getLangOpts();
- Info.Underlying = getTypeInfoForType(D->getUnderlyingType(), LO);
- Info.TypeDeclaration = getTypeAlias(D);
- Info.IsUsing = true;
- populateTemplateParameters(Info.Template, D);
- if (Info.Template)
- populateConstraints(Info.Template.value(), D->getDescribedAliasTemplate());
+ Info->Underlying = getTypeInfoForType(D->getUnderlyingType(), LO);
+ Info->TypeDeclaration = getTypeAlias(D);
+ Info->IsUsing = true;
+ populateTemplateParameters(Info->Template, D);
+ if (Info->Template)
+ populateConstraints(Info->Template.value(), D->getDescribedAliasTemplate());
- extractCommentFromDecl(D, Info);
+ extractCommentFromDecl(D, *Info);
// Info is wrapped in its parent scope so is returned in the second position.
- return {nullptr, makeAndInsertIntoParent<TypedefInfo &&>(std::move(Info))};
+ return {nullptr, makeAndInsertIntoParent(*Info)};
}
std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
Serializer::emitInfo(const EnumDecl *D, const FullComment *FC, Location Loc,
bool PublicOnly) {
- EnumInfo Enum;
+ EnumInfo *Enum = allocatePtr<EnumInfo>();
bool IsInAnonymousNamespace = false;
- populateSymbolInfo(Enum, D, FC, Loc, IsInAnonymousNamespace);
+ populateSymbolInfo(*Enum, D, FC, Loc, IsInAnonymousNamespace);
if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
return {};
- Enum.Scoped = D->isScoped();
+ Enum->Scoped = D->isScoped();
if (const TypeSourceInfo *TSI = D->getIntegerTypeSourceInfo()) {
auto Name = TSI->getType().getAsString();
- Enum.BaseType = TypeInfo(Name, Name);
+ Enum->BaseType = TypeInfo(Name, Name);
}
- parseEnumerators(Enum, D);
+ parseEnumerators(*Enum, D);
// Info is wrapped in its parent scope so is returned in the second position.
- return {nullptr, makeAndInsertIntoParent<EnumInfo &&>(std::move(Enum))};
+ return {nullptr, makeAndInsertIntoParent(*Enum)};
}
std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
Serializer::emitInfo(const ConceptDecl *D, const FullComment *FC,
const Location &Loc, bool PublicOnly) {
- ConceptInfo Concept;
+ ConceptInfo *Concept = allocatePtr<ConceptInfo>();
bool IsInAnonymousNamespace = false;
- populateInfo(Concept, D, FC, IsInAnonymousNamespace);
- Concept.IsType = D->isTypeConcept();
- Concept.DefLoc = Loc;
- Concept.ConstraintExpression = exprToString(D->getConstraintExpr());
+ populateInfo(*Concept, D, FC, IsInAnonymousNamespace);
+ Concept->IsType = D->isTypeConcept();
+ Concept->DefLoc = Loc;
+ Concept->ConstraintExpression = exprToString(D->getConstraintExpr());
if (auto *ConceptParams = D->getTemplateParameters()) {
llvm::SmallVector<TemplateParamInfo, 4> LocalParams;
@@ -1322,34 +1317,34 @@ Serializer::emitInfo(const ConceptDecl *D, const FullComment *FC,
LocalParams.emplace_back(getSourceCode(Param, Param->getSourceRange()));
}
if (!LocalParams.empty())
- Concept.Template.Params =
+ Concept->Template.Params =
allocateArray<TemplateParamInfo>(LocalParams, TransientArena);
}
if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
return {};
- return {nullptr, makeAndInsertIntoParent<ConceptInfo &&>(std::move(Concept))};
+ return {nullptr, makeAndInsertIntoParent(*Concept)};
}
std::pair<OwnedPtr<Info>, OwnedPtr<Info>>
Serializer::emitInfo(const VarDecl *D, const FullComment *FC,
const Location &Loc, bool PublicOnly) {
- VarInfo Var;
+ VarInfo *Var = allocatePtr<VarInfo>();
bool IsInAnonymousNamespace = false;
- populateSymbolInfo(Var, D, FC, Loc, IsInAnonymousNamespace);
+ populateSymbolInfo(*Var, D, FC, Loc, IsInAnonymousNamespace);
if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
return {};
if (D->getStorageClass() == StorageClass::SC_Static)
- Var.IsStatic = true;
- Var.Type =
+ Var->IsStatic = true;
+ Var->Type =
getTypeInfoForType(D->getType(), D->getASTContext().getPrintingPolicy());
if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
return {};
- return {nullptr, makeAndInsertIntoParent<VarInfo &&>(std::move(Var))};
+ return {nullptr, makeAndInsertIntoParent(*Var)};
}
} // namespace serialize
diff --git a/clang-tools-extra/clang-doc/Serialize.h b/clang-tools-extra/clang-doc/Serialize.h
index 3d53514d0756a..fe3a70548e617 100644
--- a/clang-tools-extra/clang-doc/Serialize.h
+++ b/clang-tools-extra/clang-doc/Serialize.h
@@ -117,14 +117,14 @@ class Serializer {
void InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info);
void InsertChild(ScopeChildren &Scope, const RecordInfo &Info);
- void InsertChild(ScopeChildren &Scope, EnumInfo Info);
- void InsertChild(ScopeChildren &Scope, FunctionInfo Info);
- void InsertChild(ScopeChildren &Scope, TypedefInfo Info);
- void InsertChild(ScopeChildren &Scope, ConceptInfo Info);
- void InsertChild(ScopeChildren &Scope, VarInfo Info);
+ void InsertChild(ScopeChildren &Scope, EnumInfo &Info);
+ void InsertChild(ScopeChildren &Scope, FunctionInfo &Info);
+ void InsertChild(ScopeChildren &Scope, TypedefInfo &Info);
+ void InsertChild(ScopeChildren &Scope, ConceptInfo &Info);
+ void InsertChild(ScopeChildren &Scope, VarInfo &Info);
template <typename ChildType>
- OwnedPtr<Info> makeAndInsertIntoParent(ChildType Child);
+ OwnedPtr<Info> makeAndInsertIntoParent(ChildType &Child);
AccessSpecifier getFinalAccessSpecifier(AccessSpecifier FirstAS,
AccessSpecifier SecondAS);
>From 6cfd2b09135b131f5fcf1137e3754326b9c9b93e Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Tue, 21 Apr 2026 20:17:08 +0000
Subject: [PATCH 04/11] Check if the ilist is empty over using its size
---
clang-tools-extra/clang-doc/Representation.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index 1687c517f1aeb..d7ec9e300e5be 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -524,7 +524,7 @@ 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 &&
+ if (!Loc.empty() && !Other.Loc.empty() &&
Loc.front() != Other.Loc.front())
return Loc.front() < Other.Loc.front();
>From a5fe12ac9c27f8040a54833e77d08e9f008f4ee1 Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Tue, 21 Apr 2026 20:21:27 +0000
Subject: [PATCH 05/11] git clang-format
---
clang-tools-extra/clang-doc/Representation.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index d7ec9e300e5be..88b4c85569b7b 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -524,8 +524,7 @@ 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.empty() && !Other.Loc.empty() &&
- Loc.front() != Other.Loc.front())
+ if (!Loc.empty() && !Other.Loc.empty() && Loc.front() != Other.Loc.front())
return Loc.front() < Other.Loc.front();
if (DefLoc && Other.DefLoc && *DefLoc != *Other.DefLoc)
>From 13ffc27511cb1f4c7f34332dc542e19a4c757050 Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Tue, 21 Apr 2026 20:52:44 +0000
Subject: [PATCH 06/11] Default initialize StringRefs and ArrayRefs in Info
types
---
clang-tools-extra/clang-doc/Representation.h | 95 ++++++++++----------
1 file changed, 48 insertions(+), 47 deletions(-)
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index 88b4c85569b7b..91ed25cd94939 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -203,18 +203,18 @@ struct CommentInfo : public llvm::ilist_node<CommentInfo> {
// the vector.
bool operator<(const CommentInfo &Other) const;
- 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.
- llvm::ArrayRef<StringRef> AttrKeys; // List of attribute keys (for HTML).
- llvm::ArrayRef<StringRef>
- AttrValues; // List of attribute values for each key (for HTML).
- llvm::ArrayRef<StringRef>
- Args; // List of arguments to commands (for InlineCommand).
+ 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.
+ llvm::ArrayRef<StringRef> AttrKeys = {}; // List of attribute keys (for HTML).
+ llvm::ArrayRef<StringRef> AttrValues =
+ {}; // List of attribute values for each key (for HTML).
+ llvm::ArrayRef<StringRef> Args =
+ {}; // List of arguments to commands (for InlineCommand).
CommentKind Kind = CommentKind::
CK_Unknown; // Kind of comment (FullComment, ParagraphComment,
// TextComment, InlineCommandComment, HTMLStartTagComment,
@@ -271,17 +271,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
@@ -291,7 +291,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.
@@ -345,7 +345,7 @@ 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 {
@@ -353,7 +353,7 @@ struct TemplateSpecializationInfo {
SymbolID SpecializationOf;
// Template parameters applying to the specialized record/function.
- llvm::ArrayRef<TemplateParamInfo> Params;
+ llvm::ArrayRef<TemplateParamInfo> Params = {};
};
struct ConstraintInfo {
@@ -362,18 +362,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 {
// May be empty for non-partial specializations.
- llvm::ArrayRef<TemplateParamInfo> Params;
+ llvm::ArrayRef<TemplateParamInfo> Params = {};
// Set when this is a specialization of another record/function.
std::optional<TemplateSpecializationInfo> Specialization;
- llvm::ArrayRef<ConstraintInfo> Constraints;
+ llvm::ArrayRef<ConstraintInfo> Constraints = {};
};
// Info for field types.
@@ -389,11 +389,11 @@ 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.
@@ -443,7 +443,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;
@@ -472,15 +472,15 @@ 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;
@@ -535,7 +535,7 @@ 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;
+ StringRef MangledName = {};
bool IsStatic = false;
};
@@ -551,7 +551,7 @@ struct FriendInfo : public SymbolInfo, public llvm::ilist_node<FriendInfo> {
Reference Ref;
std::optional<TemplateInfo> Template;
std::optional<TypeInfo> ReturnType;
- llvm::ArrayRef<FieldTypeInfo> Params;
+ llvm::ArrayRef<FieldTypeInfo> Params = {};
bool IsClass = false;
};
@@ -574,8 +574,8 @@ struct FunctionInfo : public SymbolInfo, public llvm::ilist_node<FunctionInfo> {
Reference Parent;
TypeInfo ReturnType;
- llvm::ArrayRef<FieldTypeInfo> Params;
- StringRef Prototype;
+ llvm::ArrayRef<FieldTypeInfo> Params = {};
+ StringRef Prototype = {};
// When present, this function is a template or specialization.
std::optional<TemplateInfo> Template;
@@ -610,18 +610,19 @@ 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
+ 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>
- VirtualParents; // List of virtual base/parent records.
+ llvm::ArrayRef<Reference> VirtualParents =
+ {}; // List of virtual base/parent records.
- llvm::ArrayRef<BaseRecordInfo>
- Bases; // List of base/parent records; this includes
- // inherited methods and attributes
+ llvm::ArrayRef<BaseRecordInfo> Bases =
+ {}; // List of base/parent records; this includes
+ // inherited methods and attributes
- llvm::ArrayRef<FriendInfo> Friends;
+ llvm::ArrayRef<FriendInfo> Friends = {};
ScopeChildren Children;
};
@@ -639,7 +640,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>
@@ -675,16 +676,16 @@ struct EnumValueInfo {
std::tie(Other.Name, Other.Value, Other.ValueExpr);
}
- StringRef Name;
+ StringRef Name = {};
// The computed value of the enumeration constant. This could be the result of
// evaluating the ValueExpr, or it could be automatically generated according
// to C rules.
- StringRef Value;
+ StringRef Value = {};
// Stores the user-supplied initialization expression for this enumeration
// constant. This will be empty for implicit enumeration values.
- StringRef ValueExpr;
+ StringRef ValueExpr = {};
/// Comment description of this field.
OwningVec<CommentInfo> Description;
@@ -706,7 +707,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::ArrayRef<EnumValueInfo> Members = {}; // List of enum members.
};
struct ConceptInfo : public SymbolInfo, public llvm::ilist_node<ConceptInfo> {
@@ -715,9 +716,9 @@ struct ConceptInfo : public SymbolInfo, public llvm::ilist_node<ConceptInfo> {
void merge(ConceptInfo &&I);
- bool IsType;
+ bool IsType = false;
TemplateInfo Template;
- StringRef ConstraintExpression;
+ StringRef ConstraintExpression = {};
};
struct Index : public Reference {
>From d0a664b0e648986847e32f745602c720ae401ad3 Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Tue, 21 Apr 2026 21:26:12 +0000
Subject: [PATCH 07/11] Format comments
---
clang-tools-extra/clang-doc/Representation.h | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index 91ed25cd94939..68bcbd2b04fa8 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -611,16 +611,15 @@ struct RecordInfo : public SymbolInfo {
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).
+ {}; // List of info about record members.
+ llvm::ArrayRef<Reference> Parents =
+ {}; // List of base/parent records (does not include virtual parents).
llvm::ArrayRef<Reference> VirtualParents =
{}; // List of virtual base/parent records.
llvm::ArrayRef<BaseRecordInfo> Bases =
- {}; // List of base/parent records; this includes
- // inherited methods and attributes
+ {}; // List of base/parent records; this includes inherited methods and
+ // attributes
llvm::ArrayRef<FriendInfo> Friends = {};
>From 8e7f88f88c7a75a7e0c3a715307b6137e043d720 Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Wed, 22 Apr 2026 00:15:01 +0000
Subject: [PATCH 08/11] Deep copy CommentInfo
---
clang-tools-extra/clang-doc/BitcodeReader.cpp | 2 +-
.../clang-doc/Representation.cpp | 22 +++++++++++++++++++
clang-tools-extra/clang-doc/Representation.h | 13 +++++++++++
3 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp
index c5e848ae4c28d..6e035b0a8d431 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -541,7 +541,7 @@ llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, CommentInfo *I) {
[&]() -> llvm::Error {
if (!LocalChildren.empty())
I->Children =
- allocateArray<CommentInfo>(LocalChildren, TransientArena);
+ deepCopyArray<CommentInfo>(LocalChildren, TransientArena);
if (!AttrKeys.empty())
I->AttrKeys = allocateArray(AttrKeys, TransientArena);
if (!AttrValues.empty())
diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp
index 1f01169b4c638..6798ba22e4547 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -197,6 +197,28 @@ 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) {
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index 68bcbd2b04fa8..07499f5df0db5 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -91,6 +91,18 @@ llvm::ArrayRef<T> allocateArray(llvm::ArrayRef<T> V,
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 = static_cast<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 *;
@@ -180,6 +192,7 @@ 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;
>From f94e7ccd0d70c9dbd399f700023e4967a54598ae Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Thu, 23 Apr 2026 17:00:20 +0000
Subject: [PATCH 09/11] Avoid accessing member after move
---
clang-tools-extra/clang-doc/Representation.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp
index 6798ba22e4547..11740c23bb132 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -315,11 +315,11 @@ void SymbolInfo::merge(SymbolInfo &&Other) {
assert(mergeable(Other));
if (!DefLoc)
DefLoc = std::move(Other.DefLoc);
+ if (MangledName.empty())
+ MangledName = std::move(Other.MangledName);
// Unconditionally extend the list of locations, since we want all of them.
mergeUnkeyed(Loc, std::move(Other.Loc));
mergeBase(std::move(Other));
- if (MangledName.empty())
- MangledName = std::move(Other.MangledName);
}
NamespaceInfo::NamespaceInfo(SymbolID USR, StringRef Name, StringRef Path)
@@ -361,9 +361,9 @@ void RecordInfo::merge(RecordInfo &&Other) {
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)
Template = Other.Template;
+ SymbolInfo::merge(std::move(Other));
}
void EnumInfo::merge(EnumInfo &&Other) {
@@ -387,9 +387,9 @@ void FunctionInfo::merge(FunctionInfo &&Other) {
Parent = std::move(Other.Parent);
if (Params.empty())
Params = std::move(Other.Params);
- SymbolInfo::merge(std::move(Other));
if (!Template)
Template = Other.Template;
+ SymbolInfo::merge(std::move(Other));
}
void TypedefInfo::merge(TypedefInfo &&Other) {
>From f4e253f31ea5fbe3a2f5c240c960ba6e3a7cc8fc Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Thu, 23 Apr 2026 17:34:11 +0000
Subject: [PATCH 10/11] Forward argument over using std::move
---
clang-tools-extra/clang-doc/BitcodeReader.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp
index 6e035b0a8d431..8b95f2318487b 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -12,6 +12,7 @@
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>
+#include <utility>
namespace clang {
namespace doc {
@@ -1080,7 +1081,7 @@ static void addChild(Target I, Child &&R) {
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));
+ auto *Node = allocatePtr<BareChild>(std::forward<Child>(R));
getList(I->Children, Node).push_back(*Node);
return;
}
>From 75f7c6fca1b1b476c49f0feb75d85bfd363aba2c Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Fri, 24 Apr 2026 20:51:08 +0000
Subject: [PATCH 11/11] Try to use indirect CommentInfo data
---
clang-tools-extra/clang-doc/BitcodeReader.cpp | 3 ++-
clang-tools-extra/clang-doc/BitcodeWriter.cpp | 20 ++++++++--------
clang-tools-extra/clang-doc/JSONGenerator.cpp | 4 ++--
clang-tools-extra/clang-doc/MDGenerator.cpp | 12 +++++-----
clang-tools-extra/clang-doc/Representation.h | 23 +++++++++++++++----
clang-tools-extra/clang-doc/Serialize.cpp | 18 +++++++++------
clang-tools-extra/clang-doc/YAMLGenerator.cpp | 7 ++++++
.../unittests/clang-doc/BitcodeTest.cpp | 9 +++++---
.../unittests/clang-doc/ClangDocTest.cpp | 6 ++---
.../unittests/clang-doc/ClangDocTest.h | 4 ++--
.../unittests/clang-doc/MDGeneratorTest.cpp | 3 ++-
.../unittests/clang-doc/MergeTest.cpp | 9 +++++---
.../unittests/clang-doc/YAMLGeneratorTest.cpp | 7 +++---
13 files changed, 80 insertions(+), 45 deletions(-)
diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp
index 8b95f2318487b..7696209fd6f80 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -886,7 +886,8 @@ template <typename T> static llvm::Expected<CommentInfo *> getCommentInfo(T I) {
using Pointee = std::remove_pointer_t<T>;
if constexpr (has_description<Pointee>::value) {
auto *NewComment = allocatePtr<CommentInfo>();
- I->Description.push_back(*NewComment);
+ auto *Node = allocatePtr<CommentInfoNode>(NewComment);
+ I->Description.push_back(*Node);
return NewComment;
}
}
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
index 1aa1632f7bf9d..24cbebf737cf3 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -495,7 +495,7 @@ void ClangDocBitcodeWriter::emitBlock(const FriendInfo &R) {
if (R.ReturnType)
emitBlock(*R.ReturnType);
for (const auto &CI : R.Description)
- emitBlock(CI);
+ emitBlock(*CI.Ptr);
}
void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) {
@@ -512,7 +512,7 @@ void ClangDocBitcodeWriter::emitBlock(const TypedefInfo &T) {
for (const auto &N : T.Namespace)
emitBlock(N, FieldId::F_namespace);
for (const auto &CI : T.Description)
- emitBlock(CI);
+ emitBlock(*CI.Ptr);
if (T.DefLoc)
emitRecord(*T.DefLoc, TYPEDEF_DEFLOCATION);
if (T.Template)
@@ -540,7 +540,7 @@ void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) {
emitRecord(T.IsTemplate, MEMBER_TYPE_IS_TEMPLATE);
emitRecord(T.IsTemplate, MEMBER_TYPE_IS_TEMPLATE);
for (const auto &CI : T.Description)
- emitBlock(CI);
+ emitBlock(*CI.Ptr);
}
void ClangDocBitcodeWriter::emitBlock(const CommentInfo &I) {
@@ -575,7 +575,7 @@ void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
for (const auto &N : I.Namespace)
emitBlock(N, FieldId::F_namespace);
for (const auto &CI : I.Description)
- emitBlock(CI);
+ emitBlock(*CI.Ptr);
for (const auto &C : I.Children.Namespaces)
emitBlock(C, FieldId::F_child_namespace);
for (const auto &C : I.Children.Records)
@@ -599,7 +599,7 @@ void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {
for (const auto &N : I.Namespace)
emitBlock(N, FieldId::F_namespace);
for (const auto &CI : I.Description)
- emitBlock(CI);
+ emitBlock(*CI.Ptr);
if (I.DefLoc)
emitRecord(*I.DefLoc, ENUM_DEFLOCATION);
for (const auto &L : I.Loc)
@@ -617,7 +617,7 @@ void ClangDocBitcodeWriter::emitBlock(const EnumValueInfo &I) {
emitRecord(I.Value, ENUM_VALUE_VALUE);
emitRecord(I.ValueExpr, ENUM_VALUE_EXPR);
for (const auto &CI : I.Description)
- emitBlock(CI);
+ emitBlock(*CI.Ptr);
}
void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
@@ -630,7 +630,7 @@ void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
for (const auto &N : I.Namespace)
emitBlock(N, FieldId::F_namespace);
for (const auto &CI : I.Description)
- emitBlock(CI);
+ emitBlock(*CI.Ptr);
if (I.DefLoc)
emitRecord(*I.DefLoc, RECORD_DEFLOCATION);
for (const auto &L : I.Loc)
@@ -681,7 +681,7 @@ void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {
for (const auto &N : I.Namespace)
emitBlock(N, FieldId::F_namespace);
for (const auto &CI : I.Description)
- emitBlock(CI);
+ emitBlock(*CI.Ptr);
emitRecord(I.Access, FUNCTION_ACCESS);
emitRecord(I.IsMethod, FUNCTION_IS_METHOD);
emitRecord(I.IsStatic, FUNCTION_IS_STATIC);
@@ -702,7 +702,7 @@ void ClangDocBitcodeWriter::emitBlock(const ConceptInfo &I) {
emitRecord(I.USR, CONCEPT_USR);
emitRecord(I.Name, CONCEPT_NAME);
for (const auto &CI : I.Description)
- emitBlock(CI);
+ emitBlock(*CI.Ptr);
emitRecord(I.IsType, CONCEPT_IS_TYPE);
emitRecord(I.ConstraintExpression, CONCEPT_CONSTRAINT_EXPRESSION);
emitBlock(I.Template);
@@ -745,7 +745,7 @@ void ClangDocBitcodeWriter::emitBlock(const VarInfo &I) {
for (const auto &N : I.Namespace)
emitBlock(N, FieldId::F_namespace);
for (const auto &CI : I.Description)
- emitBlock(CI);
+ emitBlock(*CI.Ptr);
if (I.DefLoc)
emitRecord(*I.DefLoc, VAR_DEFLOCATION);
emitRecord(I.IsStatic, VAR_IS_STATIC);
diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp
index 4854c6114b760..72d7dac445360 100644
--- a/clang-tools-extra/clang-doc/JSONGenerator.cpp
+++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp
@@ -384,13 +384,13 @@ void JSONGenerator::generateContext(const Info &I, Object &Obj) {
ContextArrayRef.back().getAsObject()->insert({"End", true});
}
-static void serializeDescription(const OwningVec<CommentInfo> &Description,
+static void serializeDescription(const OwningVec<CommentInfoNode> &Description,
json::Object &Obj, StringRef Key = "") {
if (Description.empty())
return;
// Skip straight to the FullComment's children
- auto &Comments = Description.front().Children;
+ auto &Comments = Description.front().Ptr->Children;
Object DescriptionObj = Object();
for (const auto &CommentInfo : Comments) {
json::Value Comment = serializeComment(CommentInfo, DescriptionObj);
diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp b/clang-tools-extra/clang-doc/MDGenerator.cpp
index 9ccb7a8ccd633..eddc08f04182f 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -81,9 +81,9 @@ class TableCommentWriter {
public:
explicit TableCommentWriter(llvm::raw_ostream &OS) : OS(OS) {}
- void write(const OwningVec<CommentInfo> &Comments) {
+ void write(const OwningVec<CommentInfoNode> &Comments) {
for (const auto &C : Comments)
- writeTableSafeComment(C);
+ writeTableSafeComment(*C.Ptr);
if (!Started)
OS << "--";
@@ -271,7 +271,7 @@ static void genMarkdown(const ClangDocContext &CDCtx, const EnumInfo &I,
maybeWriteSourceFileRef(OS, CDCtx, I.DefLoc);
for (const auto &C : I.Description)
- writeDescription(C, OS);
+ writeDescription(*C.Ptr, OS);
}
static void genMarkdown(const ClangDocContext &CDCtx, const FunctionInfo &I,
@@ -296,7 +296,7 @@ static void genMarkdown(const ClangDocContext &CDCtx, const FunctionInfo &I,
maybeWriteSourceFileRef(OS, CDCtx, I.DefLoc);
for (const auto &C : I.Description)
- writeDescription(C, OS);
+ writeDescription(*C.Ptr, OS);
}
static void genMarkdown(const ClangDocContext &CDCtx, const NamespaceInfo &I,
@@ -309,7 +309,7 @@ static void genMarkdown(const ClangDocContext &CDCtx, const NamespaceInfo &I,
if (!I.Description.empty()) {
for (const auto &C : I.Description)
- writeDescription(C, OS);
+ writeDescription(*C.Ptr, OS);
writeNewLine(OS);
}
@@ -357,7 +357,7 @@ static void genMarkdown(const ClangDocContext &CDCtx, const RecordInfo &I,
if (!I.Description.empty()) {
for (const auto &C : I.Description)
- writeDescription(C, OS);
+ writeDescription(*C.Ptr, OS);
writeNewLine(OS);
}
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index 07499f5df0db5..31ad078954b98 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -187,8 +187,17 @@ enum OutputFormatTy { md, yaml, html, json, md_mustache };
CommentKind stringToCommentKind(llvm::StringRef KindStr);
llvm::StringRef commentKindToString(CommentKind Kind);
+struct CommentInfo;
+
+struct CommentInfoNode : public llvm::ilist_node<CommentInfoNode> {
+ CommentInfoNode(CommentInfo* P) : Ptr(P) {}
+ CommentInfo* Ptr;
+
+ bool operator==(const CommentInfoNode &Other) const;
+};
+
// A representation of a parsed comment.
-struct CommentInfo : public llvm::ilist_node<CommentInfo> {
+struct CommentInfo {
CommentInfo() = default;
CommentInfo(const CommentInfo &Other) = default;
CommentInfo &operator=(const CommentInfo &Other) = default;
@@ -240,6 +249,12 @@ struct CommentInfo : public llvm::ilist_node<CommentInfo> {
// (for (T)ParamCommand).
};
+inline bool CommentInfoNode::operator==(const CommentInfoNode &Other) const {
+ if (!Ptr || !Other.Ptr)
+ return Ptr == Other.Ptr;
+ return *Ptr == *Other.Ptr;
+}
+
struct Reference : public llvm::ilist_node<Reference> {
// This variant (that takes no qualified name parameter) uses the Name as the
// QualName (very useful in unit tests to reduce verbosity). This can't use an
@@ -424,7 +439,7 @@ struct MemberTypeInfo : public FieldTypeInfo {
Other.Description.begin(), Other.Description.end());
}
- OwningVec<CommentInfo> Description;
+ OwningVec<CommentInfoNode> Description;
// Access level associated with this info (public, protected, private, none).
// AS_public is set as default because the bitcode writer requires the enum
@@ -508,7 +523,7 @@ struct Info {
InfoType IT = InfoType::IT_default;
// Comment description of this decl.
- OwningVec<CommentInfo> Description;
+ OwningVec<CommentInfoNode> Description;
};
inline Context::Context(const Info &I)
@@ -700,7 +715,7 @@ struct EnumValueInfo {
StringRef ValueExpr = {};
/// Comment description of this field.
- OwningVec<CommentInfo> Description;
+ OwningVec<CommentInfoNode> Description;
};
// TODO: Expand to allow for documenting templating.
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index e6ec6dee58939..ebb164475aea3 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -613,8 +613,9 @@ void Serializer::parseEnumerators(EnumInfo &I, const EnumDecl *D) {
Comment->setAttached();
if (comments::FullComment *Fc = Comment->parse(Context, nullptr, E)) {
CommentInfo *NewCI = allocatePtr<CommentInfo>();
- Member.Description.push_back(*NewCI);
- parseFullComment(Fc, Member.Description.back());
+ auto *Node = allocatePtr<CommentInfoNode>(NewCI);
+ Member.Description.push_back(*Node);
+ parseFullComment(Fc, *NewCI);
}
}
}
@@ -796,8 +797,9 @@ void Serializer::populateInfo(Info &I, const T *D, const FullComment *C,
if (C) {
CommentInfo *NewCI = allocatePtr<CommentInfo>();
- I.Description.push_back(*NewCI);
- parseFullComment(C, I.Description.back());
+ auto *Node = allocatePtr<CommentInfoNode>(NewCI);
+ I.Description.push_back(*Node);
+ parseFullComment(C, *NewCI);
}
}
@@ -933,8 +935,9 @@ 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);
- parseFullComment(Fc, I.Description.back());
+ auto *Node = allocatePtr<CommentInfoNode>(NewCI);
+ I.Description.push_back(*Node);
+ parseFullComment(Fc, *NewCI);
}
}
@@ -1218,7 +1221,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);
+ auto *Node = allocatePtr<CommentInfoNode>(NewCI);
+ Info.Description.push_back(*Node);
parseFullComment(Fc, *NewCI);
}
}
diff --git a/clang-tools-extra/clang-doc/YAMLGenerator.cpp b/clang-tools-extra/clang-doc/YAMLGenerator.cpp
index b5c43837f9505..9401fac10a020 100644
--- a/clang-tools-extra/clang-doc/YAMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/YAMLGenerator.cpp
@@ -498,6 +498,13 @@ template <> struct MappingTraits<TemplateInfo> {
}
};
+template <> struct MappingTraits<clang::doc::CommentInfoNode> {
+ static void mapping(IO &IO, clang::doc::CommentInfoNode &N) {
+ if (N.Ptr)
+ commentInfoMapping(IO, *N.Ptr);
+ }
+};
+
template <> struct MappingTraits<CommentInfo> {
static void mapping(IO &IO, CommentInfo &I) { commentInfoMapping(IO, I); }
};
diff --git a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
index 81de4ff2f6381..96a08ff46428c 100644
--- a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
@@ -112,7 +112,8 @@ TEST_F(BitcodeTest, emitRecordInfoBitcode) {
CommentInfo TopCommentChildren[] = {
CommentInfo(CommentKind::CK_ParagraphComment, BriefChildren)};
CommentInfo TopComment(CommentKind::CK_FullComment, TopCommentChildren);
- BM.Description.push_back(TopComment);
+ CommentInfoNode TopCommentNode(&TopComment);
+ BM.Description.push_back(TopCommentNode);
MemberTypeInfo BMem[] = {std::move(BM)};
B.Members = llvm::ArrayRef(BMem);
BaseRecordInfo Bases[] = {std::move(B)};
@@ -226,7 +227,8 @@ TEST_F(BitcodeTest, emitTypedefInfoBitcode) {
CommentInfo(CommentKind::CK_ParagraphComment, BlankChildren)};
CommentInfo Top(CommentKind::CK_FullComment, TopChildren);
- I.Description.push_back(Top);
+ CommentInfoNode TopNode(&Top);
+ I.Description.push_back(TopNode);
std::string WriteResult = writeInfo(&I, this->Diags);
EXPECT_TRUE(WriteResult.size() > 0);
@@ -324,7 +326,8 @@ TEST_F(BitcodeTest, emitInfoWithCommentBitcode) {
Verbatim, ParamOut, ParamIn, Return};
CommentInfo Top(CommentKind::CK_FullComment, TopChildren);
- F.Description.push_back(Top);
+ CommentInfoNode TopNode(&Top);
+ F.Description.push_back(TopNode);
std::string WriteResult = writeInfo(&F, this->Diags);
EXPECT_TRUE(WriteResult.size() > 0);
diff --git a/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp b/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
index 2e5466c172a18..0ef352f742b12 100644
--- a/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
@@ -96,12 +96,12 @@ void CheckCommentInfo(ArrayRef<CommentInfo> Expected,
EXPECT_TRUE(ItE == Expected.end() && ItA == Actual.end());
}
-void CheckCommentInfo(const OwningVec<CommentInfo> &Expected,
- const OwningVec<CommentInfo> &Actual) {
+void CheckCommentInfo(const OwningVec<CommentInfoNode> &Expected,
+ const OwningVec<CommentInfoNode> &Actual) {
auto ItE = Expected.begin();
auto ItA = Actual.begin();
while (ItE != Expected.end() && ItA != Actual.end()) {
- CheckCommentInfo(*ItE, *ItA);
+ CheckCommentInfo(*ItE->Ptr, *ItA->Ptr);
++ItE;
++ItA;
}
diff --git a/clang-tools-extra/unittests/clang-doc/ClangDocTest.h b/clang-tools-extra/unittests/clang-doc/ClangDocTest.h
index 1525b1ed382ce..62062be9645f3 100644
--- a/clang-tools-extra/unittests/clang-doc/ClangDocTest.h
+++ b/clang-tools-extra/unittests/clang-doc/ClangDocTest.h
@@ -33,8 +33,8 @@ TypedefInfo *InfoAsTypedef(Info *I);
void CheckCommentInfo(ArrayRef<CommentInfo> Expected,
ArrayRef<CommentInfo> Actual);
-void CheckCommentInfo(const OwningVec<CommentInfo> &Expected,
- const OwningVec<CommentInfo> &Actual);
+void CheckCommentInfo(const OwningVec<CommentInfoNode> &Expected,
+ const OwningVec<CommentInfoNode> &Actual);
void CheckReference(const Reference &Expected, const Reference &Actual);
void CheckTypeInfo(const TypeInfo *Expected, const TypeInfo *Actual);
void CheckFieldTypeInfo(const FieldTypeInfo *Expected,
diff --git a/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
index 2dc472a352fd8..cdec4f0f1685d 100644
--- a/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
@@ -370,7 +370,8 @@ TEST_F(MDGeneratorTest, emitCommentMD) {
Top.Children = TopChildren;
- I.Description.push_back(Top);
+ CommentInfoNode TopNode(&Top);
+ I.Description.push_back(TopNode);
auto G = getMDGenerator();
assert(G);
diff --git a/clang-tools-extra/unittests/clang-doc/MergeTest.cpp b/clang-tools-extra/unittests/clang-doc/MergeTest.cpp
index 50374743681e3..3c351b4aef963 100644
--- a/clang-tools-extra/unittests/clang-doc/MergeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/MergeTest.cpp
@@ -221,7 +221,8 @@ TEST_F(MergeTest, mergeFunctionInfos) {
CommentInfo OnePara[] = {
CommentInfo(CommentKind::CK_ParagraphComment, OneText)};
CommentInfo TopOne(CommentKind::CK_FullComment, OnePara);
- One.Description.push_back(TopOne);
+ CommentInfoNode TopOneNode(&TopOne);
+ One.Description.push_back(TopOneNode);
FunctionInfo Two;
Two.Name = "f";
@@ -241,7 +242,8 @@ TEST_F(MergeTest, mergeFunctionInfos) {
CommentInfo TwoPara[] = {
CommentInfo(CommentKind::CK_ParagraphComment, TwoText)};
CommentInfo TopTwo(CommentKind::CK_FullComment, TwoPara);
- Two.Description.push_back(TopTwo);
+ CommentInfoNode TopTwoNode(&TopTwo);
+ Two.Description.push_back(TopTwoNode);
OwningPtrVec<Info> Infos;
Infos.push_back(&One);
@@ -268,7 +270,8 @@ TEST_F(MergeTest, mergeFunctionInfos) {
CommentInfo ExpectedPara[] = {
CommentInfo(CommentKind::CK_ParagraphComment, ExpectedText)};
CommentInfo TopE(CommentKind::CK_FullComment, ExpectedPara);
- Expected.Description.push_back(TopE);
+ CommentInfoNode TopENode(&TopE);
+ Expected.Description.push_back(TopENode);
auto Actual = mergeInfos(Infos);
assert(Actual);
diff --git a/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
index 6f4b724bd9427..88d09ad5b7cec 100644
--- a/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
@@ -106,7 +106,8 @@ TEST_F(YAMLGeneratorTest, emitRecordYAML) {
CommentInfo TopCommentChildren[] = {
CommentInfo(CommentKind::CK_ParagraphComment, BriefChildren)};
CommentInfo TopComment(CommentKind::CK_FullComment, TopCommentChildren);
- M.Description.push_back(TopComment);
+ CommentInfoNode TopCommentNode(&TopComment);
+ M.Description.push_back(TopCommentNode);
MemberTypeInfo MemArr[] = {std::move(M)};
I.Members = llvm::ArrayRef(MemArr);
@@ -473,8 +474,8 @@ TEST_F(YAMLGeneratorTest, emitCommentYAML) {
CommentInfo TopChildren[] = {BlankLine, Brief, Extended, HTML,
Verbatim, ParamOut, ParamIn, Return};
CommentInfo Top(CommentKind::CK_FullComment, TopChildren);
-
- I.Description.push_back(Top);
+ CommentInfoNode TopNode(&Top);
+ I.Description.push_back(TopNode);
auto G = getYAMLGenerator();
assert(G);
More information about the cfe-commits
mailing list