Author: Gábor Tóthvári
Date: 2026-09-09T20:51:27+02:00
New Revision: e829049823905405779c6b908437b200e7ed1b2e

URL: 
https://github.com/llvm/llvm-project/commit/e829049823905405779c6b908437b200e7ed1b2e
DIFF: 
https://github.com/llvm/llvm-project/commit/e829049823905405779c6b908437b200e7ed1b2e.diff

LOG: [NFC][analyzer] Cleanup checker calls in `ExprEngine::ProcessStmt`, 
`ExprEngine::Visit*` (#218691)

Begin standardizing how `PreStmt` checkers and `PostStmt` checkers are
called by the analyzer engine. Previously, checkers were called either
from `ExprEngine::Visit` or the visit method of the statement. Now this
logic was hoisted out into `ExprEngine::ProcessStmt` and most of the
checker calls happen from there.

There are several statement kinds that do not call checkers at all or
only call `PreVisit` or only call `PostVisit` checkers. There are also
statement kinds whose visit code does not easily lend itself to the
`PreVisit`, `Visit`, `PostVisit` scheme, so those have been left
unmodified and will be refactored in a separate patch. The checker
calling status of statement kinds have been documented in the function
`shouldJustCallCheckers`.

Added: 
    

Modified: 
    clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
    clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
    clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
    clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
    clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
    clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp

Removed: 
    


################################################################################
diff  --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 195d63b0e0936..fe49e830fde76 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -510,9 +510,10 @@ class ExprEngine {
   void VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
                      ExplodedNodeSet &Dst);
 
-  /// VisitCast - Transfer function logic for all casts (implicit and 
explicit).
-  void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred,
-                 ExplodedNodeSet &Dst);
+  /// VisitCastExpr - Transfer function logic for all casts (implicit and
+  /// explicit).
+  void VisitCastExpr(const CastExpr *CastE, ExplodedNode *Pred,
+                     ExplodedNodeSet &Dst);
 
   /// VisitCompoundLiteralExpr - Transfer function logic for compound literals.
   void VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
@@ -546,10 +547,6 @@ class ExprEngine {
   void VisitAtomicExpr(const AtomicExpr *E, ExplodedNode *Pred,
                        ExplodedNodeSet &Dst);
 
-  /// Transfer function logic for ObjCAtSynchronizedStmts.
-  void VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
-                                   ExplodedNode *Pred, ExplodedNodeSet &Dst);
-
   /// Transfer function logic for computing the lvalue of an Objective-C ivar.
   void VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *DR, ExplodedNode *Pred,
                                 ExplodedNodeSet &Dst);
@@ -582,22 +579,34 @@ class ExprEngine {
   void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
                                      ExplodedNode *Pred, ExplodedNodeSet &Dst);
 
+  void VisitStmtExpr(const StmtExpr *SE, ExplodedNode *Pred,
+                     ExplodedNodeSet &Dst);
+
   /// VisitUnaryOperator - Transfer function logic for unary operators.
   void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode *Pred,
                           ExplodedNodeSet &Dst);
 
+  void VisitPseudoObjectExpr(const PseudoObjectExpr *PE, ExplodedNode *Pred,
+                             ExplodedNodeSet &Dst);
+
+  void VisitObjCIndirectCopyRestoreExpr(const ObjCIndirectCopyRestoreExpr *OIE,
+                                        ExplodedNode *Pred,
+                                        ExplodedNodeSet &Dst);
+
   /// Handle ++ and -- (both pre- and post-increment).
   void VisitIncrementDecrementOperator(const UnaryOperator* U,
                                        ExplodedNode *Pred,
                                        ExplodedNodeSet &Dst);
 
   void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE,
-                                 ExplodedNodeSet &PreVisit,
-                                 ExplodedNodeSet &Dst);
+                                 ExplodedNode *Pred, ExplodedNodeSet &Dst);
 
   void VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred,
                          ExplodedNodeSet &Dst);
 
+  void VisitCXXParenListInitExpr(const CXXParenListInitExpr *E,
+                                 ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
   void VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
                         ExplodedNodeSet & Dst);
 
@@ -623,9 +632,8 @@ class ExprEngine {
                           ExplodedNodeSet &Dst);
 
   /// Create a C++ temporary object for an rvalue.
