Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -60,6 +60,33 @@ HalfRank, FloatRank, DoubleRank, LongDoubleRank }; +/// \brief Determines whether there is only whitespace in `Buffer` between `P` +/// and the previous line. +/// \param Buffer The buffer to search in. +/// \param P The offset from the beginning of `Buffer` to start from. +/// \return true if all of the characters in `Buffer` ranging from the closest +/// line-ending character before `P` (or the beginning of `Buffer`) to `P - 1` +/// are whitespace. +static bool OnlyWhitespaceOnLineBefore(const char *Buffer, unsigned P) { + // Search backwards until we see linefeed or carriage return. + for (unsigned I = P; I != 0; --I) { + switch (Buffer[I - 1]) { + default: + return false; + case ' ': + case '\t': + case '\f': + case '\v': + break; + case '\r': + case '\n': + return true; + } + } + // We hit the beginning of the buffer. + return true; +} + RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { if (!CommentsLoaded && ExternalSource) { ExternalSource->ReadComments(); @@ -203,7 +230,8 @@ // First check whether we have a trailing comment. if (Comment != RawComments.end() && - (*Comment)->isDocumentation() && (*Comment)->isTrailingComment() && + ((*Comment)->isParseAllComments() || + ((*Comment)->isDocumentation() && (*Comment)->isTrailingComment())) && (isa(D) || isa(D) || isa(D) || isa(D) || isa(D))) { std::pair CommentBeginDecomp @@ -224,6 +252,27 @@ return nullptr; --Comment; + if ((*Comment)->isParseAllComments() && + ((*Comment)->getKind() == RawComment::RCK_OrdinaryBCPL || + (*Comment)->getKind() == RawComment::RCK_OrdinaryC)) { + // When we're trying to guess which comments are actually documentation + // comments and the previous comment was ordinary, assume that it's + // unrelated if it's not the first thing on its starting line. This may + // be a comment unrelated to anything, or it might be a trailing comment + // for a different Decl. + std::pair CommentBeginDecomp = + SourceMgr.getDecomposedLoc((*Comment)->getSourceRange().getBegin()); + if (CommentBeginDecomp.second != 0) { + // We're spuriously OK if this was the first thing in the file. + bool Invalid = false; + const char *Buffer = + SourceMgr.getBufferData(CommentBeginDecomp.first, &Invalid).data(); + if (Invalid || + !OnlyWhitespaceOnLineBefore(Buffer, CommentBeginDecomp.second)) + return nullptr; + } + } + // Check that we actually have a non-member Doxygen comment. if (!(*Comment)->isDocumentation() || (*Comment)->isTrailingComment()) return nullptr; Index: test/Index/parse-all-comments.c =================================================================== --- test/Index/parse-all-comments.c +++ test/Index/parse-all-comments.c @@ -33,6 +33,9 @@ // WITH EMPTY LINE void multi_line_comment_empty_line(int); +int notdoxy7; // Not a Doxygen juxtaposed comment. notdoxy7 NOT_DOXYGEN +int notdoxy8; // Not a Doxygen juxtaposed comment. notdoxy8 NOT_DOXYGEN + #endif // RUN: rm -rf %t @@ -60,3 +63,5 @@ // CHECK: parse-all-comments.c:22:6: FunctionDecl=isdoxy6:{{.*}} isdoxy6 IS_DOXYGEN_SINGLE // CHECK: parse-all-comments.c:29:6: FunctionDecl=multi_line_comment_plus_ordinary:{{.*}} BLOCK_ORDINARY_COMMENT {{.*}} ORDINARY COMMENT {{.*}} IS_DOXYGEN_START {{.*}} IS_DOXYGEN_END // CHECK: parse-all-comments.c:34:6: FunctionDecl=multi_line_comment_empty_line:{{.*}} MULTILINE COMMENT{{.*}}\n{{.*}}\n{{.*}} WITH EMPTY LINE +// CHECK: parse-all-comments.c:36:5: VarDecl=notdoxy7:{{.*}} notdoxy7 NOT_DOXYGEN +// CHECK: parse-all-comments.c:37:5: VarDecl=notdoxy8:{{.*}} notdoxy8 NOT_DOXYGEN