[CFG] Add a new function to get the proper condition of a CFGBlock
getTerminatorCondition() returned a condition that may be outside of the block, while the new function returns the proper one: if (A && B && C) {} Return C instead of A && B && C. Differential Revision: https://reviews.llvm.org/D63538 llvm-svn: 365177
This commit is contained in:
parent
bb7e97d783
commit
d5c9d9b682
|
@ -860,6 +860,14 @@ public:
|
|||
Stmt *getTerminatorStmt() { return Terminator.getStmt(); }
|
||||
const Stmt *getTerminatorStmt() const { return Terminator.getStmt(); }
|
||||
|
||||
/// \returns the last (\c rbegin()) condition, e.g. observe the following code
|
||||
/// snippet:
|
||||
/// if (A && B && C)
|
||||
/// A block would be created for \c A, \c B, and \c C. For the latter,
|
||||
/// \c getTerminatorStmt() would retrieve the entire condition, rather than
|
||||
/// C itself, while this method would only return C.
|
||||
const Expr *getLastCondition() const;
|
||||
|
||||
Stmt *getTerminatorCondition(bool StripParens = true);
|
||||
|
||||
const Stmt *getTerminatorCondition(bool StripParens = true) const {
|
||||
|
|
|
@ -5615,6 +5615,30 @@ void CFGBlock::printTerminatorJson(raw_ostream &Out, const LangOptions &LO,
|
|||
Out << JsonFormat(TempOut.str(), AddQuotes);
|
||||
}
|
||||
|
||||
const Expr *CFGBlock::getLastCondition() const {
|
||||
// If the terminator is a temporary dtor or a virtual base, etc, we can't
|
||||
// retrieve a meaningful condition, bail out.
|
||||
if (Terminator.getKind() != CFGTerminator::StmtBranch)
|
||||
return nullptr;
|
||||
|
||||
// Also, if this method was called on a block that doesn't have 2 successors,
|
||||
// this block doesn't have retrievable condition.
|
||||
if (succ_size() < 2)
|
||||
return nullptr;
|
||||
|
||||
auto StmtElem = rbegin()->getAs<CFGStmt>();
|
||||
if (!StmtElem)
|
||||
return nullptr;
|
||||
|
||||
const Stmt *Cond = StmtElem->getStmt();
|
||||
if (isa<ObjCForCollectionStmt>(Cond))
|
||||
return nullptr;
|
||||
|
||||
// Only ObjCForCollectionStmt is known not to be a non-Expr terminator, hence
|
||||
// the cast<>.
|
||||
return cast<Expr>(Cond)->IgnoreParens();
|
||||
}
|
||||
|
||||
Stmt *CFGBlock::getTerminatorCondition(bool StripParens) {
|
||||
Stmt *Terminator = getTerminatorStmt();
|
||||
if (!Terminator)
|
||||
|
|
|
@ -117,6 +117,58 @@ TEST(CFG, IsLinear) {
|
|||
expectLinear(true, "void foo() { foo(); }"); // Recursion is not our problem.
|
||||
}
|
||||
|
||||
TEST(CFG, ConditionExpr) {
|
||||
const char *Code = R"(void f(bool A, bool B, bool C) {
|
||||
if (A && B && C)
|
||||
int x;
|
||||
})";
|
||||
BuildResult Result = BuildCFG(Code);
|
||||
EXPECT_EQ(BuildResult::BuiltCFG, Result.getStatus());
|
||||
|
||||
// [B5 (ENTRY)] -> [B4] -> [B3] -> [B2] -> [B1] -> [B0 (EXIT)]
|
||||
// \ \ \ /
|
||||
// ------------------------------->
|
||||
|
||||
CFG *cfg = Result.getCFG();
|
||||
|
||||
auto GetBlock = [cfg] (unsigned Index) -> CFGBlock * {
|
||||
assert(Index < cfg->size());
|
||||
return *(cfg->begin() + Index);
|
||||
};
|
||||
|
||||
auto GetExprText = [] (const Expr *E) -> std::string {
|
||||
// It's very awkward trying to recover the actual expression text without
|
||||
// a real source file, so use this as a workaround. We know that the
|
||||
// condition expression looks like this:
|
||||
//
|
||||
// ImplicitCastExpr 0xd07bf8 '_Bool' <LValueToRValue>
|
||||
// `-DeclRefExpr 0xd07bd8 '_Bool' lvalue ParmVar 0xd07960 'C' '_Bool'
|
||||
|
||||
assert(isa<ImplicitCastExpr>(E));
|
||||
assert(++E->child_begin() == E->child_end());
|
||||
const auto *D = dyn_cast<DeclRefExpr>(*E->child_begin());
|
||||
return D->getFoundDecl()->getNameAsString();
|
||||
};
|
||||
|
||||
EXPECT_EQ(GetBlock(1)->getLastCondition(), nullptr);
|
||||
EXPECT_EQ(GetExprText(GetBlock(4)->getLastCondition()), "A");
|
||||
EXPECT_EQ(GetExprText(GetBlock(3)->getLastCondition()), "B");
|
||||
EXPECT_EQ(GetExprText(GetBlock(2)->getLastCondition()), "C");
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
Code = R"(void foo(int x, int y) {
|
||||
(void)(x + y);
|
||||
})";
|
||||
Result = BuildCFG(Code);
|
||||
EXPECT_EQ(BuildResult::BuiltCFG, Result.getStatus());
|
||||
|
||||
// [B2 (ENTRY)] -> [B1] -> [B0 (EXIT)]
|
||||
|
||||
cfg = Result.getCFG();
|
||||
EXPECT_EQ(GetBlock(1)->getLastCondition(), nullptr);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace analysis
|
||||
} // namespace clang
|
||||
|
|
Loading…
Reference in New Issue