diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp --- a/clang-tools-extra/clang-doc/BitcodeReader.cpp +++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp @@ -350,6 +350,11 @@ return &I->Description.back(); } +template <> llvm::Expected getCommentInfo(MemberTypeInfo *I) { + I->Description.emplace_back(); + return &I->Description.back(); +} + template <> llvm::Expected getCommentInfo(EnumInfo *I) { I->Description.emplace_back(); return &I->Description.back(); diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp --- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp +++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp @@ -426,6 +426,8 @@ emitBlock(T.Type, FieldId::F_type); emitRecord(T.Name, MEMBER_TYPE_NAME); emitRecord(T.Access, MEMBER_TYPE_ACCESS); + for (const auto &CI : T.Description) + emitBlock(CI); } void ClangDocBitcodeWriter::emitBlock(const CommentInfo &I) { diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h --- a/clang-tools-extra/clang-doc/Representation.h +++ b/clang-tools-extra/clang-doc/Representation.h @@ -210,6 +210,8 @@ // with value 0 to be used as the default. // (AS_public = 0, AS_protected = 1, AS_private = 2, AS_none = 3) AccessSpecifier Access = AccessSpecifier::AS_public; + + std::vector Description; // Comment description of this field. }; struct Location { diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp --- a/clang-tools-extra/clang-doc/Serialize.cpp +++ b/clang-tools-extra/clang-doc/Serialize.cpp @@ -29,6 +29,8 @@ populateParentNamespaces(llvm::SmallVector &Namespaces, const T *D, bool &IsAnonymousNamespace); +static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D); + // A function to extract the appropriate relative path for a given info's // documentation. The path returned is a composite of the parent namespaces. // @@ -293,9 +295,11 @@ continue; } } - I.Members.emplace_back( + + auto& member = I.Members.emplace_back( F->getTypeSourceInfo()->getType().getAsString(), F->getNameAsString(), getFinalAccessSpecifier(Access, F->getAccessUnsafe())); + populateMemberTypeInfo(member, F); } } @@ -431,6 +435,19 @@ parseParameters(I, D); } +static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D) { + ASTContext& Context = D->getASTContext(); + RawComment *Comment = Context.getRawCommentForDeclNoCache(D); + if (!Comment) + return; + + Comment->setAttached(); + if (comments::FullComment* fc = Comment->parse(Context, nullptr, D)) { + I.Description.emplace_back(); + parseFullComment(fc, I.Description.back()); + } +} + static void parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir, bool PublicOnly, bool IsParent, diff --git a/clang-tools-extra/clang-doc/YAMLGenerator.cpp b/clang-tools-extra/clang-doc/YAMLGenerator.cpp --- a/clang-tools-extra/clang-doc/YAMLGenerator.cpp +++ b/clang-tools-extra/clang-doc/YAMLGenerator.cpp @@ -192,6 +192,7 @@ // the AS that shouldn't be part of the output. Even though AS_public is the // default in the struct, it should be displayed in the YAML output. IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none); + IO.mapOptional("Description", I.Description); } };