/src/cppcheck/oss-fuzz/build/valueflow.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "matchcompiler.h" |
2 | | #include <string> |
3 | | #include <cstring> |
4 | | #include "errorlogger.h" |
5 | | #include "token.h" |
6 | | // pattern: <|<= |
7 | 5.03k | static inline bool match1(const Token* tok) { |
8 | 5.03k | if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<=")))) |
9 | 3.09k | return false; |
10 | 1.94k | return true; |
11 | 5.03k | } |
12 | | // pattern: >|>= |
13 | 3.09k | static inline bool match2(const Token* tok) { |
14 | 3.09k | if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">=")))) |
15 | 1.74k | return false; |
16 | 1.34k | return true; |
17 | 3.09k | } |
18 | | // pattern: ==|!=|>=|<= |
19 | 2.51k | static inline bool match3(const Token* tok) { |
20 | 2.51k | if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!=")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">=")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<=")))) |
21 | 1.29k | return false; |
22 | 1.22k | return true; |
23 | 2.51k | } |
24 | | // pattern: { |
25 | 1.30k | static inline bool match4(const Token* tok) { |
26 | 1.30k | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))) |
27 | 392 | return false; |
28 | 910 | return true; |
29 | 1.30k | } |
30 | | // pattern: return|continue|break|throw|goto |
31 | 30 | template<class T> static inline T * findmatch5(T * start_tok, const Token * end) { |
32 | 60 | for (; start_tok && start_tok != end; start_tok = start_tok->next()) { |
33 | | |
34 | 31 | T * tok = start_tok; |
35 | 31 | if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("continue")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("break")) || (tok->str() == MatchCompiler::makeConstString("throw")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("goto")))) |
36 | 30 | continue; |
37 | 1 | return start_tok; |
38 | 31 | } |
39 | 29 | return nullptr; |
40 | 30 | } |
41 | | // pattern: false|true |
42 | 10.9k | static inline bool match6(const Token* tok) { |
43 | 10.9k | if (!tok || !(((tok->tokType() == Token::eBoolean) && tok->str() == MatchCompiler::makeConstString("false")) || ((tok->tokType() == Token::eBoolean) && tok->str() == MatchCompiler::makeConstString("true")))) |
44 | 10.9k | return false; |
45 | 0 | return true; |
46 | 10.9k | } |
47 | | // pattern: [(,] NULL [,)] |
48 | 54.9k | static inline bool match7(const Token* tok) { |
49 | 54.9k | if (!tok || tok->str().size() != 1U || !strchr("(,", tok->str()[0])) |
50 | 52.8k | return false; |
51 | 2.09k | tok = tok->next(); |
52 | 2.09k | if (!tok || !(tok->str() == MatchCompiler::makeConstString("NULL"))) |
53 | 2.09k | return false; |
54 | 0 | tok = tok->next(); |
55 | 0 | if (!tok || tok->str().size() != 1U || !strchr(",)", tok->str()[0])) |
56 | 0 | return false; |
57 | 0 | return true; |
58 | 0 | } |
59 | | // pattern: %var% [ %num%| ] = { |
60 | 0 | static inline bool match8(const Token* tok) { |
61 | 0 | if (!tok || !(tok->varId() != 0)) |
62 | 0 | return false; |
63 | 0 | tok = tok->next(); |
64 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("["))) |
65 | 0 | return false; |
66 | 0 | tok = tok->next(); |
67 | 0 | if (tok && (tok->isNumber())) |
68 | 0 | tok = tok->next(); |
69 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]"))) |
70 | 0 | return false; |
71 | 0 | tok = tok->next(); |
72 | 0 | if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("="))) |
73 | 0 | return false; |
74 | 0 | tok = tok->next(); |
75 | 0 | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))) |
76 | 0 | return false; |
77 | 0 | return true; |
78 | 0 | } |
79 | | // pattern: = |
80 | 24.9k | static inline bool match9(const Token* tok) { |
81 | 24.9k | if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("="))) |
82 | 22.4k | return false; |
83 | 2.53k | return true; |
84 | 24.9k | } |
85 | | // pattern: const %type% %var% [ %num%| ] = { |
86 | 43.2k | static inline bool match10(const Token* tok) { |
87 | 43.2k | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("const"))) |
88 | 43.2k | return false; |
89 | 0 | tok = tok->next(); |
90 | 0 | if (!tok || !(tok->isName() && tok->varId() == 0U)) |
91 | 0 | return false; |
92 | 0 | tok = tok->next(); |
93 | 0 | if (!tok || !(tok->varId() != 0)) |
94 | 0 | return false; |
95 | 0 | tok = tok->next(); |
96 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("["))) |
97 | 0 | return false; |
98 | 0 | tok = tok->next(); |
99 | 0 | if (tok && (tok->isNumber())) |
100 | 0 | tok = tok->next(); |
101 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]"))) |
102 | 0 | return false; |
103 | 0 | tok = tok->next(); |
104 | 0 | if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("="))) |
105 | 0 | return false; |
106 | 0 | tok = tok->next(); |
107 | 0 | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))) |
108 | 0 | return false; |
109 | 0 | return true; |
110 | 0 | } |
111 | | // pattern: const char %var% [ %num%| ] = %str% ; |
112 | 43.2k | static inline bool match11(const Token* tok) { |
113 | 43.2k | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("const"))) |
114 | 43.2k | return false; |
115 | 0 | tok = tok->next(); |
116 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("char"))) |
117 | 0 | return false; |
118 | 0 | tok = tok->next(); |
119 | 0 | if (!tok || !(tok->varId() != 0)) |
120 | 0 | return false; |
121 | 0 | tok = tok->next(); |
122 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("["))) |
123 | 0 | return false; |
124 | 0 | tok = tok->next(); |
125 | 0 | if (tok && (tok->isNumber())) |
126 | 0 | tok = tok->next(); |
127 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]"))) |
128 | 0 | return false; |
129 | 0 | tok = tok->next(); |
130 | 0 | if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("="))) |
131 | 0 | return false; |
132 | 0 | tok = tok->next(); |
133 | 0 | if (!tok || !(tok->tokType() == Token::eString)) |
134 | 0 | return false; |
135 | 0 | tok = tok->next(); |
136 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString(";"))) |
137 | 0 | return false; |
138 | 0 | return true; |
139 | 0 | } |
140 | | // pattern: %comp% |
141 | 89.7k | static inline bool match12(const Token* tok) { |
142 | 89.7k | if (!tok || !tok->isComparisonOp()) |
143 | 86.7k | return false; |
144 | 3.00k | return true; |
145 | 89.7k | } |
146 | | // pattern: (|%name% |
147 | 0 | static inline bool match13(const Token* tok) { |
148 | 0 | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || tok->isName())) |
149 | 0 | return false; |
150 | 0 | return true; |
151 | 0 | } |
152 | | // pattern: if|while|for ( |
153 | 585k | static inline bool match14(const Token* tok) { |
154 | 585k | if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("if")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("for")))) |
155 | 510k | return false; |
156 | 75.5k | tok = tok->next(); |
157 | 75.5k | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
158 | 0 | return false; |
159 | 75.5k | return true; |
160 | 75.5k | } |
161 | | // pattern: [ |
162 | 177k | static inline bool match15(const Token* tok) { |
163 | 177k | if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("["))) |
164 | 177k | return false; |
165 | 0 | return true; |
166 | 177k | } |
167 | | // pattern: . %name% ( |
168 | 115k | static inline bool match16(const Token* tok) { |
169 | 115k | if (!tok || !(tok->str() == MatchCompiler::makeConstString("."))) |
170 | 115k | return false; |
171 | 0 | tok = tok->next(); |
172 | 0 | if (!tok || !tok->isName()) |
173 | 0 | return false; |
174 | 0 | tok = tok->next(); |
175 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
176 | 0 | return false; |
177 | 0 | return true; |
178 | 0 | } |
179 | | // pattern: ==|>=|<=|/ |
180 | 4.11k | static inline bool match17(const Token* tok) { |
181 | 4.11k | if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">=")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<=")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("/")))) |
182 | 3.76k | return false; |
183 | 350 | return true; |
184 | 4.11k | } |
185 | | // pattern: !=|>|<|%|- |
186 | 3.76k | static inline bool match18(const Token* tok) { |
187 | 3.76k | if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!=")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("%")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")))) |
188 | 3.04k | return false; |
189 | 717 | return true; |
190 | 3.76k | } |
191 | | // pattern: -|%|&|^ |
192 | 0 | static inline bool match19(const Token* tok) { |
193 | 0 | if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("%")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("^")))) |
194 | 0 | return false; |
195 | 0 | return true; |
196 | 0 | } |
197 | | // pattern: true|false |
198 | 75.5k | static inline bool match20(const Token* tok) { |
199 | 75.5k | if (!tok || !(((tok->tokType() == Token::eBoolean) && tok->str() == MatchCompiler::makeConstString("true")) || ((tok->tokType() == Token::eBoolean) && tok->str() == MatchCompiler::makeConstString("false")))) |
200 | 75.5k | return false; |
201 | 0 | return true; |
202 | 75.5k | } |
203 | | // pattern: <|<=|>|>= |
204 | 0 | static inline bool match21(const Token* tok) { |
205 | 0 | if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<=")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">=")))) |
206 | 0 | return false; |
207 | 0 | return true; |
208 | 0 | } |
209 | | // pattern: ? |
210 | 77.9k | static inline bool match22(const Token* tok) { |
211 | 77.9k | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("?"))) |
212 | 77.9k | return false; |
213 | 0 | return true; |
214 | 77.9k | } |
215 | | // pattern: % |
216 | 75.5k | static inline bool match23(const Token* tok) { |
217 | 75.5k | if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("%"))) |
218 | 75.4k | return false; |
219 | 134 | return true; |
220 | 75.5k | } |
221 | | // pattern: abs|labs|llabs|fabs|fabsf|fabsl ( |
222 | 113k | static inline bool match24(const Token* tok) { |
223 | 113k | if (!tok || !((tok->str() == MatchCompiler::makeConstString("abs")) || (tok->str() == MatchCompiler::makeConstString("labs")) || (tok->str() == MatchCompiler::makeConstString("llabs")) || (tok->str() == MatchCompiler::makeConstString("fabs")) || (tok->str() == MatchCompiler::makeConstString("fabsf")) || (tok->str() == MatchCompiler::makeConstString("fabsl")))) |
224 | 113k | return false; |
225 | 0 | tok = tok->next(); |
226 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
227 | 0 | return false; |
228 | 0 | return true; |
229 | 0 | } |
230 | | // pattern: . data|c_str ( |
231 | 75.5k | static inline bool match25(const Token* tok) { |
232 | 75.5k | if (!tok || !(tok->str() == MatchCompiler::makeConstString("."))) |
233 | 75.5k | return false; |
234 | 0 | tok = tok->next(); |
235 | 0 | if (!tok || !((tok->str() == MatchCompiler::makeConstString("data")) || (tok->str() == MatchCompiler::makeConstString("c_str")))) |
236 | 0 | return false; |
237 | 0 | tok = tok->next(); |
238 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
239 | 0 | return false; |
240 | 0 | return true; |
241 | 0 | } |
242 | | // pattern: make_shared|make_unique < |
243 | 75.5k | static inline bool match26(const Token* tok) { |
244 | 75.5k | if (!tok || !((tok->str() == MatchCompiler::makeConstString("make_shared")) || (tok->str() == MatchCompiler::makeConstString("make_unique")))) |
245 | 75.5k | return false; |
246 | 0 | tok = tok->next(); |
247 | 0 | if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<"))) |
248 | 0 | return false; |
249 | 0 | return true; |
250 | 0 | } |
251 | | // pattern: > ( |
252 | 0 | static inline bool match27(const Token* tok) { |
253 | 0 | if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">"))) |
254 | 0 | return false; |
255 | 0 | tok = tok->next(); |
256 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
257 | 0 | return false; |
258 | 0 | return true; |
259 | 0 | } |
260 | | // pattern: this |
261 | 75.5k | static inline bool match28(const Token* tok) { |
262 | 75.5k | if (!tok || !(tok->str() == MatchCompiler::makeConstString("this"))) |
263 | 75.5k | return false; |
264 | 0 | return true; |
265 | 75.5k | } |
266 | | // pattern: %name% = |
267 | 0 | static inline bool match29(const Token* tok) { |
268 | 0 | if (!tok || !tok->isName()) |
269 | 0 | return false; |
270 | 0 | tok = tok->next(); |
271 | 0 | if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("="))) |
272 | 0 | return false; |
273 | 0 | return true; |
274 | 0 | } |
275 | | // pattern: ++|--|& |
276 | 7.87k | static inline bool match30(const Token* tok) { |
277 | 7.87k | if (!tok || !(((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("++")) || ((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("--")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")))) |
278 | 7.18k | return false; |
279 | 692 | return true; |
280 | 7.87k | } |
281 | | // pattern: & %name% = |
282 | 1.58k | static inline bool match31(const Token* tok) { |
283 | 1.58k | if (!tok || !((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&"))) |
284 | 1.58k | return false; |
285 | 0 | tok = tok->next(); |
286 | 0 | if (!tok || !tok->isName()) |
287 | 0 | return false; |
288 | 0 | tok = tok->next(); |
289 | 0 | if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("="))) |
290 | 0 | return false; |
291 | 0 | return true; |
292 | 0 | } |
293 | | // pattern: [(,] |
294 | 1.59k | static inline bool match32(const Token* tok) { |
295 | 1.59k | if (!tok || tok->str().size() != 1U || !strchr("(,", tok->str()[0])) |
296 | 1.59k | return false; |
297 | 0 | return true; |
298 | 1.59k | } |
299 | | // pattern: ; |
300 | 686 | static inline bool match33(const Token* tok) { |
301 | 686 | if (!tok || !(tok->str() == MatchCompiler::makeConstString(";"))) |
302 | 686 | return false; |
303 | 0 | return true; |
304 | 686 | } |
305 | | // pattern: ... |
306 | 11.2k | static inline bool match34(const Token* tok) { |
307 | 11.2k | if (!tok || !((tok->tokType() == Token::eEllipsis) && tok->str() == MatchCompiler::makeConstString("..."))) |
308 | 11.2k | return false; |
309 | 0 | return true; |
310 | 11.2k | } |
311 | | // pattern: =|{ |
312 | 0 | static inline bool match35(const Token* tok) { |
313 | 0 | if (!tok || !(((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))) |
314 | 0 | return false; |
315 | 0 | return true; |
316 | 0 | } |
317 | | // pattern: : |
318 | 0 | static inline bool match36(const Token* tok) { |
319 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":"))) |
320 | 0 | return false; |
321 | 0 | return true; |
322 | 0 | } |
323 | | // pattern: for ( |
324 | 156 | static inline bool match37(const Token* tok) { |
325 | 156 | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("for"))) |
326 | 156 | return false; |
327 | 0 | tok = tok->next(); |
328 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
329 | 0 | return false; |
330 | 0 | return true; |
331 | 0 | } |
332 | | // pattern: %name% ( |
333 | 102k | static inline bool match38(const Token* tok) { |
334 | 102k | if (!tok || !tok->isName()) |
335 | 64.2k | return false; |
336 | 38.4k | tok = tok->next(); |
337 | 38.4k | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
338 | 34.9k | return false; |
339 | 3.48k | return true; |
340 | 38.4k | } |
341 | | // pattern: .|::|[ |
342 | 0 | static inline bool match39(const Token* tok) { |
343 | 0 | if (!tok || !((tok->str() == MatchCompiler::makeConstString(".")) || (tok->str() == MatchCompiler::makeConstString("::")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")))) |
344 | 0 | return false; |
345 | 0 | return true; |
346 | 0 | } |
347 | | // pattern: . |
348 | 187 | static inline bool match40(const Token* tok) { |
349 | 187 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("."))) |
350 | 187 | return false; |
351 | 0 | return true; |
352 | 187 | } |
353 | | // pattern: , |
354 | 0 | static inline bool match41(const Token* tok) { |
355 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(","))) |
356 | 0 | return false; |
357 | 0 | return true; |
358 | 0 | } |
359 | | // pattern: const|volatile|auto|&|&& |
360 | 0 | static inline bool match42(const Token* tok) { |
361 | 0 | if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("const")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("volatile")) || ((tok->tokType() == Token::eKeyword || tok->tokType() == Token::eType) && tok->str() == MatchCompiler::makeConstString("auto")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")))) |
362 | 0 | return false; |
363 | 0 | return true; |
364 | 0 | } |
365 | | // pattern: auto |
366 | 0 | static inline bool match43(const Token* tok) { |
367 | 0 | if (!tok || !((tok->tokType() == Token::eKeyword || tok->tokType() == Token::eType) && tok->str() == MatchCompiler::makeConstString("auto"))) |
368 | 0 | return false; |
369 | 0 | return true; |
370 | 0 | } |
371 | | // pattern: ) { |
372 | 3.55k | static inline bool match44(const Token* tok) { |
373 | 3.55k | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")"))) |
374 | 0 | return false; |
375 | 3.55k | tok = tok->next(); |
376 | 3.55k | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))) |
377 | 187 | return false; |
378 | 3.37k | return true; |
379 | 3.55k | } |
380 | | // pattern: if ( |
381 | 4.89k | static inline bool match45(const Token* tok) { |
382 | 4.89k | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("if"))) |
383 | 3.93k | return false; |
384 | 957 | tok = tok->next(); |
385 | 957 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
386 | 0 | return false; |
387 | 957 | return true; |
388 | 957 | } |
389 | | // pattern: } else { |
390 | 1.25k | static inline bool match46(const Token* tok) { |
391 | 1.25k | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}"))) |
392 | 0 | return false; |
393 | 1.25k | tok = tok->next(); |
394 | 1.25k | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("else"))) |
395 | 705 | return false; |
396 | 547 | tok = tok->next(); |
397 | 547 | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))) |
398 | 0 | return false; |
399 | 547 | return true; |
400 | 547 | } |
401 | | // pattern: %var% {|( |
402 | 392 | static inline bool match47(const Token* tok) { |
403 | 392 | if (!tok || !(tok->varId() != 0)) |
404 | 386 | return false; |
405 | 6 | tok = tok->next(); |
406 | 6 | if (!tok || !(((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))) |
407 | 6 | return false; |
408 | 0 | return true; |
409 | 6 | } |
410 | | // pattern: ( |
411 | 0 | static inline bool match48(const Token* tok) { |
412 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
413 | 0 | return false; |
414 | 0 | return true; |
415 | 0 | } |
416 | | // pattern: std :: ref|cref|tie|front_inserter|back_inserter |
417 | 187 | static inline bool match49(const Token* tok) { |
418 | 187 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("std"))) |
419 | 187 | return false; |
420 | 0 | tok = tok->next(); |
421 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("::"))) |
422 | 0 | return false; |
423 | 0 | tok = tok->next(); |
424 | 0 | if (!tok || !((tok->str() == MatchCompiler::makeConstString("ref")) || (tok->str() == MatchCompiler::makeConstString("cref")) || (tok->str() == MatchCompiler::makeConstString("tie")) || (tok->str() == MatchCompiler::makeConstString("front_inserter")) || (tok->str() == MatchCompiler::makeConstString("back_inserter")))) |
425 | 0 | return false; |
426 | 0 | return true; |
427 | 0 | } |
428 | | // pattern: std :: make_tuple|tuple_cat|make_pair|make_reverse_iterator|next|prev|move|bind |
429 | 187 | static inline bool match50(const Token* tok) { |
430 | 187 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("std"))) |
431 | 187 | return false; |
432 | 0 | tok = tok->next(); |
433 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("::"))) |
434 | 0 | return false; |
435 | 0 | tok = tok->next(); |
436 | 0 | if (!tok || !((tok->str() == MatchCompiler::makeConstString("make_tuple")) || (tok->str() == MatchCompiler::makeConstString("tuple_cat")) || (tok->str() == MatchCompiler::makeConstString("make_pair")) || (tok->str() == MatchCompiler::makeConstString("make_reverse_iterator")) || (tok->str() == MatchCompiler::makeConstString("next")) || (tok->str() == MatchCompiler::makeConstString("prev")) || (tok->str() == MatchCompiler::makeConstString("move")) || (tok->str() == MatchCompiler::makeConstString("bind")))) |
437 | 0 | return false; |
438 | 0 | return true; |
439 | 0 | } |
440 | | // pattern: . push_back|push_front|insert|push|assign |
441 | 0 | static inline bool match51(const Token* tok) { |
442 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("."))) |
443 | 0 | return false; |
444 | 0 | tok = tok->next(); |
445 | 0 | if (!tok || !((tok->str() == MatchCompiler::makeConstString("push_back")) || (tok->str() == MatchCompiler::makeConstString("push_front")) || (tok->str() == MatchCompiler::makeConstString("insert")) || (tok->str() == MatchCompiler::makeConstString("push")) || (tok->str() == MatchCompiler::makeConstString("assign")))) |
446 | 0 | return false; |
447 | 0 | return true; |
448 | 0 | } |
449 | | // pattern: (|{ |
450 | 187 | static inline bool match52(const Token* tok) { |
451 | 187 | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))) |
452 | 0 | return false; |
453 | 187 | return true; |
454 | 187 | } |
455 | | // pattern: %var% ( |
456 | 0 | static inline bool match53(const Token* tok) { |
457 | 0 | if (!tok || !(tok->varId() != 0)) |
458 | 0 | return false; |
459 | 0 | tok = tok->next(); |
460 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
461 | 0 | return false; |
462 | 0 | return true; |
463 | 0 | } |
464 | | // pattern: %name% |
465 | 0 | static inline bool match54(const Token* tok) { |
466 | 0 | if (!tok || !tok->isName()) |
467 | 0 | return false; |
468 | 0 | return true; |
469 | 0 | } |
470 | | // pattern: ] ( |
471 | 0 | static inline bool match55(const Token* tok) { |
472 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("]"))) |
473 | 0 | return false; |
474 | 0 | tok = tok->next(); |
475 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
476 | 0 | return false; |
477 | 0 | return true; |
478 | 0 | } |
479 | | // pattern: { |
480 | 0 | template<class T> static inline T * findmatch56(T * start_tok) { |
481 | 0 | for (; start_tok; start_tok = start_tok->next()) { |
482 | |
|
483 | 0 | T * tok = start_tok; |
484 | 0 | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))) |
485 | 0 | continue; |
486 | 0 | return start_tok; |
487 | 0 | } |
488 | 0 | return nullptr; |
489 | 0 | } |
490 | | // pattern: this !!. |
491 | 0 | static inline bool match57(const Token* tok) { |
492 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("this"))) |
493 | 0 | return false; |
494 | 0 | tok = tok->next(); |
495 | 0 | if (tok && tok->str() == MatchCompiler::makeConstString(".")) |
496 | 0 | return false; |
497 | 0 | return true; |
498 | 0 | } |
499 | | // pattern: * this |
500 | 0 | static inline bool match58(const Token* tok) { |
501 | 0 | if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*"))) |
502 | 0 | return false; |
503 | 0 | tok = tok->next(); |
504 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("this"))) |
505 | 0 | return false; |
506 | 0 | return true; |
507 | 0 | } |
508 | | // pattern: %var% |
509 | 0 | static inline bool match59(const Token* tok) { |
510 | 0 | if (!tok || !(tok->varId() != 0)) |
511 | 0 | return false; |
512 | 0 | return true; |
513 | 0 | } |
514 | | // pattern: return |
515 | 425 | static inline bool match60(const Token* tok) { |
516 | 425 | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return"))) |
517 | 425 | return false; |
518 | 0 | return true; |
519 | 425 | } |
520 | | // pattern: * |
521 | 12 | static inline bool match61(const Token* tok) { |
522 | 12 | if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*"))) |
523 | 12 | return false; |
524 | 0 | return true; |
525 | 12 | } |
526 | | // pattern: .|[ |
527 | 12 | static inline bool match62(const Token* tok) { |
528 | 12 | if (!tok || !((tok->str() == MatchCompiler::makeConstString(".")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")))) |
529 | 12 | return false; |
530 | 0 | return true; |
531 | 12 | } |
532 | | // pattern: data|c_str |
533 | 0 | static inline bool match63(const Token* tok) { |
534 | 0 | if (!tok || !((tok->str() == MatchCompiler::makeConstString("data")) || (tok->str() == MatchCompiler::makeConstString("c_str")))) |
535 | 0 | return false; |
536 | 0 | return true; |
537 | 0 | } |
538 | | // pattern: =|return|%name%|{|,|> { |
539 | 65.1k | static inline bool match64(const Token* tok) { |
540 | 65.1k | if (!tok || !(((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")) || tok->isName() || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(",")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")))) |
541 | 27.9k | return false; |
542 | 37.1k | tok = tok->next(); |
543 | 37.1k | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))) |
544 | 36.3k | return false; |
545 | 796 | return true; |
546 | 37.1k | } |
547 | | // pattern: . get ( ) |
548 | 0 | static inline bool match65(const Token* tok) { |
549 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("."))) |
550 | 0 | return false; |
551 | 0 | tok = tok->next(); |
552 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("get"))) |
553 | 0 | return false; |
554 | 0 | tok = tok->next(); |
555 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
556 | 0 | return false; |
557 | 0 | tok = tok->next(); |
558 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")"))) |
559 | 0 | return false; |
560 | 0 | return true; |
561 | 0 | } |
562 | | // pattern: std :: move ( %var% ) |
563 | 0 | static inline bool match66(const Token* tok) { |
564 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("std"))) |
565 | 0 | return false; |
566 | 0 | tok = tok->next(); |
567 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("::"))) |
568 | 0 | return false; |
569 | 0 | tok = tok->next(); |
570 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("move"))) |
571 | 0 | return false; |
572 | 0 | tok = tok->next(); |
573 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
574 | 0 | return false; |
575 | 0 | tok = tok->next(); |
576 | 0 | if (!tok || !(tok->varId() != 0)) |
577 | 0 | return false; |
578 | 0 | tok = tok->next(); |
579 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")"))) |
580 | 0 | return false; |
581 | 0 | return true; |
582 | 0 | } |
583 | | // pattern: std :: forward < |
584 | 0 | static inline bool match67(const Token* tok) { |
585 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("std"))) |
586 | 0 | return false; |
587 | 0 | tok = tok->next(); |
588 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("::"))) |
589 | 0 | return false; |
590 | 0 | tok = tok->next(); |
591 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("forward"))) |
592 | 0 | return false; |
593 | 0 | tok = tok->next(); |
594 | 0 | if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<"))) |
595 | 0 | return false; |
596 | 0 | return true; |
597 | 0 | } |
598 | | // pattern: > ( %var% ) |
599 | 0 | static inline bool match68(const Token* tok) { |
600 | 0 | if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">"))) |
601 | 0 | return false; |
602 | 0 | tok = tok->next(); |
603 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
604 | 0 | return false; |
605 | 0 | tok = tok->next(); |
606 | 0 | if (!tok || !(tok->varId() != 0)) |
607 | 0 | return false; |
608 | 0 | tok = tok->next(); |
609 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")"))) |
610 | 0 | return false; |
611 | 0 | return true; |
612 | 0 | } |
613 | | // pattern: %varid% . %name% ( |
614 | 0 | static inline bool match69(const Token* tok, const int varid) { |
615 | 0 | if (varid==0U) |
616 | 0 | throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers"); |
617 | 0 | if (!tok || !(tok->isName() && tok->varId() == varid)) |
618 | 0 | return false; |
619 | 0 | tok = tok->next(); |
620 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("."))) |
621 | 0 | return false; |
622 | 0 | tok = tok->next(); |
623 | 0 | if (!tok || !tok->isName()) |
624 | 0 | return false; |
625 | 0 | tok = tok->next(); |
626 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
627 | 0 | return false; |
628 | 0 | return true; |
629 | 0 | } |
630 | | // pattern: [({] |
631 | 25 | static inline bool match70(const Token* tok) { |
632 | 25 | if (!tok || tok->str().size() != 1U || !strchr("({", tok->str()[0])) |
633 | 25 | return false; |
634 | 0 | return true; |
635 | 25 | } |
636 | | // pattern: %var% . reset|clear ( |
637 | 39.6k | static inline bool match71(const Token* tok) { |
638 | 39.6k | if (!tok || !(tok->varId() != 0)) |
639 | 32.4k | return false; |
640 | 7.20k | tok = tok->next(); |
641 | 7.20k | if (!tok || !(tok->str() == MatchCompiler::makeConstString("."))) |
642 | 7.20k | return false; |
643 | 0 | tok = tok->next(); |
644 | 0 | if (!tok || !((tok->str() == MatchCompiler::makeConstString("reset")) || (tok->str() == MatchCompiler::makeConstString("clear")))) |
645 | 0 | return false; |
646 | 0 | tok = tok->next(); |
647 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
648 | 0 | return false; |
649 | 0 | return true; |
650 | 0 | } |
651 | | // pattern: %var%|. |
652 | 0 | static inline bool match72(const Token* tok) { |
653 | 0 | if (!tok || !((tok->varId() != 0) || (tok->str() == MatchCompiler::makeConstString(".")))) |
654 | 0 | return false; |
655 | 0 | return true; |
656 | 0 | } |
657 | | // pattern: } |
658 | 162 | static inline bool match73(const Token* tok) { |
659 | 162 | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}"))) |
660 | 0 | return false; |
661 | 162 | return true; |
662 | 162 | } |
663 | | // pattern: break|continue ; |
664 | 78 | static inline bool match74(const Token* tok) { |
665 | 78 | if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("break")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("continue")))) |
666 | 78 | return false; |
667 | 0 | tok = tok->next(); |
668 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString(";"))) |
669 | 0 | return false; |
670 | 0 | return true; |
671 | 0 | } |
672 | | // pattern: %comp%|%oror%|&& |
673 | 0 | static inline bool match75(const Token* tok) { |
674 | 0 | if (!tok || !(tok->isComparisonOp() || (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")))) |
675 | 0 | return false; |
676 | 0 | return true; |
677 | 0 | } |
678 | | // pattern: strlen ( |
679 | 0 | static inline bool match76(const Token* tok) { |
680 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("strlen"))) |
681 | 0 | return false; |
682 | 0 | tok = tok->next(); |
683 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
684 | 0 | return false; |
685 | 0 | return true; |
686 | 0 | } |
687 | | // pattern: *|/|<<|>>|^|+|-|%or% |
688 | 37.7k | static inline bool match77(const Token* tok) { |
689 | 37.7k | if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("/")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("<<")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString(">>")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("^")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")) || (tok->tokType() == Token::eBitOp && tok->str() == MatchCompiler::makeConstString("|") ))) |
690 | 36.9k | return false; |
691 | 826 | return true; |
692 | 37.7k | } |
693 | | // pattern: <<|>>|/ |
694 | 67 | static inline bool match78(const Token* tok) { |
695 | 67 | if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("<<")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString(">>")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("/")))) |
696 | 61 | return false; |
697 | 6 | return true; |
698 | 67 | } |
699 | | // pattern: <<|>>|^|+|-|%or% |
700 | 61 | static inline bool match79(const Token* tok) { |
701 | 61 | if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("<<")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString(">>")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("^")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")) || (tok->tokType() == Token::eBitOp && tok->str() == MatchCompiler::makeConstString("|") ))) |
702 | 10 | return false; |
703 | 51 | return true; |
704 | 61 | } |
705 | | // pattern: *|/ |
706 | 40 | static inline bool match80(const Token* tok) { |
707 | 40 | if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("/")))) |
708 | 30 | return false; |
709 | 10 | return true; |
710 | 40 | } |
711 | | // pattern: -|%comp% |
712 | 39.6k | static inline bool match81(const Token* tok) { |
713 | 39.6k | if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")) || tok->isComparisonOp())) |
714 | 37.7k | return false; |
715 | 1.94k | return true; |
716 | 39.6k | } |
717 | | // pattern: ++ |
718 | 0 | static inline bool match82(const Token* tok) { |
719 | 0 | if (!tok || !((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("++"))) |
720 | 0 | return false; |
721 | 0 | return true; |
722 | 0 | } |
723 | | // pattern: -- |
724 | 0 | static inline bool match83(const Token* tok) { |
725 | 0 | if (!tok || !((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("--"))) |
726 | 0 | return false; |
727 | 0 | return true; |
728 | 0 | } |
729 | | // pattern: %var% ; %var% |
730 | 10 | static inline bool match84(const Token* tok) { |
731 | 10 | if (!tok || !(tok->varId() != 0)) |
732 | 7 | return false; |
733 | 3 | tok = tok->next(); |
734 | 3 | if (!tok || !(tok->str() == MatchCompiler::makeConstString(";"))) |
735 | 1 | return false; |
736 | 2 | tok = tok->next(); |
737 | 2 | if (!tok || !(tok->varId() != 0)) |
738 | 2 | return false; |
739 | 0 | return true; |
740 | 2 | } |
741 | | // pattern: bool|_Bool |
742 | 10 | static inline bool match85(const Token* tok) { |
743 | 10 | if (!tok || !((tok->str() == MatchCompiler::makeConstString("bool")) || (tok->str() == MatchCompiler::makeConstString("_Bool")))) |
744 | 10 | return false; |
745 | 0 | return true; |
746 | 10 | } |
747 | | // pattern: %var% (|{ |
748 | 35.7k | static inline bool match86(const Token* tok) { |
749 | 35.7k | if (!tok || !(tok->varId() != 0)) |
750 | 29.0k | return false; |
751 | 6.73k | tok = tok->next(); |
752 | 6.73k | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))) |
753 | 6.73k | return false; |
754 | 0 | return true; |
755 | 6.73k | } |
756 | | // pattern: swap ( |
757 | 39.6k | static inline bool match87(const Token* tok) { |
758 | 39.6k | if (!tok || !(tok->str() == MatchCompiler::makeConstString("swap"))) |
759 | 39.6k | return false; |
760 | 0 | tok = tok->next(); |
761 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
762 | 0 | return false; |
763 | 0 | return true; |
764 | 0 | } |
765 | | // pattern: ==|!|( |
766 | 1.00k | static inline bool match88(const Token* tok) { |
767 | 1.00k | if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))) |
768 | 801 | return false; |
769 | 205 | return true; |
770 | 1.00k | } |
771 | | // pattern: !=|%var%|( |
772 | 511 | static inline bool match89(const Token* tok) { |
773 | 511 | if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!=")) || (tok->varId() != 0) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))) |
774 | 463 | return false; |
775 | 48 | return true; |
776 | 511 | } |
777 | | // pattern: break|goto |
778 | 84 | template<class T> static inline T * findmatch90(T * start_tok, const Token * end) { |
779 | 888 | for (; start_tok && start_tok != end; start_tok = start_tok->next()) { |
780 | | |
781 | 804 | T * tok = start_tok; |
782 | 804 | if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("break")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("goto")))) |
783 | 804 | continue; |
784 | 0 | return start_tok; |
785 | 804 | } |
786 | 84 | return nullptr; |
787 | 84 | } |
788 | | // pattern: !=|=|(|. |
789 | 1.26k | static inline bool match91(const Token* tok) { |
790 | 1.26k | if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!=")) || ((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("=")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString(".")))) |
791 | 1.00k | return false; |
792 | 262 | return true; |
793 | 1.26k | } |
794 | | // pattern: ==|! |
795 | 1.26k | static inline bool match92(const Token* tok) { |
796 | 1.26k | if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")))) |
797 | 1.04k | return false; |
798 | 226 | return true; |
799 | 1.26k | } |
800 | | // pattern: :|;|, |
801 | 307k | static inline bool match93(const Token* tok) { |
802 | 307k | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":")) || (tok->str() == MatchCompiler::makeConstString(";")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(",")))) |
803 | 265k | return false; |
804 | 42.7k | return true; |
805 | 307k | } |
806 | | // pattern: &&|%oror%|?|! |
807 | 202k | static inline bool match94(const Token* tok) { |
808 | 202k | if (!tok || !(((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("?")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")))) |
809 | 202k | return false; |
810 | 0 | return true; |
811 | 202k | } |
812 | | // pattern: %assign% |
813 | 1.24k | static inline bool match95(const Token* tok) { |
814 | 1.24k | if (!tok || !tok->isAssignmentOp()) |
815 | 1.24k | return false; |
816 | 0 | return true; |
817 | 1.24k | } |
818 | | // pattern: %assign%|++|-- |
819 | 1.24k | static inline bool match96(const Token* tok) { |
820 | 1.24k | if (!tok || !(tok->isAssignmentOp() || ((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("++")) || ((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("--")))) |
821 | 1.14k | return false; |
822 | 96 | return true; |
823 | 1.24k | } |
824 | | // pattern: <|>|<=|>= |
825 | 1.12k | static inline bool match97(const Token* tok) { |
826 | 1.12k | if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<=")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">=")))) |
827 | 413 | return false; |
828 | 715 | return true; |
829 | 1.12k | } |
830 | | // pattern: for|while ( |
831 | 653 | static inline bool match98(const Token* tok) { |
832 | 653 | if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("for")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while")))) |
833 | 497 | return false; |
834 | 156 | tok = tok->next(); |
835 | 156 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
836 | 0 | return false; |
837 | 156 | return true; |
838 | 156 | } |
839 | | // pattern: ! |
840 | 2.02k | static inline bool match99(const Token* tok) { |
841 | 2.02k | if (!tok || !((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!"))) |
842 | 2.02k | return false; |
843 | 0 | return true; |
844 | 2.02k | } |
845 | | // pattern: ==|!= |
846 | 31.0k | static inline bool match100(const Token* tok) { |
847 | 31.0k | if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!=")))) |
848 | 28.4k | return false; |
849 | 2.62k | return true; |
850 | 31.0k | } |
851 | | // pattern: != |
852 | 0 | static inline bool match101(const Token* tok) { |
853 | 0 | if (!tok || !((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!="))) |
854 | 0 | return false; |
855 | 0 | return true; |
856 | 0 | } |
857 | | // pattern: %oror%|&& |
858 | 4.29k | static inline bool match102(const Token* tok) { |
859 | 4.29k | if (!tok || !((tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")))) |
860 | 4.29k | return false; |
861 | 0 | return true; |
862 | 4.29k | } |
863 | | // pattern: ++|-- |
864 | 0 | static inline bool match103(const Token* tok) { |
865 | 0 | if (!tok || !(((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("++")) || ((tok->tokType() == Token::eIncDecOp) && tok->str() == MatchCompiler::makeConstString("--")))) |
866 | 0 | return false; |
867 | 0 | return true; |
868 | 0 | } |
869 | | // pattern: while ( |
870 | 50 | static inline bool match104(const Token* tok) { |
871 | 50 | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while"))) |
872 | 36 | return false; |
873 | 14 | tok = tok->next(); |
874 | 14 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
875 | 0 | return false; |
876 | 14 | return true; |
877 | 14 | } |
878 | | // pattern: while|for ( |
879 | 331 | static inline bool match105(const Token* tok) { |
880 | 331 | if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("for")))) |
881 | 247 | return false; |
882 | 84 | tok = tok->next(); |
883 | 84 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
884 | 0 | return false; |
885 | 84 | return true; |
886 | 84 | } |
887 | | // pattern: &&|%oror% |
888 | 115 | static inline bool match106(const Token* tok) { |
889 | 115 | if (!tok || !(((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")))) |
890 | 115 | return false; |
891 | 0 | return true; |
892 | 115 | } |
893 | | // pattern: == false |
894 | 0 | static inline bool match107(const Token* tok) { |
895 | 0 | if (!tok || !((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("=="))) |
896 | 0 | return false; |
897 | 0 | tok = tok->next(); |
898 | 0 | if (!tok || !((tok->tokType() == Token::eBoolean) && tok->str() == MatchCompiler::makeConstString("false"))) |
899 | 0 | return false; |
900 | 0 | return true; |
901 | 0 | } |
902 | | // pattern: } while ( |
903 | 0 | static inline bool match108(const Token* tok) { |
904 | 0 | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}"))) |
905 | 0 | return false; |
906 | 0 | tok = tok->next(); |
907 | 0 | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while"))) |
908 | 0 | return false; |
909 | 0 | tok = tok->next(); |
910 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
911 | 0 | return false; |
912 | 0 | return true; |
913 | 0 | } |
914 | | // pattern: %oror%|&&|? |
915 | 12.9k | static inline bool match109(const Token* tok) { |
916 | 12.9k | if (!tok || !((tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || ((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("?")))) |
917 | 12.9k | return false; |
918 | 0 | return true; |
919 | 12.9k | } |
920 | | // pattern: if|while ( |
921 | 35.0k | static inline bool match110(const Token* tok) { |
922 | 35.0k | if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("if")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while")))) |
923 | 31.2k | return false; |
924 | 3.76k | tok = tok->next(); |
925 | 3.76k | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
926 | 0 | return false; |
927 | 3.76k | return true; |
928 | 3.76k | } |
929 | | // pattern: %comp%|%assign% |
930 | 2.01k | static inline bool match111(const Token* tok) { |
931 | 2.01k | if (!tok || !(tok->isComparisonOp() || tok->isAssignmentOp())) |
932 | 272 | return false; |
933 | 1.74k | return true; |
934 | 2.01k | } |
935 | | // pattern: %|<<|>>|&|^|~|%or% |
936 | 1.64k | static inline bool match112(const Token* tok) { |
937 | 1.64k | if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("%")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("<<")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString(">>")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("^")) || ((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("~")) || (tok->tokType() == Token::eBitOp && tok->str() == MatchCompiler::makeConstString("|") ))) |
938 | 1.55k | return false; |
939 | 91 | return true; |
940 | 1.64k | } |
941 | | // pattern: NULL|nullptr |
942 | 868 | static inline bool match113(const Token* tok) { |
943 | 868 | if (!tok || !((tok->str() == MatchCompiler::makeConstString("NULL")) || (tok->str() == MatchCompiler::makeConstString("nullptr")))) |
944 | 868 | return false; |
945 | 0 | return true; |
946 | 868 | } |
947 | | // pattern: +|-|*|/ |
948 | 777 | static inline bool match114(const Token* tok) { |
949 | 777 | if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("*")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("/")))) |
950 | 636 | return false; |
951 | 141 | return true; |
952 | 777 | } |
953 | | // pattern: %comp%|- |
954 | 23.6k | static inline bool match115(const Token* tok) { |
955 | 23.6k | if (!tok || !(tok->isComparisonOp() || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")))) |
956 | 22.1k | return false; |
957 | 1.56k | return true; |
958 | 23.6k | } |
959 | | // pattern: ?|&&|!|%oror% |
960 | 22.1k | static inline bool match116(const Token* tok) { |
961 | 22.1k | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("?")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")) || (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")))) |
962 | 22.1k | return false; |
963 | 0 | return true; |
964 | 22.1k | } |
965 | | // pattern: ) ( |
966 | 0 | static inline bool match117(const Token* tok) { |
967 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")"))) |
968 | 0 | return false; |
969 | 0 | tok = tok->next(); |
970 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
971 | 0 | return false; |
972 | 0 | return true; |
973 | 0 | } |
974 | | // pattern: %varid% |
975 | 0 | template<class T> static inline T * findmatch118(T * start_tok, const Token * end, int varid) { |
976 | 0 | for (; start_tok && start_tok != end; start_tok = start_tok->next()) { |
977 | |
|
978 | 0 | T * tok = start_tok; |
979 | 0 | if (varid==0U) |
980 | 0 | throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers"); |
981 | 0 | if (!tok || !(tok->isName() && tok->varId() == varid)) |
982 | 0 | continue; |
983 | 0 | return start_tok; |
984 | 0 | } |
985 | 0 | return nullptr; |
986 | 0 | } |
987 | | // pattern: switch ( %var% ) { |
988 | 0 | static inline bool match119(const Token* tok) { |
989 | 0 | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("switch"))) |
990 | 0 | return false; |
991 | 0 | tok = tok->next(); |
992 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
993 | 0 | return false; |
994 | 0 | tok = tok->next(); |
995 | 0 | if (!tok || !(tok->varId() != 0)) |
996 | 0 | return false; |
997 | 0 | tok = tok->next(); |
998 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")"))) |
999 | 0 | return false; |
1000 | 0 | tok = tok->next(); |
1001 | 0 | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))) |
1002 | 0 | return false; |
1003 | 0 | return true; |
1004 | 0 | } |
1005 | | // pattern: case %num% : |
1006 | 0 | static inline bool match120(const Token* tok) { |
1007 | 0 | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("case"))) |
1008 | 0 | return false; |
1009 | 0 | tok = tok->next(); |
1010 | 0 | if (!tok || !tok->isNumber()) |
1011 | 0 | return false; |
1012 | 0 | tok = tok->next(); |
1013 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":"))) |
1014 | 0 | return false; |
1015 | 0 | return true; |
1016 | 0 | } |
1017 | | // pattern: break ; |
1018 | 0 | static inline bool match121(const Token* tok) { |
1019 | 0 | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("break"))) |
1020 | 0 | return false; |
1021 | 0 | tok = tok->next(); |
1022 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString(";"))) |
1023 | 0 | return false; |
1024 | 0 | return true; |
1025 | 0 | } |
1026 | | // pattern: ;| case |
1027 | 0 | static inline bool match122(const Token* tok) { |
1028 | 0 | if (tok && ((tok->str() == MatchCompiler::makeConstString(";")))) |
1029 | 0 | tok = tok->next(); |
1030 | 0 | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("case"))) |
1031 | 0 | return false; |
1032 | 0 | return true; |
1033 | 0 | } |
1034 | | // pattern: ;| case %num% : |
1035 | 0 | static inline bool match123(const Token* tok) { |
1036 | 0 | if (tok && ((tok->str() == MatchCompiler::makeConstString(";")))) |
1037 | 0 | tok = tok->next(); |
1038 | 0 | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("case"))) |
1039 | 0 | return false; |
1040 | 0 | tok = tok->next(); |
1041 | 0 | if (!tok || !tok->isNumber()) |
1042 | 0 | return false; |
1043 | 0 | tok = tok->next(); |
1044 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":"))) |
1045 | 0 | return false; |
1046 | 0 | return true; |
1047 | 0 | } |
1048 | | // pattern: %comp%|%oror%|&&|! |
1049 | 0 | static inline bool match124(const Token* tok) { |
1050 | 0 | if (!tok || !(tok->isComparisonOp() || (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || ((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")))) |
1051 | 0 | return false; |
1052 | 0 | return true; |
1053 | 0 | } |
1054 | | // pattern: %var% = %num%|%str%|%char%|%name% [,)] |
1055 | 0 | static inline bool match125(const Token* tok) { |
1056 | 0 | if (!tok || !(tok->varId() != 0)) |
1057 | 0 | return false; |
1058 | 0 | tok = tok->next(); |
1059 | 0 | if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("="))) |
1060 | 0 | return false; |
1061 | 0 | tok = tok->next(); |
1062 | 0 | if (!tok || !(tok->isNumber() || (tok->tokType() == Token::eString) || (tok->tokType() == Token::eChar) || tok->isName())) |
1063 | 0 | return false; |
1064 | 0 | tok = tok->next(); |
1065 | 0 | if (!tok || tok->str().size() != 1U || !strchr(",)", tok->str()[0])) |
1066 | 0 | return false; |
1067 | 0 | return true; |
1068 | 0 | } |
1069 | | // pattern: goto|asm|setjmp|longjmp |
1070 | 0 | template<class T> static inline T * findmatch126(T * start_tok, const Token * end) { |
1071 | 0 | for (; start_tok && start_tok != end; start_tok = start_tok->next()) { |
1072 | |
|
1073 | 0 | T * tok = start_tok; |
1074 | 0 | if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("goto")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("asm")) || (tok->str() == MatchCompiler::makeConstString("setjmp")) || (tok->str() == MatchCompiler::makeConstString("longjmp")))) |
1075 | 0 | continue; |
1076 | 0 | return start_tok; |
1077 | 0 | } |
1078 | 0 | return nullptr; |
1079 | 0 | } |
1080 | | // pattern: [&*(] |
1081 | 0 | static inline bool match127(const Token* tok) { |
1082 | 0 | if (!tok || tok->str().size() != 1U || !strchr("&*(", tok->str()[0])) |
1083 | 0 | return false; |
1084 | 0 | return true; |
1085 | 0 | } |
1086 | | // pattern: %var% ;|[ |
1087 | 41.3k | static inline bool match128(const Token* tok) { |
1088 | 41.3k | if (!tok || !(tok->varId() != 0)) |
1089 | 34.1k | return false; |
1090 | 7.20k | tok = tok->next(); |
1091 | 7.20k | if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || ((tok->tokType() == Token::eExtendedOp || tok->tokType() == Token::eLambda) && tok->str() == MatchCompiler::makeConstString("[")))) |
1092 | 3.68k | return false; |
1093 | 3.51k | return true; |
1094 | 7.20k | } |
1095 | | // pattern: union |
1096 | 0 | template<class T> static inline T * findmatch129(T * start_tok, const Token * end) { |
1097 | 0 | for (; start_tok && start_tok != end; start_tok = start_tok->next()) { |
1098 | |
|
1099 | 0 | T * tok = start_tok; |
1100 | 0 | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("union"))) |
1101 | 0 | continue; |
1102 | 0 | return start_tok; |
1103 | 0 | } |
1104 | 0 | return nullptr; |
1105 | 0 | } |
1106 | | // pattern: %name% . %name% ( |
1107 | 0 | static inline bool match130(const Token* tok) { |
1108 | 0 | if (!tok || !tok->isName()) |
1109 | 0 | return false; |
1110 | 0 | tok = tok->next(); |
1111 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("."))) |
1112 | 0 | return false; |
1113 | 0 | tok = tok->next(); |
1114 | 0 | if (!tok || !tok->isName()) |
1115 | 0 | return false; |
1116 | 0 | tok = tok->next(); |
1117 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
1118 | 0 | return false; |
1119 | 0 | return true; |
1120 | 0 | } |
1121 | | // pattern: +|- |
1122 | 4.39k | static inline bool match131(const Token* tok) { |
1123 | 4.39k | if (!tok || !(((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+")) || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-")))) |
1124 | 4.34k | return false; |
1125 | 58 | return true; |
1126 | 4.39k | } |
1127 | | // pattern: - |
1128 | 0 | static inline bool match132(const Token* tok) { |
1129 | 0 | if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("-"))) |
1130 | 0 | return false; |
1131 | 0 | return true; |
1132 | 0 | } |
1133 | | // pattern: %assign%|<< |
1134 | 0 | static inline bool match133(const Token* tok) { |
1135 | 0 | if (!tok || !(tok->isAssignmentOp() || ((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("<<")))) |
1136 | 0 | return false; |
1137 | 0 | return true; |
1138 | 0 | } |
1139 | | // pattern: %var% (|{|; |
1140 | 0 | static inline bool match134(const Token* tok) { |
1141 | 0 | if (!tok || !(tok->varId() != 0)) |
1142 | 0 | return false; |
1143 | 0 | tok = tok->next(); |
1144 | 0 | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString(";")))) |
1145 | 0 | return false; |
1146 | 0 | return true; |
1147 | 0 | } |
1148 | | // pattern: %var% ; |
1149 | 0 | static inline bool match135(const Token* tok) { |
1150 | 0 | if (!tok || !(tok->varId() != 0)) |
1151 | 0 | return false; |
1152 | 0 | tok = tok->next(); |
1153 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString(";"))) |
1154 | 0 | return false; |
1155 | 0 | return true; |
1156 | 0 | } |
1157 | | // pattern: . reset ( |
1158 | 0 | static inline bool match136(const Token* tok) { |
1159 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("."))) |
1160 | 0 | return false; |
1161 | 0 | tok = tok->next(); |
1162 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("reset"))) |
1163 | 0 | return false; |
1164 | 0 | tok = tok->next(); |
1165 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
1166 | 0 | return false; |
1167 | 0 | return true; |
1168 | 0 | } |
1169 | | // pattern: ( ) |
1170 | 0 | static inline bool match137(const Token* tok) { |
1171 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
1172 | 0 | return false; |
1173 | 0 | tok = tok->next(); |
1174 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")"))) |
1175 | 0 | return false; |
1176 | 0 | return true; |
1177 | 0 | } |
1178 | | // pattern: . release ( ) |
1179 | 0 | static inline bool match138(const Token* tok) { |
1180 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("."))) |
1181 | 0 | return false; |
1182 | 0 | tok = tok->next(); |
1183 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("release"))) |
1184 | 0 | return false; |
1185 | 0 | tok = tok->next(); |
1186 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
1187 | 0 | return false; |
1188 | 0 | tok = tok->next(); |
1189 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")"))) |
1190 | 0 | return false; |
1191 | 0 | return true; |
1192 | 0 | } |
1193 | | // pattern: . release|reset ( |
1194 | 0 | static inline bool match139(const Token* tok) { |
1195 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString("."))) |
1196 | 0 | return false; |
1197 | 0 | tok = tok->next(); |
1198 | 0 | if (!tok || !((tok->str() == MatchCompiler::makeConstString("release")) || (tok->str() == MatchCompiler::makeConstString("reset")))) |
1199 | 0 | return false; |
1200 | 0 | tok = tok->next(); |
1201 | 0 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
1202 | 0 | return false; |
1203 | 0 | return true; |
1204 | 0 | } |
1205 | | // pattern: %name%|> (|{ |
1206 | 0 | static inline bool match140(const Token* tok) { |
1207 | 0 | if (!tok || !(tok->isName() || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")))) |
1208 | 0 | return false; |
1209 | 0 | tok = tok->next(); |
1210 | 0 | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))) |
1211 | 0 | return false; |
1212 | 0 | return true; |
1213 | 0 | } |
1214 | | // pattern: + |
1215 | 3.91k | static inline bool match141(const Token* tok) { |
1216 | 3.91k | if (!tok || !((tok->tokType() == Token::eArithmeticalOp) && tok->str() == MatchCompiler::makeConstString("+"))) |
1217 | 3.87k | return false; |
1218 | 41 | return true; |
1219 | 3.91k | } |
1220 | | // pattern: %str% |
1221 | 2.25k | static inline bool match142(const Token* tok) { |
1222 | 2.25k | if (!tok || !(tok->tokType() == Token::eString)) |
1223 | 2.25k | return false; |
1224 | 0 | return true; |
1225 | 2.25k | } |
1226 | | // pattern: %name% ; |
1227 | 0 | static inline bool match143(const Token* tok) { |
1228 | 0 | if (!tok || !tok->isName()) |
1229 | 0 | return false; |
1230 | 0 | tok = tok->next(); |
1231 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString(";"))) |
1232 | 0 | return false; |
1233 | 0 | return true; |
1234 | 0 | } |
1235 | | // pattern: %name% { |
1236 | 0 | static inline bool match144(const Token* tok) { |
1237 | 0 | if (!tok || !tok->isName()) |
1238 | 0 | return false; |
1239 | 0 | tok = tok->next(); |
1240 | 0 | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))) |
1241 | 0 | return false; |
1242 | 0 | return true; |
1243 | 0 | } |
1244 | | // pattern: } ; |
1245 | 0 | static inline bool match145(const Token* tok) { |
1246 | 0 | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}"))) |
1247 | 0 | return false; |
1248 | 0 | tok = tok->next(); |
1249 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString(";"))) |
1250 | 0 | return false; |
1251 | 0 | return true; |
1252 | 0 | } |
1253 | | // pattern: for|while |
1254 | 0 | static inline bool match146(const Token* tok) { |
1255 | 0 | if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("for")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while")))) |
1256 | 0 | return false; |
1257 | 0 | return true; |
1258 | 0 | } |
1259 | | // pattern: %name%|;|{|} %var% = %str% ; |
1260 | 39.6k | static inline bool match147(const Token* tok) { |
1261 | 39.6k | if (!tok || !(tok->isName() || (tok->str() == MatchCompiler::makeConstString(";")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))) |
1262 | 13.4k | return false; |
1263 | 26.2k | tok = tok->next(); |
1264 | 26.2k | if (!tok || !(tok->varId() != 0)) |
1265 | 26.0k | return false; |
1266 | 198 | tok = tok->next(); |
1267 | 198 | if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("="))) |
1268 | 143 | return false; |
1269 | 55 | tok = tok->next(); |
1270 | 55 | if (!tok || !(tok->tokType() == Token::eString)) |
1271 | 55 | return false; |
1272 | 0 | tok = tok->next(); |
1273 | 0 | if (!tok || !(tok->str() == MatchCompiler::makeConstString(";"))) |
1274 | 0 | return false; |
1275 | 0 | return true; |
1276 | 0 | } |
1277 | | // pattern: >|return (|{ |
1278 | 39.6k | static inline bool match148(const Token* tok) { |
1279 | 39.6k | if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")))) |
1280 | 37.3k | return false; |
1281 | 2.34k | tok = tok->next(); |
1282 | 2.34k | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))) |
1283 | 2.19k | return false; |
1284 | 147 | return true; |
1285 | 2.34k | } |
1286 | | // pattern: ;|{|} %var% = |
1287 | 39.6k | static inline bool match149(const Token* tok) { |
1288 | 39.6k | if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))) |
1289 | 29.1k | return false; |
1290 | 10.5k | tok = tok->next(); |
1291 | 10.5k | if (!tok || !(tok->varId() != 0)) |
1292 | 10.4k | return false; |
1293 | 25 | tok = tok->next(); |
1294 | 25 | if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("="))) |
1295 | 0 | return false; |
1296 | 25 | return true; |
1297 | 25 | } |
1298 | | // pattern: %type% |
1299 | 0 | static inline bool match150(const Token* tok) { |
1300 | 0 | if (!tok || !(tok->isName() && tok->varId() == 0U)) |
1301 | 0 | return false; |
1302 | 0 | return true; |
1303 | 0 | } |
1304 | | // pattern: [;{}] %var% = |
1305 | 22.6k | static inline bool match151(const Token* tok) { |
1306 | 22.6k | if (!tok || tok->str().size() != 1U || !strchr(";{}", tok->str()[0])) |
1307 | 16.5k | return false; |
1308 | 6.15k | tok = tok->next(); |
1309 | 6.15k | if (!tok || !(tok->varId() != 0)) |
1310 | 6.14k | return false; |
1311 | 14 | tok = tok->next(); |
1312 | 14 | if (!tok || !((tok->tokType() == Token::eAssignmentOp) && tok->str() == MatchCompiler::makeConstString("="))) |
1313 | 0 | return false; |
1314 | 14 | return true; |
1315 | 14 | } |
1316 | | // pattern: [{[(<] |
1317 | 0 | static inline bool match152(const Token* tok) { |
1318 | 0 | if (!tok || tok->str().size() != 1U || !strchr("{[(<", tok->str()[0])) |
1319 | 0 | return false; |
1320 | 0 | return true; |
1321 | 0 | } |
1322 | | // pattern: %name%|%num% %name%|%num% |
1323 | 0 | static inline bool match153(const Token* tok) { |
1324 | 0 | if (!tok || !(tok->isName() || tok->isNumber())) |
1325 | 0 | return false; |
1326 | 0 | tok = tok->next(); |
1327 | 0 | if (!tok || !(tok->isName() || tok->isNumber())) |
1328 | 0 | return false; |
1329 | 0 | return true; |
1330 | 0 | } |
1331 | | /* |
1332 | | * Cppcheck - A tool for static C/C++ code analysis |
1333 | | * Copyright (C) 2007-2024 Cppcheck team. |
1334 | | * |
1335 | | * This program is free software: you can redistribute it and/or modify |
1336 | | * it under the terms of the GNU General Public License as published by |
1337 | | * the Free Software Foundation, either version 3 of the License, or |
1338 | | * (at your option) any later version. |
1339 | | * |
1340 | | * This program is distributed in the hope that it will be useful, |
1341 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1342 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1343 | | * GNU General Public License for more details. |
1344 | | * |
1345 | | * You should have received a copy of the GNU General Public License |
1346 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1347 | | */ |
1348 | | |
1349 | | /** |
1350 | | * @brief This is the ValueFlow component in Cppcheck. |
1351 | | * |
1352 | | * Each @sa Token in the token list has a list of values. These are |
1353 | | * the "possible" values for the Token at runtime. |
1354 | | * |
1355 | | * In the --debug and --debug-normal output you can see the ValueFlow data. For example: |
1356 | | * |
1357 | | * int f() |
1358 | | * { |
1359 | | * int x = 10; |
1360 | | * return 4 * x + 2; |
1361 | | * } |
1362 | | * |
1363 | | * The --debug-normal output says: |
1364 | | * |
1365 | | * ##Value flow |
1366 | | * Line 3 |
1367 | | * 10 always 10 |
1368 | | * Line 4 |
1369 | | * 4 always 4 |
1370 | | * * always 40 |
1371 | | * x always 10 |
1372 | | * + always 42 |
1373 | | * 2 always 2 |
1374 | | * |
1375 | | * All value flow analysis is executed in the ValueFlow::setValues() function. The ValueFlow analysis is executed after |
1376 | | * the tokenizer/ast/symboldatabase/etc.. The ValueFlow analysis is done in a series of valueFlow* function calls, where |
1377 | | * each such function call can only use results from previous function calls. The function calls should be arranged so |
1378 | | * that valueFlow* that do not require previous ValueFlow information should be first. |
1379 | | * |
1380 | | * Type of analysis |
1381 | | * ================ |
1382 | | * |
1383 | | * This is "flow sensitive" value flow analysis. We _usually_ track the value for 1 variable at a time. |
1384 | | * |
1385 | | * How are calculations handled |
1386 | | * ============================ |
1387 | | * |
1388 | | * Here is an example code: |
1389 | | * |
1390 | | * x = 3 + 4; |
1391 | | * |
1392 | | * The valueFlowNumber set the values for the "3" and "4" tokens by calling setTokenValue(). |
1393 | | * The setTokenValue() handle the calculations automatically. When both "3" and "4" have values, the "+" can be |
1394 | | * calculated. setTokenValue() recursively calls itself when parents in calculations can be calculated. |
1395 | | * |
1396 | | * Forward / Reverse flow analysis |
1397 | | * =============================== |
1398 | | * |
1399 | | * In forward value flow analysis we know a value and see what happens when we are stepping the program forward. Like |
1400 | | * normal execution. The valueFlowForward is used in this analysis. |
1401 | | * |
1402 | | * In reverse value flow analysis we know the value of a variable at line X. And try to "execute backwards" to determine |
1403 | | * possible values before line X. The valueFlowReverse is used in this analysis. |
1404 | | * |
1405 | | * |
1406 | | */ |
1407 | | |
1408 | | #include "valueflow.h" |
1409 | | |
1410 | | #include "analyzer.h" |
1411 | | #include "astutils.h" |
1412 | | #include "calculate.h" |
1413 | | #include "checkuninitvar.h" |
1414 | | #include "config.h" |
1415 | | #include "errorlogger.h" |
1416 | | #include "errortypes.h" |
1417 | | #include "findtoken.h" |
1418 | | #include "forwardanalyzer.h" |
1419 | | #include "infer.h" |
1420 | | #include "library.h" |
1421 | | #include "mathlib.h" |
1422 | | #include "path.h" |
1423 | | #include "platform.h" |
1424 | | #include "programmemory.h" |
1425 | | #include "reverseanalyzer.h" |
1426 | | #include "settings.h" |
1427 | | #include "smallvector.h" |
1428 | | #include "sourcelocation.h" |
1429 | | #include "standards.h" |
1430 | | #include "symboldatabase.h" |
1431 | | #include "timer.h" |
1432 | | #include "token.h" |
1433 | | #include "tokenlist.h" |
1434 | | #include "utils.h" |
1435 | | #include "valueptr.h" |
1436 | | #include "vfvalue.h" |
1437 | | |
1438 | | #include "vf_analyzers.h" |
1439 | | #include "vf_common.h" |
1440 | | #include "vf_settokenvalue.h" |
1441 | | |
1442 | | #include <algorithm> |
1443 | | #include <array> |
1444 | | #include <cassert> |
1445 | | #include <chrono> |
1446 | | #include <cstdint> |
1447 | | #include <cstdlib> |
1448 | | #include <cstring> |
1449 | | #include <functional> |
1450 | | #include <initializer_list> |
1451 | | #include <iterator> |
1452 | | #include <limits> |
1453 | | #include <map> |
1454 | | #include <memory> |
1455 | | #include <numeric> |
1456 | | #include <set> |
1457 | | #include <sstream> |
1458 | | #include <string> |
1459 | | #include <unordered_map> |
1460 | | #include <unordered_set> |
1461 | | #include <vector> |
1462 | | |
1463 | | static void bailoutInternal(const std::string& type, |
1464 | | const TokenList& tokenlist, |
1465 | | ErrorLogger& errorLogger, |
1466 | | const Token* tok, |
1467 | | const std::string& what, |
1468 | | const std::string& file, |
1469 | | int line, |
1470 | | std::string function) |
1471 | 0 | { |
1472 | 0 | if (function.find("operator") != std::string::npos) |
1473 | 0 | function = "(valueFlow)"; |
1474 | 0 | ErrorMessage::FileLocation loc(tok, &tokenlist); |
1475 | 0 | const std::string location = Path::stripDirectoryPart(file) + ":" + std::to_string(line) + ":"; |
1476 | 0 | ErrorMessage errmsg({std::move(loc)}, |
1477 | 0 | tokenlist.getSourceFilePath(), |
1478 | 0 | Severity::debug, |
1479 | 0 | (file.empty() ? "" : location) + function + " bailout: " + what, |
1480 | 0 | type, |
1481 | 0 | Certainty::normal); |
1482 | 0 | errorLogger.reportErr(errmsg); |
1483 | 0 | } |
1484 | | |
1485 | | #define bailout2(type, tokenlist, errorLogger, tok, what) \ |
1486 | 0 | bailoutInternal((type), (tokenlist), (errorLogger), (tok), (what), __FILE__, __LINE__, __func__) |
1487 | | |
1488 | | #define bailout(tokenlist, errorLogger, tok, what) \ |
1489 | 0 | bailout2("valueFlowBailout", (tokenlist), (errorLogger), (tok), (what)) |
1490 | | |
1491 | | #define bailoutIncompleteVar(tokenlist, errorLogger, tok, what) \ |
1492 | 0 | bailoutInternal("valueFlowBailoutIncompleteVar", (tokenlist), (errorLogger), (tok), (what), "", 0, __func__) |
1493 | | |
1494 | | static void changeKnownToPossible(std::list<ValueFlow::Value>& values, int indirect = -1) |
1495 | 1.28k | { |
1496 | 1.97k | for (ValueFlow::Value& v : values) { |
1497 | 1.97k | if (indirect >= 0 && v.indirect != indirect) |
1498 | 0 | continue; |
1499 | 1.97k | v.changeKnownToPossible(); |
1500 | 1.97k | } |
1501 | 1.28k | } |
1502 | | |
1503 | | static void removeImpossible(std::list<ValueFlow::Value>& values, int indirect = -1) |
1504 | 0 | { |
1505 | 0 | values.remove_if([&](const ValueFlow::Value& v) { |
1506 | 0 | if (indirect >= 0 && v.indirect != indirect) |
1507 | 0 | return false; |
1508 | 0 | return v.isImpossible(); |
1509 | 0 | }); |
1510 | 0 | } |
1511 | | |
1512 | | static void lowerToPossible(std::list<ValueFlow::Value>& values, int indirect = -1) |
1513 | 0 | { |
1514 | 0 | changeKnownToPossible(values, indirect); |
1515 | 0 | removeImpossible(values, indirect); |
1516 | 0 | } |
1517 | | |
1518 | | static void changePossibleToKnown(std::list<ValueFlow::Value>& values, int indirect = -1) |
1519 | 253 | { |
1520 | 253 | for (ValueFlow::Value& v : values) { |
1521 | 253 | if (indirect >= 0 && v.indirect != indirect) |
1522 | 0 | continue; |
1523 | 253 | if (!v.isPossible()) |
1524 | 23 | continue; |
1525 | 230 | if (v.bound != ValueFlow::Value::Bound::Point) |
1526 | 0 | continue; |
1527 | 230 | v.setKnown(); |
1528 | 230 | } |
1529 | 253 | } |
1530 | | |
1531 | | static bool isNonConditionalPossibleIntValue(const ValueFlow::Value& v) |
1532 | 0 | { |
1533 | 0 | if (v.conditional) |
1534 | 0 | return false; |
1535 | 0 | if (v.condition) |
1536 | 0 | return false; |
1537 | 0 | if (!v.isPossible()) |
1538 | 0 | return false; |
1539 | 0 | if (!v.isIntValue()) |
1540 | 0 | return false; |
1541 | 0 | return true; |
1542 | 0 | } |
1543 | | |
1544 | | static void setValueUpperBound(ValueFlow::Value& value, bool upper) |
1545 | 3.28k | { |
1546 | 3.28k | if (upper) |
1547 | 1.64k | value.bound = ValueFlow::Value::Bound::Upper; |
1548 | 1.64k | else |
1549 | 1.64k | value.bound = ValueFlow::Value::Bound::Lower; |
1550 | 3.28k | } |
1551 | | |
1552 | | static void setValueBound(ValueFlow::Value& value, const Token* tok, bool invert) |
1553 | 5.03k | { |
1554 | 5.03k | if (match1(tok)) { |
1555 | 1.94k | setValueUpperBound(value, !invert); |
1556 | 3.09k | } else if (match2(tok)) { |
1557 | 1.34k | setValueUpperBound(value, invert); |
1558 | 1.34k | } |
1559 | 5.03k | } |
1560 | | |
1561 | | static void setConditionalValue(ValueFlow::Value& value, const Token* tok, MathLib::bigint i) |
1562 | 5.03k | { |
1563 | 5.03k | assert(value.isIntValue()); |
1564 | 5.03k | value.intvalue = i; |
1565 | 5.03k | value.assumeCondition(tok); |
1566 | 5.03k | value.setPossible(); |
1567 | 5.03k | } |
1568 | | |
1569 | | static void setConditionalValues(const Token* tok, |
1570 | | bool lhs, |
1571 | | MathLib::bigint value, |
1572 | | ValueFlow::Value& true_value, |
1573 | | ValueFlow::Value& false_value) |
1574 | 2.51k | { |
1575 | 2.51k | if (match3(tok)) { |
1576 | 1.22k | setConditionalValue(true_value, tok, value); |
1577 | 1.22k | const char* greaterThan = ">="; |
1578 | 1.22k | const char* lessThan = "<="; |
1579 | 1.22k | if (lhs) |
1580 | 658 | std::swap(greaterThan, lessThan); |
1581 | 1.22k | if (Token::simpleMatch(tok, greaterThan, strlen(greaterThan))) { |
1582 | 180 | setConditionalValue(false_value, tok, value - 1); |
1583 | 1.04k | } else if (Token::simpleMatch(tok, lessThan, strlen(lessThan))) { |
1584 | 170 | setConditionalValue(false_value, tok, value + 1); |
1585 | 874 | } else { |
1586 | 874 | setConditionalValue(false_value, tok, value); |
1587 | 874 | } |
1588 | 1.29k | } else { |
1589 | 1.29k | const char* greaterThan = ">"; |
1590 | 1.29k | const char* lessThan = "<"; |
1591 | 1.29k | if (lhs) |
1592 | 656 | std::swap(greaterThan, lessThan); |
1593 | 1.29k | if (Token::simpleMatch(tok, greaterThan, strlen(greaterThan))) { |
1594 | 650 | setConditionalValue(true_value, tok, value + 1); |
1595 | 650 | setConditionalValue(false_value, tok, value); |
1596 | 650 | } else if (Token::simpleMatch(tok, lessThan, strlen(lessThan))) { |
1597 | 644 | setConditionalValue(true_value, tok, value - 1); |
1598 | 644 | setConditionalValue(false_value, tok, value); |
1599 | 644 | } |
1600 | 1.29k | } |
1601 | 2.51k | setValueBound(true_value, tok, lhs); |
1602 | 2.51k | setValueBound(false_value, tok, !lhs); |
1603 | 2.51k | } |
1604 | | |
1605 | | static bool isSaturated(MathLib::bigint value) |
1606 | 578 | { |
1607 | 578 | return value == std::numeric_limits<MathLib::bigint>::max() || value == std::numeric_limits<MathLib::bigint>::min(); |
1608 | 578 | } |
1609 | | |
1610 | | static void parseCompareEachInt( |
1611 | | const Token* tok, |
1612 | | const std::function<void(const Token* varTok, ValueFlow::Value true_value, ValueFlow::Value false_value)>& each, |
1613 | | const std::function<std::vector<ValueFlow::Value>(const Token*)>& evaluate) |
1614 | 32.5k | { |
1615 | 32.5k | if (!tok->astOperand1() || !tok->astOperand2()) |
1616 | 17.1k | return; |
1617 | 15.4k | if (tok->isComparisonOp()) { |
1618 | 7.23k | std::vector<ValueFlow::Value> value1 = evaluate(tok->astOperand1()); |
1619 | 7.23k | std::vector<ValueFlow::Value> value2 = evaluate(tok->astOperand2()); |
1620 | 7.23k | if (!value1.empty() && !value2.empty()) { |
1621 | 18 | if (tok->astOperand1()->hasKnownIntValue()) |
1622 | 0 | value2.clear(); |
1623 | 18 | if (tok->astOperand2()->hasKnownIntValue()) |
1624 | 4 | value1.clear(); |
1625 | 18 | } |
1626 | 7.23k | for (const ValueFlow::Value& v1 : value1) { |
1627 | 344 | if (isSaturated(v1.intvalue) || astIsFloat(tok->astOperand2(), /*unknown*/ false)) |
1628 | 0 | continue; |
1629 | 344 | ValueFlow::Value true_value = v1; |
1630 | 344 | ValueFlow::Value false_value = v1; |
1631 | 344 | setConditionalValues(tok, true, v1.intvalue, true_value, false_value); |
1632 | 344 | each(tok->astOperand2(), std::move(true_value), std::move(false_value)); |
1633 | 344 | } |
1634 | 7.23k | for (const ValueFlow::Value& v2 : value2) { |
1635 | 234 | if (isSaturated(v2.intvalue) || astIsFloat(tok->astOperand1(), /*unknown*/ false)) |
1636 | 0 | continue; |
1637 | 234 | ValueFlow::Value true_value = v2; |
1638 | 234 | ValueFlow::Value false_value = v2; |
1639 | 234 | setConditionalValues(tok, false, v2.intvalue, true_value, false_value); |
1640 | 234 | each(tok->astOperand1(), std::move(true_value), std::move(false_value)); |
1641 | 234 | } |
1642 | 7.23k | } |
1643 | 15.4k | } |
1644 | | |
1645 | | static void parseCompareEachInt( |
1646 | | const Token* tok, |
1647 | | const std::function<void(const Token* varTok, ValueFlow::Value true_value, ValueFlow::Value false_value)>& each) |
1648 | 31.2k | { |
1649 | 31.2k | parseCompareEachInt(tok, each, [](const Token* t) -> std::vector<ValueFlow::Value> { |
1650 | 12.0k | if (t->hasKnownIntValue()) |
1651 | 496 | return {t->values().front()}; |
1652 | 11.5k | std::vector<ValueFlow::Value> result; |
1653 | 11.5k | std::copy_if(t->values().cbegin(), t->values().cend(), std::back_inserter(result), [&](const ValueFlow::Value& v) { |
1654 | 2.01k | if (v.path < 1) |
1655 | 2.01k | return false; |
1656 | 0 | if (!isNonConditionalPossibleIntValue(v)) |
1657 | 0 | return false; |
1658 | 0 | return true; |
1659 | 0 | }); |
1660 | 11.5k | return result; |
1661 | 12.0k | }); |
1662 | 31.2k | } |
1663 | | |
1664 | | const Token* ValueFlow::parseCompareInt(const Token* tok, |
1665 | | ValueFlow::Value& true_value, |
1666 | | ValueFlow::Value& false_value, |
1667 | | const std::function<std::vector<MathLib::bigint>(const Token*)>& evaluate) |
1668 | 1.23k | { |
1669 | 1.23k | const Token* result = nullptr; |
1670 | 1.23k | parseCompareEachInt( |
1671 | 1.23k | tok, |
1672 | 1.23k | [&](const Token* vartok, ValueFlow::Value true_value2, ValueFlow::Value false_value2) { |
1673 | 82 | if (result) |
1674 | 14 | return; |
1675 | 68 | result = vartok; |
1676 | 68 | true_value = std::move(true_value2); |
1677 | 68 | false_value = std::move(false_value2); |
1678 | 68 | }, |
1679 | 2.47k | [&](const Token* t) -> std::vector<ValueFlow::Value> { |
1680 | 2.47k | std::vector<ValueFlow::Value> r; |
1681 | 2.47k | std::vector<MathLib::bigint> v = evaluate(t); |
1682 | | |
1683 | 2.47k | std::transform(v.cbegin(), v.cend(), std::back_inserter(r), [&](MathLib::bigint i) { |
1684 | 86 | return ValueFlow::Value{i}; |
1685 | 86 | }); |
1686 | 2.47k | return r; |
1687 | 2.47k | }); |
1688 | 1.23k | return result; |
1689 | 1.23k | } |
1690 | | |
1691 | | const Token *ValueFlow::parseCompareInt(const Token *tok, ValueFlow::Value &true_value, ValueFlow::Value &false_value) |
1692 | 0 | { |
1693 | 0 | return parseCompareInt(tok, true_value, false_value, [](const Token* t) -> std::vector<MathLib::bigint> { |
1694 | 0 | if (t->hasKnownIntValue()) |
1695 | 0 | return {t->values().front().intvalue}; |
1696 | 0 | return std::vector<MathLib::bigint>{}; |
1697 | 0 | }); |
1698 | 0 | } |
1699 | | |
1700 | | static bool isEscapeScope(const Token* tok, const Settings& settings, bool unknown = false) |
1701 | 30 | { |
1702 | 30 | if (!match4(tok)) |
1703 | 0 | return false; |
1704 | | // TODO this search for termTok in all subscopes. It should check the end of the scope. |
1705 | 30 | const Token* termTok = findmatch5(tok, tok->link()) ; |
1706 | 30 | if (termTok && termTok->scope() == tok->scope()) |
1707 | 1 | return true; |
1708 | 29 | std::string unknownFunction; |
1709 | 29 | if (settings.library.isScopeNoReturn(tok->link(), &unknownFunction)) |
1710 | 0 | return unknownFunction.empty() || unknown; |
1711 | 29 | return false; |
1712 | 29 | } |
1713 | | |
1714 | | void ValueFlow::combineValueProperties(const ValueFlow::Value &value1, const ValueFlow::Value &value2, ValueFlow::Value &result) |
1715 | 7 | { |
1716 | 7 | if (value1.isKnown() && value2.isKnown()) |
1717 | 1 | result.setKnown(); |
1718 | 6 | else if (value1.isImpossible() || value2.isImpossible()) |
1719 | 0 | result.setImpossible(); |
1720 | 6 | else if (value1.isInconclusive() || value2.isInconclusive()) |
1721 | 0 | result.setInconclusive(); |
1722 | 6 | else |
1723 | 6 | result.setPossible(); |
1724 | 7 | if (value1.tokvalue) |
1725 | 1 | result.tokvalue = value1.tokvalue; |
1726 | 6 | else if (value2.tokvalue) |
1727 | 1 | result.tokvalue = value2.tokvalue; |
1728 | 7 | if (value1.isSymbolicValue()) { |
1729 | 0 | result.valueType = value1.valueType; |
1730 | 0 | result.tokvalue = value1.tokvalue; |
1731 | 0 | } |
1732 | 7 | if (value2.isSymbolicValue()) { |
1733 | 0 | result.valueType = value2.valueType; |
1734 | 0 | result.tokvalue = value2.tokvalue; |
1735 | 0 | } |
1736 | 7 | if (value1.isIteratorValue()) |
1737 | 0 | result.valueType = value1.valueType; |
1738 | 7 | if (value2.isIteratorValue()) |
1739 | 0 | result.valueType = value2.valueType; |
1740 | 7 | result.condition = value1.condition ? value1.condition : value2.condition; |
1741 | 7 | result.varId = (value1.varId != 0) ? value1.varId : value2.varId; |
1742 | 7 | result.varvalue = (result.varId == value1.varId) ? value1.varvalue : value2.varvalue; |
1743 | 7 | result.errorPath = (value1.errorPath.empty() ? value2 : value1).errorPath; |
1744 | 7 | result.safe = value1.safe || value2.safe; |
1745 | 7 | if (value1.bound == ValueFlow::Value::Bound::Point || value2.bound == ValueFlow::Value::Bound::Point) { |
1746 | 7 | if (value1.bound == ValueFlow::Value::Bound::Upper || value2.bound == ValueFlow::Value::Bound::Upper) |
1747 | 0 | result.bound = ValueFlow::Value::Bound::Upper; |
1748 | 7 | if (value1.bound == ValueFlow::Value::Bound::Lower || value2.bound == ValueFlow::Value::Bound::Lower) |
1749 | 0 | result.bound = ValueFlow::Value::Bound::Lower; |
1750 | 7 | } |
1751 | 7 | if (value1.path != value2.path) |
1752 | 0 | result.path = -1; |
1753 | 7 | else |
1754 | 7 | result.path = value1.path; |
1755 | 7 | } |
1756 | | |
1757 | | |
1758 | | template<class F> |
1759 | | static size_t accumulateStructMembers(const Scope* scope, F f) |
1760 | 0 | { |
1761 | 0 | size_t total = 0; |
1762 | 0 | std::set<const Scope*> anonScopes; |
1763 | 0 | for (const Variable& var : scope->varlist) { |
1764 | 0 | if (var.isStatic()) |
1765 | 0 | continue; |
1766 | 0 | if (const ValueType* vt = var.valueType()) { |
1767 | 0 | if (vt->type == ValueType::Type::RECORD && vt->typeScope == scope) |
1768 | 0 | return 0; |
1769 | 0 | const MathLib::bigint dim = std::accumulate(var.dimensions().cbegin(), var.dimensions().cend(), 1LL, [](MathLib::bigint i1, const Dimension& dim) { |
1770 | 0 | return i1 * dim.num; |
1771 | 0 | }); Unexecuted instantiation: valueflow.cpp:accumulateStructMembers<getAlignOf(ValueType const&, Settings const&, int)::$_0>(Scope const*, getAlignOf(ValueType const&, Settings const&, int)::$_0)::{lambda(long long, Dimension const&)#1}::operator()(long long, Dimension const&) const Unexecuted instantiation: valueflow.cpp:accumulateStructMembers<ValueFlow::getSizeOf(ValueType const&, Settings const&, int)::$_0>(Scope const*, ValueFlow::getSizeOf(ValueType const&, Settings const&, int)::$_0)::{lambda(long long, Dimension const&)#1}::operator()(long long, Dimension const&) const |
1772 | 0 | if (var.nameToken()->scope() != scope && var.nameToken()->scope()->definedType) { // anonymous union |
1773 | 0 | const auto ret = anonScopes.insert(var.nameToken()->scope()); |
1774 | 0 | if (ret.second) |
1775 | 0 | total = f(total, *vt, dim); |
1776 | 0 | } |
1777 | 0 | else |
1778 | 0 | total = f(total, *vt, dim); |
1779 | 0 | } |
1780 | 0 | if (total == 0) |
1781 | 0 | return 0; |
1782 | 0 | } |
1783 | 0 | return total; |
1784 | 0 | } Unexecuted instantiation: valueflow.cpp:unsigned long accumulateStructMembers<getAlignOf(ValueType const&, Settings const&, int)::$_0>(Scope const*, getAlignOf(ValueType const&, Settings const&, int)::$_0) Unexecuted instantiation: valueflow.cpp:unsigned long accumulateStructMembers<ValueFlow::getSizeOf(ValueType const&, Settings const&, int)::$_0>(Scope const*, ValueFlow::getSizeOf(ValueType const&, Settings const&, int)::$_0) |
1785 | | |
1786 | | static size_t bitCeil(size_t x) |
1787 | 0 | { |
1788 | 0 | if (x <= 1) |
1789 | 0 | return 1; |
1790 | 0 | --x; |
1791 | 0 | x |= x >> 1; |
1792 | 0 | x |= x >> 2; |
1793 | 0 | x |= x >> 4; |
1794 | 0 | x |= x >> 8; |
1795 | 0 | x |= x >> 16; |
1796 | 0 | x |= x >> 32; |
1797 | 0 | return x + 1; |
1798 | 0 | } |
1799 | | |
1800 | | static size_t getAlignOf(const ValueType& vt, const Settings& settings, int maxRecursion = 0) |
1801 | 0 | { |
1802 | 0 | if (maxRecursion == settings.vfOptions.maxAlignOfRecursion) { |
1803 | | // TODO: add bailout message |
1804 | 0 | return 0; |
1805 | 0 | } |
1806 | 0 | if (vt.pointer || vt.reference != Reference::None || vt.isPrimitive()) { |
1807 | 0 | auto align = ValueFlow::getSizeOf(vt, settings); |
1808 | 0 | return align == 0 ? 0 : bitCeil(align); |
1809 | 0 | } |
1810 | 0 | if (vt.type == ValueType::Type::RECORD && vt.typeScope) { |
1811 | 0 | auto accHelper = [&](size_t max, const ValueType& vt2, size_t /*dim*/) { |
1812 | 0 | size_t a = getAlignOf(vt2, settings, ++maxRecursion); |
1813 | 0 | return std::max(max, a); |
1814 | 0 | }; |
1815 | 0 | size_t total = 0; |
1816 | 0 | if (const Type* dt = vt.typeScope->definedType) { |
1817 | 0 | total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const Type::BaseInfo& bi) { |
1818 | 0 | if (bi.type && bi.type->classScope) |
1819 | 0 | v += accumulateStructMembers(bi.type->classScope, accHelper); |
1820 | 0 | return v; |
1821 | 0 | }); |
1822 | 0 | } |
1823 | 0 | return total + accumulateStructMembers(vt.typeScope, accHelper); |
1824 | 0 | } |
1825 | 0 | if (vt.type == ValueType::Type::CONTAINER) |
1826 | 0 | return settings.platform.sizeof_pointer; // Just guess |
1827 | 0 | return 0; |
1828 | 0 | } |
1829 | | |
1830 | | size_t ValueFlow::getSizeOf(const ValueType &vt, const Settings &settings, int maxRecursion) |
1831 | 280 | { |
1832 | 280 | if (maxRecursion == settings.vfOptions.maxSizeOfRecursion) { |
1833 | | // TODO: add bailout message |
1834 | 0 | return 0; |
1835 | 0 | } |
1836 | 280 | if (vt.pointer || vt.reference != Reference::None) |
1837 | 0 | return settings.platform.sizeof_pointer; |
1838 | 280 | if (vt.type == ValueType::Type::BOOL || vt.type == ValueType::Type::CHAR) |
1839 | 59 | return 1; |
1840 | 221 | if (vt.type == ValueType::Type::SHORT) |
1841 | 0 | return settings.platform.sizeof_short; |
1842 | 221 | if (vt.type == ValueType::Type::WCHAR_T) |
1843 | 0 | return settings.platform.sizeof_wchar_t; |
1844 | 221 | if (vt.type == ValueType::Type::INT) |
1845 | 221 | return settings.platform.sizeof_int; |
1846 | 0 | if (vt.type == ValueType::Type::LONG) |
1847 | 0 | return settings.platform.sizeof_long; |
1848 | 0 | if (vt.type == ValueType::Type::LONGLONG) |
1849 | 0 | return settings.platform.sizeof_long_long; |
1850 | 0 | if (vt.type == ValueType::Type::FLOAT) |
1851 | 0 | return settings.platform.sizeof_float; |
1852 | 0 | if (vt.type == ValueType::Type::DOUBLE) |
1853 | 0 | return settings.platform.sizeof_double; |
1854 | 0 | if (vt.type == ValueType::Type::LONGDOUBLE) |
1855 | 0 | return settings.platform.sizeof_long_double; |
1856 | 0 | if (vt.type == ValueType::Type::CONTAINER) |
1857 | 0 | return 3 * settings.platform.sizeof_pointer; // Just guess |
1858 | 0 | if (vt.type == ValueType::Type::RECORD && vt.typeScope) { |
1859 | 0 | auto accHelper = [&](size_t total, const ValueType& vt2, size_t dim) -> size_t { |
1860 | 0 | size_t n = ValueFlow::getSizeOf(vt2, settings, ++maxRecursion); |
1861 | 0 | size_t a = getAlignOf(vt2, settings); |
1862 | 0 | if (n == 0 || a == 0) |
1863 | 0 | return 0; |
1864 | 0 | n *= dim; |
1865 | 0 | size_t padding = (a - (total % a)) % a; |
1866 | 0 | return vt.typeScope->type == Scope::eUnion ? std::max(total, n) : total + padding + n; |
1867 | 0 | }; |
1868 | 0 | size_t total = accumulateStructMembers(vt.typeScope, accHelper); |
1869 | 0 | if (const Type* dt = vt.typeScope->definedType) { |
1870 | 0 | total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const Type::BaseInfo& bi) { |
1871 | 0 | if (bi.type && bi.type->classScope) |
1872 | 0 | v += accumulateStructMembers(bi.type->classScope, accHelper); |
1873 | 0 | return v; |
1874 | 0 | }); |
1875 | 0 | } |
1876 | 0 | if (total == 0) |
1877 | 0 | return 0; |
1878 | 0 | size_t align = getAlignOf(vt, settings); |
1879 | 0 | if (align == 0) |
1880 | 0 | return 0; |
1881 | 0 | total += (align - (total % align)) % align; |
1882 | 0 | return total; |
1883 | 0 | } |
1884 | 0 | return 0; |
1885 | 0 | } |
1886 | | |
1887 | | static void valueFlowNumber(TokenList &tokenlist, const Settings& settings) |
1888 | 764 | { |
1889 | 55.6k | for (Token *tok = tokenlist.front(); tok;) { |
1890 | 54.9k | tok = ValueFlow::valueFlowSetConstantValue(tok, settings); |
1891 | 54.9k | } |
1892 | | |
1893 | 764 | if (tokenlist.isCPP() || settings.standards.c >= Standards::C23) { |
1894 | 55.6k | for (Token *tok = tokenlist.front(); tok; tok = tok->next()) { |
1895 | 54.9k | if (tok->isName() && !tok->varId() && match6(tok)) { |
1896 | 0 | ValueFlow::Value value(tok->str() == MatchCompiler::makeConstString("true")); |
1897 | 0 | if (!tok->isTemplateArg()) |
1898 | 0 | value.setKnown(); |
1899 | 0 | setTokenValue(tok, std::move(value), settings); |
1900 | 54.9k | } else if (match7(tok)) { |
1901 | | // NULL function parameters are not simplified in the |
1902 | | // normal tokenlist |
1903 | 0 | ValueFlow::Value value(0); |
1904 | 0 | if (!tok->isTemplateArg()) |
1905 | 0 | value.setKnown(); |
1906 | 0 | setTokenValue(tok->next(), std::move(value), settings); |
1907 | 0 | } |
1908 | 54.9k | } |
1909 | 764 | } |
1910 | 764 | } |
1911 | | |
1912 | | static void valueFlowString(TokenList& tokenlist, const Settings& settings) |
1913 | 764 | { |
1914 | 55.6k | for (Token* tok = tokenlist.front(); tok; tok = tok->next()) { |
1915 | 54.9k | if (tok->tokType() == Token::eString) { |
1916 | 0 | ValueFlow::Value strvalue; |
1917 | 0 | strvalue.valueType = ValueFlow::Value::ValueType::TOK; |
1918 | 0 | strvalue.tokvalue = tok; |
1919 | 0 | strvalue.setKnown(); |
1920 | 0 | setTokenValue(tok, std::move(strvalue), settings); |
1921 | 0 | } |
1922 | 54.9k | } |
1923 | 764 | } |
1924 | | |
1925 | | static void valueFlowArray(TokenList& tokenlist, const Settings& settings) |
1926 | 764 | { |
1927 | 764 | std::map<nonneg int, const Token*> constantArrays; |
1928 | | |
1929 | 55.6k | for (Token* tok = tokenlist.front(); tok; tok = tok->next()) { |
1930 | 54.9k | if (tok->varId() > 0) { |
1931 | | // array |
1932 | 11.6k | const auto it = utils::as_const(constantArrays).find(tok->varId()); |
1933 | 11.6k | if (it != constantArrays.end()) { |
1934 | 0 | ValueFlow::Value value; |
1935 | 0 | value.valueType = ValueFlow::Value::ValueType::TOK; |
1936 | 0 | value.tokvalue = it->second; |
1937 | 0 | value.setKnown(); |
1938 | 0 | setTokenValue(tok, std::move(value), settings); |
1939 | 0 | } |
1940 | | |
1941 | | // const array decl |
1942 | 11.6k | else if (tok->variable() && tok->variable()->isArray() && tok->variable()->isConst() && |
1943 | 11.6k | tok->variable()->nameToken() == tok && match8(tok)) { |
1944 | 0 | Token* rhstok = tok->linkAt(1)->tokAt(2); |
1945 | 0 | constantArrays[tok->varId()] = rhstok; |
1946 | 0 | tok = rhstok->link(); |
1947 | 0 | } |
1948 | | |
1949 | | // pointer = array |
1950 | 11.6k | else if (tok->variable() && tok->variable()->isArray() && match9(tok->astParent()) && |
1951 | 11.6k | astIsRHS(tok) && tok->astParent()->astOperand1() && tok->astParent()->astOperand1()->variable() && |
1952 | 11.6k | tok->astParent()->astOperand1()->variable()->isPointer()) { |
1953 | 0 | ValueFlow::Value value; |
1954 | 0 | value.valueType = ValueFlow::Value::ValueType::TOK; |
1955 | 0 | value.tokvalue = tok; |
1956 | 0 | value.setKnown(); |
1957 | 0 | setTokenValue(tok, std::move(value), settings); |
1958 | 0 | } |
1959 | 11.6k | continue; |
1960 | 11.6k | } |
1961 | | |
1962 | 43.2k | if (match10(tok)) { |
1963 | 0 | Token* vartok = tok->tokAt(2); |
1964 | 0 | Token* rhstok = vartok->linkAt(1)->tokAt(2); |
1965 | 0 | constantArrays[vartok->varId()] = rhstok; |
1966 | 0 | tok = rhstok->link(); |
1967 | 0 | continue; |
1968 | 0 | } |
1969 | | |
1970 | 43.2k | if (match11(tok)) { |
1971 | 0 | Token* vartok = tok->tokAt(2); |
1972 | 0 | Token* strtok = vartok->linkAt(1)->tokAt(2); |
1973 | 0 | constantArrays[vartok->varId()] = strtok; |
1974 | 0 | tok = strtok->next(); |
1975 | 0 | continue; |
1976 | 0 | } |
1977 | 43.2k | } |
1978 | 764 | } |
1979 | | |
1980 | | static bool isNonZero(const Token* tok) |
1981 | 0 | { |
1982 | 0 | return tok && (!tok->hasKnownIntValue() || tok->values().front().intvalue != 0); |
1983 | 0 | } |
1984 | | |
1985 | | static const Token* getOtherOperand(const Token* tok) |
1986 | 0 | { |
1987 | 0 | if (!tok) |
1988 | 0 | return nullptr; |
1989 | 0 | if (!tok->astParent()) |
1990 | 0 | return nullptr; |
1991 | 0 | if (tok->astParent()->astOperand1() != tok) |
1992 | 0 | return tok->astParent()->astOperand1(); |
1993 | 0 | if (tok->astParent()->astOperand2() != tok) |
1994 | 0 | return tok->astParent()->astOperand2(); |
1995 | 0 | return nullptr; |
1996 | 0 | } |
1997 | | |
1998 | | static void valueFlowArrayBool(TokenList& tokenlist, const Settings& settings) |
1999 | 1.17k | { |
2000 | 90.3k | for (Token* tok = tokenlist.front(); tok; tok = tok->next()) { |
2001 | 89.1k | if (tok->hasKnownIntValue()) |
2002 | 13.6k | continue; |
2003 | 75.5k | const Variable* var = nullptr; |
2004 | 75.5k | bool known = false; |
2005 | 75.5k | const auto val = |
2006 | 75.5k | std::find_if(tok->values().cbegin(), tok->values().cend(), std::mem_fn(&ValueFlow::Value::isTokValue)); |
2007 | 75.5k | if (val == tok->values().end()) { |
2008 | 75.5k | var = tok->variable(); |
2009 | 75.5k | known = true; |
2010 | 75.5k | } else { |
2011 | 0 | var = val->tokvalue->variable(); |
2012 | 0 | known = val->isKnown(); |
2013 | 0 | } |
2014 | 75.5k | if (!var) |
2015 | 56.6k | continue; |
2016 | 18.9k | if (!var->isArray() || var->isArgument() || var->isStlType()) |
2017 | 18.9k | continue; |
2018 | 0 | if (isNonZero(getOtherOperand(tok)) && match12(tok->astParent())) |
2019 | 0 | continue; |
2020 | | // TODO: Check for function argument |
2021 | 0 | if ((astIsBool(tok->astParent()) && !match13(tok->astParent())) || |
2022 | 0 | (tok->astParent() && match14(tok->astParent()->previous()))) { |
2023 | 0 | ValueFlow::Value value{1}; |
2024 | 0 | if (known) |
2025 | 0 | value.setKnown(); |
2026 | 0 | setTokenValue(tok, std::move(value), settings); |
2027 | 0 | } |
2028 | 0 | } |
2029 | 1.17k | } |
2030 | | |
2031 | | static void valueFlowArrayElement(TokenList& tokenlist, const Settings& settings) |
2032 | 1.17k | { |
2033 | 90.3k | for (Token* tok = tokenlist.front(); tok; tok = tok->next()) { |
2034 | 89.1k | if (tok->hasKnownIntValue()) |
2035 | 13.6k | continue; |
2036 | 75.5k | const Token* indexTok = nullptr; |
2037 | 75.5k | const Token* arrayTok = nullptr; |
2038 | 75.5k | if (match15(tok) && tok->isBinaryOp()) { |
2039 | 0 | indexTok = tok->astOperand2(); |
2040 | 0 | arrayTok = tok->astOperand1(); |
2041 | 75.5k | } else if (match16(tok->tokAt(-2)) && astIsContainer(tok->tokAt(-2)->astOperand1())) { |
2042 | 0 | arrayTok = tok->tokAt(-2)->astOperand1(); |
2043 | 0 | const Library::Container* container = getLibraryContainer(arrayTok); |
2044 | 0 | if (!container || container->stdAssociativeLike) |
2045 | 0 | continue; |
2046 | 0 | const Library::Container::Yield yield = container->getYield(tok->strAt(-1)); |
2047 | 0 | if (yield != Library::Container::Yield::AT_INDEX) |
2048 | 0 | continue; |
2049 | 0 | indexTok = tok->astOperand2(); |
2050 | 0 | } |
2051 | | |
2052 | 75.5k | if (!indexTok || !arrayTok) |
2053 | 75.5k | continue; |
2054 | | |
2055 | 0 | for (const ValueFlow::Value& arrayValue : arrayTok->values()) { |
2056 | 0 | if (!arrayValue.isTokValue()) |
2057 | 0 | continue; |
2058 | 0 | if (arrayValue.isImpossible()) |
2059 | 0 | continue; |
2060 | 0 | for (const ValueFlow::Value& indexValue : indexTok->values()) { |
2061 | 0 | if (!indexValue.isIntValue()) |
2062 | 0 | continue; |
2063 | 0 | if (indexValue.isImpossible()) |
2064 | 0 | continue; |
2065 | 0 | if (!arrayValue.isKnown() && !indexValue.isKnown() && arrayValue.varId != 0 && indexValue.varId != 0 && |
2066 | 0 | !(arrayValue.varId == indexValue.varId && arrayValue.varvalue == indexValue.varvalue)) |
2067 | 0 | continue; |
2068 | | |
2069 | 0 | ValueFlow::Value result(0); |
2070 | 0 | result.condition = arrayValue.condition ? arrayValue.condition : indexValue.condition; |
2071 | 0 | result.setInconclusive(arrayValue.isInconclusive() || indexValue.isInconclusive()); |
2072 | 0 | result.varId = (arrayValue.varId != 0) ? arrayValue.varId : indexValue.varId; |
2073 | 0 | result.varvalue = (result.varId == arrayValue.varId) ? arrayValue.intvalue : indexValue.intvalue; |
2074 | 0 | if (arrayValue.valueKind == indexValue.valueKind) |
2075 | 0 | result.valueKind = arrayValue.valueKind; |
2076 | |
|
2077 | 0 | result.errorPath.insert(result.errorPath.end(), |
2078 | 0 | arrayValue.errorPath.cbegin(), |
2079 | 0 | arrayValue.errorPath.cend()); |
2080 | 0 | result.errorPath.insert(result.errorPath.end(), |
2081 | 0 | indexValue.errorPath.cbegin(), |
2082 | 0 | indexValue.errorPath.cend()); |
2083 | |
|
2084 | 0 | const MathLib::bigint index = indexValue.intvalue; |
2085 | |
|
2086 | 0 | if (arrayValue.tokvalue->tokType() == Token::eString) { |
2087 | 0 | const std::string s = arrayValue.tokvalue->strValue(); |
2088 | 0 | if (index == s.size()) { |
2089 | 0 | result.intvalue = 0; |
2090 | 0 | setTokenValue(tok, std::move(result), settings); |
2091 | 0 | } else if (index >= 0 && index < s.size()) { |
2092 | 0 | result.intvalue = s[static_cast<std::size_t>(index)]; |
2093 | 0 | setTokenValue(tok, std::move(result), settings); |
2094 | 0 | } |
2095 | 0 | } else if (match4(arrayValue.tokvalue)) { |
2096 | 0 | std::vector<const Token*> args = getArguments(arrayValue.tokvalue); |
2097 | 0 | if (index < 0 || index >= args.size()) |
2098 | 0 | continue; |
2099 | 0 | const Token* arg = args[static_cast<std::size_t>(index)]; |
2100 | 0 | if (!arg->hasKnownIntValue()) |
2101 | 0 | continue; |
2102 | 0 | const ValueFlow::Value& v = arg->values().front(); |
2103 | 0 | result.intvalue = v.intvalue; |
2104 | 0 | result.errorPath.insert(result.errorPath.end(), v.errorPath.cbegin(), v.errorPath.cend()); |
2105 | 0 | setTokenValue(tok, std::move(result), settings); |
2106 | 0 | } |
2107 | 0 | } |
2108 | 0 | } |
2109 | 0 | } |
2110 | 1.17k | } |
2111 | | |
2112 | | static void valueFlowPointerAlias(TokenList& tokenlist, const Settings& settings) |
2113 | 764 | { |
2114 | 55.6k | for (Token* tok = tokenlist.front(); tok; tok = tok->next()) { |
2115 | | // not address of |
2116 | 54.9k | if (!tok->isUnaryOp("&")) |
2117 | 54.9k | continue; |
2118 | | |
2119 | | // parent should be a '=' |
2120 | 4 | if (!match9(tok->astParent())) |
2121 | 4 | continue; |
2122 | | |
2123 | | // child should be some buffer or variable |
2124 | 0 | const Token* vartok = tok->astOperand1(); |
2125 | 0 | while (vartok) { |
2126 | 0 | if (vartok->str() == MatchCompiler::makeConstString("[")) |
2127 | 0 | vartok = vartok->astOperand1(); |
2128 | 0 | else if (vartok->str() == MatchCompiler::makeConstString(".") || vartok->str() == MatchCompiler::makeConstString("::")) |
2129 | 0 | vartok = vartok->astOperand2(); |
2130 | 0 | else |
2131 | 0 | break; |
2132 | 0 | } |
2133 | 0 | if (!(vartok && vartok->variable() && !vartok->variable()->isPointer())) |
2134 | 0 | continue; |
2135 | | |
2136 | 0 | ValueFlow::Value value; |
2137 | 0 | value.valueType = ValueFlow::Value::ValueType::TOK; |
2138 | 0 | value.tokvalue = tok; |
2139 | 0 | setTokenValue(tok, std::move(value), settings); |
2140 | 0 | } |
2141 | 764 | } |
2142 | | |
2143 | | static void valueFlowBitAnd(TokenList& tokenlist, const Settings& settings) |
2144 | 764 | { |
2145 | 55.6k | for (Token* tok = tokenlist.front(); tok; tok = tok->next()) { |
2146 | 54.9k | if (tok->str() != MatchCompiler::makeConstString("&")) |
2147 | 54.7k | continue; |
2148 | | |
2149 | 139 | if (tok->hasKnownValue()) |
2150 | 2 | continue; |
2151 | | |
2152 | 137 | if (!tok->astOperand1() || !tok->astOperand2()) |
2153 | 10 | continue; |
2154 | | |
2155 | 127 | MathLib::bigint number; |
2156 | 127 | if (MathLib::isInt(tok->astOperand1()->str())) |
2157 | 1 | number = MathLib::toBigNumber(tok->astOperand1()); |
2158 | 126 | else if (MathLib::isInt(tok->astOperand2()->str())) |
2159 | 3 | number = MathLib::toBigNumber(tok->astOperand2()); |
2160 | 123 | else |
2161 | 123 | continue; |
2162 | | |
2163 | 4 | int bit = 0; |
2164 | 8 | while (bit <= (MathLib::bigint_bits - 2) && ((((MathLib::bigint)1) << bit) < number)) |
2165 | 4 | ++bit; |
2166 | | |
2167 | 4 | if ((((MathLib::bigint)1) << bit) == number) { |
2168 | 3 | setTokenValue(tok, ValueFlow::Value(0), settings); |
2169 | 3 | setTokenValue(tok, ValueFlow::Value(number), settings); |
2170 | 3 | } |
2171 | 4 | } |
2172 | 764 | } |
2173 | | |
2174 | | static void valueFlowSameExpressions(TokenList& tokenlist, const Settings& settings) |
2175 | 764 | { |
2176 | 55.6k | for (Token* tok = tokenlist.front(); tok; tok = tok->next()) { |
2177 | 54.9k | if (tok->hasKnownIntValue()) |
2178 | 8.49k | continue; |
2179 | | |
2180 | 46.4k | if (!tok->astOperand1() || !tok->astOperand2()) |
2181 | 41.9k | continue; |
2182 | | |
2183 | 4.49k | if (tok->astOperand1()->isLiteral() || tok->astOperand2()->isLiteral()) |
2184 | 21 | continue; |
2185 | | |
2186 | 4.47k | if (!astIsIntegral(tok->astOperand1(), false) && !astIsIntegral(tok->astOperand2(), false)) |
2187 | 361 | continue; |
2188 | | |
2189 | 4.11k | long long val; |
2190 | | |
2191 | 4.11k | if (match17(tok)) { |
2192 | 350 | val = 1; |
2193 | 350 | } |
2194 | 3.76k | else if (match18(tok)) { |
2195 | 717 | val = 0; |
2196 | 717 | } |
2197 | 3.04k | else |
2198 | 3.04k | continue; |
2199 | | |
2200 | 1.06k | ValueFlow::Value value(val); |
2201 | 1.06k | value.setKnown(); |
2202 | | |
2203 | 1.06k | if (isSameExpression(false, tok->astOperand1(), tok->astOperand2(), settings, true, true, &value.errorPath)) { |
2204 | 265 | setTokenValue(tok, std::move(value), settings); |
2205 | 265 | } |
2206 | 1.06k | } |
2207 | 764 | } |
2208 | | |
2209 | | static bool getExpressionRange(const Token* expr, MathLib::bigint* minvalue, MathLib::bigint* maxvalue) |
2210 | 0 | { |
2211 | 0 | if (expr->hasKnownIntValue()) { |
2212 | 0 | if (minvalue) |
2213 | 0 | *minvalue = expr->values().front().intvalue; |
2214 | 0 | if (maxvalue) |
2215 | 0 | *maxvalue = expr->values().front().intvalue; |
2216 | 0 | return true; |
2217 | 0 | } |
2218 | | |
2219 | 0 | if (expr->str() == MatchCompiler::makeConstString("&") && expr->astOperand1() && expr->astOperand2()) { |
2220 | 0 | MathLib::bigint vals[4]; |
2221 | 0 | const bool lhsHasKnownRange = getExpressionRange(expr->astOperand1(), &vals[0], &vals[1]); |
2222 | 0 | const bool rhsHasKnownRange = getExpressionRange(expr->astOperand2(), &vals[2], &vals[3]); |
2223 | 0 | if (!lhsHasKnownRange && !rhsHasKnownRange) |
2224 | 0 | return false; |
2225 | 0 | if (!lhsHasKnownRange || !rhsHasKnownRange) { |
2226 | 0 | if (minvalue) |
2227 | 0 | *minvalue = lhsHasKnownRange ? vals[0] : vals[2]; |
2228 | 0 | if (maxvalue) |
2229 | 0 | *maxvalue = lhsHasKnownRange ? vals[1] : vals[3]; |
2230 | 0 | } else { |
2231 | 0 | if (minvalue) |
2232 | 0 | *minvalue = vals[0] & vals[2]; |
2233 | 0 | if (maxvalue) |
2234 | 0 | *maxvalue = vals[1] & vals[3]; |
2235 | 0 | } |
2236 | 0 | return true; |
2237 | 0 | } |
2238 | | |
2239 | 0 | if (expr->str() == MatchCompiler::makeConstString("%") && expr->astOperand1() && expr->astOperand2()) { |
2240 | 0 | MathLib::bigint vals[4]; |
2241 | 0 | if (!getExpressionRange(expr->astOperand2(), &vals[2], &vals[3])) |
2242 | 0 | return false; |
2243 | 0 | if (vals[2] <= 0) |
2244 | 0 | return false; |
2245 | 0 | const bool lhsHasKnownRange = getExpressionRange(expr->astOperand1(), &vals[0], &vals[1]); |
2246 | 0 | if (lhsHasKnownRange && vals[0] < 0) |
2247 | 0 | return false; |
2248 | | // If lhs has unknown value, it must be unsigned |
2249 | 0 | if (!lhsHasKnownRange && |
2250 | 0 | (!expr->astOperand1()->valueType() || expr->astOperand1()->valueType()->sign != ValueType::Sign::UNSIGNED)) |
2251 | 0 | return false; |
2252 | 0 | if (minvalue) |
2253 | 0 | *minvalue = 0; |
2254 | 0 | if (maxvalue) |
2255 | 0 | *maxvalue = vals[3] - 1; |
2256 | 0 | return true; |
2257 | 0 | } |
2258 | | |
2259 | 0 | return false; |
2260 | 0 | } |
2261 | | |
2262 | | static void valueFlowRightShift(TokenList& tokenList, const Settings& settings) |
2263 | 1.17k | { |
2264 | 90.3k | for (Token* tok = tokenList.front(); tok; tok = tok->next()) { |
2265 | 89.1k | if (tok->str() != MatchCompiler::makeConstString(">>")) |
2266 | 89.1k | continue; |
2267 | | |
2268 | 0 | if (tok->hasKnownValue()) |
2269 | 0 | continue; |
2270 | | |
2271 | 0 | if (!tok->astOperand1() || !tok->astOperand2()) |
2272 | 0 | continue; |
2273 | | |
2274 | 0 | if (!tok->astOperand2()->hasKnownValue()) |
2275 | 0 | continue; |
2276 | | |
2277 | 0 | const MathLib::bigint rhsvalue = tok->astOperand2()->values().front().intvalue; |
2278 | 0 | if (rhsvalue < 0) |
2279 | 0 | continue; |
2280 | | |
2281 | 0 | if (!tok->astOperand1()->valueType() || !tok->astOperand1()->valueType()->isIntegral()) |
2282 | 0 | continue; |
2283 | | |
2284 | 0 | if (!tok->astOperand2()->valueType() || !tok->astOperand2()->valueType()->isIntegral()) |
2285 | 0 | continue; |
2286 | | |
2287 | 0 | MathLib::bigint lhsmax = 0; |
2288 | 0 | if (!getExpressionRange(tok->astOperand1(), nullptr, &lhsmax)) |
2289 | 0 | continue; |
2290 | 0 | if (lhsmax < 0) |
2291 | 0 | continue; |
2292 | 0 | int lhsbits; |
2293 | 0 | if ((tok->astOperand1()->valueType()->type == ValueType::Type::CHAR) || |
2294 | 0 | (tok->astOperand1()->valueType()->type == ValueType::Type::SHORT) || |
2295 | 0 | (tok->astOperand1()->valueType()->type == ValueType::Type::WCHAR_T) || |
2296 | 0 | (tok->astOperand1()->valueType()->type == ValueType::Type::BOOL) || |
2297 | 0 | (tok->astOperand1()->valueType()->type == ValueType::Type::INT)) |
2298 | 0 | lhsbits = settings.platform.int_bit; |
2299 | 0 | else if (tok->astOperand1()->valueType()->type == ValueType::Type::LONG) |
2300 | 0 | lhsbits = settings.platform.long_bit; |
2301 | 0 | else if (tok->astOperand1()->valueType()->type == ValueType::Type::LONGLONG) |
2302 | 0 | lhsbits = settings.platform.long_long_bit; |
2303 | 0 | else |
2304 | 0 | continue; |
2305 | 0 | if (rhsvalue >= lhsbits || rhsvalue >= MathLib::bigint_bits || (1ULL << rhsvalue) <= lhsmax) |
2306 | 0 | continue; |
2307 | | |
2308 | 0 | ValueFlow::Value val(0); |
2309 | 0 | val.setKnown(); |
2310 | 0 | setTokenValue(tok, std::move(val), settings); |
2311 | 0 | } |
2312 | 1.17k | } |
2313 | | |
2314 | | static std::vector<MathLib::bigint> minUnsignedValue(const Token* tok, int depth = 8) |
2315 | 0 | { |
2316 | 0 | std::vector<MathLib::bigint> result; |
2317 | 0 | if (!tok) |
2318 | 0 | return result; |
2319 | 0 | if (depth < 0) |
2320 | 0 | return result; |
2321 | 0 | if (tok->hasKnownIntValue()) { |
2322 | 0 | result = {tok->values().front().intvalue}; |
2323 | 0 | } else if (!match19(tok) && tok->isConstOp() && tok->astOperand1() && tok->astOperand2()) { |
2324 | 0 | std::vector<MathLib::bigint> op1 = minUnsignedValue(tok->astOperand1(), depth - 1); |
2325 | 0 | if (!op1.empty()) { |
2326 | 0 | std::vector<MathLib::bigint> op2 = minUnsignedValue(tok->astOperand2(), depth - 1); |
2327 | 0 | if (!op2.empty()) { |
2328 | 0 | result = calculate<std::vector<MathLib::bigint>>(tok->str(), op1.front(), op2.front()); |
2329 | 0 | } |
2330 | 0 | } |
2331 | 0 | } |
2332 | 0 | if (result.empty() && astIsUnsigned(tok)) |
2333 | 0 | result = {0}; |
2334 | 0 | return result; |
2335 | 0 | } |
2336 | | |
2337 | | static bool isConvertedToIntegral(const Token* tok, const Settings& settings) |
2338 | 2 | { |
2339 | 2 | if (!tok) |
2340 | 0 | return false; |
2341 | 2 | std::vector<ValueType> parentTypes = getParentValueTypes(tok, settings); |
2342 | 2 | if (parentTypes.empty()) |
2343 | 2 | return false; |
2344 | 0 | const ValueType& vt = parentTypes.front(); |
2345 | 0 | return vt.type != ValueType::UNKNOWN_INT && vt.isIntegral(); |
2346 | 2 | } |
2347 | | |
2348 | | static bool isSameToken(const Token* tok1, const Token* tok2) |
2349 | 0 | { |
2350 | 0 | if (!tok1 || !tok2) |
2351 | 0 | return false; |
2352 | 0 | if (tok1->exprId() != 0 && tok1->exprId() == tok2->exprId()) |
2353 | 0 | return true; |
2354 | 0 | if (tok1->hasKnownIntValue() && tok2->hasKnownIntValue()) |
2355 | 0 | return tok1->values().front().intvalue == tok2->values().front().intvalue; |
2356 | 0 | return false; |
2357 | 0 | } |
2358 | | |
2359 | | static void valueFlowImpossibleValues(TokenList& tokenList, const Settings& settings) |
2360 | 1.17k | { |
2361 | 90.3k | for (Token* tok = tokenList.front(); tok; tok = tok->next()) { |
2362 | 89.1k | if (tok->hasKnownIntValue()) |
2363 | 13.6k | continue; |
2364 | 75.5k | if (match20(tok)) |
2365 | 0 | continue; |
2366 | 75.5k | if (astIsBool(tok) || match12(tok)) { |
2367 | 1.45k | ValueFlow::Value lower{-1}; |
2368 | 1.45k | lower.bound = ValueFlow::Value::Bound::Upper; |
2369 | 1.45k | lower.setImpossible(); |
2370 | 1.45k | setTokenValue(tok, std::move(lower), settings); |
2371 | | |
2372 | 1.45k | ValueFlow::Value upper{2}; |
2373 | 1.45k | upper.bound = ValueFlow::Value::Bound::Lower; |
2374 | 1.45k | upper.setImpossible(); |
2375 | 1.45k | setTokenValue(tok, std::move(upper), settings); |
2376 | 74.0k | } else if (astIsUnsigned(tok) && !astIsPointer(tok)) { |
2377 | 0 | std::vector<MathLib::bigint> minvalue = minUnsignedValue(tok); |
2378 | 0 | if (minvalue.empty()) |
2379 | 0 | continue; |
2380 | 0 | ValueFlow::Value value{std::max<MathLib::bigint>(0, minvalue.front()) - 1}; |
2381 | 0 | value.bound = ValueFlow::Value::Bound::Upper; |
2382 | 0 | value.setImpossible(); |
2383 | 0 | setTokenValue(tok, std::move(value), settings); |
2384 | 0 | } |
2385 | 75.5k | if (match22(tok) && match21(tok->astOperand1())) { |
2386 | 0 | const Token* condTok = tok->astOperand1(); |
2387 | 0 | const Token* branchesTok = tok->astOperand2(); |
2388 | |
|
2389 | 0 | auto tokens = makeArray(condTok->astOperand1(), condTok->astOperand2()); |
2390 | 0 | auto branches = makeArray(branchesTok->astOperand1(), branchesTok->astOperand2()); |
2391 | 0 | bool flipped = false; |
2392 | 0 | if (std::equal(tokens.cbegin(), tokens.cend(), branches.crbegin(), &isSameToken)) |
2393 | 0 | flipped = true; |
2394 | 0 | else if (!std::equal(tokens.cbegin(), tokens.cend(), branches.cbegin(), &isSameToken)) |
2395 | 0 | continue; |
2396 | 0 | std::vector<ValueFlow::Value> values; |
2397 | 0 | for (const Token* tok2 : tokens) { |
2398 | 0 | if (tok2->hasKnownIntValue()) { |
2399 | 0 | values.emplace_back(tok2->values().front()); |
2400 | 0 | } else { |
2401 | 0 | ValueFlow::Value symValue{}; |
2402 | 0 | symValue.valueType = ValueFlow::Value::ValueType::SYMBOLIC; |
2403 | 0 | symValue.tokvalue = tok2; |
2404 | 0 | values.push_back(symValue); |
2405 | 0 | std::copy_if(tok2->values().cbegin(), |
2406 | 0 | tok2->values().cend(), |
2407 | 0 | std::back_inserter(values), |
2408 | 0 | [](const ValueFlow::Value& v) { |
2409 | 0 | if (!v.isKnown()) |
2410 | 0 | return false; |
2411 | 0 | return v.isSymbolicValue(); |
2412 | 0 | }); |
2413 | 0 | } |
2414 | 0 | } |
2415 | 0 | const bool isMin = match1(condTok) ^ flipped; |
2416 | 0 | for (ValueFlow::Value& value : values) { |
2417 | 0 | value.setImpossible(); |
2418 | 0 | if (isMin) { |
2419 | 0 | value.intvalue++; |
2420 | 0 | value.bound = ValueFlow::Value::Bound::Lower; |
2421 | 0 | } else { |
2422 | 0 | value.intvalue--; |
2423 | 0 | value.bound = ValueFlow::Value::Bound::Upper; |
2424 | 0 | } |
2425 | 0 | setTokenValue(tok, std::move(value), settings); |
2426 | 0 | } |
2427 | |
|
2428 | 75.5k | } else if (match23(tok) && tok->astOperand2() && tok->astOperand2()->hasKnownIntValue()) { |
2429 | 0 | ValueFlow::Value value{tok->astOperand2()->values().front()}; |
2430 | 0 | value.bound = ValueFlow::Value::Bound::Lower; |
2431 | 0 | value.setImpossible(); |
2432 | 0 | setTokenValue(tok, std::move(value), settings); |
2433 | 75.5k | } else if (match24(tok)) { |
2434 | 0 | ValueFlow::Value value{-1}; |
2435 | 0 | value.bound = ValueFlow::Value::Bound::Upper; |
2436 | 0 | value.setImpossible(); |
2437 | 0 | setTokenValue(tok->next(), std::move(value), settings); |
2438 | 75.5k | } else if (match25(tok) && astIsContainerOwned(tok->astOperand1())) { |
2439 | 0 | const Library::Container* container = getLibraryContainer(tok->astOperand1()); |
2440 | 0 | if (!container) |
2441 | 0 | continue; |
2442 | 0 | if (!container->stdStringLike) |
2443 | 0 | continue; |
2444 | 0 | if (container->view) |
2445 | 0 | continue; |
2446 | 0 | ValueFlow::Value value{0}; |
2447 | 0 | value.setImpossible(); |
2448 | 0 | setTokenValue(tok->tokAt(2), std::move(value), settings); |
2449 | 75.5k | } else if (match26(tok) && match27(tok->linkAt(1))) { |
2450 | 0 | ValueFlow::Value value{0}; |
2451 | 0 | value.setImpossible(); |
2452 | 0 | setTokenValue(tok->linkAt(1)->next(), std::move(value), settings); |
2453 | 75.5k | } else if ((tokenList.isCPP() && match28(tok)) || tok->isUnaryOp("&")) { |
2454 | 8 | ValueFlow::Value value{0}; |
2455 | 8 | value.setImpossible(); |
2456 | 8 | setTokenValue(tok, std::move(value), settings); |
2457 | 75.5k | } else if (tok->variable() && tok->variable()->isArray() && !tok->variable()->isArgument() && |
2458 | 75.5k | !tok->variable()->isStlType()) { |
2459 | 0 | ValueFlow::Value value{0}; |
2460 | 0 | value.setImpossible(); |
2461 | 0 | setTokenValue(tok, std::move(value), settings); |
2462 | 75.5k | } else if (tok->isIncompleteVar() && tok->astParent() && tok->astParent()->isUnaryOp("-") && |
2463 | 75.5k | isConvertedToIntegral(tok->astParent(), settings)) { |
2464 | 0 | ValueFlow::Value value{0}; |
2465 | 0 | value.setImpossible(); |
2466 | 0 | setTokenValue(tok, std::move(value), settings); |
2467 | 0 | } |
2468 | 75.5k | } |
2469 | 1.17k | } |
2470 | | |
2471 | | static void valueFlowEnumValue(SymbolDatabase & symboldatabase, const Settings & settings) |
2472 | 1.52k | { |
2473 | 5.59k | for (Scope & scope : symboldatabase.scopeList) { |
2474 | 5.59k | if (scope.type != Scope::eEnum) |
2475 | 5.59k | continue; |
2476 | 0 | MathLib::bigint value = 0; |
2477 | 0 | bool prev_enum_is_known = true; |
2478 | |
|
2479 | 0 | for (Enumerator & enumerator : scope.enumeratorList) { |
2480 | 0 | if (enumerator.start) { |
2481 | 0 | auto* rhs = const_cast<Token*>(enumerator.start->previous()->astOperand2()); |
2482 | 0 | ValueFlow::valueFlowConstantFoldAST(rhs, settings); |
2483 | 0 | if (rhs && rhs->hasKnownIntValue()) { |
2484 | 0 | enumerator.value = rhs->values().front().intvalue; |
2485 | 0 | enumerator.value_known = true; |
2486 | 0 | value = enumerator.value + 1; |
2487 | 0 | prev_enum_is_known = true; |
2488 | 0 | } else |
2489 | 0 | prev_enum_is_known = false; |
2490 | 0 | } else if (prev_enum_is_known) { |
2491 | 0 | enumerator.value = value++; |
2492 | 0 | enumerator.value_known = true; |
2493 | 0 | } |
2494 | 0 | } |
2495 | 0 | } |
2496 | 1.52k | } |
2497 | | |
2498 | | static void valueFlowGlobalConstVar(TokenList& tokenList, const Settings& settings) |
2499 | 764 | { |
2500 | | // Get variable values... |
2501 | 764 | std::map<const Variable*, ValueFlow::Value> vars; |
2502 | 55.6k | for (const Token* tok = tokenList.front(); tok; tok = tok->next()) { |
2503 | 54.9k | if (!tok->variable()) |
2504 | 43.2k | continue; |
2505 | | // Initialization... |
2506 | 11.6k | if (tok == tok->variable()->nameToken() && !tok->variable()->isVolatile() && !tok->variable()->isArgument() && |
2507 | 11.6k | tok->variable()->isConst() && tok->valueType() && tok->valueType()->isIntegral() && |
2508 | 11.6k | tok->valueType()->pointer == 0 && tok->valueType()->constness == 1 && match29(tok) && |
2509 | 11.6k | tok->next()->astOperand2() && tok->next()->astOperand2()->hasKnownIntValue()) { |
2510 | 0 | vars[tok->variable()] = tok->next()->astOperand2()->values().front(); |
2511 | 0 | } |
2512 | 11.6k | } |
2513 | | |
2514 | | // Set values.. |
2515 | 55.6k | for (Token* tok = tokenList.front(); tok; tok = tok->next()) { |
2516 | 54.9k | if (!tok->variable()) |
2517 | 43.2k | continue; |
2518 | 11.6k | const auto var = utils::as_const(vars).find(tok->variable()); |
2519 | 11.6k | if (var == vars.end()) |
2520 | 11.6k | continue; |
2521 | 0 | setTokenValue(tok, var->second, settings); |
2522 | 0 | } |
2523 | 764 | } |
2524 | | |
2525 | | static void valueFlowGlobalStaticVar(TokenList& tokenList, const Settings& settings) |
2526 | 764 | { |
2527 | | // Get variable values... |
2528 | 764 | std::map<const Variable*, ValueFlow::Value> vars; |
2529 | 55.6k | for (const Token* tok = tokenList.front(); tok; tok = tok->next()) { |
2530 | 54.9k | if (!tok->variable()) |
2531 | 43.2k | continue; |
2532 | | // Initialization... |
2533 | 11.6k | if (tok == tok->variable()->nameToken() && tok->variable()->isStatic() && !tok->variable()->isConst() && |
2534 | 11.6k | tok->valueType() && tok->valueType()->isIntegral() && tok->valueType()->pointer == 0 && |
2535 | 11.6k | tok->valueType()->constness == 0 && match29(tok) && tok->next()->astOperand2() && |
2536 | 11.6k | tok->next()->astOperand2()->hasKnownIntValue()) { |
2537 | 0 | vars[tok->variable()] = tok->next()->astOperand2()->values().front(); |
2538 | 11.6k | } else { |
2539 | | // If variable is written anywhere in TU then remove it from vars |
2540 | 11.6k | if (!tok->astParent()) |
2541 | 3.82k | continue; |
2542 | 7.87k | if (match30(tok->astParent()) && !tok->astParent()->astOperand2()) |
2543 | 633 | vars.erase(tok->variable()); |
2544 | 7.24k | else if (tok->astParent()->isAssignmentOp()) { |
2545 | 5.64k | if (tok == tok->astParent()->astOperand1()) |
2546 | 4.06k | vars.erase(tok->variable()); |
2547 | 1.58k | else if (tok->isCpp() && match31(tok->astParent()->tokAt(-2))) |
2548 | 0 | vars.erase(tok->variable()); |
2549 | 5.64k | } else if (isLikelyStreamRead(tok->astParent())) { |
2550 | 0 | vars.erase(tok->variable()); |
2551 | 1.59k | } else if (match32(tok->astParent())) |
2552 | 0 | vars.erase(tok->variable()); |
2553 | 7.87k | } |
2554 | 11.6k | } |
2555 | | |
2556 | | // Set values.. |
2557 | 55.6k | for (Token* tok = tokenList.front(); tok; tok = tok->next()) { |
2558 | 54.9k | if (!tok->variable()) |
2559 | 43.2k | continue; |
2560 | 11.6k | const auto var = utils::as_const(vars).find(tok->variable()); |
2561 | 11.6k | if (var == vars.end()) |
2562 | 11.6k | continue; |
2563 | 0 | setTokenValue(tok, var->second, settings); |
2564 | 0 | } |
2565 | 764 | } |
2566 | | |
2567 | | static Analyzer::Result valueFlowForward(Token* startToken, |
2568 | | const Token* endToken, |
2569 | | const Token* exprTok, |
2570 | | ValueFlow::Value value, |
2571 | | const TokenList& tokenlist, |
2572 | | ErrorLogger& errorLogger, |
2573 | | const Settings& settings, |
2574 | | SourceLocation loc = SourceLocation::current()) |
2575 | 3.03k | { |
2576 | 3.03k | if (settings.debugnormal) |
2577 | 0 | setSourceLocation(value, loc, startToken); |
2578 | 3.03k | return valueFlowGenericForward(startToken, |
2579 | 3.03k | endToken, |
2580 | 3.03k | makeAnalyzer(exprTok, std::move(value), settings), |
2581 | 3.03k | tokenlist, |
2582 | 3.03k | errorLogger, |
2583 | 3.03k | settings); |
2584 | 3.03k | } |
2585 | | |
2586 | | static Analyzer::Result valueFlowForward(Token* startToken, |
2587 | | const Token* endToken, |
2588 | | const Token* exprTok, |
2589 | | std::list<ValueFlow::Value> values, |
2590 | | const TokenList& tokenlist, |
2591 | | ErrorLogger& errorLogger, |
2592 | | const Settings& settings, |
2593 | | SourceLocation loc = SourceLocation::current()) |
2594 | 2.03k | { |
2595 | 2.03k | Analyzer::Result result{}; |
2596 | 2.96k | for (ValueFlow::Value& v : values) { |
2597 | 2.96k | result.update(valueFlowForward(startToken, endToken, exprTok, std::move(v), tokenlist, errorLogger, settings, loc)); |
2598 | 2.96k | } |
2599 | 2.03k | return result; |
2600 | 2.03k | } |
2601 | | |
2602 | | template<class ValueOrValues> |
2603 | | static Analyzer::Result valueFlowForward(Token* startToken, |
2604 | | const Token* exprTok, |
2605 | | ValueOrValues v, |
2606 | | const TokenList& tokenlist, |
2607 | | ErrorLogger& errorLogger, |
2608 | | const Settings& settings, |
2609 | | SourceLocation loc = SourceLocation::current()) |
2610 | 0 | { |
2611 | 0 | const Token* endToken = nullptr; |
2612 | 0 | const Function* f = Scope::nestedInFunction(startToken->scope()); |
2613 | 0 | if (f && f->functionScope) |
2614 | 0 | endToken = f->functionScope->bodyEnd; |
2615 | 0 | if (!endToken && exprTok && exprTok->variable() && !exprTok->variable()->isLocal()) |
2616 | 0 | endToken = startToken->scope()->bodyEnd; |
2617 | 0 | return valueFlowForward(startToken, endToken, exprTok, std::move(v), tokenlist, errorLogger, settings, loc); |
2618 | 0 | } |
2619 | | |
2620 | | static Analyzer::Result valueFlowForwardRecursive(Token* top, |
2621 | | const Token* exprTok, |
2622 | | std::list<ValueFlow::Value> values, |
2623 | | const TokenList& tokenlist, |
2624 | | ErrorLogger& errorLogger, |
2625 | | const Settings& settings, |
2626 | | SourceLocation loc = SourceLocation::current()) |
2627 | 0 | { |
2628 | 0 | Analyzer::Result result{}; |
2629 | 0 | for (ValueFlow::Value& v : values) { |
2630 | 0 | if (settings.debugnormal) |
2631 | 0 | setSourceLocation(v, loc, top); |
2632 | 0 | result.update( |
2633 | 0 | valueFlowGenericForward(top, makeAnalyzer(exprTok, std::move(v), settings), tokenlist, errorLogger, settings)); |
2634 | 0 | } |
2635 | 0 | return result; |
2636 | 0 | } |
2637 | | |
2638 | | static void valueFlowReverse(Token* tok, |
2639 | | const Token* const endToken, |
2640 | | const Token* const varToken, |
2641 | | std::list<ValueFlow::Value> values, |
2642 | | const TokenList& tokenlist, |
2643 | | ErrorLogger& errorLogger, |
2644 | | const Settings& settings, |
2645 | | SourceLocation loc = SourceLocation::current()) |
2646 | 633 | { |
2647 | 865 | for (ValueFlow::Value& v : values) { |
2648 | 865 | if (settings.debugnormal) |
2649 | 0 | setSourceLocation(v, loc, tok); |
2650 | 865 | valueFlowGenericReverse(tok, |
2651 | 865 | endToken, |
2652 | 865 | makeReverseAnalyzer(varToken, std::move(v), settings), |
2653 | 865 | tokenlist, |
2654 | 865 | errorLogger, |
2655 | 865 | settings); |
2656 | 865 | } |
2657 | 633 | } |
2658 | | |
2659 | | // Deprecated |
2660 | | static void valueFlowReverse(const TokenList& tokenlist, |
2661 | | Token* tok, |
2662 | | const Token* const varToken, |
2663 | | ValueFlow::Value val, |
2664 | | ErrorLogger& errorLogger, |
2665 | | const Settings& settings, |
2666 | | SourceLocation loc = SourceLocation::current()) |
2667 | 0 | { |
2668 | 0 | valueFlowReverse(tok, nullptr, varToken, {std::move(val)}, tokenlist, errorLogger, settings, loc); |
2669 | 0 | } |
2670 | | |
2671 | | static bool isConditionKnown(const Token* tok, bool then) |
2672 | 2.24k | { |
2673 | 2.24k | const char* op = "||"; |
2674 | 2.24k | if (then) |
2675 | 1.24k | op = "&&"; |
2676 | 2.24k | const Token* parent = tok->astParent(); |
2677 | 2.24k | while (parent && (parent->str() == op || parent->str() == MatchCompiler::makeConstString("!") || parent->isCast())) |
2678 | 0 | parent = parent->astParent(); |
2679 | 2.24k | const Token* top = tok->astTop(); |
2680 | 2.24k | if (match14(top->previous())) |
2681 | 2.24k | return parent == top || match33(parent); |
2682 | 0 | return parent && parent->str() != op; |
2683 | 2.24k | } |
2684 | | |
2685 | | enum class LifetimeCapture : std::uint8_t { Undefined, ByValue, ByReference }; |
2686 | | |
2687 | | static std::string lifetimeType(const Token *tok, const ValueFlow::Value *val) |
2688 | 0 | { |
2689 | 0 | std::string result; |
2690 | 0 | if (!val) |
2691 | 0 | return "object"; |
2692 | 0 | switch (val->lifetimeKind) { |
2693 | 0 | case ValueFlow::Value::LifetimeKind::Lambda: |
2694 | 0 | result = "lambda"; |
2695 | 0 | break; |
2696 | 0 | case ValueFlow::Value::LifetimeKind::Iterator: |
2697 | 0 | result = "iterator"; |
2698 | 0 | break; |
2699 | 0 | case ValueFlow::Value::LifetimeKind::Object: |
2700 | 0 | case ValueFlow::Value::LifetimeKind::SubObject: |
2701 | 0 | case ValueFlow::Value::LifetimeKind::Address: |
2702 | 0 | if (astIsPointer(tok)) |
2703 | 0 | result = "pointer"; |
2704 | 0 | else if (match9(tok) && astIsPointer(tok->astOperand2())) |
2705 | 0 | result = "pointer"; |
2706 | 0 | else |
2707 | 0 | result = "object"; |
2708 | 0 | break; |
2709 | 0 | } |
2710 | 0 | return result; |
2711 | 0 | } |
2712 | | |
2713 | | std::string ValueFlow::lifetimeMessage(const Token *tok, const ValueFlow::Value *val, ErrorPath &errorPath) |
2714 | 0 | { |
2715 | 0 | const Token *tokvalue = val ? val->tokvalue : nullptr; |
2716 | 0 | const Variable *tokvar = tokvalue ? tokvalue->variable() : nullptr; |
2717 | 0 | const Token *vartok = tokvar ? tokvar->nameToken() : nullptr; |
2718 | 0 | const bool classVar = tokvar ? (!tokvar->isLocal() && !tokvar->isArgument() && !tokvar->isGlobal()) : false; |
2719 | 0 | std::string type = lifetimeType(tok, val); |
2720 | 0 | std::string msg = type; |
2721 | 0 | if (vartok) { |
2722 | 0 | if (!classVar) |
2723 | 0 | errorPath.emplace_back(vartok, "Variable created here."); |
2724 | 0 | const Variable * var = vartok->variable(); |
2725 | 0 | if (var) { |
2726 | 0 | std::string submessage; |
2727 | 0 | switch (val->lifetimeKind) { |
2728 | 0 | case ValueFlow::Value::LifetimeKind::SubObject: |
2729 | 0 | case ValueFlow::Value::LifetimeKind::Object: |
2730 | 0 | case ValueFlow::Value::LifetimeKind::Address: |
2731 | 0 | if (type == MatchCompiler::makeConstString("pointer")) |
2732 | 0 | submessage = " to local variable"; |
2733 | 0 | else |
2734 | 0 | submessage = " that points to local variable"; |
2735 | 0 | break; |
2736 | 0 | case ValueFlow::Value::LifetimeKind::Lambda: |
2737 | 0 | submessage = " that captures local variable"; |
2738 | 0 | break; |
2739 | 0 | case ValueFlow::Value::LifetimeKind::Iterator: |
2740 | 0 | submessage = " to local container"; |
2741 | 0 | break; |
2742 | 0 | } |
2743 | 0 | if (classVar) |
2744 | 0 | submessage.replace(submessage.find("local"), 5, "member"); |
2745 | 0 | msg += submessage + " '" + var->name() + "'"; |
2746 | 0 | } |
2747 | 0 | } |
2748 | 0 | return msg; |
2749 | 0 | } |
2750 | | |
2751 | | std::vector<ValueFlow::Value> ValueFlow::getLifetimeObjValues(const Token* tok, bool inconclusive, MathLib::bigint path) |
2752 | 2.04k | { |
2753 | 2.04k | std::vector<ValueFlow::Value> result; |
2754 | 2.04k | auto pred = [&](const ValueFlow::Value& v) { |
2755 | 386 | if (!v.isLocalLifetimeValue() && !(path != 0 && v.isSubFunctionLifetimeValue())) |
2756 | 383 | return false; |
2757 | 3 | if (!inconclusive && v.isInconclusive()) |
2758 | 0 | return false; |
2759 | 3 | if (!v.tokvalue) |
2760 | 0 | return false; |
2761 | 3 | if (path >= 0 && v.path != 0 && v.path != path) |
2762 | 0 | return false; |
2763 | 3 | return true; |
2764 | 3 | }; |
2765 | 2.04k | std::copy_if(tok->values().cbegin(), tok->values().cend(), std::back_inserter(result), pred); |
2766 | 2.04k | return result; |
2767 | 2.04k | } |
2768 | | |
2769 | | static bool hasUniqueOwnership(const Token* tok) |
2770 | 0 | { |
2771 | 0 | if (!tok) |
2772 | 0 | return false; |
2773 | 0 | const Variable* var = tok->variable(); |
2774 | 0 | if (var && var->isArray() && !var->isArgument()) |
2775 | 0 | return true; |
2776 | 0 | if (astIsPointer(tok)) |
2777 | 0 | return false; |
2778 | 0 | if (astIsUniqueSmartPointer(tok)) |
2779 | 0 | return true; |
2780 | 0 | if (astIsContainerOwned(tok)) |
2781 | 0 | return true; |
2782 | 0 | return false; |
2783 | 0 | } |
2784 | | |
2785 | | // Check if dereferencing an object that doesn't have unique ownership |
2786 | | static bool derefShared(const Token* tok) |
2787 | 0 | { |
2788 | 0 | if (!tok) |
2789 | 0 | return false; |
2790 | 0 | if (!tok->isUnaryOp("*") && tok->str() != MatchCompiler::makeConstString("[") && tok->str() != MatchCompiler::makeConstString(".")) |
2791 | 0 | return false; |
2792 | 0 | if (tok->str() == MatchCompiler::makeConstString(".") && tok->originalName() != MatchCompiler::makeConstString("->")) |
2793 | 0 | return false; |
2794 | 0 | const Token* ptrTok = tok->astOperand1(); |
2795 | 0 | return !hasUniqueOwnership(ptrTok); |
2796 | 0 | } |
2797 | | |
2798 | | ValueFlow::Value ValueFlow::getLifetimeObjValue(const Token *tok, bool inconclusive) |
2799 | 2 | { |
2800 | 2 | std::vector<ValueFlow::Value> values = ValueFlow::getLifetimeObjValues(tok, inconclusive); |
2801 | | // There should only be one lifetime |
2802 | 2 | if (values.size() != 1) |
2803 | 2 | return ValueFlow::Value{}; |
2804 | 0 | return values.front(); |
2805 | 2 | } |
2806 | | |
2807 | | template<class Predicate> |
2808 | | static std::vector<ValueFlow::LifetimeToken> getLifetimeTokens(const Token* tok, |
2809 | | bool escape, |
2810 | | ErrorPath errorPath, |
2811 | | Predicate pred, |
2812 | | const Settings& settings, |
2813 | | int depth = 20) |
2814 | 11.2k | { |
2815 | 11.2k | if (!tok) |
2816 | 0 | return std::vector<ValueFlow::LifetimeToken> {}; |
2817 | 11.2k | if (match34(tok)) |
2818 | 0 | return std::vector<ValueFlow::LifetimeToken>{}; |
2819 | 11.2k | const Variable *var = tok->variable(); |
2820 | 11.2k | if (pred(tok)) |
2821 | 0 | return {{tok, std::move(errorPath)}}; |
2822 | 11.2k | if (depth < 0) |
2823 | 0 | return {{tok, std::move(errorPath)}}; |
2824 | 11.2k | if (var && var->declarationId() == tok->varId()) { |
2825 | 11.2k | if (var->isReference() || var->isRValueReference()) { |
2826 | 0 | const Token * const varDeclEndToken = var->declEndToken(); |
2827 | 0 | if (!varDeclEndToken) |
2828 | 0 | return {{tok, true, std::move(errorPath)}}; |
2829 | 0 | if (var->isArgument()) { |
2830 | 0 | errorPath.emplace_back(varDeclEndToken, "Passed to reference."); |
2831 | 0 | return {{tok, true, std::move(errorPath)}}; |
2832 | 0 | } |
2833 | 0 | if (match35(varDeclEndToken)) { |
2834 | 0 | errorPath.emplace_back(varDeclEndToken, "Assigned to reference."); |
2835 | 0 | const Token *vartok = varDeclEndToken->astOperand2(); |
2836 | 0 | const bool temporary = isTemporary(vartok, nullptr, true); |
2837 | 0 | const bool nonlocal = var->isStatic() || var->isGlobal(); |
2838 | 0 | if (vartok == tok || (nonlocal && temporary) || |
2839 | 0 | (!escape && (var->isConst() || var->isRValueReference()) && temporary)) |
2840 | 0 | return {{tok, true, std::move(errorPath)}}; |
2841 | 0 | if (vartok) |
2842 | 0 | return getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1); |
2843 | 0 | } else if (match36(var->nameToken()->astParent()) && |
2844 | 0 | var->nameToken()->astParent()->astParent() && |
2845 | 0 | match37(var->nameToken()->astParent()->astParent()->previous())) { |
2846 | 0 | errorPath.emplace_back(var->nameToken(), "Assigned to reference."); |
2847 | 0 | const Token* vartok = var->nameToken(); |
2848 | 0 | if (vartok == tok) |
2849 | 0 | return {{tok, true, std::move(errorPath)}}; |
2850 | 0 | const Token* contok = var->nameToken()->astParent()->astOperand2(); |
2851 | 0 | if (astIsContainer(contok)) |
2852 | 0 | return ValueFlow::LifetimeToken::setAddressOf( |
2853 | 0 | getLifetimeTokens(contok, escape, std::move(errorPath), pred, settings, depth - 1), |
2854 | 0 | false); |
2855 | 0 | return std::vector<ValueFlow::LifetimeToken>{}; |
2856 | 0 | } else { |
2857 | 0 | return std::vector<ValueFlow::LifetimeToken> {}; |
2858 | 0 | } |
2859 | 0 | } |
2860 | 11.2k | } else if (match38(tok->previous())) { |
2861 | 0 | const Function *f = tok->previous()->function(); |
2862 | 0 | if (f) { |
2863 | 0 | if (!Function::returnsReference(f)) |
2864 | 0 | return {{tok, std::move(errorPath)}}; |
2865 | 0 | std::vector<ValueFlow::LifetimeToken> result; |
2866 | 0 | std::vector<const Token*> returns = Function::findReturns(f); |
2867 | 0 | for (const Token* returnTok : returns) { |
2868 | 0 | if (returnTok == tok) |
2869 | 0 | continue; |
2870 | 0 | for (ValueFlow::LifetimeToken& lt : getLifetimeTokens(returnTok, escape, errorPath, pred, settings, depth - returns.size())) { |
2871 | 0 | const Token* argvarTok = lt.token; |
2872 | 0 | const Variable* argvar = argvarTok->variable(); |
2873 | 0 | if (!argvar) |
2874 | 0 | continue; |
2875 | 0 | const Token* argTok = nullptr; |
2876 | 0 | if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) { |
2877 | 0 | const int n = getArgumentPos(argvar, f); |
2878 | 0 | if (n < 0) |
2879 | 0 | return std::vector<ValueFlow::LifetimeToken> {}; |
2880 | 0 | std::vector<const Token*> args = getArguments(tok->previous()); |
2881 | | // TODO: Track lifetimes of default parameters |
2882 | 0 | if (n >= args.size()) |
2883 | 0 | return std::vector<ValueFlow::LifetimeToken> {}; |
2884 | 0 | argTok = args[n]; |
2885 | 0 | lt.errorPath.emplace_back(returnTok, "Return reference."); |
2886 | 0 | lt.errorPath.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'."); |
2887 | 0 | } else if (match16(tok->tokAt(-2)) && !derefShared(tok->tokAt(-2)) && |
2888 | 0 | exprDependsOnThis(argvarTok)) { |
2889 | 0 | argTok = tok->tokAt(-2)->astOperand1(); |
2890 | 0 | lt.errorPath.emplace_back(returnTok, "Return reference that depends on 'this'."); |
2891 | 0 | lt.errorPath.emplace_back(tok->previous(), |
2892 | 0 | "Calling member function on '" + argTok->expressionString() + "'."); |
2893 | 0 | } |
2894 | 0 | if (argTok) { |
2895 | 0 | std::vector<ValueFlow::LifetimeToken> arglts = ValueFlow::LifetimeToken::setInconclusive( |
2896 | 0 | getLifetimeTokens(argTok, escape, std::move(lt.errorPath), pred, settings, depth - returns.size()), |
2897 | 0 | returns.size() > 1); |
2898 | 0 | result.insert(result.end(), arglts.cbegin(), arglts.cend()); |
2899 | 0 | } |
2900 | 0 | } |
2901 | 0 | } |
2902 | 0 | return result; |
2903 | 0 | } |
2904 | 0 | if (match16(tok->tokAt(-2)) && tok->tokAt(-2)->originalName() != MatchCompiler::makeConstString("->") && astIsContainer(tok->tokAt(-2)->astOperand1())) { |
2905 | 0 | const Library::Container* library = getLibraryContainer(tok->tokAt(-2)->astOperand1()); |
2906 | 0 | const Library::Container::Yield y = library->getYield(tok->strAt(-1)); |
2907 | 0 | if (y == Library::Container::Yield::AT_INDEX || y == Library::Container::Yield::ITEM) { |
2908 | 0 | errorPath.emplace_back(tok->previous(), "Accessing container."); |
2909 | 0 | return ValueFlow::LifetimeToken::setAddressOf( |
2910 | 0 | getLifetimeTokens(tok->tokAt(-2)->astOperand1(), escape, std::move(errorPath), pred, settings, depth - 1), |
2911 | 0 | false); |
2912 | 0 | } |
2913 | 0 | } |
2914 | 0 | } else if (match39(tok) || tok->isUnaryOp("*")) { |
2915 | |
|
2916 | 0 | const Token *vartok = tok; |
2917 | 0 | while (vartok) { |
2918 | 0 | if (vartok->str() == MatchCompiler::makeConstString("[") || vartok->isUnaryOp("*")) |
2919 | 0 | vartok = vartok->astOperand1(); |
2920 | 0 | else if (vartok->str() == MatchCompiler::makeConstString(".")) { |
2921 | 0 | if (!match40(vartok->astOperand1()) && |
2922 | 0 | !(vartok->astOperand2() && vartok->astOperand2()->valueType() && vartok->astOperand2()->valueType()->reference != Reference::None)) |
2923 | 0 | vartok = vartok->astOperand1(); |
2924 | 0 | else |
2925 | 0 | break; |
2926 | 0 | } |
2927 | 0 | else if (vartok->str() == MatchCompiler::makeConstString("::")) |
2928 | 0 | vartok = vartok->astOperand2(); |
2929 | 0 | else |
2930 | 0 | break; |
2931 | 0 | } |
2932 | |
|
2933 | 0 | if (!vartok) |
2934 | 0 | return {{tok, std::move(errorPath)}}; |
2935 | 0 | if (derefShared(vartok->astParent())) { |
2936 | 0 | for (const ValueFlow::Value &v : vartok->values()) { |
2937 | 0 | if (!v.isLocalLifetimeValue()) |
2938 | 0 | continue; |
2939 | 0 | if (v.tokvalue == tok) |
2940 | 0 | continue; |
2941 | 0 | errorPath.insert(errorPath.end(), v.errorPath.cbegin(), v.errorPath.cend()); |
2942 | 0 | return ValueFlow::LifetimeToken::setAddressOf( |
2943 | 0 | getLifetimeTokens(v.tokvalue, escape, std::move(errorPath), pred, settings, depth - 1), |
2944 | 0 | false); |
2945 | 0 | } |
2946 | 0 | } else { |
2947 | 0 | return ValueFlow::LifetimeToken::setAddressOf(getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1), |
2948 | 0 | !(astIsContainer(vartok) && match15(vartok->astParent()))); |
2949 | 0 | } |
2950 | 0 | } else if (match4(tok) && getArgumentStart(tok) && |
2951 | 0 | !match41(getArgumentStart(tok)) && getArgumentStart(tok)->valueType()) { |
2952 | 0 | const Token* vartok = getArgumentStart(tok); |
2953 | 0 | auto vts = getParentValueTypes(tok, settings); |
2954 | 0 | auto it = std::find_if(vts.cbegin(), vts.cend(), [&](const ValueType& vt) { |
2955 | 0 | return vt.isTypeEqual(vartok->valueType()); |
2956 | 0 | }); Unexecuted instantiation: valueflow.cpp:getLifetimeTokens<ValueFlow::getLifetimeTokens(Token const*, Settings const&, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >)::$_0>(Token const*, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >, ValueFlow::getLifetimeTokens(Token const*, Settings const&, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >)::$_0, Settings const&, int)::{lambda(ValueType const&)#1}::operator()(ValueType const&) const Unexecuted instantiation: valueflow.cpp:getLifetimeTokens<ValueFlow::hasLifetimeToken(Token const*, Token const*, Settings const&)::$_0>(Token const*, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >, ValueFlow::hasLifetimeToken(Token const*, Token const*, Settings const&)::$_0, Settings const&, int)::{lambda(ValueType const&)#1}::operator()(ValueType const&) const |
2957 | 0 | if (it != vts.end()) |
2958 | 0 | return getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1); |
2959 | 0 | } |
2960 | 11.2k | return {{tok, std::move(errorPath)}}; |
2961 | 11.2k | } valueflow.cpp:std::__1::vector<ValueFlow::LifetimeToken, std::__1::allocator<ValueFlow::LifetimeToken> > getLifetimeTokens<ValueFlow::getLifetimeTokens(Token const*, Settings const&, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >)::$_0>(Token const*, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >, ValueFlow::getLifetimeTokens(Token const*, Settings const&, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >)::$_0, Settings const&, int) Line | Count | Source | 2814 | 11.2k | { | 2815 | 11.2k | if (!tok) | 2816 | 0 | return std::vector<ValueFlow::LifetimeToken> {}; | 2817 | 11.2k | if (match34(tok)) | 2818 | 0 | return std::vector<ValueFlow::LifetimeToken>{}; | 2819 | 11.2k | const Variable *var = tok->variable(); | 2820 | 11.2k | if (pred(tok)) | 2821 | 0 | return {{tok, std::move(errorPath)}}; | 2822 | 11.2k | if (depth < 0) | 2823 | 0 | return {{tok, std::move(errorPath)}}; | 2824 | 11.2k | if (var && var->declarationId() == tok->varId()) { | 2825 | 11.2k | if (var->isReference() || var->isRValueReference()) { | 2826 | 0 | const Token * const varDeclEndToken = var->declEndToken(); | 2827 | 0 | if (!varDeclEndToken) | 2828 | 0 | return {{tok, true, std::move(errorPath)}}; | 2829 | 0 | if (var->isArgument()) { | 2830 | 0 | errorPath.emplace_back(varDeclEndToken, "Passed to reference."); | 2831 | 0 | return {{tok, true, std::move(errorPath)}}; | 2832 | 0 | } | 2833 | 0 | if (match35(varDeclEndToken)) { | 2834 | 0 | errorPath.emplace_back(varDeclEndToken, "Assigned to reference."); | 2835 | 0 | const Token *vartok = varDeclEndToken->astOperand2(); | 2836 | 0 | const bool temporary = isTemporary(vartok, nullptr, true); | 2837 | 0 | const bool nonlocal = var->isStatic() || var->isGlobal(); | 2838 | 0 | if (vartok == tok || (nonlocal && temporary) || | 2839 | 0 | (!escape && (var->isConst() || var->isRValueReference()) && temporary)) | 2840 | 0 | return {{tok, true, std::move(errorPath)}}; | 2841 | 0 | if (vartok) | 2842 | 0 | return getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1); | 2843 | 0 | } else if (match36(var->nameToken()->astParent()) && | 2844 | 0 | var->nameToken()->astParent()->astParent() && | 2845 | 0 | match37(var->nameToken()->astParent()->astParent()->previous())) { | 2846 | 0 | errorPath.emplace_back(var->nameToken(), "Assigned to reference."); | 2847 | 0 | const Token* vartok = var->nameToken(); | 2848 | 0 | if (vartok == tok) | 2849 | 0 | return {{tok, true, std::move(errorPath)}}; | 2850 | 0 | const Token* contok = var->nameToken()->astParent()->astOperand2(); | 2851 | 0 | if (astIsContainer(contok)) | 2852 | 0 | return ValueFlow::LifetimeToken::setAddressOf( | 2853 | 0 | getLifetimeTokens(contok, escape, std::move(errorPath), pred, settings, depth - 1), | 2854 | 0 | false); | 2855 | 0 | return std::vector<ValueFlow::LifetimeToken>{}; | 2856 | 0 | } else { | 2857 | 0 | return std::vector<ValueFlow::LifetimeToken> {}; | 2858 | 0 | } | 2859 | 0 | } | 2860 | 11.2k | } else if (match38(tok->previous())) { | 2861 | 0 | const Function *f = tok->previous()->function(); | 2862 | 0 | if (f) { | 2863 | 0 | if (!Function::returnsReference(f)) | 2864 | 0 | return {{tok, std::move(errorPath)}}; | 2865 | 0 | std::vector<ValueFlow::LifetimeToken> result; | 2866 | 0 | std::vector<const Token*> returns = Function::findReturns(f); | 2867 | 0 | for (const Token* returnTok : returns) { | 2868 | 0 | if (returnTok == tok) | 2869 | 0 | continue; | 2870 | 0 | for (ValueFlow::LifetimeToken& lt : getLifetimeTokens(returnTok, escape, errorPath, pred, settings, depth - returns.size())) { | 2871 | 0 | const Token* argvarTok = lt.token; | 2872 | 0 | const Variable* argvar = argvarTok->variable(); | 2873 | 0 | if (!argvar) | 2874 | 0 | continue; | 2875 | 0 | const Token* argTok = nullptr; | 2876 | 0 | if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) { | 2877 | 0 | const int n = getArgumentPos(argvar, f); | 2878 | 0 | if (n < 0) | 2879 | 0 | return std::vector<ValueFlow::LifetimeToken> {}; | 2880 | 0 | std::vector<const Token*> args = getArguments(tok->previous()); | 2881 | | // TODO: Track lifetimes of default parameters | 2882 | 0 | if (n >= args.size()) | 2883 | 0 | return std::vector<ValueFlow::LifetimeToken> {}; | 2884 | 0 | argTok = args[n]; | 2885 | 0 | lt.errorPath.emplace_back(returnTok, "Return reference."); | 2886 | 0 | lt.errorPath.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'."); | 2887 | 0 | } else if (match16(tok->tokAt(-2)) && !derefShared(tok->tokAt(-2)) && | 2888 | 0 | exprDependsOnThis(argvarTok)) { | 2889 | 0 | argTok = tok->tokAt(-2)->astOperand1(); | 2890 | 0 | lt.errorPath.emplace_back(returnTok, "Return reference that depends on 'this'."); | 2891 | 0 | lt.errorPath.emplace_back(tok->previous(), | 2892 | 0 | "Calling member function on '" + argTok->expressionString() + "'."); | 2893 | 0 | } | 2894 | 0 | if (argTok) { | 2895 | 0 | std::vector<ValueFlow::LifetimeToken> arglts = ValueFlow::LifetimeToken::setInconclusive( | 2896 | 0 | getLifetimeTokens(argTok, escape, std::move(lt.errorPath), pred, settings, depth - returns.size()), | 2897 | 0 | returns.size() > 1); | 2898 | 0 | result.insert(result.end(), arglts.cbegin(), arglts.cend()); | 2899 | 0 | } | 2900 | 0 | } | 2901 | 0 | } | 2902 | 0 | return result; | 2903 | 0 | } | 2904 | 0 | if (match16(tok->tokAt(-2)) && tok->tokAt(-2)->originalName() != MatchCompiler::makeConstString("->") && astIsContainer(tok->tokAt(-2)->astOperand1())) { | 2905 | 0 | const Library::Container* library = getLibraryContainer(tok->tokAt(-2)->astOperand1()); | 2906 | 0 | const Library::Container::Yield y = library->getYield(tok->strAt(-1)); | 2907 | 0 | if (y == Library::Container::Yield::AT_INDEX || y == Library::Container::Yield::ITEM) { | 2908 | 0 | errorPath.emplace_back(tok->previous(), "Accessing container."); | 2909 | 0 | return ValueFlow::LifetimeToken::setAddressOf( | 2910 | 0 | getLifetimeTokens(tok->tokAt(-2)->astOperand1(), escape, std::move(errorPath), pred, settings, depth - 1), | 2911 | 0 | false); | 2912 | 0 | } | 2913 | 0 | } | 2914 | 0 | } else if (match39(tok) || tok->isUnaryOp("*")) { | 2915 | |
| 2916 | 0 | const Token *vartok = tok; | 2917 | 0 | while (vartok) { | 2918 | 0 | if (vartok->str() == MatchCompiler::makeConstString("[") || vartok->isUnaryOp("*")) | 2919 | 0 | vartok = vartok->astOperand1(); | 2920 | 0 | else if (vartok->str() == MatchCompiler::makeConstString(".")) { | 2921 | 0 | if (!match40(vartok->astOperand1()) && | 2922 | 0 | !(vartok->astOperand2() && vartok->astOperand2()->valueType() && vartok->astOperand2()->valueType()->reference != Reference::None)) | 2923 | 0 | vartok = vartok->astOperand1(); | 2924 | 0 | else | 2925 | 0 | break; | 2926 | 0 | } | 2927 | 0 | else if (vartok->str() == MatchCompiler::makeConstString("::")) | 2928 | 0 | vartok = vartok->astOperand2(); | 2929 | 0 | else | 2930 | 0 | break; | 2931 | 0 | } | 2932 | |
| 2933 | 0 | if (!vartok) | 2934 | 0 | return {{tok, std::move(errorPath)}}; | 2935 | 0 | if (derefShared(vartok->astParent())) { | 2936 | 0 | for (const ValueFlow::Value &v : vartok->values()) { | 2937 | 0 | if (!v.isLocalLifetimeValue()) | 2938 | 0 | continue; | 2939 | 0 | if (v.tokvalue == tok) | 2940 | 0 | continue; | 2941 | 0 | errorPath.insert(errorPath.end(), v.errorPath.cbegin(), v.errorPath.cend()); | 2942 | 0 | return ValueFlow::LifetimeToken::setAddressOf( | 2943 | 0 | getLifetimeTokens(v.tokvalue, escape, std::move(errorPath), pred, settings, depth - 1), | 2944 | 0 | false); | 2945 | 0 | } | 2946 | 0 | } else { | 2947 | 0 | return ValueFlow::LifetimeToken::setAddressOf(getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1), | 2948 | 0 | !(astIsContainer(vartok) && match15(vartok->astParent()))); | 2949 | 0 | } | 2950 | 0 | } else if (match4(tok) && getArgumentStart(tok) && | 2951 | 0 | !match41(getArgumentStart(tok)) && getArgumentStart(tok)->valueType()) { | 2952 | 0 | const Token* vartok = getArgumentStart(tok); | 2953 | 0 | auto vts = getParentValueTypes(tok, settings); | 2954 | 0 | auto it = std::find_if(vts.cbegin(), vts.cend(), [&](const ValueType& vt) { | 2955 | 0 | return vt.isTypeEqual(vartok->valueType()); | 2956 | 0 | }); | 2957 | 0 | if (it != vts.end()) | 2958 | 0 | return getLifetimeTokens(vartok, escape, std::move(errorPath), pred, settings, depth - 1); | 2959 | 0 | } | 2960 | 11.2k | return {{tok, std::move(errorPath)}}; | 2961 | 11.2k | } |
Unexecuted instantiation: valueflow.cpp:std::__1::vector<ValueFlow::LifetimeToken, std::__1::allocator<ValueFlow::LifetimeToken> > getLifetimeTokens<ValueFlow::hasLifetimeToken(Token const*, Token const*, Settings const&)::$_0>(Token const*, bool, std::__1::list<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<Token const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >, ValueFlow::hasLifetimeToken(Token const*, Token const*, Settings const&)::$_0, Settings const&, int) |
2962 | | |
2963 | | std::vector<ValueFlow::LifetimeToken> ValueFlow::getLifetimeTokens(const Token* tok, const Settings& settings, bool escape, ErrorPath errorPath) |
2964 | 11.2k | { |
2965 | 11.2k | return getLifetimeTokens(tok, escape, std::move(errorPath), [](const Token*) { |
2966 | 11.2k | return false; |
2967 | 11.2k | }, settings); |
2968 | 11.2k | } |
2969 | | |
2970 | | bool ValueFlow::hasLifetimeToken(const Token* tok, const Token* lifetime, const Settings& settings) |
2971 | 0 | { |
2972 | 0 | bool result = false; |
2973 | 0 | getLifetimeTokens(tok, false, ErrorPath{}, [&](const Token* tok2) { |
2974 | 0 | result = tok2->exprId() == lifetime->exprId(); |
2975 | 0 | return result; |
2976 | 0 | }, settings); |
2977 | 0 | return result; |
2978 | 0 | } |
2979 | | |
2980 | | static const Token* getLifetimeToken(const Token* tok, ErrorPath& errorPath, const Settings& settings, bool* addressOf = nullptr) |
2981 | 11.2k | { |
2982 | 11.2k | std::vector<ValueFlow::LifetimeToken> lts = ValueFlow::getLifetimeTokens(tok, settings); |
2983 | 11.2k | if (lts.size() != 1) |
2984 | 0 | return nullptr; |
2985 | 11.2k | if (lts.front().inconclusive) |
2986 | 0 | return nullptr; |
2987 | 11.2k | if (addressOf) |
2988 | 0 | *addressOf = lts.front().addressOf; |
2989 | 11.2k | errorPath.insert(errorPath.end(), lts.front().errorPath.cbegin(), lts.front().errorPath.cend()); |
2990 | 11.2k | return lts.front().token; |
2991 | 11.2k | } |
2992 | | |
2993 | | const Variable* ValueFlow::getLifetimeVariable(const Token* tok, ErrorPath& errorPath, const Settings& settings, bool* addressOf) |
2994 | 11.2k | { |
2995 | 11.2k | const Token* tok2 = getLifetimeToken(tok, errorPath, settings, addressOf); |
2996 | 11.2k | if (tok2 && tok2->variable()) |
2997 | 11.2k | return tok2->variable(); |
2998 | 0 | return nullptr; |
2999 | 11.2k | } |
3000 | | |
3001 | | const Variable* ValueFlow::getLifetimeVariable(const Token* tok, const Settings& settings) |
3002 | 0 | { |
3003 | 0 | ErrorPath errorPath; |
3004 | 0 | return getLifetimeVariable(tok, errorPath, settings, nullptr); |
3005 | 0 | } |
3006 | | |
3007 | | static bool isNotLifetimeValue(const ValueFlow::Value& val) |
3008 | 0 | { |
3009 | 0 | return !val.isLifetimeValue(); |
3010 | 0 | } |
3011 | | |
3012 | | static bool isLifetimeOwned(const ValueType* vtParent) |
3013 | 2 | { |
3014 | 2 | if (vtParent->container) |
3015 | 0 | return !vtParent->container->view; |
3016 | 2 | return vtParent->type == ValueType::CONTAINER; |
3017 | 2 | } |
3018 | | |
3019 | | static bool isLifetimeOwned(const ValueType *vt, const ValueType *vtParent) |
3020 | 1 | { |
3021 | 1 | if (!vtParent) |
3022 | 0 | return false; |
3023 | 1 | if (isLifetimeOwned(vtParent)) |
3024 | 0 | return true; |
3025 | 1 | if (!vt) |
3026 | 0 | return false; |
3027 | | // If converted from iterator to pointer then the iterator is most likely a pointer |
3028 | 1 | if (vtParent->pointer == 1 && vt->pointer == 0 && vt->type == ValueType::ITERATOR) |
3029 | 0 | return false; |
3030 | 1 | if (vt->type != ValueType::UNKNOWN_TYPE && vtParent->type != ValueType::UNKNOWN_TYPE) { |
3031 | 1 | if (vt->pointer != vtParent->pointer) |
3032 | 0 | return true; |
3033 | 1 | if (vt->type != vtParent->type) { |
3034 | 1 | if (vtParent->type == ValueType::RECORD) |
3035 | 0 | return true; |
3036 | 1 | if (isLifetimeOwned(vtParent)) |
3037 | 0 | return true; |
3038 | 1 | } |
3039 | 1 | } |
3040 | | |
3041 | 1 | return false; |
3042 | 1 | } |
3043 | | |
3044 | | static bool isLifetimeBorrowed(const ValueType *vt, const ValueType *vtParent) |
3045 | 4 | { |
3046 | 4 | if (!vtParent) |
3047 | 0 | return false; |
3048 | 4 | if (!vt) |
3049 | 0 | return false; |
3050 | 4 | if (vt->pointer > 0 && vt->pointer == vtParent->pointer) |
3051 | 0 | return true; |
3052 | 4 | if (vtParent->container && vtParent->container->view) |
3053 | 0 | return true; |
3054 | 4 | if (vt->type != ValueType::UNKNOWN_TYPE && vtParent->type != ValueType::UNKNOWN_TYPE && vtParent->container == vt->container) { |
3055 | 4 | if (vtParent->pointer > vt->pointer) |
3056 | 0 | return true; |
3057 | 4 | if (vtParent->pointer < vt->pointer && vtParent->isIntegral()) |
3058 | 2 | return true; |
3059 | 2 | if (vtParent->str() == vt->str()) |
3060 | 1 | return true; |
3061 | 2 | } |
3062 | | |
3063 | 1 | return false; |
3064 | 4 | } |
3065 | | |
3066 | | static const Token* skipCVRefs(const Token* tok, const Token* endTok) |
3067 | 0 | { |
3068 | 0 | while (tok != endTok && match42(tok)) |
3069 | 0 | tok = tok->next(); |
3070 | 0 | return tok; |
3071 | 0 | } |
3072 | | |
3073 | | static bool isNotEqual(std::pair<const Token*, const Token*> x, std::pair<const Token*, const Token*> y) |
3074 | 1.73k | { |
3075 | 1.73k | const Token* start1 = x.first; |
3076 | 1.73k | const Token* start2 = y.first; |
3077 | 1.73k | if (start1 == nullptr || start2 == nullptr) |
3078 | 1.73k | return false; |
3079 | 0 | while (start1 != x.second && start2 != y.second) { |
3080 | 0 | const Token* tok1 = skipCVRefs(start1, x.second); |
3081 | 0 | if (tok1 != start1) { |
3082 | 0 | start1 = tok1; |
3083 | 0 | continue; |
3084 | 0 | } |
3085 | 0 | const Token* tok2 = skipCVRefs(start2, y.second); |
3086 | 0 | if (tok2 != start2) { |
3087 | 0 | start2 = tok2; |
3088 | 0 | continue; |
3089 | 0 | } |
3090 | 0 | if (start1->str() != start2->str()) |
3091 | 0 | return true; |
3092 | 0 | start1 = start1->next(); |
3093 | 0 | start2 = start2->next(); |
3094 | 0 | } |
3095 | 0 | start1 = skipCVRefs(start1, x.second); |
3096 | 0 | start2 = skipCVRefs(start2, y.second); |
3097 | 0 | return !(start1 == x.second && start2 == y.second); |
3098 | 0 | } |
3099 | | static bool isNotEqual(std::pair<const Token*, const Token*> x, const std::string& y, bool cpp) |
3100 | 0 | { |
3101 | 0 | TokenList tokenList(nullptr); |
3102 | 0 | std::istringstream istr(y); |
3103 | 0 | tokenList.createTokens(istr, cpp ? Standards::Language::CPP : Standards::Language::C); // TODO: check result? |
3104 | 0 | return isNotEqual(x, std::make_pair(tokenList.front(), tokenList.back())); |
3105 | 0 | } |
3106 | | static bool isNotEqual(std::pair<const Token*, const Token*> x, const ValueType* y, bool cpp) |
3107 | 3.46k | { |
3108 | 3.46k | if (y == nullptr) |
3109 | 1.89k | return false; |
3110 | 1.57k | if (y->originalTypeName.empty()) |
3111 | 1.57k | return false; |
3112 | 0 | return isNotEqual(x, y->originalTypeName, cpp); |
3113 | 1.57k | } |
3114 | | |
3115 | | static bool isDifferentType(const Token* src, const Token* dst) |
3116 | 1.73k | { |
3117 | 1.73k | const Type* t = Token::typeOf(src); |
3118 | 1.73k | const Type* parentT = Token::typeOf(dst); |
3119 | 1.73k | if (t && parentT) { |
3120 | 0 | if (t->classDef && parentT->classDef && t->classDef != parentT->classDef) |
3121 | 0 | return true; |
3122 | 1.73k | } else { |
3123 | 1.73k | std::pair<const Token*, const Token*> decl = Token::typeDecl(src); |
3124 | 1.73k | std::pair<const Token*, const Token*> parentdecl = Token::typeDecl(dst); |
3125 | 1.73k | const bool isCpp = (src && src->isCpp()) || (dst && dst->isCpp()); |
3126 | 1.73k | if (isNotEqual(decl, parentdecl) && !(isCpp && (match43(decl.first) || match43(parentdecl.first)))) |
3127 | 0 | return true; |
3128 | 1.73k | if (isNotEqual(decl, dst->valueType(), isCpp)) |
3129 | 0 | return true; |
3130 | 1.73k | if (isNotEqual(parentdecl, src->valueType(), isCpp)) |
3131 | 0 | return true; |
3132 | 1.73k | } |
3133 | 1.73k | return false; |
3134 | 1.73k | } |
3135 | | |
3136 | | bool ValueFlow::isLifetimeBorrowed(const Token *tok, const Settings &settings) |
3137 | 6 | { |
3138 | 6 | if (!tok) |
3139 | 0 | return true; |
3140 | 6 | if (tok->str() == MatchCompiler::makeConstString(",")) |
3141 | 0 | return true; |
3142 | 6 | if (!tok->astParent()) |
3143 | 0 | return true; |
3144 | 6 | const Token* parent = nullptr; |
3145 | 6 | const ValueType* vt = tok->valueType(); |
3146 | 6 | std::vector<ValueType> vtParents = getParentValueTypes(tok, settings, &parent); |
3147 | 6 | for (const ValueType& vtParent : vtParents) { |
3148 | 4 | if (isLifetimeBorrowed(vt, &vtParent)) |
3149 | 3 | return true; |
3150 | 1 | if (isLifetimeOwned(vt, &vtParent)) |
3151 | 0 | return false; |
3152 | 1 | } |
3153 | 3 | if (parent) { |
3154 | 1 | if (isDifferentType(tok, parent)) |
3155 | 0 | return false; |
3156 | 1 | } |
3157 | 3 | return true; |
3158 | 3 | } |
3159 | | |
3160 | | static void valueFlowLifetimeFunction(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings); |
3161 | | |
3162 | | static void valueFlowLifetimeConstructor(Token *tok, |
3163 | | const TokenList &tokenlist, |
3164 | | ErrorLogger &errorLogger, |
3165 | | const Settings &settings); |
3166 | | |
3167 | | static bool isRangeForScope(const Scope* scope) |
3168 | 0 | { |
3169 | 0 | if (!scope) |
3170 | 0 | return false; |
3171 | 0 | if (scope->type != Scope::eFor) |
3172 | 0 | return false; |
3173 | 0 | if (!scope->bodyStart) |
3174 | 0 | return false; |
3175 | 0 | if (!match44(scope->bodyStart->previous())) |
3176 | 0 | return false; |
3177 | 0 | return match36(scope->bodyStart->linkAt(-1)->astOperand2()); |
3178 | 0 | } |
3179 | | |
3180 | | static const Token* getEndOfVarScope(const Variable* var) |
3181 | 0 | { |
3182 | 0 | if (!var) |
3183 | 0 | return nullptr; |
3184 | 0 | const Scope* innerScope = var->scope(); |
3185 | 0 | const Scope* outerScope = innerScope; |
3186 | 0 | if (var->typeStartToken() && var->typeStartToken()->scope()) |
3187 | 0 | outerScope = var->typeStartToken()->scope(); |
3188 | 0 | if (!innerScope && outerScope) |
3189 | 0 | innerScope = outerScope; |
3190 | 0 | if (!innerScope || !outerScope) |
3191 | 0 | return nullptr; |
3192 | 0 | if (!innerScope->isExecutable()) |
3193 | 0 | return nullptr; |
3194 | | // If the variable is defined in a for/while initializer then we want to |
3195 | | // pick one token after the end so forward analysis can analyze the exit |
3196 | | // conditions |
3197 | 0 | if (innerScope != outerScope && outerScope->isExecutable() && innerScope->isLoopScope() && |
3198 | 0 | !isRangeForScope(innerScope)) |
3199 | 0 | return innerScope->bodyEnd->next(); |
3200 | 0 | return innerScope->bodyEnd; |
3201 | 0 | } |
3202 | | |
3203 | | const Token* ValueFlow::getEndOfExprScope(const Token* tok, const Scope* defaultScope, bool smallest) |
3204 | 2.86k | { |
3205 | 2.86k | const Token* end = nullptr; |
3206 | 2.86k | bool local = false; |
3207 | 2.93k | visitAstNodes(tok, [&](const Token* child) { |
3208 | 2.93k | if (const Variable* var = child->variable()) { |
3209 | 483 | local |= var->isLocal(); |
3210 | 483 | if (var->isLocal() || var->isArgument()) { |
3211 | 0 | const Token* varEnd = getEndOfVarScope(var); |
3212 | 0 | if (!end || (smallest ? precedes(varEnd, end) : succeeds(varEnd, end))) |
3213 | 0 | end = varEnd; |
3214 | |
|
3215 | 0 | const Token* top = var->nameToken()->astTop(); |
3216 | 0 | if (match45(top->tokAt(-1))) { // variable declared in if (...) |
3217 | 0 | const Token* elseTok = top->link()->linkAt(1); |
3218 | 0 | if (match46(elseTok) && tok->scope()->isNestedIn(elseTok->tokAt(2)->scope())) |
3219 | 0 | end = tok->scope()->bodyEnd; |
3220 | 0 | } |
3221 | 0 | } |
3222 | 483 | } |
3223 | 2.93k | return ChildrenToVisit::op1_and_op2; |
3224 | 2.93k | }); |
3225 | 2.86k | if (!end && defaultScope) |
3226 | 2.43k | end = defaultScope->bodyEnd; |
3227 | 2.86k | if (!end) { |
3228 | 425 | const Scope* scope = tok->scope(); |
3229 | 425 | if (scope) |
3230 | 425 | end = scope->bodyEnd; |
3231 | | // If there is no local variables then pick the function scope |
3232 | 425 | if (!local) { |
3233 | 654 | while (scope && scope->isLocal()) |
3234 | 229 | scope = scope->nestedIn; |
3235 | 425 | if (scope && scope->isExecutable()) |
3236 | 425 | end = scope->bodyEnd; |
3237 | 425 | } |
3238 | 425 | } |
3239 | 2.86k | return end; |
3240 | 2.86k | } |
3241 | | |
3242 | | static void valueFlowForwardLifetime(Token * tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings) |
3243 | 205 | { |
3244 | | // Forward lifetimes to constructed variable |
3245 | 205 | if (match47(tok->previous()) && isVariableDecl(tok->previous())) { |
3246 | 0 | std::list<ValueFlow::Value> values = tok->values(); |
3247 | 0 | values.remove_if(&isNotLifetimeValue); |
3248 | 0 | valueFlowForward(nextAfterAstRightmostLeaf(tok), ValueFlow::getEndOfExprScope(tok), tok->previous(), std::move(values), tokenlist, errorLogger, settings); |
3249 | 0 | return; |
3250 | 0 | } |
3251 | 205 | Token *parent = tok->astParent(); |
3252 | 205 | while (parent && parent->str() == MatchCompiler::makeConstString(",")) |
3253 | 0 | parent = parent->astParent(); |
3254 | 205 | if (!parent) |
3255 | 187 | return; |
3256 | | // Assignment |
3257 | 18 | if (parent->str() == MatchCompiler::makeConstString("=") && (!parent->astParent() || match33(parent->astParent()))) { |
3258 | | // Rhs values.. |
3259 | 0 | if (!parent->astOperand2() || parent->astOperand2()->values().empty()) |
3260 | 0 | return; |
3261 | | |
3262 | 0 | if (!ValueFlow::isLifetimeBorrowed(parent->astOperand2(), settings)) |
3263 | 0 | return; |
3264 | | |
3265 | 0 | const Token* expr = getLHSVariableToken(parent); |
3266 | 0 | if (!expr) |
3267 | 0 | return; |
3268 | | |
3269 | 0 | if (expr->exprId() == 0) |
3270 | 0 | return; |
3271 | | |
3272 | 0 | const Token* endOfVarScope = ValueFlow::getEndOfExprScope(expr); |
3273 | | |
3274 | | // Only forward lifetime values |
3275 | 0 | std::list<ValueFlow::Value> values = parent->astOperand2()->values(); |
3276 | 0 | values.remove_if(&isNotLifetimeValue); |
3277 | | // Dont forward lifetimes that overlap |
3278 | 0 | values.remove_if([&](const ValueFlow::Value& value) { |
3279 | 0 | return findAstNode(value.tokvalue, [&](const Token* child) { |
3280 | 0 | return child->exprId() == expr->exprId(); |
3281 | 0 | }); |
3282 | 0 | }); |
3283 | | |
3284 | | // Skip RHS |
3285 | 0 | Token* nextExpression = nextAfterAstRightmostLeaf(parent); |
3286 | |
|
3287 | 0 | if (expr->exprId() > 0) { |
3288 | 0 | valueFlowForward(nextExpression, endOfVarScope->next(), expr, values, tokenlist, errorLogger, settings); |
3289 | |
|
3290 | 0 | for (ValueFlow::Value& val : values) { |
3291 | 0 | if (val.lifetimeKind == ValueFlow::Value::LifetimeKind::Address) |
3292 | 0 | val.lifetimeKind = ValueFlow::Value::LifetimeKind::SubObject; |
3293 | 0 | } |
3294 | | // TODO: handle `[` |
3295 | 0 | if (match40(parent->astOperand1())) { |
3296 | 0 | const Token* parentLifetime = |
3297 | 0 | getParentLifetime(parent->astOperand1()->astOperand2(), settings.library); |
3298 | 0 | if (parentLifetime && parentLifetime->exprId() > 0) { |
3299 | 0 | valueFlowForward(nextExpression, endOfVarScope, parentLifetime, std::move(values), tokenlist, errorLogger, settings); |
3300 | 0 | } |
3301 | 0 | } |
3302 | 0 | } |
3303 | | // Constructor |
3304 | 18 | } else if (match4(parent) && !isScopeBracket(parent)) { |
3305 | 0 | valueFlowLifetimeConstructor(parent, tokenlist, errorLogger, settings); |
3306 | 0 | valueFlowForwardLifetime(parent, tokenlist, errorLogger, settings); |
3307 | | // Function call |
3308 | 18 | } else if (match38(parent->previous())) { |
3309 | 0 | valueFlowLifetimeFunction(parent->previous(), tokenlist, errorLogger, settings); |
3310 | 0 | valueFlowForwardLifetime(parent, tokenlist, errorLogger, settings); |
3311 | | // Variable |
3312 | 18 | } else if (tok->variable() && tok->variable()->scope()) { |
3313 | 0 | const Variable *var = tok->variable(); |
3314 | 0 | const Token *endOfVarScope = var->scope()->bodyEnd; |
3315 | |
|
3316 | 0 | std::list<ValueFlow::Value> values = tok->values(); |
3317 | 0 | Token *nextExpression = nextAfterAstRightmostLeaf(parent); |
3318 | | // Only forward lifetime values |
3319 | 0 | values.remove_if(&isNotLifetimeValue); |
3320 | 0 | valueFlowForward(nextExpression, endOfVarScope, tok, std::move(values), tokenlist, errorLogger, settings); |
3321 | | // Cast |
3322 | 18 | } else if (parent->isCast()) { |
3323 | 0 | std::list<ValueFlow::Value> values = tok->values(); |
3324 | | // Only forward lifetime values |
3325 | 0 | values.remove_if(&isNotLifetimeValue); |
3326 | 0 | for (ValueFlow::Value& value:values) |
3327 | 0 | setTokenValue(parent, std::move(value), settings); |
3328 | 0 | valueFlowForwardLifetime(parent, tokenlist, errorLogger, settings); |
3329 | 0 | } |
3330 | 18 | } |
3331 | | |
3332 | | struct LifetimeStore { |
3333 | | const Token* argtok{}; |
3334 | | std::string message; |
3335 | | ValueFlow::Value::LifetimeKind type = ValueFlow::Value::LifetimeKind::Object; |
3336 | | ErrorPath errorPath; |
3337 | | bool inconclusive{}; |
3338 | | bool forward = true; |
3339 | | |
3340 | 0 | LifetimeStore() = default; |
3341 | | |
3342 | | LifetimeStore(const Token* argtok, |
3343 | | std::string message, |
3344 | | ValueFlow::Value::LifetimeKind type = ValueFlow::Value::LifetimeKind::Object, |
3345 | | bool inconclusive = false) |
3346 | 0 | : argtok(argtok), |
3347 | 0 | message(std::move(message)), |
3348 | 0 | type(type), |
3349 | 0 | inconclusive(inconclusive) |
3350 | 0 | {} |
3351 | | |
3352 | | template<class F> |
3353 | | static void forEach(const TokenList& tokenlist, |
3354 | | ErrorLogger& errorLogger, |
3355 | | const Settings& settings, |
3356 | | const std::vector<const Token*>& argtoks, |
3357 | | const std::string& message, |
3358 | | ValueFlow::Value::LifetimeKind type, |
3359 | 0 | F f) { |
3360 | 0 | std::set<Token*> forwardToks; |
3361 | 0 | for (const Token* arg : argtoks) { |
3362 | 0 | LifetimeStore ls{arg, message, type}; |
3363 | 0 | ls.forward = false; |
3364 | 0 | f(ls); |
3365 | 0 | if (ls.forwardTok) |
3366 | 0 | forwardToks.emplace(ls.forwardTok); |
3367 | 0 | } |
3368 | 0 | for (auto* tok : forwardToks) { |
3369 | 0 | valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings); |
3370 | 0 | } |
3371 | 0 | } Unexecuted instantiation: valueflow.cpp:void LifetimeStore::forEach<valueFlowLifetimeConstructor(Token*, TokenList const&, ErrorLogger&, Settings const&)::$_0>(TokenList const&, ErrorLogger&, Settings const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ValueFlow::Value::LifetimeKind, valueFlowLifetimeConstructor(Token*, TokenList const&, ErrorLogger&, Settings const&)::$_0) Unexecuted instantiation: valueflow.cpp:void LifetimeStore::forEach<valueFlowLifetimeConstructor(Token*, TokenList const&, ErrorLogger&, Settings const&)::$_1>(TokenList const&, ErrorLogger&, Settings const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ValueFlow::Value::LifetimeKind, valueFlowLifetimeConstructor(Token*, TokenList const&, ErrorLogger&, Settings const&)::$_1) Unexecuted instantiation: valueflow.cpp:void LifetimeStore::forEach<valueFlowLifetimeConstructor(Token*, TokenList const&, ErrorLogger&, Settings const&)::$_2>(TokenList const&, ErrorLogger&, Settings const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ValueFlow::Value::LifetimeKind, valueFlowLifetimeConstructor(Token*, TokenList const&, ErrorLogger&, Settings const&)::$_2) Unexecuted instantiation: valueflow.cpp:void LifetimeStore::forEach<valueFlowLifetimeClassConstructor(Token*, Type const*, TokenList const&, ErrorLogger&, Settings const&)::$_0>(TokenList const&, ErrorLogger&, Settings const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ValueFlow::Value::LifetimeKind, valueFlowLifetimeClassConstructor(Token*, Type const*, TokenList const&, ErrorLogger&, Settings const&)::$_0) Unexecuted instantiation: valueflow.cpp:void LifetimeStore::forEach<valueFlowLifetimeClassConstructor(Token*, Type const*, TokenList const&, ErrorLogger&, Settings const&)::$_1>(TokenList const&, ErrorLogger&, Settings const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ValueFlow::Value::LifetimeKind, valueFlowLifetimeClassConstructor(Token*, Type const*, TokenList const&, ErrorLogger&, Settings const&)::$_1) Unexecuted instantiation: valueflow.cpp:void LifetimeStore::forEach<valueFlowLifetimeUserConstructor(Token*, Function const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, TokenList const&, ErrorLogger&, Settings const&)::$_0>(TokenList const&, ErrorLogger&, Settings const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ValueFlow::Value::LifetimeKind, valueFlowLifetimeUserConstructor(Token*, Function const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, TokenList const&, ErrorLogger&, Settings const&)::$_0) Unexecuted instantiation: valueflow.cpp:void LifetimeStore::forEach<valueFlowLifetimeUserConstructor(Token*, Function const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, TokenList const&, ErrorLogger&, Settings const&)::$_1>(TokenList const&, ErrorLogger&, Settings const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ValueFlow::Value::LifetimeKind, valueFlowLifetimeUserConstructor(Token*, Function const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<Token const*, std::__1::allocator<Token const*> > const&, TokenList const&, ErrorLogger&, Settings const&)::$_1) |
3372 | | |
3373 | 0 | static LifetimeStore fromFunctionArg(const Function * f, const Token *tok, const Variable *var, const TokenList &tokenlist, const Settings& settings, ErrorLogger &errorLogger) { |
3374 | 0 | if (!var) |
3375 | 0 | return LifetimeStore{}; |
3376 | 0 | if (!var->isArgument()) |
3377 | 0 | return LifetimeStore{}; |
3378 | 0 | const int n = getArgumentPos(var, f); |
3379 | 0 | if (n < 0) |
3380 | 0 | return LifetimeStore{}; |
3381 | 0 | std::vector<const Token *> args = getArguments(tok); |
3382 | 0 | if (n >= args.size()) { |
3383 | 0 | if (settings.debugwarnings) |
3384 | 0 | bailout(tokenlist, |
3385 | 0 | errorLogger, |
3386 | 0 | tok, |
3387 | 0 | "Argument mismatch: Function '" + tok->str() + "' returning lifetime from argument index " + |
3388 | 0 | std::to_string(n) + " but only " + std::to_string(args.size()) + |
3389 | 0 | " arguments are available."); |
3390 | 0 | return LifetimeStore{}; |
3391 | 0 | } |
3392 | 0 | const Token *argtok2 = args[n]; |
3393 | 0 | return LifetimeStore{argtok2, "Passed to '" + tok->expressionString() + "'.", ValueFlow::Value::LifetimeKind::Object}; |
3394 | 0 | } |
3395 | | |
3396 | | template<class Predicate> |
3397 | | bool byRef(Token* tok, |
3398 | | const TokenList& tokenlist, |
3399 | | ErrorLogger& errorLogger, |
3400 | | const Settings& settings, |
3401 | | const Predicate& pred, |
3402 | | SourceLocation loc = SourceLocation::current()) |
3403 | 0 | { |
3404 | 0 | if (!argtok) |
3405 | 0 | return false; |
3406 | 0 | bool update = false; |
3407 | 0 | for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(argtok, settings)) { |
3408 | 0 | if (!settings.certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive) |
3409 | 0 | continue; |
3410 | 0 | if (!lt.token) |
3411 | 0 | return false; |
3412 | 0 | if (!pred(lt.token)) |
3413 | 0 | return false; |
3414 | 0 | ErrorPath er = errorPath; |
3415 | 0 | er.insert(er.end(), lt.errorPath.cbegin(), lt.errorPath.cend()); |
3416 | 0 | er.emplace_back(argtok, message); |
3417 | |
|
3418 | 0 | ValueFlow::Value value; |
3419 | 0 | value.valueType = ValueFlow::Value::ValueType::LIFETIME; |
3420 | 0 | value.lifetimeScope = ValueFlow::Value::LifetimeScope::Local; |
3421 | 0 | value.tokvalue = lt.token; |
3422 | 0 | value.errorPath = std::move(er); |
3423 | 0 | value.lifetimeKind = type; |
3424 | 0 | value.setInconclusive(lt.inconclusive || inconclusive); |
3425 | | // Don't add the value a second time |
3426 | 0 | if (std::find(tok->values().cbegin(), tok->values().cend(), value) != tok->values().cend()) |
3427 | 0 | return false; |
3428 | 0 | if (settings.debugnormal) |
3429 | 0 | setSourceLocation(value, loc, tok); |
3430 | 0 | setTokenValue(tok, std::move(value), settings); |
3431 | 0 | update = true; |
3432 | 0 | } |
3433 | 0 | if (update && forward) |
3434 | 0 | forwardLifetime(tok, tokenlist, errorLogger, settings); |
3435 | 0 | return update; |
3436 | 0 | } Unexecuted instantiation: bool LifetimeStore::byRef<std::__1::function<bool (Token const*)> >(Token*, TokenList const&, ErrorLogger&, Settings const&, std::__1::function<bool (Token const*)> const&, SourceLocation) Unexecuted instantiation: bool LifetimeStore::byRef<LifetimeStore::byRef(Token*, TokenList const&, ErrorLogger&, Settings const&, SourceLocation)::{lambda(Token const*)#1}>(Token*, TokenList const&, ErrorLogger&, Settings const&, LifetimeStore::byRef(Token*, TokenList const&, ErrorLogger&, Settings const&, SourceLocation)::{lambda(Token const*)#1} const&, SourceLocation) |
3437 | | |
3438 | | bool byRef(Token* tok, |
3439 | | const TokenList& tokenlist, |
3440 | | ErrorLogger& errorLogger, |
3441 | | const Settings& settings, |
3442 | | SourceLocation loc = SourceLocation::current()) |
3443 | 0 | { |
3444 | 0 | return byRef( |
3445 | 0 | tok, |
3446 | 0 | tokenlist, |
3447 | 0 | errorLogger, |
3448 | 0 | settings, |
3449 | 0 | [](const Token*) { |
3450 | 0 | return true; |
3451 | 0 | }, |
3452 | 0 | loc); |
3453 | 0 | } |
3454 | | |
3455 | | template<class Predicate> |
3456 | | bool byVal(Token* tok, |
3457 | | const TokenList& tokenlist, |
3458 | | ErrorLogger& errorLogger, |
3459 | | const Settings& settings, |
3460 | | const Predicate& pred, |
3461 | | SourceLocation loc = SourceLocation::current()) |
3462 | 0 | { |
3463 | 0 | if (!argtok) |
3464 | 0 | return false; |
3465 | 0 | bool update = false; |
3466 | 0 | if (argtok->values().empty()) { |
3467 | 0 | ErrorPath er; |
3468 | 0 | er.emplace_back(argtok, message); |
3469 | 0 | for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(argtok, settings)) { |
3470 | 0 | if (!settings.certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive) |
3471 | 0 | continue; |
3472 | 0 | ValueFlow::Value value; |
3473 | 0 | value.valueType = ValueFlow::Value::ValueType::LIFETIME; |
3474 | 0 | value.tokvalue = lt.token; |
3475 | 0 | value.capturetok = argtok; |
3476 | 0 | value.errorPath = er; |
3477 | 0 | value.lifetimeKind = type; |
3478 | 0 | value.setInconclusive(inconclusive || lt.inconclusive); |
3479 | 0 | const Variable* var = lt.token->variable(); |
3480 | 0 | if (var && var->isArgument()) { |
3481 | 0 | value.lifetimeScope = ValueFlow::Value::LifetimeScope::Argument; |
3482 | 0 | } else { |
3483 | 0 | continue; |
3484 | 0 | } |
3485 | | // Don't add the value a second time |
3486 | 0 | if (std::find(tok->values().cbegin(), tok->values().cend(), value) != tok->values().cend()) |
3487 | 0 | continue; |
3488 | 0 | if (settings.debugnormal) |
3489 | 0 | setSourceLocation(value, loc, tok); |
3490 | 0 | setTokenValue(tok, std::move(value), settings); |
3491 | 0 | update = true; |
3492 | 0 | } |
3493 | 0 | } |
3494 | 0 | for (const ValueFlow::Value &v : argtok->values()) { |
3495 | 0 | if (!v.isLifetimeValue()) |
3496 | 0 | continue; |
3497 | 0 | const Token *tok3 = v.tokvalue; |
3498 | 0 | for (const ValueFlow::LifetimeToken& lt : ValueFlow::getLifetimeTokens(tok3, settings)) { |
3499 | 0 | if (!settings.certainty.isEnabled(Certainty::inconclusive) && lt.inconclusive) |
3500 | 0 | continue; |
3501 | 0 | ErrorPath er = v.errorPath; |
3502 | 0 | er.insert(er.end(), lt.errorPath.cbegin(), lt.errorPath.cend()); |
3503 | 0 | if (!lt.token) |
3504 | 0 | return false; |
3505 | 0 | if (!pred(lt.token)) |
3506 | 0 | return false; |
3507 | 0 | er.emplace_back(argtok, message); |
3508 | 0 | er.insert(er.end(), errorPath.cbegin(), errorPath.cend()); |
3509 | |
|
3510 | 0 | ValueFlow::Value value; |
3511 | 0 | value.valueType = ValueFlow::Value::ValueType::LIFETIME; |
3512 | 0 | value.lifetimeScope = v.lifetimeScope; |
3513 | 0 | value.path = v.path; |
3514 | 0 | value.tokvalue = lt.token; |
3515 | 0 | value.capturetok = argtok; |
3516 | 0 | value.errorPath = std::move(er); |
3517 | 0 | value.lifetimeKind = type; |
3518 | 0 | value.setInconclusive(lt.inconclusive || v.isInconclusive() || inconclusive); |
3519 | | // Don't add the value a second time |
3520 | 0 | if (std::find(tok->values().cbegin(), tok->values().cend(), value) != tok->values().cend()) |
3521 | 0 | continue; |
3522 | 0 | if (settings.debugnormal) |
3523 | 0 | setSourceLocation(value, loc, tok); |
3524 | 0 | setTokenValue(tok, std::move(value), settings); |
3525 | 0 | update = true; |
3526 | 0 | } |
3527 | 0 | } |
3528 | 0 | if (update && forward) |
3529 | 0 | forwardLifetime(tok, tokenlist, errorLogger, settings); |
3530 | 0 | return update; |
3531 | 0 | } Unexecuted instantiation: bool LifetimeStore::byVal<std::__1::function<bool (Token const*)> >(Token*, TokenList const&, ErrorLogger&, Settings const&, std::__1::function<bool (Token const*)> const&, SourceLocation) Unexecuted instantiation: bool LifetimeStore::byVal<LifetimeStore::byVal(Token*, TokenList const&, ErrorLogger&, Settings const&, SourceLocation)::{lambda(Token const*)#1}>(Token*, TokenList const&, ErrorLogger&, Settings const&, LifetimeStore::byVal(Token*, TokenList const&, ErrorLogger&, Settings const&, SourceLocation)::{lambda(Token const*)#1} const&, SourceLocation) Unexecuted instantiation: bool LifetimeStore::byVal<LifetimeStore::byDerefCopy(Token*, TokenList const&, ErrorLogger&, Settings const&, SourceLocation) const::{lambda(Token const*)#1}>(Token*, TokenList const&, ErrorLogger&, Settings const&, LifetimeStore::byDerefCopy(Token*, TokenList const&, ErrorLogger&, Settings const&, SourceLocation) const::{lambda(Token const*)#1} const&, SourceLocation) |
3532 | | |
3533 | | bool byVal(Token* tok, |
3534 | | const TokenList& tokenlist, |
3535 | | ErrorLogger& errorLogger, |
3536 | | const Settings& settings, |
3537 | | SourceLocation loc = SourceLocation::current()) |
3538 | 0 | { |
3539 | 0 | return byVal( |
3540 | 0 | tok, |
3541 | 0 | tokenlist, |
3542 | 0 | errorLogger, |
3543 | 0 | settings, |
3544 | 0 | [](const Token*) { |
3545 | 0 | return true; |
3546 | 0 | }, |
3547 | 0 | loc); |
3548 | 0 | } |
3549 | | |
3550 | | template<class Predicate> |
3551 | | bool byDerefCopy(Token* tok, |
3552 | | const TokenList& tokenlist, |
3553 | | ErrorLogger& errorLogger, |
3554 | | const Settings& settings, |
3555 | | Predicate pred, |
3556 | | SourceLocation loc = SourceLocation::current()) const |
3557 | 0 | { |
3558 | 0 | bool update = false; |
3559 | 0 | if (!settings.certainty.isEnabled(Certainty::inconclusive) && inconclusive) |
3560 | 0 | return update; |
3561 | 0 | if (!argtok) |
3562 | 0 | return update; |
3563 | 0 | if (!tok) |
3564 | 0 | return update; |
3565 | 0 | for (const ValueFlow::Value &v : argtok->values()) { |
3566 | 0 | if (!v.isLifetimeValue()) |
3567 | 0 | continue; |
3568 | 0 | const Token *tok2 = v.tokvalue; |
3569 | 0 | ErrorPath er = v.errorPath; |
3570 | 0 | const Variable *var = ValueFlow::getLifetimeVariable(tok2, er, settings); |
3571 | | // TODO: the inserted data is never used |
3572 | 0 | er.insert(er.end(), errorPath.cbegin(), errorPath.cend()); |
3573 | 0 | if (!var) |
3574 | 0 | continue; |
3575 | 0 | const Token * const varDeclEndToken = var->declEndToken(); |
3576 | 0 | for (const Token *tok3 = tok; tok3 && tok3 != varDeclEndToken; tok3 = tok3->previous()) { |
3577 | 0 | if (tok3->varId() == var->declarationId()) { |
3578 | 0 | update |= LifetimeStore{tok3, message, type, inconclusive} |
3579 | 0 | .byVal(tok, tokenlist, errorLogger, settings, pred, loc); |
3580 | 0 | break; |
3581 | 0 | } |
3582 | 0 | } |
3583 | 0 | } |
3584 | 0 | return update; |
3585 | 0 | } |
3586 | | |
3587 | | bool byDerefCopy(Token* tok, |
3588 | | const TokenList& tokenlist, |
3589 | | ErrorLogger& errorLogger, |
3590 | | const Settings& settings, |
3591 | | SourceLocation loc = SourceLocation::current()) const |
3592 | 0 | { |
3593 | 0 | return byDerefCopy( |
3594 | 0 | tok, |
3595 | 0 | tokenlist, |
3596 | 0 | errorLogger, |
3597 | 0 | settings, |
3598 | 0 | [](const Token*) { |
3599 | 0 | return true; |
3600 | 0 | }, |
3601 | 0 | loc); |
3602 | 0 | } |
3603 | | |
3604 | | private: |
3605 | | // cppcheck-suppress naming-privateMemberVariable |
3606 | | Token* forwardTok{}; |
3607 | 0 | void forwardLifetime(Token* tok, const TokenList& tokenlist, ErrorLogger& errorLogger, const Settings& settings) { |
3608 | 0 | forwardTok = tok; |
3609 | 0 | valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings); |
3610 | 0 | } |
3611 | | }; |
3612 | | |
3613 | | static bool hasBorrowingVariables(const std::list<Variable>& vars, const std::vector<const Token*>& args, int depth = 10) |
3614 | 0 | { |
3615 | 0 | if (depth < 0) |
3616 | 0 | return true; |
3617 | 0 | return std::any_of(vars.cbegin(), vars.cend(), [&](const Variable& var) { |
3618 | 0 | if (const ValueType* vt = var.valueType()) { |
3619 | 0 | if (vt->pointer > 0 && |
3620 | 0 | std::none_of(args.begin(), args.end(), [vt](const Token* arg) { |
3621 | 0 | return arg->valueType() && arg->valueType()->type == vt->type; |
3622 | 0 | })) |
3623 | 0 | return false; |
3624 | 0 | if (vt->pointer > 0) |
3625 | 0 | return true; |
3626 | 0 | if (vt->reference != Reference::None) |
3627 | 0 | return true; |
3628 | 0 | if (vt->isPrimitive()) |
3629 | 0 | return false; |
3630 | 0 | if (vt->isEnum()) |
3631 | 0 | return false; |
3632 | | // TODO: Check container inner type |
3633 | 0 | if (vt->type == ValueType::CONTAINER && vt->container) |
3634 | 0 | return vt->container->view; |
3635 | 0 | if (vt->typeScope) |
3636 | 0 | return hasBorrowingVariables(vt->typeScope->varlist, args, depth - 1); |
3637 | 0 | } |
3638 | 0 | return true; |
3639 | 0 | }); |
3640 | 0 | } |
3641 | | |
3642 | | static void valueFlowLifetimeUserConstructor(Token* tok, |
3643 | | const Function* constructor, |
3644 | | const std::string& name, |
3645 | | const std::vector<const Token*>& args, |
3646 | | const TokenList& tokenlist, |
3647 | | ErrorLogger& errorLogger, |
3648 | | const Settings& settings) |
3649 | 0 | { |
3650 | 0 | if (!constructor) |
3651 | 0 | return; |
3652 | 0 | std::unordered_map<const Token*, const Variable*> argToParam; |
3653 | 0 | for (std::size_t i = 0; i < args.size(); i++) |
3654 | 0 | argToParam[args[i]] = constructor->getArgumentVar(i); |
3655 | 0 | if (const Token* initList = constructor->constructorMemberInitialization()) { |
3656 | 0 | std::unordered_map<const Variable*, LifetimeCapture> paramCapture; |
3657 | 0 | for (const Token* tok2 : astFlatten(initList->astOperand2(), ",")) { |
3658 | 0 | if (!match48(tok2)) |
3659 | 0 | continue; |
3660 | 0 | if (!tok2->astOperand1()) |
3661 | 0 | continue; |
3662 | 0 | if (!tok2->astOperand2()) |
3663 | 0 | continue; |
3664 | 0 | const Variable* var = tok2->astOperand1()->variable(); |
3665 | 0 | const Token* expr = tok2->astOperand2(); |
3666 | 0 | if (!var) |
3667 | 0 | continue; |
3668 | 0 | if (!ValueFlow::isLifetimeBorrowed(expr, settings)) |
3669 | 0 | continue; |
3670 | 0 | const Variable* argvar = ValueFlow::getLifetimeVariable(expr, settings); |
3671 | 0 | if (var->isReference() || var->isRValueReference()) { |
3672 | 0 | if (argvar && argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) { |
3673 | 0 | paramCapture[argvar] = LifetimeCapture::ByReference; |
3674 | 0 | } |
3675 | 0 | } else { |
3676 | 0 | bool found = false; |
3677 | 0 | for (const ValueFlow::Value& v : expr->values()) { |
3678 | 0 | if (!v.isLifetimeValue()) |
3679 | 0 | continue; |
3680 | 0 | if (v.path > 0) |
3681 | 0 | continue; |
3682 | 0 | if (!v.tokvalue) |
3683 | 0 | continue; |
3684 | 0 | const Variable* lifeVar = v.tokvalue->variable(); |
3685 | 0 | if (!lifeVar) |
3686 | 0 | continue; |
3687 | 0 | LifetimeCapture c = LifetimeCapture::Undefined; |
3688 | 0 | if (!v.isArgumentLifetimeValue() && (lifeVar->isReference() || lifeVar->isRValueReference())) |
3689 | 0 | c = LifetimeCapture::ByReference; |
3690 | 0 | else if (v.isArgumentLifetimeValue()) |
3691 | 0 | c = LifetimeCapture::ByValue; |
3692 | 0 | if (c != LifetimeCapture::Undefined) { |
3693 | 0 | paramCapture[lifeVar] = c; |
3694 | 0 | found = true; |
3695 | 0 | } |
3696 | 0 | } |
3697 | 0 | if (!found && argvar && argvar->isArgument()) |
3698 | 0 | paramCapture[argvar] = LifetimeCapture::ByValue; |
3699 | 0 | } |
3700 | 0 | } |
3701 | | // TODO: Use SubExpressionAnalyzer for members |
3702 | 0 | LifetimeStore::forEach(tokenlist, |
3703 | 0 | errorLogger, |
3704 | 0 | settings, |
3705 | 0 | args, |
3706 | 0 | "Passed to constructor of '" + name + "'.", |
3707 | 0 | ValueFlow::Value::LifetimeKind::SubObject, |
3708 | 0 | [&](LifetimeStore& ls) { |
3709 | 0 | const Variable* paramVar = argToParam.at(ls.argtok); |
3710 | 0 | if (paramCapture.count(paramVar) == 0) |
3711 | 0 | return; |
3712 | 0 | const LifetimeCapture c = paramCapture.at(paramVar); |
3713 | 0 | if (c == LifetimeCapture::ByReference) |
3714 | 0 | ls.byRef(tok, tokenlist, errorLogger, settings); |
3715 | 0 | else |
3716 | 0 | ls.byVal(tok, tokenlist, errorLogger, settings); |
3717 | 0 | }); |
3718 | 0 | } else if (hasBorrowingVariables(constructor->nestedIn->varlist, args)) { |
3719 | 0 | LifetimeStore::forEach(tokenlist, |
3720 | 0 | errorLogger, |
3721 | 0 | settings, |
3722 | 0 | args, |
3723 | 0 | "Passed to constructor of '" + name + "'.", |
3724 | 0 | ValueFlow::Value::LifetimeKind::SubObject, |
3725 | 0 | [&](LifetimeStore& ls) { |
3726 | 0 | ls.inconclusive = true; |
3727 | 0 | const Variable* var = argToParam.at(ls.argtok); |
3728 | 0 | if (var && !var->isConst() && var->isReference()) |
3729 | 0 | ls.byRef(tok, tokenlist, errorLogger, settings); |
3730 | 0 | else |
3731 | 0 | ls.byVal(tok, tokenlist, errorLogger, settings); |
3732 | 0 | }); |
3733 | 0 | } |
3734 | 0 | } |
3735 | | |
3736 | | static void valueFlowLifetimeFunction(Token *tok, const TokenList &tokenlist, ErrorLogger &errorLogger, const Settings &settings) |
3737 | 187 | { |
3738 | 187 | if (!match38(tok)) |
3739 | 0 | return; |
3740 | 187 | Token* memtok = nullptr; |
3741 | 187 | if (match16(tok->astParent()) && astIsRHS(tok)) |
3742 | 0 | memtok = tok->astParent()->astOperand1(); |
3743 | 187 | const int returnContainer = settings.library.returnValueContainer(tok); |
3744 | 187 | if (returnContainer >= 0) { |
3745 | 0 | std::vector<const Token *> args = getArguments(tok); |
3746 | 0 | for (int argnr = 1; argnr <= args.size(); ++argnr) { |
3747 | 0 | const Library::ArgumentChecks::IteratorInfo *i = settings.library.getArgIteratorInfo(tok, argnr); |
3748 | 0 | if (!i) |
3749 | 0 | continue; |
3750 | 0 | if (i->container != returnContainer) |
3751 | 0 | continue; |
3752 | 0 | const Token * const argTok = args[argnr - 1]; |
3753 | 0 | bool forward = false; |
3754 | 0 | for (ValueFlow::Value val : argTok->values()) { |
3755 | 0 | if (!val.isLifetimeValue()) |
3756 | 0 | continue; |
3757 | 0 | val.errorPath.emplace_back(argTok, "Passed to '" + tok->str() + "'."); |
3758 | 0 | setTokenValue(tok->next(), std::move(val), settings); |
3759 | 0 | forward = true; |
3760 | 0 | } |
3761 | | // Check if lifetime is available to avoid adding the lifetime twice |
3762 | 0 | if (forward) { |
3763 | 0 | valueFlowForwardLifetime(tok, tokenlist, errorLogger, settings); |
3764 | 0 | break; |
3765 | 0 | } |
3766 | 0 | } |
3767 | 187 | } else if (match49(tok->tokAt(-2))) { |
3768 | 0 | for (const Token *argtok : getArguments(tok)) { |
3769 | 0 | LifetimeStore{argtok, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}.byRef( |
3770 | 0 | tok->next(), tokenlist, errorLogger, settings); |
3771 | 0 | } |
3772 | 187 | } else if (match50(tok->tokAt(-2))) { |
3773 | 0 | for (const Token *argtok : getArguments(tok)) { |
3774 | 0 | LifetimeStore{argtok, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Object}.byVal( |
3775 | 0 | tok->next(), tokenlist, errorLogger, settings); |
3776 | 0 | } |
3777 | 187 | } else if (memtok && match51(tok->astParent()) && |
3778 | 187 | astIsNonStringContainer(memtok)) { |
3779 | 0 | std::vector<const Token *> args = getArguments(tok); |
3780 | 0 | const std::size_t n = args.size(); |
3781 | 0 | if (n > 1 && Token::typeStr(args[n - 2]) == Token::typeStr(args[n - 1]) && |
3782 | 0 | (((astIsIterator(args[n - 2]) && astIsIterator(args[n - 1])) || |
3783 | 0 | (astIsPointer(args[n - 2]) && astIsPointer(args[n - 1]))))) { |
3784 | 0 | LifetimeStore{ |
3785 | 0 | args.back(), "Added to container '" + memtok->str() + "'.", ValueFlow::Value::LifetimeKind::Object} |
3786 | 0 | .byDerefCopy(memtok, tokenlist, errorLogger, settings); |
3787 | 0 | } else if (!args.empty() && ValueFlow::isLifetimeBorrowed(args.back(), settings)) { |
3788 | 0 | LifetimeStore{ |
3789 | 0 | args.back(), "Added to container '" + memtok->str() + "'.", ValueFlow::Value::LifetimeKind::Object} |
3790 | 0 | .byVal(memtok, tokenlist, errorLogger, settings); |
3791 | 0 | } |
3792 | 187 | } else if (tok->function()) { |
3793 | 0 | const Function *f = tok->function(); |
3794 | 0 | if (f->isConstructor()) { |
3795 | 0 | valueFlowLifetimeUserConstructor(tok->next(), f, tok->str(), getArguments(tok), tokenlist, errorLogger, settings); |
3796 | 0 | return; |
3797 | 0 | } |
3798 | 0 | if (Function::returnsReference(f)) |
3799 | 0 | return; |
3800 | 0 | std::vector<const Token*> returns = Function::findReturns(f); |
3801 | 0 | const bool inconclusive = returns.size() > 1; |
3802 | 0 | bool update = false; |
3803 | 0 | for (const Token* returnTok : returns) { |
3804 | 0 | if (returnTok == tok) |
3805 | 0 | continue; |
3806 | 0 | const Variable *returnVar = ValueFlow::getLifetimeVariable(returnTok, settings); |
3807 | 0 | if (returnVar && returnVar->isArgument() && (returnVar->isConst() || !isVariableChanged(returnVar, settings))) { |
3808 | 0 | LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, returnVar, tokenlist, settings, errorLogger); |
3809 | 0 | ls.inconclusive = inconclusive; |
3810 | 0 | ls.forward = false; |
3811 | 0 | update |= ls.byVal(tok->next(), tokenlist, errorLogger, settings); |
3812 | 0 | } |
3813 | 0 | for (const ValueFlow::Value &v : returnTok->values()) { |
3814 | 0 | if (!v.isLifetimeValue()) |
3815 | 0 | continue; |
3816 | 0 | if (!v.tokvalue) |
3817 | 0 | continue; |
3818 | 0 | if (memtok && |
3819 | 0 | (contains({ValueFlow::Value::LifetimeScope::ThisPointer, ValueFlow::Value::LifetimeScope::ThisValue}, |
3820 | 0 | v.lifetimeScope) || |
3821 | 0 | exprDependsOnThis(v.tokvalue))) { |
3822 | 0 | LifetimeStore ls = LifetimeStore{memtok, |
3823 | 0 | "Passed to member function '" + tok->expressionString() + "'.", |
3824 | 0 | ValueFlow::Value::LifetimeKind::Object}; |
3825 | 0 | ls.inconclusive = inconclusive; |
3826 | 0 | ls.forward = false; |
3827 | 0 | ls.errorPath = v.errorPath; |
3828 | 0 | ls.errorPath.emplace_front(returnTok, "Return " + lifetimeType(returnTok, &v) + "."); |
3829 | 0 | int thisIndirect = v.lifetimeScope == ValueFlow::Value::LifetimeScope::ThisValue ? 0 : 1; |
3830 | 0 | if (derefShared(memtok->astParent())) |
3831 | 0 | thisIndirect--; |
3832 | 0 | if (thisIndirect == -1) |
3833 | 0 | update |= ls.byDerefCopy(tok->next(), tokenlist, errorLogger, settings); |
3834 | 0 | else if (thisIndirect == 0) |
3835 | 0 | update |= ls.byVal(tok->next(), tokenlist, errorLogger, settings); |
3836 | 0 | else if (thisIndirect == 1) |
3837 | 0 | update |= ls.byRef(tok->next(), tokenlist, errorLogger, settings); |
3838 | 0 | continue; |
3839 | 0 | } |
3840 | 0 | const Variable *var = v.tokvalue->variable(); |
3841 | 0 | LifetimeStore ls = LifetimeStore::fromFunctionArg(f, tok, var, tokenlist, settings, errorLogger); |
3842 | 0 | if (!ls.argtok) |
3843 | 0 | continue; |
3844 | 0 | ls.forward = false; |
3845 | 0 | ls.inconclusive = inconclusive; |
3846 | 0 | ls.errorPath = v.errorPath; |
3847 | 0 | ls.errorPath.emplace_front(returnTok, "Return " + lifetimeType(returnTok, &v) + "."); |
3848 | 0 | if (!v.isArgumentLifetimeValue() && (var->isReference() || var->isRValueReference())) { |
3849 | 0 | update |= ls.byRef(tok->next(), tokenlist, errorLogger, settings); |
3850 | 0 | } else if (v.isArgumentLifetimeValue()) { |
3851 | 0 | update |= ls.byVal(tok->next(), tokenlist, errorLogger, settings); |
3852 | 0 | } |
3853 | 0 | } |
3854 | 0 | } |
3855 | 0 | if (update) |
3856 | 0 | valueFlowForwardLifetime(tok->next(), tokenlist, errorLogger, settings); |
3857 | 187 | } else if (tok->valueType()) { |
3858 | | // TODO: Propagate lifetimes with library functions |
3859 | 187 | if (settings.library.getFunction(tok->previous())) |
3860 | 0 | return; |
3861 | 187 | if (match40(tok->astParent())) |
3862 | 0 | return; |
3863 | | // Assume constructing the valueType |
3864 | 187 | valueFlowLifetimeConstructor(tok->next(), tokenlist, errorLogger, settings); |
3865 | 187 | valueFlowForwardLifetime(tok->next(), tokenlist, errorLogger, settings); |
3866 | 187 | } else { |
3867 | 0 | const std::string& retVal = settings.library.returnValue(tok); |
3868 | 0 | if (startsWith(retVal, "arg")) { |
3869 | 0 | std::size_t iArg{}; |
3870 | 0 | try { |
3871 | 0 | iArg = strToInt<std::size_t>(retVal.substr(3)); |
3872 | 0 | } catch (...) { |
3873 | 0 | return; |
3874 | 0 | } |
3875 | 0 | std::vector<const Token*> args = getArguments(tok); |
3876 | 0 | if (iArg > 0 && iArg <= args.size()) { |
3877 | 0 | const Token* varTok = args[iArg - 1]; |
3878 | 0 | if (varTok->variable() && varTok->variable()->isLocal()) |
3879 | 0 | LifetimeStore{ varTok, "Passed to '" + tok->str() + "'.", ValueFlow::Value::LifetimeKind::Address }.byRef( |
3880 | 0 | tok->next(), tokenlist, errorLogger, settings); |
3881 | 0 | } |
3882 | 0 | } |
3883 | 0 | } |
3884 | 187 | } |
3885 | | |
3886 | | static bool isScope(const Token* tok) |
3887 | 983 | { |
3888 | 983 | if (!tok) |
3889 | 0 | return false; |
3890 | 983 | if (!match4(tok)) |
3891 | 187 | return false; |
3892 | 796 | const Scope* scope = tok->scope(); |
3893 | 796 | if (!scope) |
3894 | 0 | return false; |
3895 | 796 | if (!scope->bodyStart) |
3896 | 0 | return false; |
3897 | 796 | return scope->bodyStart == tok; |
3898 | 796 | } |
3899 | | |
3900 | | static const Function* findConstructor(const Scope* scope, const Token* tok, const std::vector<const Token*>& args) |
3901 | 0 | { |
3902 | 0 | if (!tok) |
3903 | 0 | return nullptr; |
3904 | 0 | const Function* f = tok->function(); |
3905 | 0 | if (!f && tok->astOperand1()) |
3906 | 0 | f = tok->astOperand1()->function(); |
3907 | | // Search for a constructor |
3908 | 0 | if (!f || !f->isConstructor()) { |
3909 | 0 | f = nullptr; |
3910 | 0 | std::vector<const Function*> candidates; |
3911 | 0 | for (const Function& function : scope->functionList) { |
3912 | 0 | if (function.minArgCount() > args.size()) |
3913 | 0 | continue; |
3914 | 0 | if (!function.isConstructor()) |
3915 | 0 | continue; |
3916 | 0 | candidates.push_back(&function); |
3917 | 0 | } |
3918 | | // TODO: Narrow the candidates |
3919 | 0 | if (candidates.size() == 1) |
3920 | 0 | f = candidates.front(); |
3921 | 0 | } |
3922 | 0 | if (!f) |
3923 | 0 | return nullptr; |
3924 | 0 | return f; |
3925 | 0 | } |
3926 | | |
3927 | | static void valueFlowLifetimeClassConstructor(Token* tok, |
3928 | | const Type* t, |
3929 | | const TokenList& tokenlist, |
3930 | | ErrorLogger& errorLogger, |
3931 | | const Settings& settings) |
3932 | 0 | { |
3933 | 0 | if (!match52(tok)) |
3934 | 0 | return; |
3935 | 0 | if (isScope(tok)) |
3936 | 0 | return; |
3937 | 0 | if (!t) { |
3938 | 0 | if (tok->valueType() && tok->valueType()->type != ValueType::RECORD) |
3939 | 0 | return; |
3940 | 0 | if (tok->str() != MatchCompiler::makeConstString("{") && !match53(tok->previous()) && !isVariableDecl(tok->previous())) |
3941 | 0 | return; |
3942 | | // If the type is unknown then assume it captures by value in the |
3943 | | // constructor, but make each lifetime inconclusive |
3944 | 0 | std::vector<const Token*> args = getArguments(tok); |
3945 | 0 | LifetimeStore::forEach(tokenlist, |
3946 | 0 | errorLogger, |
3947 | 0 | settings, |
3948 | 0 | args, |
3949 | 0 | "Passed to initializer list.", |
3950 | 0 | ValueFlow::Value::LifetimeKind::SubObject, |
3951 | 0 | [&](LifetimeStore& ls) { |
3952 | 0 | ls.inconclusive = true; |
3953 | 0 | ls.byVal(tok, tokenlist, errorLogger, settings); |
3954 | 0 | }); |
3955 | 0 | return; |
3956 | 0 | } |
3957 | 0 | const Scope* scope = t->classScope; |
3958 | 0 | if (!scope) |
3959 | 0 | return; |
3960 | | // Aggregate constructor |
3961 | 0 | if (t->derivedFrom.empty() && (t->isClassType() || t->isStructType())) { |
3962 | 0 | std::vector<const Token*> args = getArguments(tok); |
3963 | 0 | if (scope->numConstructors == 0) { |
3964 | 0 | auto it = scope->varlist.cbegin(); |
3965 | 0 | LifetimeStore::forEach( |
3966 | 0 | tokenlist, |
3967 | 0 | errorLogger, |
3968 | 0 | settings, |
3969 | 0 | args, |
3970 | 0 | "Passed to constructor of '" + t->name() + "'.", |
3971 | 0 | ValueFlow::Value::LifetimeKind::SubObject, |
3972 | 0 | [&](LifetimeStore& ls) { |
3973 | | // Skip static variable |
3974 | 0 | it = std::find_if(it, scope->varlist.cend(), [](const Variable& var) { |
3975 | 0 | return !var.isStatic(); |
3976 | 0 | }); |
3977 | 0 | if (it == scope->varlist.cend()) |
3978 | 0 | return; |
3979 | 0 | const Variable& var = *it; |
3980 | 0 | if (var.valueType() && var.valueType()->container && var.valueType()->container->stdStringLike && !var.valueType()->container->view) |
3981 | 0 | return; // TODO: check in isLifetimeBorrowed()? |
3982 | 0 | if (var.isReference() || var.isRValueReference()) { |
3983 | 0 | ls.byRef(tok, tokenlist, errorLogger, settings); |
3984 | 0 | } else if (ValueFlow::isLifetimeBorrowed(ls.argtok, settings)) { |
3985 | 0 | ls.byVal(tok, tokenlist, errorLogger, settings); |
3986 | 0 | } |
3987 | 0 | it++; |
3988 | 0 | }); |
3989 | 0 | } else { |
3990 | 0 | const Function* constructor = findConstructor(scope, tok, args); |
3991 | 0 | valueFlowLifetimeUserConstructor(tok, constructor, t->name(), args, tokenlist, errorLogger, settings); |
3992 | 0 | } |
3993 | 0 | } |
3994 | 0 | } |
3995 | | |
3996 | | static void valueFlowLifetimeConstructor(Token* tok, const TokenList& tokenlist, ErrorLogger& errorLogger, const Settings& settings) |
3997 | 187 | { |
3998 | 187 | if (!match52(tok)) |
3999 | 0 | return; |
4000 | 187 | if (isScope(tok)) |
4001 | 0 | return; |
4002 | 187 | std::vector<ValueType> vts; |
4003 | 187 | if (tok->valueType()) { |
4004 | 0 | vts = {*tok->valueType()}; |
4005 | 187 | } else if (match47(tok->previous()) && isVariableDecl(tok->previous()) && |
4006 | 187 | tok->previous()->valueType()) { |
4007 | 0 | vts = {*tok->previous()->valueType()}; |
4008 | 187 | } else if (match4(tok) && !match54(tok->previous())) { |
4009 | 0 | vts = getParentValueTypes(tok, settings); |
4010 | 0 | } |
4011 | | |
4012 | 187 | for (const ValueType& vt : vts) { |
4013 | 0 | if (vt.pointer > 0) { |
4014 | 0 | std::vector<const Token*> args = getArguments(tok); |
4015 | 0 | LifetimeStore::forEach(tokenlist, |
4016 | 0 | errorLogger, |
4017 | 0 | settings, |
4018 | 0 | args, |
4019 | 0 | "Passed to initializer list.", |
4020 | 0 | ValueFlow::Value::LifetimeKind::SubObject, |
4021 | 0 | [&](LifetimeStore& ls) { |
4022 | 0 | ls.byVal(tok, tokenlist, errorLogger, settings); |
4023 | 0 | }); |
4024 | 0 | } else if (vt.container && vt.type == ValueType::CONTAINER) { |
4025 | 0 | std::vector<const Token*> args = getArguments(tok); |
4026 | 0 | if (args.size() == 1 && vt.container->view && astIsContainerOwned(args.front())) { |
4027 | 0 | LifetimeStore{args.front(), "Passed to container view.", ValueFlow::Value::LifetimeKind::SubObject} |
4028 | 0 | .byRef(tok, tokenlist, errorLogger, settings); |
4029 | 0 | } else if (args.size() == 2 && (astIsIterator(args[0]) || astIsIterator(args[1]))) { |
4030 | 0 | LifetimeStore::forEach( |
4031 | 0 | tokenlist, |
4032 | 0 | errorLogger, |
4033 | 0 | settings, |
4034 | 0 | args, |
4035 | 0 |