#include "CFGBuildResult.h"
#include "clang/Analysis/Analyses/Dominators.h"
#include "gtest/gtest.h"
namespace clang {
namespace analysis {
namespace {
TEST(CFGDominatorTree, DomTree) {
const char *Code = R"(enum Kind {
A
};
void f() {
switch(Kind{}) {
case A:
break;
}
})";
BuildResult Result = BuildCFG(Code);
EXPECT_EQ(BuildResult::BuiltCFG, Result.getStatus());
CFG *cfg = Result.getCFG();
EXPECT_EQ(cfg->size(), 4u);
CFGBlock *ExitBlock = *cfg->begin();
EXPECT_EQ(ExitBlock, &cfg->getExit());
CFGBlock *SwitchBlock = *(cfg->begin() + 1);
CFGBlock *CaseABlock = *(cfg->begin() + 2);
CFGBlock *EntryBlock = *(cfg->begin() + 3);
EXPECT_EQ(EntryBlock, &cfg->getEntry());
CFGDomTree Dom;
Dom.buildDominatorTree(cfg);
EXPECT_TRUE(Dom.dominates(ExitBlock, ExitBlock));
EXPECT_FALSE(Dom.properlyDominates(ExitBlock, ExitBlock));
EXPECT_TRUE(Dom.dominates(CaseABlock, ExitBlock));
EXPECT_TRUE(Dom.dominates(SwitchBlock, ExitBlock));
EXPECT_TRUE(Dom.dominates(EntryBlock, ExitBlock));
EXPECT_TRUE(Dom.dominates(CaseABlock, CaseABlock));
EXPECT_FALSE(Dom.properlyDominates(CaseABlock, CaseABlock));
EXPECT_TRUE(Dom.dominates(SwitchBlock, CaseABlock));
EXPECT_TRUE(Dom.dominates(EntryBlock, CaseABlock));
EXPECT_TRUE(Dom.dominates(SwitchBlock, SwitchBlock));
EXPECT_FALSE(Dom.properlyDominates(SwitchBlock, SwitchBlock));
EXPECT_TRUE(Dom.dominates(EntryBlock, SwitchBlock));
EXPECT_TRUE(Dom.dominates(EntryBlock, EntryBlock));
EXPECT_FALSE(Dom.properlyDominates(EntryBlock, EntryBlock));
CFGPostDomTree PostDom;
PostDom.buildDominatorTree(cfg);
EXPECT_TRUE(PostDom.dominates(ExitBlock, EntryBlock));
EXPECT_TRUE(PostDom.dominates(CaseABlock, EntryBlock));
EXPECT_TRUE(PostDom.dominates(SwitchBlock, EntryBlock));
EXPECT_TRUE(PostDom.dominates(EntryBlock, EntryBlock));
EXPECT_FALSE(Dom.properlyDominates(EntryBlock, EntryBlock));
EXPECT_TRUE(PostDom.dominates(ExitBlock, SwitchBlock));
EXPECT_TRUE(PostDom.dominates(CaseABlock, SwitchBlock));
EXPECT_TRUE(PostDom.dominates(SwitchBlock, SwitchBlock));
EXPECT_FALSE(Dom.properlyDominates(SwitchBlock, SwitchBlock));
EXPECT_TRUE(PostDom.dominates(ExitBlock, CaseABlock));
EXPECT_TRUE(PostDom.dominates(CaseABlock, CaseABlock));
EXPECT_FALSE(Dom.properlyDominates(CaseABlock, CaseABlock));
EXPECT_TRUE(PostDom.dominates(ExitBlock, ExitBlock));
EXPECT_FALSE(Dom.properlyDominates(ExitBlock, ExitBlock));
EXPECT_TRUE(PostDom.dominates(nullptr, EntryBlock));
EXPECT_TRUE(PostDom.dominates(nullptr, SwitchBlock));
EXPECT_TRUE(PostDom.dominates(nullptr, CaseABlock));
EXPECT_TRUE(PostDom.dominates(nullptr, ExitBlock));
}
TEST(CFGDominatorTree, ControlDependency) {
const char *Code = R"(bool coin();
void funcWithBranch() {
int x = 0;
if (coin()) {
if (coin()) {
x = 5;
}
int j = 10 / x;
(void)j;
}
};)";
BuildResult Result = BuildCFG(Code);
EXPECT_EQ(BuildResult::BuiltCFG, Result.getStatus());
CFG *cfg = Result.getCFG();
EXPECT_EQ(cfg->size(), 6u);
CFGBlock *ExitBlock = *cfg->begin();
EXPECT_EQ(ExitBlock, &cfg->getExit());
CFGBlock *NullDerefBlock = *(cfg->begin() + 1);
CFGBlock *SecondThenBlock = *(cfg->begin() + 2);
CFGBlock *SecondIfBlock = *(cfg->begin() + 3);
CFGBlock *FirstIfBlock = *(cfg->begin() + 4);
CFGBlock *EntryBlock = *(cfg->begin() + 5);
EXPECT_EQ(EntryBlock, &cfg->getEntry());
ControlDependencyCalculator Control(cfg);
EXPECT_TRUE(Control.isControlDependent(SecondThenBlock, SecondIfBlock));
EXPECT_TRUE(Control.isControlDependent(SecondIfBlock, FirstIfBlock));
EXPECT_FALSE(Control.isControlDependent(NullDerefBlock, SecondIfBlock));
}
TEST(CFGDominatorTree, ControlDependencyWithLoops) {
const char *Code = R"(int test3() {
int x,y,z;
x = y = z = 1;
if (x > 0) {
while (x >= 0){
while (y >= x) {
x = x-1;
y = y/2;
}
}
}
z = y;
return 0;
})";
BuildResult Result = BuildCFG(Code);
EXPECT_EQ(BuildResult::BuiltCFG, Result.getStatus());
CFG *cfg = Result.getCFG();
ControlDependencyCalculator Control(cfg);
auto GetBlock = [cfg] (unsigned Index) -> CFGBlock * {
assert(Index < cfg->size());
return *(cfg->begin() + Index);
};
EXPECT_FALSE(Control.isControlDependent(GetBlock(5), GetBlock(2)));
}
} } }