Index: clang-tools-extra/clang-doc/Serialize.cpp =================================================================== --- clang-tools-extra/clang-doc/Serialize.cpp +++ clang-tools-extra/clang-doc/Serialize.cpp @@ -331,6 +331,14 @@ Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), InfoType::IT_enum); } + // The global namespace should be added to the list of namespaces if the decl + // corresponds to a Record and if it doesn't have any namespace (because this + // means it's in the global namespace). Also if its outermost namespace is a + // record because that record matches the previous condition mentioned. + if ((Namespaces.empty() && dyn_cast(D)) || + (!Namespaces.empty() && Namespaces.back().RefType == InfoType::IT_record)) + Namespaces.emplace_back(SymbolID(), "GlobalNamespace", + InfoType::IT_namespace); } template @@ -424,16 +432,6 @@ } I->Path = getInfoRelativePath(I->Namespace); - if (I->Namespace.empty()) { - auto ParentI = std::make_unique(); - ParentI->USR = SymbolID(); - ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record, - getInfoRelativePath(I->Namespace)); - ParentI->Path = getInfoRelativePath(ParentI->Namespace); - return {std::unique_ptr{std::move(I)}, - std::unique_ptr{std::move(ParentI)}}; - } - switch (I->Namespace[0].RefType) { case InfoType::IT_namespace: { auto ParentI = std::make_unique(); @@ -510,8 +508,6 @@ // Wrap in enclosing scope auto ParentI = std::make_unique(); ParentI->USR = ParentUSR; - if (Func.Namespace.empty()) - ParentI->Path = getInfoRelativePath(ParentI->Namespace); ParentI->ChildFunctions.emplace_back(std::move(Func)); // Info is wrapped in its parent scope so it's returned in the second position return {nullptr, std::unique_ptr{std::move(ParentI)}}; Index: clang-tools-extra/test/clang-doc/single-file-public.cpp =================================================================== --- clang-tools-extra/test/clang-doc/single-file-public.cpp +++ clang-tools-extra/test/clang-doc/single-file-public.cpp @@ -3,7 +3,7 @@ // RUN: echo "" > %t/compile_flags.txt // RUN: cp "%s" "%t/test.cpp" // RUN: clang-doc --doxygen --public --executor=standalone -p %t %t/test.cpp -output=%t/docs -// RUN: cat %t/docs/Record.yaml | FileCheck %s --check-prefix=CHECK +// RUN: cat %t/docs/GlobalNamespace/Record.yaml | FileCheck %s --check-prefix=CHECK // RUN: rm -rf %t class Record { @@ -21,8 +21,12 @@ // CHECK: --- // CHECK-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}' // CHECK-NEXT: Name: 'Record' +// CHECK-NEXT: Path: 'GlobalNamespace' +// CHECK-NEXT: Namespace: +// CHECK-NEXT: - Type: Namespace +// CHECK-NEXT: Name: 'GlobalNamespace' // CHECK-NEXT: DefLocation: -// CHECK-NEXT: LineNumber: [[@LINE-16]] +// CHECK-NEXT: LineNumber: [[@LINE-20]] // CHECK-NEXT: Filename: '{{.*}}' // CHECK-NEXT: TagType: Class // CHECK-NEXT: ChildFunctions: @@ -32,11 +36,13 @@ // CHECK-NEXT: - Type: Record // CHECK-NEXT: Name: 'Record' // CHECK-NEXT: USR: '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}' +// CHECK-NEXT: - Type: Namespace +// CHECK-NEXT: Name: 'GlobalNamespace' // CHECK-NEXT: DefLocation: -// CHECK-NEXT: LineNumber: [[@LINE-17]] +// CHECK-NEXT: LineNumber: [[@LINE-23]] // CHECK-NEXT: Filename: '{{.*}}' // CHECK-NEXT: Location: -// CHECK-NEXT: - LineNumber: [[@LINE-25]] +// CHECK-NEXT: - LineNumber: [[@LINE-31]] // CHECK-NEXT: Filename: '{{.*}}' // CHECK-NEXT: IsMethod: true // CHECK-NEXT: Parent: Index: clang-tools-extra/unittests/clang-doc/SerializeTest.cpp =================================================================== --- clang-tools-extra/unittests/clang-doc/SerializeTest.cpp +++ clang-tools-extra/unittests/clang-doc/SerializeTest.cpp @@ -136,7 +136,9 @@ 10, /*Public=*/false, Infos); RecordInfo *E = InfoAsRecord(Infos[0].get()); - RecordInfo ExpectedE(EmptySID, "E"); + RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace"); + ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); ExpectedE.TagType = TagTypeKind::TTK_Class; ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); CheckRecordInfo(&ExpectedE, E); @@ -149,6 +151,8 @@ EConstructor.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default); EConstructor.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); EConstructor.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record); + EConstructor.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); EConstructor.Access = AccessSpecifier::AS_public; EConstructor.IsMethod = true; ExpectedRecordWithEConstructor.ChildFunctions.emplace_back( @@ -163,13 +167,17 @@ Method.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default); Method.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"}); Method.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record); + Method.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); Method.Access = AccessSpecifier::AS_protected; Method.IsMethod = true; ExpectedRecordWithMethod.ChildFunctions.emplace_back(std::move(Method)); CheckRecordInfo(&ExpectedRecordWithMethod, RecordWithMethod); RecordInfo *F = InfoAsRecord(Infos[4].get()); - RecordInfo ExpectedF(EmptySID, "F"); + RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace"); + ExpectedF.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); ExpectedF.TagType = TagTypeKind::TTK_Struct; ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); CheckRecordInfo(&ExpectedF, F); @@ -182,6 +190,8 @@ TemplateMethod.ReturnType = TypeInfo(EmptySID, "void", InfoType::IT_default); TemplateMethod.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"}); TemplateMethod.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record); + TemplateMethod.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); TemplateMethod.Access = AccessSpecifier::AS_public; TemplateMethod.IsMethod = true; ExpectedRecordWithTemplateMethod.ChildFunctions.emplace_back( @@ -200,6 +210,8 @@ llvm::SmallString<16>{"test.cpp"}); SpecializedTemplateMethod.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record); + SpecializedTemplateMethod.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); SpecializedTemplateMethod.Access = AccessSpecifier::AS_public; SpecializedTemplateMethod.IsMethod = true; ExpectedTemplatedRecord.ChildFunctions.emplace_back( @@ -207,7 +219,9 @@ CheckRecordInfo(&ExpectedTemplatedRecord, TemplatedRecord); RecordInfo *G = InfoAsRecord(Infos[8].get()); - RecordInfo ExpectedG(EmptySID, "G"); + RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace"); + ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); ExpectedG.TagType = TagTypeKind::TTK_Struct; ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); ExpectedG.IsTypeDef = true; @@ -247,7 +261,9 @@ ExtractInfosFromCode("class E;", 2, /*Public=*/false, Infos); RecordInfo *E = InfoAsRecord(Infos[0].get()); - RecordInfo ExpectedE(EmptySID, "E"); + RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace"); + ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); ExpectedE.TagType = TagTypeKind::TTK_Class; ExpectedE.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"}); CheckRecordInfo(&ExpectedE, E); @@ -258,7 +274,9 @@ ExtractInfosFromCode("struct E { int I; };", 2, /*Public=*/false, Infos); RecordInfo *E = InfoAsRecord(Infos[0].get()); - RecordInfo ExpectedE(EmptySID, "E"); + RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace"); + ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); ExpectedE.TagType = TagTypeKind::TTK_Struct; ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); ExpectedE.Members.emplace_back("int", "I", AccessSpecifier::AS_public); @@ -270,16 +288,20 @@ ExtractInfosFromCode("class E { class G {}; };", 4, /*Public=*/false, Infos); RecordInfo *E = InfoAsRecord(Infos[0].get()); - RecordInfo ExpectedE(EmptySID, "E"); + RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace"); + ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); ExpectedE.TagType = TagTypeKind::TTK_Class; CheckRecordInfo(&ExpectedE, E); RecordInfo *G = InfoAsRecord(Infos[2].get()); - RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"E"); + RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/"GlobalNamespace/E"); ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); ExpectedG.TagType = TagTypeKind::TTK_Class; ExpectedG.Namespace.emplace_back(EmptySID, "E", InfoType::IT_record); + ExpectedG.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); CheckRecordInfo(&ExpectedG, G); } @@ -402,13 +424,14 @@ NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get()); NamespaceInfo ExpectedParentA(EmptySID); - ExpectedParentA.ChildRecords.emplace_back(EmptySID, "A", InfoType::IT_record); + ExpectedParentA.ChildRecords.emplace_back(EmptySID, "A", InfoType::IT_record, + "GlobalNamespace"); CheckNamespaceInfo(&ExpectedParentA, ParentA); RecordInfo *ParentB = InfoAsRecord(Infos[3].get()); RecordInfo ExpectedParentB(EmptySID); ExpectedParentB.ChildRecords.emplace_back(EmptySID, "B", InfoType::IT_record, - "A"); + "GlobalNamespace/A"); CheckRecordInfo(&ExpectedParentB, ParentB); NamespaceInfo *ParentC = InfoAsNamespace(Infos[7].get());