Index: clang/include/clang/Analysis/CFG.h =================================================================== --- clang/include/clang/Analysis/CFG.h +++ clang/include/clang/Analysis/CFG.h @@ -860,10 +860,12 @@ 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; } Index: clang/lib/Analysis/CFG.cpp =================================================================== --- clang/lib/Analysis/CFG.cpp +++ clang/lib/Analysis/CFG.cpp @@ -5615,69 +5615,21 @@ 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; } //===----------------------------------------------------------------------===//