-  void CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
-                                ExplodedNode *Pred,
-                                ExplodedNodeSet &Dst);
+  void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE,
+                                     ExplodedNode *Pred, ExplodedNodeSet &Dst);
 
   void ConstructInitList(const Expr *Source, ArrayRef<Expr *> Args,
                          bool IsTransparent, ExplodedNode *Pred,
@@ -641,10 +649,10 @@ class ExprEngine {
   static std::pair<const ProgramPointTag *, const ProgramPointTag *>
   getEagerlyAssumeBifurcationTags();
 
-  ProgramStateRef handleLValueBitCast(ProgramStateRef state, const Expr *Ex,
-                                      const StackFrame *SF, QualType T,
-                                      QualType ExTy, const CastExpr *CastE,
-                                      ExplodedNodeSet &Dst, ExplodedNode 
*Pred);
+  void handleLValueBitCast(ProgramStateRef state, const Expr *Ex,
+                           const StackFrame *SF, QualType T, QualType ExTy,
+                           const CastExpr *CastE, ExplodedNodeSet &Dst,
+                           ExplodedNode *Pred);
 
 public:
   SVal evalBinOp(ProgramStateRef ST, BinaryOperator::Opcode Op,

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index f0f7d78fc5d50..4d1cd51f3a2ab 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1100,6 +1100,334 @@ const ProgramPointTag *ExprEngine::cleanupNodeTag() {
   return &cleanupTag;
 }
 
+namespace {
+enum class VisitKind {
+  Pre,
+  Post,
+};
+}
+
+static bool shouldJustCallCheckers(const Stmt *S, VisitKind K) {
+
+  switch (S->getStmtClass()) {
+
+  default:
+    return true;
+
+  // C++, OpenMP and ARC stuff we don't support yet.
+  case Stmt::CXXDependentScopeMemberExprClass:
+  case Stmt::CXXReflectExprClass:
+  case Stmt::CXXTryStmtClass:
+  case Stmt::CXXTypeidExprClass:
+  case Stmt::CXXUuidofExprClass:
+  case Stmt::CXXFoldExprClass:
+  case Stmt::MSPropertyRefExprClass:
+  case Stmt::MSPropertySubscriptExprClass:
+  case Stmt::CXXUnresolvedConstructExprClass:
+  case Stmt::DependentScopeDeclRefExprClass:
+  case Stmt::ArrayTypeTraitExprClass:
+  case Stmt::ExpressionTraitExprClass:
+  case Stmt::UnresolvedLookupExprClass:
+  case Stmt::UnresolvedMemberExprClass:
+  case Stmt::DependentTemplateIdExprClass:
+  case Stmt::RecoveryExprClass:
+  case Stmt::CXXNoexceptExprClass:
+  case Stmt::PackExpansionExprClass:
+  case Stmt::PackIndexingExprClass:
+  case Stmt::SubstNonTypeTemplateParmPackExprClass:
+  case Stmt::FunctionParmPackExprClass:
+  case Stmt::CoroutineBodyStmtClass:
+  case Stmt::CoawaitExprClass:
+  case Stmt::DependentCoawaitExprClass:
+  case Stmt::CoreturnStmtClass:
+  case Stmt::CoyieldExprClass:
+  case Stmt::SEHTryStmtClass:
+  case Stmt::SEHExceptStmtClass:
+  case Stmt::SEHLeaveStmtClass:
+  case Stmt::SEHFinallyStmtClass:
+  case Stmt::CXXExpansionStmtPatternClass:
+  case Stmt::CXXExpansionStmtInstantiationClass:
+  case Stmt::CXXExpansionSelectExprClass:
+  case Stmt::OMPCanonicalLoopClass:
+  case Stmt::OMPParallelDirectiveClass:
+  case Stmt::OMPSimdDirectiveClass:
+  case Stmt::OMPForDirectiveClass:
+  case Stmt::OMPForSimdDirectiveClass:
+  case Stmt::OMPSectionsDirectiveClass:
+  case Stmt::OMPSectionDirectiveClass:
+  case Stmt::OMPScopeDirectiveClass:
+  case Stmt::OMPSingleDirectiveClass:
+  case Stmt::OMPMasterDirectiveClass:
+  case Stmt::OMPCriticalDirectiveClass:
+  case Stmt::OMPParallelForDirectiveClass:
+  case Stmt::OMPParallelForSimdDirectiveClass:
+  case Stmt::OMPParallelSectionsDirectiveClass:
+  case Stmt::OMPParallelMasterDirectiveClass:
+  case Stmt::OMPParallelMaskedDirectiveClass:
+  case Stmt::OMPTaskDirectiveClass:
+  case Stmt::OMPTaskyieldDirectiveClass:
+  case Stmt::OMPBarrierDirectiveClass:
+  case Stmt::OMPTaskwaitDirectiveClass:
+  case Stmt::OMPErrorDirectiveClass:
+  case Stmt::OMPTaskgroupDirectiveClass:
+  case Stmt::OMPFlushDirectiveClass:
+  case Stmt::OMPDepobjDirectiveClass:
+  case Stmt::OMPScanDirectiveClass:
+  case Stmt::OMPOrderedStandaloneDirectiveClass:
+  case Stmt::OMPOrderedBlockAssocDirectiveClass:
+  case Stmt::OMPAtomicDirectiveClass:
+  case Stmt::OMPAssumeDirectiveClass:
+  case Stmt::OMPTargetDirectiveClass:
+  case Stmt::OMPTargetDataDirectiveClass:
+  case Stmt::OMPTargetEnterDataDirectiveClass:
+  case Stmt::OMPTargetExitDataDirectiveClass:
+  case Stmt::OMPTargetParallelDirectiveClass:
+  case Stmt::OMPTargetParallelForDirectiveClass:
+  case Stmt::OMPTargetUpdateDirectiveClass:
+  case Stmt::OMPTeamsDirectiveClass:
+  case Stmt::OMPCancellationPointDirectiveClass:
+  case Stmt::OMPCancelDirectiveClass:
+  case Stmt::OMPTaskLoopDirectiveClass:
+  case Stmt::OMPTaskLoopSimdDirectiveClass:
+  case Stmt::OMPMasterTaskLoopDirectiveClass:
+  case Stmt::OMPMaskedTaskLoopDirectiveClass:
+  case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
+  case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:
+  case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
+  case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:
+  case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
+  case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:
+  case Stmt::OMPDistributeDirectiveClass:
+  case Stmt::OMPDistributeParallelForDirectiveClass:
+  case Stmt::OMPDistributeParallelForSimdDirectiveClass:
+  case Stmt::OMPDistributeSimdDirectiveClass:
+  case Stmt::OMPTargetParallelForSimdDirectiveClass:
+  case Stmt::OMPTargetSimdDirectiveClass:
+  case Stmt::OMPTeamsDistributeDirectiveClass:
+  case Stmt::OMPTeamsDistributeSimdDirectiveClass:
+  case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
+  case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
+  case Stmt::OMPTargetTeamsDirectiveClass:
+  case Stmt::OMPTargetTeamsDistributeDirectiveClass:
+  case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
+  case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
+  case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
+  case Stmt::OMPReverseDirectiveClass:
+  case Stmt::OMPStripeDirectiveClass:
+  case Stmt::OMPTileDirectiveClass:
+  case Stmt::OMPInterchangeDirectiveClass:
+  case Stmt::OMPSplitDirectiveClass:
+  case Stmt::OMPFuseDirectiveClass:
+  case Stmt::OMPInteropDirectiveClass:
+  case Stmt::OMPDispatchDirectiveClass:
+  case Stmt::OMPMaskedDirectiveClass:
+  case Stmt::OMPGenericLoopDirectiveClass:
+  case Stmt::OMPTeamsGenericLoopDirectiveClass:
+  case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:
+  case Stmt::OMPParallelGenericLoopDirectiveClass:
+  case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
+  case Stmt::CapturedStmtClass:
+  case Stmt::SYCLKernelCallStmtClass:
+  case Stmt::UnresolvedSYCLKernelCallStmtClass:
+  case Stmt::OpenACCComputeConstructClass:
+  case Stmt::OpenACCLoopConstructClass:
+  case Stmt::OpenACCCombinedConstructClass:
+  case Stmt::OpenACCDataConstructClass:
+  case Stmt::OpenACCEnterDataConstructClass:
+  case Stmt::OpenACCExitDataConstructClass:
+  case Stmt::OpenACCHostDataConstructClass:
+  case Stmt::OpenACCWaitConstructClass:
+  case Stmt::OpenACCCacheConstructClass:
+  case Stmt::OpenACCInitConstructClass:
+  case Stmt::OpenACCShutdownConstructClass:
+  case Stmt::OpenACCSetConstructClass:
+  case Stmt::OpenACCUpdateConstructClass:
+  case Stmt::OpenACCAtomicConstructClass:
+  case Stmt::OMPUnrollDirectiveClass:
+  case Stmt::OMPMetaDirectiveClass:
+  case Stmt::HLSLOutArgExprClass:
+    return false;
+
+  // ParenExprs already handled.
+  case Stmt::ParenExprClass:
+    return false;
+
+  // GenericSelectionExprs already handled.
+  case Stmt::GenericSelectionExprClass:
+    return false;
+
+  // Cases that should never be evaluated simply because they shouldn't
+  // appear in the CFG.
+  case Stmt::BreakStmtClass:
+  case Stmt::CaseStmtClass:
+  case Stmt::CompoundStmtClass:
+  case Stmt::ContinueStmtClass:
+  case Stmt::CXXForRangeStmtClass:
+  case Stmt::DefaultStmtClass:
+  case Stmt::DoStmtClass:
+  case Stmt::ForStmtClass:
+  case Stmt::GotoStmtClass:
+  case Stmt::IfStmtClass:
+  case Stmt::IndirectGotoStmtClass:
+  case Stmt::LabelStmtClass:
+  case Stmt::NoStmtClass:
+  case Stmt::NullStmtClass:
+  case Stmt::SwitchStmtClass:
+  case Stmt::WhileStmtClass:
+  case Stmt::DeferStmtClass:
+  case Expr::MSDependentExistsStmtClass:
+    return false;
+
+  // These nodes are shared in the CFG and would case caching out.
+  // Moreover, no additional evaluation required for them, the
+  // analyzer can reconstruct these values from the AST.
+  case Stmt::ImplicitValueInitExprClass:
+    return false;
+
+  // These are handled by PseudoObjectExpr
+  case Stmt::ObjCSubscriptRefExprClass:
+  case Stmt::ObjCPropertyRefExprClass:
+    return false;
+
+  // FIXME: Does not call checkers
+  case Stmt::GNUNullExprClass:
+    return false;
+
+  // FIXME: Does not call PostVisit checkers
+  case Stmt::ObjCAtSynchronizedStmtClass:
+    return K == VisitKind::Pre;
+
+  // FIXME: They do not call checkers
+  case Expr::ConstantExprClass:
+  case Stmt::ExprWithCleanupsClass:
+    return false;
+
+  // Support for MatrixSingleSubscriptExprClass is not implemented.
+  case Stmt::MatrixSingleSubscriptExprClass:
+    return false;
+
+  // Support for MatrixSubscriptExpr is not implemented.
+  case Stmt::MatrixSubscriptExprClass:
+    return false;
+
+  // FIXME: Does not call checkers
+  case Stmt::MSAsmStmtClass:
+    return false;
+
+  // FIXME: Does not call PreVisit checkers
+  case Stmt::BlockExprClass:
+    return K == VisitKind::Post;
+
+  // FIXME: Does not call PreVisit checkers
+  // Currently the engine does not call PostVisit checkers when
+  // lambda inlining is disabled, so K == PostVisitKind
+  // cannot be returned here.
+  case Stmt::LambdaExprClass:
+    return false;
+
+  // Checkers are called manually with custom logic when this calls
+  // VisitBinaryOperator, but calls no checkers during VisitLogicalExpr
+  case Stmt::BinaryOperatorClass:
+    return false;
+
+  // Checkers are called manually with custom logic in these cases
+  // (VisitCallExpr)
+  case Stmt::CXXOperatorCallExprClass:
+  case Stmt::CallExprClass:
+  case Stmt::CXXMemberCallExprClass:
+  case Stmt::UserDefinedLiteralClass:
+    return false;
+
+  // FIXME: Does not call checkers
+  case Stmt::CXXCatchStmtClass:
+    return false;
+
+  // Checkers are called manually with custom logic in these cases
+  // (handleConstructor)
+  case Stmt::CXXTemporaryObjectExprClass:
+  case Stmt::CXXConstructExprClass:
+    return false;
+
+  // Checkers are called manually with custom logic in this case
+  // (handleConstructor)
+  case Stmt::CXXInheritedCtorInitExprClass:
+    return false;
+
+  // FIXME: Does not call checkers
+  case Stmt::ChooseExprClass:
+    return false;
+
+  // Checkers are called manually with custom logic in this case
+  // (VisitBinaryOperator)
+  case Stmt::CompoundAssignOperatorClass:
+    return false;
+
+  // FIXME: Does not call checkers
+  case Stmt::CompoundLiteralExprClass:
+    return false;
+
+  // FIXME: These do not call checkers
+  case Stmt::BinaryConditionalOperatorClass:
+  case Stmt::ConditionalOperatorClass:
+    return false;
+
+  // FIXME: Does not call checkers
+  case Stmt::CXXThisExprClass:
+    return false;
+
+  // FIXME: Does not call checkers
+  case Stmt::DeclRefExprClass:
+    return false;
+
+  // Checkers are called manually with custom logic in this case
+  case Stmt::DeclStmtClass:
+    return false;
+
+  // FIXME: These do not call checkers
+  // (ConstructInitList)
+  case Stmt::InitListExprClass:
+  case Expr::CXXParenListInitExprClass:
+    return false;
+
+  // FIXME: Does not call PreVisit checkers
+  case Stmt::ObjCIvarRefExprClass:
+    return K == VisitKind::Post;
+
+  // FIXME: Does not call PreVisit checkers
+  case Stmt::ObjCForCollectionStmtClass:
+    return K == VisitKind::Post;
+
+  // FIXME: Does not call checkers
+  case Stmt::ObjCMessageExprClass:
+    return false;
+
+  // FIXME: These do not call checkers
+  case Stmt::ObjCAtThrowStmtClass:
+  case Stmt::CXXThrowExprClass:
+    return false;
+
+  // FIXME: Does not call PostVisit checkers
+  case Stmt::ReturnStmtClass:
+    return K == VisitKind::Pre;
+
+  // FIXME: Does not call checkers
+  case Stmt::StmtExprClass:
+    return false;
+
+  // Checkers are called manually with custom logic in this case
+  case Stmt::UnaryOperatorClass:
+    return false;
+
+  // FIXME: Does not call checkers
+  case Stmt::PseudoObjectExprClass:
+    return false;
+
+  // FIXME: Does not call checkers
+  case Expr::ObjCIndirectCopyRestoreExprClass:
+    return false;
+  }
+}
+
 void ExprEngine::ProcessStmt(const Stmt *currStmt, ExplodedNode *Pred) {
   // Reclaim any unnecessary nodes in the ExplodedGraph.
   G.reclaimRecentlyAllocatedNodes();
@@ -1115,17 +1443,29 @@ void ExprEngine::ProcessStmt(const Stmt *currStmt, 
ExplodedNode *Pred) {
   } else
     CleanedStates.insert(Pred);
 
-  // Visit the statement.
-  ExplodedNodeSet Dst;
-  for (const auto I : CleanedStates) {
-    ExplodedNodeSet DstI;
-    // Visit the statement.
-    Visit(currStmt, I, DstI);
-    Dst.insert(DstI);
+  ExplodedNodeSet PreVisited;
+  if (shouldJustCallCheckers(currStmt, VisitKind::Pre)) {
+    getCheckerManager().runCheckersForPreStmt(PreVisited, CleanedStates,
+                                              currStmt, *this);
+  } else
+    PreVisited.insert(CleanedStates);
+
+  ExplodedNodeSet Visited;
+  for (const auto I : PreVisited) {
+    ExplodedNodeSet Tmp;
+    Visit(currStmt, I, Tmp);
+    Visited.insert(Tmp);
   }
 
+  ExplodedNodeSet PostVisited;
+  if (shouldJustCallCheckers(currStmt, VisitKind::Post)) {
+    getCheckerManager().runCheckersForPostStmt(PostVisited, Visited, currStmt,
+                                               *this);
+  } else
+    PostVisited.insert(Visited);
+
   // Enqueue the new nodes onto the work list.
-  Engine.enqueueStmtNodes(Dst, getCurrBlock(), currStmtIdx);
+  Engine.enqueueStmtNodes(PostVisited, getCurrBlock(), currStmtIdx);
 }
 
 void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) {
@@ -1624,7 +1964,7 @@ void ExprEngine::processCleanupTemporaryBranch(const 
CXXBindTemporaryExpr *BTE,
 }
 
 void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE,
-                                           ExplodedNodeSet &PreVisit,
+                                           ExplodedNode *Pred,
                                            ExplodedNodeSet &Dst) {
   // This is a fallback solution in case we didn't have a construction
   // context when we were constructing the temporary. Otherwise the map should
@@ -1632,21 +1972,19 @@ void ExprEngine::VisitCXXBindTemporaryExpr(const 
CXXBindTemporaryExpr *BTE,
   if (!getAnalysisManager().options.ShouldIncludeTemporaryDtorsInCFG) {
     // In case we don't have temporary destructors in the CFG, do not mark
     // the initialization - we would otherwise never clean it up.
-    Dst = PreVisit;
+    Dst.insert(Pred);
     return;
   }
-  for (ExplodedNode *Node : PreVisit) {
-    ProgramStateRef State = Node->getState();
-    const StackFrame *SF = Node->getStackFrame();
-    if (!getObjectUnderConstruction(State, BTE, SF)) {
-      // FIXME: Currently the state might also already contain the marker due 
to
-      // incorrect handling of temporaries bound to default parameters; for
-      // those, we currently skip the CXXBindTemporaryExpr but rely on adding
-      // temporary destructor nodes.
-      State = addObjectUnderConstruction(State, BTE, SF, UnknownVal());
-    }
-    Dst.insert(Engine.makePostStmtNode(BTE, State, Node));
+  ProgramStateRef State = Pred->getState();
+  const StackFrame *SF = Pred->getStackFrame();
+  if (!getObjectUnderConstruction(State, BTE, SF)) {
+    // FIXME: Currently the state might also already contain the marker due to
+    // incorrect handling of temporaries bound to default parameters; for
+    // those, we currently skip the CXXBindTemporaryExpr but rely on adding
+    // temporary destructor nodes.
+    State = addObjectUnderConstruction(State, BTE, SF, UnknownVal());
   }
+  Dst.insert(Engine.makePostStmtNode(BTE, State, Pred));
 }
 
 ProgramStateRef ExprEngine::escapeValues(ProgramStateRef State,
@@ -1864,9 +2202,10 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
       break;
     }
 
-    case Stmt::ObjCAtSynchronizedStmtClass:
-      VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S), Pred, Dst);
+    case Stmt::ObjCAtSynchronizedStmtClass: {
+      Dst.insert(Pred);
       break;
+    }
 
     case Expr::ConstantExprClass:
     case Stmt::ExprWithCleanupsClass:
@@ -1874,14 +2213,9 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
       // Handled due to fully linearised CFG.
       break;
 
-    case Stmt::CXXBindTemporaryExprClass: {
-      ExplodedNodeSet PreVisit;
-      getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
-      ExplodedNodeSet Next;
-      VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), PreVisit, Next);
-      getCheckerManager().runCheckersForPostStmt(Dst, Next, S, *this);
+    case Stmt::CXXBindTemporaryExprClass:
+      VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), Pred, Dst);
       break;
