Index: clang/include/clang/Analysis/CFG.h =================================================================== --- clang/include/clang/Analysis/CFG.h +++ clang/include/clang/Analysis/CFG.h @@ -860,6 +860,14 @@ 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 { Index: clang/lib/Analysis/CFG.cpp =================================================================== --- clang/lib/Analysis/CFG.cpp +++ clang/lib/Analysis/CFG.cpp @@ -5615,6 +5615,22 @@ 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 (rbegin()->getKind() != CFGElement::Kind::Statement) + return nullptr; + + // This should be the condition of the terminator block. + const Stmt *S = rbegin()->castAs().getStmt(); + if (isa(S)) + return nullptr; + + // Only ObjCForCollectionStmt is known not to be a non-Expr terminator. + const Expr *Cond = cast(S); + return Cond->IgnoreParens(); +} + Stmt *CFGBlock::getTerminatorCondition(bool StripParens) { Stmt *Terminator = getTerminatorStmt(); if (!Terminator)