diff options
Diffstat (limited to 'clang/unittests/Analysis/CFGTest.cpp')
-rw-r--r-- | clang/unittests/Analysis/CFGTest.cpp | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/clang/unittests/Analysis/CFGTest.cpp b/clang/unittests/Analysis/CFGTest.cpp index 46a6751..6aa09a8 100644 --- a/clang/unittests/Analysis/CFGTest.cpp +++ b/clang/unittests/Analysis/CFGTest.cpp @@ -93,6 +93,159 @@ TEST(CFG, DependantBaseAddImplicitDtors) { .getStatus()); } +TEST(CFG, SwitchCoveredEnumNoDefault) { + const char *Code = R"( + enum class E {E1, E2}; + int f(E e) { + switch(e) { + case E::E1: + return 1; + case E::E2: + return 2; + } + return 0; + } + )"; + CFG::BuildOptions Options; + Options.AssumeReachableDefaultInSwitchStatements = true; + BuildResult B = BuildCFG(Code, Options); + ASSERT_EQ(BuildResult::BuiltCFG, B.getStatus()); + + // [B5 (ENTRY)] + // Succs (1): B2 + // + // [B1] + // 1: 0 + // 2: return [B1.1]; + // Preds (1): B2 + // Succs (1): B0 + // + // [B2] + // 1: e (ImplicitCastExpr, LValueToRValue, E) + // T: switch [B2.1] + // Preds (1): B5 + // Succs (3): B3 B4 B1 + // + // [B3] + // case E::E2: + // 1: 2 + // 2: return [B3.1]; + // Preds (1): B2 + // Succs (1): B0 + // + // [B4] + // case E::E1: + // 1: 1 + // 2: return [B4.1]; + // Preds (1): B2 + // Succs (1): B0 + // + // [B0 (EXIT)] + // Preds (3): B1 B3 B4 + + auto *CFG = B.getCFG(); + const auto &Entry = CFG->getEntry(); + ASSERT_EQ(1u, Entry.succ_size()); + // First successor of Entry is the switch + CFGBlock *SwitchBlock = *Entry.succ_begin(); + ASSERT_EQ(3u, SwitchBlock->succ_size()); + // Last successor of the switch is after the switch + auto NoCaseSucc = SwitchBlock->succ_rbegin(); + EXPECT_TRUE(NoCaseSucc->isReachable()); + + // Checking that the same node is Unreachable without this setting + Options.AssumeReachableDefaultInSwitchStatements = false; + B = BuildCFG(Code, Options); + ASSERT_EQ(BuildResult::BuiltCFG, B.getStatus()); + + const auto &Entry2 = B.getCFG()->getEntry(); + ASSERT_EQ(1u, Entry2.succ_size()); + CFGBlock *SwitchBlock2 = *Entry2.succ_begin(); + ASSERT_EQ(3u, SwitchBlock2->succ_size()); + auto NoCaseSucc2 = SwitchBlock2->succ_rbegin(); + EXPECT_FALSE(NoCaseSucc2->isReachable()); +} + +TEST(CFG, SwitchCoveredEnumWithDefault) { + const char *Code = R"( + enum class E {E1, E2}; + int f(E e) { + switch(e) { + case E::E1: + return 1; + case E::E2: + return 2; + default: + return 0; + } + return -1; + } + )"; + CFG::BuildOptions Options; + Options.AssumeReachableDefaultInSwitchStatements = true; + BuildResult B = BuildCFG(Code, Options); + ASSERT_EQ(BuildResult::BuiltCFG, B.getStatus()); + + // [B6 (ENTRY)] + // Succs (1): B2 + // + // [B1] + // 1: -1 + // 2: return [B1.1]; + // Succs (1): B0 + // + // [B2] + // 1: e (ImplicitCastExpr, LValueToRValue, E) + // T: switch [B2.1] + // Preds (1): B6 + // Succs (3): B4 B5 B3 + // + // [B3] + // default: + // 1: 0 + // 2: return [B3.1]; + // Preds (1): B2 + // Succs (1): B0 + // + // [B4] + // case E::E2: + // 1: 2 + // 2: return [B4.1]; + // Preds (1): B2 + // Succs (1): B0 + // + // [B5] + // case E::E1: + // 1: 1 + // 2: return [B5.1]; + // Preds (1): B2 + // Succs (1): B0 + // + // [B0 (EXIT)] + // Preds (4): B1 B3 B4 B5 + + const auto &Entry = B.getCFG()->getEntry(); + ASSERT_EQ(1u, Entry.succ_size()); + // First successor of Entry is the switch + CFGBlock *SwitchBlock = *Entry.succ_begin(); + ASSERT_EQ(3u, SwitchBlock->succ_size()); + // Last successor of the switch is the default branch + auto defaultBlock = SwitchBlock->succ_rbegin(); + EXPECT_TRUE(defaultBlock->isReachable()); + + // Checking that the same node is Unreachable without this setting + Options.AssumeReachableDefaultInSwitchStatements = false; + B = BuildCFG(Code, Options); + ASSERT_EQ(BuildResult::BuiltCFG, B.getStatus()); + + const auto &Entry2 = B.getCFG()->getEntry(); + ASSERT_EQ(1u, Entry2.succ_size()); + CFGBlock *SwitchBlock2 = *Entry2.succ_begin(); + ASSERT_EQ(3u, SwitchBlock2->succ_size()); + auto defaultBlock2 = SwitchBlock2->succ_rbegin(); + EXPECT_FALSE(defaultBlock2->isReachable()); +} + TEST(CFG, IsLinear) { auto expectLinear = [](bool IsLinear, const char *Code) { BuildResult B = BuildCFG(Code); |