-    }
 
     case Stmt::ArrayInitLoopExprClass:
       VisitArrayInitLoopExpr(cast<ArrayInitLoopExpr>(S), Pred, Dst);
@@ -1940,23 +2274,16 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode 
*Pred,
     case Stmt::SYCLUniqueStableNameExprClass:
     case Stmt::OpenACCAsteriskSizeExprClass:
     case Stmt::TypeTraitExprClass: {
-      ExplodedNodeSet preVisit;
-      getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
-      getCheckerManager().runCheckersForPostStmt(Dst, preVisit, S, *this);
+      Dst.insert(Pred);
       break;
     }
 
-    case Stmt::AttributedStmtClass: {
+    case Stmt::AttributedStmtClass:
       VisitAttributedStmt(cast<AttributedStmt>(S), Pred, Dst);
       break;
-    }
 
     case Stmt::CXXDefaultArgExprClass:
     case Stmt::CXXDefaultInitExprClass: {
-      ExplodedNodeSet PreVisit;
-      getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
-
-      ExplodedNodeSet Tmp;
 
       const Expr *ArgE;
       if (const auto *DefE = dyn_cast<CXXDefaultArgExpr>(S))
@@ -1977,16 +2304,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode 
*Pred,
         ConstantVal = UnknownVal();
 
       const StackFrame *SF = Pred->getStackFrame();
-      for (const auto I : PreVisit) {
-        ProgramStateRef State = I->getState();
-        State = State->BindExpr(cast<Expr>(S), SF, *ConstantVal);
-        if (IsTemporary)
-          State = createTemporaryRegionIfNeeded(State, SF, cast<Expr>(S),
-                                                cast<Expr>(S));
-        Tmp.insert(Engine.makePostStmtNode(S, State, I));
-      }
+      ProgramStateRef State = Pred->getState();
+      State = State->BindExpr(cast<Expr>(S), SF, *ConstantVal);
+      if (IsTemporary)
+        State = createTemporaryRegionIfNeeded(State, SF, cast<Expr>(S),
+                                              cast<Expr>(S));
+      Dst.insert(Engine.makePostStmtNode(S, State, Pred));
 
-      getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
       break;
     }
 
@@ -1995,37 +2319,27 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode 
*Pred,
     case Expr::ObjCArrayLiteralClass:
     case Expr::ObjCDictionaryLiteralClass:
     case Expr::ObjCBoxedExprClass: {
-      ExplodedNodeSet preVisit;
-      getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
-
-      ExplodedNodeSet Tmp;
-
       const auto *Ex = cast<Expr>(S);
       QualType resultType = Ex->getType();
 
-      for (const auto N : preVisit) {
-        const StackFrame *SF = N->getStackFrame();
-        SVal result = svalBuilder.conjureSymbolVal(
-            /*symbolTag=*/nullptr, getCFGElementRef(), SF, resultType,
-            getNumVisitedCurrent());
-        ProgramStateRef State = N->getState()->BindExpr(Ex, SF, result);
-
-        // Escape pointers passed into the list, unless it's an ObjC boxed
-        // expression which is not a boxable C structure.
-        if (!(isa<ObjCBoxedExpr>(Ex) &&
-              !cast<ObjCBoxedExpr>(Ex)->getSubExpr()
-                                      ->getType()->isRecordType()))
-          for (auto Child : Ex->children()) {
-            assert(Child);
-            const auto *ChildExpr = dyn_cast<Expr>(Child);
-            SVal Val = ChildExpr ? State->getSVal(ChildExpr, SF) : 
UnknownVal();
-            State = escapeValues(State, Val, PSK_EscapeOther);
-          }
-
-        Tmp.insert(Engine.makePostStmtNode(S, State, N));
-      }
+      const StackFrame *SF = Pred->getStackFrame();
+      SVal result = svalBuilder.conjureSymbolVal(
+          /*symbolTag=*/nullptr, getCFGElementRef(), SF, resultType,
+          getNumVisitedCurrent());
+      ProgramStateRef State = Pred->getState()->BindExpr(Ex, SF, result);
+
+      // Escape pointers passed into the list, unless it's an ObjC boxed
+      // expression which is not a boxable C structure.
+      if (!(isa<ObjCBoxedExpr>(Ex) &&
+            !cast<ObjCBoxedExpr>(Ex)->getSubExpr()->getType()->isRecordType()))
+        for (auto Child : Ex->children()) {
+          assert(Child);
+          const auto *ChildExpr = dyn_cast<Expr>(Child);
+          SVal Val = ChildExpr ? State->getSVal(ChildExpr, SF) : UnknownVal();
+          State = escapeValues(State, Val, PSK_EscapeOther);
+        }
 
-      getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
+      Dst.insert(Engine.makePostStmtNode(S, State, Pred));
       break;
     }
 
@@ -2042,15 +2356,9 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
       llvm_unreachable("Support for MatrixSubscriptExpr is not implemented.");
       break;
 
-    case Stmt::GCCAsmStmtClass: {
-      ExplodedNodeSet PreVisit;
-      getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
-      ExplodedNodeSet PostVisit;
-      for (ExplodedNode *const N : PreVisit)
-        VisitGCCAsmStmt(cast<GCCAsmStmt>(S), N, PostVisit);
-      getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this);
+    case Stmt::GCCAsmStmtClass:
+      VisitGCCAsmStmt(cast<GCCAsmStmt>(S), Pred, Dst);
       break;
-    }
 
     case Stmt::MSAsmStmtClass:
       VisitMSAsmStmt(cast<MSAsmStmt>(S), Pred, Dst);
@@ -2061,13 +2369,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
       break;
 
     case Stmt::LambdaExprClass:
-      if (AMgr.options.ShouldInlineLambdas) {
-        VisitLambdaExpr(cast<LambdaExpr>(S), Pred, Dst);
-      } else {
-        const ExplodedNode *Node = Engine.makePostStmtNode(
-            S, Pred->getState(), Pred, /*MarkAsSink=*/true);
-        Engine.addAbortedBlock(Node, getCurrBlock());
-      }
+      VisitLambdaExpr(cast<LambdaExpr>(S), Pred, Dst);
       break;
 
     case Stmt::BinaryOperatorClass: {
@@ -2115,34 +2417,16 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode 
*Pred,
                                     Dst);
       break;
 
-    case Stmt::CXXNewExprClass: {
-
-      ExplodedNodeSet PreVisit;
-      getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
-
-      ExplodedNodeSet PostVisit;
-      for (const auto i : PreVisit)
-        VisitCXXNewExpr(cast<CXXNewExpr>(S), i, PostVisit);
-
-      getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this);
+    case Stmt::CXXNewExprClass:
+      VisitCXXNewExpr(cast<CXXNewExpr>(S), Pred, Dst);
       break;
-    }
-
-    case Stmt::CXXDeleteExprClass: {
-      ExplodedNodeSet PreVisit;
-      const auto *CDE = cast<CXXDeleteExpr>(S);
-      getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
-
-      ExplodedNodeSet PostVisit;
-      for (const auto i : PreVisit)
-        VisitCXXDeleteExpr(CDE, i, PostVisit);
 
-      getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this);
+    case Stmt::CXXDeleteExprClass:
+      VisitCXXDeleteExpr(cast<CXXDeleteExpr>(S), Pred, Dst);
       break;
-    }
-      // FIXME: ChooseExpr is really a constant.  We need to fix
-      //        the CFG do not model them as explicit control-flow.
 
+    // FIXME: ChooseExpr is really a constant.  We need to fix
+    //        the CFG do not model them as explicit control-flow.
     case Stmt::ChooseExprClass: { // __builtin_choose_expr
       const auto *C = cast<ChooseExpr>(S);
       VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
@@ -2187,26 +2471,14 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode 
*Pred,
     case Stmt::CXXFunctionalCastExprClass:
     case Stmt::BuiltinBitCastExprClass:
     case Stmt::ObjCBridgedCastExprClass:
-    case Stmt::CXXAddrspaceCastExprClass: {
-      const auto *C = cast<CastExpr>(S);
-      ExplodedNodeSet dstExpr;
-      VisitCast(C, C->getSubExpr(), Pred, dstExpr);
-
-      // Handle the postvisit checks.
-      getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, C, *this);
+    case Stmt::CXXAddrspaceCastExprClass:
+      VisitCastExpr(cast<CastExpr>(S), Pred, Dst);
       break;
-    }
 
