1 //===- unittest/AST/RecursiveASTVisitorTest.cpp ---------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "clang/AST/RecursiveASTVisitor.h"
10 #include "clang/AST/ASTConsumer.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/AST/Attr.h"
13 #include "clang/Frontend/FrontendAction.h"
14 #include "clang/Tooling/Tooling.h"
15 #include "llvm/ADT/FunctionExtras.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
21 using namespace clang
;
22 using ::testing::ElementsAre
;
25 class ProcessASTAction
: public clang::ASTFrontendAction
{
27 ProcessASTAction(llvm::unique_function
<void(clang::ASTContext
&)> Process
)
28 : Process(std::move(Process
)) {
29 assert(this->Process
);
32 std::unique_ptr
<ASTConsumer
> CreateASTConsumer(CompilerInstance
&CI
,
34 class Consumer
: public ASTConsumer
{
36 Consumer(llvm::function_ref
<void(ASTContext
&CTx
)> Process
)
39 void HandleTranslationUnit(ASTContext
&Ctx
) override
{ Process(Ctx
); }
42 llvm::function_ref
<void(ASTContext
&CTx
)> Process
;
45 return std::make_unique
<Consumer
>(Process
);
49 llvm::unique_function
<void(clang::ASTContext
&)> Process
;
52 enum class VisitEvent
{
53 StartTraverseFunction
,
59 class CollectInterestingEvents
60 : public RecursiveASTVisitor
<CollectInterestingEvents
> {
62 bool TraverseFunctionDecl(FunctionDecl
*D
) {
63 Events
.push_back(VisitEvent::StartTraverseFunction
);
64 bool Ret
= RecursiveASTVisitor::TraverseFunctionDecl(D
);
65 Events
.push_back(VisitEvent::EndTraverseFunction
);
70 bool TraverseAttr(Attr
*A
) {
71 Events
.push_back(VisitEvent::StartTraverseAttr
);
72 bool Ret
= RecursiveASTVisitor::TraverseAttr(A
);
73 Events
.push_back(VisitEvent::EndTraverseAttr
);
78 std::vector
<VisitEvent
> takeEvents() && { return std::move(Events
); }
81 std::vector
<VisitEvent
> Events
;
84 std::vector
<VisitEvent
> collectEvents(llvm::StringRef Code
) {
85 CollectInterestingEvents Visitor
;
86 clang::tooling::runToolOnCode(
87 std::make_unique
<ProcessASTAction
>(
88 [&](clang::ASTContext
&Ctx
) { Visitor
.TraverseAST(Ctx
); }),
90 return std::move(Visitor
).takeEvents();
94 TEST(RecursiveASTVisitorTest
, AttributesInsideDecls
) {
95 /// Check attributes are traversed inside TraverseFunctionDecl.
96 llvm::StringRef Code
= R
"cpp(
97 __attribute__((annotate("something
"))) int foo() { return 10; }
100 EXPECT_THAT(collectEvents(Code
),
101 ElementsAre(VisitEvent::StartTraverseFunction
,
102 VisitEvent::StartTraverseAttr
,
103 VisitEvent::EndTraverseAttr
,
104 VisitEvent::EndTraverseFunction
));