llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Doug Gregor (DougGregor)

<details>
<summary>Changes</summary>

Generalize the infrastructure that finds comments attached to declarations to 
also find comments attached to macros. Surface these comments through libclang 
and the symbol graph.

Fixes issue #<!-- -->83819.

---

Patch is 23.57 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/198452.diff


8 Files Affected:

- (modified) clang/include/clang/AST/ASTContext.h (+23-14) 
- (modified) clang/include/clang/ExtractAPI/API.h (+3-2) 
- (modified) clang/lib/AST/ASTContext.cpp (+72-18) 
- (modified) clang/lib/ExtractAPI/ExtractAPIConsumer.cpp (+17-8) 
- (added) clang/test/ExtractAPI/macro_doc_comments.c (+67) 
- (added) clang/test/Index/annotate-comments-macros.c (+27) 
- (modified) clang/test/Index/annotate-comments.cpp (+2-1) 
- (modified) clang/tools/libclang/CIndex.cpp (+27-23) 


``````````diff
diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index b2fd522e6865c..5e95c1971f33d 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -30,6 +30,7 @@
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/MacroInfo.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseMapInfo.h"
 #include "llvm/ADT/DenseSet.h"
@@ -996,11 +997,16 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// True if comments are already loaded from ExternalASTSource.
   mutable bool CommentsLoaded = false;
 
-  /// Mapping from declaration to directly attached comment.
+  /// Key used to look up the raw comment attached to a declaration or macro.
+  using RawCommentLookupKey =
+      llvm::PointerUnion<const Decl *, const MacroInfo *>;
+
+  /// Mapping from declaration or macro to directly attached comment.
   ///
   /// Raw comments are owned by Comments list.  This mapping is populated
   /// lazily.
-  mutable llvm::DenseMap<const Decl *, const RawComment *> DeclRawComments;
+  mutable llvm::DenseMap<RawCommentLookupKey, const RawComment *>
+      DeclRawComments;
 
   /// Mapping from canonical declaration to the first redeclaration in chain
   /// that has a comment attached.
@@ -1022,37 +1028,40 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// redeclaration.
   mutable llvm::DenseMap<const Decl *, comments::FullComment *> ParsedComments;
 
-  /// Attaches \p Comment to \p OriginalD and to its redeclaration chain
-  /// and removes the redeclaration chain from the set of commentless chains.
+  /// Attaches \p Comment to \p Original (a declaration or macro), and to its
+  /// redeclaration chain when \p Original is a declaration. Removes the
+  /// redeclaration chain from the set of commentless chains.
   ///
-  /// Don't do anything if a comment has already been attached to \p OriginalD
+  /// Don't do anything if a comment has already been attached to \p Original
   /// or its redeclaration chain.