-    case Expr::MaterializeTemporaryExprClass: {
-      const auto *MTE = cast<MaterializeTemporaryExpr>(S);
-      ExplodedNodeSet dstPrevisit;
-      getCheckerManager().runCheckersForPreStmt(dstPrevisit, Pred, MTE, *this);
-      ExplodedNodeSet dstExpr;
-      for (const auto i : dstPrevisit)
-        CreateCXXTemporaryObject(MTE, i, dstExpr);
-      getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, MTE, *this);
+    case Expr::MaterializeTemporaryExprClass:
+      VisitMaterializeTemporaryExpr(cast<MaterializeTemporaryExpr>(S), Pred,
+                                    Dst);
       break;
-    }
 
     case Stmt::InitListExprClass: {
       const InitListExpr *E = cast<InitListExpr>(S);
@@ -2214,12 +2486,9 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
       break;
     }
 
-    case Expr::CXXParenListInitExprClass: {
-      const CXXParenListInitExpr *E = cast<CXXParenListInitExpr>(S);
-      ConstructInitList(E, E->getInitExprs(), /*IsTransparent*/ false, Pred,
-                        Dst);
+    case Expr::CXXParenListInitExprClass:
+      VisitCXXParenListInitExpr(cast<CXXParenListInitExpr>(S), Pred, Dst);
       break;
-    }
 
     case Stmt::MemberExprClass:
       VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst);
@@ -2252,38 +2521,18 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode 
*Pred,
       VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
       break;
 
-    case Stmt::OffsetOfExprClass: {
-      ExplodedNodeSet PreVisit;
-      getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
-
-      ExplodedNodeSet PostVisit;
-      for (const auto Node : PreVisit)
-        VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Node, PostVisit);
-
-      getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this);
+    case Stmt::OffsetOfExprClass:
+      VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst);
       break;
-    }
 
     case Stmt::UnaryExprOrTypeTraitExprClass:
       VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S), Pred,
                                     Dst);
       break;
 
-    case Stmt::StmtExprClass: {
-      const auto *SE = cast<StmtExpr>(S);
-
-      if (SE->getSubStmt()->body_empty()) {
-        // Empty statement expression.
-        assert(SE->getType() == getContext().VoidTy
-               && "Empty statement expression must have void type.");
-      } else if (const auto *LastExpr =
-                     dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) {
-        SVal Val = Pred->getState()->getSVal(LastExpr, Pred->getStackFrame());
-        Pred = Engine.makeNodeWithBinding(Pred, SE, Val);
-      }
-      Dst.insert(Pred);
+    case Stmt::StmtExprClass:
+      VisitStmtExpr(cast<StmtExpr>(S), Pred, Dst);
       break;
-    }
 
     case Stmt::UnaryOperatorClass: {
       const auto *U = cast<UnaryOperator>(S);
@@ -2297,26 +2546,15 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode 
*Pred,
       break;
     }
 
-    case Stmt::PseudoObjectExprClass: {
-      const auto *PE = cast<PseudoObjectExpr>(S);
-      SVal V = UnknownVal();
-      if (const Expr *Result = PE->getResultExpr())
-        V = Pred->getState()->getSVal(Result, Pred->getStackFrame());
-      Dst.insert(Engine.makeNodeWithBinding(Pred, PE, V));
+    case Stmt::PseudoObjectExprClass:
+      VisitPseudoObjectExpr(cast<PseudoObjectExpr>(S), Pred, Dst);
       break;
-    }
 
-    case Expr::ObjCIndirectCopyRestoreExprClass: {
-      // ObjCIndirectCopyRestoreExpr implies passing a temporary for
-      // correctness of lifetime management.  Due to limited analysis
-      // of ARC, this is implemented as direct arg passing.
-      const auto *OIE = cast<ObjCIndirectCopyRestoreExpr>(S);
-      const Expr *E = OIE->getSubExpr();
-      SVal V = Pred->getState()->getSVal(E, Pred->getStackFrame());
-      Dst.insert(Engine.makeNodeWithBinding(Pred, OIE, V));
+    case Expr::ObjCIndirectCopyRestoreExprClass:
+      VisitObjCIndirectCopyRestoreExpr(cast<ObjCIndirectCopyRestoreExpr>(S),
+                                       Pred, Dst);
       break;
     }
-  }
 }
 
 bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
@@ -3183,110 +3421,96 @@ void ExprEngine::VisitArrayInitLoopExpr(const 
ArrayInitLoopExpr *Ex,
                                         ExplodedNodeSet &Dst) {
   const Expr *Arr = Ex->getCommonExpr()->getSourceExpr();
 
-  ExplodedNodeSet CheckerPreStmt;
-  getCheckerManager().runCheckersForPreStmt(CheckerPreStmt, Pred, Ex, *this);
-
-  ExplodedNodeSet EvalSet;
+  // The constructor visitor has already handled everything
   if (isa<CXXConstructExpr>(Ex->getSubExpr())) {
-    // The constructor visitor has already handled everything, so let's skip
-    // forward to PostStmt handling by clearing the range of the 'for' loop.
-    EvalSet.insert(CheckerPreStmt);
-    CheckerPreStmt.clear();
+    Dst.insert(Pred);
+    return;
   }
 
-  for (auto *Node : CheckerPreStmt) {
-    const StackFrame *SF = Node->getStackFrame();
-    ProgramStateRef state = Node->getState();
-
-    SVal Base = UnknownVal();
-
-    // As in case of this expression the sub-expressions are not visited by any
-    // other transfer functions, they are handled by matching their AST.
+  const StackFrame *SF = Pred->getStackFrame();
+  ProgramStateRef state = Pred->getState();
 
-    // Case of implicit copy or move ctor of object with array member
-    //
-    // Note: ExprEngine::VisitMemberExpr is not able to bind the array to the
-    // environment.
-    //
-    //    struct S {
-    //      int arr[2];
-    //    };
-    //
-    //
-    //    S a;
-    //    S b = a;
-    //
-    // The AST in case of a *copy constructor* looks like this:
-    //    ArrayInitLoopExpr
-    //    |-OpaqueValueExpr
-    //    | `-MemberExpr              <-- match this
-    //    |   `-DeclRefExpr
-    //    ` ...
-    //
-    //
-    //    S c;
-    //    S d = std::move(d);
-    //
-    // In case of a *move constructor* the resulting AST looks like:
-    //    ArrayInitLoopExpr
-    //    |-OpaqueValueExpr
-    //    | `-MemberExpr              <-- match this first
-    //    |   `-CXXStaticCastExpr     <-- match this after
-    //    |     `-DeclRefExpr
-    //    ` ...
-    if (const auto *ME = dyn_cast<MemberExpr>(Arr)) {
-      Expr *MEBase = ME->getBase();
-
-      // Move ctor
-      if (auto CXXSCE = dyn_cast<CXXStaticCastExpr>(MEBase)) {
-        MEBase = CXXSCE->getSubExpr();
-      }
+  SVal Base = UnknownVal();
 
-      auto ObjDeclExpr = cast<DeclRefExpr>(MEBase);
-      SVal Obj = state->getLValue(cast<VarDecl>(ObjDeclExpr->getDecl()), SF);
+  // As in case of this expression the sub-expressions are not visited by any
+  // other transfer functions, they are handled by matching their AST.
 
-      Base = state->getLValue(cast<FieldDecl>(ME->getMemberDecl()), Obj);
+  // Case of implicit copy or move ctor of object with array member
+  //
+  // Note: ExprEngine::VisitMemberExpr is not able to bind the array to the
+  // environment.
+  //
+  //    struct S {
+  //      int arr[2];
+  //    };
+  //
+  //
+  //    S a;
+  //    S b = a;
+  //
+  // The AST in case of a *copy constructor* looks like this:
+  //    ArrayInitLoopExpr
+  //    |-OpaqueValueExpr
+  //    | `-MemberExpr              <-- match this
+  //    |   `-DeclRefExpr
+  //    ` ...
+  //
+  //
+  //    S c;
+  //    S d = std::move(d);
+  //
+  // In case of a *move constructor* the resulting AST looks like:
+  //    ArrayInitLoopExpr
+  //    |-OpaqueValueExpr
+  //    | `-MemberExpr              <-- match this first
+  //    |   `-CXXStaticCastExpr     <-- match this after
+  //    |     `-DeclRefExpr
+  //    ` ...
+  if (const auto *ME = dyn_cast<MemberExpr>(Arr)) {
+    Expr *MEBase = ME->getBase();
+
+    // Move ctor
+    if (auto CXXSCE = dyn_cast<CXXStaticCastExpr>(MEBase)) {
+      MEBase = CXXSCE->getSubExpr();
     }
 
-    // Case of lambda capture and decomposition declaration
-    //
-    //    int arr[2];
-    //
-    //    [arr]{ int a = arr[0]; }();
-    //    auto[a, b] = arr;
-    //
-    // In both of these cases the AST looks like the following:
-    //    ArrayInitLoopExpr
-    //    |-OpaqueValueExpr
-    //    | `-DeclRefExpr             <-- match this
-    //    ` ...
-    if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arr))
-      Base = state->getLValue(cast<VarDecl>(DRE->getDecl()), SF);
-
-    // Create a lazy compound value to the original array
-    if (const MemRegion *R = Base.getAsRegion())
-      Base = state->getSVal(R);
-    else
-      Base = UnknownVal();
+    auto ObjDeclExpr = cast<DeclRefExpr>(MEBase);
+    SVal Obj = state->getLValue(cast<VarDecl>(ObjDeclExpr->getDecl()), SF);
 
-    EvalSet.insert(Engine.makeNodeWithBinding(Node, Ex, Base));
+    Base = state->getLValue(cast<FieldDecl>(ME->getMemberDecl()), Obj);
   }
 
-  getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this);
+  // Case of lambda capture and decomposition declaration
+  //
+  //    int arr[2];
+  //
+  //    [arr]{ int a = arr[0]; }();
+  //    auto[a, b] = arr;
+  //
+  // In both of these cases the AST looks like the following:
+  //    ArrayInitLoopExpr
+  //    |-OpaqueValueExpr
+  //    | `-DeclRefExpr             <-- match this
+  //    ` ...
+  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arr))
+    Base = state->getLValue(cast<VarDecl>(DRE->getDecl()), SF);
+
+  // Create a lazy compound value to the original array
+  if (const MemRegion *R = Base.getAsRegion())
+    Base = state->getSVal(R);
+  else
+    Base = UnknownVal();
+
+  Dst.insert(Engine.makeNodeWithBinding(Pred, Ex, Base));
 }
 
 /// VisitArraySubscriptExpr - Transfer function for array accesses
 void ExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr *A,
