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