Repository: llvm/llvm-project
File: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp (C++)

Code before:

      PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame);
      evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP);
    }
  } else if (BMI->isBaseInitializer() && isa<InitListExpr>(Init)) {
    // When the base class is initialized with an initialization list and the
    // base class does not have a ctor, there will not be a CXXConstructExpr to
    // initialize the base region. Hence, we need to make the bind for it.
    SVal BaseLoc = getStoreManager().evalDerivedToBase(
        thisVal, QualType(BMI->getBaseClass(), 0), BMI->isBaseVirtual());
    SVal InitVal = State->getSVal(Init, stackFrame);
    evalBind(Tmp, Init, Pred, BaseLoc, InitVal, /*isInit=*/true);
  } else {
    assert(BMI->isBaseInitializer() || BMI->isDelegatingInitializer());
    Tmp.insert(Pred);
    // We already did all the work when visiting the CXXConstructExpr.
  }

  // Construct PostInitializer nodes whether the state changed or not,
  // so that the diagnostics don't get confused.
  PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame);

  ExplodedNodeSet Dst;
  for (ExplodedNode *Pred : Tmp) {
    Dst.Add(Engine.makeNode(PP, Pred->getState(), Pred));
  }
  // Enqueue the new nodes onto the work list.
  Engine.enqueueStmtNodes(Dst, currBldrCtx->getBlock(), currStmtIdx);
}

std::pair<ProgramStateRef, uint64_t>
ExprEngine::prepareStateForArrayDestruction(const ProgramStateRef State,
                                            const MemRegion *Region,
                                            const QualType &ElementTy,
                                            const LocationContext *LCtx,
                                            SVal *ElementCountVal) {
  assert(Region != nullptr && "Not-null region expected");

  QualType Ty = ElementTy.getDesugaredType(getContext());
  while (const auto *NTy = dyn_cast<ArrayType>(Ty))
    Ty = NTy->getElementType().getDesugaredType(getContext());

  auto ElementCount = getDynamicElementCount(State, Region, svalBuilder, Ty);

  if (ElementCountVal)
    *ElementCountVal = ElementCount;

  // Note: the destructors are called in reverse order.
  unsigned Idx = 0;
  if (auto OptionalIdx = getPendingArrayDestruction(State, LCtx)) {
    Idx = *OptionalIdx;

Review comment (suggestion):
```suggestion
  for (ExplodedNode *Pred : Tmp)
    Dst.Add(Engine.makeNode(PP, Pred->getState(), Pred));
```

Code after:

      PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame);
      evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP);
    }
  } else if (BMI->isBaseInitializer() && isa<InitListExpr>(Init)) {
    // When the base class is initialized with an initialization list and the
    // base class does not have a ctor, there will not be a CXXConstructExpr to
    // initialize the base region. Hence, we need to make the bind for it.
    SVal BaseLoc = getStoreManager().evalDerivedToBase(
        thisVal, QualType(BMI->getBaseClass(), 0), BMI->isBaseVirtual());
    SVal InitVal = State->getSVal(Init, stackFrame);
    evalBind(Tmp, Init, Pred, BaseLoc, InitVal, /*isInit=*/true);
  } else {
    assert(BMI->isBaseInitializer() || BMI->isDelegatingInitializer());
    Tmp.insert(Pred);
    // We already did all the work when visiting the CXXConstructExpr.
  }

  // Construct PostInitializer nodes whether the state changed or not,
  // so that the diagnostics don't get confused.
  PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame);

  ExplodedNodeSet Dst;
  for (ExplodedNode *Pred : Tmp)
    Dst.Add(Engine.makeNode(PP, Pred->getState(), Pred));
  // Enqueue the new nodes onto the work list.
  Engine.enqueueStmtNodes(Dst, currBldrCtx->getBlock(), currStmtIdx);
}

std::pair<ProgramStateRef, uint64_t>
ExprEngine::prepareStateForArrayDestruction(const ProgramStateRef State,
                                            const MemRegion *Region,
                                            const QualType &ElementTy,
                                            const LocationContext *LCtx,
                                            SVal *ElementCountVal) {
  assert(Region != nullptr && "Not-null region expected");

  QualType Ty = ElementTy.getDesugaredType(getContext());
  while (const auto *NTy = dyn_cast<ArrayType>(Ty))
    Ty = NTy->getElementType().getDesugaredType(getContext());

  auto ElementCount = getDynamicElementCount(State, Region, svalBuilder, Ty);

  if (ElementCountVal)
    *ElementCountVal = ElementCount;

  // Note: the destructors are called in reverse order.
  unsigned Idx = 0;
  if (auto OptionalIdx = getPendingArrayDestruction(State, LCtx)) {
    Idx = *OptionalIdx;
  } else {