-                                             ExplodedNode *Pred,
-                                             ExplodedNodeSet &Dst){
+                                         ExplodedNode *Pred,
+                                         ExplodedNodeSet &Dst) {
   const Expr *Base = A->getBase()->IgnoreParens();
   const Expr *Idx  = A->getIdx()->IgnoreParens();
 
-  ExplodedNodeSet CheckerPreStmt;
-  getCheckerManager().runCheckersForPreStmt(CheckerPreStmt, Pred, A, *this);
-
-  ExplodedNodeSet EvalSet;
-
   bool IsVectorType = A->getBase()->getType()->isVectorType();
 
   // The "like" case is for situations where C standard prohibits the type to
@@ -3295,149 +3519,124 @@ void ExprEngine::VisitArraySubscriptExpr(const 
ArraySubscriptExpr *A,
   bool IsGLValueLike = A->isGLValue() ||
     (A->getType().isCForbiddenLValueType() && !AMgr.getLangOpts().CPlusPlus);
 
-  for (auto *Node : CheckerPreStmt) {
-    const StackFrame *SF = Node->getStackFrame();
-    ProgramStateRef state = Node->getState();
-
-    if (IsGLValueLike) {
-      QualType T = A->getType();
-
-      // One of the forbidden LValue types! We still need to have sensible
-      // symbolic locations to represent this stuff. Note that arithmetic on
-      // void pointers is a GCC extension.
-      if (T->isVoidType())
-        T = getContext().CharTy;
-
-      SVal V = state->getLValue(T, state->getSVal(Idx, SF),
-                                state->getSVal(Base, SF));
-      EvalSet.insert(
-          Engine.makeNodeWithBinding(Node, A, V, 
ProgramPoint::PostLValueKind));
-    } else if (IsVectorType) {
-      // FIXME: non-glvalue vector reads are not modelled.
-      EvalSet.insert(Engine.makePostStmtNode(A, state, Node));
-    } else {
-      llvm_unreachable("Array subscript should be an lValue when not \
+  const StackFrame *SF = Pred->getStackFrame();
+  ProgramStateRef state = Pred->getState();
+
+  if (IsGLValueLike) {
+    QualType T = A->getType();
+
+    // One of the forbidden LValue types! We still need to have sensible
+    // symbolic locations to represent this stuff. Note that arithmetic on
+    // void pointers is a GCC extension.
+    if (T->isVoidType())
+      T = getContext().CharTy;
+
+    SVal V =
+        state->getLValue(T, state->getSVal(Idx, SF), state->getSVal(Base, SF));
+    Dst.insert(
+        Engine.makeNodeWithBinding(Pred, A, V, ProgramPoint::PostLValueKind));
+  } else if (IsVectorType) {
+    // FIXME: non-glvalue vector reads are not modelled.
+    Dst.insert(Engine.makePostStmtNode(A, state, Pred));
+  } else {
+    llvm_unreachable("Array subscript should be an lValue when not \
 a vector and not a forbidden lvalue type");
-    }
   }
-
-  getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, A, *this);
 }
 
 /// VisitMemberExpr - Transfer function for member expressions.
 void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
                                  ExplodedNodeSet &Dst) {
-  // FIXME: Prechecks eventually go in ::Visit().
-  ExplodedNodeSet CheckedSet;
-  getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, M, *this);
-
-  ExplodedNodeSet EvalSet;
   ValueDecl *Member = M->getMemberDecl();
 
   // Handle static member variables and enum constants accessed via
   // member syntax.
   if (isa<VarDecl, EnumConstantDecl>(Member)) {
-    for (const auto I : CheckedSet)
-      VisitCommonDeclRefExpr(M, Member, I, EvalSet);
-  } else {
-
-    for (const auto I : CheckedSet) {
-      ProgramStateRef state = I->getState();
-      const StackFrame *SF = I->getStackFrame();
-      Expr *BaseExpr = M->getBase();
-
-      // Handle C++ method calls.
-      if (const auto *MD = dyn_cast<CXXMethodDecl>(Member)) {
-        if (MD->isImplicitObjectMemberFunction())
-          state = createTemporaryRegionIfNeeded(state, SF, BaseExpr);
+    VisitCommonDeclRefExpr(M, Member, Pred, Dst);
+    return;
+  }
 
-        SVal MDVal = svalBuilder.getFunctionPointer(MD);
+  ProgramStateRef state = Pred->getState();
+  const StackFrame *SF = Pred->getStackFrame();
+  Expr *BaseExpr = M->getBase();
 
-        EvalSet.insert(Engine.makeNodeWithBinding(I, M, MDVal, state));
-        continue;
-      }
+  // Handle C++ method calls.
+  if (const auto *MD = dyn_cast<CXXMethodDecl>(Member)) {
+    if (MD->isImplicitObjectMemberFunction())
+      state = createTemporaryRegionIfNeeded(state, SF, BaseExpr);
 
-      // Handle regular struct fields / member variables.
-      const SubRegion *MR = nullptr;
-      state = createTemporaryRegionIfNeeded(state, SF, BaseExpr,
-                                            /*Result=*/nullptr,
-                                            /*OutRegionWithAdjustments=*/&MR);
-      SVal baseExprVal =
-          MR ? loc::MemRegionVal(MR) : state->getSVal(BaseExpr, SF);
-
-      // FIXME: Copied from RegionStoreManager::bind()
-      if (const auto *SR =
-              dyn_cast_or_null<SymbolicRegion>(baseExprVal.getAsRegion())) {
-        QualType T = SR->getPointeeStaticType();
-        baseExprVal =
-            loc::MemRegionVal(getStoreManager().GetElementZeroRegion(SR, T));
-      }
+    SVal MDVal = svalBuilder.getFunctionPointer(MD);
 
-      const auto *field = cast<FieldDecl>(Member);
-      SVal L = state->getLValue(field, baseExprVal);
-
-      if (M->isGLValue() || M->getType()->isArrayType()) {
-        // We special-case rvalues of array type because the analyzer cannot
-        // reason about them, since we expect all regions to be wrapped in 
Locs.
-        // We instead treat these as lvalues and assume that they will decay to
-        // pointers as soon as they are used.
-        if (!M->isGLValue()) {
-          assert(M->getType()->isArrayType());
-          const auto *PE =
-            
dyn_cast<ImplicitCastExpr>(I->getParentMap().getParentIgnoreParens(M));
-          if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) {
-            llvm_unreachable("should always be wrapped in 
ArrayToPointerDecay");
-          }
-        }
+    Dst.insert(Engine.makeNodeWithBinding(Pred, M, MDVal, state));
+    return;
+  }
 
-        if (field->getType()->isReferenceType()) {
-          if (const MemRegion *R = L.getAsRegion())
-            L = state->getSVal(R);
-          else
-            L = UnknownVal();
-        }
+  // Handle regular struct fields / member variables.
+  const SubRegion *MR = nullptr;
+  state = createTemporaryRegionIfNeeded(state, SF, BaseExpr,
+                                        /*Result=*/nullptr,
+                                        /*OutRegionWithAdjustments=*/&MR);
+  SVal baseExprVal = MR ? loc::MemRegionVal(MR) : state->getSVal(BaseExpr, SF);
+
+  // FIXME: Copied from RegionStoreManager::bind()
+  if (const auto *SR =
+          dyn_cast_or_null<SymbolicRegion>(baseExprVal.getAsRegion())) {
+    QualType T = SR->getPointeeStaticType();
+    baseExprVal =
+        loc::MemRegionVal(getStoreManager().GetElementZeroRegion(SR, T));
+  }
 
-        EvalSet.insert(Engine.makeNodeWithBinding(
-            I, M, L, state, ProgramPoint::PostLValueKind));
-      } else {
-        evalLoad(EvalSet, M, M, I, state, L);
+  const auto *field = cast<FieldDecl>(Member);
+  SVal L = state->getLValue(field, baseExprVal);
+
+  if (M->isGLValue() || M->getType()->isArrayType()) {
+    // We special-case rvalues of array type because the analyzer cannot
+    // reason about them, since we expect all regions to be wrapped in Locs.
+    // We instead treat these as lvalues and assume that they will decay to
+    // pointers as soon as they are used.
+    if (!M->isGLValue()) {
+      assert(M->getType()->isArrayType());
+      const auto *PE = dyn_cast<ImplicitCastExpr>(
+          Pred->getParentMap().getParentIgnoreParens(M));
+      if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) {
+        llvm_unreachable("should always be wrapped in ArrayToPointerDecay");
       }
     }
-  }
 
-  getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, M, *this);
+    if (field->getType()->isReferenceType()) {
+      if (const MemRegion *R = L.getAsRegion())
+        L = state->getSVal(R);
+      else
+        L = UnknownVal();
+    }
+
+    Dst.insert(Engine.makeNodeWithBinding(Pred, M, L, state,
+                                          ProgramPoint::PostLValueKind));
+  } else {
+    evalLoad(Dst, M, M, Pred, state, L);
+  }
 }
 
 void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred,
                                  ExplodedNodeSet &Dst) {
-  ExplodedNodeSet AfterPreSet;
-  getCheckerManager().runCheckersForPreStmt(AfterPreSet, Pred, AE, *this);
-
   // For now, treat all the arguments to C11 atomics as escaping.
   // FIXME: Ideally we should model the behavior of the atomics precisely here.
 
-  ExplodedNodeSet AfterInvalidateSet;
-
-  for (const auto I : AfterPreSet) {
-    ProgramStateRef State = I->getState();
-    const StackFrame *SF = I->getStackFrame();
-
-    SmallVector<SVal, 8> ValuesToInvalidate;
-    for (const Stmt *SubExpr : AE->children()) {
-      SVal SubExprVal = State->getSVal(cast<Expr>(SubExpr), SF);
-      ValuesToInvalidate.push_back(SubExprVal);
-    }
-
-    State = State->invalidateRegions(ValuesToInvalidate, getCFGElementRef(),
-                                     getNumVisitedCurrent(), SF,
-                                     /*CausedByPointerEscape*/ true,
-                                     /*Symbols=*/nullptr);
+  ProgramStateRef State = Pred->getState();
+  const StackFrame *SF = Pred->getStackFrame();
 
-    AfterInvalidateSet.insert(
-        Engine.makeNodeWithBinding(I, AE, UnknownVal(), State));
+  SmallVector<SVal, 8> ValuesToInvalidate;
+  for (const Stmt *SubExpr : AE->children()) {
+    SVal SubExprVal = State->getSVal(cast<Expr>(SubExpr), SF);
+    ValuesToInvalidate.push_back(SubExprVal);
   }
 
-  getCheckerManager().runCheckersForPostStmt(Dst, AfterInvalidateSet, AE, 
*this);
+  State = State->invalidateRegions(ValuesToInvalidate, getCFGElementRef(),
+                                   getNumVisitedCurrent(), SF,
+                                   /*CausedByPointerEscape*/ true,
+                                   /*Symbols=*/nullptr);
+
+  Dst.insert(Engine.makeNodeWithBinding(Pred, AE, UnknownVal(), State));
 }
 
 // A value escapes in four possible cases:

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 6127328cefe23..d89c80ca01754 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -214,18 +214,14 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, 
ExplodedNode *Pred,
     }
   }
 
