void ExprEngine::Visit()

in clang/lib/StaticAnalyzer/Core/ExprEngine.cpp [1201:1896]


void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
                       ExplodedNodeSet &DstTop) {
  PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
                                S->getBeginLoc(), "Error evaluating statement");
  ExplodedNodeSet Dst;
  StmtNodeBuilder Bldr(Pred, DstTop, *currBldrCtx);

  assert(!isa<Expr>(S) || S == cast<Expr>(S)->IgnoreParens());

  switch (S->getStmtClass()) {
    // C++, OpenMP and ARC stuff we don't support yet.
    case Stmt::CXXDependentScopeMemberExprClass:
    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::TypoExprClass:
    case Stmt::RecoveryExprClass:
    case Stmt::CXXNoexceptExprClass:
    case Stmt::PackExpansionExprClass:
    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::OMPCanonicalLoopClass:
    case Stmt::OMPParallelDirectiveClass:
    case Stmt::OMPSimdDirectiveClass:
    case Stmt::OMPForDirectiveClass:
    case Stmt::OMPForSimdDirectiveClass:
    case Stmt::OMPSectionsDirectiveClass:
    case Stmt::OMPSectionDirectiveClass:
    case Stmt::OMPSingleDirectiveClass:
    case Stmt::OMPMasterDirectiveClass:
    case Stmt::OMPCriticalDirectiveClass:
    case Stmt::OMPParallelForDirectiveClass:
    case Stmt::OMPParallelForSimdDirectiveClass:
    case Stmt::OMPParallelSectionsDirectiveClass:
    case Stmt::OMPParallelMasterDirectiveClass:
    case Stmt::OMPTaskDirectiveClass:
    case Stmt::OMPTaskyieldDirectiveClass:
    case Stmt::OMPBarrierDirectiveClass:
    case Stmt::OMPTaskwaitDirectiveClass:
    case Stmt::OMPTaskgroupDirectiveClass:
    case Stmt::OMPFlushDirectiveClass:
    case Stmt::OMPDepobjDirectiveClass:
    case Stmt::OMPScanDirectiveClass:
    case Stmt::OMPOrderedDirectiveClass:
    case Stmt::OMPAtomicDirectiveClass:
    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::OMPMasterTaskLoopSimdDirectiveClass:
    case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
    case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
    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::OMPTileDirectiveClass:
    case Stmt::OMPInteropDirectiveClass:
    case Stmt::OMPDispatchDirectiveClass:
    case Stmt::OMPMaskedDirectiveClass:
    case Stmt::OMPGenericLoopDirectiveClass:
    case Stmt::CapturedStmtClass:
    case Stmt::OMPUnrollDirectiveClass:
    case Stmt::OMPMetaDirectiveClass: {
      const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
      Engine.addAbortedBlock(node, currBldrCtx->getBlock());
      break;
    }

    case Stmt::ParenExprClass:
      llvm_unreachable("ParenExprs already handled.");
    case Stmt::GenericSelectionExprClass:
      llvm_unreachable("GenericSelectionExprs already handled.");
    // 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 Expr::MSDependentExistsStmtClass:
      llvm_unreachable("Stmt should not be in analyzer evaluation loop");
    case Stmt::ImplicitValueInitExprClass:
      // 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.
      llvm_unreachable("Should be pruned from CFG");

    case Stmt::ObjCSubscriptRefExprClass:
    case Stmt::ObjCPropertyRefExprClass:
      llvm_unreachable("These are handled by PseudoObjectExpr");

    case Stmt::GNUNullExprClass: {
      // GNU __null is a pointer-width integer, not an actual pointer.
      ProgramStateRef state = Pred->getState();
      state = state->BindExpr(S, Pred->getLocationContext(),
                              svalBuilder.makeIntValWithPtrWidth(0, false));
      Bldr.generateNode(S, Pred, state);
      break;
    }

    case Stmt::ObjCAtSynchronizedStmtClass:
      Bldr.takeNodes(Pred);
      VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Expr::ConstantExprClass:
    case Stmt::ExprWithCleanupsClass:
      // Handled due to fully linearised CFG.
      break;

    case Stmt::CXXBindTemporaryExprClass: {
      Bldr.takeNodes(Pred);
      ExplodedNodeSet PreVisit;
      getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
      ExplodedNodeSet Next;
      VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), PreVisit, Next);
      getCheckerManager().runCheckersForPostStmt(Dst, Next, S, *this);
      Bldr.addNodes(Dst);
      break;
    }

    // Cases not handled yet; but will handle some day.
    case Stmt::DesignatedInitExprClass:
    case Stmt::DesignatedInitUpdateExprClass:
    case Stmt::ArrayInitLoopExprClass:
    case Stmt::ArrayInitIndexExprClass:
    case Stmt::ExtVectorElementExprClass:
    case Stmt::ImaginaryLiteralClass:
    case Stmt::ObjCAtCatchStmtClass:
    case Stmt::ObjCAtFinallyStmtClass:
    case Stmt::ObjCAtTryStmtClass:
    case Stmt::ObjCAutoreleasePoolStmtClass:
    case Stmt::ObjCEncodeExprClass:
    case Stmt::ObjCIsaExprClass:
    case Stmt::ObjCProtocolExprClass:
    case Stmt::ObjCSelectorExprClass:
    case Stmt::ParenListExprClass:
    case Stmt::ShuffleVectorExprClass:
    case Stmt::ConvertVectorExprClass:
    case Stmt::VAArgExprClass:
    case Stmt::CUDAKernelCallExprClass:
    case Stmt::OpaqueValueExprClass:
    case Stmt::AsTypeExprClass:
    case Stmt::ConceptSpecializationExprClass:
    case Stmt::CXXRewrittenBinaryOperatorClass:
    case Stmt::RequiresExprClass:
      // Fall through.

    // Cases we intentionally don't evaluate, since they don't need
    // to be explicitly evaluated.
    case Stmt::PredefinedExprClass:
    case Stmt::AddrLabelExprClass:
    case Stmt::AttributedStmtClass:
    case Stmt::IntegerLiteralClass:
    case Stmt::FixedPointLiteralClass:
    case Stmt::CharacterLiteralClass:
    case Stmt::CXXScalarValueInitExprClass:
    case Stmt::CXXBoolLiteralExprClass:
    case Stmt::ObjCBoolLiteralExprClass:
    case Stmt::ObjCAvailabilityCheckExprClass:
    case Stmt::FloatingLiteralClass:
    case Stmt::NoInitExprClass:
    case Stmt::SizeOfPackExprClass:
    case Stmt::StringLiteralClass:
    case Stmt::SourceLocExprClass:
    case Stmt::ObjCStringLiteralClass:
    case Stmt::CXXPseudoDestructorExprClass:
    case Stmt::SubstNonTypeTemplateParmExprClass:
    case Stmt::CXXNullPtrLiteralExprClass:
    case Stmt::OMPArraySectionExprClass:
    case Stmt::OMPArrayShapingExprClass:
    case Stmt::OMPIteratorExprClass:
    case Stmt::SYCLUniqueStableNameExprClass:
    case Stmt::TypeTraitExprClass: {
      Bldr.takeNodes(Pred);
      ExplodedNodeSet preVisit;
      getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
      getCheckerManager().runCheckersForPostStmt(Dst, preVisit, S, *this);
      Bldr.addNodes(Dst);
      break;
    }

    case Stmt::CXXDefaultArgExprClass:
    case Stmt::CXXDefaultInitExprClass: {
      Bldr.takeNodes(Pred);
      ExplodedNodeSet PreVisit;
      getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);

      ExplodedNodeSet Tmp;
      StmtNodeBuilder Bldr2(PreVisit, Tmp, *currBldrCtx);

      const Expr *ArgE;
      if (const auto *DefE = dyn_cast<CXXDefaultArgExpr>(S))
        ArgE = DefE->getExpr();
      else if (const auto *DefE = dyn_cast<CXXDefaultInitExpr>(S))
        ArgE = DefE->getExpr();
      else
        llvm_unreachable("unknown constant wrapper kind");

      bool IsTemporary = false;
      if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(ArgE)) {
        ArgE = MTE->getSubExpr();
        IsTemporary = true;
      }

      Optional<SVal> ConstantVal = svalBuilder.getConstantVal(ArgE);
      if (!ConstantVal)
        ConstantVal = UnknownVal();

      const LocationContext *LCtx = Pred->getLocationContext();
      for (const auto I : PreVisit) {
        ProgramStateRef State = I->getState();
        State = State->BindExpr(S, LCtx, *ConstantVal);
        if (IsTemporary)
          State = createTemporaryRegionIfNeeded(State, LCtx,
                                                cast<Expr>(S),
                                                cast<Expr>(S));
        Bldr2.generateNode(S, I, State);
      }

      getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
      Bldr.addNodes(Dst);
      break;
    }

    // Cases we evaluate as opaque expressions, conjuring a symbol.
    case Stmt::CXXStdInitializerListExprClass:
    case Expr::ObjCArrayLiteralClass:
    case Expr::ObjCDictionaryLiteralClass:
    case Expr::ObjCBoxedExprClass: {
      Bldr.takeNodes(Pred);

      ExplodedNodeSet preVisit;
      getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);

      ExplodedNodeSet Tmp;
      StmtNodeBuilder Bldr2(preVisit, Tmp, *currBldrCtx);

      const auto *Ex = cast<Expr>(S);
      QualType resultType = Ex->getType();

      for (const auto N : preVisit) {
        const LocationContext *LCtx = N->getLocationContext();
        SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx,
                                                   resultType,
                                                   currBldrCtx->blockCount());
        ProgramStateRef State = N->getState()->BindExpr(Ex, LCtx, 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);
            SVal Val = State->getSVal(Child, LCtx);
            State = escapeValues(State, Val, PSK_EscapeOther);
          }

        Bldr2.generateNode(S, N, State);
      }

      getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
      Bldr.addNodes(Dst);
      break;
    }

    case Stmt::ArraySubscriptExprClass:
      Bldr.takeNodes(Pred);
      VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::MatrixSubscriptExprClass:
      llvm_unreachable("Support for MatrixSubscriptExpr is not implemented.");
      break;

    case Stmt::GCCAsmStmtClass:
      Bldr.takeNodes(Pred);
      VisitGCCAsmStmt(cast<GCCAsmStmt>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::MSAsmStmtClass:
      Bldr.takeNodes(Pred);
      VisitMSAsmStmt(cast<MSAsmStmt>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::BlockExprClass:
      Bldr.takeNodes(Pred);
      VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::LambdaExprClass:
      if (AMgr.options.ShouldInlineLambdas) {
        Bldr.takeNodes(Pred);
        VisitLambdaExpr(cast<LambdaExpr>(S), Pred, Dst);
        Bldr.addNodes(Dst);
      } else {
        const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
        Engine.addAbortedBlock(node, currBldrCtx->getBlock());
      }
      break;

    case Stmt::BinaryOperatorClass: {
      const auto *B = cast<BinaryOperator>(S);
      if (B->isLogicalOp()) {
        Bldr.takeNodes(Pred);
        VisitLogicalExpr(B, Pred, Dst);
        Bldr.addNodes(Dst);
        break;
      }
      else if (B->getOpcode() == BO_Comma) {
        ProgramStateRef state = Pred->getState();
        Bldr.generateNode(B, Pred,
                          state->BindExpr(B, Pred->getLocationContext(),
                                          state->getSVal(B->getRHS(),
                                                  Pred->getLocationContext())));
        break;
      }

      Bldr.takeNodes(Pred);

      if (AMgr.options.ShouldEagerlyAssume &&
          (B->isRelationalOp() || B->isEqualityOp())) {
        ExplodedNodeSet Tmp;
        VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp);
        evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, cast<Expr>(S));
      }
      else
        VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);

      Bldr.addNodes(Dst);
      break;
    }

    case Stmt::CXXOperatorCallExprClass: {
      const auto *OCE = cast<CXXOperatorCallExpr>(S);

      // For instance method operators, make sure the 'this' argument has a
      // valid region.
      const Decl *Callee = OCE->getCalleeDecl();
      if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Callee)) {
        if (MD->isInstance()) {
          ProgramStateRef State = Pred->getState();
          const LocationContext *LCtx = Pred->getLocationContext();
          ProgramStateRef NewState =
            createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0));
          if (NewState != State) {
            Pred = Bldr.generateNode(OCE, Pred, NewState, /*tag=*/nullptr,
                                     ProgramPoint::PreStmtKind);
            // Did we cache out?
            if (!Pred)
              break;
          }
        }
      }
      // FALLTHROUGH
      LLVM_FALLTHROUGH;
    }

    case Stmt::CallExprClass:
    case Stmt::CXXMemberCallExprClass:
    case Stmt::UserDefinedLiteralClass:
      Bldr.takeNodes(Pred);
      VisitCallExpr(cast<CallExpr>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::CXXCatchStmtClass:
      Bldr.takeNodes(Pred);
      VisitCXXCatchStmt(cast<CXXCatchStmt>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::CXXTemporaryObjectExprClass:
    case Stmt::CXXConstructExprClass:
      Bldr.takeNodes(Pred);
      VisitCXXConstructExpr(cast<CXXConstructExpr>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::CXXInheritedCtorInitExprClass:
      Bldr.takeNodes(Pred);
      VisitCXXInheritedCtorInitExpr(cast<CXXInheritedCtorInitExpr>(S), Pred,
                                    Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::CXXNewExprClass: {
      Bldr.takeNodes(Pred);

      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);
      Bldr.addNodes(Dst);
      break;
    }

    case Stmt::CXXDeleteExprClass: {
      Bldr.takeNodes(Pred);
      ExplodedNodeSet PreVisit;
      const auto *CDE = cast<CXXDeleteExpr>(S);
      getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
      ExplodedNodeSet PostVisit;
      getCheckerManager().runCheckersForPostStmt(PostVisit, PreVisit, S, *this);

      for (const auto i : PostVisit)
        VisitCXXDeleteExpr(CDE, i, Dst);

      Bldr.addNodes(Dst);
      break;
    }
      // 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
      Bldr.takeNodes(Pred);
      const auto *C = cast<ChooseExpr>(S);
      VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
      Bldr.addNodes(Dst);
      break;
    }

    case Stmt::CompoundAssignOperatorClass:
      Bldr.takeNodes(Pred);
      VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::CompoundLiteralExprClass:
      Bldr.takeNodes(Pred);
      VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::BinaryConditionalOperatorClass:
    case Stmt::ConditionalOperatorClass: { // '?' operator
      Bldr.takeNodes(Pred);
      const auto *C = cast<AbstractConditionalOperator>(S);
      VisitGuardedExpr(C, C->getTrueExpr(), C->getFalseExpr(), Pred, Dst);
      Bldr.addNodes(Dst);
      break;
    }

    case Stmt::CXXThisExprClass:
      Bldr.takeNodes(Pred);
      VisitCXXThisExpr(cast<CXXThisExpr>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::DeclRefExprClass: {
      Bldr.takeNodes(Pred);
      const auto *DE = cast<DeclRefExpr>(S);
      VisitCommonDeclRefExpr(DE, DE->getDecl(), Pred, Dst);
      Bldr.addNodes(Dst);
      break;
    }

    case Stmt::DeclStmtClass:
      Bldr.takeNodes(Pred);
      VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::ImplicitCastExprClass:
    case Stmt::CStyleCastExprClass:
    case Stmt::CXXStaticCastExprClass:
    case Stmt::CXXDynamicCastExprClass:
    case Stmt::CXXReinterpretCastExprClass:
    case Stmt::CXXConstCastExprClass:
    case Stmt::CXXFunctionalCastExprClass:
    case Stmt::BuiltinBitCastExprClass:
    case Stmt::ObjCBridgedCastExprClass:
    case Stmt::CXXAddrspaceCastExprClass: {
      Bldr.takeNodes(Pred);
      const auto *C = cast<CastExpr>(S);
      ExplodedNodeSet dstExpr;
      VisitCast(C, C->getSubExpr(), Pred, dstExpr);

      // Handle the postvisit checks.
      getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, C, *this);
      Bldr.addNodes(Dst);
      break;
    }

    case Expr::MaterializeTemporaryExprClass: {
      Bldr.takeNodes(Pred);
      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);
      Bldr.addNodes(Dst);
      break;
    }

    case Stmt::InitListExprClass:
      Bldr.takeNodes(Pred);
      VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::MemberExprClass:
      Bldr.takeNodes(Pred);
      VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::AtomicExprClass:
      Bldr.takeNodes(Pred);
      VisitAtomicExpr(cast<AtomicExpr>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::ObjCIvarRefExprClass:
      Bldr.takeNodes(Pred);
      VisitLvalObjCIvarRefExpr(cast<ObjCIvarRefExpr>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::ObjCForCollectionStmtClass:
      Bldr.takeNodes(Pred);
      VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::ObjCMessageExprClass:
      Bldr.takeNodes(Pred);
      VisitObjCMessage(cast<ObjCMessageExpr>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::ObjCAtThrowStmtClass:
    case Stmt::CXXThrowExprClass:
      // FIXME: This is not complete.  We basically treat @throw as
      // an abort.
      Bldr.generateSink(S, Pred, Pred->getState());
      break;

    case Stmt::ReturnStmtClass:
      Bldr.takeNodes(Pred);
      VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
      Bldr.addNodes(Dst);
      break;

    case Stmt::OffsetOfExprClass: {
      Bldr.takeNodes(Pred);
      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);
      Bldr.addNodes(Dst);
      break;
    }

    case Stmt::UnaryExprOrTypeTraitExprClass:
      Bldr.takeNodes(Pred);
      VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S),
                                    Pred, Dst);
      Bldr.addNodes(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.");
        break;
      }

      if (const auto *LastExpr =
              dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) {
        ProgramStateRef state = Pred->getState();
        Bldr.generateNode(SE, Pred,
                          state->BindExpr(SE, Pred->getLocationContext(),
                                          state->getSVal(LastExpr,
                                                  Pred->getLocationContext())));
      }
      break;
    }

    case Stmt::UnaryOperatorClass: {
      Bldr.takeNodes(Pred);
      const auto *U = cast<UnaryOperator>(S);
      if (AMgr.options.ShouldEagerlyAssume && (U->getOpcode() == UO_LNot)) {
        ExplodedNodeSet Tmp;
        VisitUnaryOperator(U, Pred, Tmp);
        evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, U);
      }
      else
        VisitUnaryOperator(U, Pred, Dst);
      Bldr.addNodes(Dst);
      break;
    }

    case Stmt::PseudoObjectExprClass: {
      Bldr.takeNodes(Pred);
      ProgramStateRef state = Pred->getState();
      const auto *PE = cast<PseudoObjectExpr>(S);
      if (const Expr *Result = PE->getResultExpr()) {
        SVal V = state->getSVal(Result, Pred->getLocationContext());
        Bldr.generateNode(S, Pred,
                          state->BindExpr(S, Pred->getLocationContext(), V));
      }
      else
        Bldr.generateNode(S, Pred,
                          state->BindExpr(S, Pred->getLocationContext(),
                                                   UnknownVal()));

      Bldr.addNodes(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.
      Bldr.takeNodes(Pred);
      ProgramStateRef state = Pred->getState();
      const auto *OIE = cast<ObjCIndirectCopyRestoreExpr>(S);
      const Expr *E = OIE->getSubExpr();
      SVal V = state->getSVal(E, Pred->getLocationContext());
      Bldr.generateNode(S, Pred,
              state->BindExpr(S, Pred->getLocationContext(), V));
      Bldr.addNodes(Dst);
      break;
    }
  }
}