Index: clang-tools-extra/trunk/clang-doc/Serialize.cpp =================================================================== --- clang-tools-extra/trunk/clang-doc/Serialize.cpp +++ clang-tools-extra/trunk/clang-doc/Serialize.cpp @@ -378,6 +378,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 @@ -528,16 +536,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(); @@ -611,8 +609,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/trunk/test/clang-doc/single-file-public.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-doc/single-file-public.cpp +++ clang-tools-extra/trunk/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/trunk/unittests/clang-doc/SerializeTest.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp +++ clang-tools-extra/trunk/unittests/clang-doc/SerializeTest.cpp @@ -137,7 +137,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); @@ -150,6 +152,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( @@ -164,13 +168,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); @@ -183,6 +191,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( @@ -201,6 +211,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( @@ -208,7 +220,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; @@ -248,7 +262,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); @@ -259,7 +275,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); @@ -271,16 +289,22 @@ 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"); + llvm::SmallString<128> ExpectedGPath("GlobalNamespace/E"); + llvm::sys::path::native(ExpectedGPath); + RecordInfo ExpectedG(EmptySID, /*Name=*/"G", /*Path=*/ExpectedGPath); 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); } @@ -333,23 +357,32 @@ 14, /*Public=*/false, Infos); RecordInfo *F = InfoAsRecord(Infos[0].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_Class; ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); CheckRecordInfo(&ExpectedF, F); RecordInfo *G = InfoAsRecord(Infos[3].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_Class; ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); ExpectedG.Members.emplace_back("int", "I", AccessSpecifier::AS_protected); CheckRecordInfo(&ExpectedG, G); RecordInfo *E = InfoAsRecord(Infos[6].get()); - RecordInfo ExpectedE(EmptySID, "E"); - ExpectedE.Parents.emplace_back(EmptySID, "F", InfoType::IT_record); - ExpectedE.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record); - ExpectedE.Bases.emplace_back(EmptySID, "F", "", false, + 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, + /*Path*=*/"GlobalNamespace"); + ExpectedE.VirtualParents.emplace_back( + EmptySID, /*Name=*/"G", InfoType::IT_record, /*Path*=*/"GlobalNamespace"); + ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"F", + /*Path=*/"GlobalNamespace", false, AccessSpecifier::AS_public, true); FunctionInfo FunctionSet; FunctionSet.Name = "set"; @@ -357,16 +390,21 @@ FunctionSet.Loc.emplace_back(); FunctionSet.Params.emplace_back("int", "N"); FunctionSet.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record); + FunctionSet.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); FunctionSet.Access = AccessSpecifier::AS_protected; FunctionSet.IsMethod = true; ExpectedE.Bases.back().ChildFunctions.emplace_back(std::move(FunctionSet)); - ExpectedE.Bases.emplace_back(EmptySID, "G", "", true, + ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"G", + /*Path=*/"GlobalNamespace", true, AccessSpecifier::AS_private, true); FunctionInfo FunctionGet; FunctionGet.Name = "get"; FunctionGet.ReturnType = TypeInfo(EmptySID, "int", InfoType::IT_default); FunctionGet.DefLoc = Location(); FunctionGet.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record); + FunctionGet.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); FunctionGet.Access = AccessSpecifier::AS_private; FunctionGet.IsMethod = true; ExpectedE.Bases.back().ChildFunctions.emplace_back(std::move(FunctionGet)); @@ -377,14 +415,20 @@ CheckRecordInfo(&ExpectedE, E); RecordInfo *H = InfoAsRecord(Infos[8].get()); - RecordInfo ExpectedH(EmptySID, "H"); + RecordInfo ExpectedH(EmptySID, /*Name=*/"H", /*Path=*/"GlobalNamespace"); + ExpectedH.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); ExpectedH.TagType = TagTypeKind::TTK_Class; ExpectedH.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); - ExpectedH.Parents.emplace_back(EmptySID, "E", InfoType::IT_record); - ExpectedH.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record); - ExpectedH.Bases.emplace_back(EmptySID, "E", "", false, + ExpectedH.Parents.emplace_back(EmptySID, /*Name=*/"E", InfoType::IT_record, + /*Path=*/"GlobalNamespace"); + ExpectedH.VirtualParents.emplace_back( + EmptySID, /*Name=*/"G", InfoType::IT_record, /*Path=*/"GlobalNamespace"); + ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"E", + /*Path=*/"GlobalNamespace", false, AccessSpecifier::AS_private, true); - ExpectedH.Bases.emplace_back(EmptySID, "F", "", false, + ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"F", + /*Path=*/"GlobalNamespace", false, AccessSpecifier::AS_private, false); FunctionInfo FunctionSetNew; FunctionSetNew.Name = "set"; @@ -392,16 +436,21 @@ FunctionSetNew.Loc.emplace_back(); FunctionSetNew.Params.emplace_back("int", "N"); FunctionSetNew.Namespace.emplace_back(EmptySID, "F", InfoType::IT_record); + FunctionSetNew.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); FunctionSetNew.Access = AccessSpecifier::AS_private; FunctionSetNew.IsMethod = true; ExpectedH.Bases.back().ChildFunctions.emplace_back(std::move(FunctionSetNew)); - ExpectedH.Bases.emplace_back(EmptySID, "G", "", true, + ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"G", + /*Path=*/"GlobalNamespace", true, AccessSpecifier::AS_private, false); FunctionInfo FunctionGetNew; FunctionGetNew.Name = "get"; FunctionGetNew.ReturnType = TypeInfo(EmptySID, "int", InfoType::IT_default); FunctionGetNew.DefLoc = Location(); FunctionGetNew.Namespace.emplace_back(EmptySID, "G", InfoType::IT_record); + FunctionGetNew.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); FunctionGetNew.Access = AccessSpecifier::AS_private; FunctionGetNew.IsMethod = true; ExpectedH.Bases.back().ChildFunctions.emplace_back(std::move(FunctionGetNew)); @@ -410,15 +459,21 @@ CheckRecordInfo(&ExpectedH, H); RecordInfo *I = InfoAsRecord(Infos[10].get()); - RecordInfo ExpectedI(EmptySID, "I"); + RecordInfo ExpectedI(EmptySID, /*Name=*/"I", /*Path=*/"GlobalNamespace"); + ExpectedI.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); ExpectedI.TagType = TagTypeKind::TTK_Class; ExpectedI.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); CheckRecordInfo(&ExpectedI, I); RecordInfo *J = InfoAsRecord(Infos[12].get()); - RecordInfo ExpectedJ(EmptySID, "J"); - ExpectedJ.Parents.emplace_back(EmptySID, "I", InfoType::IT_record); - ExpectedJ.Bases.emplace_back(EmptySID, "I", "", false, + RecordInfo ExpectedJ(EmptySID, /*Name=*/"J", /*Path=*/"GlobalNamespace"); + ExpectedJ.Namespace.emplace_back(EmptySID, "GlobalNamespace", + InfoType::IT_namespace); + ExpectedJ.Parents.emplace_back(EmptySID, /*Name=*/"I", + InfoType::IT_record); + ExpectedJ.Bases.emplace_back(EmptySID, /*Name=*/"I", + /*Path=*/"GlobalNamespace", false, AccessSpecifier::AS_public, true); ExpectedJ.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); ExpectedJ.TagType = TagTypeKind::TTK_Class; @@ -467,13 +522,16 @@ 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); + llvm::SmallString<128> ExpectedParentBPath("GlobalNamespace/A"); + llvm::sys::path::native(ExpectedParentBPath); ExpectedParentB.ChildRecords.emplace_back(EmptySID, "B", InfoType::IT_record, - "A"); + ExpectedParentBPath); CheckRecordInfo(&ExpectedParentB, ParentB); NamespaceInfo *ParentC = InfoAsNamespace(Infos[7].get());