-  ExplodedNode *N = Engine.makeNodeWithBinding(Pred, BE, V, State,
-                                               ProgramPoint::PostLValueKind);
-
-  // FIXME: Move all post/pre visits to ::Visit().
-  getCheckerManager().runCheckersForPostStmt(Dst, N, BE, *this);
+  Dst.insert(Engine.makeNodeWithBinding(Pred, BE, V, State,
+                                        ProgramPoint::PostLValueKind));
 }
 
-ProgramStateRef
-ExprEngine::handleLValueBitCast(ProgramStateRef state, const Expr *Ex,
-                                const StackFrame *SF, QualType T, QualType 
ExTy,
-                                const CastExpr *CastE, ExplodedNodeSet &Dst,
-                                ExplodedNode *Pred) {
+void ExprEngine::handleLValueBitCast(ProgramStateRef state, const Expr *Ex,
+                                     const StackFrame *SF, QualType T,
+                                     QualType ExTy, const CastExpr *CastE,
+                                     ExplodedNodeSet &Dst, ExplodedNode *Pred) 
{
   if (T->isLValueReferenceType()) {
     assert(!CastE->getType()->isLValueReferenceType());
     ExTy = getContext().getLValueReferenceType(ExTy);
@@ -246,22 +242,16 @@ ExprEngine::handleLValueBitCast(ProgramStateRef state, 
const Expr *Ex,
     state = escapeValues(state, OrigV, PSK_EscapeOther);
   }
   Dst.insert(Engine.makePostStmtNode(CastE, state, Pred));
-
-  return state;
 }
 
-void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
-                           ExplodedNode *Pred, ExplodedNodeSet &Dst) {
-
-  ExplodedNodeSet DstPreStmt;
-  getCheckerManager().runCheckersForPreStmt(DstPreStmt, Pred, CastE, *this);
+void ExprEngine::VisitCastExpr(const CastExpr *CastE, ExplodedNode *Pred,
+                               ExplodedNodeSet &Dst) {
+  const Expr *Ex = CastE->getSubExpr();
+  ProgramStateRef State = Pred->getState();
+  const StackFrame *SF = Pred->getStackFrame();
 
   if (CastE->getCastKind() == CK_LValueToRValue) {
-    for (ExplodedNode *Node : DstPreStmt) {
-      ProgramStateRef State = Node->getState();
-      const StackFrame *SF = Node->getStackFrame();
-      evalLoad(Dst, CastE, CastE, Node, State, State->getSVal(Ex, SF));
-    }
+    evalLoad(Dst, CastE, CastE, Pred, State, State->getSVal(Ex, SF));
     return;
   }
   if (CastE->getCastKind() == CK_LValueToRValueBitCast) {
@@ -269,12 +259,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const 
Expr *Ex,
     ExplodedNodeSet DstEvalLoc;
 
     // Simulate the lvalue-to-rvalue conversion on `Ex`:
-    for (ExplodedNode *Node : DstPreStmt) {
-      ProgramStateRef State = Node->getState();
-      const StackFrame *SF = Node->getStackFrame();
-      evalLocation(DstEvalLoc, CastE, Ex, Node, State, State->getSVal(Ex, SF),
-                   true);
-    }
+    evalLocation(DstEvalLoc, CastE, Ex, Pred, State, State->getSVal(Ex, SF),
+                 true);
     // Simulate the operation that actually casts the original value to a new
     // value of the destination type :
 
@@ -303,228 +289,219 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const 
Expr *Ex,
   if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
     T = ExCast->getTypeAsWritten();
 
-  for (ExplodedNode *Pred : DstPreStmt) {
-    ProgramStateRef state = Pred->getState();
-    const StackFrame *SF = Pred->getStackFrame();
-
-    switch (CastE->getCastKind()) {
-      case CK_LValueToRValue:
-      case CK_LValueToRValueBitCast:
-        llvm_unreachable("LValueToRValue casts handled earlier.");
-      case CK_ToVoid:
-        Dst.insert(Pred);
-        continue;
-        // The analyzer doesn't do anything special with these casts,
-        // since it understands retain/release semantics already.
-      case CK_ARCProduceObject:
-      case CK_ARCConsumeObject:
-      case CK_ARCReclaimReturnedObject:
-      case CK_ARCExtendBlockObject: // Fall-through.
-      case CK_CopyAndAutoreleaseBlockObject:
-        // The analyser can ignore atomic casts for now, although some future
-        // checkers may want to make certain that you're not modifying the same
-        // value through atomic and nonatomic pointers.
-      case CK_AtomicToNonAtomic:
-      case CK_NonAtomicToAtomic:
-        // True no-ops.
-      case CK_NoOp:
-      case CK_ConstructorConversion:
-      case CK_UserDefinedConversion:
-      case CK_FunctionToPointerDecay:
-      case CK_BuiltinFnToFnPtr:
-      case CK_HLSLArrayRValue: {
-        // Copy the SVal of Ex to CastE.
-        ProgramStateRef state = Pred->getState();
-        const StackFrame *SF = Pred->getStackFrame();
-        SVal V = state->getSVal(Ex, SF);
-        Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
-        continue;
-      }
-      case CK_MemberPointerToBoolean:
-      case CK_PointerToBoolean: {
-        SVal V = state->getSVal(Ex, SF);
-        auto PTMSV = V.getAs<nonloc::PointerToMember>();
-        if (PTMSV)
-          V = svalBuilder.makeTruthVal(!PTMSV->isNullMemberPointer(), ExTy);
-        if (V.isUndef() || PTMSV) {
-          Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
-          continue;
-        }
-        // Explicitly proceed with default handler for this case cascade.
-        state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Dst, Pred);
-        continue;
-      }
-      case CK_Dependent:
-      case CK_ArrayToPointerDecay:
-      case CK_BitCast:
-      case CK_AddressSpaceConversion:
-      case CK_BooleanToSignedIntegral:
-      case CK_IntegralToPointer:
-      case CK_PointerToIntegral: {
-        SVal V = state->getSVal(Ex, SF);
-        if (isa<nonloc::PointerToMember>(V)) {
-          Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, UnknownVal()));
-          continue;
-        }
-        // Explicitly proceed with default handler for this case cascade.
-        state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Dst, Pred);
-        continue;
-      }
-      case CK_IntegralToBoolean:
-      case CK_IntegralToFloating:
-      case CK_FloatingToIntegral:
-      case CK_FloatingToBoolean:
-      case CK_FloatingCast:
-      case CK_FloatingRealToComplex:
-      case CK_FloatingComplexToReal:
-      case CK_FloatingComplexToBoolean:
-      case CK_FloatingComplexCast:
-      case CK_FloatingComplexToIntegralComplex:
-      case CK_IntegralRealToComplex:
-      case CK_IntegralComplexToReal:
-      case CK_IntegralComplexToBoolean:
-      case CK_IntegralComplexCast:
-      case CK_IntegralComplexToFloatingComplex:
-      case CK_CPointerToObjCPointerCast:
-      case CK_BlockPointerToObjCPointerCast:
-      case CK_AnyPointerToBlockPointerCast:
-      case CK_ObjCObjectLValueCast:
-      case CK_ZeroToOCLOpaqueType:
-      case CK_IntToOCLSampler:
-      case CK_LValueBitCast:
-      case CK_FloatingToFixedPoint:
-      case CK_FixedPointToFloating:
-      case CK_FixedPointCast:
-      case CK_FixedPointToBoolean:
-      case CK_FixedPointToIntegral:
-      case CK_IntegralToFixedPoint: {
-        state = handleLValueBitCast(state, Ex, SF, T, ExTy, CastE, Dst, Pred);
-        continue;
-      }
-      case CK_IntegralCast: {
-        // Delegate to SValBuilder to process.
-        SVal V = state->getSVal(Ex, SF);
-        if (AMgr.options.analyzerSymbolicIntegerCasts())
-          V = svalBuilder.evalCast(V, T, ExTy);
-        else
-          V = svalBuilder.evalIntegralCast(state, V, T, ExTy);
-        Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
-        continue;
-      }
-      case CK_DerivedToBase:
-      case CK_UncheckedDerivedToBase: {
-        // For DerivedToBase cast, delegate to the store manager.
-        SVal val = state->getSVal(Ex, SF);
-        val = getStoreManager().evalDerivedToBase(val, CastE);
-        Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, val));
-        continue;
+  switch (CastE->getCastKind()) {
+  case CK_LValueToRValue:
+  case CK_LValueToRValueBitCast:
+    llvm_unreachable("LValueToRValue casts handled earlier.");
+  case CK_ToVoid:
+    Dst.insert(Pred);
+    return;
+    // The analyzer doesn't do anything special with these casts,
+    // since it understands retain/release semantics already.
+  case CK_ARCProduceObject:
+  case CK_ARCConsumeObject:
+  case CK_ARCReclaimReturnedObject:
+  case CK_ARCExtendBlockObject: // Fall-through.
+  case CK_CopyAndAutoreleaseBlockObject:
+    // The analyser can ignore atomic casts for now, although some future
+    // checkers may want to make certain that you're not modifying the same
+    // value through atomic and nonatomic pointers.
+  case CK_AtomicToNonAtomic:
+  case CK_NonAtomicToAtomic:
+    // True no-ops.
+  case CK_NoOp:
+  case CK_ConstructorConversion:
+  case CK_UserDefinedConversion:
+  case CK_FunctionToPointerDecay:
+  case CK_BuiltinFnToFnPtr:
+  case CK_HLSLArrayRValue: {
+    // Copy the SVal of Ex to CastE.
+    SVal V = State->getSVal(Ex, SF);
+    Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
+    return;
+  }
+  case CK_MemberPointerToBoolean:
+  case CK_PointerToBoolean: {
+    SVal V = State->getSVal(Ex, SF);
+    auto PTMSV = V.getAs<nonloc::PointerToMember>();
+    if (PTMSV)
+      V = svalBuilder.makeTruthVal(!PTMSV->isNullMemberPointer(), ExTy);
+    if (V.isUndef() || PTMSV) {
+      Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
+      return;
+    }
+    handleLValueBitCast(State, Ex, SF, T, ExTy, CastE, Dst, Pred);
+    return;
+  }
+  case CK_Dependent:
+  case CK_ArrayToPointerDecay:
+  case CK_BitCast:
+  case CK_AddressSpaceConversion:
+  case CK_BooleanToSignedIntegral:
+  case CK_IntegralToPointer:
+  case CK_PointerToIntegral: {
+    SVal V = State->getSVal(Ex, SF);
+    if (isa<nonloc::PointerToMember>(V)) {
+      Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, UnknownVal()));
+      return;
+    }
+    handleLValueBitCast(State, Ex, SF, T, ExTy, CastE, Dst, Pred);
+    return;
+  }
+  case CK_IntegralToBoolean:
+  case CK_IntegralToFloating:
+  case CK_FloatingToIntegral:
+  case CK_FloatingToBoolean:
+  case CK_FloatingCast:
+  case CK_FloatingRealToComplex:
+  case CK_FloatingComplexToReal:
+  case CK_FloatingComplexToBoolean:
+  case CK_FloatingComplexCast:
+  case CK_FloatingComplexToIntegralComplex:
+  case CK_IntegralRealToComplex:
+  case CK_IntegralComplexToReal:
+  case CK_IntegralComplexToBoolean:
+  case CK_IntegralComplexCast:
+  case CK_IntegralComplexToFloatingComplex:
+  case CK_CPointerToObjCPointerCast:
+  case CK_BlockPointerToObjCPointerCast:
+  case CK_AnyPointerToBlockPointerCast:
+  case CK_ObjCObjectLValueCast:
+  case CK_ZeroToOCLOpaqueType:
+  case CK_IntToOCLSampler:
+  case CK_LValueBitCast:
+  case CK_FloatingToFixedPoint:
+  case CK_FixedPointToFloating:
+  case CK_FixedPointCast:
+  case CK_FixedPointToBoolean:
+  case CK_FixedPointToIntegral:
+  case CK_IntegralToFixedPoint: {
+    handleLValueBitCast(State, Ex, SF, T, ExTy, CastE, Dst, Pred);
+    return;
+  }
+  case CK_IntegralCast: {
+    // Delegate to SValBuilder to process.
+    SVal V = State->getSVal(Ex, SF);
+    if (AMgr.options.analyzerSymbolicIntegerCasts())
+      V = svalBuilder.evalCast(V, T, ExTy);
+    else
+      V = svalBuilder.evalIntegralCast(State, V, T, ExTy);
+    Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
+    return;
+  }
+  case CK_DerivedToBase:
+  case CK_UncheckedDerivedToBase: {
+    // For DerivedToBase cast, delegate to the store manager.
+    SVal val = State->getSVal(Ex, SF);
+    val = getStoreManager().evalDerivedToBase(val, CastE);
+    Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, val));
+    return;
+  }
+  // Handle C++ dyn_cast.
+  case CK_Dynamic: {
+    SVal val = State->getSVal(Ex, SF);
+
+    // Compute the type of the result.
+    QualType resultType = CastE->getType();
+    if (CastE->isGLValue())
+      resultType = getContext().getPointerType(resultType);
+
+    bool Failed = true;
+
+    // Check if the value being cast does not evaluates to 0.
+    if (!val.isZeroConstant())
+      if (std::optional<SVal> V =
+              StateMgr.getStoreManager().evalBaseToDerived(val, T)) {
+        val = *V;
+        Failed = false;
       }
-      // Handle C++ dyn_cast.
-      case CK_Dynamic: {
-        SVal val = state->getSVal(Ex, SF);
-
-        // Compute the type of the result.
-        QualType resultType = CastE->getType();
-        if (CastE->isGLValue())
-          resultType = getContext().getPointerType(resultType);
-
-        bool Failed = true;
-
-        // Check if the value being cast does not evaluates to 0.
-        if (!val.isZeroConstant())
-          if (std::optional<SVal> V =
-                  StateMgr.getStoreManager().evalBaseToDerived(val, T)) {
-          val = *V;
-          Failed = false;
-          }
 
-        if (Failed) {
-          if (T->isReferenceType()) {
-            // A bad_cast exception is thrown if input value is a reference.
-            // Currently, we model this, by generating a sink.
-            Engine.makePostStmtNode(CastE, state, Pred, /*MarkAsSink=*/true);
-            continue;
-          } else {
-            // If the cast fails on a pointer, bind to 0.
-            state = state->BindExpr(CastE, SF,
-                                    svalBuilder.makeNullWithType(resultType));
-          }
-        } else {
-          // If we don't know if the cast succeeded, conjure a new symbol.
-          if (val.isUnknown()) {
-            DefinedOrUnknownSVal NewSym = svalBuilder.conjureSymbolVal(
-                /*symbolTag=*/nullptr, getCFGElementRef(), SF, resultType,
-                getNumVisitedCurrent());
-            state = state->BindExpr(CastE, SF, NewSym);
-          } else
-            // Else, bind to the derived region value.
-            state = state->BindExpr(CastE, SF, val);
-        }
-        Dst.insert(Engine.makePostStmtNode(CastE, state, Pred));
-        continue;
-      }
-      case CK_BaseToDerived: {
-        SVal val = state->getSVal(Ex, SF);
-        QualType resultType = CastE->getType();
-        if (CastE->isGLValue())
-          resultType = getContext().getPointerType(resultType);
-
-        if (!val.isConstant()) {
-          std::optional<SVal> V = getStoreManager().evalBaseToDerived(val, T);
-          val = V ? *V : UnknownVal();
-        }
-
-        // Failed to cast or the result is unknown, fall back to conservative.
-        if (val.isUnknown()) {
-          val = svalBuilder.conjureSymbolVal(
-              /*symbolTag=*/nullptr, getCFGElementRef(), SF, resultType,
-              getNumVisitedCurrent());
-        }
-        Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, val));
-        continue;
-      }
-      case CK_NullToPointer: {
-        SVal V = svalBuilder.makeNullWithType(CastE->getType());
-        Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
-        continue;
-      }
-      case CK_NullToMemberPointer: {
-        SVal V = svalBuilder.getMemberPointer(nullptr);
-        Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
-        continue;
-      }
-      case CK_DerivedToBaseMemberPointer:
-      case CK_BaseToDerivedMemberPointer:
-      case CK_ReinterpretMemberPointer: {
-        SVal V = state->getSVal(Ex, SF);
-        if (auto PTMSV = V.getAs<nonloc::PointerToMember>()) {
-          SVal CastedPTMSV =
-              svalBuilder.makePointerToMember(getBasicVals().accumCXXBase(
-                  CastE->path(), *PTMSV, CastE->getCastKind()));
-          Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, CastedPTMSV));
-          continue;
-        }
-        // Explicitly proceed with default handler for this case cascade.
+    if (Failed) {
+      if (T->isReferenceType()) {
+        // A bad_cast exception is thrown if input value is a reference.
+        // Currently, we model this, by generating a sink.
+        Engine.makePostStmtNode(CastE, State, Pred, /*MarkAsSink=*/true);
+        return;
+      } else {
+        // If the cast fails on a pointer, bind to 0.
+        State = State->BindExpr(CastE, SF,
+                                svalBuilder.makeNullWithType(resultType));
       }
-        [[fallthrough]];
-      // Various C++ casts that are not handled yet.
-      case CK_ToUnion:
-      case CK_MatrixCast:
-      case CK_VectorSplat:
-      case CK_HLSLElementwiseCast:
-      case CK_HLSLAggregateSplatCast:
-      case CK_HLSLMatrixTruncation:
-      case CK_HLSLVectorTruncation: {
-        QualType resultType = CastE->getType();
-        if (CastE->isGLValue())
-          resultType = getContext().getPointerType(resultType);
-        SVal result = svalBuilder.conjureSymbolVal(
+    } else {
+      // If we don't know if the cast succeeded, conjure a new symbol.
+      if (val.isUnknown()) {
+        DefinedOrUnknownSVal NewSym = svalBuilder.conjureSymbolVal(
             /*symbolTag=*/nullptr, getCFGElementRef(), SF, resultType,
             getNumVisitedCurrent());
-        Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, result));
-        continue;
-      }
+        State = State->BindExpr(CastE, SF, NewSym);
+      } else
+        // Else, bind to the derived region value.
+        State = State->BindExpr(CastE, SF, val);
+    }
+    Dst.insert(Engine.makePostStmtNode(CastE, State, Pred));
+    return;
+  }
+  case CK_BaseToDerived: {
+    SVal val = State->getSVal(Ex, SF);
+    QualType resultType = CastE->getType();
+    if (CastE->isGLValue())
+      resultType = getContext().getPointerType(resultType);
+
+    if (!val.isConstant()) {
+      std::optional<SVal> V = getStoreManager().evalBaseToDerived(val, T);
+      val = V ? *V : UnknownVal();
+    }
+
+    // Failed to cast or the result is unknown, fall back to conservative.
+    if (val.isUnknown()) {
+      val = svalBuilder.conjureSymbolVal(
+          /*symbolTag=*/nullptr, getCFGElementRef(), SF, resultType,
+          getNumVisitedCurrent());
+    }
+    Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, val));
+    return;
+  }
+  case CK_NullToPointer: {
+    SVal V = svalBuilder.makeNullWithType(CastE->getType());
+    Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
+    return;
+  }
+  case CK_NullToMemberPointer: {
+    SVal V = svalBuilder.getMemberPointer(nullptr);
+    Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, V));
+    return;
+  }
+  case CK_DerivedToBaseMemberPointer:
+  case CK_BaseToDerivedMemberPointer:
+  case CK_ReinterpretMemberPointer: {
+    SVal V = State->getSVal(Ex, SF);
+    if (auto PTMSV = V.getAs<nonloc::PointerToMember>()) {
+      SVal CastedPTMSV =
+          svalBuilder.makePointerToMember(getBasicVals().accumCXXBase(
+              CastE->path(), *PTMSV, CastE->getCastKind()));
+      Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, CastedPTMSV));
+      return;
     }
