27 using namespace clang;
29 using namespace iterator;
33 class ContainerModeling
34 :
public Checker<check::PostCall, check::LiveSymbols, check::DeadSymbols> {
36 void handleBegin(CheckerContext &C,
const Expr *CE, SVal RetVal,
38 void handleEnd(CheckerContext &C,
const Expr *CE, SVal RetVal,
41 SVal OldCont = UndefinedVal())
const;
42 void handleAssign(CheckerContext &C, SVal Cont,
const Expr *ContE)
const;
43 void handleClear(CheckerContext &C, SVal Cont,
const Expr *ContE)
const;
44 void handlePushBack(CheckerContext &C, SVal Cont,
const Expr *ContE)
const;
45 void handlePopBack(CheckerContext &C, SVal Cont,
const Expr *ContE)
const;
46 void handlePushFront(CheckerContext &C, SVal Cont,
const Expr *ContE)
const;
47 void handlePopFront(CheckerContext &C, SVal Cont,
const Expr *ContE)
const;
48 void handleInsert(CheckerContext &C, SVal Cont, SVal Iter)
const;
49 void handleErase(CheckerContext &C, SVal Cont, SVal Iter)
const;
50 void handleErase(CheckerContext &C, SVal Cont, SVal Iter1, SVal Iter2)
const;
51 void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter)
const;
52 void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter1,
54 const NoteTag *getChangeTag(CheckerContext &C, StringRef
Text,
55 const MemRegion *ContReg,
56 const Expr *ContE)
const;
58 const char *Sep)
const override;
61 ContainerModeling() =
default;
63 void checkPostCall(
const CallEvent &Call, CheckerContext &C)
const;
65 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C)
const;
67 using NoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal,
69 using OneItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal,
71 using TwoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, SVal,
74 CallDescriptionMap<NoItParamFn> NoIterParamFunctions = {
75 {{
"clear", 0}, &ContainerModeling::handleClear},
76 {{
"assign", 2}, &ContainerModeling::handleAssign},
77 {{
"push_back", 1}, &ContainerModeling::handlePushBack},
78 {{
"emplace_back", 1}, &ContainerModeling::handlePushBack},
79 {{
"pop_back", 0}, &ContainerModeling::handlePopBack},
80 {{
"push_front", 1}, &ContainerModeling::handlePushFront},
81 {{
"emplace_front", 1}, &ContainerModeling::handlePushFront},
82 {{
"pop_front", 0}, &ContainerModeling::handlePopFront},
85 CallDescriptionMap<OneItParamFn> OneIterParamFunctions = {
86 {{
"insert", 2}, &ContainerModeling::handleInsert},
87 {{
"emplace", 2}, &ContainerModeling::handleInsert},
88 {{
"erase", 1}, &ContainerModeling::handleErase},
89 {{
"erase_after", 1}, &ContainerModeling::handleEraseAfter},
92 CallDescriptionMap<TwoItParamFn> TwoIterParamFunctions = {
93 {{
"erase", 2}, &ContainerModeling::handleErase},
94 {{
"erase_after", 2}, &ContainerModeling::handleEraseAfter},
106 const MemRegion *Cont,
const Expr *E,
108 unsigned BlockCount);
112 unsigned BlockCount);
114 const ContainerData &CData);
116 const MemRegion *Cont);
130 const MemRegion *Cont,
131 const MemRegion *NewCont);
133 const MemRegion *Cont,
134 const MemRegion *NewCont,
146 void ContainerModeling::checkPostCall(
const CallEvent &Call,
147 CheckerContext &C)
const {
148 const auto *Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
152 if (Func->isOverloadedOperator()) {
153 const auto Op = Func->getOverloadedOperator();
154 if (Op == OO_Equal) {
156 const auto *InstCall = cast<CXXInstanceCall>(&Call);
157 if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) {
167 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
168 const NoItParamFn *Handler0 = NoIterParamFunctions.lookup(Call);
170 (this->**Handler0)(C, InstCall->getCXXThisVal(),
171 InstCall->getCXXThisExpr());
175 const OneItParamFn *Handler1 = OneIterParamFunctions.lookup(Call);
177 (this->**Handler1)(C, InstCall->getCXXThisVal(),
Call.getArgSVal(0));
181 const TwoItParamFn *Handler2 = TwoIterParamFunctions.lookup(Call);
183 (this->**Handler2)(C, InstCall->getCXXThisVal(),
Call.getArgSVal(0),
188 const auto *OrigExpr =
Call.getOriginExpr();
192 if (isBeginCall(Func)) {
193 handleBegin(C, OrigExpr,
Call.getReturnValue(),
194 InstCall->getCXXThisVal());
198 if (isEndCall(Func)) {
199 handleEnd(C, OrigExpr,
Call.getReturnValue(),
200 InstCall->getCXXThisVal());
208 SymbolReaper &SR)
const {
210 auto ContMap =
State->get<ContainerMap>();
211 for (
const auto &Cont : ContMap) {
212 const auto CData = Cont.second;
213 if (CData.getBegin()) {
214 SR.markLive(CData.getBegin());
215 if(
const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin()))
216 SR.markLive(SIE->getLHS());
218 if (CData.getEnd()) {
219 SR.markLive(CData.getEnd());
220 if(
const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd()))
221 SR.markLive(SIE->getLHS());
226 void ContainerModeling::checkDeadSymbols(SymbolReaper &SR,
227 CheckerContext &C)
const {
229 auto State =
C.getState();
231 auto ContMap =
State->get<ContainerMap>();
232 for (
const auto &Cont : ContMap) {
233 if (!SR.isLiveRegion(Cont.first)) {
236 if (!hasLiveIterators(
State, Cont.first)) {
237 State =
State->remove<ContainerMap>(Cont.first);
245 void ContainerModeling::handleBegin(CheckerContext &C,
const Expr *CE,
246 SVal RetVal, SVal Cont)
const {
247 const auto *ContReg = Cont.getAsRegion();
251 ContReg = ContReg->getMostDerivedObjectRegion();
255 auto State =
C.getState();
256 auto BeginSym = getContainerBegin(
State, ContReg);
258 State = createContainerBegin(
State, ContReg, CE,
C.getASTContext().LongTy,
259 C.getLocationContext(),
C.blockCount());
260 BeginSym = getContainerBegin(
State, ContReg);
267 void ContainerModeling::handleEnd(CheckerContext &C,
const Expr *CE,
268 SVal RetVal, SVal Cont)
const {
269 const auto *ContReg = Cont.getAsRegion();
273 ContReg = ContReg->getMostDerivedObjectRegion();
277 auto State =
C.getState();
278 auto EndSym = getContainerEnd(
State, ContReg);
280 State = createContainerEnd(
State, ContReg, CE,
C.getASTContext().LongTy,
281 C.getLocationContext(),
C.blockCount());
282 EndSym = getContainerEnd(
State, ContReg);
290 const Expr *CE, SVal OldCont)
const {
291 const auto *ContReg = Cont.getAsRegion();
295 ContReg = ContReg->getMostDerivedObjectRegion();
299 auto State =
C.getState();
302 State = invalidateAllIteratorPositions(
State, ContReg);
307 if (!OldCont.isUndef()) {
308 const auto *OldContReg = OldCont.getAsRegion();
310 OldContReg = OldContReg->getMostDerivedObjectRegion();
313 if (
const auto OldEndSym = OldCData->getEnd()) {
318 State = reassignAllIteratorPositionsUnless(
State, OldContReg, ContReg,
320 auto &SymMgr =
C.getSymbolManager();
321 auto &SVB =
C.getSValBuilder();
324 SymMgr.conjureSymbol(CE,
C.getLocationContext(),
325 C.getASTContext().LongTy,
C.blockCount());
328 State = setContainerData(
State, ContReg, CData->newEnd(NewEndSym));
335 State = rebaseSymbolInIteratorPositionsIf(
336 State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT);
340 State = reassignAllIteratorPositions(
State, OldContReg, ContReg);
342 if (
const auto OldBeginSym = OldCData->getBegin()) {
347 setContainerData(
State, ContReg, CData->newBegin(OldBeginSym));
353 setContainerData(
State, OldContReg, OldCData->newBegin(
nullptr));
358 State = reassignAllIteratorPositions(
State, OldContReg, ContReg);
365 void ContainerModeling::handleAssign(CheckerContext &C, SVal Cont,
366 const Expr *ContE)
const {
367 const auto *ContReg = Cont.getAsRegion();
371 ContReg = ContReg->getMostDerivedObjectRegion();
374 auto State =
C.getState();
375 State = invalidateAllIteratorPositions(
State, ContReg);
379 void ContainerModeling::handleClear(CheckerContext &C, SVal Cont,
380 const Expr *ContE)
const {
381 const auto *ContReg = Cont.getAsRegion();
385 ContReg = ContReg->getMostDerivedObjectRegion();
389 auto State =
C.getState();
390 if (!hasSubscriptOperator(
State, ContReg) ||
391 !backModifiable(
State, ContReg)) {
394 if (
const auto EndSym = CData->getEnd()) {
396 invalidateAllIteratorPositionsExcept(
State, ContReg, EndSym, BO_GE);
402 const NoteTag *ChangeTag =
403 getChangeTag(C,
"became empty", ContReg, ContE);
404 State = invalidateAllIteratorPositions(
State, ContReg);
405 C.addTransition(
State, ChangeTag);
408 void ContainerModeling::handlePushBack(CheckerContext &C, SVal Cont,
409 const Expr *ContE)
const {
410 const auto *ContReg = Cont.getAsRegion();
414 ContReg = ContReg->getMostDerivedObjectRegion();
417 auto State =
C.getState();
418 if (hasSubscriptOperator(
State, ContReg) && frontModifiable(
State, ContReg)) {
419 State = invalidateAllIteratorPositions(
State, ContReg);
429 if (
const auto EndSym = CData->getEnd()) {
430 if (hasSubscriptOperator(
State, ContReg)) {
431 State = invalidateIteratorPositions(
State, EndSym, BO_GE);
433 auto &SymMgr =
C.getSymbolManager();
434 auto &BVF = SymMgr.getBasicVals();
435 auto &SVB =
C.getSValBuilder();
436 const auto newEndSym =
437 SVB.evalBinOp(
State, BO_Add,
438 nonloc::SymbolVal(EndSym),
439 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
440 SymMgr.getType(EndSym)).getAsSymbol();
441 const NoteTag *ChangeTag =
442 getChangeTag(C,
"extended to the back by 1 position", ContReg, ContE);
443 State = setContainerData(
State, ContReg, CData->newEnd(newEndSym));
444 C.addTransition(
State, ChangeTag);
448 void ContainerModeling::handlePopBack(CheckerContext &C, SVal Cont,
449 const Expr *ContE)
const {
450 const auto *ContReg = Cont.getAsRegion();
454 ContReg = ContReg->getMostDerivedObjectRegion();
456 auto State =
C.getState();
461 if (
const auto EndSym = CData->getEnd()) {
462 auto &SymMgr =
C.getSymbolManager();
463 auto &BVF = SymMgr.getBasicVals();
464 auto &SVB =
C.getSValBuilder();
466 SVB.evalBinOp(
State, BO_Sub,
467 nonloc::SymbolVal(EndSym),
468 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
469 SymMgr.getType(EndSym)).getAsSymbol();
470 const NoteTag *ChangeTag =
471 getChangeTag(C,
"shrank from the back by 1 position", ContReg, ContE);
475 if (hasSubscriptOperator(
State, ContReg) &&
476 backModifiable(
State, ContReg)) {
477 State = invalidateIteratorPositions(
State, BackSym, BO_GE);
478 State = setContainerData(
State, ContReg, CData->newEnd(
nullptr));
480 State = invalidateIteratorPositions(
State, BackSym, BO_EQ);
482 auto newEndSym = BackSym;
483 State = setContainerData(
State, ContReg, CData->newEnd(newEndSym));
484 C.addTransition(
State, ChangeTag);
488 void ContainerModeling::handlePushFront(CheckerContext &C, SVal Cont,
489 const Expr *ContE)
const {
490 const auto *ContReg = Cont.getAsRegion();
494 ContReg = ContReg->getMostDerivedObjectRegion();
497 auto State =
C.getState();
498 if (hasSubscriptOperator(
State, ContReg)) {
499 State = invalidateAllIteratorPositions(
State, ContReg);
506 if (
const auto BeginSym = CData->getBegin()) {
507 auto &SymMgr =
C.getSymbolManager();
508 auto &BVF = SymMgr.getBasicVals();
509 auto &SVB =
C.getSValBuilder();
510 const auto newBeginSym =
511 SVB.evalBinOp(
State, BO_Sub,
512 nonloc::SymbolVal(BeginSym),
513 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
514 SymMgr.getType(BeginSym)).getAsSymbol();
515 const NoteTag *ChangeTag =
516 getChangeTag(C,
"extended to the front by 1 position", ContReg, ContE);
517 State = setContainerData(
State, ContReg, CData->newBegin(newBeginSym));
518 C.addTransition(
State, ChangeTag);
523 void ContainerModeling::handlePopFront(CheckerContext &C, SVal Cont,
524 const Expr *ContE)
const {
525 const auto *ContReg = Cont.getAsRegion();
529 ContReg = ContReg->getMostDerivedObjectRegion();
531 auto State =
C.getState();
538 if (
const auto BeginSym = CData->getBegin()) {
539 if (hasSubscriptOperator(
State, ContReg)) {
540 State = invalidateIteratorPositions(
State, BeginSym, BO_LE);
542 State = invalidateIteratorPositions(
State, BeginSym, BO_EQ);
544 auto &SymMgr =
C.getSymbolManager();
545 auto &BVF = SymMgr.getBasicVals();
546 auto &SVB =
C.getSValBuilder();
547 const auto newBeginSym =
548 SVB.evalBinOp(
State, BO_Add,
549 nonloc::SymbolVal(BeginSym),
550 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
551 SymMgr.getType(BeginSym)).getAsSymbol();
552 const NoteTag *ChangeTag =
553 getChangeTag(C,
"shrank from the front by 1 position", ContReg, ContE);
554 State = setContainerData(
State, ContReg, CData->newBegin(newBeginSym));
555 C.addTransition(
State, ChangeTag);
559 void ContainerModeling::handleInsert(CheckerContext &C, SVal Cont,
561 const auto *ContReg = Cont.getAsRegion();
565 ContReg = ContReg->getMostDerivedObjectRegion();
567 auto State =
C.getState();
574 if (hasSubscriptOperator(
State, ContReg) && backModifiable(
State, ContReg)) {
575 if (frontModifiable(
State, ContReg)) {
576 State = invalidateAllIteratorPositions(
State, ContReg);
578 State = invalidateIteratorPositions(
State, Pos->getOffset(), BO_GE);
581 if (
const auto EndSym = CData->getEnd()) {
582 State = invalidateIteratorPositions(
State, EndSym, BO_GE);
583 State = setContainerData(
State, ContReg, CData->newEnd(
nullptr));
590 void ContainerModeling::handleErase(CheckerContext &C, SVal Cont,
592 const auto *ContReg = Cont.getAsRegion();
596 ContReg = ContReg->getMostDerivedObjectRegion();
598 auto State =
C.getState();
606 if (hasSubscriptOperator(
State, ContReg) && backModifiable(
State, ContReg)) {
607 if (frontModifiable(
State, ContReg)) {
608 State = invalidateAllIteratorPositions(
State, ContReg);
610 State = invalidateIteratorPositions(
State, Pos->getOffset(), BO_GE);
613 if (
const auto EndSym = CData->getEnd()) {
614 State = invalidateIteratorPositions(
State, EndSym, BO_GE);
615 State = setContainerData(
State, ContReg, CData->newEnd(
nullptr));
619 State = invalidateIteratorPositions(
State, Pos->getOffset(), BO_EQ);
624 void ContainerModeling::handleErase(CheckerContext &C, SVal Cont, SVal Iter1,
626 const auto *ContReg = Cont.getAsRegion();
630 ContReg = ContReg->getMostDerivedObjectRegion();
631 auto State =
C.getState();
641 if (hasSubscriptOperator(
State, ContReg) && backModifiable(
State, ContReg)) {
642 if (frontModifiable(
State, ContReg)) {
643 State = invalidateAllIteratorPositions(
State, ContReg);
645 State = invalidateIteratorPositions(
State, Pos1->getOffset(), BO_GE);
648 if (
const auto EndSym = CData->getEnd()) {
649 State = invalidateIteratorPositions(
State, EndSym, BO_GE);
650 State = setContainerData(
State, ContReg, CData->newEnd(
nullptr));
654 State = invalidateIteratorPositions(
State, Pos1->getOffset(), BO_GE,
655 Pos2->getOffset(), BO_LT);
660 void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont,
662 auto State =
C.getState();
669 auto &SymMgr =
C.getSymbolManager();
670 auto &BVF = SymMgr.getBasicVals();
671 auto &SVB =
C.getSValBuilder();
673 SVB.evalBinOp(
State, BO_Add,
674 nonloc::SymbolVal(Pos->getOffset()),
675 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
676 SymMgr.getType(Pos->getOffset())).getAsSymbol();
677 State = invalidateIteratorPositions(
State, NextSym, BO_EQ);
681 void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont,
682 SVal Iter1, SVal Iter2)
const {
683 auto State =
C.getState();
690 State = invalidateIteratorPositions(
State, Pos1->getOffset(), BO_GT,
691 Pos2->getOffset(), BO_LT);
695 const NoteTag *ContainerModeling::getChangeTag(CheckerContext &C,
697 const MemRegion *ContReg,
698 const Expr *ContE)
const {
701 if (
const auto *DR = dyn_cast<DeclRegion>(ContReg)) {
702 Name = DR->getDecl()->getName();
704 }
else if (
const auto *DRE =
706 Name = DRE->getDecl()->getName();
711 if (!BR.isInteresting(ContReg))
715 llvm::raw_svector_ostream Out(Msg);
716 Out <<
"Container " << (!Name.empty() ? (
"'" + Name.str() +
"' ") :
"" )
723 const char *NL,
const char *Sep)
const {
724 auto ContMap =
State->get<ContainerMap>();
726 if (!ContMap.isEmpty()) {
727 Out << Sep <<
"Container Data :" << NL;
728 for (
const auto &Cont : ContMap) {
729 Cont.first->dumpToStream(Out);
731 const auto CData = Cont.second;
732 if (CData.getBegin())
733 CData.getBegin()->dumpToStream(Out);
738 CData.getEnd()->dumpToStream(Out);
752 return IdInfo->
getName().endswith_insensitive(
"begin");
759 return IdInfo->
getName().endswith_insensitive(
"end");
763 const MemRegion *Reg) {
768 auto Type = TI.getType();
777 const auto *CRD = getCXXRecordDecl(
State, Reg);
781 for (
const auto *Method : CRD->methods()) {
782 if (!Method->isOverloadedOperator())
784 const auto OPK = Method->getOverloadedOperator();
785 if (OPK == OO_Subscript) {
793 const auto *CRD = getCXXRecordDecl(
State, Reg);
797 for (
const auto *Method : CRD->methods()) {
798 if (!Method->getDeclName().isIdentifier())
800 if (Method->getName() ==
"push_front" || Method->getName() ==
"pop_front") {
808 const auto *CRD = getCXXRecordDecl(
State, Reg);
812 for (
const auto *Method : CRD->methods()) {
813 if (!Method->getDeclName().isIdentifier())
815 if (Method->getName() ==
"push_back" || Method->getName() ==
"pop_back") {
827 return CDataPtr->getBegin();
835 return CDataPtr->getEnd();
839 const MemRegion *Cont,
const Expr *E,
841 unsigned BlockCount) {
844 if (CDataPtr && CDataPtr->getBegin())
847 auto &SymMgr =
State->getSymbolManager();
848 const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
853 const auto CData = CDataPtr->newBegin(Sym);
854 return setContainerData(
State, Cont, CData);
858 return setContainerData(
State, Cont, CData);
864 unsigned BlockCount) {
867 if (CDataPtr && CDataPtr->getEnd())
870 auto &SymMgr =
State->getSymbolManager();
871 const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
876 const auto CData = CDataPtr->newEnd(Sym);
877 return setContainerData(
State, Cont, CData);
881 return setContainerData(
State, Cont, CData);
885 const ContainerData &CData) {
886 return State->set<ContainerMap>(Cont, CData);
889 template <
typename Condition,
typename Process>
892 auto &RegionMapFactory =
State->get_context<IteratorRegionMap>();
893 auto RegionMap =
State->get<IteratorRegionMap>();
895 for (
const auto &Reg : RegionMap) {
896 if (Cond(Reg.second)) {
897 RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second));
903 State =
State->set<IteratorRegionMap>(RegionMap);
905 auto &SymbolMapFactory =
State->get_context<IteratorSymbolMap>();
906 auto SymbolMap =
State->get<IteratorSymbolMap>();
908 for (
const auto &Sym : SymbolMap) {
909 if (Cond(Sym.second)) {
910 SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second));
916 State =
State->set<IteratorSymbolMap>(SymbolMap);
922 const MemRegion *Cont) {
923 auto MatchCont = [&](
const IteratorPosition &Pos) {
924 return Pos.getContainer() == Cont;
926 auto Invalidate = [&](
const IteratorPosition &Pos) {
927 return Pos.invalidate();
929 return processIteratorPositions(
State, MatchCont, Invalidate);
936 auto MatchContAndCompare = [&](
const IteratorPosition &Pos) {
937 return Pos.getContainer() == Cont &&
940 auto Invalidate = [&](
const IteratorPosition &Pos) {
941 return Pos.invalidate();
943 return processIteratorPositions(
State, MatchContAndCompare, Invalidate);
949 auto Compare = [&](
const IteratorPosition &Pos) {
952 auto Invalidate = [&](
const IteratorPosition &Pos) {
953 return Pos.invalidate();
955 return processIteratorPositions(
State,
Compare, Invalidate);
963 auto Compare = [&](
const IteratorPosition &Pos) {
964 return compare(
State, Pos.getOffset(), Offset1, Opc1) &&
967 auto Invalidate = [&](
const IteratorPosition &Pos) {
968 return Pos.invalidate();
970 return processIteratorPositions(
State,
Compare, Invalidate);
974 const MemRegion *Cont,
975 const MemRegion *NewCont) {
976 auto MatchCont = [&](
const IteratorPosition &Pos) {
977 return Pos.getContainer() == Cont;
979 auto ReAssign = [&](
const IteratorPosition &Pos) {
980 return Pos.reAssign(NewCont);
982 return processIteratorPositions(
State, MatchCont, ReAssign);
986 const MemRegion *Cont,
987 const MemRegion *NewCont,
990 auto MatchContAndCompare = [&](
const IteratorPosition &Pos) {
991 return Pos.getContainer() == Cont &&
994 auto ReAssign = [&](
const IteratorPosition &Pos) {
995 return Pos.reAssign(NewCont);
997 return processIteratorPositions(
State, MatchContAndCompare, ReAssign);
1006 auto LessThanEnd = [&](
const IteratorPosition &Pos) {
1009 auto RebaseSymbol = [&](
const IteratorPosition &Pos) {
1010 return Pos.setTo(rebaseSymbol(
State, SVB, Pos.getOffset(), OldSym,
1013 return processIteratorPositions(
State, LessThanEnd, RebaseSymbol);
1022 auto &SymMgr = SVB.getSymbolManager();
1023 auto Diff = SVB.evalBinOpNN(
State, BO_Sub, nonloc::SymbolVal(OrigExpr),
1024 nonloc::SymbolVal(OldExpr),
1025 SymMgr.getType(OrigExpr));
1027 const auto DiffInt = Diff.getAs<nonloc::ConcreteInt>();
1031 return SVB.evalBinOpNN(
State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym),
1032 SymMgr.getType(OrigExpr)).getAsSymbol();
1036 auto RegionMap =
State->get<IteratorRegionMap>();
1037 for (
const auto &Reg : RegionMap) {
1038 if (Reg.second.getContainer() == Cont)
1042 auto SymbolMap =
State->get<IteratorSymbolMap>();
1043 for (
const auto &Sym : SymbolMap) {
1044 if (Sym.second.getContainer() == Cont)
1053 void ento::registerContainerModeling(CheckerManager &mgr) {
1054 mgr.registerChecker<ContainerModeling>();
1057 bool ento::shouldRegisterContainerModeling(
const CheckerManager &mgr) {
1058 if (!mgr.getLangOpts().CPlusPlus)
1061 if (!mgr.getAnalyzerOptions().ShouldAggressivelySimplifyBinaryOperation) {
1062 mgr.getASTContext().getDiagnostics().Report(
1063 diag::err_analyzer_checker_incompatible_analyzer_option)
1064 <<
"aggressive-binary-operation-simplification" <<
"false";