-  void cacheRawCommentForDecl(const Decl &OriginalD,
+  void cacheRawCommentForDecl(RawCommentLookupKey Original,
                               const RawComment &Comment) const;
 
-  /// \returns searches \p CommentsInFile for doc comment for \p D.
+  /// \returns searches \p CommentsInFile for doc comment for \p Key.
   ///
   /// \p RepresentativeLocForDecl is used as a location for searching doc
   /// comments. \p CommentsInFile is a mapping offset -> comment of files in 
the
   /// same file where \p RepresentativeLocForDecl is.
   RawComment *getRawCommentForDeclNoCacheImpl(
-      const Decl *D, const SourceLocation RepresentativeLocForDecl,
+      RawCommentLookupKey Key, const SourceLocation RepresentativeLocForDecl,
       const std::map<unsigned, RawComment *> &CommentsInFile) const;
 
-  /// Return the documentation comment attached to a given declaration,
-  /// without looking into cache.
-  RawComment *getRawCommentForDeclNoCache(const Decl *D) const;
+  /// Return the documentation comment attached to a given declaration or
+  /// macro, without looking into cache.
+  RawComment *getRawCommentForDeclNoCache(RawCommentLookupKey Key) const;
 
 public:
   void addComment(const RawComment &RC);
 
-  /// Return the documentation comment attached to a given declaration.
-  /// Returns nullptr if no comment is attached.
+  /// Return the documentation comment attached to a given declaration or
+  /// macro.  Returns nullptr if no comment is attached.
   ///
   /// \param OriginalDecl if not nullptr, is set to declaration AST node that
   /// had the comment, if the comment we found comes from a redeclaration.
+  /// Macros have no redeclaration chain, so this is set to nullptr when
+  /// \p Key is a \c MacroInfo.
   const RawComment *
-  getRawCommentForAnyRedecl(const Decl *D,
+  getRawCommentForAnyRedecl(RawCommentLookupKey Key,
                             const Decl **OriginalDecl = nullptr) const;
 
   /// Searches existing comments for doc comments that should be attached to \p
diff --git a/clang/include/clang/ExtractAPI/API.h 
b/clang/include/clang/ExtractAPI/API.h
index bea5416a626b9..62483bcf2cdc9 100644
--- a/clang/include/clang/ExtractAPI/API.h
+++ b/clang/include/clang/ExtractAPI/API.h
@@ -1380,11 +1380,12 @@ struct ObjCProtocolRecord : ObjCContainerRecord {
 /// This holds information associated with macro definitions.
 struct MacroDefinitionRecord : APIRecord {
   MacroDefinitionRecord(StringRef USR, StringRef Name, SymbolReference Parent,
-                        PresumedLoc Loc, DeclarationFragments Declaration,
+                        PresumedLoc Loc, const DocComment &Comment,
+                        DeclarationFragments Declaration,
                         DeclarationFragments SubHeading,
                         bool IsFromSystemHeader)
       : APIRecord(RK_MacroDefinition, USR, Name, Parent, Loc,
-                  AvailabilityInfo(), LinkageInfo(), {}, Declaration,
+                  AvailabilityInfo(), LinkageInfo(), Comment, Declaration,
                   SubHeading, IsFromSystemHeader) {}
 
   static bool classof(const APIRecord *Record) {
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index bc4771aec77d1..6621789a7c1a8 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -66,6 +66,7 @@
 #include "clang/Basic/TargetCXXABI.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/XRayLists.h"
+#include "clang/Lex/MacroInfo.h"
 #include "llvm/ADT/APFixedPoint.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/APSInt.h"
@@ -116,9 +117,38 @@ enum FloatingRank {
 };
 
 /// \returns The locations that are relevant when searching for Doc comments
-/// related to \p D.
+/// related to \p Key.
 static SmallVector<SourceLocation, 2>
-getDeclLocsForCommentSearch(const Decl *D, SourceManager &SourceMgr) {
+getDeclLocsForCommentSearch(ASTContext::RawCommentLookupKey Key,
+                            SourceManager &SourceMgr) {
+  if (const auto *MI = dyn_cast<const MacroInfo *>(Key)) {
+    SourceLocation DefLoc = MI->getDefinitionLoc();
+    if (DefLoc.isInvalid() || !DefLoc.isFileID())
+      return {};
+
+    // The macro's definition location points at its name (e.g. FOO in
+    // `#define FOO 1`). The text between a preceding documentation comment
+    // and the name contains the `#define` directive itself, which would be
+    // rejected by the preprocessor-directive guard in
+    // getRawCommentForDeclNoCacheImpl. Walk back to the leading `#` so that
+    // the guard only fires when something *else* sits between the comment
+    // and our directive.
+    FileIDAndOffset Decomposed = SourceMgr.getDecomposedLoc(DefLoc);
+    bool Invalid = false;
+    StringRef Buffer = SourceMgr.getBufferData(Decomposed.first, &Invalid);
+    if (Invalid)
+      return {};
+    unsigned Offset = Decomposed.second;
+    while (Offset > 0 && Buffer[Offset - 1] != '#' &&
+           Buffer[Offset - 1] != '\n')
+      --Offset;
+    if (Offset > 0 && Buffer[Offset - 1] == '#')
+      --Offset;
+    return {SourceMgr.getLocForStartOfFile(Decomposed.first)
+                .getLocWithOffset(Offset)};
+  }
+
+  const auto *D = cast<const Decl *>(Key);
   assert(D);
 
   // User can not attach documentation to implicit declarations.
@@ -215,7 +245,7 @@ getDeclLocsForCommentSearch(const Decl *D, SourceManager 
&SourceMgr) {
 }
 
 RawComment *ASTContext::getRawCommentForDeclNoCacheImpl(
-    const Decl *D, const SourceLocation RepresentativeLocForDecl,
+    RawCommentLookupKey Key, const SourceLocation RepresentativeLocForDecl,
     const std::map<unsigned, RawComment *> &CommentsInTheFile) const {
   // If the declaration doesn't map directly to a location in a file, we
   // can't find the comment.
@@ -227,6 +257,9 @@ RawComment *ASTContext::getRawCommentForDeclNoCacheImpl(
   if (CommentsInTheFile.empty())
     return nullptr;
 
+  const auto *D = dyn_cast<const Decl *>(Key);
+  const bool IsMacro = isa<const MacroInfo *>(Key);
+
   // Decompose the location for the declaration and find the beginning of the
   // file buffer.
   const FileIDAndOffset DeclLocDecomp =
@@ -242,8 +275,10 @@ RawComment *ASTContext::getRawCommentForDeclNoCacheImpl(
     if ((CommentBehindDecl->isDocumentation() ||
          LangOpts.CommentOpts.ParseAllComments) &&
         CommentBehindDecl->isTrailingComment() &&
-        (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D) ||
-         isa<ObjCMethodDecl>(D) || isa<ObjCPropertyDecl>(D))) {
+        (IsMacro ||
+         (D && (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) ||
+                isa<VarDecl>(D) || isa<ObjCMethodDecl>(D) ||
+                isa<ObjCPropertyDecl>(D))))) {
 
       // Check that Doxygen trailing comment comes after the declaration, 
starts
       // on the same line and in the same file as the declaration.
@@ -292,8 +327,9 @@ RawComment *ASTContext::getRawCommentForDeclNoCacheImpl(
   return CommentBeforeDecl;
 }
 
-RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
-  const auto DeclLocs = getDeclLocsForCommentSearch(D, SourceMgr);
+RawComment *
+ASTContext::getRawCommentForDeclNoCache(RawCommentLookupKey Key) const {
+  const auto DeclLocs = getDeclLocsForCommentSearch(Key, SourceMgr);
 
   for (const auto DeclLoc : DeclLocs) {
     // If the declaration doesn't map directly to a location in a file, we
@@ -318,7 +354,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const 
Decl *D) const {
       continue;
 
     if (RawComment *Comment =
-            getRawCommentForDeclNoCacheImpl(D, DeclLoc, *CommentsInThisFile))
+            getRawCommentForDeclNoCacheImpl(Key, DeclLoc, *CommentsInThisFile))
       return Comment;
   }
 
@@ -332,14 +368,30 @@ void ASTContext::addComment(const RawComment &RC) {
 }
 
 const RawComment *ASTContext::getRawCommentForAnyRedecl(
-                                                const Decl *D,
+                                                RawCommentLookupKey Key,
                                                 const Decl **OriginalDecl) 
const {
-  if (!D) {
+  if (Key.isNull()) {
     if (OriginalDecl)
-      OriginalDecl = nullptr;
+      *OriginalDecl = nullptr;
     return nullptr;
   }
 
+  // Macros have no redeclaration chain: look up directly, populate the cache,
+  // and return.
+  if (const auto *MI = dyn_cast<const MacroInfo *>(Key)) {
+    if (OriginalDecl)
+      *OriginalDecl = nullptr;
+    auto Existing = DeclRawComments.find(Key);
+    if (Existing != DeclRawComments.end())
+      return Existing->second;
+    if (const RawComment *RC = getRawCommentForDeclNoCache(Key)) {
+      cacheRawCommentForDecl(MI, *RC);
+      return RC;
+    }
+    return nullptr;
+  }
+
+  const Decl *D = cast<const Decl *>(Key);
   D = &adjustDeclToTemplate(*D);
 
   // Any comment directly attached to D?
@@ -400,7 +452,7 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl(
     }
     const RawComment *RedeclComment = getRawCommentForDeclNoCache(Redecl);
     if (RedeclComment) {
-      cacheRawCommentForDecl(*Redecl, *RedeclComment);
+      cacheRawCommentForDecl(Redecl, *RedeclComment);
       if (OriginalDecl)
         *OriginalDecl = Redecl;
       return RedeclComment;
@@ -413,13 +465,15 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl(
   return nullptr;
 }
 
-void ASTContext::cacheRawCommentForDecl(const Decl &OriginalD,
+void ASTContext::cacheRawCommentForDecl(RawCommentLookupKey Original,
                                         const RawComment &Comment) const {
   assert(Comment.isDocumentation() || LangOpts.CommentOpts.ParseAllComments);
-  DeclRawComments.try_emplace(&OriginalD, &Comment);
-  const Decl *const CanonicalDecl = OriginalD.getCanonicalDecl();
-  RedeclChainComments.try_emplace(CanonicalDecl, &OriginalD);
-  CommentlessRedeclChains.erase(CanonicalDecl);
+  DeclRawComments.try_emplace(Original, &Comment);
+  if (const auto *D = dyn_cast<const Decl *>(Original)) {
+    const Decl *const CanonicalDecl = D->getCanonicalDecl();
+    RedeclChainComments.try_emplace(CanonicalDecl, D);
+    CommentlessRedeclChains.erase(CanonicalDecl);
+  }
 }
 
 static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod,
@@ -492,7 +546,7 @@ void 
ASTContext::attachCommentsToJustParsedDecls(ArrayRef<Decl *> Decls,
 
       if (RawComment *const DocComment = getRawCommentForDeclNoCacheImpl(
               D, DeclLoc, *CommentsInThisFile)) {
-        cacheRawCommentForDecl(*D, *DocComment);
+        cacheRawCommentForDecl(D, *DocComment);
         comments::FullComment *FC = DocComment->parse(*this, PP, D);
         ParsedComments[D->getCanonicalDecl()] = FC;
         break;
diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp 
b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
index 20389b5e4149d..92c722d9f06bb 100644
--- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
+++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
@@ -282,8 +282,9 @@ class ExtractAPIConsumer : public ASTConsumer {
 
 class MacroCallback : public PPCallbacks {
 public:
-  MacroCallback(const SourceManager &SM, APISet &API, Preprocessor &PP)
-      : SM(SM), API(API), PP(PP) {}
+  MacroCallback(ASTContext &Ctx, const SourceManager &SM, APISet &API,
+                Preprocessor &PP)
+      : Ctx(Ctx), SM(SM), API(API), PP(PP) {}
 
   void EndOfMainFile() override {
     for (const auto &M : PP.macros()) {
@@ -321,8 +322,13 @@ class MacroCallback : public PPCallbacks {
       PresumedLoc Loc = SM.getPresumedLoc(DefLoc);
       SmallString<128> USR;
       index::generateUSRForMacro(Name, DefLoc, SM, USR);
+
+      DocComment Comment;
+      if (const auto *RC = Ctx.getRawCommentForAnyRedecl(MI))
+        Comment = RC->getFormattedLines(SM, Ctx.getDiagnostics());
+
       API.createRecord<extractapi::MacroDefinitionRecord>(
-          USR, Name, SymbolReference(), Loc,
+          USR, Name, SymbolReference(), Loc, Comment,
           DeclarationFragmentsBuilder::getFragmentsForMacro(Name, MI),
           DeclarationFragmentsBuilder::getSubHeadingForMacro(Name),
           SM.isInSystemHeader(DefLoc));
@@ -334,6 +340,7 @@ class MacroCallback : public PPCallbacks {
     return true;
   }
 
+  ASTContext &Ctx;
   const SourceManager &SM;
   APISet &API;
   Preprocessor &PP;
@@ -341,9 +348,9 @@ class MacroCallback : public PPCallbacks {
 
 class APIMacroCallback : public MacroCallback {
 public:
-  APIMacroCallback(const SourceManager &SM, APISet &API, Preprocessor &PP,
-                   LocationFileChecker &LCF)
-      : MacroCallback(SM, API, PP), LCF(LCF) {}
+  APIMacroCallback(ASTContext &Ctx, const SourceManager &SM, APISet &API,
+                   Preprocessor &PP, LocationFileChecker &LCF)
+      : MacroCallback(Ctx, SM, API, PP), LCF(LCF) {}
 
   bool shouldMacroBeIncluded(const SourceLocation &MacroLoc,
                              StringRef ModuleName) override {
@@ -415,7 +422,8 @@ ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, 
StringRef InFile) {
   auto LCF = std::make_unique<LocationFileChecker>(CI, KnownInputFiles);
 
   CI.getPreprocessor().addPPCallbacks(std::make_unique<APIMacroCallback>(
-      CI.getSourceManager(), *API, CI.getPreprocessor(), *LCF));
+      CI.getASTContext(), CI.getSourceManager(), *API, CI.getPreprocessor(),
+      *LCF));
 
   // Do not include location in anonymous decls.
   PrintingPolicy Policy = CI.getASTContext().getPrintingPolicy();
@@ -519,7 +527,8 @@ 
WrappingExtractAPIAction::CreateASTConsumer(CompilerInstance &CI,
       CI.getFrontendOpts().Inputs.back().getKind().getLanguage(), ProductName);
 
   CI.getPreprocessor().addPPCallbacks(std::make_unique<MacroCallback>(
-      CI.getSourceManager(), *API, CI.getPreprocessor()));
+      CI.getASTContext(), CI.getSourceManager(), *API,
+      CI.getPreprocessor()));
 
   // Do not include location in anonymous decls.
   PrintingPolicy Policy = CI.getASTContext().getPrintingPolicy();
diff --git a/clang/test/ExtractAPI/macro_doc_comments.c 
b/clang/test/ExtractAPI/macro_doc_comments.c
new file mode 100644
index 0000000000000..d1d5e41574eb7
--- /dev/null
+++ b/clang/test/ExtractAPI/macro_doc_comments.c
@@ -0,0 +1,67 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -extract-api --pretty-sgf 
--emit-sgf-symbol-labels-for-testing --product-name=MacroDoc -triple 
arm64-apple-macosx \
+// RUN:   -fretain-comments-from-system-headers -isystem %S -x 
objective-c-header %s -o %t/output.symbols.json
+
+// Verify documentation comments attached to `#define` macros end up in the
+// symbol graph as a `docComment` block.
+
+// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix HELLO
+/// The greeting count.
+#define HELLO 1
+// HELLO-LABEL: "!testLabel": "c:@macro@HELLO"
+// HELLO:      "docComment": {
+// HELLO-NEXT:   "lines": [
+// HELLO:          "text": "The greeting count."
+// HELLO:        ]
+// HELLO-NEXT: },
+
+// A C-style block doc comment also attaches.
+// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix BLOCK
+/**
+ * \brief A version number.
+ */
+#define VERSION 42
+// BLOCK-LABEL: "!testLabel": "c:@macro@VERSION"
+// BLOCK:      "docComment": {
+// BLOCK-NEXT:   "lines": [
+// BLOCK:          "text": " \\brief A version number."
+// BLOCK:        ]
+// BLOCK-NEXT: },
+
+// Function-like macros pick up their preceding doc comment.
+// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix SUM
+/// Add two numbers.
+#define SUM(x, y) ((x) + (y))
+// SUM-LABEL: "!testLabel": "c:@macro@SUM"
+// SUM:      "docComment": {
+// SUM-NEXT:   "lines": [
+// SUM:          "text": "Add two numbers."
+// SUM:        ]
+// SUM-NEXT: },
+
+// Trailing `///<` doc comments attach to macros, just like fields/enumerators.
+// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix TRAIL
+#define ANSWER 42 ///< The answer.
+// TRAIL-LABEL: "!testLabel": "c:@macro@ANSWER"
+// TRAIL:      "docComment": {
+// TRAIL-NEXT:   "lines": [
+// TRAIL:          "text": "The answer."
+// TRAIL:        ]
+// TRAIL-NEXT: },
+
+// A macro with no documentation comment must NOT have a `docComment` key.
+// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix BARE
+#define BARE 7
+// BARE-LABEL: "!testLabel": "c:@macro@BARE"
+// BARE-NOT:   "docComment"
+// BARE:       "kind":
+
+// A non-doc `//` comment must not be attached as a docComment.
+// RUN: FileCheck %s --input-file %t/output.symbols.json --check-prefix PLAIN
+// just an ordinary comment, not Doxygen
+#define PLAIN 8
+// PLAIN-LABEL: "!testLabel": "c:@macro@PLAIN"
+// PLAIN-NOT:   "docComment"
+// PLAIN:       "kind":
+
+// expected-no-diagnostics
diff --git a/clang/test/Index/annotate-comments-macros.c 
b/clang/test/Index/annotate-comments-macros.c
new file mode 100644
index 0000000000000..0dfa52906a04a
--- /dev/null
+++ b/clang/test/Index/annotate-comments-macros.c
@@ -0,0 +1,27 @@
+// Run lines are sensitive to line numbers and come below the code.
+
+/// Greeting count.
+#define HELLO 1
+
+#define BARE 2
+
+/**
+ * \brief Add two numbers.
+ */
+#define SUM(x, y) ((x) + (y))
+
+#define TRAILING 3 ///< Trailing macro doc.
+
+// RUN: c-index-test -test-load-source all %s | FileCheck %s
+
+// Documented object-like macro picks up the preceding `///` comment.
+// CHECK: annotate-comments-macros.c:4:9: macro definition=HELLO 
RawComment=[/// Greeting count.] RawCommentRange=[3:1 - 3:20] 
BriefComment=[Greeting count.]
+
+// A macro without any preceding doc comment must not have a RawComment.
+// CHECK: annotate-comments-macros.c:6:9: macro definition=BARE Extent=
+
+// Function-like macros are documented just like object-like ones.
+// CHECK: annotate-comments-macros.c:11:9: macro definition=SUM 
RawComment=[/**\n * \brief Add two numbers.\n */] RawCommentRange=[8:1 - 10:4] 
BriefComment=[Add two numbers.]
+
+// Trailing `///<` comments attach to macros, mirroring fields/enumerators.
+// CHECK: annotate-comments-macros.c:13:9: macro definition=TRAILING 
RawComment=[///< Trailing macro doc.] RawCommentRange=[13:20 - 13:44] 
BriefComment=[Trailing macro doc.]
diff --git a/clang/test/Index/annotate-comments.cpp 
b/clang/test/Index/annotate-comments.cpp
index 6f9f8f0bbbc9e..17e7beb1b7ca6 100644
--- a/clang/test/Index/annotate-comments.cpp
+++ b/clang/test/Index/annotate-comments.cpp
@@ -204,7 +204,7 @@ void isdoxy45(void);
 /// Ggg. IS_DOXYGEN_E...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/198452
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to