Coverage Report

Created: 2025-01-24 06:31

/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
}