summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulie Hockett <juliehockett@google.com>2019-06-24 19:31:02 +0000
committerJulie Hockett <juliehockett@google.com>2019-06-24 19:31:02 +0000
commitb1f01e27ec0cea2f28eaa2026aa1e63a3b2ae0f0 (patch)
treec35282329e294ecf439e4908611a8a61345ac6e9
parentea08248b2bc9ab6cd14cfd1a05c4fb0fae49e97a (diff)
downloadbcm5719-llvm-b1f01e27ec0cea2f28eaa2026aa1e63a3b2ae0f0.tar.gz
bcm5719-llvm-b1f01e27ec0cea2f28eaa2026aa1e63a3b2ae0f0.zip
[clang-doc] Add basic support for templates and typedef
In serialize::parseBases(...), when a base record is a template specialization, the specialization was used as the parent. It should be the base template so there is only one file generated for this record. When the specialized template is implicitly declared the reference USR corresponded to the GlobalNamespace's USR, this will now be the base template's USR. More information about templates will be added later. In serialize::emiInfo(RecorDecl*, ...), typedef records were not handled and the name was empty. This is now handled and a IsTypeDef attribute is added to RecordInfo struct. In serialize::emitInfo(CXXMethodDecl*, ...), template specialization is handled like in serialize::parseBases(...). Bitcode writer and reader are modified to handle the new attribute of RecordInfo. Submitted on behalf of Diego Astiazarán (diegoaat97@gmail.com) Differential Revision: https://reviews.llvm.org/D63367 llvm-svn: 364222
-rw-r--r--clang-tools-extra/clang-doc/BitcodeReader.cpp2
-rw-r--r--clang-tools-extra/clang-doc/BitcodeWriter.cpp4
-rw-r--r--clang-tools-extra/clang-doc/BitcodeWriter.h1
-rw-r--r--clang-tools-extra/clang-doc/Representation.h1
-rw-r--r--clang-tools-extra/clang-doc/Serialize.cpp33
-rw-r--r--clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp1
-rw-r--r--clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp2
-rw-r--r--clang-tools-extra/unittests/clang-doc/SerializeTest.cpp78
8 files changed, 108 insertions, 14 deletions
diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp
index 04e5d7d24f1..4489daf3d92 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -167,6 +167,8 @@ llvm::Error parseRecord(Record R, unsigned ID, llvm::StringRef Blob,
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<llvm::StringError>(
"Invalid field for RecordInfo.\n", llvm::inconvertibleErrorCode());
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
index 232c3f13fbd..ed235e09947 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -159,6 +159,7 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
{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 @@ static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
// 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 @@ void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
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)
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.h b/clang-tools-extra/clang-doc/BitcodeWriter.h
index 9deba830a30..57c3b056699 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.h
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.h
@@ -102,6 +102,7 @@ enum RecordId {
RECORD_DEFLOCATION,
RECORD_LOCATION,
RECORD_TAG_TYPE,
+ RECORD_IS_TYPE_DEF,
REFERENCE_USR,
REFERENCE_NAME,
REFERENCE_TYPE,
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index ad12ec4d42a..c5a643c65c4 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -241,6 +241,7 @@ struct RecordInfo : public SymbolInfo {
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<MemberTypeInfo, 4>
Members; // List of info about record members.
llvm::SmallVector<Reference, 4> Parents; // List of base/parent records
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index 2bd54cf2d98..11845e1a616 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -179,10 +179,9 @@ static SymbolID getUSRForDecl(const Decl *D) {
}
static RecordDecl *getDeclForType(const QualType &T) {
- auto *Ty = T->getAs<RecordType>();
- 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 @@ static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
for (const CXXBaseSpecifier &B : D->bases()) {
if (B.isVirtual())
continue;
- if (const auto *P = getDeclForType(B.getType()))
+ 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);
+ } else if (const RecordDecl *P = getDeclForType(B.getType()))
I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
InfoType::IT_record);
else
@@ -343,8 +346,13 @@ std::unique_ptr<Info> emitInfo(const RecordDecl *D, const FullComment *FC,
populateSymbolInfo(*I, D, FC, LineNumber, File);
I->TagType = D->getTagKind();
parseFields(*I, D, PublicOnly);
- if (const auto *C = dyn_cast<CXXRecordDecl>(D))
+ if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
+ if (const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl()) {
+ I->Name = TD->getNameAsString();
+ I->IsTypeDef = true;
+ }
parseBases(*I, C);
+ }
return std::unique_ptr<Info>{std::move(I)};
}
@@ -376,9 +384,16 @@ std::unique_ptr<Info> emitInfo(const CXXMethodDecl *D, const FullComment *FC,
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<ClassTemplateSpecializationDecl>(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
diff --git a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
index c89a6491b6c..a22f8af7394 100644
--- a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
@@ -80,6 +80,7 @@ TEST(BitcodeTest, emitRecordInfoBitcode) {
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);
diff --git a/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp b/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
index 99ea76b7aff..75767986e63 100644
--- a/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
@@ -151,6 +151,8 @@ void CheckRecordInfo(RecordInfo *Expected, RecordInfo *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]);
diff --git a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
index 1c044f7d0da..8a1ee77ebf2 100644
--- a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
@@ -142,7 +142,15 @@ public:
E() {}
protected:
void ProtectedMethod();
-};)raw", 3, /*Public=*/false, Infos);
+};
+template <typename T>
+struct F {
+ void TemplateMethod();
+};
+template <>
+void F<int>::TemplateMethod();
+typedef struct {} G;)raw",
+ 7, /*Public=*/false, Infos);
RecordInfo *E = InfoAsRecord(Infos[0].get());
RecordInfo ExpectedE(EmptySID, "E");
@@ -176,6 +184,51 @@ protected:
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, emitInlinedFunctionInfo) {
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 <typename T>
+class H {} ;
+class I : public H<int> {} ;)raw",
+ 5, /*Public=*/false, Infos);
RecordInfo *F = InfoAsRecord(Infos[0].get());
RecordInfo ExpectedF(EmptySID, "F");
@@ -307,6 +364,19 @@ TEST(SerializeTest, emitInheritedRecordInfo) {
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<int>", InfoType::IT_record);
+ ExpectedI.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
+ ExpectedI.TagType = TagTypeKind::TTK_Class;
+ CheckRecordInfo(&ExpectedI, I);
}
TEST(SerializeTest, emitModulePublicLFunctions) {
OpenPOWER on IntegriCloud