diff options
author | Kristof Umann <dkszelethus@gmail.com> | 2019-07-03 12:53:19 +0000 |
---|---|---|
committer | Kristof Umann <dkszelethus@gmail.com> | 2019-07-03 12:53:19 +0000 |
commit | 00aab1d45e1f67fbc265ed5ea4b2230148181970 (patch) | |
tree | e288b807ca296ba4aa8fda363994c8b302fa23c0 | |
parent | 5cf3cc624609b420319acef498becf48cc011c9a (diff) | |
download | bcm5719-llvm-00aab1d45e1f67fbc265ed5ea4b2230148181970.tar.gz bcm5719-llvm-00aab1d45e1f67fbc265ed5ea4b2230148181970.zip |
[analyzer][CFG] Return the correct terminator condition
For the following terminator statement:
if (A && B && C && D)
The built CFG is the following:
[B5 (ENTRY)]
Succs (1): B4
[B1]
1: 10
2: j
3: [B1.2] (ImplicitCastExpr, LValueToRValue, int)
4: [B1.1] / [B1.3]
5: int x = 10 / j;
Preds (1): B2
Succs (1): B0
[B2]
1: C
2: [B2.1] (ImplicitCastExpr, LValueToRValue, _Bool)
T: if [B4.4] && [B3.2] && [B2.2]
Preds (1): B3
Succs (2): B1 B0
[B3]
1: B
2: [B3.1] (ImplicitCastExpr, LValueToRValue, _Bool)
T: [B4.4] && [B3.2] && ...
Preds (1): B4
Succs (2): B2 B0
[B4]
1: 0
2: int j = 0;
3: A
4: [B4.3] (ImplicitCastExpr, LValueToRValue, _Bool)
T: [B4.4] && ...
Preds (1): B5
Succs (2): B3 B0
[B0 (EXIT)]
Preds (4): B1 B2 B3 B4
However, even though the path of execution in B2 only depends on C's value,
CFGBlock::getCondition() would return the entire condition (A && B && C). For
B3, it would return A && B. I changed this the actual condition.
Differential Revision: https://reviews.llvm.org/D63538
llvm-svn: 365036
-rw-r--r-- | clang/include/clang/Analysis/CFG.h | 8 | ||||
-rw-r--r-- | clang/lib/Analysis/CFG.cpp | 70 |
2 files changed, 16 insertions, 62 deletions
diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h index d8b3d6ff71e..945d36498cf 100644 --- a/clang/include/clang/Analysis/CFG.h +++ b/clang/include/clang/Analysis/CFG.h @@ -860,10 +860,12 @@ public: Stmt *getTerminatorStmt() { return Terminator.getStmt(); } const Stmt *getTerminatorStmt() const { return Terminator.getStmt(); } - Stmt *getTerminatorCondition(bool StripParens = true); + /// \returns the condition of the terminator (condition of an if statement, + /// for loop, etc). + const Stmt *getTerminatorCondition(bool StripParens = true) const; - const Stmt *getTerminatorCondition(bool StripParens = true) const { - return const_cast<CFGBlock*>(this)->getTerminatorCondition(StripParens); + const Expr *getTerminatorConditionExpr(bool StripParens = true) const { + return dyn_cast_or_null<Expr>(getTerminatorCondition(StripParens)); } const Stmt *getLoopTarget() const { return LoopTarget; } diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index b53bfcca37c..3e6185c76c9 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -5615,69 +5615,21 @@ void CFGBlock::printTerminatorJson(raw_ostream &Out, const LangOptions &LO, Out << JsonFormat(TempOut.str(), AddQuotes); } -Stmt *CFGBlock::getTerminatorCondition(bool StripParens) { - Stmt *Terminator = getTerminatorStmt(); - if (!Terminator) +const Stmt *CFGBlock::getTerminatorCondition(bool StripParens) const { + // If the terminator is a temporary dtor or a virtual base, etc, we can't + // retrieve a meaningful condition, bail out. + if (rbegin()->getKind() != CFGElement::Kind::Statement) return nullptr; - Expr *E = nullptr; - - switch (Terminator->getStmtClass()) { - default: - break; - - case Stmt::CXXForRangeStmtClass: - E = cast<CXXForRangeStmt>(Terminator)->getCond(); - break; - - case Stmt::ForStmtClass: - E = cast<ForStmt>(Terminator)->getCond(); - break; - - case Stmt::WhileStmtClass: - E = cast<WhileStmt>(Terminator)->getCond(); - break; - - case Stmt::DoStmtClass: - E = cast<DoStmt>(Terminator)->getCond(); - break; - - case Stmt::IfStmtClass: - E = cast<IfStmt>(Terminator)->getCond(); - break; - - case Stmt::ChooseExprClass: - E = cast<ChooseExpr>(Terminator)->getCond(); - break; - - case Stmt::IndirectGotoStmtClass: - E = cast<IndirectGotoStmt>(Terminator)->getTarget(); - break; - - case Stmt::SwitchStmtClass: - E = cast<SwitchStmt>(Terminator)->getCond(); - break; - - case Stmt::BinaryConditionalOperatorClass: - E = cast<BinaryConditionalOperator>(Terminator)->getCond(); - break; - - case Stmt::ConditionalOperatorClass: - E = cast<ConditionalOperator>(Terminator)->getCond(); - break; - - case Stmt::BinaryOperatorClass: // '&&' and '||' - E = cast<BinaryOperator>(Terminator)->getLHS(); - break; - - case Stmt::ObjCForCollectionStmtClass: - return Terminator; + // This should be the condition of the terminator block. + const Stmt *S = rbegin()->castAs<CFGStmt>().getStmt(); + if (isa<ObjCForCollectionStmt>(S)) { + return getTerminatorStmt(); } - if (!StripParens) - return E; - - return E ? E->IgnoreParens() : nullptr; + // Only ObjCForCollectionStmt is known not to be a non-Expr terminator. + const Expr *Cond = cast<Expr>(S); + return StripParens ? Cond->IgnoreParens() : Cond; } //===----------------------------------------------------------------------===// |