1afb13afcSAdam Balogh //=== Iterator.cpp - Common functions for iterator checkers. -------*- C++ -*-//
2afb13afcSAdam Balogh //
3afb13afcSAdam Balogh // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4afb13afcSAdam Balogh // See https://llvm.org/LICENSE.txt for license information.
5afb13afcSAdam Balogh // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6afb13afcSAdam Balogh //
7afb13afcSAdam Balogh //===----------------------------------------------------------------------===//
8afb13afcSAdam Balogh //
9afb13afcSAdam Balogh // Defines common functions to be used by the itertor checkers .
10afb13afcSAdam Balogh //
11afb13afcSAdam Balogh //===----------------------------------------------------------------------===//
12afb13afcSAdam Balogh 
13afb13afcSAdam Balogh #include "Iterator.h"
14afb13afcSAdam Balogh 
15afb13afcSAdam Balogh namespace clang {
16afb13afcSAdam Balogh namespace ento {
17afb13afcSAdam Balogh namespace iterator {
18afb13afcSAdam Balogh 
isIteratorType(const QualType & Type)19afb13afcSAdam Balogh bool isIteratorType(const QualType &Type) {
20afb13afcSAdam Balogh   if (Type->isPointerType())
21afb13afcSAdam Balogh     return true;
22afb13afcSAdam Balogh 
23afb13afcSAdam Balogh   const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
24afb13afcSAdam Balogh   return isIterator(CRD);
25afb13afcSAdam Balogh }
26afb13afcSAdam Balogh 
isIterator(const CXXRecordDecl * CRD)27afb13afcSAdam Balogh bool isIterator(const CXXRecordDecl *CRD) {
28afb13afcSAdam Balogh   if (!CRD)
29afb13afcSAdam Balogh     return false;
30afb13afcSAdam Balogh 
31afb13afcSAdam Balogh   const auto Name = CRD->getName();
32e5c7c171SMartin Storsjö   if (!(Name.endswith_insensitive("iterator") ||
33e5c7c171SMartin Storsjö         Name.endswith_insensitive("iter") || Name.endswith_insensitive("it")))
34afb13afcSAdam Balogh     return false;
35afb13afcSAdam Balogh 
36afb13afcSAdam Balogh   bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
37afb13afcSAdam Balogh        HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
38afb13afcSAdam Balogh   for (const auto *Method : CRD->methods()) {
39afb13afcSAdam Balogh     if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
40afb13afcSAdam Balogh       if (Ctor->isCopyConstructor()) {
41afb13afcSAdam Balogh         HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
42afb13afcSAdam Balogh       }
43afb13afcSAdam Balogh       continue;
44afb13afcSAdam Balogh     }
45afb13afcSAdam Balogh     if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
46afb13afcSAdam Balogh       HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
47afb13afcSAdam Balogh       continue;
48afb13afcSAdam Balogh     }
49afb13afcSAdam Balogh     if (Method->isCopyAssignmentOperator()) {
50afb13afcSAdam Balogh       HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
51afb13afcSAdam Balogh       continue;
52afb13afcSAdam Balogh     }
53afb13afcSAdam Balogh     if (!Method->isOverloadedOperator())
54afb13afcSAdam Balogh       continue;
55afb13afcSAdam Balogh     const auto OPK = Method->getOverloadedOperator();
56afb13afcSAdam Balogh     if (OPK == OO_PlusPlus) {
57afb13afcSAdam Balogh       HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
58afb13afcSAdam Balogh       HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
59afb13afcSAdam Balogh       continue;
60afb13afcSAdam Balogh     }
61afb13afcSAdam Balogh     if (OPK == OO_Star) {
62afb13afcSAdam Balogh       HasDerefOp = (Method->getNumParams() == 0);
63afb13afcSAdam Balogh       continue;
64afb13afcSAdam Balogh     }
65afb13afcSAdam Balogh   }
66afb13afcSAdam Balogh 
67afb13afcSAdam Balogh   return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
68afb13afcSAdam Balogh          HasPostIncrOp && HasDerefOp;
69afb13afcSAdam Balogh }
70afb13afcSAdam Balogh 
isComparisonOperator(OverloadedOperatorKind OK)71afb13afcSAdam Balogh bool isComparisonOperator(OverloadedOperatorKind OK) {
72afb13afcSAdam Balogh   return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less ||
73afb13afcSAdam Balogh          OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual;
74afb13afcSAdam Balogh }
75afb13afcSAdam Balogh 
isInsertCall(const FunctionDecl * Func)76afb13afcSAdam Balogh bool isInsertCall(const FunctionDecl *Func) {
77afb13afcSAdam Balogh   const auto *IdInfo = Func->getIdentifier();
78afb13afcSAdam Balogh   if (!IdInfo)
79afb13afcSAdam Balogh     return false;
80afb13afcSAdam Balogh   if (Func->getNumParams() < 2 || Func->getNumParams() > 3)
81afb13afcSAdam Balogh     return false;
82afb13afcSAdam Balogh   if (!isIteratorType(Func->getParamDecl(0)->getType()))
83afb13afcSAdam Balogh     return false;
84afb13afcSAdam Balogh   return IdInfo->getName() == "insert";
85afb13afcSAdam Balogh }
86afb13afcSAdam Balogh 
isEmplaceCall(const FunctionDecl * Func)87afb13afcSAdam Balogh bool isEmplaceCall(const FunctionDecl *Func) {
88afb13afcSAdam Balogh   const auto *IdInfo = Func->getIdentifier();
89afb13afcSAdam Balogh   if (!IdInfo)
90afb13afcSAdam Balogh     return false;
91afb13afcSAdam Balogh   if (Func->getNumParams() < 2)
92afb13afcSAdam Balogh     return false;
93afb13afcSAdam Balogh   if (!isIteratorType(Func->getParamDecl(0)->getType()))
94afb13afcSAdam Balogh     return false;
95afb13afcSAdam Balogh   return IdInfo->getName() == "emplace";
96afb13afcSAdam Balogh }
97afb13afcSAdam Balogh 
isEraseCall(const FunctionDecl * Func)98afb13afcSAdam Balogh bool isEraseCall(const FunctionDecl *Func) {
99afb13afcSAdam Balogh   const auto *IdInfo = Func->getIdentifier();
100afb13afcSAdam Balogh   if (!IdInfo)
101afb13afcSAdam Balogh     return false;
102afb13afcSAdam Balogh   if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
103afb13afcSAdam Balogh     return false;
104afb13afcSAdam Balogh   if (!isIteratorType(Func->getParamDecl(0)->getType()))
105afb13afcSAdam Balogh     return false;
106afb13afcSAdam Balogh   if (Func->getNumParams() == 2 &&
107afb13afcSAdam Balogh       !isIteratorType(Func->getParamDecl(1)->getType()))
108afb13afcSAdam Balogh     return false;
109afb13afcSAdam Balogh   return IdInfo->getName() == "erase";
110afb13afcSAdam Balogh }
111afb13afcSAdam Balogh 
isEraseAfterCall(const FunctionDecl * Func)112afb13afcSAdam Balogh bool isEraseAfterCall(const FunctionDecl *Func) {
113afb13afcSAdam Balogh   const auto *IdInfo = Func->getIdentifier();
114afb13afcSAdam Balogh   if (!IdInfo)
115afb13afcSAdam Balogh     return false;
116afb13afcSAdam Balogh   if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
117afb13afcSAdam Balogh     return false;
118afb13afcSAdam Balogh   if (!isIteratorType(Func->getParamDecl(0)->getType()))
119afb13afcSAdam Balogh     return false;
120afb13afcSAdam Balogh   if (Func->getNumParams() == 2 &&
121afb13afcSAdam Balogh       !isIteratorType(Func->getParamDecl(1)->getType()))
122afb13afcSAdam Balogh     return false;
123afb13afcSAdam Balogh   return IdInfo->getName() == "erase_after";
124afb13afcSAdam Balogh }
125afb13afcSAdam Balogh 
isAccessOperator(OverloadedOperatorKind OK)126afb13afcSAdam Balogh bool isAccessOperator(OverloadedOperatorKind OK) {
127afb13afcSAdam Balogh   return isDereferenceOperator(OK) || isIncrementOperator(OK) ||
128afb13afcSAdam Balogh          isDecrementOperator(OK) || isRandomIncrOrDecrOperator(OK);
129afb13afcSAdam Balogh }
130afb13afcSAdam Balogh 
isAccessOperator(UnaryOperatorKind OK)1319e63b190SAdam Balogh bool isAccessOperator(UnaryOperatorKind OK) {
1329e63b190SAdam Balogh   return isDereferenceOperator(OK) || isIncrementOperator(OK) ||
1339e63b190SAdam Balogh          isDecrementOperator(OK);
1349e63b190SAdam Balogh }
1359e63b190SAdam Balogh 
isAccessOperator(BinaryOperatorKind OK)1369e63b190SAdam Balogh bool isAccessOperator(BinaryOperatorKind OK) {
1379e63b190SAdam Balogh   return isDereferenceOperator(OK) || isRandomIncrOrDecrOperator(OK);
1389e63b190SAdam Balogh }
1399e63b190SAdam Balogh 
isDereferenceOperator(OverloadedOperatorKind OK)140afb13afcSAdam Balogh bool isDereferenceOperator(OverloadedOperatorKind OK) {
141afb13afcSAdam Balogh   return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
142afb13afcSAdam Balogh          OK == OO_Subscript;
143afb13afcSAdam Balogh }
144afb13afcSAdam Balogh 
isDereferenceOperator(UnaryOperatorKind OK)1459e63b190SAdam Balogh bool isDereferenceOperator(UnaryOperatorKind OK) {
1469e63b190SAdam Balogh   return OK == UO_Deref;
1479e63b190SAdam Balogh }
1489e63b190SAdam Balogh 
isDereferenceOperator(BinaryOperatorKind OK)1499e63b190SAdam Balogh bool isDereferenceOperator(BinaryOperatorKind OK) {
1509e63b190SAdam Balogh   return OK == BO_PtrMemI;
1519e63b190SAdam Balogh }
1529e63b190SAdam Balogh 
isIncrementOperator(OverloadedOperatorKind OK)153afb13afcSAdam Balogh bool isIncrementOperator(OverloadedOperatorKind OK) {
154afb13afcSAdam Balogh   return OK == OO_PlusPlus;
155afb13afcSAdam Balogh }
156afb13afcSAdam Balogh 
isIncrementOperator(UnaryOperatorKind OK)1579e63b190SAdam Balogh bool isIncrementOperator(UnaryOperatorKind OK) {
1589e63b190SAdam Balogh   return OK == UO_PreInc || OK == UO_PostInc;
1599e63b190SAdam Balogh }
1609e63b190SAdam Balogh 
isDecrementOperator(OverloadedOperatorKind OK)161afb13afcSAdam Balogh bool isDecrementOperator(OverloadedOperatorKind OK) {
162afb13afcSAdam Balogh   return OK == OO_MinusMinus;
163afb13afcSAdam Balogh }
164afb13afcSAdam Balogh 
isDecrementOperator(UnaryOperatorKind OK)1659e63b190SAdam Balogh bool isDecrementOperator(UnaryOperatorKind OK) {
1669e63b190SAdam Balogh   return OK == UO_PreDec || OK == UO_PostDec;
1679e63b190SAdam Balogh }
1689e63b190SAdam Balogh 
isRandomIncrOrDecrOperator(OverloadedOperatorKind OK)169afb13afcSAdam Balogh bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK) {
170afb13afcSAdam Balogh   return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus ||
171afb13afcSAdam Balogh          OK == OO_MinusEqual;
172afb13afcSAdam Balogh }
173afb13afcSAdam Balogh 
isRandomIncrOrDecrOperator(BinaryOperatorKind OK)1749e63b190SAdam Balogh bool isRandomIncrOrDecrOperator(BinaryOperatorKind OK) {
1759e63b190SAdam Balogh   return OK == BO_Add || OK == BO_AddAssign ||
1769e63b190SAdam Balogh          OK == BO_Sub || OK == BO_SubAssign;
1779e63b190SAdam Balogh }
1789e63b190SAdam Balogh 
getContainerData(ProgramStateRef State,const MemRegion * Cont)179afb13afcSAdam Balogh const ContainerData *getContainerData(ProgramStateRef State,
180afb13afcSAdam Balogh                                       const MemRegion *Cont) {
181afb13afcSAdam Balogh   return State->get<ContainerMap>(Cont);
182afb13afcSAdam Balogh }
183afb13afcSAdam Balogh 
getIteratorPosition(ProgramStateRef State,const SVal & Val)184afb13afcSAdam Balogh const IteratorPosition *getIteratorPosition(ProgramStateRef State,
185afb13afcSAdam Balogh                                             const SVal &Val) {
186afb13afcSAdam Balogh   if (auto Reg = Val.getAsRegion()) {
187afb13afcSAdam Balogh     Reg = Reg->getMostDerivedObjectRegion();
188afb13afcSAdam Balogh     return State->get<IteratorRegionMap>(Reg);
189afb13afcSAdam Balogh   } else if (const auto Sym = Val.getAsSymbol()) {
190afb13afcSAdam Balogh     return State->get<IteratorSymbolMap>(Sym);
191afb13afcSAdam Balogh   } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
192afb13afcSAdam Balogh     return State->get<IteratorRegionMap>(LCVal->getRegion());
193afb13afcSAdam Balogh   }
194afb13afcSAdam Balogh   return nullptr;
195afb13afcSAdam Balogh }
196afb13afcSAdam Balogh 
setIteratorPosition(ProgramStateRef State,const SVal & Val,const IteratorPosition & Pos)197afb13afcSAdam Balogh ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
198afb13afcSAdam Balogh                                     const IteratorPosition &Pos) {
199afb13afcSAdam Balogh   if (auto Reg = Val.getAsRegion()) {
200afb13afcSAdam Balogh     Reg = Reg->getMostDerivedObjectRegion();
201afb13afcSAdam Balogh     return State->set<IteratorRegionMap>(Reg, Pos);
202afb13afcSAdam Balogh   } else if (const auto Sym = Val.getAsSymbol()) {
203afb13afcSAdam Balogh     return State->set<IteratorSymbolMap>(Sym, Pos);
204afb13afcSAdam Balogh   } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
205afb13afcSAdam Balogh     return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
206afb13afcSAdam Balogh   }
207afb13afcSAdam Balogh   return nullptr;
208afb13afcSAdam Balogh }
209afb13afcSAdam Balogh 
createIteratorPosition(ProgramStateRef State,const SVal & Val,const MemRegion * Cont,const Stmt * S,const LocationContext * LCtx,unsigned blockCount)210b198f16eSAdam Balogh ProgramStateRef createIteratorPosition(ProgramStateRef State, const SVal &Val,
211b198f16eSAdam Balogh                                        const MemRegion *Cont, const Stmt* S,
212b198f16eSAdam Balogh                                        const LocationContext *LCtx,
213b198f16eSAdam Balogh                                        unsigned blockCount) {
214b198f16eSAdam Balogh   auto &StateMgr = State->getStateManager();
215b198f16eSAdam Balogh   auto &SymMgr = StateMgr.getSymbolManager();
216b198f16eSAdam Balogh   auto &ACtx = StateMgr.getContext();
217b198f16eSAdam Balogh 
218b198f16eSAdam Balogh   auto Sym = SymMgr.conjureSymbol(S, LCtx, ACtx.LongTy, blockCount);
219b198f16eSAdam Balogh   State = assumeNoOverflow(State, Sym, 4);
220b198f16eSAdam Balogh   return setIteratorPosition(State, Val,
221b198f16eSAdam Balogh                              IteratorPosition::getPosition(Cont, Sym));
222b198f16eSAdam Balogh }
223b198f16eSAdam Balogh 
advancePosition(ProgramStateRef State,const SVal & Iter,OverloadedOperatorKind Op,const SVal & Distance)224afb13afcSAdam Balogh ProgramStateRef advancePosition(ProgramStateRef State, const SVal &Iter,
225afb13afcSAdam Balogh                                 OverloadedOperatorKind Op,
226afb13afcSAdam Balogh                                 const SVal &Distance) {
227afb13afcSAdam Balogh   const auto *Pos = getIteratorPosition(State, Iter);
228afb13afcSAdam Balogh   if (!Pos)
229afb13afcSAdam Balogh     return nullptr;
230afb13afcSAdam Balogh 
231afb13afcSAdam Balogh   auto &SymMgr = State->getStateManager().getSymbolManager();
232afb13afcSAdam Balogh   auto &SVB = State->getStateManager().getSValBuilder();
233770ad9f5SAdam Balogh   auto &BVF = State->getStateManager().getBasicVals();
234afb13afcSAdam Balogh 
235afb13afcSAdam Balogh   assert ((Op == OO_Plus || Op == OO_PlusEqual ||
236afb13afcSAdam Balogh            Op == OO_Minus || Op == OO_MinusEqual) &&
237afb13afcSAdam Balogh           "Advance operator must be one of +, -, += and -=.");
238afb13afcSAdam Balogh   auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
239770ad9f5SAdam Balogh   const auto IntDistOp = Distance.getAs<nonloc::ConcreteInt>();
240770ad9f5SAdam Balogh   if (!IntDistOp)
241770ad9f5SAdam Balogh     return nullptr;
242770ad9f5SAdam Balogh 
243afb13afcSAdam Balogh   // For concrete integers we can calculate the new position
244770ad9f5SAdam Balogh   nonloc::ConcreteInt IntDist = *IntDistOp;
245770ad9f5SAdam Balogh 
246770ad9f5SAdam Balogh   if (IntDist.getValue().isNegative()) {
247770ad9f5SAdam Balogh     IntDist = nonloc::ConcreteInt(BVF.getValue(-IntDist.getValue()));
248770ad9f5SAdam Balogh     BinOp = (BinOp == BO_Add) ? BO_Sub : BO_Add;
249770ad9f5SAdam Balogh   }
250afb13afcSAdam Balogh   const auto NewPos =
251afb13afcSAdam Balogh     Pos->setTo(SVB.evalBinOp(State, BinOp,
252afb13afcSAdam Balogh                              nonloc::SymbolVal(Pos->getOffset()),
253770ad9f5SAdam Balogh                              IntDist, SymMgr.getType(Pos->getOffset()))
254afb13afcSAdam Balogh                .getAsSymbol());
255afb13afcSAdam Balogh   return setIteratorPosition(State, Iter, NewPos);
256afb13afcSAdam Balogh }
257afb13afcSAdam Balogh 
2589a08a3faSAdam Balogh // This function tells the analyzer's engine that symbols produced by our
2599a08a3faSAdam Balogh // checker, most notably iterator positions, are relatively small.
2609a08a3faSAdam Balogh // A distance between items in the container should not be very large.
2619a08a3faSAdam Balogh // By assuming that it is within around 1/8 of the address space,
2629a08a3faSAdam Balogh // we can help the analyzer perform operations on these symbols
2639a08a3faSAdam Balogh // without being afraid of integer overflows.
2649a08a3faSAdam Balogh // FIXME: Should we provide it as an API, so that all checkers could use it?
assumeNoOverflow(ProgramStateRef State,SymbolRef Sym,long Scale)2659a08a3faSAdam Balogh ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
2669a08a3faSAdam Balogh                                  long Scale) {
2679a08a3faSAdam Balogh   SValBuilder &SVB = State->getStateManager().getSValBuilder();
2689a08a3faSAdam Balogh   BasicValueFactory &BV = SVB.getBasicValueFactory();
2699a08a3faSAdam Balogh 
2709a08a3faSAdam Balogh   QualType T = Sym->getType();
2719a08a3faSAdam Balogh   assert(T->isSignedIntegerOrEnumerationType());
2729a08a3faSAdam Balogh   APSIntType AT = BV.getAPSIntType(T);
2739a08a3faSAdam Balogh 
2749a08a3faSAdam Balogh   ProgramStateRef NewState = State;
2759a08a3faSAdam Balogh 
2769a08a3faSAdam Balogh   llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale);
2779a08a3faSAdam Balogh   SVal IsCappedFromAbove =
2789a08a3faSAdam Balogh       SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym),
2799a08a3faSAdam Balogh                       nonloc::ConcreteInt(Max), SVB.getConditionType());
2809a08a3faSAdam Balogh   if (auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) {
2819a08a3faSAdam Balogh     NewState = NewState->assume(*DV, true);
2829a08a3faSAdam Balogh     if (!NewState)
2839a08a3faSAdam Balogh       return State;
2849a08a3faSAdam Balogh   }
2859a08a3faSAdam Balogh 
2869a08a3faSAdam Balogh   llvm::APSInt Min = -Max;
2879a08a3faSAdam Balogh   SVal IsCappedFromBelow =
2889a08a3faSAdam Balogh       SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym),
2899a08a3faSAdam Balogh                       nonloc::ConcreteInt(Min), SVB.getConditionType());
2909a08a3faSAdam Balogh   if (auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) {
2919a08a3faSAdam Balogh     NewState = NewState->assume(*DV, true);
2929a08a3faSAdam Balogh     if (!NewState)
2939a08a3faSAdam Balogh       return State;
2949a08a3faSAdam Balogh   }
2959a08a3faSAdam Balogh 
2969a08a3faSAdam Balogh   return NewState;
2979a08a3faSAdam Balogh }
2989a08a3faSAdam Balogh 
compare(ProgramStateRef State,SymbolRef Sym1,SymbolRef Sym2,BinaryOperator::Opcode Opc)299afb13afcSAdam Balogh bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
300afb13afcSAdam Balogh              BinaryOperator::Opcode Opc) {
301afb13afcSAdam Balogh   return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc);
302afb13afcSAdam Balogh }
303afb13afcSAdam Balogh 
compare(ProgramStateRef State,NonLoc NL1,NonLoc NL2,BinaryOperator::Opcode Opc)304afb13afcSAdam Balogh bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
305afb13afcSAdam Balogh              BinaryOperator::Opcode Opc) {
306afb13afcSAdam Balogh   auto &SVB = State->getStateManager().getSValBuilder();
307afb13afcSAdam Balogh 
308afb13afcSAdam Balogh   const auto comparison =
309afb13afcSAdam Balogh     SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType());
310afb13afcSAdam Balogh 
311*96ccb690SBalazs Benics   assert(isa<DefinedSVal>(comparison) &&
312afb13afcSAdam Balogh          "Symbol comparison must be a `DefinedSVal`");
313afb13afcSAdam Balogh 
314afb13afcSAdam Balogh   return !State->assume(comparison.castAs<DefinedSVal>(), false);
315afb13afcSAdam Balogh }
316afb13afcSAdam Balogh 
317afb13afcSAdam Balogh } // namespace iterator
318afb13afcSAdam Balogh } // namespace ento
319afb13afcSAdam Balogh } // namespace clang
320