1 //===- unittests/Analysis/FlowSensitive/MatchSwitchTest.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/Analysis/FlowSensitive/MatchSwitch.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/Decl.h"
12 #include "clang/AST/DeclCXX.h"
13 #include "clang/AST/Expr.h"
14 #include "clang/AST/Stmt.h"
15 #include "clang/ASTMatchers/ASTMatchFinder.h"
16 #include "clang/ASTMatchers/ASTMatchers.h"
17 #include "clang/Tooling/Tooling.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "gtest/gtest.h"
26 using namespace clang
;
27 using namespace dataflow
;
28 using namespace ast_matchers
;
32 TEST(MatchSwitchTest
, Stmts
) {
33 std::string Code
= R
"(
42 auto Unit
= tooling::buildASTFromCode(Code
);
43 auto &Ctx
= Unit
->getASTContext();
45 llvm::StringRef XStr
= "X";
46 llvm::StringRef FooStr
= "Foo";
47 llvm::StringRef BarStr
= "Bar";
49 auto XMatcher
= declStmt(hasSingleDecl(varDecl(hasName(XStr
))));
50 auto FooMatcher
= callExpr(callee(functionDecl(hasName(FooStr
))));
51 auto BarMatcher
= callExpr(callee(functionDecl(hasName(BarStr
))));
53 ASTMatchSwitch
<Stmt
, llvm::StringRef
> MS
=
54 ASTMatchSwitchBuilder
<Stmt
, llvm::StringRef
>()
55 .CaseOf
<Stmt
>(XMatcher
,
56 [&XStr
](const Stmt
*, const MatchFinder::MatchResult
&,
57 llvm::StringRef
&State
) { State
= XStr
; })
58 .CaseOf
<Stmt
>(FooMatcher
,
59 [&FooStr
](const Stmt
*,
60 const MatchFinder::MatchResult
&,
61 llvm::StringRef
&State
) { State
= FooStr
; })
63 llvm::StringRef State
;
65 // State modified from the first case of the switch
66 const auto *X
= selectFirst
<Stmt
>(XStr
, match(XMatcher
.bind(XStr
), Ctx
));
68 EXPECT_EQ(State
, XStr
);
70 // State modified from the second case of the switch
72 selectFirst
<Stmt
>(FooStr
, match(FooMatcher
.bind(FooStr
), Ctx
));
74 EXPECT_EQ(State
, FooStr
);
76 // State unmodified, no case defined for calling Bar
78 selectFirst
<Stmt
>(BarStr
, match(BarMatcher
.bind(BarStr
), Ctx
));
80 EXPECT_EQ(State
, FooStr
);
83 TEST(MatchSwitchTest
, CtorInitializers
) {
84 std::string Code
= R
"(
89 f(): i(1), j(1), z(1) {}
92 auto Unit
= tooling::buildASTFromCode(Code
);
93 auto &Ctx
= Unit
->getASTContext();
95 llvm::StringRef IStr
= "i";
96 llvm::StringRef JStr
= "j";
97 llvm::StringRef ZStr
= "z";
99 auto InitI
= cxxCtorInitializer(forField(hasName(IStr
)));
100 auto InitJ
= cxxCtorInitializer(forField(hasName(JStr
)));
101 auto InitZ
= cxxCtorInitializer(forField(hasName(ZStr
)));
103 ASTMatchSwitch
<CXXCtorInitializer
, llvm::StringRef
> MS
=
104 ASTMatchSwitchBuilder
<CXXCtorInitializer
, llvm::StringRef
>()
105 .CaseOf
<CXXCtorInitializer
>(
106 InitI
, [&IStr
](const CXXCtorInitializer
*,
107 const MatchFinder::MatchResult
&,
108 llvm::StringRef
&State
) { State
= IStr
; })
109 .CaseOf
<CXXCtorInitializer
>(
110 InitJ
, [&JStr
](const CXXCtorInitializer
*,
111 const MatchFinder::MatchResult
&,
112 llvm::StringRef
&State
) { State
= JStr
; })
114 llvm::StringRef State
;
116 // State modified from the first case of the switch
118 selectFirst
<CXXCtorInitializer
>(IStr
, match(InitI
.bind(IStr
), Ctx
));
120 EXPECT_EQ(State
, IStr
);
122 // State modified from the second case of the switch
124 selectFirst
<CXXCtorInitializer
>(JStr
, match(InitJ
.bind(JStr
), Ctx
));
126 EXPECT_EQ(State
, JStr
);
128 // State unmodified, no case defined for the initializer of z
130 selectFirst
<CXXCtorInitializer
>(ZStr
, match(InitZ
.bind(ZStr
), Ctx
));
132 EXPECT_EQ(State
, JStr
);
135 TEST(MatchSwitchTest
, ReturnNonVoid
) {
137 tooling::buildASTFromCode("void f() { int x = 42; }", "input.cc",
138 std::make_shared
<PCHContainerOperations
>());
139 auto &Context
= Unit
->getASTContext();
141 selectFirst
<FunctionDecl
>(
143 match(functionDecl(isDefinition(), hasName("f")).bind("f"), Context
))
146 ASTMatchSwitch
<Stmt
, const int, std::vector
<int>> Switch
=
147 ASTMatchSwitchBuilder
<Stmt
, const int, std::vector
<int>>()
148 .CaseOf
<Stmt
>(stmt(),
149 [](const Stmt
*, const MatchFinder::MatchResult
&,
150 const int &State
) -> std::vector
<int> {
151 return {1, State
, 3};
154 std::vector
<int> Actual
= Switch(*S
, Context
, 7);
155 std::vector
<int> Expected
{1, 7, 3};
156 EXPECT_EQ(Actual
, Expected
);