xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
1*480093f4SDimitry Andric //=== Iterator.cpp - Common functions for iterator checkers. -------*- C++ -*-//
2*480093f4SDimitry Andric //
3*480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*480093f4SDimitry Andric //
7*480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8*480093f4SDimitry Andric //
9*480093f4SDimitry Andric // Defines common functions to be used by the itertor checkers .
10*480093f4SDimitry Andric //
11*480093f4SDimitry Andric //===----------------------------------------------------------------------===//
12*480093f4SDimitry Andric 
13*480093f4SDimitry Andric #include "Iterator.h"
14*480093f4SDimitry Andric 
15*480093f4SDimitry Andric namespace clang {
16*480093f4SDimitry Andric namespace ento {
17*480093f4SDimitry Andric namespace iterator {
18*480093f4SDimitry Andric 
19*480093f4SDimitry Andric bool isIteratorType(const QualType &Type) {
20*480093f4SDimitry Andric   if (Type->isPointerType())
21*480093f4SDimitry Andric     return true;
22*480093f4SDimitry Andric 
23*480093f4SDimitry Andric   const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
24*480093f4SDimitry Andric   return isIterator(CRD);
25*480093f4SDimitry Andric }
26*480093f4SDimitry Andric 
27*480093f4SDimitry Andric bool isIterator(const CXXRecordDecl *CRD) {
28*480093f4SDimitry Andric   if (!CRD)
29*480093f4SDimitry Andric     return false;
30*480093f4SDimitry Andric 
31*480093f4SDimitry Andric   const auto Name = CRD->getName();
32*480093f4SDimitry Andric   if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") ||
33*480093f4SDimitry Andric         Name.endswith_lower("it")))
34*480093f4SDimitry Andric     return false;
35*480093f4SDimitry Andric 
36*480093f4SDimitry Andric   bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
37*480093f4SDimitry Andric        HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
38*480093f4SDimitry Andric   for (const auto *Method : CRD->methods()) {
39*480093f4SDimitry Andric     if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
40*480093f4SDimitry Andric       if (Ctor->isCopyConstructor()) {
41*480093f4SDimitry Andric         HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
42*480093f4SDimitry Andric       }
43*480093f4SDimitry Andric       continue;
44*480093f4SDimitry Andric     }
45*480093f4SDimitry Andric     if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
46*480093f4SDimitry Andric       HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
47*480093f4SDimitry Andric       continue;
48*480093f4SDimitry Andric     }
49*480093f4SDimitry Andric     if (Method->isCopyAssignmentOperator()) {
50*480093f4SDimitry Andric       HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
51*480093f4SDimitry Andric       continue;
52*480093f4SDimitry Andric     }
53*480093f4SDimitry Andric     if (!Method->isOverloadedOperator())
54*480093f4SDimitry Andric       continue;
55*480093f4SDimitry Andric     const auto OPK = Method->getOverloadedOperator();
56*480093f4SDimitry Andric     if (OPK == OO_PlusPlus) {
57*480093f4SDimitry Andric       HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
58*480093f4SDimitry Andric       HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
59*480093f4SDimitry Andric       continue;
60*480093f4SDimitry Andric     }
61*480093f4SDimitry Andric     if (OPK == OO_Star) {
62*480093f4SDimitry Andric       HasDerefOp = (Method->getNumParams() == 0);
63*480093f4SDimitry Andric       continue;
64*480093f4SDimitry Andric     }
65*480093f4SDimitry Andric   }
66*480093f4SDimitry Andric 
67*480093f4SDimitry Andric   return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
68*480093f4SDimitry Andric          HasPostIncrOp && HasDerefOp;
69*480093f4SDimitry Andric }
70*480093f4SDimitry Andric 
71*480093f4SDimitry Andric bool isComparisonOperator(OverloadedOperatorKind OK) {
72*480093f4SDimitry Andric   return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less ||
73*480093f4SDimitry Andric          OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual;
74*480093f4SDimitry Andric }
75*480093f4SDimitry Andric 
76*480093f4SDimitry Andric bool isInsertCall(const FunctionDecl *Func) {
77*480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
78*480093f4SDimitry Andric   if (!IdInfo)
79*480093f4SDimitry Andric     return false;
80*480093f4SDimitry Andric   if (Func->getNumParams() < 2 || Func->getNumParams() > 3)
81*480093f4SDimitry Andric     return false;
82*480093f4SDimitry Andric   if (!isIteratorType(Func->getParamDecl(0)->getType()))
83*480093f4SDimitry Andric     return false;
84*480093f4SDimitry Andric   return IdInfo->getName() == "insert";
85*480093f4SDimitry Andric }
86*480093f4SDimitry Andric 
87*480093f4SDimitry Andric bool isEmplaceCall(const FunctionDecl *Func) {
88*480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
89*480093f4SDimitry Andric   if (!IdInfo)
90*480093f4SDimitry Andric     return false;
91*480093f4SDimitry Andric   if (Func->getNumParams() < 2)
92*480093f4SDimitry Andric     return false;
93*480093f4SDimitry Andric   if (!isIteratorType(Func->getParamDecl(0)->getType()))
94*480093f4SDimitry Andric     return false;
95*480093f4SDimitry Andric   return IdInfo->getName() == "emplace";
96*480093f4SDimitry Andric }
97*480093f4SDimitry Andric 
98*480093f4SDimitry Andric bool isEraseCall(const FunctionDecl *Func) {
99*480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
100*480093f4SDimitry Andric   if (!IdInfo)
101*480093f4SDimitry Andric     return false;
102*480093f4SDimitry Andric   if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
103*480093f4SDimitry Andric     return false;
104*480093f4SDimitry Andric   if (!isIteratorType(Func->getParamDecl(0)->getType()))
105*480093f4SDimitry Andric     return false;
106*480093f4SDimitry Andric   if (Func->getNumParams() == 2 &&
107*480093f4SDimitry Andric       !isIteratorType(Func->getParamDecl(1)->getType()))
108*480093f4SDimitry Andric     return false;
109*480093f4SDimitry Andric   return IdInfo->getName() == "erase";
110*480093f4SDimitry Andric }
111*480093f4SDimitry Andric 
112*480093f4SDimitry Andric bool isEraseAfterCall(const FunctionDecl *Func) {
113*480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
114*480093f4SDimitry Andric   if (!IdInfo)
115*480093f4SDimitry Andric     return false;
116*480093f4SDimitry Andric   if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
117*480093f4SDimitry Andric     return false;
118*480093f4SDimitry Andric   if (!isIteratorType(Func->getParamDecl(0)->getType()))
119*480093f4SDimitry Andric     return false;
120*480093f4SDimitry Andric   if (Func->getNumParams() == 2 &&
121*480093f4SDimitry Andric       !isIteratorType(Func->getParamDecl(1)->getType()))
122*480093f4SDimitry Andric     return false;
123*480093f4SDimitry Andric   return IdInfo->getName() == "erase_after";
124*480093f4SDimitry Andric }
125*480093f4SDimitry Andric 
126*480093f4SDimitry Andric bool isAccessOperator(OverloadedOperatorKind OK) {
127*480093f4SDimitry Andric   return isDereferenceOperator(OK) || isIncrementOperator(OK) ||
128*480093f4SDimitry Andric          isDecrementOperator(OK) || isRandomIncrOrDecrOperator(OK);
129*480093f4SDimitry Andric }
130*480093f4SDimitry Andric 
131*480093f4SDimitry Andric bool isDereferenceOperator(OverloadedOperatorKind OK) {
132*480093f4SDimitry Andric   return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
133*480093f4SDimitry Andric          OK == OO_Subscript;
134*480093f4SDimitry Andric }
135*480093f4SDimitry Andric 
136*480093f4SDimitry Andric bool isIncrementOperator(OverloadedOperatorKind OK) {
137*480093f4SDimitry Andric   return OK == OO_PlusPlus;
138*480093f4SDimitry Andric }
139*480093f4SDimitry Andric 
140*480093f4SDimitry Andric bool isDecrementOperator(OverloadedOperatorKind OK) {
141*480093f4SDimitry Andric   return OK == OO_MinusMinus;
142*480093f4SDimitry Andric }
143*480093f4SDimitry Andric 
144*480093f4SDimitry Andric bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK) {
145*480093f4SDimitry Andric   return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus ||
146*480093f4SDimitry Andric          OK == OO_MinusEqual;
147*480093f4SDimitry Andric }
148*480093f4SDimitry Andric 
149*480093f4SDimitry Andric const ContainerData *getContainerData(ProgramStateRef State,
150*480093f4SDimitry Andric                                       const MemRegion *Cont) {
151*480093f4SDimitry Andric   return State->get<ContainerMap>(Cont);
152*480093f4SDimitry Andric }
153*480093f4SDimitry Andric 
154*480093f4SDimitry Andric const IteratorPosition *getIteratorPosition(ProgramStateRef State,
155*480093f4SDimitry Andric                                             const SVal &Val) {
156*480093f4SDimitry Andric   if (auto Reg = Val.getAsRegion()) {
157*480093f4SDimitry Andric     Reg = Reg->getMostDerivedObjectRegion();
158*480093f4SDimitry Andric     return State->get<IteratorRegionMap>(Reg);
159*480093f4SDimitry Andric   } else if (const auto Sym = Val.getAsSymbol()) {
160*480093f4SDimitry Andric     return State->get<IteratorSymbolMap>(Sym);
161*480093f4SDimitry Andric   } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
162*480093f4SDimitry Andric     return State->get<IteratorRegionMap>(LCVal->getRegion());
163*480093f4SDimitry Andric   }
164*480093f4SDimitry Andric   return nullptr;
165*480093f4SDimitry Andric }
166*480093f4SDimitry Andric 
167*480093f4SDimitry Andric ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
168*480093f4SDimitry Andric                                     const IteratorPosition &Pos) {
169*480093f4SDimitry Andric   if (auto Reg = Val.getAsRegion()) {
170*480093f4SDimitry Andric     Reg = Reg->getMostDerivedObjectRegion();
171*480093f4SDimitry Andric     return State->set<IteratorRegionMap>(Reg, Pos);
172*480093f4SDimitry Andric   } else if (const auto Sym = Val.getAsSymbol()) {
173*480093f4SDimitry Andric     return State->set<IteratorSymbolMap>(Sym, Pos);
174*480093f4SDimitry Andric   } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
175*480093f4SDimitry Andric     return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
176*480093f4SDimitry Andric   }
177*480093f4SDimitry Andric   return nullptr;
178*480093f4SDimitry Andric }
179*480093f4SDimitry Andric 
180*480093f4SDimitry Andric ProgramStateRef advancePosition(ProgramStateRef State, const SVal &Iter,
181*480093f4SDimitry Andric                                 OverloadedOperatorKind Op,
182*480093f4SDimitry Andric                                 const SVal &Distance) {
183*480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, Iter);
184*480093f4SDimitry Andric   if (!Pos)
185*480093f4SDimitry Andric     return nullptr;
186*480093f4SDimitry Andric 
187*480093f4SDimitry Andric   auto &SymMgr = State->getStateManager().getSymbolManager();
188*480093f4SDimitry Andric   auto &SVB = State->getStateManager().getSValBuilder();
189*480093f4SDimitry Andric 
190*480093f4SDimitry Andric   assert ((Op == OO_Plus || Op == OO_PlusEqual ||
191*480093f4SDimitry Andric            Op == OO_Minus || Op == OO_MinusEqual) &&
192*480093f4SDimitry Andric           "Advance operator must be one of +, -, += and -=.");
193*480093f4SDimitry Andric   auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
194*480093f4SDimitry Andric   if (const auto IntDist = Distance.getAs<nonloc::ConcreteInt>()) {
195*480093f4SDimitry Andric     // For concrete integers we can calculate the new position
196*480093f4SDimitry Andric     const auto NewPos =
197*480093f4SDimitry Andric       Pos->setTo(SVB.evalBinOp(State, BinOp,
198*480093f4SDimitry Andric                                nonloc::SymbolVal(Pos->getOffset()),
199*480093f4SDimitry Andric                                *IntDist, SymMgr.getType(Pos->getOffset()))
200*480093f4SDimitry Andric                  .getAsSymbol());
201*480093f4SDimitry Andric     return setIteratorPosition(State, Iter, NewPos);
202*480093f4SDimitry Andric   }
203*480093f4SDimitry Andric 
204*480093f4SDimitry Andric   return nullptr;
205*480093f4SDimitry Andric }
206*480093f4SDimitry Andric 
207*480093f4SDimitry Andric bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
208*480093f4SDimitry Andric              BinaryOperator::Opcode Opc) {
209*480093f4SDimitry Andric   return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc);
210*480093f4SDimitry Andric }
211*480093f4SDimitry Andric 
212*480093f4SDimitry Andric bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
213*480093f4SDimitry Andric              BinaryOperator::Opcode Opc) {
214*480093f4SDimitry Andric   auto &SVB = State->getStateManager().getSValBuilder();
215*480093f4SDimitry Andric 
216*480093f4SDimitry Andric   const auto comparison =
217*480093f4SDimitry Andric     SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType());
218*480093f4SDimitry Andric 
219*480093f4SDimitry Andric   assert(comparison.getAs<DefinedSVal>() &&
220*480093f4SDimitry Andric     "Symbol comparison must be a `DefinedSVal`");
221*480093f4SDimitry Andric 
222*480093f4SDimitry Andric   return !State->assume(comparison.castAs<DefinedSVal>(), false);
223*480093f4SDimitry Andric }
224*480093f4SDimitry Andric 
225*480093f4SDimitry Andric } // namespace iterator
226*480093f4SDimitry Andric } // namespace ento
227*480093f4SDimitry Andric } // namespace clang
228