jkorous created this revision.
jkorous added reviewers: gribozavr, arphaman.
Herald added subscribers: cfe-commits, dexonsmith.
Herald added a project: clang.
Loading external comments and sorting them is expensive - mostly due to
getDecomposedLoc() begin expensive. For modules with very large number of
comments (~100k) this is prohibitively expensive.
In this particular case we are actually not at all interested in getting
comments for declarations - just using a side-effect of the implementation
which causes documentation comments to be parsed (doxygen) and attached to
relevant declarations.
The FIXME in tests is fixed now.
Repository:
rC Clang
https://reviews.llvm.org/D61103
Files:
clang/include/clang/AST/ASTContext.h
clang/lib/AST/ASTContext.cpp
clang/lib/Sema/SemaDecl.cpp
clang/test/Sema/warn-documentation.cpp
Index: clang/test/Sema/warn-documentation.cpp
===================================================================
--- clang/test/Sema/warn-documentation.cpp
+++ clang/test/Sema/warn-documentation.cpp
@@ -760,16 +760,6 @@
/// \endcode
int test_verbatim_2();
-// FIXME: we give a bad diagnostic here because we throw away non-documentation
-// comments early.
-//
-// expected-warning@+3 {{'\endcode' command does not terminate a verbatim text block}}
-/// \code
-// foo
-/// \endcode
-int test_verbatim_3();
-
-
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
int test1; ///< \brief\author Aaa
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -12380,19 +12380,7 @@
}
// See if there are any new comments that are not attached to a decl.
- ArrayRef<RawComment *> Comments = Context.getRawCommentList().getComments();
- if (!Comments.empty() &&
- !Comments.back()->isAttached()) {
- // There is at least one comment that not attached to a decl.
- // Maybe it should be attached to one of these decls?
- //
- // Note that this way we pick up not only comments that precede the
- // declaration, but also comments that *follow* the declaration -- thanks to
- // the lookahead in the lexer: we've consumed the semicolon and looked
- // ahead through comments.
- for (unsigned i = 0, e = Group.size(); i != e; ++i)
- Context.getCommentForDecl(Group[i], &PP);
- }
+ Context.tryToAttachCommentsToDecls(Group, &PP);
}
/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator()
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -489,6 +489,134 @@
return RC;
}
+void ASTContext::tryToAttachCommentsToDecls(ArrayRef<Decl *> Decls, const Preprocessor *PP) {
+ // Explicitly not calling ExternalSource->ReadComments() as we're not
+ // interested in those.
+ ArrayRef<RawComment *> RawComments = Comments.getComments();
+ if (RawComments.empty())
+ return;
+
+ auto CacheCommentForDecl = [this, PP](const Decl *D, const RawComment *C) {
+ RawCommentAndCacheFlags CacheEntry;
+ CacheEntry.setKind(RawCommentAndCacheFlags::FromDecl);
+ CacheEntry.setRaw(C);
+ CacheEntry.setOriginalDecl(D);
+ RedeclComments[D] = CacheEntry;
+
+ // Always try to parse in order to eventually produce diagnostics.
+ comments::FullComment *FC = C->parse(*this, PP, D);
+ // But cache only if we don't have a comment yet
+ const Decl* Canonical = D->getCanonicalDecl();
+ auto ParsedComment = ParsedComments.find(Canonical);
+ if (ParsedComment != ParsedComments.end())
+ ParsedComment->second = FC;
+ };
+
+ // explicit comment location caching
+ std::unordered_map<RawComment *, std::pair<FileID, unsigned>>
+ DecomposedCommentBegin;
+ std::unordered_map<RawComment *, std::pair<FileID, unsigned>>
+ DecomposedCommentEnd;
+ std::unordered_map<unsigned, std::unordered_map<unsigned, unsigned>> CommentBeginLine;
+
+ // Don't store the result for long - might go dangling.
+ auto GetCachedCommentBegin =
+ [&DecomposedCommentBegin,
+ this](RawComment *RC) -> const std::pair<FileID, unsigned> & {
+ assert(RC);
+ auto BeginIt = DecomposedCommentBegin.find(RC);
+ if (BeginIt != DecomposedCommentBegin.end()) {
+ return BeginIt->second;
+ }
+ DecomposedCommentBegin[RC] =
+ SourceMgr.getDecomposedLoc(RC->getSourceRange().getBegin());
+ return DecomposedCommentBegin[RC];
+ };
+ // Don't store the result for long - might go dangling.
+ auto GetCachedCommentEnd =
+ [&DecomposedCommentEnd,
+ this](RawComment *RC) -> const std::pair<FileID, unsigned> & {
+ assert(RC);
+ auto EndIt = DecomposedCommentEnd.find(RC);
+ if (EndIt != DecomposedCommentEnd.end()) {
+ return EndIt->second;
+ }
+ DecomposedCommentEnd[RC] =
+ SourceMgr.getDecomposedLoc(RC->getSourceRange().getEnd());
+ return DecomposedCommentEnd[RC];
+ };
+ auto GetCachedCommentBeginLine =
+ [&CommentBeginLine,
+ this](const std::pair<FileID, unsigned>& CommentBeginLoc) -> unsigned {
+ auto BeginFileIt = CommentBeginLine.find(CommentBeginLoc.first.getHashValue());
+ if (BeginFileIt != CommentBeginLine.end()) {
+ auto BeginLineIt = BeginFileIt->second.find(CommentBeginLoc.second);
+ if (BeginLineIt != BeginFileIt->second.end()) {
+ return BeginLineIt->second;
+ }
+ }
+ CommentBeginLine[CommentBeginLoc.first.getHashValue()][CommentBeginLoc.second] =
+ SourceMgr.getLineNumber(CommentBeginLoc.first, CommentBeginLoc.second);
+ return CommentBeginLine[CommentBeginLoc.first.getHashValue()][CommentBeginLoc.second];
+ };
+
+ for (const Decl *D : Decls) {
+ D = adjustDeclToTemplate(D);
+ if (!CanDeclHaveDocComment(D))
+ continue;
+
+ {
+ auto CIt = RedeclComments.find(D);
+ if ( CIt != RedeclComments.end() && CIt->second.getOriginalDecl() == D) {
+ continue;
+ }
+ }
+
+ llvm::Optional<SourceLocation> OptCandidateCommentLoc = getCandidateCommentLocation(SourceMgr,D);
+ if (!OptCandidateCommentLoc)
+ continue;
+
+ const std::pair<FileID, unsigned> DeclLocDecomp =
+ SourceMgr.getDecomposedLoc(OptCandidateCommentLoc.getValue());
+
+ // FIXME: We might optimize by keeping count of unattached comments and
+ // terminating early.
+ for (auto CIt = RawComments.begin(); CIt != RawComments.end(); ++CIt) {
+ RawComment *C = *CIt;
+ if (!C->isDocumentation() && !LangOpts.CommentOpts.ParseAllComments)
+ continue;
+
+ if (C->isAttached())
+ continue;
+
+ if (C->isTrailingComment()) {
+ if (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D) ||
+ isa<ObjCMethodDecl>(D) || isa<ObjCPropertyDecl>(D)) {
+ const std::pair<FileID, unsigned> &CommentBeginDecomp =
+ GetCachedCommentBegin(C);
+ // Check that Doxygen trailing comment comes after the declaration,
+ // starts on the same line and in the same file as the declaration.
+ if (DeclLocDecomp.first == CommentBeginDecomp.first &&
+ SourceMgr.getLineNumber(DeclLocDecomp.first,
+ DeclLocDecomp.second) ==
+ GetCachedCommentBeginLine(CommentBeginDecomp)) {
+ C->setAttached();
+ CacheCommentForDecl(D, C);
+ break;
+ }
+ }
+ } else {
+ if (IsCommentBeforeDecl(SourceMgr, GetCachedCommentEnd(C),
+ DeclLocDecomp)) {
+ C->setAttached();
+ CacheCommentForDecl(D, C);
+ break;
+ }
+ }
+ }
+ }
+}
+
static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod,
SmallVectorImpl<const NamedDecl *> &Redeclared) {
const DeclContext *DC = ObjCMethod->getDeclContext();
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -814,6 +814,13 @@
getRawCommentForAnyRedecl(const Decl *D,
const Decl **OriginalDecl = nullptr) const;
+ /// For every comment not attached to any decl check if it should be attached
+ /// to any of \param Decls
+ ///
+ /// \param PP the Preprocessor used with this TU. Could be nullptr if
+ /// preprocessor is not available.
+ void tryToAttachCommentsToDecls(ArrayRef<Decl *> Decls, const Preprocessor *PP);
+
/// Return parsed documentation comment attached to a given declaration.
/// Returns nullptr if no comment is attached.
///
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits