File: CFGMatchSwitchTest.cpp

package info (click to toggle)
llvm-toolchain-19 1%3A19.1.7-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,998,520 kB
  • sloc: cpp: 6,951,680; ansic: 1,486,157; asm: 913,598; python: 232,024; f90: 80,126; objc: 75,281; lisp: 37,276; pascal: 16,990; sh: 10,009; ml: 5,058; perl: 4,724; awk: 3,523; makefile: 3,167; javascript: 2,504; xml: 892; fortran: 664; cs: 573
file content (124 lines) | stat: -rw-r--r-- 4,169 bytes parent folder | download | duplicates (12)
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
//===- unittests/Analysis/FlowSensitive/CFGMatchSwitchTest.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/Analysis/FlowSensitive/CFGMatchSwitch.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Stmt.h"
#include "clang/Analysis/CFG.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/StringRef.h"
#include "gtest/gtest.h"

using namespace clang;
using namespace dataflow;
using namespace ast_matchers;

namespace {
// State for tracking the number of matches on each kind of CFGElement by the
// CFGMatchSwitch. Currently only tracks CFGStmt and CFGInitializer.
struct CFGElementMatches {
  unsigned StmtMatches = 0;
  unsigned InitializerMatches = 0;
};

// Returns a match switch that counts the number of local variables
// (singly-declared) and fields initialized to the integer literal 42.
auto buildCFGMatchSwitch() {
  return CFGMatchSwitchBuilder<CFGElementMatches>()
      .CaseOfCFGStmt<DeclStmt>(
          declStmt(hasSingleDecl(
              varDecl(hasInitializer(integerLiteral(equals(42)))))),
          [](const DeclStmt *, const MatchFinder::MatchResult &,
             CFGElementMatches &Counter) { Counter.StmtMatches++; })
      .CaseOfCFGInit<CXXCtorInitializer>(
          cxxCtorInitializer(withInitializer(integerLiteral(equals(42)))),
          [](const CXXCtorInitializer *, const MatchFinder::MatchResult &,
             CFGElementMatches &Counter) { Counter.InitializerMatches++; })
      .Build();
}

// Runs the match switch `MS` on the control flow graph generated from `Code`,
// tracking information in state `S`. For simplicity, this test utility is
// restricted to CFGs with a single control flow block (excluding entry and
// exit blocks) - generated by `Code` with sequential flow (i.e. no branching).
//
// Requirements:
//
//  `Code` must contain a function named `f`, the body of this function will be
//  used to generate the CFG.
template <typename State>
void applySwitchToCode(CFGMatchSwitch<State> &MS, State &S,
                       llvm::StringRef Code) {
  auto Unit = tooling::buildASTFromCodeWithArgs(Code, {"-Wno-unused-value"});
  auto &Ctx = Unit->getASTContext();
  const auto *F = selectFirst<FunctionDecl>(
      "f", match(functionDecl(isDefinition(), hasName("f")).bind("f"), Ctx));

  CFG::BuildOptions BO;
  BO.AddInitializers = true;

  auto CFG = CFG::buildCFG(F, F->getBody(), &Ctx, BO);
  auto CFGBlock = *CFG->getEntry().succ_begin();
  for (auto &Elt : CFGBlock->Elements) {
    MS(Elt, Ctx, S);
  }
}

TEST(CFGMatchSwitchTest, NoInitializationTo42) {
  CFGMatchSwitch<CFGElementMatches> Switch = buildCFGMatchSwitch();
  CFGElementMatches Counter;
  applySwitchToCode(Switch, Counter, R"(
    void f() {
      42;
    }
  )");
  EXPECT_EQ(Counter.StmtMatches, 0u);
  EXPECT_EQ(Counter.InitializerMatches, 0u);
}

TEST(CFGMatchSwitchTest, SingleLocalVarInitializationTo42) {
  CFGMatchSwitch<CFGElementMatches> Switch = buildCFGMatchSwitch();
  CFGElementMatches Counter;
  applySwitchToCode(Switch, Counter, R"(
    void f() {
      int i = 42;
    }
  )");
  EXPECT_EQ(Counter.StmtMatches, 1u);
  EXPECT_EQ(Counter.InitializerMatches, 0u);
}

TEST(CFGMatchSwitchTest, SingleFieldInitializationTo42) {
  CFGMatchSwitch<CFGElementMatches> Switch = buildCFGMatchSwitch();
  CFGElementMatches Counter;
  applySwitchToCode(Switch, Counter, R"(
    struct f {
      int i;
      f(): i(42) {}
    };
  )");
  EXPECT_EQ(Counter.StmtMatches, 0u);
  EXPECT_EQ(Counter.InitializerMatches, 1u);
}

TEST(CFGMatchSwitchTest, LocalVarAndFieldInitializationTo42) {
  CFGMatchSwitch<CFGElementMatches> Switch = buildCFGMatchSwitch();
  CFGElementMatches Counter;
  applySwitchToCode(Switch, Counter, R"(
    struct f {
      int i;
      f(): i(42) {
        int j = 42;
      }
    };
  )");
  EXPECT_EQ(Counter.StmtMatches, 1u);
  EXPECT_EQ(Counter.InitializerMatches, 1u);
}
} // namespace