xref: /llvm-project/clang/unittests/AST/RawCommentForDeclTest.cpp (revision ea578804c81bbad1f31a0c940c8f4378d6893ede)
1 //===- unittests/AST/RawCommentForDeclTestTest.cpp
2 //-------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "clang/AST/ASTConsumer.h"
11 #include "clang/AST/DeclGroup.h"
12 #include "clang/Frontend/CompilerInstance.h"
13 #include "clang/Frontend/FrontendAction.h"
14 #include "clang/Tooling/Tooling.h"
15 
16 #include "gmock/gmock-matchers.h"
17 #include "gtest/gtest.h"
18 
19 namespace clang {
20 
21 struct FoundComment {
22   std::string DeclName;
23   bool IsDefinition;
24   std::string Comment;
25 
26   bool operator==(const FoundComment &RHS) const {
27     return DeclName == RHS.DeclName && IsDefinition == RHS.IsDefinition &&
28            Comment == RHS.Comment;
29   }
30   friend llvm::raw_ostream &operator<<(llvm::raw_ostream &Stream,
31                                        const FoundComment &C) {
32     return Stream << "{Name: " << C.DeclName << ", Def: " << C.IsDefinition
33                   << ", Comment: " << C.Comment << "}";
34   }
35 };
36 
37 class CollectCommentsAction : public ASTFrontendAction {
38 public:
39   CollectCommentsAction(std::vector<FoundComment> &Comments)
40       : Comments(Comments) {}
41 
42   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
43                                                  llvm::StringRef) override {
44     CI.getLangOpts().CommentOpts.ParseAllComments = true;
45     return std::make_unique<Consumer>(*this);
46   }
47 
48   std::vector<FoundComment> &Comments;
49 
50 private:
51   class Consumer : public clang::ASTConsumer {
52   private:
53     CollectCommentsAction &Action;
54 
55   public:
56     Consumer(CollectCommentsAction &Action) : Action(Action) {}
57 
58     bool HandleTopLevelDecl(DeclGroupRef DG) override {
59       for (Decl *D : DG) {
60         if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
61           auto &Ctx = D->getASTContext();
62           const auto *RC = Ctx.getRawCommentForAnyRedecl(D);
63           Action.Comments.push_back(FoundComment{
64               ND->getNameAsString(), IsDefinition(D),
65               RC ? RC->getRawText(Ctx.getSourceManager()).str() : ""});
66         }
67       }
68 
69       return true;
70     }
71 
72     static bool IsDefinition(const Decl *D) {
73       if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
74         return FD->isThisDeclarationADefinition();
75       }
76       if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
77         return TD->isThisDeclarationADefinition();
78       }
79       return false;
80     }
81   };
82 };
83 
84 TEST(RawCommentForDecl, DefinitionComment) {
85   std::vector<FoundComment> Comments;
86   auto Action = std::make_unique<CollectCommentsAction>(Comments);
87   ASSERT_TRUE(tooling::runToolOnCode(std::move(Action), R"cpp(
88     void f();
89 
90     // f is the best
91     void f() {}
92   )cpp"));
93   EXPECT_THAT(Comments, testing::ElementsAre(
94                             FoundComment{"f", false, ""},
95                             FoundComment{"f", true, "// f is the best"}));
96 }
97 
98 } // namespace clang
99