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