+    // Explicitly proceed with default handler for this case cascade.
+  }
+    [[fallthrough]];
+  // Various C++ casts that are not handled yet.
+  case CK_ToUnion:
+  case CK_MatrixCast:
+  case CK_VectorSplat:
+  case CK_HLSLElementwiseCast:
+  case CK_HLSLAggregateSplatCast:
+  case CK_HLSLMatrixTruncation:
+  case CK_HLSLVectorTruncation: {
+    QualType resultType = CastE->getType();
+    if (CastE->isGLValue())
+      resultType = getContext().getPointerType(resultType);
+    SVal result = svalBuilder.conjureSymbolVal(
+        /*symbolTag=*/nullptr, getCFGElementRef(), SF, resultType,
+        getNumVisitedCurrent());
+    Dst.insert(Engine.makeNodeWithBinding(Pred, CastE, result));
+    return;
+  }
   }
 }
 
@@ -815,44 +792,48 @@ void ExprEngine::VisitOffsetOfExpr(const OffsetOfExpr 
*OOE, ExplodedNode *Pred,
   }
 }
 
-void ExprEngine::
-VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
-                              ExplodedNode *Pred,
-                              ExplodedNodeSet &Dst) {
-  // FIXME: Prechecks eventually go in ::Visit().
-  ExplodedNodeSet CheckedSet;
-  getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, Ex, *this);
-
-  ExplodedNodeSet EvalSet;
+void ExprEngine::VisitUnaryExprOrTypeTraitExpr(
+    const UnaryExprOrTypeTraitExpr *Ex, ExplodedNode *Pred,
+    ExplodedNodeSet &Dst) {
   QualType T = Ex->getTypeOfArgument();
 
-  for (ExplodedNode *N : CheckedSet) {
-    if (Ex->getKind() == UETT_SizeOf || Ex->getKind() == UETT_DataSizeOf ||
-        Ex->getKind() == UETT_CountOf) {
-      if (!T->isIncompleteType() && !T->isConstantSizeType()) {
-        assert(T->isVariableArrayType() && "Unknown non-constant-sized type.");
+  if (Ex->getKind() == UETT_SizeOf || Ex->getKind() == UETT_DataSizeOf ||
+      Ex->getKind() == UETT_CountOf) {
+    if (!T->isIncompleteType() && !T->isConstantSizeType()) {
+      assert(T->isVariableArrayType() && "Unknown non-constant-sized type.");
 
-        // FIXME: Add support for VLA type arguments and VLA expressions.
-        // When that happens, we should probably refactor VLASizeChecker's 
code.
-        EvalSet.insert(N);
-        continue;
-      } else if (T->getAs<ObjCObjectType>()) {
-        // Some code tries to take the sizeof an ObjCObjectType, relying that
-        // the compiler has laid out its representation.  Just report Unknown
-        // for these.
-        EvalSet.insert(N);
-        continue;
-      }
+      // FIXME: Add support for VLA type arguments and VLA expressions.
+      // When that happens, we should probably refactor VLASizeChecker's code.
+      Dst.insert(Pred);
+      return;
+    } else if (T->getAs<ObjCObjectType>()) {
+      // Some code tries to take the sizeof an ObjCObjectType, relying that
+      // the compiler has laid out its representation.  Just report Unknown
+      // for these.
+      Dst.insert(Pred);
+      return;
     }
+  }
 
-    APSInt Value = Ex->EvaluateKnownConstInt(getContext());
-    CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue());
+  APSInt Value = Ex->EvaluateKnownConstInt(getContext());
+  CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue());
 
-    SVal V = svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType());
-    EvalSet.insert(Engine.makeNodeWithBinding(N, Ex, V));
-  }
+  SVal V = svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType());
+  Dst.insert(Engine.makeNodeWithBinding(Pred, Ex, V));
+}
 
