Index: clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp =================================================================== --- clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp +++ clang-tools-extra/trunk/clang-doc/BitcodeReader.cpp @@ -167,6 +167,8 @@ return decodeRecord(R, I->Loc, Blob); case RECORD_TAG_TYPE: return decodeRecord(R, I->TagType, Blob); + case RECORD_IS_TYPE_DEF: + return decodeRecord(R, I->IsTypeDef, Blob); default: return llvm::make_error( "Invalid field for RecordInfo.\n", llvm::inconvertibleErrorCode()); Index: clang-tools-extra/trunk/clang-doc/BitcodeWriter.h =================================================================== --- clang-tools-extra/trunk/clang-doc/BitcodeWriter.h +++ clang-tools-extra/trunk/clang-doc/BitcodeWriter.h @@ -102,6 +102,7 @@ RECORD_DEFLOCATION, RECORD_LOCATION, RECORD_TAG_TYPE, + RECORD_IS_TYPE_DEF, REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, Index: clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp =================================================================== --- clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp +++ clang-tools-extra/trunk/clang-doc/BitcodeWriter.cpp @@ -159,6 +159,7 @@ {RECORD_DEFLOCATION, {"DefLocation", &LocationAbbrev}}, {RECORD_LOCATION, {"Location", &LocationAbbrev}}, {RECORD_TAG_TYPE, {"TagType", &IntAbbrev}}, + {RECORD_IS_TYPE_DEF, {"IsTypeDef", &BoolAbbrev}}, {FUNCTION_USR, {"USR", &SymbolIDAbbrev}}, {FUNCTION_NAME, {"Name", &StringAbbrev}}, {FUNCTION_DEFLOCATION, {"DefLocation", &LocationAbbrev}}, @@ -202,7 +203,7 @@ // Record Block {BI_RECORD_BLOCK_ID, {RECORD_USR, RECORD_NAME, RECORD_DEFLOCATION, RECORD_LOCATION, - RECORD_TAG_TYPE}}, + RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF}}, // Function Block {BI_FUNCTION_BLOCK_ID, {FUNCTION_USR, FUNCTION_NAME, FUNCTION_DEFLOCATION, FUNCTION_LOCATION, @@ -471,6 +472,7 @@ for (const auto &L : I.Loc) emitRecord(L, RECORD_LOCATION); emitRecord(I.TagType, RECORD_TAG_TYPE); + emitRecord(I.IsTypeDef, RECORD_IS_TYPE_DEF); for (const auto &N : I.Members) emitBlock(N); for (const auto &P : I.Parents) Index: clang-tools-extra/trunk/clang-doc/Representation.h =================================================================== --- clang-tools-extra/trunk/clang-doc/Representation.h +++ clang-tools-extra/trunk/clang-doc/Representation.h @@ -241,6 +241,7 @@ TagTypeKind TagType = TagTypeKind::TTK_Struct; // Type of this record // (struct, class, union, // interface). + bool IsTypeDef = false; // Indicates if record was declared using typedef llvm::SmallVector Members; // List of info about record members. llvm::SmallVector Parents; // List of base/parent records 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 @@ -179,10 +179,9 @@ } static RecordDecl *getDeclForType(const QualType &T) { - auto *Ty = T->getAs(); - if (!Ty) - return nullptr; - return Ty->getDecl()->getDefinition(); + if (const RecordDecl *D = T->getAsRecordDecl()) + return D->getDefinition(); + return nullptr; } static bool isPublic(const clang::AccessSpecifier AS, @@ -249,7 +248,11 @@ for (const CXXBaseSpecifier &B : D->bases()) { if (B.isVirtual()) continue; - if (const auto *P = getDeclForType(B.getType())) + if (const auto *Ty = B.getType()->getAs()) { + const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl(); + I.Parents.emplace_back(getUSRForDecl(D), B.getType().getAsString(), + InfoType::IT_record); + } else if (const RecordDecl *P = getDeclForType(B.getType())) I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record); else @@ -343,8 +346,13 @@ populateSymbolInfo(*I, D, FC, LineNumber, File); I->TagType = D->getTagKind(); parseFields(*I, D, PublicOnly); - if (const auto *C = dyn_cast(D)) + if (const auto *C = dyn_cast(D)) { + if (const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl()) { + I->Name = TD->getNameAsString(); + I->IsTypeDef = true; + } parseBases(*I, C); + } return std::unique_ptr{std::move(I)}; } @@ -376,9 +384,16 @@ populateFunctionInfo(Func, D, FC, LineNumber, File); Func.IsMethod = true; - SymbolID ParentUSR = getUSRForDecl(D->getParent()); - Func.Parent = Reference{ParentUSR, D->getParent()->getNameAsString(), - InfoType::IT_record}; + const NamedDecl *Parent = nullptr; + if (const auto *SD = + dyn_cast(D->getParent())) + Parent = SD->getSpecializedTemplate(); + else + Parent = D->getParent(); + + SymbolID ParentUSR = getUSRForDecl(Parent); + Func.Parent = + Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record}; Func.Access = D->getAccess(); // Wrap in enclosing scope Index: clang-tools-extra/trunk/unittests/clang-doc/BitcodeTest.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clang-doc/BitcodeTest.cpp +++ clang-tools-extra/trunk/unittests/clang-doc/BitcodeTest.cpp @@ -80,6 +80,7 @@ I.Members.emplace_back("int", "X", AccessSpecifier::AS_private); I.TagType = TagTypeKind::TTK_Class; + I.IsTypeDef = true; I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record); I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record); Index: clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp +++ clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp @@ -151,6 +151,8 @@ 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]); 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 @@ -142,7 +142,15 @@ E() {} protected: void ProtectedMethod(); -};)raw", 3, /*Public=*/false, Infos); +}; +template +struct F { + void TemplateMethod(); +}; +template <> +void F::TemplateMethod(); +typedef struct {} G;)raw", + 7, /*Public=*/false, Infos); RecordInfo *E = InfoAsRecord(Infos[0].get()); RecordInfo ExpectedE(EmptySID, "E"); @@ -176,6 +184,51 @@ Method.IsMethod = true; ExpectedRecordWithMethod.ChildFunctions.emplace_back(std::move(Method)); CheckRecordInfo(&ExpectedRecordWithMethod, RecordWithMethod); + + RecordInfo *F = InfoAsRecord(Infos[3].get()); + RecordInfo ExpectedF(EmptySID, "F"); + ExpectedF.TagType = TagTypeKind::TTK_Struct; + ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); + CheckRecordInfo(&ExpectedF, F); + + RecordInfo *RecordWithTemplateMethod = InfoAsRecord(Infos[4].get()); + RecordInfo ExpectedRecordWithTemplateMethod(EmptySID); + FunctionInfo TemplateMethod; + TemplateMethod.Name = "TemplateMethod"; + TemplateMethod.Parent = Reference(EmptySID, "F", InfoType::IT_record); + 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.Access = AccessSpecifier::AS_public; + TemplateMethod.IsMethod = true; + ExpectedRecordWithTemplateMethod.ChildFunctions.emplace_back( + std::move(TemplateMethod)); + CheckRecordInfo(&ExpectedRecordWithTemplateMethod, RecordWithTemplateMethod); + + RecordInfo *TemplatedRecord = InfoAsRecord(Infos[5].get()); + RecordInfo ExpectedTemplatedRecord(EmptySID); + FunctionInfo SpecializedTemplateMethod; + SpecializedTemplateMethod.Name = "TemplateMethod"; + SpecializedTemplateMethod.Parent = + Reference(EmptySID, "F", InfoType::IT_record); + SpecializedTemplateMethod.ReturnType = + TypeInfo(EmptySID, "void", InfoType::IT_default); + SpecializedTemplateMethod.Loc.emplace_back(0, + llvm::SmallString<16>{"test.cpp"}); + SpecializedTemplateMethod.Namespace.emplace_back(EmptySID, "F", + InfoType::IT_record); + SpecializedTemplateMethod.Access = AccessSpecifier::AS_public; + SpecializedTemplateMethod.IsMethod = true; + ExpectedTemplatedRecord.ChildFunctions.emplace_back( + std::move(SpecializedTemplateMethod)); + CheckRecordInfo(&ExpectedTemplatedRecord, TemplatedRecord); + + RecordInfo *G = InfoAsRecord(Infos[6].get()); + RecordInfo ExpectedG(EmptySID, "G"); + ExpectedG.TagType = TagTypeKind::TTK_Struct; + ExpectedG.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); + ExpectedG.IsTypeDef = true; + CheckRecordInfo(&ExpectedG, G); } // Test serialization of enum declarations. @@ -284,9 +337,13 @@ TEST(SerializeTest, emitInheritedRecordInfo) { EmittedInfoList Infos; - ExtractInfosFromCode( - "class F {}; class G{} ; class E : public F, virtual private G {};", 3, - /*Public=*/false, Infos); + ExtractInfosFromCode(R"raw(class F {}; +class G {} ; +class E : public F, virtual private G {}; +template +class H {} ; +class I : public H {} ;)raw", + 5, /*Public=*/false, Infos); RecordInfo *F = InfoAsRecord(Infos[0].get()); RecordInfo ExpectedF(EmptySID, "F"); @@ -307,6 +364,19 @@ ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); ExpectedE.TagType = TagTypeKind::TTK_Class; CheckRecordInfo(&ExpectedE, E); + + RecordInfo *H = InfoAsRecord(Infos[3].get()); + RecordInfo ExpectedH(EmptySID, "H"); + ExpectedH.TagType = TagTypeKind::TTK_Class; + ExpectedH.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); + CheckRecordInfo(&ExpectedH, H); + + RecordInfo *I = InfoAsRecord(Infos[4].get()); + RecordInfo ExpectedI(EmptySID, "I"); + ExpectedI.Parents.emplace_back(EmptySID, "H", InfoType::IT_record); + ExpectedI.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"}); + ExpectedI.TagType = TagTypeKind::TTK_Class; + CheckRecordInfo(&ExpectedI, I); } TEST(SerializeTest, emitModulePublicLFunctions) {