Index: clang/include/clang/Serialization/ASTBitCodes.h =================================================================== --- clang/include/clang/Serialization/ASTBitCodes.h +++ clang/include/clang/Serialization/ASTBitCodes.h @@ -782,7 +782,16 @@ /// Record types used within a comments block. enum CommentRecordTypes { - COMMENTS_RAW_COMMENT = 0 + COMMENTS_RAW_COMMENT = 0, + + /// Maps from a decl to the comment that documents it. + COMMENTS_DECL_TO_COMMENT = 1, + + /// Maps from a canonical decl to a redecl in the chain that has comment attached. + COMMENTS_CANON_DECL_TO_COMMENTED_DECL = 2, + + /// For redecl chains with no comment attached maps from a canonical decl to the last redecl in the chain that has no comment attached. + COMMENTS_CANON_DECL_TO_LAST_COMMENLESS_REDECL = 3 }; /// \defgroup ASTAST AST file AST constants Index: clang/lib/Serialization/ASTReader.cpp =================================================================== --- clang/lib/Serialization/ASTReader.cpp +++ clang/lib/Serialization/ASTReader.cpp @@ -9728,6 +9728,28 @@ SR, Kind, IsTrailingComment, IsAlmostTrailingComment)); break; } + case COMMENTS_DECL_TO_COMMENT: { + unsigned Idx = 0; + const Decl *D = GetDecl(Record[Idx++]); + RawComment *RC = Comments[Record[Idx++]]; + RC->setAttached(); + Context.DeclRawComments[D] = RC; + break; + } + case COMMENTS_CANON_DECL_TO_COMMENTED_DECL : { + unsigned Idx = 0; + const Decl *CanonD = GetDecl(Record[Idx++]); + const Decl *CommentedD = GetDecl(Record[Idx++]); + Context.RedeclChainComments[CanonD] = CommentedD; + break; + } + case COMMENTS_CANON_DECL_TO_LAST_COMMENLESS_REDECL : { + unsigned Idx = 0; + const Decl *CanonD = GetDecl(Record[Idx++]); + const Decl *LastCommentlessRedecl = GetDecl(Record[Idx++]); + Context.RedeclChainComments[CanonD] = LastCommentlessRedecl; + break; + } } } NextCursor: Index: clang/lib/Serialization/ASTWriter.cpp =================================================================== --- clang/lib/Serialization/ASTWriter.cpp +++ clang/lib/Serialization/ASTWriter.cpp @@ -3266,9 +3266,13 @@ auto _ = llvm::make_scope_exit([this] { Stream.ExitBlock(); }); if (!PP->getPreprocessorOpts().WriteCommentListToPCH) return; + + llvm::DenseMap RawCommentIndex; + uint32_t NextCommentIndex = 0; + RecordData Record; - for (const auto &FO : Context->Comments.OrderedComments) { - for (const auto &OC : FO.second) { + for (const auto& FO : Context->Comments.OrderedComments) { + for (const auto& OC : FO.second) { const RawComment *I = OC.second; Record.clear(); AddSourceRange(I->getSourceRange(), Record); @@ -3276,8 +3280,30 @@ Record.push_back(I->isTrailingComment()); Record.push_back(I->isAlmostTrailingComment()); Stream.EmitRecord(COMMENTS_RAW_COMMENT, Record); + RawCommentIndex[I] = NextCommentIndex++; } } + + for (const auto I : Context->DeclRawComments) { + Record.clear(); + AddDeclRef(I.getFirst(), Record); + Record.push_back(RawCommentIndex[I.getSecond()]); + Stream.EmitRecord(COMMENTS_DECL_TO_COMMENT, Record); + } + + for (const auto I : Context->RedeclChainComments) { + Record.clear(); + AddDeclRef(I.getFirst(), Record); + AddDeclRef(I.getSecond(), Record); + Stream.EmitRecord(COMMENTS_CANON_DECL_TO_COMMENTED_DECL, Record); + } + + for (const auto I : Context->CommentlessRedeclChains) { + Record.clear(); + AddDeclRef(I.getFirst(), Record); + AddDeclRef(I.getSecond(), Record); + Stream.EmitRecord(COMMENTS_CANON_DECL_TO_LAST_COMMENLESS_REDECL, Record); + } } //===----------------------------------------------------------------------===// Index: clang/test/Modules/Inputs/documentation.h =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/documentation.h @@ -0,0 +1,9 @@ +/// This function is really cool +void foo() { + +} + +/// But this one is at least 20% cooler +void bar() { + +} Index: clang/test/Modules/Inputs/module.map =================================================================== --- clang/test/Modules/Inputs/module.map +++ clang/test/Modules/Inputs/module.map @@ -14,6 +14,7 @@ header "diamond_bottom.h" export * } +module documentation { header "documentation.h" } module irgen { header "irgen.h" } module cxx_irgen_top { header "cxx-irgen-top.h" } module cxx_irgen_left { header "cxx-irgen-left.h" } Index: clang/test/Modules/documentation.cpp =================================================================== --- /dev/null +++ clang/test/Modules/documentation.cpp @@ -0,0 +1,17 @@ +// Note: the run lines follow their respective tests, since line/column matter +// in this test. + +#include "documentation.h" + +void other() { + +} + +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -fmodule-map-file=%S/Inputs/module.map \ +// RUN: -fmodules-cache-path=%t -code-completion-brief-comments \ +// RUN: -code-completion-at=%s:7:1 -o - -Wdocumentation -I%S/Inputs %s \ +// RUN: | FileCheck %s + +// CHECK: COMPLETION: bar : [#void#]bar() : But this one is at least 20% cooler +// CHECK: COMPLETION: foo : [#void#]foo() : This function is really cool