Coverage Report

Created: 2023-09-25 06:15

/src/cppcheck/lib/tokenize.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Cppcheck - A tool for static C/C++ code analysis
3
 * Copyright (C) 2007-2023 Cppcheck team.
4
 *
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18
19
//---------------------------------------------------------------------------
20
#include "tokenize.h"
21
22
#include "check.h"
23
#include "errorlogger.h"
24
#include "library.h"
25
#include "mathlib.h"
26
#include "platform.h"
27
#include "preprocessor.h"
28
#include "settings.h"
29
#include "standards.h"
30
#include "summaries.h"
31
#include "symboldatabase.h"
32
#include "templatesimplifier.h"
33
#include "timer.h"
34
#include "token.h"
35
#include "utils.h"
36
#include "valueflow.h"
37
#include "vfvalue.h"
38
39
#include <algorithm>
40
#include <cassert>
41
#include <cctype>
42
#include <cstdlib>
43
#include <cstring>
44
#include <ctime>
45
#include <iostream>
46
#include <iterator>
47
#include <exception>
48
#include <memory>
49
#include <set>
50
#include <sstream> // IWYU pragma: keep
51
#include <stack>
52
#include <stdexcept>
53
#include <type_traits>
54
#include <unordered_map>
55
#include <unordered_set>
56
#include <utility>
57
#include <vector>
58
59
#include <simplecpp.h>
60
61
//---------------------------------------------------------------------------
62
63
namespace {
64
    // local struct used in setVarId
65
    // in order to store information about the scope
66
    struct VarIdScopeInfo {
67
1.36k
        VarIdScopeInfo() = default;
68
        VarIdScopeInfo(bool isExecutable, bool isStructInit, bool isEnum, nonneg int startVarid)
69
3.58k
            : isExecutable(isExecutable), isStructInit(isStructInit), isEnum(isEnum), startVarid(startVarid) {}
70
71
        const bool isExecutable{};
72
        const bool isStructInit{};
73
        const bool isEnum{};
74
        const nonneg int startVarid{};
75
    };
76
}
77
78
/** Return whether tok is the "{" that starts an enumerator list */
79
static bool isEnumStart(const Token* tok)
80
458
{
81
458
    if (!tok || tok->str() != "{")
82
0
        return false;
83
458
    return (tok->strAt(-1) == "enum") || (tok->strAt(-2) == "enum") || Token::Match(tok->tokAt(-3), "enum class %name%");
84
458
}
85
86
template<typename T>
87
static void skipEnumBody(T **tok)
88
0
{
89
0
    T *defStart = *tok;
90
0
    while (Token::Match(defStart, "%name%|::|:"))
91
0
        defStart = defStart->next();
92
0
    if (defStart && defStart->str() == "{")
93
0
        *tok = defStart->link()->next();
94
0
}
95
96
const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &endsWith) const
97
12.9k
{
98
12.9k
    return Tokenizer::isFunctionHead(tok, endsWith, isCPP());
99
12.9k
}
100
101
const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &endsWith, bool cpp)
102
16.4k
{
103
16.4k
    if (!tok)
104
0
        return nullptr;
105
16.4k
    if (tok->str() == "(")
106
7.30k
        tok = tok->link();
107
16.4k
    if (Token::Match(tok, ") ;|{|[")) {
108
15.2k
        tok = tok->next();
109
15.2k
        while (tok && tok->str() == "[" && tok->link()) {
110
0
            if (endsWith.find(tok->str()) != std::string::npos)
111
0
                return tok;
112
0
            tok = tok->link()->next();
113
0
        }
114
15.2k
        return (tok && endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr;
115
15.2k
    }
116
1.23k
    if (cpp && tok->str() == ")") {
117
1.23k
        tok = tok->next();
118
1.29k
        while (Token::Match(tok, "const|noexcept|override|final|volatile|mutable|&|&& !!(") ||
119
1.29k
               (Token::Match(tok, "%name% !!(") && tok->isUpperCaseName()))
120
59
            tok = tok->next();
121
1.23k
        if (tok && tok->str() == ")")
122
364
            tok = tok->next();
123
1.23k
        while (tok && tok->str() == "[")
124
0
            tok = tok->link()->next();
125
1.23k
        if (Token::Match(tok, "throw|noexcept ("))
126
0
            tok = tok->linkAt(1)->next();
127
1.23k
        if (Token::Match(tok, "%name% (") && tok->isUpperCaseName())
128
0
            tok = tok->linkAt(1)->next();
129
1.23k
        if (tok && tok->originalName() == "->") { // trailing return type
130
0
            for (tok = tok->next(); tok && !Token::Match(tok, ";|{|override|final"); tok = tok->next())
131
0
                if (tok->link() && Token::Match(tok, "<|[|("))
132
0
                    tok = tok->link();
133
0
        }
134
1.23k
        while (Token::Match(tok, "override|final !!(") ||
135
1.23k
               (Token::Match(tok, "%name% !!(") && tok->isUpperCaseName()))
136
0
            tok = tok->next();
137
1.23k
        if (Token::Match(tok, "= 0|default|delete ;"))
138
0
            tok = tok->tokAt(2);
139
140
1.23k
        return (tok && endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr;
141
1.23k
    }
142
0
    return nullptr;
143
1.23k
}
144
145
/**
146
 * is tok the start brace { of a class, struct, union, or enum
147
 */
148
static bool isClassStructUnionEnumStart(const Token * tok)
149
458
{
150
458
    if (!Token::Match(tok->previous(), "class|struct|union|enum|%name%|>|>> {"))
151
0
        return false;
152
458
    const Token * tok2 = tok->previous();
153
916
    while (tok2 && !Token::Match(tok2, "class|struct|union|enum|{|}|;"))
154
458
        tok2 = tok2->previous();
155
458
    return Token::Match(tok2, "class|struct|union|enum");
156
458
}
157
158
//---------------------------------------------------------------------------
159
160
Tokenizer::Tokenizer(const Settings *settings, ErrorLogger *errorLogger, const Preprocessor *preprocessor) :
161
    list(settings),
162
    mSettings(settings),
163
    mErrorLogger(errorLogger),
164
    mTemplateSimplifier(new TemplateSimplifier(*this)),
165
    mPreprocessor(preprocessor)
166
1.36k
{
167
    // make sure settings are specified
168
1.36k
    assert(mSettings);
169
1.36k
}
170
171
Tokenizer::~Tokenizer()
172
1.36k
{
173
1.36k
    delete mSymbolDatabase;
174
1.36k
    delete mTemplateSimplifier;
175
1.36k
}
176
177
178
//---------------------------------------------------------------------------
179
// SizeOfType - gives the size of a type
180
//---------------------------------------------------------------------------
181
182
nonneg int Tokenizer::sizeOfType(const std::string& type) const
183
0
{
184
0
    const std::map<std::string, int>::const_iterator it = mTypeSize.find(type);
185
0
    if (it == mTypeSize.end()) {
186
0
        const Library::PodType* podtype = mSettings->library.podtype(type);
187
0
        if (!podtype)
188
0
            return 0;
189
190
0
        return podtype->size;
191
0
    }
192
0
    return it->second;
193
0
}
194
195
nonneg int Tokenizer::sizeOfType(const Token *type) const
196
0
{
197
0
    if (!type || type->str().empty())
198
0
        return 0;
199
200
0
    if (type->tokType() == Token::eString)
201
0
        return Token::getStrLength(type) + 1U;
202
203
0
    const std::map<std::string, int>::const_iterator it = mTypeSize.find(type->str());
204
0
    if (it == mTypeSize.end()) {
205
0
        const Library::PodType* podtype = mSettings->library.podtype(type->str());
206
0
        if (!podtype)
207
0
            return 0;
208
209
0
        return podtype->size;
210
0
    }
211
0
    if (type->isLong()) {
212
0
        if (type->str() == "double")
213
0
            return mSettings->platform.sizeof_long_double;
214
0
        if (type->str() == "long")
215
0
            return mSettings->platform.sizeof_long_long;
216
0
    }
217
218
0
    return it->second;
219
0
}
220
//---------------------------------------------------------------------------
221
222
// check if this statement is a duplicate definition
223
bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name, const Token *typeDef) const
224
0
{
225
    // check for an end of definition
226
0
    Token * tok = *tokPtr;
227
0
    if (tok && Token::Match(tok->next(), ";|,|[|=|)|>|(|{")) {
228
0
        Token * end = tok->next();
229
230
0
        if (end->str() == "[") {
231
0
            if (!end->link())
232
0
                syntaxError(end); // invalid code
233
0
            end = end->link()->next();
234
0
        } else if (end->str() == ",") {
235
            // check for derived class
236
0
            if (Token::Match(tok->previous(), "public|private|protected"))
237
0
                return false;
238
239
            // find end of definition
240
0
            while (end && end->next() && !Token::Match(end->next(), ";|)|>")) {
241
0
                if (end->next()->str() == "(")
242
0
                    end = end->linkAt(1);
243
244
0
                end = (end)?end->next():nullptr;
245
0
            }
246
0
            if (end)
247
0
                end = end->next();
248
0
        } else if (end->str() == "(") {
249
0
            if (startsWith(tok->previous()->str(), "operator"))
250
                // conversion operator
251
0
                return false;
252
0
            if (tok->previous()->str() == "typedef")
253
                // typedef of function returning this type
254
0
                return false;
255
0
            if (Token::Match(tok->previous(), "public:|private:|protected:"))
256
0
                return false;
257
0
            if (tok->previous()->str() == ">") {
258
0
                if (!Token::Match(tok->tokAt(-2), "%type%"))
259
0
                    return false;
260
261
0
                if (!Token::Match(tok->tokAt(-3), ",|<"))
262
0
                    return false;
263
264
0
                *tokPtr = end->link();
265
0
                return true;
266
0
            }
267
0
        }
268
269
0
        if (end) {
270
0
            if (Token::simpleMatch(end, ") {")) { // function parameter ?
271
                // look backwards
272
0
                if (Token::Match(tok->previous(), "%type%") &&
273
0
                    !Token::Match(tok->previous(), "return|new|const|struct")) {
274
                    // duplicate definition so skip entire function
275
0
                    *tokPtr = end->next()->link();
276
0
                    return true;
277
0
                }
278
0
            } else if (end->str() == ">") { // template parameter ?
279
                // look backwards
280
0
                if (Token::Match(tok->previous(), "%type%") &&
281
0
                    !Token::Match(tok->previous(), "return|new|const|volatile")) {
282
                    // duplicate definition so skip entire template
283
0
                    while (end && end->str() != "{")
284
0
                        end = end->next();
285
0
                    if (end) {
286
0
                        *tokPtr = end->link();
287
0
                        return true;
288
0
                    }
289
0
                }
290
0
            } else {
291
                // look backwards
292
0
                if (Token::Match(tok->previous(), "typedef|}|>") ||
293
0
                    (end->str() == ";" && tok->previous()->str() == ",") ||
294
0
                    (tok->previous()->str() == "*" && tok->next()->str() != "(") ||
295
0
                    (Token::Match(tok->previous(), "%type%") &&
296
0
                     (!Token::Match(tok->previous(), "return|new|const|friend|public|private|protected|throw|extern") &&
297
0
                      !Token::simpleMatch(tok->tokAt(-2), "friend class")))) {
298
                    // scan backwards for the end of the previous statement
299
0
                    while (tok && tok->previous() && !Token::Match(tok->previous(), ";|{")) {
300
0
                        if (tok->previous()->str() == "}") {
301
0
                            tok = tok->previous()->link();
302
0
                        } else if (tok->previous()->str() == "typedef") {
303
0
                            return true;
304
0
                        } else if (tok->previous()->str() == "enum") {
305
0
                            return true;
306
0
                        } else if (tok->previous()->str() == "struct") {
307
0
                            if (tok->strAt(-2) == "typedef" &&
308
0
                                tok->next()->str() == "{" &&
309
0
                                typeDef->strAt(3) != "{") {
310
                                // declaration after forward declaration
311
0
                                return true;
312
0
                            }
313
0
                            if (tok->next()->str() == "{")
314
0
                                return true;
315
0
                            if (Token::Match(tok->next(), ")|*"))
316
0
                                return true;
317
0
                            if (tok->next()->str() == name->str())
318
0
                                return true;
319
0
                            if (tok->next()->str() != ";")
320
0
                                return true;
321
0
                            return false;
322
0
                        } else if (tok->previous()->str() == "union") {
323
0
                            return tok->next()->str() != ";";
324
0
                        } else if (isCPP() && tok->previous()->str() == "class") {
325
0
                            return tok->next()->str() != ";";
326
0
                        }
327
0
                        if (tok)
328
0
                            tok = tok->previous();
329
0
                    }
330
331
0
                    if ((*tokPtr)->strAt(1) != "(" || !Token::Match((*tokPtr)->linkAt(1), ") .|(|["))
332
0
                        return true;
333
0
                }
334
0
            }
335
0
        }
336
0
    }
337
338
0
    return false;
339
0
}
340
341
void Tokenizer::unsupportedTypedef(const Token *tok) const
342
0
{
343
0
    if (!mSettings->debugwarnings)
344
0
        return;
345
346
0
    std::ostringstream str;
347
0
    const Token *tok1 = tok;
348
0
    int level = 0;
349
0
    while (tok) {
350
0
        if (level == 0 && tok->str() == ";")
351
0
            break;
352
0
        if (tok->str() == "{")
353
0
            ++level;
354
0
        else if (tok->str() == "}") {
355
0
            if (level == 0)
356
0
                break;
357
0
            --level;
358
0
        }
359
360
0
        if (tok != tok1)
361
0
            str << " ";
362
0
        str << tok->str();
363
0
        tok = tok->next();
364
0
    }
365
0
    if (tok)
366
0
        str << " ;";
367
368
0
    reportError(tok1, Severity::debug, "simplifyTypedef",
369
0
                "Failed to parse \'" + str.str() + "\'. The checking continues anyway.");
370
0
}
371
372
Token * Tokenizer::deleteInvalidTypedef(Token *typeDef)
373
0
{
374
0
    Token *tok = nullptr;
375
376
    // remove typedef but leave ;
377
0
    while (typeDef->next()) {
378
0
        if (typeDef->next()->str() == ";") {
379
0
            typeDef->deleteNext();
380
0
            break;
381
0
        }
382
0
        if (typeDef->next()->str() == "{")
383
0
            Token::eraseTokens(typeDef, typeDef->linkAt(1));
384
0
        else if (typeDef->next()->str() == "}")
385
0
            break;
386
0
        typeDef->deleteNext();
387
0
    }
388
389
0
    if (typeDef != list.front()) {
390
0
        tok = typeDef->previous();
391
0
        tok->deleteNext();
392
0
    } else {
393
0
        list.front()->deleteThis();
394
0
        tok = list.front();
395
0
    }
396
397
0
    return tok;
398
0
}
399
400
namespace {
401
    struct Space {
402
        std::string className;
403
        const Token* bodyEnd{};  // for body contains typedef define
404
        const Token* bodyEnd2{}; // for body contains typedef using
405
        bool isNamespace{};
406
        std::set<std::string> recordTypes;
407
    };
408
}
409
410
static Token *splitDefinitionFromTypedef(Token *tok, nonneg int *unnamedCount)
411
0
{
412
0
    std::string name;
413
0
    bool isConst = false;
414
0
    Token *tok1 = tok->next();
415
416
    // skip const if present
417
0
    if (tok1->str() == "const") {
418
0
        tok1->deleteThis();
419
0
        isConst = true;
420
0
    }
421
422
    // skip "class|struct|union|enum"
423
0
    tok1 = tok1->next();
424
425
0
    const bool hasName = Token::Match(tok1, "%name%");
426
427
    // skip name
428
0
    if (hasName) {
429
0
        name = tok1->str();
430
0
        tok1 = tok1->next();
431
0
    }
432
433
    // skip base classes if present
434
0
    if (tok1->str() == ":") {
435
0
        tok1 = tok1->next();
436
0
        while (tok1 && tok1->str() != "{")
437
0
            tok1 = tok1->next();
438
0
        if (!tok1)
439
0
            return nullptr;
440
0
    }
441
442
    // skip to end
443
0
    tok1 = tok1->link();
444
445
0
    if (!hasName) { // unnamed
446
0
        if (tok1->next()) {
447
            // use typedef name if available
448
0
            if (Token::Match(tok1->next(), "%type%"))
449
0
                name = tok1->next()->str();
450
0
            else // create a unique name
451
0
                name = "Unnamed" + std::to_string((*unnamedCount)++);
452
0
            tok->next()->insertToken(name);
453
0
        } else
454
0
            return nullptr;
455
0
    }
456
457
0
    tok1->insertToken(";");
458
0
    tok1 = tok1->next();
459
460
0
    if (tok1->next() && tok1->next()->str() == ";" && tok1->previous()->str() == "}") {
461
0
        tok->deleteThis();
462
0
        tok1->deleteThis();
463
0
        return nullptr;
464
0
    }
465
0
    tok1->insertToken("typedef");
466
0
    tok1 = tok1->next();
467
0
    Token * tok3 = tok1;
468
0
    if (isConst) {
469
0
        tok1->insertToken("const");
470
0
        tok1 = tok1->next();
471
0
    }
472
0
    tok1->insertToken(tok->next()->str()); // struct, union or enum
473
0
    tok1 = tok1->next();
474
0
    tok1->insertToken(name);
475
0
    tok->deleteThis();
476
0
    tok = tok3;
477
478
0
    return tok;
479
0
}
480
481
/* This function is called when processing function related typedefs.
482
 * If simplifyTypedef generates an "Internal Error" message and the
483
 * code that generated it deals in some way with functions, then this
484
 * function will probably need to be extended to handle a new function
485
 * related pattern */
486
const Token *Tokenizer::processFunc(const Token *tok2, bool inOperator) const
487
0
{
488
0
    if (tok2->next() && tok2->next()->str() != ")" &&
489
0
        tok2->next()->str() != ",") {
490
        // skip over tokens for some types of canonicalization
491
0
        if (Token::Match(tok2->next(), "( * %type% ) ("))
492
0
            tok2 = tok2->linkAt(5);
493
0
        else if (Token::Match(tok2->next(), "* ( * %type% ) ("))
494
0
            tok2 = tok2->linkAt(6);
495
0
        else if (Token::Match(tok2->next(), "* ( * %type% ) ;"))
496
0
            tok2 = tok2->tokAt(5);
497
0
        else if (Token::Match(tok2->next(), "* ( %type% [") &&
498
0
                 Token::Match(tok2->linkAt(4), "] ) ;|="))
499
0
            tok2 = tok2->linkAt(4)->next();
500
0
        else if (Token::Match(tok2->next(), "* ( * %type% ("))
501
0
            tok2 = tok2->linkAt(5)->next();
502
0
        else if (Token::simpleMatch(tok2->next(), "* [") &&
503
0
                 Token::simpleMatch(tok2->linkAt(2), "] ;"))
504
0
            tok2 = tok2->next();
505
0
        else {
506
0
            if (tok2->next()->str() == "(")
507
0
                tok2 = tok2->next()->link();
508
0
            else if (!inOperator && !Token::Match(tok2->next(), "[|>|;")) {
509
0
                tok2 = tok2->next();
510
511
0
                while (Token::Match(tok2, "*|&") &&
512
0
                       !Token::Match(tok2->next(), ")|>"))
513
0
                    tok2 = tok2->next();
514
515
                // skip over namespace
516
0
                while (Token::Match(tok2, "%name% ::"))
517
0
                    tok2 = tok2->tokAt(2);
518
519
0
                if (!tok2)
520
0
                    return nullptr;
521
522
0
                if (tok2->str() == "(" &&
523
0
                    tok2->link()->next() &&
524
0
                    tok2->link()->next()->str() == "(") {
525
0
                    tok2 = tok2->link();
526
527
0
                    if (tok2->next()->str() == "(")
528
0
                        tok2 = tok2->next()->link();
529
0
                }
530
531
                // skip over typedef parameter
532
0
                if (tok2->next() && tok2->next()->str() == "(") {
533
0
                    tok2 = tok2->next()->link();
534
0
                    if (!tok2->next())
535
0
                        syntaxError(tok2);
536
537
0
                    if (tok2->next()->str() == "(")
538
0
                        tok2 = tok2->next()->link();
539
0
                }
540
0
            }
541
0
        }
542
0
    }
543
0
    return tok2;
544
0
}
545
546
Token *Tokenizer::processFunc(Token *tok2, bool inOperator)
547
0
{
548
0
    return const_cast<Token*>(processFunc(const_cast<const Token*>(tok2), inOperator));
549
0
}
550
551
void Tokenizer::simplifyUsingToTypedef()
552
1.36k
{
553
1.36k
    if (!isCPP() || mSettings->standards.cpp < Standards::CPP11)
554
0
        return;
555
556
94.1k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
557
        // using a::b;  =>   typedef  a::b  b;
558
92.7k
        if ((Token::Match(tok, "[;{}] using %name% :: %name% ::|;") && !tok->tokAt(2)->isKeyword()) ||
559
92.7k
            (Token::Match(tok, "[;{}] using :: %name% :: %name% ::|;") && !tok->tokAt(3)->isKeyword())) {
560
0
            Token *endtok = tok->tokAt(5);
561
0
            if (Token::Match(endtok, "%name%"))
562
0
                endtok = endtok->next();
563
0
            while (Token::Match(endtok, ":: %name%"))
564
0
                endtok = endtok->tokAt(2);
565
0
            if (endtok && endtok->str() == ";") {
566
0
                tok->next()->str("typedef");
567
0
                endtok = endtok->previous();
568
0
                endtok->insertToken(endtok->str());
569
0
            }
570
0
        }
571
92.7k
    }
572
1.36k
}
573
574
void Tokenizer::simplifyTypedefLHS()
575
1.36k
{
576
1.36k
    if (!list.front())
577
0
        return;
578
579
92.7k
    for (Token* tok = list.front()->next(); tok; tok = tok->next()) {
580
91.3k
        if (tok->str() == "typedef") {
581
0
            bool doSimplify = !Token::Match(tok->previous(), ";|{|}|:|public:|private:|protected:");
582
0
            if (doSimplify && Token::simpleMatch(tok->previous(), ")") && Token::Match(tok->linkAt(-1)->previous(), "if|for|while"))
583
0
                doSimplify = false;
584
0
            bool haveStart = false;
585
0
            Token* start{};
586
0
            if (!doSimplify && Token::simpleMatch(tok->previous(), "}")) {
587
0
                start = tok->linkAt(-1)->previous();
588
0
                while (Token::Match(start, "%name%")) {
589
0
                    if (Token::Match(start, "class|struct|union|enum")) {
590
0
                        start = start->previous();
591
0
                        doSimplify = true;
592
0
                        haveStart = true;
593
0
                        break;
594
0
                    }
595
0
                    start = start->previous();
596
0
                }
597
0
            }
598
0
            if (doSimplify) {
599
0
                if (!haveStart) {
600
0
                    start = tok;
601
0
                    while (start && !Token::Match(start, "[;{}]"))
602
0
                        start = start->previous();
603
0
                }
604
0
                if (start)
605
0
                    start = start->next();
606
0
                else
607
0
                    start = list.front();
608
0
                start->insertTokenBefore(tok->str());
609
0
                tok->deleteThis();
610
0
            }
611
0
        }
612
91.3k
    }
613
1.36k
}
614
615
namespace {
616
    class TypedefSimplifier {
617
    private:
618
        Token* mTypedefToken;  // The "typedef" token
619
        Token* mEndToken{nullptr};  // Semicolon
620
        std::pair<Token*, Token*> mRangeType;
621
        std::pair<Token*, Token*> mRangeTypeQualifiers;
622
        std::pair<Token*, Token*> mRangeAfterVar;
623
        std::string mTypedefName;  // Name of typedef type
624
        Token* mNameToken{nullptr};
625
        bool mFail = false;
626
        bool mReplaceFailed = false;
627
        bool mUsed = false;
628
629
    public:
630
0
        TypedefSimplifier(Token* typedefToken, int &num) : mTypedefToken(typedefToken) {
631
0
            Token* start = typedefToken->next();
632
0
            if (Token::simpleMatch(start, "typename"))
633
0
                start = start->next();
634
635
            // TODO handle unnamed structs etc
636
0
            if (Token::Match(start, "const| enum|struct|union|class %name% {")) {
637
0
                const std::pair<Token*, Token*> rangeBefore(start, Token::findsimplematch(start, "{"));
638
639
                // find typedef name token
640
0
                Token* nameToken = rangeBefore.second->link()->next();
641
0
                while (Token::Match(nameToken, "%name%|* %name%|*"))
642
0
                    nameToken = nameToken->next();
643
0
                const std::pair<Token*, Token*> rangeQualifiers(rangeBefore.second->link()->next(), nameToken);
644
645
0
                if (Token::Match(nameToken, "%name% ;")) {
646
0
                    mRangeType = rangeBefore;
647
0
                    mRangeTypeQualifiers = rangeQualifiers;
648
0
                    mTypedefName = nameToken->str();
649
0
                    Token* typeName = rangeBefore.second->previous();
650
0
                    if (typeName->isKeyword()) {
651
0
                        (void)num;
652
                        // TODO typeName->insertToken("T:" + std::to_string(num++));
653
0
                        typeName->insertToken(nameToken->str());
654
0
                    }
655
0
                    mNameToken = nameToken;
656
0
                    mEndToken = nameToken->next();
657
0
                    return;
658
0
                }
659
0
            }
660
661
0
            for (Token* type = start; Token::Match(type, "%name%|*|&"); type = type->next()) {
662
0
                if (type != start && Token::Match(type, "%name% ;") && !type->isStandardType()) {
663
0
                    mRangeType.first = start;
664
0
                    mRangeType.second = type;
665
0
                    mNameToken = type;
666
0
                    mEndToken = mNameToken->next();
667
0
                    return;
668
0
                }
669
0
                if (type != start && Token::Match(type, "%name% [")) {
670
0
                    Token* end = type->linkAt(1);
671
0
                    while (Token::simpleMatch(end, "] ["))
672
0
                        end = end->linkAt(1);
673
0
                    if (!Token::simpleMatch(end, "] ;"))
674
0
                        break;
675
0
                    mRangeType.first = start;
676
0
                    mRangeType.second = type;
677
0
                    mNameToken = type;
678
0
                    mEndToken = end->next();
679
0
                    mRangeAfterVar.first = mNameToken->next();
680
0
                    mRangeAfterVar.second = mEndToken;
681
0
                    return;
682
0
                }
683
0
                if (Token::Match(type->next(), "( * const| %name% ) (") && Token::simpleMatch(type->linkAt(1)->linkAt(1), ") ;")) {
684
0
                    mNameToken = type->linkAt(1)->previous();
685
0
                    mEndToken = type->linkAt(1)->linkAt(1)->next();
686
0
                    mRangeType.first = start;
687
0
                    mRangeType.second = mNameToken;
688
0
                    mRangeAfterVar.first = mNameToken->next();
689
0
                    mRangeAfterVar.second = mEndToken;
690
0
                    return;
691
0
                }
692
0
                if (Token::Match(type, "%name% ( !!(") && Token::simpleMatch(type->linkAt(1), ") ;") && !type->isStandardType()) {
693
0
                    mNameToken = type;
694
0
                    mEndToken = type->linkAt(1)->next();
695
0
                    mRangeType.first = start;
696
0
                    mRangeType.second = type;
697
0
                    mRangeAfterVar.first = mNameToken->next();
698
0
                    mRangeAfterVar.second = mEndToken;
699
0
                    return;
700
0
                }
701
0
            }
702
            // TODO: handle all typedefs
703
0
            if ((false))
704
0
                printTypedef(typedefToken);
705
0
            mFail = true;
706
0
        }
707
708
0
        const Token* getTypedefToken() const {
709
0
            return mTypedefToken;
710
0
        }
711
712
0
        bool isUsed() const {
713
0
            return mUsed;
714
0
        }
715
716
0
        bool isInvalidConstFunctionType(const std::map<std::string, TypedefSimplifier>& m) const {
717
0
            if (!Token::Match(mTypedefToken, "typedef const %name% %name% ;"))
718
0
                return false;
719
0
            const auto it = m.find(mTypedefToken->strAt(2));
720
0
            if (it == m.end())
721
0
                return false;
722
0
            return Token::Match(it->second.mNameToken, "%name% (");
723
0
        }
724
725
0
        bool fail() const {
726
0
            return mFail;
727
0
        }
728
729
0
        bool replaceFailed() const {
730
0
            return mReplaceFailed;
731
0
        }
732
733
0
        bool isStructEtc() const {
734
0
            return mRangeType.second && mRangeType.second->str() == "{";
735
0
        }
736
737
0
        std::string name() const {
738
0
            return mNameToken ? mNameToken->str() : "";
739
0
        }
740
741
0
        void replace(Token* tok) {
742
0
            if (tok == mNameToken)
743
0
                return;
744
745
0
            mUsed = true;
746
747
            // Special handling for T() when T is a pointer
748
0
            if (Token::Match(tok, "%name% ( )")) {
749
0
                bool pointerType = false;
750
0
                for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
751
0
                    if (type->str() == "*" || type->str() == "&") {
752
0
                        pointerType = true;
753
0
                        break;
754
0
                    }
755
0
                }
756
0
                for (const Token* type = mRangeTypeQualifiers.first; type != mRangeTypeQualifiers.second; type = type->next()) {
757
0
                    if (type->str() == "*" || type->str() == "&") {
758
0
                        pointerType = true;
759
0
                        break;
760
0
                    }
761
0
                }
762
0
                if (pointerType) {
763
0
                    tok->deleteThis();
764
0
                    tok->next()->insertToken("0");
765
0
                    Token* tok2 = insertTokens(tok, mRangeType);
766
0
                    insertTokens(tok2, mRangeTypeQualifiers);
767
0
                    return;
768
0
                }
769
0
            }
770
771
            // Special handling of function pointer cast
772
0
            const bool isFunctionPointer = Token::Match(mNameToken, "%name% )");
773
0
            if (isFunctionPointer && isCast(tok->previous())) {
774
0
                tok->insertToken("*");
775
0
                insertTokens(tok, std::pair<Token*, Token*>(mRangeType.first, mNameToken->linkAt(1)));
776
0
                tok->deleteThis();
777
0
                return;
778
0
            }
779
780
            // Inherited type => skip "struct" / "class"
781
0
            if (Token::Match(mRangeType.first, "const| struct|class %name% {") && Token::Match(tok->previous(), "public|protected|private")) {
782
0
                tok->originalName(tok->str());
783
0
                tok->str(mRangeType.second->previous()->str());
784
0
                return;
785
0
            }
786
787
0
            if (Token::Match(tok, "%name% ::")) {
788
0
                if (Token::Match(mRangeType.first, "const| struct|class %name% %name% ;")) {
789
0
                    tok->originalName(tok->str());
790
0
                    tok->str(mRangeType.second->previous()->str());
791
0
                } else {
792
0
                    mReplaceFailed = true;
793
0
                }
794
0
                return;
795
0
            }
796
797
            // pointer => move "const"
798
0
            if (Token::simpleMatch(tok->previous(), "const")) {
799
0
                bool pointerType = false;
800
0
                for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
801
0
                    if (type->str() == "*") {
802
0
                        pointerType = true;
803
0
                        break;
804
0
                    }
805
0
                }
806
0
                if (pointerType) {
807
0
                    tok->insertToken("const");
808
0
                    tok->next()->column(tok->column());
809
0
                    tok->next()->isExpandedMacro(tok->previous()->isExpandedMacro());
810
0
                    tok->deletePrevious();
811
0
                }
812
0
            }
813
814
            // Do not duplicate class/struct/enum/union
815
0
            if (Token::Match(tok->previous(), "enum|union|struct|class")) {
816
0
                bool found = false;
817
0
                const std::string &kw = tok->previous()->str();
818
0
                for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
819
0
                    if (type->str() == kw) {
820
0
                        found = true;
821
0
                        break;
822
0
                    }
823
0
                }
824
0
                if (found)
825
0
                    tok->deletePrevious();
826
0
                else {
827
0
                    mReplaceFailed = true;
828
0
                    return;
829
0
                }
830
0
            }
831
832
0
            Token* const tok2 = insertTokens(tok, mRangeType);
833
0
            Token* const tok3 = insertTokens(tok2, mRangeTypeQualifiers);
834
835
0
            Token *after = tok3;
836
0
            while (Token::Match(after, "%name%|*|&|&&|::"))
837
0
                after = after->next();
838
0
            if (Token::Match(mNameToken, "%name% (") && Token::simpleMatch(tok3->next(), "*")) {
839
0
                while (Token::Match(after, "(|["))
840
0
                    after = after->link()->next();
841
0
                if (after) {
842
0
                    tok3->insertToken("(");
843
0
                    after->previous()->insertToken(")");
844
0
                    Token::createMutualLinks(tok3->next(), after->previous());
845
0
                }
846
0
            }
847
848
0
            bool useAfterVarRange = true;
849
0
            if (Token::simpleMatch(mRangeAfterVar.first, "[")) {
850
0
                if (Token::Match(after->previous(), "%name% ( !!*")) {
851
0
                    useAfterVarRange = false;
852
                    // Function return type => replace array with "*"
853
0
                    for (const Token* a = mRangeAfterVar.first; Token::simpleMatch(a, "["); a = a->link()->next())
854
0
                        tok3->insertToken("*");
855
0
                } else if (Token::Match(after->previous(), "%name% ( * %name% ) [")) {
856
0
                    after = after->linkAt(4)->next();
857
0
                } else {
858
0
                    Token* prev = after->previous();
859
0
                    if (prev->isName() && prev != tok3)
860
0
                        prev = prev->previous();
861
0
                    if (Token::Match(prev, "*|&|&&") && prev != tok3) {
862
0
                        while (Token::Match(prev, "*|&|&&") && prev != tok3)
863
0
                            prev = prev->previous();
864
0
                        prev->insertToken("(");
865
0
                        after->previous()->insertToken(")");
866
0
                    }
867
0
                }
868
0
            }
869
870
0
            if (isFunctionPointer) {
871
0
                if (Token::Match(after, "( * %name% ) ("))
872
0
                    after = after->link()->linkAt(1)->next();
873
0
                else if (after->str() == "(") {
874
0
                    useAfterVarRange = false;
875
0
                    if (Token::simpleMatch(tok3->previous(), "( *"))
876
0
                        tok3->deletePrevious();
877
0
                }
878
0
                else if (after->str() == "[") {
879
0
                    while (after && after->str() == "[")
880
0
                        after = after->link()->next();
881
0
                }
882
0
            }
883
0
            else {
884
0
                while (Token::simpleMatch(after, "["))
885
0
                    after = after->link()->next();
886
0
            }
887
888
0
            if (!after)
889
0
                throw InternalError(tok, "Failed to simplify typedef. Is the code valid?");
890
891
0
            const Token* const tok4 = useAfterVarRange ? insertTokens(after->previous(), mRangeAfterVar)->next() : tok3->next();
892
893
0
            tok->deleteThis();
894
895
            // Set links
896
0
            std::stack<Token*> brackets;
897
0
            for (; tok != tok4; tok = tok->next()) {
898
0
                if (Token::Match(tok, "[{([]"))
899
0
                    brackets.push(tok);
900
0
                else if (Token::Match(tok, "[})]]")) {
901
0
                    Token::createMutualLinks(brackets.top(), tok);
902
0
                    brackets.pop();
903
0
                }
904
0
            }
905
0
        }
906
907
0
        void removeDeclaration() {
908
0
            if (Token::simpleMatch(mRangeType.second, "{")) {
909
0
                while (Token::Match(mTypedefToken, "typedef|const"))
910
0
                    mTypedefToken->deleteThis();
911
0
                Token::eraseTokens(mRangeType.second->link(), mEndToken);
912
0
            } else {
913
0
                Token::eraseTokens(mTypedefToken, mEndToken);
914
0
                mTypedefToken->deleteThis();
915
0
            }
916
0
        }
917
918
0
        bool canReplace(const Token* tok) {
919
0
            if (mNameToken == tok)
920
0
                return false;
921
0
            if (!Token::Match(tok->previous(), "%name%|;|{|}|(|,|<") && !Token::Match(tok->previous(), "!!. %name% ("))
922
0
                return false;
923
0
            if (!Token::Match(tok, "%name% %name%|*|&|&&|;|(|)|,|::")) {
924
0
                if (Token::Match(tok->previous(), "( %name% =") && Token::Match(tok->linkAt(-1), ") %name%|{") && !tok->tokAt(-2)->isKeyword())
925
0
                    return true;
926
0
                if (Token::Match(tok->previous(), ", %name% ="))
927
0
                    return true;
928
0
                if (Token::Match(tok->previous(), "new %name% ["))
929
0
                    return true;
930
0
                if (Token::Match(tok->previous(), "< %name% >"))
931
0
                    return true;
932
0
                if (Token::Match(tok->previous(), "public|protected|private"))
933
0
                    return true;
934
0
                if (Token::Match(tok->previous(), ", %name% :")) {
935
0
                    bool isGeneric = false;
936
0
                    for (; tok; tok = tok->previous()) {
937
0
                        if (Token::Match(tok, ")|]"))
938
0
                            tok = tok->link();
939
0
                        else if (Token::Match(tok, "[;{}(]")) {
940
0
                            isGeneric = Token::simpleMatch(tok->previous(), "_Generic (");
941
0
                            break;
942
0
                        }
943
0
                    }
944
0
                    return isGeneric;
945
0
                }
946
0
                return false;
947
0
            }
948
0
            if (Token::Match(tok->previous(), "%name%") && !tok->previous()->isKeyword())
949
0
                return false;
950
0
            if (Token::simpleMatch(tok->next(), "(") && Token::Match(tok->linkAt(1), ") %name%|{"))
951
0
                return false;
952
0
            if (Token::Match(tok->previous(), "struct|union|class|enum %name% %name%") &&
953
0
                Token::simpleMatch(mRangeType.second, "{") &&
954
0
                tok->str() != mRangeType.second->previous()->str())
955
0
                return true;
956
0
            if (Token::Match(tok->previous(), "; %name% ;"))
957
0
                return false;
958
0
            if (Token::Match(tok->previous(), "<|, %name% * ,|>"))
959
0
                return true;
960
0
            for (const Token* after = tok->next(); after; after = after->next()) {
961
0
                if (Token::Match(after, "%name%|::|&|*|&&"))
962
0
                    continue;
963
0
                if (after->str() == "<" && after->link())
964
0
                    break;
965
0
                if (after->isNumber())
966
0
                    return false;
967
0
                if (after->isComparisonOp() || after->isArithmeticalOp())
968
0
                    return false;
969
0
                break;
970
0
            }
971
0
            for (const Token* before = tok->previous(); before; before = before->previous()) {
972
0
                if (Token::Match(before, "[+-*/&|~!]"))
973
0
                    return false;
974
0
                if (Token::Match(before, "struct|union|class|enum") || before->isStandardType())
975
0
                    return false;
976
0
                if (before->str() == "::")
977
0
                    return false;
978
0
                if (before->isName())
979
0
                    continue;
980
0
                break;
981
0
            }
982
0
            return true;
983
0
        }
984
985
0
        Token* endToken() const {
986
0
            return mEndToken;
987
0
        }
988
989
    private:
990
0
        static bool isCast(const Token* tok) {
991
0
            if (Token::Match(tok, "( %name% ) (|%name%"))
992
0
                return !tok->tokAt(2)->isKeyword();
993
0
            if (Token::Match(tok, "< %name% > (") && tok->previous() && endsWith(tok->previous()->str(), "_cast", 5))
994
0
                return true;
995
0
            return false;
996
0
        }
997
998
0
        static Token* insertTokens(Token* to, std::pair<Token*,Token*> range) {
999
0
            for (const Token* from = range.first; from != range.second; from = from->next()) {
1000
0
                to->insertToken(from->str());
1001
0
                to->next()->column(to->column());
1002
0
                to = to->next();
1003
0
                to->isSimplifiedTypedef(true);
1004
0
                to->isExternC(from->isExternC());
1005
0
            }
1006
0
            return to;
1007
0
        }
1008
1009
0
        static void printTypedef(const Token *tok) {
1010
0
            int indent = 0;
1011
0
            while (tok && (indent > 0 || tok->str() != ";")) {
1012
0
                if (tok->str() == "{")
1013
0
                    ++indent;
1014
0
                else if (tok->str() == "}")
1015
0
                    --indent;
1016
0
                std::cout << " " << tok->str();
1017
0
                tok = tok->next();
1018
0
            }
1019
0
            std::cout << "\n";
1020
0
        }
1021
    };
1022
}
1023
1024
void Tokenizer::simplifyTypedef()
1025
1.36k
{
1026
    // Simplify global typedefs that are not redefined with the fast 1-pass simplification.
1027
    // Then use the slower old typedef simplification.
1028
1.36k
    std::map<std::string, int> numberOfTypedefs;
1029
94.1k
    for (Token* tok = list.front(); tok; tok = tok->next()) {
1030
92.7k
        if (tok->str() == "typedef") {
1031
0
            int dummy = 0;
1032
0
            TypedefSimplifier ts(tok, dummy);
1033
0
            if (!ts.fail())
1034
0
                numberOfTypedefs[ts.name()]++;
1035
0
            continue;
1036
0
        }
1037
92.7k
    }
1038
1039
1.36k
    int indentlevel = 0;
1040
1.36k
    int typeNum = 1;
1041
1.36k
    std::map<std::string, TypedefSimplifier> typedefs;
1042
94.1k
    for (Token* tok = list.front(); tok; tok = tok->next()) {
1043
92.7k
        if (!tok->isName()) {
1044
56.9k
            if (tok->str()[0] == '{')
1045
3.58k
                ++indentlevel;
1046
53.3k
            else if (tok->str()[0] == '}')
1047
3.58k
                --indentlevel;
1048
56.9k
            continue;
1049
56.9k
        }
1050
1051
35.7k
        if (indentlevel == 0 && tok->str() == "typedef") {
1052
0
            TypedefSimplifier ts(tok, typeNum);
1053
0
            if (!ts.fail() && numberOfTypedefs[ts.name()] == 1) {
1054
0
                if (mSettings->severity.isEnabled(Severity::portability) && ts.isInvalidConstFunctionType(typedefs))
1055
0
                    reportError(tok->next(), Severity::portability, "invalidConstFunctionType",
1056
0
                                "It is unspecified behavior to const qualify a function type.");
1057
0
                typedefs.emplace(ts.name(), ts);
1058
0
                if (!ts.isStructEtc())
1059
0
                    tok = ts.endToken();
1060
0
            }
1061
0
            continue;
1062
0
        }
1063
1064
35.7k
        auto it = typedefs.find(tok->str());
1065
35.7k
        if (it != typedefs.end() && it->second.canReplace(tok)) {
1066
0
            std::set<std::string> r;
1067
0
            while (it != typedefs.end() && r.insert(tok->str()).second) {
1068
0
                it->second.replace(tok);
1069
0
                it = typedefs.find(tok->str());
1070
0
            }
1071
35.7k
        } else if (tok->str() == "enum") {
1072
0
            while (Token::Match(tok, "%name%|:|::"))
1073
0
                tok = tok->next();
1074
0
            if (!tok)
1075
0
                break;
1076
0
            if (tok->str() == "{")
1077
0
                tok = tok->link();
1078
0
        }
1079
35.7k
    }
1080
1081
1.36k
    if (!typedefs.empty())
1082
0
    {
1083
        // remove typedefs
1084
0
        for (auto &t: typedefs) {
1085
0
            if (!t.second.replaceFailed()) {
1086
0
                const Token* const typedefToken = t.second.getTypedefToken();
1087
0
                TypedefInfo typedefInfo;
1088
0
                typedefInfo.name = t.second.name();
1089
0
                typedefInfo.filename = list.file(typedefToken);
1090
0
                typedefInfo.lineNumber = typedefToken->linenr();
1091
0
                typedefInfo.column = typedefToken->column();
1092
0
                typedefInfo.used = t.second.isUsed();
1093
0
                mTypedefInfo.push_back(std::move(typedefInfo));
1094
1095
0
                t.second.removeDeclaration();
1096
0
            }
1097
0
        }
1098
1099
0
        while (Token::Match(list.front(), "; %any%"))
1100
0
            list.front()->deleteThis();
1101
0
    }
1102
1103
1.36k
    simplifyTypedefCpp();
1104
1.36k
}
1105
1106
void Tokenizer::simplifyTypedefCpp()
1107
1.36k
{
1108
1.36k
    std::vector<Space> spaceInfo;
1109
1.36k
    bool isNamespace = false;
1110
1.36k
    std::string className;
1111
1.36k
    std::string fullClassName;
1112
1.36k
    bool hasClass = false;
1113
1.36k
    bool goback = false;
1114
1115
    // add global namespace
1116
1.36k
    spaceInfo.emplace_back(/*Space{}*/);
1117
1118
    // Convert "using a::b;" to corresponding typedef statements
1119
1.36k
    simplifyUsingToTypedef();
1120
1121
1.36k
    const std::time_t maxTime = mSettings->typedefMaxTime > 0 ? std::time(nullptr) + mSettings->typedefMaxTime: 0;
1122
1123
94.1k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
1124
92.7k
        if (mErrorLogger && !list.getFiles().empty())
1125
92.7k
            mErrorLogger->reportProgress(list.getFiles()[0], "Tokenize (typedef)", tok->progressValue());
1126
1127
92.7k
        if (Settings::terminated())
1128
0
            return;
1129
1130
92.7k
        if (maxTime > 0 && std::time(nullptr) > maxTime) {
1131
0
            if (mSettings->debugwarnings) {
1132
0
                ErrorMessage::FileLocation loc;
1133
0
                loc.setfile(list.getFiles()[0]);
1134
0
                ErrorMessage errmsg({std::move(loc)},
1135
0
                                    emptyString,
1136
0
                                    Severity::debug,
1137
0
                                    "Typedef simplification instantiation maximum time exceeded",
1138
0
                                    "typedefMaxTime",
1139
0
                                    Certainty::normal);
1140
0
                mErrorLogger->reportErr(errmsg);
1141
0
            }
1142
0
            return;
1143
0
        }
1144
1145
92.7k
        if (goback) {
1146
            //jump back once, see the comment at the end of the function
1147
0
            goback = false;
1148
0
            tok = tok->previous();
1149
0
        }
1150
1151
92.7k
        if (tok->str() != "typedef") {
1152
92.7k
            if (Token::simpleMatch(tok, "( typedef")) {
1153
                // Skip typedefs inside parentheses (#2453 and #4002)
1154
0
                tok = tok->next();
1155
92.7k
            } else if (Token::Match(tok, "class|struct|namespace %any%") &&
1156
92.7k
                       (!tok->previous() || tok->previous()->str() != "enum")) {
1157
0
                isNamespace = (tok->str() == "namespace");
1158
0
                hasClass = true;
1159
0
                className = tok->next()->str();
1160
0
                const Token *tok1 = tok->next();
1161
0
                fullClassName = className;
1162
0
                while (Token::Match(tok1, "%name% :: %name%")) {
1163
0
                    tok1 = tok1->tokAt(2);
1164
0
                    fullClassName += " :: " + tok1->str();
1165
0
                }
1166
92.7k
            } else if (hasClass && tok->str() == ";") {
1167
0
                hasClass = false;
1168
92.7k
            } else if (hasClass && tok->str() == "{") {
1169
0
                if (!isNamespace)
1170
0
                    spaceInfo.back().recordTypes.insert(fullClassName);
1171
1172
0
                Space info;
1173
0
                info.isNamespace = isNamespace;
1174
0
                info.className = className;
1175
0
                info.bodyEnd = tok->link();
1176
0
                info.bodyEnd2 = tok->link();
1177
0
                spaceInfo.push_back(std::move(info));
1178
1179
0
                hasClass = false;
1180
92.7k
            } else if (spaceInfo.size() > 1 && tok->str() == "}" && spaceInfo.back().bodyEnd == tok) {
1181
0
                spaceInfo.pop_back();
1182
0
            }
1183
92.7k
            continue;
1184
92.7k
        }
1185
1186
        // pull struct, union, enum or class definition out of typedef
1187
        // use typedef name for unnamed struct, union, enum or class
1188
0
        if (Token::Match(tok->next(), "const| struct|enum|union|class %type%| {|:")) {
1189
0
            Token *tok1 = splitDefinitionFromTypedef(tok, &mUnnamedCount);
1190
0
            if (!tok1)
1191
0
                continue;
1192
0
            tok = tok1;
1193
0
        }
1194
1195
        /** @todo add support for union */
1196
0
        if (Token::Match(tok->next(), "enum %type% %type% ;") && tok->strAt(2) == tok->strAt(3)) {
1197
0
            tok->deleteNext(3);
1198
0
            tok->deleteThis();
1199
0
            if (tok->next())
1200
0
                tok->deleteThis();
1201
            //now the next token to process is 'tok', not 'tok->next()';
1202
0
            goback = true;
1203
0
            continue;
1204
0
        }
1205
1206
0
        Token *typeName;
1207
0
        Token *typeStart = nullptr;
1208
0
        Token *typeEnd = nullptr;
1209
0
        Token *argStart = nullptr;
1210
0
        Token *argEnd = nullptr;
1211
0
        Token *arrayStart = nullptr;
1212
0
        Token *arrayEnd = nullptr;
1213
0
        Token *specStart = nullptr;
1214
0
        Token *specEnd = nullptr;
1215
0
        Token *typeDef = tok;
1216
0
        Token *argFuncRetStart = nullptr;
1217
0
        Token *argFuncRetEnd = nullptr;
1218
0
        Token *funcStart = nullptr;
1219
0
        Token *funcEnd = nullptr;
1220
0
        Token *tokOffset = tok->next();
1221
0
        bool function = false;
1222
0
        bool functionPtr = false;
1223
0
        bool functionRetFuncPtr = false;
1224
0
        bool functionPtrRetFuncPtr = false;
1225
0
        bool ptrToArray = false;
1226
0
        bool refToArray = false;
1227
0
        bool ptrMember = false;
1228
0
        bool typeOf = false;
1229
0
        Token *namespaceStart = nullptr;
1230
0
        Token *namespaceEnd = nullptr;
1231
1232
        // check for invalid input
1233
0
        if (!tokOffset)
1234
0
            syntaxError(tok);
1235
1236
1237
0
        if (tokOffset->str() == "::") {
1238
0
            typeStart = tokOffset;
1239
0
            tokOffset = tokOffset->next();
1240
1241
0
            while (Token::Match(tokOffset, "%type% ::"))
1242
0
                tokOffset = tokOffset->tokAt(2);
1243
1244
0
            typeEnd = tokOffset;
1245
1246
0
            if (Token::Match(tokOffset, "%type%"))
1247
0
                tokOffset = tokOffset->next();
1248
0
        } else if (Token::Match(tokOffset, "%type% ::")) {
1249
0
            typeStart = tokOffset;
1250
1251
0
            do {
1252
0
                tokOffset = tokOffset->tokAt(2);
1253
0
            } while (Token::Match(tokOffset, "%type% ::"));
1254
1255
0
            typeEnd = tokOffset;
1256
1257
0
            if (Token::Match(tokOffset, "%type%"))
1258
0
                tokOffset = tokOffset->next();
1259
0
        } else if (Token::Match(tokOffset, "%type%")) {
1260
0
            typeStart = tokOffset;
1261
1262
0
            while (Token::Match(tokOffset, "const|struct|enum %type%") ||
1263
0
                   (tokOffset->next() && tokOffset->next()->isStandardType() && !Token::Match(tokOffset->next(), "%name% ;")))
1264
0
                tokOffset = tokOffset->next();
1265
1266
0
            typeEnd = tokOffset;
1267
0
            if (!Token::Match(tokOffset->next(), "%name% ;"))
1268
0
                tokOffset = tokOffset->next();
1269
1270
0
            while (Token::Match(tokOffset, "%type%") &&
1271
0
                   (tokOffset->isStandardType() || Token::Match(tokOffset, "unsigned|signed")) &&
1272
0
                   !Token::Match(tokOffset->next(), "%name% ;")) {
1273
0
                typeEnd = tokOffset;
1274
0
                tokOffset = tokOffset->next();
1275
0
            }
1276
1277
0
            bool atEnd = false;
1278
0
            while (!atEnd) {
1279
0
                if (tokOffset && tokOffset->str() == "::") {
1280
0
                    typeEnd = tokOffset;
1281
0
                    tokOffset = tokOffset->next();
1282
0
                }
1283
1284
0
                if (Token::Match(tokOffset, "%type%") &&
1285
0
                    tokOffset->next() && !Token::Match(tokOffset->next(), "[|;|,|(")) {
1286
0
                    typeEnd = tokOffset;
1287
0
                    tokOffset = tokOffset->next();
1288
0
                } else if (Token::simpleMatch(tokOffset, "const (")) {
1289
0
                    typeEnd = tokOffset;
1290
0
                    tokOffset = tokOffset->next();
1291
0
                    atEnd = true;
1292
0
                } else
1293
0
                    atEnd = true;
1294
0
            }
1295
0
        } else
1296
0
            continue; // invalid input
1297
1298
        // check for invalid input
1299
0
        if (!tokOffset)
1300
0
            syntaxError(tok);
1301
1302
        // check for template
1303
0
        if (!isC() && tokOffset->str() == "<") {
1304
0
            typeEnd = tokOffset->findClosingBracket();
1305
1306
0
            while (typeEnd && Token::Match(typeEnd->next(), ":: %type%"))
1307
0
                typeEnd = typeEnd->tokAt(2);
1308
1309
0
            if (!typeEnd) {
1310
                // internal error
1311
0
                return;
1312
0
            }
1313
1314
0
            while (Token::Match(typeEnd->next(), "const|volatile"))
1315
0
                typeEnd = typeEnd->next();
1316
1317
0
            tok = typeEnd;
1318
0
            tokOffset = tok->next();
1319
0
        }
1320
1321
0
        std::list<std::string> pointers;
1322
        // check for pointers and references
1323
0
        while (Token::Match(tokOffset, "*|&|&&|const")) {
1324
0
            pointers.push_back(tokOffset->str());
1325
0
            tokOffset = tokOffset->next();
1326
0
        }
1327
1328
        // check for invalid input
1329
0
        if (!tokOffset)
1330
0
            syntaxError(tok);
1331
1332
0
        if (tokOffset->isName() && !tokOffset->isKeyword()) {
1333
            // found the type name
1334
0
            typeName = tokOffset;
1335
0
            tokOffset = tokOffset->next();
1336
1337
            // check for array
1338
0
            while (tokOffset && tokOffset->str() == "[") {
1339
0
                if (!arrayStart)
1340
0
                    arrayStart = tokOffset;
1341
0
                arrayEnd = tokOffset->link();
1342
0
                tokOffset = arrayEnd->next();
1343
0
            }
1344
1345
            // check for end or another
1346
0
            if (Token::Match(tokOffset, ";|,"))
1347
0
                tok = tokOffset;
1348
1349
            // or a function typedef
1350
0
            else if (tokOffset && tokOffset->str() == "(") {
1351
0
                Token *tokOffset2 = nullptr;
1352
0
                if (Token::Match(tokOffset, "( *|%name%")) {
1353
0
                    tokOffset2 = tokOffset->next();
1354
0
                    if (tokOffset2->str() == "typename")
1355
0
                        tokOffset2 = tokOffset2->next();
1356
0
                    while (Token::Match(tokOffset2, "%type% ::"))
1357
0
                        tokOffset2 = tokOffset2->tokAt(2);
1358
0
                }
1359
1360
                // unhandled typedef, skip it and continue
1361
0
                if (typeName->str() == "void") {
1362
0
                    unsupportedTypedef(typeDef);
1363
0
                    tok = deleteInvalidTypedef(typeDef);
1364
0
                    if (tok == list.front())
1365
                        //now the next token to process is 'tok', not 'tok->next()';
1366
0
                        goback = true;
1367
0
                    continue;
1368
0
                }
1369
1370
                // function pointer
1371
0
                if (Token::Match(tokOffset2, "* %name% ) (")) {
1372
                    // name token wasn't a name, it was part of the type
1373
0
                    typeEnd = typeEnd->next();
1374
0
                    functionPtr = true;
1375
0
                    funcStart = funcEnd = tokOffset2; // *
1376
0
                    tokOffset = tokOffset2->tokAt(3); // (
1377
0
                    typeName = tokOffset->tokAt(-2);
1378
0
                    argStart = tokOffset;
1379
0
                    argEnd = tokOffset->link();
1380
0
                    tok = argEnd->next();
1381
0
                }
1382
1383
                // function
1384
0
                else if (isFunctionHead(tokOffset->link(), ";,")) {
1385
0
                    function = true;
1386
0
                    if (tokOffset->link()->next()->str() == "const") {
1387
0
                        specStart = tokOffset->link()->next();
1388
0
                        specEnd = specStart;
1389
0
                    }
1390
0
                    argStart = tokOffset;
1391
0
                    argEnd = tokOffset->link();
1392
0
                    tok = argEnd->next();
1393
0
                    if (specStart)
1394
0
                        tok = tok->next();
1395
0
                }
1396
1397
                // syntax error
1398
0
                else
1399
0
                    syntaxError(tok);
1400
0
            }
1401
1402
            // unhandled typedef, skip it and continue
1403
0
            else {
1404
0
                unsupportedTypedef(typeDef);
1405
0
                tok = deleteInvalidTypedef(typeDef);
1406
0
                if (tok == list.front())
1407
                    //now the next token to process is 'tok', not 'tok->next()';
1408
0
                    goback = true;
1409
0
                continue;
1410
0
            }
1411
0
        }
1412
1413
        // typeof: typedef typeof ( ... ) type;
1414
0
        else if (Token::simpleMatch(tokOffset->previous(), "typeof (") &&
1415
0
                 Token::Match(tokOffset->link(), ") %type% ;")) {
1416
0
            argStart = tokOffset;
1417
0
            argEnd = tokOffset->link();
1418
0
            typeName = tokOffset->link()->next();
1419
0
            tok = typeName->next();
1420
0
            typeOf = true;
1421
0
        }
1422
1423
        // function: typedef ... ( ... type )( ... );
1424
        //           typedef ... (( ... type )( ... ));
1425
        //           typedef ... ( * ( ... type )( ... ));
1426
0
        else if (tokOffset->str() == "(" && (
1427
0
                     (tokOffset->link() && Token::Match(tokOffset->link()->previous(), "%type% ) (") &&
1428
0
                      Token::Match(tokOffset->link()->next()->link(), ") const|volatile|;")) ||
1429
0
                     (Token::simpleMatch(tokOffset, "( (") &&
1430
0
                      tokOffset->next() && Token::Match(tokOffset->next()->link()->previous(), "%type% ) (") &&
1431
0
                      Token::Match(tokOffset->next()->link()->next()->link(), ") const|volatile| ) ;|,")) ||
1432
0
                     (Token::simpleMatch(tokOffset, "( * (") &&
1433
0
                      tokOffset->linkAt(2) && Token::Match(tokOffset->linkAt(2)->previous(), "%type% ) (") &&
1434
0
                      Token::Match(tokOffset->linkAt(2)->next()->link(), ") const|volatile| ) ;|,")))) {
1435
0
            if (tokOffset->next()->str() == "(")
1436
0
                tokOffset = tokOffset->next();
1437
0
            else if (Token::simpleMatch(tokOffset, "( * (")) {
1438
0
                pointers.emplace_back("*");
1439
0
                tokOffset = tokOffset->tokAt(2);
1440
0
            }
1441
1442
0
            if (tokOffset->link()->strAt(-2) == "*")
1443
0
                functionPtr = true;
1444
0
            else
1445
0
                function = true;
1446
0
            funcStart = tokOffset->next();
1447
0
            tokOffset = tokOffset->link();
1448
0
            funcEnd = tokOffset->tokAt(-2);
1449
0
            typeName = tokOffset->previous();
1450
0
            argStart = tokOffset->next();
1451
0
            argEnd = tokOffset->next()->link();
1452
0
            if (!argEnd)
1453
0
                syntaxError(argStart);
1454
1455
0
            tok = argEnd->next();
1456
0
            Token *spec = tok;
1457
0
            if (Token::Match(spec, "const|volatile")) {
1458
0
                specStart = spec;
1459
0
                specEnd = spec;
1460
0
                while (Token::Match(spec->next(), "const|volatile")) {
1461
0
                    specEnd = spec->next();
1462
0
                    spec = specEnd;
1463
0
                }
1464
0
                tok = specEnd->next();
1465
0
            }
1466
0
            if (!tok)
1467
0
                syntaxError(specEnd);
1468
1469
0
            if (tok->str() == ")")
1470
0
                tok = tok->next();
1471
0
        }
1472
1473
0
        else if (Token::Match(tokOffset, "( %type% (")) {
1474
0
            function = true;
1475
0
            if (tokOffset->link()->next()) {
1476
0
                tok = tokOffset->link()->next();
1477
0
                tokOffset = tokOffset->tokAt(2);
1478
0
                typeName = tokOffset->previous();
1479
0
                argStart = tokOffset;
1480
0
                argEnd = tokOffset->link();
1481
0
            } else {
1482
                // internal error
1483
0
                continue;
1484
0
            }
1485
0
        }
1486
1487
        // pointer to function returning pointer to function
1488
0
        else if (Token::Match(tokOffset, "( * ( * %type% ) (") &&
1489
0
                 Token::simpleMatch(tokOffset->linkAt(6), ") ) (") &&
1490
0
                 Token::Match(tokOffset->linkAt(6)->linkAt(2), ") ;|,")) {
1491
0
            functionPtrRetFuncPtr = true;
1492
1493
0
            tokOffset = tokOffset->tokAt(6);
1494
0
            typeName = tokOffset->tokAt(-2);
1495
0
            argStart = tokOffset;
1496
0
            argEnd = tokOffset->link();
1497
0
            if (!argEnd)
1498
0
                syntaxError(arrayStart);
1499
1500
0
            argFuncRetStart = argEnd->tokAt(2);
1501
0
            argFuncRetEnd = argFuncRetStart->link();
1502
0
            if (!argFuncRetEnd)
1503
0
                syntaxError(argFuncRetStart);
1504
1505
0
            tok = argFuncRetEnd->next();
1506
0
        }
1507
1508
        // function returning pointer to function
1509
0
        else if (Token::Match(tokOffset, "( * %type% (") &&
1510
0
                 Token::simpleMatch(tokOffset->linkAt(3), ") ) (") &&
1511
0
                 Token::Match(tokOffset->linkAt(3)->linkAt(2), ") ;|,")) {
1512
0
            functionRetFuncPtr = true;
1513
1514
0
            tokOffset = tokOffset->tokAt(3);
1515
0
            typeName = tokOffset->previous();
1516
0
            argStart = tokOffset;
1517
0
            argEnd = tokOffset->link();
1518
1519
0
            argFuncRetStart = argEnd->tokAt(2);
1520
0
            if (!argFuncRetStart)
1521
0
                syntaxError(tokOffset);
1522
1523
0
            argFuncRetEnd = argFuncRetStart->link();
1524
0
            if (!argFuncRetEnd)
1525
0
                syntaxError(tokOffset);
1526
1527
0
            tok = argFuncRetEnd->next();
1528
0
        } else if (Token::Match(tokOffset, "( * ( %type% ) (")) {
1529
0
            functionRetFuncPtr = true;
1530
1531
0
            tokOffset = tokOffset->tokAt(5);
1532
0
            typeName = tokOffset->tokAt(-2);
1533
0
            argStart = tokOffset;
1534
0
            argEnd = tokOffset->link();
1535
0
            if (!argEnd)
1536
0
                syntaxError(arrayStart);
1537
1538
0
            argFuncRetStart = argEnd->tokAt(2);
1539
0
            if (!argFuncRetStart)
1540
0
                syntaxError(tokOffset);
1541
1542
0
            argFuncRetEnd = argFuncRetStart->link();
1543
0
            if (!argFuncRetEnd)
1544
0
                syntaxError(tokOffset);
1545
1546
0
            tok = argFuncRetEnd->next();
1547
0
        }
1548
1549
        // pointer/reference to array
1550
0
        else if (Token::Match(tokOffset, "( *|& %type% ) [")) {
1551
0
            ptrToArray = (tokOffset->next()->str() == "*");
1552
0
            refToArray = !ptrToArray;
1553
0
            tokOffset = tokOffset->tokAt(2);
1554
0
            typeName = tokOffset;
1555
0
            arrayStart = tokOffset->tokAt(2);
1556
0
            arrayEnd = arrayStart->link();
1557
0
            if (!arrayEnd)
1558
0
                syntaxError(arrayStart);
1559
1560
0
            tok = arrayEnd->next();
1561
0
        }
1562
1563
        // pointer to class member
1564
0
        else if (Token::Match(tokOffset, "( %type% :: * %type% ) ;")) {
1565
0
            tokOffset = tokOffset->tokAt(2);
1566
0
            namespaceStart = tokOffset->previous();
1567
0
            namespaceEnd = tokOffset;
1568
0
            ptrMember = true;
1569
0
            tokOffset = tokOffset->tokAt(2);
1570
0
            typeName = tokOffset;
1571
0
            tok = tokOffset->tokAt(2);
1572
0
        }
1573
1574
        // unhandled typedef, skip it and continue
1575
0
        else {
1576
0
            unsupportedTypedef(typeDef);
1577
0
            tok = deleteInvalidTypedef(typeDef);
1578
0
            if (tok == list.front())
1579
                //now the next token to process is 'tok', not 'tok->next()';
1580
0
                goback = true;
1581
0
            continue;
1582
0
        }
1583
1584
0
        bool done = false;
1585
0
        bool ok = true;
1586
1587
0
        TypedefInfo typedefInfo;
1588
0
        typedefInfo.name = typeName->str();
1589
0
        typedefInfo.filename = list.file(typeName);
1590
0
        typedefInfo.lineNumber = typeName->linenr();
1591
0
        typedefInfo.column = typeName->column();
1592
0
        typedefInfo.used = false;
1593
0
        mTypedefInfo.push_back(std::move(typedefInfo));
1594
1595
0
        while (!done) {
1596
0
            std::string pattern = typeName->str();
1597
0
            int scope = 0;
1598
0
            bool simplifyType = false;
1599
0
            bool inMemberFunc = false;
1600
0
            int memberScope = 0;
1601
0
            bool globalScope = false;
1602
0
            int classLevel = spaceInfo.size();
1603
0
            bool inTypeDef = false;
1604
0
            bool inEnumClass = false;
1605
0
            std::string removed;
1606
0
            std::string classPath;
1607
0
            for (size_t i = 1; i < spaceInfo.size(); ++i) {
1608
0
                if (!classPath.empty())
1609
0
                    classPath += " :: ";
1610
0
                classPath += spaceInfo[i].className;
1611
0
            }
1612
1613
0
            for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
1614
0
                if (Settings::terminated())
1615
0
                    return;
1616
1617
0
                removed.clear();
1618
1619
0
                if (Token::simpleMatch(tok2, "typedef"))
1620
0
                    inTypeDef = true;
1621
1622
0
                if (inTypeDef && Token::simpleMatch(tok2, ";"))
1623
0
                    inTypeDef = false;
1624
1625
                // Check for variable declared with the same name
1626
0
                if (!inTypeDef && spaceInfo.size() == 1 && Token::Match(tok2->previous(), "%name%") &&
1627
0
                    !tok2->previous()->isKeyword()) {
1628
0
                    Token* varDecl = tok2;
1629
0
                    while (Token::Match(varDecl, "*|&|&&|const"))
1630
0
                        varDecl = varDecl->next();
1631
0
                    if (Token::Match(varDecl, "%name% ;|,|)|=") && varDecl->str() == typeName->str()) {
1632
                        // Skip to the next closing brace
1633
0
                        if (Token::Match(varDecl, "%name% ) {")) { // is argument variable
1634
0
                            tok2 = varDecl->linkAt(2)->next();
1635
0
                        } else {
1636
0
                            tok2 = varDecl;
1637
0
                            while (tok2 && !Token::simpleMatch(tok2, "}")) {
1638
0
                                if (Token::Match(tok2, "(|{|["))
1639
0
                                    tok2 = tok2->link();
1640
0
                                tok2 = tok2->next();
1641
0
                            }
1642
0
                        }
1643
0
                        if (!tok2)
1644
0
                            break;
1645
0
                        continue;
1646
0
                    }
1647
0
                }
1648
1649
0
                if (tok2->link()) { // Pre-check for performance
1650
                    // check for end of scope
1651
0
                    if (tok2->str() == "}") {
1652
                        // check for end of member function
1653
0
                        if (inMemberFunc) {
1654
0
                            --memberScope;
1655
0
                            if (memberScope == 0)
1656
0
                                inMemberFunc = false;
1657
0
                        }
1658
0
                        inEnumClass = false;
1659
1660
0
                        if (classLevel > 1 && tok2 == spaceInfo[classLevel - 1].bodyEnd2) {
1661
0
                            --classLevel;
1662
0
                            pattern.clear();
1663
1664
0
                            for (int i = classLevel; i < spaceInfo.size(); ++i)
1665
0
                                pattern += (spaceInfo[i].className + " :: ");
1666
1667
0
                            pattern += typeName->str();
1668
0
                        } else {
1669
0
                            if (scope == 0 && !(classLevel > 1 && tok2 == spaceInfo[classLevel - 1].bodyEnd))
1670
0
                                break;
1671
0
                            --scope;
1672
0
                        }
1673
0
                    }
1674
1675
                    // check for member functions
1676
0
                    else if (isCPP() && tok2->str() == "(" && isFunctionHead(tok2, "{:")) {
1677
0
                        const Token *func = tok2->previous();
1678
1679
                        /** @todo add support for multi-token operators */
1680
0
                        if (func->previous()->str() == "operator")
1681
0
                            func = func->previous();
1682
1683
0
                        if (!func->previous())
1684
0
                            syntaxError(func);
1685
1686
                        // check for qualifier
1687
0
                        if (Token::Match(func->tokAt(-2), "%name% ::")) {
1688
0
                            int offset = -2;
1689
0
                            while (Token::Match(func->tokAt(offset - 2), "%name% ::"))
1690
0
                                offset -= 2;
1691
                            // check for available and matching class name
1692
0
                            if (spaceInfo.size() > 1 && classLevel < spaceInfo.size() &&
1693
0
                                func->strAt(offset) == spaceInfo[classLevel].className) {
1694
0
                                memberScope = 0;
1695
0
                                inMemberFunc = true;
1696
0
                            }
1697
0
                        }
1698
0
                    }
1699
1700
                    // check for entering a new scope
1701
0
                    else if (tok2->str() == "{") {
1702
                        // check for entering a new namespace
1703
0
                        if (isCPP()) {
1704
0
                            if (tok2->strAt(-2) == "namespace") {
1705
0
                                if (classLevel < spaceInfo.size() &&
1706
0
                                    spaceInfo[classLevel].isNamespace &&
1707
0
                                    spaceInfo[classLevel].className == tok2->previous()->str()) {
1708
0
                                    spaceInfo[classLevel].bodyEnd2 = tok2->link();
1709
0
                                    ++classLevel;
1710
0
                                    pattern.clear();
1711
0
                                    for (int i = classLevel; i < spaceInfo.size(); ++i)
1712
0
                                        pattern += spaceInfo[i].className + " :: ";
1713
1714
0
                                    pattern += typeName->str();
1715
0
                                }
1716
0
                                ++scope;
1717
0
                            }
1718
0
                            if (Token::Match(tok2->tokAt(-3), "enum class %name%"))
1719
0
                                inEnumClass = true;
1720
0
                        }
1721
1722
                        // keep track of scopes within member function
1723
0
                        if (inMemberFunc)
1724
0
                            ++memberScope;
1725
1726
0
                        ++scope;
1727
0
                    }
1728
0
                }
1729
1730
                // check for operator typedef
1731
                /** @todo add support for multi-token operators */
1732
0
                else if (isCPP() &&
1733
0
                         tok2->str() == "operator" &&
1734
0
                         tok2->next() &&
1735
0
                         tok2->next()->str() == typeName->str() &&
1736
0
                         tok2->linkAt(2) &&
1737
0
                         tok2->strAt(2) == "(" &&
1738
0
                         Token::Match(tok2->linkAt(2), ") const| {")) {
1739
                    // check for qualifier
1740
0
                    if (tok2->previous()->str() == "::") {
1741
                        // check for available and matching class name
1742
0
                        if (spaceInfo.size() > 1 && classLevel < spaceInfo.size() &&
1743
0
                            tok2->strAt(-2) == spaceInfo[classLevel].className) {
1744
0
                            tok2 = tok2->next();
1745
0
                            simplifyType = true;
1746
0
                        }
1747
0
                    }
1748
0
                }
1749
1750
0
                else if (Token::Match(tok2->previous(), "class|struct %name% [:{]")) {
1751
                    // don't replace names in struct/class definition
1752
0
                }
1753
1754
                // check for typedef that can be substituted
1755
0
                else if ((tok2->isNameOnly() || (tok2->isName() && (tok2->isExpandedMacro() || tok2->isInline()))) &&
1756
0
                         (Token::simpleMatch(tok2, pattern.c_str(), pattern.size()) ||
1757
0
                          (inMemberFunc && tok2->str() == typeName->str()))) {
1758
                    // member function class variables don't need qualification
1759
0
                    if (!(inMemberFunc && tok2->str() == typeName->str()) && pattern.find("::") != std::string::npos) { // has a "something ::"
1760
0
                        Token *start = tok2;
1761
0
                        int count = 0;
1762
0
                        int back = classLevel - 1;
1763
0
                        bool good = true;
1764
                        // check for extra qualification
1765
0
                        while (back >= 1) {
1766
0
                            Token *qualificationTok = start->tokAt(-2);
1767
0
                            if (!Token::Match(qualificationTok, "%type% ::"))
1768
0
                                break;
1769
0
                            if (qualificationTok->str() == spaceInfo[back].className) {
1770
0
                                start = qualificationTok;
1771
0
                                back--;
1772
0
                                count++;
1773
0
                            } else {
1774
0
                                good = false;
1775
0
                                break;
1776
0
                            }
1777
0
                        }
1778
                        // check global namespace
1779
0
                        if (good && back == 1 && start->strAt(-1) == "::")
1780
0
                            good = false;
1781
1782
0
                        if (good) {
1783
                            // remove any extra qualification if present
1784
0
                            while (count) {
1785
0
                                if (!removed.empty())
1786
0
                                    removed.insert(0, " ");
1787
0
                                removed.insert(0, tok2->strAt(-2) + " " + tok2->strAt(-1));
1788
0
                                tok2->tokAt(-3)->deleteNext(2);
1789
0
                                --count;
1790
0
                            }
1791
1792
                            // remove global namespace if present
1793
0
                            if (tok2->strAt(-1) == "::") {
1794
0
                                removed.insert(0, ":: ");
1795
0
                                tok2->tokAt(-2)->deleteNext();
1796
0
                                globalScope = true;
1797
0
                            }
1798
1799
                            // remove qualification if present
1800
0
                            for (int i = classLevel; i < spaceInfo.size(); ++i) {
1801
0
                                if (!removed.empty())
1802
0
                                    removed += " ";
1803
0
                                removed += (tok2->str() + " " + tok2->strAt(1));
1804
0
                                tok2->deleteThis();
1805
0
                                tok2->deleteThis();
1806
0
                            }
1807
0
                            simplifyType = true;
1808
0
                        }
1809
0
                    } else {
1810
0
                        if (tok2->strAt(-1) == "::") {
1811
0
                            int relativeSpaceInfoSize = spaceInfo.size();
1812
0
                            Token * tokBeforeType = tok2->previous();
1813
0
                            while (relativeSpaceInfoSize > 1 &&
1814
0
                                   tokBeforeType && tokBeforeType->str() == "::" &&
1815
0
                                   tokBeforeType->strAt(-1) == spaceInfo[relativeSpaceInfoSize-1].className) {
1816
0
                                tokBeforeType = tokBeforeType->tokAt(-2);
1817
0
                                --relativeSpaceInfoSize;
1818
0
                            }
1819
0
                            if (tokBeforeType && tokBeforeType->str() != "::") {
1820
0
                                Token::eraseTokens(tokBeforeType, tok2);
1821
0
                                simplifyType = true;
1822
0
                            }
1823
0
                        } else if (Token::Match(tok2->previous(), "case|;|{|} %type% :")) {
1824
0
                            tok2 = tok2->next();
1825
0
                        } else if (duplicateTypedef(&tok2, typeName, typeDef)) {
1826
                            // skip to end of scope if not already there
1827
0
                            if (tok2->str() != "}") {
1828
0
                                while (tok2->next()) {
1829
0
                                    if (tok2->next()->str() == "{")
1830
0
                                        tok2 = tok2->linkAt(1)->previous();
1831
0
                                    else if (tok2->next()->str() == "}")
1832
0
                                        break;
1833
1834
0
                                    tok2 = tok2->next();
1835
0
                                }
1836
0
                            }
1837
0
                        } else if (Token::Match(tok2->tokAt(-2), "%type% *|&")) {
1838
                            // Ticket #5868: Don't substitute variable names
1839
0
                        } else if (tok2->previous()->str() != ".") {
1840
0
                            simplifyType = true;
1841
0
                        }
1842
0
                    }
1843
0
                }
1844
1845
0
                simplifyType = simplifyType && (!inEnumClass || Token::simpleMatch(tok2->previous(), "="));
1846
1847
0
                if (simplifyType) {
1848
0
                    mTypedefInfo.back().used = true;
1849
1850
                    // can't simplify 'operator functionPtr ()' and 'functionPtr operator ... ()'
1851
0
                    if (functionPtr && (tok2->previous()->str() == "operator" ||
1852
0
                                        (tok2->next() && tok2->next()->str() == "operator"))) {
1853
0
                        simplifyType = false;
1854
0
                        tok2 = tok2->next();
1855
0
                        continue;
1856
0
                    }
1857
1858
                    // There are 2 categories of typedef substitutions:
1859
                    // 1. variable declarations that preserve the variable name like
1860
                    //    global, local, and function parameters
1861
                    // 2. not variable declarations that have no name like derived
1862
                    //    classes, casts, operators, and template parameters
1863
1864
                    // try to determine which category this substitution is
1865
0
                    bool inCast = false;
1866
0
                    bool inTemplate = false;
1867
0
                    bool inOperator = false;
1868
0
                    bool inSizeof = false;
1869
1870
0
                    const bool sameStartEnd = (typeStart == typeEnd);
1871
1872
                    // check for derived class: class A : some_typedef {
1873
0
                    const bool isDerived = Token::Match(tok2->previous(), "public|protected|private|: %type% {|,");
1874
1875
                    // check for cast: (some_typedef) A or static_cast<some_typedef>(A)
1876
                    // todo: check for more complicated casts like: (const some_typedef *)A
1877
0
                    if ((tok2->previous()->str() == "(" && tok2->next()->str() == ")" && tok2->strAt(-2) != "sizeof") ||
1878
0
                        (tok2->previous()->str() == "<" && Token::simpleMatch(tok2->next(), "> (")) ||
1879
0
                        Token::Match(tok2->tokAt(-2), "( const %name% )"))
1880
0
                        inCast = true;
1881
1882
                    // check for template parameters: t<some_typedef> t1
1883
0
                    else if (Token::Match(tok2->previous(), "<|,") &&
1884
0
                             Token::Match(tok2->next(), "&|*| &|*| >|,"))
1885
0
                        inTemplate = true;
1886
1887
0
                    else if (Token::Match(tok2->tokAt(-2), "sizeof ( %type% )"))
1888
0
                        inSizeof = true;
1889
1890
                    // check for operator
1891
0
                    if (tok2->strAt(-1) == "operator" ||
1892
0
                        Token::simpleMatch(tok2->tokAt(-2), "operator const"))
1893
0
                        inOperator = true;
1894
1895
0
                    if (typeStart->str() == "typename" && tok2->strAt(-1)=="typename") {
1896
                        // Remove one typename if it is already contained in the goal
1897
0
                        typeStart = typeStart->next();
1898
0
                    }
1899
1900
                    // skip over class or struct in derived class declaration
1901
0
                    bool structRemoved = false;
1902
0
                    if ((isDerived || inTemplate) && Token::Match(typeStart, "class|struct")) {
1903
0
                        if (typeStart->str() == "struct")
1904
0
                            structRemoved = true;
1905
0
                        typeStart = typeStart->next();
1906
0
                    }
1907
0
                    if (Token::Match(typeStart, "struct|class|union") && Token::Match(tok2, "%name% ::"))
1908
0
                        typeStart = typeStart->next();
1909
1910
0
                    if (sameStartEnd)
1911
0
                        typeEnd = typeStart;
1912
1913
                    // Is this a "T()" expression where T is a pointer type?
1914
0
                    const bool isPointerTypeCall = !inOperator && Token::Match(tok2, "%name% ( )") && !pointers.empty();
1915
1916
                    // start substituting at the typedef name by replacing it with the type
1917
0
                    Token* replStart = tok2; // track first replaced token
1918
0
                    for (Token* tok3 = typeStart; tok3->str() != ";"; tok3 = tok3->next())
1919
0
                        tok3->isSimplifiedTypedef(true);
1920
0
                    if (isPointerTypeCall) {
1921
0
                        tok2->deleteThis();
1922
0
                        tok2->insertToken("0");
1923
0
                        tok2 = tok2->next();
1924
0
                        tok2->next()->insertToken("0");
1925
0
                    }
1926
0
                    tok2->str(typeStart->str());
1927
1928
                    // restore qualification if it was removed
1929
0
                    if (typeStart->str() == "struct" || structRemoved) {
1930
0
                        if (structRemoved)
1931
0
                            tok2 = tok2->previous();
1932
1933
0
                        if (globalScope) {
1934
0
                            replStart = tok2->insertToken("::");
1935
0
                            tok2 = tok2->next();
1936
0
                        }
1937
1938
0
                        for (int i = classLevel; i < spaceInfo.size(); ++i) {
1939
0
                            tok2->insertToken(spaceInfo[i].className);
1940
0
                            tok2 = tok2->next();
1941
0
                            tok2->insertToken("::");
1942
0
                            tok2 = tok2->next();
1943
0
                        }
1944
0
                    }
1945
1946
                    // add some qualification back if needed
1947
0
                    Token *start = tok2;
1948
0
                    std::string removed1 = removed;
1949
0
                    std::string::size_type idx = removed1.rfind(" ::");
1950
1951
0
                    if (idx != std::string::npos)
1952
0
                        removed1.resize(idx);
1953
0
                    if (removed1 == classPath && !removed1.empty()) {
1954
0
                        for (std::vector<Space>::const_reverse_iterator it = spaceInfo.crbegin(); it != spaceInfo.crend(); ++it) {
1955
0
                            if (it->recordTypes.find(start->str()) != it->recordTypes.end()) {
1956
0
                                std::string::size_type spaceIdx = 0;
1957
0
                                std::string::size_type startIdx = 0;
1958
0
                                while ((spaceIdx = removed1.find(' ', startIdx)) != std::string::npos) {
1959
0
                                    tok2->previous()->insertToken(removed1.substr(startIdx, spaceIdx - startIdx));
1960
0
                                    startIdx = spaceIdx + 1;
1961
0
                                }
1962
0
                                tok2->previous()->insertToken(removed1.substr(startIdx));
1963
0
                                replStart = tok2->previous()->insertToken("::");
1964
0
                                break;
1965
0
                            }
1966
0
                            idx = removed1.rfind(" ::");
1967
0
                            if (idx == std::string::npos)
1968
0
                                break;
1969
1970
0
                            removed1.resize(idx);
1971
0
                        }
1972
0
                    }
1973
0
                    replStart->isSimplifiedTypedef(true);
1974
0
                    Token* constTok = Token::simpleMatch(tok2->previous(), "const") ? tok2->previous() : nullptr;
1975
                    // add remainder of type
1976
0
                    tok2 = TokenList::copyTokens(tok2, typeStart->next(), typeEnd);
1977
1978
0
                    if (!pointers.empty()) {
1979
0
                        for (const std::string &p : pointers) {
1980
0
                            tok2->insertToken(p);
1981
0
                            tok2->isSimplifiedTypedef(true);
1982
0
                            tok2 = tok2->next();
1983
0
                        }
1984
0
                        if (constTok) {
1985
0
                            constTok->deleteThis();
1986
0
                            tok2->insertToken("const");
1987
0
                            tok2->isSimplifiedTypedef(true);
1988
0
                            tok2 = tok2->next();
1989
0
                        }
1990
0
                    }
1991
1992
0
                    if (funcStart && funcEnd) {
1993
0
                        tok2->insertToken("(");
1994
0
                        tok2 = tok2->next();
1995
0
                        Token *paren = tok2;
1996
0
                        tok2 = TokenList::copyTokens(tok2, funcStart, funcEnd);
1997
1998
0
                        if (!inCast)
1999
0
                            tok2 = processFunc(tok2, inOperator);
2000
2001
0
                        if (!tok2)
2002
0
                            break;
2003
2004
0
                        while (Token::Match(tok2, "%name%|] ["))
2005
0
                            tok2 = tok2->linkAt(1);
2006
2007
0
                        tok2->insertToken(")");
2008
0
                        tok2 = tok2->next();
2009
0
                        Token::createMutualLinks(tok2, paren);
2010
2011
0
                        tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2012
2013
0
                        if (specStart) {
2014
0
                            Token *spec = specStart;
2015
0
                            tok2->insertToken(spec->str());
2016
0
                            tok2 = tok2->next();
2017
0
                            while (spec != specEnd) {
2018
0
                                spec = spec->next();
2019
0
                                tok2->insertToken(spec->str());
2020
0
                                tok2 = tok2->next();
2021
0
                            }
2022
0
                        }
2023
0
                    }
2024
2025
0
                    else if (functionPtr || function) {
2026
                        // don't add parentheses around function names because it
2027
                        // confuses other simplifications
2028
0
                        bool needParen = true;
2029
0
                        if (!inTemplate && function && tok2->next() && tok2->next()->str() != "*")
2030
0
                            needParen = false;
2031
0
                        if (needParen) {
2032
0
                            tok2->insertToken("(");
2033
0
                            tok2 = tok2->next();
2034
0
                        }
2035
0
                        Token *tok3 = tok2;
2036
0
                        if (namespaceStart) {
2037
0
                            const Token *tok4 = namespaceStart;
2038
2039
0
                            while (tok4 != namespaceEnd) {
2040
0
                                tok2->insertToken(tok4->str());
2041
0
                                tok2 = tok2->next();
2042
0
                                tok4 = tok4->next();
2043
0
                            }
2044
0
                            tok2->insertToken(namespaceEnd->str());
2045
0
                            tok2 = tok2->next();
2046
0
                        }
2047
0
                        if (functionPtr) {
2048
0
                            tok2->insertToken("*");
2049
0
                            tok2 = tok2->next();
2050
0
                        }
2051
2052
0
                        if (!inCast)
2053
0
                            tok2 = processFunc(tok2, inOperator);
2054
2055
0
                        if (needParen) {
2056
0
                            if (!tok2)
2057
0
                                syntaxError(nullptr);
2058
2059
0
                            tok2->insertToken(")");
2060
0
                            tok2 = tok2->next();
2061
0
                            Token::createMutualLinks(tok2, tok3);
2062
0
                        }
2063
0
                        if (!tok2)
2064
0
                            syntaxError(nullptr);
2065
2066
0
                        tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2067
0
                        if (inTemplate) {
2068
0
                            if (!tok2)
2069
0
                                syntaxError(nullptr);
2070
2071
0
                            tok2 = tok2->next();
2072
0
                        }
2073
2074
0
                        if (specStart) {
2075
0
                            Token *spec = specStart;
2076
0
                            tok2->insertToken(spec->str());
2077
0
                            tok2 = tok2->next();
2078
0
                            while (spec != specEnd) {
2079
0
                                spec = spec->next();
2080
0
                                tok2->insertToken(spec->str());
2081
0
                                tok2 = tok2->next();
2082
0
                            }
2083
0
                        }
2084
0
                    } else if (functionRetFuncPtr || functionPtrRetFuncPtr) {
2085
0
                        tok2->insertToken("(");
2086
0
                        tok2 = tok2->next();
2087
0
                        Token *tok3 = tok2;
2088
0
                        tok2->insertToken("*");
2089
0
                        tok2 = tok2->next();
2090
2091
0
                        Token * tok4 = nullptr;
2092
0
                        if (functionPtrRetFuncPtr) {
2093
0
                            tok2->insertToken("(");
2094
0
                            tok2 = tok2->next();
2095
0
                            tok4 = tok2;
2096
0
                            tok2->insertToken("*");
2097
0
                            tok2 = tok2->next();
2098
0
                        }
2099
2100
                        // skip over variable name if there
2101
0
                        if (!inCast) {
2102
0
                            if (!tok2 || !tok2->next())
2103
0
                                syntaxError(nullptr);
2104
2105
0
                            if (tok2->next()->str() != ")")
2106
0
                                tok2 = tok2->next();
2107
0
                        }
2108
2109
0
                        if (tok4 && functionPtrRetFuncPtr) {
2110
0
                            tok2->insertToken(")");
2111
0
                            tok2 = tok2->next();
2112
0
                            Token::createMutualLinks(tok2, tok4);
2113
0
                        }
2114
2115
0
                        tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2116
2117
0
                        tok2->insertToken(")");
2118
0
                        tok2 = tok2->next();
2119
0
                        Token::createMutualLinks(tok2, tok3);
2120
2121
0
                        tok2 = TokenList::copyTokens(tok2, argFuncRetStart, argFuncRetEnd);
2122
0
                    } else if (ptrToArray || refToArray) {
2123
0
                        tok2->insertToken("(");
2124
0
                        tok2 = tok2->next();
2125
0
                        Token *tok3 = tok2;
2126
2127
0
                        if (ptrToArray)
2128
0
                            tok2->insertToken("*");
2129
0
                        else
2130
0
                            tok2->insertToken("&");
2131
0
                        tok2 = tok2->next();
2132
2133
0
                        bool hasName = false;
2134
                        // skip over name
2135
0
                        if (tok2->next() && tok2->next()->str() != ")" && tok2->next()->str() != "," &&
2136
0
                            tok2->next()->str() != ">") {
2137
0
                            hasName = true;
2138
0
                            if (tok2->next()->str() != "(")
2139
0
                                tok2 = tok2->next();
2140
2141
                            // check for function and skip over args
2142
0
                            if (tok2 && tok2->next() && tok2->next()->str() == "(")
2143
0
                                tok2 = tok2->next()->link();
2144
2145
                            // check for array
2146
0
                            if (tok2 && tok2->next() && tok2->next()->str() == "[")
2147
0
                                tok2 = tok2->next()->link();
2148
0
                        }
2149
2150
0
                        tok2->insertToken(")");
2151
0
                        Token::createMutualLinks(tok2->next(), tok3);
2152
2153
0
                        if (!hasName)
2154
0
                            tok2 = tok2->next();
2155
0
                    } else if (ptrMember) {
2156
0
                        if (Token::simpleMatch(tok2, "* (")) {
2157
0
                            tok2->insertToken("*");
2158
0
                            tok2 = tok2->next();
2159
0
                        } else {
2160
                            // This is the case of casting operator.
2161
                            // Name is not available, and () should not be
2162
                            // inserted
2163
0
                            const bool castOperator = inOperator && Token::Match(tok2, "%type% (");
2164
0
                            Token *openParenthesis = nullptr;
2165
2166
0
                            if (!castOperator) {
2167
0
                                tok2->insertToken("(");
2168
0
                                tok2 = tok2->next();
2169
2170
0
                                openParenthesis = tok2;
2171
0
                            }
2172
2173
0
                            const Token *tok4 = namespaceStart;
2174
2175
0
                            while (tok4 != namespaceEnd) {
2176
0
                                tok2->insertToken(tok4->str());
2177
0
                                tok2 = tok2->next();
2178
0
                                tok4 = tok4->next();
2179
0
                            }
2180
0
                            tok2->insertToken(namespaceEnd->str());
2181
0
                            tok2 = tok2->next();
2182
2183
0
                            tok2->insertToken("*");
2184
0
                            tok2 = tok2->next();
2185
2186
0
                            if (openParenthesis) {
2187
                                // Skip over name, if any
2188
0
                                if (Token::Match(tok2->next(), "%name%"))
2189
0
                                    tok2 = tok2->next();
2190
2191
0
                                tok2->insertToken(")");
2192
0
                                tok2 = tok2->next();
2193
2194
0
                                Token::createMutualLinks(tok2, openParenthesis);
2195
0
                            }
2196
0
                        }
2197
0
                    } else if (typeOf) {
2198
0
                        tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2199
0
                    } else if (Token::Match(tok2, "%name% [")) {
2200
0
                        while (Token::Match(tok2, "%name%|] [")) {
2201
0
                            tok2 = tok2->linkAt(1);
2202
0
                        }
2203
0
                        tok2 = tok2->previous();
2204
0
                    }
2205
2206
0
                    if (arrayStart && arrayEnd) {
2207
0
                        do {
2208
0
                            if (!tok2->next())
2209
0
                                syntaxError(tok2); // can't recover so quit
2210
2211
0
                            if (!inCast && !inSizeof && !inTemplate)
2212
0
                                tok2 = tok2->next();
2213
2214
0
                            if (tok2->str() == "const")
2215
0
                                tok2 = tok2->next();
2216
2217
                            // reference or pointer to array?
2218
0
                            if (Token::Match(tok2, "&|*|&&")) {
2219
0
                                tok2 = tok2->previous();
2220
0
                                tok2->insertToken("(");
2221
0
                                Token *tok3 = tok2->next();
2222
2223
                                // handle missing variable name
2224
0
                                if (Token::Match(tok3, "( *|&|&& *|&|&& %name%"))
2225
0
                                    tok2 = tok3->tokAt(3);
2226
0
                                else if (Token::Match(tok2->tokAt(3), "[(),;]"))
2227
0
                                    tok2 = tok2->tokAt(2);
2228
0
                                else
2229
0
                                    tok2 = tok2->tokAt(3);
2230
0
                                if (!tok2)
2231
0
                                    syntaxError(nullptr);
2232
2233
0
                                while (tok2->strAt(1) == "::")
2234
0
                                    tok2 = tok2->tokAt(2);
2235
2236
                                // skip over function parameters
2237
0
                                if (tok2->str() == "(")
2238
0
                                    tok2 = tok2->link();
2239
2240
0
                                if (tok2->strAt(1) == "(")
2241
0
                                    tok2 = tok2->linkAt(1);
2242
2243
                                // skip over const/noexcept
2244
0
                                while (Token::Match(tok2->next(), "const|noexcept")) {
2245
0
                                    tok2 = tok2->next();
2246
0
                                    if (Token::Match(tok2->next(), "( true|false )"))
2247
0
                                        tok2 = tok2->tokAt(3);
2248
0
                                }
2249
2250
0
                                tok2->insertToken(")");
2251
0
                                tok2 = tok2->next();
2252
0
                                Token::createMutualLinks(tok2, tok3);
2253
0
                            }
2254
2255
0
                            if (!tok2->next())
2256
0
                                syntaxError(tok2); // can't recover so quit
2257
2258
                            // skip over array dimensions
2259
0
                            while (tok2->next()->str() == "[")
2260
0
                                tok2 = tok2->linkAt(1);
2261
2262
0
                            tok2 = TokenList::copyTokens(tok2, arrayStart, arrayEnd);
2263
0
                            if (!tok2->next())
2264
0
                                syntaxError(tok2);
2265
2266
0
                            if (tok2->str() == "=") {
2267
0
                                if (tok2->next()->str() == "{")
2268
0
                                    tok2 = tok2->next()->link()->next();
2269
0
                                else if (tok2->next()->str().at(0) == '\"')
2270
0
                                    tok2 = tok2->tokAt(2);
2271
0
                            }
2272
0
                        } while (Token::Match(tok2, ", %name% ;|=|,"));
2273
0
                    }
2274
2275
0
                    simplifyType = false;
2276
0
                }
2277
0
                if (!tok2)
2278
0
                    break;
2279
0
            }
2280
2281
0
            if (!tok)
2282
0
                syntaxError(nullptr);
2283
2284
0
            if (tok->str() == ";")
2285
0
                done = true;
2286
0
            else if (tok->str() == ",") {
2287
0
                arrayStart = nullptr;
2288
0
                arrayEnd = nullptr;
2289
0
                tokOffset = tok->next();
2290
0
                pointers.clear();
2291
2292
0
                while (Token::Match(tokOffset, "*|&")) {
2293
0
                    pointers.push_back(tokOffset->str());
2294
0
                    tokOffset = tokOffset->next();
2295
0
                }
2296
2297
0
                if (Token::Match(tokOffset, "%type%")) {
2298
0
                    typeName = tokOffset;
2299
0
                    tokOffset = tokOffset->next();
2300
2301
0
                    if (tokOffset && tokOffset->str() == "[") {
2302
0
                        arrayStart = tokOffset;
2303
2304
0
                        for (;;) {
2305
0
                            while (tokOffset->next() && !Token::Match(tokOffset->next(), ";|,"))
2306
0
                                tokOffset = tokOffset->next();
2307
2308
0
                            if (!tokOffset->next())
2309
0
                                return; // invalid input
2310
0
                            if (tokOffset->next()->str() == ";")
2311
0
                                break;
2312
0
                            if (tokOffset->str() == "]")
2313
0
                                break;
2314
0
                            tokOffset = tokOffset->next();
2315
0
                        }
2316
2317
0
                        arrayEnd = tokOffset;
2318
0
                        tokOffset = tokOffset->next();
2319
0
                    }
2320
2321
0
                    if (Token::Match(tokOffset, ";|,"))
2322
0
                        tok = tokOffset;
2323
0
                    else {
2324
                        // we encountered a typedef we don't support yet so just continue
2325
0
                        done = true;
2326
0
                        ok = false;
2327
0
                    }
2328
0
                } else {
2329
                    // we encountered a typedef we don't support yet so just continue
2330
0
                    done = true;
2331
0
                    ok = false;
2332
0
                }
2333
0
            } else {
2334
                // something is really wrong (internal error)
2335
0
                done = true;
2336
0
                ok = false;
2337
0
            }
2338
0
        }
2339
2340
0
        if (ok) {
2341
            // remove typedef
2342
0
            Token::eraseTokens(typeDef, tok);
2343
2344
0
            if (typeDef != list.front()) {
2345
0
                tok = typeDef->previous();
2346
0
                tok->deleteNext();
2347
                //no need to remove last token in the list
2348
0
                if (tok->tokAt(2))
2349
0
                    tok->deleteNext();
2350
0
            } else {
2351
0
                list.front()->deleteThis();
2352
                //no need to remove last token in the list
2353
0
                if (list.front()->next())
2354
0
                    list.front()->deleteThis();
2355
0
                tok = list.front();
2356
                //now the next token to process is 'tok', not 'tok->next()';
2357
0
                goback = true;
2358
0
            }
2359
0
        }
2360
0
    }
2361
1.36k
}
2362
2363
namespace {
2364
    struct ScopeInfo3 {
2365
        enum Type { Global, Namespace, Record, MemberFunction, Other };
2366
1.36k
        ScopeInfo3() : parent(nullptr), type(Global), bodyStart(nullptr), bodyEnd(nullptr) {}
2367
        ScopeInfo3(ScopeInfo3 *parent_, Type type_, std::string name_, const Token *bodyStart_, const Token *bodyEnd_)
2368
3.58k
            : parent(parent_), type(type_), name(std::move(name_)), bodyStart(bodyStart_), bodyEnd(bodyEnd_) {
2369
3.58k
            if (name.empty())
2370
3.58k
                return;
2371
0
            fullName = name;
2372
0
            ScopeInfo3 *scope = parent;
2373
0
            while (scope && scope->parent) {
2374
0
                if (scope->name.empty())
2375
0
                    break;
2376
0
                fullName = scope->name + " :: " + fullName;
2377
0
                scope = scope->parent;
2378
0
            }
2379
0
        }
2380
        ScopeInfo3 *parent;
2381
        std::list<ScopeInfo3> children;
2382
        Type type;
2383
        std::string fullName;
2384
        std::string name;
2385
        const Token * bodyStart;
2386
        const Token * bodyEnd;
2387
        std::set<std::string> usingNamespaces;
2388
        std::set<std::string> recordTypes;
2389
        std::set<std::string> baseTypes;
2390
2391
3.58k
        ScopeInfo3 *addChild(Type scopeType, const std::string &scopeName, const Token *bodyStartToken, const Token *bodyEndToken) {
2392
3.58k
            children.emplace_back(this, scopeType, scopeName, bodyStartToken, bodyEndToken);
2393
3.58k
            return &children.back();
2394
3.58k
        }
2395
2396
0
        bool hasChild(const std::string &childName) const {
2397
0
            return std::any_of(children.cbegin(), children.cend(), [&](const ScopeInfo3& child) {
2398
0
                return child.name == childName;
2399
0
            });
2400
0
        }
2401
2402
0
        const ScopeInfo3 * findInChildren(const std::string & scope) const {
2403
0
            for (const auto & child : children) {
2404
0
                if (child.type == Record && (child.name == scope || child.fullName == scope))
2405
0
                    return &child;
2406
2407
0
                const ScopeInfo3 * temp = child.findInChildren(scope);
2408
0
                if (temp)
2409
0
                    return temp;
2410
0
            }
2411
0
            return nullptr;
2412
0
        }
2413
2414
0
        const ScopeInfo3 * findScope(const std::string & scope) const {
2415
0
            const ScopeInfo3 * tempScope = this;
2416
0
            while (tempScope) {
2417
                // check children
2418
0
                auto it = std::find_if(tempScope->children.cbegin(), tempScope->children.cend(), [&](const ScopeInfo3& child) {
2419
0
                    return &child != this && child.type == Record && (child.name == scope || child.fullName == scope);
2420
0
                });
2421
0
                if (it != tempScope->children.end())
2422
0
                    return &*it;
2423
                // check siblings for same name
2424
0
                if (tempScope->parent) {
2425
0
                    for (const auto &sibling : tempScope->parent->children) {
2426
0
                        if (sibling.name == tempScope->name && &sibling != this) {
2427
0
                            const ScopeInfo3 * temp = sibling.findInChildren(scope);
2428
0
                            if (temp)
2429
0
                                return temp;
2430
0
                        }
2431
0
                    }
2432
0
                }
2433
0
                tempScope = tempScope->parent;
2434
0
            }
2435
0
            return nullptr;
2436
0
        }
2437
2438
0
        bool findTypeInBase(const std::string &scope) const {
2439
0
            if (scope.empty())
2440
0
                return false;
2441
            // check in base types first
2442
0
            if (baseTypes.find(scope) != baseTypes.end())
2443
0
                return true;
2444
            // check in base types base types
2445
0
            for (const std::string & base : baseTypes) {
2446
0
                const ScopeInfo3 * baseScope = findScope(base);
2447
                // bail on uninstantiated recursive template
2448
0
                if (baseScope == this)
2449
0
                    return false;
2450
0
                if (baseScope && baseScope->fullName == scope)
2451
0
                    return true;
2452
0
                if (baseScope && baseScope->findTypeInBase(scope))
2453
0
                    return true;
2454
0
            }
2455
0
            return false;
2456
0
        }
2457
2458
0
        ScopeInfo3 * findScope(const ScopeInfo3 * scope) {
2459
0
            if (scope->bodyStart == bodyStart)
2460
0
                return this;
2461
0
            for (auto & child : children) {
2462
0
                ScopeInfo3 * temp = child.findScope(scope);
2463
0
                if (temp)
2464
0
                    return temp;
2465
0
            }
2466
0
            return nullptr;
2467
0
        }
2468
    };
2469
2470
    void setScopeInfo(Token *tok, ScopeInfo3 **scopeInfo, bool debug=false)
2471
7.17k
    {
2472
7.17k
        if (!tok)
2473
0
            return;
2474
7.17k
        if (tok->str() == "{" && (*scopeInfo)->parent && tok == (*scopeInfo)->bodyStart)
2475
0
            return;
2476
7.17k
        if (tok->str() == "}") {
2477
3.58k
            if ((*scopeInfo)->parent && tok == (*scopeInfo)->bodyEnd)
2478
3.58k
                *scopeInfo = (*scopeInfo)->parent;
2479
0
            else {
2480
                // Try to find parent scope
2481
0
                ScopeInfo3 *parent = (*scopeInfo)->parent;
2482
0
                while (parent && parent->bodyEnd != tok)
2483
0
                    parent = parent->parent;
2484
0
                if (parent) {
2485
0
                    *scopeInfo = parent;
2486
0
                    if (debug)
2487
0
                        throw std::runtime_error("Internal error: unmatched }");
2488
0
                }
2489
0
            }
2490
3.58k
            return;
2491
3.58k
        }
2492
3.58k
        if (!Token::Match(tok, "namespace|class|struct|union %name% {|:|::|<")) {
2493
            // check for using namespace
2494
3.58k
            if (Token::Match(tok, "using namespace %name% ;|::")) {
2495
0
                const Token * tok1 = tok->tokAt(2);
2496
0
                std::string nameSpace;
2497
0
                while (tok1 && tok1->str() != ";") {
2498
0
                    if (!nameSpace.empty())
2499
0
                        nameSpace += " ";
2500
0
                    nameSpace += tok1->str();
2501
0
                    tok1 = tok1->next();
2502
0
                }
2503
0
                (*scopeInfo)->usingNamespaces.insert(std::move(nameSpace));
2504
0
            }
2505
            // check for member function
2506
3.58k
            else if (tok->str() == "{") {
2507
3.58k
                bool added = false;
2508
3.58k
                Token *tok1 = tok;
2509
3.58k
                while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
2510
0
                    tok1 = tok1->previous();
2511
3.58k
                if (tok1->previous() && (tok1->strAt(-1) == ")" || tok->strAt(-1) == "}")) {
2512
3.12k
                    tok1 = tok1->linkAt(-1);
2513
3.12k
                    if (Token::Match(tok1->previous(), "throw|noexcept (")) {
2514
0
                        tok1 = tok1->previous();
2515
0
                        while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
2516
0
                            tok1 = tok1->previous();
2517
0
                        if (tok1->strAt(-1) != ")")
2518
0
                            return;
2519
0
                        tok1 = tok1->linkAt(-1);
2520
3.12k
                    } else {
2521
3.12k
                        while (Token::Match(tok1->tokAt(-2), ":|, %name%")) {
2522
0
                            tok1 = tok1->tokAt(-2);
2523
0
                            if (tok1->strAt(-1) != ")" && tok1->strAt(-1) != "}")
2524
0
                                return;
2525
0
                            tok1 = tok1->linkAt(-1);
2526
0
                        }
2527
3.12k
                    }
2528
3.12k
                    if (tok1->strAt(-1) == ">")
2529
0
                        tok1 = tok1->previous()->findOpeningBracket();
2530
3.12k
                    if (tok1 && (Token::Match(tok1->tokAt(-3), "%name% :: %name%") ||
2531
3.12k
                                 Token::Match(tok1->tokAt(-4), "%name% :: ~ %name%"))) {
2532
0
                        tok1 = tok1->tokAt(-2);
2533
0
                        if (tok1->str() == "~")
2534
0
                            tok1 = tok1->previous();
2535
0
                        std::string scope = tok1->strAt(-1);
2536
0
                        while (Token::Match(tok1->tokAt(-2), ":: %name%")) {
2537
0
                            scope = tok1->strAt(-3) + " :: " + scope;
2538
0
                            tok1 = tok1->tokAt(-2);
2539
0
                        }
2540
0
                        *scopeInfo = (*scopeInfo)->addChild(ScopeInfo3::MemberFunction, scope, tok, tok->link());
2541
0
                        added = true;
2542
0
                    }
2543
3.12k
                }
2544
2545
3.58k
                if (!added)
2546
3.58k
                    *scopeInfo = (*scopeInfo)->addChild(ScopeInfo3::Other, emptyString, tok, tok->link());
2547
3.58k
            }
2548
3.58k
            return;
2549
3.58k
        }
2550
2551
0
        const bool record = Token::Match(tok, "class|struct|union %name%");
2552
0
        tok = tok->next();
2553
0
        std::string classname = tok->str();
2554
0
        while (Token::Match(tok, "%name% :: %name%")) {
2555
0
            tok = tok->tokAt(2);
2556
0
            classname += " :: " + tok->str();
2557
0
        }
2558
2559
        // add record type to scope info
2560
0
        if (record)
2561
0
            (*scopeInfo)->recordTypes.insert(classname);
2562
0
        tok = tok->next();
2563
2564
        // skip template parameters
2565
0
        if (tok && tok->str() == "<") {
2566
0
            tok = tok->findClosingBracket();
2567
0
            if (tok)
2568
0
                tok = tok->next();
2569
0
        }
2570
2571
        // get base class types
2572
0
        std::set<std::string> baseTypes;
2573
0
        if (tok && tok->str() == ":") {
2574
0
            do {
2575
0
                tok = tok->next();
2576
0
                while (Token::Match(tok, "public|protected|private|virtual"))
2577
0
                    tok = tok->next();
2578
0
                std::string base;
2579
0
                while (tok && !Token::Match(tok, ";|,|{")) {
2580
0
                    if (!base.empty())
2581
0
                        base += ' ';
2582
0
                    base += tok->str();
2583
0
                    tok = tok->next();
2584
                    // add template parameters
2585
0
                    if (tok && tok->str() == "<") {
2586
0
                        const Token* endTok = tok->findClosingBracket();
2587
0
                        if (endTok) {
2588
0
                            endTok = endTok->next();
2589
0
                            while (tok != endTok) {
2590
0
                                base += tok->str();
2591
0
                                tok = tok->next();
2592
0
                            }
2593
0
                        }
2594
0
                    }
2595
0
                }
2596
0
                baseTypes.insert(std::move(base));
2597
0
            } while (tok && !Token::Match(tok, ";|{"));
2598
0
        }
2599
2600
0
        if (tok && tok->str() == "{") {
2601
0
            *scopeInfo = (*scopeInfo)->addChild(record ? ScopeInfo3::Record : ScopeInfo3::Namespace, classname, tok, tok->link());
2602
0
            (*scopeInfo)->baseTypes = baseTypes;
2603
0
        }
2604
0
    }
2605
2606
    Token *findSemicolon(Token *tok)
2607
0
    {
2608
0
        int level = 0;
2609
2610
0
        for (; tok && (level > 0 || tok->str() != ";"); tok = tok->next()) {
2611
0
            if (tok->str() == "{")
2612
0
                ++level;
2613
0
            else if (level > 0 && tok->str() == "}")
2614
0
                --level;
2615
0
        }
2616
2617
0
        return tok;
2618
0
    }
2619
2620
    bool usingMatch(
2621
        const Token *nameToken,
2622
        const std::string &scope,
2623
        Token **tok,
2624
        const std::string &scope1,
2625
        const ScopeInfo3 *currentScope,
2626
        const ScopeInfo3 *memberClassScope)
2627
0
    {
2628
0
        Token *tok1 = *tok;
2629
2630
0
        if (tok1 && tok1->str() != nameToken->str())
2631
0
            return false;
2632
2633
        // skip this using
2634
0
        if (tok1 == nameToken) {
2635
0
            *tok = findSemicolon(tok1);
2636
0
            return false;
2637
0
        }
2638
2639
        // skip other using with this name
2640
0
        if (tok1->strAt(-1) == "using") {
2641
            // fixme: this is wrong
2642
            // skip to end of scope
2643
0
            if (currentScope->bodyEnd)
2644
0
                *tok = const_cast<Token*>(currentScope->bodyEnd->previous());
2645
0
            return false;
2646
0
        }
2647
2648
0
        if (Token::Match(tok1->tokAt(-1), "class|struct|union|enum|namespace")) {
2649
            // fixme
2650
0
            return false;
2651
0
        }
2652
2653
        // get qualification
2654
0
        std::string qualification;
2655
0
        const Token* tok2 = tok1;
2656
0
        std::string::size_type index = scope.size();
2657
0
        std::string::size_type new_index = std::string::npos;
2658
0
        bool match = true;
2659
0
        while (Token::Match(tok2->tokAt(-2), "%name% ::") && !tok2->tokAt(-2)->isKeyword()) {
2660
0
            std::string last;
2661
0
            if (match && !scope1.empty()) {
2662
0
                new_index = scope1.rfind(' ', index - 1);
2663
0
                if (new_index != std::string::npos)
2664
0
                    last = scope1.substr(new_index, index - new_index);
2665
0
                else if (!qualification.empty())
2666
0
                    last.clear();
2667
0
                else
2668
0
                    last = scope1;
2669
0
            } else
2670
0
                match = false;
2671
0
            if (match && tok2->strAt(-2) == last)
2672
0
                index = new_index;
2673
0
            else {
2674
0
                if (!qualification.empty())
2675
0
                    qualification = " :: " + qualification;
2676
0
                qualification = tok2->strAt(-2) + qualification;
2677
0
            }
2678
0
            tok2 = tok2->tokAt(-2);
2679
0
        }
2680
2681
0
        std::string fullScope1 = scope1;
2682
0
        if (!scope1.empty() && !qualification.empty())
2683
0
            fullScope1 += " :: ";
2684
0
        fullScope1 += qualification;
2685
2686
0
        if (scope == fullScope1)
2687
0
            return true;
2688
2689
0
        const ScopeInfo3 *scopeInfo = memberClassScope ? memberClassScope : currentScope;
2690
2691
        // check in base types
2692
0
        if (qualification.empty() && scopeInfo->findTypeInBase(scope))
2693
0
            return true;
2694
2695
        // check using namespace
2696
0
        const ScopeInfo3 * tempScope = scopeInfo;
2697
0
        while (tempScope) {
2698
            //if (!tempScope->parent->usingNamespaces.empty()) {
2699
0
            const std::set<std::string>& usingNS = tempScope->usingNamespaces;
2700
0
            if (!usingNS.empty()) {
2701
0
                if (qualification.empty()) {
2702
0
                    if (usingNS.find(scope) != usingNS.end())
2703
0
                        return true;
2704
0
                } else {
2705
0
                    const std::string suffix = " :: " + qualification;
2706
0
                    if (std::any_of(usingNS.cbegin(), usingNS.cend(), [&](const std::string& ns) {
2707
0
                        return scope == ns + suffix;
2708
0
                    }))
2709
0
                        return true;
2710
0
                }
2711
0
            }
2712
0
            tempScope = tempScope->parent;
2713
0
        }
2714
2715
0
        std::string newScope1 = scope1;
2716
2717
        // scopes didn't match so try higher scopes
2718
0
        index = newScope1.size();
2719
0
        while (!newScope1.empty()) {
2720
0
            const std::string::size_type separator = newScope1.rfind(" :: ", index - 1);
2721
0
            if (separator != std::string::npos)
2722
0
                newScope1.resize(separator);
2723
0
            else
2724
0
                newScope1.clear();
2725
2726
0
            std::string newFullScope1 = newScope1;
2727
0
            if (!newScope1.empty() && !qualification.empty())
2728
0
                newFullScope1 += " :: ";
2729
0
            newFullScope1 += qualification;
2730
2731
0
            if (scope == newFullScope1)
2732
0
                return true;
2733
0
        }
2734
2735
0
        return false;
2736
0
    }
2737
2738
    std::string memberFunctionScope(const Token *tok)
2739
0
    {
2740
0
        std::string qualification;
2741
0
        const Token *qualTok = tok->strAt(-2) == "~" ? tok->tokAt(-4) : tok->tokAt(-3);
2742
0
        while (Token::Match(qualTok, "%type% ::")) {
2743
0
            if (!qualification.empty())
2744
0
                qualification = " :: " + qualification;
2745
0
            qualification = qualTok->str() + qualification;
2746
0
            qualTok = qualTok->tokAt(-2);
2747
0
        }
2748
0
        return qualification;
2749
0
    }
2750
2751
    const Token * memberFunctionEnd(const Token *tok)
2752
0
    {
2753
0
        if (tok->str() != "(")
2754
0
            return nullptr;
2755
0
        const Token *end = tok->link()->next();
2756
0
        while (end) {
2757
0
            if (end->str() == "{" && !Token::Match(end->tokAt(-2), ":|, %name%"))
2758
0
                return end;
2759
0
            if (end->str() == ";")
2760
0
                break;
2761
0
            end = end->next();
2762
0
        }
2763
0
        return nullptr;
2764
0
    }
2765
} // namespace
2766
2767
bool Tokenizer::isMemberFunction(const Token *openParen) const
2768
0
{
2769
0
    return (Token::Match(openParen->tokAt(-2), ":: %name% (") ||
2770
0
            Token::Match(openParen->tokAt(-3), ":: ~ %name% (")) &&
2771
0
           isFunctionHead(openParen, "{|:");
2772
0
}
2773
2774
static bool scopesMatch(const std::string &scope1, const std::string &scope2, const ScopeInfo3 *globalScope)
2775
0
{
2776
0
    if (scope1.empty() || scope2.empty())
2777
0
        return false;
2778
2779
    // check if scopes match
2780
0
    if (scope1 == scope2)
2781
0
        return true;
2782
2783
    // check if scopes only differ by global qualification
2784
0
    if (scope1 == (":: " + scope2)) {
2785
0
        std::string::size_type end = scope2.find_first_of(' ');
2786
0
        if (end == std::string::npos)
2787
0
            end = scope2.size();
2788
0
        if (globalScope->hasChild(scope2.substr(0, end)))
2789
0
            return true;
2790
0
    } else if (scope2 == (":: " + scope1)) {
2791
0
        std::string::size_type end = scope1.find_first_of(' ');
2792
0
        if (end == std::string::npos)
2793
0
            end = scope1.size();
2794
0
        if (globalScope->hasChild(scope1.substr(0, end)))
2795
0
            return true;
2796
0
    }
2797
2798
0
    return false;
2799
0
}
2800
2801
0
static unsigned int tokDistance(const Token* tok1, const Token* tok2) {
2802
0
    unsigned int dist = 0;
2803
0
    const Token* tok = tok1;
2804
0
    while (tok != tok2) {
2805
0
        ++dist;
2806
0
        tok = tok->next();
2807
0
    }
2808
0
    return dist;
2809
0
}
2810
2811
bool Tokenizer::simplifyUsing()
2812
1.36k
{
2813
1.36k
    if (!isCPP() || mSettings->standards.cpp < Standards::CPP11)
2814
0
        return false;
2815
2816
1.36k
    const unsigned int maxReplacementTokens = 1000; // limit the number of tokens we replace
2817
2818
1.36k
    bool substitute = false;
2819
1.36k
    ScopeInfo3 scopeInfo;
2820
1.36k
    ScopeInfo3 *currentScope = &scopeInfo;
2821
1.36k
    struct Using {
2822
1.36k
        Using(Token *start, Token *end) : startTok(start), endTok(end) {}
2823
1.36k
        Token *startTok;
2824
1.36k
        Token *endTok;
2825
1.36k
    };
2826
1.36k
    std::list<Using> usingList;
2827
2828
94.1k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
2829
92.7k
        if (mErrorLogger && !list.getFiles().empty())
2830
92.7k
            mErrorLogger->reportProgress(list.getFiles()[0], "Tokenize (using)", tok->progressValue());
2831
2832
92.7k
        if (Settings::terminated())
2833
0
            return substitute;
2834
2835
92.7k
        if (Token::Match(tok, "enum class|struct")) {
2836
0
            Token *bodyStart = tok;
2837
0
            while (Token::Match(bodyStart, "%name%|:|::|<")) {
2838
0
                if (bodyStart->str() == "<")
2839
0
                    bodyStart = bodyStart->findClosingBracket();
2840
0
                bodyStart = bodyStart ? bodyStart->next() : nullptr;
2841
0
            }
2842
0
            if (Token::simpleMatch(bodyStart, "{"))
2843
0
                tok = bodyStart->link();
2844
0
            continue;
2845
0
        }
2846
2847
92.7k
        if (Token::Match(tok, "{|}|namespace|class|struct|union") ||
2848
92.7k
            Token::Match(tok, "using namespace %name% ;|::")) {
2849
7.17k
            try {
2850
7.17k
                setScopeInfo(tok, &currentScope, mSettings->debugwarnings);
2851
7.17k
            } catch (const std::runtime_error &) {
2852
0
                reportError(tok, Severity::debug, "simplifyUsingUnmatchedBodyEnd",
2853
0
                            "simplifyUsing: unmatched body end");
2854
0
            }
2855
7.17k
            continue;
2856
7.17k
        }
2857
2858
        // skip template declarations
2859
85.5k
        if (Token::Match(tok, "template < !!>")) {
2860
            // add template record type to scope info
2861
0
            const Token *end = tok->next()->findClosingBracket();
2862
0
            if (end && Token::Match(end->next(), "class|struct|union %name%"))
2863
0
                currentScope->recordTypes.insert(end->strAt(2));
2864
2865
0
            Token *declEndToken = TemplateSimplifier::findTemplateDeclarationEnd(tok);
2866
0
            if (declEndToken)
2867
0
                tok = declEndToken;
2868
0
            continue;
2869
0
        }
2870
2871
        // look for non-template type aliases
2872
85.5k
        if (!(tok->strAt(-1) != ">" &&
2873
85.5k
              (Token::Match(tok, "using %name% = ::| %name%") ||
2874
85.0k
               (Token::Match(tok, "using %name% [ [") &&
2875
85.0k
                Token::Match(tok->linkAt(2), "] ] = ::| %name%")))))
2876
85.5k
            continue;
2877
2878
0
        const std::string& name = tok->strAt(1);
2879
0
        const Token *nameToken = tok->next();
2880
0
        std::string scope = currentScope->fullName;
2881
0
        Token *usingStart = tok;
2882
0
        Token *start;
2883
0
        if (tok->strAt(2) == "=")
2884
0
            start = tok->tokAt(3);
2885
0
        else
2886
0
            start = tok->linkAt(2)->tokAt(3);
2887
0
        Token *usingEnd = findSemicolon(start);
2888
0
        if (!usingEnd)
2889
0
            continue;
2890
2891
        // Move struct defined in using out of using.
2892
        // using T = struct t { }; => struct t { }; using T = struct t;
2893
        // fixme: this doesn't handle attributes
2894
0
        if (Token::Match(start, "class|struct|union|enum %name%| {|:")) {
2895
0
            Token *structEnd = start->tokAt(1);
2896
0
            const bool hasName = Token::Match(structEnd, "%name%");
2897
2898
            // skip over name if present
2899
0
            if (hasName)
2900
0
                structEnd = structEnd->next();
2901
2902
            // skip over base class information
2903
0
            if (structEnd->str() == ":") {
2904
0
                structEnd = structEnd->next(); // skip over ":"
2905
0
                while (structEnd && structEnd->str() != "{")
2906
0
                    structEnd = structEnd->next();
2907
0
                if (!structEnd)
2908
0
                    continue;
2909
0
            }
2910
2911
            // use link to go to end
2912
0
            structEnd = structEnd->link();
2913
2914
            // add ';' after end of struct
2915
0
            structEnd->insertToken(";", emptyString);
2916
2917
            // add name for anonymous struct
2918
0
            if (!hasName) {
2919
0
                std::string newName;
2920
0
                if (structEnd->strAt(2) == ";")
2921
0
                    newName = name;
2922
0
                else
2923
0
                    newName = "Unnamed" + std::to_string(mUnnamedCount++);
2924
0
                TokenList::copyTokens(structEnd->next(), tok, start);
2925
0
                structEnd->tokAt(5)->insertToken(newName, emptyString);
2926
0
                start->insertToken(newName, emptyString);
2927
0
            } else
2928
0
                TokenList::copyTokens(structEnd->next(), tok, start->next());
2929
2930
            // add using after end of struct
2931
0
            usingStart = structEnd->tokAt(2);
2932
0
            nameToken = usingStart->next();
2933
0
            if (usingStart->strAt(2) == "=")
2934
0
                start = usingStart->tokAt(3);
2935
0
            else
2936
0
                start = usingStart->linkAt(2)->tokAt(3);
2937
0
            usingEnd = findSemicolon(start);
2938
2939
            // delete original using before struct
2940
0
            tok->deleteThis();
2941
0
            tok->deleteThis();
2942
0
            tok->deleteThis();
2943
0
            tok = usingStart;
2944
0
        }
2945
2946
        // remove 'typename' and 'template'
2947
0
        else if (start->str() == "typename") {
2948
0
            start->deleteThis();
2949
0
            Token *temp = start;
2950
0
            while (Token::Match(temp, "%name% ::"))
2951
0
                temp = temp->tokAt(2);
2952
0
            if (Token::Match(temp, "template %name%"))
2953
0
                temp->deleteThis();
2954
0
        }
2955
2956
0
        if (usingEnd)
2957
0
            tok = usingEnd;
2958
2959
        // Unfortunately we have to start searching from the beginning
2960
        // of the token stream because templates are instantiated at
2961
        // the end of the token stream and it may be used before then.
2962
0
        ScopeInfo3 scopeInfo1;
2963
0
        ScopeInfo3 *currentScope1 = &scopeInfo1;
2964
0
        Token *startToken = list.front();
2965
0
        Token *endToken = nullptr;
2966
0
        bool inMemberFunc = false;
2967
0
        const ScopeInfo3 * memberFuncScope = nullptr;
2968
0
        const Token * memberFuncEnd = nullptr;
2969
2970
        // We can limit the search to the current function when the type alias
2971
        // is defined in that function.
2972
0
        if (currentScope->type == ScopeInfo3::Other ||
2973
0
            currentScope->type == ScopeInfo3::MemberFunction) {
2974
0
            scopeInfo1 = scopeInfo;
2975
0
            currentScope1 = scopeInfo1.findScope(currentScope);
2976
0
            if (!currentScope1)
2977
0
                return substitute; // something bad happened
2978
0
            startToken = usingEnd->next();
2979
0
            endToken = const_cast<Token*>(currentScope->bodyEnd->next());
2980
0
            if (currentScope->type == ScopeInfo3::MemberFunction) {
2981
0
                const ScopeInfo3 * temp = currentScope->findScope(currentScope->fullName);
2982
0
                if (temp) {
2983
0
                    inMemberFunc = true;
2984
0
                    memberFuncScope = temp;
2985
0
                    memberFuncEnd = endToken;
2986
0
                }
2987
0
            }
2988
0
        }
2989
2990
0
        std::string scope1 = currentScope1->fullName;
2991
0
        bool skip = false; // don't erase type aliases we can't parse
2992
0
        Token *enumOpenBrace = nullptr;
2993
0
        for (Token* tok1 = startToken; !skip && tok1 && tok1 != endToken; tok1 = tok1->next()) {
2994
            // skip enum body
2995
0
            if (tok1 && tok1 == enumOpenBrace) {
2996
0
                tok1 = tok1->link();
2997
0
                enumOpenBrace = nullptr;
2998
0
                continue;
2999
0
            }
3000
3001
0
            if ((Token::Match(tok1, "{|}|namespace|class|struct|union") && tok1->strAt(-1) != "using") ||
3002
0
                Token::Match(tok1, "using namespace %name% ;|::")) {
3003
0
                try {
3004
0
                    setScopeInfo(tok1, &currentScope1, mSettings->debugwarnings);
3005
0
                } catch (const std::runtime_error &) {
3006
0
                    reportError(tok1, Severity::debug, "simplifyUsingUnmatchedBodyEnd",
3007
0
                                "simplifyUsing: unmatched body end");
3008
0
                }
3009
0
                scope1 = currentScope1->fullName;
3010
0
                if (inMemberFunc && memberFuncEnd && tok1 == memberFuncEnd) {
3011
0
                    inMemberFunc = false;
3012
0
                    memberFuncScope = nullptr;
3013
0
                    memberFuncEnd = nullptr;
3014
0
                }
3015
0
                continue;
3016
0
            }
3017
3018
            // skip template definitions
3019
0
            if (Token::Match(tok1, "template < !!>")) {
3020
0
                Token *declEndToken = TemplateSimplifier::findTemplateDeclarationEnd(tok1);
3021
0
                if (declEndToken)
3022
0
                    tok1 = declEndToken;
3023
0
                continue;
3024
0
            }
3025
3026
            // check for enum with body
3027
0
            if (tok1->str() == "enum") {
3028
0
                if (Token::Match(tok1, "enum class|struct"))
3029
0
                    tok1 = tok1->next();
3030
0
                Token *defStart = tok1;
3031
0
                while (Token::Match(defStart, "%name%|::|:"))
3032
0
                    defStart = defStart->next();
3033
0
                if (Token::simpleMatch(defStart, "{"))
3034
0
                    enumOpenBrace = defStart;
3035
0
                continue;
3036
0
            }
3037
3038
            // check for member function and adjust scope
3039
0
            if (isMemberFunction(tok1)) {
3040
0
                if (!scope1.empty())
3041
0
                    scope1 += " :: ";
3042
0
                scope1 += memberFunctionScope(tok1);
3043
0
                const ScopeInfo3 * temp = currentScope1->findScope(scope1);
3044
0
                if (temp) {
3045
0
                    const Token *end = memberFunctionEnd(tok1);
3046
0
                    if (end) {
3047
0
                        inMemberFunc = true;
3048
0
                        memberFuncScope = temp;
3049
0
                        memberFuncEnd = end;
3050
0
                    }
3051
0
                }
3052
0
                continue;
3053
0
            }
3054
0
            if (inMemberFunc && memberFuncScope) {
3055
0
                if (!usingMatch(nameToken, scope, &tok1, scope1, currentScope1, memberFuncScope))
3056
0
                    continue;
3057
0
            } else if (!usingMatch(nameToken, scope, &tok1, scope1, currentScope1, nullptr))
3058
0
                continue;
3059
3060
0
            const auto nReplace = tokDistance(start, usingEnd);
3061
0
            if (nReplace > maxReplacementTokens) {
3062
0
                simplifyUsingError(usingStart, usingEnd);
3063
0
                continue;
3064
0
            }
3065
3066
            // remove the qualification
3067
0
            std::string fullScope = scope;
3068
0
            std::string removed;
3069
0
            while (Token::Match(tok1->tokAt(-2), "%name% ::") && !tok1->tokAt(-2)->isKeyword()) {
3070
0
                removed = (tok1->strAt(-2) + " :: ") + removed;
3071
0
                if (fullScope == tok1->strAt(-2)) {
3072
0
                    tok1->deletePrevious();
3073
0
                    tok1->deletePrevious();
3074
0
                    break;
3075
0
                }
3076
0
                const std::string::size_type idx = fullScope.rfind("::");
3077
3078
0
                if (idx == std::string::npos)
3079
0
                    break;
3080
3081
0
                if (tok1->strAt(-2) == fullScope.substr(idx + 3)) {
3082
0
                    tok1->deletePrevious();
3083
0
                    tok1->deletePrevious();
3084
0
                    fullScope.resize(idx - 1);
3085
0
                } else
3086
0
                    break;
3087
0
            }
3088
3089
            // remove global namespace if present
3090
0
            if (tok1->strAt(-1) == "::") {
3091
0
                removed.insert(0, ":: ");
3092
0
                tok1->deletePrevious();
3093
0
            }
3094
3095
0
            Token * arrayStart = nullptr;
3096
3097
            // parse the type
3098
0
            Token *type = start;
3099
0
            if (type->str() == "::") {
3100
0
                type = type->next();
3101
0
                while (Token::Match(type, "%type% ::"))
3102
0
                    type = type->tokAt(2);
3103
0
                if (Token::Match(type, "%type%"))
3104
0
                    type = type->next();
3105
0
            } else if (Token::Match(type, "%type% ::")) {
3106
0
                do {
3107
0
                    type = type->tokAt(2);
3108
0
                } while (Token::Match(type, "%type% ::"));
3109
0
                if (Token::Match(type, "%type%"))
3110
0
                    type = type->next();
3111
0
            } else if (Token::Match(type, "%type%")) {
3112
0
                while (Token::Match(type, "const|class|struct|union|enum %type%") ||
3113
0
                       (type->next() && type->next()->isStandardType()))
3114
0
                    type = type->next();
3115
3116
0
                type = type->next();
3117
3118
0
                while (Token::Match(type, "%type%") &&
3119
0
                       (type->isStandardType() || Token::Match(type, "unsigned|signed"))) {
3120
0
                    type = type->next();
3121
0
                }
3122
3123
0
                bool atEnd = false;
3124
0
                while (!atEnd) {
3125
0
                    if (type && type->str() == "::") {
3126
0
                        type = type->next();
3127
0
                    }
3128
3129
0
                    if (Token::Match(type, "%type%") &&
3130
0
                        type->next() && !Token::Match(type->next(), "[|,|(")) {
3131
0
                        type = type->next();
3132
0
                    } else if (Token::simpleMatch(type, "const (")) {
3133
0
                        type = type->next();
3134
0
                        atEnd = true;
3135
0
                    } else
3136
0
                        atEnd = true;
3137
0
                }
3138
0
            } else
3139
0
                syntaxError(type);
3140
3141
            // check for invalid input
3142
0
            if (!type)
3143
0
                syntaxError(tok1);
3144
3145
            // check for template
3146
0
            if (type->str() == "<") {
3147
0
                type = type->findClosingBracket();
3148
3149
0
                while (type && Token::Match(type->next(), ":: %type%"))
3150
0
                    type = type->tokAt(2);
3151
3152
0
                if (!type) {
3153
0
                    syntaxError(tok1);
3154
0
                }
3155
3156
0
                while (Token::Match(type->next(), "const|volatile"))
3157
0
                    type = type->next();
3158
3159
0
                type = type->next();
3160
0
            }
3161
3162
            // check for pointers and references
3163
0
            std::list<std::string> pointers;
3164
0
            while (Token::Match(type, "*|&|&&|const")) {
3165
0
                pointers.push_back(type->str());
3166
0
                type = type->next();
3167
0
            }
3168
3169
            // check for array
3170
0
            if (type && type->str() == "[") {
3171
0
                do {
3172
0
                    if (!arrayStart)
3173
0
                        arrayStart = type;
3174
3175
0
                    bool atEnd = false;
3176
0
                    while (!atEnd) {
3177
0
                        while (type->next() && !Token::Match(type->next(), ";|,")) {
3178
0
                            type = type->next();
3179
0
                        }
3180
3181
0
                        if (!type->next())
3182
0
                            syntaxError(type); // invalid input
3183
0
                        else if (type->next()->str() == ";")
3184
0
                            atEnd = true;
3185
0
                        else if (type->str() == "]")
3186
0
                            atEnd = true;
3187
0
                        else
3188
0
                            type = type->next();
3189
0
                    }
3190
3191
0
                    type = type->next();
3192
0
                } while (type && type->str() == "[");
3193
0
            }
3194
3195
            // make sure we are in a good state
3196
0
            if (!tok1 || !tok1->next())
3197
0
                break; // bail
3198
3199
0
            Token* after = tok1->next();
3200
            // check if type was parsed
3201
0
            if (type && type == usingEnd) {
3202
                // check for array syntax and add type around variable
3203
0
                if (arrayStart) {
3204
0
                    if (Token::Match(tok1->next(), "%name%")) {
3205
0
                        TokenList::copyTokens(tok1->next(), arrayStart, usingEnd->previous());
3206
0
                        TokenList::copyTokens(tok1, start, arrayStart->previous());
3207
0
                        tok1->deleteThis();
3208
0
                        substitute = true;
3209
0
                    }
3210
0
                } else {
3211
                    // add some qualification back if needed
3212
0
                    std::string removed1 = removed;
3213
0
                    std::string::size_type idx = removed1.rfind(" ::");
3214
0
                    if (idx != std::string::npos)
3215
0
                        removed1.resize(idx);
3216
0
                    if (scopesMatch(removed1, scope, &scopeInfo1)) {
3217
0
                        ScopeInfo3 * tempScope = currentScope;
3218
0
                        while (tempScope->parent) {
3219
0
                            if (tempScope->recordTypes.find(start->str()) != tempScope->recordTypes.end()) {
3220
0
                                std::string::size_type spaceIdx = 0;
3221
0
                                std::string::size_type startIdx = 0;
3222
0
                                while ((spaceIdx = removed1.find(' ', startIdx)) != std::string::npos) {
3223
0
                                    tok1->previous()->insertToken(removed1.substr(startIdx, spaceIdx - startIdx));
3224
0
                                    startIdx = spaceIdx + 1;
3225
0
                                }
3226
0
                                tok1->previous()->insertToken(removed1.substr(startIdx));
3227
0
                                tok1->previous()->insertToken("::");
3228
0
                                break;
3229
0
                            }
3230
0
                            idx = removed1.rfind(" ::");
3231
0
                            if (idx == std::string::npos)
3232
0
                                break;
3233
3234
0
                            removed1.resize(idx);
3235
0
                            tempScope = tempScope->parent;
3236
0
                        }
3237
0
                    }
3238
3239
                    // Is this a "T()" expression where T is a pointer type?
3240
0
                    if (Token::Match(tok1, "%name% ( )") && !pointers.empty()) {
3241
0
                        Token* tok2 = tok1->linkAt(1);
3242
0
                        tok1->deleteThis();
3243
0
                        TokenList::copyTokens(tok1, start, usingEnd->previous());
3244
0
                        tok2->insertToken("0");
3245
0
                        after = tok2->next();
3246
0
                    }
3247
0
                    else { // just replace simple type aliases
3248
0
                        TokenList::copyTokens(tok1, start, usingEnd->previous());
3249
0
                        tok1->deleteThis();
3250
0
                    }
3251
0
                    substitute = true;
3252
0
                }
3253
0
            } else {
3254
0
                skip = true;
3255
0
                simplifyUsingError(usingStart, usingEnd);
3256
0
            }
3257
0
            tok1 = after->previous();
3258
0
        }
3259
3260
0
        if (!skip)
3261
0
            usingList.emplace_back(usingStart, usingEnd);
3262
0
    }
3263
3264
    // delete all used type alias definitions
3265
1.36k
    for (std::list<Using>::reverse_iterator it = usingList.rbegin(); it != usingList.rend(); ++it) {
3266
0
        Token *usingStart = it->startTok;
3267
0
        Token *usingEnd = it->endTok;
3268
0
        if (usingStart->previous()) {
3269
0
            if (usingEnd->next())
3270
0
                Token::eraseTokens(usingStart->previous(), usingEnd->next());
3271
0
            else {
3272
0
                Token::eraseTokens(usingStart->previous(), usingEnd);
3273
0
                usingEnd->deleteThis();
3274
0
            }
3275
0
        } else {
3276
0
            if (usingEnd->next()) {
3277
0
                Token::eraseTokens(usingStart, usingEnd->next());
3278
0
                usingStart->deleteThis();
3279
0
            } else {
3280
                // this is the only code being checked so leave ';'
3281
0
                Token::eraseTokens(usingStart, usingEnd);
3282
0
                usingStart->deleteThis();
3283
0
            }
3284
0
        }
3285
0
    }
3286
3287
1.36k
    return substitute;
3288
1.36k
}
3289
3290
void Tokenizer::simplifyUsingError(const Token* usingStart, const Token* usingEnd)
3291
0
{
3292
0
    if (mSettings->debugwarnings && mErrorLogger) {
3293
0
        std::string str;
3294
0
        for (const Token *tok = usingStart; tok && tok != usingEnd; tok = tok->next()) {
3295
0
            if (!str.empty())
3296
0
                str += ' ';
3297
0
            str += tok->str();
3298
0
        }
3299
0
        str += " ;";
3300
0
        std::list<const Token *> callstack(1, usingStart);
3301
0
        mErrorLogger->reportErr(ErrorMessage(callstack, &list, Severity::debug, "simplifyUsing",
3302
0
                                             "Failed to parse \'" + str + "\'. The checking continues anyway.", Certainty::normal));
3303
0
    }
3304
0
}
3305
3306
bool Tokenizer::createTokens(std::istream &code,
3307
                             const std::string& FileName)
3308
0
{
3309
0
    return list.createTokens(code, FileName);
3310
0
}
3311
3312
void Tokenizer::createTokens(simplecpp::TokenList&& tokenList)
3313
1.36k
{
3314
1.36k
    list.createTokens(std::move(tokenList));
3315
1.36k
}
3316
3317
bool Tokenizer::simplifyTokens1(const std::string &configuration)
3318
1.36k
{
3319
    // Fill the map mTypeSize..
3320
1.36k
    fillTypeSizes();
3321
3322
1.36k
    mConfiguration = configuration;
3323
3324
1.36k
    if (mTimerResults) {
3325
0
        Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1", mSettings->showtime, mTimerResults);
3326
0
        if (!simplifyTokenList1(list.getFiles().front().c_str()))
3327
0
            return false;
3328
1.36k
    } else {
3329
1.36k
        if (!simplifyTokenList1(list.getFiles().front().c_str()))
3330
0
            return false;
3331
1.36k
    }
3332
3333
1.36k
    if (mTimerResults) {
3334
0
        Timer t("Tokenizer::simplifyTokens1::createAst", mSettings->showtime, mTimerResults);
3335
0
        list.createAst();
3336
0
        list.validateAst();
3337
1.36k
    } else {
3338
1.36k
        list.createAst();
3339
1.36k
        list.validateAst();
3340
1.36k
    }
3341
3342
1.36k
    if (mTimerResults) {
3343
0
        Timer t("Tokenizer::simplifyTokens1::createSymbolDatabase", mSettings->showtime, mTimerResults);
3344
0
        createSymbolDatabase();
3345
1.36k
    } else {
3346
1.36k
        createSymbolDatabase();
3347
1.36k
    }
3348
3349
1.36k
    if (mTimerResults) {
3350
0
        Timer t("Tokenizer::simplifyTokens1::setValueType", mSettings->showtime, mTimerResults);
3351
0
        mSymbolDatabase->setValueTypeInTokenList(false);
3352
0
        mSymbolDatabase->setValueTypeInTokenList(true);
3353
1.36k
    } else {
3354
1.36k
        mSymbolDatabase->setValueTypeInTokenList(false);
3355
1.36k
        mSymbolDatabase->setValueTypeInTokenList(true);
3356
1.36k
    }
3357
3358
1.36k
    if (!mSettings->buildDir.empty())
3359
0
        Summaries::create(this, configuration);
3360
3361
    // TODO: do not run valueflow if no checks are being performed at all - e.g. unusedFunctions only
3362
1.36k
    const char* disableValueflowEnv = std::getenv("DISABLE_VALUEFLOW");
3363
1.36k
    const bool doValueFlow = !disableValueflowEnv || (std::strcmp(disableValueflowEnv, "1") != 0);
3364
3365
1.36k
    if (doValueFlow) {
3366
1.36k
        if (mTimerResults) {
3367
0
            Timer t("Tokenizer::simplifyTokens1::ValueFlow", mSettings->showtime, mTimerResults);
3368
0
            ValueFlow::setValues(list, *mSymbolDatabase, mErrorLogger, mSettings, mTimerResults);
3369
1.36k
        } else {
3370
1.36k
            ValueFlow::setValues(list, *mSymbolDatabase, mErrorLogger, mSettings, mTimerResults);
3371
1.36k
        }
3372
1.36k
    }
3373
3374
    // Warn about unhandled character literals
3375
1.36k
    if (mSettings->severity.isEnabled(Severity::portability)) {
3376
93.5k
        for (const Token *tok = tokens(); tok; tok = tok->next()) {
3377
92.2k
            if (tok->tokType() == Token::eChar && tok->values().empty()) {
3378
0
                try {
3379
0
                    simplecpp::characterLiteralToLL(tok->str());
3380
0
                } catch (const std::exception &e) {
3381
0
                    unhandledCharLiteral(tok, e.what());
3382
0
                }
3383
0
            }
3384
92.2k
        }
3385
1.36k
    }
3386
3387
1.36k
    if (doValueFlow) {
3388
1.36k
        mSymbolDatabase->setArrayDimensionsUsingValueFlow();
3389
1.36k
    }
3390
3391
1.36k
    printDebugOutput(1);
3392
3393
1.36k
    return true;
3394
1.36k
}
3395
3396
bool Tokenizer::tokenize(std::istream &code,
3397
                         const char FileName[],
3398
                         const std::string &configuration)
3399
0
{
3400
0
    if (!createTokens(code, FileName))
3401
0
        return false;
3402
3403
0
    return simplifyTokens1(configuration);
3404
0
}
3405
//---------------------------------------------------------------------------
3406
3407
void Tokenizer::findComplicatedSyntaxErrorsInTemplates()
3408
1.36k
{
3409
1.36k
    validate();
3410
1.36k
    mTemplateSimplifier->checkComplicatedSyntaxErrorsInTemplates();
3411
1.36k
}
3412
3413
void Tokenizer::checkForEnumsWithTypedef()
3414
1.36k
{
3415
80.4k
    for (const Token *tok = list.front(); tok; tok = tok->next()) {
3416
79.1k
        if (Token::Match(tok, "enum %name% {")) {
3417
0
            tok = tok->tokAt(2);
3418
0
            const Token *tok2 = Token::findsimplematch(tok, "typedef", tok->link());
3419
0
            if (tok2)
3420
0
                syntaxError(tok2);
3421
0
            tok = tok->link();
3422
0
        }
3423
79.1k
    }
3424
1.36k
}
3425
3426
void Tokenizer::fillTypeSizes()
3427
1.36k
{
3428
1.36k
    mTypeSize.clear();
3429
1.36k
    mTypeSize["char"] = 1;
3430
1.36k
    mTypeSize["_Bool"] = mSettings->platform.sizeof_bool;
3431
1.36k
    mTypeSize["bool"] = mSettings->platform.sizeof_bool;
3432
1.36k
    mTypeSize["short"] = mSettings->platform.sizeof_short;
3433
1.36k
    mTypeSize["int"] = mSettings->platform.sizeof_int;
3434
1.36k
    mTypeSize["long"] = mSettings->platform.sizeof_long;
3435
1.36k
    mTypeSize["long long"] = mSettings->platform.sizeof_long_long;
3436
1.36k
    mTypeSize["float"] = mSettings->platform.sizeof_float;
3437
1.36k
    mTypeSize["double"] = mSettings->platform.sizeof_double;
3438
1.36k
    mTypeSize["long double"] = mSettings->platform.sizeof_long_double;
3439
1.36k
    mTypeSize["wchar_t"] = mSettings->platform.sizeof_wchar_t;
3440
1.36k
    mTypeSize["size_t"] = mSettings->platform.sizeof_size_t;
3441
1.36k
    mTypeSize["*"] = mSettings->platform.sizeof_pointer;
3442
1.36k
}
3443
3444
void Tokenizer::combineOperators()
3445
1.36k
{
3446
1.36k
    const bool cpp = isCPP();
3447
3448
    // Combine tokens..
3449
80.4k
    for (Token *tok = list.front(); tok && tok->next(); tok = tok->next()) {
3450
79.1k
        const char c1 = tok->str()[0];
3451
3452
79.1k
        if (tok->str().length() == 1 && tok->next()->str().length() == 1) {
3453
27.0k
            const char c2 = tok->next()->str()[0];
3454
3455
            // combine +-*/ and =
3456
27.0k
            if (c2 == '=' && (std::strchr("+-*/%|^=!<>", c1)) && !Token::Match(tok->previous(), "%type% *")) {
3457
                // skip templates
3458
0
                if (cpp && (tok->str() == ">" || Token::simpleMatch(tok->previous(), "> *"))) {
3459
0
                    const Token* opening =
3460
0
                        tok->str() == ">" ? tok->findOpeningBracket() : tok->previous()->findOpeningBracket();
3461
0
                    if (opening && Token::Match(opening->previous(), "%name%"))
3462
0
                        continue;
3463
0
                }
3464
0
                tok->str(tok->str() + c2);
3465
0
                tok->deleteNext();
3466
0
                continue;
3467
0
            }
3468
52.0k
        } else if (tok->next()->str() == "=") {
3469
8.71k
            if (tok->str() == ">>") {
3470
0
                tok->str(">>=");
3471
0
                tok->deleteNext();
3472
8.71k
            } else if (tok->str() == "<<") {
3473
0
                tok->str("<<=");
3474
0
                tok->deleteNext();
3475
0
            }
3476
43.3k
        } else if (cpp && (c1 == 'p' || c1 == '_') &&
3477
43.3k
                   Token::Match(tok, "private|protected|public|__published : !!:")) {
3478
0
            bool simplify = false;
3479
0
            int par = 0;
3480
0
            for (const Token *prev = tok->previous(); prev; prev = prev->previous()) {
3481
0
                if (prev->str() == ")") {
3482
0
                    ++par;
3483
0
                } else if (prev->str() == "(") {
3484
0
                    if (par == 0U)
3485
0
                        break;
3486
0
                    --par;
3487
0
                }
3488
0
                if (par != 0U || prev->str() == "(")
3489
0
                    continue;
3490
0
                if (Token::Match(prev, "[;{}]")) {
3491
0
                    simplify = true;
3492
0
                    break;
3493
0
                }
3494
0
                if (prev->isName() && prev->isUpperCaseName())
3495
0
                    continue;
3496
0
                if (prev->isName() && endsWith(prev->str(), ':'))
3497
0
                    simplify = true;
3498
0
                break;
3499
0
            }
3500
0
            if (simplify) {
3501
0
                tok->str(tok->str() + ":");
3502
0
                tok->deleteNext();
3503
0
            }
3504
43.3k
        } else if (tok->str() == "->") {
3505
            // If the preceding sequence is "( & %name% )", replace it by "%name%"
3506
0
            Token *t = tok->tokAt(-4);
3507
0
            if (Token::Match(t, "( & %name% )") && !Token::simpleMatch(t->previous(), ">")) {
3508
0
                t->deleteThis();
3509
0
                t->deleteThis();
3510
0
                t->deleteNext();
3511
0
                tok->str(".");
3512
0
            } else {
3513
0
                tok->str(".");
3514
0
                tok->originalName("->");
3515
0
            }
3516
0
        }
3517
79.1k
    }
3518
1.36k
}
3519
3520
void Tokenizer::combineStringAndCharLiterals()
3521
1.36k
{
3522
    // Combine strings
3523
81.8k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
3524
80.4k
        if (!isStringLiteral(tok->str()))
3525
80.4k
            continue;
3526
3527
0
        tok->str(simplifyString(tok->str()));
3528
3529
0
        while (Token::Match(tok->next(), "%str%") || Token::Match(tok->next(), "_T|_TEXT|TEXT ( %str% )")) {
3530
0
            if (tok->next()->isName()) {
3531
0
                if (!mSettings->platform.isWindows())
3532
0
                    break;
3533
0
                tok->deleteNext(2);
3534
0
                tok->next()->deleteNext();
3535
0
            }
3536
            // Two strings after each other, combine them
3537
0
            tok->concatStr(simplifyString(tok->next()->str()));
3538
0
            tok->deleteNext();
3539
0
        }
3540
0
    }
3541
1.36k
}
3542
3543
void Tokenizer::concatenateNegativeNumberAndAnyPositive()
3544
1.36k
{
3545
80.4k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
3546
79.1k
        if (!Token::Match(tok, "?|:|,|(|[|{|return|case|sizeof|%op% +|-") || tok->tokType() == Token::eIncDecOp)
3547
77.7k
            continue;
3548
3549
1.36k
        while (tok->str() != ">" && tok->next() && tok->next()->str() == "+" && (!Token::Match(tok->tokAt(2), "%name% (|;") || Token::Match(tok, "%op%")))
3550
0
            tok->deleteNext();
3551
3552
1.36k
        if (Token::Match(tok->next(), "- %num%")) {
3553
1.36k
            tok->deleteNext();
3554
1.36k
            tok->next()->str("-" + tok->next()->str());
3555
1.36k
        }
3556
1.36k
    }
3557
1.36k
}
3558
3559
void Tokenizer::simplifyExternC()
3560
1.36k
{
3561
1.36k
    if (isC())
3562
0
        return;
3563
3564
    // Add attributes to all tokens within `extern "C"` inlines and blocks, and remove the `extern "C"` tokens.
3565
80.4k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
3566
79.1k
        if (Token::simpleMatch(tok, "extern \"C\"")) {
3567
0
            Token *tok2 = tok->next();
3568
0
            if (tok->strAt(2) == "{") {
3569
0
                tok2 = tok2->next(); // skip {
3570
0
                while ((tok2 = tok2->next()) && tok2 != tok->linkAt(2))
3571
0
                    tok2->isExternC(true);
3572
0
                tok->linkAt(2)->deleteThis(); // }
3573
0
                tok->deleteNext(2); // "C" {
3574
0
            } else {
3575
0
                while ((tok2 = tok2->next()) && !Token::Match(tok2, "[;{]"))
3576
0
                    tok2->isExternC(true);
3577
0
                tok->deleteNext(); // "C"
3578
0
            }
3579
0
            tok->deleteThis(); // extern
3580
0
        }
3581
79.1k
    }
3582
1.36k
}
3583
3584
void Tokenizer::simplifyRoundCurlyParentheses()
3585
1.36k
{
3586
80.4k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
3587
79.1k
        while (Token::Match(tok, "[;{}:] ( {") &&
3588
79.1k
               Token::simpleMatch(tok->linkAt(2), "} ) ;")) {
3589
0
            if (tok->str() == ":" && !Token::Match(tok->tokAt(-2),"[;{}] %type% :"))
3590
0
                break;
3591
0
            Token *end = tok->linkAt(2)->tokAt(-3);
3592
0
            if (Token::Match(end, "[;{}] %num%|%str% ;"))
3593
0
                end->deleteNext(2);
3594
0
            tok->linkAt(2)->previous()->deleteNext(3);
3595
0
            tok->deleteNext(2);
3596
0
        }
3597
79.1k
        if (Token::Match(tok, "( { %bool%|%char%|%num%|%str%|%name% ; } )")) {
3598
0
            tok->deleteNext();
3599
0
            tok->deleteThis();
3600
0
            tok->deleteNext(3);
3601
0
        }
3602
79.1k
    }
3603
1.36k
}
3604
3605
void Tokenizer::simplifySQL()
3606
1.36k
{
3607
81.8k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
3608
80.4k
        if (!Token::simpleMatch(tok, "__CPPCHECK_EMBEDDED_SQL_EXEC__ SQL"))
3609
80.4k
            continue;
3610
3611
0
        const Token *end = findSQLBlockEnd(tok);
3612
0
        if (end == nullptr)
3613
0
            syntaxError(nullptr);
3614
3615
0
        const std::string instruction = tok->stringifyList(end);
3616
        // delete all tokens until the embedded SQL block end
3617
0
        Token::eraseTokens(tok, end);
3618
3619
        // insert "asm ( "instruction" ) ;"
3620
0
        tok->str("asm");
3621
        // it can happen that 'end' is NULL when wrong code is inserted
3622
0
        if (!tok->next())
3623
0
            tok->insertToken(";");
3624
0
        tok->insertToken(")");
3625
0
        tok->insertToken("\"" + instruction + "\"");
3626
0
        tok->insertToken("(");
3627
        // jump to ';' and continue
3628
0
        tok = tok->tokAt(3);
3629
0
    }
3630
1.36k
}
3631
3632
void Tokenizer::simplifyArrayAccessSyntax()
3633
1.36k
{
3634
    // 0[a] -> a[0]
3635
93.6k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
3636
92.3k
        if (tok->isNumber() && Token::Match(tok, "%num% [ %name% ]")) {
3637
0
            const std::string number(tok->str());
3638
0
            Token* indexTok = tok->tokAt(2);
3639
0
            tok->str(indexTok->str());
3640
0
            tok->varId(indexTok->varId());
3641
0
            indexTok->str(number);
3642
0
        }
3643
92.3k
    }
3644
1.36k
}
3645
3646
void Tokenizer::simplifyParameterVoid()
3647
1.36k
{
3648
93.6k
    for (Token* tok = list.front(); tok; tok = tok->next()) {
3649
92.3k
        if (Token::Match(tok, "%name% ( void )") && !Token::Match(tok, "sizeof|decltype|typeof|return")) {
3650
0
            tok->next()->deleteNext();
3651
0
            tok->next()->setRemovedVoidParameter(true);
3652
0
        }
3653
92.3k
    }
3654
1.36k
}
3655
3656
void Tokenizer::simplifyRedundantConsecutiveBraces()
3657
1.36k
{
3658
    // Remove redundant consecutive braces, i.e. '.. { { .. } } ..' -> '.. { .. } ..'.
3659
93.6k
    for (Token *tok = list.front(); tok;) {
3660
92.3k
        if (Token::simpleMatch(tok, "= {")) {
3661
0
            tok = tok->linkAt(1);
3662
92.3k
        } else if (Token::simpleMatch(tok, "{ {") && Token::simpleMatch(tok->next()->link(), "} }")) {
3663
            //remove internal parentheses
3664
0
            tok->next()->link()->deleteThis();
3665
0
            tok->deleteNext();
3666
0
        } else
3667
92.3k
            tok = tok->next();
3668
92.3k
    }
3669
1.36k
}
3670
3671
void Tokenizer::simplifyDoublePlusAndDoubleMinus()
3672
1.36k
{
3673
    // Convert - - into + and + - into -
3674
93.6k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
3675
92.3k
        while (tok->next()) {
3676
90.9k
            if (tok->str() == "+") {
3677
279
                if (tok->next()->str()[0] == '-') {
3678
12
                    tok = tok->next();
3679
12
                    if (tok->str().size() == 1) {
3680
0
                        tok = tok->previous();
3681
0
                        tok->str("-");
3682
0
                        tok->deleteNext();
3683
12
                    } else if (tok->isNumber()) {
3684
0
                        tok->str(tok->str().substr(1));
3685
0
                        tok = tok->previous();
3686
0
                        tok->str("-");
3687
0
                    }
3688
12
                    continue;
3689
12
                }
3690
90.6k
            } else if (tok->str() == "-") {
3691
250
                if (tok->next()->str()[0] == '-') {
3692
1
                    tok = tok->next();
3693
1
                    if (tok->str().size() == 1) {
3694
0
                        tok = tok->previous();
3695
0
                        tok->str("+");
3696
0
                        tok->deleteNext();
3697
1
                    } else if (tok->isNumber()) {
3698
0
                        tok->str(tok->str().substr(1));
3699
0
                        tok = tok->previous();
3700
0
                        tok->str("+");
3701
0
                    }
3702
1
                    continue;
3703
1
                }
3704
250
            }
3705
3706
90.9k
            break;
3707
90.9k
        }
3708
92.3k
    }
3709
1.36k
}
3710
3711
/** Specify array size if it hasn't been given */
3712
3713
void Tokenizer::arraySize()
3714
1.36k
{
3715
1.36k
    auto getStrTok = [](Token* tok, bool addLength, Token** endStmt) -> Token* {
3716
0
        if (addLength) {
3717
0
            *endStmt = tok->tokAt(5);
3718
0
            return tok->tokAt(4);
3719
0
        }
3720
0
        if (Token::Match(tok, "%var% [ ] =")) {
3721
0
            tok = tok->tokAt(4);
3722
0
            int parCount = 0;
3723
0
            while (Token::simpleMatch(tok, "(")) {
3724
0
                ++parCount;
3725
0
                tok = tok->next();
3726
0
            }
3727
0
            if (Token::Match(tok, "%str%")) {
3728
0
                *endStmt = tok->tokAt(parCount + 1);
3729
0
                return tok;
3730
0
            }
3731
0
        }
3732
0
        return nullptr;
3733
0
    };
3734
3735
93.6k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
3736
92.3k
        if (!tok->isName() || !Token::Match(tok, "%var% [ ] ="))
3737
92.3k
            continue;
3738
0
        bool addlength = false;
3739
0
        if (Token::Match(tok->previous(), "!!* %var% [ ] = { %str% } ;")) {
3740
0
            Token *t = tok->tokAt(3);
3741
0
            t->deleteNext();
3742
0
            t->next()->deleteNext();
3743
0
            addlength = true;
3744
0
        }
3745
3746
0
        Token* endStmt{};
3747
0
        if (const Token* strTok = getStrTok(tok, addlength, &endStmt)) {
3748
0
            const int sz = Token::getStrArraySize(strTok);
3749
0
            tok->next()->insertToken(std::to_string(sz));
3750
0
            tok = endStmt;
3751
0
        }
3752
3753
0
        else if (Token::Match(tok, "%var% [ ] = {")) {
3754
0
            MathLib::biguint sz = 1;
3755
0
            tok = tok->next();
3756
0
            Token *end = tok->linkAt(3);
3757
0
            for (Token *tok2 = tok->tokAt(4); tok2 && tok2 != end; tok2 = tok2->next()) {
3758
0
                if (tok2->link() && Token::Match(tok2, "{|(|[|<")) {
3759
0
                    if (tok2->str() == "[" && tok2->link()->strAt(1) == "=") { // designated initializer
3760
0
                        if (Token::Match(tok2, "[ %num% ]"))
3761
0
                            sz = std::max(sz, MathLib::toULongNumber(tok2->strAt(1)) + 1U);
3762
0
                        else {
3763
0
                            sz = 0;
3764
0
                            break;
3765
0
                        }
3766
0
                    }
3767
0
                    tok2 = tok2->link();
3768
0
                } else if (tok2->str() == ",") {
3769
0
                    if (!Token::Match(tok2->next(), "[},]"))
3770
0
                        ++sz;
3771
0
                    else {
3772
0
                        tok2 = tok2->previous();
3773
0
                        tok2->deleteNext();
3774
0
                    }
3775
0
                }
3776
0
            }
3777
3778
0
            if (sz != 0)
3779
0
                tok->insertToken(std::to_string(sz));
3780
3781
0
            tok = end->next() ? end->next() : end;
3782
0
        }
3783
0
    }
3784
1.36k
}
3785
3786
static Token *skipTernaryOp(Token *tok)
3787
0
{
3788
0
    int colonLevel = 1;
3789
0
    while (nullptr != (tok = tok->next())) {
3790
0
        if (tok->str() == "?") {
3791
0
            ++colonLevel;
3792
0
        } else if (tok->str() == ":") {
3793
0
            --colonLevel;
3794
0
            if (colonLevel == 0) {
3795
0
                tok = tok->next();
3796
0
                break;
3797
0
            }
3798
0
        }
3799
0
        if (tok->link() && Token::Match(tok, "[(<]"))
3800
0
            tok = tok->link();
3801
0
        else if (Token::Match(tok->next(), "[{};)]"))
3802
0
            break;
3803
0
    }
3804
0
    if (colonLevel > 0) // Ticket #5214: Make sure the ':' matches the proper '?'
3805
0
        return nullptr;
3806
0
    return tok;
3807
0
}
3808
3809
// Skips until the colon at the end of the case label, the argument must point to the "case" token.
3810
// In case of success returns the colon token.
3811
// In case of failure returns the token that caused the error.
3812
static Token *skipCaseLabel(Token *tok)
3813
0
{
3814
0
    assert(tok->str() == "case");
3815
0
    while (nullptr != (tok = tok->next())) {
3816
0
        if (Token::Match(tok, "(|["))
3817
0
            tok = tok->link();
3818
0
        else if (tok->str() == "?") {
3819
0
            Token * tok1 = skipTernaryOp(tok);
3820
0
            if (!tok1)
3821
0
                return tok;
3822
0
            tok = tok1;
3823
0
        }
3824
0
        if (Token::Match(tok, "[:{};]"))
3825
0
            return tok;
3826
0
    }
3827
0
    return nullptr;
3828
0
}
3829
3830
const Token * Tokenizer::startOfExecutableScope(const Token * tok)
3831
99.1k
{
3832
99.1k
    if (tok->str() != ")")
3833
95.6k
        return nullptr;
3834
3835
3.48k
    tok = isFunctionHead(tok, ":{", true);
3836
3837
3.48k
    if (Token::Match(tok, ": %name% [({]")) {
3838
0
        while (Token::Match(tok, "[:,] %name% [({]"))
3839
0
            tok = tok->linkAt(2)->next();
3840
0
    }
3841
3842
3.48k
    return (tok && tok->str() == "{") ? tok : nullptr;
3843
99.1k
}
3844
3845
3846
/** simplify labels and case|default in the code: add a ";" if not already in.*/
3847
3848
void Tokenizer::simplifyLabelsCaseDefault()
3849
1.36k
{
3850
1.36k
    const bool cpp = isCPP();
3851
1.36k
    bool executablescope = false;
3852
1.36k
    int indentLevel = 0;
3853
66.3k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
3854
        // Simplify labels in the executable scope..
3855
64.9k
        Token *start = const_cast<Token *>(startOfExecutableScope(tok));
3856
64.9k
        if (start) {
3857
1.74k
            tok = start;
3858
1.74k
            executablescope = true;
3859
1.74k
        }
3860
3861
64.9k
        if (!executablescope)
3862
39.2k
            continue;
3863
3864
25.6k
        if (tok->str() == "{") {
3865
3.58k
            if (tok->previous()->str() == "=")
3866
0
                tok = tok->link();
3867
3.58k
            else
3868
3.58k
                ++indentLevel;
3869
22.0k
        } else if (tok->str() == "}") {
3870
3.58k
            --indentLevel;
3871
3.58k
            if (indentLevel == 0) {
3872
1.74k
                executablescope = false;
3873
1.74k
                continue;
3874
1.74k
            }
3875
18.5k
        } else if (Token::Match(tok, "(|["))
3876
1.76k
            tok = tok->link();
3877
3878
23.9k
        if (Token::Match(tok, "[;{}:] case")) {
3879
0
            tok = skipCaseLabel(tok->next());
3880
0
            if (!tok)
3881
0
                break;
3882
0
            if (tok->str() != ":" || tok->strAt(-1) == "case" || !tok->next())
3883
0
                syntaxError(tok);
3884
0
            if (tok->next()->str() != ";" && tok->next()->str() != "case")
3885
0
                tok->insertToken(";");
3886
0
            else
3887
0
                tok = tok->previous();
3888
23.9k
        } else if (Token::Match(tok, "[;{}] %name% : !!;")) {
3889
0
            if (!cpp || !Token::Match(tok->next(), "class|struct|enum")) {
3890
0
                tok = tok->tokAt(2);
3891
0
                tok->insertToken(";");
3892
0
            }
3893
0
        }
3894
23.9k
    }
3895
1.36k
}
3896
3897
3898
void Tokenizer::simplifyCaseRange()
3899
1.36k
{
3900
80.4k
    for (Token* tok = list.front(); tok; tok = tok->next()) {
3901
79.1k
        if (Token::Match(tok, "case %num%|%char% ... %num%|%char% :")) {
3902
0
            const MathLib::bigint start = MathLib::toLongNumber(tok->strAt(1));
3903
0
            MathLib::bigint end = MathLib::toLongNumber(tok->strAt(3));
3904
0
            end = std::min(start + 50, end); // Simplify it 50 times at maximum
3905
0
            if (start < end) {
3906
0
                tok = tok->tokAt(2);
3907
0
                tok->str(":");
3908
0
                tok->insertToken("case");
3909
0
                for (MathLib::bigint i = end-1; i > start; i--) {
3910
0
                    tok->insertToken(":");
3911
0
                    tok->insertToken(std::to_string(i));
3912
0
                    tok->insertToken("case");
3913
0
                }
3914
0
            }
3915
0
        }
3916
79.1k
    }
3917
1.36k
}
3918
3919
void Tokenizer::calculateScopes()
3920
1.36k
{
3921
93.6k
    for (auto *tok = list.front(); tok; tok = tok->next())
3922
92.3k
        tok->scopeInfo(nullptr);
3923
3924
1.36k
    std::string nextScopeNameAddition;
3925
1.36k
    std::shared_ptr<ScopeInfo2> primaryScope = std::make_shared<ScopeInfo2>("", nullptr);
3926
1.36k
    list.front()->scopeInfo(primaryScope);
3927
3928
93.6k
    for (Token* tok = list.front(); tok; tok = tok->next()) {
3929
92.3k
        if (tok == list.front() || !tok->scopeInfo()) {
3930
88.7k
            if (tok != list.front())
3931
87.3k
                tok->scopeInfo(tok->previous()->scopeInfo());
3932
3933
88.7k
            if (Token::Match(tok, "using namespace %name% ::|<|;")) {
3934
0
                std::string usingNamespaceName;
3935
0
                for (const Token* namespaceNameToken = tok->tokAt(2);
3936
0
                     namespaceNameToken && namespaceNameToken->str() != ";";
3937
0
                     namespaceNameToken = namespaceNameToken->next()) {
3938
0
                    usingNamespaceName += namespaceNameToken->str();
3939
0
                    usingNamespaceName += " ";
3940
0
                }
3941
0
                if (!usingNamespaceName.empty())
3942
0
                    usingNamespaceName.pop_back();
3943
0
                tok->scopeInfo()->usingNamespaces.insert(std::move(usingNamespaceName));
3944
88.7k
            } else if (Token::Match(tok, "namespace|class|struct|union %name% {|::|:|<")) {
3945
0
                for (Token* nameTok = tok->next(); nameTok && !Token::Match(nameTok, "{|:"); nameTok = nameTok->next()) {
3946
0
                    if (Token::Match(nameTok, ";|<")) {
3947
0
                        nextScopeNameAddition = "";
3948
0
                        break;
3949
0
                    }
3950
0
                    nextScopeNameAddition.append(nameTok->str());
3951
0
                    nextScopeNameAddition.append(" ");
3952
0
                }
3953
0
                if (!nextScopeNameAddition.empty())
3954
0
                    nextScopeNameAddition.pop_back();
3955
0
            }
3956
3957
88.7k
            if (Token::simpleMatch(tok, "{")) {
3958
                // This might be the opening of a member function
3959
3.58k
                Token *tok1 = tok;
3960
3.58k
                while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
3961
0
                    tok1 = tok1->previous();
3962
3.58k
                if (tok1->previous() && tok1->strAt(-1) == ")") {
3963
3.12k
                    bool member = true;
3964
3.12k
                    tok1 = tok1->linkAt(-1);
3965
3.12k
                    if (Token::Match(tok1->previous(), "throw|noexcept")) {
3966
0
                        tok1 = tok1->previous();
3967
0
                        while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
3968
0
                            tok1 = tok1->previous();
3969
0
                        if (tok1->strAt(-1) != ")")
3970
0
                            member = false;
3971
3.12k
                    } else if (Token::Match(tok->tokAt(-2), ":|, %name%")) {
3972
0
                        tok1 = tok1->tokAt(-2);
3973
0
                        if (tok1->strAt(-1) != ")")
3974
0
                            member = false;
3975
0
                    }
3976
3.12k
                    if (member) {
3977
3.12k
                        if (tok1->strAt(-1) == ">")
3978
0
                            tok1 = tok1->previous()->findOpeningBracket();
3979
3.12k
                        if (tok1 && Token::Match(tok1->tokAt(-3), "%name% :: %name%")) {
3980
0
                            tok1 = tok1->tokAt(-2);
3981
0
                            std::string scope = tok1->strAt(-1);
3982
0
                            while (Token::Match(tok1->tokAt(-2), ":: %name%")) {
3983
0
                                scope = tok1->strAt(-3) + " :: " + scope;
3984
0
                                tok1 = tok1->tokAt(-2);
3985
0
                            }
3986
3987
0
                            if (!nextScopeNameAddition.empty() && !scope.empty())
3988
0
                                nextScopeNameAddition += " :: ";
3989
0
                            nextScopeNameAddition += scope;
3990
0
                        }
3991
3.12k
                    }
3992
3.12k
                }
3993
3994
                // New scope is opening, record it here
3995
3.58k
                std::shared_ptr<ScopeInfo2> newScopeInfo = std::make_shared<ScopeInfo2>(tok->scopeInfo()->name, tok->link(), tok->scopeInfo()->usingNamespaces);
3996
3997
3.58k
                if (!newScopeInfo->name.empty() && !nextScopeNameAddition.empty())
3998
0
                    newScopeInfo->name.append(" :: ");
3999
3.58k
                newScopeInfo->name.append(nextScopeNameAddition);
4000
3.58k
                nextScopeNameAddition = "";
4001
4002
3.58k
                if (tok->link())
4003
3.58k
                    tok->link()->scopeInfo(tok->scopeInfo());
4004
3.58k
                tok->scopeInfo(newScopeInfo);
4005
3.58k
            }
4006
88.7k
        }
4007
92.3k
    }
4008
1.36k
}
4009
4010
void Tokenizer::simplifyTemplates()
4011
1.36k
{
4012
1.36k
    if (isC())
4013
0
        return;
4014
4015
1.36k
    const std::time_t maxTime = mSettings->templateMaxTime > 0 ? std::time(nullptr) + mSettings->templateMaxTime : 0;
4016
1.36k
    mTemplateSimplifier->simplifyTemplates(
4017
1.36k
        maxTime);
4018
1.36k
}
4019
//---------------------------------------------------------------------------
4020
4021
4022
/** Class used in Tokenizer::setVarIdPass1 */
4023
class VariableMap {
4024
private:
4025
    std::unordered_map<std::string, nonneg int> mVariableId;
4026
    std::unordered_map<std::string, nonneg int> mVariableId_global;
4027
    std::stack<std::vector<std::pair<std::string, nonneg int>>> mScopeInfo;
4028
    mutable nonneg int mVarId{};
4029
public:
4030
1.36k
    VariableMap() = default;
4031
    void enterScope();
4032
    bool leaveScope();
4033
    void addVariable(const std::string& varname, bool globalNamespace);
4034
0
    bool hasVariable(const std::string& varname) const {
4035
0
        return mVariableId.find(varname) != mVariableId.end();
4036
0
    }
4037
4038
74.9k
    const std::unordered_map<std::string, nonneg int>& map(bool global) const {
4039
74.9k
        return global ? mVariableId_global : mVariableId;
4040
74.9k
    }
4041
0
    nonneg int getVarId() const {
4042
0
        return mVarId;
4043
0
    }
4044
24.8k
    nonneg int& getVarId() {
4045
24.8k
        return mVarId;
4046
24.8k
    }
4047
};
4048
4049
4050
void VariableMap::enterScope()
4051
4.50k
{
4052
4.50k
    mScopeInfo.emplace(/*std::vector<std::pair<std::string, nonneg int>>()*/);
4053
4.50k
}
4054
4055
bool VariableMap::leaveScope()
4056
4.50k
{
4057
4.50k
    if (mScopeInfo.empty())
4058
0
        return false;
4059
4060
4.50k
    for (const std::pair<std::string, nonneg int>& outerVariable : mScopeInfo.top()) {
4061
1
        if (outerVariable.second != 0)
4062
1
            mVariableId[outerVariable.first] = outerVariable.second;
4063
0
        else
4064
0
            mVariableId.erase(outerVariable.first);
4065
1
    }
4066
4.50k
    mScopeInfo.pop();
4067
4.50k
    return true;
4068
4.50k
}
4069
4070
void VariableMap::addVariable(const std::string& varname, bool globalNamespace)
4071
6.81k
{
4072
6.81k
    if (mScopeInfo.empty()) {
4073
6.81k
        mVariableId[varname] = ++mVarId;
4074
6.81k
        if (globalNamespace)
4075
6.81k
            mVariableId_global[varname] = mVariableId[varname];
4076
6.81k
        return;
4077
6.81k
    }
4078
1
    std::unordered_map<std::string, nonneg int>::iterator it = mVariableId.find(varname);
4079
1
    if (it == mVariableId.end()) {
4080
0
        mScopeInfo.top().emplace_back(varname, 0);
4081
0
        mVariableId[varname] = ++mVarId;
4082
0
        if (globalNamespace)
4083
0
            mVariableId_global[varname] = mVariableId[varname];
4084
0
        return;
4085
0
    }
4086
1
    mScopeInfo.top().emplace_back(varname, it->second);
4087
1
    it->second = ++mVarId;
4088
1
}
4089
4090
static bool setVarIdParseDeclaration(Token** tok, const VariableMap& variableMap, bool executableScope, bool cpp, bool c)
4091
25.5k
{
4092
25.5k
    const Token* const tok1 = *tok;
4093
25.5k
    Token* tok2 = *tok;
4094
25.5k
    if (!tok2->isName())
4095
6.11k
        return false;
4096
4097
19.4k
    nonneg int typeCount = 0;
4098
19.4k
    nonneg int singleNameCount = 0;
4099
19.4k
    bool hasstruct = false;   // Is there a "struct" or "class"?
4100
19.4k
    bool bracket = false;
4101
19.4k
    bool ref = false;
4102
39.0k
    while (tok2) {
4103
39.0k
        if (tok2->isName()) {
4104
28.0k
            if (Token::simpleMatch(tok2, "alignas (")) {
4105
0
                tok2 = tok2->linkAt(1)->next();
4106
0
                continue;
4107
0
            }
4108
28.0k
            if (cpp && Token::Match(tok2, "namespace|public|private|protected"))
4109
0
                return false;
4110
28.0k
            if (cpp && Token::simpleMatch(tok2, "decltype (")) {
4111
0
                typeCount = 1;
4112
0
                tok2 = tok2->linkAt(1)->next();
4113
0
                continue;
4114
0
            }
4115
28.0k
            if (Token::Match(tok2, "struct|union|enum") || (!c && Token::Match(tok2, "class|typename"))) {
4116
0
                hasstruct = true;
4117
0
                typeCount = 0;
4118
0
                singleNameCount = 0;
4119
28.0k
            } else if (Token::Match(tok2, "const|extern")) {
4120
                // just skip "const", "extern"
4121
28.0k
            } else if (!hasstruct && variableMap.map(false).count(tok2->str()) && tok2->previous()->str() != "::") {
4122
8.43k
                ++typeCount;
4123
8.43k
                tok2 = tok2->next();
4124
8.43k
                if (!tok2 || tok2->str() != "::")
4125
8.43k
                    break;
4126
19.5k
            } else {
4127
19.5k
                if (tok2->str() != "void" || Token::Match(tok2, "void const| *|(")) // just "void" cannot be a variable type
4128
19.5k
                    ++typeCount;
4129
19.5k
                ++singleNameCount;
4130
19.5k
            }
4131
28.0k
        } else if (!c && ((TemplateSimplifier::templateParameters(tok2) > 0) ||
4132
11.0k
                          Token::simpleMatch(tok2, "< >") /* Ticket #4764 */)) {
4133
3
            const Token *start = *tok;
4134
3
            if (Token::Match(start->previous(), "%or%|%oror%|&&|&|^|+|-|*|/"))
4135
0
                return false;
4136
3
            Token* const closingBracket = tok2->findClosingBracket();
4137
3
            if (closingBracket == nullptr) { /* Ticket #8151 */
4138
0
                throw tok2;
4139
0
            }
4140
3
            tok2 = closingBracket;
4141
3
            if (tok2->str() != ">")
4142
0
                break;
4143
3
            singleNameCount = 1;
4144
3
            if (Token::Match(tok2, "> %name% %or%|%oror%|&&|&|^|+|-|*|/") && !Token::Match(tok2, "> const [*&]"))
4145
0
                return false;
4146
3
            if (Token::Match(tok2, "> %name% )")) {
4147
2
                if (Token::Match(tok2->linkAt(2)->previous(), "if|for|while ("))
4148
2
                    return false;
4149
0
                if (!Token::Match(tok2->linkAt(2)->previous(), "%name%|] ("))
4150
0
                    return false;
4151
0
            }
4152
11.0k
        } else if (Token::Match(tok2, "&|&&")) {
4153
8
            ref = !bracket;
4154
11.0k
        } else if (singleNameCount >= 1 && Token::Match(tok2, "( [*&]") && Token::Match(tok2->link(), ") (|[")) {
4155
0
            for (const Token* tok3 = tok2->tokAt(2); Token::Match(tok3, "!!)"); tok3 = tok3->next()) {
4156
0
                if (Token::Match(tok3, "(|["))
4157
0
                    tok3 = tok3->link();
4158
0
                if (tok3->str() == ",")
4159
0
                    return false;
4160
0
            }
4161
0
            bracket = true; // Skip: Seems to be valid pointer to array or function pointer
4162
11.0k
        } else if (singleNameCount >= 1 && Token::Match(tok2, "( * %name% [") && Token::Match(tok2->linkAt(3), "] ) [;,]")) {
4163
0
            bracket = true;
4164
11.0k
        } else if (singleNameCount >= 1 && tok2->previous() && tok2->previous()->isStandardType() && Token::Match(tok2, "( *|&| %name% ) ;")) {
4165
0
            bracket = true;
4166
11.0k
        } else if (tok2->str() == "::") {
4167
0
            singleNameCount = 0;
4168
11.0k
        } else if (tok2->str() != "*" && tok2->str() != "::" && tok2->str() != "...") {
4169
11.0k
            break;
4170
11.0k
        }
4171
19.6k
        tok2 = tok2->next();
4172
19.6k
    }
4173
4174
19.4k
    if (tok2) {
4175
19.4k
        bool isLambdaArg = false;
4176
19.4k
        {
4177
19.4k
            const Token *tok3 = (*tok)->previous();
4178
19.4k
            if (tok3 && tok3->str() == ",") {
4179
0
                while (tok3 && !Token::Match(tok3,";|(|[|{")) {
4180
0
                    if (Token::Match(tok3, ")|]"))
4181
0
                        tok3 = tok3->link();
4182
0
                    tok3 = tok3->previous();
4183
0
                }
4184
4185
0
                if (tok3 && executableScope && Token::Match(tok3->previous(), "%name% (")) {
4186
0
                    const Token *fdecl = tok3->previous();
4187
0
                    int count = 0;
4188
0
                    while (Token::Match(fdecl, "%name%|*")) {
4189
0
                        fdecl = fdecl->previous();
4190
0
                        count++;
4191
0
                    }
4192
0
                    if (!Token::Match(fdecl, "[;{}] %name%") || count <= 1)
4193
0
                        return false;
4194
0
                }
4195
0
            }
4196
4197
19.4k
            if (cpp && tok3 && Token::simpleMatch(tok3->previous(), "] (") &&
4198
19.4k
                (Token::simpleMatch(tok3->link(), ") {") || Token::Match(tok3->link(), ") . %name%")))
4199
0
                isLambdaArg = true;
4200
19.4k
        }
4201
4202
4203
0
        *tok = tok2;
4204
4205
        // In executable scopes, references must be assigned
4206
        // Catching by reference is an exception
4207
19.4k
        if (executableScope && ref && !isLambdaArg) {
4208
8
            if (Token::Match(tok2, "(|=|{|:"))
4209
1
                ;   // reference is assigned => ok
4210
7
            else if (tok2->str() != ")" || tok2->link()->strAt(-1) != "catch")
4211
7
                return false;   // not catching by reference => not declaration
4212
8
        }
4213
19.4k
    }
4214
4215
    // Check if array declaration is valid (#2638)
4216
    // invalid declaration: AAA a[4] = 0;
4217
19.4k
    if (typeCount >= 2 && executableScope && Token::Match(tok2, ")| [")) {
4218
0
        const Token *tok3 = tok2->str() == ")" ? tok2->next() : tok2;
4219
0
        while (tok3 && tok3->str() == "[") {
4220
0
            tok3 = tok3->link()->next();
4221
0
        }
4222
0
        if (Token::Match(tok3, "= %num%"))
4223
0
            return false;
4224
0
        if (bracket && Token::Match(tok1->previous(), "[(,]") && Token::Match(tok3, "[,)]"))
4225
0
            return false;
4226
0
    }
4227
4228
19.4k
    return (typeCount >= 2 && tok2 && Token::Match(tok2->tokAt(-2), "!!:: %type%"));
4229
19.4k
}
4230
4231
4232
void Tokenizer::setVarIdStructMembers(Token **tok1,
4233
                                      std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
4234
                                      nonneg int &varId) const
4235
19.8k
{
4236
19.8k
    Token *tok = *tok1;
4237
4238
19.8k
    if (Token::Match(tok, "%name% = { . %name% =|{")) {
4239
0
        const nonneg int struct_varid = tok->varId();
4240
0
        if (struct_varid == 0)
4241
0
            return;
4242
4243
0
        std::map<std::string, nonneg int>& members = structMembers[struct_varid];
4244
4245
0
        tok = tok->tokAt(3);
4246
0
        while (tok->str() != "}") {
4247
0
            if (Token::Match(tok, "{|[|("))
4248
0
                tok = tok->link();
4249
0
            if (Token::Match(tok->previous(), "[,{] . %name% =|{")) {
4250
0
                tok = tok->next();
4251
0
                const std::map<std::string, nonneg int>::iterator it = members.find(tok->str());
4252
0
                if (it == members.end()) {
4253
0
                    members[tok->str()] = ++varId;
4254
0
                    tok->varId(varId);
4255
0
                } else {
4256
0
                    tok->varId(it->second);
4257
0
                }
4258
0
            }
4259
0
            tok = tok->next();
4260
0
        }
4261
4262
0
        return;
4263
0
    }
4264
4265
19.8k
    while (Token::Match(tok->next(), ")| . %name% !!(")) {
4266
        // Don't set varid for trailing return type
4267
0
        if (tok->strAt(1) == ")" && (tok->linkAt(1)->previous()->isName() || tok->linkAt(1)->strAt(-1) == "]") &&
4268
0
            isFunctionHead(tok->linkAt(1), "{|;")) {
4269
0
            tok = tok->tokAt(3);
4270
0
            continue;
4271
0
        }
4272
0
        const nonneg int struct_varid = tok->varId();
4273
0
        tok = tok->tokAt(2);
4274
0
        if (struct_varid == 0)
4275
0
            continue;
4276
4277
0
        if (tok->str() == ".")
4278
0
            tok = tok->next();
4279
4280
        // Don't set varid for template function
4281
0
        if (TemplateSimplifier::templateParameters(tok->next()) > 0)
4282
0
            break;
4283
4284
0
        std::map<std::string, nonneg int>& members = structMembers[struct_varid];
4285
0
        const std::map<std::string, nonneg int>::iterator it = members.find(tok->str());
4286
0
        if (it == members.end()) {
4287
0
            members[tok->str()] = ++varId;
4288
0
            tok->varId(varId);
4289
0
        } else {
4290
0
            tok->varId(it->second);
4291
0
        }
4292
0
    }
4293
    // tok can't be null
4294
19.8k
    *tok1 = tok;
4295
19.8k
}
4296
4297
void Tokenizer::setVarIdClassDeclaration(Token* const startToken,
4298
                                         VariableMap& variableMap,
4299
                                         const nonneg int scopeStartVarId,
4300
                                         std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers)
4301
0
{
4302
    // end of scope
4303
0
    const Token* const endToken = startToken->link();
4304
4305
    // determine class name
4306
0
    std::string className;
4307
0
    for (const Token *tok = startToken->previous(); tok; tok = tok->previous()) {
4308
0
        if (!tok->isName() && tok->str() != ":")
4309
0
            break;
4310
0
        if (Token::Match(tok, "class|struct|enum %type% [:{]")) {
4311
0
            className = tok->next()->str();
4312
0
            break;
4313
0
        }
4314
0
    }
4315
4316
    // replace varids..
4317
0
    int indentlevel = 0;
4318
0
    bool initList = false;
4319
0
    bool inEnum = false;
4320
0
    const Token *initListArgLastToken = nullptr;
4321
0
    for (Token *tok = startToken->next(); tok != endToken; tok = tok->next()) {
4322
0
        if (!tok)
4323
0
            syntaxError(nullptr);
4324
0
        if (initList) {
4325
0
            if (tok == initListArgLastToken)
4326
0
                initListArgLastToken = nullptr;
4327
0
            else if (!initListArgLastToken &&
4328
0
                     Token::Match(tok->previous(), "%name%|>|>> {|(") &&
4329
0
                     Token::Match(tok->link(), "}|) ,|{"))
4330
0
                initListArgLastToken = tok->link();
4331
0
        }
4332
0
        if (tok->str() == "{") {
4333
0
            inEnum = isEnumStart(tok);
4334
0
            if (initList && !initListArgLastToken)
4335
0
                initList = false;
4336
0
            ++indentlevel;
4337
0
        } else if (tok->str() == "}") {
4338
0
            --indentlevel;
4339
0
            inEnum = false;
4340
0
        } else if (initList && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %name% [({]")) {
4341
0
            const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
4342
0
            if (it != variableMap.map(false).end()) {
4343
0
                tok->varId(it->second);
4344
0
            }
4345
0
        } else if (tok->isName() && tok->varId() <= scopeStartVarId) {
4346
0
            if (indentlevel > 0 || initList) {
4347
0
                if (Token::Match(tok->previous(), "::|.") && tok->strAt(-2) != "this" && !Token::simpleMatch(tok->tokAt(-5), "( * this ) ."))
4348
0
                    continue;
4349
0
                if (!tok->next())
4350
0
                    syntaxError(nullptr);
4351
0
                if (tok->next()->str() == "::") {
4352
0
                    if (tok->str() == className)
4353
0
                        tok = tok->tokAt(2);
4354
0
                    else
4355
0
                        continue;
4356
0
                }
4357
4358
0
                if (!inEnum) {
4359
0
                    const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
4360
0
                    if (it != variableMap.map(false).end()) {
4361
0
                        tok->varId(it->second);
4362
0
                        setVarIdStructMembers(&tok, structMembers, variableMap.getVarId());
4363
0
                    }
4364
0
                }
4365
0
            }
4366
0
        } else if (indentlevel == 0 && tok->str() == ":" && !initListArgLastToken)
4367
0
            initList = true;
4368
0
    }
4369
0
}
4370
4371
4372
4373
// Update the variable ids..
4374
// Parse each function..
4375
void Tokenizer::setVarIdClassFunction(const std::string &classname,
4376
                                      Token * const startToken,
4377
                                      const Token * const endToken,
4378
                                      const std::map<std::string, nonneg int> &varlist,
4379
                                      std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
4380
                                      nonneg int &varId_)
4381
0
{
4382
0
    for (Token *tok2 = startToken; tok2 && tok2 != endToken; tok2 = tok2->next()) {
4383
0
        if (tok2->varId() != 0 || !tok2->isName())
4384
0
            continue;
4385
0
        if (Token::Match(tok2->tokAt(-2), ("!!" + classname + " ::").c_str()))
4386
0
            continue;
4387
0
        if (Token::Match(tok2->tokAt(-4), "%name% :: %name% ::")) // Currently unsupported
4388
0
            continue;
4389
0
        if (Token::Match(tok2->tokAt(-2), "!!this .") && !Token::simpleMatch(tok2->tokAt(-5), "( * this ) ."))
4390
0
            continue;
4391
0
        if (Token::Match(tok2, "%name% ::"))
4392
0
            continue;
4393
4394
0
        const std::map<std::string, nonneg int>::const_iterator it = varlist.find(tok2->str());
4395
0
        if (it != varlist.end()) {
4396
0
            tok2->varId(it->second);
4397
0
            setVarIdStructMembers(&tok2, structMembers, varId_);
4398
0
        }
4399
0
    }
4400
0
}
4401
4402
4403
4404
void Tokenizer::setVarId()
4405
1.36k
{
4406
    // Clear all variable ids
4407
93.6k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
4408
92.3k
        if (tok->isName())
4409
35.7k
            tok->varId(0);
4410
92.3k
    }
4411
4412
1.36k
    setVarIdPass1();
4413
4414
1.36k
    setPodTypes();
4415
4416
1.36k
    setVarIdPass2();
4417
1.36k
}
4418
4419
4420
// Variable declarations can't start with "return" etc.
4421
#define NOTSTART_C "NOT", "case", "default", "goto", "not", "return", "sizeof", "typedef"
4422
static const std::unordered_set<std::string> notstart_c = { NOTSTART_C };
4423
static const std::unordered_set<std::string> notstart_cpp = { NOTSTART_C,
4424
                                                              "delete", "friend", "new", "throw", "using", "virtual", "explicit", "const_cast", "dynamic_cast", "reinterpret_cast", "static_cast", "template"
4425
};
4426
4427
void Tokenizer::setVarIdPass1()
4428
1.36k
{
4429
    // Variable declarations can't start with "return" etc.
4430
1.36k
    const std::unordered_set<std::string>& notstart = (isC()) ? notstart_c : notstart_cpp;
4431
4432
1.36k
    VariableMap variableMap;
4433
1.36k
    std::map<nonneg int, std::map<std::string, nonneg int>> structMembers;
4434
4435
1.36k
    std::stack<VarIdScopeInfo> scopeStack;
4436
4437
1.36k
    scopeStack.emplace(/*VarIdScopeInfo()*/);
4438
1.36k
    std::stack<const Token *> functionDeclEndStack;
4439
1.36k
    const Token *functionDeclEndToken = nullptr;
4440
1.36k
    bool initlist = false;
4441
1.36k
    bool inlineFunction = false;
4442
80.0k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
4443
80.0k
        if (tok->isOp())
4444
15.0k
            continue;
4445
64.9k
        if (isCPP() && Token::simpleMatch(tok, "template <")) {
4446
0
            Token* closingBracket = tok->next()->findClosingBracket();
4447
0
            if (closingBracket)
4448
0
                tok = closingBracket;
4449
0
            continue;
4450
0
        }
4451
4452
64.9k
        if (tok == functionDeclEndToken) {
4453
3.12k
            functionDeclEndStack.pop();
4454
3.12k
            functionDeclEndToken = functionDeclEndStack.empty() ? nullptr : functionDeclEndStack.top();
4455
3.12k
            if (tok->str() == ":")
4456
0
                initlist = true;
4457
3.12k
            else if (tok->str() == ";") {
4458
0
                if (!variableMap.leaveScope())
4459
0
                    cppcheckError(tok);
4460
3.12k
            } else if (tok->str() == "{") {
4461
3.12k
                scopeStack.emplace(true, scopeStack.top().isStructInit || tok->strAt(-1) == "=", /*isEnum=*/ false, variableMap.getVarId());
4462
4463
                // check if this '{' is a start of an "if" body
4464
3.12k
                const Token * ifToken = tok->previous();
4465
3.12k
                if (ifToken && ifToken->str() == ")")
4466
3.12k
                    ifToken = ifToken->link();
4467
0
                else
4468
0
                    ifToken = nullptr;
4469
3.12k
                if (ifToken)
4470
3.12k
                    ifToken = ifToken->previous();
4471
3.12k
                if (ifToken && ifToken->str() == "if") {
4472
                    // open another scope to differentiate between variables declared in the "if" condition and in the "if" body
4473
920
                    variableMap.enterScope();
4474
920
                }
4475
3.12k
            }
4476
61.8k
        } else if (!initlist && tok->str()=="(") {
4477
3.82k
            const Token * newFunctionDeclEnd = nullptr;
4478
3.82k
            if (!scopeStack.top().isExecutable)
4479
1.74k
                newFunctionDeclEnd = isFunctionHead(tok, "{:;");
4480
2.08k
            else {
4481
2.08k
                const Token* tokenLinkNext = tok->link()->next();
4482
2.08k
                if (Token::simpleMatch(tokenLinkNext, ".")) { // skip trailing return type
4483
0
                    tokenLinkNext = tokenLinkNext->next();
4484
0
                    while (Token::Match(tokenLinkNext, "%name%|::")) {
4485
0
                        tokenLinkNext = tokenLinkNext->next();
4486
0
                        if (Token::simpleMatch(tokenLinkNext, "<") && tokenLinkNext->link())
4487
0
                            tokenLinkNext = tokenLinkNext->link()->next();
4488
0
                    }
4489
0
                }
4490
2.08k
                if (tokenLinkNext && tokenLinkNext->str() == "{") // might be for- or while-loop or if-statement
4491
1.38k
                    newFunctionDeclEnd = tokenLinkNext;
4492
2.08k
            }
4493
3.82k
            if (newFunctionDeclEnd && newFunctionDeclEnd != functionDeclEndToken) {
4494
3.12k
                functionDeclEndStack.push(newFunctionDeclEnd);
4495
3.12k
                functionDeclEndToken = newFunctionDeclEnd;
4496
3.12k
                variableMap.enterScope();
4497
3.12k
            }
4498
58.0k
        } else if (Token::Match(tok, "{|}")) {
4499
4.04k
            inlineFunction = false;
4500
4501
4.04k
            const Token * const startToken = (tok->str() == "{") ? tok : tok->link();
4502
4503
            // parse anonymous namespaces as part of the current scope
4504
4.04k
            if (!Token::Match(startToken->previous(), "union|struct|enum|namespace {") &&
4505
4.04k
                !(initlist && Token::Match(startToken->previous(), "%name%|>|>>|(") && Token::Match(startToken->link(), "} ,|{|)"))) {
4506
4507
4.04k
                if (tok->str() == "{") {
4508
458
                    bool isExecutable;
4509
458
                    const Token *prev = tok->previous();
4510
916
                    while (Token::Match(prev, "%name%|."))
4511
458
                        prev = prev->previous();
4512
458
                    const bool isLambda = prev && prev->str() == ")" && Token::simpleMatch(prev->link()->previous(), "] (");
4513
458
                    if ((!isLambda && (tok->strAt(-1) == ")" || Token::Match(tok->tokAt(-2), ") %type%"))) ||
4514
458
                        (initlist && tok->strAt(-1) == "}")) {
4515
0
                        isExecutable = true;
4516
458
                    } else {
4517
458
                        isExecutable = ((scopeStack.top().isExecutable || initlist || tok->strAt(-1) == "else") &&
4518
458
                                        !isClassStructUnionEnumStart(tok));
4519
458
                        if (!(scopeStack.top().isStructInit || tok->strAt(-1) == "="))
4520
458
                            variableMap.enterScope();
4521
458
                    }
4522
458
                    initlist = false;
4523
458
                    scopeStack.emplace(isExecutable, scopeStack.top().isStructInit || tok->strAt(-1) == "=", isEnumStart(tok), variableMap.getVarId());
4524
3.58k
                } else { /* if (tok->str() == "}") */
4525
3.58k
                    bool isNamespace = false;
4526
4.04k
                    for (const Token *tok1 = tok->link()->previous(); tok1 && tok1->isName(); tok1 = tok1->previous()) {
4527
458
                        if (tok1->str() == "namespace") {
4528
0
                            isNamespace = true;
4529
0
                            break;
4530
0
                        }
4531
458
                    }
4532
                    // Set variable ids in class declaration..
4533
3.58k
                    if (!initlist && !isC() && !scopeStack.top().isExecutable && tok->link() && !isNamespace) {
4534
0
                        setVarIdClassDeclaration(tok->link(),
4535
0
                                                 variableMap,
4536
0
                                                 scopeStack.top().startVarid,
4537
0
                                                 structMembers);
4538
0
                    }
4539
4540
3.58k
                    if (!scopeStack.top().isStructInit) {
4541
3.58k
                        variableMap.leaveScope();
4542
4543
                        // check if this '}' is an end of an "else" body or an "if" body without an "else" part
4544
3.58k
                        const Token * ifToken = startToken->previous();
4545
3.58k
                        if (ifToken && ifToken->str() == ")")
4546
3.12k
                            ifToken = ifToken->link()->previous();
4547
458
                        else
4548
458
                            ifToken = nullptr;
4549
3.58k
                        if (startToken->strAt(-1) == "else" || (ifToken && ifToken->str() == "if" && tok->strAt(1) != "else")) {
4550
                            // leave the extra scope used to differentiate between variables declared in the "if" condition and in the "if" body
4551
920
                            variableMap.leaveScope();
4552
920
                        }
4553
3.58k
                    }
4554
4555
3.58k
                    scopeStack.pop();
4556
3.58k
                    if (scopeStack.empty()) {  // should be impossible
4557
0
                        scopeStack.emplace(/*VarIdScopeInfo()*/);
4558
0
                    }
4559
3.58k
                }
4560
4.04k
            }
4561
4.04k
        }
4562
4563
64.9k
        if (!scopeStack.top().isStructInit &&
4564
64.9k
            (tok == list.front() ||
4565
64.9k
             Token::Match(tok, "[;{}]") ||
4566
64.9k
             (tok->str() == "(" && isFunctionHead(tok,"{")) ||
4567
64.9k
             (tok->str() == "(" && !scopeStack.top().isExecutable && isFunctionHead(tok,";:")) ||
4568
64.9k
             (tok->str() == "," && (!scopeStack.top().isExecutable || inlineFunction || !tok->previous()->varId())) ||
4569
64.9k
             (tok->isName() && endsWith(tok->str(), ':')))) {
4570
4571
            // No variable declarations in sizeof
4572
28.8k
            if (Token::simpleMatch(tok->previous(), "sizeof (")) {
4573
0
                continue;
4574
0
            }
4575
4576
28.8k
            if (Settings::terminated())
4577
0
                return;
4578
4579
            // locate the variable name..
4580
28.8k
            Token* tok2 = (tok->isName()) ? tok : tok->next();
4581
4582
            // private: protected: public: etc
4583
28.8k
            while (tok2 && endsWith(tok2->str(), ':')) {
4584
0
                tok2 = tok2->next();
4585
0
            }
4586
28.8k
            if (!tok2)
4587
1.36k
                break;
4588
4589
            // Variable declaration can't start with "return", etc
4590
27.4k
            if (notstart.find(tok2->str()) != notstart.end())
4591
1.91k
                continue;
4592
4593
25.5k
            if (!isC() && Token::simpleMatch(tok2, "const new"))
4594
0
                continue;
4595
4596
25.5k
            bool decl;
4597
25.5k
            if (isCPP() && mSettings->standards.cpp >= Standards::CPP17 && Token::Match(tok, "[(;{}] const| auto &|&&| [")) {
4598
                // Structured bindings
4599
0
                tok2 = Token::findsimplematch(tok, "[");
4600
0
                if ((Token::simpleMatch(tok->previous(), "for (") && Token::simpleMatch(tok2->link(), "] :")) ||
4601
0
                    Token::simpleMatch(tok2->link(), "] =")) {
4602
0
                    while (tok2 && tok2->str() != "]") {
4603
0
                        if (Token::Match(tok2, "%name% [,]]"))
4604
0
                            variableMap.addVariable(tok2->str(), false);
4605
0
                        tok2 = tok2->next();
4606
0
                    }
4607
0
                    continue;
4608
0
                }
4609
0
            }
4610
4611
25.5k
            try { /* Ticket #8151 */
4612
25.5k
                decl = setVarIdParseDeclaration(&tok2, variableMap, scopeStack.top().isExecutable, isCPP(), isC());
4613
25.5k
            } catch (const Token * errTok) {
4614
0
                syntaxError(errTok);
4615
0
            }
4616
25.5k
            if (decl) {
4617
8.55k
                if (isCPP()) {
4618
8.55k
                    if (Token *declTypeTok = Token::findsimplematch(tok, "decltype (", tok2)) {
4619
0
                        for (Token *declTok = declTypeTok->linkAt(1); declTok != declTypeTok; declTok = declTok->previous()) {
4620
0
                            if (declTok->isName() && !Token::Match(declTok->previous(), "::|.") && variableMap.hasVariable(declTok->str()))
4621
0
                                declTok->varId(variableMap.map(false).find(declTok->str())->second);
4622
0
                        }
4623
0
                    }
4624
8.55k
                }
4625
4626
8.55k
                if (tok->str() == "(" && isFunctionHead(tok,"{") && scopeStack.top().isExecutable)
4627
4
                    inlineFunction = true;
4628
4629
8.55k
                const Token* prev2 = tok2->previous();
4630
8.55k
                if (Token::Match(prev2, "%type% [;[=,)]") && tok2->previous()->str() != "const")
4631
6.81k
                    ;
4632
1.74k
                else if (Token::Match(prev2, "%type% :") && tok->strAt(-1) == "for")
4633
0
                    ;
4634
1.74k
                else if (Token::Match(prev2, "%type% ( !!)") && Token::simpleMatch(tok2->link(), ") ;")) {
4635
                    // In C++ , a variable can't be called operator+ or something like that.
4636
0
                    if (isCPP() &&
4637
0
                        prev2->isOperatorKeyword())
4638
0
                        continue;
4639
4640
0
                    const Token *tok3 = tok2->next();
4641
0
                    if (!tok3->isStandardType() && tok3->str() != "void" && !Token::Match(tok3, "struct|union|class %type%") && tok3->str() != "." && !Token::Match(tok2->link()->previous(), "[&*]")) {
4642
0
                        if (!scopeStack.top().isExecutable) {
4643
                            // Detecting initializations with () in non-executable scope is hard and often impossible to be done safely. Thus, only treat code as a variable that definitely is one.
4644
0
                            decl = false;
4645
0
                            bool rhs = false;
4646
0
                            for (; tok3; tok3 = tok3->nextArgumentBeforeCreateLinks2()) {
4647
0
                                if (tok3->str() == "=") {
4648
0
                                    rhs = true;
4649
0
                                    continue;
4650
0
                                }
4651
4652
0
                                if (tok3->str() == ",") {
4653
0
                                    rhs = false;
4654
0
                                    continue;
4655
0
                                }
4656
4657
0
                                if (rhs)
4658
0
                                    continue;
4659
4660
0
                                if (tok3->isLiteral() ||
4661
0
                                    (tok3->isName() && (variableMap.hasVariable(tok3->str()) ||
4662
0
                                                        (tok3->strAt(-1) == "(" && Token::simpleMatch(tok3->next(), "(") && !Token::simpleMatch(tok3->linkAt(1)->next(), "(")))) ||
4663
0
                                    tok3->isOp() ||
4664
0
                                    tok3->str() == "(" ||
4665
0
                                    notstart.find(tok3->str()) != notstart.end()) {
4666
0
                                    decl = true;
4667
0
                                    break;
4668
0
                                }
4669
0
                            }
4670
0
                        }
4671
0
                    } else
4672
0
                        decl = false;
4673
1.74k
                } else if (isCPP() && Token::Match(prev2, "%type% {") && Token::simpleMatch(tok2->link(), "} ;")) { // C++11 initialization style
4674
0
                    if (tok2->link() != tok2->next() && // add value-initialized variable T x{};
4675
0
                        (Token::Match(prev2, "do|try|else") || Token::Match(prev2->tokAt(-2), "struct|class|:")))
4676
0
                        continue;
4677
0
                } else
4678
1.74k
                    decl = false;
4679
4680
8.55k
                if (decl) {
4681
6.81k
                    if (isC() && Token::Match(prev2->previous(), "&|&&"))
4682
0
                        syntaxErrorC(prev2, prev2->strAt(-2) + prev2->strAt(-1) + " " + prev2->str());
4683
6.81k
                    variableMap.addVariable(prev2->str(), scopeStack.size() <= 1);
4684
4685
6.81k
                    if (Token::simpleMatch(tok->previous(), "for (") && Token::Match(prev2, "%name% [=,]")) {
4686
0
                        for (const Token *tok3 = prev2->next(); tok3 && tok3->str() != ";"; tok3 = tok3->next()) {
4687
0
                            if (Token::Match(tok3, "[([]"))
4688
0
                                tok3 = tok3->link();
4689
0
                            if (Token::Match(tok3, ", %name% [,=;]"))
4690
0
                                variableMap.addVariable(tok3->next()->str(), false);
4691
0
                        }
4692
0
                    }
4693
4694
                    // set varid for template parameters..
4695
6.81k
                    tok = tok->next();
4696
19.0k
                    while (Token::Match(tok, "%name%|::"))
4697
12.2k
                        tok = tok->next();
4698
6.81k
                    if (tok && tok->str() == "<") {
4699
0
                        const Token *end = tok->findClosingBracket();
4700
0
                        while (tok != end) {
4701
0
                            if (tok->isName() && !(Token::simpleMatch(tok->next(), "<") &&
4702
0
                                                   Token::Match(tok->tokAt(-1), ":: %name%"))) {
4703
0
                                const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
4704
0
                                if (it != variableMap.map(false).end())
4705
0
                                    tok->varId(it->second);
4706
0
                            }
4707
0
                            tok = tok->next();
4708
0
                        }
4709
0
                    }
4710
4711
6.81k
                    tok = tok2->previous();
4712
6.81k
                }
4713
8.55k
            }
4714
25.5k
        }
4715
4716
61.7k
        if (tok->isName() && !tok->isKeyword() && !tok->isStandardType()) {
4717
            // don't set variable id after a struct|enum|union
4718
23.4k
            if (Token::Match(tok->previous(), "struct|enum|union") || (isCPP() && tok->strAt(-1) == "class"))
4719
0
                continue;
4720
4721
23.4k
            bool globalNamespace = false;
4722
23.4k
            if (!isC()) {
4723
23.4k
                if (tok->previous() && tok->previous()->str() == "::") {
4724
0
                    if (Token::Match(tok->tokAt(-2), ")|]|%name%"))
4725
0
                        continue;
4726
0
                    globalNamespace = true;
4727
0
                }
4728
23.4k
                if (tok->next() && tok->next()->str() == "::")
4729
0
                    continue;
4730
23.4k
                if (Token::simpleMatch(tok->tokAt(-2), ":: template"))
4731
0
                    continue;
4732
23.4k
            }
4733
4734
            // function declaration inside executable scope? Function declaration is of form: type name "(" args ")"
4735
23.4k
            if (scopeStack.top().isExecutable && Token::Match(tok, "%name% [,)]")) {
4736
1.68k
                bool par = false;
4737
1.68k
                const Token *start, *end;
4738
4739
                // search begin of function declaration
4740
3.45k
                for (start = tok; Token::Match(start, "%name%|*|&|,|("); start = start->previous()) {
4741
2.03k
                    if (start->str() == "(") {
4742
242
                        if (par)
4743
1
                            break;
4744
241
                        par = true;
4745
241
                    }
4746
2.03k
                    if (Token::Match(start, "[(,]")) {
4747
241
                        if (!Token::Match(start, "[(,] %type% %name%|*|&"))
4748
236
                            break;
4749
241
                    }
4750
1.79k
                    if (start->varId() > 0)
4751
27
                        break;
4752
1.79k
                }
4753
4754
                // search end of function declaration
4755
1.68k
                for (end = tok->next(); Token::Match(end, "%name%|*|&|,"); end = end->next()) {}
4756
4757
                // there are tokens which can't appear at the begin of a function declaration such as "return"
4758
1.68k
                const bool isNotstartKeyword = start->next() && notstart.find(start->next()->str()) != notstart.end();
4759
4760
                // now check if it is a function declaration
4761
1.68k
                if (Token::Match(start, "[;{}] %type% %name%|*") && par && Token::simpleMatch(end, ") ;") && !isNotstartKeyword)
4762
                    // function declaration => don't set varid
4763
0
                    continue;
4764
1.68k
            }
4765
4766
23.4k
            if ((!scopeStack.top().isEnum || !(Token::Match(tok->previous(), "{|,") && Token::Match(tok->next(), ",|=|}"))) &&
4767
23.4k
                !Token::simpleMatch(tok->next(), ": ;")) {
4768
23.4k
                const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(globalNamespace).find(tok->str());
4769
23.4k
                if (it != variableMap.map(globalNamespace).end()) {
4770
19.8k
                    tok->varId(it->second);
4771
19.8k
                    setVarIdStructMembers(&tok, structMembers, variableMap.getVarId());
4772
19.8k
                }
4773
23.4k
            }
4774
38.2k
        } else if (Token::Match(tok, "::|. %name%") && Token::Match(tok->previous(), ")|]|>|%name%")) {
4775
            // Don't set varid after a :: or . token
4776
0
            tok = tok->next();
4777
38.2k
        } else if (tok->str() == ":" && Token::Match(tok->tokAt(-2), "class %type%")) {
4778
0
            do {
4779
0
                tok = tok->next();
4780
0
            } while (tok && (tok->isName() || tok->str() == ","));
4781
0
            if (!tok)
4782
0
                break;
4783
0
            tok = tok->previous();
4784
0
        }
4785
61.7k
    }
4786
4787
1.36k
    mVarId = variableMap.getVarId();
4788
1.36k
}
4789
4790
namespace {
4791
    struct Member {
4792
0
        Member(std::list<std::string> s, std::list<const Token *> ns, Token *t) : usingnamespaces(std::move(ns)), scope(std::move(s)), tok(t) {}
4793
        std::list<const Token *> usingnamespaces;
4794
        std::list<std::string> scope;
4795
        Token *tok;
4796
    };
4797
}
4798
4799
static std::string getScopeName(const std::list<ScopeInfo2> &scopeInfo)
4800
0
{
4801
0
    std::string ret;
4802
0
    for (const ScopeInfo2 &si : scopeInfo)
4803
0
        ret += (ret.empty() ? "" : " :: ") + (si.name);
4804
0
    return ret;
4805
0
}
4806
4807
static Token * matchMemberName(const std::list<std::string> &scope, const Token *nsToken, Token *memberToken, const std::list<ScopeInfo2> &scopeInfo)
4808
0
{
4809
0
    std::list<ScopeInfo2>::const_iterator scopeIt = scopeInfo.cbegin();
4810
4811
    // Current scope..
4812
0
    for (std::list<std::string>::const_iterator it = scope.cbegin(); it != scope.cend(); ++it) {
4813
0
        if (scopeIt == scopeInfo.cend() || scopeIt->name != *it)
4814
0
            return nullptr;
4815
0
        ++scopeIt;
4816
0
    }
4817
4818
    // using namespace..
4819
0
    if (nsToken) {
4820
0
        while (Token::Match(nsToken, "%name% ::")) {
4821
0
            if (scopeIt != scopeInfo.end() && nsToken->str() == scopeIt->name) {
4822
0
                nsToken = nsToken->tokAt(2);
4823
0
                ++scopeIt;
4824
0
            } else {
4825
0
                return nullptr;
4826
0
            }
4827
0
        }
4828
0
        if (!Token::Match(nsToken, "%name% ;"))
4829
0
            return nullptr;
4830
0
        if (scopeIt == scopeInfo.end() || nsToken->str() != scopeIt->name)
4831
0
            return nullptr;
4832
0
        ++scopeIt;
4833
0
    }
4834
4835
    // Parse member tokens..
4836
0
    while (scopeIt != scopeInfo.end()) {
4837
0
        if (!Token::Match(memberToken, "%name% ::|<"))
4838
0
            return nullptr;
4839
0
        if (memberToken->str() != scopeIt->name)
4840
0
            return nullptr;
4841
0
        if (memberToken->next()->str() == "<") {
4842
0
            memberToken = memberToken->next()->findClosingBracket();
4843
0
            if (!Token::simpleMatch(memberToken, "> ::"))
4844
0
                return nullptr;
4845
0
        }
4846
0
        memberToken = memberToken->tokAt(2);
4847
0
        ++scopeIt;
4848
0
    }
4849
4850
0
    return Token::Match(memberToken, "~| %name%") ? memberToken : nullptr;
4851
0
}
4852
4853
static Token * matchMemberName(const Member &member, const std::list<ScopeInfo2> &scopeInfo)
4854
0
{
4855
0
    if (scopeInfo.empty())
4856
0
        return nullptr;
4857
4858
    // Does this member match without "using namespace"..
4859
0
    Token *ret = matchMemberName(member.scope, nullptr, member.tok, scopeInfo);
4860
0
    if (ret)
4861
0
        return ret;
4862
4863
    // Try to match member using the "using namespace ..." namespaces..
4864
0
    for (const Token *ns : member.usingnamespaces) {
4865
0
        ret = matchMemberName(member.scope, ns, member.tok, scopeInfo);
4866
0
        if (ret)
4867
0
            return ret;
4868
0
    }
4869
4870
0
    return nullptr;
4871
0
}
4872
4873
static Token * matchMemberVarName(const Member &var, const std::list<ScopeInfo2> &scopeInfo)
4874
0
{
4875
0
    Token *tok = matchMemberName(var, scopeInfo);
4876
0
    if (Token::Match(tok, "%name%")) {
4877
0
        if (!tok->next() || tok->strAt(1) != "(" || (tok->tokAt(2) && tok->tokAt(2)->isLiteral()))
4878
0
            return tok;
4879
0
    }
4880
0
    return nullptr;
4881
0
}
4882
4883
static Token * matchMemberFunctionName(const Member &func, const std::list<ScopeInfo2> &scopeInfo)
4884
0
{
4885
0
    Token *tok = matchMemberName(func, scopeInfo);
4886
0
    return Token::Match(tok, "~| %name% (") ? tok : nullptr;
4887
0
}
4888
4889
template<typename T>
4890
static T* skipInitializerList(T* tok)
4891
0
{
4892
0
    T* const start = tok;
4893
0
    while (Token::Match(tok, "[:,] ::| %name%")) {
4894
0
        tok = tok->tokAt(tok->strAt(1) == "::" ? 1 : 2);
4895
0
        while (Token::Match(tok, ":: %name%"))
4896
0
            tok = tok->tokAt(2);
4897
0
        if (!Token::Match(tok, "[({<]") || !tok->link())
4898
0
            return start;
4899
0
        const bool isTemplate = tok->str() == "<";
4900
0
        tok = tok->link()->next();
4901
0
        if (isTemplate && tok && tok->link())
4902
0
            tok = tok->link()->next();
4903
0
    }
4904
0
    return tok;
4905
0
}
4906
4907
void Tokenizer::setVarIdPass2()
4908
1.36k
{
4909
1.36k
    std::map<nonneg int, std::map<std::string, nonneg int>> structMembers;
4910
4911
    // Member functions and variables in this source
4912
1.36k
    std::list<Member> allMemberFunctions;
4913
1.36k
    std::list<Member> allMemberVars;
4914
1.36k
    if (!isC()) {
4915
1.36k
        std::map<const Token *, std::string> endOfScope;
4916
1.36k
        std::list<std::string> scope;
4917
1.36k
        std::list<const Token *> usingnamespaces;
4918
93.6k
        for (Token *tok = list.front(); tok; tok = tok->next()) {
4919
92.3k
            if (!tok->previous() || Token::Match(tok->previous(), "[;{}]")) {
4920
24.2k
                if (Token::Match(tok, "using namespace %name% ::|;")) {
4921
0
                    Token *endtok = tok->tokAt(2);
4922
0
                    while (Token::Match(endtok, "%name% ::"))
4923
0
                        endtok = endtok->tokAt(2);
4924
0
                    if (Token::Match(endtok, "%name% ;"))
4925
0
                        usingnamespaces.push_back(tok->tokAt(2));
4926
0
                    tok = endtok;
4927
0
                    continue;
4928
0
                }
4929
24.2k
                if (Token::Match(tok, "namespace %name% {")) {
4930
0
                    scope.push_back(tok->strAt(1));
4931
0
                    endOfScope[tok->linkAt(2)] = tok->strAt(1);
4932
0
                }
4933
24.2k
            }
4934
4935
92.3k
            if (tok->str() == "}") {
4936
3.58k
                const std::map<const Token *, std::string>::iterator it = endOfScope.find(tok);
4937
3.58k
                if (it != endOfScope.end())
4938
0
                    scope.remove(it->second);
4939
3.58k
            }
4940
4941
92.3k
            Token* const tok1 = tok;
4942
92.3k
            if (Token::Match(tok, "%name% :: ~| %name%"))
4943
0
                tok = tok->next();
4944
92.3k
            else if (Token::Match(tok, "%name% <") && Token::Match(tok->next()->findClosingBracket(),"> :: ~| %name%"))
4945
0
                tok = tok->next()->findClosingBracket()->next();
4946
92.3k
            else if (usingnamespaces.empty() || tok->varId() || !tok->isName() || tok->isStandardType() || tok->tokType() == Token::eKeyword || tok->tokType() == Token::eBoolean ||
4947
92.3k
                     Token::Match(tok->previous(), ".|namespace|class|struct|&|&&|*|> %name%") || Token::Match(tok->previous(), "%type%| %name% ( %type%|)") || Token::Match(tok, "public:|private:|protected:") ||
4948
92.3k
                     (!tok->next() && Token::Match(tok->previous(), "}|; %name%")))
4949
92.3k
                continue;
4950
4951
0
            if (tok->strAt(-1) == "::" && tok->tokAt(-2) && tok->tokAt(-2)->isName())
4952
0
                continue;
4953
4954
0
            while (Token::Match(tok, ":: ~| %name%")) {
4955
0
                tok = tok->next();
4956
0
                if (tok->str() == "~")
4957
0
                    tok = tok->next();
4958
0
                else if (Token::Match(tok, "%name% <") && Token::Match(tok->next()->findClosingBracket(),"> :: ~| %name%"))
4959
0
                    tok = tok->next()->findClosingBracket()->next();
4960
0
                else if (Token::Match(tok, "%name% ::"))
4961
0
                    tok = tok->next();
4962
0
                else
4963
0
                    break;
4964
0
            }
4965
0
            if (!tok->next())
4966
0
                syntaxError(tok);
4967
0
            if (Token::Match(tok, "%name% (") && !(tok->tokAt(2) && tok->tokAt(2)->isLiteral()))
4968
0
                allMemberFunctions.emplace_back(scope, usingnamespaces, tok1);
4969
0
            else
4970
0
                allMemberVars.emplace_back(scope, usingnamespaces, tok1);
4971
0
        }
4972
1.36k
    }
4973
4974
1.36k
    std::list<ScopeInfo2> scopeInfo;
4975
4976
    // class members..
4977
1.36k
    std::map<std::string, std::map<std::string, nonneg int>> varsByClass;
4978
93.6k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
4979
92.3k
        while (tok->str() == "}" && !scopeInfo.empty() && tok == scopeInfo.back().bodyEnd)
4980
0
            scopeInfo.pop_back();
4981
4982
92.3k
        if (!Token::Match(tok, "namespace|class|struct %name% {|:|::|<"))
4983
92.3k
            continue;
4984
4985
0
        const std::string &scopeName(getScopeName(scopeInfo));
4986
0
        const std::string scopeName2(scopeName.empty() ? std::string() : (scopeName + " :: "));
4987
4988
0
        std::list<const Token *> classnameTokens;
4989
0
        classnameTokens.push_back(tok->next());
4990
0
        Token* tokStart = tok->tokAt(2);
4991
0
        while (Token::Match(tokStart, ":: %name%") || tokStart->str() == "<") {
4992
0
            if (tokStart->str() == "<") {
4993
                // skip the template part
4994
0
                Token* closeTok = tokStart->findClosingBracket();
4995
0
                if (!closeTok)
4996
0
                    syntaxError(tok);
4997
0
                tokStart = closeTok->next();
4998
0
            } else {
4999
0
                classnameTokens.push_back(tokStart->next());
5000
0
                tokStart = tokStart->tokAt(2);
5001
0
            }
5002
0
        }
5003
5004
0
        std::string classname;
5005
0
        for (const Token *it : classnameTokens)
5006
0
            classname += (classname.empty() ? "" : " :: ") + it->str();
5007
5008
0
        std::map<std::string, nonneg int> &thisClassVars = varsByClass[scopeName2 + classname];
5009
0
        while (Token::Match(tokStart, ":|::|,|%name%")) {
5010
0
            if (Token::Match(tokStart, "%name% <")) { // TODO: why skip templates?
5011
0
                tokStart = tokStart->next()->findClosingBracket();
5012
0
                if (tokStart)
5013
0
                    tokStart = tokStart->next();
5014
0
                continue;
5015
0
            }
5016
0
            if (Token::Match(tokStart, "%name% ,|{")) {
5017
0
                std::string baseClassName = tokStart->str();
5018
0
                const Token* baseStart = tokStart;
5019
0
                while (Token::Match(baseStart->tokAt(-2), "%name% ::")) { // build base class name
5020
0
                    baseClassName.insert(0, baseStart->strAt(-2) + " :: ");
5021
0
                    baseStart = baseStart->tokAt(-2);
5022
0
                }
5023
0
                std::string scopeName3(scopeName2);
5024
0
                while (!scopeName3.empty()) {
5025
0
                    const std::string name = scopeName3 + baseClassName;
5026
0
                    if (varsByClass.find(name) != varsByClass.end()) {
5027
0
                        baseClassName = name;
5028
0
                        break;
5029
0
                    }
5030
                    // Remove last scope name
5031
0
                    if (scopeName3.size() <= 8)
5032
0
                        break;
5033
0
                    scopeName3.erase(scopeName3.size() - 4);
5034
0
                    const std::string::size_type pos = scopeName3.rfind(" :: ");
5035
0
                    if (pos == std::string::npos)
5036
0
                        break;
5037
0
                    scopeName3.erase(pos + 4);
5038
0
                }
5039
0
                const std::map<std::string, nonneg int>& baseClassVars = varsByClass[baseClassName];
5040
0
                thisClassVars.insert(baseClassVars.cbegin(), baseClassVars.cend());
5041
0
            }
5042
0
            tokStart = tokStart->next();
5043
0
        }
5044
0
        if (!Token::simpleMatch(tokStart, "{"))
5045
0
            continue;
5046
5047
        // What member variables are there in this class?
5048
0
        std::transform(classnameTokens.cbegin(), classnameTokens.cend(), std::back_inserter(scopeInfo), [&](const Token* tok) {
5049
0
            return ScopeInfo2(tok->str(), tokStart->link());
5050
0
        });
5051
5052
0
        for (Token *tok2 = tokStart->next(); tok2 && tok2 != tokStart->link(); tok2 = tok2->next()) {
5053
            // skip parentheses..
5054
0
            if (tok2->link()) {
5055
0
                if (tok2->str() == "(") {
5056
0
                    Token *funcstart = const_cast<Token*>(isFunctionHead(tok2, "{"));
5057
0
                    if (funcstart) {
5058
0
                        setVarIdClassFunction(scopeName2 + classname, funcstart, funcstart->link(), thisClassVars, structMembers, mVarId);
5059
0
                        tok2 = funcstart->link();
5060
0
                        continue;
5061
0
                    }
5062
0
                }
5063
0
                if (tok2->str() == "{") {
5064
0
                    if (tok2->strAt(-1) == ")")
5065
0
                        setVarIdClassFunction(scopeName2 + classname, tok2, tok2->link(), thisClassVars, structMembers, mVarId);
5066
0
                    tok2 = tok2->link();
5067
0
                } else if (Token::Match(tok2, "( %name%|)") && !Token::Match(tok2->link(), "(|[")) {
5068
0
                    tok2 = tok2->link();
5069
5070
                    // Skip initialization list
5071
0
                    if (Token::simpleMatch(tok2, ") :"))
5072
0
                        tok2 = skipInitializerList(tok2->next());
5073
0
                }
5074
0
            }
5075
5076
            // Found a member variable..
5077
0
            else if (tok2->varId() > 0)
5078
0
                thisClassVars[tok2->str()] = tok2->varId();
5079
0
        }
5080
5081
        // Are there any member variables in this class?
5082
0
        if (thisClassVars.empty())
5083
0
            continue;
5084
5085
        // Member variables
5086
0
        for (const Member &var : allMemberVars) {
5087
0
            Token *tok2 = matchMemberVarName(var, scopeInfo);
5088
0
            if (!tok2)
5089
0
                continue;
5090
0
            if (tok2->varId() == 0)
5091
0
                tok2->varId(thisClassVars[tok2->str()]);
5092
0
        }
5093
5094
0
        if (isC() || tok->str() == "namespace")
5095
0
            continue;
5096
5097
        // Set variable ids in member functions for this class..
5098
0
        for (const Member &func : allMemberFunctions) {
5099
0
            Token *tok2 = matchMemberFunctionName(func, scopeInfo);
5100
0
            if (!tok2)
5101
0
                continue;
5102
5103
0
            if (tok2->str() == "~")
5104
0
                tok2 = tok2->linkAt(2);
5105
0
            else
5106
0
                tok2 = tok2->linkAt(1);
5107
5108
            // If this is a function implementation.. add it to funclist
5109
0
            Token * start = const_cast<Token *>(isFunctionHead(tok2, "{"));
5110
0
            if (start) {
5111
0
                setVarIdClassFunction(classname, start, start->link(), thisClassVars, structMembers, mVarId);
5112
0
            }
5113
5114
0
            if (Token::Match(tok2, ") %name% ("))
5115
0
                tok2 = tok2->linkAt(2);
5116
5117
            // constructor with initializer list
5118
0
            if (!Token::Match(tok2, ") : ::| %name%"))
5119
0
                continue;
5120
5121
0
            Token *tok3 = tok2;
5122
0
            while (Token::Match(tok3, "[)}] [,:]")) {
5123
0
                tok3 = tok3->tokAt(2);
5124
0
                if (Token::Match(tok3, ":: %name%"))
5125
0
                    tok3 = tok3->next();
5126
0
                while (Token::Match(tok3, "%name% :: %name%"))
5127
0
                    tok3 = tok3->tokAt(2);
5128
0
                if (!Token::Match(tok3, "%name% (|{|<"))
5129
0
                    break;
5130
5131
                // set varid
5132
0
                const std::map<std::string, nonneg int>::const_iterator varpos = thisClassVars.find(tok3->str());
5133
0
                if (varpos != thisClassVars.end())
5134
0
                    tok3->varId(varpos->second);
5135
5136
                // goto end of var
5137
0
                if (tok3->strAt(1) == "<") {
5138
0
                    tok3 = tok3->next()->findClosingBracket();
5139
0
                    if (tok3 && tok3->next() && tok3->next()->link())
5140
0
                        tok3 = tok3->next()->link();
5141
0
                } else
5142
0
                    tok3 = tok3->linkAt(1);
5143
0
            }
5144
0
            if (Token::Match(tok3, ")|} {")) {
5145
0
                setVarIdClassFunction(classname, tok2, tok3->next()->link(), thisClassVars, structMembers, mVarId);
5146
0
            }
5147
0
        }
5148
0
    }
5149
1.36k
}
5150
5151
static void linkBrackets(const Tokenizer * const tokenizer, std::stack<const Token*>& type, std::stack<Token*>& links, Token * const token, const char open, const char close)
5152
241k
{
5153
241k
    if (token->str()[0] == open) {
5154
7.63k
        links.push(token);
5155
7.63k
        type.push(token);
5156
233k
    } else if (token->str()[0] == close) {
5157
7.63k
        if (links.empty()) {
5158
            // Error, { and } don't match.
5159
0
            tokenizer->unmatchedToken(token);
5160
0
        }
5161
7.63k
        if (type.top()->str()[0] != open) {
5162
0
            tokenizer->unmatchedToken(type.top());
5163
0
        }
5164
7.63k
        type.pop();
5165
5166
7.63k
        Token::createMutualLinks(links.top(), token);
5167
7.63k
        links.pop();
5168
7.63k
    }
5169
241k
}
5170
5171
void Tokenizer::createLinks()
5172
1.36k
{
5173
1.36k
    std::stack<const Token*> type;
5174
1.36k
    std::stack<Token*> links1;
5175
1.36k
    std::stack<Token*> links2;
5176
1.36k
    std::stack<Token*> links3;
5177
81.8k
    for (Token *token = list.front(); token; token = token->next()) {
5178
80.4k
        if (token->link()) {
5179
0
            token->link(nullptr);
5180
0
        }
5181
5182
80.4k
        linkBrackets(this, type, links1, token, '{', '}');
5183
5184
80.4k
        linkBrackets(this, type, links2, token, '(', ')');
5185
5186
80.4k
        linkBrackets(this, type, links3, token, '[', ']');
5187
80.4k
    }
5188
5189
1.36k
    if (!links1.empty()) {
5190
        // Error, { and } don't match.
5191
0
        unmatchedToken(links1.top());
5192
0
    }
5193
5194
1.36k
    if (!links2.empty()) {
5195
        // Error, ( and ) don't match.
5196
0
        unmatchedToken(links2.top());
5197
0
    }
5198
5199
1.36k
    if (!links3.empty()) {
5200
        // Error, [ and ] don't match.
5201
0
        unmatchedToken(links3.top());
5202
0
    }
5203
1.36k
}
5204
5205
void Tokenizer::createLinks2()
5206
1.36k
{
5207
1.36k
    if (isC())
5208
0
        return;
5209
5210
1.36k
    bool isStruct = false;
5211
5212
1.36k
    std::stack<Token*> type;
5213
1.36k
    std::stack<Token*> templateTokens;
5214
93.6k
    for (Token *token = list.front(); token; token = token->next()) {
5215
92.3k
        if (Token::Match(token, "%name%|> %name% [:<]"))
5216
21
            isStruct = true;
5217
92.2k
        else if (Token::Match(token, "[;{}]"))
5218
24.2k
            isStruct = false;
5219
5220
92.3k
        if (token->link()) {
5221
14.8k
            if (Token::Match(token, "{|[|("))
5222
7.40k
                type.push(token);
5223
7.40k
            else if (!type.empty() && Token::Match(token, "}|]|)")) {
5224
7.48k
                while (type.top()->str() == "<") {
5225
72
                    if (!templateTokens.empty() && templateTokens.top()->next() == type.top())
5226
0
                        templateTokens.pop();
5227
72
                    type.pop();
5228
72
                }
5229
7.40k
                type.pop();
5230
7.40k
            }
5231
77.4k
        } else if (templateTokens.empty() && !isStruct && Token::Match(token, "%oror%|&&|;")) {
5232
17.0k
            if (Token::Match(token, "&& [,>]"))
5233
0
                continue;
5234
            // If there is some such code:  A<B||C>..
5235
            // Then this is probably a template instantiation if either "B" or "C" has comparisons
5236
17.0k
            if (token->tokType() == Token::eLogicalOp && !type.empty() && type.top()->str() == "<") {
5237
0
                const Token *prev = token->previous();
5238
0
                bool foundComparison = false;
5239
0
                while (Token::Match(prev, "%name%|%num%|%str%|%cop%|)|]") && prev != type.top()) {
5240
0
                    if (prev->str() == ")" || prev->str() == "]")
5241
0
                        prev = prev->link();
5242
0
                    else if (prev->tokType() == Token::eLogicalOp)
5243
0
                        break;
5244
0
                    else if (prev->isComparisonOp())
5245
0
                        foundComparison = true;
5246
0
                    prev = prev->previous();
5247
0
                }
5248
0
                if (prev == type.top() && foundComparison)
5249
0
                    continue;
5250
0
                const Token *next = token->next();
5251
0
                foundComparison = false;
5252
0
                while (Token::Match(next, "%name%|%num%|%str%|%cop%|(|[") && next->str() != ">") {
5253
0
                    if (next->str() == "(" || next->str() == "[")
5254
0
                        next = next->link();
5255
0
                    else if (next->tokType() == Token::eLogicalOp)
5256
0
                        break;
5257
0
                    else if (next->isComparisonOp())
5258
0
                        foundComparison = true;
5259
0
                    next = next->next();
5260
0
                }
5261
0
                if (next && next->str() == ">" && foundComparison)
5262
0
                    continue;
5263
0
            }
5264
5265
17.1k
            while (!type.empty() && type.top()->str() == "<") {
5266
27
                const Token* end = type.top()->findClosingBracket();
5267
27
                if (Token::Match(end, "> %comp%|;|.|=|{|::"))
5268
0
                    break;
5269
                // Variable declaration
5270
27
                if (Token::Match(end, "> %var% ;") && (type.top()->tokAt(-2) == nullptr || Token::Match(type.top()->tokAt(-2), ";|}|{")))
5271
0
                    break;
5272
27
                type.pop();
5273
27
            }
5274
60.4k
        } else if (token->str() == "<" &&
5275
60.4k
                   ((token->previous() && (token->previous()->isTemplate() ||
5276
524
                                           (token->previous()->isName() && !token->previous()->varId()) ||
5277
524
                                           (token->strAt(-1) == "]" && (!Token::Match(token->linkAt(-1)->previous(), "%name%|)") || token->linkAt(-1)->previous()->isKeyword())) ||
5278
524
                                           (token->strAt(-1) == ")" && token->linkAt(-1)->strAt(-1) == "operator"))) ||
5279
524
                    Token::Match(token->next(), ">|>>"))) {
5280
115
            type.push(token);
5281
115
            if (token->previous()->str() == "template")
5282
0
                templateTokens.push(token);
5283
60.3k
        } else if (token->str() == ">" || token->str() == ">>") {
5284
501
            if (type.empty() || type.top()->str() != "<") // < and > don't match.
5285
482
                continue;
5286
19
            Token * const top1 = type.top();
5287
19
            type.pop();
5288
19
            Token * const top2 = type.empty() ? nullptr : type.top();
5289
19
            type.push(top1);
5290
19
            if (!top2 || top2->str() != "<") {
5291
19
                if (token->str() == ">>")
5292
0
                    continue;
5293
19
                if (!Token::Match(token->next(), "%name%|%cop%|%assign%|::|,|(|)|{|}|;|[|]|:|.|=|...") &&
5294
19
                    !Token::Match(token->next(), "&& %name% ="))
5295
3
                    continue;
5296
19
            }
5297
5298
16
            if (token->str() == ">>" && top1 && top2) {
5299
0
                type.pop();
5300
0
                type.pop();
5301
                // Split the angle brackets
5302
0
                token->str(">");
5303
0
                Token::createMutualLinks(top1, token->insertTokenBefore(">"));
5304
0
                Token::createMutualLinks(top2, token);
5305
0
                if (templateTokens.size() == 2 && (top1 == templateTokens.top() || top2 == templateTokens.top())) {
5306
0
                    templateTokens.pop();
5307
0
                    templateTokens.pop();
5308
0
                }
5309
16
            } else {
5310
16
                type.pop();
5311
16
                if (Token::Match(token, "> %name%") && !token->next()->isKeyword() &&
5312
16
                    Token::Match(top1->tokAt(-2), "%op% %name% <") && top1->strAt(-2) != "<" &&
5313
16
                    (templateTokens.empty() || top1 != templateTokens.top()))
5314
12
                    continue;
5315
4
                Token::createMutualLinks(top1, token);
5316
4
                if (!templateTokens.empty() && top1 == templateTokens.top())
5317
0
                    templateTokens.pop();
5318
4
            }
5319
16
        }
5320
92.3k
    }
5321
1.36k
}
5322
5323
void Tokenizer::sizeofAddParentheses()
5324
1.36k
{
5325
80.4k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
5326
79.1k
        if (!Token::Match(tok, "sizeof !!("))
5327
79.1k
            continue;
5328
0
        if (tok->next()->isLiteral() || Token::Match(tok->next(), "%name%|*|~|!|&")) {
5329
0
            Token *endToken = tok->next();
5330
0
            while (Token::simpleMatch(endToken, "* *"))
5331
0
                endToken = endToken->next();
5332
0
            while (Token::Match(endToken->next(), "%name%|%num%|%str%|[|(|.|::|++|--|!|~") || (Token::Match(endToken, "%type% * %op%|?|:|const|;|,"))) {
5333
0
                if (Token::Match(endToken->next(), "(|["))
5334
0
                    endToken = endToken->linkAt(1);
5335
0
                else
5336
0
                    endToken = endToken->next();
5337
0
            }
5338
5339
            // Add ( after sizeof and ) behind endToken
5340
0
            tok->insertToken("(");
5341
0
            endToken->insertToken(")");
5342
0
            Token::createMutualLinks(tok->next(), endToken->next());
5343
0
        }
5344
0
    }
5345
1.36k
}
5346
5347
bool Tokenizer::simplifyTokenList1(const char FileName[])
5348
1.36k
{
5349
1.36k
    if (Settings::terminated())
5350
0
        return false;
5351
5352
    // if MACRO
5353
81.8k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
5354
80.4k
        if (Token::Match(tok, "if|for|while|BOOST_FOREACH %name% (")) {
5355
0
            if (Token::simpleMatch(tok, "for each")) {
5356
                // 'for each ( )' -> 'asm ( )'
5357
0
                tok->str("asm");
5358
0
                tok->deleteNext();
5359
0
            } else if (tok->strAt(1) == "constexpr") {
5360
0
                tok->deleteNext();
5361
0
                tok->isConstexpr(true);
5362
0
            } else {
5363
0
                syntaxError(tok);
5364
0
            }
5365
0
        }
5366
80.4k
    }
5367
5368
    // Is there C++ code in C file?
5369
1.36k
    validateC();
5370
5371
    // Combine strings and character literals, e.g. L"string", L'c', "string1" "string2"
5372
1.36k
    combineStringAndCharLiterals();
5373
5374
    // replace inline SQL with "asm()" (Oracle PRO*C). Ticket: #1959
5375
1.36k
    simplifySQL();
5376
5377
1.36k
    createLinks();
5378
5379
    // Simplify debug intrinsics
5380
1.36k
    simplifyDebug();
5381
5382
1.36k
    removePragma();
5383
5384
    // Simplify the C alternative tokens (and, or, etc.)
5385
1.36k
    simplifyCAlternativeTokens();
5386
5387
1.36k
    simplifyFunctionTryCatch();
5388
5389
1.36k
    simplifyHeadersAndUnusedTemplates();
5390
5391
    // Remove __asm..
5392
1.36k
    simplifyAsm();
5393
5394
    // foo < bar < >> => foo < bar < > >
5395
1.36k
    if (isCPP() || mSettings->daca)
5396
1.36k
        splitTemplateRightAngleBrackets(!isCPP());
5397
5398
    // Remove extra "template" tokens that are not used by cppcheck
5399
1.36k
    removeExtraTemplateKeywords();
5400
5401
1.36k
    simplifySpaceshipOperator();
5402
5403
    // Bail out if code is garbage
5404
1.36k
    if (mTimerResults) {
5405
0
        Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::findGarbageCode", mSettings->showtime, mTimerResults);
5406
0
        findGarbageCode();
5407
1.36k
    } else {
5408
1.36k
        findGarbageCode();
5409
1.36k
    }
5410
5411
1.36k
    checkConfiguration();
5412
5413
    // if (x) MACRO() ..
5414
73.6k
    for (const Token *tok = list.front(); tok; tok = tok->next()) {
5415
72.3k
        if (Token::simpleMatch(tok, "if (")) {
5416
920
            tok = tok->next()->link();
5417
920
            if (Token::Match(tok, ") %name% (") &&
5418
920
                tok->next()->isUpperCaseName() &&
5419
920
                Token::Match(tok->linkAt(2), ") {|else")) {
5420
0
                syntaxError(tok->next());
5421
0
            }
5422
920
        }
5423
72.3k
    }
5424
5425
1.36k
    if (Settings::terminated())
5426
0
        return false;
5427
5428
    // convert C++17 style nested namespaces to old style namespaces
5429
1.36k
    simplifyNestedNamespace();
5430
5431
    // convert c++20 coroutines
5432
1.36k
    simplifyCoroutines();
5433
5434
    // simplify namespace aliases
5435
1.36k
    simplifyNamespaceAliases();
5436
5437
    // Remove [[attribute]]
5438
1.36k
    simplifyCPPAttribute();
5439
5440
    // remove __attribute__((?))
5441
1.36k
    simplifyAttribute();
5442
5443
    // simplify cppcheck attributes __cppcheck_?__(?)
5444
1.36k
    simplifyCppcheckAttribute();
5445
5446
    // Combine tokens..
5447
1.36k
    combineOperators();
5448
5449
    // combine "- %num%"
5450
1.36k
    concatenateNegativeNumberAndAnyPositive();
5451
5452
    // remove extern "C" and extern "C" {}
5453
1.36k
    if (isCPP())
5454
1.36k
        simplifyExternC();
5455
5456
    // simplify weird but legal code: "[;{}] ( { code; } ) ;"->"[;{}] code;"
5457
1.36k
    simplifyRoundCurlyParentheses();
5458
5459
    // check for simple syntax errors..
5460
80.4k
    for (const Token *tok = list.front(); tok; tok = tok->next()) {
5461
79.1k
        if (Token::simpleMatch(tok, "> struct {") &&
5462
79.1k
            Token::simpleMatch(tok->linkAt(2), "} ;")) {
5463
0
            syntaxError(tok);
5464
0
        }
5465
79.1k
    }
5466
5467
1.36k
    if (!simplifyAddBraces())
5468
0
        return false;
5469
5470
1.36k
    sizeofAddParentheses();
5471
5472
    // Simplify: 0[foo] -> *(foo)
5473
80.4k
    for (Token* tok = list.front(); tok; tok = tok->next()) {
5474
79.1k
        if (Token::simpleMatch(tok, "0 [") && tok->linkAt(1)) {
5475
0
            tok->str("*");
5476
0
            tok->next()->str("(");
5477
0
            tok->linkAt(1)->str(")");
5478
0
        }
5479
79.1k
    }
5480
5481
1.36k
    if (Settings::terminated())
5482
0
        return false;
5483
5484
    // Remove __declspec()
5485
1.36k
    simplifyDeclspec();
5486
1.36k
    validate();
5487
5488
    // Remove "inline", "register", and "restrict"
5489
1.36k
    simplifyKeyword();
5490
5491
    // simplify simple calculations inside <..>
5492
1.36k
    if (isCPP()) {
5493
1.36k
        Token *lt = nullptr;
5494
80.4k
        for (Token *tok = list.front(); tok; tok = tok->next()) {
5495
79.1k
            if (Token::Match(tok, "[;{}]"))
5496
17.4k
                lt = nullptr;
5497
61.7k
            else if (Token::Match(tok, "%type% <"))
5498
395
                lt = tok->next();
5499
61.3k
            else if (lt && Token::Match(tok, ">|>> %name%|::|(")) {
5500
41
                const Token * const end = tok;
5501
181
                for (tok = lt; tok != end; tok = tok->next()) {
5502
140
                    if (tok->isNumber())
5503
14
                        TemplateSimplifier::simplifyNumericCalculations(tok);
5504
140
                }
5505
41
                lt = tok->next();
5506
41
            }
5507
79.1k
        }
5508
1.36k
    }
5509
5510
    // Convert K&R function declarations to modern C
5511
1.36k
    simplifyVarDecl(true);
5512
1.36k
    simplifyFunctionParameters();
5513
5514
    // simplify case ranges (gcc extension)
5515
1.36k
    simplifyCaseRange();
5516
5517
    // simplify labels and 'case|default'-like syntaxes
5518
1.36k
    simplifyLabelsCaseDefault();
5519
5520
1.36k
    if (!isC() && !mSettings->library.markupFile(FileName)) {
5521
1.36k
        findComplicatedSyntaxErrorsInTemplates();
5522
1.36k
    }
5523
5524
1.36k
    if (Settings::terminated())
5525
0
        return false;
5526
5527
    // remove calling conventions __cdecl, __stdcall..
5528
1.36k
    simplifyCallingConvention();
5529
5530
1.36k
    addSemicolonAfterUnknownMacro();
5531
5532
    // remove some unhandled macros in global scope
5533
1.36k
    removeMacrosInGlobalScope();
5534
5535
    // remove undefined macro in class definition:
5536
    // class DLLEXPORT Fred { };
5537
    // class Fred FINAL : Base { };
5538
1.36k
    removeMacroInClassDef();
5539
5540
    // That call here fixes #7190
5541
1.36k
    validate();
5542
5543
    // remove unnecessary member qualification..
5544
1.36k
    removeUnnecessaryQualification();
5545
5546
    // convert Microsoft memory functions
5547
1.36k
    simplifyMicrosoftMemoryFunctions();
5548
5549
    // convert Microsoft string functions
5550
1.36k
    simplifyMicrosoftStringFunctions();
5551
5552
1.36k
    if (Settings::terminated())
5553
0
        return false;
5554
5555
    // remove Borland stuff..
5556
1.36k
    simplifyBorland();
5557
5558
    // syntax error: enum with typedef in it
5559
1.36k
    checkForEnumsWithTypedef();
5560
5561
    // Add parentheses to ternary operator where necessary
5562
1.36k
    prepareTernaryOpForAST();
5563
5564
    // Change initialisation of variable to assignment
5565
1.36k
    simplifyInitVar();
5566
5567
    // Split up variable declarations.
5568
1.36k
    simplifyVarDecl(false);
5569
5570
1.36k
    reportUnknownMacros();
5571
5572
1.36k
    simplifyTypedefLHS();
5573
5574
    // typedef..
5575
1.36k
    if (mTimerResults) {
5576
0
        Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTypedef", mSettings->showtime, mTimerResults);
5577
0
        simplifyTypedef();
5578
1.36k
    } else {
5579
1.36k
        simplifyTypedef();
5580
1.36k
    }
5581
5582
    // using A = B;
5583
1.36k
    while (simplifyUsing())
5584
0
        ;
5585
5586
    // Add parentheses to ternary operator where necessary
5587
    // TODO: this is only necessary if one typedef simplification had a comma and was used within ?:
5588
    // If typedef handling is refactored and moved to symboldatabase someday we can remove this
5589
1.36k
    prepareTernaryOpForAST();
5590
5591
94.1k
    for (Token* tok = list.front(); tok;) {
5592
92.7k
        if (Token::Match(tok, "union|struct|class union|struct|class"))
5593
0
            tok->deleteNext();
5594
92.7k
        else
5595
92.7k
            tok = tok->next();
5596
92.7k
    }
5597
5598
    // class x y {
5599
1.36k
    if (isCPP() && mSettings->severity.isEnabled(Severity::information)) {
5600
94.1k
        for (const Token *tok = list.front(); tok; tok = tok->next()) {
5601
92.7k
            if (Token::Match(tok, "class %type% %type% [:{]")) {
5602
0
                unhandled_macro_class_x_y(tok);
5603
0
            }
5604
92.7k
        }
5605
1.36k
    }
5606
5607
    // catch bad typedef canonicalization
5608
    //
5609
    // to reproduce bad typedef, download upx-ucl from:
5610
    // http://packages.debian.org/sid/upx-ucl
5611
    // analyse the file src/stub/src/i386-linux.elf.interp-main.c
5612
1.36k
    validate();
5613
5614
    // The simplify enum have inner loops
5615
1.36k
    if (Settings::terminated())
5616
0
        return false;
5617
5618
    // Put ^{} statements in asm()
5619
1.36k
    simplifyAsm2();
5620
5621
    // @..
5622
1.36k
    simplifyAt();
5623
5624
    // When the assembly code has been cleaned up, no @ is allowed
5625
79.9k
    for (const Token *tok = list.front(); tok; tok = tok->next()) {
5626
78.5k
        if (tok->str() == "(") {
5627
3.50k
            const Token *tok1 = tok;
5628
3.50k
            tok = tok->link();
5629
3.50k
            if (!tok)
5630
0
                syntaxError(tok1);
5631
75.0k
        } else if (tok->str() == "@") {
5632
0
            syntaxError(tok);
5633
0
        }
5634
78.5k
    }
5635
5636
    // Order keywords "static" and "const"
5637
1.36k
    simplifyStaticConst();
5638
5639
    // convert platform dependent types to standard types
5640
    // 32 bits: size_t -> unsigned long
5641
    // 64 bits: size_t -> unsigned long long
5642
1.36k
    list.simplifyPlatformTypes();
5643
5644
    // collapse compound standard types into a single token
5645
    // unsigned long long int => long (with _isUnsigned=true,_isLong=true)
5646
1.36k
    list.simplifyStdType();
5647
5648
1.36k
    if (Settings::terminated())
5649
0
        return false;
5650
5651
    // simplify bit fields..
5652
1.36k
    simplifyBitfields();
5653
5654
1.36k
    if (Settings::terminated())
5655
0
        return false;
5656
5657
    // struct simplification "struct S {} s; => struct S { } ; S s ;
5658
1.36k
    simplifyStructDecl();
5659
5660
1.36k
    if (Settings::terminated())
5661
0
        return false;
5662
5663
    // x = ({ 123; });  =>   { x = 123; }
5664
1.36k
    simplifyAssignmentBlock();
5665
5666
1.36k
    if (Settings::terminated())
5667
0
        return false;
5668
5669
1.36k
    simplifyVariableMultipleAssign();
5670
5671
    // Collapse operator name tokens into single token
5672
    // operator = => operator=
5673
1.36k
    simplifyOperatorName();
5674
5675
    // Remove redundant parentheses
5676
1.36k
    simplifyRedundantParentheses();
5677
5678
1.36k
    if (isCPP())
5679
1.36k
        simplifyTypeIntrinsics();
5680
5681
1.36k
    if (!isC()) {
5682
        // Handle templates..
5683
1.36k
        if (mTimerResults) {
5684
0
            Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTemplates", mSettings->showtime, mTimerResults);
5685
0
            simplifyTemplates();
5686
1.36k
        } else {
5687
1.36k
            simplifyTemplates();
5688
1.36k
        }
5689
5690
        // The simplifyTemplates have inner loops
5691
1.36k
        if (Settings::terminated())
5692
0
            return false;
5693
5694
1.36k
        validate(); // #6847 - invalid code
5695
1.36k
    }
5696
5697
    // Simplify pointer to standard types (C only)
5698
1.36k
    simplifyPointerToStandardType();
5699
5700
    // simplify function pointers
5701
1.36k
    simplifyFunctionPointers();
5702
5703
    // Change initialisation of variable to assignment
5704
1.36k
    simplifyInitVar();
5705
5706
    // Split up variable declarations.
5707
1.36k
    simplifyVarDecl(false);
5708
5709
1.36k
    elseif();
5710
5711
1.36k
    validate(); // #6772 "segmentation fault (invalid code) in Tokenizer::setVarId"
5712
5713
1.36k
    if (mTimerResults) {
5714
0
        Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::setVarId", mSettings->showtime, mTimerResults);
5715
0
        setVarId();
5716
1.36k
    } else {
5717
1.36k
        setVarId();
5718
1.36k
    }
5719
5720
    // Link < with >
5721
1.36k
    createLinks2();
5722
5723
    // Mark C++ casts
5724
93.6k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
5725
92.3k
        if (Token::Match(tok, "const_cast|dynamic_cast|reinterpret_cast|static_cast <") && Token::simpleMatch(tok->linkAt(1), "> (")) {
5726
0
            tok = tok->linkAt(1)->next();
5727
0
            tok->isCast(true);
5728
0
        }
5729
92.3k
    }
5730
5731
    // specify array size
5732
1.36k
    arraySize();
5733
5734
    // The simplify enum might have inner loops
5735
1.36k
    if (Settings::terminated())
5736
0
        return false;
5737
5738
    // Add std:: in front of std classes, when using namespace std; was given
5739
1.36k
    simplifyNamespaceStd();
5740
5741
    // Change initialisation of variable to assignment
5742
1.36k
    simplifyInitVar();
5743
5744
1.36k
    simplifyDoublePlusAndDoubleMinus();
5745
5746
1.36k
    simplifyArrayAccessSyntax();
5747
5748
1.36k
    Token::assignProgressValues(list.front());
5749
5750
1.36k
    removeRedundantSemicolons();
5751
5752
1.36k
    simplifyParameterVoid();
5753
5754
1.36k
    simplifyRedundantConsecutiveBraces();
5755
5756
1.36k
    simplifyEmptyNamespaces();
5757
5758
1.36k
    simplifyIfSwitchForInit();
5759
5760
1.36k
    simplifyOverloadedOperators();
5761
5762
1.36k
    validate();
5763
5764
1.36k
    list.front()->assignIndexes();
5765
5766
1.36k
    return true;
5767
1.36k
}
5768
//---------------------------------------------------------------------------
5769
5770
void Tokenizer::printDebugOutput(int simplification) const
5771
1.36k
{
5772
1.36k
    const bool debug = (simplification != 1U && mSettings->debugSimplified) ||
5773
1.36k
                       (simplification != 2U && mSettings->debugnormal);
5774
5775
1.36k
    if (debug && list.front()) {
5776
0
        list.front()->printOut(nullptr, list.getFiles());
5777
5778
0
        if (mSettings->xml)
5779
0
            std::cout << "<debug>" << std::endl;
5780
5781
0
        if (mSymbolDatabase) {
5782
0
            if (mSettings->xml)
5783
0
                mSymbolDatabase->printXml(std::cout);
5784
0
            else if (mSettings->verbose) {
5785
0
                mSymbolDatabase->printOut("Symbol database");
5786
0
            }
5787
0
        }
5788
5789
0
        if (mSettings->verbose)
5790
0
            list.front()->printAst(mSettings->verbose, mSettings->xml, list.getFiles(), std::cout);
5791
5792
0
        list.front()->printValueFlow(mSettings->xml, std::cout);
5793
5794
0
        if (mSettings->xml)
5795
0
            std::cout << "</debug>" << std::endl;
5796
0
    }
5797
5798
1.36k
    if (mSymbolDatabase && simplification == 2U && mSettings->debugwarnings) {
5799
0
        printUnknownTypes();
5800
5801
        // the typeStartToken() should come before typeEndToken()
5802
0
        for (const Variable *var : mSymbolDatabase->variableList()) {
5803
0
            if (!var)
5804
0
                continue;
5805
5806
0
            const Token * typetok = var->typeStartToken();
5807
0
            while (typetok && typetok != var->typeEndToken())
5808
0
                typetok = typetok->next();
5809
5810
0
            if (typetok != var->typeEndToken()) {
5811
0
                reportError(var->typeStartToken(),
5812
0
                            Severity::debug,
5813
0
                            "debug",
5814
0
                            "Variable::typeStartToken() of variable '" + var->name() + "' is not located before Variable::typeEndToken(). The location of the typeStartToken() is '" + var->typeStartToken()->str() + "' at line " + std::to_string(var->typeStartToken()->linenr()));
5815
0
            }
5816
0
        }
5817
0
    }
5818
1.36k
}
5819
5820
void Tokenizer::dump(std::ostream &out) const
5821
0
{
5822
    // Create a xml data dump.
5823
    // The idea is not that this will be readable for humans. It's a
5824
    // data dump that 3rd party tools could load and get useful info from.
5825
5826
0
    std::string outs;
5827
5828
0
    std::set<const Library::Container*> containers;
5829
5830
    // tokens..
5831
0
    outs += "  <tokenlist>";
5832
0
    outs += '\n';
5833
0
    for (const Token *tok = list.front(); tok; tok = tok->next()) {
5834
0
        outs += "    <token id=\"";
5835
0
        outs += id_string(tok);
5836
0
        outs += "\" file=\"";
5837
0
        outs += ErrorLogger::toxml(list.file(tok));
5838
0
        outs += "\" linenr=\"";
5839
0
        outs += std::to_string(tok->linenr());
5840
0
        outs += "\" column=\"";
5841
0
        outs += std::to_string(tok->column());
5842
0
        outs += "\"";
5843
5844
0
        outs += " str=\"";
5845
0
        outs += ErrorLogger::toxml(tok->str());
5846
0
        outs += '\"';
5847
5848
0
        outs += " scope=\"";
5849
0
        outs += id_string(tok->scope());
5850
0
        outs += '\"';
5851
0
        if (tok->isName()) {
5852
0
            outs += " type=\"name\"";
5853
0
            if (tok->isUnsigned())
5854
0
                outs += " isUnsigned=\"true\"";
5855
0
            else if (tok->isSigned())
5856
0
                outs += " isSigned=\"true\"";
5857
0
        } else if (tok->isNumber()) {
5858
0
            outs += " type=\"number\"";
5859
0
            if (MathLib::isInt(tok->str()))
5860
0
                outs += " isInt=\"true\"";
5861
0
            if (MathLib::isFloat(tok->str()))
5862
0
                outs += " isFloat=\"true\"";
5863
0
        } else if (tok->tokType() == Token::eString) {
5864
0
            outs += " type=\"string\" strlen=\"";
5865
0
            outs += std::to_string(Token::getStrLength(tok));
5866
0
            outs += '\"';
5867
0
        }
5868
0
        else if (tok->tokType() == Token::eChar)
5869
0
            outs += " type=\"char\"";
5870
0
        else if (tok->isBoolean())
5871
0
            outs += " type=\"boolean\"";
5872
0
        else if (tok->isOp()) {
5873
0
            outs += " type=\"op\"";
5874
0
            if (tok->isArithmeticalOp())
5875
0
                outs += " isArithmeticalOp=\"true\"";
5876
0
            else if (tok->isAssignmentOp())
5877
0
                outs += " isAssignmentOp=\"true\"";
5878
0
            else if (tok->isComparisonOp())
5879
0
                outs += " isComparisonOp=\"true\"";
5880
0
            else if (tok->tokType() == Token::eLogicalOp)
5881
0
                outs += " isLogicalOp=\"true\"";
5882
0
        }
5883
0
        if (tok->isCast())
5884
0
            outs += " isCast=\"true\"";
5885
0
        if (tok->isExternC())
5886
0
            outs += " externLang=\"C\"";
5887
0
        if (tok->isExpandedMacro())
5888
0
            outs += " isExpandedMacro=\"true\"";
5889
0
        if (tok->isTemplateArg())
5890
0
            outs += " isTemplateArg=\"true\"";
5891
0
        if (tok->isRemovedVoidParameter())
5892
0
            outs += " isRemovedVoidParameter=\"true\"";
5893
0
        if (tok->isSplittedVarDeclComma())
5894
0
            outs += " isSplittedVarDeclComma=\"true\"";
5895
0
        if (tok->isSplittedVarDeclEq())
5896
0
            outs += " isSplittedVarDeclEq=\"true\"";
5897
0
        if (tok->isImplicitInt())
5898
0
            outs += " isImplicitInt=\"true\"";
5899
0
        if (tok->isComplex())
5900
0
            outs += " isComplex=\"true\"";
5901
0
        if (tok->isRestrict())
5902
0
            outs += " isRestrict=\"true\"";
5903
0
        if (tok->isAtomic())
5904
0
            outs += " isAtomic=\"true\"";
5905
0
        if (tok->isAttributeExport())
5906
0
            outs += " isAttributeExport=\"true\"";
5907
0
        if (tok->link()) {
5908
0
            outs += " link=\"";
5909
0
            outs += id_string(tok->link());
5910
0
            outs += '\"';
5911
0
        }
5912
0
        if (tok->varId() > 0) {
5913
0
            outs += " varId=\"";
5914
0
            outs += std::to_string(tok->varId());
5915
0
            outs += '\"';
5916
0
        }
5917
0
        if (tok->exprId() > 0) {
5918
0
            outs += " exprId=\"";
5919
0
            outs += std::to_string(tok->exprId());
5920
0
            outs += '\"';
5921
0
        }
5922
0
        if (tok->variable()) {
5923
0
            outs += " variable=\"";
5924
0
            outs += id_string(tok->variable());
5925
0
            outs += '\"';
5926
0
        }
5927
0
        if (tok->function()) {
5928
0
            outs += " function=\"";
5929
0
            outs += id_string(tok->function());
5930
0
            outs += '\"';
5931
0
        }
5932
0
        if (!tok->values().empty()) {
5933
0
            outs += " values=\"";
5934
0
            outs += id_string(&tok->values());
5935
0
            outs += '\"';
5936
0
        }
5937
0
        if (tok->type()) {
5938
0
            outs += " type-scope=\"";
5939
0
            outs += id_string(tok->type()->classScope);
5940
0
            outs += '\"';
5941
0
        }
5942
0
        if (tok->astParent()) {
5943
0
            outs += " astParent=\"";
5944
0
            outs += id_string(tok->astParent());
5945
0
            outs += '\"';
5946
0
        }
5947
0
        if (tok->astOperand1()) {
5948
0
            outs += " astOperand1=\"";
5949
0
            outs += id_string(tok->astOperand1());
5950
0
            outs += '\"';
5951
0
        }
5952
0
        if (tok->astOperand2()) {
5953
0
            outs += " astOperand2=\"";
5954
0
            outs += id_string(tok->astOperand2());
5955
0
            outs += '\"';
5956
0
        }
5957
0
        if (!tok->originalName().empty()) {
5958
0
            outs += " originalName=\"";
5959
0
            outs += tok->originalName();
5960
0
            outs += '\"';
5961
0
        }
5962
0
        if (tok->valueType()) {
5963
0
            const std::string vt = tok->valueType()->dump();
5964
0
            if (!vt.empty()) {
5965
0
                outs += ' ';
5966
0
                outs += vt;
5967
0
            }
5968
0
            containers.insert(tok->valueType()->container);
5969
0
        }
5970
0
        if (!tok->varId() && tok->scope()->isExecutable() && Token::Match(tok, "%name% (")) {
5971
0
            if (mSettings->library.isnoreturn(tok))
5972
0
                outs += " noreturn=\"true\"";
5973
0
        }
5974
5975
0
        outs += "/>";
5976
0
        outs += '\n';
5977
0
    }
5978
0
    outs += "  </tokenlist>";
5979
0
    outs += '\n';
5980
5981
0
    out << outs;
5982
0
    outs.clear();
5983
5984
0
    mSymbolDatabase->printXml(out);
5985
5986
0
    containers.erase(nullptr);
5987
0
    if (!containers.empty()) {
5988
0
        outs += "  <containers>";
5989
0
        outs += '\n';
5990
0
        for (const Library::Container* c: containers) {
5991
0
            outs += "    <container id=\"";
5992
0
            outs += id_string(c);
5993
0
            outs += "\" array-like-index-op=\"";
5994
0
            outs += bool_to_string(c->arrayLike_indexOp);
5995
0
            outs += "\" ";
5996
0
            outs += "std-string-like=\"";
5997
0
            outs += bool_to_string(c->stdStringLike);
5998
0
            outs += "\"/>";
5999
0
            outs += '\n';
6000
0
        }
6001
0
        outs += "  </containers>";
6002
0
        outs += '\n';
6003
0
    }
6004
6005
0
    if (list.front())
6006
0
        list.front()->printValueFlow(true, out);
6007
6008
0
    if (!mTypedefInfo.empty()) {
6009
0
        outs += "  <typedef-info>";
6010
0
        outs += '\n';
6011
0
        for (const TypedefInfo &typedefInfo: mTypedefInfo) {
6012
0
            outs += "    <info";
6013
6014
0
            outs += " name=\"";
6015
0
            outs += typedefInfo.name;
6016
0
            outs += "\"";
6017
6018
0
            outs += " file=\"";
6019
0
            outs += ErrorLogger::toxml(typedefInfo.filename);
6020
0
            outs += "\"";
6021
6022
0
            outs += " line=\"";
6023
0
            outs += std::to_string(typedefInfo.lineNumber);
6024
0
            outs += "\"";
6025
6026
0
            outs += " column=\"";
6027
0
            outs += std::to_string(typedefInfo.column);
6028
0
            outs += "\"";
6029
6030
0
            outs += " used=\"";
6031
0
            outs += std::to_string(typedefInfo.used?1:0);
6032
0
            outs += "\"";
6033
6034
0
            outs += "/>";
6035
0
            outs += '\n';
6036
0
        }
6037
0
        outs += "  </typedef-info>";
6038
0
        outs += '\n';
6039
0
    }
6040
0
    outs += mTemplateSimplifier->dump();
6041
6042
0
    out << outs;
6043
0
}
6044
6045
void Tokenizer::simplifyHeadersAndUnusedTemplates()
6046
1.36k
{
6047
1.36k
    if (mSettings->checkHeaders && mSettings->checkUnusedTemplates)
6048
        // Full analysis. All information in the headers are kept.
6049
1.36k
        return;
6050
6051
0
    const bool checkHeaders = mSettings->checkHeaders;
6052
0
    const bool removeUnusedIncludedFunctions = !mSettings->checkHeaders;
6053
0
    const bool removeUnusedIncludedClasses   = !mSettings->checkHeaders;
6054
0
    const bool removeUnusedIncludedTemplates = !mSettings->checkUnusedTemplates || !mSettings->checkHeaders;
6055
0
    const bool removeUnusedTemplates = !mSettings->checkUnusedTemplates;
6056
6057
    // checkHeaders:
6058
    //
6059
    // If it is true then keep all code in the headers. It's possible
6060
    // to remove unused types/variables if false positives / false
6061
    // negatives can be avoided.
6062
    //
6063
    // If it is false, then we want to remove selected stuff from the
6064
    // headers but not *everything*. The intention here is to not damage
6065
    // the analysis of the source file. You should get all warnings in
6066
    // the source file. You should not get false positives.
6067
6068
    // functions and types to keep
6069
0
    std::set<std::string> keep;
6070
0
    for (const Token *tok = list.front(); tok; tok = tok->next()) {
6071
0
        if (isCPP() && Token::simpleMatch(tok, "template <")) {
6072
0
            const Token *closingBracket = tok->next()->findClosingBracket();
6073
0
            if (Token::Match(closingBracket, "> class|struct %name% {"))
6074
0
                tok = closingBracket->linkAt(3);
6075
0
        }
6076
6077
0
        if (!tok->isName() || tok->isKeyword())
6078
0
            continue;
6079
6080
0
        if (!checkHeaders && tok->fileIndex() != 0)
6081
0
            continue;
6082
6083
0
        if (Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->linkAt(1), ") {")) {
6084
0
            keep.insert(tok->str());
6085
0
            continue;
6086
0
        }
6087
6088
0
        if (Token::Match(tok, "%name% %name%|::|*|&|<")) {
6089
0
            keep.insert(tok->str());
6090
0
        }
6091
0
    }
6092
6093
0
    const std::set<std::string> functionStart{"static", "const", "unsigned", "signed", "void", "bool", "char", "short", "int", "long", "float", "*"};
6094
6095
0
    for (Token *tok = list.front(); tok; tok = tok->next()) {
6096
0
        const bool isIncluded = (tok->fileIndex() != 0);
6097
6098
        // Remove executable code
6099
0
        if (isIncluded && !mSettings->checkHeaders && tok->str() == "{") {
6100
            // TODO: We probably need to keep the executable code if this function is called from the source file.
6101
0
            const Token *prev = tok->previous();
6102
0
            while (prev && prev->isName())
6103
0
                prev = prev->previous();
6104
0
            if (Token::simpleMatch(prev, ")")) {
6105
                // Replace all tokens from { to } with a ";".
6106
0
                Token::eraseTokens(tok,tok->link()->next());
6107
0
                tok->str(";");
6108
0
                tok->link(nullptr);
6109
0
            }
6110
0
        }
6111
6112
0
        if (!tok->previous() || Token::Match(tok->previous(), "[;{}]")) {
6113
            // Remove unused function declarations
6114
0
            if (isIncluded && removeUnusedIncludedFunctions) {
6115
0
                while (true) {
6116
0
                    Token *start = tok;
6117
0
                    while (start && functionStart.find(start->str()) != functionStart.end())
6118
0
                        start = start->next();
6119
0
                    if (Token::Match(start, "%name% (") && Token::Match(start->linkAt(1), ") const| ;") && keep.find(start->str()) == keep.end()) {
6120
0
                        Token::eraseTokens(tok, start->linkAt(1)->tokAt(2));
6121
0
                        tok->deleteThis();
6122
0
                    } else
6123
0
                        break;
6124
0
                }
6125
0
            }
6126
6127
0
            if (isIncluded && removeUnusedIncludedClasses) {
6128
0
                if (Token::Match(tok, "class|struct %name% [:{]") && keep.find(tok->strAt(1)) == keep.end()) {
6129
                    // Remove this class/struct
6130
0
                    const Token *endToken = tok->tokAt(2);
6131
0
                    if (endToken->str() == ":") {
6132
0
                        endToken = endToken->next();
6133
0
                        while (Token::Match(endToken, "%name%|,"))
6134
0
                            endToken = endToken->next();
6135
0
                    }
6136
0
                    if (endToken && endToken->str() == "{" && Token::simpleMatch(endToken->link(), "} ;")) {
6137
0
                        Token::eraseTokens(tok, endToken->link()->next());
6138
0
                        tok->deleteThis();
6139
0
                    }
6140
0
                }
6141
0
            }
6142
6143
0
            if (removeUnusedTemplates || (isIncluded && removeUnusedIncludedTemplates)) {
6144
0
                if (Token::Match(tok, "template < %name%")) {
6145
0
                    const Token *closingBracket = tok->next()->findClosingBracket();
6146
0
                    if (Token::Match(closingBracket, "> class|struct %name% [;:{]") && keep.find(closingBracket->strAt(2)) == keep.end()) {
6147
0
                        const Token *endToken = closingBracket->tokAt(3);
6148
0
                        if (endToken->str() == ":") {
6149
0
                            endToken = endToken->next();
6150
0
                            while (Token::Match(endToken, "%name%|,"))
6151
0
                                endToken = endToken->next();
6152
0
                        }
6153
0
                        if (endToken && endToken->str() == "{")
6154
0
                            endToken = endToken->link()->next();
6155
0
                        if (endToken && endToken->str() == ";") {
6156
0
                            Token::eraseTokens(tok, endToken);
6157
0
                            tok->deleteThis();
6158
0
                        }
6159
0
                    } else if (Token::Match(closingBracket, "> %type% %name% (") && Token::simpleMatch(closingBracket->linkAt(3), ") {") && keep.find(closingBracket->strAt(2)) == keep.end()) {
6160
0
                        const Token *endToken = closingBracket->linkAt(3)->linkAt(1)->next();
6161
0
                        Token::eraseTokens(tok, endToken);
6162
0
                        tok->deleteThis();
6163
0
                    }
6164
0
                }
6165
0
            }
6166
0
        }
6167
0
    }
6168
0
}
6169
6170
void Tokenizer::removeExtraTemplateKeywords()
6171
1.36k
{
6172
1.36k
    if (isCPP()) {
6173
81.8k
        for (Token *tok = list.front(); tok; tok = tok->next()) {
6174
80.4k
            if (Token::Match(tok, "%name%|>|) .|:: template %name%")) {
6175
0
                tok->next()->deleteNext();
6176
0
                Token* templateName = tok->tokAt(2);
6177
0
                while (Token::Match(templateName, "%name%|::")) {
6178
0
                    templateName->isTemplate(true);
6179
0
                    templateName = templateName->next();
6180
0
                }
6181
0
                if (Token::Match(templateName->previous(), "operator %op%|(")) {
6182
0
                    templateName->isTemplate(true);
6183
0
                    if (templateName->str() == "(" && templateName->link())
6184
0
                        templateName->link()->isTemplate(true);
6185
0
                }
6186
0
            }
6187
80.4k
        }
6188
1.36k
    }
6189
1.36k
}
6190
6191
static std::string getExpression(const Token *tok)
6192
0
{
6193
0
    std::string line;
6194
0
    for (const Token *prev = tok->previous(); prev && !Token::Match(prev, "[;{}]"); prev = prev->previous())
6195
0
        line = prev->str() + " " + line;
6196
0
    line += "!!!" + tok->str() + "!!!";
6197
0
    for (const Token *next = tok->next(); next && !Token::Match(next, "[;{}]"); next = next->next())
6198
0
        line += " " + next->str();
6199
0
    return line;
6200
0
}
6201
6202
void Tokenizer::splitTemplateRightAngleBrackets(bool check)
6203
1.36k
{
6204
1.36k
    std::vector<std::pair<std::string, int>> vars;
6205
6206
1.36k
    int scopeLevel = 0;
6207
81.8k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
6208
80.4k
        if (tok->str() == "{")
6209
3.58k
            ++scopeLevel;
6210
76.9k
        else if (tok->str() == "}") {
6211
14.3k
            vars.erase(std::remove_if(vars.begin(), vars.end(), [scopeLevel](const std::pair<std::string, int>& v) {
6212
14.3k
                return v.second == scopeLevel;
6213
14.3k
            }), vars.end());
6214
3.58k
            --scopeLevel;
6215
3.58k
        }
6216
80.4k
        if (Token::Match(tok, "[;{}] %type% %type% [;,=]") && tok->next()->isStandardType())
6217
5.44k
            vars.emplace_back(tok->strAt(2), scopeLevel);
6218
6219
        // Ticket #6181: normalize C++11 template parameter list closing syntax
6220
80.4k
        if (tok->previous() && tok->str() == "<" && TemplateSimplifier::templateParameters(tok) && std::none_of(vars.begin(), vars.end(), [&](const std::pair<std::string, int>& v) {
6221
184
            return v.first == tok->previous()->str();
6222
184
        })) {
6223
37
            Token *endTok = tok->findClosingBracket();
6224
37
            if (check) {
6225
0
                if (Token::Match(endTok, ">>|>>="))
6226
0
                    reportError(tok, Severity::debug, "dacaWrongSplitTemplateRightAngleBrackets", "bad closing bracket for !!!<!!!: " + getExpression(tok), false);
6227
0
                continue;
6228
0
            }
6229
37
            if (endTok && endTok->str() == ">>") {
6230
0
                endTok->str(">");
6231
0
                endTok->insertToken(">");
6232
37
            } else if (endTok && endTok->str() == ">>=") {
6233
0
                endTok->str(">");
6234
0
                endTok->insertToken("=");
6235
0
                endTok->insertToken(">");
6236
0
            }
6237
80.4k
        } else if (Token::Match(tok, "class|struct|union|=|:|public|protected|private %name% <") && std::none_of(vars.begin(), vars.end(), [&](const std::pair<std::string, int>& v) {
6238
151
            return v.first == tok->next()->str();
6239
151
        })) {
6240
33
            Token *endTok = tok->tokAt(2)->findClosingBracket();
6241
33
            if (check) {
6242
0
                if (Token::simpleMatch(endTok, ">>"))
6243
0
                    reportError(tok, Severity::debug, "dacaWrongSplitTemplateRightAngleBrackets", "bad closing bracket for !!!<!!!: " + getExpression(tok), false);
6244
0
                continue;
6245
0
            }
6246
33
            if (Token::Match(endTok, ">> ;|{|%type%")) {
6247
0
                endTok->str(">");
6248
0
                endTok->insertToken(">");
6249
0
            }
6250
33
        }
6251
80.4k
    }
6252
1.36k
}
6253
6254
void Tokenizer::removeMacrosInGlobalScope()
6255
1.36k
{
6256
42.3k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
6257
41.0k
        if (tok->str() == "(") {
6258
1.74k
            tok = tok->link();
6259
1.74k
            if (Token::Match(tok, ") %type% {") &&
6260
1.74k
                !tok->next()->isStandardType() &&
6261
1.74k
                !tok->next()->isKeyword() &&
6262
1.74k
                !Token::Match(tok->next(), "override|final") &&
6263
1.74k
                tok->next()->isUpperCaseName())
6264
0
                tok->deleteNext();
6265
1.74k
        }
6266
6267
41.0k
        if (Token::Match(tok, "%type%") && tok->isUpperCaseName() &&
6268
41.0k
            (!tok->previous() || Token::Match(tok->previous(), "[;{}]") || (tok->previous()->isName() && endsWith(tok->previous()->str(), ':')))) {
6269
0
            const Token *tok2 = tok->next();
6270
0
            if (tok2 && tok2->str() == "(")
6271
0
                tok2 = tok2->link()->next();
6272
6273
            // Several unknown macros...
6274
0
            while (Token::Match(tok2, "%type% (") && tok2->isUpperCaseName())
6275
0
                tok2 = tok2->linkAt(1)->next();
6276
6277
0
            if (Token::Match(tok, "%name% (") && Token::Match(tok2, "%name% *|&|::|<| %name%") && !Token::Match(tok2, "namespace|class|struct|union|private:|protected:|public:"))
6278
0
                unknownMacroError(tok);
6279
6280
0
            if (Token::Match(tok, "%type% (") && Token::Match(tok2, "%type% (") && !Token::Match(tok2, "noexcept|throw") && isFunctionHead(tok2->next(), ":;{"))
6281
0
                unknownMacroError(tok);
6282
6283
            // remove unknown macros before namespace|class|struct|union
6284
0
            if (Token::Match(tok2, "namespace|class|struct|union")) {
6285
                // is there a "{" for?
6286
0
                const Token *tok3 = tok2;
6287
0
                while (tok3 && !Token::Match(tok3,"[;{}()]"))
6288
0
                    tok3 = tok3->next();
6289
0
                if (tok3 && tok3->str() == "{") {
6290
0
                    Token::eraseTokens(tok, tok2);
6291
0
                    tok->deleteThis();
6292
0
                }
6293
0
                continue;
6294
0
            }
6295
6296
            // replace unknown macros before foo(
6297
            /*
6298
                        if (Token::Match(tok2, "%type% (") && isFunctionHead(tok2->next(), "{")) {
6299
                            std::string typeName;
6300
                            for (const Token* tok3 = tok; tok3 != tok2; tok3 = tok3->next())
6301
                                typeName += tok3->str();
6302
                            Token::eraseTokens(tok, tok2);
6303
                            tok->str(typeName);
6304
                        }
6305
             */
6306
            // remove unknown macros before foo::foo(
6307
0
            if (Token::Match(tok2, "%type% :: %type%")) {
6308
0
                const Token *tok3 = tok2;
6309
0
                while (Token::Match(tok3, "%type% :: %type% ::"))
6310
0
                    tok3 = tok3->tokAt(2);
6311
0
                if (Token::Match(tok3, "%type% :: %type% (") && tok3->str() == tok3->strAt(2)) {
6312
0
                    Token::eraseTokens(tok, tok2);
6313
0
                    tok->deleteThis();
6314
0
                }
6315
0
                continue;
6316
0
            }
6317
0
        }
6318
6319
        // Skip executable scopes
6320
41.0k
        if (tok->str() == "{") {
6321
1.74k
            const Token *prev = tok->previous();
6322
1.74k
            while (prev && prev->isName())
6323
0
                prev = prev->previous();
6324
1.74k
            if (prev && prev->str() == ")")
6325
1.74k
                tok = tok->link();
6326
1.74k
        }
6327
41.0k
    }
6328
1.36k
}
6329
6330
//---------------------------------------------------------------------------
6331
6332
void Tokenizer::removePragma()
6333
1.36k
{
6334
1.36k
    if (isC() && mSettings->standards.c == Standards::C89)
6335
0
        return;
6336
1.36k
    if (isCPP() && mSettings->standards.cpp == Standards::CPP03)
6337
0
        return;
6338
81.8k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
6339
80.4k
        while (Token::simpleMatch(tok, "_Pragma (")) {
6340
0
            Token::eraseTokens(tok, tok->linkAt(1)->next());
6341
0
            tok->deleteThis();
6342
0
        }
6343
80.4k
    }
6344
1.36k
}
6345
6346
//---------------------------------------------------------------------------
6347
6348
void Tokenizer::removeMacroInClassDef()
6349
1.36k
{
6350
80.4k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
6351
79.1k
        if (!Token::Match(tok, "class|struct %name% %name% final| {|:"))
6352
79.1k
            continue;
6353
6354
0
        const bool nextIsUppercase = tok->next()->isUpperCaseName();
6355
0
        const bool afterNextIsUppercase = tok->tokAt(2)->isUpperCaseName();
6356
0
        if (nextIsUppercase && !afterNextIsUppercase)
6357
0
            tok->deleteNext();
6358
0
        else if (!nextIsUppercase && afterNextIsUppercase)
6359
0
            tok->next()->deleteNext();
6360
0
    }
6361
1.36k
}
6362
6363
//---------------------------------------------------------------------------
6364
6365
void Tokenizer::addSemicolonAfterUnknownMacro()
6366
1.36k
{
6367
1.36k
    if (!isCPP())
6368
0
        return;
6369
80.4k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
6370
79.1k
        if (tok->str() != ")")
6371
75.0k
            continue;
6372
4.05k
        const Token *macro = tok->link() ? tok->link()->previous() : nullptr;
6373
4.05k
        if (!macro || !macro->isName())
6374
848
            continue;
6375
3.20k
        if (Token::simpleMatch(tok, ") try") && !Token::Match(macro, "if|for|while"))
6376
0
            tok->insertToken(";");
6377
3.20k
        else if (Token::simpleMatch(tok, ") using"))
6378
0
            tok->insertToken(";");
6379
3.20k
    }
6380
1.36k
}
6381
//---------------------------------------------------------------------------
6382
6383
void Tokenizer::simplifyEmptyNamespaces()
6384
1.36k
{
6385
1.36k
    if (isC())
6386
0
        return;
6387
6388
1.36k
    bool goback = false;
6389
55.9k
    for (Token *tok = list.front(); tok; tok = tok ? tok->next() : nullptr) {
6390
54.6k
        if (goback) {
6391
0
            tok = tok->previous();
6392
0
            goback = false;
6393
0
        }
6394
54.6k
        if (Token::Match(tok, "(|[|{")) {
6395
3.48k
            tok = tok->link();
6396
3.48k
            continue;
6397
3.48k
        }
6398
51.1k
        if (!Token::Match(tok, "namespace %name%| {"))
6399
51.1k
            continue;
6400
0
        const bool isAnonymousNS = tok->strAt(1) == "{";
6401
0
        if (tok->strAt(3 - isAnonymousNS) == "}") {
6402
0
            tok->deleteNext(3 - isAnonymousNS); // remove '%name%| { }'
6403
0
            if (!tok->previous()) {
6404
                // remove 'namespace' or replace it with ';' if isolated
6405
0
                tok->deleteThis();
6406
0
                goback = true;
6407
0
            } else {                    // '%any% namespace %any%'
6408
0
                tok = tok->previous();  // goto previous token
6409
0
                tok->deleteNext();      // remove next token: 'namespace'
6410
0
                if (tok->str() == "{") {
6411
                    // Go back in case we were within a namespace that's empty now
6412
0
                    tok = tok->tokAt(-2) ? tok->tokAt(-2) : tok->previous();
6413
0
                    goback = true;
6414
0
                }
6415
0
            }
6416
0
        } else {
6417
0
            tok = tok->tokAt(2 - isAnonymousNS);
6418
0
        }
6419
0
    }
6420
1.36k
}
6421
6422
void Tokenizer::removeRedundantSemicolons()
6423
1.36k
{
6424
80.0k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
6425
78.7k
        if (tok->link() && tok->str() == "(") {
6426
3.40k
            tok = tok->link();
6427
3.40k
            continue;
6428
3.40k
        }
6429
75.3k
        for (;;) {
6430
75.3k
            if (Token::simpleMatch(tok, "; ;")) {
6431
0
                tok->deleteNext();
6432
75.3k
            } else if (Token::simpleMatch(tok, "; { ; }")) {
6433
0
                tok->deleteNext(3);
6434
75.3k
            } else {
6435
75.3k
                break;
6436
75.3k
            }
6437
75.3k
        }
6438
75.3k
    }
6439
1.36k
}
6440
6441
6442
bool Tokenizer::simplifyAddBraces()
6443
1.36k
{
6444
80.4k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
6445
79.1k
        Token const * tokRet=simplifyAddBracesToCommand(tok);
6446
79.1k
        if (!tokRet)
6447
0
            return false;
6448
79.1k
    }
6449
1.36k
    return true;
6450
1.36k
}
6451
6452
Token *Tokenizer::simplifyAddBracesToCommand(Token *tok)
6453
79.1k
{
6454
79.1k
    Token * tokEnd=tok;
6455
79.1k
    if (Token::Match(tok,"for|switch|BOOST_FOREACH")) {
6456
0
        tokEnd=simplifyAddBracesPair(tok,true);
6457
79.1k
    } else if (tok->str()=="while") {
6458
468
        Token *tokPossibleDo=tok->previous();
6459
468
        if (Token::simpleMatch(tok->previous(), "{"))
6460
326
            tokPossibleDo = nullptr;
6461
142
        else if (Token::simpleMatch(tokPossibleDo,"}"))
6462
9
            tokPossibleDo = tokPossibleDo->link();
6463
468
        if (!tokPossibleDo || tokPossibleDo->strAt(-1) != "do")
6464
468
            tokEnd=simplifyAddBracesPair(tok,true);
6465
78.6k
    } else if (tok->str()=="do") {
6466
0
        tokEnd=simplifyAddBracesPair(tok,false);
6467
0
        if (tokEnd!=tok) {
6468
            // walk on to next token, i.e. "while"
6469
            // such that simplifyAddBracesPair does not close other braces
6470
            // before the "while"
6471
0
            if (tokEnd) {
6472
0
                tokEnd=tokEnd->next();
6473
0
                if (!tokEnd || tokEnd->str()!="while") // no while
6474
0
                    syntaxError(tok);
6475
0
            }
6476
0
        }
6477
78.6k
    } else if (tok->str()=="if" && !Token::simpleMatch(tok->tokAt(-2), "operator \"\"")) {
6478
920
        tokEnd=simplifyAddBracesPair(tok,true);
6479
920
        if (!tokEnd)
6480
0
            return nullptr;
6481
920
        if (tokEnd->strAt(1) == "else") {
6482
458
            Token * tokEndNextNext= tokEnd->tokAt(2);
6483
458
            if (!tokEndNextNext || tokEndNextNext->str() == "}")
6484
0
                syntaxError(tokEndNextNext);
6485
458
            if (tokEndNextNext->str() == "if")
6486
                // do not change "else if ..." to "else { if ... }"
6487
0
                tokEnd=simplifyAddBracesToCommand(tokEndNextNext);
6488
458
            else
6489
458
                tokEnd=simplifyAddBracesPair(tokEnd->next(),false);
6490
458
        }
6491
920
    }
6492
6493
79.1k
    return tokEnd;
6494
79.1k
}
6495
6496
Token *Tokenizer::simplifyAddBracesPair(Token *tok, bool commandWithCondition)
6497
1.84k
{
6498
1.84k
    Token * tokCondition=tok->next();
6499
1.84k
    if (!tokCondition) // Missing condition
6500
0
        return tok;
6501
6502
1.84k
    Token *tokAfterCondition=tokCondition;
6503
1.84k
    if (commandWithCondition) {
6504
1.38k
        if (tokCondition->str()=="(")
6505
1.38k
            tokAfterCondition=tokCondition->link();
6506
0
        else
6507
0
            syntaxError(tok); // Bad condition
6508
6509
1.38k
        if (!tokAfterCondition || tokAfterCondition->strAt(1) == "]")
6510
0
            syntaxError(tok); // Bad condition
6511
6512
1.38k
        tokAfterCondition=tokAfterCondition->next();
6513
1.38k
        if (!tokAfterCondition || Token::Match(tokAfterCondition, ")|}|,")) {
6514
            // No tokens left where to add braces around
6515
0
            return tok;
6516
0
        }
6517
1.38k
    }
6518
    // Skip labels
6519
1.84k
    Token * tokStatement = tokAfterCondition;
6520
1.84k
    while (true) {
6521
1.84k
        if (Token::Match(tokStatement, "%name% :"))
6522
0
            tokStatement = tokStatement->tokAt(2);
6523
1.84k
        else if (tokStatement->str() == "case") {
6524
0
            tokStatement = skipCaseLabel(tokStatement);
6525
0
            if (!tokStatement)
6526
0
                return tok;
6527
0
            if (tokStatement->str() != ":")
6528
0
                syntaxError(tokStatement);
6529
0
            tokStatement = tokStatement->next();
6530
0
        } else
6531
1.84k
            break;
6532
0
        if (!tokStatement)
6533
0
            return tok;
6534
0
    }
6535
1.84k
    Token * tokBracesEnd=nullptr;
6536
1.84k
    if (tokStatement->str() == "{") {
6537
        // already surrounded by braces
6538
1.84k
        if (tokStatement != tokAfterCondition) {
6539
            // Move the opening brace before labels
6540
0
            Token::move(tokStatement, tokStatement, tokAfterCondition->previous());
6541
0
        }
6542
1.84k
        tokBracesEnd = tokStatement->link();
6543
1.84k
    } else if (Token::simpleMatch(tokStatement, "try {") &&
6544
0
               Token::simpleMatch(tokStatement->linkAt(1), "} catch (")) {
6545
0
        tokAfterCondition->previous()->insertToken("{");
6546
0
        Token * tokOpenBrace = tokAfterCondition->previous();
6547
0
        Token * tokEnd = tokStatement->linkAt(1)->linkAt(2)->linkAt(1);
6548
0
        if (!tokEnd) {
6549
0
            syntaxError(tokStatement);
6550
0
        }
6551
0
        tokEnd->insertToken("}");
6552
0
        Token * tokCloseBrace = tokEnd->next();
6553
6554
0
        Token::createMutualLinks(tokOpenBrace, tokCloseBrace);
6555
0
        tokBracesEnd = tokCloseBrace;
6556
0
    } else {
6557
0
        Token * tokEnd = simplifyAddBracesToCommand(tokStatement);
6558
0
        if (!tokEnd) // Ticket #4887
6559
0
            return tok;
6560
0
        if (tokEnd->str()!="}") {
6561
            // Token does not end with brace
6562
            // Look for ; to add own closing brace after it
6563
0
            while (tokEnd && !Token::Match(tokEnd, ";|)|}")) {
6564
0
                if (tokEnd->tokType()==Token::eBracket || tokEnd->str() == "(") {
6565
0
                    tokEnd = tokEnd->link();
6566
0
                    if (!tokEnd) {
6567
                        // Inner bracket does not close
6568
0
                        return tok;
6569
0
                    }
6570
0
                }
6571
0
                tokEnd=tokEnd->next();
6572
0
            }
6573
0
            if (!tokEnd || tokEnd->str() != ";") {
6574
                // No trailing ;
6575
0
                return tok;
6576
0
            }
6577
0
        }
6578
6579
0
        tokAfterCondition->previous()->insertToken("{");
6580
0
        Token * tokOpenBrace=tokAfterCondition->previous();
6581
6582
0
        tokEnd->insertToken("}");
6583
0
        Token * tokCloseBrace=tokEnd->next();
6584
6585
0
        Token::createMutualLinks(tokOpenBrace,tokCloseBrace);
6586
0
        tokBracesEnd=tokCloseBrace;
6587
0
    }
6588
6589
1.84k
    return tokBracesEnd;
6590
1.84k
}
6591
6592
void Tokenizer::simplifyFunctionParameters()
6593
1.36k
{
6594
42.3k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
6595
41.0k
        if (tok->link() && Token::Match(tok, "{|[|(")) {
6596
3.48k
            tok = tok->link();
6597
3.48k
        }
6598
6599
        // Find the function e.g. foo( x ) or foo( x, y )
6600
37.5k
        else if (Token::Match(tok, "%name% ( %name% [,)]") &&
6601
37.5k
                 !(tok->strAt(-1) == ":" || tok->strAt(-1) == "," || tok->strAt(-1) == "::")) {
6602
            // We have found old style function, now we need to change it
6603
6604
            // First step: Get list of argument names in parentheses
6605
0
            std::map<std::string, Token *> argumentNames;
6606
0
            bool bailOut = false;
6607
0
            Token * tokparam = nullptr;
6608
6609
            //take count of the function name..
6610
0
            const std::string& funcName(tok->str());
6611
6612
            //floating token used to check for parameters
6613
0
            Token *tok1 = tok;
6614
6615
0
            while (nullptr != (tok1 = tok1->tokAt(2))) {
6616
0
                if (!Token::Match(tok1, "%name% [,)]")) {
6617
0
                    bailOut = true;
6618
0
                    break;
6619
0
                }
6620
6621
                //same parameters: take note of the parameter
6622
0
                if (argumentNames.find(tok1->str()) != argumentNames.end())
6623
0
                    tokparam = tok1;
6624
0
                else if (tok1->str() != funcName)
6625
0
                    argumentNames[tok1->str()] = tok1;
6626
0
                else {
6627
0
                    if (tok1->next()->str() == ")") {
6628
0
                        if (tok1->previous()->str() == ",") {
6629
0
                            tok1 = tok1->tokAt(-2);
6630
0
                            tok1->deleteNext(2);
6631
0
                        } else {
6632
0
                            tok1 = tok1->previous();
6633
0
                            tok1->deleteNext();
6634
0
                            bailOut = true;
6635
0
                            break;
6636
0
                        }
6637
0
                    } else {
6638
0
                        tok1 = tok1->tokAt(-2);
6639
0
                        tok1->next()->deleteNext(2);
6640
0
                    }
6641
0
                }
6642
6643
0
                if (tok1->next()->str() == ")") {
6644
0
                    tok1 = tok1->tokAt(2);
6645
                    //expect at least a type name after round brace..
6646
0
                    if (!tok1 || !tok1->isName())
6647
0
                        bailOut = true;
6648
0
                    break;
6649
0
                }
6650
0
            }
6651
6652
            //goto '('
6653
0
            tok = tok->next();
6654
6655
0
            if (bailOut) {
6656
0
                tok = tok->link();
6657
0
                continue;
6658
0
            }
6659
6660
0
            tok1 = tok->link()->next();
6661
6662
            // there should be the sequence '; {' after the round parentheses
6663
0
            for (const Token* tok2 = tok1; tok2; tok2 = tok2->next()) {
6664
0
                if (Token::simpleMatch(tok2, "; {"))
6665
0
                    break;
6666
0
                if (tok2->str() == "{") {
6667
0
                    bailOut = true;
6668
0
                    break;
6669
0
                }
6670
0
            }
6671
6672
0
            if (bailOut) {
6673
0
                tok = tok->link();
6674
0
                continue;
6675
0
            }
6676
6677
            // Last step: check out if the declarations between ')' and '{' match the parameters list
6678
0
            std::map<std::string, Token *> argumentNames2;
6679
6680
0
            while (tok1 && tok1->str() != "{") {
6681
0
                if (Token::Match(tok1, "(|)")) {
6682
0
                    bailOut = true;
6683
0
                    break;
6684
0
                }
6685
0
                if (tok1->str() == ";") {
6686
0
                    if (tokparam) {
6687
0
                        syntaxError(tokparam);
6688
0
                    }
6689
0
                    Token *tok2 = tok1->previous();
6690
0
                    while (tok2->str() == "]")
6691
0
                        tok2 = tok2->link()->previous();
6692
6693
                    //it should be a name..
6694
0
                    if (!tok2->isName()) {
6695
0
                        bailOut = true;
6696
0
                        break;
6697
0
                    }
6698
6699
0
                    if (argumentNames2.find(tok2->str()) != argumentNames2.end()) {
6700
                        //same parameter names...
6701
0
                        syntaxError(tok1);
6702
0
                    } else
6703
0
                        argumentNames2[tok2->str()] = tok2;
6704
6705
0
                    if (argumentNames.find(tok2->str()) == argumentNames.end()) {
6706
                        //non-matching parameter... bailout
6707
0
                        bailOut = true;
6708
0
                        break;
6709
0
                    }
6710
0
                }
6711
0
                tok1 = tok1->next();
6712
0
            }
6713
6714
0
            if (bailOut || !tok1) {
6715
0
                tok = tok->link();
6716
0
                continue;
6717
0
            }
6718
6719
            //the two containers may not hold the same size...
6720
            //in that case, the missing parameters are defined as 'int'
6721
0
            if (argumentNames.size() != argumentNames2.size()) {
6722
                //move back 'tok1' to the last ';'
6723
0
                tok1 = tok1->previous();
6724
0
                for (const std::pair<const std::string, Token *>& argumentName : argumentNames) {
6725
0
                    if (argumentNames2.find(argumentName.first) == argumentNames2.end()) {
6726
                        //add the missing parameter argument declaration
6727
0
                        tok1->insertToken(";");
6728
0
                        tok1->insertToken(argumentName.first);
6729
                        //register the change inside argumentNames2
6730
0
                        argumentNames2[argumentName.first] = tok1->next();
6731
0
                        tok1->insertToken("int");
6732
0
                    }
6733
0
                }
6734
0
            }
6735
6736
0
            while (tok->str() != ")") {
6737
                //initialize start and end tokens to be moved
6738
0
                Token *declStart = argumentNames2[tok->next()->str()];
6739
0
                Token *declEnd = declStart;
6740
0
                while (declStart->previous()->str() != ";" && declStart->previous()->str() != ")")
6741
0
                    declStart = declStart->previous();
6742
0
                while (declEnd->next()->str() != ";" && declEnd->next()->str() != "{")
6743
0
                    declEnd = declEnd->next();
6744
6745
                //remove ';' after declaration
6746
0
                declEnd->deleteNext();
6747
6748
                //replace the parameter name in the parentheses with all the declaration
6749
0
                Token::replace(tok->next(), declStart, declEnd);
6750
6751
                //since there are changes to tokens, put tok where tok1 is
6752
0
                tok = declEnd->next();
6753
6754
                //fix up line number
6755
0
                if (tok->str() == ",")
6756
0
                    tok->linenr(tok->previous()->linenr());
6757
0
            }
6758
            //goto forward and continue
6759
0
            tok = tok->next()->link();
6760
0
        }
6761
41.0k
    }
6762
1.36k
}
6763
6764
void Tokenizer::simplifyPointerToStandardType()
6765
1.36k
{
6766
1.36k
    if (!isC())
6767
1.36k
        return;
6768
6769
0
    for (Token *tok = list.front(); tok; tok = tok->next()) {
6770
0
        if (!Token::Match(tok, "& %name% [ 0 ] !!["))
6771
0
            continue;
6772
6773
0
        if (!Token::Match(tok->previous(), "[,(=]"))
6774
0
            continue;
6775
6776
        // Remove '[ 0 ]' suffix
6777
0
        Token::eraseTokens(tok->next(), tok->tokAt(5));
6778
        // Remove '&' prefix
6779
0
        tok = tok->previous();
6780
0
        if (!tok)
6781
0
            break;
6782
0
        tok->deleteNext();
6783
0
    }
6784
0
}
6785
6786
void Tokenizer::simplifyFunctionPointers()
6787
1.36k
{
6788
85.1k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
6789
        // #2873 - do not simplify function pointer usage here:
6790
        // (void)(xy(*p)(0));
6791
83.7k
        if (Token::simpleMatch(tok, ") (")) {
6792
0
            tok = tok->next()->link();
6793
0
            continue;
6794
0
        }
6795
6796
        // check for function pointer cast
6797
83.7k
        if (Token::Match(tok, "( %type% %type%| *| *| ( * ) (") ||
6798
83.7k
            Token::Match(tok, "static_cast < %type% %type%| *| *| ( * ) (")) {
6799
0
            Token *tok1 = tok;
6800
6801
0
            if (isCPP() && tok1->str() == "static_cast")
6802
0
                tok1 = tok1->next();
6803
6804
0
            tok1 = tok1->next();
6805
6806
0
            if (Token::Match(tok1->next(), "%type%"))
6807
0
                tok1 = tok1->next();
6808
6809
0
            while (tok1->next()->str() == "*")
6810
0
                tok1 = tok1->next();
6811
6812
            // check that the cast ends
6813
0
            if (!Token::Match(tok1->linkAt(4), ") )|>"))
6814
0
                continue;
6815
6816
            // ok simplify this function pointer cast to an ordinary pointer cast
6817
0
            tok1->deleteNext();
6818
0
            tok1->next()->deleteNext();
6819
0
            Token::eraseTokens(tok1->next(), tok1->linkAt(2)->next());
6820
0
            continue;
6821
0
        }
6822
6823
        // check for start of statement
6824
83.7k
        if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|,|(|public:|protected:|private:"))
6825
55.6k
            continue;
6826
6827
28.0k
        if (Token::Match(tok, "delete|else|return|throw|typedef"))
6828
2.37k
            continue;
6829
6830
34.2k
        while (Token::Match(tok, "%type%|:: %type%|::"))
6831
8.55k
            tok = tok->next();
6832
6833
25.6k
        Token *tok2 = (tok && tok->isName()) ? tok->next() : nullptr;
6834
25.7k
        while (Token::Match(tok2, "*|&"))
6835
55
            tok2 = tok2->next();
6836
25.6k
        if (!tok2 || tok2->str() != "(")
6837
22.5k
            continue;
6838
3.78k
        while (Token::Match(tok2, "(|:: %type%"))
6839
654
            tok2 = tok2->tokAt(2);
6840
3.13k
        if (!Token::Match(tok2, "(|:: * *| %name%"))
6841
3.13k
            continue;
6842
0
        tok2 = tok2->tokAt(2);
6843
0
        if (tok2->str() == "*")
6844
0
            tok2 = tok2->next();
6845
0
        while (Token::Match(tok2, "%type%|:: %type%|::"))
6846
0
            tok2 = tok2->next();
6847
6848
0
        if (!Token::Match(tok2, "%name% ) (") &&
6849
0
            !Token::Match(tok2, "%name% [ ] ) (") &&
6850
0
            !(Token::Match(tok2, "%name% (") && Token::simpleMatch(tok2->linkAt(1), ") ) (")))
6851
0
            continue;
6852
6853
0
        while (tok && tok->str() != "(")
6854
0
            tok = tok->next();
6855
6856
        // check that the declaration ends
6857
0
        if (!tok || !tok->link() || !tok->link()->next()) {
6858
0
            syntaxError(nullptr);
6859
0
        }
6860
0
        Token *endTok = tok->link()->next()->link();
6861
0
        if (Token::simpleMatch(endTok, ") throw ("))
6862
0
            endTok = endTok->linkAt(2);
6863
0
        if (!Token::Match(endTok, ") const|volatile| const|volatile| ;|,|)|=|[|{"))
6864
0
            continue;
6865
6866
0
        while (Token::Match(endTok->next(), "const|volatile"))
6867
0
            endTok->deleteNext();
6868
6869
        // ok simplify this function pointer to an ordinary pointer
6870
0
        if (Token::simpleMatch(tok->link()->previous(), ") )")) {
6871
            // Function returning function pointer
6872
            // void (*dostuff(void))(void) {}
6873
0
            Token::eraseTokens(tok->link(), endTok->next());
6874
0
            tok->link()->deleteThis();
6875
0
            tok->deleteThis();
6876
0
        } else {
6877
0
            Token::eraseTokens(tok->link()->linkAt(1), endTok->next());
6878
6879
            // remove variable names
6880
0
            int indent = 0;
6881
0
            for (Token* tok3 = tok->link()->tokAt(2); Token::Match(tok3, "%name%|*|&|[|(|)|::|,|<"); tok3 = tok3->next()) {
6882
0
                if (tok3->str() == ")" && --indent < 0)
6883
0
                    break;
6884
0
                if (tok3->str() == "<" && tok3->link())
6885
0
                    tok3 = tok3->link();
6886
0
                else if (Token::Match(tok3, "["))
6887
0
                    tok3 = tok3->link();
6888
0
                else if (tok3->str() == "(") {
6889
0
                    tok3 = tok3->link();
6890
0
                    if (Token::simpleMatch(tok3, ") (")) {
6891
0
                        tok3 = tok3->next();
6892
0
                        ++indent;
6893
0
                    } else
6894
0
                        break;
6895
0
                }
6896
0
                if (Token::Match(tok3, "%type%|*|&|> %name% [,)[]"))
6897
0
                    tok3->deleteNext();
6898
0
            }
6899
6900
            // TODO Keep this info
6901
0
            while (Token::Match(tok, "( %type% ::"))
6902
0
                tok->deleteNext(2);
6903
0
        }
6904
0
    }
6905
1.36k
}
6906
6907
void Tokenizer::simplifyVarDecl(const bool only_k_r_fpar)
6908
4.08k
{
6909
4.08k
    simplifyVarDecl(list.front(), nullptr, only_k_r_fpar);
6910
4.08k
}
6911
6912
void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, const bool only_k_r_fpar)
6913
4.08k
{
6914
4.08k
    const bool isCPP11  = mSettings->standards.cpp >= Standards::CPP11;
6915
6916
    // Split up variable declarations..
6917
    // "int a=4;" => "int a; a=4;"
6918
4.08k
    bool finishedwithkr = true;
6919
4.08k
    bool scopeDecl = false;
6920
202k
    for (Token *tok = tokBegin; tok != tokEnd; tok = tok->next()) {
6921
198k
        if (Token::Match(tok, "{|;"))
6922
49.8k
            scopeDecl = false;
6923
198k
        if (isCPP()) {
6924
198k
            if (Token::Match(tok, "class|struct|namespace|union"))
6925
0
                scopeDecl = true;
6926
198k
            if (Token::Match(tok, "decltype|noexcept (")) {
6927
0
                tok = tok->next()->link();
6928
                // skip decltype(...){...}
6929
0
                if (tok && Token::simpleMatch(tok->previous(), ") {"))
6930
0
                    tok = tok->link();
6931
198k
            } else if (Token::simpleMatch(tok, "= {") ||
6932
198k
                       (!scopeDecl && Token::Match(tok, "%name%|> {") &&
6933
198k
                        !Token::Match(tok, "else|try|do|const|constexpr|override|volatile|noexcept"))) {
6934
0
                if (!tok->next()->link())
6935
0
                    syntaxError(tokBegin);
6936
                // Check for lambdas before skipping
6937
0
                if (Token::Match(tok->tokAt(-2), ") . %name%")) { // trailing return type
6938
                    // TODO: support lambda without parameter clause?
6939
0
                    Token* lambdaStart = tok->linkAt(-2)->previous();
6940
0
                    if (Token::simpleMatch(lambdaStart, "]"))
6941
0
                        lambdaStart = lambdaStart->link();
6942
0
                    Token* lambdaEnd = findLambdaEndScope(lambdaStart);
6943
0
                    if (lambdaEnd)
6944
0
                        simplifyVarDecl(lambdaEnd->link()->next(), lambdaEnd, only_k_r_fpar);
6945
0
                } else {
6946
0
                    for (Token* tok2 = tok->next(); tok2 != tok->next()->link(); tok2 = tok2->next()) {
6947
0
                        Token* lambdaEnd = findLambdaEndScope(tok2);
6948
0
                        if (!lambdaEnd)
6949
0
                            continue;
6950
0
                        simplifyVarDecl(lambdaEnd->link()->next(), lambdaEnd, only_k_r_fpar);
6951
0
                    }
6952
0
                }
6953
0
                tok = tok->next()->link();
6954
0
            }
6955
6956
198k
        } else if (Token::simpleMatch(tok, "= {")) {
6957
0
            tok = tok->next()->link();
6958
0
        }
6959
198k
        if (!tok) {
6960
0
            syntaxError(tokBegin);
6961
0
        }
6962
198k
        if (only_k_r_fpar && finishedwithkr) {
6963
41.0k
            if (Token::Match(tok, "(|[|{")) {
6964
3.48k
                tok = tok->link();
6965
3.48k
                if (tok->next() && Token::Match(tok, ") !!{"))
6966
0
                    tok = tok->next();
6967
3.48k
                else
6968
3.48k
                    continue;
6969
3.48k
            } else
6970
37.5k
                continue;
6971
157k
        } else if (tok->str() == "(") {
6972
6.91k
            if (isCPP()) {
6973
34.6k
                for (Token * tok2 = tok; tok2 && tok2 != tok->link(); tok2 = tok2->next()) {
6974
27.7k
                    if (Token::Match(tok2, "[(,] [")) {
6975
                        // lambda function at tok2->next()
6976
                        // find start of lambda body
6977
0
                        Token * lambdaBody = tok2;
6978
0
                        while (lambdaBody && lambdaBody != tok2->link() && lambdaBody->str() != "{")
6979
0
                            lambdaBody = lambdaBody->next();
6980
0
                        if (lambdaBody && lambdaBody != tok2->link() && lambdaBody->link())
6981
0
                            simplifyVarDecl(lambdaBody, lambdaBody->link()->next(), only_k_r_fpar);
6982
0
                    }
6983
27.7k
                }
6984
6.91k
            }
6985
6.91k
            tok = tok->link();
6986
6.91k
        }
6987
6988
157k
        if (!tok)
6989
0
            syntaxError(nullptr); // #7043 invalid code
6990
157k
        if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|)|public:|protected:|private:"))
6991
101k
            continue;
6992
55.7k
        if (Token::simpleMatch(tok, "template <"))
6993
0
            continue;
6994
6995
55.7k
        Token *type0 = tok;
6996
55.7k
        if (!Token::Match(type0, "::|extern| %type%"))
6997
14.3k
            continue;
6998
41.3k
        if (Token::Match(type0, "else|return|public:|protected:|private:"))
6999
4.74k
            continue;
7000
36.5k
        if (isCPP11 && type0->str() == "using")
7001
0
            continue;
7002
36.5k
        if (isCPP() && type0->str() == "namespace")
7003
0
            continue;
7004
7005
36.5k
        bool isconst = false;
7006
36.5k
        bool isstatic = false;
7007
36.5k
        Token *tok2 = type0;
7008
36.5k
        int typelen = 1;
7009
7010
36.5k
        if (Token::Match(tok2, "::|extern")) {
7011
0
            tok2 = tok2->next();
7012
0
            typelen++;
7013
0
        }
7014
7015
        //check if variable is declared 'const' or 'static' or both
7016
36.5k
        while (tok2) {
7017
36.5k
            if (!Token::Match(tok2, "const|static|constexpr") && Token::Match(tok2, "%type% const|static")) {
7018
0
                tok2 = tok2->next();
7019
0
                ++typelen;
7020
0
            }
7021
7022
36.5k
            if (Token::Match(tok2, "const|constexpr"))
7023
0
                isconst = true;
7024
7025
36.5k
            else if (Token::Match(tok2, "static|constexpr"))
7026
0
                isstatic = true;
7027
7028
36.5k
            else if (Token::Match(tok2, "%type% :: %type%")) {
7029
0
                tok2 = tok2->next();
7030
0
                ++typelen;
7031
0
            }
7032
7033
36.5k
            else
7034
36.5k
                break;
7035
7036
0
            if (tok2->strAt(1) == "*")
7037
0
                break;
7038
7039
0
            if (Token::Match(tok2->next(), "& %name% ,"))
7040
0
                break;
7041
7042
0
            tok2 = tok2->next();
7043
0
            ++typelen;
7044
0
        }
7045
7046
        // strange looking variable declaration => don't split up.
7047
36.5k
        if (Token::Match(tok2, "%type% *|&| %name% , %type% *|&| %name%"))
7048
0
            continue;
7049
7050
36.5k
        if (Token::Match(tok2, "struct|union|class %type%")) {
7051
0
            tok2 = tok2->next();
7052
0
            ++typelen;
7053
0
        }
7054
7055
        // check for qualification..
7056
36.5k
        if (Token::Match(tok2,  ":: %type%")) {
7057
0
            ++typelen;
7058
0
            tok2 = tok2->next();
7059
0
        }
7060
7061
        //skip combinations of templates and namespaces
7062
36.5k
        while (!isC() && (Token::Match(tok2, "%type% <") || Token::Match(tok2, "%type% ::"))) {
7063
0
            if (tok2->next()->str() == "<" && !TemplateSimplifier::templateParameters(tok2->next())) {
7064
0
                tok2 = nullptr;
7065
0
                break;
7066
0
            }
7067
0
            typelen += 2;
7068
0
            tok2 = tok2->tokAt(2);
7069
0
            if (tok2 && tok2->previous()->str() == "::")
7070
0
                continue;
7071
0
            int indentlevel = 0;
7072
0
            int parens = 0;
7073
7074
0
            for (Token *tok3 = tok2; tok3; tok3 = tok3->next()) {
7075
0
                ++typelen;
7076
7077
0
                if (!parens && tok3->str() == "<") {
7078
0
                    ++indentlevel;
7079
0
                } else if (!parens && tok3->str() == ">") {
7080
0
                    if (indentlevel == 0) {
7081
0
                        tok2 = tok3->next();
7082
0
                        break;
7083
0
                    }
7084
0
                    --indentlevel;
7085
0
                } else if (!parens && tok3->str() == ">>") {
7086
0
                    if (indentlevel <= 1) {
7087
0
                        tok2 = tok3->next();
7088
0
                        break;
7089
0
                    }
7090
0
                    indentlevel -= 2;
7091
0
                } else if (tok3->str() == "(") {
7092
0
                    ++parens;
7093
0
                } else if (tok3->str() == ")") {
7094
0
                    if (!parens) {
7095
0
                        tok2 = nullptr;
7096
0
                        break;
7097
0
                    }
7098
0
                    --parens;
7099
0
                } else if (tok3->str() == ";") {
7100
0
                    break;
7101
0
                }
7102
0
            }
7103
7104
0
            if (Token::Match(tok2,  ":: %type%")) {
7105
0
                ++typelen;
7106
0
                tok2 = tok2->next();
7107
0
            }
7108
7109
            // east const
7110
0
            if (Token::simpleMatch(tok2, "const"))
7111
0
                isconst = true;
7112
0
        }
7113
7114
        //pattern: "%type% *| ... *| const| %name% ,|="
7115
36.5k
        if (Token::Match(tok2, "%type%") ||
7116
36.5k
            (tok2 && tok2->previous() && tok2->previous()->str() == ">")) {
7117
36.5k
            Token *varName = tok2;
7118
36.5k
            if (!tok2->previous() || tok2->previous()->str() != ">")
7119
36.5k
                varName = varName->next();
7120
0
            else
7121
0
                --typelen;
7122
36.5k
            if (isCPP() && Token::Match(varName, "public:|private:|protected:|using"))
7123
0
                continue;
7124
            //skip all the pointer part
7125
36.5k
            bool isPointerOrRef = false;
7126
36.5k
            while (Token::simpleMatch(varName, "*") || Token::Match(varName, "& %name% ,")) {
7127
0
                isPointerOrRef = true;
7128
0
                varName = varName->next();
7129
0
            }
7130
7131
36.5k
            while (Token::Match(varName, "%type% %type%")) {
7132
0
                if (varName->str() != "const" && varName->str() != "volatile") {
7133
0
                    ++typelen;
7134
0
                }
7135
0
                varName = varName->next();
7136
0
            }
7137
            // Function pointer
7138
36.5k
            if (Token::simpleMatch(varName, "( *") &&
7139
36.5k
                Token::Match(varName->link()->previous(), "%name% ) (") &&
7140
36.5k
                Token::simpleMatch(varName->link()->linkAt(1), ") =")) {
7141
0
                Token *endDecl = varName->link()->linkAt(1);
7142
0
                varName = varName->link()->previous();
7143
0
                endDecl->insertToken(";");
7144
0
                endDecl = endDecl->next();
7145
0
                endDecl->next()->isSplittedVarDeclEq(true);
7146
0
                endDecl->insertToken(varName->str());
7147
0
                endDecl->next()->isExpandedMacro(varName->isExpandedMacro());
7148
0
                continue;
7149
0
            }
7150
            //non-VLA case
7151
36.5k
            if (Token::Match(varName, "%name% ,|=")) {
7152
6.81k
                if (varName->str() != "operator") {
7153
6.81k
                    tok2 = varName->next(); // The ',' or '=' token
7154
7155
6.81k
                    if (tok2->str() == "=" && (isstatic || (isconst && !isPointerOrRef))) {
7156
                        //do not split const non-pointer variables..
7157
0
                        while (tok2 && tok2->str() != "," && tok2->str() != ";") {
7158
0
                            if (Token::Match(tok2, "{|(|["))
7159
0
                                tok2 = tok2->link();
7160
0
                            const Token *tok3 = tok2;
7161
0
                            if (!isC() && tok2->str() == "<" && TemplateSimplifier::templateParameters(tok2) > 0) {
7162
0
                                tok2 = tok2->findClosingBracket();
7163
0
                            }
7164
0
                            if (!tok2)
7165
0
                                syntaxError(tok3); // #6881 invalid code
7166
0
                            tok2 = tok2->next();
7167
0
                        }
7168
0
                        if (tok2 && tok2->str() == ";")
7169
0
                            tok2 = nullptr;
7170
0
                    }
7171
6.81k
                } else
7172
0
                    tok2 = nullptr;
7173
6.81k
            }
7174
7175
            //VLA case
7176
29.7k
            else if (Token::Match(varName, "%name% [")) {
7177
0
                tok2 = varName->next();
7178
7179
0
                while (Token::Match(tok2->link(), "] ,|=|["))
7180
0
                    tok2 = tok2->link()->next();
7181
0
                if (!Token::Match(tok2, "=|,"))
7182
0
                    tok2 = nullptr;
7183
0
                if (tok2 && tok2->str() == "=") {
7184
0
                    while (tok2 && tok2->str() != "," && tok2->str() != ";") {
7185
0
                        if (Token::Match(tok2, "{|(|["))
7186
0
                            tok2 = tok2->link();
7187
0
                        tok2 = tok2->next();
7188
0
                    }
7189
0
                    if (tok2 && tok2->str() == ";")
7190
0
                        tok2 = nullptr;
7191
0
                }
7192
0
            }
7193
7194
            // brace initialization
7195
29.7k
            else if (Token::Match(varName, "%name% {")) {
7196
0
                tok2 = varName->next();
7197
0
                tok2 = tok2->link();
7198
0
                if (tok2)
7199
0
                    tok2 = tok2->next();
7200
0
                if (tok2 && tok2->str() != ",")
7201
0
                    tok2 = nullptr;
7202
0
            }
7203
7204
            // function declaration
7205
29.7k
            else if (Token::Match(varName, "%name% (")) {
7206
3.48k
                Token* commaTok = varName->linkAt(1)->next();
7207
3.48k
                while (Token::Match(commaTok, "const|noexcept|override|final")) {
7208
0
                    commaTok = commaTok->next();
7209
0
                    if (Token::Match(commaTok, "( true|false )"))
7210
0
                        commaTok = commaTok->link()->next();
7211
0
                }
7212
3.48k
                tok2 = Token::simpleMatch(commaTok, ",") ? commaTok : nullptr;
7213
3.48k
            }
7214
7215
26.2k
            else
7216
26.2k
                tok2 = nullptr;
7217
36.5k
        } else {
7218
0
            tok2 = nullptr;
7219
0
        }
7220
7221
36.5k
        if (!tok2) {
7222
29.7k
            if (only_k_r_fpar)
7223
0
                finishedwithkr = false;
7224
29.7k
            continue;
7225
29.7k
        }
7226
7227
6.81k
        if (tok2->str() == ",") {
7228
0
            tok2->str(";");
7229
0
            tok2->isSplittedVarDeclComma(true);
7230
            //TODO: should we have to add also template '<>' links?
7231
0
            TokenList::insertTokens(tok2, type0, typelen);
7232
0
        }
7233
7234
6.81k
        else {
7235
6.81k
            Token *eq = tok2;
7236
7237
20.4k
            while (tok2) {
7238
20.4k
                if (Token::Match(tok2, "{|(|["))
7239
0
                    tok2 = tok2->link();
7240
7241
20.4k
                else if (!isC() && tok2->str() == "<" && ((tok2->previous()->isName() && !tok2->previous()->varId()) || tok2->strAt(-1) == "]"))
7242
0
                    tok2 = tok2->findClosingBracket();
7243
7244
20.4k
                else if (std::strchr(";,", tok2->str()[0])) {
7245
                    // "type var ="   =>   "type var; var ="
7246
6.81k
                    const Token *varTok = type0->tokAt(typelen);
7247
6.81k
                    while (Token::Match(varTok, "%name%|*|& %name%|*|&"))
7248
0
                        varTok = varTok->next();
7249
6.81k
                    if (!varTok)
7250
0
                        syntaxError(tok2); // invalid code
7251
6.81k
                    TokenList::insertTokens(eq, varTok, 2);
7252
6.81k
                    eq->str(";");
7253
6.81k
                    eq->isSplittedVarDeclEq(true);
7254
7255
                    // "= x, "   =>   "= x; type "
7256
6.81k
                    if (tok2->str() == ",") {
7257
0
                        tok2->str(";");
7258
0
                        tok2->isSplittedVarDeclComma(true);
7259
0
                        TokenList::insertTokens(tok2, type0, typelen);
7260
0
                    }
7261
6.81k
                    break;
7262
6.81k
                }
7263
13.6k
                if (tok2)
7264
13.6k
                    tok2 = tok2->next();
7265
13.6k
            }
7266
6.81k
        }
7267
6.81k
        finishedwithkr = (only_k_r_fpar && tok2 && tok2->strAt(1) == "{");
7268
6.81k
    }
7269
4.08k
}
7270
7271
void Tokenizer::simplifyStaticConst()
7272
1.36k
{
7273
    // This function will simplify the token list so that the qualifiers "extern", "static"
7274
    // and "const" appear in the same order as in the array below.
7275
1.36k
    const std::string qualifiers[] = {"extern", "static", "const"};
7276
7277
    // Move 'const' before all other qualifiers and types and then
7278
    // move 'static' before all other qualifiers and types, ...
7279
94.1k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
7280
92.7k
        bool continue2 = false;
7281
370k
        for (int i = 0; i < sizeof(qualifiers)/sizeof(qualifiers[0]); i++) {
7282
7283
            // Keep searching for a qualifier
7284
278k
            if (!tok->next() || tok->next()->str() != qualifiers[i])
7285
278k
                continue;
7286
7287
            // Look backwards to find the beginning of the declaration
7288
0
            Token* leftTok = tok;
7289
0
            bool behindOther = false;
7290
0
            for (; leftTok; leftTok = leftTok->previous()) {
7291
0
                for (int j = 0; j <= i; j++) {
7292
0
                    if (leftTok->str() == qualifiers[j]) {
7293
0
                        behindOther = true;
7294
0
                        break;
7295
0
                    }
7296
0
                }
7297
0
                if (behindOther)
7298
0
                    break;
7299
0
                if (isCPP() && Token::simpleMatch(leftTok, ">")) {
7300
0
                    Token* opening = leftTok->findOpeningBracket();
7301
0
                    if (opening) {
7302
0
                        leftTok = opening;
7303
0
                        continue;
7304
0
                    }
7305
0
                }
7306
0
                if (!Token::Match(leftTok, "%type%|struct|::") ||
7307
0
                    (isCPP() && Token::Match(leftTok, "private:|protected:|public:|operator|template"))) {
7308
0
                    break;
7309
0
                }
7310
0
            }
7311
7312
            // The token preceding the declaration should indicate the start of a declaration
7313
0
            if (leftTok == tok)
7314
0
                continue;
7315
7316
0
            if (leftTok && !behindOther && !Token::Match(leftTok, ";|{|}|(|,|private:|protected:|public:")) {
7317
0
                continue2 = true;
7318
0
                break;
7319
0
            }
7320
7321
            // Move the qualifier to the left-most position in the declaration
7322
0
            tok->deleteNext();
7323
0
            if (!leftTok) {
7324
0
                list.front()->insertToken(qualifiers[i], emptyString, false);
7325
0
                list.front()->swapWithNext();
7326
0
                tok = list.front();
7327
0
            } else if (leftTok->next()) {
7328
0
                leftTok->next()->insertToken(qualifiers[i], emptyString, true);
7329
0
                tok = leftTok->next();
7330
0
            } else {
7331
0
                leftTok->insertToken(qualifiers[i]);
7332
0
                tok = leftTok;
7333
0
            }
7334
0
        }
7335
92.7k
        if (continue2)
7336
0
            continue;
7337
92.7k
    }
7338
1.36k
}
7339
7340
void Tokenizer::simplifyVariableMultipleAssign()
7341
1.36k
{
7342
94.1k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
7343
92.7k
        if (Token::Match(tok, "%name% = %name% = %num%|%name% ;")) {
7344
            // skip intermediate assignments
7345
22
            Token *tok2 = tok->previous();
7346
22
            while (tok2 &&
7347
22
                   tok2->str() == "=" &&
7348
22
                   Token::Match(tok2->previous(), "%name%")) {
7349
0
                tok2 = tok2->tokAt(-2);
7350
0
            }
7351
7352
22
            if (!tok2 || tok2->str() != ";") {
7353
12
                continue;
7354
12
            }
7355
7356
10
            Token *stopAt = tok->tokAt(2);
7357
10
            const Token *valueTok = stopAt->tokAt(2);
7358
10
            const std::string& value(valueTok->str());
7359
10
            tok2 = tok2->next();
7360
7361
20
            while (tok2 != stopAt) {
7362
10
                tok2->next()->insertToken(";");
7363
10
                tok2->next()->insertToken(value);
7364
10
                tok2 = tok2->tokAt(4);
7365
10
            }
7366
10
        }
7367
92.7k
    }
7368
1.36k
}
7369
7370
// Binary operators simplification map
7371
static const std::unordered_map<std::string, std::string> cAlternativeTokens = {
7372
    std::make_pair("and", "&&")
7373
    , std::make_pair("and_eq", "&=")
7374
    , std::make_pair("bitand", "&")
7375
    , std::make_pair("bitor", "|")
7376
    , std::make_pair("not_eq", "!=")
7377
    , std::make_pair("or", "||")
7378
    , std::make_pair("or_eq", "|=")
7379
    , std::make_pair("xor", "^")
7380
    , std::make_pair("xor_eq", "^=")
7381
};
7382
7383
// Simplify the C alternative tokens:
7384
//  and      =>     &&
7385
//  and_eq   =>     &=
7386
//  bitand   =>     &
7387
//  bitor    =>     |
7388
//  compl    =>     ~
7389
//  not      =>     !
7390
//  not_eq   =>     !=
7391
//  or       =>     ||
7392
//  or_eq    =>     |=
7393
//  xor      =>     ^
7394
//  xor_eq   =>     ^=
7395
bool Tokenizer::simplifyCAlternativeTokens()
7396
1.36k
{
7397
    /* executable scope level */
7398
1.36k
    int executableScopeLevel = 0;
7399
7400
1.36k
    std::vector<Token *> alt;
7401
1.36k
    bool replaceAll = false;  // replace all or none
7402
7403
78.5k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
7404
77.2k
        if (tok->str() == ")") {
7405
3.91k
            if (const Token *end = isFunctionHead(tok, "{")) {
7406
3.12k
                ++executableScopeLevel;
7407
3.12k
                tok = const_cast<Token *>(end);
7408
3.12k
                continue;
7409
3.12k
            }
7410
3.91k
        }
7411
7412
74.1k
        if (tok->str() == "{") {
7413
458
            if (executableScopeLevel > 0)
7414
458
                ++executableScopeLevel;
7415
458
            continue;
7416
458
        }
7417
7418
73.6k
        if (tok->str() == "}") {
7419
3.58k
            if (executableScopeLevel > 0)
7420
3.58k
                --executableScopeLevel;
7421
3.58k
            continue;
7422
3.58k
        }
7423
7424
70.0k
        if (!tok->isName())
7425
41.1k
            continue;
7426
7427
28.9k
        const std::unordered_map<std::string, std::string>::const_iterator cOpIt = cAlternativeTokens.find(tok->str());
7428
28.9k
        if (cOpIt != cAlternativeTokens.end()) {
7429
0
            alt.push_back(tok);
7430
7431
            // Is this a variable declaration..
7432
0
            if (isC() && Token::Match(tok->previous(), "%type%|* %name% [;,=]"))
7433
0
                return false;
7434
7435
0
            if (!Token::Match(tok->previous(), "%name%|%num%|%char%|)|]|> %name% %name%|%num%|%char%|%op%|("))
7436
0
                continue;
7437
0
            if (Token::Match(tok->next(), "%assign%|%or%|%oror%|&&|*|/|%|^") && !Token::Match(tok->previous(), "%num%|%char%|) %name% *"))
7438
0
                continue;
7439
0
            if (executableScopeLevel == 0 && Token::Match(tok, "%name% (")) {
7440
0
                const Token *start = tok;
7441
0
                while (Token::Match(start, "%name%|*"))
7442
0
                    start = start->previous();
7443
0
                if (!start || Token::Match(start, "[;}]"))
7444
0
                    continue;
7445
0
            }
7446
0
            replaceAll = true;
7447
28.9k
        } else if (Token::Match(tok, "not|compl")) {
7448
0
            alt.push_back(tok);
7449
7450
0
            if (Token::Match(tok->previous(), "%assign%") || Token::Match(tok->next(), "%num%")) {
7451
0
                replaceAll = true;
7452
0
                continue;
7453
0
            }
7454
7455
            // Don't simplify 'not p;' (in case 'not' is a type)
7456
0
            if (!Token::Match(tok->next(), "%name%|(") ||
7457
0
                Token::Match(tok->previous(), "[;{}]") ||
7458
0
                (executableScopeLevel == 0U && tok->strAt(-1) == "("))
7459
0
                continue;
7460
7461
0
            replaceAll = true;
7462
0
        }
7463
28.9k
    }
7464
7465
1.36k
    if (!replaceAll)
7466
1.36k
        return false;
7467
7468
0
    for (Token *tok: alt) {
7469
0
        const std::unordered_map<std::string, std::string>::const_iterator cOpIt = cAlternativeTokens.find(tok->str());
7470
0
        if (cOpIt != cAlternativeTokens.end())
7471
0
            tok->str(cOpIt->second);
7472
0
        else if (tok->str() == "not")
7473
0
            tok->str("!");
7474
0
        else
7475
0
            tok->str("~");
7476
0
    }
7477
7478
0
    return !alt.empty();
7479
1.36k
}
7480
7481
// int i(0); => int i; i = 0;
7482
// int i(0), j; => int i; i = 0; int j;
7483
void Tokenizer::simplifyInitVar()
7484
4.08k
{
7485
4.08k
    if (isC())
7486
0
        return;
7487
7488
267k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
7489
263k
        if (!tok->isName() || (tok->previous() && !Token::Match(tok->previous(), "[;{}]")))
7490
208k
            continue;
7491
7492
55.1k
        if (tok->str() == "return")
7493
5.74k
            continue;
7494
7495
49.4k
        if (Token::Match(tok, "class|struct|union| %type% *| %name% ( &| %any% ) ;")) {
7496
0
            tok = initVar(tok);
7497
49.4k
        } else if (Token::Match(tok, "%type% *| %name% ( %type% (")) {
7498
0
            const Token* tok2 = tok->tokAt(2);
7499
0
            if (!tok2->link())
7500
0
                tok2 = tok2->next();
7501
0
            if (!tok2->link() || (tok2->link()->strAt(1) == ";" && !Token::simpleMatch(tok2->linkAt(2), ") (")))
7502
0
                tok = initVar(tok);
7503
49.4k
        } else if (Token::Match(tok, "class|struct|union| %type% *| %name% ( &| %any% ) ,") && tok->str() != "new") {
7504
0
            Token *tok1 = tok->tokAt(5);
7505
0
            while (tok1->str() != ",")
7506
0
                tok1 = tok1->next();
7507
0
            tok1->str(";");
7508
7509
0
            const int numTokens = (Token::Match(tok, "class|struct|union")) ? 2U : 1U;
7510
0
            TokenList::insertTokens(tok1, tok, numTokens);
7511
0
            tok = initVar(tok);
7512
0
        }
7513
49.4k
    }
7514
4.08k
}
7515
7516
Token * Tokenizer::initVar(Token * tok)
7517
0
{
7518
    // call constructor of class => no simplification
7519
0
    if (Token::Match(tok, "class|struct|union")) {
7520
0
        if (tok->strAt(2) != "*")
7521
0
            return tok;
7522
7523
0
        tok = tok->next();
7524
0
    } else if (!tok->isStandardType() && tok->str() != "auto" && tok->next()->str() != "*")
7525
0
        return tok;
7526
7527
    // goto variable name..
7528
0
    tok = tok->next();
7529
0
    if (tok->str() == "*")
7530
0
        tok = tok->next();
7531
7532
    // sizeof is not a variable name..
7533
0
    if (tok->str() == "sizeof")
7534
0
        return tok;
7535
7536
    // check initializer..
7537
0
    if (tok->tokAt(2)->isStandardType() || tok->strAt(2) == "void")
7538
0
        return tok;
7539
0
    if (!tok->tokAt(2)->isNumber() && !Token::Match(tok->tokAt(2), "%type% (") && tok->strAt(2) != "&" && tok->tokAt(2)->varId() == 0)
7540
0
        return tok;
7541
7542
    // insert '; var ='
7543
0
    tok->insertToken(";");
7544
0
    tok->next()->insertToken(tok->str());
7545
0
    tok->tokAt(2)->varId(tok->varId());
7546
0
    tok = tok->tokAt(2);
7547
0
    tok->insertToken("=");
7548
7549
    // goto '('..
7550
0
    tok = tok->tokAt(2);
7551
7552
    // delete ')'
7553
0
    tok->link()->deleteThis();
7554
7555
    // delete this
7556
0
    tok->deleteThis();
7557
7558
0
    return tok;
7559
0
}
7560
7561
void Tokenizer::elseif()
7562
1.36k
{
7563
93.6k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
7564
92.3k
        if (tok->str() != "else")
7565
91.8k
            continue;
7566
7567
458
        if (!Token::Match(tok->previous(), ";|}"))
7568
0
            syntaxError(tok->previous());
7569
7570
458
        if (!Token::Match(tok->next(), "%name%"))
7571
458
            continue;
7572
7573
0
        if (tok->strAt(1) != "if")
7574
0
            unknownMacroError(tok->next());
7575
7576
0
        for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
7577
0
            if (Token::Match(tok2, "(|{|["))
7578
0
                tok2 = tok2->link();
7579
7580
0
            if (Token::Match(tok2, "}|;")) {
7581
0
                if (tok2->next() && tok2->next()->str() != "else") {
7582
0
                    tok->insertToken("{");
7583
0
                    tok2->insertToken("}");
7584
0
                    Token::createMutualLinks(tok->next(), tok2->next());
7585
0
                    break;
7586
0
                }
7587
0
            }
7588
0
        }
7589
0
    }
7590
1.36k
}
7591
7592
7593
void Tokenizer::simplifyIfSwitchForInit()
7594
1.36k
{
7595
1.36k
    if (!isCPP() || mSettings->standards.cpp < Standards::CPP17)
7596
0
        return;
7597
7598
1.36k
    const bool forInit = (mSettings->standards.cpp >= Standards::CPP20);
7599
7600
93.6k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
7601
92.3k
        if (!Token::Match(tok, "if|switch|for ("))
7602
91.3k
            continue;
7603
7604
920
        Token *semicolon = tok->tokAt(2);
7605
6.23k
        while (!Token::Match(semicolon, "[;)]")) {
7606
5.31k
            if (Token::Match(semicolon, "(|{|[") && semicolon->link())
7607
265
                semicolon = semicolon->link();
7608
5.31k
            semicolon = semicolon->next();
7609
5.31k
        }
7610
920
        if (semicolon->str() != ";")
7611
920
            continue;
7612
7613
0
        if (tok->str() ==  "for") {
7614
0
            if (!forInit)
7615
0
                continue;
7616
7617
            // Is it a for range..
7618
0
            const Token *tok2 = semicolon->next();
7619
0
            bool rangeFor = false;
7620
0
            while (!Token::Match(tok2, "[;)]")) {
7621
0
                if (tok2->str() == "(")
7622
0
                    tok2 = tok2->link();
7623
0
                else if (!rangeFor && tok2->str() == "?")
7624
0
                    break;
7625
0
                else if (tok2->str() == ":")
7626
0
                    rangeFor = true;
7627
0
                tok2 = tok2->next();
7628
0
            }
7629
0
            if (!rangeFor || tok2->str() != ")")
7630
0
                continue;
7631
0
        }
7632
7633
0
        Token *endpar = tok->linkAt(1);
7634
0
        if (!Token::simpleMatch(endpar, ") {"))
7635
0
            continue;
7636
7637
0
        Token *endscope = endpar->linkAt(1);
7638
0
        if (Token::simpleMatch(endscope, "} else {"))
7639
0
            endscope = endscope->linkAt(2);
7640
7641
        // Simplify, the initialization expression is broken out..
7642
0
        semicolon->insertToken(tok->str());
7643
0
        semicolon->next()->insertToken("(");
7644
0
        Token::createMutualLinks(semicolon->next()->next(), endpar);
7645
0
        tok->deleteNext();
7646
0
        tok->str("{");
7647
0
        endscope->insertToken("}");
7648
0
        Token::createMutualLinks(tok, endscope->next());
7649
0
        tok->isSimplifiedScope(true);
7650
0
    }
7651
1.36k
}
7652
7653
7654
bool Tokenizer::simplifyRedundantParentheses()
7655
1.36k
{
7656
1.36k
    bool ret = false;
7657
93.6k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
7658
92.3k
        if (tok->str() != "(")
7659
88.3k
            continue;
7660
7661
3.98k
        if (isCPP() && Token::simpleMatch(tok->previous(), "} (")) {
7662
0
            const Token* plp = tok->previous()->link()->previous();
7663
0
            if (Token::Match(plp, "%name%|>|] {") || (Token::simpleMatch(plp, ")") && Token::simpleMatch(plp->link()->previous(), "]")))
7664
0
                continue;
7665
0
        }
7666
7667
3.98k
        if (Token::simpleMatch(tok, "( {"))
7668
0
            continue;
7669
7670
3.98k
        if (Token::Match(tok->link(), ") %num%")) {
7671
0
            tok = tok->link();
7672
0
            continue;
7673
0
        }
7674
7675
        // Do not simplify if there is comma inside parentheses..
7676
3.98k
        if (Token::Match(tok->previous(), "%op% (") || Token::Match(tok->link(), ") %op%")) {
7677
800
            bool innerComma = false;
7678
2.52k
            for (const Token *inner = tok->link()->previous(); inner != tok; inner = inner->previous()) {
7679
1.72k
                if (inner->str() == ")")
7680
91
                    inner = inner->link();
7681
1.72k
                if (inner->str() == ",") {
7682
0
                    innerComma = true;
7683
0
                    break;
7684
0
                }
7685
1.72k
            }
7686
800
            if (innerComma)
7687
0
                continue;
7688
800
        }
7689
7690
        // !!operator = ( x ) ;
7691
3.98k
        if (tok->strAt(-2) != "operator" &&
7692
3.98k
            tok->previous() && tok->previous()->str() == "=" &&
7693
3.98k
            tok->next() && tok->next()->str() != "{" &&
7694
3.98k
            Token::simpleMatch(tok->link(), ") ;")) {
7695
106
            tok->link()->deleteThis();
7696
106
            tok->deleteThis();
7697
106
            continue;
7698
106
        }
7699
7700
3.92k
        while (Token::simpleMatch(tok, "( (") &&
7701
3.92k
               tok->link() && tok->link()->previous() == tok->next()->link()) {
7702
            // We have "(( *something* ))", remove the inner
7703
            // parentheses
7704
46
            tok->deleteNext();
7705
46
            tok->link()->tokAt(-2)->deleteNext();
7706
46
            ret = true;
7707
46
        }
7708
7709
3.87k
        if (isCPP() && Token::Match(tok->tokAt(-2), "[;{}=(] new (") && Token::Match(tok->link(), ") [;,{}[]")) {
7710
            // Remove the parentheses in "new (type)" constructs
7711
0
            tok->link()->deleteThis();
7712
0
            tok->deleteThis();
7713
0
            ret = true;
7714
0
        }
7715
7716
3.87k
        if (Token::Match(tok->previous(), "! ( %name% )")) {
7717
            // Remove the parentheses
7718
0
            tok->deleteThis();
7719
0
            tok->deleteNext();
7720
0
            ret = true;
7721
0
        }
7722
7723
3.87k
        if (Token::Match(tok->previous(), "[(,;{}] ( %name% ) .")) {
7724
            // Remove the parentheses
7725
0
            tok->deleteThis();
7726
0
            tok->deleteNext();
7727
0
            ret = true;
7728
0
        }
7729
7730
3.87k
        if (Token::Match(tok->previous(), "[(,;{}] ( %name% (") && !tok->next()->isKeyword() &&
7731
3.87k
            tok->link()->previous() == tok->linkAt(2)) {
7732
            // We have "( func ( *something* ))", remove the outer
7733
            // parentheses
7734
0
            tok->link()->deleteThis();
7735
0
            tok->deleteThis();
7736
0
            ret = true;
7737
0
        }
7738
7739
3.87k
        if (Token::Match(tok->previous(), "[,;{}] ( delete [| ]| %name% ) ;")) {
7740
            // We have "( delete [| ]| var )", remove the outer
7741
            // parentheses
7742
0
            tok->link()->deleteThis();
7743
0
            tok->deleteThis();
7744
0
            ret = true;
7745
0
        }
7746
7747
3.87k
        if (!Token::simpleMatch(tok->tokAt(-2), "operator delete") &&
7748
3.87k
            Token::Match(tok->previous(), "delete|; (") &&
7749
3.87k
            (tok->previous()->str() != "delete" || tok->next()->varId() > 0) &&
7750
3.87k
            Token::Match(tok->link(), ") ;|,")) {
7751
0
            tok->link()->deleteThis();
7752
0
            tok->deleteThis();
7753
0
            ret = true;
7754
0
        }
7755
7756
3.87k
        if (Token::Match(tok->previous(), "[(!*;{}] ( %name% )") &&
7757
3.87k
            (tok->next()->varId() != 0 || Token::Match(tok->tokAt(3), "[+-/=]")) && !tok->next()->isStandardType()) {
7758
            // We have "( var )", remove the parentheses
7759
5
            tok->deleteThis();
7760
5
            tok->deleteNext();
7761
5
            ret = true;
7762
5
        }
7763
7764
3.87k
        while (Token::Match(tok->previous(), "[;{}[(,!*] ( %name% .")) {
7765
0
            Token *tok2 = tok->tokAt(2);
7766
0
            while (Token::Match(tok2, ". %name%")) {
7767
0
                tok2 = tok2->tokAt(2);
7768
0
            }
7769
0
            if (tok2 != tok->link())
7770
0
                break;
7771
            // We have "( var . var . ... . var )", remove the parentheses
7772
0
            tok = tok->previous();
7773
0
            tok->deleteNext();
7774
0
            tok2->deleteThis();
7775
0
            ret = true;
7776
0
        }
7777
7778
3.87k
        if (Token::simpleMatch(tok->previous(), "? (") && Token::simpleMatch(tok->link(), ") :")) {
7779
0
            const Token *tok2 = tok->next();
7780
0
            while (tok2 && (Token::Match(tok2,"%bool%|%num%|%name%") || tok2->isArithmeticalOp()))
7781
0
                tok2 = tok2->next();
7782
0
            if (tok2 && tok2->str() == ")") {
7783
0
                tok->link()->deleteThis();
7784
0
                tok->deleteThis();
7785
0
                ret = true;
7786
0
                continue;
7787
0
            }
7788
0
        }
7789
7790
3.87k
        while (Token::Match(tok->previous(), "[{([,] ( !!{") &&
7791
3.87k
               Token::Match(tok->link(), ") [;,])]") &&
7792
3.87k
               !Token::simpleMatch(tok->tokAt(-2), "operator ,") && // Ticket #5709
7793
3.87k
               !Token::findsimplematch(tok, ",", tok->link())) {
7794
            // We have "( ... )", remove the parentheses
7795
4
            tok->link()->deleteThis();
7796
4
            tok->deleteThis();
7797
4
            ret = true;
7798
4
        }
7799
7800
3.87k
        if (Token::simpleMatch(tok->previous(), ", (") &&
7801
3.87k
            Token::simpleMatch(tok->link(), ") =")) {
7802
0
            tok->link()->deleteThis();
7803
0
            tok->deleteThis();
7804
0
            ret = true;
7805
0
        }
7806
7807
        // Simplify "!!operator !!%name%|)|]|>|>> ( %num%|%bool% ) %op%|;|,|)"
7808
3.87k
        if (Token::Match(tok, "( %bool%|%num% ) %cop%|;|,|)") &&
7809
3.87k
            tok->strAt(-2) != "operator" &&
7810
3.87k
            tok->previous() &&
7811
3.87k
            !Token::Match(tok->previous(), "%name%|)|]") &&
7812
3.87k
            (!(isCPP() && Token::Match(tok->previous(),">|>>")))) {
7813
64
            tok->link()->deleteThis();
7814
64
            tok->deleteThis();
7815
64
            ret = true;
7816
64
        }
7817
7818
3.87k
        if (Token::Match(tok->previous(), "*|& ( %name% )")) {
7819
            // We may have a variable declaration looking like "type_name *(var_name)"
7820
16
            Token *tok2 = tok->tokAt(-2);
7821
30
            while (Token::Match(tok2, "%type%|static|const|extern") && tok2->str() != "operator") {
7822
14
                tok2 = tok2->previous();
7823
14
            }
7824
16
            if (tok2 && !Token::Match(tok2, "[;,{]")) {
7825
                // Not a variable declaration
7826
14
            } else {
7827
2
                tok->deleteThis();
7828
2
                tok->deleteNext();
7829
2
            }
7830
16
        }
7831
3.87k
    }
7832
1.36k
    return ret;
7833
1.36k
}
7834
7835
void Tokenizer::simplifyTypeIntrinsics()
7836
1.36k
{
7837
1.36k
    static const std::unordered_map<std::string, std::string> intrinsics = {
7838
1.36k
        { "__has_nothrow_assign", "has_nothrow_assign" },
7839
1.36k
        { "__has_nothrow_constructor", "has_nothrow_constructor" },
7840
1.36k
        { "__has_nothrow_copy", "has_nothrow_copy" },
7841
1.36k
        { "__has_trivial_assign", "has_trivial_assign" },
7842
1.36k
        { "__has_trivial_constructor", "has_trivial_constructor" },
7843
1.36k
        { "__has_trivial_copy", "has_trivial_copy" },
7844
1.36k
        { "__has_trivial_destructor", "has_trivial_destructor" },
7845
1.36k
        { "__has_virtual_destructor", "has_virtual_destructor" },
7846
1.36k
        { "__is_abstract", "is_abstract" },
7847
1.36k
        { "__is_aggregate", "is_aggregate" },
7848
1.36k
        { "__is_assignable", "is_assignable" },
7849
1.36k
        { "__is_base_of", "is_base_of" },
7850
1.36k
        { "__is_class", "is_class" },
7851
1.36k
        { "__is_constructible", "is_constructible" },
7852
1.36k
        { "__is_convertible_to", "is_convertible_to" },
7853
1.36k
        { "__is_destructible", "is_destructible" },
7854
1.36k
        { "__is_empty", "is_empty" },
7855
1.36k
        { "__is_enum", "is_enum" },
7856
1.36k
        { "__is_final", "is_final" },
7857
1.36k
        { "__is_nothrow_assignable", "is_nothrow_assignable" },
7858
1.36k
        { "__is_nothrow_constructible", "is_nothrow_constructible" },
7859
1.36k
        { "__is_nothrow_destructible", "is_nothrow_destructible" },
7860
1.36k
        { "__is_pod", "is_pod" },
7861
1.36k
        { "__is_polymorphic", "is_polymorphic" },
7862
1.36k
        { "__is_trivially_assignable", "is_trivially_assignable" },
7863
1.36k
        { "__is_trivially_constructible", "is_trivially_constructible" },
7864
1.36k
        { "__is_union", "is_union" },
7865
1.36k
    };
7866
93.6k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
7867
92.3k
        if (!Token::Match(tok, "%name% ("))
7868
89.1k
            continue;
7869
3.20k
        auto p = intrinsics.find(tok->str());
7870
3.20k
        if (p == intrinsics.end())
7871
3.20k
            continue;
7872
0
        Token * end = tok->next()->link();
7873
0
        Token * prev = tok->previous();
7874
0
        tok->str(p->second);
7875
0
        prev->insertToken("::");
7876
0
        prev->insertToken("std");
7877
0
        tok->next()->str("<");
7878
0
        end->str(">");
7879
0
        end->insertToken("}");
7880
0
        end->insertToken("{");
7881
0
        Token::createMutualLinks(end->tokAt(1), end->tokAt(2));
7882
0
    }
7883
1.36k
}
7884
7885
//---------------------------------------------------------------------------
7886
// Helper functions for handling the tokens list
7887
//---------------------------------------------------------------------------
7888
7889
//---------------------------------------------------------------------------
7890
7891
bool Tokenizer::isScopeNoReturn(const Token *endScopeToken, bool *unknown) const
7892
0
{
7893
0
    std::string unknownFunc;
7894
0
    const bool ret = mSettings->library.isScopeNoReturn(endScopeToken,&unknownFunc);
7895
0
    if (!unknownFunc.empty() && mSettings->summaryReturn.find(unknownFunc) != mSettings->summaryReturn.end()) {
7896
0
        return false;
7897
0
    }
7898
0
    if (unknown)
7899
0
        *unknown = !unknownFunc.empty();
7900
0
    if (!unknownFunc.empty() && mSettings->checkLibrary) {
7901
0
        bool warn = true;
7902
0
        if (Token::simpleMatch(endScopeToken->tokAt(-2), ") ; }")) {
7903
0
            const Token * const ftok = endScopeToken->linkAt(-2)->previous();
7904
0
            if (ftok && (ftok->type() || ftok->function() || ftok->variable())) // constructor call
7905
0
                warn = false;
7906
0
        }
7907
7908
0
        if (warn) {
7909
0
            reportError(endScopeToken->previous(),
7910
0
                        Severity::information,
7911
0
                        "checkLibraryNoReturn",
7912
0
                        "--check-library: Function " + unknownFunc + "() should have <noreturn> configuration");
7913
0
        }
7914
0
    }
7915
0
    return ret;
7916
0
}
7917
7918
//---------------------------------------------------------------------------
7919
7920
void Tokenizer::syntaxError(const Token *tok, const std::string &code) const
7921
0
{
7922
0
    printDebugOutput(0);
7923
0
    throw InternalError(tok, code.empty() ? "syntax error" : "syntax error: " + code, InternalError::SYNTAX);
7924
0
}
7925
7926
void Tokenizer::unmatchedToken(const Token *tok) const
7927
0
{
7928
0
    printDebugOutput(0);
7929
0
    throw InternalError(tok,
7930
0
                        "Unmatched '" + tok->str() + "'. Configuration: '" + mConfiguration + "'.",
7931
0
                        InternalError::SYNTAX);
7932
0
}
7933
7934
void Tokenizer::syntaxErrorC(const Token *tok, const std::string &what) const
7935
0
{
7936
0
    printDebugOutput(0);
7937
0
    throw InternalError(tok, "Code '"+what+"' is invalid C code. Use --std or --language to configure the language.", InternalError::SYNTAX);
7938
0
}
7939
7940
void Tokenizer::unknownMacroError(const Token *tok1) const
7941
0
{
7942
0
    printDebugOutput(0);
7943
0
    throw InternalError(tok1, "There is an unknown macro here somewhere. Configuration is required. If " + tok1->str() + " is a macro then please configure it.", InternalError::UNKNOWN_MACRO);
7944
0
}
7945
7946
void Tokenizer::unhandled_macro_class_x_y(const Token *tok) const
7947
0
{
7948
0
    reportError(tok,
7949
0
                Severity::information,
7950
0
                "class_X_Y",
7951
0
                "The code '" +
7952
0
                tok->str() + " " +
7953
0
                tok->strAt(1) + " " +
7954
0
                tok->strAt(2) + " " +
7955
0
                tok->strAt(3) + "' is not handled. You can use -I or --include to add handling of this code.");
7956
0
}
7957
7958
void Tokenizer::macroWithSemicolonError(const Token *tok, const std::string &macroName) const
7959
0
{
7960
0
    reportError(tok,
7961
0
                Severity::information,
7962
0
                "macroWithSemicolon",
7963
0
                "Ensure that '" + macroName + "' is defined either using -I, --include or -D.");
7964
0
}
7965
7966
void Tokenizer::cppcheckError(const Token *tok) const
7967
0
{
7968
0
    printDebugOutput(0);
7969
0
    throw InternalError(tok, "Analysis failed. If the code is valid then please report this failure.", InternalError::INTERNAL);
7970
0
}
7971
7972
void Tokenizer::unhandledCharLiteral(const Token *tok, const std::string& msg) const
7973
0
{
7974
0
    std::string s = tok ? (" " + tok->str()) : "";
7975
0
    for (int i = 0; i < s.size(); ++i) {
7976
0
        if ((unsigned char)s[i] >= 0x80)
7977
0
            s.clear();
7978
0
    }
7979
7980
0
    reportError(tok,
7981
0
                Severity::portability,
7982
0
                "nonStandardCharLiteral",
7983
0
                "Non-standard character literal" + s + ". " + msg);
7984
0
}
7985
7986
/**
7987
 * Helper function to check whether number is equal to integer constant X
7988
 * or floating point pattern X.0
7989
 * @param s the string to check
7990
 * @param intConstant the integer constant to check against
7991
 * @param floatConstant the string with stringified float constant to check against
7992
 * @return true in case s is equal to X or X.0 and false otherwise.
7993
 */
7994
static bool isNumberOneOf(const std::string &s, MathLib::bigint intConstant, const char* floatConstant)
7995
0
{
7996
0
    if (MathLib::isInt(s)) {
7997
0
        if (MathLib::toLongNumber(s) == intConstant)
7998
0
            return true;
7999
0
    } else if (MathLib::isFloat(s)) {
8000
0
        if (MathLib::toString(MathLib::toDoubleNumber(s)) == floatConstant)
8001
0
            return true;
8002
0
    }
8003
0
    return false;
8004
0
}
8005
8006
// ------------------------------------------------------------------------
8007
// Helper function to check whether number is one (1 or 0.1E+1 or 1E+0) or not?
8008
// @param s the string to check
8009
// @return true in case s is one and false otherwise.
8010
// ------------------------------------------------------------------------
8011
bool Tokenizer::isOneNumber(const std::string &s)
8012
0
{
8013
0
    if (!MathLib::isPositive(s))
8014
0
        return false;
8015
0
    return isNumberOneOf(s, 1L, "1.0");
8016
0
}
8017
// ------------------------------------------------------------------------
8018
void Tokenizer::checkConfiguration() const
8019
1.36k
{
8020
1.36k
    if (!mSettings->checkConfiguration)
8021
1.36k
        return;
8022
0
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8023
0
        if (!Token::Match(tok, "%name% ("))
8024
0
            continue;
8025
0
        if (tok->isControlFlowKeyword())
8026
0
            continue;
8027
0
        for (const Token *tok2 = tok->tokAt(2); tok2 && tok2->str() != ")"; tok2 = tok2->next()) {
8028
0
            if (tok2->str() == ";") {
8029
0
                macroWithSemicolonError(tok, tok->str());
8030
0
                break;
8031
0
            }
8032
0
            if (Token::Match(tok2, "(|{"))
8033
0
                tok2 = tok2->link();
8034
0
        }
8035
0
    }
8036
0
}
8037
8038
void Tokenizer::validateC() const
8039
1.36k
{
8040
1.36k
    if (isCPP())
8041
1.36k
        return;
8042
0
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8043
        // That might trigger false positives, but it's much faster to have this truncated pattern
8044
0
        if (Token::Match(tok, "const_cast|dynamic_cast|reinterpret_cast|static_cast <"))
8045
0
            syntaxErrorC(tok, "C++ cast <...");
8046
        // Template function..
8047
0
        if (Token::Match(tok, "%name% < %name% > (")) {
8048
0
            const Token *tok2 = tok->tokAt(5);
8049
0
            while (tok2 && !Token::Match(tok2, "[()]"))
8050
0
                tok2 = tok2->next();
8051
0
            if (Token::simpleMatch(tok2, ") {"))
8052
0
                syntaxErrorC(tok, tok->str() + '<' + tok->strAt(2) + ">() {}");
8053
0
        }
8054
0
        if (tok->previous() && !Token::Match(tok->previous(), "[;{}]"))
8055
0
            continue;
8056
0
        if (Token::Match(tok, "using namespace %name% ;"))
8057
0
            syntaxErrorC(tok, "using namespace " + tok->strAt(2));
8058
0
        if (Token::Match(tok, "template < class|typename %name% [,>]"))
8059
0
            syntaxErrorC(tok, "template<...");
8060
0
        if (Token::Match(tok, "%name% :: %name%"))
8061
0
            syntaxErrorC(tok, tok->str() + tok->strAt(1) + tok->strAt(2));
8062
0
        if (Token::Match(tok, "class|namespace %name% [:{]"))
8063
0
            syntaxErrorC(tok, tok->str() + tok->strAt(1) + tok->strAt(2));
8064
0
    }
8065
0
}
8066
8067
void Tokenizer::validate() const
8068
9.53k
{
8069
9.53k
    std::stack<const Token *> linkTokens;
8070
9.53k
    const Token *lastTok = nullptr;
8071
616k
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8072
607k
        lastTok = tok;
8073
607k
        if (Token::Match(tok, "[{([]") || (tok->str() == "<" && tok->link())) {
8074
52.7k
            if (tok->link() == nullptr)
8075
0
                cppcheckError(tok);
8076
8077
52.7k
            linkTokens.push(tok);
8078
52.7k
        }
8079
8080
554k
        else if (Token::Match(tok, "[})]]") || (Token::Match(tok, ">|>>") && tok->link())) {
8081
52.7k
            if (tok->link() == nullptr)
8082
0
                cppcheckError(tok);
8083
8084
52.7k
            if (linkTokens.empty())
8085
0
                cppcheckError(tok);
8086
8087
52.7k
            if (tok->link() != linkTokens.top())
8088
0
                cppcheckError(tok);
8089
8090
52.7k
            if (tok != tok->link()->link())
8091
0
                cppcheckError(tok);
8092
8093
52.7k
            linkTokens.pop();
8094
52.7k
        }
8095
8096
501k
        else if (tok->link() != nullptr)
8097
0
            cppcheckError(tok);
8098
607k
    }
8099
8100
9.53k
    if (!linkTokens.empty())
8101
0
        cppcheckError(linkTokens.top());
8102
8103
    // Validate that the Tokenizer::list.back() is updated correctly during simplifications
8104
9.53k
    if (lastTok != list.back())
8105
0
        cppcheckError(lastTok);
8106
9.53k
}
8107
8108
static const Token *findUnmatchedTernaryOp(const Token * const begin, const Token * const end, int depth = 0)
8109
1.36k
{
8110
1.36k
    std::stack<const Token *> ternaryOp;
8111
6.81k
    for (const Token *tok = begin; tok != end && tok->str() != ";"; tok = tok->next()) {
8112
5.44k
        if (tok->str() == "?")
8113
0
            ternaryOp.push(tok);
8114
5.44k
        else if (!ternaryOp.empty() && tok->str() == ":")
8115
0
            ternaryOp.pop();
8116
5.44k
        else if (depth < 100 && Token::Match(tok,"(|[")) {
8117
0
            const Token *inner = findUnmatchedTernaryOp(tok->next(), tok->link(), depth+1);
8118
0
            if (inner)
8119
0
                return inner;
8120
0
            tok = tok->link();
8121
0
        }
8122
5.44k
    }
8123
1.36k
    return ternaryOp.empty() ? nullptr : ternaryOp.top();
8124
1.36k
}
8125
8126
static bool isCPPAttribute(const Token * tok)
8127
160k
{
8128
160k
    return Token::simpleMatch(tok, "[ [") && tok->link() && tok->link()->previous() == tok->linkAt(1);
8129
160k
}
8130
8131
static bool isAlignAttribute(const Token * tok)
8132
160k
{
8133
160k
    return Token::simpleMatch(tok, "alignas (") && tok->next()->link();
8134
160k
}
8135
8136
template<typename T>
8137
static T* skipCPPOrAlignAttribute(T * tok)
8138
0
{
8139
0
    if (isCPPAttribute(tok))
8140
0
        return tok->link();
8141
0
    if (isAlignAttribute(tok)) {
8142
0
        return tok->next()->link();
8143
0
    }
8144
0
    return tok;
8145
0
}
Unexecuted instantiation: tokenize.cpp:Token const* skipCPPOrAlignAttribute<Token const>(Token const*)
Unexecuted instantiation: tokenize.cpp:Token* skipCPPOrAlignAttribute<Token>(Token*)
8146
8147
static bool isNonMacro(const Token* tok)
8148
3.20k
{
8149
3.20k
    if (tok->isKeyword() || tok->isStandardType())
8150
1.46k
        return true;
8151
1.74k
    if (cAlternativeTokens.count(tok->str()) > 0)
8152
0
        return true;
8153
1.74k
    if (startsWith(tok->str(), "__")) // attribute/annotation
8154
0
        return true;
8155
1.74k
    if (Token::simpleMatch(tok, "alignas ("))
8156
0
        return true;
8157
1.74k
    return false;
8158
1.74k
}
8159
8160
void Tokenizer::reportUnknownMacros() const
8161
1.36k
{
8162
    // Report unknown macros used in expressions "%name% %num%"
8163
94.1k
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8164
92.7k
        if (Token::Match(tok, "%name% %num%")) {
8165
            // A keyword is not an unknown macro
8166
1.42k
            if (tok->isKeyword())
8167
1.42k
                continue;
8168
8169
0
            if (Token::Match(tok->previous(), "%op%|("))
8170
0
                unknownMacroError(tok);
8171
0
        }
8172
92.7k
    }
8173
8174
    // Report unknown macros before } "{ .. if (x) MACRO }"
8175
94.1k
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8176
92.7k
        if (Token::Match(tok, ")|; %name% } !!)")) {
8177
0
            if (tok->link() && !Token::simpleMatch(tok->link()->tokAt(-1), "if"))
8178
0
                continue;
8179
0
            const Token* prev = tok->linkAt(2);
8180
0
            while (Token::simpleMatch(prev, "{"))
8181
0
                prev = prev->previous();
8182
0
            if (Token::Match(prev, ";|)"))
8183
0
                unknownMacroError(tok->next());
8184
0
        }
8185
92.7k
    }
8186
8187
    // Report unknown macros that contain several statements "MACRO(a;b;c)"
8188
94.1k
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8189
92.7k
        if (!Token::Match(tok, "%name% ("))
8190
89.5k
            continue;
8191
3.20k
        if (!tok->isUpperCaseName())
8192
3.20k
            continue;
8193
0
        const Token *endTok = tok->linkAt(1);
8194
0
        for (const Token *inner = tok->tokAt(2); inner != endTok; inner = inner->next()) {
8195
0
            if (Token::Match(inner, "[[({]"))
8196
0
                inner = inner->link();
8197
0
            else if (inner->str() == ";")
8198
0
                unknownMacroError(tok);
8199
0
        }
8200
0
    }
8201
8202
    // Report unknown macros that contain struct initialization "MACRO(a, .b=3)"
8203
94.1k
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8204
92.7k
        if (!Token::Match(tok, "%name% ("))
8205
89.5k
            continue;
8206
3.20k
        const Token *endTok = tok->linkAt(1);
8207
11.5k
        for (const Token *inner = tok->tokAt(2); inner != endTok; inner = inner->next()) {
8208
8.31k
            if (Token::Match(inner, "[[({]"))
8209
444
                inner = inner->link();
8210
7.87k
            else if (Token::Match(inner->previous(), "[,(] . %name% =|{"))
8211
0
                unknownMacroError(tok);
8212
8.31k
        }
8213
3.20k
    }
8214
8215
    // Report unknown macros in non-executable scopes..
8216
1.36k
    std::set<std::string> possible;
8217
57.7k
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8218
        // Skip executable scopes..
8219
56.3k
        if (tok->str() == "{") {
8220
1.74k
            const Token *prev = tok->previous();
8221
1.74k
            while (prev && prev->isName())
8222
0
                prev = prev->previous();
8223
1.74k
            if (prev && prev->str() == ")")
8224
1.74k
                tok = tok->link();
8225
0
            else
8226
0
                possible.clear();
8227
54.6k
        } else if (tok->str() == "}")
8228
0
            possible.clear();
8229
8230
56.3k
        if (Token::Match(tok, "%name% (") && tok->isUpperCaseName() && Token::simpleMatch(tok->linkAt(1), ") (") && Token::simpleMatch(tok->linkAt(1)->linkAt(1), ") {")) {
8231
            // A keyword is not an unknown macro
8232
0
            if (tok->isKeyword())
8233
0
                continue;
8234
8235
0
            const Token *bodyStart = tok->linkAt(1)->linkAt(1)->tokAt(2);
8236
0
            const Token *bodyEnd = tok->link();
8237
0
            for (const Token *tok2 = bodyStart; tok2 && tok2 != bodyEnd; tok2 = tok2->next()) {
8238
0
                if (Token::Match(tok2, "if|switch|for|while|return"))
8239
0
                    unknownMacroError(tok);
8240
0
            }
8241
56.3k
        } else if (Token::Match(tok, "%name% (") && tok->isUpperCaseName() && Token::Match(tok->linkAt(1), ") %name% (") && Token::Match(tok->linkAt(1)->linkAt(2), ") [;{]")) {
8242
0
            if (!(tok->linkAt(1)->next() && tok->linkAt(1)->next()->isKeyword())) { // e.g. noexcept(true)
8243
0
                if (possible.count(tok->str()) == 0)
8244
0
                    possible.insert(tok->str());
8245
0
                else
8246
0
                    unknownMacroError(tok);
8247
0
            }
8248
56.3k
        } else if (isCPP() && Token::Match(tok, "public|private|protected %name% :")) {
8249
0
            unknownMacroError(tok->next());
8250
0
        }
8251
56.3k
    }
8252
8253
    // String concatenation with unknown macros
8254
94.1k
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8255
92.7k
        if (Token::Match(tok, "%str% %name% (") && Token::Match(tok->linkAt(2), ") %str%")) {
8256
0
            if (tok->next()->isKeyword())
8257
0
                continue;
8258
0
            unknownMacroError(tok->next());
8259
0
        }
8260
92.7k
        if (Token::Match(tok, "[(,] %name% (") && Token::Match(tok->linkAt(2), ") %name% %name%|,|)")) {
8261
0
            if (tok->next()->isKeyword() || tok->linkAt(2)->next()->isKeyword())
8262
0
                continue;
8263
0
            if (cAlternativeTokens.count(tok->linkAt(2)->next()->str()) > 0)
8264
0
                continue;
8265
0
            if (startsWith(tok->next()->str(), "__")) // attribute/annotation
8266
0
                continue;
8267
0
            unknownMacroError(tok->next());
8268
0
        }
8269
92.7k
    }
8270
8271
    // Report unknown macros without commas or operators inbetween statements: MACRO1() MACRO2()
8272
94.1k
    for (const Token* tok = tokens(); tok; tok = tok->next()) {
8273
92.7k
        if (!Token::Match(tok, "%name% ("))
8274
89.5k
            continue;
8275
3.20k
        if (isNonMacro(tok) && !tok->isStandardType())
8276
1.46k
            continue;
8277
8278
1.74k
        const Token* endTok = tok->linkAt(1);
8279
1.74k
        if (!Token::Match(endTok, ") %name% (|."))
8280
1.74k
            continue;
8281
8282
0
        const Token* tok2 = endTok->next();
8283
0
        if (isNonMacro(tok2))
8284
0
            continue;
8285
8286
0
        if (tok2->next()->str() == "(") {
8287
0
            if (Token::Match(tok->previous(), "%name%|::|>"))
8288
0
                continue;
8289
0
        }
8290
8291
0
        unknownMacroError(tok->isStandardType() ? tok2 : tok);
8292
0
    }
8293
1.36k
}
8294
8295
void Tokenizer::findGarbageCode() const
8296
1.36k
{
8297
1.36k
    const bool isCPP11 = isCPP() && mSettings->standards.cpp >= Standards::CPP11;
8298
8299
1.36k
    static const std::unordered_set<std::string> nonConsecutiveKeywords{ "break",
8300
1.36k
                                                                         "continue",
8301
1.36k
                                                                         "for",
8302
1.36k
                                                                         "goto",
8303
1.36k
                                                                         "if",
8304
1.36k
                                                                         "return",
8305
1.36k
                                                                         "switch",
8306
1.36k
                                                                         "throw",
8307
1.36k
                                                                         "typedef",
8308
1.36k
                                                                         "while" };
8309
8310
81.8k
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8311
        // initialization: = {
8312
80.4k
        if (Token::simpleMatch(tok, "= {") && Token::simpleMatch(tok->linkAt(1), "} ("))
8313
0
            syntaxError(tok->linkAt(1));
8314
8315
        // Inside [] there can't be ; or various keywords
8316
80.4k
        else if (tok->str() == "[") {
8317
0
            for (const Token* inner = tok->next(); inner != tok->link(); inner = inner->next()) {
8318
0
                if (Token::Match(inner, "(|[|{"))
8319
0
                    inner = inner->link();
8320
0
                else if (Token::Match(inner, ";|goto|return|typedef"))
8321
0
                    syntaxError(inner);
8322
0
            }
8323
0
        }
8324
8325
        // array assignment
8326
80.4k
        else if (Token::Match(tok, "%assign% [") && Token::simpleMatch(tok->linkAt(1), "] ;"))
8327
0
            syntaxError(tok, tok->str() + "[...];");
8328
8329
        // UNKNOWN_MACRO(return)
8330
80.4k
        if (tok->isKeyword() && Token::Match(tok, "throw|return )") && Token::Match(tok->linkAt(1)->previous(), "%name% ("))
8331
0
            unknownMacroError(tok->linkAt(1)->previous());
8332
8333
        // UNKNOWN_MACRO(return)
8334
80.4k
        else if (Token::Match(tok, "%name% throw|return") && std::isupper(tok->str()[0]))
8335
0
            unknownMacroError(tok);
8336
8337
        // Assign/increment/decrement literal
8338
80.4k
        else if (Token::Match(tok, "!!) %num%|%str%|%char% %assign%|++|--")) {
8339
0
            if (!isCPP() || mSettings->standards.cpp < Standards::CPP20 || !Token::Match(tok->previous(), "%name% : %num% ="))
8340
0
                syntaxError(tok, tok->next()->str() + " " + tok->strAt(2));
8341
0
        }
8342
80.4k
        else if (Token::simpleMatch(tok, ") return") && !Token::Match(tok->link()->previous(), "if|while|for (")) {
8343
0
            if (tok->link()->previous() && tok->link()->previous()->isUpperCaseName())
8344
0
                unknownMacroError(tok->link()->previous());
8345
0
            else
8346
0
                syntaxError(tok);
8347
0
        }
8348
8349
80.4k
        if (tok->isControlFlowKeyword() && Token::Match(tok, "if|while|for|switch")) { // if|while|for|switch (EXPR) { ... }
8350
1.38k
            if (tok->previous() && !Token::Match(tok->previous(), "%name%|:|;|{|}|)")) {
8351
0
                if (Token::Match(tok->previous(), "[,(]")) {
8352
0
                    const Token *prev = tok->previous();
8353
0
                    while (prev && prev->str() != "(") {
8354
0
                        if (prev->str() == ")")
8355
0
                            prev = prev->link();
8356
0
                        prev = prev->previous();
8357
0
                    }
8358
0
                    if (prev && Token::Match(prev->previous(), "%name% ("))
8359
0
                        unknownMacroError(prev->previous());
8360
0
                }
8361
0
                if (!Token::simpleMatch(tok->tokAt(-2), "operator \"\" if"))
8362
0
                    syntaxError(tok);
8363
0
            }
8364
1.38k
            if (!Token::Match(tok->next(), "( !!)"))
8365
0
                syntaxError(tok);
8366
1.38k
            if (tok->str() != "for") {
8367
1.38k
                if (isGarbageExpr(tok->next(), tok->linkAt(1), mSettings->standards.cpp>=Standards::cppstd_t::CPP17))
8368
0
                    syntaxError(tok);
8369
1.38k
            }
8370
1.38k
        }
8371
8372
        // keyword keyword
8373
80.4k
        if (tok->isKeyword() && nonConsecutiveKeywords.count(tok->str()) != 0) {
8374
3.30k
            if (Token::Match(tok, "%name% %name%") && nonConsecutiveKeywords.count(tok->next()->str()) == 1)
8375
0
                syntaxError(tok);
8376
3.30k
            const Token* prev = tok;
8377
6.60k
            while (prev && prev->isName())
8378
3.30k
                prev = prev->previous();
8379
3.30k
            if (Token::Match(prev, "%op%|%num%|%str%|%char%")) {
8380
0
                if (!Token::simpleMatch(tok->tokAt(-2), "operator \"\" if") &&
8381
0
                    !Token::simpleMatch(tok->tokAt(-2), "extern \"C\"") &&
8382
0
                    !Token::simpleMatch(prev, "> typedef"))
8383
0
                    syntaxError(tok, prev == tok->previous() ? (prev->str() + " " + tok->str()) : (prev->str() + " .. " + tok->str()));
8384
0
            }
8385
3.30k
        }
8386
80.4k
    }
8387
8388
    // invalid struct declaration
8389
81.8k
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8390
80.4k
        if (Token::Match(tok, "struct|class|enum %name%| {") && (!tok->previous() || Token::Match(tok->previous(), "[;{}]"))) {
8391
0
            const Token *tok2 = tok->linkAt(tok->next()->isName() ? 2 : 1);
8392
0
            if (Token::Match(tok2, "} %op%")) {
8393
0
                tok2 = tok2->next();
8394
0
                if (!Token::Match(tok2, "*|&|&&"))
8395
0
                    syntaxError(tok2, "Unexpected token '" + tok2->str() + "'");
8396
0
                while (Token::Match(tok2, "*|&|&&"))
8397
0
                    tok2 = tok2->next();
8398
0
                if (!Token::Match(tok2, "%name%"))
8399
0
                    syntaxError(tok2, "Unexpected token '" + (tok2 ? tok2->str() : "") + "'");
8400
0
            }
8401
0
        }
8402
80.4k
        if (Token::Match(tok, "enum : %num%| {"))
8403
0
            syntaxError(tok->tokAt(2), "Unexpected token '" + tok->strAt(2) + "'");
8404
80.4k
    }
8405
8406
    // Keywords in global scope
8407
1.36k
    static const std::unordered_set<std::string> nonGlobalKeywords{"break",
8408
1.36k
                                                                   "continue",
8409
1.36k
                                                                   "for",
8410
1.36k
                                                                   "goto",
8411
1.36k
                                                                   "if",
8412
1.36k
                                                                   "return",
8413
1.36k
                                                                   "switch",
8414
1.36k
                                                                   "while",
8415
1.36k
                                                                   "try",
8416
1.36k
                                                                   "catch"};
8417
45.4k
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8418
44.1k
        if (tok->str() == "{")
8419
1.74k
            tok = tok->link();
8420
42.3k
        else if (tok->isKeyword() && nonGlobalKeywords.count(tok->str()) && !Token::Match(tok->tokAt(-2), "operator %str%"))
8421
0
            syntaxError(tok, "keyword '" + tok->str() + "' is not allowed in global scope");
8422
44.1k
    }
8423
8424
    // case keyword must be inside switch
8425
67.6k
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8426
66.3k
        if (Token::simpleMatch(tok, "switch (")) {
8427
0
            if (Token::simpleMatch(tok->linkAt(1), ") {")) {
8428
0
                tok = tok->linkAt(1)->linkAt(1);
8429
0
                continue;
8430
0
            }
8431
0
            const Token *switchToken = tok;
8432
0
            tok = tok->linkAt(1);
8433
0
            if (!tok)
8434
0
                syntaxError(switchToken);
8435
            // Look for the end of the switch statement, i.e. the first semi-colon or '}'
8436
0
            for (; tok; tok = tok->next()) {
8437
0
                if (tok->str() == "{") {
8438
0
                    tok = tok->link();
8439
0
                }
8440
0
                if (Token::Match(tok, ";|}")) {
8441
                    // We're at the end of the switch block
8442
0
                    if (tok->str() == "}" && tok->strAt(-1) == ":") // Invalid case
8443
0
                        syntaxError(switchToken);
8444
0
                    break;
8445
0
                }
8446
0
            }
8447
0
            if (!tok)
8448
0
                break;
8449
66.3k
        } else if (tok->str() == "(") {
8450
3.50k
            tok = tok->link();
8451
62.8k
        } else if (tok->str() == "case") {
8452
0
            syntaxError(tok);
8453
0
        }
8454
66.3k
    }
8455
8456
81.8k
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8457
80.4k
        if (!Token::simpleMatch(tok, "for (")) // find for loops
8458
80.4k
            continue;
8459
        // count number of semicolons
8460
0
        int semicolons = 0;
8461
0
        const Token* const startTok = tok;
8462
0
        tok = tok->next()->link()->previous(); // find ")" of the for-loop
8463
        // walk backwards until we find the beginning (startTok) of the for() again
8464
0
        for (; tok != startTok; tok = tok->previous()) {
8465
0
            if (tok->str() == ";") { // do the counting
8466
0
                semicolons++;
8467
0
            } else if (tok->str() == ")") { // skip pairs of ( )
8468
0
                tok = tok->link();
8469
0
            }
8470
0
        }
8471
        // if we have an invalid number of semicolons inside for( ), assume syntax error
8472
0
        if (semicolons > 2)
8473
0
            syntaxError(tok);
8474
0
        if (semicolons == 1 && !(isCPP() && mSettings->standards.cpp >= Standards::CPP20))
8475
0
            syntaxError(tok);
8476
0
    }
8477
8478
    // Operators without operands..
8479
1.36k
    const Token *templateEndToken = nullptr;
8480
81.8k
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8481
80.4k
        if (!templateEndToken) {
8482
80.3k
            if (tok->str() == "<" && isCPP())
8483
522
                templateEndToken = tok->findClosingBracket();
8484
80.3k
        } else {
8485
156
            if (templateEndToken == tok)
8486
45
                templateEndToken = nullptr;
8487
156
            if (Token::Match(tok, "> %cop%"))
8488
2
                continue;
8489
156
        }
8490
        // skip C++ attributes [[...]]
8491
80.4k
        if (isCPP11 && (isCPPAttribute(tok) || isAlignAttribute(tok))) {
8492
0
            tok = skipCPPOrAlignAttribute(tok);
8493
0
            continue;
8494
0
        }
8495
80.4k
        {
8496
80.4k
            bool match1 = Token::Match(tok, "%or%|%oror%|==|!=|+|-|/|!|>=|<=|~|^|++|--|::|sizeof");
8497
80.4k
            bool match2 = Token::Match(tok->next(), "{|if|else|while|do|for|return|switch|break");
8498
80.4k
            if (isCPP()) {
8499
80.4k
                match1 = match1 || Token::Match(tok, "::|throw|decltype|typeof");
8500
80.4k
                match2 = match2 || Token::Match(tok->next(), "try|catch|namespace");
8501
80.4k
            }
8502
80.4k
            if (match1 && match2)
8503
0
                syntaxError(tok);
8504
80.4k
        }
8505
80.4k
        if (Token::Match(tok, "%or%|%oror%|~|^|!|%comp%|+|-|/|%")) {
8506
5.75k
            std::string code;
8507
5.75k
            if (Token::Match(tok->next(), ")|]|}"))
8508
0
                code = tok->str() + tok->next()->str();
8509
5.75k
            if (Token::simpleMatch(tok->next(), "( )"))
8510
0
                code = tok->str() + "()";
8511
5.75k
            if (!code.empty()) {
8512
0
                if (isC() || (tok->str() != ">" && !Token::simpleMatch(tok->previous(), "operator")))
8513
0
                    syntaxError(tok, code);
8514
0
            }
8515
5.75k
        }
8516
80.4k
        if (Token::Match(tok, "%num%|%bool%|%char%|%str% %num%|%bool%|%char%|%str%") && !Token::Match(tok, "%str% %str%"))
8517
0
            syntaxError(tok);
8518
80.4k
        if (Token::Match(tok, "%assign% typename|class %assign%"))
8519
0
            syntaxError(tok);
8520
80.4k
        if (Token::Match(tok, "%cop%|=|,|[ %or%|%oror%|/|%"))
8521
0
            syntaxError(tok);
8522
80.4k
        if (Token::Match(tok, ";|(|[ %comp%"))
8523
0
            syntaxError(tok);
8524
80.4k
        if (Token::Match(tok, "%cop%|= ]") && !(isCPP() && Token::Match(tok->previous(), "%type%|[|,|%num% &|=|> ]")))
8525
0
            syntaxError(tok);
8526
80.4k
        if (Token::Match(tok, "[+-] [;,)]}]") && !(isCPP() && Token::Match(tok->previous(), "operator [+-] ;")))
8527
0
            syntaxError(tok);
8528
80.4k
        if (Token::simpleMatch(tok, ",") &&
8529
80.4k
            !Token::Match(tok->tokAt(-2), "[ = , &|%name%")) {
8530
0
            if (Token::Match(tok->previous(), "(|[|{|<|%assign%|%or%|%oror%|==|!=|+|-|/|!|>=|<=|~|^|::|sizeof"))
8531
0
                syntaxError(tok);
8532
0
            if (isCPP() && Token::Match(tok->previous(), "throw|decltype|typeof"))
8533
0
                syntaxError(tok);
8534
0
            if (Token::Match(tok->next(), ")|]|>|%assign%|%or%|%oror%|==|!=|/|>=|<=|&&"))
8535
0
                syntaxError(tok);
8536
0
        }
8537
80.4k
        if (Token::simpleMatch(tok, ".") &&
8538
80.4k
            !Token::simpleMatch(tok->previous(), ".") &&
8539
80.4k
            !Token::simpleMatch(tok->next(), ".") &&
8540
80.4k
            !Token::Match(tok->previous(), "{|, . %name% =|.|[|{") &&
8541
80.4k
            !Token::Match(tok->previous(), ", . %name%")) {
8542
0
            if (!Token::Match(tok->previous(), "%name%|)|]|>|}"))
8543
0
                syntaxError(tok, tok->strAt(-1) + " " + tok->str() + " " + tok->strAt(1));
8544
0
            if (!Token::Match(tok->next(), "%name%|*|~"))
8545
0
                syntaxError(tok, tok->strAt(-1) + " " + tok->str() + " " + tok->strAt(1));
8546
0
        }
8547
80.4k
        if (Token::Match(tok, "[!|+-/%^~] )|]"))
8548
0
            syntaxError(tok);
8549
80.4k
        if (Token::Match(tok, "==|!=|<=|>= %comp%") && tok->strAt(-1) != "operator")
8550
0
            syntaxError(tok, tok->str() + " " + tok->strAt(1));
8551
80.4k
    }
8552
8553
    // ternary operator without :
8554
1.36k
    if (const Token *ternaryOp = findUnmatchedTernaryOp(tokens(), nullptr))
8555
0
        syntaxError(ternaryOp);
8556
8557
    // Code must not start with an arithmetical operand
8558
1.36k
    if (Token::Match(list.front(), "%cop%"))
8559
0
        syntaxError(list.front());
8560
8561
    // Code must end with } ; ) NAME
8562
1.36k
    if (!Token::Match(list.back(), "%name%|;|}|)"))
8563
0
        syntaxError(list.back());
8564
1.36k
    if (list.back()->str() == ")" && !Token::Match(list.back()->link()->previous(), "%name%|> ("))
8565
0
        syntaxError(list.back());
8566
1.36k
    for (const Token *end = list.back(); end && end->isName(); end = end->previous()) {
8567
0
        if (Token::Match(end, "void|char|short|int|long|float|double|const|volatile|static|inline|struct|class|enum|union|template|sizeof|case|break|continue|typedef"))
8568
0
            syntaxError(list.back());
8569
0
    }
8570
1.36k
    if ((list.back()->str()==")" || list.back()->str()=="}") && list.back()->previous() && list.back()->previous()->isControlFlowKeyword())
8571
0
        syntaxError(list.back()->previous());
8572
8573
    // Garbage templates..
8574
1.36k
    if (isCPP()) {
8575
81.8k
        for (const Token *tok = tokens(); tok; tok = tok->next()) {
8576
80.4k
            if (!Token::simpleMatch(tok, "template <"))
8577
80.4k
                continue;
8578
0
            if (tok->previous() && !Token::Match(tok->previous(), ":|;|{|}|)|>|\"C++\"")) {
8579
0
                if (tok->previous()->isUpperCaseName())
8580
0
                    unknownMacroError(tok->previous());
8581
0
                else
8582
0
                    syntaxError(tok);
8583
0
            }
8584
0
            const Token * const tok1 = tok;
8585
0
            tok = tok->next()->findClosingBracket();
8586
0
            if (!tok)
8587
0
                syntaxError(tok1);
8588
0
            if (!Token::Match(tok, ">|>> ::|...| %name%") &&
8589
0
                !Token::Match(tok, ">|>> [ [ %name%") &&
8590
0
                !Token::Match(tok, "> >|*"))
8591
0
                syntaxError(tok->next() ? tok->next() : tok1);
8592
0
        }
8593
1.36k
    }
8594
8595
    // Objective C/C++
8596
81.8k
    for (const Token *tok = tokens(); tok; tok = tok->next()) {
8597
80.4k
        if (Token::Match(tok, "[;{}] [ %name% %name% ] ;"))
8598
0
            syntaxError(tok->next());
8599
80.4k
    }
8600
1.36k
}
8601
8602
8603
bool Tokenizer::isGarbageExpr(const Token *start, const Token *end, bool allowSemicolon)
8604
1.38k
{
8605
12.4k
    for (const Token *tok = start; tok != end; tok = tok->next()) {
8606
11.1k
        if (tok->isControlFlowKeyword())
8607
0
            return true;
8608
11.1k
        if (!allowSemicolon && tok->str() == ";")
8609
0
            return true;
8610
11.1k
        if (tok->str() == "{")
8611
0
            tok = tok->link();
8612
11.1k
    }
8613
1.38k
    return false;
8614
1.38k
}
8615
8616
std::string Tokenizer::simplifyString(const std::string &source)
8617
0
{
8618
0
    std::string str = source;
8619
8620
0
    for (std::string::size_type i = 0; i + 1U < str.size(); ++i) {
8621
0
        if (str[i] != '\\')
8622
0
            continue;
8623
8624
0
        int c = 'a';   // char
8625
0
        int sz = 0;    // size of stringdata
8626
0
        if (str[i+1] == 'x') {
8627
0
            sz = 2;
8628
0
            while (sz < 4 && std::isxdigit((unsigned char)str[i+sz]))
8629
0
                sz++;
8630
0
            if (sz > 2) {
8631
0
                std::istringstream istr(str.substr(i+2, sz-2));
8632
0
                istr >> std::hex >> c;
8633
0
            }
8634
0
        } else if (MathLib::isOctalDigit(str[i+1])) {
8635
0
            sz = 2;
8636
0
            while (sz < 4 && MathLib::isOctalDigit(str[i+sz]))
8637
0
                sz++;
8638
0
            std::istringstream istr(str.substr(i+1, sz-1));
8639
0
            istr >> std::oct >> c;
8640
0
            str = str.replace(i, sz, std::string(1U, (char)c));
8641
0
            continue;
8642
0
        }
8643
8644
0
        if (sz <= 2)
8645
0
            i++;
8646
0
        else if (i+sz < str.size())
8647
0
            str.replace(i, sz, std::string(1U, (char)c));
8648
0
        else
8649
0
            str.replace(i, str.size() - i - 1U, "a");
8650
0
    }
8651
8652
0
    return str;
8653
0
}
8654
8655
void Tokenizer::simplifyFunctionTryCatch()
8656
1.36k
{
8657
1.36k
    if (!isCPP())
8658
0
        return;
8659
8660
81.8k
    for (Token * tok = list.front(); tok; tok = tok->next()) {
8661
80.4k
        if (!Token::Match(tok, "try {|:"))
8662
80.4k
            continue;
8663
0
        if (!isFunctionHead(tok->previous(), "try"))
8664
0
            continue;
8665
8666
0
        Token* tryStartToken = skipInitializerList(tok->next());
8667
8668
0
        if (!Token::simpleMatch(tryStartToken, "{"))
8669
0
            syntaxError(tryStartToken, "Invalid function-try-catch block code. Did not find '{' for try body.");
8670
8671
        // find the end of the last catch block
8672
0
        Token * const tryEndToken = tryStartToken->link();
8673
0
        Token * endToken = tryEndToken;
8674
0
        while (Token::simpleMatch(endToken, "} catch (")) {
8675
0
            endToken = endToken->linkAt(2)->next();
8676
0
            if (!endToken)
8677
0
                break;
8678
0
            if (endToken->str() != "{") {
8679
0
                endToken = nullptr;
8680
0
                break;
8681
0
            }
8682
0
            endToken = endToken->link();
8683
0
        }
8684
0
        if (!endToken || endToken == tryEndToken)
8685
0
            continue;
8686
8687
0
        tok->previous()->insertToken("{");
8688
0
        endToken->insertToken("}");
8689
0
        Token::createMutualLinks(tok->previous(), endToken->next());
8690
0
    }
8691
1.36k
}
8692
8693
8694
void Tokenizer::simplifyStructDecl()
8695
1.36k
{
8696
1.36k
    const bool cpp = isCPP();
8697
8698
    // A counter that is used when giving unique names for anonymous structs.
8699
1.36k
    int count = 0;
8700
8701
    // Add names for anonymous structs
8702
94.1k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
8703
92.7k
        if (!tok->isName())
8704
56.9k
            continue;
8705
        // check for anonymous struct/union
8706
35.7k
        if (Token::Match(tok, "struct|union {")) {
8707
0
            if (Token::Match(tok->next()->link(), "} const| *|&| const| %type% ,|;|[|(|{|=")) {
8708
0
                tok->insertToken("Anonymous" + std::to_string(count++));
8709
0
            }
8710
0
        }
8711
        // check for derived anonymous class/struct
8712
35.7k
        else if (cpp && Token::Match(tok, "class|struct :")) {
8713
0
            const Token *tok1 = Token::findsimplematch(tok, "{");
8714
0
            if (tok1 && Token::Match(tok1->link(), "} const| *|&| const| %type% ,|;|[|(|{")) {
8715
0
                tok->insertToken("Anonymous" + std::to_string(count++));
8716
0
            }
8717
0
        }
8718
        // check for anonymous enum
8719
35.7k
        else if ((Token::simpleMatch(tok, "enum {") &&
8720
35.7k
                  !Token::Match(tok->tokAt(-3), "using %name% =") &&
8721
35.7k
                  Token::Match(tok->next()->link(), "} (| %type%| )| ,|;|[|(|{")) ||
8722
35.7k
                 (Token::Match(tok, "enum : %type% {") && Token::Match(tok->linkAt(3), "} (| %type%| )| ,|;|[|(|{"))) {
8723
0
            Token *start = tok->strAt(1) == ":" ? tok->linkAt(3) : tok->linkAt(1);
8724
0
            if (start && Token::Match(start->next(), "( %type% )")) {
8725
0
                start->next()->link()->deleteThis();
8726
0
                start->next()->deleteThis();
8727
0
            }
8728
0
            tok->insertToken("Anonymous" + std::to_string(count++));
8729
0
        }
8730
35.7k
    }
8731
8732
    // "{" token for current scope
8733
1.36k
    std::stack<const Token*> scopeStart;
8734
1.36k
    const Token* functionEnd = nullptr;
8735
8736
94.1k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
8737
8738
        // check for start of scope and determine if it is in a function
8739
92.7k
        if (tok->str() == "{") {
8740
3.58k
            scopeStart.push(tok);
8741
3.58k
            if (!functionEnd && Token::Match(tok->previous(), "const|)"))
8742
1.74k
                functionEnd = tok->link();
8743
3.58k
        }
8744
8745
        // end of scope
8746
89.1k
        else if (tok->str() == "}") {
8747
3.58k
            if (!scopeStart.empty())
8748
3.58k
                scopeStart.pop();
8749
3.58k
            if (tok == functionEnd)
8750
1.74k
                functionEnd = nullptr;
8751
3.58k
        }
8752
8753
        // check for named struct/union
8754
85.5k
        else if (Token::Match(tok, "class|struct|union|enum %type% :|{")) {
8755
0
            Token *start = tok;
8756
0
            while (Token::Match(start->previous(), "%type%"))
8757
0
                start = start->previous();
8758
0
            const Token * const type = tok->next();
8759
0
            Token *next = tok->tokAt(2);
8760
8761
0
            while (next && next->str() != "{")
8762
0
                next = next->next();
8763
0
            if (!next)
8764
0
                continue;
8765
0
            Token* after = next->link();
8766
0
            if (!after)
8767
0
                break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
8768
8769
            // check for named type
8770
0
            if (Token::Match(after->next(), "const|static|volatile| *|&| const| (| %type% )| ,|;|[|=|(|{")) {
8771
0
                after->insertToken(";");
8772
0
                after = after->next();
8773
0
                while (!Token::Match(start, "struct|class|union|enum")) {
8774
0
                    after->insertToken(start->str());
8775
0
                    after = after->next();
8776
0
                    start->deleteThis();
8777
0
                }
8778
0
                tok = start;
8779
0
                if (!after)
8780
0
                    break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
8781
0
                after->insertToken(type->str());
8782
0
                if (start->str() != "class") {
8783
0
                    after->insertToken(start->str());
8784
0
                    after = after->next();
8785
0
                }
8786
8787
0
                after = after->tokAt(2);
8788
8789
0
                if (Token::Match(after, "( %type% )")) {
8790
0
                    after->link()->deleteThis();
8791
0
                    after->deleteThis();
8792
0
                }
8793
8794
                // check for initialization
8795
0
                if (Token::Match(after, "%any% (|{")) {
8796
0
                    after->insertToken("=");
8797
0
                    after = after->next();
8798
0
                    const bool isEnum = start->str() == "enum";
8799
0
                    if (!isEnum && cpp) {
8800
0
                        after->insertToken(type->str());
8801
0
                        after = after->next();
8802
0
                    }
8803
8804
0
                    if (isEnum) {
8805
0
                        if (Token::Match(after->next(), "{ !!}")) {
8806
0
                            after->next()->str("(");
8807
0
                            after->linkAt(1)->str(")");
8808
0
                        }
8809
0
                    }
8810
0
                }
8811
0
            }
8812
0
        }
8813
8814
        // check for anonymous struct/union
8815
85.5k
        else {
8816
            // unnamed anonymous struct/union so possibly remove it
8817
85.5k
            bool done = false;
8818
85.5k
            while (!done && Token::Match(tok, "struct|union {") && Token::simpleMatch(tok->linkAt(1), "} ;")) {
8819
0
                done = true;
8820
8821
                // is this a class/struct/union scope?
8822
0
                bool isClassStructUnionScope = false;
8823
0
                if (!scopeStart.empty()) {
8824
0
                    for (const Token* tok2 = scopeStart.top()->previous(); tok2 && !Token::Match(tok2, "[;{}]"); tok2 = tok2->previous()) {
8825
0
                        if (Token::Match(tok2, "class|struct|union")) {
8826
0
                            isClassStructUnionScope = true;
8827
0
                            break;
8828
0
                        }
8829
0
                    }
8830
0
                }
8831
8832
                // remove unnamed anonymous struct/union
8833
                // * not in class/struct/union scopes
8834
0
                if (Token::simpleMatch(tok->linkAt(1), "} ;") && !isClassStructUnionScope && tok->str() != "union") {
8835
0
                    tok->linkAt(1)->previous()->deleteNext(2);
8836
0
                    tok->deleteNext();
8837
0
                    tok->deleteThis();
8838
0
                    done = false;
8839
0
                }
8840
0
            }
8841
85.5k
        }
8842
92.7k
    }
8843
1.36k
}
8844
8845
void Tokenizer::simplifyCallingConvention()
8846
1.36k
{
8847
1.36k
    const bool windows = mSettings->platform.isWindows();
8848
8849
80.4k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
8850
79.1k
        while (Token::Match(tok, "__cdecl|__stdcall|__fastcall|__thiscall|__clrcall|__syscall|__pascal|__fortran|__far|__near") || (windows && Token::Match(tok, "WINAPI|APIENTRY|CALLBACK"))) {
8851
0
            tok->deleteThis();
8852
0
        }
8853
79.1k
    }
8854
1.36k
}
8855
8856
159k
static bool isAttribute(const Token* tok, bool gcc) {
8857
159k
    return gcc ? Token::Match(tok, "__attribute__|__attribute (") : Token::Match(tok, "__declspec|_declspec (");
8858
159k
}
8859
8860
0
static Token* getTokenAfterAttributes(Token* tok, bool gccattr) {
8861
0
    Token* after = tok;
8862
0
    while (isAttribute(after, gccattr))
8863
0
        after = after->linkAt(1)->next();
8864
0
    return after;
8865
0
}
8866
8867
0
Token* Tokenizer::getAttributeFuncTok(Token* tok, bool gccattr) const {
8868
0
    if (!Token::Match(tok, "%name% ("))
8869
0
        return nullptr;
8870
0
    Token* const after = getTokenAfterAttributes(tok, gccattr);
8871
0
    if (!after)
8872
0
        syntaxError(tok);
8873
8874
0
    if (Token::Match(after, "%name%|*|&|(")) {
8875
0
        Token *ftok = after;
8876
0
        while (Token::Match(ftok, "%name%|::|<|*|& !!(")) {
8877
0
            if (ftok->str() == "<") {
8878
0
                ftok = ftok->findClosingBracket();
8879
0
                if (!ftok)
8880
0
                    break;
8881
0
            }
8882
0
            ftok = ftok->next();
8883
0
        }
8884
0
        if (Token::simpleMatch(ftok, "( *"))
8885
0
            ftok = ftok->tokAt(2);
8886
0
        if (Token::Match(ftok, "%name% (|)"))
8887
0
            return ftok;
8888
0
    } else if (Token::Match(after, "[;{=:]")) {
8889
0
        Token *prev = tok->previous();
8890
0
        while (Token::Match(prev, "%name%"))
8891
0
            prev = prev->previous();
8892
0
        if (Token::simpleMatch(prev, ")") && Token::Match(prev->link()->previous(), "%name% ("))
8893
0
            return prev->link()->previous();
8894
0
        if (Token::simpleMatch(prev, ")") && Token::Match(prev->link()->tokAt(-2), "operator %op% (") && isCPP())
8895
0
            return prev->link()->tokAt(-2);
8896
0
        if ((!prev || Token::Match(prev, "[;{}*]")) && Token::Match(tok->previous(), "%name%"))
8897
0
            return tok->previous();
8898
0
    }
8899
0
    return nullptr;
8900
0
}
8901
8902
void Tokenizer::simplifyDeclspec()
8903
1.36k
{
8904
80.4k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
8905
79.1k
        while (isAttribute(tok, false)) {
8906
0
            Token *functok = getAttributeFuncTok(tok, false);
8907
0
            if (Token::Match(tok->tokAt(2), "noreturn|nothrow|dllexport")) {
8908
0
                if (functok) {
8909
0
                    if (tok->strAt(2) == "noreturn")
8910
0
                        functok->isAttributeNoreturn(true);
8911
0
                    else if (tok->strAt(2) == "nothrow")
8912
0
                        functok->isAttributeNothrow(true);
8913
0
                    else
8914
0
                        functok->isAttributeExport(true);
8915
0
                }
8916
0
            } else if (tok->strAt(2) == "property")
8917
0
                tok->next()->link()->insertToken("__property");
8918
8919
0
            Token::eraseTokens(tok, tok->next()->link()->next());
8920
0
            tok->deleteThis();
8921
0
        }
8922
79.1k
    }
8923
1.36k
}
8924
8925
void Tokenizer::simplifyAttribute()
8926
1.36k
{
8927
81.8k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
8928
80.4k
        if (!tok->isKeyword() && Token::Match(tok, "%type% (") && !mSettings->library.isNotLibraryFunction(tok)) {
8929
0
            if (mSettings->library.isFunctionConst(tok->str(), true))
8930
0
                tok->isAttributePure(true);
8931
0
            if (mSettings->library.isFunctionConst(tok->str(), false))
8932
0
                tok->isAttributeConst(true);
8933
0
        }
8934
80.4k
        while (isAttribute(tok, true)) {
8935
0
            Token *functok = getAttributeFuncTok(tok, true);
8936
8937
0
            for (Token *attr = tok->tokAt(2); attr->str() != ")"; attr = attr->next()) {
8938
0
                if (Token::Match(attr, "%name% ("))
8939
0
                    attr = attr->linkAt(1);
8940
8941
0
                if (Token::Match(attr, "[(,] constructor|__constructor__ [,()]")) {
8942
0
                    if (!functok)
8943
0
                        syntaxError(tok);
8944
0
                    functok->isAttributeConstructor(true);
8945
0
                }
8946
8947
0
                else if (Token::Match(attr, "[(,] destructor|__destructor__ [,()]")) {
8948
0
                    if (!functok)
8949
0
                        syntaxError(tok);
8950
0
                    functok->isAttributeDestructor(true);
8951
0
                }
8952
8953
0
                else if (Token::Match(attr, "[(,] unused|__unused__|used|__used__ [,)]")) {
8954
0
                    Token *vartok = nullptr;
8955
0
                    Token *after = getTokenAfterAttributes(tok, true);
8956
8957
                    // check if after variable name
8958
0
                    if (Token::Match(after, ";|=")) {
8959
0
                        Token *prev = tok->previous();
8960
0
                        while (Token::simpleMatch(prev, "]"))
8961
0
                            prev = prev->link()->previous();
8962
0
                        if (Token::Match(prev, "%type%"))
8963
0
                            vartok = prev;
8964
0
                    }
8965
8966
                    // check if before variable name
8967
0
                    else if (Token::Match(after, "%type%"))
8968
0
                        vartok = after;
8969
8970
0
                    if (vartok) {
8971
0
                        const std::string &attribute(attr->next()->str());
8972
0
                        if (attribute.find("unused") != std::string::npos)
8973
0
                            vartok->isAttributeUnused(true);
8974
0
                        else
8975
0
                            vartok->isAttributeUsed(true);
8976
0
                    }
8977
0
                }
8978
8979
0
                else if (Token::Match(attr, "[(,] pure|__pure__|const|__const__|noreturn|__noreturn__|nothrow|__nothrow__|warn_unused_result [,)]")) {
8980
0
                    if (!functok)
8981
0
                        syntaxError(tok);
8982
8983
0
                    const std::string &attribute(attr->next()->str());
8984
0
                    if (attribute.find("pure") != std::string::npos)
8985
0
                        functok->isAttributePure(true);
8986
0
                    else if (attribute.find("const") != std::string::npos)
8987
0
                        functok->isAttributeConst(true);
8988
0
                    else if (attribute.find("noreturn") != std::string::npos)
8989
0
                        functok->isAttributeNoreturn(true);
8990
0
                    else if (attribute.find("nothrow") != std::string::npos)
8991
0
                        functok->isAttributeNothrow(true);
8992
0
                    else if (attribute.find("warn_unused_result") != std::string::npos)
8993
0
                        functok->isAttributeNodiscard(true);
8994
0
                }
8995
8996
0
                else if (Token::Match(attr, "[(,] packed [,)]") && Token::simpleMatch(tok->previous(), "}"))
8997
0
                    tok->previous()->isAttributePacked(true);
8998
8999
0
                else if (functok && Token::simpleMatch(attr, "( __visibility__ ( \"default\" ) )"))
9000
0
                    functok->isAttributeExport(true);
9001
0
            }
9002
9003
0
            Token::eraseTokens(tok, tok->linkAt(1)->next());
9004
0
            tok->deleteThis();
9005
0
        }
9006
80.4k
    }
9007
1.36k
}
9008
9009
void Tokenizer::simplifyCppcheckAttribute()
9010
1.36k
{
9011
81.8k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
9012
80.4k
        if (tok->str() != "(")
9013
76.4k
            continue;
9014
4.05k
        if (!tok->previous())
9015
0
            continue;
9016
4.05k
        const std::string &attr = tok->previous()->str();
9017
4.05k
        if (!startsWith(attr, "__cppcheck_"))
9018
4.05k
            continue;
9019
0
        if (attr.compare(attr.size()-2, 2, "__") != 0) // TODO: ends_with("__")
9020
0
            continue;
9021
9022
0
        Token *vartok = tok->link();
9023
0
        while (Token::Match(vartok->next(), "%name%|*|&|::")) {
9024
0
            vartok = vartok->next();
9025
0
            if (Token::Match(vartok, "%name% (") && startsWith(vartok->str(),"__cppcheck_"))
9026
0
                vartok = vartok->linkAt(1);
9027
0
        }
9028
9029
0
        if (vartok->isName()) {
9030
0
            if (Token::Match(tok->previous(), "__cppcheck_low__ ( %num% )"))
9031
0
                vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, MathLib::toLongNumber(tok->next()->str()));
9032
0
            else if (Token::Match(tok->previous(), "__cppcheck_high__ ( %num% )"))
9033
0
                vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, MathLib::toLongNumber(tok->next()->str()));
9034
0
        }
9035
9036
        // Delete cppcheck attribute..
9037
0
        if (tok->tokAt(-2)) {
9038
0
            tok = tok->tokAt(-2);
9039
0
            Token::eraseTokens(tok, tok->linkAt(2)->next());
9040
0
        } else {
9041
0
            tok = tok->previous();
9042
0
            Token::eraseTokens(tok, tok->linkAt(1)->next());
9043
0
            tok->str(";");
9044
0
        }
9045
0
    }
9046
1.36k
}
9047
9048
void Tokenizer::simplifyCPPAttribute()
9049
1.36k
{
9050
1.36k
    if (mSettings->standards.cpp < Standards::CPP11 || isC())
9051
0
        return;
9052
9053
81.8k
    for (Token *tok = list.front(); tok;) {
9054
80.4k
        if (!isCPPAttribute(tok) && !isAlignAttribute(tok)) {
9055
80.4k
            tok = tok->next();
9056
80.4k
            continue;
9057
80.4k
        }
9058
0
        if (isCPPAttribute(tok)) {
9059
0
            if (Token::findsimplematch(tok->tokAt(2), "noreturn", tok->link())) {
9060
0
                Token * head = skipCPPOrAlignAttribute(tok)->next();
9061
0
                while (isCPPAttribute(head) || isAlignAttribute(head))
9062
0
                    head = skipCPPOrAlignAttribute(head)->next();
9063
0
                while (Token::Match(head, "%name%|::|*|&|<|>|,")) // skip return type
9064
0
                    head = head->next();
9065
0
                if (head && head->str() == "(" && isFunctionHead(head, "{|;")) {
9066
0
                    head->previous()->isAttributeNoreturn(true);
9067
0
                }
9068
0
            } else if (Token::findsimplematch(tok->tokAt(2), "nodiscard", tok->link())) {
9069
0
                Token * head = skipCPPOrAlignAttribute(tok)->next();
9070
0
                while (isCPPAttribute(head) || isAlignAttribute(head))
9071
0
                    head = skipCPPOrAlignAttribute(head)->next();
9072
0
                while (Token::Match(head, "%name%|::|*|&|<|>|,"))
9073
0
                    head = head->next();
9074
0
                if (head && head->str() == "(" && isFunctionHead(head, "{|;")) {
9075
0
                    head->previous()->isAttributeNodiscard(true);
9076
0
                }
9077
0
            } else if (Token::findsimplematch(tok->tokAt(2), "maybe_unused", tok->link())) {
9078
0
                Token* head = skipCPPOrAlignAttribute(tok)->next();
9079
0
                while (isCPPAttribute(head) || isAlignAttribute(head))
9080
0
                    head = skipCPPOrAlignAttribute(head)->next();
9081
0
                head->isAttributeMaybeUnused(true);
9082
0
            } else if (Token::Match(tok->previous(), ") [ [ expects|ensures|assert default|audit|axiom| : %name% <|<=|>|>= %num% ] ]")) {
9083
0
                const Token *vartok = tok->tokAt(4);
9084
0
                if (vartok->str() == ":")
9085
0
                    vartok = vartok->next();
9086
0
                Token *argtok = tok->tokAt(-2);
9087
0
                while (argtok && argtok->str() != "(") {
9088
0
                    if (argtok->str() == vartok->str())
9089
0
                        break;
9090
0
                    if (argtok->str() == ")")
9091
0
                        argtok = argtok->link();
9092
0
                    argtok = argtok->previous();
9093
0
                }
9094
0
                if (argtok && argtok->str() == vartok->str()) {
9095
0
                    if (vartok->next()->str() == ">=")
9096
0
                        argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, MathLib::toLongNumber(vartok->strAt(2)));
9097
0
                    else if (vartok->next()->str() == ">")
9098
0
                        argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, MathLib::toLongNumber(vartok->strAt(2))+1);
9099
0
                    else if (vartok->next()->str() == "<=")
9100
0
                        argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, MathLib::toLongNumber(vartok->strAt(2)));
9101
0
                    else if (vartok->next()->str() == "<")
9102
0
                        argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, MathLib::toLongNumber(vartok->strAt(2))-1);
9103
0
                }
9104
0
            }
9105
0
        } else {
9106
0
            if (Token::simpleMatch(tok, "alignas (")) {
9107
                // alignment requirements could be checked here
9108
0
            }
9109
0
        }
9110
0
        Token::eraseTokens(tok, skipCPPOrAlignAttribute(tok)->next());
9111
0
        tok->deleteThis();
9112
0
    }
9113
1.36k
}
9114
9115
void Tokenizer::simplifySpaceshipOperator()
9116
1.36k
{
9117
1.36k
    if (isCPP() && mSettings->standards.cpp >= Standards::CPP20) {
9118
80.4k
        for (Token *tok = list.front(); tok && tok->next(); tok = tok->next()) {
9119
79.1k
            if (Token::simpleMatch(tok, "<= >")) {
9120
0
                tok->str("<=>");
9121
0
                tok->deleteNext();
9122
0
            }
9123
79.1k
        }
9124
1.36k
    }
9125
1.36k
}
9126
9127
static const std::unordered_set<std::string> keywords = {
9128
    "inline"
9129
    , "_inline"
9130
    , "__inline"
9131
    , "__forceinline"
9132
    , "register"
9133
    , "__restrict"
9134
    , "__restrict__"
9135
    , "__thread"
9136
};
9137
// Remove "inline", "register", "restrict", "override", "static" and "constexpr"
9138
// "restrict" keyword
9139
//   - New to 1999 ANSI/ISO C standard
9140
//   - Not in C++ standard yet
9141
void Tokenizer::simplifyKeyword()
9142
1.36k
{
9143
    // FIXME: There is a risk that "keywords" are removed by mistake. This
9144
    // code should be fixed so it doesn't remove variables etc. Nonstandard
9145
    // keywords should be defined with a library instead. For instance the
9146
    // linux kernel code at least uses "_inline" as struct member name at some
9147
    // places.
9148
9149
1.36k
    const bool c99 = isC() && mSettings->standards.c >= Standards::C99;
9150
1.36k
    const bool cpp11 = isCPP() && mSettings->standards.cpp >= Standards::CPP11;
9151
1.36k
    const bool cpp20 = isCPP() && mSettings->standards.cpp >= Standards::CPP20;
9152
9153
80.4k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
9154
79.1k
        if (keywords.find(tok->str()) != keywords.end()) {
9155
            // Don't remove struct members
9156
0
            if (!Token::simpleMatch(tok->previous(), ".")) {
9157
0
                const bool isinline = (tok->str().find("inline") != std::string::npos);
9158
0
                const bool isrestrict = (tok->str().find("restrict") != std::string::npos);
9159
0
                if (isinline || isrestrict) {
9160
0
                    for (Token *temp = tok->next(); Token::Match(temp, "%name%"); temp = temp->next()) {
9161
0
                        if (isinline)
9162
0
                            temp->isInline(true);
9163
0
                        if (isrestrict)
9164
0
                            temp->isRestrict(true);
9165
0
                    }
9166
0
                }
9167
0
                tok->deleteThis(); // Simplify..
9168
0
            }
9169
0
        }
9170
9171
79.1k
        if (isC() || mSettings->standards.cpp == Standards::CPP03) {
9172
0
            if (tok->str() == "auto")
9173
0
                tok->deleteThis();
9174
0
        }
9175
9176
        // simplify static keyword:
9177
        // void foo( int [ static 5 ] ); ==> void foo( int [ 5 ] );
9178
79.1k
        if (Token::Match(tok, "[ static %num%"))
9179
0
            tok->deleteNext();
9180
9181
79.1k
        if (c99) {
9182
0
            auto getTypeTokens = [tok]() {
9183
0
                std::vector<Token*> ret;
9184
0
                for (Token *temp = tok; Token::Match(temp, "%name%"); temp = temp->previous()) {
9185
0
                    if (!temp->isKeyword())
9186
0
                        ret.emplace_back(temp);
9187
0
                }
9188
0
                for (Token *temp = tok->next(); Token::Match(temp, "%name%"); temp = temp->next()) {
9189
0
                    if (!temp->isKeyword())
9190
0
                        ret.emplace_back(temp);
9191
0
                }
9192
0
                return ret;
9193
0
            };
9194
9195
0
            if (tok->str() == "restrict") {
9196
0
                for (Token* temp: getTypeTokens())
9197
0
                    temp->isRestrict(true);
9198
0
                tok->deleteThis();
9199
0
            }
9200
9201
0
            if (mSettings->standards.c >= Standards::C11) {
9202
0
                while (tok->str() == "_Atomic") {
9203
0
                    for (Token* temp: getTypeTokens())
9204
0
                        temp->isAtomic(true);
9205
0
                    tok->deleteThis();
9206
0
                }
9207
0
            }
9208
0
        }
9209
9210
79.1k
        else if (cpp11) {
9211
79.1k
            if (cpp20 && tok->str() == "consteval") {
9212
0
                tok->originalName(tok->str());
9213
0
                tok->str("constexpr");
9214
79.1k
            } else if (cpp20 && tok->str() == "constinit") {
9215
0
                tok->deleteThis();
9216
0
            }
9217
9218
            // final:
9219
            // 1) struct name final { };   <- struct is final
9220
79.1k
            if (Token::Match(tok->previous(), "struct|class|union %type%")) {
9221
0
                Token* finalTok = tok->next();
9222
0
                if (tok->isUpperCaseName() && Token::Match(finalTok, "%type%") && finalTok->str() != "final") {
9223
0
                    tok = finalTok;
9224
0
                    finalTok = finalTok->next();
9225
0
                }
9226
0
                if (Token::simpleMatch(finalTok, "<")) { // specialization
9227
0
                    finalTok = finalTok->findClosingBracket();
9228
0
                    if (finalTok)
9229
0
                        finalTok = finalTok->next();
9230
0
                }
9231
0
                if (Token::Match(finalTok, "final [:{]")) {
9232
0
                    finalTok->deleteThis();
9233
0
                    tok->previous()->isFinalType(true);
9234
0
                }
9235
0
            }
9236
9237
            // noexcept -> noexcept(true)
9238
            // 2) void f() noexcept; -> void f() noexcept(true);
9239
79.1k
            else if (Token::Match(tok, ") const|override|final| noexcept :|{|;|,|const|override|final")) {
9240
                // Insertion is done in inverse order
9241
                // The brackets are linked together accordingly afterwards
9242
0
                Token* tokNoExcept = tok->next();
9243
0
                while (tokNoExcept->str() != "noexcept")
9244
0
                    tokNoExcept = tokNoExcept->next();
9245
0
                tokNoExcept->insertToken(")");
9246
0
                Token * braceEnd = tokNoExcept->next();
9247
0
                tokNoExcept->insertToken("true");
9248
0
                tokNoExcept->insertToken("(");
9249
0
                Token * braceStart = tokNoExcept->next();
9250
0
                tok = tok->tokAt(3);
9251
0
                Token::createMutualLinks(braceStart, braceEnd);
9252
0
            }
9253
9254
            // 3) thread_local -> static
9255
            //    on single thread thread_local has the effect of static
9256
79.1k
            else if (tok->str() == "thread_local") {
9257
0
                tok->originalName(tok->str());
9258
0
                tok->str("static");
9259
0
            }
9260
79.1k
        }
9261
79.1k
    }
9262
1.36k
}
9263
9264
static Token* setTokenDebug(Token* start, TokenDebug td)
9265
0
{
9266
0
    if (!start->link())
9267
0
        return nullptr;
9268
0
    Token* end = start->link();
9269
0
    start->deleteThis();
9270
0
    for (Token* tok = start; tok != end; tok = tok->next()) {
9271
0
        tok->setTokenDebug(td);
9272
0
    }
9273
0
    end->deleteThis();
9274
0
    return end;
9275
0
}
9276
9277
void Tokenizer::simplifyDebug()
9278
1.36k
{
9279
1.36k
    if (!mSettings->debugnormal && !mSettings->debugwarnings)
9280
1.36k
        return;
9281
0
    static const std::unordered_map<std::string, TokenDebug> m = {{"debug_valueflow", TokenDebug::ValueFlow},
9282
0
        {"debug_valuetype", TokenDebug::ValueType}};
9283
0
    for (Token* tok = list.front(); tok; tok = tok->next()) {
9284
0
        if (!Token::Match(tok, "%name% ("))
9285
0
            continue;
9286
0
        auto it = m.find(tok->str());
9287
0
        if (it != m.end()) {
9288
0
            tok->deleteThis();
9289
0
            tok = setTokenDebug(tok, it->second);
9290
0
        }
9291
0
    }
9292
0
}
9293
9294
void Tokenizer::simplifyAssignmentBlock()
9295
1.36k
{
9296
94.1k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
9297
92.7k
        if (Token::Match(tok, "[;{}] %name% = ( {")) {
9298
0
            const std::string &varname = tok->next()->str();
9299
9300
            // goto the "} )"
9301
0
            int indentlevel = 0;
9302
0
            Token *tok2 = tok;
9303
0
            while (nullptr != (tok2 = tok2->next())) {
9304
0
                if (Token::Match(tok2, "(|{"))
9305
0
                    ++indentlevel;
9306
0
                else if (Token::Match(tok2, ")|}")) {
9307
0
                    if (indentlevel <= 2)
9308
0
                        break;
9309
0
                    --indentlevel;
9310
0
                } else if (indentlevel == 2 && tok2->str() == varname && Token::Match(tok2->previous(), "%type%|*"))
9311
                    // declaring variable in inner scope with same name as lhs variable
9312
0
                    break;
9313
0
            }
9314
0
            if (indentlevel == 2 && Token::simpleMatch(tok2, "} )")) {
9315
0
                tok2 = tok2->tokAt(-3);
9316
0
                if (Token::Match(tok2, "[;{}] %num%|%name% ;")) {
9317
0
                    tok2->insertToken("=");
9318
0
                    tok2->insertToken(tok->next()->str());
9319
0
                    tok2->next()->varId(tok->next()->varId());
9320
0
                    tok->deleteNext(3);
9321
0
                    tok2->tokAt(5)->deleteNext();
9322
0
                }
9323
0
            }
9324
0
        }
9325
92.7k
    }
9326
1.36k
}
9327
9328
// Remove __asm..
9329
void Tokenizer::simplifyAsm()
9330
1.36k
{
9331
1.36k
    std::string instruction;
9332
81.8k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
9333
80.4k
        if (Token::Match(tok, "__asm|_asm|asm {") &&
9334
80.4k
            tok->next()->link()->next()) {
9335
0
            instruction = tok->tokAt(2)->stringifyList(tok->next()->link());
9336
0
            Token::eraseTokens(tok, tok->next()->link()->next());
9337
0
        }
9338
9339
80.4k
        else if (Token::Match(tok, "asm|__asm|__asm__ volatile|__volatile|__volatile__| (")) {
9340
            // Goto "("
9341
0
            Token *partok = tok->next();
9342
0
            if (partok->str() != "(")
9343
0
                partok = partok->next();
9344
0
            instruction = partok->next()->stringifyList(partok->link());
9345
0
            Token::eraseTokens(tok, partok->link()->next());
9346
0
        }
9347
9348
80.4k
        else if (Token::Match(tok, "_asm|__asm")) {
9349
0
            Token *endasm = tok->next();
9350
0
            const Token *firstSemiColon = nullptr;
9351
0
            int comment = 0;
9352
0
            while (Token::Match(endasm, "%num%|%name%|,|:|;") || (endasm && endasm->linenr() == comment)) {
9353
0
                if (Token::Match(endasm, "_asm|__asm|__endasm"))
9354
0
                    break;
9355
0
                if (endasm->str() == ";") {
9356
0
                    comment = endasm->linenr();
9357
0
                    if (!firstSemiColon)
9358
0
                        firstSemiColon = endasm;
9359
0
                }
9360
0
                endasm = endasm->next();
9361
0
            }
9362
0
            if (Token::simpleMatch(endasm, "__endasm")) {
9363
0
                instruction = tok->next()->stringifyList(endasm);
9364
0
                Token::eraseTokens(tok, endasm->next());
9365
0
                if (!Token::simpleMatch(tok->next(), ";"))
9366
0
                    tok->insertToken(";");
9367
0
            } else if (firstSemiColon) {
9368
0
                instruction = tok->next()->stringifyList(firstSemiColon);
9369
0
                Token::eraseTokens(tok, firstSemiColon);
9370
0
            } else if (!endasm) {
9371
0
                instruction = tok->next()->stringifyList(endasm);
9372
0
                Token::eraseTokens(tok, endasm);
9373
0
                tok->insertToken(";");
9374
0
            } else
9375
0
                continue;
9376
0
        }
9377
9378
80.4k
        else
9379
80.4k
            continue;
9380
9381
0
        if (Token::Match(tok->previous(), ") %name% %name% (")) {
9382
0
            tok->deleteThis();
9383
0
            continue;
9384
0
        }
9385
9386
        // insert "asm ( "instruction" )"
9387
0
        tok->str("asm");
9388
0
        if (tok->strAt(1) != ";" && tok->strAt(1) != "{")
9389
0
            tok->insertToken(";");
9390
0
        tok->insertToken(")");
9391
0
        tok->insertToken("\"" + instruction + "\"");
9392
0
        tok->insertToken("(");
9393
9394
0
        tok = tok->next();
9395
0
        Token::createMutualLinks(tok, tok->tokAt(2));
9396
9397
        //move the new tokens in the same line as ";" if available
9398
0
        tok = tok->tokAt(2);
9399
0
        if (tok->next() && tok->next()->str() == ";" &&
9400
0
            tok->next()->linenr() != tok->linenr()) {
9401
0
            const int endposition = tok->next()->linenr();
9402
0
            tok = tok->tokAt(-3);
9403
0
            for (int i = 0; i < 4; ++i) {
9404
0
                tok = tok->next();
9405
0
                tok->linenr(endposition);
9406
0
            }
9407
0
        }
9408
0
    }
9409
1.36k
}
9410
9411
void Tokenizer::simplifyAsm2()
9412
1.36k
{
9413
    // Block declarations: ^{}
9414
    // A C extension used to create lambda like closures.
9415
9416
    // Put ^{} statements in asm()
9417
94.1k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
9418
92.7k
        if (tok->str() != "^")
9419
92.4k
            continue;
9420
9421
266
        if (Token::simpleMatch(tok, "^ {") || (Token::simpleMatch(tok->linkAt(1), ") {") && tok->strAt(-1) != "operator")) {
9422
0
            Token * start = tok;
9423
0
            while (start && !Token::Match(start, "[,(;{}=]")) {
9424
0
                if (start->link() && Token::Match(start, ")|]|>"))
9425
0
                    start = start->link();
9426
0
                start = start->previous();
9427
0
            }
9428
9429
0
            const Token *last = tok->next()->link();
9430
0
            if (Token::simpleMatch(last, ") {"))
9431
0
                last = last->linkAt(1);
9432
0
            last = last->next();
9433
0
            while (last && !Token::Match(last, "%cop%|,|;|{|}|)")) {
9434
0
                if (Token::Match(last, "(|["))
9435
0
                    last = last->link();
9436
0
                last = last->next();
9437
0
            }
9438
9439
0
            if (start && last) {
9440
0
                std::string asmcode;
9441
0
                while (start->next() != last) {
9442
0
                    asmcode += start->next()->str();
9443
0
                    start->deleteNext();
9444
0
                }
9445
0
                if (last->str() == "}")
9446
0
                    start->insertToken(";");
9447
0
                start->insertToken(")");
9448
0
                start->insertToken("\"" + asmcode + "\"");
9449
0
                start->insertToken("(");
9450
0
                start->insertToken("asm");
9451
0
                start->tokAt(2)->link(start->tokAt(4));
9452
0
                start->tokAt(4)->link(start->tokAt(2));
9453
0
                tok = start->tokAt(4);
9454
0
            }
9455
0
        }
9456
266
    }
9457
1.36k
}
9458
9459
void Tokenizer::simplifyAt()
9460
1.36k
{
9461
1.36k
    std::set<std::string> var;
9462
9463
94.1k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
9464
92.7k
        if (Token::Match(tok, "%name%|] @ %num%|%name%|(")) {
9465
0
            const Token *end = tok->tokAt(2);
9466
0
            if (end->isNumber())
9467
0
                end = end->next();
9468
0
            else if (end->str() == "(") {
9469
0
                int par = 0;
9470
0
                while ((end = end->next()) != nullptr) {
9471
0
                    if (end->str() == "(")
9472
0
                        par++;
9473
0
                    else if (end->str() == ")") {
9474
0
                        if (--par < 0)
9475
0
                            break;
9476
0
                    }
9477
0
                }
9478
0
                end = end ? end->next() : nullptr;
9479
0
            } else if (var.find(end->str()) != var.end())
9480
0
                end = end->next();
9481
0
            else
9482
0
                continue;
9483
9484
0
            if (Token::Match(end, ": %num% ;"))
9485
0
                end = end->tokAt(2);
9486
9487
0
            if (end && end->str() == ";") {
9488
0
                if (tok->isName())
9489
0
                    var.insert(tok->str());
9490
0
                tok->isAtAddress(true);
9491
0
                Token::eraseTokens(tok, end);
9492
0
            }
9493
0
        }
9494
9495
        // keywords in compiler from cosmic software for STM8
9496
        // TODO: Should use platform configuration.
9497
92.7k
        if (Token::Match(tok, "@ builtin|eeprom|far|inline|interrupt|near|noprd|nostack|nosvf|packed|stack|svlreg|tiny|vector")) {
9498
0
            tok->str(tok->next()->str() + "@");
9499
0
            tok->deleteNext();
9500
0
        }
9501
92.7k
    }
9502
1.36k
}
9503
9504
// Simplify bitfields
9505
void Tokenizer::simplifyBitfields()
9506
1.36k
{
9507
1.36k
    bool goback = false;
9508
94.1k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
9509
92.7k
        if (goback) {
9510
0
            goback = false;
9511
0
            tok = tok->previous();
9512
0
        }
9513
92.7k
        Token *last = nullptr;
9514
9515
92.7k
        if (Token::simpleMatch(tok, "for ("))
9516
0
            tok = tok->linkAt(1);
9517
9518
92.7k
        if (!Token::Match(tok, ";|{|}|public:|protected:|private:"))
9519
68.5k
            continue;
9520
9521
24.2k
        bool isEnum = false;
9522
24.2k
        if (tok->str() == "}") {
9523
3.58k
            const Token *type = tok->link()->previous();
9524
4.04k
            while (type && type->isName()) {
9525
458
                if (type->str() == "enum") {
9526
0
                    isEnum = true;
9527
0
                    break;
9528
0
                }
9529
458
                type = type->previous();
9530
458
            }
9531
3.58k
        }
9532
9533
24.2k
        if (Token::Match(tok->next(), "const| %type% %name% :") &&
9534
24.2k
            !Token::Match(tok->next(), "case|public|protected|private|class|struct") &&
9535
24.2k
            !Token::simpleMatch(tok->tokAt(2), "default :")) {
9536
0
            Token *tok1 = (tok->next()->str() == "const") ? tok->tokAt(3) : tok->tokAt(2);
9537
0
            if (Token::Match(tok1, "%name% : %num% [;=]"))
9538
0
                tok1->setBits(MathLib::toLongNumber(tok1->strAt(2)));
9539
0
            if (tok1 && tok1->tokAt(2) &&
9540
0
                (Token::Match(tok1->tokAt(2), "%bool%|%num%") ||
9541
0
                 !Token::Match(tok1->tokAt(2), "public|protected|private| %type% ::|<|,|{|;"))) {
9542
0
                while (tok1->next() && !Token::Match(tok1->next(), "[;,)]{}=]")) {
9543
0
                    if (Token::Match(tok1->next(), "[([]"))
9544
0
                        Token::eraseTokens(tok1, tok1->next()->link());
9545
0
                    tok1->deleteNext();
9546
0
                }
9547
9548
0
                last = tok1->next();
9549
0
            }
9550
24.2k
        } else if (isEnum && Token::Match(tok, "} %name%| : %num% ;")) {
9551
0
            if (tok->next()->str() == ":") {
9552
0
                tok->deleteNext(2);
9553
0
                tok->insertToken("Anonymous");
9554
0
            } else {
9555
0
                tok->next()->deleteNext(2);
9556
0
            }
9557
24.2k
        } else if (Token::Match(tok->next(), "const| %type% : %num%|%bool% ;") &&
9558
24.2k
                   tok->next()->str() != "default") {
9559
0
            const int offset = (tok->next()->str() == "const") ? 1 : 0;
9560
0
            if (!Token::Match(tok->tokAt(3 + offset), "[{};()]")) {
9561
0
                tok->deleteNext(4 + offset);
9562
0
                goback = true;
9563
0
            }
9564
0
        }
9565
9566
24.2k
        if (last && last->str() == ",") {
9567
0
            Token * tok1 = last;
9568
0
            tok1->str(";");
9569
9570
0
            const Token *const tok2 = tok->next();
9571
0
            tok1->insertToken(tok2->str());
9572
0
            tok1 = tok1->next();
9573
0
            tok1->isSigned(tok2->isSigned());
9574
0
            tok1->isUnsigned(tok2->isUnsigned());
9575
0
            tok1->isLong(tok2->isLong());
9576
0
        }
9577
24.2k
    }
9578
1.36k
}
9579
9580
// Add std:: in front of std classes, when using namespace std; was given
9581
void Tokenizer::simplifyNamespaceStd()
9582
1.36k
{
9583
1.36k
    if (!isCPP())
9584
0
        return;
9585
9586
1.36k
    std::set<std::string> userFunctions;
9587
9588
1.36k
    for (Token* tok = Token::findsimplematch(list.front(), "using namespace std ;"); tok; tok = tok->next()) {
9589
0
        bool insert = false;
9590
0
        if (Token::Match(tok, "enum class|struct| %name%| :|{")) { // Don't replace within enum definitions
9591
0
            skipEnumBody(&tok);
9592
0
        }
9593
0
        if (!tok->isName() || tok->isKeyword() || tok->isStandardType() || tok->varId())
9594
0
            continue;
9595
0
        if (Token::Match(tok->previous(), ".|::|namespace"))
9596
0
            continue;
9597
0
        if (Token::simpleMatch(tok->next(), "(")) {
9598
0
            if (isFunctionHead(tok->next(), "{"))
9599
0
                userFunctions.insert(tok->str());
9600
0
            else if (isFunctionHead(tok->next(), ";")) {
9601
0
                const Token *start = tok;
9602
0
                while (Token::Match(start->previous(), "%type%|*|&"))
9603
0
                    start = start->previous();
9604
0
                if (start != tok && start->isName() && !start->isKeyword() && (!start->previous() || Token::Match(start->previous(), "[;{}]")))
9605
0
                    userFunctions.insert(tok->str());
9606
0
            }
9607
0
            if (userFunctions.find(tok->str()) == userFunctions.end() && mSettings->library.matchArguments(tok, "std::" + tok->str()))
9608
0
                insert = true;
9609
0
        } else if (Token::simpleMatch(tok->next(), "<") &&
9610
0
                   (mSettings->library.detectContainerOrIterator(tok, nullptr, /*withoutStd*/ true) || mSettings->library.detectSmartPointer(tok, /*withoutStd*/ true)))
9611
0
            insert = true;
9612
0
        else if (mSettings->library.hasAnyTypeCheck("std::" + tok->str()) ||
9613
0
                 mSettings->library.podtype("std::" + tok->str()) ||
9614
0
                 mSettings->library.detectContainerOrIterator(tok, nullptr, /*withoutStd*/ true))
9615
0
            insert = true;
9616
9617
0
        if (insert) {
9618
0
            tok->previous()->insertToken("std");
9619
0
            tok->previous()->linenr(tok->linenr()); // For stylistic reasons we put the std:: in the same line as the following token
9620
0
            tok->previous()->fileIndex(tok->fileIndex());
9621
0
            tok->previous()->insertToken("::");
9622
0
        }
9623
0
    }
9624
9625
93.6k
    for (Token* tok = list.front(); tok; tok = tok->next()) {
9626
92.3k
        if (Token::simpleMatch(tok, "using namespace std ;")) {
9627
0
            Token::eraseTokens(tok, tok->tokAt(4));
9628
0
            tok->deleteThis();
9629
0
        }
9630
92.3k
    }
9631
1.36k
}
9632
9633
9634
void Tokenizer::simplifyMicrosoftMemoryFunctions()
9635
1.36k
{
9636
    // skip if not Windows
9637
1.36k
    if (!mSettings->platform.isWindows())
9638
1.36k
        return;
9639
9640
0
    for (Token *tok = list.front(); tok; tok = tok->next()) {
9641
0
        if (tok->strAt(1) != "(")
9642
0
            continue;
9643
9644
0
        if (Token::Match(tok, "CopyMemory|RtlCopyMemory|RtlCopyBytes")) {
9645
0
            tok->str("memcpy");
9646
0
        } else if (Token::Match(tok, "MoveMemory|RtlMoveMemory")) {
9647
0
            tok->str("memmove");
9648
0
        } else if (Token::Match(tok, "FillMemory|RtlFillMemory|RtlFillBytes")) {
9649
            // FillMemory(dst, len, val) -> memset(dst, val, len)
9650
0
            tok->str("memset");
9651
9652
0
            Token *tok1 = tok->tokAt(2);
9653
0
            if (tok1)
9654
0
                tok1 = tok1->nextArgument(); // Second argument
9655
0
            if (tok1) {
9656
0
                Token *tok2 = tok1->nextArgument(); // Third argument
9657
9658
0
                if (tok2)
9659
0
                    Token::move(tok1->previous(), tok2->tokAt(-2), tok->next()->link()->previous()); // Swap third with second argument
9660
0
            }
9661
0
        } else if (Token::Match(tok, "ZeroMemory|RtlZeroMemory|RtlZeroBytes|RtlSecureZeroMemory")) {
9662
            // ZeroMemory(dst, len) -> memset(dst, 0, len)
9663
0
            tok->str("memset");
9664
9665
0
            Token *tok1 = tok->tokAt(2);
9666
0
            if (tok1)
9667
0
                tok1 = tok1->nextArgument(); // Second argument
9668
9669
0
            if (tok1) {
9670
0
                tok1 = tok1->previous();
9671
0
                tok1->insertToken("0");
9672
0
                tok1 = tok1->next();
9673
0
                tok1->insertToken(",");
9674
0
            }
9675
0
        } else if (Token::simpleMatch(tok, "RtlCompareMemory")) {
9676
            // RtlCompareMemory(src1, src2, len) -> memcmp(src1, src2, len)
9677
0
            tok->str("memcmp");
9678
            // For the record, when memcmp returns 0, both strings are equal.
9679
            // When RtlCompareMemory returns len, both strings are equal.
9680
            // It might be needed to improve this replacement by something
9681
            // like ((len - memcmp(src1, src2, len)) % (len + 1)) to
9682
            // respect execution path (if required)
9683
0
        }
9684
0
    }
9685
0
}
9686
9687
namespace {
9688
    struct triplet {
9689
64
        triplet(const char* m, const char* u) :  mbcs(m), unicode(u) {}
9690
        std::string mbcs, unicode;
9691
    };
9692
9693
    const std::map<std::string, triplet> apis = {
9694
        std::make_pair("_topen", triplet("open", "_wopen")),
9695
        std::make_pair("_tsopen_s", triplet("_sopen_s", "_wsopen_s")),
9696
        std::make_pair("_tfopen", triplet("fopen", "_wfopen")),
9697
        std::make_pair("_tfopen_s", triplet("fopen_s", "_wfopen_s")),
9698
        std::make_pair("_tfreopen", triplet("freopen", "_wfreopen")),
9699
        std::make_pair("_tfreopen_s", triplet("freopen_s", "_wfreopen_s")),
9700
        std::make_pair("_tcscat", triplet("strcat", "wcscat")),
9701
        std::make_pair("_tcschr", triplet("strchr", "wcschr")),
9702
        std::make_pair("_tcscmp", triplet("strcmp", "wcscmp")),
9703
        std::make_pair("_tcsdup", triplet("strdup", "wcsdup")),
9704
        std::make_pair("_tcscpy", triplet("strcpy", "wcscpy")),
9705
        std::make_pair("_tcslen", triplet("strlen", "wcslen")),
9706
        std::make_pair("_tcsncat", triplet("strncat", "wcsncat")),
9707
        std::make_pair("_tcsncpy", triplet("strncpy", "wcsncpy")),
9708
        std::make_pair("_tcsnlen", triplet("strnlen", "wcsnlen")),
9709
        std::make_pair("_tcsrchr", triplet("strrchr", "wcsrchr")),
9710
        std::make_pair("_tcsstr", triplet("strstr", "wcsstr")),
9711
        std::make_pair("_tcstok", triplet("strtok", "wcstok")),
9712
        std::make_pair("_ftprintf", triplet("fprintf", "fwprintf")),
9713
        std::make_pair("_tprintf", triplet("printf", "wprintf")),
9714
        std::make_pair("_stprintf", triplet("sprintf", "swprintf")),
9715
        std::make_pair("_sntprintf", triplet("_snprintf", "_snwprintf")),
9716
        std::make_pair("_ftscanf", triplet("fscanf", "fwscanf")),
9717
        std::make_pair("_tscanf", triplet("scanf", "wscanf")),
9718
        std::make_pair("_stscanf", triplet("sscanf", "swscanf")),
9719
        std::make_pair("_ftprintf_s", triplet("fprintf_s", "fwprintf_s")),
9720
        std::make_pair("_tprintf_s", triplet("printf_s", "wprintf_s")),
9721
        std::make_pair("_stprintf_s", triplet("sprintf_s", "swprintf_s")),
9722
        std::make_pair("_sntprintf_s", triplet("_snprintf_s", "_snwprintf_s")),
9723
        std::make_pair("_ftscanf_s", triplet("fscanf_s", "fwscanf_s")),
9724
        std::make_pair("_tscanf_s", triplet("scanf_s", "wscanf_s")),
9725
        std::make_pair("_stscanf_s", triplet("sscanf_s", "swscanf_s"))
9726
    };
9727
}
9728
9729
void Tokenizer::simplifyMicrosoftStringFunctions()
9730
1.36k
{
9731
    // skip if not Windows
9732
1.36k
    if (!mSettings->platform.isWindows())
9733
1.36k
        return;
9734
9735
0
    const bool ansi = mSettings->platform.type == cppcheck::Platform::Type::Win32A;
9736
0
    for (Token *tok = list.front(); tok; tok = tok->next()) {
9737
0
        if (tok->strAt(1) != "(")
9738
0
            continue;
9739
9740
0
        const std::map<std::string, triplet>::const_iterator match = apis.find(tok->str());
9741
0
        if (match!=apis.end()) {
9742
0
            tok->str(ansi ? match->second.mbcs : match->second.unicode);
9743
0
            tok->originalName(match->first);
9744
0
        } else if (Token::Match(tok, "_T|_TEXT|TEXT ( %char%|%str% )")) {
9745
0
            tok->deleteNext();
9746
0
            tok->deleteThis();
9747
0
            tok->deleteNext();
9748
0
            if (!ansi) {
9749
0
                tok->isLong(true);
9750
0
                if (tok->str()[0] != 'L')
9751
0
                    tok->str("L" + tok->str());
9752
0
            }
9753
0
            while (Token::Match(tok->next(), "_T|_TEXT|TEXT ( %char%|%str% )")) {
9754
0
                tok->next()->deleteNext();
9755
0
                tok->next()->deleteThis();
9756
0
                tok->next()->deleteNext();
9757
0
                tok->concatStr(tok->next()->str());
9758
0
                tok->deleteNext();
9759
0
            }
9760
0
        }
9761
0
    }
9762
0
}
9763
9764
// Remove Borland code
9765
void Tokenizer::simplifyBorland()
9766
1.36k
{
9767
    // skip if not Windows
9768
1.36k
    if (!mSettings->platform.isWindows())
9769
1.36k
        return;
9770
0
    if (isC())
9771
0
        return;
9772
0
    for (Token *tok = list.front(); tok; tok = tok->next()) {
9773
0
        if (Token::Match(tok, "( __closure * %name% )")) {
9774
0
            tok->deleteNext();
9775
0
        }
9776
0
    }
9777
9778
    // I think that these classes are always declared at the outer scope
9779
    // I save some time by ignoring inner classes.
9780
0
    for (Token *tok = list.front(); tok; tok = tok->next()) {
9781
0
        if (tok->str() == "{" && !Token::Match(tok->tokAt(-2), "namespace %type%")) {
9782
0
            tok = tok->link();
9783
0
            if (!tok)
9784
0
                break;
9785
0
        } else if (Token::Match(tok, "class %name% :|{")) {
9786
0
            while (tok && tok->str() != "{" && tok->str() != ";")
9787
0
                tok = tok->next();
9788
0
            if (!tok)
9789
0
                break;
9790
0
            if (tok->str() == ";")
9791
0
                continue;
9792
9793
0
            const Token* end = tok->link()->next();
9794
0
            for (Token *tok2 = tok->next(); tok2 != end; tok2 = tok2->next()) {
9795
0
                if (tok2->str() == "__property" &&
9796
0
                    Token::Match(tok2->previous(), ";|{|}|protected:|public:|__published:")) {
9797
0
                    while (tok2->next() && !Token::Match(tok2->next(), "{|;"))
9798
0
                        tok2->deleteNext();
9799
0
                    tok2->deleteThis();
9800
0
                    if (tok2->str() == "{") {
9801
0
                        Token::eraseTokens(tok2, tok2->link());
9802
0
                        tok2->deleteNext();
9803
0
                        tok2->deleteThis();
9804
9805
                        // insert "; __property ;"
9806
0
                        tok2->previous()->insertToken(";");
9807
0
                        tok2->previous()->insertToken("__property");
9808
0
                        tok2->previous()->insertToken(";");
9809
0
                    }
9810
0
                }
9811
0
            }
9812
0
        }
9813
0
    }
9814
0
}
9815
9816
void Tokenizer::createSymbolDatabase()
9817
1.36k
{
9818
1.36k
    if (!mSymbolDatabase)
9819
1.36k
        mSymbolDatabase = new SymbolDatabase(*this, *mSettings, mErrorLogger);
9820
1.36k
    mSymbolDatabase->validate();
9821
1.36k
}
9822
9823
bool Tokenizer::operatorEnd(const Token * tok) const
9824
0
{
9825
0
    if (tok && tok->str() == ")") {
9826
0
        if (isFunctionHead(tok, "{|;|?|:|["))
9827
0
            return true;
9828
9829
0
        tok = tok->next();
9830
0
        while (tok && !Token::Match(tok, "[=;{),]")) {
9831
0
            if (Token::Match(tok, "const|volatile|override")) {
9832
0
                tok = tok->next();
9833
0
            } else if (tok->str() == "noexcept") {
9834
0
                tok = tok->next();
9835
0
                if (tok && tok->str() == "(") {
9836
0
                    tok = tok->link()->next();
9837
0
                }
9838
0
            } else if (tok->str() == "throw" && tok->next() && tok->next()->str() == "(") {
9839
0
                tok = tok->next()->link()->next();
9840
0
            }
9841
            // unknown macros ") MACRO {" and ") MACRO(...) {"
9842
0
            else if (tok->isUpperCaseName()) {
9843
0
                tok = tok->next();
9844
0
                if (tok && tok->str() == "(") {
9845
0
                    tok = tok->link()->next();
9846
0
                }
9847
0
            } else if (Token::Match(tok, "%op% !!(") ||
9848
0
                       (Token::Match(tok, "%op% (") && !isFunctionHead(tok->next(), "{")))
9849
0
                break;
9850
0
            else
9851
0
                return false;
9852
0
        }
9853
9854
0
        return true;
9855
0
    }
9856
9857
0
    return false;
9858
0
}
9859
9860
void Tokenizer::simplifyOperatorName()
9861
1.36k
{
9862
1.36k
    if (isC())
9863
0
        return;
9864
9865
94.1k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
9866
92.7k
        if (Token::Match(tok, "using|:: operator %op%|%name% ;")) {
9867
0
            tok->next()->str("operator" + tok->strAt(2));
9868
0
            tok->next()->deleteNext();
9869
0
            continue;
9870
0
        }
9871
9872
92.7k
        if (tok->str() != "operator")
9873
92.7k
            continue;
9874
        // operator op
9875
0
        if (Token::Match(tok, "operator %op% (") && !operatorEnd(tok->linkAt(2))) {
9876
0
            tok->str(tok->str() + tok->next()->str());
9877
0
            tok->deleteNext();
9878
0
            continue;
9879
0
        }
9880
0
        std::string op;
9881
0
        Token *par = tok->next();
9882
0
        bool done = false;
9883
0
        while (!done && par) {
9884
0
            done = true;
9885
0
            if (par->isName()) {
9886
0
                op += par->str();
9887
0
                par = par->next();
9888
                // merge namespaces eg. 'operator std :: string () const {'
9889
0
                if (Token::Match(par, ":: %name%|%op%|.")) {
9890
0
                    op += par->str();
9891
0
                    par = par->next();
9892
0
                }
9893
0
                done = false;
9894
0
            } else if (Token::Match(par, ".|%op%|,")) {
9895
                // check for operator in template
9896
0
                if (par->str() == "," && !op.empty())
9897
0
                    break;
9898
0
                if (!(Token::Match(par, "<|>") && !op.empty())) {
9899
0
                    op += par->str() == "." ? par->originalName() : par->str();
9900
0
                    par = par->next();
9901
0
                    done = false;
9902
0
                }
9903
0
            } else if (Token::simpleMatch(par, "[ ]")) {
9904
0
                op += "[]";
9905
0
                par = par->tokAt(2);
9906
0
                done = false;
9907
0
            } else if (Token::Match(par, "( *| )")) {
9908
                // break out and simplify..
9909
0
                if (operatorEnd(par->next()))
9910
0
                    break;
9911
9912
0
                while (par->str() != ")") {
9913
0
                    op += par->str();
9914
0
                    par = par->next();
9915
0
                }
9916
0
                op += ")";
9917
0
                par = par->next();
9918
0
                if (Token::simpleMatch(par, "...")) {
9919
0
                    op.clear();
9920
0
                    par = nullptr;
9921
0
                    break;
9922
0
                }
9923
0
                done = false;
9924
0
            } else if (Token::Match(par, "\"\" %name% )| (|;|<")) {
9925
0
                op += "\"\"";
9926
0
                op += par->strAt(1);
9927
0
                par = par->tokAt(2);
9928
0
                if (par->str() == ")") {
9929
0
                    par->link()->deleteThis();
9930
0
                    par = par->next();
9931
0
                    par->deletePrevious();
9932
0
                    tok = par->tokAt(-3);
9933
0
                }
9934
0
                done = true;
9935
0
            } else if (par->str() == "::") {
9936
0
                op += par->str();
9937
0
                par = par->next();
9938
0
                done = false;
9939
0
            } else if (par->str() == ";" || par->str() == ")") {
9940
0
                done = true;
9941
0
            } else if (par->str() != "(") {
9942
0
                syntaxError(par, "operator");
9943
0
            }
9944
0
        }
9945
9946
0
        if (par && !op.empty()) {
9947
0
            tok->str("operator" + op);
9948
0
            Token::eraseTokens(tok, par);
9949
0
        }
9950
9951
0
        if (!op.empty())
9952
0
            tok->isOperatorKeyword(true);
9953
0
    }
9954
9955
94.1k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
9956
92.7k
        if (Token::Match(tok, "%op% %str% %name%")) {
9957
0
            const std::string name = tok->strAt(2);
9958
0
            Token * const str = tok->next();
9959
0
            str->deleteNext();
9960
0
            tok->insertToken("operator\"\"" + name);
9961
0
            tok = tok->next();
9962
0
            tok->isOperatorKeyword(true);
9963
0
            tok->insertToken("(");
9964
0
            str->insertToken(")");
9965
0
            Token::createMutualLinks(tok->next(), str->next());
9966
0
            str->insertToken(std::to_string(Token::getStrLength(str)));
9967
0
            str->insertToken(",");
9968
0
        }
9969
92.7k
    }
9970
9971
1.36k
    if (mSettings->debugwarnings) {
9972
0
        const Token *tok = list.front();
9973
9974
0
        while ((tok = Token::findsimplematch(tok, "operator")) != nullptr) {
9975
0
            reportError(tok, Severity::debug, "debug",
9976
0
                        "simplifyOperatorName: found unsimplified operator name");
9977
0
            tok = tok->next();
9978
0
        }
9979
0
    }
9980
1.36k
}
9981
9982
void Tokenizer::simplifyOverloadedOperators()
9983
1.36k
{
9984
1.36k
    if (isC())
9985
0
        return;
9986
1.36k
    std::set<std::string> classNames;
9987
1.36k
    std::set<nonneg int> classVars;
9988
93.6k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
9989
92.3k
        if (!tok->isName())
9990
56.5k
            continue;
9991
9992
35.7k
        if (Token::simpleMatch(tok, "this ) (") && Token::simpleMatch(tok->tokAt(-2), "( *")) {
9993
0
            tok = tok->next();
9994
0
            tok->insertToken("operator()");
9995
0
            tok->insertToken(".");
9996
0
            continue;
9997
0
        }
9998
9999
        // Get classes that have operator() member
10000
35.7k
        if (Token::Match(tok, "class|struct %name% [:{]")) {
10001
0
            int indent = 0;
10002
0
            for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
10003
0
                if (tok2->str() == "}")
10004
0
                    break;
10005
0
                if (indent == 0 && tok2->str() == ";")
10006
0
                    break;
10007
0
                if (tok2->str() == "{") {
10008
0
                    if (indent == 0)
10009
0
                        ++indent;
10010
0
                    else
10011
0
                        tok2 = tok2->link();
10012
0
                } else if (indent == 1 && Token::simpleMatch(tok2, "operator() (") && isFunctionHead(tok2->next(), ";{")) {
10013
0
                    classNames.insert(tok->strAt(1));
10014
0
                    break;
10015
0
                }
10016
0
            }
10017
0
        }
10018
10019
        // Get variables that have operator() member
10020
35.7k
        if (Token::Match(tok, "%type% &| %var%") && classNames.find(tok->str()) != classNames.end()) {
10021
0
            tok = tok->next();
10022
0
            while (!tok->isName())
10023
0
                tok = tok->next();
10024
0
            classVars.insert(tok->varId());
10025
0
        }
10026
10027
        // Simplify operator() calls
10028
35.7k
        if (Token::Match(tok, "%var% (") && classVars.find(tok->varId()) != classVars.end()) {
10029
            // constructor init list..
10030
0
            if (Token::Match(tok->previous(), "[:,]")) {
10031
0
                const Token *start = tok->previous();
10032
0
                while (Token::simpleMatch(start, ",")) {
10033
0
                    if (Token::simpleMatch(start->previous(), ")"))
10034
0
                        start = start->linkAt(-1);
10035
0
                    else
10036
0
                        break;
10037
0
                    if (Token::Match(start->previous(), "%name%"))
10038
0
                        start = start->tokAt(-2);
10039
0
                    else
10040
0
                        break;
10041
0
                }
10042
0
                const Token *after = tok->linkAt(1);
10043
0
                while (Token::Match(after, ")|} , %name% (|{"))
10044
0
                    after = after->linkAt(3);
10045
10046
                // Do not simplify initlist
10047
0
                if (Token::simpleMatch(start, ":") && Token::simpleMatch(after, ") {"))
10048
0
                    continue;
10049
0
            }
10050
10051
0
            tok->insertToken("operator()");
10052
0
            tok->insertToken(".");
10053
0
        }
10054
35.7k
    }
10055
1.36k
}
10056
10057
// remove unnecessary member qualification..
10058
void Tokenizer::removeUnnecessaryQualification()
10059
1.36k
{
10060
1.36k
    if (isC())
10061
0
        return;
10062
10063
1.36k
    std::vector<Space> classInfo;
10064
80.4k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
10065
79.1k
        if (Token::Match(tok, "class|struct|namespace %type% :|{") &&
10066
79.1k
            (!tok->previous() || tok->previous()->str() != "enum")) {
10067
0
            Space info;
10068
0
            info.isNamespace = tok->str() == "namespace";
10069
0
            tok = tok->next();
10070
0
            info.className = tok->str();
10071
0
            tok = tok->next();
10072
0
            while (tok && tok->str() != "{")
10073
0
                tok = tok->next();
10074
0
            if (!tok)
10075
0
                return;
10076
0
            info.bodyEnd = tok->link();
10077
0
            classInfo.push_back(std::move(info));
10078
79.1k
        } else if (!classInfo.empty()) {
10079
0
            if (tok == classInfo.back().bodyEnd)
10080
0
                classInfo.pop_back();
10081
0
            else if (tok->str() == classInfo.back().className &&
10082
0
                     !classInfo.back().isNamespace && tok->previous()->str() != ":" &&
10083
0
                     (Token::Match(tok, "%type% :: ~| %type% (") ||
10084
0
                      Token::Match(tok, "%type% :: operator"))) {
10085
0
                const Token *tok1 = tok->tokAt(3);
10086
0
                if (tok->strAt(2) == "operator") {
10087
                    // check for operator ()
10088
0
                    if (tok1->str() == "(")
10089
0
                        tok1 = tok1->next();
10090
10091
0
                    while (tok1 && tok1->str() != "(") {
10092
0
                        if (tok1->str() == ";")
10093
0
                            break;
10094
0
                        tok1 = tok1->next();
10095
0
                    }
10096
0
                    if (!tok1 || tok1->str() != "(")
10097
0
                        continue;
10098
0
                } else if (tok->strAt(2) == "~")
10099
0
                    tok1 = tok1->next();
10100
10101
0
                if (!tok1 || !Token::Match(tok1->link(), ") const| {|;|:")) {
10102
0
                    continue;
10103
0
                }
10104
10105
0
                const bool isConstructorOrDestructor =
10106
0
                    Token::Match(tok, "%type% :: ~| %type%") && (tok->strAt(2) == tok->str() || (tok->strAt(2) == "~" && tok->strAt(3) == tok->str()));
10107
0
                if (!isConstructorOrDestructor) {
10108
0
                    bool isPrependedByType = Token::Match(tok->previous(), "%type%");
10109
0
                    if (!isPrependedByType) {
10110
0
                        const Token* tok2 = tok->tokAt(-2);
10111
0
                        isPrependedByType = Token::Match(tok2, "%type% *|&");
10112
0
                    }
10113
0
                    if (!isPrependedByType) {
10114
0
                        const Token* tok3 = tok->tokAt(-3);
10115
0
                        isPrependedByType = Token::Match(tok3, "%type% * *|&");
10116
0
                    }
10117
0
                    if (!isPrependedByType) {
10118
                        // It's not a constructor declaration and it's not a function declaration so
10119
                        // this is a function call which can have all the qualifiers just fine - skip.
10120
0
                        continue;
10121
0
                    }
10122
0
                }
10123
0
            }
10124
0
        }
10125
79.1k
    }
10126
1.36k
}
10127
10128
void Tokenizer::printUnknownTypes() const
10129
0
{
10130
0
    if (!mSymbolDatabase)
10131
0
        return;
10132
10133
0
    std::vector<std::pair<std::string, const Token *>> unknowns;
10134
10135
0
    for (int i = 1; i <= mVarId; ++i) {
10136
0
        const Variable *var = mSymbolDatabase->getVariableFromVarId(i);
10137
0
        if (!var)
10138
0
            continue;
10139
        // is unknown type?
10140
0
        if (var->type() || var->typeStartToken()->isStandardType())
10141
0
            continue;
10142
10143
0
        std::string name;
10144
0
        const Token * nameTok;
10145
10146
        // single token type?
10147
0
        if (var->typeStartToken() == var->typeEndToken()) {
10148
0
            nameTok = var->typeStartToken();
10149
0
            name = nameTok->str();
10150
0
        }
10151
10152
        // complicated type
10153
0
        else {
10154
0
            const Token *tok = var->typeStartToken();
10155
0
            int level = 0;
10156
10157
0
            nameTok =  tok;
10158
10159
0
            while (tok) {
10160
                // skip pointer and reference part of type
10161
0
                if (level == 0 && Token::Match(tok, "*|&"))
10162
0
                    break;
10163
10164
0
                name += tok->str();
10165
10166
0
                if (Token::Match(tok, "struct|union|enum"))
10167
0
                    name += " ";
10168
10169
                // pointers and references are OK in template
10170
0
                else if (tok->str() == "<")
10171
0
                    ++level;
10172
0
                else if (tok->str() == ">")
10173
0
                    --level;
10174
10175
0
                if (tok == var->typeEndToken())
10176
0
                    break;
10177
10178
0
                tok = tok->next();
10179
0
            }
10180
0
        }
10181
10182
0
        unknowns.emplace_back(std::move(name), nameTok);
10183
0
    }
10184
10185
0
    if (!unknowns.empty()) {
10186
0
        std::string last;
10187
0
        int count = 0;
10188
10189
0
        for (auto it = unknowns.cbegin(); it != unknowns.cend(); ++it) {
10190
            // skip types is std namespace because they are not interesting
10191
0
            if (it->first.find("std::") != 0) {
10192
0
                if (it->first != last) {
10193
0
                    last = it->first;
10194
0
                    count = 1;
10195
0
                    reportError(it->second, Severity::debug, "debug", "Unknown type \'" + it->first + "\'.");
10196
0
                } else {
10197
0
                    if (count < 3) // limit same type to 3
10198
0
                        reportError(it->second, Severity::debug, "debug", "Unknown type \'" + it->first + "\'.");
10199
0
                    count++;
10200
0
                }
10201
0
            }
10202
0
        }
10203
0
    }
10204
0
}
10205
10206
void Tokenizer::prepareTernaryOpForAST()
10207
2.72k
{
10208
    // http://en.cppreference.com/w/cpp/language/operator_precedence says about ternary operator:
10209
    //       "The expression in the middle of the conditional operator (between ? and :) is parsed as if parenthesized: its precedence relative to ?: is ignored."
10210
    // The AST parser relies on this function to add such parentheses where necessary.
10211
174k
    for (Token* tok = list.front(); tok; tok = tok->next()) {
10212
171k
        if (tok->str() == "?") {
10213
0
            bool parenthesesNeeded = false;
10214
0
            int depth = 0;
10215
0
            Token* tok2 = tok->next();
10216
0
            for (; tok2; tok2 = tok2->next()) {
10217
0
                if (tok2->link() && Token::Match(tok2, "[|(|<"))
10218
0
                    tok2 = tok2->link();
10219
0
                else if (tok2->str() == ":") {
10220
0
                    if (depth == 0)
10221
0
                        break;
10222
0
                    depth--;
10223
0
                } else if (tok2->str() == ";" || (tok2->link() && tok2->str() != "{" && tok2->str() != "}"))
10224
0
                    break;
10225
0
                else if (tok2->str() == ",")
10226
0
                    parenthesesNeeded = true;
10227
0
                else if (tok2->str() == "<")
10228
0
                    parenthesesNeeded = true;
10229
0
                else if (tok2->str() == "?") {
10230
0
                    depth++;
10231
0
                    parenthesesNeeded = true;
10232
0
                }
10233
0
            }
10234
0
            if (parenthesesNeeded && tok2 && tok2->str() == ":") {
10235
0
                tok->insertToken("(");
10236
0
                tok2->insertToken(")", emptyString, true);
10237
0
                Token::createMutualLinks(tok->next(), tok2->previous());
10238
0
            }
10239
0
        }
10240
171k
    }
10241
2.72k
}
10242
10243
void Tokenizer::reportError(const Token* tok, const Severity::SeverityType severity, const std::string& id, const std::string& msg, bool inconclusive) const
10244
0
{
10245
0
    const std::list<const Token*> callstack(1, tok);
10246
0
    reportError(callstack, severity, id, msg, inconclusive);
10247
0
}
10248
10249
void Tokenizer::reportError(const std::list<const Token*>& callstack, Severity::SeverityType severity, const std::string& id, const std::string& msg, bool inconclusive) const
10250
0
{
10251
0
    const ErrorMessage errmsg(callstack, &list, severity, id, msg, inconclusive ? Certainty::inconclusive : Certainty::normal);
10252
0
    if (mErrorLogger)
10253
0
        mErrorLogger->reportErr(errmsg);
10254
0
    else
10255
0
        Check::writeToErrorList(errmsg);
10256
0
}
10257
10258
void Tokenizer::setPodTypes()
10259
1.36k
{
10260
1.36k
    if (!mSettings)
10261
0
        return;
10262
93.6k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
10263
92.3k
        if (!tok->isName() || tok->varId())
10264
76.3k
            continue;
10265
10266
        // pod type
10267
15.9k
        const struct Library::PodType *podType = mSettings->library.podtype(tok->str());
10268
15.9k
        if (podType) {
10269
0
            const Token *prev = tok->previous();
10270
0
            while (prev && prev->isName())
10271
0
                prev = prev->previous();
10272
0
            if (prev && !Token::Match(prev, ";|{|}|,|("))
10273
0
                continue;
10274
0
            tok->isStandardType(true);
10275
0
        }
10276
15.9k
    }
10277
1.36k
}
10278
10279
const Token *Tokenizer::findSQLBlockEnd(const Token *tokSQLStart)
10280
0
{
10281
0
    const Token *tokLastEnd = nullptr;
10282
0
    for (const Token *tok = tokSQLStart->tokAt(2); tok != nullptr; tok = tok->next()) {
10283
0
        if (tokLastEnd == nullptr && tok->str() == ";")
10284
0
            tokLastEnd = tok;
10285
0
        else if (tok->str() == "__CPPCHECK_EMBEDDED_SQL_EXEC__") {
10286
0
            if (Token::simpleMatch(tok->tokAt(-2), "END - __CPPCHECK_EMBEDDED_SQL_EXEC__ ;"))
10287
0
                return tok->next();
10288
0
            return tokLastEnd;
10289
0
        } else if (Token::Match(tok, "{|}|==|&&|!|^|<<|>>|++|+=|-=|/=|*=|>>=|<<=|~"))
10290
0
            break; // We are obviously outside the SQL block
10291
0
    }
10292
10293
0
    return tokLastEnd;
10294
0
}
10295
10296
void Tokenizer::simplifyNestedNamespace()
10297
1.36k
{
10298
1.36k
    if (!isCPP())
10299
0
        return;
10300
10301
81.8k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
10302
80.4k
        if (Token::Match(tok, "namespace %name% ::") && tok->strAt(-1) != "using") {
10303
0
            Token * tok2 = tok->tokAt(2);
10304
10305
            // validate syntax
10306
0
            while (Token::Match(tok2, ":: %name%"))
10307
0
                tok2 = tok2->tokAt(2);
10308
10309
0
            if (!tok2 || tok2->str() != "{")
10310
0
                return; // syntax error
10311
10312
0
            std::stack<Token *> links;
10313
0
            tok2 = tok->tokAt(2);
10314
10315
0
            while (tok2->str() == "::") {
10316
0
                links.push(tok2);
10317
0
                tok2->str("{");
10318
0
                tok2->insertToken("namespace");
10319
0
                tok2 = tok2->tokAt(3);
10320
0
            }
10321
10322
0
            tok = tok2;
10323
10324
0
            if (!links.empty() && tok2->str() == "{") {
10325
0
                tok2 = tok2->link();
10326
0
                while (!links.empty()) {
10327
0
                    tok2->insertToken("}");
10328
0
                    tok2 = tok2->next();
10329
0
                    Token::createMutualLinks(links.top(), tok2);
10330
0
                    links.pop();
10331
0
                }
10332
0
            }
10333
0
        }
10334
80.4k
    }
10335
1.36k
}
10336
10337
void Tokenizer::simplifyCoroutines()
10338
1.36k
{
10339
1.36k
    if (!isCPP() || mSettings->standards.cpp < Standards::CPP20)
10340
0
        return;
10341
81.8k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
10342
80.4k
        if (!tok->isName() || !Token::Match(tok, "co_return|co_yield|co_await"))
10343
80.4k
            continue;
10344
0
        Token *end = tok->next();
10345
0
        while (end && end->str() != ";") {
10346
0
            if (Token::Match(end, "[({[]"))
10347
0
                end = end->link();
10348
0
            else if (Token::Match(end, "[)]}]"))
10349
0
                break;
10350
0
            end = end->next();
10351
0
        }
10352
0
        if (Token::simpleMatch(end, ";")) {
10353
0
            tok->insertToken("(");
10354
0
            end->previous()->insertToken(")");
10355
0
            Token::createMutualLinks(tok->next(), end->previous());
10356
0
        }
10357
0
    }
10358
1.36k
}
10359
10360
static bool sameTokens(const Token *first, const Token *last, const Token *other)
10361
0
{
10362
0
    while (other && first->str() == other->str()) {
10363
0
        if (first == last)
10364
0
            return true;
10365
0
        first = first->next();
10366
0
        other = other->next();
10367
0
    }
10368
10369
0
    return false;
10370
0
}
10371
10372
static bool alreadyHasNamespace(const Token *first, const Token *last, const Token *end)
10373
0
{
10374
0
    while (end && last->str() == end->str()) {
10375
0
        if (first == last)
10376
0
            return true;
10377
0
        last = last->previous();
10378
0
        end = end->previous();
10379
0
    }
10380
10381
0
    return false;
10382
0
}
10383
10384
static Token * deleteAlias(Token * tok)
10385
0
{
10386
0
    Token::eraseTokens(tok, Token::findsimplematch(tok, ";"));
10387
10388
    // delete first token
10389
0
    tok->deleteThis();
10390
10391
    // delete ';' if not last token
10392
0
    tok->deleteThis();
10393
10394
0
    return tok;
10395
0
}
10396
10397
void Tokenizer::simplifyNamespaceAliases()
10398
1.36k
{
10399
1.36k
    if (!isCPP())
10400
0
        return;
10401
10402
1.36k
    int scope = 0;
10403
10404
81.8k
    for (Token *tok = list.front(); tok; tok = tok->next()) {
10405
80.4k
        bool isPrev{};
10406
80.4k
        if (tok->str() == "{")
10407
3.58k
            scope++;
10408
76.9k
        else if (tok->str() == "}")
10409
3.58k
            scope--;
10410
73.3k
        else if (Token::Match(tok, "namespace %name% =") || (isPrev = Token::Match(tok->previous(), "namespace %name% ="))) {
10411
0
            if (isPrev)
10412
0
                tok = tok->previous();
10413
0
            const std::string name(tok->next()->str());
10414
0
            Token * tokNameStart = tok->tokAt(3);
10415
0
            Token * tokNameEnd = tokNameStart;
10416
10417
0
            while (tokNameEnd && tokNameEnd->next() && tokNameEnd->next()->str() != ";") {
10418
0
                if (tokNameEnd->str() == "(") {
10419
0
                    if (tokNameEnd->previous()->isName())
10420
0
                        unknownMacroError(tokNameEnd->previous());
10421
0
                    else
10422
0
                        syntaxError(tokNameEnd);
10423
0
                }
10424
0
                tokNameEnd = tokNameEnd->next();
10425
0
            }
10426
10427
0
            if (!tokNameEnd)
10428
0
                return; // syntax error
10429
10430
0
            int endScope = scope;
10431
0
            Token * tokLast = tokNameEnd->next();
10432
0
            Token * tokNext = tokLast->next();
10433
0
            Token * tok2 = tokNext;
10434
10435
0
            while (tok2 && endScope >= scope) {
10436
0
                if (Token::simpleMatch(tok2, "{"))
10437
0
                    endScope++;
10438
0
                else if (Token::simpleMatch(tok2, "}"))
10439
0
                    endScope--;
10440
0
                else if (tok2->str() == name) {
10441
0
                    if (Token::Match(tok2->previous(), "namespace %name% =")) {
10442
                        // check for possible duplicate aliases
10443
0
                        if (sameTokens(tokNameStart, tokNameEnd, tok2->tokAt(2))) {
10444
                            // delete duplicate
10445
0
                            tok2 = deleteAlias(tok2->previous());
10446
0
                            continue;
10447
0
                        }
10448
                        // conflicting declaration (syntax error)
10449
                        // cppcheck-suppress duplicateBranch - remove when TODO below is addressed
10450
0
                        if (endScope == scope) {
10451
                            // delete conflicting declaration
10452
0
                            tok2 = deleteAlias(tok2->previous());
10453
0
                        }
10454
10455
                        // new declaration
10456
0
                        else {
10457
                            // TODO: use the new alias in this scope
10458
0
                            tok2 = deleteAlias(tok2->previous());
10459
0
                        }
10460
0
                        continue;
10461
0
                    }
10462
10463
0
                    if (tok2->strAt(1) == "::" && !alreadyHasNamespace(tokNameStart, tokNameEnd, tok2)) {
10464
0
                        tok2->str(tokNameStart->str());
10465
0
                        Token * tok3 = tokNameStart;
10466
0
                        while (tok3 != tokNameEnd) {
10467
0
                            tok2->insertToken(tok3->next()->str());
10468
0
                            tok2 = tok2->next();
10469
0
                            tok3 = tok3->next();
10470
0
                        }
10471
0
                    }
10472
0
                }
10473
0
                tok2 = tok2->next();
10474
0
            }
10475
10476
0
            if (tok->previous() && tokNext) {
10477
0
                Token::eraseTokens(tok->previous(), tokNext);
10478
0
                tok = tokNext->previous();
10479
0
            } else if (tok->previous()) {
10480
0
                Token::eraseTokens(tok->previous(), tokLast);
10481
0
                tok = tokLast;
10482
0
            } else if (tokNext) {
10483
0
                Token::eraseTokens(tok, tokNext);
10484
0
                tok->deleteThis();
10485
0
            } else {
10486
0
                Token::eraseTokens(tok, tokLast);
10487
0
                tok->deleteThis();
10488
0
            }
10489
0
        }
10490
80.4k
    }
10491
1.36k
}
10492
10493
bool Tokenizer::hasIfdef(const Token *start, const Token *end) const
10494
2.00k
{
10495
2.00k
    assert(mPreprocessor);
10496
10497
0
    return std::any_of(mPreprocessor->getDirectives().cbegin(), mPreprocessor->getDirectives().cend(), [&](const Directive& d) {
10498
0
        return startsWith(d.str, "#if") &&
10499
0
        d.linenr >= start->linenr() &&
10500
0
        d.linenr <= end->linenr() &&
10501
0
        start->fileIndex() < list.getFiles().size() &&
10502
0
        d.file == list.getFiles()[start->fileIndex()];
10503
0
    });
10504
2.00k
}