1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H |
15 | #define LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H |
16 | |
17 | #include "clang/Analysis/Analyses/PostOrderCFGView.h" |
18 | #include "clang/Analysis/CFG.h" |
19 | #include "clang/Basic/LLVM.h" |
20 | #include "clang/Basic/PartialDiagnostic.h" |
21 | #include "clang/Basic/SourceLocation.h" |
22 | #include "llvm/ADT/DenseMap.h" |
23 | #include "llvm/ADT/SmallVector.h" |
24 | #include "llvm/ADT/StringRef.h" |
25 | #include <list> |
26 | #include <memory> |
27 | #include <utility> |
28 | #include <vector> |
29 | |
30 | namespace clang { |
31 | |
32 | class AnalysisDeclContext; |
33 | class CXXBindTemporaryExpr; |
34 | class FunctionDecl; |
35 | class PostOrderCFGView; |
36 | class Stmt; |
37 | class VarDecl; |
38 | |
39 | namespace consumed { |
40 | |
41 | class ConsumedStmtVisitor; |
42 | |
43 | enum ConsumedState { |
44 | |
45 | CS_None, |
46 | |
47 | CS_Unknown, |
48 | CS_Unconsumed, |
49 | CS_Consumed |
50 | }; |
51 | |
52 | using OptionalNotes = SmallVector<PartialDiagnosticAt, 1>; |
53 | using DelayedDiag = std::pair<PartialDiagnosticAt, OptionalNotes>; |
54 | using DiagList = std::list<DelayedDiag>; |
55 | |
56 | class ConsumedWarningsHandlerBase { |
57 | public: |
58 | virtual ~ConsumedWarningsHandlerBase(); |
59 | |
60 | |
61 | virtual void emitDiagnostics() {} |
62 | |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | virtual void warnLoopStateMismatch(SourceLocation Loc, |
71 | StringRef VariableName) {} |
72 | |
73 | |
74 | |
75 | |
76 | |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | virtual void warnParamReturnTypestateMismatch(SourceLocation Loc, |
83 | StringRef VariableName, |
84 | StringRef ExpectedState, |
85 | StringRef ObservedState) {} |
86 | |
87 | |
88 | virtual void warnParamTypestateMismatch(SourceLocation LOC, |
89 | StringRef ExpectedState, |
90 | StringRef ObservedState) {} |
91 | |
92 | |
93 | |
94 | |
95 | |
96 | |
97 | |
98 | |
99 | virtual void warnReturnTypestateForUnconsumableType(SourceLocation Loc, |
100 | StringRef TypeName) {} |
101 | |
102 | |
103 | |
104 | |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | |
111 | virtual void warnReturnTypestateMismatch(SourceLocation Loc, |
112 | StringRef ExpectedState, |
113 | StringRef ObservedState) {} |
114 | |
115 | |
116 | |
117 | |
118 | |
119 | |
120 | |
121 | |
122 | virtual void warnUseOfTempInInvalidState(StringRef MethodName, |
123 | StringRef State, |
124 | SourceLocation Loc) {} |
125 | |
126 | |
127 | |
128 | |
129 | |
130 | |
131 | |
132 | |
133 | |
134 | |
135 | |
136 | virtual void warnUseInInvalidState(StringRef MethodName, |
137 | StringRef VariableName, |
138 | StringRef State, |
139 | SourceLocation Loc) {} |
140 | }; |
141 | |
142 | class ConsumedStateMap { |
143 | using VarMapType = llvm::DenseMap<const VarDecl *, ConsumedState>; |
144 | using TmpMapType = |
145 | llvm::DenseMap<const CXXBindTemporaryExpr *, ConsumedState>; |
146 | |
147 | protected: |
148 | bool Reachable = true; |
149 | const Stmt *From = nullptr; |
150 | VarMapType VarMap; |
151 | TmpMapType TmpMap; |
152 | |
153 | public: |
154 | ConsumedStateMap() = default; |
155 | ConsumedStateMap(const ConsumedStateMap &Other) |
156 | : Reachable(Other.Reachable), From(Other.From), VarMap(Other.VarMap), |
157 | TmpMap() {} |
158 | |
159 | |
160 | |
161 | void checkParamsForReturnTypestate(SourceLocation BlameLoc, |
162 | ConsumedWarningsHandlerBase &WarningsHandler) const; |
163 | |
164 | |
165 | void clearTemporaries(); |
166 | |
167 | |
168 | ConsumedState getState(const VarDecl *Var) const; |
169 | |
170 | |
171 | ConsumedState getState(const CXXBindTemporaryExpr *Tmp) const; |
172 | |
173 | |
174 | void intersect(const ConsumedStateMap &Other); |
175 | |
176 | void intersectAtLoopHead(const CFGBlock *LoopHead, const CFGBlock *LoopBack, |
177 | const ConsumedStateMap *LoopBackStates, |
178 | ConsumedWarningsHandlerBase &WarningsHandler); |
179 | |
180 | |
181 | bool isReachable() const { return Reachable; } |
182 | |
183 | |
184 | void markUnreachable(); |
185 | |
186 | |
187 | |
188 | |
189 | void setSource(const Stmt *Source) { this->From = Source; } |
190 | |
191 | |
192 | void setState(const VarDecl *Var, ConsumedState State); |
193 | |
194 | |
195 | void setState(const CXXBindTemporaryExpr *Tmp, ConsumedState State); |
196 | |
197 | |
198 | void remove(const CXXBindTemporaryExpr *Tmp); |
199 | |
200 | |
201 | |
202 | |
203 | |
204 | bool operator!=(const ConsumedStateMap *Other) const; |
205 | }; |
206 | |
207 | class ConsumedBlockInfo { |
208 | std::vector<std::unique_ptr<ConsumedStateMap>> StateMapsArray; |
209 | std::vector<unsigned int> VisitOrder; |
210 | |
211 | public: |
212 | ConsumedBlockInfo() = default; |
213 | |
214 | ConsumedBlockInfo(unsigned int NumBlocks, PostOrderCFGView *SortedGraph) |
215 | : StateMapsArray(NumBlocks), VisitOrder(NumBlocks, 0) { |
216 | unsigned int VisitOrderCounter = 0; |
217 | for (const auto BI : *SortedGraph) |
218 | VisitOrder[BI->getBlockID()] = VisitOrderCounter++; |
219 | } |
220 | |
221 | bool allBackEdgesVisited(const CFGBlock *CurrBlock, |
222 | const CFGBlock *TargetBlock); |
223 | |
224 | void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap, |
225 | std::unique_ptr<ConsumedStateMap> &OwnedStateMap); |
226 | void addInfo(const CFGBlock *Block, |
227 | std::unique_ptr<ConsumedStateMap> StateMap); |
228 | |
229 | ConsumedStateMap* borrowInfo(const CFGBlock *Block); |
230 | |
231 | void discardInfo(const CFGBlock *Block); |
232 | |
233 | std::unique_ptr<ConsumedStateMap> getInfo(const CFGBlock *Block); |
234 | |
235 | bool isBackEdge(const CFGBlock *From, const CFGBlock *To); |
236 | bool isBackEdgeTarget(const CFGBlock *Block); |
237 | }; |
238 | |
239 | |
240 | class ConsumedAnalyzer { |
241 | ConsumedBlockInfo BlockInfo; |
242 | std::unique_ptr<ConsumedStateMap> CurrStates; |
243 | |
244 | ConsumedState ExpectedReturnState; |
245 | |
246 | void determineExpectedReturnState(AnalysisDeclContext &AC, |
247 | const FunctionDecl *D); |
248 | bool splitState(const CFGBlock *CurrBlock, |
249 | const ConsumedStmtVisitor &Visitor); |
250 | |
251 | public: |
252 | ConsumedWarningsHandlerBase &WarningsHandler; |
253 | |
254 | ConsumedAnalyzer(ConsumedWarningsHandlerBase &WarningsHandler) |
255 | : WarningsHandler(WarningsHandler) {} |
256 | |
257 | ConsumedState getExpectedReturnState() const { return ExpectedReturnState; } |
258 | |
259 | |
260 | |
261 | |
262 | |
263 | |
264 | |
265 | void run(AnalysisDeclContext &AC); |
266 | }; |
267 | |
268 | } |
269 | |
270 | } |
271 | |
272 | #endif |
273 | |