Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[analyzer][Dominators][NFC] Add unit tests
Differential Revision: https://reviews.llvm.org/D62611 llvm-svn: 365179
- Loading branch information
Showing
4 changed files
with
174 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
//===- unittests/Analysis/CFGBuildResult.h - CFG tests --------------------===// | ||
// | ||
// 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/CFG.h" | ||
#include "clang/ASTMatchers/ASTMatchFinder.h" | ||
#include "clang/Tooling/Tooling.h" | ||
|
||
namespace clang { | ||
namespace analysis { | ||
|
||
class BuildResult { | ||
public: | ||
enum Status { | ||
ToolFailed, | ||
ToolRan, | ||
SawFunctionBody, | ||
BuiltCFG, | ||
}; | ||
|
||
BuildResult(Status S, std::unique_ptr<CFG> Cfg = nullptr) | ||
: S(S), Cfg(std::move(Cfg)) {} | ||
|
||
Status getStatus() const { return S; } | ||
CFG *getCFG() const { return Cfg.get(); } | ||
|
||
private: | ||
Status S; | ||
std::unique_ptr<CFG> Cfg; | ||
}; | ||
|
||
class CFGCallback : public ast_matchers::MatchFinder::MatchCallback { | ||
public: | ||
BuildResult TheBuildResult = BuildResult::ToolRan; | ||
|
||
void run(const ast_matchers::MatchFinder::MatchResult &Result) override { | ||
const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func"); | ||
Stmt *Body = Func->getBody(); | ||
if (!Body) | ||
return; | ||
TheBuildResult = BuildResult::SawFunctionBody; | ||
CFG::BuildOptions Options; | ||
Options.AddImplicitDtors = true; | ||
if (std::unique_ptr<CFG> Cfg = | ||
CFG::buildCFG(nullptr, Body, Result.Context, Options)) | ||
TheBuildResult = {BuildResult::BuiltCFG, std::move(Cfg)}; | ||
} | ||
}; | ||
|
||
inline BuildResult BuildCFG(const char *Code) { | ||
CFGCallback Callback; | ||
|
||
ast_matchers::MatchFinder Finder; | ||
Finder.addMatcher(ast_matchers::functionDecl().bind("func"), &Callback); | ||
std::unique_ptr<tooling::FrontendActionFactory> Factory( | ||
tooling::newFrontendActionFactory(&Finder)); | ||
std::vector<std::string> Args = {"-std=c++11", | ||
"-fno-delayed-template-parsing"}; | ||
if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args)) | ||
return BuildResult::ToolFailed; | ||
return std::move(Callback.TheBuildResult); | ||
} | ||
|
||
} // namespace analysis | ||
} // namespace clang |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
//===- unittests/Analysis/CFGDominatorTree.cpp - CFG tests ----------------===// | ||
// | ||
// 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 "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()); | ||
|
||
// [B3 (ENTRY)] -> [B1] -> [B2] -> [B0 (EXIT)] | ||
// switch case A | ||
|
||
CFG *cfg = Result.getCFG(); | ||
|
||
// Sanity checks. | ||
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()); | ||
|
||
// Test the dominator tree. | ||
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)); | ||
|
||
// Test the post dominator tree. | ||
|
||
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)); | ||
|
||
// Tests for the post dominator tree's virtual root. | ||
EXPECT_TRUE(PostDom.dominates(nullptr, EntryBlock)); | ||
EXPECT_TRUE(PostDom.dominates(nullptr, SwitchBlock)); | ||
EXPECT_TRUE(PostDom.dominates(nullptr, CaseABlock)); | ||
EXPECT_TRUE(PostDom.dominates(nullptr, ExitBlock)); | ||
} | ||
|
||
} // namespace | ||
} // namespace analysis | ||
} // namespace clang |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters