From: Kristof Umann Date: Wed, 3 Jul 2019 12:53:19 +0000 (+0000) Subject: [analyzer][CFG] Return the correct terminator condition X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d6dbda40c8398a217b4f482c4e68e337a00029c3;p=clang [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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@365036 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index d8b3d6ff71..945d36498c 100644 --- a/include/clang/Analysis/CFG.h +++ b/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(this)->getTerminatorCondition(StripParens); + const Expr *getTerminatorConditionExpr(bool StripParens = true) const { + return dyn_cast_or_null(getTerminatorCondition(StripParens)); } const Stmt *getLoopTarget() const { return LoopTarget; } diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index b53bfcca37..3e6185c76c 100644 --- a/lib/Analysis/CFG.cpp +++ b/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(Terminator)->getCond(); - break; - - case Stmt::ForStmtClass: - E = cast(Terminator)->getCond(); - break; - - case Stmt::WhileStmtClass: - E = cast(Terminator)->getCond(); - break; - - case Stmt::DoStmtClass: - E = cast(Terminator)->getCond(); - break; - - case Stmt::IfStmtClass: - E = cast(Terminator)->getCond(); - break; - - case Stmt::ChooseExprClass: - E = cast(Terminator)->getCond(); - break; - - case Stmt::IndirectGotoStmtClass: - E = cast(Terminator)->getTarget(); - break; - - case Stmt::SwitchStmtClass: - E = cast(Terminator)->getCond(); - break; - - case Stmt::BinaryConditionalOperatorClass: - E = cast(Terminator)->getCond(); - break; - - case Stmt::ConditionalOperatorClass: - E = cast(Terminator)->getCond(); - break; - - case Stmt::BinaryOperatorClass: // '&&' and '||' - E = cast(Terminator)->getLHS(); - break; - - case Stmt::ObjCForCollectionStmtClass: - return Terminator; + // This should be the condition of the terminator block. + const Stmt *S = rbegin()->castAs().getStmt(); + if (isa(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(S); + return StripParens ? Cond->IgnoreParens() : Cond; } //===----------------------------------------------------------------------===//