/src/cppcheck/oss-fuzz/build/reverseanalyzer.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 | 0 | static inline bool match1(const Token* tok) { |
8 | 0 | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{")))) |
9 | 0 | return false; |
10 | 0 | return true; |
11 | 0 | } |
12 | | // pattern: } else { |
13 | 64 | static inline bool match2(const Token* tok) { |
14 | 64 | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}"))) |
15 | 60 | return false; |
16 | 4 | tok = tok->next(); |
17 | 4 | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("else"))) |
18 | 0 | return false; |
19 | 4 | tok = tok->next(); |
20 | 4 | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))) |
21 | 0 | return false; |
22 | 4 | return true; |
23 | 4 | } |
24 | | // pattern: ) { |
25 | 46 | static inline bool match3(const Token* tok) { |
26 | 46 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")"))) |
27 | 0 | return false; |
28 | 46 | tok = tok->next(); |
29 | 46 | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))) |
30 | 0 | return false; |
31 | 46 | return true; |
32 | 46 | } |
33 | | // pattern: do { |
34 | 0 | static inline bool match4(const Token* tok) { |
35 | 0 | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("do"))) |
36 | 0 | return false; |
37 | 0 | tok = tok->next(); |
38 | 0 | if (!tok || !((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("{"))) |
39 | 0 | return false; |
40 | 0 | return true; |
41 | 0 | } |
42 | | // pattern: : |
43 | 4.00k | static inline bool match5(const Token* tok) { |
44 | 4.00k | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":"))) |
45 | 4.00k | return false; |
46 | 0 | return true; |
47 | 4.00k | } |
48 | | // pattern: %oror%|&&|? |
49 | 513 | static inline bool match6(const Token* tok) { |
50 | 513 | 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("?")))) |
51 | 513 | return false; |
52 | 0 | return true; |
53 | 513 | } |
54 | | // pattern: return|break|continue |
55 | 1.19k | static inline bool match7(const Token* tok) { |
56 | 1.19k | if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("break")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("continue")))) |
57 | 1.19k | return false; |
58 | 0 | return true; |
59 | 1.19k | } |
60 | | // pattern: %name% : |
61 | 1.19k | static inline bool match8(const Token* tok) { |
62 | 1.19k | if (!tok || !tok->isName()) |
63 | 539 | return false; |
64 | 655 | tok = tok->next(); |
65 | 655 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(":"))) |
66 | 655 | return false; |
67 | 0 | return true; |
68 | 655 | } |
69 | | // pattern: %assign% |
70 | 459 | static inline bool match9(const Token* tok) { |
71 | 459 | if (!tok || !tok->isAssignmentOp()) |
72 | 459 | return false; |
73 | 0 | return true; |
74 | 459 | } |
75 | | // pattern: for|while ( |
76 | 54 | static inline bool match10(const Token* tok) { |
77 | 54 | if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("for")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while")))) |
78 | 44 | return false; |
79 | 10 | tok = tok->next(); |
80 | 10 | if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("("))) |
81 | 0 | return false; |
82 | 10 | return true; |
83 | 10 | } |
84 | | // pattern: goto|break |
85 | 4 | template<class T> static inline T * findmatch11(T * start_tok, const Token * end) { |
86 | 24 | for (; start_tok && start_tok != end; start_tok = start_tok->next()) { |
87 | | |
88 | 20 | T * tok = start_tok; |
89 | 20 | if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("goto")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("break")))) |
90 | 20 | continue; |
91 | 0 | return start_tok; |
92 | 20 | } |
93 | 4 | return nullptr; |
94 | 4 | } |
95 | | // pattern: do |
96 | 40 | static inline bool match12(const Token* tok) { |
97 | 40 | if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("do"))) |
98 | 40 | return false; |
99 | 0 | return true; |
100 | 40 | } |
101 | | // pattern: )|} |
102 | 1.19k | static inline bool match13(const Token* tok) { |
103 | 1.19k | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")) || ((tok->tokType() == Token::eBracket) && tok->str() == MatchCompiler::makeConstString("}")))) |
104 | 1.17k | return false; |
105 | 22 | return true; |
106 | 1.19k | } |
107 | | // pattern: )|> |
108 | 1.71k | static inline bool match14(const Token* tok) { |
109 | 1.71k | if (!tok || !(((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString(")")) || ((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")))) |
110 | 1.69k | return false; |
111 | 20 | return true; |
112 | 1.71k | } |
113 | | // pattern: < |
114 | 4 | static inline bool match15(const Token* tok) { |
115 | 4 | if (!tok || !((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<"))) |
116 | 4 | return false; |
117 | 0 | return true; |
118 | 4 | } |
119 | | /* |
120 | | * Cppcheck - A tool for static C/C++ code analysis |
121 | | * Copyright (C) 2007-2024 Cppcheck team. |
122 | | * |
123 | | * This program is free software: you can redistribute it and/or modify |
124 | | * it under the terms of the GNU General Public License as published by |
125 | | * the Free Software Foundation, either version 3 of the License, or |
126 | | * (at your option) any later version. |
127 | | * |
128 | | * This program is distributed in the hope that it will be useful, |
129 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
130 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
131 | | * GNU General Public License for more details. |
132 | | * |
133 | | * You should have received a copy of the GNU General Public License |
134 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
135 | | */ |
136 | | |
137 | | #include "reverseanalyzer.h" |
138 | | |
139 | | #include "analyzer.h" |
140 | | #include "astutils.h" |
141 | | #include "errortypes.h" |
142 | | #include "forwardanalyzer.h" |
143 | | #include "mathlib.h" |
144 | | #include "settings.h" |
145 | | #include "symboldatabase.h" |
146 | | #include "token.h" |
147 | | #include "valueptr.h" |
148 | | |
149 | | #include <algorithm> |
150 | | #include <cstddef> |
151 | | #include <string> |
152 | | #include <tuple> |
153 | | #include <utility> |
154 | | #include <vector> |
155 | | |
156 | | namespace { |
157 | | struct ReverseTraversal { |
158 | | ReverseTraversal(const ValuePtr<Analyzer>& analyzer, const TokenList& tokenlist, ErrorLogger& errorLogger, const Settings& settings) |
159 | 140 | : analyzer(analyzer), tokenlist(tokenlist), errorLogger(errorLogger), settings(settings) |
160 | 140 | {} |
161 | | ValuePtr<Analyzer> analyzer; |
162 | | const TokenList& tokenlist; |
163 | | ErrorLogger& errorLogger; |
164 | | const Settings& settings; |
165 | | |
166 | 0 | std::pair<bool, bool> evalCond(const Token* tok) const { |
167 | 0 | std::vector<MathLib::bigint> result = analyzer->evaluate(tok); |
168 | | // TODO: We should convert to bool |
169 | 0 | const bool checkThen = std::any_of(result.cbegin(), result.cend(), [](MathLib::bigint x) { |
170 | 0 | return x == 1; |
171 | 0 | }); |
172 | 0 | const bool checkElse = std::any_of(result.cbegin(), result.cend(), [](MathLib::bigint x) { |
173 | 0 | return x == 0; |
174 | 0 | }); |
175 | 0 | return std::make_pair(checkThen, checkElse); |
176 | 0 | } |
177 | | |
178 | 1.70k | bool update(Token* tok) { |
179 | 1.70k | Analyzer::Action action = analyzer->analyze(tok, Analyzer::Direction::Reverse); |
180 | 1.70k | if (action.isInconclusive() && !analyzer->lowerToInconclusive()) |
181 | 0 | return false; |
182 | 1.70k | if (action.isInvalid()) |
183 | 12 | return false; |
184 | 1.69k | if (!action.isNone()) |
185 | 213 | analyzer->update(tok, action, Analyzer::Direction::Reverse); |
186 | 1.69k | return true; |
187 | 1.70k | } |
188 | | |
189 | | static Token* getParentFunction(Token* tok) |
190 | 0 | { |
191 | 0 | if (!tok) |
192 | 0 | return nullptr; |
193 | 0 | if (!tok->astParent()) |
194 | 0 | return nullptr; |
195 | 0 | int argn = -1; |
196 | 0 | if (Token* ftok = getTokenArgumentFunction(tok, argn)) { |
197 | 0 | while (!match1(ftok)) { |
198 | 0 | if (!ftok) |
199 | 0 | return nullptr; |
200 | 0 | if (ftok->index() >= tok->index()) |
201 | 0 | return nullptr; |
202 | 0 | if (!ftok->link() || ftok->str() == MatchCompiler::makeConstString(")")) |
203 | 0 | ftok = ftok->next(); |
204 | 0 | else |
205 | 0 | ftok = ftok->link()->next(); |
206 | 0 | } |
207 | 0 | if (ftok == tok) |
208 | 0 | return nullptr; |
209 | 0 | return ftok; |
210 | 0 | } |
211 | 0 | return nullptr; |
212 | 0 | } |
213 | | |
214 | | static Token* getTopFunction(Token* tok) |
215 | 4 | { |
216 | 4 | if (!tok) |
217 | 0 | return nullptr; |
218 | 4 | if (!tok->astParent()) |
219 | 4 | return tok; |
220 | 0 | Token* parent = tok; |
221 | 0 | Token* top = tok; |
222 | 0 | while ((parent = getParentFunction(parent))) |
223 | 0 | top = parent; |
224 | 0 | return top; |
225 | 4 | } |
226 | | |
227 | | static Token* jumpToStart(Token* tok) |
228 | 46 | { |
229 | 46 | if (match2(tok->tokAt(-2))) |
230 | 4 | tok = tok->linkAt(-2); |
231 | 46 | if (match3(tok->previous())) |
232 | 46 | return tok->linkAt(-1); |
233 | 0 | if (match4(tok->previous())) |
234 | 0 | return tok->previous(); |
235 | 0 | return tok; |
236 | 0 | } |
237 | | |
238 | 918 | bool updateRecursive(Token* start) { |
239 | 918 | bool continueB = true; |
240 | 1.03k | visitAstNodes(start, [&](Token* tok) { |
241 | 1.03k | const Token* parent = tok->astParent(); |
242 | 1.03k | while (match5(parent)) |
243 | 0 | parent = parent->astParent(); |
244 | 1.03k | if (isUnevaluated(tok) || isDeadCode(tok, parent)) |
245 | 0 | return ChildrenToVisit::none; |
246 | 1.03k | continueB &= update(tok); |
247 | 1.03k | if (continueB) |
248 | 1.02k | return ChildrenToVisit::op1_and_op2; |
249 | 12 | return ChildrenToVisit::done; |
250 | 1.03k | }); |
251 | 918 | return continueB; |
252 | 918 | } |
253 | | |
254 | 18 | Analyzer::Action analyzeRecursive(const Token* start) const { |
255 | 18 | Analyzer::Action result = Analyzer::Action::None; |
256 | 96 | visitAstNodes(start, [&](const Token* tok) { |
257 | 96 | result |= analyzer->analyze(tok, Analyzer::Direction::Reverse); |
258 | 96 | if (result.isModified()) |
259 | 0 | return ChildrenToVisit::done; |
260 | 96 | return ChildrenToVisit::op1_and_op2; |
261 | 96 | }); |
262 | 18 | return result; |
263 | 18 | } |
264 | | |
265 | 24 | Analyzer::Action analyzeRange(const Token* start, const Token* end) const { |
266 | 24 | Analyzer::Action result = Analyzer::Action::None; |
267 | 496 | for (const Token* tok = start; tok && tok != end; tok = tok->next()) { |
268 | 472 | Analyzer::Action action = analyzer->analyze(tok, Analyzer::Direction::Reverse); |
269 | 472 | if (action.isModified()) |
270 | 0 | return action; |
271 | 472 | result |= action; |
272 | 472 | } |
273 | 24 | return result; |
274 | 24 | } |
275 | | |
276 | 2.16k | Token* isDeadCode(Token* tok, const Token* end = nullptr) const { |
277 | 2.16k | int opSide = 0; |
278 | 3.43k | for (; tok && tok->astParent(); tok = tok->astParent()) { |
279 | 1.38k | if (tok == end) |
280 | 116 | break; |
281 | 1.26k | Token* parent = tok->astParent(); |
282 | 1.26k | if (match5(parent)) { |
283 | 0 | if (astIsLHS(tok)) |
284 | 0 | opSide = 1; |
285 | 0 | else if (astIsRHS(tok)) |
286 | 0 | opSide = 2; |
287 | 0 | else |
288 | 0 | opSide = 0; |
289 | 0 | } |
290 | 1.26k | if (tok != parent->astOperand2()) |
291 | 751 | continue; |
292 | 513 | if (match5(parent)) |
293 | 0 | parent = parent->astParent(); |
294 | 513 | if (!match6(parent)) |
295 | 513 | continue; |
296 | 0 | const Token* condTok = parent->astOperand1(); |
297 | 0 | if (!condTok) |
298 | 0 | continue; |
299 | 0 | bool checkThen, checkElse; |
300 | 0 | std::tie(checkThen, checkElse) = evalCond(condTok); |
301 | |
|
302 | 0 | if (parent->str() == MatchCompiler::makeConstString("?")) { |
303 | 0 | if (checkElse && opSide == 1) |
304 | 0 | return parent; |
305 | 0 | if (checkThen && opSide == 2) |
306 | 0 | return parent; |
307 | 0 | } |
308 | 0 | if (!checkThen && parent->str() == MatchCompiler::makeConstString("&&")) |
309 | 0 | return parent; |
310 | 0 | if (!checkElse && parent->str() == MatchCompiler::makeConstString("||")) |
311 | 0 | return parent; |
312 | 0 | } |
313 | 2.16k | return nullptr; |
314 | 2.16k | } |
315 | | |
316 | 140 | void traverse(Token* start, const Token* end = nullptr) { |
317 | 140 | if (start == end) |
318 | 0 | return; |
319 | 140 | std::size_t i = start->index(); |
320 | 1.31k | for (Token* tok = start->previous(); succeeds(tok, end); tok = tok->previous()) { |
321 | 1.31k | if (tok->index() >= i) |
322 | 0 | throw InternalError(tok, "Cyclic reverse analysis."); |
323 | 1.31k | i = tok->index(); |
324 | 1.31k | if (tok == start || (tok->str() == MatchCompiler::makeConstString("{") && (tok->scope()->type == Scope::ScopeType::eFunction || |
325 | 156 | tok->scope()->type == Scope::ScopeType::eLambda))) { |
326 | 116 | const Function* f = tok->scope()->function; |
327 | 116 | if (f && f->isConstructor()) { |
328 | 0 | if (const Token* initList = f->constructorMemberInitialization()) |
329 | 0 | traverse(tok->previous(), tok->tokAt(initList->index() - tok->index())); |
330 | 0 | } |
331 | 116 | break; |
332 | 116 | } |
333 | 1.19k | if (match7(tok)) |
334 | 0 | break; |
335 | 1.19k | if (match8(tok)) |
336 | 0 | break; |
337 | 1.19k | if (match5(tok)) |
338 | 0 | continue; |
339 | | // Evaluate LHS of assignment before RHS |
340 | 1.19k | if (Token* assignTok = assignExpr(tok)) { |
341 | | // If assignTok has broken ast then stop |
342 | 459 | if (!assignTok->astOperand1() || !assignTok->astOperand2()) |
343 | 0 | break; |
344 | 459 | Token* assignTop = assignTok; |
345 | 459 | bool continueB = true; |
346 | 459 | while (assignTop->isAssignmentOp()) { |
347 | 459 | if (!match9(assignTop->astOperand1())) { |
348 | 459 | continueB &= updateRecursive(assignTop->astOperand1()); |
349 | 459 | } |
350 | 459 | if (!assignTop->astParent()) |
351 | 459 | break; |
352 | 0 | assignTop = assignTop->astParent(); |
353 | 0 | } |
354 | | // Is assignment in dead code |
355 | 459 | if (Token* parent = isDeadCode(assignTok)) { |
356 | 0 | tok = parent; |
357 | 0 | continue; |
358 | 0 | } |
359 | | // Simple assign |
360 | 459 | if (assignTok->str() == MatchCompiler::makeConstString("=") && (assignTok->astParent() == assignTop || assignTok == assignTop)) { |
361 | 459 | Analyzer::Action rhsAction = |
362 | 459 | analyzer->analyze(assignTok->astOperand2(), Analyzer::Direction::Reverse); |
363 | 459 | Analyzer::Action lhsAction = |
364 | 459 | analyzer->analyze(assignTok->astOperand1(), Analyzer::Direction::Reverse); |
365 | | // Assignment from |
366 | 459 | if (rhsAction.isRead() && !lhsAction.isInvalid() && assignTok->astOperand1()->exprId() > 0) { |
367 | 196 | const std::string info = "Assignment from '" + assignTok->expressionString() + "'"; |
368 | 196 | ValuePtr<Analyzer> a = analyzer->reanalyze(assignTok->astOperand1(), info); |
369 | 196 | if (a) { |
370 | 196 | valueFlowGenericForward(nextAfterAstRightmostLeaf(assignTok->astOperand2()), |
371 | 196 | assignTok->astOperand2()->scope()->bodyEnd, |
372 | 196 | a, |
373 | 196 | tokenlist, |
374 | 196 | errorLogger, |
375 | 196 | settings); |
376 | 196 | } |
377 | | // Assignment to |
378 | 263 | } else if (lhsAction.matches() && !assignTok->astOperand2()->hasKnownIntValue() && |
379 | 263 | assignTok->astOperand2()->exprId() > 0 && |
380 | 263 | isConstExpression(assignTok->astOperand2(), settings.library)) { |
381 | 4 | const std::string info = "Assignment to '" + assignTok->expressionString() + "'"; |
382 | 4 | ValuePtr<Analyzer> a = analyzer->reanalyze(assignTok->astOperand2(), info); |
383 | 4 | if (a) { |
384 | 4 | valueFlowGenericForward(nextAfterAstRightmostLeaf(assignTok->astOperand2()), |
385 | 4 | assignTok->astOperand2()->scope()->bodyEnd, |
386 | 4 | a, |
387 | 4 | tokenlist, |
388 | 4 | errorLogger, |
389 | 4 | settings); |
390 | 4 | valueFlowGenericReverse(assignTok->astOperand1()->previous(), end, a, tokenlist, errorLogger, settings); |
391 | 4 | } |
392 | 4 | } |
393 | 459 | } |
394 | 459 | if (!continueB) |
395 | 4 | break; |
396 | 455 | if (!updateRecursive(assignTop->astOperand2())) |
397 | 8 | break; |
398 | 447 | tok = previousBeforeAstLeftmostLeaf(assignTop)->next(); |
399 | 447 | continue; |
400 | 455 | } |
401 | 735 | if (tok->str() == MatchCompiler::makeConstString(")") && !isUnevaluated(tok)) { |
402 | 4 | if (Token* top = getTopFunction(tok->link())) { |
403 | 4 | if (!updateRecursive(top)) |
404 | 0 | break; |
405 | 4 | Token* next = previousBeforeAstLeftmostLeaf(top); |
406 | 4 | if (next && precedes(next, tok)) |
407 | 4 | tok = next->next(); |
408 | 4 | } |
409 | 4 | continue; |
410 | 4 | } |
411 | 731 | if (tok->str() == MatchCompiler::makeConstString("}")) { |
412 | 18 | Token* condTok = getCondTokFromEnd(tok); |
413 | 18 | if (!condTok) |
414 | 0 | break; |
415 | 18 | Analyzer::Action condAction = analyzeRecursive(condTok); |
416 | 18 | const bool inLoop = match10(condTok->astTop()->previous()); |
417 | | // Evaluate condition of for and while loops first |
418 | 18 | if (inLoop) { |
419 | 4 | if (findmatch11(tok->link(), tok) ) |
420 | 0 | break; |
421 | 4 | if (condAction.isModified()) |
422 | 0 | break; |
423 | 4 | valueFlowGenericForward(condTok, analyzer, tokenlist, errorLogger, settings); |
424 | 4 | } |
425 | 18 | Token* thenEnd; |
426 | 18 | const bool hasElse = match2(tok->link()->tokAt(-2)); |
427 | 18 | if (hasElse) { |
428 | 0 | thenEnd = tok->link()->tokAt(-2); |
429 | 18 | } else { |
430 | 18 | thenEnd = tok; |
431 | 18 | } |
432 | | |
433 | 18 | Analyzer::Action thenAction = analyzeRange(thenEnd->link(), thenEnd); |
434 | 18 | Analyzer::Action elseAction = Analyzer::Action::None; |
435 | 18 | if (hasElse) { |
436 | 0 | elseAction = analyzeRange(tok->link(), tok); |
437 | 0 | } |
438 | 18 | if (thenAction.isModified() && inLoop) |
439 | 0 | break; |
440 | 18 | if (thenAction.isModified() && !elseAction.isModified()) |
441 | 0 | analyzer->assume(condTok, hasElse); |
442 | 18 | else if (elseAction.isModified() && !thenAction.isModified()) |
443 | 0 | analyzer->assume(condTok, !hasElse); |
444 | | // Bail if one of the branches are read to avoid FPs due to over constraints |
445 | 18 | else if (thenAction.isIdempotent() || elseAction.isIdempotent() || thenAction.isRead() || |
446 | 18 | elseAction.isRead()) |
447 | 6 | break; |
448 | 12 | if (thenAction.isInvalid() || elseAction.isInvalid()) |
449 | 0 | break; |
450 | | |
451 | 12 | if (!thenAction.isModified() && !elseAction.isModified()) |
452 | 12 | valueFlowGenericForward(condTok, analyzer, tokenlist, errorLogger, settings); |
453 | 0 | else if (condAction.isRead()) |
454 | 0 | break; |
455 | | // If the condition modifies the variable then bail |
456 | 12 | if (condAction.isModified()) |
457 | 0 | break; |
458 | 12 | tok = jumpToStart(tok->link()); |
459 | 12 | continue; |
460 | 12 | } |
461 | 713 | if (tok->str() == MatchCompiler::makeConstString("{")) { |
462 | 40 | if (tok->previous() && |
463 | 40 | (match12(tok->previous()) || |
464 | 40 | (tok->strAt(-1) == MatchCompiler::makeConstString(")") && match10(tok->linkAt(-1)->previous())))) { |
465 | 6 | Analyzer::Action action = analyzeRange(tok, tok->link()); |
466 | 6 | if (action.isModified()) |
467 | 0 | break; |
468 | 6 | } |
469 | 40 | Token* condTok = getCondTokFromEnd(tok->link()); |
470 | 40 | if (condTok) { |
471 | 40 | Analyzer::Result r = valueFlowGenericForward(condTok, analyzer, tokenlist, errorLogger, settings); |
472 | 40 | if (r.action.isModified()) |
473 | 6 | break; |
474 | 40 | } |
475 | 34 | tok = jumpToStart(tok); |
476 | 34 | continue; |
477 | 40 | } |
478 | 673 | if (Token* next = isUnevaluated(tok)) { |
479 | 0 | tok = next; |
480 | 0 | continue; |
481 | 0 | } |
482 | 673 | if (Token* parent = isDeadCode(tok)) { |
483 | 0 | tok = parent; |
484 | 0 | continue; |
485 | 0 | } |
486 | 673 | if (tok->str() == MatchCompiler::makeConstString("case")) { |
487 | 0 | const Scope* scope = tok->scope(); |
488 | 0 | while (scope && scope->type != Scope::eSwitch) |
489 | 0 | scope = scope->nestedIn; |
490 | 0 | if (!scope || scope->type != Scope::eSwitch) |
491 | 0 | break; |
492 | 0 | tok = tok->tokAt(scope->bodyStart->index() - tok->index() - 1); |
493 | 0 | continue; |
494 | 0 | } |
495 | 673 | if (!update(tok)) |
496 | 0 | break; |
497 | 673 | } |
498 | 140 | } |
499 | | |
500 | 1.19k | static Token* assignExpr(Token* tok) { |
501 | 1.19k | if (match13(tok)) |
502 | 22 | tok = tok->link(); |
503 | 1.25k | while (tok->astParent() && (astIsRHS(tok) || !tok->astParent()->isBinaryOp())) { |
504 | 521 | if (tok->astParent()->isAssignmentOp()) |
505 | 459 | return tok->astParent(); |
506 | 62 | tok = tok->astParent(); |
507 | 62 | } |
508 | 735 | return nullptr; |
509 | 1.19k | } |
510 | | |
511 | 1.71k | static Token* isUnevaluated(Token* tok) { |
512 | 1.71k | if (match14(tok) && tok->link()) { |
513 | 4 | Token* start = tok->link(); |
514 | 4 | if (::isUnevaluated(start->previous())) |
515 | 0 | return start->previous(); |
516 | 4 | if (match15(start)) |
517 | 0 | return start; |
518 | 4 | } |
519 | 1.71k | return nullptr; |
520 | 1.71k | } |
521 | | }; |
522 | | } |
523 | | |
524 | | void valueFlowGenericReverse(Token* start, const Token* end, const ValuePtr<Analyzer>& a, const TokenList& tokenlist, ErrorLogger& errorLogger, const Settings& settings) |
525 | 869 | { |
526 | 869 | if (a->invalid()) |
527 | 729 | return; |
528 | 140 | ReverseTraversal rt{a, tokenlist, errorLogger, settings}; |
529 | 140 | rt.traverse(start, end); |
530 | 140 | } |