xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp (revision 88210b81eed803598afeeaa2a60eb26ddbb65435)
1c88deef0SYitzhak Mandelbaum //===- unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp ---------------===//
2c88deef0SYitzhak Mandelbaum //
3c88deef0SYitzhak Mandelbaum // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c88deef0SYitzhak Mandelbaum // See https://llvm.org/LICENSE.txt for license information.
5c88deef0SYitzhak Mandelbaum // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c88deef0SYitzhak Mandelbaum //
7c88deef0SYitzhak Mandelbaum //===----------------------------------------------------------------------===//
8c88deef0SYitzhak Mandelbaum 
9c88deef0SYitzhak Mandelbaum #include "clang/Analysis/FlowSensitive/MatchSwitch.h"
10c88deef0SYitzhak Mandelbaum #include "clang/AST/ASTContext.h"
11c88deef0SYitzhak Mandelbaum #include "clang/AST/Decl.h"
12*88210b81SWei Yi Tee #include "clang/AST/DeclCXX.h"
13c88deef0SYitzhak Mandelbaum #include "clang/AST/Expr.h"
14c88deef0SYitzhak Mandelbaum #include "clang/AST/Stmt.h"
15c88deef0SYitzhak Mandelbaum #include "clang/ASTMatchers/ASTMatchFinder.h"
16c88deef0SYitzhak Mandelbaum #include "clang/ASTMatchers/ASTMatchers.h"
17c88deef0SYitzhak Mandelbaum #include "clang/Tooling/Tooling.h"
18c88deef0SYitzhak Mandelbaum #include "llvm/ADT/StringRef.h"
19c88deef0SYitzhak Mandelbaum #include "gtest/gtest.h"
20c88deef0SYitzhak Mandelbaum #include <cstdint>
21c88deef0SYitzhak Mandelbaum #include <memory>
22c88deef0SYitzhak Mandelbaum #include <ostream>
23c88deef0SYitzhak Mandelbaum #include <string>
24c88deef0SYitzhak Mandelbaum #include <utility>
25c88deef0SYitzhak Mandelbaum 
26c88deef0SYitzhak Mandelbaum using namespace clang;
27c88deef0SYitzhak Mandelbaum using namespace dataflow;
28*88210b81SWei Yi Tee using namespace ast_matchers;
29c88deef0SYitzhak Mandelbaum 
30c88deef0SYitzhak Mandelbaum namespace {
31c88deef0SYitzhak Mandelbaum 
TEST(MatchSwitchTest,Stmts)32*88210b81SWei Yi Tee TEST(MatchSwitchTest, Stmts) {
33c88deef0SYitzhak Mandelbaum   std::string Code = R"(
34c88deef0SYitzhak Mandelbaum     void Foo();
35c88deef0SYitzhak Mandelbaum     void Bar();
36*88210b81SWei Yi Tee     void f() {
37*88210b81SWei Yi Tee       int X = 1;
38*88210b81SWei Yi Tee       Foo();
39c88deef0SYitzhak Mandelbaum       Bar();
40c88deef0SYitzhak Mandelbaum     }
41c88deef0SYitzhak Mandelbaum   )";
42*88210b81SWei Yi Tee   auto Unit = tooling::buildASTFromCode(Code);
43*88210b81SWei Yi Tee   auto &Ctx = Unit->getASTContext();
44*88210b81SWei Yi Tee 
45*88210b81SWei Yi Tee   llvm::StringRef XStr = "X";
46*88210b81SWei Yi Tee   llvm::StringRef FooStr = "Foo";
47*88210b81SWei Yi Tee   llvm::StringRef BarStr = "Bar";
48*88210b81SWei Yi Tee 
49*88210b81SWei Yi Tee   auto XMatcher = declStmt(hasSingleDecl(varDecl(hasName(XStr))));
50*88210b81SWei Yi Tee   auto FooMatcher = callExpr(callee(functionDecl(hasName(FooStr))));
51*88210b81SWei Yi Tee   auto BarMatcher = callExpr(callee(functionDecl(hasName(BarStr))));
52*88210b81SWei Yi Tee 
53*88210b81SWei Yi Tee   ASTMatchSwitch<Stmt, llvm::StringRef> MS =
54*88210b81SWei Yi Tee       ASTMatchSwitchBuilder<Stmt, llvm::StringRef>()
55*88210b81SWei Yi Tee           .CaseOf<Stmt>(XMatcher,
56*88210b81SWei Yi Tee                         [&XStr](const Stmt *, const MatchFinder::MatchResult &,
57*88210b81SWei Yi Tee                                 llvm::StringRef &State) { State = XStr; })
58*88210b81SWei Yi Tee           .CaseOf<Stmt>(FooMatcher,
59*88210b81SWei Yi Tee                         [&FooStr](const Stmt *,
60*88210b81SWei Yi Tee                                   const MatchFinder::MatchResult &,
61*88210b81SWei Yi Tee                                   llvm::StringRef &State) { State = FooStr; })
62*88210b81SWei Yi Tee           .Build();
63*88210b81SWei Yi Tee   llvm::StringRef State;
64*88210b81SWei Yi Tee 
65*88210b81SWei Yi Tee   // State modified from the first case of the switch
66*88210b81SWei Yi Tee   const auto *X = selectFirst<Stmt>(XStr, match(XMatcher.bind(XStr), Ctx));
67*88210b81SWei Yi Tee   MS(*X, Ctx, State);
68*88210b81SWei Yi Tee   EXPECT_EQ(State, XStr);
69*88210b81SWei Yi Tee 
70*88210b81SWei Yi Tee   // State modified from the second case of the switch
71*88210b81SWei Yi Tee   const auto *Foo =
72*88210b81SWei Yi Tee       selectFirst<Stmt>(FooStr, match(FooMatcher.bind(FooStr), Ctx));
73*88210b81SWei Yi Tee   MS(*Foo, Ctx, State);
74*88210b81SWei Yi Tee   EXPECT_EQ(State, FooStr);
75*88210b81SWei Yi Tee 
76*88210b81SWei Yi Tee   // State unmodified, no case defined for calling Bar
77*88210b81SWei Yi Tee   const auto *Bar =
78*88210b81SWei Yi Tee       selectFirst<Stmt>(BarStr, match(BarMatcher.bind(BarStr), Ctx));
79*88210b81SWei Yi Tee   MS(*Bar, Ctx, State);
80*88210b81SWei Yi Tee   EXPECT_EQ(State, FooStr);
81*88210b81SWei Yi Tee }
82*88210b81SWei Yi Tee 
TEST(MatchSwitchTest,CtorInitializers)83*88210b81SWei Yi Tee TEST(MatchSwitchTest, CtorInitializers) {
84*88210b81SWei Yi Tee   std::string Code = R"(
85*88210b81SWei Yi Tee     struct f {
86*88210b81SWei Yi Tee       int i;
87*88210b81SWei Yi Tee       int j;
88*88210b81SWei Yi Tee       int z;
89*88210b81SWei Yi Tee       f(): i(1), j(1), z(1) {}
90*88210b81SWei Yi Tee     };
91*88210b81SWei Yi Tee   )";
92*88210b81SWei Yi Tee   auto Unit = tooling::buildASTFromCode(Code);
93*88210b81SWei Yi Tee   auto &Ctx = Unit->getASTContext();
94*88210b81SWei Yi Tee 
95*88210b81SWei Yi Tee   llvm::StringRef IStr = "i";
96*88210b81SWei Yi Tee   llvm::StringRef JStr = "j";
97*88210b81SWei Yi Tee   llvm::StringRef ZStr = "z";
98*88210b81SWei Yi Tee 
99*88210b81SWei Yi Tee   auto InitI = cxxCtorInitializer(forField(hasName(IStr)));
100*88210b81SWei Yi Tee   auto InitJ = cxxCtorInitializer(forField(hasName(JStr)));
101*88210b81SWei Yi Tee   auto InitZ = cxxCtorInitializer(forField(hasName(ZStr)));
102*88210b81SWei Yi Tee 
103*88210b81SWei Yi Tee   ASTMatchSwitch<CXXCtorInitializer, llvm::StringRef> MS =
104*88210b81SWei Yi Tee       ASTMatchSwitchBuilder<CXXCtorInitializer, llvm::StringRef>()
105*88210b81SWei Yi Tee           .CaseOf<CXXCtorInitializer>(
106*88210b81SWei Yi Tee               InitI, [&IStr](const CXXCtorInitializer *,
107*88210b81SWei Yi Tee                              const MatchFinder::MatchResult &,
108*88210b81SWei Yi Tee                              llvm::StringRef &State) { State = IStr; })
109*88210b81SWei Yi Tee           .CaseOf<CXXCtorInitializer>(
110*88210b81SWei Yi Tee               InitJ, [&JStr](const CXXCtorInitializer *,
111*88210b81SWei Yi Tee                              const MatchFinder::MatchResult &,
112*88210b81SWei Yi Tee                              llvm::StringRef &State) { State = JStr; })
113*88210b81SWei Yi Tee           .Build();
114*88210b81SWei Yi Tee   llvm::StringRef State;
115*88210b81SWei Yi Tee 
116*88210b81SWei Yi Tee   // State modified from the first case of the switch
117*88210b81SWei Yi Tee   const auto *I =
118*88210b81SWei Yi Tee       selectFirst<CXXCtorInitializer>(IStr, match(InitI.bind(IStr), Ctx));
119*88210b81SWei Yi Tee   MS(*I, Ctx, State);
120*88210b81SWei Yi Tee   EXPECT_EQ(State, IStr);
121*88210b81SWei Yi Tee 
122*88210b81SWei Yi Tee   // State modified from the second case of the switch
123*88210b81SWei Yi Tee   const auto *J =
124*88210b81SWei Yi Tee       selectFirst<CXXCtorInitializer>(JStr, match(InitJ.bind(JStr), Ctx));
125*88210b81SWei Yi Tee   MS(*J, Ctx, State);
126*88210b81SWei Yi Tee   EXPECT_EQ(State, JStr);
127*88210b81SWei Yi Tee 
128*88210b81SWei Yi Tee   // State unmodified, no case defined for the initializer of z
129*88210b81SWei Yi Tee   const auto *Z =
130*88210b81SWei Yi Tee       selectFirst<CXXCtorInitializer>(ZStr, match(InitZ.bind(ZStr), Ctx));
131*88210b81SWei Yi Tee   MS(*Z, Ctx, State);
132*88210b81SWei Yi Tee   EXPECT_EQ(State, JStr);
133c88deef0SYitzhak Mandelbaum }
1348c278a27SSam Estep 
TEST(MatchSwitchTest,ReturnNonVoid)1351d83a16bSSam Estep TEST(MatchSwitchTest, ReturnNonVoid) {
1368c278a27SSam Estep   auto Unit =
1378c278a27SSam Estep       tooling::buildASTFromCode("void f() { int x = 42; }", "input.cc",
1388c278a27SSam Estep                                 std::make_shared<PCHContainerOperations>());
1398c278a27SSam Estep   auto &Context = Unit->getASTContext();
1408c278a27SSam Estep   const auto *S =
1418c278a27SSam Estep       selectFirst<FunctionDecl>(
1428c278a27SSam Estep           "f",
1438c278a27SSam Estep           match(functionDecl(isDefinition(), hasName("f")).bind("f"), Context))
1448c278a27SSam Estep           ->getBody();
1458c278a27SSam Estep 
146*88210b81SWei Yi Tee   ASTMatchSwitch<Stmt, const int, std::vector<int>> Switch =
147*88210b81SWei Yi Tee       ASTMatchSwitchBuilder<Stmt, const int, std::vector<int>>()
1488c278a27SSam Estep           .CaseOf<Stmt>(stmt(),
1498c278a27SSam Estep                         [](const Stmt *, const MatchFinder::MatchResult &,
1508c278a27SSam Estep                            const int &State) -> std::vector<int> {
1518c278a27SSam Estep                           return {1, State, 3};
1528c278a27SSam Estep                         })
1538c278a27SSam Estep           .Build();
1548c278a27SSam Estep   std::vector<int> Actual = Switch(*S, Context, 7);
1558c278a27SSam Estep   std::vector<int> Expected{1, 7, 3};
1568c278a27SSam Estep   EXPECT_EQ(Actual, Expected);
1578c278a27SSam Estep }
158*88210b81SWei Yi Tee 
159*88210b81SWei Yi Tee } // namespace
160