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