32class ContainerModeling
33 :
public Checker<check::PostCall, check::LiveSymbols, check::DeadSymbols> {
40 SVal OldCont = UndefinedVal())
const;
41 void handleAssign(CheckerContext &
C, SVal Cont,
const Expr *ContE)
const;
42 void handleClear(CheckerContext &
C, SVal Cont,
const Expr *ContE)
const;
43 void handlePushBack(CheckerContext &
C, SVal Cont,
const Expr *ContE)
const;
44 void handlePopBack(CheckerContext &
C, SVal Cont,
const Expr *ContE)
const;
45 void handlePushFront(CheckerContext &
C, SVal Cont,
const Expr *ContE)
const;
46 void handlePopFront(CheckerContext &
C, SVal Cont,
const Expr *ContE)
const;
47 void handleInsert(CheckerContext &
C, SVal Cont, SVal Iter)
const;
48 void handleErase(CheckerContext &
C, SVal Cont, SVal Iter)
const;
49 void handleErase(CheckerContext &
C, SVal Cont, SVal Iter1, SVal Iter2)
const;
50 void handleEraseAfter(CheckerContext &
C, SVal Cont, SVal Iter)
const;
51 void handleEraseAfter(CheckerContext &
C, SVal Cont, SVal Iter1,
53 const NoteTag *getChangeTag(CheckerContext &
C, StringRef
Text,
54 const MemRegion *ContReg,
55 const Expr *ContE)
const;
56 void printState(raw_ostream &Out,
ProgramStateRef State,
const char *NL,
57 const char *Sep)
const override;
60 ContainerModeling() =
default;
62 void checkPostCall(
const CallEvent &
Call, CheckerContext &
C)
const;
64 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &
C)
const;
66 using NoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal,
68 using OneItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal,
70 using TwoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, SVal,
73 CallDescriptionMap<NoItParamFn> NoIterParamFunctions = {
74 {{CDM::CXXMethod, {
"clear"}, 0}, &ContainerModeling::handleClear},
75 {{CDM::CXXMethod, {
"assign"}, 2}, &ContainerModeling::handleAssign},
76 {{CDM::CXXMethod, {
"push_back"}, 1}, &ContainerModeling::handlePushBack},
77 {{CDM::CXXMethod, {
"emplace_back"}, 1},
78 &ContainerModeling::handlePushBack},
79 {{CDM::CXXMethod, {
"pop_back"}, 0}, &ContainerModeling::handlePopBack},
80 {{CDM::CXXMethod, {
"push_front"}, 1},
81 &ContainerModeling::handlePushFront},
82 {{CDM::CXXMethod, {
"emplace_front"}, 1},
83 &ContainerModeling::handlePushFront},
84 {{CDM::CXXMethod, {
"pop_front"}, 0}, &ContainerModeling::handlePopFront},
87 CallDescriptionMap<OneItParamFn> OneIterParamFunctions = {
88 {{CDM::CXXMethod, {
"insert"}, 2}, &ContainerModeling::handleInsert},
89 {{CDM::CXXMethod, {
"emplace"}, 2}, &ContainerModeling::handleInsert},
90 {{CDM::CXXMethod, {
"erase"}, 1}, &ContainerModeling::handleErase},
91 {{CDM::CXXMethod, {
"erase_after"}, 1},
92 &ContainerModeling::handleEraseAfter},
95 CallDescriptionMap<TwoItParamFn> TwoIterParamFunctions = {
96 {{CDM::CXXMethod, {
"erase"}, 2}, &ContainerModeling::handleErase},
97 {{CDM::CXXMethod, {
"erase_after"}, 2},
98 &ContainerModeling::handleEraseAfter},
151 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
155 if (
Func->isOverloadedOperator()) {
156 const auto Op =
Func->getOverloadedOperator();
157 if (Op == OO_Equal) {
159 const auto *InstCall = dyn_cast<CXXInstanceCall>(&
Call);
173 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&
Call)) {
174 const NoItParamFn *Handler0 = NoIterParamFunctions.lookup(
Call);
176 (this->**Handler0)(
C, InstCall->getCXXThisVal(),
177 InstCall->getCXXThisExpr());
181 const OneItParamFn *Handler1 = OneIterParamFunctions.lookup(
Call);
183 (this->**Handler1)(
C, InstCall->getCXXThisVal(),
Call.getArgSVal(0));
187 const TwoItParamFn *Handler2 = TwoIterParamFunctions.lookup(
Call);
189 (this->**Handler2)(
C, InstCall->getCXXThisVal(),
Call.getArgSVal(0),
194 const auto *OrigExpr =
Call.getOriginExpr();
198 if (isBeginCall(
Func)) {
199 handleBegin(
C,
Call.getCFGElementRef(),
Call.getReturnValue(),
200 InstCall->getCXXThisVal());
204 if (isEndCall(
Func)) {
205 handleEnd(
C,
Call.getCFGElementRef(),
Call.getReturnValue(),
206 InstCall->getCXXThisVal());
214 SymbolReaper &SR)
const {
216 auto ContMap = State->get<ContainerMap>();
217 for (
const auto &Cont : ContMap) {
218 const auto CData = Cont.second;
219 if (CData.getBegin()) {
221 if(
const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin()))
224 if (CData.getEnd()) {
226 if(
const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd()))
232void ContainerModeling::checkDeadSymbols(SymbolReaper &SR,
233 CheckerContext &
C)
const {
235 auto State =
C.getState();
237 auto ContMap = State->get<ContainerMap>();
238 for (
const auto &Cont : ContMap) {
242 if (!hasLiveIterators(State, Cont.first)) {
243 State = State->remove<ContainerMap>(Cont.first);
248 C.addTransition(State);
252 SVal RetVal, SVal Cont)
const {
261 auto State =
C.getState();
262 auto BeginSym = getContainerBegin(State, ContReg);
264 State = createContainerBegin(State, ContReg, Elem,
C.getASTContext().LongTy,
265 C.getStackFrame(),
C.blockCount());
266 BeginSym = getContainerBegin(State, ContReg);
270 C.addTransition(State);
274 SVal RetVal, SVal Cont)
const {
283 auto State =
C.getState();
284 auto EndSym = getContainerEnd(State, ContReg);
286 State = createContainerEnd(State, ContReg, Elem,
C.getASTContext().LongTy,
287 C.getStackFrame(),
C.blockCount());
288 EndSym = getContainerEnd(State, ContReg);
292 C.addTransition(State);
295void ContainerModeling::handleAssignment(CheckerContext &
C, SVal Cont,
297 SVal OldCont)
const {
306 auto State =
C.getState();
309 State = invalidateAllIteratorPositions(State, ContReg);
317 OldContReg = OldContReg->getMostDerivedObjectRegion();
320 if (
const auto OldEndSym = OldCData->getEnd()) {
325 State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg,
327 auto &SymMgr =
C.getSymbolManager();
328 auto &SVB =
C.getSValBuilder();
331 SymMgr.conjureSymbol(Elem,
C.getStackFrame(),
332 C.getASTContext().LongTy,
C.blockCount());
335 State = setContainerData(State, ContReg, CData->newEnd(NewEndSym));
337 State = setContainerData(State, ContReg,
342 State = rebaseSymbolInIteratorPositionsIf(
343 State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT);
347 State = reassignAllIteratorPositions(State, OldContReg, ContReg);
349 if (
const auto OldBeginSym = OldCData->getBegin()) {
354 setContainerData(State, ContReg, CData->newBegin(OldBeginSym));
356 State = setContainerData(State, ContReg,
360 setContainerData(State, OldContReg, OldCData->newBegin(
nullptr));
365 State = reassignAllIteratorPositions(State, OldContReg, ContReg);
369 C.addTransition(State);
372void ContainerModeling::handleAssign(CheckerContext &
C, SVal Cont,
373 const Expr *ContE)
const {
381 auto State =
C.getState();
382 State = invalidateAllIteratorPositions(State, ContReg);
383 C.addTransition(State);
386void ContainerModeling::handleClear(CheckerContext &
C, SVal Cont,
387 const Expr *ContE)
const {
396 auto State =
C.getState();
397 if (!hasSubscriptOperator(State, ContReg) ||
398 !backModifiable(State, ContReg)) {
401 if (
const auto EndSym = CData->getEnd()) {
403 invalidateAllIteratorPositionsExcept(State, ContReg, EndSym, BO_GE);
404 C.addTransition(State);
409 const NoteTag *ChangeTag =
410 getChangeTag(
C,
"became empty", ContReg, ContE);
411 State = invalidateAllIteratorPositions(State, ContReg);
412 C.addTransition(State, ChangeTag);
415void ContainerModeling::handlePushBack(CheckerContext &
C, SVal Cont,
416 const Expr *ContE)
const {
424 auto State =
C.getState();
425 if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) {
426 State = invalidateAllIteratorPositions(State, ContReg);
427 C.addTransition(State);
436 if (
const auto EndSym = CData->getEnd()) {
437 if (hasSubscriptOperator(State, ContReg)) {
438 State = invalidateIteratorPositions(State, EndSym, BO_GE);
440 auto &SymMgr =
C.getSymbolManager();
441 auto &BVF = SymMgr.getBasicVals();
442 auto &SVB =
C.getSValBuilder();
443 const auto newEndSym =
444 SVB.evalBinOp(State, BO_Add,
445 nonloc::SymbolVal(EndSym),
446 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
447 SymMgr.getType(EndSym)).getAsSymbol();
448 const NoteTag *ChangeTag =
449 getChangeTag(
C,
"extended to the back by 1 position", ContReg, ContE);
450 State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
451 C.addTransition(State, ChangeTag);
455void ContainerModeling::handlePopBack(CheckerContext &
C, SVal Cont,
456 const Expr *ContE)
const {
463 auto State =
C.getState();
468 if (
const auto EndSym = CData->getEnd()) {
469 auto &SymMgr =
C.getSymbolManager();
470 auto &BVF = SymMgr.getBasicVals();
471 auto &SVB =
C.getSValBuilder();
473 SVB.evalBinOp(State, BO_Sub,
474 nonloc::SymbolVal(EndSym),
475 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
476 SymMgr.getType(EndSym)).getAsSymbol();
477 const NoteTag *ChangeTag =
478 getChangeTag(
C,
"shrank from the back by 1 position", ContReg, ContE);
482 if (hasSubscriptOperator(State, ContReg) &&
483 backModifiable(State, ContReg)) {
484 State = invalidateIteratorPositions(State, BackSym, BO_GE);
485 State = setContainerData(State, ContReg, CData->newEnd(
nullptr));
487 State = invalidateIteratorPositions(State, BackSym, BO_EQ);
489 auto newEndSym = BackSym;
490 State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
491 C.addTransition(State, ChangeTag);
495void ContainerModeling::handlePushFront(CheckerContext &
C, SVal Cont,
496 const Expr *ContE)
const {
504 auto State =
C.getState();
505 if (hasSubscriptOperator(State, ContReg)) {
506 State = invalidateAllIteratorPositions(State, ContReg);
507 C.addTransition(State);
513 if (
const auto BeginSym = CData->getBegin()) {
514 auto &SymMgr =
C.getSymbolManager();
515 auto &BVF = SymMgr.getBasicVals();
516 auto &SVB =
C.getSValBuilder();
517 const auto newBeginSym =
518 SVB.evalBinOp(State, BO_Sub,
519 nonloc::SymbolVal(BeginSym),
520 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
521 SymMgr.getType(BeginSym)).getAsSymbol();
522 const NoteTag *ChangeTag =
523 getChangeTag(
C,
"extended to the front by 1 position", ContReg, ContE);
524 State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
525 C.addTransition(State, ChangeTag);
530void ContainerModeling::handlePopFront(CheckerContext &
C, SVal Cont,
531 const Expr *ContE)
const {
538 auto State =
C.getState();
545 if (
const auto BeginSym = CData->getBegin()) {
546 if (hasSubscriptOperator(State, ContReg)) {
547 State = invalidateIteratorPositions(State, BeginSym, BO_LE);
549 State = invalidateIteratorPositions(State, BeginSym, BO_EQ);
551 auto &SymMgr =
C.getSymbolManager();
552 auto &BVF = SymMgr.getBasicVals();
553 auto &SVB =
C.getSValBuilder();
554 const auto newBeginSym =
555 SVB.evalBinOp(State, BO_Add,
556 nonloc::SymbolVal(BeginSym),
557 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
558 SymMgr.getType(BeginSym)).getAsSymbol();
559 const NoteTag *ChangeTag =
560 getChangeTag(
C,
"shrank from the front by 1 position", ContReg, ContE);
561 State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
562 C.addTransition(State, ChangeTag);
566void ContainerModeling::handleInsert(CheckerContext &
C, SVal Cont,
574 auto State =
C.getState();
581 if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) {
582 if (frontModifiable(State, ContReg)) {
583 State = invalidateAllIteratorPositions(State, ContReg);
585 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
588 if (
const auto EndSym = CData->getEnd()) {
589 State = invalidateIteratorPositions(State, EndSym, BO_GE);
590 State = setContainerData(State, ContReg, CData->newEnd(
nullptr));
593 C.addTransition(State);
597void ContainerModeling::handleErase(CheckerContext &
C, SVal Cont,
605 auto State =
C.getState();
613 if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) {
614 if (frontModifiable(State, ContReg)) {
615 State = invalidateAllIteratorPositions(State, ContReg);
617 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
620 if (
const auto EndSym = CData->getEnd()) {
621 State = invalidateIteratorPositions(State, EndSym, BO_GE);
622 State = setContainerData(State, ContReg, CData->newEnd(
nullptr));
626 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_EQ);
628 C.addTransition(State);
631void ContainerModeling::handleErase(CheckerContext &
C, SVal Cont, SVal Iter1,
638 auto State =
C.getState();
648 if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) {
649 if (frontModifiable(State, ContReg)) {
650 State = invalidateAllIteratorPositions(State, ContReg);
652 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE);
655 if (
const auto EndSym = CData->getEnd()) {
656 State = invalidateIteratorPositions(State, EndSym, BO_GE);
657 State = setContainerData(State, ContReg, CData->newEnd(
nullptr));
661 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE,
662 Pos2->getOffset(), BO_LT);
664 C.addTransition(State);
667void ContainerModeling::handleEraseAfter(CheckerContext &
C, SVal Cont,
669 auto State =
C.getState();
676 auto &SymMgr =
C.getSymbolManager();
677 auto &BVF = SymMgr.getBasicVals();
678 auto &SVB =
C.getSValBuilder();
680 SVB.evalBinOp(State, BO_Add,
681 nonloc::SymbolVal(Pos->getOffset()),
682 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))),
683 SymMgr.getType(Pos->getOffset())).getAsSymbol();
684 State = invalidateIteratorPositions(State, NextSym, BO_EQ);
685 C.addTransition(State);
688void ContainerModeling::handleEraseAfter(CheckerContext &
C, SVal Cont,
689 SVal Iter1, SVal Iter2)
const {
690 auto State =
C.getState();
697 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GT,
698 Pos2->getOffset(), BO_LT);
699 C.addTransition(State);
702const NoteTag *ContainerModeling::getChangeTag(CheckerContext &
C,
704 const MemRegion *ContReg,
705 const Expr *ContE)
const {
708 if (
const auto *DR = dyn_cast<DeclRegion>(ContReg)) {
709 Name = DR->getDecl()->getName();
711 }
else if (
const auto *DRE =
713 Name = DRE->getDecl()->getName();
717 [
Text, Name, ContReg](PathSensitiveBugReport &BR) -> std::string {
721 SmallString<256> Msg;
722 llvm::raw_svector_ostream
Out(Msg);
723 Out <<
"Container " << (!Name.empty() ? (
"'" + Name.str() +
"' ") :
"" )
725 return std::string(
Out.str());
729void ContainerModeling::printState(raw_ostream &Out,
ProgramStateRef State,
730 const char *NL,
const char *Sep)
const {
731 auto ContMap = State->get<ContainerMap>();
733 if (!ContMap.isEmpty()) {
734 Out << Sep <<
"Container Data :" << NL;
735 for (
const auto &Cont : ContMap) {
738 const auto CData = Cont.second;
739 if (CData.getBegin())
745 CData.getEnd()->dumpToStream(Out);
755bool isBeginCall(
const FunctionDecl *
Func) {
756 const auto *IdInfo =
Func->getIdentifier();
759 return IdInfo->getName().ends_with_insensitive(
"begin");
762bool isEndCall(
const FunctionDecl *
Func) {
763 const auto *IdInfo =
Func->getIdentifier();
766 return IdInfo->getName().ends_with_insensitive(
"end");
770 const MemRegion *Reg) {
775 auto Type = TI.getType();
776 if (
const auto *RefT =
Type->getAs<ReferenceType>()) {
777 Type = RefT->getPointeeType();
780 if (
const auto *PtrT =
Type->getAs<PointerType>()) {
781 Type = PtrT->getPointeeType();
784 return Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
787bool hasSubscriptOperator(
ProgramStateRef State,
const MemRegion *Reg) {
788 const auto *CRD = getCXXRecordDecl(State, Reg);
792 for (
const auto *
Method : CRD->methods()) {
793 if (!
Method->isOverloadedOperator())
795 const auto OPK =
Method->getOverloadedOperator();
796 if (OPK == OO_Subscript) {
804 const auto *CRD = getCXXRecordDecl(State, Reg);
808 for (
const auto *
Method : CRD->methods()) {
809 if (!
Method->getDeclName().isIdentifier())
811 if (
Method->getName() ==
"push_front" ||
Method->getName() ==
"pop_front") {
819 const auto *CRD = getCXXRecordDecl(State, Reg);
823 for (
const auto *
Method : CRD->methods()) {
824 if (!
Method->getDeclName().isIdentifier())
826 if (
Method->getName() ==
"push_back" ||
Method->getName() ==
"pop_back") {
838 return CDataPtr->getBegin();
846 return CDataPtr->getEnd();
850 const MemRegion *Cont,
852 const StackFrame *SF,
853 unsigned BlockCount) {
856 if (CDataPtr && CDataPtr->getBegin())
859 auto &SymMgr = State->getSymbolManager();
860 const SymbolConjured *Sym =
861 SymMgr.conjureSymbol(Elem, SF, T, BlockCount,
"begin");
865 const auto CData = CDataPtr->newBegin(Sym);
866 return setContainerData(State, Cont, CData);
870 return setContainerData(State, Cont, CData);
875 const StackFrame *SF,
unsigned BlockCount) {
878 if (CDataPtr && CDataPtr->getEnd())
881 auto &SymMgr = State->getSymbolManager();
882 const SymbolConjured *Sym =
883 SymMgr.conjureSymbol(Elem, SF, T, BlockCount,
"end");
887 const auto CData = CDataPtr->newEnd(Sym);
888 return setContainerData(State, Cont, CData);
892 return setContainerData(State, Cont, CData);
896 const ContainerData &CData) {
897 return State->set<ContainerMap>(Cont, CData);
900template <
typename Condition,
typename Process>
903 auto &RegionMapFactory = State->get_context<IteratorRegionMap>();
904 auto RegionMap = State->get<IteratorRegionMap>();
906 for (
const auto &Reg : RegionMap) {
907 if (
Cond(Reg.second)) {
908 RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second));
914 State = State->set<IteratorRegionMap>(RegionMap);
916 auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>();
917 auto SymbolMap = State->get<IteratorSymbolMap>();
919 for (
const auto &Sym : SymbolMap) {
920 if (
Cond(Sym.second)) {
921 SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second));
927 State = State->set<IteratorSymbolMap>(SymbolMap);
933 const MemRegion *Cont) {
934 auto MatchCont = [&](
const IteratorPosition &Pos) {
935 return Pos.getContainer() == Cont;
937 auto Invalidate = [&](
const IteratorPosition &Pos) {
938 return Pos.invalidate();
940 return processIteratorPositions(State, MatchCont, Invalidate);
947 auto MatchContAndCompare = [&](
const IteratorPosition &Pos) {
948 return Pos.getContainer() == Cont &&
949 !
compare(State, Pos.getOffset(), Offset, Opc);
951 auto Invalidate = [&](
const IteratorPosition &Pos) {
952 return Pos.invalidate();
954 return processIteratorPositions(State, MatchContAndCompare, Invalidate);
960 auto Compare = [&](
const IteratorPosition &Pos) {
961 return compare(State, Pos.getOffset(), Offset, Opc);
963 auto Invalidate = [&](
const IteratorPosition &Pos) {
964 return Pos.invalidate();
966 return processIteratorPositions(State, Compare, Invalidate);
974 auto Compare = [&](
const IteratorPosition &Pos) {
975 return compare(State, Pos.getOffset(), Offset1, Opc1) &&
976 compare(State, Pos.getOffset(), Offset2, Opc2);
978 auto Invalidate = [&](
const IteratorPosition &Pos) {
979 return Pos.invalidate();
981 return processIteratorPositions(State, Compare, Invalidate);
985 const MemRegion *Cont,
986 const MemRegion *NewCont) {
987 auto MatchCont = [&](
const IteratorPosition &Pos) {
988 return Pos.getContainer() == Cont;
990 auto ReAssign = [&](
const IteratorPosition &Pos) {
991 return Pos.reAssign(NewCont);
993 return processIteratorPositions(State, MatchCont, ReAssign);
997 const MemRegion *Cont,
998 const MemRegion *NewCont,
1001 auto MatchContAndCompare = [&](
const IteratorPosition &Pos) {
1002 return Pos.getContainer() == Cont &&
1003 !
compare(State, Pos.getOffset(), Offset, Opc);
1005 auto ReAssign = [&](
const IteratorPosition &Pos) {
1006 return Pos.reAssign(NewCont);
1008 return processIteratorPositions(State, MatchContAndCompare, ReAssign);
1017 auto LessThanEnd = [&](
const IteratorPosition &Pos) {
1018 return compare(State, Pos.getOffset(), CondSym, Opc);
1020 auto RebaseSymbol = [&](
const IteratorPosition &Pos) {
1021 return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym,
1024 return processIteratorPositions(State, LessThanEnd, RebaseSymbol);
1034 auto Diff = SVB.
evalBinOpNN(State, BO_Sub, nonloc::SymbolVal(OrigExpr),
1035 nonloc::SymbolVal(OldExpr),
1036 SymMgr.getType(OrigExpr));
1038 const auto DiffInt = Diff.
getAs<nonloc::ConcreteInt>();
1042 return SVB.
evalBinOpNN(State, BO_Add, *DiffInt, nonloc::SymbolVal(NewSym),
1047 auto RegionMap = State->get<IteratorRegionMap>();
1048 for (
const auto &Reg : RegionMap) {
1049 if (Reg.second.getContainer() == Cont)
1053 auto SymbolMap = State->get<IteratorSymbolMap>();
1054 for (
const auto &Sym : SymbolMap) {
1055 if (Sym.second.getContainer() == Cont)
1064void ento::registerContainerModeling(CheckerManager &mgr) {
1068bool ento::shouldRegisterContainerModeling(
const CheckerManager &mgr) {
1074 diag::err_analyzer_checker_incompatible_analyzer_option)
1075 <<
"aggressive-binary-operation-simplification" <<
"false";
Defines the C++ template declaration subclasses.
static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal, QualType LValType, APValue &Val)
Perform an assignment of Val to LVal. Takes ownership of Val.
static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y)
DiagnosticsEngine & getDiagnostics() const
BinaryOperatorKind Opcode
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Represents a function declaration or definition.
A (possibly-)qualified type.
It represents a stack frame of the call stack.
Represents an abstract call to a function or method along a particular path.
const AnalyzerOptions & getAnalyzerOptions() const
ASTContext & getASTContext() const
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
const LangOptions & getLangOpts() const
Simple checker classes that implement one frontend (i.e.
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getMostDerivedObjectRegion() const
Recursively retrieve the region of the most derived class instance of regions of C++ base class insta...
bool isInteresting(SymbolRef sym) const
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
SymbolManager & getSymbolManager()
void dumpToStream(raw_ostream &OS) const
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
const MemRegion * getAsRegion() const
void markLive(SymbolRef sym)
Unconditionally marks a symbol as live.
bool isLiveRegion(const MemRegion *region)
const IteratorPosition * getIteratorPosition(ProgramStateRef State, SVal Val)
ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, long Scale)
const ContainerData * getContainerData(ProgramStateRef State, const MemRegion *Cont)
ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val, const IteratorPosition &Pos)
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR)
Get dynamic type information for the region MR.
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
The JSON file list parser is used to communicate input to InstallAPI.
CFGBlock::ConstCFGElementRef ConstCFGElementRef
@ Type
The name was classified as a type.
U cast(CodeGen::Address addr)
static ContainerData fromEnd(SymbolRef E)
static ContainerData fromBegin(SymbolRef B)
static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of)