xref: /llvm-project/clang/unittests/Analysis/FlowSensitive/CFGMatchSwitchTest.cpp (revision d931ac9e27cab964c65078c80e4488185c62b3d8)
1*d931ac9eSWei Yi Tee //===- unittests/Analysis/FlowSensitive/CFGMatchSwitchTest.cpp ------------===//
2*d931ac9eSWei Yi Tee //
3*d931ac9eSWei Yi Tee // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*d931ac9eSWei Yi Tee // See https://llvm.org/LICENSE.txt for license information.
5*d931ac9eSWei Yi Tee // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*d931ac9eSWei Yi Tee //
7*d931ac9eSWei Yi Tee //===----------------------------------------------------------------------===//
8*d931ac9eSWei Yi Tee 
9*d931ac9eSWei Yi Tee #include "clang/Analysis/FlowSensitive/CFGMatchSwitch.h"
10*d931ac9eSWei Yi Tee #include "clang/AST/ASTContext.h"
11*d931ac9eSWei Yi Tee #include "clang/AST/Decl.h"
12*d931ac9eSWei Yi Tee #include "clang/AST/Stmt.h"
13*d931ac9eSWei Yi Tee #include "clang/Analysis/CFG.h"
14*d931ac9eSWei Yi Tee #include "clang/Tooling/Tooling.h"
15*d931ac9eSWei Yi Tee #include "llvm/ADT/StringRef.h"
16*d931ac9eSWei Yi Tee #include "gtest/gtest.h"
17*d931ac9eSWei Yi Tee 
18*d931ac9eSWei Yi Tee using namespace clang;
19*d931ac9eSWei Yi Tee using namespace dataflow;
20*d931ac9eSWei Yi Tee using namespace ast_matchers;
21*d931ac9eSWei Yi Tee 
22*d931ac9eSWei Yi Tee namespace {
23*d931ac9eSWei Yi Tee // State for tracking the number of matches on each kind of CFGElement by the
24*d931ac9eSWei Yi Tee // CFGMatchSwitch. Currently only tracks CFGStmt and CFGInitializer.
25*d931ac9eSWei Yi Tee struct CFGElementMatches {
26*d931ac9eSWei Yi Tee   unsigned StmtMatches = 0;
27*d931ac9eSWei Yi Tee   unsigned InitializerMatches = 0;
28*d931ac9eSWei Yi Tee };
29*d931ac9eSWei Yi Tee 
30*d931ac9eSWei Yi Tee // Returns a match switch that counts the number of local variables
31*d931ac9eSWei Yi Tee // (singly-declared) and fields initialized to the integer literal 42.
buildCFGMatchSwitch()32*d931ac9eSWei Yi Tee auto buildCFGMatchSwitch() {
33*d931ac9eSWei Yi Tee   return CFGMatchSwitchBuilder<CFGElementMatches>()
34*d931ac9eSWei Yi Tee       .CaseOfCFGStmt<DeclStmt>(
35*d931ac9eSWei Yi Tee           declStmt(hasSingleDecl(
36*d931ac9eSWei Yi Tee               varDecl(hasInitializer(integerLiteral(equals(42)))))),
37*d931ac9eSWei Yi Tee           [](const DeclStmt *, const MatchFinder::MatchResult &,
38*d931ac9eSWei Yi Tee              CFGElementMatches &Counter) { Counter.StmtMatches++; })
39*d931ac9eSWei Yi Tee       .CaseOfCFGInit<CXXCtorInitializer>(
40*d931ac9eSWei Yi Tee           cxxCtorInitializer(withInitializer(integerLiteral(equals(42)))),
41*d931ac9eSWei Yi Tee           [](const CXXCtorInitializer *, const MatchFinder::MatchResult &,
42*d931ac9eSWei Yi Tee              CFGElementMatches &Counter) { Counter.InitializerMatches++; })
43*d931ac9eSWei Yi Tee       .Build();
44*d931ac9eSWei Yi Tee }
45*d931ac9eSWei Yi Tee 
46*d931ac9eSWei Yi Tee // Runs the match switch `MS` on the control flow graph generated from `Code`,
47*d931ac9eSWei Yi Tee // tracking information in state `S`. For simplicity, this test utility is
48*d931ac9eSWei Yi Tee // restricted to CFGs with a single control flow block (excluding entry and
49*d931ac9eSWei Yi Tee // exit blocks) - generated by `Code` with sequential flow (i.e. no branching).
50*d931ac9eSWei Yi Tee //
51*d931ac9eSWei Yi Tee // Requirements:
52*d931ac9eSWei Yi Tee //
53*d931ac9eSWei Yi Tee //  `Code` must contain a function named `f`, the body of this function will be
54*d931ac9eSWei Yi Tee //  used to generate the CFG.
55*d931ac9eSWei Yi Tee template <typename State>
applySwitchToCode(CFGMatchSwitch<State> & MS,State & S,llvm::StringRef Code)56*d931ac9eSWei Yi Tee void applySwitchToCode(CFGMatchSwitch<State> &MS, State &S,
57*d931ac9eSWei Yi Tee                        llvm::StringRef Code) {
58*d931ac9eSWei Yi Tee   auto Unit = tooling::buildASTFromCodeWithArgs(Code, {"-Wno-unused-value"});
59*d931ac9eSWei Yi Tee   auto &Ctx = Unit->getASTContext();
60*d931ac9eSWei Yi Tee   const auto *F = selectFirst<FunctionDecl>(
61*d931ac9eSWei Yi Tee       "f", match(functionDecl(isDefinition(), hasName("f")).bind("f"), Ctx));
62*d931ac9eSWei Yi Tee 
63*d931ac9eSWei Yi Tee   CFG::BuildOptions BO;
64*d931ac9eSWei Yi Tee   BO.AddInitializers = true;
65*d931ac9eSWei Yi Tee 
66*d931ac9eSWei Yi Tee   auto CFG = CFG::buildCFG(F, F->getBody(), &Ctx, BO);
67*d931ac9eSWei Yi Tee   auto CFGBlock = *CFG->getEntry().succ_begin();
68*d931ac9eSWei Yi Tee   for (auto &Elt : CFGBlock->Elements) {
69*d931ac9eSWei Yi Tee     MS(Elt, Ctx, S);
70*d931ac9eSWei Yi Tee   }
71*d931ac9eSWei Yi Tee }
72*d931ac9eSWei Yi Tee 
TEST(CFGMatchSwitchTest,NoInitializationTo42)73*d931ac9eSWei Yi Tee TEST(CFGMatchSwitchTest, NoInitializationTo42) {
74*d931ac9eSWei Yi Tee   CFGMatchSwitch<CFGElementMatches> Switch = buildCFGMatchSwitch();
75*d931ac9eSWei Yi Tee   CFGElementMatches Counter;
76*d931ac9eSWei Yi Tee   applySwitchToCode(Switch, Counter, R"(
77*d931ac9eSWei Yi Tee     void f() {
78*d931ac9eSWei Yi Tee       42;
79*d931ac9eSWei Yi Tee     }
80*d931ac9eSWei Yi Tee   )");
81*d931ac9eSWei Yi Tee   EXPECT_EQ(Counter.StmtMatches, 0u);
82*d931ac9eSWei Yi Tee   EXPECT_EQ(Counter.InitializerMatches, 0u);
83*d931ac9eSWei Yi Tee }
84*d931ac9eSWei Yi Tee 
TEST(CFGMatchSwitchTest,SingleLocalVarInitializationTo42)85*d931ac9eSWei Yi Tee TEST(CFGMatchSwitchTest, SingleLocalVarInitializationTo42) {
86*d931ac9eSWei Yi Tee   CFGMatchSwitch<CFGElementMatches> Switch = buildCFGMatchSwitch();
87*d931ac9eSWei Yi Tee   CFGElementMatches Counter;
88*d931ac9eSWei Yi Tee   applySwitchToCode(Switch, Counter, R"(
89*d931ac9eSWei Yi Tee     void f() {
90*d931ac9eSWei Yi Tee       int i = 42;
91*d931ac9eSWei Yi Tee     }
92*d931ac9eSWei Yi Tee   )");
93*d931ac9eSWei Yi Tee   EXPECT_EQ(Counter.StmtMatches, 1u);
94*d931ac9eSWei Yi Tee   EXPECT_EQ(Counter.InitializerMatches, 0u);
95*d931ac9eSWei Yi Tee }
96*d931ac9eSWei Yi Tee 
TEST(CFGMatchSwitchTest,SingleFieldInitializationTo42)97*d931ac9eSWei Yi Tee TEST(CFGMatchSwitchTest, SingleFieldInitializationTo42) {
98*d931ac9eSWei Yi Tee   CFGMatchSwitch<CFGElementMatches> Switch = buildCFGMatchSwitch();
99*d931ac9eSWei Yi Tee   CFGElementMatches Counter;
100*d931ac9eSWei Yi Tee   applySwitchToCode(Switch, Counter, R"(
101*d931ac9eSWei Yi Tee     struct f {
102*d931ac9eSWei Yi Tee       int i;
103*d931ac9eSWei Yi Tee       f(): i(42) {}
104*d931ac9eSWei Yi Tee     };
105*d931ac9eSWei Yi Tee   )");
106*d931ac9eSWei Yi Tee   EXPECT_EQ(Counter.StmtMatches, 0u);
107*d931ac9eSWei Yi Tee   EXPECT_EQ(Counter.InitializerMatches, 1u);
108*d931ac9eSWei Yi Tee }
109*d931ac9eSWei Yi Tee 
TEST(CFGMatchSwitchTest,LocalVarAndFieldInitializationTo42)110*d931ac9eSWei Yi Tee TEST(CFGMatchSwitchTest, LocalVarAndFieldInitializationTo42) {
111*d931ac9eSWei Yi Tee   CFGMatchSwitch<CFGElementMatches> Switch = buildCFGMatchSwitch();
112*d931ac9eSWei Yi Tee   CFGElementMatches Counter;
113*d931ac9eSWei Yi Tee   applySwitchToCode(Switch, Counter, R"(
114*d931ac9eSWei Yi Tee     struct f {
115*d931ac9eSWei Yi Tee       int i;
116*d931ac9eSWei Yi Tee       f(): i(42) {
117*d931ac9eSWei Yi Tee         int j = 42;
118*d931ac9eSWei Yi Tee       }
119*d931ac9eSWei Yi Tee     };
120*d931ac9eSWei Yi Tee   )");
121*d931ac9eSWei Yi Tee   EXPECT_EQ(Counter.StmtMatches, 1u);
122*d931ac9eSWei Yi Tee   EXPECT_EQ(Counter.InitializerMatches, 1u);
123*d931ac9eSWei Yi Tee }
124*d931ac9eSWei Yi Tee } // namespace
125