xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/Iterator.h (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1480093f4SDimitry Andric //=== Iterator.h - Common functions for iterator checkers. ---------*- C++ -*-//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric //
9480093f4SDimitry Andric // Defines common functions to be used by the itertor checkers .
10480093f4SDimitry Andric //
11480093f4SDimitry Andric //===----------------------------------------------------------------------===//
12480093f4SDimitry Andric 
13480093f4SDimitry Andric #ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_ITERATOR_H
14480093f4SDimitry Andric #define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_ITERATOR_H
15480093f4SDimitry Andric 
16480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
17480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
18480093f4SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
19480093f4SDimitry Andric 
20480093f4SDimitry Andric namespace clang {
21480093f4SDimitry Andric namespace ento {
22480093f4SDimitry Andric namespace iterator {
23480093f4SDimitry Andric 
24480093f4SDimitry Andric // Abstract position of an iterator. This helps to handle all three kinds
25480093f4SDimitry Andric // of operators in a common way by using a symbolic position.
26480093f4SDimitry Andric struct IteratorPosition {
27480093f4SDimitry Andric private:
28480093f4SDimitry Andric 
29480093f4SDimitry Andric   // Container the iterator belongs to
30480093f4SDimitry Andric   const MemRegion *Cont;
31480093f4SDimitry Andric 
32480093f4SDimitry Andric   // Whether iterator is valid
33480093f4SDimitry Andric   const bool Valid;
34480093f4SDimitry Andric 
35480093f4SDimitry Andric   // Abstract offset
36480093f4SDimitry Andric   const SymbolRef Offset;
37480093f4SDimitry Andric 
38480093f4SDimitry Andric   IteratorPosition(const MemRegion *C, bool V, SymbolRef Of)
39480093f4SDimitry Andric       : Cont(C), Valid(V), Offset(Of) {}
40480093f4SDimitry Andric 
41480093f4SDimitry Andric public:
42480093f4SDimitry Andric   const MemRegion *getContainer() const { return Cont; }
43480093f4SDimitry Andric   bool isValid() const { return Valid; }
44480093f4SDimitry Andric   SymbolRef getOffset() const { return Offset; }
45480093f4SDimitry Andric 
46480093f4SDimitry Andric   IteratorPosition invalidate() const {
47480093f4SDimitry Andric     return IteratorPosition(Cont, false, Offset);
48480093f4SDimitry Andric   }
49480093f4SDimitry Andric 
50480093f4SDimitry Andric   static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of) {
51480093f4SDimitry Andric     return IteratorPosition(C, true, Of);
52480093f4SDimitry Andric   }
53480093f4SDimitry Andric 
54480093f4SDimitry Andric   IteratorPosition setTo(SymbolRef NewOf) const {
55480093f4SDimitry Andric     return IteratorPosition(Cont, Valid, NewOf);
56480093f4SDimitry Andric   }
57480093f4SDimitry Andric 
58480093f4SDimitry Andric   IteratorPosition reAssign(const MemRegion *NewCont) const {
59480093f4SDimitry Andric     return IteratorPosition(NewCont, Valid, Offset);
60480093f4SDimitry Andric   }
61480093f4SDimitry Andric 
62480093f4SDimitry Andric   bool operator==(const IteratorPosition &X) const {
63480093f4SDimitry Andric     return Cont == X.Cont && Valid == X.Valid && Offset == X.Offset;
64480093f4SDimitry Andric   }
65480093f4SDimitry Andric 
66480093f4SDimitry Andric   bool operator!=(const IteratorPosition &X) const {
67480093f4SDimitry Andric     return Cont != X.Cont || Valid != X.Valid || Offset != X.Offset;
68480093f4SDimitry Andric   }
69480093f4SDimitry Andric 
70480093f4SDimitry Andric   void Profile(llvm::FoldingSetNodeID &ID) const {
71480093f4SDimitry Andric     ID.AddPointer(Cont);
72480093f4SDimitry Andric     ID.AddInteger(Valid);
73480093f4SDimitry Andric     ID.Add(Offset);
74480093f4SDimitry Andric   }
75480093f4SDimitry Andric };
76480093f4SDimitry Andric 
77480093f4SDimitry Andric // Structure to record the symbolic begin and end position of a container
78480093f4SDimitry Andric struct ContainerData {
79480093f4SDimitry Andric private:
80480093f4SDimitry Andric   const SymbolRef Begin, End;
81480093f4SDimitry Andric 
82480093f4SDimitry Andric   ContainerData(SymbolRef B, SymbolRef E) : Begin(B), End(E) {}
83480093f4SDimitry Andric 
84480093f4SDimitry Andric public:
85480093f4SDimitry Andric   static ContainerData fromBegin(SymbolRef B) {
86480093f4SDimitry Andric     return ContainerData(B, nullptr);
87480093f4SDimitry Andric   }
88480093f4SDimitry Andric 
89480093f4SDimitry Andric   static ContainerData fromEnd(SymbolRef E) {
90480093f4SDimitry Andric     return ContainerData(nullptr, E);
91480093f4SDimitry Andric   }
92480093f4SDimitry Andric 
93480093f4SDimitry Andric   SymbolRef getBegin() const { return Begin; }
94480093f4SDimitry Andric   SymbolRef getEnd() const { return End; }
95480093f4SDimitry Andric 
96480093f4SDimitry Andric   ContainerData newBegin(SymbolRef B) const { return ContainerData(B, End); }
97480093f4SDimitry Andric 
98480093f4SDimitry Andric   ContainerData newEnd(SymbolRef E) const { return ContainerData(Begin, E); }
99480093f4SDimitry Andric 
100480093f4SDimitry Andric   bool operator==(const ContainerData &X) const {
101480093f4SDimitry Andric     return Begin == X.Begin && End == X.End;
102480093f4SDimitry Andric   }
103480093f4SDimitry Andric 
104480093f4SDimitry Andric   bool operator!=(const ContainerData &X) const {
105480093f4SDimitry Andric     return Begin != X.Begin || End != X.End;
106480093f4SDimitry Andric   }
107480093f4SDimitry Andric 
108480093f4SDimitry Andric   void Profile(llvm::FoldingSetNodeID &ID) const {
109480093f4SDimitry Andric     ID.Add(Begin);
110480093f4SDimitry Andric     ID.Add(End);
111480093f4SDimitry Andric   }
112480093f4SDimitry Andric };
113480093f4SDimitry Andric 
114480093f4SDimitry Andric class IteratorSymbolMap {};
115480093f4SDimitry Andric class IteratorRegionMap {};
116480093f4SDimitry Andric class ContainerMap {};
117480093f4SDimitry Andric 
118*5ffd83dbSDimitry Andric using IteratorSymbolMapTy =
119*5ffd83dbSDimitry Andric   CLANG_ENTO_PROGRAMSTATE_MAP(SymbolRef, IteratorPosition);
120*5ffd83dbSDimitry Andric using IteratorRegionMapTy =
121*5ffd83dbSDimitry Andric   CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *, IteratorPosition);
122*5ffd83dbSDimitry Andric using ContainerMapTy =
123*5ffd83dbSDimitry Andric   CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *, ContainerData);
124480093f4SDimitry Andric 
125480093f4SDimitry Andric } // namespace iterator
126480093f4SDimitry Andric 
127480093f4SDimitry Andric template<>
128480093f4SDimitry Andric struct ProgramStateTrait<iterator::IteratorSymbolMap>
129480093f4SDimitry Andric   : public ProgramStatePartialTrait<iterator::IteratorSymbolMapTy> {
130480093f4SDimitry Andric   static void *GDMIndex() { static int Index; return &Index; }
131480093f4SDimitry Andric };
132480093f4SDimitry Andric 
133480093f4SDimitry Andric template<>
134480093f4SDimitry Andric struct ProgramStateTrait<iterator::IteratorRegionMap>
135480093f4SDimitry Andric   : public ProgramStatePartialTrait<iterator::IteratorRegionMapTy> {
136480093f4SDimitry Andric   static void *GDMIndex() { static int Index; return &Index; }
137480093f4SDimitry Andric };
138480093f4SDimitry Andric 
139480093f4SDimitry Andric template<>
140480093f4SDimitry Andric struct ProgramStateTrait<iterator::ContainerMap>
141480093f4SDimitry Andric   : public ProgramStatePartialTrait<iterator::ContainerMapTy> {
142480093f4SDimitry Andric   static void *GDMIndex() { static int Index; return &Index; }
143480093f4SDimitry Andric };
144480093f4SDimitry Andric 
145480093f4SDimitry Andric namespace iterator {
146480093f4SDimitry Andric 
147480093f4SDimitry Andric bool isIteratorType(const QualType &Type);
148480093f4SDimitry Andric bool isIterator(const CXXRecordDecl *CRD);
149480093f4SDimitry Andric bool isComparisonOperator(OverloadedOperatorKind OK);
150480093f4SDimitry Andric bool isInsertCall(const FunctionDecl *Func);
151480093f4SDimitry Andric bool isEraseCall(const FunctionDecl *Func);
152480093f4SDimitry Andric bool isEraseAfterCall(const FunctionDecl *Func);
153480093f4SDimitry Andric bool isEmplaceCall(const FunctionDecl *Func);
154480093f4SDimitry Andric bool isAccessOperator(OverloadedOperatorKind OK);
155*5ffd83dbSDimitry Andric bool isAccessOperator(UnaryOperatorKind OK);
156*5ffd83dbSDimitry Andric bool isAccessOperator(BinaryOperatorKind OK);
157480093f4SDimitry Andric bool isDereferenceOperator(OverloadedOperatorKind OK);
158*5ffd83dbSDimitry Andric bool isDereferenceOperator(UnaryOperatorKind OK);
159*5ffd83dbSDimitry Andric bool isDereferenceOperator(BinaryOperatorKind OK);
160480093f4SDimitry Andric bool isIncrementOperator(OverloadedOperatorKind OK);
161*5ffd83dbSDimitry Andric bool isIncrementOperator(UnaryOperatorKind OK);
162480093f4SDimitry Andric bool isDecrementOperator(OverloadedOperatorKind OK);
163*5ffd83dbSDimitry Andric bool isDecrementOperator(UnaryOperatorKind OK);
164480093f4SDimitry Andric bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK);
165*5ffd83dbSDimitry Andric bool isRandomIncrOrDecrOperator(BinaryOperatorKind OK);
166480093f4SDimitry Andric const ContainerData *getContainerData(ProgramStateRef State,
167480093f4SDimitry Andric                                       const MemRegion *Cont);
168480093f4SDimitry Andric const IteratorPosition *getIteratorPosition(ProgramStateRef State,
169480093f4SDimitry Andric                                             const SVal &Val);
170480093f4SDimitry Andric ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
171480093f4SDimitry Andric                                     const IteratorPosition &Pos);
172*5ffd83dbSDimitry Andric ProgramStateRef createIteratorPosition(ProgramStateRef State, const SVal &Val,
173*5ffd83dbSDimitry Andric                                        const MemRegion *Cont, const Stmt* S,
174*5ffd83dbSDimitry Andric                                        const LocationContext *LCtx,
175*5ffd83dbSDimitry Andric                                        unsigned blockCount);
176480093f4SDimitry Andric ProgramStateRef advancePosition(ProgramStateRef State,
177480093f4SDimitry Andric                                 const SVal &Iter,
178480093f4SDimitry Andric                                 OverloadedOperatorKind Op,
179480093f4SDimitry Andric                                 const SVal &Distance);
180*5ffd83dbSDimitry Andric ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
181*5ffd83dbSDimitry Andric                                  long Scale);
182480093f4SDimitry Andric bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
183480093f4SDimitry Andric              BinaryOperator::Opcode Opc);
184480093f4SDimitry Andric bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
185480093f4SDimitry Andric              BinaryOperator::Opcode Opc);
186480093f4SDimitry Andric 
187480093f4SDimitry Andric } // namespace iterator
188480093f4SDimitry Andric } // namespace ento
189480093f4SDimitry Andric } // namespace clang
190480093f4SDimitry Andric 
191480093f4SDimitry Andric #endif
192