This patch allocates the NamespaceInfo types in the local arenas, and adapts the merging logic for the new list type and its children. Memory use and performance improve slightly. Micro-benchmarks show a regression in merge operations due to the more complex list operations. ## Build Clang-Doc Documentation | Metric | Baseline | Prev | This | Culm% | Seq% | | :--- | :--- | :--- | :--- | :--- | :--- | | Time | 920.5s | 1009.2s | 1002.4s | +8.9% | -0.7% | | Memory | 86.0G | 43.2G | 43.9G | -49.0% | +1.6% | ## Microbenchmarks (Filtered for >1% Delta) | Benchmark | Baseline | Prev | This | Culm% | Seq% | | :--- | :--- | :--- | :--- | :--- | :--- | | BM_BitcodeReader_Scale/10 | 67.9us | 69.7us | 69.3us | +1.9% | -0.7% | | BM_BitcodeReader_Scale/10000 | 70.5ms | 22.3ms | 24.8ms | -64.8% | +11.4% | | BM_BitcodeReader_Scale/4096 | 23.2ms | 4.7ms | 4.4ms | -80.9% | -5.7% | | BM_BitcodeReader_Scale/512 | 509.4us | 558.7us | 540.2us | +6.0% | -3.3% | | BM_BitcodeReader_Scale/64 | 114.8us | 119.2us | 117.0us | +1.9% | -1.8% | | BM_EmitInfoFunction | 1.6us | 1.6us | 1.6us | -1.1% | +0.8% | | BM_Index_Insertion/10 | 2.3us | 4.2us | 3.7us | +61.7% | -11.3% | | BM_Index_Insertion/10000 | 3.1ms | 5.4ms | 4.9ms | +56.8% | -9.1% | | BM_Index_Insertion/4096 | 1.3ms | 2.2ms | 2.0ms | +54.5% | -8.2% | | BM_Index_Insertion/512 | 153.6us | 259.6us | 236.7us | +54.1% | -8.8% | | BM_Index_Insertion/64 | 18.1us | 30.7us | 27.9us | +54.5% | -9.0% | | BM_JSONGenerator_Scale/10 | 36.8us | 37.6us | 36.6us | -0.7% | -2.7% | | BM_JSONGenerator_Scale/4096 | 33.7ms | 34.3ms | 34.2ms | +1.4% | -0.3% | | BM_JSONGenerator_Scale/64 | 222.4us | 225.6us | 220.2us | -1.0% | -2.4% | | BM_Mapper_Scale/10 | 2.5ms | 2.5ms | 2.5ms | -1.4% | -1.7% | | BM_Mapper_Scale/10000 | 104.3ms | 109.3ms | 105.9ms | +1.6% | -3.1% | | BM_Mapper_Scale/4096 | 44.3ms | 43.9ms | 44.7ms | +0.8% | +1.8% | | BM_Mapper_Scale/512 | 7.6ms | 7.6ms | 7.6ms | +0.8% | +1.2% | | BM_MergeInfos_Scale/10000 | 12.2ms | 1.6ms | 2.0ms | -83.6% | +28.7% | | BM_MergeInfos_Scale/2 | 1.9us | 1.7us | 1.7us | -8.1% | +0.9% | | BM_MergeInfos_Scale/4096 | 2.8ms | 520.5us | 557.4us | -79.9% | +7.1% | | BM_MergeInfos_Scale/512 | 68.9us | 37.9us | 39.9us | -42.0% | +5.3% | | BM_MergeInfos_Scale/64 | 10.3us | 6.3us | 6.5us | -36.7% | +2.7% | | BM_MergeInfos_Scale/8 | 2.8us | 2.2us | 2.2us | -20.7% | +1.2% | | BM_SerializeFunctionInfo | 25.5us | 25.8us | 26.1us | +2.1% | +1.1% |
278 lines
7.0 KiB
C++
278 lines
7.0 KiB
C++
#include "ClangDocTest.h"
|
|
#include "Generators.h"
|
|
#include "Representation.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
namespace clang {
|
|
namespace doc {
|
|
|
|
static std::unique_ptr<Generator> getJSONGenerator() {
|
|
auto G = doc::findGeneratorByName("json");
|
|
if (!G)
|
|
return nullptr;
|
|
return std::move(G.get());
|
|
}
|
|
|
|
class JSONGeneratorTest : public ClangDocContextTest {};
|
|
|
|
TEST_F(JSONGeneratorTest, emitRecordJSON) {
|
|
RecordInfo I;
|
|
I.Name = "Foo";
|
|
I.IsTypeDef = false;
|
|
I.Namespace.emplace_back(EmptySID, "GlobalNamespace", InfoType::IT_namespace);
|
|
I.Path = "GlobalNamespace";
|
|
I.DefLoc = Location(1, 1, "main.cpp");
|
|
I.TagType = TagTypeKind::Class;
|
|
|
|
I.Template = TemplateInfo();
|
|
I.Template->Params.emplace_back("class T");
|
|
|
|
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";
|
|
|
|
I.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_protected);
|
|
|
|
I.Bases.emplace_back(EmptySID, "F", "path/to/F", true,
|
|
AccessSpecifier::AS_public, true);
|
|
I.Bases.back().Children.Functions.emplace_back();
|
|
I.Bases.back().Children.Functions.back().Name = "InheritedFunctionOne";
|
|
I.Bases.back().Members.emplace_back(TypeInfo("int"), "N",
|
|
AccessSpecifier::AS_public);
|
|
|
|
// F is in the global namespace
|
|
I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, "");
|
|
I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record,
|
|
"path::to::G::G", "path/to/G");
|
|
|
|
I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
|
|
"path::to::A::r::ChildStruct", "path/to/A/r");
|
|
I.Children.Functions.emplace_back();
|
|
I.Children.Functions.back().Name = "OneFunction";
|
|
|
|
auto G = getJSONGenerator();
|
|
assert(G);
|
|
std::string Buffer;
|
|
llvm::raw_string_ostream Actual(Buffer);
|
|
auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
|
|
assert(!Err);
|
|
std::string Expected = R"raw({
|
|
"Bases": [
|
|
{
|
|
"Access": "public",
|
|
"End": true,
|
|
"HasMembers": true,
|
|
"HasPublicMembers": true,
|
|
"HasPublicMethods": true,
|
|
"InfoType": "record",
|
|
"IsParent": true,
|
|
"IsTypedef": false,
|
|
"IsVirtual": true,
|
|
"MangledName": "",
|
|
"Name": "F",
|
|
"Path": "path/to/F",
|
|
"PublicMembers": [
|
|
{
|
|
"IsStatic": false,
|
|
"Name": "N",
|
|
"Type": "int"
|
|
}
|
|
],
|
|
"PublicMethods": [
|
|
{
|
|
"InfoType": "function",
|
|
"IsStatic": false,
|
|
"Name": "InheritedFunctionOne",
|
|
"ReturnType": {
|
|
"IsBuiltIn": false,
|
|
"IsTemplate": false,
|
|
"Name": "",
|
|
"QualName": "",
|
|
"USR": "0000000000000000000000000000000000000000"
|
|
}
|
|
}
|
|
],
|
|
"TagType": "struct"
|
|
}
|
|
],
|
|
"Enums": [
|
|
{
|
|
"End": true,
|
|
"InfoType": "enum",
|
|
"Members": [
|
|
{
|
|
"End": true,
|
|
"Name": "RED",
|
|
"Value": "0"
|
|
}
|
|
],
|
|
"Name": "Color",
|
|
"Scoped": false
|
|
}
|
|
],
|
|
"HasEnums": true,
|
|
"HasMembers": true,
|
|
"HasParents": true,
|
|
"HasProtectedMembers": true,
|
|
"HasPublicMethods": true,
|
|
"HasRecords": true,
|
|
"HasVirtualParents": true,
|
|
"InfoType": "record",
|
|
"IsTypedef": false,
|
|
"Location": {
|
|
"Filename": "main.cpp",
|
|
"LineNumber": 1
|
|
},
|
|
"MangledName": "",
|
|
"Name": "Foo",
|
|
"Namespace": [
|
|
"GlobalNamespace"
|
|
],
|
|
"Parents": [
|
|
{
|
|
"End": true,
|
|
"Name": "F",
|
|
"QualName": "",
|
|
"USR": "0000000000000000000000000000000000000000"
|
|
}
|
|
],
|
|
"Path": "GlobalNamespace",
|
|
"ProtectedMembers": [
|
|
{
|
|
"IsStatic": false,
|
|
"Name": "X",
|
|
"Type": "int"
|
|
}
|
|
],
|
|
"PublicMethods": [
|
|
{
|
|
"InfoType": "function",
|
|
"IsStatic": false,
|
|
"Name": "OneFunction",
|
|
"ReturnType": {
|
|
"IsBuiltIn": false,
|
|
"IsTemplate": false,
|
|
"Name": "",
|
|
"QualName": "",
|
|
"USR": "0000000000000000000000000000000000000000"
|
|
}
|
|
}
|
|
],
|
|
"Records": [
|
|
{
|
|
"End": true,
|
|
"Name": "ChildStruct",
|
|
"Path": "path/to/A/r",
|
|
"QualName": "path::to::A::r::ChildStruct",
|
|
"USR": "0000000000000000000000000000000000000000"
|
|
}
|
|
],
|
|
"TagType": "class",
|
|
"Template": {
|
|
"Parameters": [
|
|
{
|
|
"End": true,
|
|
"Param": "class T"
|
|
}
|
|
],
|
|
"VerticalDisplay": false
|
|
},
|
|
"VirtualParents": [
|
|
{
|
|
"End": true,
|
|
"Name": "G",
|
|
"Path": "path/to/G",
|
|
"QualName": "path::to::G::G",
|
|
"USR": "0000000000000000000000000000000000000000"
|
|
}
|
|
]
|
|
})raw";
|
|
EXPECT_EQ(Expected, Actual.str());
|
|
}
|
|
|
|
TEST_F(JSONGeneratorTest, emitNamespaceJSON) {
|
|
NamespaceInfo I;
|
|
I.Name = "Namespace";
|
|
I.Path = "path/to/A";
|
|
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
|
|
|
|
Reference NewNamespace(EmptySID, "ChildNamespace", InfoType::IT_namespace,
|
|
"path::to::A::Namespace::ChildNamespace",
|
|
"path/to/A/Namespace");
|
|
I.Children.Namespaces.push_back(NewNamespace);
|
|
I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
|
|
"path::to::A::Namespace::ChildStruct",
|
|
"path/to/A/Namespace");
|
|
I.Children.Functions.emplace_back();
|
|
I.Children.Functions.back().Name = "OneFunction";
|
|
I.Children.Functions.back().Access = AccessSpecifier::AS_none;
|
|
I.Children.Enums.emplace_back();
|
|
I.Children.Enums.back().Name = "OneEnum";
|
|
|
|
auto G = getJSONGenerator();
|
|
assert(G);
|
|
std::string Buffer;
|
|
llvm::raw_string_ostream Actual(Buffer);
|
|
auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
|
|
assert(!Err);
|
|
std::string Expected = R"raw({
|
|
"Enums": [
|
|
{
|
|
"End": true,
|
|
"InfoType": "enum",
|
|
"Name": "OneEnum",
|
|
"Scoped": false
|
|
}
|
|
],
|
|
"Functions": [
|
|
{
|
|
"End": true,
|
|
"InfoType": "function",
|
|
"IsStatic": false,
|
|
"Name": "OneFunction",
|
|
"ReturnType": {
|
|
"IsBuiltIn": false,
|
|
"IsTemplate": false,
|
|
"Name": "",
|
|
"QualName": "",
|
|
"USR": "0000000000000000000000000000000000000000"
|
|
}
|
|
}
|
|
],
|
|
"HasEnums": true,
|
|
"HasFunctions": true,
|
|
"HasNamespaces": true,
|
|
"HasRecords": true,
|
|
"InfoType": "namespace",
|
|
"Name": "Global Namespace",
|
|
"Namespace": [
|
|
"A"
|
|
],
|
|
"Namespaces": [
|
|
{
|
|
"End": true,
|
|
"Name": "ChildNamespace",
|
|
"Path": "path/to/A/Namespace",
|
|
"QualName": "path::to::A::Namespace::ChildNamespace",
|
|
"USR": "0000000000000000000000000000000000000000"
|
|
}
|
|
],
|
|
"Path": "path/to/A",
|
|
"Records": [
|
|
{
|
|
"End": true,
|
|
"Name": "ChildStruct",
|
|
"Path": "path/to/A/Namespace",
|
|
"QualName": "path::to::A::Namespace::ChildStruct",
|
|
"USR": "0000000000000000000000000000000000000000"
|
|
}
|
|
]
|
|
})raw";
|
|
EXPECT_EQ(Expected, Actual.str());
|
|
}
|
|
} // namespace doc
|
|
} // namespace clang
|