-  getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this);
+void ExprEngine::VisitStmtExpr(const StmtExpr *SE, ExplodedNode *Pred,
+                               ExplodedNodeSet &Dst) {
+  if (SE->getSubStmt()->body_empty()) {
+    // Empty statement expression.
+    assert(SE->getType() == getContext().VoidTy &&
+           "Empty statement expression must have void type.");
+  } else if (const auto *LastExpr =
+                 dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) {
+    SVal Val = Pred->getState()->getSVal(LastExpr, Pred->getStackFrame());
+    Pred = Engine.makeNodeWithBinding(Pred, SE, Val);
+  }
+  Dst.insert(Pred);
 }
 
 void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
@@ -991,6 +972,26 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* 
U, ExplodedNode *Pred,
   getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, U, *this);
 }
 
+void ExprEngine::VisitPseudoObjectExpr(const PseudoObjectExpr *PE,
+                                       ExplodedNode *Pred,
+                                       ExplodedNodeSet &Dst) {
+  SVal V = UnknownVal();
+  if (const Expr *Result = PE->getResultExpr())
+    V = Pred->getState()->getSVal(Result, Pred->getStackFrame());
+  Dst.insert(Engine.makeNodeWithBinding(Pred, PE, V));
+}
+
+void ExprEngine::VisitObjCIndirectCopyRestoreExpr(
+    const ObjCIndirectCopyRestoreExpr *OIE, ExplodedNode *Pred,
+    ExplodedNodeSet &Dst) {
+  // ObjCIndirectCopyRestoreExpr implies passing a temporary for
+  // correctness of lifetime management.  Due to limited analysis
+  // of ARC, this is implemented as direct arg passing.
+  const Expr *E = OIE->getSubExpr();
+  SVal V = Pred->getState()->getSVal(E, Pred->getStackFrame());
+  Dst.insert(Engine.makeNodeWithBinding(Pred, OIE, V));
+}
+
 void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
                                                  ExplodedNode *Pred,
                                                  ExplodedNodeSet &Dst) {

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index bb6deabba8a43..609b3882e3867 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -30,15 +30,15 @@
 using namespace clang;
 using namespace ento;
 
-void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
-                                          ExplodedNode *Pred,
-                                          ExplodedNodeSet &Dst) {
-  const Expr *tempExpr = ME->getSubExpr()->IgnoreParens();
-  ProgramStateRef state = Pred->getState();
+void ExprEngine::VisitMaterializeTemporaryExpr(
+    const MaterializeTemporaryExpr *MTE, ExplodedNode *Pred,
+    ExplodedNodeSet &Dst) {
+  const Expr *TempExpr = MTE->getSubExpr()->IgnoreParens();
+  ProgramStateRef State = Pred->getState();
   const StackFrame *SF = Pred->getStackFrame();
 
-  state = createTemporaryRegionIfNeeded(state, SF, tempExpr, ME);
-  Dst.insert(Engine.makePostStmtNode(ME, state, Pred));
+  State = createTemporaryRegionIfNeeded(State, SF, TempExpr, MTE);
+  Dst.insert(Engine.makePostStmtNode(MTE, State, Pred));
 }
 
 void ExprEngine::performTrivialCopy(ExplodedNodeSet &Dst, ExplodedNode *Pred,
@@ -1098,6 +1098,12 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt 
*CS, ExplodedNode *Pred,
   Dst.insert(Engine.makePostStmtNode(CS, state, Pred));
 }
 
+void ExprEngine::VisitCXXParenListInitExpr(const CXXParenListInitExpr *E,
+                                           ExplodedNode *Pred,
+                                           ExplodedNodeSet &Dst) {
+  ConstructInitList(E, E->getInitExprs(), /*IsTransparent*/ false, Pred, Dst);
+}
+
 void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred,
                                   ExplodedNodeSet &Dst) {
   // Get the this object region from StoreManager.
@@ -1112,6 +1118,14 @@ void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, 
ExplodedNode *Pred,
 
 void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
                                  ExplodedNodeSet &Dst) {
+
+  if (!AMgr.options.ShouldInlineLambdas) {
+    const ExplodedNode *Node = Engine.makePostStmtNode(
+        LE, Pred->getState(), Pred, /*MarkAsSink=*/true);
+    Engine.addAbortedBlock(Node, getCurrBlock());
+    return;
+  }
+
   const StackFrame *SF = Pred->getStackFrame();
 
   // Get the region of the lambda itself.
@@ -1183,28 +1197,20 @@ void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, 
ExplodedNode *Pred,
 void ExprEngine::VisitAttributedStmt(const AttributedStmt *A,
                                      ExplodedNode *Pred, ExplodedNodeSet &Dst) 
{
   const StackFrame *SF = Pred->getStackFrame();
-  ExplodedNodeSet CheckerPreStmt;
-  getCheckerManager().runCheckersForPreStmt(CheckerPreStmt, Pred, A, *this);
-
-  ExplodedNodeSet EvalSet;
-
-  for (ExplodedNode *N : CheckerPreStmt) {
-    ProgramStateRef State = N->getState();
-    for (const auto *Attr : getSpecificAttrs<CXXAssumeAttr>(A->getAttrs())) {
-      SVal AssumedVal = State->getSVal(Attr->getAssumption(), SF);
-      // This code ignores assumptions that evaluate to UndefinedVal.
-      // Perhaps there should be a checker that reports this situation.
-      if (auto ValidAssumedVal = AssumedVal.getAs<DefinedOrUnknownSVal>()) {
-        State = State->assume(*ValidAssumedVal, true);
-      }
+  ProgramStateRef State = Pred->getState();
 
-      if (!State)
-        break;
+  for (const auto *Attr : getSpecificAttrs<CXXAssumeAttr>(A->getAttrs())) {
+    SVal AssumedVal = State->getSVal(Attr->getAssumption(), SF);
+    // This code ignores assumptions that evaluate to UndefinedVal.
+    // Perhaps there should be a checker that reports this situation.
+    if (auto ValidAssumedVal = AssumedVal.getAs<DefinedOrUnknownSVal>()) {
+      State = State->assume(*ValidAssumedVal, true);
     }
 
-    if (State)
-      EvalSet.insert(Engine.makePostStmtNode(A, State, N));
+    if (!State)
+      break;
   }
 
-  getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, A, *this);
+  if (State)
+    Dst.insert(Engine.makePostStmtNode(A, State, Pred));
 }

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 511bb036c5b68..86facd6c838b3 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -1296,14 +1296,9 @@ void ExprEngine::dynDispatchBifurcate(const MemRegion 
*BifurReg,
 
 void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
                                  ExplodedNodeSet &Dst) {
-  ExplodedNodeSet DstPreVisit;
-  getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, RS, *this);
-
   if (RS->getRetValue()) {
-    for (ExplodedNode *N : DstPreVisit) {
-      Dst.insert(Engine.makePostStmtNode(RS, N->getState(), N));
-    }
+    Dst.insert(Engine.makePostStmtNode(RS, Pred->getState(), Pred));
   } else {
-    Dst.insert(DstPreVisit);
+    Dst.insert(Pred);
   }
 }

diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp 
b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index bc214f4aa7054..ada445815b1d5 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -25,18 +25,7 @@ void ExprEngine::VisitLvalObjCIvarRefExpr(const 
ObjCIvarRefExpr *Ex,
   const StackFrame *SF = Pred->getStackFrame();
   SVal baseVal = state->getSVal(Ex->getBase(), SF);
   SVal location = state->getLValue(Ex->getDecl(), baseVal);
-
-  ExplodedNode *N = Engine.makeNodeWithBinding(Pred, Ex, location);
-
-  // Perform the post-condition check of the ObjCIvarRefExpr and store
-  // the created nodes in 'Dst'.
-  getCheckerManager().runCheckersForPostStmt(Dst, N, Ex, *this);
-}
-
-void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
-                                             ExplodedNode *Pred,
-                                             ExplodedNodeSet &Dst) {
-  getCheckerManager().runCheckersForPreStmt(Dst, Pred, S, *this);
+  Dst.insert(Engine.makeNodeWithBinding(Pred, Ex, location));
 }
 
 void ExprEngine::populateObjCForDestinationSet(const ObjCForCollectionStmt *S,
@@ -128,9 +117,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const 
ObjCForCollectionStmt *S,
 
     populateObjCForDestinationSet(S, N, Tmp, elementV, /*hasElements=*/false);
 
-    // Finally, run any custom checkers.
-    // FIXME: Eventually all pre- and post-checks should live in VisitStmt.
-    getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
+    Dst.insert(Tmp);
   }
 }
 


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to