[clang] [Clang][Comments] Attach comments to decl even if preproc directives are in between (PR #88367)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 11 02:28:53 PDT 2024
https://github.com/hdoc updated https://github.com/llvm/llvm-project/pull/88367
>From 61612c5f340e25198deaf68e6904323955efe489 Mon Sep 17 00:00:00 2001
From: hdoc <github at hdoc.io>
Date: Thu, 11 Apr 2024 01:54:18 -0700
Subject: [PATCH] Attach comments to decl even if preproc directives are in
between
---
clang/lib/AST/ASTContext.cpp | 7 +-
clang/lib/Headers/amxcomplexintrin.h | 4 +
clang/lib/Headers/ia32intrin.h | 2 +
clang/test/Index/annotate-comments.cpp | 5 +-
clang/unittests/AST/DeclTest.cpp | 310 +++++++++++++++++++++++++
5 files changed, 323 insertions(+), 5 deletions(-)
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 2fa6aedca4c6ab..1c8d55b8627452 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -282,9 +282,10 @@ RawComment *ASTContext::getRawCommentForDeclNoCacheImpl(
StringRef Text(Buffer + CommentEndOffset,
DeclLocDecomp.second - CommentEndOffset);
- // There should be no other declarations or preprocessor directives between
- // comment and declaration.
- if (Text.find_last_of(";{}#@") != StringRef::npos)
+ // There should be no other declarations between comment and declaration.
+ // Preprocessor directives are implicitly allowed to be between a comment and
+ // its associated decl.
+ if (Text.find_last_of(";{}@") != StringRef::npos)
return nullptr;
return CommentBeforeDecl;
diff --git a/clang/lib/Headers/amxcomplexintrin.h b/clang/lib/Headers/amxcomplexintrin.h
index 84ef972fcadf03..19eaee10ede659 100644
--- a/clang/lib/Headers/amxcomplexintrin.h
+++ b/clang/lib/Headers/amxcomplexintrin.h
@@ -62,6 +62,8 @@
/// The 2nd source tile. Max size is 1024 Bytes.
#define _tile_cmmimfp16ps(dst, a, b) __builtin_ia32_tcmmimfp16ps(dst, a, b)
+;
+
/// Perform matrix multiplication of two tiles containing complex elements and
/// accumulate the results into a packed single precision tile. Each dword
/// element in input tiles \a a and \a b is interpreted as a complex number
@@ -107,6 +109,8 @@
/// The 2nd source tile. Max size is 1024 Bytes.
#define _tile_cmmrlfp16ps(dst, a, b) __builtin_ia32_tcmmrlfp16ps(dst, a, b)
+;
+
static __inline__ _tile1024i __DEFAULT_FN_ATTRS_COMPLEX
_tile_cmmimfp16ps_internal(unsigned short m, unsigned short n, unsigned short k,
_tile1024i dst, _tile1024i src1, _tile1024i src2) {
diff --git a/clang/lib/Headers/ia32intrin.h b/clang/lib/Headers/ia32intrin.h
index 8e65f232a0def8..c9c92b9ee0f991 100644
--- a/clang/lib/Headers/ia32intrin.h
+++ b/clang/lib/Headers/ia32intrin.h
@@ -533,6 +533,8 @@ __rdtscp(unsigned int *__A) {
/// \see __rdpmc
#define _rdpmc(A) __rdpmc(A)
+;
+
static __inline__ void __DEFAULT_FN_ATTRS
_wbinvd(void) {
__builtin_ia32_wbinvd();
diff --git a/clang/test/Index/annotate-comments.cpp b/clang/test/Index/annotate-comments.cpp
index 6f9f8f0bbbc9e5..bff25d46cf80ee 100644
--- a/clang/test/Index/annotate-comments.cpp
+++ b/clang/test/Index/annotate-comments.cpp
@@ -204,9 +204,9 @@ void isdoxy45(void);
/// Ggg. IS_DOXYGEN_END
void isdoxy46(void);
-/// IS_DOXYGEN_NOT_ATTACHED
+/// isdoxy47 IS_DOXYGEN_SINGLE
#define FOO
-void notdoxy47(void);
+void isdoxy47(void);
/// IS_DOXYGEN_START Aaa bbb
/// \param ccc
@@ -330,6 +330,7 @@ void isdoxy54(int);
// CHECK: annotate-comments.cpp:185:6: FunctionDecl=isdoxy44:{{.*}} BriefComment=[IS_DOXYGEN_START Aaa bbb ccc.]
// CHECK: annotate-comments.cpp:195:6: FunctionDecl=isdoxy45:{{.*}} BriefComment=[Ddd eee. Fff.]
// CHECK: annotate-comments.cpp:205:6: FunctionDecl=isdoxy46:{{.*}} BriefComment=[Ddd eee. Fff.]
+// CHECK: annotate-comments.cpp:209:6: FunctionDecl=isdoxy47:{{.*}} isdoxy47 IS_DOXYGEN_SINGLE
// CHECK: annotate-comments.cpp:214:6: FunctionDecl=isdoxy48:{{.*}} BriefComment=[IS_DOXYGEN_START Aaa bbb]
// CHECK: annotate-comments.cpp:218:6: FunctionDecl=isdoxy49:{{.*}} BriefComment=[IS_DOXYGEN_START Aaa]
// CHECK: annotate-comments.cpp:222:6: FunctionDecl=isdoxy50:{{.*}} BriefComment=[Returns ddd IS_DOXYGEN_END]
diff --git a/clang/unittests/AST/DeclTest.cpp b/clang/unittests/AST/DeclTest.cpp
index 2530ce74eb6a37..e5c1a578864292 100644
--- a/clang/unittests/AST/DeclTest.cpp
+++ b/clang/unittests/AST/DeclTest.cpp
@@ -545,3 +545,313 @@ TEST(Decl, TemplateArgumentDefaulted) {
EXPECT_TRUE(ArgList.get(2).getIsDefaulted());
EXPECT_TRUE(ArgList.get(3).getIsDefaulted());
}
+
+TEST(Decl, CommentsAttachedToDecl1) {
+ const SmallVector<StringRef> Sources{
+ R"(
+ /// Test comment
+ void f();
+ )",
+
+ R"(
+ /// Test comment
+
+ void f();
+ )",
+
+ R"(
+ /// Test comment
+ #if 0
+ // tralala
+ #endif
+ void f();
+ )",
+
+ R"(
+ /// Test comment
+
+ #if 0
+ // tralala
+ #endif
+
+ void f();
+ )",
+
+ R"(
+ /// Test comment
+ #ifdef DOCS
+ template<typename T>
+ #endif
+ void f();
+ )",
+
+ R"(
+ /// Test comment
+
+ #ifdef DOCS
+ template<typename T>
+ #endif
+
+ void f();
+ )",
+ };
+
+ for (const auto code : Sources) {
+ auto AST = tooling::buildASTFromCodeWithArgs(code, /*Args=*/{"-std=c++20"});
+ ASTContext &Ctx = AST->getASTContext();
+
+ auto const *F = selectFirst<FunctionDecl>(
+ "id", match(functionDecl(hasName("f")).bind("id"), Ctx));
+ ASSERT_NE(F, nullptr);
+
+ auto const *C = Ctx.getRawCommentForDeclNoCache(F);
+ ASSERT_NE(C, nullptr);
+ EXPECT_EQ(C->getRawText(Ctx.getSourceManager()), "/// Test comment");
+ }
+}
+
+TEST(Decl, CommentsAttachedToDecl2) {
+ const SmallVector<StringRef> Sources{
+ R"(
+ /** Test comment
+ */
+ void f();
+ )",
+
+ R"(
+ /** Test comment
+ */
+
+ void f();
+ )",
+
+ R"(
+ /** Test comment
+ */
+ #if 0
+ /* tralala */
+ #endif
+ void f();
+ )",
+
+ R"(
+ /** Test comment
+ */
+
+ #if 0
+ /* tralala */
+ #endif
+
+ void f();
+ )",
+
+ R"(
+ /** Test comment
+ */
+ #ifdef DOCS
+ template<typename T>
+ #endif
+ void f();
+ )",
+
+ R"(
+ /** Test comment
+ */
+
+ #ifdef DOCS
+ template<typename T>
+ #endif
+
+ void f();
+ )",
+ };
+
+ for (const auto code : Sources) {
+ auto AST = tooling::buildASTFromCodeWithArgs(code, /*Args=*/{"-std=c++20"});
+ ASTContext &Ctx = AST->getASTContext();
+
+ auto const *F = selectFirst<FunctionDecl>(
+ "id", match(functionDecl(hasName("f")).bind("id"), Ctx));
+ ASSERT_NE(F, nullptr);
+
+ auto const *C = Ctx.getRawCommentForDeclNoCache(F);
+ ASSERT_NE(C, nullptr);
+ EXPECT_EQ(C->getRawText(Ctx.getSourceManager()),
+ "/** Test comment\n */");
+ }
+}
+
+TEST(Decl, CommentsAttachedToDecl3) {
+ const SmallVector<StringRef> Sources{
+ R"(
+ /// @brief Test comment
+ void f();
+ )",
+
+ R"(
+ /// @brief Test comment
+
+ void f();
+ )",
+
+ R"(
+ /// @brief Test comment
+ #if 0
+ // tralala
+ #endif
+ void f();
+ )",
+
+ R"(
+ /// @brief Test comment
+
+ #if 0
+ // tralala
+ #endif
+
+ void f();
+ )",
+
+ R"(
+ /// @brief Test comment
+ #ifdef DOCS
+ template<typename T>
+ #endif
+ void f();
+ )",
+
+ R"(
+ /// @brief Test comment
+
+ #ifdef DOCS
+ template<typename T>
+ #endif
+
+ void f();
+ )",
+ };
+
+ for (const auto code : Sources) {
+ auto AST = tooling::buildASTFromCodeWithArgs(code, /*Args=*/{"-std=c++20"});
+ ASTContext &Ctx = AST->getASTContext();
+
+ auto const *F = selectFirst<FunctionDecl>(
+ "id", match(functionDecl(hasName("f")).bind("id"), Ctx));
+ ASSERT_NE(F, nullptr);
+
+ auto const *C = Ctx.getRawCommentForDeclNoCache(F);
+ ASSERT_NE(C, nullptr);
+ EXPECT_EQ(C->getRawText(Ctx.getSourceManager()), "/// @brief Test comment");
+ }
+}
+
+TEST(Decl, CommentsAttachedToDecl4) {
+ const SmallVector<StringRef> Sources{
+ R"(
+ /** \brief Test comment
+ */
+ void f();
+ )",
+
+ R"(
+ /** \brief Test comment
+ */
+
+ void f();
+ )",
+
+ R"(
+ /** \brief Test comment
+ */
+ #if 0
+ /* tralala */
+ #endif
+ void f();
+ )",
+
+ R"(
+ /** \brief Test comment
+ */
+
+ #if 0
+ /* tralala */
+ #endif
+
+ void f();
+ )",
+
+ R"(
+ /** \brief Test comment
+ */
+ #ifdef DOCS
+ template<typename T>
+ #endif
+ void f();
+ )",
+
+ R"(
+ /** \brief Test comment
+ */
+
+ #ifdef DOCS
+ template<typename T>
+ #endif
+
+ void f();
+ )",
+ };
+
+ for (const auto code : Sources) {
+ auto AST = tooling::buildASTFromCodeWithArgs(code, /*Args=*/{"-std=c++20"});
+ ASTContext &Ctx = AST->getASTContext();
+
+ auto const *F = selectFirst<FunctionDecl>(
+ "id", match(functionDecl(hasName("f")).bind("id"), Ctx));
+ ASSERT_NE(F, nullptr);
+
+ auto const *C = Ctx.getRawCommentForDeclNoCache(F);
+ ASSERT_NE(C, nullptr);
+ EXPECT_EQ(C->getRawText(Ctx.getSourceManager()),
+ "/** \\brief Test comment\n */");
+ }
+}
+
+/// This example intentionally inserts characters between a doc comment and the
+/// associated declaration to verify that the comment does not become associated
+/// with the FunctionDecl.
+/// By default, Clang does not allow for other declarations (aside from
+/// preprocessor directives, as shown above) to be placed between a doc comment
+/// and a declaration.
+TEST(Decl, CommentsAttachedToDecl5) {
+ const SmallVector<StringRef> Sources{
+ R"(
+ /// Test comment
+ ;
+ void f();
+ )",
+
+ R"(
+ /// Test comment
+ // @
+ void f();
+ )",
+
+ R"(
+ /// Test comment
+ // {}
+ void f();
+ )",
+ };
+
+ for (const auto code : Sources) {
+ auto AST = tooling::buildASTFromCodeWithArgs(code, /*Args=*/{"-std=c++20"});
+ ASTContext &Ctx = AST->getASTContext();
+
+ auto const *F = selectFirst<FunctionDecl>(
+ "id", match(functionDecl(hasName("f")).bind("id"), Ctx));
+ ASSERT_NE(F, nullptr);
+
+ auto const *C = Ctx.getRawCommentForDeclNoCache(F);
+ ASSERT_EQ(C, nullptr);
+ }
+}
More information about the cfe-commits
mailing list