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