Author: szelethus Date: Wed Jul 3 05:53:19 2019 New Revision: 365036 URL: http://llvm.org/viewvc/llvm-project?rev=365036&view=rev Log: [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 Modified: cfe/trunk/include/clang/Analysis/CFG.h cfe/trunk/lib/Analysis/CFG.cpp Modified: cfe/trunk/include/clang/Analysis/CFG.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=365036&r1=365035&r2=365036&view=diff ============================================================================== --- cfe/trunk/include/clang/Analysis/CFG.h (original) +++ cfe/trunk/include/clang/Analysis/CFG.h Wed Jul 3 05:53:19 2019 @@ -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; } Modified: cfe/trunk/lib/Analysis/CFG.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=365036&r1=365035&r2=365036&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/CFG.cpp (original) +++ cfe/trunk/lib/Analysis/CFG.cpp Wed Jul 3 05:53:19 2019 @@ -5615,69 +5615,21 @@ void CFGBlock::printTerminatorJson(raw_o 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; } //===----------------------------------------------------------------------===// _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits