Coverage Report

Created: 2023-09-25 06:15

/src/cppcheck/lib/symboldatabase.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 "symboldatabase.h"
21
22
#include "astutils.h"
23
#include "errorlogger.h"
24
#include "errortypes.h"
25
#include "keywords.h"
26
#include "library.h"
27
#include "mathlib.h"
28
#include "path.h"
29
#include "platform.h"
30
#include "settings.h"
31
#include "standards.h"
32
#include "templatesimplifier.h"
33
#include "token.h"
34
#include "tokenize.h"
35
#include "tokenlist.h"
36
#include "utils.h"
37
#include "valueflow.h"
38
39
#include <algorithm>
40
#include <cassert>
41
#include <cstring>
42
#include <initializer_list>
43
#include <iomanip>
44
#include <iostream>
45
#include <iterator>
46
#include <limits>
47
#include <sstream> // IWYU pragma: keep
48
#include <stack>
49
#include <string>
50
#include <tuple>
51
#include <type_traits>
52
#include <unordered_map>
53
#include <unordered_set>
54
//---------------------------------------------------------------------------
55
56
SymbolDatabase::SymbolDatabase(Tokenizer& tokenizer, const Settings& settings, ErrorLogger* errorLogger)
57
    : mTokenizer(tokenizer), mSettings(settings), mErrorLogger(errorLogger)
58
1.36k
{
59
1.36k
    if (!mTokenizer.tokens())
60
0
        return;
61
62
1.36k
    mIsCpp = isCPP();
63
64
1.36k
    if (mSettings.platform.defaultSign == 's' || mSettings.platform.defaultSign == 'S')
65
1.36k
        mDefaultSignedness = ValueType::SIGNED;
66
0
    else if (mSettings.platform.defaultSign == 'u' || mSettings.platform.defaultSign == 'U')
67
0
        mDefaultSignedness = ValueType::UNSIGNED;
68
0
    else
69
0
        mDefaultSignedness = ValueType::UNKNOWN_SIGN;
70
71
1.36k
    createSymbolDatabaseFindAllScopes();
72
1.36k
    createSymbolDatabaseClassInfo();
73
1.36k
    createSymbolDatabaseVariableInfo();
74
1.36k
    createSymbolDatabaseCopyAndMoveConstructors();
75
1.36k
    createSymbolDatabaseFunctionScopes();
76
1.36k
    createSymbolDatabaseClassAndStructScopes();
77
1.36k
    createSymbolDatabaseFunctionReturnTypes();
78
1.36k
    createSymbolDatabaseNeedInitialization();
79
1.36k
    createSymbolDatabaseVariableSymbolTable();
80
1.36k
    createSymbolDatabaseSetScopePointers();
81
1.36k
    createSymbolDatabaseSetVariablePointers();
82
1.36k
    setValueTypeInTokenList(false);
83
1.36k
    createSymbolDatabaseSetTypePointers();
84
1.36k
    createSymbolDatabaseSetFunctionPointers(true);
85
1.36k
    createSymbolDatabaseSetSmartPointerType();
86
1.36k
    setValueTypeInTokenList(false);
87
1.36k
    createSymbolDatabaseEnums();
88
1.36k
    createSymbolDatabaseEscapeFunctions();
89
1.36k
    createSymbolDatabaseIncompleteVars();
90
1.36k
    createSymbolDatabaseExprIds();
91
1.36k
    debugSymbolDatabase();
92
1.36k
}
93
94
static const Token* skipScopeIdentifiers(const Token* tok)
95
27.0k
{
96
27.0k
    if (Token::Match(tok, ":: %name%"))
97
0
        tok = tok->next();
98
27.0k
    while (Token::Match(tok, "%name% ::") ||
99
27.0k
           (Token::Match(tok, "%name% <") && Token::Match(tok->linkAt(1), ">|>> ::"))) {
100
0
        if (tok->strAt(1) == "::")
101
0
            tok = tok->tokAt(2);
102
0
        else
103
0
            tok = tok->linkAt(1)->tokAt(2);
104
0
    }
105
106
27.0k
    return tok;
107
27.0k
}
108
109
static bool isExecutableScope(const Token* tok)
110
0
{
111
0
    if (!Token::simpleMatch(tok, "{"))
112
0
        return false;
113
0
    const Token * tok2 = tok->link()->previous();
114
0
    if (Token::simpleMatch(tok2, "; }"))
115
0
        return true;
116
0
    if (tok2 == tok)
117
0
        return false;
118
0
    if (Token::simpleMatch(tok2, "} }")) { // inner scope
119
0
        const Token* startTok = tok2->link();
120
0
        if (Token::Match(startTok->previous(), "do|try|else {"))
121
0
            return true;
122
0
        if (Token::Match(startTok->previous(), ")|] {"))
123
0
            return !findLambdaStartToken(tok2);
124
0
        return isExecutableScope(startTok);
125
0
    }
126
0
    return false;
127
0
}
128
129
void SymbolDatabase::createSymbolDatabaseFindAllScopes()
130
1.36k
{
131
    // create global scope
132
1.36k
    scopeList.emplace_back(this, nullptr, nullptr);
133
134
    // pointer to current scope
135
1.36k
    Scope *scope = &scopeList.back();
136
137
    // Store the ending of init lists
138
1.36k
    std::stack<std::pair<const Token*, const Scope*>> endInitList;
139
69.2k
    auto inInitList = [&] {
140
69.2k
        if (endInitList.empty())
141
69.2k
            return false;
142
0
        return endInitList.top().second == scope;
143
69.2k
    };
144
145
1.36k
    auto addLambda = [this, &scope](const Token* tok, const Token* lambdaEndToken) -> const Token* {
146
0
        const Token* lambdaStartToken = lambdaEndToken->link();
147
0
        const Token* argStart = lambdaStartToken->astParent();
148
0
        const Token* funcStart = Token::simpleMatch(argStart, "[") ? argStart : argStart->astParent();
149
0
        const Function* function = addGlobalFunction(scope, tok, argStart, funcStart);
150
0
        if (!function)
151
0
            mTokenizer.syntaxError(tok);
152
0
        return lambdaStartToken;
153
0
    };
154
155
    // Store current access in each scope (depends on evaluation progress)
156
1.36k
    std::map<const Scope*, AccessControl> access;
157
158
    // find all scopes
159
74.2k
    for (const Token *tok = mTokenizer.tokens(); tok; tok = tok ? tok->next() : nullptr) {
160
        // #5593 suggested to add here:
161
72.8k
        if (mErrorLogger)
162
72.8k
            mErrorLogger->reportProgress(mTokenizer.list.getSourceFilePath(),
163
72.8k
                                         "SymbolDatabase",
164
72.8k
                                         tok->progressValue());
165
        // Locate next class
166
72.8k
        if ((mTokenizer.isCPP() && tok->isKeyword() &&
167
72.8k
             ((Token::Match(tok, "class|struct|union|namespace ::| %name% final| {|:|::|<") &&
168
3.75k
               !Token::Match(tok->previous(), "new|friend|const|enum|typedef|mutable|volatile|using|)|(|<")) ||
169
3.75k
              (Token::Match(tok, "enum class| %name% {") ||
170
3.75k
               Token::Match(tok, "enum class| %name% : %name% {"))))
171
72.8k
            || (mTokenizer.isC() && tok->isKeyword() && Token::Match(tok, "struct|union|enum %name% {"))) {
172
0
            const Token *tok2 = tok->tokAt(2);
173
174
0
            if (tok->strAt(1) == "::")
175
0
                tok2 = tok2->next();
176
0
            else if (mTokenizer.isCPP() && tok->strAt(1) == "class")
177
0
                tok2 = tok2->next();
178
179
0
            while (Token::Match(tok2, ":: %name%"))
180
0
                tok2 = tok2->tokAt(2);
181
0
            while (Token::Match(tok2, "%name% :: %name%"))
182
0
                tok2 = tok2->tokAt(2);
183
184
            // skip over template args
185
0
            while (tok2 && tok2->str() == "<" && tok2->link()) {
186
0
                tok2 = tok2->link()->next();
187
0
                while (Token::Match(tok2, ":: %name%"))
188
0
                    tok2 = tok2->tokAt(2);
189
0
            }
190
191
            // skip over final
192
0
            if (mTokenizer.isCPP() && Token::simpleMatch(tok2, "final"))
193
0
                tok2 = tok2->next();
194
195
            // make sure we have valid code
196
0
            if (!Token::Match(tok2, "{|:")) {
197
                // check for qualified variable
198
0
                if (tok2 && tok2->next()) {
199
0
                    if (tok2->next()->str() == ";")
200
0
                        tok = tok2->next();
201
0
                    else if (Token::simpleMatch(tok2->next(), "= {") &&
202
0
                             Token::simpleMatch(tok2->linkAt(2), "} ;"))
203
0
                        tok = tok2->linkAt(2)->next();
204
0
                    else if (Token::Match(tok2->next(), "(|{") &&
205
0
                             tok2->next()->link()->strAt(1) == ";")
206
0
                        tok = tok2->next()->link()->next();
207
                    // skip variable declaration
208
0
                    else if (Token::Match(tok2, "*|&|>"))
209
0
                        continue;
210
0
                    else if (Token::Match(tok2, "%name% (") && mTokenizer.isFunctionHead(tok2->next(), "{;"))
211
0
                        continue;
212
0
                    else if (Token::Match(tok2, "%name% [|="))
213
0
                        continue;
214
                    // skip template
215
0
                    else if (Token::simpleMatch(tok2, ";") &&
216
0
                             Token::Match(tok->previous(), "template|> class|struct")) {
217
0
                        tok = tok2;
218
0
                        continue;
219
0
                    }
220
                    // forward declaration
221
0
                    else if (Token::simpleMatch(tok2, ";") &&
222
0
                             Token::Match(tok, "class|struct|union")) {
223
                        // TODO: see if it can be used
224
0
                        tok = tok2;
225
0
                        continue;
226
0
                    }
227
                    // skip constructor
228
0
                    else if (Token::simpleMatch(tok2, "(") &&
229
0
                             Token::simpleMatch(tok2->link(), ") ;")) {
230
0
                        tok = tok2->link()->next();
231
0
                        continue;
232
0
                    } else
233
0
                        throw InternalError(tok2, "SymbolDatabase bailout; unhandled code", InternalError::SYNTAX);
234
0
                    continue;
235
0
                }
236
0
                break; // bail
237
0
            }
238
239
0
            const Token * name = tok->next();
240
241
0
            if (name->str() == "class" && name->strAt(-1) == "enum")
242
0
                name = name->next();
243
244
0
            Scope *new_scope = findScope(name, scope);
245
246
0
            if (new_scope) {
247
                // only create base list for classes and structures
248
0
                if (new_scope->isClassOrStruct()) {
249
                    // goto initial '{'
250
0
                    if (!new_scope->definedType)
251
0
                        mTokenizer.syntaxError(nullptr); // #6808
252
0
                    tok2 = new_scope->definedType->initBaseInfo(tok, tok2);
253
                    // make sure we have valid code
254
0
                    if (!tok2) {
255
0
                        break;
256
0
                    }
257
0
                }
258
259
                // definition may be different than declaration
260
0
                if (mTokenizer.isCPP() && tok->str() == "class") {
261
0
                    access[new_scope] = AccessControl::Private;
262
0
                    new_scope->type = Scope::eClass;
263
0
                } else if (tok->str() == "struct") {
264
0
                    access[new_scope] = AccessControl::Public;
265
0
                    new_scope->type = Scope::eStruct;
266
0
                }
267
268
0
                new_scope->classDef = tok;
269
0
                new_scope->setBodyStartEnd(tok2);
270
                // make sure we have valid code
271
0
                if (!new_scope->bodyEnd) {
272
0
                    mTokenizer.syntaxError(tok);
273
0
                }
274
0
                scope = new_scope;
275
0
                tok = tok2;
276
0
            } else {
277
0
                scopeList.emplace_back(this, tok, scope);
278
0
                new_scope = &scopeList.back();
279
280
0
                if (tok->str() == "class")
281
0
                    access[new_scope] = AccessControl::Private;
282
0
                else if (tok->str() == "struct" || tok->str() == "union")
283
0
                    access[new_scope] = AccessControl::Public;
284
285
                // fill typeList...
286
0
                if (new_scope->isClassOrStructOrUnion() || new_scope->type == Scope::eEnum) {
287
0
                    Type* new_type = findType(name, scope);
288
0
                    if (!new_type) {
289
0
                        typeList.emplace_back(new_scope->classDef, new_scope, scope);
290
0
                        new_type = &typeList.back();
291
0
                        scope->definedTypesMap[new_type->name()] = new_type;
292
0
                    } else
293
0
                        new_type->classScope = new_scope;
294
0
                    new_scope->definedType = new_type;
295
0
                }
296
297
                // only create base list for classes and structures
298
0
                if (new_scope->isClassOrStruct()) {
299
                    // goto initial '{'
300
0
                    tok2 = new_scope->definedType->initBaseInfo(tok, tok2);
301
302
                    // make sure we have valid code
303
0
                    if (!tok2) {
304
0
                        mTokenizer.syntaxError(tok);
305
0
                    }
306
0
                } else if (new_scope->type == Scope::eEnum) {
307
0
                    if (tok2->str() == ":")
308
0
                        tok2 = tok2->tokAt(2);
309
0
                }
310
311
0
                new_scope->setBodyStartEnd(tok2);
312
313
                // make sure we have valid code
314
0
                if (!new_scope->bodyEnd) {
315
0
                    mTokenizer.syntaxError(tok);
316
0
                }
317
318
0
                if (new_scope->type == Scope::eEnum) {
319
0
                    tok2 = new_scope->addEnum(tok, mTokenizer.isCPP());
320
0
                    scope->nestedList.push_back(new_scope);
321
322
0
                    if (!tok2)
323
0
                        mTokenizer.syntaxError(tok);
324
0
                } else {
325
                    // make the new scope the current scope
326
0
                    scope->nestedList.push_back(new_scope);
327
0
                    scope = new_scope;
328
0
                }
329
330
0
                tok = tok2;
331
0
            }
332
0
        }
333
334
        // Namespace and unknown macro (#3854)
335
72.8k
        else if (mTokenizer.isCPP() && tok->isKeyword() &&
336
72.8k
                 Token::Match(tok, "namespace %name% %type% (") &&
337
72.8k
                 tok->tokAt(2)->isUpperCaseName() &&
338
72.8k
                 Token::simpleMatch(tok->linkAt(3), ") {")) {
339
0
            scopeList.emplace_back(this, tok, scope);
340
341
0
            Scope *new_scope = &scopeList.back();
342
0
            access[new_scope] = AccessControl::Public;
343
344
0
            const Token *tok2 = tok->linkAt(3)->next();
345
346
0
            new_scope->setBodyStartEnd(tok2);
347
348
            // make sure we have valid code
349
0
            if (!new_scope->bodyEnd) {
350
0
                scopeList.pop_back();
351
0
                break;
352
0
            }
353
354
            // make the new scope the current scope
355
0
            scope->nestedList.push_back(new_scope);
356
0
            scope = &scopeList.back();
357
358
0
            tok = tok2;
359
0
        }
360
361
        // forward declaration
362
72.8k
        else if (tok->isKeyword() && Token::Match(tok, "class|struct|union %name% ;") &&
363
72.8k
                 tok->strAt(-1) != "friend") {
364
0
            if (!findType(tok->next(), scope)) {
365
                // fill typeList..
366
0
                typeList.emplace_back(tok, nullptr, scope);
367
0
                Type* new_type = &typeList.back();
368
0
                scope->definedTypesMap[new_type->name()] = new_type;
369
0
            }
370
0
            tok = tok->tokAt(2);
371
0
        }
372
373
        // using namespace
374
72.8k
        else if (mTokenizer.isCPP() && tok->isKeyword() && Token::Match(tok, "using namespace ::| %type% ;|::")) {
375
0
            Scope::UsingInfo using_info;
376
377
0
            using_info.start = tok; // save location
378
0
            using_info.scope = findNamespace(tok->tokAt(2), scope);
379
380
0
            scope->usingList.push_back(using_info);
381
382
            // check for global namespace
383
0
            if (tok->strAt(2) == "::")
384
0
                tok = tok->tokAt(4);
385
0
            else
386
0
                tok = tok->tokAt(3);
387
388
            // skip over qualification
389
0
            while (Token::Match(tok, "%type% ::"))
390
0
                tok = tok->tokAt(2);
391
0
        }
392
393
        // using type alias
394
72.8k
        else if (mTokenizer.isCPP() && tok->isKeyword() && Token::Match(tok, "using %name% =")) {
395
0
            if (tok->strAt(-1) != ">" && !findType(tok->next(), scope)) {
396
                // fill typeList..
397
0
                typeList.emplace_back(tok, nullptr, scope);
398
0
                Type* new_type = &typeList.back();
399
0
                scope->definedTypesMap[new_type->name()] = new_type;
400
0
            }
401
402
0
            tok = tok->tokAt(3);
403
404
0
            while (tok && tok->str() != ";") {
405
0
                if (Token::simpleMatch(tok, "decltype ("))
406
0
                    tok = tok->linkAt(1);
407
0
                else
408
0
                    tok = tok->next();
409
0
            }
410
0
        }
411
412
        // unnamed struct and union
413
72.8k
        else if (tok->isKeyword() && Token::Match(tok, "struct|union {") &&
414
72.8k
                 Token::Match(tok->next()->link(), "} *|&| %name% ;|[|=")) {
415
0
            scopeList.emplace_back(this, tok, scope);
416
417
0
            Scope *new_scope = &scopeList.back();
418
0
            access[new_scope] = AccessControl::Public;
419
420
0
            const Token* varNameTok = tok->next()->link()->next();
421
0
            if (varNameTok->str() == "*") {
422
0
                varNameTok = varNameTok->next();
423
0
            } else if (varNameTok->str() == "&") {
424
0
                varNameTok = varNameTok->next();
425
0
            }
426
427
0
            typeList.emplace_back(tok, new_scope, scope);
428
0
            {
429
0
                Type* new_type = &typeList.back();
430
0
                new_scope->definedType = new_type;
431
0
                scope->definedTypesMap[new_type->name()] = new_type;
432
0
            }
433
434
0
            scope->addVariable(varNameTok, tok, tok, access[scope], new_scope->definedType, scope, &mSettings);
435
436
0
            const Token *tok2 = tok->next();
437
438
0
            new_scope->setBodyStartEnd(tok2);
439
440
            // make sure we have valid code
441
0
            if (!new_scope->bodyEnd) {
442
0
                scopeList.pop_back();
443
0
                break;
444
0
            }
445
446
            // make the new scope the current scope
447
0
            scope->nestedList.push_back(new_scope);
448
0
            scope = new_scope;
449
450
0
            tok = tok2;
451
0
        }
452
453
        // anonymous struct, union and namespace
454
72.8k
        else if (tok->isKeyword() && ((Token::Match(tok, "struct|union {") &&
455
3.75k
                                       Token::simpleMatch(tok->next()->link(), "} ;")) ||
456
3.75k
                                      Token::simpleMatch(tok, "namespace {"))) {
457
0
            scopeList.emplace_back(this, tok, scope);
458
459
0
            Scope *new_scope = &scopeList.back();
460
0
            access[new_scope] = AccessControl::Public;
461
462
0
            const Token *tok2 = tok->next();
463
464
0
            new_scope->setBodyStartEnd(tok2);
465
466
0
            typeList.emplace_back(tok, new_scope, scope);
467
0
            {
468
0
                Type* new_type = &typeList.back();
469
0
                new_scope->definedType = new_type;
470
0
                scope->definedTypesMap[new_type->name()] = new_type;
471
0
            }
472
473
            // make sure we have valid code
474
0
            if (!new_scope->bodyEnd) {
475
0
                scopeList.pop_back();
476
0
                break;
477
0
            }
478
479
            // make the new scope the current scope
480
0
            scope->nestedList.push_back(new_scope);
481
0
            scope = new_scope;
482
483
0
            tok = tok2;
484
0
        }
485
486
        // forward declared enum
487
72.8k
        else if (tok->isKeyword() && (Token::Match(tok, "enum class| %name% ;") || Token::Match(tok, "enum class| %name% : %name% ;"))) {
488
0
            typeList.emplace_back(tok, nullptr, scope);
489
0
            Type* new_type = &typeList.back();
490
0
            scope->definedTypesMap[new_type->name()] = new_type;
491
0
            tok = tok->tokAt(2);
492
0
        }
493
494
        // check for end of scope
495
72.8k
        else if (tok == scope->bodyEnd) {
496
3.58k
            do {
497
3.58k
                access.erase(scope);
498
3.58k
                scope = const_cast<Scope*>(scope->nestedIn);
499
3.58k
            } while (scope->type != Scope::eGlobal && succeeds(tok, scope->bodyEnd));
500
3.58k
            continue;
501
3.58k
        }
502
        // check for end of init list
503
69.2k
        else if (inInitList() && tok == endInitList.top().first) {
504
0
            endInitList.pop();
505
0
            continue;
506
0
        }
507
508
        // check if in class or structure or union
509
69.2k
        else if (scope->isClassOrStructOrUnion()) {
510
0
            const Token *funcStart = nullptr;
511
0
            const Token *argStart = nullptr;
512
0
            const Token *declEnd = nullptr;
513
514
            // What section are we in..
515
0
            if (tok->str() == "private:")
516
0
                access[scope] = AccessControl::Private;
517
0
            else if (tok->str() == "protected:")
518
0
                access[scope] = AccessControl::Protected;
519
0
            else if (tok->str() == "public:" || tok->str() == "__published:")
520
0
                access[scope] = AccessControl::Public;
521
0
            else if (Token::Match(tok, "public|protected|private %name% :")) {
522
0
                if (tok->str() == "private")
523
0
                    access[scope] = AccessControl::Private;
524
0
                else if (tok->str() == "protected")
525
0
                    access[scope] = AccessControl::Protected;
526
0
                else
527
0
                    access[scope] = AccessControl::Public;
528
529
0
                tok = tok->tokAt(2);
530
0
            }
531
532
            // class function?
533
0
            else if (isFunction(tok, scope, &funcStart, &argStart, &declEnd)) {
534
0
                if (tok->previous()->str() != "::" || tok->strAt(-2) == scope->className) {
535
0
                    Function function(&mTokenizer, tok, scope, funcStart, argStart);
536
537
                    // save the access type
538
0
                    function.access = access[scope];
539
540
0
                    const Token *end = function.argDef->link();
541
542
                    // count the number of constructors
543
0
                    if (function.isConstructor())
544
0
                        scope->numConstructors++;
545
546
                    // assume implementation is inline (definition and implementation same)
547
0
                    function.token = function.tokenDef;
548
0
                    function.arg = function.argDef;
549
550
                    // out of line function
551
0
                    if (const Token *endTok = mTokenizer.isFunctionHead(end, ";")) {
552
0
                        tok = endTok;
553
0
                        scope->addFunction(function);
554
0
                    }
555
556
                    // inline function
557
0
                    else {
558
                        // find start of function '{'
559
0
                        bool foundInitList = false;
560
0
                        while (end && end->str() != "{" && end->str() != ";") {
561
0
                            if (end->link() && Token::Match(end, "(|<")) {
562
0
                                end = end->link();
563
0
                            } else if (foundInitList &&
564
0
                                       Token::Match(end, "%name%|> {") &&
565
0
                                       Token::Match(end->linkAt(1), "} ,|{")) {
566
0
                                end = end->linkAt(1);
567
0
                            } else {
568
0
                                if (end->str() == ":")
569
0
                                    foundInitList = true;
570
0
                                end = end->next();
571
0
                            }
572
0
                        }
573
574
0
                        if (!end || end->str() == ";")
575
0
                            continue;
576
577
0
                        scope->addFunction(function);
578
579
0
                        Function* funcptr = &scope->functionList.back();
580
0
                        const Token *tok2 = funcStart;
581
582
0
                        addNewFunction(&scope, &tok2);
583
0
                        if (scope) {
584
0
                            scope->functionOf = function.nestedIn;
585
0
                            scope->function = funcptr;
586
0
                            scope->function->functionScope = scope;
587
0
                        }
588
589
0
                        tok = tok2;
590
0
                    }
591
0
                }
592
593
                // nested class or friend function?
594
0
                else {
595
                    /** @todo check entire qualification for match */
596
0
                    const Scope * const nested = scope->findInNestedListRecursive(tok->strAt(-2));
597
598
0
                    if (nested)
599
0
                        addClassFunction(&scope, &tok, argStart);
600
0
                    else {
601
                        /** @todo handle friend functions */
602
0
                    }
603
0
                }
604
0
            }
605
606
            // friend class declaration?
607
0
            else if (mTokenizer.isCPP() && tok->isKeyword() && Token::Match(tok, "friend class|struct| ::| %any% ;|::")) {
608
0
                Type::FriendInfo friendInfo;
609
610
                // save the name start
611
0
                friendInfo.nameStart = tok->strAt(1) == "class" ? tok->tokAt(2) : tok->next();
612
0
                friendInfo.nameEnd = friendInfo.nameStart;
613
614
                // skip leading "::"
615
0
                if (friendInfo.nameEnd->str() == "::")
616
0
                    friendInfo.nameEnd = friendInfo.nameEnd->next();
617
618
                // skip qualification "name ::"
619
0
                while (friendInfo.nameEnd && friendInfo.nameEnd->strAt(1) == "::")
620
0
                    friendInfo.nameEnd = friendInfo.nameEnd->tokAt(2);
621
622
                // fill this in after parsing is complete
623
0
                friendInfo.type = nullptr;
624
625
0
                if (!scope->definedType)
626
0
                    mTokenizer.syntaxError(tok);
627
628
0
                scope->definedType->friendList.push_back(friendInfo);
629
0
            }
630
69.2k
        } else if (scope->type == Scope::eNamespace || scope->type == Scope::eGlobal) {
631
51.1k
            const Token *funcStart = nullptr;
632
51.1k
            const Token *argStart = nullptr;
633
51.1k
            const Token *declEnd = nullptr;
634
635
            // function?
636
51.1k
            if (isFunction(tok, scope, &funcStart, &argStart, &declEnd)) {
637
                // has body?
638
1.73k
                if (declEnd && declEnd->str() == "{") {
639
1.73k
                    tok = funcStart;
640
641
                    // class function
642
1.73k
                    if (tok->previous() && tok->previous()->str() == "::")
643
0
                        addClassFunction(&scope, &tok, argStart);
644
645
                    // class destructor
646
1.73k
                    else if (tok->previous() &&
647
1.73k
                             tok->previous()->str() == "~" &&
648
1.73k
                             tok->strAt(-2) == "::")
649
0
                        addClassFunction(&scope, &tok, argStart);
650
651
                    // regular function
652
1.73k
                    else {
653
1.73k
                        const Function* const function = addGlobalFunction(scope, tok, argStart, funcStart);
654
655
1.73k
                        if (!function)
656
0
                            mTokenizer.syntaxError(tok);
657
1.73k
                    }
658
659
                    // syntax error?
660
1.73k
                    if (!scope)
661
0
                        mTokenizer.syntaxError(tok);
662
1.73k
                }
663
                // function prototype?
664
0
                else if (declEnd && declEnd->str() == ";") {
665
0
                    if (tok->astParent() && tok->astParent()->str() == "::" &&
666
0
                        Token::Match(declEnd->previous(), "default|delete")) {
667
0
                        addClassFunction(&scope, &tok, argStart);
668
0
                        continue;
669
0
                    }
670
671
0
                    bool newFunc = true; // Is this function already in the database?
672
0
                    auto range = scope->functionMap.equal_range(tok->str());
673
0
                    for (std::multimap<std::string, const Function*>::const_iterator it = range.first; it != range.second; ++it) {
674
0
                        if (it->second->argsMatch(scope, it->second->argDef, argStart, emptyString, 0)) {
675
0
                            newFunc = false;
676
0
                            break;
677
0
                        }
678
0
                    }
679
680
                    // save function prototype in database
681
0
                    if (newFunc) {
682
0
                        addGlobalFunctionDecl(scope, tok, argStart, funcStart);
683
0
                    }
684
685
0
                    tok = declEnd;
686
0
                    continue;
687
0
                }
688
49.3k
            } else if (const Token *lambdaEndToken = findLambdaEndToken(tok)) {
689
0
                tok = addLambda(tok, lambdaEndToken);
690
0
            }
691
51.1k
        } else if (scope->isExecutable()) {
692
18.1k
            if (tok->isKeyword() && Token::Match(tok, "else|try|do {")) {
693
457
                const Token* tok1 = tok->next();
694
457
                if (tok->str() == "else")
695
457
                    scopeList.emplace_back(this, tok, scope, Scope::eElse, tok1);
696
0
                else if (tok->str() == "do")
697
0
                    scopeList.emplace_back(this, tok, scope, Scope::eDo, tok1);
698
0
                else //if (tok->str() == "try")
699
0
                    scopeList.emplace_back(this, tok, scope, Scope::eTry, tok1);
700
701
457
                tok = tok1;
702
457
                scope->nestedList.push_back(&scopeList.back());
703
457
                scope = &scopeList.back();
704
17.6k
            } else if (tok->isKeyword() && Token::Match(tok, "if|for|while|catch|switch (") && Token::simpleMatch(tok->next()->link(), ") {")) {
705
1.38k
                const Token *scopeStartTok = tok->next()->link()->next();
706
1.38k
                if (tok->str() == "if")
707
919
                    scopeList.emplace_back(this, tok, scope, Scope::eIf, scopeStartTok);
708
468
                else if (tok->str() == "for") {
709
0
                    scopeList.emplace_back(this, tok, scope, Scope::eFor, scopeStartTok);
710
468
                } else if (tok->str() == "while")
711
468
                    scopeList.emplace_back(this, tok, scope, Scope::eWhile, scopeStartTok);
712
0
                else if (tok->str() == "catch") {
713
0
                    scopeList.emplace_back(this, tok, scope, Scope::eCatch, scopeStartTok);
714
0
                } else // if (tok->str() == "switch")
715
0
                    scopeList.emplace_back(this, tok, scope, Scope::eSwitch, scopeStartTok);
716
717
1.38k
                scope->nestedList.push_back(&scopeList.back());
718
1.38k
                scope = &scopeList.back();
719
1.38k
                if (scope->type == Scope::eFor)
720
0
                    scope->checkVariable(tok->tokAt(2), AccessControl::Local, &mSettings); // check for variable declaration and add it to new scope if found
721
1.38k
                else if (scope->type == Scope::eCatch)
722
0
                    scope->checkVariable(tok->tokAt(2), AccessControl::Throw, &mSettings); // check for variable declaration and add it to new scope if found
723
1.38k
                tok = scopeStartTok;
724
16.3k
            } else if (Token::Match(tok, "%var% {")) {
725
0
                endInitList.emplace(tok->next()->link(), scope);
726
0
                tok = tok->next();
727
16.3k
            } else if (const Token *lambdaEndToken = findLambdaEndToken(tok)) {
728
0
                tok = addLambda(tok, lambdaEndToken);
729
16.3k
            } else if (tok->str() == "{") {
730
0
                if (inInitList()) {
731
0
                    endInitList.emplace(tok->link(), scope);
732
0
                } else if (isExecutableScope(tok)) {
733
0
                    scopeList.emplace_back(this, tok, scope, Scope::eUnconditional, tok);
734
0
                    scope->nestedList.push_back(&scopeList.back());
735
0
                    scope = &scopeList.back();
736
0
                } else if (scope->isExecutable()) {
737
0
                    endInitList.emplace(tok->link(), scope);
738
0
                } else {
739
0
                    tok = tok->link();
740
0
                }
741
0
            }
742
            // syntax error?
743
18.1k
            if (!scope)
744
0
                mTokenizer.syntaxError(tok);
745
            // End of scope or list should be handled above
746
18.1k
            if (tok->str() == "}")
747
0
                mTokenizer.syntaxError(tok);
748
18.1k
        }
749
72.8k
    }
750
1.36k
}
751
752
void SymbolDatabase::createSymbolDatabaseClassInfo()
753
1.36k
{
754
1.36k
    if (mTokenizer.isC())
755
0
        return;
756
757
    // fill in using info
758
4.94k
    for (Scope& scope : scopeList) {
759
4.94k
        for (Scope::UsingInfo& usingInfo : scope.usingList) {
760
            // only find if not already found
761
0
            if (usingInfo.scope == nullptr) {
762
                // check scope for match
763
0
                const Scope * const found = findScope(usingInfo.start->tokAt(2), &scope);
764
0
                if (found) {
765
                    // set found scope
766
0
                    usingInfo.scope = found;
767
0
                    break;
768
0
                }
769
0
            }
770
0
        }
771
4.94k
    }
772
773
    // fill in base class info
774
1.36k
    for (Type& type : typeList) {
775
        // finish filling in base class info
776
0
        for (Type::BaseInfo & i : type.derivedFrom) {
777
0
            const Type* found = findType(i.nameTok, type.enclosingScope, /*lookOutside*/ true);
778
0
            if (found && found->findDependency(&type)) {
779
                // circular dependency
780
                //mTokenizer.syntaxError(nullptr);
781
0
            } else {
782
0
                i.type = found;
783
0
            }
784
0
        }
785
0
    }
786
787
    // fill in friend info
788
1.36k
    for (Type & type : typeList) {
789
0
        for (Type::FriendInfo &friendInfo : type.friendList) {
790
0
            friendInfo.type = findType(friendInfo.nameStart, type.enclosingScope);
791
0
        }
792
0
    }
793
1.36k
}
794
795
796
void SymbolDatabase::createSymbolDatabaseVariableInfo()
797
1.36k
{
798
    // fill in variable info
799
4.94k
    for (Scope& scope : scopeList) {
800
        // find variables
801
4.94k
        scope.getVariableList(&mSettings);
802
4.94k
    }
803
804
    // fill in function arguments
805
4.94k
    for (Scope& scope : scopeList) {
806
4.94k
        std::list<Function>::iterator func;
807
808
6.68k
        for (func = scope.functionList.begin(); func != scope.functionList.end(); ++func) {
809
            // add arguments
810
1.73k
            func->addArguments(this, &scope);
811
1.73k
        }
812
4.94k
    }
813
1.36k
}
814
815
void SymbolDatabase::createSymbolDatabaseCopyAndMoveConstructors()
816
1.36k
{
817
    // fill in class and struct copy/move constructors
818
4.94k
    for (Scope& scope : scopeList) {
819
4.94k
        if (!scope.isClassOrStruct())
820
4.94k
            continue;
821
822
0
        std::list<Function>::iterator func;
823
0
        for (func = scope.functionList.begin(); func != scope.functionList.end(); ++func) {
824
0
            if (!func->isConstructor() || func->minArgCount() != 1)
825
0
                continue;
826
827
0
            const Variable* firstArg = func->getArgumentVar(0);
828
0
            if (firstArg->type() == scope.definedType) {
829
0
                if (firstArg->isRValueReference())
830
0
                    func->type = Function::eMoveConstructor;
831
0
                else if (firstArg->isReference() && !firstArg->isPointer())
832
0
                    func->type = Function::eCopyConstructor;
833
0
            }
834
835
0
            if (func->type == Function::eCopyConstructor ||
836
0
                func->type == Function::eMoveConstructor)
837
0
                scope.numCopyOrMoveConstructors++;
838
0
        }
839
0
    }
840
1.36k
}
841
842
void SymbolDatabase::createSymbolDatabaseFunctionScopes()
843
1.36k
{
844
    // fill in function scopes
845
4.94k
    for (const Scope & scope : scopeList) {
846
4.94k
        if (scope.type == Scope::eFunction)
847
1.73k
            functionScopes.push_back(&scope);
848
4.94k
    }
849
1.36k
}
850
851
void SymbolDatabase::createSymbolDatabaseClassAndStructScopes()
852
1.36k
{
853
    // fill in class and struct scopes
854
4.94k
    for (const Scope& scope : scopeList) {
855
4.94k
        if (scope.isClassOrStruct())
856
0
            classAndStructScopes.push_back(&scope);
857
4.94k
    }
858
1.36k
}
859
860
void SymbolDatabase::createSymbolDatabaseFunctionReturnTypes()
861
1.36k
{
862
    // fill in function return types
863
4.94k
    for (Scope& scope : scopeList) {
864
4.94k
        std::list<Function>::iterator func;
865
866
6.68k
        for (func = scope.functionList.begin(); func != scope.functionList.end(); ++func) {
867
            // add return types
868
1.73k
            if (func->retDef) {
869
1.73k
                const Token *type = func->retDef;
870
1.73k
                while (Token::Match(type, "static|const|struct|union|enum"))
871
0
                    type = type->next();
872
1.73k
                if (type) {
873
1.73k
                    func->retType = findVariableTypeInBase(&scope, type);
874
1.73k
                    if (!func->retType)
875
1.73k
                        func->retType = findTypeInNested(type, func->nestedIn);
876
1.73k
                }
877
1.73k
            }
878
1.73k
        }
879
4.94k
    }
880
1.36k
}
881
882
void SymbolDatabase::createSymbolDatabaseNeedInitialization()
883
1.36k
{
884
1.36k
    if (mTokenizer.isC()) {
885
        // For C code it is easy, as there are no constructors and no default values
886
0
        for (const Scope& scope : scopeList) {
887
0
            if (scope.definedType)
888
0
                scope.definedType->needInitialization = Type::NeedInitialization::True;
889
0
        }
890
1.36k
    } else {
891
        // For C++, it is more difficult: Determine if user defined type needs initialization...
892
1.36k
        unsigned int unknowns = 0; // stop checking when there are no unknowns
893
1.36k
        unsigned int retry = 0;    // bail if we don't resolve all the variable types for some reason
894
895
1.36k
        do {
896
1.36k
            unknowns = 0;
897
898
4.94k
            for (Scope& scope : scopeList) {
899
4.94k
                if (!scope.isClassOrStructOrUnion())
900
4.94k
                    continue;
901
0
                if (scope.classDef && Token::simpleMatch(scope.classDef->previous(), ">")) // skip uninstantiated template
902
0
                    continue;
903
904
0
                if (!scope.definedType) {
905
0
                    mBlankTypes.emplace_back();
906
0
                    scope.definedType = &mBlankTypes.back();
907
0
                }
908
909
0
                if (scope.isClassOrStruct() && scope.definedType->needInitialization == Type::NeedInitialization::Unknown) {
910
                    // check for default constructor
911
0
                    bool hasDefaultConstructor = false;
912
913
0
                    for (const Function& func : scope.functionList) {
914
0
                        if (func.type == Function::eConstructor) {
915
                            // check for no arguments: func ( )
916
0
                            if (func.argCount() == 0) {
917
0
                                hasDefaultConstructor = true;
918
0
                                break;
919
0
                            }
920
921
                            /** check for arguments with default values */
922
0
                            if (func.argCount() == func.initializedArgCount()) {
923
0
                                hasDefaultConstructor = true;
924
0
                                break;
925
0
                            }
926
0
                        }
927
0
                    }
928
929
                    // User defined types with user defined default constructor doesn't need initialization.
930
                    // We assume the default constructor initializes everything.
931
                    // Another check will figure out if the constructor actually initializes everything.
932
0
                    if (hasDefaultConstructor)
933
0
                        scope.definedType->needInitialization = Type::NeedInitialization::False;
934
935
                    // check each member variable to see if it needs initialization
936
0
                    else {
937
0
                        bool needInitialization = false;
938
0
                        bool unknown = false;
939
940
0
                        for (const Variable& var: scope.varlist) {
941
0
                            if (var.isClass()) {
942
0
                                if (var.type()) {
943
                                    // does this type need initialization?
944
0
                                    if (var.type()->needInitialization == Type::NeedInitialization::True && !var.hasDefault() && !var.isStatic())
945
0
                                        needInitialization = true;
946
0
                                    else if (var.type()->needInitialization == Type::NeedInitialization::Unknown) {
947
0
                                        if (!(var.valueType() && var.valueType()->type == ValueType::CONTAINER))
948
0
                                            unknown = true;
949
0
                                    }
950
0
                                }
951
0
                            } else if (!var.hasDefault() && !var.isStatic()) {
952
0
                                needInitialization = true;
953
0
                                break;
954
0
                            }
955
0
                        }
956
957
0
                        if (needInitialization)
958
0
                            scope.definedType->needInitialization = Type::NeedInitialization::True;
959
0
                        else if (!unknown)
960
0
                            scope.definedType->needInitialization = Type::NeedInitialization::False;
961
0
                        else {
962
0
                            if (scope.definedType->needInitialization == Type::NeedInitialization::Unknown)
963
0
                                unknowns++;
964
0
                        }
965
0
                    }
966
0
                } else if (scope.type == Scope::eUnion && scope.definedType->needInitialization == Type::NeedInitialization::Unknown)
967
0
                    scope.definedType->needInitialization = Type::NeedInitialization::True;
968
0
            }
969
970
1.36k
            retry++;
971
1.36k
        } while (unknowns && retry < 100);
972
973
        // this shouldn't happen so output a debug warning
974
1.36k
        if (retry == 100 && mSettings.debugwarnings) {
975
0
            for (const Scope& scope : scopeList) {
976
0
                if (scope.isClassOrStruct() && scope.definedType->needInitialization == Type::NeedInitialization::Unknown)
977
0
                    debugMessage(scope.classDef, "debug", "SymbolDatabase couldn't resolve all user defined types.");
978
0
            }
979
0
        }
980
1.36k
    }
981
1.36k
}
982
983
void SymbolDatabase::createSymbolDatabaseVariableSymbolTable()
984
1.36k
{
985
    // create variable symbol table
986
1.36k
    mVariableList.resize(mTokenizer.varIdCount() + 1);
987
1.36k
    std::fill_n(mVariableList.begin(), mVariableList.size(), nullptr);
988
989
    // check all scopes for variables
990
4.94k
    for (Scope& scope : scopeList) {
991
        // add all variables
992
6.80k
        for (Variable& var: scope.varlist) {
993
6.80k
            const unsigned int varId = var.declarationId();
994
6.80k
            if (varId)
995
6.80k
                mVariableList[varId] = &var;
996
            // fix up variables without type
997
6.80k
            if (!var.type() && !var.typeStartToken()->isStandardType()) {
998
0
                const Type *type = findType(var.typeStartToken(), &scope);
999
0
                if (type)
1000
0
                    var.type(type);
1001
0
            }
1002
6.80k
        }
1003
1004
        // add all function parameters
1005
4.94k
        for (Function& func : scope.functionList) {
1006
1.73k
            for (Variable& arg: func.argumentList) {
1007
                // check for named parameters
1008
0
                if (arg.nameToken() && arg.declarationId()) {
1009
0
                    const unsigned int declarationId = arg.declarationId();
1010
0
                    mVariableList[declarationId] = &arg;
1011
                    // fix up parameters without type
1012
0
                    if (!arg.type() && !arg.typeStartToken()->isStandardType()) {
1013
0
                        const Type *type = findTypeInNested(arg.typeStartToken(), &scope);
1014
0
                        if (type)
1015
0
                            arg.type(type);
1016
0
                    }
1017
0
                }
1018
0
            }
1019
1.73k
        }
1020
4.94k
    }
1021
1022
    // fill in missing variables if possible
1023
1.73k
    for (const Scope *func: functionScopes) {
1024
35.9k
        for (const Token *tok = func->bodyStart->next(); tok && tok != func->bodyEnd; tok = tok->next()) {
1025
            // check for member variable
1026
34.1k
            if (!Token::Match(tok, "%var% .|["))
1027
34.1k
                continue;
1028
0
            const Token* tokDot = tok->next();
1029
0
            while (Token::simpleMatch(tokDot, "["))
1030
0
                tokDot = tokDot->link()->next();
1031
0
            if (!Token::Match(tokDot, ". %var%"))
1032
0
                continue;
1033
0
            const Token *member = tokDot->next();
1034
0
            if (mVariableList[member->varId()] == nullptr) {
1035
0
                const Variable *var1 = mVariableList[tok->varId()];
1036
0
                if (var1 && var1->typeScope()) {
1037
0
                    const Variable* memberVar = var1->typeScope()->getVariable(member->str());
1038
0
                    if (memberVar) {
1039
                        // add this variable to the look up table
1040
0
                        mVariableList[member->varId()] = memberVar;
1041
0
                    }
1042
0
                }
1043
0
            }
1044
0
        }
1045
1.73k
    }
1046
1.36k
}
1047
1048
void SymbolDatabase::createSymbolDatabaseSetScopePointers()
1049
1.36k
{
1050
4.94k
    auto setScopePointers = [](const Scope &scope, const Token *bodyStart, const Token *bodyEnd) {
1051
4.94k
        assert(bodyStart);
1052
0
        assert(bodyEnd);
1053
1054
0
        const_cast<Token *>(bodyEnd)->scope(&scope);
1055
1056
93.5k
        for (Token* tok = const_cast<Token *>(bodyStart); tok != bodyEnd; tok = tok->next()) {
1057
90.4k
            if (bodyStart != bodyEnd && tok->str() == "{") {
1058
7.16k
                bool isEndOfScope = false;
1059
7.16k
                for (Scope* innerScope: scope.nestedList) {
1060
6.54k
                    const auto &list = innerScope->bodyStartList;
1061
6.54k
                    if (std::find(list.cbegin(), list.cend(), tok) != list.cend()) {     // Is begin of inner scope
1062
3.58k
                        tok = tok->link();
1063
3.58k
                        if (tok->next() == bodyEnd || !tok->next()) {
1064
1.78k
                            isEndOfScope = true;
1065
1.78k
                            break;
1066
1.78k
                        }
1067
1.80k
                        tok = tok->next();
1068
1.80k
                        break;
1069
3.58k
                    }
1070
6.54k
                }
1071
7.16k
                if (isEndOfScope)
1072
1.78k
                    break;
1073
7.16k
            }
1074
88.6k
            tok->scope(&scope);
1075
88.6k
        }
1076
4.94k
    };
1077
1078
    // Set scope pointers
1079
4.94k
    for (const Scope& scope: scopeList) {
1080
4.94k
        if (scope.type == Scope::eGlobal)
1081
1.36k
            setScopePointers(scope, mTokenizer.list.front(), mTokenizer.list.back());
1082
3.58k
        else {
1083
3.58k
            for (const Token *bodyStart: scope.bodyStartList)
1084
3.58k
                setScopePointers(scope, bodyStart, bodyStart->link());
1085
3.58k
        }
1086
4.94k
    }
1087
1.36k
}
1088
1089
void SymbolDatabase::createSymbolDatabaseSetFunctionPointers(bool firstPass)
1090
6.80k
{
1091
6.80k
    if (firstPass) {
1092
        // Set function definition and declaration pointers
1093
4.94k
        for (const Scope& scope: scopeList) {
1094
4.94k
            for (const Function& func: scope.functionList) {
1095
1.73k
                if (func.tokenDef)
1096
1.73k
                    const_cast<Token *>(func.tokenDef)->function(&func);
1097
1098
1.73k
                if (func.token)
1099
1.73k
                    const_cast<Token *>(func.token)->function(&func);
1100
1.73k
            }
1101
4.94k
        }
1102
1.36k
    }
1103
1104
    // Set function call pointers
1105
461k
    for (const Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
1106
454k
        if (tok->isName() && !tok->function() && tok->varId() == 0 && Token::Match(tok, "%name% [{(,)>;]") && !isReservedName(tok->str())) {
1107
5.46k
            if (tok->next()->str() == ">" && !tok->next()->link())
1108
455
                continue;
1109
1110
5.01k
            bool isTemplateArg = false;
1111
5.01k
            if (!Token::Match(tok->next(), "(|{")) {
1112
3.27k
                const Token *start = tok;
1113
3.27k
                while (Token::Match(start->tokAt(-2), "%name% ::"))
1114
0
                    start = start->tokAt(-2);
1115
3.27k
                if (!Token::Match(start->previous(), "[(,<=]") && !Token::simpleMatch(start->previous(), "::") && !Token::Match(start->tokAt(-2), "[(,<=] &") && !Token::Match(start, "%name% ;"))
1116
800
                    continue;
1117
2.47k
                isTemplateArg = Token::simpleMatch(start->previous(), "<") || Token::simpleMatch(start->tokAt(-2), "<");
1118
2.47k
            }
1119
1120
4.21k
            const Function *function = findFunction(tok);
1121
4.21k
            if (!function || (isTemplateArg && function->isConstructor()))
1122
2.47k
                continue;
1123
1124
1.73k
            const_cast<Token *>(tok)->function(function);
1125
1126
1.73k
            if (tok->next()->str() != "(")
1127
0
                const_cast<Function *>(function)->functionPointerUsage = tok;
1128
1.73k
        }
1129
454k
    }
1130
1131
    // Set C++ 11 delegate constructor function call pointers
1132
24.7k
    for (const Scope& scope: scopeList) {
1133
24.7k
        for (const Function& func: scope.functionList) {
1134
            // look for initializer list
1135
8.69k
            if (func.isConstructor() && func.functionScope && func.functionScope->functionOf && func.arg) {
1136
0
                const Token * tok = func.arg->link()->next();
1137
0
                if (tok->str() == "noexcept") {
1138
0
                    const Token * closingParenTok = tok->linkAt(1);
1139
0
                    if (!closingParenTok || !closingParenTok->next()) {
1140
0
                        continue;
1141
0
                    }
1142
0
                    tok = closingParenTok->next();
1143
0
                }
1144
0
                if (tok->str() != ":") {
1145
0
                    continue;
1146
0
                }
1147
0
                tok = tok->next();
1148
0
                while (tok && tok != func.functionScope->bodyStart) {
1149
0
                    if (Token::Match(tok, "%name% {|(")) {
1150
0
                        if (tok->str() == func.tokenDef->str()) {
1151
0
                            const Function *function = func.functionScope->functionOf->findFunction(tok);
1152
0
                            if (function)
1153
0
                                const_cast<Token *>(tok)->function(function);
1154
0
                            break;
1155
0
                        }
1156
0
                        tok = tok->linkAt(1);
1157
0
                    }
1158
0
                    tok = tok->next();
1159
0
                }
1160
0
            }
1161
8.69k
        }
1162
24.7k
    }
1163
6.80k
}
1164
1165
void SymbolDatabase::createSymbolDatabaseSetTypePointers()
1166
1.36k
{
1167
1.36k
    std::unordered_set<std::string> typenames;
1168
1.36k
    for (const Type &t : typeList) {
1169
0
        typenames.insert(t.name());
1170
0
    }
1171
1172
    // Set type pointers
1173
92.2k
    for (const Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
1174
90.8k
        if (!tok->isName() || tok->varId() || tok->function() || tok->type() || tok->enumerator())
1175
76.7k
            continue;
1176
1177
14.1k
        if (typenames.find(tok->str()) == typenames.end())
1178
14.1k
            continue;
1179
1180
0
        const Type *type = findVariableType(tok->scope(), tok);
1181
0
        if (type)
1182
0
            const_cast<Token *>(tok)->type(type); // TODO: avoid const_cast
1183
0
    }
1184
1.36k
}
1185
1186
void SymbolDatabase::createSymbolDatabaseSetSmartPointerType()
1187
1.36k
{
1188
4.94k
    for (Scope &scope: scopeList) {
1189
6.80k
        for (Variable &var: scope.varlist) {
1190
6.80k
            if (var.valueType() && var.valueType()->smartPointerTypeToken && !var.valueType()->smartPointerType) {
1191
0
                ValueType vt(*var.valueType());
1192
0
                vt.smartPointerType = vt.smartPointerTypeToken->type();
1193
0
                var.setValueType(vt);
1194
0
            }
1195
6.80k
        }
1196
4.94k
    }
1197
1.36k
}
1198
1199
void SymbolDatabase::fixVarId(VarIdMap & varIds, const Token * vartok, Token * membertok, const Variable * membervar)
1200
0
{
1201
0
    VarIdMap::iterator varId = varIds.find(vartok->varId());
1202
0
    if (varId == varIds.end()) {
1203
0
        MemberIdMap memberId;
1204
0
        if (membertok->varId() == 0) {
1205
0
            memberId[membervar->nameToken()->varId()] = const_cast<Tokenizer &>(mTokenizer).newVarId();
1206
0
            mVariableList.push_back(membervar);
1207
0
        } else
1208
0
            mVariableList[membertok->varId()] = membervar;
1209
0
        varIds.insert(std::make_pair(vartok->varId(), memberId));
1210
0
        varId = varIds.find(vartok->varId());
1211
0
    }
1212
0
    MemberIdMap::iterator memberId = varId->second.find(membervar->nameToken()->varId());
1213
0
    if (memberId == varId->second.end()) {
1214
0
        if (membertok->varId() == 0) {
1215
0
            varId->second.insert(std::make_pair(membervar->nameToken()->varId(), const_cast<Tokenizer &>(mTokenizer).newVarId()));
1216
0
            mVariableList.push_back(membervar);
1217
0
            memberId = varId->second.find(membervar->nameToken()->varId());
1218
0
        } else
1219
0
            mVariableList[membertok->varId()] = membervar;
1220
0
    }
1221
0
    if (membertok->varId() == 0)
1222
0
        membertok->varId(memberId->second);
1223
0
}
1224
1225
static bool isContainerYieldElement(Library::Container::Yield yield);
1226
1227
void SymbolDatabase::createSymbolDatabaseSetVariablePointers()
1228
6.80k
{
1229
6.80k
    VarIdMap varIds;
1230
1231
6.80k
    auto setMemberVar = [&](const Variable* membervar, Token* membertok, const Token* vartok) -> void {
1232
0
        if (membervar) {
1233
0
            membertok->variable(membervar);
1234
0
            if (vartok && (membertok->varId() == 0 || mVariableList[membertok->varId()] == nullptr))
1235
0
                fixVarId(varIds, vartok, membertok, membervar);
1236
0
        }
1237
0
    };
1238
1239
    // Set variable pointers
1240
461k
    for (Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
1241
454k
        if (!tok->isName() || tok->isKeyword() || tok->isStandardType())
1242
337k
            continue;
1243
117k
        if (tok->varId())
1244
99.1k
            const_cast<Token*>(tok)->variable(getVariableFromVarId(tok->varId()));
1245
1246
        // Set Token::variable pointer for array member variable
1247
        // Since it doesn't point at a fixed location it doesn't have varid
1248
117k
        const bool isVar = tok->variable() && (tok->variable()->typeScope() || tok->variable()->isSmartPointer() ||
1249
99.1k
                                               (tok->valueType() && (tok->valueType()->type == ValueType::CONTAINER || tok->valueType()->type == ValueType::ITERATOR)));
1250
117k
        const bool isArrayAccess = isVar && Token::simpleMatch(tok->astParent(), "[");
1251
117k
        const bool isDirectAccess = isVar && !isArrayAccess && Token::simpleMatch(tok->astParent(), ".");
1252
117k
        const bool isDerefAccess = isVar && !isDirectAccess && Token::simpleMatch(tok->astParent(), "*") && Token::simpleMatch(tok->astParent()->astParent(), ".");
1253
117k
        if (isVar && (isArrayAccess || isDirectAccess || isDerefAccess)) {
1254
0
            Token* membertok{};
1255
0
            if (isArrayAccess) {
1256
0
                membertok = const_cast<Token*>(tok->astParent());
1257
0
                while (Token::simpleMatch(membertok, "["))
1258
0
                    membertok = membertok->astParent();
1259
0
                if (membertok)
1260
0
                    membertok = membertok->astOperand2();
1261
0
            }
1262
0
            else if (isDirectAccess) {
1263
0
                membertok = const_cast<Token*>(tok->astParent()->astOperand2());
1264
0
                if (membertok == tok) {
1265
0
                    Token* gptok = const_cast<Token*>(tok->astParent()->astParent());
1266
0
                    if (Token::simpleMatch(gptok, ".")) // chained access
1267
0
                        membertok = gptok->astOperand2();
1268
0
                    else if (Token::simpleMatch(gptok, "[") && Token::simpleMatch(gptok->astParent(), "."))
1269
0
                        membertok = gptok->astParent()->astOperand2();
1270
0
                }
1271
0
            }
1272
0
            else { // isDerefAccess
1273
0
                membertok = const_cast<Token*>(tok->astParent());
1274
0
                while (Token::simpleMatch(membertok, "*"))
1275
0
                    membertok = membertok->astParent();
1276
0
                if (membertok)
1277
0
                    membertok = membertok->astOperand2();
1278
0
            }
1279
1280
0
            if (membertok && membertok != tok) {
1281
0
                const Variable *var = tok->variable();
1282
0
                if (var->typeScope()) {
1283
0
                    const Variable *membervar = var->typeScope()->getVariable(membertok->str());
1284
0
                    setMemberVar(membervar, membertok, tok);
1285
0
                } else if (const ::Type *type = var->smartPointerType()) {
1286
0
                    const Scope *classScope = type->classScope;
1287
0
                    const Variable *membervar = classScope ? classScope->getVariable(membertok->str()) : nullptr;
1288
0
                    setMemberVar(membervar, membertok, tok);
1289
0
                } else if (tok->valueType() && tok->valueType()->type == ValueType::CONTAINER) {
1290
0
                    if (const Token* ctt = tok->valueType()->containerTypeToken) {
1291
0
                        while (ctt && ctt->isKeyword())
1292
0
                            ctt = ctt->next();
1293
0
                        const Type* ct = findTypeInNested(ctt, tok->scope());
1294
0
                        if (ct && ct->classScope && ct->classScope->definedType) {
1295
0
                            const Variable *membervar = ct->classScope->getVariable(membertok->str());
1296
0
                            setMemberVar(membervar, membertok, tok);
1297
0
                        }
1298
0
                    }
1299
0
                } else if (const Type* iterType = var->iteratorType()) {
1300
0
                    if (iterType->classScope && iterType->classScope->definedType) {
1301
0
                        const Variable *membervar = iterType->classScope->getVariable(membertok->str());
1302
0
                        setMemberVar(membervar, membertok, tok);
1303
0
                    }
1304
0
                }
1305
0
            }
1306
0
        }
1307
1308
        // check for function returning record type
1309
        // func(...).var
1310
        // func(...)[...].var
1311
117k
        else if (tok->function() && tok->next()->str() == "(" &&
1312
117k
                 (Token::Match(tok->next()->link(), ") . %name% !!(") ||
1313
6.95k
                  (Token::Match(tok->next()->link(), ") [") && Token::Match(tok->next()->link()->next()->link(), "] . %name% !!(")))) {
1314
0
            const Type *type = tok->function()->retType;
1315
0
            Token* membertok;
1316
0
            if (tok->next()->link()->next()->str() == ".")
1317
0
                membertok = tok->next()->link()->next()->next();
1318
0
            else
1319
0
                membertok = tok->next()->link()->next()->link()->next()->next();
1320
0
            if (type) {
1321
0
                const Variable *membervar = membertok->variable();
1322
0
                if (!membervar) {
1323
0
                    if (type->classScope) {
1324
0
                        membervar = type->classScope->getVariable(membertok->str());
1325
0
                        setMemberVar(membervar, membertok, tok->function()->retDef);
1326
0
                    }
1327
0
                }
1328
0
            } else if (mSettings.library.detectSmartPointer(tok->function()->retDef)) {
1329
0
                if (const Token* templateArg = Token::findsimplematch(tok->function()->retDef, "<")) {
1330
0
                    if (const Type* spType = findTypeInNested(templateArg->next(), tok->scope())) {
1331
0
                        if (spType->classScope) {
1332
0
                            const Variable* membervar = spType->classScope->getVariable(membertok->str());
1333
0
                            setMemberVar(membervar, membertok, tok->function()->retDef);
1334
0
                        }
1335
0
                    }
1336
0
                }
1337
0
            }
1338
0
        }
1339
117k
        else if (Token::simpleMatch(tok->astParent(), ".") && tok->next()->str() == "(" &&
1340
117k
                 astIsContainer(tok->astParent()->astOperand1()) && Token::Match(tok->next()->link(), ") . %name% !!(")) {
1341
0
            const ValueType* vt = tok->astParent()->astOperand1()->valueType();
1342
0
            const Library::Container* cont = vt->container;
1343
0
            auto it = cont->functions.find(tok->str());
1344
0
            if (it != cont->functions.end() && isContainerYieldElement(it->second.yield) && vt->containerTypeToken) {
1345
0
                Token* memberTok = tok->next()->link()->tokAt(2);
1346
0
                const Scope* scope = vt->containerTypeToken->scope();
1347
0
                const Type* contType{};
1348
0
                const std::string& typeStr = vt->containerTypeToken->str(); // TODO: handle complex type expressions
1349
0
                while (scope && !contType) {
1350
0
                    contType = scope->findType(typeStr); // find the type stored in the container
1351
0
                    scope = scope->nestedIn;
1352
0
                }
1353
0
                if (contType && contType->classScope) {
1354
0
                    const Variable* membervar = contType->classScope->getVariable(memberTok->str());
1355
0
                    setMemberVar(membervar, memberTok, vt->containerTypeToken);
1356
0
                }
1357
0
            }
1358
0
        }
1359
117k
    }
1360
6.80k
}
1361
1362
void SymbolDatabase::createSymbolDatabaseEnums()
1363
1.36k
{
1364
    // fill in enumerators in enum
1365
4.94k
    for (const Scope &scope : scopeList) {
1366
4.94k
        if (scope.type != Scope::eEnum)
1367
4.94k
            continue;
1368
1369
        // add enumerators to enumerator tokens
1370
0
        for (const Enumerator & i : scope.enumeratorList)
1371
0
            const_cast<Token *>(i.name)->enumerator(&i);
1372
0
    }
1373
1374
1.36k
    std::set<std::string> tokensThatAreNotEnumeratorValues;
1375
1376
4.94k
    for (const Scope &scope : scopeList) {
1377
4.94k
        if (scope.type != Scope::eEnum)
1378
4.94k
            continue;
1379
1380
0
        for (const Enumerator & enumerator : scope.enumeratorList) {
1381
            // look for initialization tokens that can be converted to enumerators and convert them
1382
0
            if (enumerator.start) {
1383
0
                if (!enumerator.end)
1384
0
                    mTokenizer.syntaxError(enumerator.start);
1385
0
                for (const Token * tok3 = enumerator.start; tok3 && tok3 != enumerator.end->next(); tok3 = tok3->next()) {
1386
0
                    if (tok3->tokType() == Token::eName) {
1387
0
                        const Enumerator * e = findEnumerator(tok3, tokensThatAreNotEnumeratorValues);
1388
0
                        if (e)
1389
0
                            const_cast<Token *>(tok3)->enumerator(e);
1390
0
                    }
1391
0
                }
1392
0
            }
1393
0
        }
1394
0
    }
1395
1396
    // find enumerators
1397
92.2k
    for (const Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
1398
90.8k
        const bool isVariable = (tok->tokType() == Token::eVariable && !tok->variable());
1399
90.8k
        if (tok->tokType() != Token::eName && !isVariable)
1400
82.2k
            continue;
1401
8.67k
        const Enumerator * enumerator = findEnumerator(tok, tokensThatAreNotEnumeratorValues);
1402
8.67k
        if (enumerator) {
1403
0
            if (isVariable)
1404
0
                const_cast<Token*>(tok)->varId(0);
1405
0
            const_cast<Token*>(tok)->enumerator(enumerator);
1406
0
        }
1407
8.67k
    }
1408
1.36k
}
1409
1410
void SymbolDatabase::createSymbolDatabaseIncompleteVars()
1411
1.36k
{
1412
    // TODO: replace with Keywords::getX()
1413
1.36k
    static const std::unordered_set<std::string> cpp20keywords = {
1414
1.36k
        "alignas",
1415
1.36k
        "alignof",
1416
1.36k
        "axiom",
1417
1.36k
        "co_await",
1418
1.36k
        "co_return",
1419
1.36k
        "co_yield",
1420
1.36k
        "concept",
1421
1.36k
        "synchronized",
1422
1.36k
        "consteval",
1423
1.36k
        "reflexpr",
1424
1.36k
        "requires",
1425
1.36k
    };
1426
1.36k
    static const std::unordered_set<std::string> cppkeywords = {
1427
1.36k
        "asm",
1428
1.36k
        "auto",
1429
1.36k
        "catch",
1430
1.36k
        "char",
1431
1.36k
        "class",
1432
1.36k
        "const",
1433
1.36k
        "constexpr",
1434
1.36k
        "decltype",
1435
1.36k
        "default",
1436
1.36k
        "do",
1437
1.36k
        "enum",
1438
1.36k
        "explicit",
1439
1.36k
        "export",
1440
1.36k
        "extern",
1441
1.36k
        "final",
1442
1.36k
        "friend",
1443
1.36k
        "inline",
1444
1.36k
        "mutable",
1445
1.36k
        "namespace",
1446
1.36k
        "new",
1447
1.36k
        "noexcept",
1448
1.36k
        "nullptr",
1449
1.36k
        "override",
1450
1.36k
        "private",
1451
1.36k
        "protected",
1452
1.36k
        "public",
1453
1.36k
        "register",
1454
1.36k
        "sizeof",
1455
1.36k
        "static",
1456
1.36k
        "static_assert",
1457
1.36k
        "struct",
1458
1.36k
        "template",
1459
1.36k
        "this",
1460
1.36k
        "thread_local",
1461
1.36k
        "throw",
1462
1.36k
        "try",
1463
1.36k
        "typedef",
1464
1.36k
        "typeid",
1465
1.36k
        "typename",
1466
1.36k
        "union",
1467
1.36k
        "using",
1468
1.36k
        "virtual",
1469
1.36k
        "void",
1470
1.36k
        "volatile",
1471
1.36k
        "NULL",
1472
1.36k
    };
1473
92.2k
    for (const Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
1474
90.8k
        const Scope * scope = tok->scope();
1475
90.8k
        if (!scope)
1476
0
            continue;
1477
90.8k
        if (!scope->isExecutable())
1478
54.5k
            continue;
1479
36.2k
        if (tok->varId() != 0)
1480
6.22k
            continue;
1481
30.0k
        if (tok->isCast() && !isCPPCast(tok) && tok->link() && tok->str() == "(") {
1482
0
            tok = tok->link();
1483
0
            continue;
1484
0
        }
1485
30.0k
        if (Token::Match(tok, "catch|typeid (")) {
1486
0
            tok = tok->linkAt(1);
1487
0
            continue;
1488
0
        }
1489
30.0k
        if (!(tok->isNameOnly() || tok->isKeyword()))
1490
24.4k
            continue;
1491
5.62k
        if (tok->type())
1492
0
            continue;
1493
5.62k
        if (Token::Match(tok->next(), "::|.|(|{|:|%var%"))
1494
2.06k
            continue;
1495
3.56k
        if (Token::Match(tok->next(), "&|&&|* )|,|%var%|const"))
1496
35
            continue;
1497
        // Very likely a typelist
1498
3.52k
        if (Token::Match(tok->tokAt(-2), "%type% ,") || Token::Match(tok->next(), ", %type%"))
1499
0
            continue;
1500
        // Inside template brackets
1501
3.52k
        if (Token::simpleMatch(tok->next(), "<") && tok->linkAt(1)) {
1502
4
            tok = tok->linkAt(1);
1503
4
            continue;
1504
4
        }
1505
3.52k
        if (tok->isKeyword())
1506
1.69k
            continue;
1507
        // Skip goto labels
1508
1.82k
        if (Token::simpleMatch(tok->previous(), "goto"))
1509
0
            continue;
1510
        // TODO: handle all C/C++ standards
1511
1.82k
        if (cppkeywords.count(tok->str()) > 0)
1512
0
            continue;
1513
1.82k
        if (mSettings.standards.cpp >= Standards::CPP20 && cpp20keywords.count(tok->str()) > 0)
1514
0
            continue;
1515
1.82k
        std::string fstr = tok->str();
1516
1.82k
        const Token* ftok = tok->previous();
1517
1.82k
        while (Token::simpleMatch(ftok, "::")) {
1518
0
            if (!Token::Match(ftok->previous(), "%name%"))
1519
0
                break;
1520
0
            fstr.insert(0, ftok->previous()->str() + "::");
1521
0
            ftok = ftok->tokAt(-2);
1522
0
        }
1523
1.82k
        if (mSettings.library.functions.find(fstr) != mSettings.library.functions.end())
1524
0
            continue;
1525
1.82k
        const_cast<Token *>(tok)->isIncompleteVar(true); // TODO: avoid const_cast
1526
1.82k
    }
1527
1.36k
}
1528
1529
void SymbolDatabase::createSymbolDatabaseEscapeFunctions()
1530
1.36k
{
1531
4.94k
    for (const Scope& scope : scopeList) {
1532
4.94k
        if (scope.type != Scope::eFunction)
1533
3.20k
            continue;
1534
1.73k
        Function * function = scope.function;
1535
1.73k
        if (!function)
1536
0
            continue;
1537
1.73k
        if (Token::findsimplematch(scope.bodyStart, "return", scope.bodyEnd))
1538
1.73k
            continue;
1539
0
        function->isEscapeFunction(isReturnScope(scope.bodyEnd, &mSettings.library, nullptr, true));
1540
0
    }
1541
1.36k
}
1542
1543
static bool isExpression(const Token* tok)
1544
31.5k
{
1545
31.5k
    if (!tok)
1546
0
        return false;
1547
31.5k
    if (Token::simpleMatch(tok, "{") && tok->scope() && tok->scope()->bodyStart != tok &&
1548
31.5k
        (tok->astOperand1() || tok->astOperand2()))
1549
0
        return true;
1550
31.5k
    if (!Token::Match(tok, "(|.|[|::|?|:|++|--|%cop%|%assign%"))
1551
19.4k
        return false;
1552
12.0k
    if (Token::Match(tok, "*|&|&&")) {
1553
3.18k
        const Token* vartok = findAstNode(tok, [&](const Token* tok2) {
1554
3.18k
            const Variable* var = tok2->variable();
1555
3.18k
            if (!var)
1556
2.25k
                return false;
1557
938
            return var->nameToken() == tok2;
1558
3.18k
        });
1559
620
        if (vartok)
1560
0
            return false;
1561
620
    }
1562
12.0k
    return true;
1563
12.0k
}
1564
1565
static std::string getIncompleteNameID(const Token* tok)
1566
1.76k
{
1567
1.76k
    std::string result = tok->str() + "@";
1568
1.76k
    while (Token::Match(tok->astParent(), ".|::"))
1569
0
        tok = tok->astParent();
1570
1.76k
    return result + tok->expressionString();
1571
1.76k
}
1572
1573
void SymbolDatabase::createSymbolDatabaseExprIds()
1574
1.36k
{
1575
1.36k
    nonneg int base = 0;
1576
    // Find highest varId
1577
8.16k
    for (const Variable *var : mVariableList) {
1578
8.16k
        if (!var)
1579
1.36k
            continue;
1580
6.80k
        base = std::max<MathLib::bigint>(base, var->declarationId());
1581
6.80k
    }
1582
1.36k
    nonneg int id = base + 1;
1583
    // Find incomplete vars that are used in constant context
1584
1.36k
    std::unordered_map<std::string, nonneg int> unknownConstantIds;
1585
1.36k
    const Token* inConstExpr = nullptr;
1586
92.2k
    for (const Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
1587
90.8k
        if (Token::Match(tok, "decltype|sizeof|typeof (") && tok->next()->link()) {
1588
0
            tok = tok->next()->link()->previous();
1589
90.8k
        } else if (tok == inConstExpr) {
1590
4
            inConstExpr = nullptr;
1591
90.8k
        } else if (inConstExpr) {
1592
11
            if (!tok->isIncompleteVar())
1593
11
                continue;
1594
0
            if (!isExpression(tok->astParent()))
1595
0
                continue;
1596
0
            const std::string& name = getIncompleteNameID(tok);
1597
0
            if (unknownConstantIds.count(name) > 0)
1598
0
                continue;
1599
0
            unknownConstantIds[name] = id++;
1600
90.8k
        } else if (tok->link() && tok->str() == "<") {
1601
4
            inConstExpr = tok->link();
1602
90.8k
        } else if (Token::Match(tok, "%var% [") && tok->variable() && tok->variable()->nameToken() == tok) {
1603
0
            inConstExpr = tok->next()->link();
1604
0
        }
1605
90.8k
    }
1606
1607
1.36k
    auto exprScopes = functionScopes; // functions + global lambdas
1608
1.73k
    std::copy_if(scopeList.front().nestedList.begin(), scopeList.front().nestedList.end(), std::back_inserter(exprScopes), [](const Scope* scope) {
1609
1.73k
        return scope && scope->type == Scope::eLambda;
1610
1.73k
    });
1611
1612
1.73k
    for (const Scope * scope : exprScopes) {
1613
1.73k
        nonneg int thisId = 0;
1614
1.73k
        std::unordered_map<std::string, std::vector<Token*>> exprs;
1615
1616
1.73k
        std::unordered_map<std::string, nonneg int> unknownIds;
1617
        // Assign IDs to incomplete vars which are part of an expression
1618
        // Such variables should be assumed global
1619
37.6k
        for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
1620
35.9k
            if (!tok->isIncompleteVar())
1621
34.0k
                continue;
1622
1.82k
            if (!isExpression(tok->astParent()))
1623
63
                continue;
1624
1.76k
            const std::string& name = getIncompleteNameID(tok);
1625
1.76k
            nonneg int sid = 0;
1626
1.76k
            if (unknownConstantIds.count(name) > 0) {
1627
0
                sid = unknownConstantIds.at(name);
1628
0
                tok->isIncompleteConstant(true);
1629
1.76k
            } else if (unknownIds.count(name) == 0) {
1630
996
                sid = id++;
1631
996
                unknownIds[name] = sid;
1632
996
            } else {
1633
767
                sid = unknownIds.at(name);
1634
767
            }
1635
1.76k
            assert(sid > 0);
1636
0
            tok->exprId(sid);
1637
1.76k
        }
1638
1639
        // Assign IDs
1640
37.6k
        for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
1641
35.9k
            if (tok->varId() > 0) {
1642
6.22k
                tok->exprId(tok->varId());
1643
29.6k
            } else if (isExpression(tok)) {
1644
10.3k
                exprs[tok->str()].push_back(tok);
1645
10.3k
                tok->exprId(id++);
1646
1647
10.3k
                if (id == std::numeric_limits<nonneg int>::max() / 4) {
1648
0
                    throw InternalError(nullptr, "Ran out of expression ids.", InternalError::INTERNAL);
1649
0
                }
1650
19.3k
            } else if (isCPP() && Token::simpleMatch(tok, "this")) {
1651
0
                if (thisId == 0)
1652
0
                    thisId = id++;
1653
0
                tok->exprId(thisId);
1654
0
            }
1655
35.9k
        }
1656
1657
        // Apply CSE
1658
6.94k
        for (const auto& p:exprs) {
1659
6.94k
            const std::vector<Token*>& tokens = p.second;
1660
6.94k
            const std::size_t N = tokens.size();
1661
17.2k
            for (std::size_t i = 0; i < N; ++i) {
1662
10.3k
                Token* const tok1 = tokens[i];
1663
16.1k
                for (std::size_t j = i + 1; j < N; ++j) {
1664
5.81k
                    Token* const tok2 = tokens[j];
1665
5.81k
                    if (tok1->exprId() == tok2->exprId())
1666
15
                        continue;
1667
5.80k
                    if (!isSameExpression(isCPP(), true, tok1, tok2, mSettings.library, false, false))
1668
5.74k
                        continue;
1669
53
                    nonneg int const cid = std::min(tok1->exprId(), tok2->exprId());
1670
53
                    tok1->exprId(cid);
1671
53
                    tok2->exprId(cid);
1672
53
                }
1673
10.3k
            }
1674
6.94k
        }
1675
        // Mark expressions that are unique
1676
1.73k
        std::unordered_map<nonneg int, Token*> exprMap;
1677
37.6k
        for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
1678
35.9k
            if (tok->exprId() == 0)
1679
17.6k
                continue;
1680
18.3k
            auto p = exprMap.emplace(tok->exprId(), tok);
1681
            // Already exists so set it to null
1682
18.3k
            if (!p.second) {
1683
3.69k
                p.first->second = nullptr;
1684
3.69k
            }
1685
18.3k
        }
1686
14.6k
        for (const auto& p : exprMap) {
1687
14.6k
            if (!p.second)
1688
2.06k
                continue;
1689
12.5k
            if (p.second->variable()) {
1690
1.73k
                const Variable* var = p.second->variable();
1691
1.73k
                if (var->nameToken() != p.second)
1692
1.73k
                    continue;
1693
1.73k
            }
1694
10.8k
            p.second->setUniqueExprId();
1695
10.8k
        }
1696
1.73k
    }
1697
1.36k
}
1698
1699
void SymbolDatabase::setArrayDimensionsUsingValueFlow()
1700
1.36k
{
1701
    // set all unknown array dimensions
1702
8.16k
    for (const Variable *var : mVariableList) {
1703
        // check each array variable
1704
8.16k
        if (!var || !var->isArray())
1705
8.16k
            continue;
1706
        // check each array dimension
1707
0
        for (const Dimension &const_dimension : var->dimensions()) {
1708
0
            Dimension &dimension = const_cast<Dimension &>(const_dimension);
1709
0
            if (dimension.num != 0 || !dimension.tok)
1710
0
                continue;
1711
1712
0
            if (Token::Match(dimension.tok->previous(), "[<,]")) {
1713
0
                if (dimension.known)
1714
0
                    continue;
1715
0
                if (!Token::Match(dimension.tok->previous(), "[<,]"))
1716
0
                    continue;
1717
1718
                // In template arguments, there might not be AST
1719
                // Determine size by using the "raw tokens"
1720
0
                TokenList tokenList(&mSettings);
1721
0
                tokenList.addtoken(";", 0, 0, 0, false);
1722
0
                bool fail = false;
1723
0
                for (const Token *tok = dimension.tok; tok && !Token::Match(tok, "[,>]"); tok = tok->next()) {
1724
0
                    if (!tok->isName())
1725
0
                        tokenList.addtoken(tok->str(), 0, 0, 0, false);
1726
1727
0
                    else if (tok->hasKnownIntValue())
1728
0
                        tokenList.addtoken(std::to_string(tok->getKnownIntValue()), 0, 0, 0, false);
1729
1730
0
                    else {
1731
0
                        fail = true;
1732
0
                        break;
1733
0
                    }
1734
0
                }
1735
1736
0
                if (fail)
1737
0
                    continue;
1738
1739
0
                tokenList.addtoken(";", 0, 0, 0, false);
1740
1741
0
                for (Token *tok = tokenList.front(); tok;) {
1742
0
                    if (TemplateSimplifier::simplifyNumericCalculations(tok, false))
1743
0
                        tok = tokenList.front();
1744
0
                    else
1745
0
                        tok = tok->next();
1746
0
                }
1747
1748
0
                if (Token::Match(tokenList.front(), "; %num% ;")) {
1749
0
                    dimension.known = true;
1750
0
                    dimension.num = MathLib::toLongNumber(tokenList.front()->next()->str());
1751
0
                }
1752
1753
0
                continue;
1754
0
            }
1755
1756
            // Normal array [..dimension..]
1757
0
            dimension.known = false;
1758
1759
            // check for a single token dimension
1760
0
            if (dimension.tok->hasKnownIntValue()) {
1761
0
                dimension.known = true;
1762
0
                dimension.num = dimension.tok->getKnownIntValue();
1763
0
                continue;
1764
0
            }
1765
1766
0
            if (dimension.tok->valueType() && dimension.tok->valueType()->pointer == 0) {
1767
0
                int bits = 0;
1768
0
                switch (dimension.tok->valueType()->type) {
1769
0
                case ValueType::Type::CHAR:
1770
0
                    bits = mSettings.platform.char_bit;
1771
0
                    break;
1772
0
                case ValueType::Type::SHORT:
1773
0
                    bits = mSettings.platform.short_bit;
1774
0
                    break;
1775
0
                case ValueType::Type::INT:
1776
0
                    bits = mSettings.platform.int_bit;
1777
0
                    break;
1778
0
                case ValueType::Type::LONG:
1779
0
                    bits = mSettings.platform.long_bit;
1780
0
                    break;
1781
0
                case ValueType::Type::LONGLONG:
1782
0
                    bits = mSettings.platform.long_long_bit;
1783
0
                    break;
1784
0
                default:
1785
0
                    break;
1786
0
                }
1787
1788
0
                if (bits > 0 && bits <= 62) {
1789
0
                    if (dimension.tok->valueType()->sign == ValueType::Sign::UNSIGNED)
1790
0
                        dimension.num = 1LL << bits;
1791
0
                    else
1792
0
                        dimension.num = 1LL << (bits - 1);
1793
0
                }
1794
0
            }
1795
0
        }
1796
0
    }
1797
1.36k
}
1798
1799
SymbolDatabase::~SymbolDatabase()
1800
1.36k
{
1801
    // Clear scope, type, function and variable pointers
1802
93.5k
    for (const Token* tok = mTokenizer.list.front(); tok; tok = tok->next()) {
1803
92.2k
        const_cast<Token *>(tok)->scope(nullptr);
1804
92.2k
        const_cast<Token *>(tok)->type(nullptr);
1805
92.2k
        const_cast<Token *>(tok)->function(nullptr);
1806
92.2k
        const_cast<Token *>(tok)->variable(nullptr);
1807
92.2k
        const_cast<Token *>(tok)->enumerator(nullptr);
1808
92.2k
        const_cast<Token *>(tok)->setValueType(nullptr);
1809
92.2k
    }
1810
1.36k
}
1811
1812
bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const Token **funcStart, const Token **argStart, const Token** declEnd) const
1813
51.1k
{
1814
51.1k
    if (tok->varId())
1815
13.6k
        return false;
1816
1817
    // function returning function pointer? '... ( ... %name% ( ... ))( ... ) {'
1818
    // function returning reference to array '... ( & %name% ( ... ))[ ... ] {'
1819
    // TODO: Activate this again
1820
37.5k
    if ((false) && tok->str() == "(" && tok->strAt(1) != "*" && // NOLINT(readability-simplify-boolean-expr)
1821
37.5k
        (tok->link()->previous()->str() == ")" || Token::simpleMatch(tok->link()->tokAt(-2), ") const"))) {
1822
0
        const Token* tok2 = tok->link()->next();
1823
0
        if (tok2 && tok2->str() == "(" && Token::Match(tok2->link()->next(), "{|;|const|=")) {
1824
0
            const Token* argStartTok;
1825
0
            if (tok->link()->previous()->str() == "const")
1826
0
                argStartTok = tok->link()->linkAt(-2);
1827
0
            else
1828
0
                argStartTok = tok->link()->linkAt(-1);
1829
0
            *funcStart = argStartTok->previous();
1830
0
            *argStart = argStartTok;
1831
0
            *declEnd = Token::findmatch(tok2->link()->next(), "{|;");
1832
0
            return true;
1833
0
        }
1834
0
        if (tok2 && tok2->str() == "[") {
1835
0
            while (tok2 && tok2->str() == "[")
1836
0
                tok2 = tok2->link()->next();
1837
0
            if (Token::Match(tok2, "{|;|const|=")) {
1838
0
                const Token* argStartTok;
1839
0
                if (tok->link()->previous()->str() == "const")
1840
0
                    argStartTok = tok->link()->linkAt(-2);
1841
0
                else
1842
0
                    argStartTok = tok->link()->linkAt(-1);
1843
0
                *funcStart = argStartTok->previous();
1844
0
                *argStart = argStartTok;
1845
0
                *declEnd = Token::findmatch(tok2, "{|;");
1846
0
                return true;
1847
0
            }
1848
0
        }
1849
0
    }
1850
1851
37.5k
    else if (!tok->isName() || !tok->next() || !tok->next()->link())
1852
35.7k
        return false;
1853
1854
    // regular function?
1855
1.73k
    else if (Token::Match(tok, "%name% (") && !isReservedName(tok->str()) && tok->previous() &&
1856
1.73k
             (Token::Match(tok->previous(), "%name%|>|&|&&|*|::|~") || // Either a return type or scope qualifier in front of tok
1857
1.73k
              outerScope->isClassOrStructOrUnion())) { // or a ctor/dtor
1858
1.73k
        const Token* tok1 = tok->previous();
1859
1.73k
        const Token* tok2 = tok->next()->link()->next();
1860
1861
1.73k
        if (!mTokenizer.isFunctionHead(tok->next(), ";:{"))
1862
0
            return false;
1863
1864
        // skip over destructor "~"
1865
1.73k
        if (tok1->str() == "~")
1866
0
            tok1 = tok1->previous();
1867
1868
        // skip over qualification
1869
1.73k
        while (Token::simpleMatch(tok1, "::")) {
1870
0
            tok1 = tok1->previous();
1871
0
            if (tok1 && tok1->isName())
1872
0
                tok1 = tok1->previous();
1873
0
            else if (tok1 && tok1->str() == ">" && tok1->link() && Token::Match(tok1->link()->previous(), "%name%"))
1874
0
                tok1 = tok1->link()->tokAt(-2);
1875
0
        }
1876
1877
        // skip over const, noexcept, throw, override, final and volatile specifiers
1878
1.73k
        while (Token::Match(tok2, "const|noexcept|throw|override|final|volatile|&|&&")) {
1879
0
            tok2 = tok2->next();
1880
0
            if (tok2 && tok2->str() == "(")
1881
0
                tok2 = tok2->link()->next();
1882
0
        }
1883
1884
        // skip over trailing return type
1885
1.73k
        if (tok2 && tok2->str() == ".") {
1886
0
            for (tok2 = tok2->next(); tok2; tok2 = tok2->next()) {
1887
0
                if (Token::Match(tok2, ";|{|=|override|final"))
1888
0
                    break;
1889
0
                if (tok2->link() && Token::Match(tok2, "<|[|("))
1890
0
                    tok2 = tok2->link();
1891
0
            }
1892
0
        }
1893
1894
        // done if constructor or destructor
1895
1.73k
        if (!Token::Match(tok1, "{|}|;|public:|protected:|private:") && tok1) {
1896
            // skip over pointers and references
1897
1.73k
            while (Token::Match(tok1, "%type%|*|&|&&") && !endsWith(tok1->str(), ':') && (!isReservedName(tok1->str()) || tok1->str() == "const"))
1898
0
                tok1 = tok1->previous();
1899
1900
            // skip over decltype
1901
1.73k
            if (Token::simpleMatch(tok1, ")") && tok1->link() &&
1902
1.73k
                Token::simpleMatch(tok1->link()->previous(), "decltype ("))
1903
0
                tok1 = tok1->link()->tokAt(-2);
1904
1905
            // skip over template
1906
1.73k
            if (tok1 && tok1->str() == ">") {
1907
0
                if (tok1->link())
1908
0
                    tok1 = tok1->link()->previous();
1909
0
                else
1910
0
                    return false;
1911
0
            }
1912
1913
            // function can't have number or variable as return type
1914
1.73k
            if (tok1 && (tok1->isNumber() || tok1->varId()))
1915
0
                return false;
1916
1917
            // skip over return type
1918
1.73k
            if (tok1 && tok1->isName()) {
1919
1.73k
                if (tok1->str() == "return")
1920
0
                    return false;
1921
1.73k
                if (tok1->str() != "friend")
1922
1.73k
                    tok1 = tok1->previous();
1923
1.73k
            }
1924
1925
            // skip over qualification
1926
1.73k
            while (Token::simpleMatch(tok1, "::")) {
1927
0
                tok1 = tok1->previous();
1928
0
                if (tok1 && tok1->isName())
1929
0
                    tok1 = tok1->previous();
1930
0
                else if (tok1 && tok1->str() == ">" && tok1->link() && Token::Match(tok1->link()->previous(), "%name%"))
1931
0
                    tok1 = tok1->link()->tokAt(-2);
1932
0
                else if (Token::simpleMatch(tok1, ")") && tok1->link() &&
1933
0
                         Token::simpleMatch(tok1->link()->previous(), "decltype ("))
1934
0
                    tok1 = tok1->link()->tokAt(-2);
1935
0
            }
1936
1937
            // skip over modifiers and other stuff
1938
1.73k
            while (Token::Match(tok1, "const|static|extern|template|virtual|struct|class|enum|%name%")) {
1939
                // friend type func(); is not a function
1940
0
                if (isCPP() && tok1->str() == "friend" && tok2->str() == ";")
1941
0
                    return false;
1942
0
                tok1 = tok1->previous();
1943
0
            }
1944
1945
            // should be at a sequence point if this is a function
1946
1.73k
            if (!Token::Match(tok1, ">|{|}|;|public:|protected:|private:") && tok1)
1947
0
                return false;
1948
1.73k
        }
1949
1950
1.73k
        if (tok2 &&
1951
1.73k
            (Token::Match(tok2, ";|{|=") ||
1952
1.73k
             (tok2->isUpperCaseName() && Token::Match(tok2, "%name% ;|{")) ||
1953
1.73k
             (tok2->isUpperCaseName() && Token::Match(tok2, "%name% (") && tok2->next()->link()->strAt(1) == "{") ||
1954
1.73k
             Token::Match(tok2, ": ::| %name% (|::|<|{") ||
1955
1.73k
             Token::Match(tok2, "&|&&| ;|{") ||
1956
1.73k
             Token::Match(tok2, "= delete|default ;"))) {
1957
1.73k
            *funcStart = tok;
1958
1.73k
            *argStart = tok->next();
1959
1.73k
            *declEnd = Token::findmatch(tok2, "{|;");
1960
1.73k
            return true;
1961
1.73k
        }
1962
1.73k
    }
1963
1964
    // UNKNOWN_MACRO(a,b) { ... }
1965
0
    else if (outerScope->type == Scope::eGlobal &&
1966
0
             Token::Match(tok, "%name% (") &&
1967
0
             tok->isUpperCaseName() &&
1968
0
             Token::simpleMatch(tok->linkAt(1), ") {") &&
1969
0
             (!tok->previous() || Token::Match(tok->previous(), "[;{}]"))) {
1970
0
        *funcStart = tok;
1971
0
        *argStart = tok->next();
1972
0
        *declEnd = tok->linkAt(1)->next();
1973
0
        return true;
1974
0
    }
1975
1976
    // template constructor?
1977
0
    else if (Token::Match(tok, "%name% <") && Token::simpleMatch(tok->next()->link(), "> (")) {
1978
0
        const Token* tok2 = tok->next()->link()->next()->link();
1979
0
        if (Token::Match(tok2, ") const| ;|{|=") ||
1980
0
            Token::Match(tok2, ") : ::| %name% (|::|<|{") ||
1981
0
            Token::Match(tok2, ") const| noexcept {|;|(")) {
1982
0
            *funcStart = tok;
1983
0
            *argStart = tok2->link();
1984
0
            *declEnd = Token::findmatch(tok2->next(), "{|;");
1985
0
            return true;
1986
0
        }
1987
0
    }
1988
1989
    // regular C function with missing return or invalid C++ ?
1990
0
    else if (Token::Match(tok, "%name% (") && !isReservedName(tok->str()) &&
1991
0
             Token::simpleMatch(tok->linkAt(1), ") {") &&
1992
0
             (!tok->previous() || Token::Match(tok->previous(), ";|}"))) {
1993
0
        if (mTokenizer.isC()) {
1994
0
            debugMessage(tok, "debug", "SymbolDatabase::isFunction found C function '" + tok->str() + "' without a return type.");
1995
0
            *funcStart = tok;
1996
0
            *argStart = tok->next();
1997
0
            *declEnd = tok->linkAt(1)->next();
1998
0
            return true;
1999
0
        }
2000
0
        mTokenizer.syntaxError(tok);
2001
0
    }
2002
2003
0
    return false;
2004
37.5k
}
2005
2006
void SymbolDatabase::validateExecutableScopes() const
2007
0
{
2008
0
    const std::size_t functions = functionScopes.size();
2009
0
    for (std::size_t i = 0; i < functions; ++i) {
2010
0
        const Scope* const scope = functionScopes[i];
2011
0
        const Function* const function = scope->function;
2012
0
        if (scope->isExecutable() && !function) {
2013
0
            const std::list<const Token*> callstack(1, scope->classDef);
2014
0
            const std::string msg = std::string("Executable scope '") + scope->classDef->str() + "' with unknown function.";
2015
0
            const ErrorMessage errmsg(callstack, &mTokenizer.list, Severity::debug,
2016
0
                                      "symbolDatabaseWarning",
2017
0
                                      msg,
2018
0
                                      Certainty::normal);
2019
0
            mErrorLogger->reportErr(errmsg);
2020
0
        }
2021
0
    }
2022
0
}
2023
2024
namespace {
2025
    const Function* getFunctionForArgumentvariable(const Variable * const var, const std::vector<const Scope *>& functionScopes)
2026
0
    {
2027
0
        const std::size_t functions = functionScopes.size();
2028
0
        for (std::size_t i = 0; i < functions; ++i) {
2029
0
            const Scope* const scope = functionScopes[i];
2030
0
            const Function* const function = scope->function;
2031
0
            if (function) {
2032
0
                for (std::size_t arg=0; arg < function->argCount(); ++arg) {
2033
0
                    if (var==function->getArgumentVar(arg))
2034
0
                        return function;
2035
0
                }
2036
0
            }
2037
0
        }
2038
0
        return nullptr;
2039
0
    }
2040
}
2041
2042
void SymbolDatabase::validateVariables() const
2043
0
{
2044
0
    for (std::vector<const Variable *>::const_iterator iter = mVariableList.cbegin(); iter!=mVariableList.cend(); ++iter) {
2045
0
        const Variable * const var = *iter;
2046
0
        if (var) {
2047
0
            if (!var->scope()) {
2048
0
                const Function* function = getFunctionForArgumentvariable(var, functionScopes);
2049
0
                if (!var->isArgument() || (function && function->hasBody())) {
2050
0
                    throw InternalError(var->nameToken(), "Analysis failed (variable without scope). If the code is valid then please report this failure.", InternalError::INTERNAL);
2051
                    //std::cout << "!!!Variable found without scope: " << var->nameToken()->str() << std::endl;
2052
0
                }
2053
0
            }
2054
0
        }
2055
0
    }
2056
0
}
2057
2058
void SymbolDatabase::validate() const
2059
1.36k
{
2060
1.36k
    if (mSettings.debugwarnings) {
2061
0
        validateExecutableScopes();
2062
0
    }
2063
    // TODO
2064
    //validateVariables();
2065
1.36k
}
2066
2067
void SymbolDatabase::clangSetVariables(const std::vector<const Variable *> &variableList)
2068
0
{
2069
0
    mVariableList = variableList;
2070
0
}
2071
2072
void SymbolDatabase::debugSymbolDatabase() const
2073
1.36k
{
2074
1.36k
    if (!mSettings.debugnormal && !mSettings.debugwarnings)
2075
1.36k
        return;
2076
0
    for (const Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
2077
0
        if (tok->astParent() && tok->astParent()->getTokenDebug() == tok->getTokenDebug())
2078
0
            continue;
2079
0
        if (tok->getTokenDebug() == TokenDebug::ValueType) {
2080
2081
0
            std::string msg = "Value type is ";
2082
0
            ErrorPath errorPath;
2083
0
            if (tok->valueType()) {
2084
0
                msg += tok->valueType()->str();
2085
0
                errorPath.insert(errorPath.end(), tok->valueType()->debugPath.cbegin(), tok->valueType()->debugPath.cend());
2086
2087
0
            } else {
2088
0
                msg += "missing";
2089
0
            }
2090
0
            errorPath.emplace_back(tok, "");
2091
0
            mErrorLogger->reportErr(
2092
0
                {errorPath, &mTokenizer.list, Severity::debug, "valueType", msg, CWE{0}, Certainty::normal});
2093
0
        }
2094
0
    }
2095
0
}
2096
2097
Variable::Variable(const Token *name_, const std::string &clangType, const Token *typeStart,
2098
                   const Token *typeEnd, nonneg int index_, AccessControl access_,
2099
                   const Type *type_, const Scope *scope_)
2100
    : mNameToken(name_),
2101
    mTypeStartToken(typeStart),
2102
    mTypeEndToken(typeEnd),
2103
    mIndex(index_),
2104
    mAccess(access_),
2105
    mFlags(0),
2106
    mType(type_),
2107
    mScope(scope_)
2108
0
{
2109
0
    if (!mTypeStartToken && mTypeEndToken) {
2110
0
        mTypeStartToken = mTypeEndToken;
2111
0
        while (Token::Match(mTypeStartToken->previous(), "%type%|*|&"))
2112
0
            mTypeStartToken = mTypeStartToken->previous();
2113
0
    }
2114
2115
0
    while (Token::Match(mTypeStartToken, "const|struct|static")) {
2116
0
        if (mTypeStartToken->str() == "static")
2117
0
            setFlag(fIsStatic, true);
2118
0
        mTypeStartToken = mTypeStartToken->next();
2119
0
    }
2120
2121
0
    if (Token::simpleMatch(mTypeEndToken, "&"))
2122
0
        setFlag(fIsReference, true);
2123
0
    else if (Token::simpleMatch(mTypeEndToken, "&&")) {
2124
0
        setFlag(fIsReference, true);
2125
0
        setFlag(fIsRValueRef, true);
2126
0
    }
2127
2128
0
    std::string::size_type pos = clangType.find('[');
2129
0
    if (pos != std::string::npos) {
2130
0
        setFlag(fIsArray, true);
2131
0
        do {
2132
0
            const std::string::size_type pos1 = pos+1;
2133
0
            pos = clangType.find(']', pos1);
2134
0
            Dimension dim;
2135
0
            dim.tok = nullptr;
2136
0
            dim.known = pos > pos1;
2137
0
            if (pos > pos1)
2138
0
                dim.num = MathLib::toLongNumber(clangType.substr(pos1, pos-pos1));
2139
0
            else
2140
0
                dim.num = 0;
2141
0
            mDimensions.push_back(dim);
2142
0
            ++pos;
2143
0
        } while (pos < clangType.size() && clangType[pos] == '[');
2144
0
    }
2145
2146
    // Is there initialization in variable declaration
2147
0
    const Token *initTok = mNameToken ? mNameToken->next() : nullptr;
2148
0
    while (initTok && initTok->str() == "[")
2149
0
        initTok = initTok->link()->next();
2150
0
    if (Token::Match(initTok, "=|{") || (initTok && initTok->isSplittedVarDeclEq()))
2151
0
        setFlag(fIsInit, true);
2152
0
}
2153
2154
Variable::Variable(const Variable &var, const Scope *scope)
2155
0
{
2156
0
    *this = var;
2157
0
    mScope = scope;
2158
0
}
2159
2160
Variable::Variable(const Variable &var)
2161
0
{
2162
0
    *this = var;
2163
0
}
2164
2165
Variable::~Variable()
2166
6.80k
{
2167
6.80k
    delete mValueType;
2168
6.80k
}
2169
2170
Variable& Variable::operator=(const Variable &var)
2171
0
{
2172
0
    if (this == &var)
2173
0
        return *this;
2174
2175
0
    mNameToken = var.mNameToken;
2176
0
    mTypeStartToken = var.mTypeStartToken;
2177
0
    mTypeEndToken = var.mTypeEndToken;
2178
0
    mIndex = var.mIndex;
2179
0
    mAccess = var.mAccess;
2180
0
    mFlags = var.mFlags;
2181
0
    mType = var.mType;
2182
0
    mScope = var.mScope;
2183
0
    mDimensions = var.mDimensions;
2184
0
    delete mValueType;
2185
0
    if (var.mValueType)
2186
0
        mValueType = new ValueType(*var.mValueType);
2187
0
    else
2188
0
        mValueType = nullptr;
2189
2190
0
    return *this;
2191
0
}
2192
2193
2.83k
bool Variable::isMember() const {
2194
2.83k
    return mScope && mScope->isClassOrStructOrUnion();
2195
2.83k
}
2196
2197
bool Variable::isPointerArray() const
2198
0
{
2199
0
    return isArray() && nameToken() && nameToken()->previous() && (nameToken()->previous()->str() == "*");
2200
0
}
2201
2202
bool Variable::isUnsigned() const
2203
0
{
2204
0
    return mValueType ? (mValueType->sign == ValueType::Sign::UNSIGNED) : mTypeStartToken->isUnsigned();
2205
0
}
2206
2207
const Token * Variable::declEndToken() const
2208
5.24k
{
2209
5.24k
    Token const * declEnd = typeStartToken();
2210
15.7k
    while (declEnd && !Token::Match(declEnd, "[;,)={]")) {
2211
10.4k
        if (declEnd->link() && Token::Match(declEnd,"(|[|<"))
2212
0
            declEnd = declEnd->link();
2213
10.4k
        declEnd = declEnd->next();
2214
10.4k
    }
2215
5.24k
    return declEnd;
2216
5.24k
}
2217
2218
void Variable::evaluate(const Settings* settings)
2219
6.80k
{
2220
    // Is there initialization in variable declaration
2221
6.80k
    const Token *initTok = mNameToken ? mNameToken->next() : nullptr;
2222
6.80k
    while (Token::Match(initTok, "[|(")) {
2223
0
        initTok = initTok->link()->next();
2224
0
        if (Token::simpleMatch(initTok, ")"))
2225
0
            initTok = initTok->next();
2226
0
    }
2227
6.80k
    if (Token::Match(initTok, "=|{") || (initTok && initTok->isSplittedVarDeclEq()))
2228
6.80k
        setFlag(fIsInit, true);
2229
2230
6.80k
    if (!settings)
2231
0
        return;
2232
2233
6.80k
    const Library * const lib = &settings->library;
2234
2235
    // TODO: ValueType::parseDecl() is also performing a container lookup
2236
6.80k
    bool isContainer = false;
2237
6.80k
    if (mNameToken)
2238
6.80k
        setFlag(fIsArray, arrayDimensions(settings, isContainer));
2239
2240
6.80k
    if (mTypeStartToken)
2241
6.80k
        setValueType(ValueType::parseDecl(mTypeStartToken,*settings));
2242
2243
6.80k
    const Token* tok = mTypeStartToken;
2244
6.80k
    while (tok && tok->previous() && tok->previous()->isName())
2245
0
        tok = tok->previous();
2246
6.80k
    const Token* end = mTypeEndToken;
2247
6.80k
    if (end)
2248
6.80k
        end = end->next();
2249
13.6k
    while (tok != end) {
2250
6.80k
        if (tok->str() == "static")
2251
0
            setFlag(fIsStatic, true);
2252
6.80k
        else if (tok->str() == "extern")
2253
0
            setFlag(fIsExtern, true);
2254
6.80k
        else if (tok->str() == "volatile" || Token::simpleMatch(tok, "std :: atomic <"))
2255
0
            setFlag(fIsVolatile, true);
2256
6.80k
        else if (tok->str() == "mutable")
2257
0
            setFlag(fIsMutable, true);
2258
6.80k
        else if (tok->str() == "const")
2259
0
            setFlag(fIsConst, true);
2260
6.80k
        else if (tok->str() == "constexpr") {
2261
0
            setFlag(fIsConst, true);
2262
0
            setFlag(fIsStatic, true);
2263
6.80k
        } else if (tok->str() == "*") {
2264
0
            setFlag(fIsPointer, !isArray() || (isContainer && !Token::Match(tok->next(), "%name% [")) || Token::Match(tok, "* const| %name% )"));
2265
0
            setFlag(fIsConst, false); // Points to const, isn't necessarily const itself
2266
6.80k
        } else if (tok->str() == "&") {
2267
0
            if (isReference())
2268
0
                setFlag(fIsRValueRef, true);
2269
0
            setFlag(fIsReference, true);
2270
6.80k
        } else if (tok->str() == "&&") { // Before simplification, && isn't split up
2271
0
            setFlag(fIsRValueRef, true);
2272
0
            setFlag(fIsReference, true); // Set also fIsReference
2273
0
        }
2274
2275
6.80k
        if (tok->isAttributeMaybeUnused()) {
2276
0
            setFlag(fIsMaybeUnused, true);
2277
0
        }
2278
2279
6.80k
        if (tok->str() == "<" && tok->link())
2280
0
            tok = tok->link();
2281
6.80k
        else
2282
6.80k
            tok = tok->next();
2283
6.80k
    }
2284
2285
6.80k
    while (Token::Match(mTypeStartToken, "static|const|constexpr|volatile %any%"))
2286
0
        mTypeStartToken = mTypeStartToken->next();
2287
6.80k
    while (mTypeEndToken && mTypeEndToken->previous() && Token::Match(mTypeEndToken, "const|volatile"))
2288
0
        mTypeEndToken = mTypeEndToken->previous();
2289
2290
6.80k
    if (mTypeStartToken) {
2291
6.80k
        std::string strtype = mTypeStartToken->str();
2292
6.80k
        for (const Token *typeToken = mTypeStartToken; Token::Match(typeToken, "%type% :: %type%"); typeToken = typeToken->tokAt(2))
2293
0
            strtype += "::" + typeToken->strAt(2);
2294
6.80k
        setFlag(fIsClass, !lib->podtype(strtype) && !mTypeStartToken->isStandardType() && !isEnumType() && !isPointer() && !isReference() && strtype != "...");
2295
6.80k
        setFlag(fIsStlType, Token::simpleMatch(mTypeStartToken, "std ::"));
2296
6.80k
        setFlag(fIsStlString, ::isStlStringType(mTypeStartToken));
2297
6.80k
        setFlag(fIsSmartPointer, mTypeStartToken->isCpp() && lib->isSmartPointer(mTypeStartToken));
2298
6.80k
    }
2299
6.80k
    if (mAccess == AccessControl::Argument) {
2300
0
        tok = mNameToken;
2301
0
        if (!tok) {
2302
            // Argument without name
2303
0
            tok = mTypeEndToken;
2304
            // back up to start of array dimensions
2305
0
            while (tok && tok->str() == "]")
2306
0
                tok = tok->link()->previous();
2307
            // add array dimensions if present
2308
0
            if (tok && tok->next()->str() == "[")
2309
0
                setFlag(fIsArray, arrayDimensions(settings, isContainer));
2310
0
        }
2311
0
        if (!tok)
2312
0
            return;
2313
0
        tok = tok->next();
2314
0
        while (tok->str() == "[")
2315
0
            tok = tok->link();
2316
0
        setFlag(fHasDefault, tok->str() == "=");
2317
0
    }
2318
    // check for C++11 member initialization
2319
6.80k
    if (mScope && mScope->isClassOrStruct()) {
2320
        // type var = x or
2321
        // type var = {x}
2322
        // type var = x; gets simplified to: type var ; var = x ;
2323
0
        Token const * declEnd = declEndToken();
2324
0
        if ((Token::Match(declEnd, "; %name% =") && declEnd->strAt(1) == mNameToken->str()) ||
2325
0
            Token::Match(declEnd, "=|{"))
2326
0
            setFlag(fHasDefault, true);
2327
0
    }
2328
2329
6.80k
    if (mTypeStartToken) {
2330
6.80k
        if (Token::Match(mTypeStartToken, "float|double"))
2331
0
            setFlag(fIsFloatType, true);
2332
6.80k
    }
2333
6.80k
}
2334
2335
void Variable::setValueType(const ValueType &valueType)
2336
6.80k
{
2337
6.80k
    if (valueType.type == ValueType::Type::UNKNOWN_TYPE) {
2338
0
        const Token *declType = Token::findsimplematch(mTypeStartToken, "decltype (", mTypeEndToken);
2339
0
        if (declType && !declType->next()->valueType())
2340
0
            return;
2341
0
    }
2342
6.80k
    delete mValueType;
2343
6.80k
    mValueType = new ValueType(valueType);
2344
6.80k
    if ((mValueType->pointer > 0) && (!isArray() || Token::Match(mNameToken->previous(), "( * %name% )")))
2345
0
        setFlag(fIsPointer, true);
2346
6.80k
    setFlag(fIsConst, mValueType->constness & (1U << mValueType->pointer));
2347
6.80k
    if (mValueType->smartPointerType)
2348
0
        setFlag(fIsSmartPointer, true);
2349
6.80k
}
2350
2351
const Type* Variable::smartPointerType() const
2352
79.3k
{
2353
79.3k
    if (!isSmartPointer())
2354
79.3k
        return nullptr;
2355
2356
0
    if (mValueType->smartPointerType)
2357
0
        return mValueType->smartPointerType;
2358
2359
    // TODO: Cache result, handle more complex type expression
2360
0
    const Token* typeTok = typeStartToken();
2361
0
    while (Token::Match(typeTok, "%name%|::"))
2362
0
        typeTok = typeTok->next();
2363
0
    if (Token::Match(typeTok, "< %name% >")) {
2364
0
        const Scope* scope = typeTok->scope();
2365
0
        const Type* ptrType{};
2366
0
        while (scope && !ptrType) {
2367
0
            ptrType = scope->findType(typeTok->next()->str());
2368
0
            scope = scope->nestedIn;
2369
0
        }
2370
0
        return ptrType;
2371
0
    }
2372
0
    return nullptr;
2373
0
}
2374
2375
const Type* Variable::iteratorType() const
2376
0
{
2377
0
    if (!mValueType || mValueType->type != ValueType::ITERATOR)
2378
0
        return nullptr;
2379
2380
0
    if (mValueType->containerTypeToken)
2381
0
        return mValueType->containerTypeToken->type();
2382
2383
0
    return nullptr;
2384
0
}
2385
2386
bool Variable::isStlStringViewType() const
2387
0
{
2388
0
    return getFlag(fIsStlType) && valueType() && valueType()->container && valueType()->container->stdStringLike && valueType()->container->view;
2389
0
}
2390
2391
std::string Variable::getTypeName() const
2392
0
{
2393
0
    std::string ret;
2394
    // TODO: For known types, generate the full type name
2395
0
    for (const Token *typeTok = mTypeStartToken; Token::Match(typeTok, "%name%|::") && typeTok->varId() == 0; typeTok = typeTok->next()) {
2396
0
        ret += typeTok->str();
2397
0
        if (Token::simpleMatch(typeTok->next(), "<") && typeTok->next()->link()) // skip template arguments
2398
0
            typeTok = typeTok->next()->link();
2399
0
    }
2400
0
    return ret;
2401
0
}
2402
2403
static bool isOperator(const Token *tokenDef)
2404
1.73k
{
2405
1.73k
    if (!tokenDef)
2406
0
        return false;
2407
1.73k
    if (tokenDef->isOperatorKeyword())
2408
0
        return true;
2409
1.73k
    const std::string &name = tokenDef->str();
2410
1.73k
    return name.size() > 8 && startsWith(name,"operator") && std::strchr("+-*/%&|~^<>!=[(", name[8]);
2411
1.73k
}
2412
2413
Function::Function(const Tokenizer *mTokenizer,
2414
                   const Token *tok,
2415
                   const Scope *scope,
2416
                   const Token *tokDef,
2417
                   const Token *tokArgDef)
2418
    : tokenDef(tokDef),
2419
    argDef(tokArgDef),
2420
    nestedIn(scope)
2421
1.73k
{
2422
    // operator function
2423
1.73k
    if (::isOperator(tokenDef)) {
2424
0
        isOperator(true);
2425
2426
        // 'operator =' is special
2427
0
        if (tokenDef->str() == "operator=")
2428
0
            type = Function::eOperatorEqual;
2429
0
    }
2430
2431
1.73k
    else if (tokenDef->str() == "[") {
2432
0
        type = Function::eLambda;
2433
0
    }
2434
2435
    // class constructor/destructor
2436
1.73k
    else if (((tokenDef->str() == scope->className) ||
2437
1.73k
              (tokenDef->str().substr(0, scope->className.size()) == scope->className &&
2438
1.73k
               tokenDef->str().size() > scope->className.size() + 1 &&
2439
1.73k
               tokenDef->str()[scope->className.size() + 1] == '<')) &&
2440
1.73k
             scope->type != Scope::ScopeType::eNamespace) {
2441
        // destructor
2442
0
        if (tokenDef->previous()->str() == "~")
2443
0
            type = Function::eDestructor;
2444
        // constructor of any kind
2445
0
        else
2446
0
            type = Function::eConstructor;
2447
2448
0
        isExplicit(tokenDef->strAt(-1) == "explicit" || tokenDef->strAt(-2) == "explicit");
2449
0
    }
2450
2451
1.73k
    const Token *tok1 = setFlags(tok, scope);
2452
2453
    // find the return type
2454
1.73k
    if (!isConstructor() && !isDestructor()) {
2455
        // @todo auto type deduction should be checked
2456
        // @todo attributes and exception specification can also precede trailing return type
2457
1.73k
        if (Token::Match(argDef->link()->next(), "const|volatile| &|&&| .")) { // Trailing return type
2458
0
            hasTrailingReturnType(true);
2459
0
            if (argDef->link()->strAt(1) == ".")
2460
0
                retDef = argDef->link()->tokAt(2);
2461
0
            else if (argDef->link()->strAt(2) == ".")
2462
0
                retDef = argDef->link()->tokAt(3);
2463
0
            else if (argDef->link()->strAt(3) == ".")
2464
0
                retDef = argDef->link()->tokAt(4);
2465
1.73k
        } else if (!isLambda()) {
2466
1.73k
            if (tok1->str() == ">")
2467
0
                tok1 = tok1->next();
2468
1.73k
            while (Token::Match(tok1, "extern|virtual|static|friend|struct|union|enum"))
2469
0
                tok1 = tok1->next();
2470
1.73k
            retDef = tok1;
2471
1.73k
        }
2472
1.73k
    }
2473
2474
1.73k
    const Token *end = argDef->link();
2475
2476
    // parse function attributes..
2477
1.73k
    tok = end->next();
2478
1.73k
    while (tok) {
2479
1.73k
        if (tok->str() == "const")
2480
0
            isConst(true);
2481
1.73k
        else if (tok->str() == "&")
2482
0
            hasLvalRefQualifier(true);
2483
1.73k
        else if (tok->str() == "&&")
2484
0
            hasRvalRefQualifier(true);
2485
1.73k
        else if (tok->str() == "override")
2486
0
            setFlag(fHasOverrideSpecifier, true);
2487
1.73k
        else if (tok->str() == "final")
2488
0
            setFlag(fHasFinalSpecifier, true);
2489
1.73k
        else if (tok->str() == "volatile")
2490
0
            isVolatile(true);
2491
1.73k
        else if (tok->str() == "noexcept") {
2492
0
            isNoExcept(!Token::simpleMatch(tok->next(), "( false )"));
2493
0
            if (tok->next()->str() == "(")
2494
0
                tok = tok->linkAt(1);
2495
1.73k
        } else if (Token::simpleMatch(tok, "throw (")) {
2496
0
            isThrow(true);
2497
0
            if (tok->strAt(2) != ")")
2498
0
                throwArg = tok->next();
2499
0
            tok = tok->linkAt(1);
2500
1.73k
        } else if (Token::Match(tok, "= 0|default|delete ;")) {
2501
0
            const std::string& modifier = tok->strAt(1);
2502
0
            isPure(modifier == "0");
2503
0
            isDefault(modifier == "default");
2504
0
            isDelete(modifier == "delete");
2505
1.73k
        } else if (tok->str() == ".") { // trailing return type
2506
            // skip over return type
2507
0
            while (tok && !Token::Match(tok->next(), ";|{|override|final"))
2508
0
                tok = tok->next();
2509
0
        } else
2510
1.73k
            break;
2511
0
        if (tok)
2512
0
            tok = tok->next();
2513
0
    }
2514
2515
1.73k
    if (mTokenizer->isFunctionHead(end, ":{")) {
2516
        // assume implementation is inline (definition and implementation same)
2517
1.73k
        token = tokenDef;
2518
1.73k
        arg = argDef;
2519
1.73k
        isInline(true);
2520
1.73k
        hasBody(true);
2521
1.73k
    }
2522
1.73k
}
2523
2524
Function::Function(const Token *tokenDef, const std::string &clangType)
2525
    : tokenDef(tokenDef)
2526
0
{
2527
    // operator function
2528
0
    if (::isOperator(tokenDef)) {
2529
0
        isOperator(true);
2530
2531
        // 'operator =' is special
2532
0
        if (tokenDef->str() == "operator=")
2533
0
            type = Function::eOperatorEqual;
2534
0
    }
2535
2536
0
    setFlags(tokenDef, tokenDef->scope());
2537
2538
0
    if (endsWith(clangType, " const"))
2539
0
        isConst(true);
2540
0
}
2541
2542
const Token *Function::setFlags(const Token *tok1, const Scope *scope)
2543
1.73k
{
2544
1.73k
    if (tok1->isInline())
2545
0
        isInlineKeyword(true);
2546
2547
    // look for end of previous statement
2548
3.47k
    while (tok1->previous() && !Token::Match(tok1->previous(), ";|}|{|public:|protected:|private:")) {
2549
1.73k
        tok1 = tok1->previous();
2550
2551
1.73k
        if (tok1->isInline())
2552
0
            isInlineKeyword(true);
2553
2554
        // extern function
2555
1.73k
        if (tok1->isExternC() || tok1->str() == "extern") {
2556
0
            isExtern(true);
2557
0
        }
2558
2559
        // virtual function
2560
1.73k
        else if (tok1->str() == "virtual") {
2561
0
            hasVirtualSpecifier(true);
2562
0
        }
2563
2564
        // static function
2565
1.73k
        else if (tok1->str() == "static") {
2566
0
            isStatic(true);
2567
0
            if (scope->type == Scope::eNamespace || scope->type == Scope::eGlobal)
2568
0
                isStaticLocal(true);
2569
0
        }
2570
2571
        // friend function
2572
1.73k
        else if (tok1->str() == "friend") {
2573
0
            isFriend(true);
2574
0
        }
2575
2576
        // constexpr function
2577
1.73k
        else if (tok1->str() == "constexpr") {
2578
0
            isConstexpr(true);
2579
0
        }
2580
2581
        // decltype
2582
1.73k
        else if (tok1->str() == ")" && Token::simpleMatch(tok1->link()->previous(), "decltype (")) {
2583
0
            tok1 = tok1->link()->previous();
2584
0
        }
2585
2586
1.73k
        else if (tok1->link() && tok1->str() == ">") {
2587
            // Function template
2588
0
            if (Token::simpleMatch(tok1->link()->previous(), "template <")) {
2589
0
                templateDef = tok1->link()->previous();
2590
0
                break;
2591
0
            }
2592
0
            tok1 = tok1->link();
2593
0
        }
2594
1.73k
    }
2595
1.73k
    return tok1;
2596
1.73k
}
2597
2598
std::string Function::fullName() const
2599
0
{
2600
0
    std::string ret = name();
2601
0
    for (const Scope *s = nestedIn; s; s = s->nestedIn) {
2602
0
        if (!s->className.empty())
2603
0
            ret = s->className + "::" + ret;
2604
0
    }
2605
0
    ret += "(";
2606
0
    for (const Variable &a : argumentList)
2607
0
        ret += (a.index() == 0 ? "" : ",") + a.name();
2608
0
    return ret + ")";
2609
0
}
2610
2611
static std::string qualifiedName(const Scope *scope)
2612
0
{
2613
0
    std::string name = scope->className;
2614
0
    while (scope->nestedIn) {
2615
0
        if (!scope->nestedIn->className.empty())
2616
0
            name = (scope->nestedIn->className + " :: ") + name;
2617
0
        scope = scope->nestedIn;
2618
0
    }
2619
0
    return name;
2620
0
}
2621
2622
static bool usingNamespace(const Scope *scope, const Token *first, const Token *second, int &offset)
2623
0
{
2624
    // check if qualifications match first before checking if using is needed
2625
0
    const Token *tok1 = first;
2626
0
    const Token *tok2 = second;
2627
0
    bool match = false;
2628
0
    while (Token::Match(tok1, "%type% :: %type%") && Token::Match(tok2, "%type% :: %type%")) {
2629
0
        if (tok1->str() == tok2->str()) {
2630
0
            tok1 = tok1->tokAt(2);
2631
0
            tok2 = tok2->tokAt(2);
2632
0
            match = true;
2633
0
        } else {
2634
0
            match = false;
2635
0
            break;
2636
0
        }
2637
0
    }
2638
2639
0
    if (match)
2640
0
        return false;
2641
2642
0
    offset = 0;
2643
0
    std::string name = first->str();
2644
2645
0
    while (Token::Match(first, "%type% :: %type%")) {
2646
0
        if (offset)
2647
0
            name += (" :: " + first->str());
2648
0
        offset += 2;
2649
0
        first = first->tokAt(2);
2650
0
        if (first->str() == second->str()) {
2651
0
            break;
2652
0
        }
2653
0
    }
2654
2655
0
    if (offset) {
2656
0
        while (scope) {
2657
0
            for (const auto & info : scope->usingList) {
2658
0
                if (info.scope) {
2659
0
                    if (name == qualifiedName(info.scope))
2660
0
                        return true;
2661
0
                }
2662
                // no scope so get name from using
2663
0
                else {
2664
0
                    const Token *start = info.start->tokAt(2);
2665
0
                    std::string nsName;
2666
0
                    while (start && start->str() != ";") {
2667
0
                        if (!nsName.empty())
2668
0
                            nsName += " ";
2669
0
                        nsName += start->str();
2670
0
                        start = start->next();
2671
0
                    }
2672
0
                    if (nsName == name)
2673
0
                        return true;
2674
0
                }
2675
0
            }
2676
0
            scope = scope->nestedIn;
2677
0
        }
2678
0
    }
2679
2680
0
    return false;
2681
0
}
2682
2683
static bool typesMatch(
2684
    const Scope *first_scope,
2685
    const Token *first_token,
2686
    const Scope *second_scope,
2687
    const Token *second_token,
2688
    const Token **new_first,
2689
    const Token **new_second)
2690
0
{
2691
    // get first type
2692
0
    const Type* first_type = first_scope->check->findType(first_token, first_scope, /*lookOutside*/ true);
2693
0
    if (first_type) {
2694
        // get second type
2695
0
        const Type* second_type = second_scope->check->findType(second_token, second_scope, /*lookOutside*/ true);
2696
        // check if types match
2697
0
        if (first_type == second_type) {
2698
0
            const Token* tok1 = first_token;
2699
0
            while (tok1 && tok1->str() != first_type->name())
2700
0
                tok1 = tok1->next();
2701
0
            const Token *tok2 = second_token;
2702
0
            while (tok2 && tok2->str() != second_type->name())
2703
0
                tok2 = tok2->next();
2704
            // update parser token positions
2705
0
            if (tok1 && tok2) {
2706
0
                *new_first = tok1->previous();
2707
0
                *new_second = tok2->previous();
2708
0
                return true;
2709
0
            }
2710
0
        }
2711
0
    }
2712
0
    return false;
2713
0
}
2714
2715
bool Function::argsMatch(const Scope *scope, const Token *first, const Token *second, const std::string &path, nonneg int path_length) const
2716
0
{
2717
0
    const bool isCPP = scope->check->isCPP();
2718
0
    if (!isCPP) // C does not support overloads
2719
0
        return true;
2720
2721
0
    int arg_path_length = path_length;
2722
0
    int offset = 0;
2723
0
    int openParen = 0;
2724
2725
    // check for () == (void) and (void) == ()
2726
0
    if ((Token::simpleMatch(first, "( )") && Token::simpleMatch(second, "( void )")) ||
2727
0
        (Token::simpleMatch(first, "( void )") && Token::simpleMatch(second, "( )")))
2728
0
        return true;
2729
2730
0
    auto skipTopLevelConst = [](const Token* start) -> const Token* {
2731
0
        const Token* tok = start->next();
2732
0
        if (Token::simpleMatch(tok, "const")) {
2733
0
            tok = tok->next();
2734
0
            while (Token::Match(tok, "%name%|%type%|::"))
2735
0
                tok = tok->next();
2736
0
            if (Token::Match(tok, ",|)|="))
2737
0
                return start->next();
2738
0
        }
2739
0
        return start;
2740
0
    };
2741
2742
0
    while (first->str() == second->str() &&
2743
0
           first->isLong() == second->isLong() &&
2744
0
           first->isUnsigned() == second->isUnsigned()) {
2745
0
        if (first->str() == "(")
2746
0
            openParen++;
2747
2748
        // at end of argument list
2749
0
        else if (first->str() == ")") {
2750
0
            if (openParen == 1)
2751
0
                return true;
2752
0
            --openParen;
2753
0
        }
2754
2755
        // skip optional type information
2756
0
        if (Token::Match(first->next(), "struct|enum|union|class"))
2757
0
            first = first->next();
2758
0
        if (Token::Match(second->next(), "struct|enum|union|class"))
2759
0
            second = second->next();
2760
2761
        // skip const on type passed by value
2762
0
        const Token* const oldSecond = second;
2763
0
        first = skipTopLevelConst(first);
2764
0
        second = skipTopLevelConst(second);
2765
2766
        // skip default value assignment
2767
0
        if (oldSecond == second && first->next()->str() == "=") {
2768
0
            first = first->nextArgument();
2769
0
            if (first)
2770
0
                first = first->tokAt(-2);
2771
0
            if (second->next()->str() == "=") {
2772
0
                second = second->nextArgument();
2773
0
                if (second)
2774
0
                    second = second->tokAt(-2);
2775
0
                if (!first || !second) { // End of argument list (first or second)
2776
0
                    return !first && !second;
2777
0
                }
2778
0
            } else if (!first) { // End of argument list (first)
2779
0
                return !second->nextArgument(); // End of argument list (second)
2780
0
            }
2781
0
        } else if (oldSecond == second && second->next()->str() == "=") {
2782
0
            second = second->nextArgument();
2783
0
            if (second)
2784
0
                second = second->tokAt(-2);
2785
0
            if (!second) { // End of argument list (second)
2786
0
                return false;
2787
0
            }
2788
0
        }
2789
2790
        // definition missing variable name
2791
0
        else if ((first->next()->str() == "," && second->next()->str() != ",") ||
2792
0
                 (Token::Match(first, "!!( )") && second->next()->str() != ")")) {
2793
0
            second = second->next();
2794
            // skip default value assignment
2795
0
            if (second->next()->str() == "=") {
2796
0
                do {
2797
0
                    second = second->next();
2798
0
                } while (!Token::Match(second->next(), ",|)"));
2799
0
            }
2800
0
        } else if (first->next()->str() == "[" && second->next()->str() != "[")
2801
0
            second = second->next();
2802
2803
        // function missing variable name
2804
0
        else if ((second->next()->str() == "," && first->next()->str() != ",") ||
2805
0
                 (Token::Match(second, "!!( )") && first->next()->str() != ")")) {
2806
0
            first = first->next();
2807
            // skip default value assignment
2808
0
            if (first->next()->str() == "=") {
2809
0
                do {
2810
0
                    first = first->next();
2811
0
                } while (!Token::Match(first->next(), ",|)"));
2812
0
            }
2813
0
        } else if (second->next()->str() == "[" && first->next()->str() != "[")
2814
0
            first = first->next();
2815
2816
        // unnamed parameters
2817
0
        else if (Token::Match(first, "(|, %type% ,|)") && Token::Match(second, "(|, %type% ,|)")) {
2818
0
            if (first->next()->expressionString() != second->next()->expressionString())
2819
0
                break;
2820
0
            first = first->next();
2821
0
            second = second->next();
2822
0
            continue;
2823
0
        }
2824
2825
        // argument list has different number of arguments
2826
0
        else if (openParen == 1 && second->str() == ")" && first->str() != ")")
2827
0
            break;
2828
2829
        // ckeck for type * x == type x[]
2830
0
        else if (Token::Match(first->next(), "* %name%| ,|)|=") &&
2831
0
                 Token::Match(second->next(), "%name%| [ ] ,|)")) {
2832
0
            do {
2833
0
                first = first->next();
2834
0
            } while (!Token::Match(first->next(), ",|)"));
2835
0
            do {
2836
0
                second = second->next();
2837
0
            } while (!Token::Match(second->next(), ",|)"));
2838
0
        }
2839
2840
        // const after *
2841
0
        else if (first->next()->str() == "*" && second->next()->str() == "*" &&
2842
0
                 ((first->strAt(2) != "const" && second->strAt(2) == "const") ||
2843
0
                  (first->strAt(2) == "const" && second->strAt(2) != "const"))) {
2844
0
            if (first->strAt(2) != "const") {
2845
0
                if (Token::Match(first->tokAt(2), "%name%| ,|)") && Token::Match(second->tokAt(3), "%name%| ,|)")) {
2846
0
                    first = first->tokAt(Token::Match(first->tokAt(2), "%name%") ? 2 : 1);
2847
0
                    second = second->tokAt(Token::Match(second->tokAt(3), "%name%") ? 3 : 2);
2848
0
                } else {
2849
0
                    first = first->next();
2850
0
                    second = second->tokAt(2);
2851
0
                }
2852
0
            } else {
2853
0
                if (Token::Match(second->tokAt(2), "%name%| ,|)") && Token::Match(first->tokAt(3), "%name%| ,|)")) {
2854
0
                    first = first->tokAt(Token::Match(first->tokAt(3), "%name%") ? 3 : 2);
2855
0
                    second = second->tokAt(Token::Match(second->tokAt(2), "%name%") ? 2 : 1);
2856
0
                } else {
2857
0
                    first = first->tokAt(2);
2858
0
                    second = second->next();
2859
0
                }
2860
0
            }
2861
0
        }
2862
2863
        // variable names are different
2864
0
        else if ((Token::Match(first->next(), "%name% ,|)|=|[") &&
2865
0
                  Token::Match(second->next(), "%name% ,|)|[")) &&
2866
0
                 (first->next()->str() != second->next()->str())) {
2867
            // skip variable names
2868
0
            first = first->next();
2869
0
            second = second->next();
2870
2871
            // skip default value assignment
2872
0
            if (first->next()->str() == "=") {
2873
0
                do {
2874
0
                    first = first->next();
2875
0
                } while (!Token::Match(first->next(), ",|)"));
2876
0
            }
2877
0
        }
2878
2879
        // using namespace
2880
0
        else if (usingNamespace(scope, first->next(), second->next(), offset))
2881
0
            first = first->tokAt(offset);
2882
2883
        // same type with different qualification
2884
0
        else if (typesMatch(scope, first->next(), nestedIn, second->next(), &first, &second))
2885
0
            ;
2886
2887
        // variable with class path
2888
0
        else if (arg_path_length && Token::Match(first->next(), "%name%") && first->strAt(1) != "const") {
2889
0
            std::string param = path;
2890
2891
0
            if (Token::simpleMatch(second->next(), param.c_str(), param.size())) {
2892
                // check for redundant qualification before skipping it
2893
0
                if (!Token::simpleMatch(first->next(), param.c_str(), param.size())) {
2894
0
                    second = second->tokAt(int(arg_path_length));
2895
0
                    arg_path_length = 0;
2896
0
                }
2897
0
            }
2898
2899
            // nested or base class variable
2900
0
            else if (arg_path_length <= 2 && Token::Match(first->next(), "%name%") &&
2901
0
                     (Token::Match(second->next(), "%name% :: %name%") ||
2902
0
                      (Token::Match(second->next(), "%name% <") &&
2903
0
                       Token::Match(second->linkAt(1), "> :: %name%"))) &&
2904
0
                     ((second->next()->str() == scope->className) ||
2905
0
                      (scope->nestedIn && second->next()->str() == scope->nestedIn->className) ||
2906
0
                      (scope->definedType && scope->definedType->isDerivedFrom(second->next()->str()))) &&
2907
0
                     (first->next()->str() == second->strAt(3))) {
2908
0
                if (Token::Match(second->next(), "%name% <"))
2909
0
                    second = second->linkAt(1)->next();
2910
0
                else
2911
0
                    second = second->tokAt(2);
2912
0
            }
2913
2914
            // remove class name
2915
0
            else if (arg_path_length > 2 && first->strAt(1) != second->strAt(1)) {
2916
0
                std::string short_path = path;
2917
0
                unsigned int short_path_length = arg_path_length;
2918
2919
                // remove last " :: "
2920
0
                short_path.resize(short_path.size() - 4);
2921
0
                short_path_length--;
2922
2923
                // remove last name
2924
0
                std::string::size_type lastSpace = short_path.find_last_of(' ');
2925
0
                if (lastSpace != std::string::npos) {
2926
0
                    short_path.resize(lastSpace+1);
2927
0
                    short_path_length--;
2928
0
                    if (short_path[short_path.size() - 1] == '>') {
2929
0
                        short_path.resize(short_path.size() - 3);
2930
0
                        while (short_path[short_path.size() - 1] == '<') {
2931
0
                            lastSpace = short_path.find_last_of(' ');
2932
0
                            short_path.resize(lastSpace+1);
2933
0
                            short_path_length--;
2934
0
                        }
2935
0
                    }
2936
0
                }
2937
2938
0
                param = short_path;
2939
0
                if (Token::simpleMatch(second->next(), param.c_str(), param.size())) {
2940
0
                    second = second->tokAt(int(short_path_length));
2941
0
                    arg_path_length = 0;
2942
0
                }
2943
0
            }
2944
0
        }
2945
2946
0
        first = first->next();
2947
0
        second = second->next();
2948
2949
        // reset path length
2950
0
        if (first->str() == "," || second->str() == ",")
2951
0
            arg_path_length = path_length;
2952
0
    }
2953
2954
0
    return false;
2955
0
}
2956
2957
static bool isUnknownType(const Token* start, const Token* end)
2958
5.21k
{
2959
5.21k
    while (Token::Match(start, "const|volatile"))
2960
0
        start = start->next();
2961
5.21k
    start = skipScopeIdentifiers(start);
2962
5.21k
    if (start->tokAt(1) == end && !start->type() && !start->isStandardType())
2963
0
        return true;
2964
    // TODO: Try to deduce the type of the expression
2965
5.21k
    if (Token::Match(start, "decltype|typeof"))
2966
0
        return true;
2967
5.21k
    return false;
2968
5.21k
}
2969
2970
static const Token* getEnableIfReturnType(const Token* start)
2971
0
{
2972
0
    if (!start)
2973
0
        return nullptr;
2974
0
    for (const Token* tok = start->next(); precedes(tok, start->link()); tok = tok->next()) {
2975
0
        if (tok->link() && Token::Match(tok, "(|[|{|<")) {
2976
0
            tok = tok->link();
2977
0
            continue;
2978
0
        }
2979
0
        if (Token::simpleMatch(tok, ","))
2980
0
            return tok->next();
2981
0
    }
2982
0
    return nullptr;
2983
0
}
2984
2985
template<class Predicate>
2986
static bool checkReturns(const Function* function, bool unknown, bool emptyEnableIf, Predicate pred)
2987
7.13k
{
2988
7.13k
    if (!function)
2989
0
        return false;
2990
7.13k
    if (function->type != Function::eFunction && function->type != Function::eOperatorEqual)
2991
0
        return false;
2992
7.13k
    const Token* defStart = function->retDef;
2993
7.13k
    if (!defStart)
2994
0
        return unknown;
2995
7.13k
    const Token* defEnd = function->returnDefEnd();
2996
7.13k
    if (!defEnd)
2997
0
        return unknown;
2998
7.13k
    if (defEnd == defStart)
2999
0
        return unknown;
3000
7.13k
    if (pred(defStart, defEnd))
3001
1.91k
        return true;
3002
5.21k
    if (Token::Match(defEnd->tokAt(-1), "*|&|&&"))
3003
0
        return false;
3004
    // void STDCALL foo()
3005
5.21k
    while (defEnd->previous() != defStart && Token::Match(defEnd->tokAt(-2), "%name%|> %name%") &&
3006
5.21k
           !Token::Match(defEnd->tokAt(-2), "const|volatile"))
3007
0
        defEnd = defEnd->previous();
3008
    // enable_if
3009
5.21k
    const Token* enableIfEnd = nullptr;
3010
5.21k
    if (Token::simpleMatch(defEnd->previous(), ">"))
3011
0
        enableIfEnd = defEnd->previous();
3012
5.21k
    else if (Token::simpleMatch(defEnd->tokAt(-3), "> :: type"))
3013
0
        enableIfEnd = defEnd->tokAt(-3);
3014
5.21k
    if (enableIfEnd && enableIfEnd->link() &&
3015
5.21k
        Token::Match(enableIfEnd->link()->previous(), "enable_if|enable_if_t|EnableIf")) {
3016
0
        if (const Token* start = getEnableIfReturnType(enableIfEnd->link())) {
3017
0
            defStart = start;
3018
0
            defEnd = enableIfEnd;
3019
0
        } else {
3020
0
            return emptyEnableIf;
3021
0
        }
3022
0
    }
3023
5.21k
    assert(defEnd != defStart);
3024
5.21k
    if (pred(defStart, defEnd))
3025
0
        return true;
3026
5.21k
    if (isUnknownType(defStart, defEnd))
3027
0
        return unknown;
3028
5.21k
    return false;
3029
5.21k
}
Unexecuted instantiation: symboldatabase.cpp:bool checkReturns<Function::returnsConst(Function const*, bool)::$_6>(Function const*, bool, bool, Function::returnsConst(Function const*, bool)::$_6)
symboldatabase.cpp:bool checkReturns<Function::returnsReference(Function const*, bool, bool)::$_7>(Function const*, bool, bool, Function::returnsReference(Function const*, bool, bool)::$_7)
Line
Count
Source
2987
3.48k
{
2988
3.48k
    if (!function)
2989
0
        return false;
2990
3.48k
    if (function->type != Function::eFunction && function->type != Function::eOperatorEqual)
2991
0
        return false;
2992
3.48k
    const Token* defStart = function->retDef;
2993
3.48k
    if (!defStart)
2994
0
        return unknown;
2995
3.48k
    const Token* defEnd = function->returnDefEnd();
2996
3.48k
    if (!defEnd)
2997
0
        return unknown;
2998
3.48k
    if (defEnd == defStart)
2999
0
        return unknown;
3000
3.48k
    if (pred(defStart, defEnd))
3001
0
        return true;
3002
3.48k
    if (Token::Match(defEnd->tokAt(-1), "*|&|&&"))
3003
0
        return false;
3004
    // void STDCALL foo()
3005
3.48k
    while (defEnd->previous() != defStart && Token::Match(defEnd->tokAt(-2), "%name%|> %name%") &&
3006
3.48k
           !Token::Match(defEnd->tokAt(-2), "const|volatile"))
3007
0
        defEnd = defEnd->previous();
3008
    // enable_if
3009
3.48k
    const Token* enableIfEnd = nullptr;
3010
3.48k
    if (Token::simpleMatch(defEnd->previous(), ">"))
3011
0
        enableIfEnd = defEnd->previous();
3012
3.48k
    else if (Token::simpleMatch(defEnd->tokAt(-3), "> :: type"))
3013
0
        enableIfEnd = defEnd->tokAt(-3);
3014
3.48k
    if (enableIfEnd && enableIfEnd->link() &&
3015
3.48k
        Token::Match(enableIfEnd->link()->previous(), "enable_if|enable_if_t|EnableIf")) {
3016
0
        if (const Token* start = getEnableIfReturnType(enableIfEnd->link())) {
3017
0
            defStart = start;
3018
0
            defEnd = enableIfEnd;
3019
0
        } else {
3020
0
            return emptyEnableIf;
3021
0
        }
3022
0
    }
3023
3.48k
    assert(defEnd != defStart);
3024
3.48k
    if (pred(defStart, defEnd))
3025
0
        return true;
3026
3.48k
    if (isUnknownType(defStart, defEnd))
3027
0
        return unknown;
3028
3.48k
    return false;
3029
3.48k
}
Unexecuted instantiation: symboldatabase.cpp:bool checkReturns<Function::returnsPointer(Function const*, bool)::$_8>(Function const*, bool, bool, Function::returnsPointer(Function const*, bool)::$_8)
symboldatabase.cpp:bool checkReturns<Function::returnsStandardType(Function const*, bool)::$_9>(Function const*, bool, bool, Function::returnsStandardType(Function const*, bool)::$_9)
Line
Count
Source
2987
1.91k
{
2988
1.91k
    if (!function)
2989
0
        return false;
2990
1.91k
    if (function->type != Function::eFunction && function->type != Function::eOperatorEqual)
2991
0
        return false;
2992
1.91k
    const Token* defStart = function->retDef;
2993
1.91k
    if (!defStart)
2994
0
        return unknown;
2995
1.91k
    const Token* defEnd = function->returnDefEnd();
2996
1.91k
    if (!defEnd)
2997
0
        return unknown;
2998
1.91k
    if (defEnd == defStart)
2999
0
        return unknown;
3000
1.91k
    if (pred(defStart, defEnd))
3001
1.91k
        return true;
3002
0
    if (Token::Match(defEnd->tokAt(-1), "*|&|&&"))
3003
0
        return false;
3004
    // void STDCALL foo()
3005
0
    while (defEnd->previous() != defStart && Token::Match(defEnd->tokAt(-2), "%name%|> %name%") &&
3006
0
           !Token::Match(defEnd->tokAt(-2), "const|volatile"))
3007
0
        defEnd = defEnd->previous();
3008
    // enable_if
3009
0
    const Token* enableIfEnd = nullptr;
3010
0
    if (Token::simpleMatch(defEnd->previous(), ">"))
3011
0
        enableIfEnd = defEnd->previous();
3012
0
    else if (Token::simpleMatch(defEnd->tokAt(-3), "> :: type"))
3013
0
        enableIfEnd = defEnd->tokAt(-3);
3014
0
    if (enableIfEnd && enableIfEnd->link() &&
3015
0
        Token::Match(enableIfEnd->link()->previous(), "enable_if|enable_if_t|EnableIf")) {
3016
0
        if (const Token* start = getEnableIfReturnType(enableIfEnd->link())) {
3017
0
            defStart = start;
3018
0
            defEnd = enableIfEnd;
3019
0
        } else {
3020
0
            return emptyEnableIf;
3021
0
        }
3022
0
    }
3023
0
    assert(defEnd != defStart);
3024
0
    if (pred(defStart, defEnd))
3025
0
        return true;
3026
0
    if (isUnknownType(defStart, defEnd))
3027
0
        return unknown;
3028
0
    return false;
3029
0
}
symboldatabase.cpp:bool checkReturns<Function::returnsVoid(Function const*, bool)::$_10>(Function const*, bool, bool, Function::returnsVoid(Function const*, bool)::$_10)
Line
Count
Source
2987
1.73k
{
2988
1.73k
    if (!function)
2989
0
        return false;
2990
1.73k
    if (function->type != Function::eFunction && function->type != Function::eOperatorEqual)
2991
0
        return false;
2992
1.73k
    const Token* defStart = function->retDef;
2993
1.73k
    if (!defStart)
2994
0
        return unknown;
2995
1.73k
    const Token* defEnd = function->returnDefEnd();
2996
1.73k
    if (!defEnd)
2997
0
        return unknown;
2998
1.73k
    if (defEnd == defStart)
2999
0
        return unknown;
3000
1.73k
    if (pred(defStart, defEnd))
3001
0
        return true;
3002
1.73k
    if (Token::Match(defEnd->tokAt(-1), "*|&|&&"))
3003
0
        return false;
3004
    // void STDCALL foo()
3005
1.73k
    while (defEnd->previous() != defStart && Token::Match(defEnd->tokAt(-2), "%name%|> %name%") &&
3006
1.73k
           !Token::Match(defEnd->tokAt(-2), "const|volatile"))
3007
0
        defEnd = defEnd->previous();
3008
    // enable_if
3009
1.73k
    const Token* enableIfEnd = nullptr;
3010
1.73k
    if (Token::simpleMatch(defEnd->previous(), ">"))
3011
0
        enableIfEnd = defEnd->previous();
3012
1.73k
    else if (Token::simpleMatch(defEnd->tokAt(-3), "> :: type"))
3013
0
        enableIfEnd = defEnd->tokAt(-3);
3014
1.73k
    if (enableIfEnd && enableIfEnd->link() &&
3015
1.73k
        Token::Match(enableIfEnd->link()->previous(), "enable_if|enable_if_t|EnableIf")) {
3016
0
        if (const Token* start = getEnableIfReturnType(enableIfEnd->link())) {
3017
0
            defStart = start;
3018
0
            defEnd = enableIfEnd;
3019
0
        } else {
3020
0
            return emptyEnableIf;
3021
0
        }
3022
0
    }
3023
1.73k
    assert(defEnd != defStart);
3024
1.73k
    if (pred(defStart, defEnd))
3025
0
        return true;
3026
1.73k
    if (isUnknownType(defStart, defEnd))
3027
0
        return unknown;
3028
1.73k
    return false;
3029
1.73k
}
3030
3031
bool Function::returnsConst(const Function* function, bool unknown)
3032
0
{
3033
0
    return checkReturns(function, unknown, false, [](const Token* defStart, const Token* defEnd) {
3034
0
        return Token::findsimplematch(defStart, "const", defEnd);
3035
0
    });
3036
0
}
3037
3038
bool Function::returnsReference(const Function* function, bool unknown, bool includeRValueRef)
3039
3.48k
{
3040
6.96k
    return checkReturns(function, unknown, false, [includeRValueRef](UNUSED const Token* defStart, const Token* defEnd) {
3041
6.96k
        return includeRValueRef ? Token::Match(defEnd->previous(), "&|&&") : Token::simpleMatch(defEnd->previous(), "&");
3042
6.96k
    });
3043
3.48k
}
3044
3045
bool Function::returnsPointer(const Function* function, bool unknown)
3046
0
{
3047
0
    return checkReturns(function, unknown, false, [](const Token* /*defStart*/, const Token* defEnd) {
3048
0
        return Token::simpleMatch(defEnd->previous(), "*");
3049
0
    });
3050
0
}
3051
3052
bool Function::returnsStandardType(const Function* function, bool unknown)
3053
1.91k
{
3054
1.91k
    return checkReturns(function, unknown, true, [](const Token* /*defStart*/, const Token* defEnd) {
3055
1.91k
        return defEnd->previous() && defEnd->previous()->isStandardType();
3056
1.91k
    });
3057
1.91k
}
3058
3059
bool Function::returnsVoid(const Function* function, bool unknown)
3060
1.73k
{
3061
3.47k
    return checkReturns(function, unknown, true, [](const Token* /*defStart*/, const Token* defEnd) {
3062
3.47k
        return Token::simpleMatch(defEnd->previous(), "void");
3063
3.47k
    });
3064
1.73k
}
3065
3066
std::vector<const Token*> Function::findReturns(const Function* f)
3067
1.73k
{
3068
1.73k
    std::vector<const Token*> result;
3069
1.73k
    if (!f)
3070
0
        return result;
3071
1.73k
    const Scope* scope = f->functionScope;
3072
1.73k
    if (!scope)
3073
0
        return result;
3074
1.73k
    if (!scope->bodyStart)
3075
0
        return result;
3076
35.9k
    for (const Token* tok = scope->bodyStart->next(); tok && tok != scope->bodyEnd; tok = tok->next()) {
3077
34.1k
        if (tok->str() == "{" && tok->scope() &&
3078
34.1k
            (tok->scope()->type == Scope::eLambda || tok->scope()->type == Scope::eClass)) {
3079
0
            tok = tok->link();
3080
0
            continue;
3081
0
        }
3082
34.1k
        if (Token::simpleMatch(tok->astParent(), "return")) {
3083
1.91k
            result.push_back(tok);
3084
1.91k
        }
3085
        // Skip lambda functions since the scope may not be set correctly
3086
34.1k
        const Token* lambdaEndToken = findLambdaEndToken(tok);
3087
34.1k
        if (lambdaEndToken) {
3088
0
            tok = lambdaEndToken;
3089
0
        }
3090
34.1k
    }
3091
1.73k
    return result;
3092
1.73k
}
3093
3094
const Token * Function::constructorMemberInitialization() const
3095
4.64k
{
3096
4.64k
    if (!isConstructor() || !arg)
3097
4.64k
        return nullptr;
3098
0
    if (Token::simpleMatch(arg->link(), ") :"))
3099
0
        return arg->link()->next();
3100
0
    if (Token::simpleMatch(arg->link(), ") noexcept (") && arg->link()->linkAt(2)->strAt(1) == ":")
3101
0
        return arg->link()->linkAt(2)->next();
3102
0
    return nullptr;
3103
0
}
3104
3105
bool Function::isSafe(const Settings *settings) const
3106
2.90k
{
3107
2.90k
    if (settings->safeChecks.externalFunctions) {
3108
0
        if (nestedIn->type == Scope::ScopeType::eNamespace && token->fileIndex() != 0)
3109
0
            return true;
3110
0
        if (nestedIn->type == Scope::ScopeType::eGlobal && (token->fileIndex() != 0 || !isStatic()))
3111
0
            return true;
3112
0
    }
3113
3114
2.90k
    if (settings->safeChecks.internalFunctions) {
3115
0
        if (nestedIn->type == Scope::ScopeType::eNamespace && token->fileIndex() == 0)
3116
0
            return true;
3117
0
        if (nestedIn->type == Scope::ScopeType::eGlobal && (token->fileIndex() == 0 || isStatic()))
3118
0
            return true;
3119
0
    }
3120
3121
2.90k
    if (settings->safeChecks.classes && access == AccessControl::Public && (nestedIn->type == Scope::ScopeType::eClass || nestedIn->type == Scope::ScopeType::eStruct))
3122
0
        return true;
3123
3124
2.90k
    return false;
3125
2.90k
}
3126
3127
Function* SymbolDatabase::addGlobalFunction(Scope*& scope, const Token*& tok, const Token *argStart, const Token* funcStart)
3128
1.73k
{
3129
1.73k
    Function* function = nullptr;
3130
    // Lambda functions are always unique
3131
1.73k
    if (tok->str() != "[") {
3132
1.73k
        auto range = scope->functionMap.equal_range(tok->str());
3133
1.73k
        for (std::multimap<std::string, const Function*>::const_iterator it = range.first; it != range.second; ++it) {
3134
0
            const Function *f = it->second;
3135
0
            if (f->hasBody())
3136
0
                continue;
3137
0
            if (f->argsMatch(scope, f->argDef, argStart, emptyString, 0)) {
3138
0
                function = const_cast<Function *>(it->second);
3139
0
                break;
3140
0
            }
3141
0
        }
3142
1.73k
    }
3143
3144
1.73k
    if (!function)
3145
1.73k
        function = addGlobalFunctionDecl(scope, tok, argStart, funcStart);
3146
3147
1.73k
    function->arg = argStart;
3148
1.73k
    function->token = funcStart;
3149
1.73k
    function->hasBody(true);
3150
3151
1.73k
    addNewFunction(&scope, &tok);
3152
3153
1.73k
    if (scope) {
3154
1.73k
        scope->function = function;
3155
1.73k
        function->functionScope = scope;
3156
1.73k
        return function;
3157
1.73k
    }
3158
0
    return nullptr;
3159
1.73k
}
3160
3161
Function* SymbolDatabase::addGlobalFunctionDecl(Scope*& scope, const Token *tok, const Token *argStart, const Token* funcStart)
3162
1.73k
{
3163
1.73k
    Function function(&mTokenizer, tok, scope, funcStart, argStart);
3164
1.73k
    scope->addFunction(std::move(function));
3165
1.73k
    return &scope->functionList.back();
3166
1.73k
}
3167
3168
void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const Token *argStart)
3169
0
{
3170
0
    const bool destructor((*tok)->previous()->str() == "~");
3171
0
    const bool has_const(argStart->link()->strAt(1) == "const");
3172
0
    const bool lval(argStart->link()->strAt(has_const ? 2 : 1) == "&");
3173
0
    const bool rval(argStart->link()->strAt(has_const ? 2 : 1) == "&&");
3174
0
    int count = 0;
3175
0
    std::string path;
3176
0
    unsigned int path_length = 0;
3177
0
    const Token *tok1 = (*tok);
3178
3179
0
    if (destructor)
3180
0
        tok1 = tok1->previous();
3181
3182
    // back up to head of path
3183
0
    while (tok1 && tok1->previous() && tok1->previous()->str() == "::" && tok1->tokAt(-2) &&
3184
0
           ((tok1->tokAt(-2)->isName() && !tok1->tokAt(-2)->isStandardType()) ||
3185
0
            (tok1->strAt(-2) == ">" && tok1->linkAt(-2) && Token::Match(tok1->linkAt(-2)->previous(), "%name%")))) {
3186
0
        count++;
3187
0
        const Token * tok2 = tok1->tokAt(-2);
3188
0
        if (tok2->str() == ">")
3189
0
            tok2 = tok2->link()->previous();
3190
3191
0
        if (tok2) {
3192
0
            do {
3193
0
                path = tok1->previous()->str() + " " + path;
3194
0
                tok1 = tok1->previous();
3195
0
                path_length++;
3196
0
            } while (tok1 != tok2);
3197
0
        } else
3198
0
            return; // syntax error ?
3199
0
    }
3200
3201
    // syntax error?
3202
0
    if (!tok1)
3203
0
        return;
3204
3205
    // add global namespace if present
3206
0
    if (tok1->strAt(-1) == "::") {
3207
0
        path_length++;
3208
0
        path.insert(0, ":: ");
3209
0
    }
3210
3211
0
    std::list<Scope>::iterator it1;
3212
3213
    // search for match
3214
0
    for (it1 = scopeList.begin(); it1 != scopeList.end(); ++it1) {
3215
0
        Scope *scope1 = &(*it1);
3216
3217
0
        bool match = false;
3218
3219
        // check in namespace if using found
3220
0
        if (*scope == scope1 && !scope1->usingList.empty()) {
3221
0
            std::vector<Scope::UsingInfo>::const_iterator it2;
3222
0
            for (it2 = scope1->usingList.cbegin(); it2 != scope1->usingList.cend(); ++it2) {
3223
0
                if (it2->scope) {
3224
0
                    Function * func = findFunctionInScope(tok1, it2->scope, path, path_length);
3225
0
                    if (func) {
3226
0
                        if (!func->hasBody()) {
3227
0
                            const Token *closeParen = (*tok)->next()->link();
3228
0
                            if (closeParen) {
3229
0
                                const Token *eq = mTokenizer.isFunctionHead(closeParen, ";");
3230
0
                                if (eq && Token::simpleMatch(eq->tokAt(-2), "= default ;")) {
3231
0
                                    func->isDefault(true);
3232
0
                                    return;
3233
0
                                }
3234
0
                            }
3235
0
                            func->hasBody(true);
3236
0
                            func->token = *tok;
3237
0
                            func->arg = argStart;
3238
0
                            addNewFunction(scope, tok);
3239
0
                            if (*scope) {
3240
0
                                (*scope)->functionOf = func->nestedIn;
3241
0
                                (*scope)->function = func;
3242
0
                                (*scope)->function->functionScope = *scope;
3243
0
                            }
3244
0
                            return;
3245
0
                        }
3246
0
                    }
3247
0
                }
3248
0
            }
3249
0
        }
3250
3251
0
        if (scope1->className == tok1->str() && (scope1->type != Scope::eFunction)) {
3252
            // do the scopes match (same scope) or do their names match (multiple namespaces)
3253
0
            if ((*scope == scope1->nestedIn) || (*scope &&
3254
0
                                                 (*scope)->className == scope1->nestedIn->className &&
3255
0
                                                 !(*scope)->className.empty() &&
3256
0
                                                 (*scope)->type == scope1->nestedIn->type)) {
3257
3258
                // nested scopes => check that they match
3259
0
                {
3260
0
                    const Scope *s1 = *scope;
3261
0
                    const Scope *s2 = scope1->nestedIn;
3262
0
                    while (s1 && s2) {
3263
0
                        if (s1->className != s2->className)
3264
0
                            break;
3265
0
                        s1 = s1->nestedIn;
3266
0
                        s2 = s2->nestedIn;
3267
0
                    }
3268
                    // Not matching scopes
3269
0
                    if (s1 || s2)
3270
0
                        continue;
3271
0
                }
3272
3273
0
                Scope *scope2 = scope1;
3274
3275
0
                while (scope2 && count > 1) {
3276
0
                    count--;
3277
0
                    if (tok1->strAt(1) == "<")
3278
0
                        tok1 = tok1->linkAt(1)->tokAt(2);
3279
0
                    else
3280
0
                        tok1 = tok1->tokAt(2);
3281
0
                    scope2 = scope2->findRecordInNestedList(tok1->str());
3282
0
                }
3283
3284
0
                if (count == 1 && scope2) {
3285
0
                    match = true;
3286
0
                    scope1 = scope2;
3287
0
                }
3288
0
            }
3289
0
        }
3290
3291
0
        if (match) {
3292
0
            auto range = scope1->functionMap.equal_range((*tok)->str());
3293
0
            for (std::multimap<std::string, const Function*>::const_iterator it = range.first; it != range.second; ++it) {
3294
0
                Function * func = const_cast<Function *>(it->second);
3295
0
                if (!func->hasBody()) {
3296
0
                    if (func->argsMatch(scope1, func->argDef, (*tok)->next(), path, path_length)) {
3297
0
                        const Token *closeParen = (*tok)->next()->link();
3298
0
                        if (closeParen) {
3299
0
                            const Token *eq = mTokenizer.isFunctionHead(closeParen, ";");
3300
0
                            if (eq && Token::simpleMatch(eq->tokAt(-2), "= default ;")) {
3301
0
                                func->isDefault(true);
3302
0
                                return;
3303
0
                            }
3304
0
                            if (func->type == Function::eDestructor && destructor) {
3305
0
                                func->hasBody(true);
3306
0
                            } else if (func->type != Function::eDestructor && !destructor) {
3307
                                // normal function?
3308
0
                                const bool hasConstKeyword = closeParen->next()->str() == "const";
3309
0
                                if ((func->isConst() == hasConstKeyword) &&
3310
0
                                    (func->hasLvalRefQualifier() == lval) &&
3311
0
                                    (func->hasRvalRefQualifier() == rval)) {
3312
0
                                    func->hasBody(true);
3313
0
                                }
3314
0
                            }
3315
0
                        }
3316
3317
0
                        if (func->hasBody()) {
3318
0
                            func->token = *tok;
3319
0
                            func->arg = argStart;
3320
0
                            addNewFunction(scope, tok);
3321
0
                            if (*scope) {
3322
0
                                (*scope)->functionOf = scope1;
3323
0
                                (*scope)->function = func;
3324
0
                                (*scope)->function->functionScope = *scope;
3325
0
                            }
3326
0
                            return;
3327
0
                        }
3328
0
                    }
3329
0
                }
3330
0
            }
3331
0
        }
3332
0
    }
3333
3334
    // class function of unknown class
3335
0
    addNewFunction(scope, tok);
3336
0
}
3337
3338
void SymbolDatabase::addNewFunction(Scope **scope, const Token **tok)
3339
1.73k
{
3340
1.73k
    const Token *tok1 = *tok;
3341
1.73k
    scopeList.emplace_back(this, tok1, *scope);
3342
1.73k
    Scope *newScope = &scopeList.back();
3343
3344
    // find start of function '{'
3345
1.73k
    bool foundInitList = false;
3346
6.95k
    while (tok1 && tok1->str() != "{" && tok1->str() != ";") {
3347
5.21k
        if (tok1->link() && Token::Match(tok1, "(|[|<")) {
3348
1.73k
            tok1 = tok1->link();
3349
3.47k
        } else if (foundInitList && Token::Match(tok1, "%name%|> {") && Token::Match(tok1->linkAt(1), "} ,|{")) {
3350
0
            tok1 = tok1->linkAt(1);
3351
3.47k
        } else {
3352
3.47k
            if (tok1->str() == ":")
3353
0
                foundInitList = true;
3354
3.47k
            tok1 = tok1->next();
3355
3.47k
        }
3356
5.21k
    }
3357
3358
1.73k
    if (tok1 && tok1->str() == "{") {
3359
1.73k
        newScope->setBodyStartEnd(tok1);
3360
3361
        // syntax error?
3362
1.73k
        if (!newScope->bodyEnd) {
3363
0
            mTokenizer.unmatchedToken(tok1);
3364
1.73k
        } else {
3365
1.73k
            (*scope)->nestedList.push_back(newScope);
3366
1.73k
            *scope = newScope;
3367
1.73k
        }
3368
1.73k
    } else if (tok1 && Token::Match(tok1->tokAt(-2), "= default|delete ;")) {
3369
0
        scopeList.pop_back();
3370
0
    } else {
3371
0
        throw InternalError(*tok, "Analysis failed (function not recognized). If the code is valid then please report this failure.");
3372
0
    }
3373
1.73k
    *tok = tok1;
3374
1.73k
}
3375
3376
bool Type::isClassType() const
3377
0
{
3378
0
    return classScope && classScope->type == Scope::ScopeType::eClass;
3379
0
}
3380
3381
bool Type::isEnumType() const
3382
0
{
3383
    //We explicitly check for "enum" because a forward declared enum doesn't get its own scope
3384
0
    return (classDef && classDef->str() == "enum") ||
3385
0
           (classScope && classScope->type == Scope::ScopeType::eEnum);
3386
0
}
3387
3388
bool Type::isStructType() const
3389
0
{
3390
0
    return classScope && classScope->type == Scope::ScopeType::eStruct;
3391
0
}
3392
3393
bool Type::isUnionType() const
3394
0
{
3395
0
    return classScope && classScope->type == Scope::ScopeType::eUnion;
3396
0
}
3397
3398
const Token *Type::initBaseInfo(const Token *tok, const Token *tok1)
3399
0
{
3400
    // goto initial '{'
3401
0
    const Token *tok2 = tok1;
3402
0
    while (tok2 && tok2->str() != "{") {
3403
        // skip unsupported templates
3404
0
        if (tok2->str() == "<")
3405
0
            tok2 = tok2->link();
3406
3407
        // check for base classes
3408
0
        else if (Token::Match(tok2, ":|,")) {
3409
0
            tok2 = tok2->next();
3410
3411
            // check for invalid code
3412
0
            if (!tok2 || !tok2->next())
3413
0
                return nullptr;
3414
3415
0
            Type::BaseInfo base;
3416
3417
0
            if (tok2->str() == "virtual") {
3418
0
                base.isVirtual = true;
3419
0
                tok2 = tok2->next();
3420
0
            }
3421
3422
0
            if (tok2->str() == "public") {
3423
0
                base.access = AccessControl::Public;
3424
0
                tok2 = tok2->next();
3425
0
            } else if (tok2->str() == "protected") {
3426
0
                base.access = AccessControl::Protected;
3427
0
                tok2 = tok2->next();
3428
0
            } else if (tok2->str() == "private") {
3429
0
                base.access = AccessControl::Private;
3430
0
                tok2 = tok2->next();
3431
0
            } else {
3432
0
                if (tok->str() == "class")
3433
0
                    base.access = AccessControl::Private;
3434
0
                else if (tok->str() == "struct")
3435
0
                    base.access = AccessControl::Public;
3436
0
            }
3437
0
            if (!tok2)
3438
0
                return nullptr;
3439
0
            if (tok2->str() == "virtual") {
3440
0
                base.isVirtual = true;
3441
0
                tok2 = tok2->next();
3442
0
            }
3443
0
            if (!tok2)
3444
0
                return nullptr;
3445
3446
0
            base.nameTok = tok2;
3447
            // handle global namespace
3448
0
            if (tok2->str() == "::") {
3449
0
                tok2 = tok2->next();
3450
0
            }
3451
3452
            // handle derived base classes
3453
0
            while (Token::Match(tok2, "%name% ::")) {
3454
0
                tok2 = tok2->tokAt(2);
3455
0
            }
3456
0
            if (!tok2)
3457
0
                return nullptr;
3458
3459
0
            base.name = tok2->str();
3460
3461
0
            tok2 = tok2->next();
3462
            // add unhandled templates
3463
0
            if (tok2 && tok2->link() && tok2->str() == "<") {
3464
0
                for (const Token* const end = tok2->link()->next(); tok2 != end; tok2 = tok2->next()) {
3465
0
                    base.name += tok2->str();
3466
0
                }
3467
0
            }
3468
3469
0
            const Type * baseType = classScope->check->findType(base.nameTok, enclosingScope);
3470
0
            if (baseType && !baseType->findDependency(this))
3471
0
                base.type = baseType;
3472
3473
            // save pattern for base class name
3474
0
            derivedFrom.push_back(std::move(base));
3475
0
        } else
3476
0
            tok2 = tok2->next();
3477
0
    }
3478
3479
0
    return tok2;
3480
0
}
3481
3482
std::string Type::name() const
3483
0
{
3484
0
    const Token* start = classDef->next();
3485
0
    if (classScope && classScope->enumClass && isEnumType())
3486
0
        start = start->tokAt(1);
3487
0
    else if (start->str() == "class")
3488
0
        start = start->tokAt(1);
3489
0
    else if (!start->isName())
3490
0
        return emptyString;
3491
0
    const Token* next = start;
3492
0
    while (Token::Match(next, "::|<|>|(|)|[|]|*|&|&&|%name%")) {
3493
0
        if (Token::Match(next, "<|(|[") && next->link())
3494
0
            next = next->link();
3495
0
        next = next->next();
3496
0
    }
3497
0
    std::string result;
3498
0
    for (const Token* tok = start; tok != next; tok = tok->next()) {
3499
0
        if (!result.empty())
3500
0
            result += ' ';
3501
0
        result += tok->str();
3502
0
    }
3503
0
    return result;
3504
0
}
3505
3506
void SymbolDatabase::debugMessage(const Token *tok, const std::string &type, const std::string &msg) const
3507
0
{
3508
0
    if (tok && mSettings.debugwarnings && mErrorLogger) {
3509
0
        const std::list<const Token*> locationList(1, tok);
3510
0
        const ErrorMessage errmsg(locationList, &mTokenizer.list,
3511
0
                                  Severity::debug,
3512
0
                                  type,
3513
0
                                  msg,
3514
0
                                  Certainty::normal);
3515
0
        mErrorLogger->reportErr(errmsg);
3516
0
    }
3517
0
}
3518
3519
const Function* Type::getFunction(const std::string& funcName) const
3520
0
{
3521
0
    if (classScope) {
3522
0
        const std::multimap<std::string, const Function *>::const_iterator it = classScope->functionMap.find(funcName);
3523
3524
0
        if (it != classScope->functionMap.end())
3525
0
            return it->second;
3526
0
    }
3527
3528
0
    for (const Type::BaseInfo & i : derivedFrom) {
3529
0
        if (i.type) {
3530
0
            const Function* const func = i.type->getFunction(funcName);
3531
0
            if (func)
3532
0
                return func;
3533
0
        }
3534
0
    }
3535
0
    return nullptr;
3536
0
}
3537
3538
bool Type::hasCircularDependencies(std::set<BaseInfo>* ancestors) const
3539
0
{
3540
0
    std::set<BaseInfo> knownAncestors;
3541
0
    if (!ancestors) {
3542
0
        ancestors=&knownAncestors;
3543
0
    }
3544
0
    for (std::vector<BaseInfo>::const_iterator parent=derivedFrom.cbegin(); parent!=derivedFrom.cend(); ++parent) {
3545
0
        if (!parent->type)
3546
0
            continue;
3547
0
        if (this==parent->type)
3548
0
            return true;
3549
0
        if (ancestors->find(*parent)!=ancestors->end())
3550
0
            return true;
3551
3552
0
        ancestors->insert(*parent);
3553
0
        if (parent->type->hasCircularDependencies(ancestors))
3554
0
            return true;
3555
0
    }
3556
0
    return false;
3557
0
}
3558
3559
bool Type::findDependency(const Type* ancestor) const
3560
0
{
3561
0
    return this == ancestor || std::any_of(derivedFrom.cbegin(), derivedFrom.cend(), [&](const BaseInfo& d) {
3562
0
        return d.type && (d.type == this || d.type->findDependency(ancestor));
3563
0
    });
3564
0
}
3565
3566
bool Type::isDerivedFrom(const std::string & ancestor) const
3567
0
{
3568
0
    for (std::vector<BaseInfo>::const_iterator parent=derivedFrom.cbegin(); parent!=derivedFrom.cend(); ++parent) {
3569
0
        if (parent->name == ancestor)
3570
0
            return true;
3571
0
        if (parent->type && parent->type->isDerivedFrom(ancestor))
3572
0
            return true;
3573
0
    }
3574
0
    return false;
3575
0
}
3576
3577
bool Variable::arrayDimensions(const Settings* settings, bool& isContainer)
3578
6.80k
{
3579
6.80k
    isContainer = false;
3580
6.80k
    const Library::Container* container = (mTypeStartToken && mTypeStartToken->isCpp()) ? settings->library.detectContainer(mTypeStartToken) : nullptr;
3581
6.80k
    if (container && container->arrayLike_indexOp && container->size_templateArgNo > 0) {
3582
0
        const Token* tok = Token::findsimplematch(mTypeStartToken, "<");
3583
0
        if (tok) {
3584
0
            isContainer = true;
3585
0
            Dimension dimension_;
3586
0
            tok = tok->next();
3587
0
            for (int i = 0; i < container->size_templateArgNo && tok; i++) {
3588
0
                tok = tok->nextTemplateArgument();
3589
0
            }
3590
0
            if (Token::Match(tok, "%num% [,>]")) {
3591
0
                dimension_.tok = tok;
3592
0
                dimension_.known = true;
3593
0
                dimension_.num = MathLib::toLongNumber(tok->str());
3594
0
            } else if (tok) {
3595
0
                dimension_.tok = tok;
3596
0
                dimension_.known = false;
3597
0
            }
3598
0
            mDimensions.push_back(dimension_);
3599
0
            return true;
3600
0
        }
3601
0
    }
3602
3603
6.80k
    const Token *dim = mNameToken;
3604
6.80k
    if (!dim) {
3605
        // Argument without name
3606
0
        dim = mTypeEndToken;
3607
        // back up to start of array dimensions
3608
0
        while (dim && dim->str() == "]")
3609
0
            dim = dim->link()->previous();
3610
0
    }
3611
6.80k
    if (dim)
3612
6.80k
        dim = dim->next();
3613
6.80k
    if (dim && dim->str() == ")")
3614
0
        dim = dim->next();
3615
3616
6.80k
    bool arr = false;
3617
6.80k
    while (dim && dim->next() && dim->str() == "[") {
3618
0
        Dimension dimension_;
3619
0
        dimension_.known = false;
3620
        // check for empty array dimension []
3621
0
        if (dim->next()->str() != "]") {
3622
0
            dimension_.tok = dim->astOperand2();
3623
0
            ValueFlow::valueFlowConstantFoldAST(const_cast<Token *>(dimension_.tok), settings);
3624
0
            if (dimension_.tok && dimension_.tok->hasKnownIntValue()) {
3625
0
                dimension_.num = dimension_.tok->getKnownIntValue();
3626
0
                dimension_.known = true;
3627
0
            }
3628
0
        }
3629
0
        mDimensions.push_back(dimension_);
3630
0
        dim = dim->link()->next();
3631
0
        arr = true;
3632
0
    }
3633
6.80k
    return arr;
3634
6.80k
}
3635
3636
static std::string scopeTypeToString(Scope::ScopeType type)
3637
0
{
3638
0
    switch (type) {
3639
0
    case Scope::ScopeType::eGlobal:
3640
0
        return "Global";
3641
0
    case Scope::ScopeType::eClass:
3642
0
        return "Class";
3643
0
    case Scope::ScopeType::eStruct:
3644
0
        return "Struct";
3645
0
    case Scope::ScopeType::eUnion:
3646
0
        return "Union";
3647
0
    case Scope::ScopeType::eNamespace:
3648
0
        return "Namespace";
3649
0
    case Scope::ScopeType::eFunction:
3650
0
        return "Function";
3651
0
    case Scope::ScopeType::eIf:
3652
0
        return "If";
3653
0
    case Scope::ScopeType::eElse:
3654
0
        return "Else";
3655
0
    case Scope::ScopeType::eFor:
3656
0
        return "For";
3657
0
    case Scope::ScopeType::eWhile:
3658
0
        return "While";
3659
0
    case Scope::ScopeType::eDo:
3660
0
        return "Do";
3661
0
    case Scope::ScopeType::eSwitch:
3662
0
        return "Switch";
3663
0
    case Scope::ScopeType::eTry:
3664
0
        return "Try";
3665
0
    case Scope::ScopeType::eCatch:
3666
0
        return "Catch";
3667
0
    case Scope::ScopeType::eUnconditional:
3668
0
        return "Unconditional";
3669
0
    case Scope::ScopeType::eLambda:
3670
0
        return "Lambda";
3671
0
    case Scope::ScopeType::eEnum:
3672
0
        return "Enum";
3673
0
    }
3674
0
    return "Unknown";
3675
0
}
3676
3677
static std::ostream & operator << (std::ostream & s, Scope::ScopeType type)
3678
0
{
3679
0
    s << scopeTypeToString(type);
3680
0
    return s;
3681
0
}
3682
3683
static std::string accessControlToString(AccessControl access)
3684
0
{
3685
0
    switch (access) {
3686
0
    case AccessControl::Public:
3687
0
        return "Public";
3688
0
    case AccessControl::Protected:
3689
0
        return "Protected";
3690
0
    case AccessControl::Private:
3691
0
        return "Private";
3692
0
    case AccessControl::Global:
3693
0
        return "Global";
3694
0
    case AccessControl::Namespace:
3695
0
        return "Namespace";
3696
0
    case AccessControl::Argument:
3697
0
        return "Argument";
3698
0
    case AccessControl::Local:
3699
0
        return "Local";
3700
0
    case AccessControl::Throw:
3701
0
        return "Throw";
3702
0
    }
3703
0
    return "Unknown";
3704
0
}
3705
3706
static std::string tokenToString(const Token* tok, const Tokenizer& tokenizer)
3707
0
{
3708
0
    std::ostringstream oss;
3709
0
    if (tok) {
3710
0
        oss << tok->str() << " ";
3711
0
        oss << tokenizer.list.fileLine(tok) << " ";
3712
0
    }
3713
0
    oss << tok;
3714
0
    return oss.str();
3715
0
}
3716
3717
static std::string scopeToString(const Scope* scope, const Tokenizer& tokenizer)
3718
0
{
3719
0
    std::ostringstream oss;
3720
0
    if (scope) {
3721
0
        oss << scope->type << " ";
3722
0
        if (!scope->className.empty())
3723
0
            oss << scope->className << " ";
3724
0
        if (scope->classDef)
3725
0
            oss << tokenizer.list.fileLine(scope->classDef) << " ";
3726
0
    }
3727
0
    oss << scope;
3728
0
    return oss.str();
3729
0
}
3730
3731
static std::string tokenType(const Token * tok)
3732
0
{
3733
0
    std::ostringstream oss;
3734
0
    if (tok) {
3735
0
        if (tok->isUnsigned())
3736
0
            oss << "unsigned ";
3737
0
        else if (tok->isSigned())
3738
0
            oss << "signed ";
3739
0
        if (tok->isComplex())
3740
0
            oss << "_Complex ";
3741
0
        if (tok->isLong())
3742
0
            oss << "long ";
3743
0
        oss << tok->str();
3744
0
    }
3745
0
    return oss.str();
3746
0
}
3747
3748
void SymbolDatabase::printVariable(const Variable *var, const char *indent) const
3749
0
{
3750
0
    std::cout << indent << "mNameToken: " << tokenToString(var->nameToken(), mTokenizer) << std::endl;
3751
0
    if (var->nameToken()) {
3752
0
        std::cout << indent << "    declarationId: " << var->declarationId() << std::endl;
3753
0
    }
3754
0
    std::cout << indent << "mTypeStartToken: " << tokenToString(var->typeStartToken(), mTokenizer) << std::endl;
3755
0
    std::cout << indent << "mTypeEndToken: " << tokenToString(var->typeEndToken(), mTokenizer) << std::endl;
3756
3757
0
    if (var->typeStartToken()) {
3758
0
        const Token * autoTok = nullptr;
3759
0
        std::cout << indent << "   ";
3760
0
        for (const Token * tok = var->typeStartToken(); tok != var->typeEndToken()->next(); tok = tok->next()) {
3761
0
            std::cout << " " << tokenType(tok);
3762
0
            if (tok->str() == "auto")
3763
0
                autoTok = tok;
3764
0
        }
3765
0
        std::cout << std::endl;
3766
0
        if (autoTok) {
3767
0
            const ValueType * valueType = autoTok->valueType();
3768
0
            std::cout << indent << "    auto valueType: " << valueType << std::endl;
3769
0
            if (var->typeStartToken()->valueType()) {
3770
0
                std::cout << indent << "        " << valueType->str() << std::endl;
3771
0
            }
3772
0
        }
3773
0
    } else if (var->valueType()) {
3774
0
        std::cout << indent << "   " << var->valueType()->str() << std::endl;
3775
0
    }
3776
0
    std::cout << indent << "mIndex: " << var->index() << std::endl;
3777
0
    std::cout << indent << "mAccess: " << accessControlToString(var->accessControl()) << std::endl;
3778
0
    std::cout << indent << "mFlags: " << std::endl;
3779
0
    std::cout << indent << "    isMutable: " << var->isMutable() << std::endl;
3780
0
    std::cout << indent << "    isStatic: " << var->isStatic() << std::endl;
3781
0
    std::cout << indent << "    isExtern: " << var->isExtern() << std::endl;
3782
0
    std::cout << indent << "    isLocal: " << var->isLocal() << std::endl;
3783
0
    std::cout << indent << "    isConst: " << var->isConst() << std::endl;
3784
0
    std::cout << indent << "    isClass: " << var->isClass() << std::endl;
3785
0
    std::cout << indent << "    isArray: " << var->isArray() << std::endl;
3786
0
    std::cout << indent << "    isPointer: " << var->isPointer() << std::endl;
3787
0
    std::cout << indent << "    isReference: " << var->isReference() << std::endl;
3788
0
    std::cout << indent << "    isRValueRef: " << var->isRValueReference() << std::endl;
3789
0
    std::cout << indent << "    hasDefault: " << var->hasDefault() << std::endl;
3790
0
    std::cout << indent << "    isStlType: " << var->isStlType() << std::endl;
3791
0
    std::cout << indent << "mType: ";
3792
0
    if (var->type()) {
3793
0
        std::cout << var->type()->type() << " " << var->type()->name();
3794
0
        std::cout << " " << mTokenizer.list.fileLine(var->type()->classDef);
3795
0
        std::cout << " " << var->type() << std::endl;
3796
0
    } else
3797
0
        std::cout << "none" << std::endl;
3798
3799
0
    if (var->nameToken()) {
3800
0
        const ValueType * valueType = var->nameToken()->valueType();
3801
0
        std::cout << indent << "valueType: " << valueType << std::endl;
3802
0
        if (valueType) {
3803
0
            std::cout << indent << "    " << valueType->str() << std::endl;
3804
0
        }
3805
0
    }
3806
3807
0
    std::cout << indent << "mScope: " << scopeToString(var->scope(), mTokenizer) << std::endl;
3808
3809
0
    std::cout << indent << "mDimensions:";
3810
0
    for (std::size_t i = 0; i < var->dimensions().size(); i++) {
3811
0
        std::cout << " " << var->dimension(i);
3812
0
        if (!var->dimensions()[i].known)
3813
0
            std::cout << "?";
3814
0
    }
3815
0
    std::cout << std::endl;
3816
0
}
3817
3818
void SymbolDatabase::printOut(const char *title) const
3819
0
{
3820
0
    std::cout << std::setiosflags(std::ios::boolalpha);
3821
0
    if (title)
3822
0
        std::cout << "\n### " << title << " ###\n";
3823
3824
0
    for (std::list<Scope>::const_iterator scope = scopeList.cbegin(); scope != scopeList.cend(); ++scope) {
3825
0
        std::cout << "Scope: " << &*scope << " " << scope->type << std::endl;
3826
0
        std::cout << "    className: " << scope->className << std::endl;
3827
0
        std::cout << "    classDef: " << tokenToString(scope->classDef, mTokenizer) << std::endl;
3828
0
        std::cout << "    bodyStart: " << tokenToString(scope->bodyStart, mTokenizer) << std::endl;
3829
0
        std::cout << "    bodyEnd: " << tokenToString(scope->bodyEnd, mTokenizer) << std::endl;
3830
3831
        // find the function body if not implemented inline
3832
0
        for (auto func = scope->functionList.cbegin(); func != scope->functionList.cend(); ++func) {
3833
0
            std::cout << "    Function: " << &*func << std::endl;
3834
0
            std::cout << "        name: " << tokenToString(func->tokenDef, mTokenizer) << std::endl;
3835
0
            std::cout << "        type: " << (func->type == Function::eConstructor? "Constructor" :
3836
0
                                              func->type == Function::eCopyConstructor ? "CopyConstructor" :
3837
0
                                              func->type == Function::eMoveConstructor ? "MoveConstructor" :
3838
0
                                              func->type == Function::eOperatorEqual ? "OperatorEqual" :
3839
0
                                              func->type == Function::eDestructor ? "Destructor" :
3840
0
                                              func->type == Function::eFunction ? "Function" :
3841
0
                                              func->type == Function::eLambda ? "Lambda" :
3842
0
                                              "Unknown") << std::endl;
3843
0
            std::cout << "        access: " << accessControlToString(func->access) << std::endl;
3844
0
            std::cout << "        hasBody: " << func->hasBody() << std::endl;
3845
0
            std::cout << "        isInline: " << func->isInline() << std::endl;
3846
0
            std::cout << "        isConst: " << func->isConst() << std::endl;
3847
0
            std::cout << "        hasVirtualSpecifier: " << func->hasVirtualSpecifier() << std::endl;
3848
0
            std::cout << "        isPure: " << func->isPure() << std::endl;
3849
0
            std::cout << "        isStatic: " << func->isStatic() << std::endl;
3850
0
            std::cout << "        isStaticLocal: " << func->isStaticLocal() << std::endl;
3851
0
            std::cout << "        isExtern: " << func->isExtern() << std::endl;
3852
0
            std::cout << "        isFriend: " << func->isFriend() << std::endl;
3853
0
            std::cout << "        isExplicit: " << func->isExplicit() << std::endl;
3854
0
            std::cout << "        isDefault: " << func->isDefault() << std::endl;
3855
0
            std::cout << "        isDelete: " << func->isDelete() << std::endl;
3856
0
            std::cout << "        hasOverrideSpecifier: " << func->hasOverrideSpecifier() << std::endl;
3857
0
            std::cout << "        hasFinalSpecifier: " << func->hasFinalSpecifier() << std::endl;
3858
0
            std::cout << "        isNoExcept: " << func->isNoExcept() << std::endl;
3859
0
            std::cout << "        isThrow: " << func->isThrow() << std::endl;
3860
0
            std::cout << "        isOperator: " << func->isOperator() << std::endl;
3861
0
            std::cout << "        hasLvalRefQual: " << func->hasLvalRefQualifier() << std::endl;
3862
0
            std::cout << "        hasRvalRefQual: " << func->hasRvalRefQualifier() << std::endl;
3863
0
            std::cout << "        isVariadic: " << func->isVariadic() << std::endl;
3864
0
            std::cout << "        isVolatile: " << func->isVolatile() << std::endl;
3865
0
            std::cout << "        hasTrailingReturnType: " << func->hasTrailingReturnType() << std::endl;
3866
0
            std::cout << "        attributes:";
3867
0
            if (func->isAttributeConst())
3868
0
                std::cout << " const ";
3869
0
            if (func->isAttributePure())
3870
0
                std::cout << " pure ";
3871
0
            if (func->isAttributeNoreturn())
3872
0
                std::cout << " noreturn ";
3873
0
            if (func->isAttributeNothrow())
3874
0
                std::cout << " nothrow ";
3875
0
            if (func->isAttributeConstructor())
3876
0
                std::cout << " constructor ";
3877
0
            if (func->isAttributeDestructor())
3878
0
                std::cout << " destructor ";
3879
0
            if (func->isAttributeNodiscard())
3880
0
                std::cout << " nodiscard ";
3881
0
            std::cout << std::endl;
3882
0
            std::cout << "        noexceptArg: " << (func->noexceptArg ? func->noexceptArg->str() : "none") << std::endl;
3883
0
            std::cout << "        throwArg: " << (func->throwArg ? func->throwArg->str() : "none") << std::endl;
3884
0
            std::cout << "        tokenDef: " << tokenToString(func->tokenDef, mTokenizer) << std::endl;
3885
0
            std::cout << "        argDef: " << tokenToString(func->argDef, mTokenizer) << std::endl;
3886
0
            if (!func->isConstructor() && !func->isDestructor())
3887
0
                std::cout << "        retDef: " << tokenToString(func->retDef, mTokenizer) << std::endl;
3888
0
            if (func->retDef) {
3889
0
                std::cout << "           ";
3890
0
                for (const Token * tok = func->retDef; tok && tok != func->tokenDef && !Token::Match(tok, "{|;|override|final"); tok = tok->next())
3891
0
                    std::cout << " " << tokenType(tok);
3892
0
                std::cout << std::endl;
3893
0
            }
3894
0
            std::cout << "        retType: " << func->retType << std::endl;
3895
3896
0
            if (const ValueType* valueType = func->tokenDef->next()->valueType()) {
3897
0
                std::cout << "        valueType: " << valueType << std::endl;
3898
0
                std::cout << "            " << valueType->str() << std::endl;
3899
0
            }
3900
3901
0
            if (func->hasBody()) {
3902
0
                std::cout << "        token: " << tokenToString(func->token, mTokenizer) << std::endl;
3903
0
                std::cout << "        arg: " << tokenToString(func->arg, mTokenizer) << std::endl;
3904
0
            }
3905
0
            std::cout << "        nestedIn: " << scopeToString(func->nestedIn, mTokenizer) << std::endl;
3906
0
            std::cout << "        functionScope: " << scopeToString(func->functionScope, mTokenizer) << std::endl;
3907
3908
0
            for (auto var = func->argumentList.cbegin(); var != func->argumentList.cend(); ++var) {
3909
0
                std::cout << "        Variable: " << &*var << std::endl;
3910
0
                printVariable(&*var, "            ");
3911
0
            }
3912
0
        }
3913
3914
0
        for (auto var = scope->varlist.cbegin(); var != scope->varlist.cend(); ++var) {
3915
0
            std::cout << "    Variable: " << &*var << std::endl;
3916
0
            printVariable(&*var, "        ");
3917
0
        }
3918
3919
0
        if (scope->type == Scope::eEnum) {
3920
0
            std::cout << "    enumType: ";
3921
0
            if (scope->enumType) {
3922
0
                std::cout << scope->enumType->stringify(false, true, false);
3923
0
            } else
3924
0
                std::cout << "int";
3925
0
            std::cout << std::endl;
3926
0
            std::cout << "    enumClass: " << scope->enumClass << std::endl;
3927
0
            for (const Enumerator &enumerator : scope->enumeratorList) {
3928
0
                std::cout << "        Enumerator: " << enumerator.name->str() << " = ";
3929
0
                if (enumerator.value_known)
3930
0
                    std::cout << enumerator.value;
3931
3932
0
                if (enumerator.start) {
3933
0
                    const Token * tok = enumerator.start;
3934
0
                    std::cout << (enumerator.value_known ? " " : "") << "[" << tok->str();
3935
0
                    while (tok && tok != enumerator.end) {
3936
0
                        if (tok->next())
3937
0
                            std::cout << " " << tok->next()->str();
3938
0
                        tok = tok->next();
3939
0
                    }
3940
3941
0
                    std::cout << "]";
3942
0
                }
3943
3944
0
                std::cout << std::endl;
3945
0
            }
3946
0
        }
3947
3948
0
        std::cout << "    nestedIn: " << scope->nestedIn;
3949
0
        if (scope->nestedIn) {
3950
0
            std::cout << " " << scope->nestedIn->type << " "
3951
0
                      << scope->nestedIn->className;
3952
0
        }
3953
0
        std::cout << std::endl;
3954
3955
0
        std::cout << "    definedType: " << scope->definedType << std::endl;
3956
3957
0
        std::cout << "    nestedList[" << scope->nestedList.size() << "] = (";
3958
3959
0
        std::size_t count = scope->nestedList.size();
3960
0
        for (std::vector<Scope*>::const_iterator nsi = scope->nestedList.cbegin(); nsi != scope->nestedList.cend(); ++nsi) {
3961
0
            std::cout << " " << (*nsi) << " " << (*nsi)->type << " " << (*nsi)->className;
3962
0
            if (count-- > 1)
3963
0
                std::cout << ",";
3964
0
        }
3965
3966
0
        std::cout << " )" << std::endl;
3967
3968
0
        for (auto use = scope->usingList.cbegin(); use != scope->usingList.cend(); ++use) {
3969
0
            std::cout << "    using: " << use->scope << " " << use->start->strAt(2);
3970
0
            const Token *tok1 = use->start->tokAt(3);
3971
0
            while (tok1 && tok1->str() == "::") {
3972
0
                std::cout << "::" << tok1->strAt(1);
3973
0
                tok1 = tok1->tokAt(2);
3974
0
            }
3975
0
            std::cout << " " << mTokenizer.list.fileLine(use->start) << std::endl;
3976
0
        }
3977
3978
0
        std::cout << "    functionOf: " << scopeToString(scope->functionOf, mTokenizer) << std::endl;
3979
3980
0
        std::cout << "    function: " << scope->function;
3981
0
        if (scope->function)
3982
0
            std::cout << " " << scope->function->name();
3983
0
        std::cout << std::endl;
3984
0
    }
3985
3986
0
    for (std::list<Type>::const_iterator type = typeList.cbegin(); type != typeList.cend(); ++type) {
3987
0
        std::cout << "Type: " << &(*type) << std::endl;
3988
0
        std::cout << "    name: " << type->name() << std::endl;
3989
0
        std::cout << "    classDef: " << tokenToString(type->classDef, mTokenizer) << std::endl;
3990
0
        std::cout << "    classScope: " << type->classScope << std::endl;
3991
0
        std::cout << "    enclosingScope: " << type->enclosingScope;
3992
0
        if (type->enclosingScope) {
3993
0
            std::cout << " " << type->enclosingScope->type << " "
3994
0
                      << type->enclosingScope->className;
3995
0
        }
3996
0
        std::cout << std::endl;
3997
0
        std::cout << "    needInitialization: " << (type->needInitialization == Type::NeedInitialization::Unknown ? "Unknown" :
3998
0
                                                    type->needInitialization == Type::NeedInitialization::True ? "True" :
3999
0
                                                    type->needInitialization == Type::NeedInitialization::False ? "False" :
4000
0
                                                    "Invalid") << std::endl;
4001
4002
0
        std::cout << "    derivedFrom[" << type->derivedFrom.size() << "] = (";
4003
0
        std::size_t count = type->derivedFrom.size();
4004
0
        for (const Type::BaseInfo & i : type->derivedFrom) {
4005
0
            if (i.isVirtual)
4006
0
                std::cout << "Virtual ";
4007
4008
0
            std::cout << (i.access == AccessControl::Public    ? " Public" :
4009
0
                          i.access == AccessControl::Protected ? " Protected" :
4010
0
                          i.access == AccessControl::Private   ? " Private" :
4011
0
                          " Unknown");
4012
4013
0
            if (i.type)
4014
0
                std::cout << " " << i.type;
4015
0
            else
4016
0
                std::cout << " Unknown";
4017
4018
0
            std::cout << " " << i.name;
4019
0
            if (count-- > 1)
4020
0
                std::cout << ",";
4021
0
        }
4022
4023
0
        std::cout << " )" << std::endl;
4024
4025
0
        std::cout << "    friendList[" << type->friendList.size() << "] = (";
4026
0
        for (size_t i = 0; i < type->friendList.size(); i++) {
4027
0
            if (type->friendList[i].type)
4028
0
                std::cout << type->friendList[i].type;
4029
0
            else
4030
0
                std::cout << " Unknown";
4031
4032
0
            std::cout << ' ';
4033
0
            if (type->friendList[i].nameEnd)
4034
0
                std::cout << type->friendList[i].nameEnd->str();
4035
0
            if (i+1 < type->friendList.size())
4036
0
                std::cout << ',';
4037
0
        }
4038
4039
0
        std::cout << " )" << std::endl;
4040
0
    }
4041
4042
0
    for (std::size_t i = 1; i < mVariableList.size(); i++) {
4043
0
        std::cout << "mVariableList[" << i << "]: " << mVariableList[i];
4044
0
        if (mVariableList[i]) {
4045
0
            std::cout << " " << mVariableList[i]->name() << " "
4046
0
                      << mTokenizer.list.fileLine(mVariableList[i]->nameToken());
4047
0
        }
4048
0
        std::cout << std::endl;
4049
0
    }
4050
0
    std::cout << std::resetiosflags(std::ios::boolalpha);
4051
0
}
4052
4053
void SymbolDatabase::printXml(std::ostream &out) const
4054
0
{
4055
0
    std::string outs;
4056
4057
0
    std::set<const Variable *> variables;
4058
4059
    // Scopes..
4060
0
    outs += "  <scopes>\n";
4061
0
    for (std::list<Scope>::const_iterator scope = scopeList.cbegin(); scope != scopeList.cend(); ++scope) {
4062
0
        outs += "    <scope";
4063
0
        outs += " id=\"";
4064
0
        outs += id_string(&*scope);
4065
0
        outs += "\"";
4066
0
        outs += " type=\"";
4067
0
        outs += scopeTypeToString(scope->type);
4068
0
        outs += "\"";
4069
0
        if (!scope->className.empty()) {
4070
0
            outs += " className=\"";
4071
0
            outs += ErrorLogger::toxml(scope->className);
4072
0
            outs += "\"";
4073
0
        }
4074
0
        if (scope->bodyStart) {
4075
0
            outs += " bodyStart=\"";
4076
0
            outs += id_string(scope->bodyStart);
4077
0
            outs += '\"';
4078
0
        }
4079
0
        if (scope->bodyEnd) {
4080
0
            outs += " bodyEnd=\"";
4081
0
            outs += id_string(scope->bodyEnd);
4082
0
            outs += '\"';
4083
0
        }
4084
0
        if (scope->nestedIn) {
4085
0
            outs += " nestedIn=\"";
4086
0
            outs += id_string(scope->nestedIn);
4087
0
            outs += "\"";
4088
0
        }
4089
0
        if (scope->function) {
4090
0
            outs += " function=\"";
4091
0
            outs += id_string(scope->function);
4092
0
            outs += "\"";
4093
0
        }
4094
0
        if (scope->definedType) {
4095
0
            outs += " definedType=\"";
4096
0
            outs += id_string(scope->definedType);
4097
0
            outs += "\"";
4098
0
        }
4099
0
        if (scope->functionList.empty() && scope->varlist.empty())
4100
0
            outs += "/>\n";
4101
0
        else {
4102
0
            outs += ">\n";
4103
0
            if (!scope->functionList.empty()) {
4104
0
                outs += "      <functionList>\n";
4105
0
                for (std::list<Function>::const_iterator function = scope->functionList.cbegin(); function != scope->functionList.cend(); ++function) {
4106
0
                    outs += "        <function id=\"";
4107
0
                    outs += id_string(&*function);
4108
0
                    outs += "\" token=\"";
4109
0
                    outs += id_string(function->token);
4110
0
                    outs += "\" tokenDef=\"";
4111
0
                    outs += id_string(function->tokenDef);
4112
0
                    outs += "\" name=\"";
4113
0
                    outs += ErrorLogger::toxml(function->name());
4114
0
                    outs += '\"';
4115
0
                    outs += " type=\"";
4116
0
                    outs += (function->type == Function::eConstructor? "Constructor" :
4117
0
                             function->type == Function::eCopyConstructor ? "CopyConstructor" :
4118
0
                             function->type == Function::eMoveConstructor ? "MoveConstructor" :
4119
0
                             function->type == Function::eOperatorEqual ? "OperatorEqual" :
4120
0
                             function->type == Function::eDestructor ? "Destructor" :
4121
0
                             function->type == Function::eFunction ? "Function" :
4122
0
                             function->type == Function::eLambda ? "Lambda" :
4123
0
                             "Unknown");
4124
0
                    outs += '\"';
4125
0
                    if (function->nestedIn->definedType) {
4126
0
                        if (function->hasVirtualSpecifier())
4127
0
                            outs += " hasVirtualSpecifier=\"true\"";
4128
0
                        else if (function->isImplicitlyVirtual())
4129
0
                            outs += " isImplicitlyVirtual=\"true\"";
4130
0
                    }
4131
0
                    if (function->access == AccessControl::Public || function->access == AccessControl::Protected || function->access == AccessControl::Private) {
4132
0
                        outs += " access=\"";
4133
0
                        outs += accessControlToString(function->access);
4134
0
                        outs +="\"";
4135
0
                    }
4136
0
                    if (function->isInlineKeyword())
4137
0
                        outs += " isInlineKeyword=\"true\"";
4138
0
                    if (function->isStatic())
4139
0
                        outs += " isStatic=\"true\"";
4140
0
                    if (function->isAttributeNoreturn())
4141
0
                        outs += " isAttributeNoreturn=\"true\"";
4142
0
                    if (const Function* overriddenFunction = function->getOverriddenFunction()) {
4143
0
                        outs += " overriddenFunction=\"";
4144
0
                        outs += id_string(overriddenFunction);
4145
0
                        outs += "\"";
4146
0
                    }
4147
0
                    if (function->argCount() == 0U)
4148
0
                        outs += "/>\n";
4149
0
                    else {
4150
0
                        outs += ">\n";
4151
0
                        for (unsigned int argnr = 0; argnr < function->argCount(); ++argnr) {
4152
0
                            const Variable *arg = function->getArgumentVar(argnr);
4153
0
                            outs += "          <arg nr=\"";
4154
0
                            outs += std::to_string(argnr+1);
4155
0
                            outs += "\" variable=\"";
4156
0
                            outs += id_string(arg);
4157
0
                            outs += "\"/>\n";
4158
0
                            variables.insert(arg);
4159
0
                        }
4160
0
                        outs += "        </function>\n";
4161
0
                    }
4162
0
                }
4163
0
                outs += "      </functionList>\n";
4164
0
            }
4165
0
            if (!scope->varlist.empty()) {
4166
0
                outs += "      <varlist>\n";
4167
0
                for (std::list<Variable>::const_iterator var = scope->varlist.cbegin(); var != scope->varlist.cend(); ++var) {
4168
0
                    outs += "        <var id=\"";
4169
0
                    outs += id_string(&*var);
4170
0
                    outs += "\"/>\n";
4171
0
                }
4172
0
                outs += "      </varlist>\n";
4173
0
            }
4174
0
            outs += "    </scope>\n";
4175
0
        }
4176
0
    }
4177
0
    outs += "  </scopes>\n";
4178
4179
0
    if (!typeList.empty()) {
4180
0
        outs += "  <types>\n";
4181
0
        for (const Type& type:typeList) {
4182
0
            outs += "    <type id=\"";
4183
0
            outs += id_string(&type);
4184
0
            outs += "\" classScope=\"";
4185
0
            outs += id_string(type.classScope);
4186
0
            outs += "\"";
4187
0
            if (type.derivedFrom.empty()) {
4188
0
                outs += "/>\n";
4189
0
                continue;
4190
0
            }
4191
0
            outs += ">\n";
4192
0
            for (const Type::BaseInfo& baseInfo: type.derivedFrom) {
4193
0
                outs += "      <derivedFrom";
4194
0
                outs += " access=\"";
4195
0
                outs += accessControlToString(baseInfo.access);
4196
0
                outs += "\"";
4197
0
                outs += " type=\"";
4198
0
                outs += id_string(baseInfo.type);
4199
0
                outs += "\"";
4200
0
                outs += " isVirtual=\"";
4201
0
                outs += bool_to_string(baseInfo.isVirtual);
4202
0
                outs += "\"";
4203
0
                outs += " nameTok=\"";
4204
0
                outs += id_string(baseInfo.nameTok);
4205
0
                outs += "\"";
4206
0
                outs += "/>\n";
4207
0
            }
4208
0
            outs += "    </type>\n";
4209
0
        }
4210
0
        outs += "  </types>\n";
4211
0
    }
4212
4213
    // Variables..
4214
0
    for (const Variable *var : mVariableList)
4215
0
        variables.insert(var);
4216
0
    outs += "  <variables>\n";
4217
0
    for (const Variable *var : variables) {
4218
0
        if (!var)
4219
0
            continue;
4220
0
        outs += "    <var id=\"";
4221
0
        outs += id_string(var);
4222
0
        outs += '\"';
4223
0
        outs += " nameToken=\"";
4224
0
        outs += id_string(var->nameToken());
4225
0
        outs += '\"';
4226
0
        outs += " typeStartToken=\"";
4227
0
        outs += id_string(var->typeStartToken());
4228
0
        outs += '\"';
4229
0
        outs += " typeEndToken=\"";
4230
0
        outs += id_string(var->typeEndToken());
4231
0
        outs += '\"';
4232
0
        outs += " access=\"";
4233
0
        outs += accessControlToString(var->mAccess);
4234
0
        outs += '\"';
4235
0
        outs += " scope=\"";
4236
0
        outs += id_string(var->scope());
4237
0
        outs += '\"';
4238
0
        if (var->valueType()) {
4239
0
            outs += " constness=\"";
4240
0
            outs += std::to_string(var->valueType()->constness);
4241
0
            outs += '\"';
4242
0
        }
4243
0
        outs += " isArray=\"";
4244
0
        outs += bool_to_string(var->isArray());
4245
0
        outs += '\"';
4246
0
        outs += " isClass=\"";
4247
0
        outs += bool_to_string(var->isClass());
4248
0
        outs += '\"';
4249
0
        outs += " isConst=\"";
4250
0
        outs += bool_to_string(var->isConst());
4251
0
        outs += '\"';
4252
0
        outs += " isExtern=\"";
4253
0
        outs += bool_to_string(var->isExtern());
4254
0
        outs += '\"';
4255
0
        outs += " isPointer=\"";
4256
0
        outs += bool_to_string(var->isPointer());
4257
0
        outs += '\"';
4258
0
        outs += " isReference=\"";
4259
0
        outs += bool_to_string(var->isReference());
4260
0
        outs += '\"';
4261
0
        outs += " isStatic=\"";
4262
0
        outs += bool_to_string(var->isStatic());
4263
0
        outs += '\"';
4264
0
        outs += " isVolatile=\"";
4265
0
        outs += bool_to_string(var->isVolatile());
4266
0
        outs += '\"';
4267
0
        outs += "/>\n";
4268
0
    }
4269
0
    outs += "  </variables>\n";
4270
4271
0
    out << outs;
4272
0
}
4273
4274
//---------------------------------------------------------------------------
4275
4276
static const Type* findVariableTypeIncludingUsedNamespaces(const SymbolDatabase* symbolDatabase, const Scope* scope, const Token* typeTok)
4277
6.80k
{
4278
6.80k
    const Type* argType = symbolDatabase->findVariableType(scope, typeTok);
4279
6.80k
    if (argType)
4280
0
        return argType;
4281
4282
    // look for variable type in any using namespace in this scope or above
4283
13.6k
    while (scope) {
4284
6.80k
        for (const Scope::UsingInfo &ui : scope->usingList) {
4285
0
            if (ui.scope) {
4286
0
                argType = symbolDatabase->findVariableType(ui.scope, typeTok);
4287
0
                if (argType)
4288
0
                    return argType;
4289
0
            }
4290
0
        }
4291
6.80k
        scope = scope->nestedIn;
4292
6.80k
    }
4293
6.80k
    return nullptr;
4294
6.80k
}
4295
4296
//---------------------------------------------------------------------------
4297
4298
void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *scope)
4299
1.73k
{
4300
    // check for non-empty argument list "( ... )"
4301
1.73k
    const Token * start = arg ? arg : argDef;
4302
1.73k
    if (!Token::simpleMatch(start, "("))
4303
0
        return;
4304
1.73k
    if (!(start && start->link() != start->next() && !Token::simpleMatch(start, "( void )")))
4305
1.73k
        return;
4306
4307
0
    unsigned int count = 0;
4308
4309
0
    for (const Token* tok = start->next(); tok; tok = tok->next()) {
4310
0
        if (Token::Match(tok, ",|)"))
4311
0
            return; // Syntax error
4312
4313
0
        const Token* startTok = tok;
4314
0
        const Token* endTok   = nullptr;
4315
0
        const Token* nameTok  = nullptr;
4316
4317
0
        do {
4318
0
            if (Token::simpleMatch(tok, "decltype (")) {
4319
0
                tok = tok->linkAt(1)->next();
4320
0
                continue;
4321
0
            }
4322
0
            if (tok != startTok && !nameTok && Token::Match(tok, "( & %var% ) [")) {
4323
0
                nameTok = tok->tokAt(2);
4324
0
                endTok = nameTok->previous();
4325
0
                tok = tok->link();
4326
0
            } else if (tok != startTok && !nameTok && Token::Match(tok, "( * %var% ) (") && Token::Match(tok->link()->linkAt(1), ") [,)]")) {
4327
0
                nameTok = tok->tokAt(2);
4328
0
                endTok = nameTok->previous();
4329
0
                tok = tok->link()->linkAt(1);
4330
0
            } else if (tok != startTok && !nameTok && Token::Match(tok, "( * %var% ) [")) {
4331
0
                nameTok = tok->tokAt(2);
4332
0
                endTok = nameTok->previous();
4333
0
                tok = tok->link();
4334
0
            } else if (tok->varId() != 0) {
4335
0
                nameTok = tok;
4336
0
                endTok = tok->previous();
4337
0
            } else if (tok->str() == "[") {
4338
                // skip array dimension(s)
4339
0
                tok = tok->link();
4340
0
                while (tok->next()->str() == "[")
4341
0
                    tok = tok->next()->link();
4342
0
            } else if (tok->str() == "<") {
4343
0
                tok = tok->link();
4344
0
                if (!tok) // something is wrong so just bail out
4345
0
                    return;
4346
0
            }
4347
4348
0
            tok = tok->next();
4349
4350
0
            if (!tok) // something is wrong so just bail
4351
0
                return;
4352
0
        } while (tok->str() != "," && tok->str() != ")" && tok->str() != "=");
4353
4354
0
        const Token *typeTok = startTok;
4355
        // skip over stuff to get to type
4356
0
        while (Token::Match(typeTok, "const|volatile|enum|struct|::"))
4357
0
            typeTok = typeTok->next();
4358
0
        if (Token::Match(typeTok, ",|)")) { // #8333
4359
0
            symbolDatabase->mTokenizer.syntaxError(typeTok);
4360
0
        }
4361
        // skip over qualification
4362
0
        while (Token::Match(typeTok, "%type% ::"))
4363
0
            typeTok = typeTok->tokAt(2);
4364
4365
        // check for argument with no name or missing varid
4366
0
        if (!endTok) {
4367
0
            if (tok->previous()->isName() && !Token::Match(tok->tokAt(-1), "const|volatile")) {
4368
0
                if (tok->previous() != typeTok) {
4369
0
                    nameTok = tok->previous();
4370
0
                    endTok = nameTok->previous();
4371
4372
0
                    if (hasBody())
4373
0
                        symbolDatabase->debugMessage(nameTok, "varid0", "Function::addArguments found argument \'" + nameTok->str() + "\' with varid 0.");
4374
0
                } else
4375
0
                    endTok = typeTok;
4376
0
            } else
4377
0
                endTok = tok->previous();
4378
0
        }
4379
4380
0
        const ::Type *argType = nullptr;
4381
0
        if (!typeTok->isStandardType()) {
4382
0
            argType = findVariableTypeIncludingUsedNamespaces(symbolDatabase, scope, typeTok);
4383
4384
            // save type
4385
0
            const_cast<Token *>(typeTok)->type(argType);
4386
0
        }
4387
4388
        // skip default values
4389
0
        if (tok->str() == "=") {
4390
0
            do {
4391
0
                if (tok->link() && Token::Match(tok, "[{[(<]"))
4392
0
                    tok = tok->link();
4393
0
                tok = tok->next();
4394
0
            } while (tok->str() != "," && tok->str() != ")");
4395
0
        }
4396
4397
        // skip over stuff before type
4398
0
        while (Token::Match(startTok, "enum|struct|const|volatile"))
4399
0
            startTok = startTok->next();
4400
4401
0
        if (startTok == nameTok)
4402
0
            break;
4403
4404
0
        argumentList.emplace_back(nameTok, startTok, endTok, count++, AccessControl::Argument, argType, functionScope, &symbolDatabase->mSettings);
4405
4406
0
        if (tok->str() == ")") {
4407
            // check for a variadic function or a variadic template function
4408
0
            if (Token::simpleMatch(endTok, "..."))
4409
0
                isVariadic(true);
4410
4411
0
            break;
4412
0
        }
4413
0
    }
4414
4415
    // count default arguments
4416
0
    for (const Token* tok = argDef->next(); tok && tok != argDef->link(); tok = tok->next()) {
4417
0
        if (tok->str() == "=") {
4418
0
            initArgCount++;
4419
0
            if (tok->strAt(1) == "[") {
4420
0
                const Token* lambdaStart = tok->next();
4421
0
                if (type == eLambda)
4422
0
                    tok = findLambdaEndTokenWithoutAST(lambdaStart);
4423
0
                else {
4424
0
                    tok = findLambdaEndToken(lambdaStart);
4425
0
                    if (!tok)
4426
0
                        tok = findLambdaEndTokenWithoutAST(lambdaStart);
4427
0
                }
4428
0
                if (!tok)
4429
0
                    throw InternalError(lambdaStart, "Analysis failed (lambda not recognized). If the code is valid then please report this failure.", InternalError::INTERNAL);
4430
0
            }
4431
0
        }
4432
0
    }
4433
0
}
4434
4435
bool Function::isImplicitlyVirtual(bool defaultVal) const
4436
0
{
4437
0
    if (hasVirtualSpecifier()) //If it has the virtual specifier it's definitely virtual
4438
0
        return true;
4439
0
    if (hasOverrideSpecifier()) //If it has the override specifier then it's either virtual or not going to compile
4440
0
        return true;
4441
0
    bool foundAllBaseClasses = true;
4442
0
    if (getOverriddenFunction(&foundAllBaseClasses)) //If it overrides a base class's method then it's virtual
4443
0
        return true;
4444
0
    if (foundAllBaseClasses) //If we've seen all the base classes and none of the above were true then it must not be virtual
4445
0
        return false;
4446
0
    return defaultVal; //If we can't see all the bases classes then we can't say conclusively
4447
0
}
4448
4449
std::vector<const Function*> Function::getOverloadedFunctions() const
4450
0
{
4451
0
    std::vector<const Function*> result;
4452
0
    const Scope* scope = nestedIn;
4453
4454
0
    while (scope) {
4455
0
        const bool isMemberFunction = scope->isClassOrStruct() && !isStatic();
4456
0
        for (std::multimap<std::string, const Function*>::const_iterator it = scope->functionMap.find(tokenDef->str());
4457
0
             it != scope->functionMap.end() && it->first == tokenDef->str();
4458
0
             ++it) {
4459
0
            const Function* func = it->second;
4460
0
            if (isMemberFunction && isMemberFunction == func->isStatic())
4461
0
                continue;
4462
0
            result.push_back(func);
4463
0
        }
4464
0
        if (isMemberFunction)
4465
0
            break;
4466
0
        scope = scope->nestedIn;
4467
0
    }
4468
4469
0
    return result;
4470
0
}
4471
4472
const Function *Function::getOverriddenFunction(bool *foundAllBaseClasses) const
4473
0
{
4474
0
    if (foundAllBaseClasses)
4475
0
        *foundAllBaseClasses = true;
4476
0
    if (!nestedIn->isClassOrStruct())
4477
0
        return nullptr;
4478
0
    return getOverriddenFunctionRecursive(nestedIn->definedType, foundAllBaseClasses);
4479
0
}
4480
4481
// prevent recursion if base is the same except for different template parameters
4482
static bool isDerivedFromItself(const std::string& thisName, const std::string& baseName)
4483
0
{
4484
0
    if (thisName.back() != '>')
4485
0
        return false;
4486
0
    const auto pos = thisName.find('<');
4487
0
    if (pos == std::string::npos)
4488
0
        return false;
4489
0
    return thisName.compare(0, pos + 1, baseName, 0, pos + 1) == 0;
4490
0
}
4491
4492
const Function * Function::getOverriddenFunctionRecursive(const ::Type* baseType, bool *foundAllBaseClasses) const
4493
0
{
4494
    // check each base class
4495
0
    for (const ::Type::BaseInfo & i : baseType->derivedFrom) {
4496
0
        const ::Type* derivedFromType = i.type;
4497
        // check if base class exists in database
4498
0
        if (!derivedFromType || !derivedFromType->classScope) {
4499
0
            if (foundAllBaseClasses)
4500
0
                *foundAllBaseClasses = false;
4501
0
            continue;
4502
0
        }
4503
4504
0
        const Scope *parent = derivedFromType->classScope;
4505
4506
        // check if function defined in base class
4507
0
        auto range = parent->functionMap.equal_range(tokenDef->str());
4508
0
        for (std::multimap<std::string, const Function*>::const_iterator it = range.first; it != range.second; ++it) {
4509
0
            const Function * func = it->second;
4510
0
            if (func->isImplicitlyVirtual()) { // Base is virtual and of same name
4511
0
                const Token *temp1 = func->tokenDef->previous();
4512
0
                const Token *temp2 = tokenDef->previous();
4513
0
                bool match = true;
4514
4515
                // check for matching return parameters
4516
0
                while (!Token::Match(temp1, "virtual|public:|private:|protected:|{|}|;")) {
4517
0
                    if (temp1->str() != temp2->str() &&
4518
0
                        !(temp1->type() && temp2->type() && temp2->type()->isDerivedFrom(temp1->type()->name()))) {
4519
0
                        match = false;
4520
0
                        break;
4521
0
                    }
4522
4523
0
                    temp1 = temp1->previous();
4524
0
                    temp2 = temp2->previous();
4525
0
                }
4526
4527
                // check for matching function parameters
4528
0
                match = match && argsMatch(baseType->classScope, func->argDef, argDef, emptyString, 0);
4529
4530
                // check for matching cv-ref qualifiers
4531
0
                match = match
4532
0
                        && isConst() == func->isConst()
4533
0
                        && isVolatile() == func->isVolatile()
4534
0
                        && hasRvalRefQualifier() == func->hasRvalRefQualifier()
4535
0
                        && hasLvalRefQualifier() == func->hasLvalRefQualifier();
4536
4537
                // it's a match
4538
0
                if (match) {
4539
0
                    return func;
4540
0
                }
4541
0
            }
4542
0
        }
4543
4544
0
        if (!derivedFromType->derivedFrom.empty() && !derivedFromType->hasCircularDependencies() && !isDerivedFromItself(baseType->classScope->className, i.name)) {
4545
            // avoid endless recursion, see #5289 Crash: Stack overflow in isImplicitlyVirtual_rec when checking SVN and
4546
            // #5590 with a loop within the class hierarchy.
4547
0
            const Function *func = getOverriddenFunctionRecursive(derivedFromType, foundAllBaseClasses);
4548
0
            if (func) {
4549
0
                return func;
4550
0
            }
4551
0
        }
4552
0
    }
4553
0
    return nullptr;
4554
0
}
4555
4556
const Variable* Function::getArgumentVar(nonneg int num) const
4557
0
{
4558
0
    if (num < argumentList.size()) {
4559
0
        auto it = argumentList.begin();
4560
0
        std::advance(it, num);
4561
0
        return &*it;
4562
0
    }
4563
0
    return nullptr;
4564
0
}
4565
4566
4567
//---------------------------------------------------------------------------
4568
4569
Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *nestedIn_, ScopeType type_, const Token *start_) :
4570
    check(check_),
4571
    classDef(classDef_),
4572
    nestedIn(nestedIn_),
4573
    type(type_)
4574
1.84k
{
4575
1.84k
    setBodyStartEnd(start_);
4576
1.84k
}
4577
4578
Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *nestedIn_) :
4579
    check(check_),
4580
    classDef(classDef_),
4581
    nestedIn(nestedIn_)
4582
3.10k
{
4583
3.10k
    const Token *nameTok = classDef;
4584
3.10k
    if (!classDef) {
4585
1.36k
        type = Scope::eGlobal;
4586
1.73k
    } else if (classDef->str() == "class" && check && check->isCPP()) {
4587
0
        type = Scope::eClass;
4588
0
        nameTok = nameTok->next();
4589
1.73k
    } else if (classDef->str() == "struct") {
4590
0
        type = Scope::eStruct;
4591
0
        nameTok = nameTok->next();
4592
1.73k
    } else if (classDef->str() == "union") {
4593
0
        type = Scope::eUnion;
4594
0
        nameTok = nameTok->next();
4595
1.73k
    } else if (classDef->str() == "namespace") {
4596
0
        type = Scope::eNamespace;
4597
0
        nameTok = nameTok->next();
4598
1.73k
    } else if (classDef->str() == "enum") {
4599
0
        type = Scope::eEnum;
4600
0
        nameTok = nameTok->next();
4601
0
        if (nameTok->str() == "class") {
4602
0
            enumClass = true;
4603
0
            nameTok = nameTok->next();
4604
0
        }
4605
1.73k
    } else if (classDef->str() == "[") {
4606
0
        type = Scope::eLambda;
4607
1.73k
    } else {
4608
1.73k
        type = Scope::eFunction;
4609
1.73k
    }
4610
    // skip over qualification if present
4611
3.10k
    nameTok = skipScopeIdentifiers(nameTok);
4612
3.10k
    if (nameTok && ((type == Scope::eEnum && Token::Match(nameTok, ":|{")) || nameTok->str() != "{")) // anonymous and unnamed structs/unions don't have a name
4613
1.73k
        className = nameTok->str();
4614
3.10k
}
4615
4616
AccessControl Scope::defaultAccess() const
4617
4.95k
{
4618
4.95k
    switch (type) {
4619
1.36k
    case eGlobal:
4620
1.36k
        return AccessControl::Global;
4621
0
    case eClass:
4622
0
        return AccessControl::Private;
4623
0
    case eStruct:
4624
0
        return AccessControl::Public;
4625
0
    case eUnion:
4626
0
        return AccessControl::Public;
4627
0
    case eNamespace:
4628
0
        return AccessControl::Namespace;
4629
3.58k
    default:
4630
3.58k
        return AccessControl::Local;
4631
4.95k
    }
4632
4.95k
}
4633
4634
void Scope::addVariable(const Token *token_, const Token *start_, const Token *end_,
4635
                        AccessControl access_, const Type *type_, const Scope *scope_, const Settings* settings)
4636
6.80k
{
4637
    // keep possible size_t -> int truncation outside emplace_back() to have a single line
4638
    // C4267 VC++ warning instead of several dozens lines
4639
6.80k
    const int varIndex = varlist.size();
4640
6.80k
    varlist.emplace_back(token_, start_, end_, varIndex, access_, type_, scope_, settings);
4641
6.80k
}
4642
4643
// Get variable list..
4644
void Scope::getVariableList(const Settings* settings)
4645
4.94k
{
4646
4.94k
    if (!bodyStartList.empty()) {
4647
3.58k
        for (const Token *bs: bodyStartList)
4648
3.58k
            getVariableList(settings, bs->next(), bs->link());
4649
3.58k
    }
4650
4651
    // global scope
4652
1.36k
    else if (type == Scope::eGlobal)
4653
1.36k
        getVariableList(settings, check->mTokenizer.tokens(), nullptr);
4654
4655
    // forward declaration
4656
0
    else
4657
0
        return;
4658
4.94k
}
4659
4660
void Scope::getVariableList(const Settings* settings, const Token* start, const Token* end)
4661
4.94k
{
4662
    // Variable declared in condition: if (auto x = bar())
4663
4.94k
    if (Token::Match(classDef, "if|while ( %type%") && Token::simpleMatch(classDef->next()->astOperand2(), "=")) {
4664
6
        checkVariable(classDef->tokAt(2), defaultAccess(), settings);
4665
6
    }
4666
4667
4.94k
    AccessControl varaccess = defaultAccess();
4668
76.7k
    for (const Token *tok = start; tok && tok != end; tok = tok->next()) {
4669
        // syntax error?
4670
71.7k
        if (tok->next() == nullptr)
4671
0
            break;
4672
4673
        // Is it a function?
4674
71.7k
        if (tok->str() == "{") {
4675
3.58k
            tok = tok->link();
4676
3.58k
            continue;
4677
3.58k
        }
4678
4679
        // Is it a nested class or structure?
4680
68.1k
        if (tok->isKeyword() && Token::Match(tok, "class|struct|union|namespace %type% :|{")) {
4681
0
            tok = tok->tokAt(2);
4682
0
            while (tok && tok->str() != "{")
4683
0
                tok = tok->next();
4684
0
            if (tok) {
4685
                // skip implementation
4686
0
                tok = tok->link();
4687
0
                continue;
4688
0
            }
4689
0
            break;
4690
0
        }
4691
68.1k
        if (tok->isKeyword() && Token::Match(tok, "struct|union {")) {
4692
0
            if (Token::Match(tok->next()->link(), "} %name% ;|[")) {
4693
0
                tok = tok->next()->link()->tokAt(2);
4694
0
                continue;
4695
0
            }
4696
0
            if (Token::simpleMatch(tok->next()->link(), "} ;")) {
4697
0
                tok = tok->next();
4698
0
                continue;
4699
0
            }
4700
0
        }
4701
4702
        // Borland C++: Skip all variables in the __published section.
4703
        // These are automatically initialized.
4704
68.1k
        else if (tok->str() == "__published:") {
4705
0
            for (; tok; tok = tok->next()) {
4706
0
                if (tok->str() == "{")
4707
0
                    tok = tok->link();
4708
0
                if (Token::Match(tok->next(), "private:|protected:|public:"))
4709
0
                    break;
4710
0
            }
4711
0
            if (tok)
4712
0
                continue;
4713
0
            break;
4714
0
        }
4715
4716
        // "private:" "public:" "protected:" etc
4717
68.1k
        else if (tok->str() == "public:") {
4718
0
            varaccess = AccessControl::Public;
4719
0
            continue;
4720
68.1k
        } else if (tok->str() == "protected:") {
4721
0
            varaccess = AccessControl::Protected;
4722
0
            continue;
4723
68.1k
        } else if (tok->str() == "private:") {
4724
0
            varaccess = AccessControl::Private;
4725
0
            continue;
4726
0
        }
4727
4728
        // Is it a forward declaration?
4729
68.1k
        else if (tok->isKeyword() && Token::Match(tok, "class|struct|union %name% ;")) {
4730
0
            tok = tok->tokAt(2);
4731
0
            continue;
4732
0
        }
4733
4734
        // Borland C++: Ignore properties..
4735
68.1k
        else if (tok->str() == "__property")
4736
0
            continue;
4737
4738
        // skip return, goto and delete
4739
68.1k
        else if (tok->isKeyword() && Token::Match(tok, "return|delete|goto")) {
4740
5.18k
            while (tok->next() &&
4741
5.18k
                   tok->next()->str() != ";" &&
4742
5.18k
                   tok->next()->str() != "}" /* ticket #4994 */) {
4743
3.27k
                tok = tok->next();
4744
3.27k
            }
4745
1.91k
            continue;
4746
1.91k
        }
4747
4748
        // skip case/default
4749
66.2k
        if (tok->isKeyword() && Token::Match(tok, "case|default")) {
4750
0
            while (tok->next() && !Token::Match(tok->next(), "[:;{}]"))
4751
0
                tok = tok->next();
4752
0
            continue;
4753
0
        }
4754
4755
        // Search for start of statement..
4756
66.2k
        if (tok->previous() && !Token::Match(tok->previous(), ";|{|}|public:|protected:|private:"))
4757
47.5k
            continue;
4758
18.7k
        if (tok->str() == ";")
4759
0
            continue;
4760
4761
18.7k
        tok = checkVariable(tok, varaccess, settings);
4762
4763
18.7k
        if (!tok)
4764
0
            break;
4765
18.7k
    }
4766
4.94k
}
4767
4768
const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess, const Settings* settings)
4769
18.7k
{
4770
    // Is it a throw..?
4771
18.7k
    if (tok->isKeyword() && Token::Match(tok, "throw %any% (") &&
4772
18.7k
        Token::simpleMatch(tok->linkAt(2), ") ;")) {
4773
0
        return tok->linkAt(2);
4774
0
    }
4775
4776
18.7k
    if (tok->isKeyword() && Token::Match(tok, "throw %any% :: %any% (") &&
4777
18.7k
        Token::simpleMatch(tok->linkAt(4), ") ;")) {
4778
0
        return tok->linkAt(4);
4779
0
    }
4780
4781
    // friend?
4782
18.7k
    if (tok->isKeyword() && Token::Match(tok, "friend %type%") && tok->next()->varId() == 0) {
4783
0
        const Token *next = Token::findmatch(tok->tokAt(2), ";|{");
4784
0
        if (next && next->str() == "{")
4785
0
            next = next->link();
4786
0
        return next;
4787
0
    }
4788
4789
    // skip const|volatile|static|mutable|extern
4790
18.7k
    while (tok && tok->isKeyword() && Token::Match(tok, "const|constexpr|volatile|static|mutable|extern")) {
4791
0
        tok = tok->next();
4792
0
    }
4793
4794
    // the start of the type tokens does not include the above modifiers
4795
18.7k
    const Token *typestart = tok;
4796
4797
    // C++17 structured bindings
4798
18.7k
    if (settings->standards.cpp >= Standards::CPP17 && Token::Match(tok, "auto &|&&| [")) {
4799
0
        const Token *typeend = Token::findsimplematch(typestart, "[")->previous();
4800
0
        for (tok = typeend->tokAt(2); Token::Match(tok, "%name%|,"); tok = tok->next()) {
4801
0
            if (tok->varId())
4802
0
                addVariable(tok, typestart, typeend, varaccess, nullptr, this, settings);
4803
0
        }
4804
0
        return typeend->linkAt(1);
4805
0
    }
4806
4807
18.7k
    while (tok && tok->isKeyword() && Token::Match(tok, "class|struct|union|enum")) {
4808
0
        tok = tok->next();
4809
0
    }
4810
4811
    // This is the start of a statement
4812
18.7k
    const Token *vartok = nullptr;
4813
18.7k
    const Token *typetok = nullptr;
4814
4815
18.7k
    if (tok && isVariableDeclaration(tok, vartok, typetok)) {
4816
        // If the vartok was set in the if-blocks above, create a entry for this variable..
4817
6.80k
        tok = vartok->next();
4818
6.80k
        while (Token::Match(tok, "[|{"))
4819
0
            tok = tok->link()->next();
4820
4821
6.80k
        if (vartok->varId() == 0) {
4822
0
            if (!vartok->isBoolean())
4823
0
                check->debugMessage(vartok, "varid0", "Scope::checkVariable found variable \'" + vartok->str() + "\' with varid 0.");
4824
0
            return tok;
4825
0
        }
4826
4827
6.80k
        const Type *vType = nullptr;
4828
4829
6.80k
        if (typetok) {
4830
6.80k
            vType = findVariableTypeIncludingUsedNamespaces(check, this, typetok);
4831
4832
6.80k
            const_cast<Token *>(typetok)->type(vType);
4833
6.80k
        }
4834
4835
        // skip "enum" or "struct"
4836
6.80k
        if (Token::Match(typestart, "enum|struct"))
4837
0
            typestart = typestart->next();
4838
4839
6.80k
        addVariable(vartok, typestart, vartok->previous(), varaccess, vType, this, settings);
4840
6.80k
    }
4841
4842
18.7k
    return tok;
4843
18.7k
}
4844
4845
const Variable *Scope::getVariable(const std::string &varname) const
4846
0
{
4847
0
    auto it = std::find_if(varlist.begin(), varlist.end(), [&varname](const Variable& var) {
4848
0
        return var.name() == varname;
4849
0
    });
4850
0
    if (it != varlist.end())
4851
0
        return &*it;
4852
4853
0
    if (definedType) {
4854
0
        for (const Type::BaseInfo& baseInfo: definedType->derivedFrom) {
4855
0
            if (baseInfo.type && baseInfo.type->classScope) {
4856
0
                if (const Variable* var = baseInfo.type->classScope->getVariable(varname))
4857
0
                    return var;
4858
0
            }
4859
0
        }
4860
0
    }
4861
0
    return nullptr;
4862
0
}
4863
4864
static const Token* skipPointers(const Token* tok)
4865
10.7k
{
4866
10.7k
    while (Token::Match(tok, "*|&|&&") || (Token::Match(tok, "( [*&]") && Token::Match(tok->link()->next(), "(|["))) {
4867
0
        tok = tok->next();
4868
0
        if (tok->strAt(-1) == "(" && Token::Match(tok, "%type% ::"))
4869
0
            tok = tok->tokAt(2);
4870
0
    }
4871
4872
10.7k
    if (Token::simpleMatch(tok, "( *") && Token::simpleMatch(tok->link()->previous(), "] ) ;")) {
4873
0
        const Token *tok2 = skipPointers(tok->next());
4874
0
        if (Token::Match(tok2, "%name% [") && Token::simpleMatch(tok2->linkAt(1), "] ) ;"))
4875
0
            return tok2;
4876
0
    }
4877
4878
10.7k
    return tok;
4879
10.7k
}
4880
4881
static const Token* skipPointersAndQualifiers(const Token* tok)
4882
10.7k
{
4883
10.7k
    tok = skipPointers(tok);
4884
10.7k
    while (Token::Match(tok, "const|static|volatile")) {
4885
0
        tok = tok->next();
4886
0
        tok = skipPointers(tok);
4887
0
    }
4888
4889
10.7k
    return tok;
4890
10.7k
}
4891
4892
bool Scope::isVariableDeclaration(const Token* const tok, const Token*& vartok, const Token*& typetok) const
4893
18.7k
{
4894
18.7k
    if (!tok)
4895
0
        return false;
4896
4897
18.7k
    const bool isCPP = check && check->mTokenizer.isCPP();
4898
4899
18.7k
    if (isCPP && Token::Match(tok, "throw|new"))
4900
0
        return false;
4901
4902
18.7k
    const bool isCPP11 = isCPP && check->mSettings.standards.cpp >= Standards::CPP11;
4903
4904
18.7k
    if (isCPP11 && tok->str() == "using")
4905
0
        return false;
4906
4907
18.7k
    const Token* localTypeTok = skipScopeIdentifiers(tok);
4908
18.7k
    const Token* localVarTok = nullptr;
4909
4910
18.7k
    while (Token::simpleMatch(localTypeTok, "alignas (") && Token::Match(localTypeTok->linkAt(1), ") %name%"))
4911
0
        localTypeTok = localTypeTok->linkAt(1)->next();
4912
4913
18.7k
    if (Token::Match(localTypeTok, "%type% <")) {
4914
0
        if (Token::Match(tok, "const_cast|dynamic_cast|reinterpret_cast|static_cast <"))
4915
0
            return false;
4916
4917
0
        const Token* closeTok = localTypeTok->next()->link();
4918
0
        if (closeTok) {
4919
0
            localVarTok = skipPointers(closeTok->next());
4920
4921
0
            if (Token::Match(localVarTok, ":: %type% %name% [;=({]")) {
4922
0
                if (localVarTok->strAt(3) != "(" ||
4923
0
                    Token::Match(localVarTok->linkAt(3), "[)}] ;")) {
4924
0
                    localTypeTok = localVarTok->next();
4925
0
                    localVarTok = localVarTok->tokAt(2);
4926
0
                }
4927
0
            }
4928
0
        }
4929
18.7k
    } else if (Token::Match(localTypeTok, "%type%")) {
4930
4931
10.7k
        if (isCPP11 && Token::simpleMatch(localTypeTok, "decltype (") && Token::Match(localTypeTok->linkAt(1), ") %name%|*|&|&&"))
4932
0
            localVarTok = skipPointersAndQualifiers(localTypeTok->linkAt(1)->next());
4933
10.7k
        else {
4934
10.7k
            localVarTok = skipPointersAndQualifiers(localTypeTok->next());
4935
10.7k
            if (isCPP11 && Token::simpleMatch(localVarTok, "decltype (") && Token::Match(localVarTok->linkAt(1), ") %name%|*|&|&&"))
4936
0
                localVarTok = skipPointersAndQualifiers(localVarTok->linkAt(1)->next());
4937
10.7k
        }
4938
10.7k
    }
4939
4940
18.7k
    if (!localVarTok)
4941
7.95k
        return false;
4942
4943
10.7k
    while (Token::Match(localVarTok, "const|*|&"))
4944
0
        localVarTok = localVarTok->next();
4945
4946
10.7k
    if (Token::Match(localVarTok, "%name% ;|=") || (localVarTok && localVarTok->varId() && localVarTok->strAt(1) == ":")) {
4947
6.80k
        vartok = localVarTok;
4948
6.80k
        typetok = localTypeTok;
4949
6.80k
    } else if (Token::Match(localVarTok, "%name% )|[") && localVarTok->str() != "operator") {
4950
0
        vartok = localVarTok;
4951
0
        typetok = localTypeTok;
4952
3.98k
    } else if (localVarTok && localVarTok->varId() && Token::Match(localVarTok, "%name% (|{") &&
4953
3.98k
               Token::Match(localVarTok->next()->link(), ")|} ;")) {
4954
0
        vartok = localVarTok;
4955
0
        typetok = localTypeTok;
4956
3.98k
    } else if (type == eCatch &&
4957
3.98k
               Token::Match(localVarTok, "%name% )")) {
4958
0
        vartok = localVarTok;
4959
0
        typetok = localTypeTok;
4960
0
    }
4961
4962
10.7k
    return nullptr != vartok;
4963
18.7k
}
4964
4965
const Token * Scope::addEnum(const Token * tok, bool isCpp)
4966
0
{
4967
0
    const Token * tok2 = tok->next();
4968
4969
    // skip over class if present
4970
0
    if (isCpp && tok2->str() == "class")
4971
0
        tok2 = tok2->next();
4972
4973
    // skip over name
4974
0
    tok2 = tok2->next();
4975
4976
    // save type if present
4977
0
    if (tok2->str() == ":") {
4978
0
        tok2 = tok2->next();
4979
4980
0
        enumType = tok2;
4981
0
        tok2 = tok2->next();
4982
0
    }
4983
4984
    // add enumerators
4985
0
    if (tok2->str() == "{") {
4986
0
        const Token * end = tok2->link();
4987
0
        tok2 = tok2->next();
4988
4989
0
        while (Token::Match(tok2, "%name% =|,|}") ||
4990
0
               (Token::Match(tok2, "%name% (") && Token::Match(tok2->linkAt(1), ") ,|}"))) {
4991
0
            Enumerator enumerator(this);
4992
4993
            // save enumerator name
4994
0
            enumerator.name = tok2;
4995
4996
            // skip over name
4997
0
            tok2 = tok2->next();
4998
4999
0
            if (tok2->str() == "=") {
5000
                // skip over "="
5001
0
                tok2 = tok2->next();
5002
5003
0
                if (tok2->str() == "}")
5004
0
                    return nullptr;
5005
5006
0
                enumerator.start = tok2;
5007
5008
0
                while (!Token::Match(tok2, ",|}")) {
5009
0
                    if (tok2->link())
5010
0
                        tok2 = tok2->link();
5011
0
                    enumerator.end = tok2;
5012
0
                    tok2 = tok2->next();
5013
0
                }
5014
0
            } else if (tok2->str() == "(") {
5015
                // skip over unknown macro
5016
0
                tok2 = tok2->link()->next();
5017
0
            }
5018
5019
0
            if (tok2->str() == ",") {
5020
0
                enumeratorList.push_back(enumerator);
5021
0
                tok2 = tok2->next();
5022
0
            } else if (tok2->str() == "}") {
5023
0
                enumeratorList.push_back(enumerator);
5024
0
                break;
5025
0
            }
5026
0
        }
5027
5028
0
        if (tok2 == end) {
5029
0
            tok2 = tok2->next();
5030
5031
0
            if (tok2 && tok2->str() != ";" && (isCpp || tok2->str() != ")"))
5032
0
                tok2 = nullptr;
5033
0
        } else
5034
0
            tok2 = nullptr;
5035
0
    } else
5036
0
        tok2 = nullptr;
5037
5038
0
    return tok2;
5039
0
}
5040
5041
const Enumerator * SymbolDatabase::findEnumerator(const Token * tok, std::set<std::string>& tokensThatAreNotEnumeratorValues) const
5042
8.67k
{
5043
8.67k
    if (tok->isKeyword())
5044
0
        return nullptr;
5045
5046
8.67k
    const std::string& tokStr = tok->str();
5047
5048
8.67k
    if (tokensThatAreNotEnumeratorValues.find(tokStr) != tokensThatAreNotEnumeratorValues.end())
5049
6.33k
        return nullptr;
5050
5051
2.33k
    const Scope* scope = tok->scope();
5052
5053
    // check for qualified name
5054
2.33k
    if (tok->strAt(-1) == "::") {
5055
        // find first scope
5056
0
        const Token *tok1 = tok;
5057
0
        while (Token::Match(tok1->tokAt(-2), "%name% ::"))
5058
0
            tok1 = tok1->tokAt(-2);
5059
5060
0
        if (tok1->strAt(-1) == "::")
5061
0
            scope = &scopeList.front();
5062
0
        else {
5063
            // FIXME search base class here
5064
5065
            // find first scope
5066
0
            while (scope && scope->nestedIn) {
5067
0
                const Scope* temp = scope->nestedIn->findRecordInNestedList(tok1->str());
5068
0
                if (!temp && scope->functionOf)
5069
0
                    temp = scope->functionOf->findRecordInNestedList(tok1->str());
5070
0
                if (temp) {
5071
0
                    scope = temp;
5072
0
                    break;
5073
0
                }
5074
0
                scope = scope->nestedIn;
5075
0
            }
5076
0
        }
5077
5078
0
        if (scope) {
5079
0
            tok1 = tok1->tokAt(2);
5080
0
            while (scope && Token::Match(tok1, "%name% ::")) {
5081
0
                scope = scope->findRecordInNestedList(tok1->str());
5082
0
                tok1 = tok1->tokAt(2);
5083
0
            }
5084
5085
0
            if (scope) {
5086
0
                const Enumerator * enumerator = scope->findEnumerator(tokStr);
5087
5088
0
                if (enumerator) // enum class
5089
0
                    return enumerator;
5090
                // enum
5091
0
                for (std::vector<Scope *>::const_iterator it = scope->nestedList.cbegin(), end = scope->nestedList.cend(); it != end; ++it) {
5092
0
                    enumerator = (*it)->findEnumerator(tokStr);
5093
5094
0
                    if (enumerator && !(enumerator->scope && enumerator->scope->enumClass))
5095
0
                        return enumerator;
5096
0
                }
5097
0
            }
5098
0
        }
5099
2.33k
    } else { // unqualified name
5100
2.33k
        const Enumerator * enumerator = scope->findEnumerator(tokStr);
5101
5102
2.33k
        if (enumerator && !(enumerator->scope && enumerator->scope->enumClass))
5103
0
            return enumerator;
5104
5105
2.33k
        if (Token::simpleMatch(tok->astParent(), ".")) {
5106
0
            const Token* varTok = tok->astParent()->astOperand1();
5107
0
            if (varTok && varTok->variable() && varTok->variable()->type() && varTok->variable()->type()->classScope)
5108
0
                scope = varTok->variable()->type()->classScope;
5109
0
        }
5110
2.33k
        else if (Token::simpleMatch(tok->astParent(), "[")) {
5111
0
            const Token* varTok = tok->astParent()->previous();
5112
0
            if (varTok && varTok->variable() && varTok->variable()->scope() && Token::simpleMatch(tok->astParent()->astOperand1(), "::"))
5113
0
                scope = varTok->variable()->scope();
5114
0
        }
5115
5116
4.87k
        for (std::vector<Scope *>::const_iterator s = scope->nestedList.cbegin(); s != scope->nestedList.cend(); ++s) {
5117
2.53k
            enumerator = (*s)->findEnumerator(tokStr);
5118
5119
2.53k
            if (enumerator && !(enumerator->scope && enumerator->scope->enumClass))
5120
0
                return enumerator;
5121
2.53k
        }
5122
5123
2.33k
        if (scope->definedType) {
5124
0
            const std::vector<Type::BaseInfo> & derivedFrom = scope->definedType->derivedFrom;
5125
0
            for (const Type::BaseInfo & i : derivedFrom) {
5126
0
                const Type *derivedFromType = i.type;
5127
0
                if (derivedFromType && derivedFromType->classScope) {
5128
0
                    enumerator = derivedFromType->classScope->findEnumerator(tokStr);
5129
5130
0
                    if (enumerator && !(enumerator->scope && enumerator->scope->enumClass))
5131
0
                        return enumerator;
5132
0
                }
5133
0
            }
5134
0
        }
5135
5136
3.59k
        while (scope->nestedIn) {
5137
1.25k
            if (scope->type == Scope::eFunction && scope->functionOf)
5138
0
                scope = scope->functionOf;
5139
1.25k
            else
5140
1.25k
                scope = scope->nestedIn;
5141
5142
1.25k
            enumerator = scope->findEnumerator(tokStr);
5143
5144
1.25k
            if (enumerator && !(enumerator->scope && enumerator->scope->enumClass))
5145
0
                return enumerator;
5146
5147
3.04k
            for (std::vector<Scope*>::const_iterator s = scope->nestedList.cbegin(); s != scope->nestedList.cend(); ++s) {
5148
1.78k
                enumerator = (*s)->findEnumerator(tokStr);
5149
5150
1.78k
                if (enumerator && !(enumerator->scope && enumerator->scope->enumClass))
5151
0
                    return enumerator;
5152
1.78k
            }
5153
1.25k
        }
5154
2.33k
    }
5155
5156
2.33k
    tokensThatAreNotEnumeratorValues.insert(tokStr);
5157
5158
2.33k
    return nullptr;
5159
2.33k
}
5160
5161
//---------------------------------------------------------------------------
5162
5163
const Type* SymbolDatabase::findVariableTypeInBase(const Scope* scope, const Token* typeTok)
5164
1.73k
{
5165
1.73k
    if (scope && scope->definedType && !scope->definedType->derivedFrom.empty()) {
5166
0
        const std::vector<Type::BaseInfo> &derivedFrom = scope->definedType->derivedFrom;
5167
0
        for (const Type::BaseInfo & i : derivedFrom) {
5168
0
            const Type *base = i.type;
5169
0
            if (base && base->classScope) {
5170
0
                if (base->classScope == scope)
5171
0
                    return nullptr;
5172
0
                const Type * type = base->classScope->findType(typeTok->str());
5173
0
                if (type)
5174
0
                    return type;
5175
0
                type = findVariableTypeInBase(base->classScope, typeTok);
5176
0
                if (type)
5177
0
                    return type;
5178
0
            }
5179
0
        }
5180
0
    }
5181
5182
1.73k
    return nullptr;
5183
1.73k
}
5184
5185
//---------------------------------------------------------------------------
5186
5187
const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *typeTok) const
5188
6.80k
{
5189
6.80k
    const Scope *scope = start;
5190
5191
    // check if type does not have a namespace
5192
6.80k
    if (typeTok->strAt(-1) != "::" && typeTok->strAt(1) != "::") {
5193
        // check if type same as scope
5194
6.80k
        if (start->isClassOrStruct() && typeTok->str() == start->className)
5195
0
            return start->definedType;
5196
5197
13.6k
        while (scope) {
5198
            // look for type in this scope
5199
6.80k
            const Type * type = scope->findType(typeTok->str());
5200
5201
6.80k
            if (type)
5202
0
                return type;
5203
5204
            // look for type in base classes if possible
5205
6.80k
            if (scope->isClassOrStruct()) {
5206
0
                type = findVariableTypeInBase(scope, typeTok);
5207
5208
0
                if (type)
5209
0
                    return type;
5210
0
            }
5211
5212
            // check if in member function class to see if it's present in class
5213
6.80k
            if (scope->type == Scope::eFunction && scope->functionOf) {
5214
0
                const Scope *scope1 = scope->functionOf;
5215
5216
0
                type = scope1->findType(typeTok->str());
5217
5218
0
                if (type)
5219
0
                    return type;
5220
5221
0
                type = findVariableTypeInBase(scope1, typeTok);
5222
5223
0
                if (type)
5224
0
                    return type;
5225
0
            }
5226
5227
6.80k
            scope = scope->nestedIn;
5228
6.80k
        }
5229
6.80k
    }
5230
5231
    // check for a qualified name and use it when given
5232
0
    else if (typeTok->strAt(-1) == "::") {
5233
        // check if type is not part of qualification
5234
0
        if (typeTok->strAt(1) == "::")
5235
0
            return nullptr;
5236
5237
        // find start of qualified function name
5238
0
        const Token *tok1 = typeTok;
5239
5240
0
        while ((Token::Match(tok1->tokAt(-2), "%type% ::") && !tok1->tokAt(-2)->isKeyword()) ||
5241
0
               (Token::simpleMatch(tok1->tokAt(-2), "> ::") && tok1->linkAt(-2) && Token::Match(tok1->linkAt(-2)->tokAt(-1), "%type%"))) {
5242
0
            if (tok1->strAt(-1) == "::")
5243
0
                tok1 = tok1->tokAt(-2);
5244
0
            else
5245
0
                tok1 = tok1->linkAt(-2)->tokAt(-1);
5246
0
        }
5247
5248
        // check for global scope
5249
0
        if (tok1->strAt(-1) == "::") {
5250
0
            scope = &scopeList.front();
5251
5252
0
            scope = scope->findRecordInNestedList(tok1->str());
5253
0
        }
5254
5255
        // find start of qualification
5256
0
        else {
5257
0
            while (scope) {
5258
0
                if (scope->className == tok1->str())
5259
0
                    break;
5260
5261
0
                const Scope *scope1 = scope->findRecordInNestedList(tok1->str());
5262
5263
0
                if (scope1) {
5264
0
                    scope = scope1;
5265
0
                    break;
5266
0
                }
5267
0
                if (scope->type == Scope::eFunction && scope->functionOf)
5268
0
                    scope = scope->functionOf;
5269
0
                else
5270
0
                    scope = scope->nestedIn;
5271
0
            }
5272
0
        }
5273
5274
0
        if (scope) {
5275
            // follow qualification
5276
0
            while (scope && (Token::Match(tok1, "%type% ::") ||
5277
0
                             (Token::Match(tok1, "%type% <") && Token::simpleMatch(tok1->linkAt(1), "> ::")))) {
5278
0
                if (tok1->strAt(1) == "::")
5279
0
                    tok1 = tok1->tokAt(2);
5280
0
                else
5281
0
                    tok1 = tok1->linkAt(1)->tokAt(2);
5282
0
                const Scope * temp = scope->findRecordInNestedList(tok1->str());
5283
0
                if (!temp) {
5284
                    // look in base classes
5285
0
                    const Type * type = findVariableTypeInBase(scope, tok1);
5286
5287
0
                    if (type)
5288
0
                        return type;
5289
0
                }
5290
0
                scope = temp;
5291
0
            }
5292
5293
0
            if (scope && scope->definedType)
5294
0
                return scope->definedType;
5295
0
        }
5296
0
    }
5297
5298
6.80k
    return nullptr;
5299
6.80k
}
5300
5301
0
static bool hasEmptyCaptureList(const Token* tok) {
5302
0
    if (!Token::simpleMatch(tok, "{"))
5303
0
        return false;
5304
0
    const Token* listTok = tok->astParent();
5305
0
    if (Token::simpleMatch(listTok, "("))
5306
0
        listTok = listTok->astParent();
5307
0
    return Token::simpleMatch(listTok, "[ ]");
5308
0
}
5309
5310
bool Scope::hasInlineOrLambdaFunction() const
5311
7.16k
{
5312
7.16k
    return std::any_of(nestedList.begin(), nestedList.end(), [&](const Scope* s) {
5313
        // Inline function
5314
3.68k
        if (s->type == Scope::eUnconditional && Token::simpleMatch(s->bodyStart->previous(), ") {"))
5315
0
            return true;
5316
        // Lambda function
5317
3.68k
        if (s->type == Scope::eLambda && !hasEmptyCaptureList(s->bodyStart))
5318
0
            return true;
5319
3.68k
        if (s->hasInlineOrLambdaFunction())
5320
0
            return true;
5321
3.68k
        return false;
5322
3.68k
    });
5323
7.16k
}
5324
5325
void Scope::findFunctionInBase(const std::string & name, nonneg int args, std::vector<const Function *> & matches) const
5326
4.21k
{
5327
4.21k
    if (isClassOrStruct() && definedType && !definedType->derivedFrom.empty()) {
5328
0
        const std::vector<Type::BaseInfo> &derivedFrom = definedType->derivedFrom;
5329
0
        for (const Type::BaseInfo & i : derivedFrom) {
5330
0
            const Type *base = i.type;
5331
0
            if (base && base->classScope) {
5332
0
                if (base->classScope == this) // Ticket #5120, #5125: Recursive class; tok should have been found already
5333
0
                    continue;
5334
5335
0
                auto range = base->classScope->functionMap.equal_range(name);
5336
0
                for (std::multimap<std::string, const Function*>::const_iterator it = range.first; it != range.second; ++it) {
5337
0
                    const Function *func = it->second;
5338
0
                    if ((func->isVariadic() && args >= (func->argCount() - 1)) ||
5339
0
                        (args == func->argCount() || (args < func->argCount() && args >= func->minArgCount()))) {
5340
0
                        matches.push_back(func);
5341
0
                    }
5342
0
                }
5343
5344
0
                base->classScope->findFunctionInBase(name, args, matches);
5345
0
            }
5346
0
        }
5347
0
    }
5348
4.21k
}
5349
5350
const Scope *Scope::findRecordInBase(const std::string & name) const
5351
0
{
5352
0
    if (isClassOrStruct() && definedType && !definedType->derivedFrom.empty()) {
5353
0
        const std::vector<Type::BaseInfo> &derivedFrom = definedType->derivedFrom;
5354
0
        for (const Type::BaseInfo & i : derivedFrom) {
5355
0
            const Type *base = i.type;
5356
0
            if (base && base->classScope) {
5357
0
                if (base->classScope == this) // Recursive class; tok should have been found already
5358
0
                    continue;
5359
5360
0
                if (base->name() == name) {
5361
0
                    return base->classScope;
5362
0
                }
5363
5364
0
                const ::Type * t = base->classScope->findType(name);
5365
0
                if (t)
5366
0
                    return t->classScope;
5367
0
            }
5368
0
        }
5369
0
    }
5370
5371
0
    return nullptr;
5372
0
}
5373
5374
std::vector<const Scope*> Scope::findAssociatedScopes() const
5375
0
{
5376
0
    std::vector<const Scope*> result = {this};
5377
0
    if (isClassOrStruct() && definedType && !definedType->derivedFrom.empty()) {
5378
0
        const std::vector<Type::BaseInfo>& derivedFrom = definedType->derivedFrom;
5379
0
        for (const Type::BaseInfo& i : derivedFrom) {
5380
0
            const Type* base = i.type;
5381
0
            if (base && base->classScope) {
5382
0
                if (contains(result, base->classScope))
5383
0
                    continue;
5384
0
                std::vector<const Scope*> baseScopes = base->classScope->findAssociatedScopes();
5385
0
                result.insert(result.end(), baseScopes.cbegin(), baseScopes.cend());
5386
0
            }
5387
0
        }
5388
0
    }
5389
0
    return result;
5390
0
}
5391
5392
//---------------------------------------------------------------------------
5393
5394
static void checkVariableCallMatch(const Variable* callarg, const Variable* funcarg, size_t& same, size_t& fallback1, size_t& fallback2)
5395
0
{
5396
0
    if (callarg) {
5397
0
        const ValueType::MatchResult res = ValueType::matchParameter(callarg->valueType(), callarg, funcarg);
5398
0
        if (res == ValueType::MatchResult::SAME) {
5399
0
            same++;
5400
0
            return;
5401
0
        }
5402
0
        if (res == ValueType::MatchResult::FALLBACK1) {
5403
0
            fallback1++;
5404
0
            return;
5405
0
        }
5406
0
        if (res == ValueType::MatchResult::FALLBACK2) {
5407
0
            fallback2++;
5408
0
            return;
5409
0
        }
5410
0
        if (res == ValueType::MatchResult::NOMATCH)
5411
0
            return;
5412
5413
0
        const bool ptrequals = callarg->isArrayOrPointer() == funcarg->isArrayOrPointer();
5414
0
        const bool constEquals = !callarg->isArrayOrPointer() || ((callarg->typeStartToken()->strAt(-1) == "const") == (funcarg->typeStartToken()->strAt(-1) == "const"));
5415
0
        if (ptrequals && constEquals &&
5416
0
            callarg->typeStartToken()->str() == funcarg->typeStartToken()->str() &&
5417
0
            callarg->typeStartToken()->isUnsigned() == funcarg->typeStartToken()->isUnsigned() &&
5418
0
            callarg->typeStartToken()->isLong() == funcarg->typeStartToken()->isLong()) {
5419
0
            same++;
5420
0
        } else if (callarg->isArrayOrPointer()) {
5421
0
            if (ptrequals && constEquals && funcarg->typeStartToken()->str() == "void")
5422
0
                fallback1++;
5423
0
            else if (constEquals && funcarg->isStlStringType() && Token::Match(callarg->typeStartToken(), "char|wchar_t"))
5424
0
                fallback2++;
5425
0
        } else if (ptrequals) {
5426
0
            const bool takesInt = Token::Match(funcarg->typeStartToken(), "char|short|int|long");
5427
0
            const bool takesFloat = Token::Match(funcarg->typeStartToken(), "float|double");
5428
0
            const bool passesInt = Token::Match(callarg->typeStartToken(), "char|short|int|long");
5429
0
            const bool passesFloat = Token::Match(callarg->typeStartToken(), "float|double");
5430
0
            if ((takesInt && passesInt) || (takesFloat && passesFloat))
5431
0
                fallback1++;
5432
0
            else if ((takesInt && passesFloat) || (takesFloat && passesInt))
5433
0
                fallback2++;
5434
0
        }
5435
0
    }
5436
0
}
5437
5438
static std::string getTypeString(const Token *typeToken)
5439
0
{
5440
0
    if (!typeToken)
5441
0
        return "";
5442
0
    while (Token::Match(typeToken, "%name%|*|&|::")) {
5443
0
        if (typeToken->str() == "::") {
5444
0
            std::string ret;
5445
0
            while (Token::Match(typeToken, ":: %name%")) {
5446
0
                ret += "::" + typeToken->strAt(1);
5447
0
                typeToken = typeToken->tokAt(2);
5448
0
                if (typeToken->str() == "<") {
5449
0
                    for (const Token *tok = typeToken; tok != typeToken->link(); tok = tok->next())
5450
0
                        ret += tok->str();
5451
0
                    ret += ">";
5452
0
                    typeToken = typeToken->link()->next();
5453
0
                }
5454
0
            }
5455
0
            return ret;
5456
0
        }
5457
0
        if (Token::Match(typeToken, "%name% const| %var%|*|&")) {
5458
0
            return typeToken->str();
5459
0
        }
5460
0
        typeToken = typeToken->next();
5461
0
    }
5462
0
    return "";
5463
0
}
5464
5465
0
static bool hasMatchingConstructor(const Scope* classScope, const ValueType* argType) {
5466
0
    if (!classScope || !argType)
5467
0
        return false;
5468
0
    return std::any_of(classScope->functionList.cbegin(),
5469
0
                       classScope->functionList.cend(),
5470
0
                       [&](const Function& f) {
5471
0
        if (!f.isConstructor() || f.argCount() != 1 || !f.getArgumentVar(0))
5472
0
            return false;
5473
0
        const ValueType* vt = f.getArgumentVar(0)->valueType();
5474
0
        return vt &&
5475
0
        vt->type == argType->type &&
5476
0
        (argType->sign == ValueType::Sign::UNKNOWN_SIGN || vt->sign == argType->sign) &&
5477
0
        vt->pointer == argType->pointer &&
5478
0
        (vt->constness & 1) >= (argType->constness & 1);
5479
0
    });
5480
0
}
5481
5482
const Function* Scope::findFunction(const Token *tok, bool requireConst) const
5483
4.21k
{
5484
4.21k
    const bool isCall = Token::Match(tok->next(), "(|{");
5485
5486
4.21k
    const std::vector<const Token *> arguments = getArguments(tok);
5487
5488
4.21k
    std::vector<const Function *> matches;
5489
5490
    // find all the possible functions that could match
5491
4.21k
    const std::size_t args = arguments.size();
5492
5493
4.21k
    auto addMatchingFunctions = [&](const Scope *scope) {
5494
4.21k
        auto range = scope->functionMap.equal_range(tok->str());
5495
5.95k
        for (std::multimap<std::string, const Function *>::const_iterator it = range.first; it != range.second; ++it) {
5496
1.73k
            const Function *func = it->second;
5497
1.73k
            if (!isCall || args == func->argCount() ||
5498
1.73k
                (func->isVariadic() && args >= (func->minArgCount() - 1)) ||
5499
1.73k
                (args < func->argCount() && args >= func->minArgCount())) {
5500
1.73k
                matches.push_back(func);
5501
1.73k
            }
5502
1.73k
        }
5503
4.21k
    };
5504
5505
4.21k
    addMatchingFunctions(this);
5506
5507
    // check in anonymous namespaces
5508
7.21k
    for (const Scope *nestedScope : nestedList) {
5509
7.21k
        if (nestedScope->type == eNamespace && nestedScope->className.empty())
5510
0
            addMatchingFunctions(nestedScope);
5511
7.21k
    }
5512
5513
4.21k
    const std::size_t numberOfMatchesNonBase = matches.size();
5514
5515
    // check in base classes
5516
4.21k
    findFunctionInBase(tok->str(), args, matches);
5517
5518
    // Non-call => Do not match parameters
5519
4.21k
    if (!isCall) {
5520
2.47k
        return matches.empty() ? nullptr : matches[0];
5521
2.47k
    }
5522
5523
1.73k
    std::vector<const Function*> fallback1Func, fallback2Func;
5524
5525
    // check each function against the arguments in the function call for a match
5526
1.73k
    for (std::size_t i = 0; i < matches.size();) {
5527
1.73k
        if (i > 0 && i == numberOfMatchesNonBase && fallback1Func.empty() && !fallback2Func.empty())
5528
0
            break;
5529
5530
1.73k
        bool constFallback = false;
5531
1.73k
        const Function * func = matches[i];
5532
1.73k
        size_t same = 0;
5533
5534
1.73k
        if (requireConst && !func->isConst()) {
5535
0
            i++;
5536
0
            continue;
5537
0
        }
5538
5539
1.73k
        if (!requireConst || !func->isConst()) {
5540
            // get the function this call is in
5541
1.73k
            const Scope * scope = tok->scope();
5542
5543
            // check if this function is a member function
5544
1.73k
            if (scope && scope->functionOf && scope->functionOf->isClassOrStruct() && scope->function &&
5545
1.73k
                func->nestedIn == scope->functionOf) {
5546
                // check if isConst mismatches
5547
0
                if (scope->function->isConst() != func->isConst()) {
5548
0
                    if (scope->function->isConst()) {
5549
0
                        ++i;
5550
0
                        continue;
5551
0
                    }
5552
0
                    constFallback = true;
5553
0
                }
5554
0
            }
5555
1.73k
        }
5556
5557
1.73k
        size_t fallback1 = 0;
5558
1.73k
        size_t fallback2 = 0;
5559
1.73k
        bool erased = false;
5560
1.73k
        for (std::size_t j = 0; j < args; ++j) {
5561
5562
            // don't check variadic arguments
5563
0
            if (func->isVariadic() && j > (func->argCount() - 1)) {
5564
0
                break;
5565
0
            }
5566
0
            const Variable *funcarg = func->getArgumentVar(j);
5567
5568
0
            if (!arguments[j]->valueType()) {
5569
0
                const Token *vartok = arguments[j];
5570
0
                int pointer = 0;
5571
0
                while (vartok && (vartok->isUnaryOp("&") || vartok->isUnaryOp("*"))) {
5572
0
                    pointer += vartok->isUnaryOp("&") ? 1 : -1;
5573
0
                    vartok = vartok->astOperand1();
5574
0
                }
5575
0
                if (vartok && vartok->variable()) {
5576
0
                    const Token *callArgTypeToken = vartok->variable()->typeStartToken();
5577
0
                    const Token *funcArgTypeToken = funcarg->typeStartToken();
5578
5579
0
                    auto parseDecl = [](const Token *typeToken) -> ValueType {
5580
0
                        ValueType ret;
5581
0
                        while (Token::Match(typeToken->previous(), "%name%"))
5582
0
                            typeToken = typeToken->previous();
5583
0
                        while (Token::Match(typeToken, "%name%|*|&|::|<"))
5584
0
                        {
5585
0
                            if (typeToken->str() == "const")
5586
0
                                ret.constness |= (1 << ret.pointer);
5587
0
                            else if (typeToken->str() == "*")
5588
0
                                ret.pointer++;
5589
0
                            else if (typeToken->str() == "<") {
5590
0
                                if (!typeToken->link())
5591
0
                                    break;
5592
0
                                typeToken = typeToken->link();
5593
0
                            }
5594
0
                            typeToken = typeToken->next();
5595
0
                        }
5596
0
                        return ret;
5597
0
                    };
5598
5599
0
                    const std::string type1 = getTypeString(callArgTypeToken);
5600
0
                    const std::string type2 = getTypeString(funcArgTypeToken);
5601
0
                    if (!type1.empty() && type1 == type2) {
5602
0
                        ValueType callArgType = parseDecl(callArgTypeToken);
5603
0
                        callArgType.pointer += pointer;
5604
0
                        ValueType funcArgType = parseDecl(funcArgTypeToken);
5605
5606
0
                        callArgType.sign = funcArgType.sign = ValueType::Sign::SIGNED;
5607
0
                        callArgType.type = funcArgType.type = ValueType::Type::INT;
5608
5609
0
                        const ValueType::MatchResult res = ValueType::matchParameter(&callArgType, &funcArgType);
5610
0
                        if (res == ValueType::MatchResult::SAME)
5611
0
                            ++same;
5612
0
                        else if (res == ValueType::MatchResult::FALLBACK1)
5613
0
                            ++fallback1;
5614
0
                        else if (res == ValueType::MatchResult::FALLBACK2)
5615
0
                            ++fallback2;
5616
0
                        continue;
5617
0
                    }
5618
0
                }
5619
0
            }
5620
5621
            // check for a match with a variable
5622
0
            if (Token::Match(arguments[j], "%var% ,|)")) {
5623
0
                const Variable * callarg = arguments[j]->variable();
5624
0
                checkVariableCallMatch(callarg, funcarg, same, fallback1, fallback2);
5625
0
            }
5626
5627
0
            else if (funcarg->isStlStringType() && arguments[j]->valueType() && arguments[j]->valueType()->pointer == 1 && arguments[j]->valueType()->type == ValueType::Type::CHAR)
5628
0
                fallback2++;
5629
5630
            // check for a match with nullptr
5631
0
            else if (funcarg->isPointer() && Token::Match(arguments[j], "nullptr|NULL ,|)"))
5632
0
                same++;
5633
5634
0
            else if (funcarg->isPointer() && MathLib::isNullValue(arguments[j]->str()))
5635
0
                fallback1++;
5636
5637
0
            else if (!funcarg->isPointer() && funcarg->type() && hasMatchingConstructor(funcarg->type()->classScope, arguments[j]->valueType()))
5638
0
                fallback2++;
5639
5640
            // Try to evaluate the apparently more complex expression
5641
0
            else if (check->isCPP()) {
5642
0
                const Token *vartok = arguments[j];
5643
0
                if (vartok->str() == ".") {
5644
0
                    const Token* rml = nextAfterAstRightmostLeaf(vartok);
5645
0
                    if (rml)
5646
0
                        vartok = rml->previous();
5647
0
                }
5648
0
                while (vartok->isUnaryOp("&") || vartok->isUnaryOp("*"))
5649
0
                    vartok = vartok->astOperand1();
5650
0
                const Variable* var = vartok->variable();
5651
                // smart pointer deref?
5652
0
                bool unknownDeref = false;
5653
0
                if (var && vartok->astParent() && vartok->astParent()->str() == "*") {
5654
0
                    if (var->isSmartPointer() && var->valueType() && var->valueType()->smartPointerTypeToken)
5655
0
                        var = var->valueType()->smartPointerTypeToken->variable();
5656
0
                    else
5657
0
                        unknownDeref = true;
5658
0
                }
5659
0
                const Token* valuetok = arguments[j];
5660
0
                if (valuetok->str() == "::") {
5661
0
                    const Token* rml = nextAfterAstRightmostLeaf(valuetok);
5662
0
                    if (rml)
5663
0
                        valuetok = rml->previous();
5664
0
                }
5665
0
                if (vartok->isEnumerator())
5666
0
                    valuetok = vartok;
5667
0
                const ValueType::MatchResult res = ValueType::matchParameter(valuetok->valueType(), var, funcarg);
5668
0
                if (res == ValueType::MatchResult::SAME)
5669
0
                    ++same;
5670
0
                else if (res == ValueType::MatchResult::FALLBACK1)
5671
0
                    ++fallback1;
5672
0
                else if (res == ValueType::MatchResult::FALLBACK2)
5673
0
                    ++fallback2;
5674
0
                else if (res == ValueType::MatchResult::NOMATCH) {
5675
0
                    if (unknownDeref)
5676
0
                        continue;
5677
                    // can't match so remove this function from possible matches
5678
0
                    matches.erase(matches.begin() + i);
5679
0
                    erased = true;
5680
0
                    break;
5681
0
                }
5682
0
            }
5683
5684
0
            else
5685
                // C code: if number of arguments match then do not match types
5686
0
                fallback1++;
5687
0
        }
5688
5689
1.73k
        const size_t hasToBe = func->isVariadic() ? (func->argCount() - 1) : args;
5690
5691
        // check if all arguments matched
5692
1.73k
        if (same == hasToBe) {
5693
1.73k
            if (constFallback || (!requireConst && func->isConst()))
5694
0
                fallback1Func.emplace_back(func);
5695
1.73k
            else
5696
1.73k
                return func;
5697
1.73k
        }
5698
5699
0
        else {
5700
0
            if (same + fallback1 == hasToBe)
5701
0
                fallback1Func.emplace_back(func);
5702
0
            else if (same + fallback2 + fallback1 == hasToBe)
5703
0
                fallback2Func.emplace_back(func);
5704
0
        }
5705
5706
0
        if (!erased)
5707
0
            ++i;
5708
0
    }
5709
5710
    // Fallback cases
5711
0
    for (const auto& fb : { fallback1Func, fallback2Func }) {
5712
0
        if (fb.size() == 1)
5713
0
            return fb.front();
5714
0
        if (fb.size() == 2) {
5715
0
            if (fb[0]->isConst() && !fb[1]->isConst())
5716
0
                return fb[1];
5717
0
            if (fb[1]->isConst() && !fb[0]->isConst())
5718
0
                return fb[0];
5719
0
        }
5720
0
    }
5721
5722
    // remove pure virtual function if there is an overrider
5723
0
    auto itPure = std::find_if(matches.begin(), matches.end(), [](const Function* m) {
5724
0
        return m->isPure();
5725
0
    });
5726
0
    if (itPure != matches.end() && std::any_of(matches.begin(), matches.end(), [&](const Function* m) {
5727
0
        return m->isImplicitlyVirtual() && m != *itPure;
5728
0
    }))
5729
0
        matches.erase(itPure);
5730
5731
    // Only one candidate left
5732
0
    if (matches.size() == 1)
5733
0
        return matches[0];
5734
5735
    // Prioritize matches in derived scopes
5736
0
    for (const auto& fb : { fallback1Func, fallback2Func }) {
5737
0
        const Function* ret = nullptr;
5738
0
        for (int i = 0; i < fb.size(); ++i) {
5739
0
            if (std::find(matches.cbegin(), matches.cend(), fb[i]) == matches.cend())
5740
0
                continue;
5741
0
            if (this == fb[i]->nestedIn) {
5742
0
                if (!ret)
5743
0
                    ret = fb[i];
5744
0
                else {
5745
0
                    ret = nullptr;
5746
0
                    break;
5747
0
                }
5748
0
            }
5749
0
        }
5750
0
        if (ret)
5751
0
            return ret;
5752
0
    }
5753
5754
0
    return nullptr;
5755
0
}
5756
5757
//---------------------------------------------------------------------------
5758
5759
const Function* SymbolDatabase::findFunction(const Token* const tok) const
5760
4.21k
{
5761
    // find the scope this function is in
5762
4.21k
    const Scope *currScope = tok->scope();
5763
8.05k
    while (currScope && currScope->isExecutable()) {
5764
3.84k
        if (currScope->functionOf)
5765
0
            currScope = currScope->functionOf;
5766
3.84k
        else
5767
3.84k
            currScope = currScope->nestedIn;
5768
3.84k
    }
5769
5770
    // check for a qualified name and use it when given
5771
4.21k
    if (tok->strAt(-1) == "::") {
5772
        // find start of qualified function name
5773
0
        const Token *tok1 = tok;
5774
5775
0
        while (Token::Match(tok1->tokAt(-2), ">|%type% ::")) {
5776
0
            if (tok1->strAt(-2) == ">") {
5777
0
                if (tok1->linkAt(-2))
5778
0
                    tok1 = tok1->linkAt(-2)->tokAt(-1);
5779
0
                else
5780
0
                    break;
5781
0
            } else
5782
0
                tok1 = tok1->tokAt(-2);
5783
0
        }
5784
5785
        // check for global scope
5786
0
        if (tok1->strAt(-1) == "::") {
5787
0
            currScope = &scopeList.front();
5788
5789
0
            if (const Function* f = currScope->findFunction(tok))
5790
0
                return f;
5791
5792
0
            currScope = currScope->findRecordInNestedList(tok1->str());
5793
0
        }
5794
5795
        // find start of qualification
5796
0
        else {
5797
0
            while (currScope) {
5798
0
                if (currScope->className == tok1->str())
5799
0
                    break;
5800
5801
0
                const Scope *scope = currScope->findRecordInNestedList(tok1->str());
5802
5803
0
                if (scope) {
5804
0
                    currScope = scope;
5805
0
                    break;
5806
0
                }
5807
0
                currScope = currScope->nestedIn;
5808
0
            }
5809
0
        }
5810
5811
0
        if (currScope) {
5812
0
            while (currScope && tok1 && !(Token::Match(tok1, "%type% :: %name% [(),>]") ||
5813
0
                                          (Token::Match(tok1, "%type% <") && Token::Match(tok1->linkAt(1), "> :: %name% (")))) {
5814
0
                if (tok1->strAt(1) == "::")
5815
0
                    tok1 = tok1->tokAt(2);
5816
0
                else if (tok1->strAt(1) == "<")
5817
0
                    tok1 = tok1->linkAt(1)->tokAt(2);
5818
0
                else
5819
0
                    tok1 = nullptr;
5820
5821
0
                if (tok1) {
5822
0
                    const Function* func = currScope->findFunction(tok1);
5823
0
                    if (func)
5824
0
                        return func;
5825
5826
0
                    currScope = currScope->findRecordInNestedList(tok1->str());
5827
0
                }
5828
0
            }
5829
5830
0
            if (tok1)
5831
0
                tok1 = tok1->tokAt(2);
5832
5833
0
            if (currScope && tok1)
5834
0
                return currScope->findFunction(tok1);
5835
0
        }
5836
0
    }
5837
5838
    // check for member function
5839
4.21k
    else if (Token::Match(tok->tokAt(-2), "!!this .")) {
5840
0
        const Token* tok1 = tok->previous()->astOperand1();
5841
0
        if (tok1 && tok1->valueType() && tok1->valueType()->typeScope)
5842
0
            return tok1->valueType()->typeScope->findFunction(tok, tok1->valueType()->constness == 1);
5843
0
        if (tok1 && Token::Match(tok1->previous(), "%name% (") && tok1->previous()->function() &&
5844
0
            tok1->previous()->function()->retDef) {
5845
0
            ValueType vt = ValueType::parseDecl(tok1->previous()->function()->retDef, mSettings);
5846
0
            if (vt.typeScope)
5847
0
                return vt.typeScope->findFunction(tok, vt.constness == 1);
5848
0
        } else if (Token::Match(tok1, "%var% .")) {
5849
0
            const Variable *var = getVariableFromVarId(tok1->varId());
5850
0
            if (var && var->typeScope())
5851
0
                return var->typeScope()->findFunction(tok, var->valueType()->constness == 1);
5852
0
            if (var && var->smartPointerType() && var->smartPointerType()->classScope && tok1->next()->originalName() == "->")
5853
0
                return var->smartPointerType()->classScope->findFunction(tok, var->valueType()->constness == 1);
5854
0
            if (var && var->iteratorType() && var->iteratorType()->classScope && tok1->next()->originalName() == "->")
5855
0
                return var->iteratorType()->classScope->findFunction(tok, var->valueType()->constness == 1);
5856
0
        } else if (Token::simpleMatch(tok->previous()->astOperand1(), "(")) {
5857
0
            const Token *castTok = tok->previous()->astOperand1();
5858
0
            if (castTok->isCast()) {
5859
0
                ValueType vt = ValueType::parseDecl(castTok->next(),mSettings);
5860
0
                if (vt.typeScope)
5861
0
                    return vt.typeScope->findFunction(tok, vt.constness == 1);
5862
0
            }
5863
0
        }
5864
0
    }
5865
5866
    // check in enclosing scopes
5867
4.21k
    else {
5868
6.68k
        while (currScope) {
5869
4.21k
            const Function *func = currScope->findFunction(tok);
5870
4.21k
            if (func)
5871
1.73k
                return func;
5872
2.47k
            currScope = currScope->nestedIn;
5873
2.47k
        }
5874
        // check using namespace
5875
2.47k
        currScope = tok->scope();
5876
8.79k
        while (currScope) {
5877
6.32k
            for (const auto& ul : currScope->usingList) {
5878
0
                if (ul.scope) {
5879
0
                    const Function* func = ul.scope->findFunction(tok);
5880
0
                    if (func)
5881
0
                        return func;
5882
0
                }
5883
0
            }
5884
6.32k
            currScope = currScope->nestedIn;
5885
6.32k
        }
5886
2.47k
    }
5887
    // Check for constructor
5888
2.47k
    if (Token::Match(tok, "%name% (|{")) {
5889
0
        ValueType vt = ValueType::parseDecl(tok, mSettings);
5890
0
        if (vt.typeScope)
5891
0
            return vt.typeScope->findFunction(tok, false);
5892
0
    }
5893
2.47k
    return nullptr;
5894
2.47k
}
5895
5896
//---------------------------------------------------------------------------
5897
5898
const Scope *SymbolDatabase::findScopeByName(const std::string& name) const
5899
0
{
5900
0
    auto it = std::find_if(scopeList.cbegin(), scopeList.cend(), [&](const Scope& s) {
5901
0
        return s.className == name;
5902
0
    });
5903
0
    return it == scopeList.end() ? nullptr : &*it;
5904
0
}
5905
5906
//---------------------------------------------------------------------------
5907
5908
const Scope *Scope::findRecordInNestedList(const std::string & name, bool isC) const
5909
0
{
5910
0
    for (const Scope* scope: nestedList) {
5911
0
        if (scope->className == name && scope->type != eFunction)
5912
0
            return scope;
5913
0
        if (isC) {
5914
0
            const Scope* nestedScope = scope->findRecordInNestedList(name, isC);
5915
0
            if (nestedScope)
5916
0
                return nestedScope;
5917
0
        }
5918
0
    }
5919
5920
0
    const Type * nested_type = findType(name);
5921
5922
0
    if (nested_type) {
5923
0
        if (nested_type->isTypeAlias()) {
5924
0
            if (nested_type->typeStart == nested_type->typeEnd)
5925
0
                return findRecordInNestedList(nested_type->typeStart->str());
5926
0
        } else
5927
0
            return nested_type->classScope;
5928
0
    }
5929
5930
0
    return nullptr;
5931
0
}
5932
5933
//---------------------------------------------------------------------------
5934
5935
const Type* Scope::findType(const std::string & name) const
5936
8.54k
{
5937
8.54k
    auto it = definedTypesMap.find(name);
5938
5939
    // Type was found
5940
8.54k
    if (definedTypesMap.end() != it)
5941
0
        return (*it).second;
5942
5943
    // is type defined in anonymous namespace..
5944
8.54k
    it = definedTypesMap.find(emptyString);
5945
8.54k
    if (it != definedTypesMap.end()) {
5946
0
        for (const Scope *scope : nestedList) {
5947
0
            if (scope->className.empty() && (scope->type == eNamespace || scope->isClassOrStructOrUnion())) {
5948
0
                const Type *t = scope->findType(name);
5949
0
                if (t)
5950
0
                    return t;
5951
0
            }
5952
0
        }
5953
0
    }
5954
5955
    // Type was not found
5956
8.54k
    return nullptr;
5957
8.54k
}
5958
5959
//---------------------------------------------------------------------------
5960
5961
Scope *Scope::findInNestedListRecursive(const std::string & name)
5962
0
{
5963
0
    auto it = std::find_if(nestedList.cbegin(), nestedList.cend(), [&](const Scope* s) {
5964
0
        return s->className == name;
5965
0
    });
5966
0
    if (it != nestedList.end())
5967
0
        return *it;
5968
5969
0
    for (Scope* scope: nestedList) {
5970
0
        Scope *child = scope->findInNestedListRecursive(name);
5971
0
        if (child)
5972
0
            return child;
5973
0
    }
5974
0
    return nullptr;
5975
0
}
5976
5977
//---------------------------------------------------------------------------
5978
5979
const Function *Scope::getDestructor() const
5980
0
{
5981
0
    auto it = std::find_if(functionList.cbegin(), functionList.cend(), [](const Function& f) {
5982
0
        return f.type == Function::eDestructor;
5983
0
    });
5984
0
    return it == functionList.end() ? nullptr : &*it;
5985
0
}
5986
5987
//---------------------------------------------------------------------------
5988
5989
bool SymbolDatabase::isCPP() const
5990
46.2k
{
5991
46.2k
    return mTokenizer.isCPP();
5992
46.2k
}
5993
5994
//---------------------------------------------------------------------------
5995
5996
const Scope *SymbolDatabase::findScope(const Token *tok, const Scope *startScope) const
5997
0
{
5998
0
    const Scope *scope = nullptr;
5999
    // absolute path
6000
0
    if (tok->str() == "::") {
6001
0
        tok = tok->next();
6002
0
        scope = &scopeList.front();
6003
0
    }
6004
    // relative path
6005
0
    else if (tok->isName()) {
6006
0
        scope = startScope;
6007
0
    }
6008
6009
0
    while (scope && tok && tok->isName()) {
6010
0
        if (tok->strAt(1) == "::") {
6011
0
            scope = scope->findRecordInNestedList(tok->str());
6012
0
            tok = tok->tokAt(2);
6013
0
        } else if (tok->strAt(1) == "<" && Token::simpleMatch(tok->linkAt(1), "> ::")) {
6014
0
            scope = scope->findRecordInNestedList(tok->str());
6015
0
            tok = tok->linkAt(1)->tokAt(2);
6016
0
        } else
6017
0
            return scope->findRecordInNestedList(tok->str());
6018
0
    }
6019
6020
    // not a valid path
6021
0
    return nullptr;
6022
0
}
6023
6024
//---------------------------------------------------------------------------
6025
6026
const Type* SymbolDatabase::findType(const Token *startTok, const Scope *startScope, bool lookOutside) const
6027
0
{
6028
    // skip over struct or union
6029
0
    if (Token::Match(startTok, "struct|union"))
6030
0
        startTok = startTok->next();
6031
6032
    // type same as scope
6033
0
    if (startTok->str() == startScope->className && startScope->isClassOrStruct() && startTok->strAt(1) != "::")
6034
0
        return startScope->definedType;
6035
6036
0
    if (mTokenizer.isC()) {
6037
0
        const Scope* scope = startScope;
6038
0
        while (scope) {
6039
0
            if (startTok->str() == scope->className && scope->isClassOrStruct())
6040
0
                return scope->definedType;
6041
0
            const Scope* typeScope = scope->findRecordInNestedList(startTok->str(), /*isC*/ true);
6042
0
            if (typeScope) {
6043
0
                if (startTok->str() == typeScope->className && typeScope->isClassOrStruct()) {
6044
0
                    if (const Type* type = typeScope->definedType)
6045
0
                        return type;
6046
0
                }
6047
0
            }
6048
0
            scope = scope->nestedIn;
6049
0
        }
6050
0
        return nullptr;
6051
0
    }
6052
6053
0
    const Scope* start_scope = startScope;
6054
6055
    // absolute path - directly start in global scope
6056
0
    if (startTok->str() == "::") {
6057
0
        startTok = startTok->next();
6058
0
        start_scope = &scopeList.front();
6059
0
    }
6060
6061
0
    const Token* tok = startTok;
6062
0
    const Scope* scope = start_scope;
6063
6064
0
    while (scope && tok && tok->isName()) {
6065
0
        if (tok->strAt(1) == "::" || (tok->strAt(1) == "<" && Token::simpleMatch(tok->linkAt(1), "> ::"))) {
6066
0
            scope = scope->findRecordInNestedList(tok->str());
6067
0
            if (scope) {
6068
0
                if (tok->strAt(1) == "::")
6069
0
                    tok = tok->tokAt(2);
6070
0
                else
6071
0
                    tok = tok->linkAt(1)->tokAt(2);
6072
0
            } else {
6073
0
                start_scope = start_scope->nestedIn;
6074
0
                if (!start_scope)
6075
0
                    break;
6076
0
                scope = start_scope;
6077
0
                tok = startTok;
6078
0
            }
6079
0
        } else {
6080
0
            const Scope* scope1{};
6081
0
            const Type* type = scope->findType(tok->str());
6082
0
            if (type)
6083
0
                return type;
6084
0
            if (lookOutside && (scope1 = scope->findRecordInBase(tok->str()))) {
6085
0
                type = scope1->definedType;
6086
0
                if (type)
6087
0
                    return type;
6088
0
            } else if (lookOutside && scope->type == Scope::ScopeType::eNamespace) {
6089
0
                scope = scope->nestedIn;
6090
0
                continue;
6091
0
            } else
6092
0
                break;
6093
0
        }
6094
0
    }
6095
6096
    // check using namespaces
6097
0
    while (startScope) {
6098
0
        for (std::vector<Scope::UsingInfo>::const_iterator it = startScope->usingList.cbegin();
6099
0
             it != startScope->usingList.cend(); ++it) {
6100
0
            tok = startTok;
6101
0
            scope = it->scope;
6102
0
            start_scope = startScope;
6103
6104
0
            while (scope && tok && tok->isName()) {
6105
0
                if (tok->strAt(1) == "::" || (tok->strAt(1) == "<" && Token::simpleMatch(tok->linkAt(1), "> ::"))) {
6106
0
                    scope = scope->findRecordInNestedList(tok->str());
6107
0
                    if (scope) {
6108
0
                        if (tok->strAt(1) == "::")
6109
0
                            tok = tok->tokAt(2);
6110
0
                        else
6111
0
                            tok = tok->linkAt(1)->tokAt(2);
6112
0
                    } else {
6113
0
                        start_scope = start_scope->nestedIn;
6114
0
                        if (!start_scope)
6115
0
                            break;
6116
0
                        scope = start_scope;
6117
0
                        tok = startTok;
6118
0
                    }
6119
0
                } else {
6120
0
                    const Type * type = scope->findType(tok->str());
6121
0
                    if (type)
6122
0
                        return type;
6123
0
                    if (const Scope *scope1 = scope->findRecordInBase(tok->str())) {
6124
0
                        type = scope1->definedType;
6125
0
                        if (type)
6126
0
                            return type;
6127
0
                    } else
6128
0
                        break;
6129
0
                }
6130
0
            }
6131
0
        }
6132
0
        startScope = startScope->nestedIn;
6133
0
    }
6134
6135
    // not a valid path
6136
0
    return nullptr;
6137
0
}
6138
6139
//---------------------------------------------------------------------------
6140
6141
const Type* SymbolDatabase::findTypeInNested(const Token *startTok, const Scope *startScope) const
6142
1.73k
{
6143
    // skip over struct or union
6144
1.73k
    if (Token::Match(startTok, "struct|union|enum"))
6145
0
        startTok = startTok->next();
6146
6147
    // type same as scope
6148
1.73k
    if (startTok->str() == startScope->className && startScope->isClassOrStruct())
6149
0
        return startScope->definedType;
6150
6151
1.73k
    bool hasPath = false;
6152
6153
    // absolute path - directly start in global scope
6154
1.73k
    if (startTok->str() == "::") {
6155
0
        hasPath = true;
6156
0
        startTok = startTok->next();
6157
0
        startScope = &scopeList.front();
6158
0
    }
6159
6160
1.73k
    const Token* tok = startTok;
6161
1.73k
    const Scope* scope = startScope;
6162
6163
1.73k
    while (scope && tok && tok->isName()) {
6164
1.73k
        if (tok->strAt(1) == "::" || (tok->strAt(1) == "<" && Token::simpleMatch(tok->linkAt(1), "> ::"))) {
6165
0
            hasPath = true;
6166
0
            scope = scope->findRecordInNestedList(tok->str());
6167
0
            if (scope) {
6168
0
                if (tok->strAt(1) == "::")
6169
0
                    tok = tok->tokAt(2);
6170
0
                else
6171
0
                    tok = tok->linkAt(1)->tokAt(2);
6172
0
            } else {
6173
0
                startScope = startScope->nestedIn;
6174
0
                if (!startScope)
6175
0
                    break;
6176
0
                scope = startScope;
6177
0
                tok = startTok;
6178
0
            }
6179
1.73k
        } else {
6180
1.73k
            const Type * type = scope->findType(tok->str());
6181
1.73k
            if (hasPath || type)
6182
0
                return type;
6183
6184
1.73k
            scope = scope->nestedIn;
6185
1.73k
            if (!scope)
6186
1.73k
                break;
6187
1.73k
        }
6188
1.73k
    }
6189
6190
    // not a valid path
6191
1.73k
    return nullptr;
6192
1.73k
}
6193
6194
//---------------------------------------------------------------------------
6195
6196
const Scope * SymbolDatabase::findNamespace(const Token * tok, const Scope * scope) const
6197
0
{
6198
0
    const Scope * s = findScope(tok, scope);
6199
6200
0
    if (s)
6201
0
        return s;
6202
0
    if (scope->nestedIn)
6203
0
        return findNamespace(tok, scope->nestedIn);
6204
6205
0
    return nullptr;
6206
0
}
6207
6208
//---------------------------------------------------------------------------
6209
6210
Function * SymbolDatabase::findFunctionInScope(const Token *func, const Scope *ns, const std::string & path, nonneg int path_length)
6211
0
{
6212
0
    const Function * function = nullptr;
6213
0
    const bool destructor = func->strAt(-1) == "~";
6214
6215
0
    auto range = ns->functionMap.equal_range(func->str());
6216
0
    for (std::multimap<std::string, const Function*>::const_iterator it = range.first; it != range.second; ++it) {
6217
0
        if (it->second->argsMatch(ns, it->second->argDef, func->next(), path, path_length) &&
6218
0
            it->second->isDestructor() == destructor) {
6219
0
            function = it->second;
6220
0
            break;
6221
0
        }
6222
0
    }
6223
6224
0
    if (!function) {
6225
0
        const Scope * scope = ns->findRecordInNestedList(func->str());
6226
0
        if (scope && Token::Match(func->tokAt(1), "::|<")) {
6227
0
            if (func->strAt(1) == "::")
6228
0
                func = func->tokAt(2);
6229
0
            else if (func->linkAt(1))
6230
0
                func = func->linkAt(1)->tokAt(2);
6231
0
            else
6232
0
                return nullptr;
6233
0
            if (func->str() == "~")
6234
0
                func = func->next();
6235
0
            function = findFunctionInScope(func, scope, path, path_length);
6236
0
        }
6237
0
    }
6238
6239
0
    return const_cast<Function *>(function);
6240
0
}
6241
6242
//---------------------------------------------------------------------------
6243
6244
bool SymbolDatabase::isReservedName(const std::string& iName) const
6245
18.5k
{
6246
18.5k
    if (isCPP()) {
6247
18.5k
        static const auto& cpp_keywords = Keywords::getAll(Standards::cppstd_t::CPPLatest);
6248
18.5k
        return cpp_keywords.find(iName) != cpp_keywords.cend();
6249
18.5k
    }
6250
0
    static const auto& c_keywords = Keywords::getAll(Standards::cstd_t::CLatest);
6251
0
    return c_keywords.find(iName) != c_keywords.cend();
6252
18.5k
}
6253
6254
nonneg int SymbolDatabase::sizeOfType(const Token *type) const
6255
0
{
6256
0
    int size = mTokenizer.sizeOfType(type);
6257
6258
0
    if (size == 0 && type->type() && type->type()->isEnumType() && type->type()->classScope) {
6259
0
        size = mSettings.platform.sizeof_int;
6260
0
        const Token * enum_type = type->type()->classScope->enumType;
6261
0
        if (enum_type)
6262
0
            size = mTokenizer.sizeOfType(enum_type);
6263
0
    }
6264
6265
0
    return size;
6266
0
}
6267
6268
static const Token* parsedecl(const Token* type,
6269
                              ValueType* const valuetype,
6270
                              ValueType::Sign defaultSignedness,
6271
                              const Settings& settings,
6272
                              bool isCpp,
6273
                              SourceLocation loc = SourceLocation::current());
6274
6275
void SymbolDatabase::setValueType(Token* tok, const Variable& var, SourceLocation loc)
6276
79.3k
{
6277
79.3k
    ValueType valuetype;
6278
79.3k
    if (mSettings.debugnormal || mSettings.debugwarnings)
6279
0
        valuetype.setDebugPath(tok, loc);
6280
79.3k
    if (var.nameToken())
6281
79.3k
        valuetype.bits = var.nameToken()->bits();
6282
6283
79.3k
    valuetype.pointer = var.dimensions().size();
6284
    // HACK: don't set pointer for plain std::array
6285
79.3k
    if (var.valueType() && var.valueType()->container && Token::simpleMatch(var.typeStartToken(), "std :: array") && !Token::simpleMatch(var.nameToken()->next(), "["))
6286
0
        valuetype.pointer = 0;
6287
6288
79.3k
    valuetype.typeScope = var.typeScope();
6289
79.3k
    if (var.valueType()) {
6290
79.3k
        valuetype.container = var.valueType()->container;
6291
79.3k
        valuetype.containerTypeToken = var.valueType()->containerTypeToken;
6292
79.3k
    }
6293
79.3k
    valuetype.smartPointerType = var.smartPointerType();
6294
79.3k
    if (parsedecl(var.typeStartToken(), &valuetype, mDefaultSignedness, mSettings, mIsCpp)) {
6295
79.3k
        if (tok->str() == "." && tok->astOperand1()) {
6296
0
            const ValueType * const vt = tok->astOperand1()->valueType();
6297
0
            if (vt && (vt->constness & 1) != 0)
6298
0
                valuetype.constness |= 1;
6299
0
        }
6300
79.3k
        setValueType(tok, valuetype);
6301
79.3k
    }
6302
79.3k
}
6303
6304
static ValueType::Type getEnumType(const Scope* scope, const cppcheck::Platform& platform);
6305
6306
void SymbolDatabase::setValueType(Token* tok, const Enumerator& enumerator, SourceLocation loc)
6307
0
{
6308
0
    ValueType valuetype;
6309
0
    if (mSettings.debugnormal || mSettings.debugwarnings)
6310
0
        valuetype.setDebugPath(tok, loc);
6311
0
    valuetype.typeScope = enumerator.scope;
6312
0
    const Token * type = enumerator.scope->enumType;
6313
0
    if (type) {
6314
0
        valuetype.type = ValueType::typeFromString(type->str(), type->isLong());
6315
0
        if (valuetype.type == ValueType::Type::UNKNOWN_TYPE && type->isStandardType())
6316
0
            valuetype.fromLibraryType(type->str(), mSettings);
6317
6318
0
        if (valuetype.isIntegral()) {
6319
0
            if (type->isSigned())
6320
0
                valuetype.sign = ValueType::Sign::SIGNED;
6321
0
            else if (type->isUnsigned())
6322
0
                valuetype.sign = ValueType::Sign::UNSIGNED;
6323
0
            else if (valuetype.type == ValueType::Type::CHAR)
6324
0
                valuetype.sign = mDefaultSignedness;
6325
0
            else
6326
0
                valuetype.sign = ValueType::Sign::SIGNED;
6327
0
        }
6328
6329
0
        setValueType(tok, valuetype);
6330
0
    } else {
6331
0
        valuetype.sign = ValueType::SIGNED;
6332
0
        valuetype.type = getEnumType(enumerator.scope, mSettings.platform);
6333
0
        setValueType(tok, valuetype);
6334
0
    }
6335
0
}
6336
6337
static void setAutoTokenProperties(Token * const autoTok)
6338
0
{
6339
0
    const ValueType *valuetype = autoTok->valueType();
6340
0
    if (valuetype->isIntegral() || valuetype->isFloat())
6341
0
        autoTok->isStandardType(true);
6342
0
}
6343
6344
bool isContainerYieldElement(Library::Container::Yield yield)
6345
0
{
6346
0
    return yield == Library::Container::Yield::ITEM || yield == Library::Container::Yield::AT_INDEX ||
6347
0
           yield == Library::Container::Yield::BUFFER || yield == Library::Container::Yield::BUFFER_NT;
6348
0
}
6349
6350
static bool isContainerYieldPointer(Library::Container::Yield yield)
6351
0
{
6352
0
    return yield == Library::Container::Yield::BUFFER || yield == Library::Container::Yield::BUFFER_NT;
6353
0
}
6354
6355
void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, SourceLocation loc)
6356
184k
{
6357
184k
    ValueType* valuetypePtr = new ValueType(valuetype);
6358
184k
    if (mSettings.debugnormal || mSettings.debugwarnings)
6359
0
        valuetypePtr->setDebugPath(tok, loc);
6360
184k
    tok->setValueType(valuetypePtr);
6361
184k
    Token *parent = tok->astParent();
6362
184k
    if (!parent || parent->valueType())
6363
117k
        return;
6364
67.1k
    if (!parent->astOperand1())
6365
0
        return;
6366
6367
67.1k
    const ValueType *vt1 = parent->astOperand1()->valueType();
6368
67.1k
    const ValueType *vt2 = parent->astOperand2() ? parent->astOperand2()->valueType() : nullptr;
6369
6370
67.1k
    if (vt1 && Token::Match(parent, "<<|>>")) {
6371
0
        if (!mIsCpp || (vt2 && vt2->isIntegral())) {
6372
0
            if (vt1->type < ValueType::Type::BOOL || vt1->type >= ValueType::Type::INT) {
6373
0
                ValueType vt(*vt1);
6374
0
                vt.reference = Reference::None;
6375
0
                setValueType(parent, vt);
6376
0
            } else {
6377
0
                ValueType vt(*vt1);
6378
0
                vt.type = ValueType::Type::INT; // Integer promotion
6379
0
                vt.sign = ValueType::Sign::SIGNED;
6380
0
                vt.reference = Reference::None;
6381
0
                setValueType(parent, vt);
6382
0
            }
6383
6384
0
        }
6385
0
        return;
6386
0
    }
6387
6388
67.1k
    if (vt1 && vt1->container && vt1->containerTypeToken && Token::Match(parent, ". %name% (") &&
6389
67.1k
        isContainerYieldElement(vt1->container->getYield(parent->next()->str()))) {
6390
0
        ValueType item;
6391
0
        if (parsedecl(vt1->containerTypeToken, &item, mDefaultSignedness, mSettings, mIsCpp)) {
6392
0
            if (item.constness == 0)
6393
0
                item.constness = vt1->constness;
6394
0
            if (isContainerYieldPointer(vt1->container->getYield(parent->next()->str())))
6395
0
                item.pointer += 1;
6396
0
            else
6397
0
                item.reference = Reference::LValue;
6398
0
            setValueType(parent->tokAt(2), item);
6399
0
        }
6400
0
    }
6401
6402
67.1k
    if (vt1 && vt1->smartPointerType && Token::Match(parent, ". %name% (") && parent->originalName() == "->" && !parent->next()->function()) {
6403
0
        const Scope *scope = vt1->smartPointerType->classScope;
6404
0
        const Function *f = scope ? scope->findFunction(parent->next(), false) : nullptr;
6405
0
        if (f)
6406
0
            parent->next()->function(f);
6407
0
    }
6408
6409
67.1k
    if (parent->isAssignmentOp()) {
6410
34.6k
        if (vt1) {
6411
33.2k
            auto vt = *vt1;
6412
33.2k
            vt.reference = Reference::None;
6413
33.2k
            setValueType(parent, vt);
6414
33.2k
        } else if (mIsCpp && ((Token::Match(parent->tokAt(-3), "%var% ; %var% =") && parent->strAt(-3) == parent->strAt(-1)) ||
6415
1.34k
                              Token::Match(parent->tokAt(-1), "%var% ="))) {
6416
8
            Token *var1Tok = parent->strAt(-2) == ";" ? parent->tokAt(-3) : parent->tokAt(-1);
6417
8
            Token *autoTok = nullptr;
6418
8
            if (Token::simpleMatch(var1Tok->tokAt(-1), "auto"))
6419
0
                autoTok = var1Tok->previous();
6420
8
            else if (Token::Match(var1Tok->tokAt(-2), "auto *|&|&&"))
6421
0
                autoTok = var1Tok->tokAt(-2);
6422
8
            else if (Token::simpleMatch(var1Tok->tokAt(-3), "auto * const"))
6423
0
                autoTok = var1Tok->tokAt(-3);
6424
8
            if (autoTok) {
6425
0
                ValueType vt(*vt2);
6426
0
                if (vt.constness & (1 << vt.pointer))
6427
0
                    vt.constness &= ~(1 << vt.pointer);
6428
0
                if (autoTok->strAt(1) == "*" && vt.pointer)
6429
0
                    vt.pointer--;
6430
0
                if (Token::Match(autoTok->tokAt(-1), "const|constexpr"))
6431
0
                    vt.constness |= (1 << vt.pointer);
6432
0
                setValueType(autoTok, vt);
6433
0
                setAutoTokenProperties(autoTok);
6434
0
                if (vt2->pointer > vt.pointer)
6435
0
                    vt.pointer++;
6436
0
                setValueType(var1Tok, vt);
6437
0
                if (var1Tok != parent->previous())
6438
0
                    setValueType(parent->previous(), vt);
6439
0
                Variable *var = const_cast<Variable *>(parent->previous()->variable());
6440
0
                if (var) {
6441
0
                    ValueType vt2_(*vt2);
6442
0
                    if (vt2_.pointer == 0 && autoTok->strAt(1) == "*")
6443
0
                        vt2_.pointer = 1;
6444
0
                    if ((vt.constness & (1 << vt2->pointer)) != 0)
6445
0
                        vt2_.constness |= (1 << vt2->pointer);
6446
0
                    if (!Token::Match(autoTok->tokAt(1), "*|&"))
6447
0
                        vt2_.constness = vt.constness;
6448
0
                    if (Token::simpleMatch(autoTok->tokAt(1), "* const"))
6449
0
                        vt2_.constness |= (1 << vt2->pointer);
6450
0
                    var->setValueType(vt2_);
6451
0
                    if (vt2->typeScope && vt2->typeScope->definedType) {
6452
0
                        var->type(vt2->typeScope->definedType);
6453
0
                        if (autoTok->valueType()->pointer == 0)
6454
0
                            autoTok->type(vt2->typeScope->definedType);
6455
0
                    }
6456
0
                }
6457
0
            }
6458
8
        }
6459
34.6k
        return;
6460
34.6k
    }
6461
6462
32.5k
    if (parent->str() == "[" && (!mIsCpp || parent->astOperand1() == tok) && valuetype.pointer > 0U && !Token::Match(parent->previous(), "[{,]")) {
6463
0
        const Token *op1 = parent->astOperand1();
6464
0
        while (op1 && op1->str() == "[")
6465
0
            op1 = op1->astOperand1();
6466
6467
0
        ValueType vt(valuetype);
6468
        // the "[" is a dereference unless this is a variable declaration
6469
0
        if (!(op1 && op1->variable() && op1->variable()->nameToken() == op1))
6470
0
            vt.pointer -= 1U;
6471
0
        setValueType(parent, vt);
6472
0
        return;
6473
0
    }
6474
32.5k
    if (Token::Match(parent->previous(), "%name% (") && parent->astOperand1() == tok && valuetype.pointer > 0U) {
6475
0
        ValueType vt(valuetype);
6476
0
        vt.pointer -= 1U;
6477
0
        setValueType(parent, vt);
6478
0
        return;
6479
0
    }
6480
    // std::move
6481
32.5k
    if (vt2 && parent->str() == "(" && Token::simpleMatch(parent->tokAt(-3), "std :: move (")) {
6482
0
        ValueType vt = valuetype;
6483
0
        vt.reference = Reference::RValue;
6484
0
        setValueType(parent, vt);
6485
0
        return;
6486
0
    }
6487
32.5k
    if (parent->str() == "*" && !parent->astOperand2() && valuetype.pointer > 0U) {
6488
0
        ValueType vt(valuetype);
6489
0
        vt.pointer -= 1U;
6490
0
        setValueType(parent, vt);
6491
0
        return;
6492
0
    }
6493
    // Dereference iterator
6494
32.5k
    if (parent->str() == "*" && !parent->astOperand2() && valuetype.type == ValueType::Type::ITERATOR &&
6495
32.5k
        valuetype.containerTypeToken) {
6496
0
        ValueType vt;
6497
0
        if (parsedecl(valuetype.containerTypeToken, &vt, mDefaultSignedness, mSettings, mIsCpp)) {
6498
0
            if (vt.constness == 0)
6499
0
                vt.constness = valuetype.constness;
6500
0
            vt.reference = Reference::LValue;
6501
0
            setValueType(parent, vt);
6502
0
            return;
6503
0
        }
6504
0
    }
6505
    // Dereference smart pointer
6506
32.5k
    if (parent->str() == "*" && !parent->astOperand2() && valuetype.type == ValueType::Type::SMART_POINTER &&
6507
32.5k
        valuetype.smartPointerTypeToken) {
6508
0
        ValueType vt;
6509
0
        if (parsedecl(valuetype.smartPointerTypeToken, &vt, mDefaultSignedness, mSettings, mIsCpp)) {
6510
0
            if (vt.constness == 0)
6511
0
                vt.constness = valuetype.constness;
6512
0
            setValueType(parent, vt);
6513
0
            return;
6514
0
        }
6515
0
    }
6516
32.5k
    if (parent->str() == "*" && Token::simpleMatch(parent->astOperand2(), "[") && valuetype.pointer > 0U) {
6517
0
        const Token *op1 = parent->astOperand2()->astOperand1();
6518
0
        while (op1 && op1->str() == "[")
6519
0
            op1 = op1->astOperand1();
6520
0
        const ValueType& vt(valuetype);
6521
0
        if (op1 && op1->variable() && op1->variable()->nameToken() == op1) {
6522
0
            setValueType(parent, vt);
6523
0
            return;
6524
0
        }
6525
0
    }
6526
32.5k
    if (parent->str() == "&" && !parent->astOperand2()) {
6527
0
        ValueType vt(valuetype);
6528
0
        vt.reference = Reference::None; //Given int& x; the type of &x is int* not int&*
6529
0
        bool isArrayToPointerDecay = false;
6530
0
        for (const Token* child = parent->astOperand1(); child;) {
6531
0
            if (Token::Match(child, ".|::"))
6532
0
                child = child->astOperand2();
6533
0
            else {
6534
0
                isArrayToPointerDecay = child->variable() && child->variable()->isArray();
6535
0
                break;
6536
0
            }
6537
0
        }
6538
0
        if (!isArrayToPointerDecay)
6539
0
            vt.pointer += 1U;
6540
0
        setValueType(parent, vt);
6541
0
        return;
6542
0
    }
6543
6544
32.5k
    if ((parent->str() == "." || parent->str() == "::") &&
6545
32.5k
        parent->astOperand2() && parent->astOperand2()->isName()) {
6546
0
        const Variable* var = parent->astOperand2()->variable();
6547
0
        if (!var && valuetype.typeScope && vt1) {
6548
0
            const std::string &name = parent->astOperand2()->str();
6549
0
            const Scope *typeScope = vt1->typeScope;
6550
0
            if (!typeScope)
6551
0
                return;
6552
0
            auto it = std::find_if(typeScope->varlist.begin(), typeScope->varlist.end(), [&name](const Variable& v) {
6553
0
                return v.nameToken()->str() == name;
6554
0
            });
6555
0
            if (it != typeScope->varlist.end())
6556
0
                var = &*it;
6557
0
        }
6558
0
        if (var) {
6559
0
            setValueType(parent, *var);
6560
0
            return;
6561
0
        }
6562
0
        if (const Enumerator* enu = parent->astOperand2()->enumerator())
6563
0
            setValueType(parent, *enu);
6564
0
        return;
6565
0
    }
6566
6567
    // range for loop, auto
6568
32.5k
    if (vt2 &&
6569
32.5k
        parent->str() == ":" &&
6570
32.5k
        Token::Match(parent->astParent(), "( const| auto *|&|&&| %var% :") && // TODO: east-const, multiple const, ref to ptr
6571
32.5k
        !parent->previous()->valueType() &&
6572
32.5k
        Token::simpleMatch(parent->astParent()->astOperand1(), "for")) {
6573
0
        const bool isconst = Token::simpleMatch(parent->astParent()->next(), "const");
6574
0
        Token * const autoToken = parent->astParent()->tokAt(isconst ? 2 : 1);
6575
0
        if (vt2->pointer) {
6576
0
            ValueType autovt(*vt2);
6577
0
            autovt.pointer--;
6578
0
            autovt.constness = 0;
6579
0
            setValueType(autoToken, autovt);
6580
0
            setAutoTokenProperties(autoToken);
6581
0
            ValueType varvt(*vt2);
6582
0
            varvt.pointer--;
6583
0
            if (Token::simpleMatch(autoToken->next(), "&"))
6584
0
                varvt.reference = Reference::LValue;
6585
0
            if (isconst) {
6586
0
                if (varvt.pointer && varvt.reference != Reference::None)
6587
0
                    varvt.constness |= (1 << varvt.pointer);
6588
0
                else
6589
0
                    varvt.constness |= 1;
6590
0
            }
6591
0
            setValueType(parent->previous(), varvt);
6592
0
            Variable *var = const_cast<Variable *>(parent->previous()->variable());
6593
0
            if (var) {
6594
0
                var->setValueType(varvt);
6595
0
                if (vt2->typeScope && vt2->typeScope->definedType) {
6596
0
                    var->type(vt2->typeScope->definedType);
6597
0
                    autoToken->type(vt2->typeScope->definedType);
6598
0
                }
6599
0
            }
6600
0
        } else if (vt2->container) {
6601
            // TODO: Determine exact type of RHS
6602
0
            const Token *typeStart = parent->astOperand2();
6603
0
            while (typeStart) {
6604
0
                if (typeStart->variable())
6605
0
                    typeStart = typeStart->variable()->typeStartToken();
6606
0
                else if (typeStart->str() == "(" && typeStart->previous() && typeStart->previous()->function())
6607
0
                    typeStart = typeStart->previous()->function()->retDef;
6608
0
                else
6609
0
                    break;
6610
0
            }
6611
6612
            // Try to determine type of "auto" token.
6613
            // TODO: Get type better
6614
0
            bool setType = false;
6615
0
            ValueType autovt;
6616
0
            const Type *templateArgType = nullptr; // container element type / smart pointer type
6617
0
            if (!vt2->container->rangeItemRecordType.empty()) {
6618
0
                setType = true;
6619
0
                autovt.type = ValueType::Type::RECORD;
6620
0
            } else if (vt2->containerTypeToken) {
6621
0
                if (mSettings.library.isSmartPointer(vt2->containerTypeToken)) {
6622
0
                    const Token *smartPointerTypeTok = vt2->containerTypeToken;
6623
0
                    while (Token::Match(smartPointerTypeTok, "%name%|::"))
6624
0
                        smartPointerTypeTok = smartPointerTypeTok->next();
6625
0
                    if (Token::simpleMatch(smartPointerTypeTok, "<")) {
6626
0
                        if ((templateArgType = findTypeInNested(smartPointerTypeTok->next(), tok->scope()))) {
6627
0
                            setType = true;
6628
0
                            autovt.smartPointerType = templateArgType;
6629
0
                            autovt.type = ValueType::Type::NONSTD;
6630
0
                        }
6631
0
                    }
6632
0
                } else if (parsedecl(vt2->containerTypeToken, &autovt, mDefaultSignedness, mSettings, mIsCpp)) {
6633
0
                    setType = true;
6634
0
                    templateArgType = vt2->containerTypeToken->type();
6635
0
                    if (Token::simpleMatch(autoToken->next(), "&"))
6636
0
                        autovt.reference = Reference::LValue;
6637
0
                    else if (Token::simpleMatch(autoToken->next(), "&&"))
6638
0
                        autovt.reference = Reference::RValue;
6639
0
                    if (autoToken->previous()->str() == "const") {
6640
0
                        if (autovt.pointer && autovt.reference != Reference::None)
6641
0
                            autovt.constness |= 2;
6642
0
                        else
6643
0
                            autovt.constness |= 1;
6644
0
                    }
6645
0
                }
6646
0
            }
6647
6648
0
            if (setType) {
6649
                // Type of "auto" has been determined.. set type information for "auto" and variable tokens
6650
0
                setValueType(autoToken, autovt);
6651
0
                setAutoTokenProperties(autoToken);
6652
0
                ValueType varvt(autovt);
6653
0
                if (autoToken->strAt(1) == "*" && autovt.pointer)
6654
0
                    autovt.pointer--;
6655
0
                if (isconst)
6656
0
                    varvt.constness |= (1 << autovt.pointer);
6657
0
                setValueType(parent->previous(), varvt);
6658
0
                Variable * var = const_cast<Variable *>(parent->previous()->variable());
6659
0
                if (var) {
6660
0
                    var->setValueType(varvt);
6661
0
                    if (templateArgType && templateArgType->classScope && templateArgType->classScope->definedType) {
6662
0
                        autoToken->type(templateArgType->classScope->definedType);
6663
0
                        var->type(templateArgType->classScope->definedType);
6664
0
                    }
6665
0
                }
6666
0
            }
6667
0
        }
6668
0
    }
6669
6670
32.5k
    if (vt1 && vt1->containerTypeToken && parent->str() == "[") {
6671
0
        ValueType vtParent;
6672
0
        if (parsedecl(vt1->containerTypeToken, &vtParent, mDefaultSignedness, mSettings, mIsCpp)) {
6673
0
            setValueType(parent, vtParent);
6674
0
            return;
6675
0
        }
6676
0
    }
6677
6678
32.5k
    if (mIsCpp && vt2 && Token::simpleMatch(parent->previous(), "decltype (")) {
6679
0
        setValueType(parent, *vt2);
6680
0
        return;
6681
0
    }
6682
6683
    // c++17 auto type deduction of braced init list
6684
32.5k
    if (mIsCpp && mSettings.standards.cpp >= Standards::CPP17 && vt2 && Token::Match(parent->tokAt(-2), "auto %var% {")) {
6685
0
        Token *autoTok = parent->tokAt(-2);
6686
0
        setValueType(autoTok, *vt2);
6687
0
        setAutoTokenProperties(autoTok);
6688
0
        if (parent->previous()->variable())
6689
0
            const_cast<Variable*>(parent->previous()->variable())->setValueType(*vt2);
6690
0
        else
6691
0
            debugMessage(parent->previous(), "debug", "Missing variable class for variable with varid");
6692
0
        return;
6693
0
    }
6694
6695
32.5k
    if (!vt1)
6696
7.00k
        return;
6697
25.5k
    if (parent->astOperand2() && !vt2)
6698
12.5k
        return;
6699
6700
13.0k
    const bool ternary = parent->str() == ":" && parent->astParent() && parent->astParent()->str() == "?";
6701
13.0k
    if (ternary) {
6702
0
        if (vt2 && vt1->pointer == vt2->pointer && vt1->type == vt2->type && vt1->sign == vt2->sign)
6703
0
            setValueType(parent, *vt2);
6704
0
        parent = parent->astParent();
6705
0
    }
6706
6707
13.0k
    if (ternary || parent->isArithmeticalOp() || parent->tokType() == Token::eIncDecOp) {
6708
6709
        // CONTAINER + x => CONTAINER
6710
8.80k
        if (parent->str() == "+" && vt1->type == ValueType::Type::CONTAINER && vt2 && vt2->isIntegral()) {
6711
0
            setValueType(parent, *vt1);
6712
0
            return;
6713
0
        }
6714
        // x + CONTAINER => CONTAINER
6715
8.80k
        if (parent->str() == "+" && vt1->isIntegral() && vt2 && vt2->type == ValueType::Type::CONTAINER) {
6716
0
            setValueType(parent, *vt2);
6717
0
            return;
6718
0
        }
6719
6720
8.80k
        if (parent->isArithmeticalOp()) {
6721
3.08k
            if (vt1->pointer != 0U && vt2 && vt2->pointer == 0U) {
6722
0
                setValueType(parent, *vt1);
6723
0
                return;
6724
0
            }
6725
6726
3.08k
            if (vt1->pointer == 0U && vt2 && vt2->pointer != 0U) {
6727
0
                setValueType(parent, *vt2);
6728
0
                return;
6729
0
            }
6730
5.72k
        } else if (ternary) {
6731
0
            if (vt1->pointer != 0U && vt2 && vt2->pointer == 0U) {
6732
0
                if (vt2->isPrimitive())
6733
0
                    setValueType(parent, *vt1);
6734
0
                else
6735
0
                    setValueType(parent, *vt2);
6736
0
                return;
6737
0
            }
6738
6739
0
            if (vt1->pointer == 0U && vt2 && vt2->pointer != 0U) {
6740
0
                if (vt1->isPrimitive())
6741
0
                    setValueType(parent, *vt2);
6742
0
                else
6743
0
                    setValueType(parent, *vt1);
6744
0
                return;
6745
0
            }
6746
6747
0
            if (vt1->isTypeEqual(vt2)) {
6748
0
                setValueType(parent, *vt1);
6749
0
                return;
6750
0
            }
6751
0
        }
6752
6753
8.80k
        if (vt1->pointer != 0U) {
6754
0
            if (ternary || parent->tokType() == Token::eIncDecOp) // result is pointer
6755
0
                setValueType(parent, *vt1);
6756
0
            else // result is pointer diff
6757
0
                setValueType(parent, ValueType(ValueType::Sign::SIGNED, ValueType::Type::INT, 0U, 0U, "ptrdiff_t"));
6758
0
            return;
6759
0
        }
6760
6761
8.80k
        if (vt1->type == ValueType::Type::LONGDOUBLE || (vt2 && vt2->type == ValueType::Type::LONGDOUBLE)) {
6762
0
            setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::LONGDOUBLE, 0U));
6763
0
            return;
6764
0
        }
6765
8.80k
        if (vt1->type == ValueType::Type::DOUBLE || (vt2 && vt2->type == ValueType::Type::DOUBLE)) {
6766
0
            setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::DOUBLE, 0U));
6767
0
            return;
6768
0
        }
6769
8.80k
        if (vt1->type == ValueType::Type::FLOAT || (vt2 && vt2->type == ValueType::Type::FLOAT)) {
6770
0
            setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::FLOAT, 0U));
6771
0
            return;
6772
0
        }
6773
6774
        // iterator +/- integral = iterator
6775
8.80k
        if (vt1->type == ValueType::Type::ITERATOR && vt2 && vt2->isIntegral() &&
6776
8.80k
            (parent->str() == "+" || parent->str() == "-")) {
6777
0
            setValueType(parent, *vt1);
6778
0
            return;
6779
0
        }
6780
6781
8.80k
        if (parent->str() == "+" && vt1->type == ValueType::Type::CONTAINER && vt2 && vt2->type == ValueType::Type::CONTAINER && vt1->container == vt2->container) {
6782
0
            setValueType(parent, *vt1);
6783
0
            return;
6784
0
        }
6785
8.80k
    }
6786
6787
13.0k
    if (vt1->isIntegral() && vt1->pointer == 0U &&
6788
13.0k
        (!vt2 || (vt2->isIntegral() && vt2->pointer == 0U)) &&
6789
13.0k
        (ternary || parent->isArithmeticalOp() || parent->tokType() == Token::eBitOp || parent->tokType() == Token::eIncDecOp || parent->isAssignmentOp())) {
6790
6791
13.0k
        ValueType vt;
6792
13.0k
        if (!vt2 || vt1->type > vt2->type) {
6793
8.58k
            vt.type = vt1->type;
6794
8.58k
            vt.sign = vt1->sign;
6795
8.58k
            vt.originalTypeName = vt1->originalTypeName;
6796
8.58k
        } else if (vt1->type == vt2->type) {
6797
4.06k
            vt.type = vt1->type;
6798
4.06k
            if (vt1->sign == ValueType::Sign::UNSIGNED || vt2->sign == ValueType::Sign::UNSIGNED)
6799
0
                vt.sign = ValueType::Sign::UNSIGNED;
6800
4.06k
            else if (vt1->sign == ValueType::Sign::UNKNOWN_SIGN || vt2->sign == ValueType::Sign::UNKNOWN_SIGN)
6801
164
                vt.sign = ValueType::Sign::UNKNOWN_SIGN;
6802
3.90k
            else
6803
3.90k
                vt.sign = ValueType::Sign::SIGNED;
6804
4.06k
            vt.originalTypeName = (vt1->originalTypeName.empty() ? vt2 : vt1)->originalTypeName;
6805
4.06k
        } else {
6806
412
            vt.type = vt2->type;
6807
412
            vt.sign = vt2->sign;
6808
412
            vt.originalTypeName = vt2->originalTypeName;
6809
412
        }
6810
13.0k
        if (vt.type < ValueType::Type::INT && !(ternary && vt.type==ValueType::Type::BOOL)) {
6811
188
            vt.type = ValueType::Type::INT;
6812
188
            vt.sign = ValueType::Sign::SIGNED;
6813
188
            vt.originalTypeName.clear();
6814
188
        }
6815
6816
13.0k
        setValueType(parent, vt);
6817
13.0k
        return;
6818
13.0k
    }
6819
13.0k
}
6820
6821
static ValueType::Type getEnumType(const Scope* scope, const cppcheck::Platform& platform) // TODO: also determine sign?
6822
0
{
6823
0
    ValueType::Type type = ValueType::Type::INT;
6824
0
    for (const Token* tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) {
6825
0
        if (!tok->isAssignmentOp())
6826
0
            continue;
6827
0
        const Token* vTok = tok->astOperand2();
6828
0
        if (!vTok->hasKnownIntValue()) {
6829
0
            if (!vTok->isLiteral())
6830
0
                continue;
6831
0
            if (const ValueType* vt = vTok->valueType()) {
6832
0
                if ((vt->type > type && (vt->type == ValueType::Type::LONG || vt->type == ValueType::Type::LONGLONG)))
6833
0
                    type = vt->type;
6834
0
            }
6835
0
            continue;
6836
0
        }
6837
0
        const MathLib::bigint value = vTok->getKnownIntValue();
6838
0
        if (!platform.isIntValue(value)) {
6839
0
            type = ValueType::Type::LONG;
6840
0
            if (!platform.isLongValue(value))
6841
0
                type = ValueType::Type::LONGLONG;
6842
0
        }
6843
0
    }
6844
0
    return type;
6845
0
}
6846
6847
static const Token* parsedecl(const Token* type,
6848
                              ValueType* const valuetype,
6849
                              ValueType::Sign defaultSignedness,
6850
                              const Settings& settings,
6851
                              bool isCpp,
6852
                              SourceLocation loc)
6853
108k
{
6854
108k
    if (settings.debugnormal || settings.debugwarnings)
6855
0
        valuetype->setDebugPath(type, loc);
6856
108k
    const Token * const previousType = type;
6857
108k
    const unsigned int pointer0 = valuetype->pointer;
6858
110k
    while (Token::Match(type->previous(), "%name%") && !endsWith(type->previous()->str(), ':'))
6859
1.73k
        type = type->previous();
6860
108k
    valuetype->sign = ValueType::Sign::UNKNOWN_SIGN;
6861
108k
    if (!valuetype->typeScope && !valuetype->smartPointerType)
6862
108k
        valuetype->type = ValueType::Type::UNKNOWN_TYPE;
6863
0
    else if (valuetype->smartPointerType)
6864
0
        valuetype->type = ValueType::Type::SMART_POINTER;
6865
0
    else if (valuetype->typeScope->type == Scope::eEnum) {
6866
0
        const Token * enum_type = valuetype->typeScope->enumType;
6867
0
        if (enum_type) {
6868
0
            if (enum_type->isSigned())
6869
0
                valuetype->sign = ValueType::Sign::SIGNED;
6870
0
            else if (enum_type->isUnsigned())
6871
0
                valuetype->sign = ValueType::Sign::UNSIGNED;
6872
0
            else
6873
0
                valuetype->sign = defaultSignedness;
6874
0
            const ValueType::Type t = ValueType::typeFromString(enum_type->str(), enum_type->isLong());
6875
0
            if (t != ValueType::Type::UNKNOWN_TYPE)
6876
0
                valuetype->type = t;
6877
0
            else if (enum_type->isStandardType())
6878
0
                valuetype->fromLibraryType(enum_type->str(), settings);
6879
0
        } else
6880
0
            valuetype->type = getEnumType(valuetype->typeScope, settings.platform);
6881
0
    } else
6882
0
        valuetype->type = ValueType::Type::RECORD;
6883
108k
    bool par = false;
6884
220k
    while (Token::Match(type, "%name%|*|&|&&|::|(") && !Token::Match(type, "typename|template") && type->varId() == 0 &&
6885
220k
           !type->variable() && !type->function()) {
6886
121k
        bool isIterator = false;
6887
121k
        if (type->str() == "(") {
6888
9.50k
            if (Token::Match(type->link(), ") const| {"))
6889
9.20k
                break;
6890
300
            if (par)
6891
4
                break;
6892
296
            par = true;
6893
296
        }
6894
112k
        if (Token::simpleMatch(type, "decltype (") && type->next()->valueType()) {
6895
0
            const ValueType *vt2 = type->next()->valueType();
6896
0
            if (valuetype->sign == ValueType::Sign::UNKNOWN_SIGN)
6897
0
                valuetype->sign = vt2->sign;
6898
0
            if (valuetype->type == ValueType::Type::UNKNOWN_TYPE)
6899
0
                valuetype->type = vt2->type;
6900
0
            valuetype->constness += vt2->constness;
6901
0
            valuetype->pointer += vt2->pointer;
6902
0
            valuetype->reference = vt2->reference;
6903
0
            type = type->linkAt(1)->next();
6904
0
            continue;
6905
0
        }
6906
112k
        if (type->isSigned())
6907
0
            valuetype->sign = ValueType::Sign::SIGNED;
6908
112k
        else if (type->isUnsigned())
6909
0
            valuetype->sign = ValueType::Sign::UNSIGNED;
6910
112k
        if (valuetype->type == ValueType::Type::UNKNOWN_TYPE &&
6911
112k
            type->type() && type->type()->isTypeAlias() && type->type()->typeStart &&
6912
112k
            type->type()->typeStart->str() != type->str() && type->type()->typeStart != previousType)
6913
0
            parsedecl(type->type()->typeStart, valuetype, defaultSignedness, settings, isCpp);
6914
112k
        else if (Token::Match(type, "const|constexpr"))
6915
0
            valuetype->constness |= (1 << (valuetype->pointer - pointer0));
6916
112k
        else if (settings.clang && type->str().size() > 2 && type->str().find("::") < type->str().find('<')) {
6917
0
            TokenList typeTokens(&settings);
6918
0
            std::string::size_type pos1 = 0;
6919
0
            do {
6920
0
                const std::string::size_type pos2 = type->str().find("::", pos1);
6921
0
                if (pos2 == std::string::npos) {
6922
0
                    typeTokens.addtoken(type->str().substr(pos1), 0, 0, 0, false);
6923
0
                    break;
6924
0
                }
6925
0
                typeTokens.addtoken(type->str().substr(pos1, pos2 - pos1), 0, 0, 0, false);
6926
0
                typeTokens.addtoken("::", 0, 0, 0, false);
6927
0
                pos1 = pos2 + 2;
6928
0
            } while (pos1 < type->str().size());
6929
0
            const Library::Container* container =
6930
0
                settings.library.detectContainerOrIterator(typeTokens.front(), &isIterator);
6931
0
            if (container) {
6932
0
                if (isIterator)
6933
0
                    valuetype->type = ValueType::Type::ITERATOR;
6934
0
                else
6935
0
                    valuetype->type = ValueType::Type::CONTAINER;
6936
0
                valuetype->container = container;
6937
0
            } else {
6938
0
                const Scope *scope = type->scope();
6939
0
                valuetype->typeScope = scope->check->findScope(typeTokens.front(), scope);
6940
0
                if (valuetype->typeScope)
6941
0
                    valuetype->type = (scope->type == Scope::ScopeType::eClass) ? ValueType::Type::RECORD : ValueType::Type::NONSTD;
6942
0
            }
6943
112k
        } else if (const Library::Container* container = (isCpp ? settings.library.detectContainerOrIterator(type, &isIterator) : nullptr)) {
6944
0
            if (isIterator)
6945
0
                valuetype->type = ValueType::Type::ITERATOR;
6946
0
            else
6947
0
                valuetype->type = ValueType::Type::CONTAINER;
6948
0
            valuetype->container = container;
6949
0
            while (Token::Match(type, "%type%|::|<") && type->str() != "const") {
6950
0
                if (type->str() == "<" && type->link()) {
6951
0
                    if (container->type_templateArgNo >= 0) {
6952
0
                        const Token *templateType = type->next();
6953
0
                        for (int j = 0; templateType && j < container->type_templateArgNo; j++)
6954
0
                            templateType = templateType->nextTemplateArgument();
6955
0
                        valuetype->containerTypeToken = templateType;
6956
0
                    }
6957
0
                    type = type->link();
6958
0
                }
6959
0
                type = type->next();
6960
0
            }
6961
0
            if (type && type->str() == "(" && type->previous()->function())
6962
                // we are past the end of the type
6963
0
                type = type->previous();
6964
0
            continue;
6965
112k
        } else if (const Library::SmartPointer* smartPointer = (isCpp ? settings.library.detectSmartPointer(type) : nullptr)) {
6966
0
            const Token* argTok = Token::findsimplematch(type, "<");
6967
0
            if (!argTok)
6968
0
                break;
6969
0
            valuetype->smartPointer = smartPointer;
6970
0
            valuetype->smartPointerTypeToken = argTok->next();
6971
0
            valuetype->smartPointerType = argTok->next()->type();
6972
0
            valuetype->type = ValueType::Type::SMART_POINTER;
6973
0
            type = argTok->link();
6974
0
            if (type)
6975
0
                type = type->next();
6976
0
            continue;
6977
112k
        } else if (Token::Match(type, "%name% :: %name%")) {
6978
0
            std::string typestr;
6979
0
            const Token *end = type;
6980
0
            while (Token::Match(end, "%name% :: %name%")) {
6981
0
                typestr += end->str() + "::";
6982
0
                end = end->tokAt(2);
6983
0
            }
6984
0
            typestr += end->str();
6985
0
            if (valuetype->fromLibraryType(typestr, settings))
6986
0
                type = end;
6987
112k
        } else if (ValueType::Type::UNKNOWN_TYPE != ValueType::typeFromString(type->str(), type->isLong())) {
6988
100k
            const ValueType::Type t0 = valuetype->type;
6989
100k
            valuetype->type = ValueType::typeFromString(type->str(), type->isLong());
6990
100k
            if (t0 == ValueType::Type::LONG) {
6991
0
                if (valuetype->type == ValueType::Type::LONG)
6992
0
                    valuetype->type = ValueType::Type::LONGLONG;
6993
0
                else if (valuetype->type == ValueType::Type::DOUBLE)
6994
0
                    valuetype->type = ValueType::Type::LONGDOUBLE;
6995
0
            }
6996
100k
        } else if (type->str() == "auto") {
6997
0
            const ValueType *vt = type->valueType();
6998
0
            if (!vt)
6999
0
                return nullptr;
7000
0
            valuetype->type = vt->type;
7001
0
            valuetype->pointer = vt->pointer;
7002
0
            valuetype->reference = vt->reference;
7003
0
            if (vt->sign != ValueType::Sign::UNKNOWN_SIGN)
7004
0
                valuetype->sign = vt->sign;
7005
0
            valuetype->constness = vt->constness;
7006
0
            valuetype->originalTypeName = vt->originalTypeName;
7007
0
            const bool hasConst = Token::simpleMatch(type->previous(), "const");
7008
0
            while (Token::Match(type, "%name%|*|&|&&|::") && !type->variable()) {
7009
0
                if (type->str() == "*") {
7010
0
                    valuetype->pointer = 1;
7011
0
                    if (hasConst)
7012
0
                        valuetype->constness = 1;
7013
0
                } else if (type->str() == "&") {
7014
0
                    valuetype->reference = Reference::LValue;
7015
0
                } else if (type->str() == "&&") {
7016
0
                    valuetype->reference = Reference::RValue;
7017
0
                }
7018
0
                if (type->str() == "const")
7019
0
                    valuetype->constness |= (1 << valuetype->pointer);
7020
0
                type = type->next();
7021
0
            }
7022
0
            break;
7023
11.6k
        } else if (!valuetype->typeScope && (type->str() == "struct" || type->str() == "enum"))
7024
0
            valuetype->type = type->str() == "struct" ? ValueType::Type::RECORD : ValueType::Type::NONSTD;
7025
11.6k
        else if (!valuetype->typeScope && type->type() && type->type()->classScope) {
7026
0
            if (type->type()->classScope->type == Scope::ScopeType::eEnum) {
7027
0
                valuetype->sign = ValueType::Sign::SIGNED;
7028
0
                valuetype->type = getEnumType(type->type()->classScope, settings.platform);
7029
0
            } else {
7030
0
                valuetype->type = ValueType::Type::RECORD;
7031
0
            }
7032
0
            valuetype->typeScope = type->type()->classScope;
7033
11.6k
        } else if (type->isName() && valuetype->sign != ValueType::Sign::UNKNOWN_SIGN && valuetype->pointer == 0U)
7034
0
            return nullptr;
7035
11.6k
        else if (type->str() == "*")
7036
4
            valuetype->pointer++;
7037
11.6k
        else if (type->str() == "&")
7038
4
            valuetype->reference = Reference::LValue;
7039
11.6k
        else if (type->str() == "&&")
7040
0
            valuetype->reference = Reference::RValue;
7041
11.6k
        else if (type->isStandardType())
7042
0
            valuetype->fromLibraryType(type->str(), settings);
7043
11.6k
        else if (Token::Match(type->previous(), "!!:: %name% !!::"))
7044
11.3k
            valuetype->fromLibraryType(type->str(), settings);
7045
112k
        if (!type->originalName().empty())
7046
0
            valuetype->originalTypeName = type->originalName();
7047
112k
        type = type->next();
7048
112k
    }
7049
7050
    // Set signedness for integral types..
7051
108k
    if (valuetype->isIntegral() && valuetype->sign == ValueType::Sign::UNKNOWN_SIGN) {
7052
100k
        if (valuetype->type == ValueType::Type::CHAR)
7053
0
            valuetype->sign = defaultSignedness;
7054
100k
        else if (valuetype->type >= ValueType::Type::SHORT)
7055
100k
            valuetype->sign = ValueType::Sign::SIGNED;
7056
100k
    }
7057
7058
108k
    return (type && (valuetype->type != ValueType::Type::UNKNOWN_TYPE || valuetype->pointer > 0 || valuetype->reference != Reference::None)) ? type : nullptr;
7059
108k
}
7060
7061
static const Scope *getClassScope(const Token *tok)
7062
15.9k
{
7063
15.9k
    return tok && tok->valueType() && tok->valueType()->typeScope && tok->valueType()->typeScope->isClassOrStruct() ?
7064
0
           tok->valueType()->typeScope :
7065
15.9k
           nullptr;
7066
15.9k
}
7067
7068
static const Function *getOperatorFunction(const Token * const tok)
7069
0
{
7070
0
    const std::string functionName("operator" + tok->str());
7071
0
    std::multimap<std::string, const Function *>::const_iterator it;
7072
7073
0
    const Scope *classScope = getClassScope(tok->astOperand1());
7074
0
    if (classScope) {
7075
0
        it = classScope->functionMap.find(functionName);
7076
0
        if (it != classScope->functionMap.end())
7077
0
            return it->second;
7078
0
    }
7079
7080
0
    classScope = getClassScope(tok->astOperand2());
7081
0
    if (classScope) {
7082
0
        it = classScope->functionMap.find(functionName);
7083
0
        if (it != classScope->functionMap.end())
7084
0
            return it->second;
7085
0
    }
7086
7087
0
    return nullptr;
7088
0
}
7089
7090
29.6k
static const Function* getFunction(const Token* tok) {
7091
29.6k
    if (!tok)
7092
0
        return nullptr;
7093
29.6k
    if (tok->function() && tok->function()->retDef)
7094
5.21k
        return tok->function();
7095
24.3k
    if (const Variable* lvar = tok->variable()) { // lambda
7096
0
        const Function* lambda{};
7097
0
        if (Token::Match(lvar->nameToken()->next(), "; %varid% = [", lvar->declarationId()))
7098
0
            lambda = lvar->nameToken()->tokAt(4)->function();
7099
0
        else if (Token::simpleMatch(lvar->nameToken()->next(), "{ ["))
7100
0
            lambda = lvar->nameToken()->tokAt(2)->function();
7101
0
        if (lambda && lambda->retDef)
7102
0
            return lambda;
7103
0
    }
7104
24.3k
    return nullptr;
7105
24.3k
}
7106
7107
void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *tokens)
7108
5.44k
{
7109
5.44k
    if (!tokens)
7110
5.44k
        tokens = const_cast<Tokenizer &>(mTokenizer).list.front();
7111
7112
374k
    for (Token *tok = tokens; tok; tok = tok->next())
7113
368k
        tok->setValueType(nullptr);
7114
7115
374k
    for (Token *tok = tokens; tok; tok = tok->next()) {
7116
368k
        if (tok->isNumber()) {
7117
38.3k
            if (MathLib::isFloat(tok->str())) {
7118
0
                ValueType::Type type = ValueType::Type::DOUBLE;
7119
0
                const char suffix = tok->str()[tok->str().size() - 1];
7120
0
                if (suffix == 'f' || suffix == 'F')
7121
0
                    type = ValueType::Type::FLOAT;
7122
0
                else if (suffix == 'L' || suffix == 'l')
7123
0
                    type = ValueType::Type::LONGDOUBLE;
7124
0
                setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, type, 0U));
7125
38.3k
            } else if (MathLib::isInt(tok->str())) {
7126
38.3k
                const std::string tokStr = MathLib::abs(tok->str());
7127
38.3k
                const bool unsignedSuffix = (tokStr.find_last_of("uU") != std::string::npos);
7128
38.3k
                ValueType::Sign sign = unsignedSuffix ? ValueType::Sign::UNSIGNED : ValueType::Sign::SIGNED;
7129
38.3k
                ValueType::Type type = ValueType::Type::INT;
7130
38.3k
                const MathLib::biguint value = MathLib::toULongNumber(tokStr);
7131
38.3k
                for (std::size_t pos = tokStr.size() - 1U; pos > 0U; --pos) {
7132
5.46k
                    const char suffix = tokStr[pos];
7133
5.46k
                    if (suffix == 'u' || suffix == 'U')
7134
0
                        sign = ValueType::Sign::UNSIGNED;
7135
5.46k
                    else if (suffix == 'l' || suffix == 'L')
7136
0
                        type = (type == ValueType::Type::INT) ? ValueType::Type::LONG : ValueType::Type::LONGLONG;
7137
5.46k
                    else if (pos > 2U && suffix == '4' && tokStr[pos - 1] == '6' && tokStr[pos - 2] == 'i') {
7138
0
                        type = ValueType::Type::LONGLONG;
7139
0
                        pos -= 2;
7140
5.46k
                    } else break;
7141
5.46k
                }
7142
38.3k
                if (mSettings.platform.type != cppcheck::Platform::Type::Unspecified) {
7143
38.3k
                    if (type <= ValueType::Type::INT && mSettings.platform.isIntValue(unsignedSuffix ? (value >> 1) : value))
7144
38.3k
                        type = ValueType::Type::INT;
7145
0
                    else if (type <= ValueType::Type::INT && !MathLib::isDec(tokStr) && mSettings.platform.isIntValue(value >> 2)) {
7146
0
                        type = ValueType::Type::INT;
7147
0
                        sign = ValueType::Sign::UNSIGNED;
7148
0
                    } else if (type <= ValueType::Type::LONG && mSettings.platform.isLongValue(unsignedSuffix ? (value >> 1) : value))
7149
0
                        type = ValueType::Type::LONG;
7150
0
                    else if (type <= ValueType::Type::LONG && !MathLib::isDec(tokStr) && mSettings.platform.isLongValue(value >> 2)) {
7151
0
                        type = ValueType::Type::LONG;
7152
0
                        sign = ValueType::Sign::UNSIGNED;
7153
0
                    } else if (mSettings.platform.isLongLongValue(unsignedSuffix ? (value >> 1) : value))
7154
0
                        type = ValueType::Type::LONGLONG;
7155
0
                    else {
7156
0
                        type = ValueType::Type::LONGLONG;
7157
0
                        sign = ValueType::Sign::UNSIGNED;
7158
0
                    }
7159
38.3k
                }
7160
7161
38.3k
                setValueType(tok, ValueType(sign, type, 0U));
7162
38.3k
            }
7163
330k
        } else if (tok->isComparisonOp() || tok->tokType() == Token::eLogicalOp) {
7164
7.96k
            if (mIsCpp && tok->isComparisonOp() && (getClassScope(tok->astOperand1()) || getClassScope(tok->astOperand2()))) {
7165
0
                const Function *function = getOperatorFunction(tok);
7166
0
                if (function) {
7167
0
                    ValueType vt;
7168
0
                    parsedecl(function->retDef, &vt, mDefaultSignedness, mSettings, mIsCpp);
7169
0
                    setValueType(tok, vt);
7170
0
                    continue;
7171
0
                }
7172
0
            }
7173
7.96k
            setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0U));
7174
322k
        } else if (tok->isBoolean()) {
7175
0
            setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0U));
7176
322k
        } else if (tok->tokType() == Token::eChar || tok->tokType() == Token::eString) {
7177
0
            nonneg int const pointer = tok->tokType() == Token::eChar ? 0U : 1U;
7178
0
            nonneg int const constness = tok->tokType() == Token::eChar ? 0U : 1U;
7179
0
            ValueType valuetype(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, pointer, constness);
7180
7181
0
            if (mIsCpp && mSettings.standards.cpp >= Standards::CPP20 && tok->isUtf8()) {
7182
0
                valuetype.originalTypeName = "char8_t";
7183
0
                valuetype.fromLibraryType(valuetype.originalTypeName, mSettings);
7184
0
            } else if (tok->isUtf16()) {
7185
0
                valuetype.originalTypeName = "char16_t";
7186
0
                valuetype.fromLibraryType(valuetype.originalTypeName, mSettings);
7187
0
            } else if (tok->isUtf32()) {
7188
0
                valuetype.originalTypeName = "char32_t";
7189
0
                valuetype.fromLibraryType(valuetype.originalTypeName, mSettings);
7190
0
            } else if (tok->isLong()) {
7191
0
                valuetype.originalTypeName = "wchar_t";
7192
0
                valuetype.type = ValueType::Type::WCHAR_T;
7193
0
            } else if ((tok->tokType() == Token::eChar) && ((tok->isCChar() && !mIsCpp) || (tok->isCMultiChar()))) {
7194
0
                valuetype.type = ValueType::Type::INT;
7195
0
                valuetype.sign = ValueType::Sign::SIGNED;
7196
0
            }
7197
0
            setValueType(tok, valuetype);
7198
322k
        } else if (tok->link() && Token::Match(tok, "(|{")) {
7199
29.6k
            const Token* start = tok->astOperand1() ? tok->astOperand1()->findExpressionStartEndTokens().first : nullptr;
7200
            // cast
7201
29.6k
            if (tok->isCast() && !tok->astOperand2() && Token::Match(tok, "( %name%")) {
7202
0
                ValueType valuetype;
7203
0
                if (Token::simpleMatch(parsedecl(tok->next(), &valuetype, mDefaultSignedness, mSettings, mIsCpp), ")"))
7204
0
                    setValueType(tok, valuetype);
7205
0
            }
7206
7207
            // C++ cast
7208
29.6k
            else if (tok->astOperand2() && Token::Match(tok->astOperand1(), "static_cast|const_cast|dynamic_cast|reinterpret_cast < %name%") && tok->astOperand1()->linkAt(1)) {
7209
0
                ValueType valuetype;
7210
0
                if (Token::simpleMatch(parsedecl(tok->astOperand1()->tokAt(2), &valuetype, mDefaultSignedness, mSettings, mIsCpp), ">"))
7211
0
                    setValueType(tok, valuetype);
7212
0
            }
7213
7214
            // Construct smart pointer
7215
29.6k
            else if (mIsCpp && mSettings.library.isSmartPointer(start)) {
7216
0
                ValueType valuetype;
7217
0
                if (parsedecl(start, &valuetype, mDefaultSignedness, mSettings, mIsCpp)) {
7218
0
                    setValueType(tok, valuetype);
7219
0
                    setValueType(tok->astOperand1(), valuetype);
7220
0
                }
7221
7222
0
            }
7223
7224
            // function or lambda
7225
29.6k
            else if (const Function* f = getFunction(tok->previous())) {
7226
5.21k
                ValueType valuetype;
7227
5.21k
                if (parsedecl(f->retDef, &valuetype, mDefaultSignedness, mSettings, mIsCpp))
7228
5.21k
                    setValueType(tok, valuetype);
7229
5.21k
            }
7230
7231
24.3k
            else if (Token::simpleMatch(tok->previous(), "sizeof (")) {
7232
0
                ValueType valuetype(ValueType::Sign::UNSIGNED, ValueType::Type::LONG, 0U);
7233
0
                if (mSettings.platform.type == cppcheck::Platform::Type::Win64)
7234
0
                    valuetype.type = ValueType::Type::LONGLONG;
7235
7236
0
                valuetype.originalTypeName = "size_t";
7237
0
                setValueType(tok, valuetype);
7238
7239
0
                if (Token::Match(tok, "( %type% %type%| *| *| )")) {
7240
0
                    ValueType vt;
7241
0
                    if (parsedecl(tok->next(), &vt, mDefaultSignedness, mSettings, mIsCpp)) {
7242
0
                        setValueType(tok->next(), vt);
7243
0
                    }
7244
0
                }
7245
0
            }
7246
7247
            // function style cast
7248
24.3k
            else if (tok->previous() && tok->previous()->isStandardType()) {
7249
0
                ValueType valuetype;
7250
0
                if (tok->astOperand1() && valuetype.fromLibraryType(tok->astOperand1()->expressionString(), mSettings)) {
7251
0
                    setValueType(tok, valuetype);
7252
0
                    continue;
7253
0
                }
7254
7255
0
                valuetype.type = ValueType::typeFromString(tok->previous()->str(), tok->previous()->isLong());
7256
0
                if (tok->previous()->isUnsigned())
7257
0
                    valuetype.sign = ValueType::Sign::UNSIGNED;
7258
0
                else if (tok->previous()->isSigned())
7259
0
                    valuetype.sign = ValueType::Sign::SIGNED;
7260
0
                else if (valuetype.isIntegral() && valuetype.type != ValueType::UNKNOWN_INT)
7261
0
                    valuetype.sign = mDefaultSignedness;
7262
0
                setValueType(tok, valuetype);
7263
0
            }
7264
7265
            // constructor call
7266
24.3k
            else if (tok->previous() && tok->previous()->function() && tok->previous()->function()->isConstructor()) {
7267
0
                ValueType valuetype;
7268
0
                valuetype.type = ValueType::RECORD;
7269
0
                valuetype.typeScope = tok->previous()->function()->token->scope();
7270
0
                setValueType(tok, valuetype);
7271
0
            }
7272
7273
24.3k
            else if (Token::simpleMatch(tok->previous(), "= {") && tok->tokAt(-2) && tok->tokAt(-2)->valueType()) {
7274
0
                ValueType vt = *tok->tokAt(-2)->valueType();
7275
0
                setValueType(tok, vt);
7276
0
            }
7277
7278
            // library type/function
7279
24.3k
            else if (tok->previous()) {
7280
                // Aggregate constructor
7281
24.3k
                if (Token::Match(tok->previous(), "%name%")) {
7282
9.41k
                    ValueType valuetype;
7283
9.41k
                    if (parsedecl(tok->previous(), &valuetype, mDefaultSignedness, mSettings, mIsCpp)) {
7284
1.74k
                        if (valuetype.typeScope) {
7285
0
                            setValueType(tok, valuetype);
7286
0
                            continue;
7287
0
                        }
7288
1.74k
                    }
7289
9.41k
                }
7290
24.3k
                if (mIsCpp && tok->astParent() && Token::Match(tok->astOperand1(), "%name%|::")) {
7291
0
                    const Token *typeStartToken = tok->astOperand1();
7292
0
                    while (typeStartToken && typeStartToken->str() == "::")
7293
0
                        typeStartToken = typeStartToken->astOperand1();
7294
0
                    if (mSettings.library.detectContainerOrIterator(typeStartToken) ||
7295
0
                        mSettings.library.detectSmartPointer(typeStartToken)) {
7296
0
                        ValueType vt;
7297
0
                        if (parsedecl(typeStartToken, &vt, mDefaultSignedness, mSettings, mIsCpp)) {
7298
0
                            setValueType(tok, vt);
7299
0
                            continue;
7300
0
                        }
7301
0
                    }
7302
7303
0
                    const std::string e = tok->astOperand1()->expressionString();
7304
7305
0
                    if ((e == "std::make_shared" || e == "std::make_unique") && Token::Match(tok->astOperand1(), ":: %name% < %name%")) {
7306
0
                        ValueType vt;
7307
0
                        parsedecl(tok->astOperand1()->tokAt(3), &vt, mDefaultSignedness, mSettings, mIsCpp);
7308
0
                        if (vt.typeScope) {
7309
0
                            vt.smartPointerType = vt.typeScope->definedType;
7310
0
                            vt.typeScope = nullptr;
7311
0
                        }
7312
0
                        if (e == "std::make_shared" && mSettings.library.smartPointers.count("std::shared_ptr") > 0)
7313
0
                            vt.smartPointer = &mSettings.library.smartPointers.at("std::shared_ptr");
7314
0
                        if (e == "std::make_unique" && mSettings.library.smartPointers.count("std::unique_ptr") > 0)
7315
0
                            vt.smartPointer = &mSettings.library.smartPointers.at("std::unique_ptr");
7316
0
                        vt.type = ValueType::Type::SMART_POINTER;
7317
0
                        vt.smartPointerTypeToken = tok->astOperand1()->tokAt(3);
7318
0
                        setValueType(tok, vt);
7319
0
                        continue;
7320
0
                    }
7321
7322
0
                    ValueType podtype;
7323
0
                    if (podtype.fromLibraryType(e, mSettings)) {
7324
0
                        setValueType(tok, podtype);
7325
0
                        continue;
7326
0
                    }
7327
0
                }
7328
7329
24.3k
                const std::string& typestr(mSettings.library.returnValueType(tok->previous()));
7330
24.3k
                if (!typestr.empty()) {
7331
0
                    ValueType valuetype;
7332
0
                    TokenList tokenList(&mSettings);
7333
0
                    std::istringstream istr(typestr+";");
7334
0
                    tokenList.createTokens(istr);
7335
0
                    tokenList.simplifyStdType();
7336
0
                    if (parsedecl(tokenList.front(), &valuetype, mDefaultSignedness, mSettings, mIsCpp)) {
7337
0
                        valuetype.originalTypeName = typestr;
7338
0
                        setValueType(tok, valuetype);
7339
0
                    }
7340
0
                }
7341
7342
                //Is iterator fetching function invoked on container?
7343
24.3k
                const bool isReturnIter = typestr == "iterator";
7344
24.3k
                if (typestr.empty() || isReturnIter) {
7345
24.3k
                    if (Token::simpleMatch(tok->astOperand1(), ".") &&
7346
24.3k
                        tok->astOperand1()->astOperand1() &&
7347
24.3k
                        tok->astOperand1()->astOperand2() &&
7348
24.3k
                        tok->astOperand1()->astOperand1()->valueType() &&
7349
24.3k
                        tok->astOperand1()->astOperand1()->valueType()->container) {
7350
0
                        const Library::Container *cont = tok->astOperand1()->astOperand1()->valueType()->container;
7351
0
                        const auto it = cont->functions.find(tok->astOperand1()->astOperand2()->str());
7352
0
                        if (it != cont->functions.end()) {
7353
0
                            if (it->second.yield == Library::Container::Yield::START_ITERATOR ||
7354
0
                                it->second.yield == Library::Container::Yield::END_ITERATOR ||
7355
0
                                it->second.yield == Library::Container::Yield::ITERATOR) {
7356
0
                                ValueType vt;
7357
0
                                vt.type = ValueType::Type::ITERATOR;
7358
0
                                vt.container = cont;
7359
0
                                vt.containerTypeToken =
7360
0
                                    tok->astOperand1()->astOperand1()->valueType()->containerTypeToken;
7361
0
                                setValueType(tok, vt);
7362
0
                                continue;
7363
0
                            }
7364
0
                        }
7365
                        //Is iterator fetching function called?
7366
24.3k
                    } else if (Token::simpleMatch(tok->astOperand1(), "::") &&
7367
24.3k
                               tok->astOperand2() &&
7368
24.3k
                               tok->astOperand2()->isVariable()) {
7369
0
                        const auto* const paramVariable = tok->astOperand2()->variable();
7370
0
                        if (!paramVariable ||
7371
0
                            !paramVariable->valueType() ||
7372
0
                            !paramVariable->valueType()->container) {
7373
0
                            continue;
7374
0
                        }
7375
7376
0
                        const auto yield = astFunctionYield(tok->previous(), &mSettings);
7377
0
                        if (yield == Library::Container::Yield::START_ITERATOR ||
7378
0
                            yield == Library::Container::Yield::END_ITERATOR ||
7379
0
                            yield == Library::Container::Yield::ITERATOR) {
7380
0
                            ValueType vt;
7381
0
                            vt.type = ValueType::Type::ITERATOR;
7382
0
                            vt.container = paramVariable->valueType()->container;
7383
0
                            vt.containerTypeToken = paramVariable->valueType()->containerTypeToken;
7384
0
                            setValueType(tok, vt);
7385
0
                        }
7386
0
                    }
7387
24.3k
                    if (isReturnIter) {
7388
0
                        const std::vector<const Token*> args = getArguments(tok);
7389
0
                        if (!args.empty()) {
7390
0
                            const Library::ArgumentChecks::IteratorInfo* info = mSettings.library.getArgIteratorInfo(tok->previous(), 1);
7391
0
                            if (info && info->it) {
7392
0
                                const Token* contTok = args[0];
7393
0
                                if (Token::simpleMatch(args[0]->astOperand1(), ".") && args[0]->astOperand1()->astOperand1()) // .begin()
7394
0
                                    contTok = args[0]->astOperand1()->astOperand1();
7395
0
                                else if (Token::simpleMatch(args[0], "(") && args[0]->astOperand2()) // std::begin()
7396
0
                                    contTok = args[0]->astOperand2();
7397
0
                                while (Token::simpleMatch(contTok, "[")) // move to container token
7398
0
                                    contTok = contTok->astOperand1();
7399
0
                                if (Token::simpleMatch(contTok, "."))
7400
0
                                    contTok = contTok->astOperand2();
7401
0
                                if (contTok && contTok->variable() && contTok->variable()->valueType() && contTok->variable()->valueType()->container) {
7402
0
                                    ValueType vt;
7403
0
                                    vt.type = ValueType::Type::ITERATOR;
7404
0
                                    vt.container = contTok->variable()->valueType()->container;
7405
0
                                    vt.containerTypeToken = contTok->variable()->valueType()->containerTypeToken;
7406
0
                                    setValueType(tok, vt);
7407
0
                                } else if (Token::simpleMatch(contTok, "(") && contTok->astOperand1() && contTok->astOperand1()->function()) {
7408
0
                                    const Function* func = contTok->astOperand1()->function();
7409
0
                                    if (const ValueType* funcVt = func->tokenDef->next()->valueType()) {
7410
0
                                        ValueType vt;
7411
0
                                        vt.type = ValueType::Type::ITERATOR;
7412
0
                                        vt.container = funcVt->container;
7413
0
                                        vt.containerTypeToken = funcVt->containerTypeToken;
7414
0
                                        setValueType(tok, vt);
7415
0
                                    }
7416
0
                                }
7417
0
                            }
7418
0
                        }
7419
0
                    }
7420
24.3k
                    continue;
7421
24.3k
                }
7422
0
                TokenList tokenList(&mSettings);
7423
0
                std::istringstream istr(typestr+";");
7424
0
                if (tokenList.createTokens(istr)) {
7425
0
                    ValueType vt;
7426
0
                    tokenList.simplifyPlatformTypes();
7427
0
                    tokenList.simplifyStdType();
7428
0
                    if (parsedecl(tokenList.front(), &vt, mDefaultSignedness, mSettings, mIsCpp)) {
7429
0
                        vt.originalTypeName = typestr;
7430
0
                        setValueType(tok, vt);
7431
0
                    }
7432
0
                }
7433
0
            }
7434
293k
        } else if (tok->str() == "return") {
7435
7.66k
            const Scope *functionScope = tok->scope();
7436
8.82k
            while (functionScope && functionScope->isExecutable() && functionScope->type != Scope::eLambda && functionScope->type != Scope::eFunction)
7437
1.16k
                functionScope = functionScope->nestedIn;
7438
7.66k
            if (functionScope && functionScope->type == Scope::eFunction && functionScope->function &&
7439
7.66k
                functionScope->function->retDef) {
7440
7.66k
                ValueType vt = ValueType::parseDecl(functionScope->function->retDef, mSettings);
7441
7.66k
                setValueType(tok, vt);
7442
7.66k
                if (Token::simpleMatch(tok, "return {"))
7443
0
                    setValueType(tok->next(), vt);
7444
7.66k
            }
7445
285k
        } else if (tok->variable()) {
7446
79.3k
            setValueType(tok, *tok->variable());
7447
79.3k
            if (!tok->variable()->valueType() && tok->valueType())
7448
0
                const_cast<Variable*>(tok->variable())->setValueType(*tok->valueType());
7449
206k
        } else if (tok->enumerator()) {
7450
0
            setValueType(tok, *tok->enumerator());
7451
206k
        } else if (tok->isKeyword() && tok->str() == "new") {
7452
0
            const Token *typeTok = tok->next();
7453
0
            if (Token::Match(typeTok, "( std| ::| nothrow )"))
7454
0
                typeTok = typeTok->link()->next();
7455
0
            bool isIterator = false;
7456
0
            if (const Library::Container* c = mSettings.library.detectContainerOrIterator(typeTok, &isIterator)) {
7457
0
                ValueType vt;
7458
0
                vt.pointer = 1;
7459
0
                vt.container = c;
7460
0
                vt.type = isIterator ? ValueType::Type::ITERATOR : ValueType::Type::CONTAINER;
7461
0
                setValueType(tok, vt);
7462
0
                continue;
7463
0
            }
7464
0
            std::string typestr;
7465
0
            while (Token::Match(typeTok, "%name% :: %name%")) {
7466
0
                typestr += typeTok->str() + "::";
7467
0
                typeTok = typeTok->tokAt(2);
7468
0
            }
7469
0
            if (!Token::Match(typeTok, "%type% ;|[|("))
7470
0
                continue;
7471
0
            typestr += typeTok->str();
7472
0
            ValueType vt;
7473
0
            vt.pointer = 1;
7474
0
            if (typeTok->type() && typeTok->type()->classScope) {
7475
0
                vt.type = ValueType::Type::RECORD;
7476
0
                vt.typeScope = typeTok->type()->classScope;
7477
0
            } else {
7478
0
                vt.type = ValueType::typeFromString(typestr, typeTok->isLong());
7479
0
                if (vt.type == ValueType::Type::UNKNOWN_TYPE)
7480
0
                    vt.fromLibraryType(typestr, mSettings);
7481
0
                if (vt.type == ValueType::Type::UNKNOWN_TYPE)
7482
0
                    continue;
7483
0
                if (typeTok->isUnsigned())
7484
0
                    vt.sign = ValueType::Sign::UNSIGNED;
7485
0
                else if (typeTok->isSigned())
7486
0
                    vt.sign = ValueType::Sign::SIGNED;
7487
0
                if (vt.sign == ValueType::Sign::UNKNOWN_SIGN && vt.isIntegral())
7488
0
                    vt.sign = (vt.type == ValueType::Type::CHAR) ? mDefaultSignedness : ValueType::Sign::SIGNED;
7489
0
            }
7490
0
            setValueType(tok, vt);
7491
0
            if (Token::simpleMatch(tok->astOperand1(), "(")) {
7492
0
                vt.pointer--;
7493
0
                setValueType(tok->astOperand1(), vt);
7494
0
            }
7495
206k
        } else if (tok->isKeyword() && tok->str() == "return" && tok->scope()) {
7496
0
            const Scope* fscope = tok->scope();
7497
0
            while (fscope && !fscope->function)
7498
0
                fscope = fscope->nestedIn;
7499
0
            if (fscope && fscope->function && fscope->function->retDef) {
7500
0
                ValueType vt;
7501
0
                parsedecl(fscope->function->retDef, &vt, mDefaultSignedness, mSettings, mIsCpp);
7502
0
                setValueType(tok, vt);
7503
0
            }
7504
206k
        } else if (tok->isKeyword() && tok->str() == "this" && tok->scope()->isExecutable()) {
7505
0
            const Scope* fscope = tok->scope();
7506
0
            while (fscope && !fscope->function)
7507
0
                fscope = fscope->nestedIn;
7508
0
            const Scope* defScope = fscope && fscope->function->tokenDef ? fscope->function->tokenDef->scope() : nullptr;
7509
0
            if (defScope && defScope->isClassOrStruct()) {
7510
0
                ValueType vt(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::RECORD, 1);
7511
0
                vt.typeScope = defScope;
7512
0
                if (fscope->function->isConst())
7513
0
                    vt.constness = 1;
7514
0
                setValueType(tok, vt);
7515
0
            }
7516
0
        }
7517
368k
    }
7518
7519
5.44k
    if (reportDebugWarnings && mSettings.debugwarnings) {
7520
0
        for (Token *tok = tokens; tok; tok = tok->next()) {
7521
0
            if (tok->str() == "auto" && !tok->valueType()) {
7522
0
                if (Token::Match(tok->next(), "%name% ; %name% = [") && isLambdaCaptureList(tok->tokAt(5)))
7523
0
                    continue;
7524
0
                if (Token::Match(tok->next(), "%name% {|= [") && isLambdaCaptureList(tok->tokAt(3)))
7525
0
                    continue;
7526
0
                debugMessage(tok, "autoNoType", "auto token with no type.");
7527
0
            }
7528
0
        }
7529
0
    }
7530
7531
    // Update functions with new type information.
7532
5.44k
    createSymbolDatabaseSetFunctionPointers(false);
7533
7534
    // Update auto variables with new type information.
7535
5.44k
    createSymbolDatabaseSetVariablePointers();
7536
5.44k
}
7537
7538
ValueType ValueType::parseDecl(const Token *type, const Settings &settings)
7539
14.4k
{
7540
14.4k
    ValueType vt;
7541
14.4k
    parsedecl(type, &vt, settings.platform.defaultSign == 'u' ? Sign::UNSIGNED : Sign::SIGNED, settings, type->isCpp());
7542
14.4k
    return vt;
7543
14.4k
}
7544
7545
ValueType::Type ValueType::typeFromString(const std::string &typestr, bool longType)
7546
213k
{
7547
213k
    if (typestr == "void")
7548
0
        return ValueType::Type::VOID;
7549
213k
    if (typestr == "bool" || typestr == "_Bool")
7550
0
        return ValueType::Type::BOOL;
7551
213k
    if (typestr== "char")
7552
0
        return ValueType::Type::CHAR;
7553
213k
    if (typestr == "short")
7554
0
        return ValueType::Type::SHORT;
7555
213k
    if (typestr == "wchar_t")
7556
0
        return ValueType::Type::WCHAR_T;
7557
213k
    if (typestr == "int")
7558
201k
        return ValueType::Type::INT;
7559
11.6k
    if (typestr == "long")
7560
0
        return longType ? ValueType::Type::LONGLONG : ValueType::Type::LONG;
7561
11.6k
    if (typestr == "float")
7562
0
        return ValueType::Type::FLOAT;
7563
11.6k
    if (typestr == "double")
7564
0
        return longType ? ValueType::Type::LONGDOUBLE : ValueType::Type::DOUBLE;
7565
11.6k
    return ValueType::Type::UNKNOWN_TYPE;
7566
11.6k
}
7567
7568
bool ValueType::fromLibraryType(const std::string &typestr, const Settings &settings)
7569
11.3k
{
7570
11.3k
    const Library::PodType* podtype = settings.library.podtype(typestr);
7571
11.3k
    if (podtype && (podtype->sign == 's' || podtype->sign == 'u')) {
7572
0
        if (podtype->size == 1)
7573
0
            type = ValueType::Type::CHAR;
7574
0
        else if (podtype->size == settings.platform.sizeof_int)
7575
0
            type = ValueType::Type::INT;
7576
0
        else if (podtype->size == settings.platform.sizeof_short)
7577
0
            type = ValueType::Type::SHORT;
7578
0
        else if (podtype->size == settings.platform.sizeof_long)
7579
0
            type = ValueType::Type::LONG;
7580
0
        else if (podtype->size == settings.platform.sizeof_long_long)
7581
0
            type = ValueType::Type::LONGLONG;
7582
0
        else if (podtype->stdtype == Library::PodType::Type::BOOL)
7583
0
            type = ValueType::Type::BOOL;
7584
0
        else if (podtype->stdtype == Library::PodType::Type::CHAR)
7585
0
            type = ValueType::Type::CHAR;
7586
0
        else if (podtype->stdtype == Library::PodType::Type::SHORT)
7587
0
            type = ValueType::Type::SHORT;
7588
0
        else if (podtype->stdtype == Library::PodType::Type::INT)
7589
0
            type = ValueType::Type::INT;
7590
0
        else if (podtype->stdtype == Library::PodType::Type::LONG)
7591
0
            type = ValueType::Type::LONG;
7592
0
        else if (podtype->stdtype == Library::PodType::Type::LONGLONG)
7593
0
            type = ValueType::Type::LONGLONG;
7594
0
        else
7595
0
            type = ValueType::Type::UNKNOWN_INT;
7596
0
        sign = (podtype->sign == 'u') ? ValueType::UNSIGNED : ValueType::SIGNED;
7597
0
        return true;
7598
0
    }
7599
11.3k
    if (podtype && podtype->stdtype == Library::PodType::Type::NO) {
7600
0
        type = ValueType::Type::POD;
7601
0
        sign = ValueType::UNKNOWN_SIGN;
7602
0
        return true;
7603
0
    }
7604
7605
11.3k
    const Library::PlatformType *platformType = settings.library.platform_type(typestr, settings.platform.toString());
7606
11.3k
    if (platformType) {
7607
0
        if (platformType->mType == "char")
7608
0
            type = ValueType::Type::CHAR;
7609
0
        else if (platformType->mType == "short")
7610
0
            type = ValueType::Type::SHORT;
7611
0
        else if (platformType->mType == "wchar_t")
7612
0
            type = ValueType::Type::WCHAR_T;
7613
0
        else if (platformType->mType == "int")
7614
0
            type = platformType->mLong ? ValueType::Type::LONG : ValueType::Type::INT;
7615
0
        else if (platformType->mType == "long")
7616
0
            type = platformType->mLong ? ValueType::Type::LONGLONG : ValueType::Type::LONG;
7617
0
        if (platformType->mSigned)
7618
0
            sign = ValueType::SIGNED;
7619
0
        else if (platformType->mUnsigned)
7620
0
            sign = ValueType::UNSIGNED;
7621
0
        if (platformType->mPointer)
7622
0
            pointer = 1;
7623
0
        if (platformType->mPtrPtr)
7624
0
            pointer = 2;
7625
0
        if (platformType->mConstPtr)
7626
0
            constness = 1;
7627
0
        return true;
7628
0
    }
7629
11.3k
    if (!podtype && (typestr == "size_t" || typestr == "std::size_t")) {
7630
0
        originalTypeName = "size_t";
7631
0
        sign = ValueType::UNSIGNED;
7632
0
        if (settings.platform.sizeof_size_t == settings.platform.sizeof_long)
7633
0
            type = ValueType::Type::LONG;
7634
0
        else if (settings.platform.sizeof_size_t == settings.platform.sizeof_long_long)
7635
0
            type = ValueType::Type::LONGLONG;
7636
0
        else if (settings.platform.sizeof_size_t == settings.platform.sizeof_int)
7637
0
            type = ValueType::Type::INT;
7638
0
        else
7639
0
            type = ValueType::Type::UNKNOWN_INT;
7640
0
        return true;
7641
0
    }
7642
7643
11.3k
    return false;
7644
11.3k
}
7645
7646
std::string ValueType::dump() const
7647
0
{
7648
0
    std::string ret;
7649
0
    switch (type) {
7650
0
    case UNKNOWN_TYPE:
7651
0
        return "";
7652
0
    case NONSTD:
7653
0
        ret += "valueType-type=\"nonstd\"";
7654
0
        break;
7655
0
    case POD:
7656
0
        ret += "valueType-type=\"pod\"";
7657
0
        break;
7658
0
    case RECORD:
7659
0
        ret += "valueType-type=\"record\"";
7660
0
        break;
7661
0
    case SMART_POINTER:
7662
0
        ret += "valueType-type=\"smart-pointer\"";
7663
0
        break;
7664
0
    case CONTAINER: {
7665
0
        ret += "valueType-type=\"container\"";
7666
0
        ret += " valueType-containerId=\"";
7667
0
        ret += id_string(container);
7668
0
        ret += "\"";
7669
0
        break;
7670
0
    }
7671
0
    case ITERATOR:
7672
0
        ret += "valueType-type=\"iterator\"";
7673
0
        break;
7674
0
    case VOID:
7675
0
        ret += "valueType-type=\"void\"";
7676
0
        break;
7677
0
    case BOOL:
7678
0
        ret += "valueType-type=\"bool\"";
7679
0
        break;
7680
0
    case CHAR:
7681
0
        ret += "valueType-type=\"char\"";
7682
0
        break;
7683
0
    case SHORT:
7684
0
        ret += "valueType-type=\"short\"";
7685
0
        break;
7686
0
    case WCHAR_T:
7687
0
        ret += "valueType-type=\"wchar_t\"";
7688
0
        break;
7689
0
    case INT:
7690
0
        ret += "valueType-type=\"int\"";
7691
0
        break;
7692
0
    case LONG:
7693
0
        ret += "valueType-type=\"long\"";
7694
0
        break;
7695
0
    case LONGLONG:
7696
0
        ret += "valueType-type=\"long long\"";
7697
0
        break;
7698
0
    case UNKNOWN_INT:
7699
0
        ret += "valueType-type=\"unknown int\"";
7700
0
        break;
7701
0
    case FLOAT:
7702
0
        ret += "valueType-type=\"float\"";
7703
0
        break;
7704
0
    case DOUBLE:
7705
0
        ret += "valueType-type=\"double\"";
7706
0
        break;
7707
0
    case LONGDOUBLE:
7708
0
        ret += "valueType-type=\"long double\"";
7709
0
        break;
7710
0
    }
7711
7712
0
    switch (sign) {
7713
0
    case Sign::UNKNOWN_SIGN:
7714
0
        break;
7715
0
    case Sign::SIGNED:
7716
0
        ret += " valueType-sign=\"signed\"";
7717
0
        break;
7718
0
    case Sign::UNSIGNED:
7719
0
        ret += " valueType-sign=\"unsigned\"";
7720
0
        break;
7721
0
    }
7722
7723
0
    if (bits > 0) {
7724
0
        ret += " valueType-bits=\"";
7725
0
        ret += std::to_string(bits);
7726
0
        ret += '\"';
7727
0
    }
7728
7729
0
    if (pointer > 0) {
7730
0
        ret += " valueType-pointer=\"";
7731
0
        ret += std::to_string(pointer);
7732
0
        ret += '\"';
7733
0
    }
7734
7735
0
    if (constness > 0) {
7736
0
        ret += " valueType-constness=\"";
7737
0
        ret += std::to_string(constness);
7738
0
        ret += '\"';
7739
0
    }
7740
7741
0
    if (reference == Reference::None)
7742
0
        ret += " valueType-reference=\"None\"";
7743
0
    else if (reference == Reference::LValue)
7744
0
        ret += " valueType-reference=\"LValue\"";
7745
0
    else if (reference == Reference::RValue)
7746
0
        ret += " valueType-reference=\"RValue\"";
7747
7748
0
    if (typeScope) {
7749
0
        ret += " valueType-typeScope=\"";
7750
0
        ret += id_string(typeScope);
7751
0
        ret += '\"';
7752
0
    }
7753
7754
0
    if (!originalTypeName.empty()) {
7755
0
        ret += " valueType-originalTypeName=\"";
7756
0
        ret += ErrorLogger::toxml(originalTypeName);
7757
0
        ret += '\"';
7758
0
    }
7759
7760
0
    return ret;
7761
0
}
7762
7763
bool ValueType::isConst(nonneg int indirect) const
7764
5.31k
{
7765
5.31k
    if (indirect > pointer)
7766
86
        return false;
7767
5.23k
    return constness & (1 << (pointer - indirect));
7768
5.31k
}
7769
7770
MathLib::bigint ValueType::typeSize(const cppcheck::Platform &platform, bool p) const
7771
0
{
7772
0
    if (p && pointer)
7773
0
        return platform.sizeof_pointer;
7774
7775
0
    if (typeScope && typeScope->definedType && typeScope->definedType->sizeOf)
7776
0
        return typeScope->definedType->sizeOf;
7777
7778
0
    switch (type) {
7779
0
    case ValueType::Type::BOOL:
7780
0
        return platform.sizeof_bool;
7781
0
    case ValueType::Type::CHAR:
7782
0
        return 1;
7783
0
    case ValueType::Type::SHORT:
7784
0
        return platform.sizeof_short;
7785
0
    case ValueType::Type::WCHAR_T:
7786
0
        return platform.sizeof_wchar_t;
7787
0
    case ValueType::Type::INT:
7788
0
        return platform.sizeof_int;
7789
0
    case ValueType::Type::LONG:
7790
0
        return platform.sizeof_long;
7791
0
    case ValueType::Type::LONGLONG:
7792
0
        return platform.sizeof_long_long;
7793
0
    case ValueType::Type::FLOAT:
7794
0
        return platform.sizeof_float;
7795
0
    case ValueType::Type::DOUBLE:
7796
0
        return platform.sizeof_double;
7797
0
    case ValueType::Type::LONGDOUBLE:
7798
0
        return platform.sizeof_long_double;
7799
0
    default:
7800
0
        break;
7801
0
    }
7802
7803
    // Unknown invalid size
7804
0
    return 0;
7805
0
}
7806
7807
bool ValueType::isTypeEqual(const ValueType* that) const
7808
0
{
7809
0
    if (!that)
7810
0
        return false;
7811
0
    auto tie = [](const ValueType* vt) {
7812
0
        return std::tie(vt->type, vt->container, vt->pointer, vt->typeScope, vt->smartPointer);
7813
0
    };
7814
0
    return tie(this) == tie(that);
7815
0
}
7816
7817
std::string ValueType::str() const
7818
0
{
7819
0
    std::string ret;
7820
0
    if (constness & 1)
7821
0
        ret = " const";
7822
0
    if (type == VOID)
7823
0
        ret += " void";
7824
0
    else if (isIntegral()) {
7825
0
        if (sign == SIGNED)
7826
0
            ret += " signed";
7827
0
        else if (sign == UNSIGNED)
7828
0
            ret += " unsigned";
7829
0
        if (type == BOOL)
7830
0
            ret += " bool";
7831
0
        else if (type == CHAR)
7832
0
            ret += " char";
7833
0
        else if (type == SHORT)
7834
0
            ret += " short";
7835
0
        else if (type == WCHAR_T)
7836
0
            ret += " wchar_t";
7837
0
        else if (type == INT)
7838
0
            ret += " int";
7839
0
        else if (type == LONG)
7840
0
            ret += " long";
7841
0
        else if (type == LONGLONG)
7842
0
            ret += " long long";
7843
0
        else if (type == UNKNOWN_INT)
7844
0
            ret += " unknown_int";
7845
0
    } else if (type == FLOAT)
7846
0
        ret += " float";
7847
0
    else if (type == DOUBLE)
7848
0
        ret += " double";
7849
0
    else if (type == LONGDOUBLE)
7850
0
        ret += " long double";
7851
0
    else if ((type == ValueType::Type::NONSTD || type == ValueType::Type::RECORD) && typeScope) {
7852
0
        std::string className(typeScope->className);
7853
0
        const Scope *scope = typeScope->definedType ? typeScope->definedType->enclosingScope : typeScope->nestedIn;
7854
0
        while (scope && scope->type != Scope::eGlobal) {
7855
0
            if (scope->type == Scope::eClass || scope->type == Scope::eStruct || scope->type == Scope::eNamespace)
7856
0
                className = scope->className + "::" + className;
7857
0
            scope = (scope->definedType && scope->definedType->enclosingScope) ? scope->definedType->enclosingScope : scope->nestedIn;
7858
0
        }
7859
0
        ret += ' ' + className;
7860
0
    } else if (type == ValueType::Type::CONTAINER && container) {
7861
0
        ret += " container(" + container->startPattern + ')';
7862
0
    } else if (type == ValueType::Type::ITERATOR && container) {
7863
0
        ret += " iterator(" + container->startPattern + ')';
7864
0
    } else if (type == ValueType::Type::SMART_POINTER && smartPointer) {
7865
0
        ret += " smart-pointer(" + smartPointer->name + ")";
7866
0
    }
7867
0
    for (unsigned int p = 0; p < pointer; p++) {
7868
0
        ret += " *";
7869
0
        if (constness & (2 << p))
7870
0
            ret += " const";
7871
0
    }
7872
0
    if (reference == Reference::LValue)
7873
0
        ret += " &";
7874
0
    else if (reference == Reference::RValue)
7875
0
        ret += " &&";
7876
0
    return ret.empty() ? ret : ret.substr(1);
7877
0
}
7878
7879
void ValueType::setDebugPath(const Token* tok, SourceLocation ctx, SourceLocation local)
7880
0
{
7881
0
    std::string file = ctx.file_name();
7882
0
    if (file.empty())
7883
0
        return;
7884
0
    std::string s = Path::stripDirectoryPart(file) + ":" + std::to_string(ctx.line()) + ": " + ctx.function_name() +
7885
0
                    " => " + local.function_name();
7886
0
    debugPath.emplace_back(tok, std::move(s));
7887
0
}
7888
7889
ValueType::MatchResult ValueType::matchParameter(const ValueType *call, const ValueType *func)
7890
0
{
7891
0
    if (!call || !func)
7892
0
        return ValueType::MatchResult::UNKNOWN;
7893
0
    if (call->pointer != func->pointer) {
7894
0
        if (call->pointer > 1 && func->pointer == 1 && func->type == ValueType::Type::VOID)
7895
0
            return ValueType::MatchResult::FALLBACK1;
7896
0
        if (call->pointer == 1 && func->pointer == 0 && func->isIntegral() && func->sign != ValueType::Sign::SIGNED)
7897
0
            return ValueType::MatchResult::FALLBACK1;
7898
0
        if (call->pointer == 1 && call->type == ValueType::Type::CHAR && func->pointer == 0 && func->container && func->container->stdStringLike)
7899
0
            return ValueType::MatchResult::FALLBACK2;
7900
0
        return ValueType::MatchResult::NOMATCH; // TODO
7901
0
    }
7902
0
    if (call->pointer > 0) {
7903
0
        if ((call->constness | func->constness) != func->constness)
7904
0
            return ValueType::MatchResult::NOMATCH;
7905
0
        if (call->constness == 0 && func->constness != 0 && func->reference != Reference::None)
7906
0
            return ValueType::MatchResult::NOMATCH;
7907
0
    }
7908
0
    if (call->type != func->type || (call->isEnum() && !func->isEnum())) {
7909
0
        if (call->type == ValueType::Type::VOID || func->type == ValueType::Type::VOID)
7910
0
            return ValueType::MatchResult::FALLBACK1;
7911
0
        if (call->pointer > 0)
7912
0
            return func->type == ValueType::UNKNOWN_TYPE ? ValueType::MatchResult::UNKNOWN : ValueType::MatchResult::NOMATCH;
7913
0
        if (call->isIntegral() && func->isIntegral())
7914
0
            return call->type < func->type ?
7915
0
                   ValueType::MatchResult::FALLBACK1 :
7916
0
                   ValueType::MatchResult::FALLBACK2;
7917
0
        if (call->isFloat() && func->isFloat())
7918
0
            return ValueType::MatchResult::FALLBACK1;
7919
0
        if (call->isIntegral() && func->isFloat())
7920
0
            return ValueType::MatchResult::FALLBACK2;
7921
0
        if (call->isFloat() && func->isIntegral())
7922
0
            return ValueType::MatchResult::FALLBACK2;
7923
0
        return ValueType::MatchResult::UNKNOWN; // TODO
7924
0
    }
7925
7926
0
    if (call->typeScope != nullptr || func->typeScope != nullptr) {
7927
0
        if (call->typeScope != func->typeScope &&
7928
0
            !(call->typeScope && func->typeScope && call->typeScope->definedType && call->typeScope->definedType->isDerivedFrom(func->typeScope->className)))
7929
0
            return ValueType::MatchResult::NOMATCH;
7930
0
    }
7931
7932
0
    if (call->container != nullptr || func->container != nullptr) {
7933
0
        if (call->container != func->container)
7934
0
            return ValueType::MatchResult::NOMATCH;
7935
0
    }
7936
7937
0
    if (func->typeScope != nullptr && func->container != nullptr) {
7938
0
        if (func->type < ValueType::Type::VOID || func->type == ValueType::Type::UNKNOWN_INT)
7939
0
            return ValueType::MatchResult::UNKNOWN;
7940
0
    }
7941
7942
0
    if (call->isIntegral() && func->isIntegral() && call->sign != ValueType::Sign::UNKNOWN_SIGN && func->sign != ValueType::Sign::UNKNOWN_SIGN && call->sign != func->sign)
7943
0
        return ValueType::MatchResult::FALLBACK1;
7944
7945
0
    if (func->reference != Reference::None && func->constness > call->constness)
7946
0
        return ValueType::MatchResult::FALLBACK1;
7947
7948
0
    return ValueType::MatchResult::SAME;
7949
0
}
7950
7951
ValueType::MatchResult ValueType::matchParameter(const ValueType *call, const Variable *callVar, const Variable *funcVar)
7952
0
{
7953
0
    ValueType vt;
7954
0
    const ValueType* pvt = funcVar->valueType();
7955
0
    if (pvt && funcVar->isArray() && !(funcVar->isStlType() && Token::simpleMatch(funcVar->typeStartToken(), "std :: array"))) { // std::array doesn't decay to a pointer
7956
0
        vt = *pvt;
7957
0
        if (vt.pointer == 0) // don't bump array of pointers
7958
0
            ++vt.pointer;
7959
0
        pvt = &vt;
7960
0
    }
7961
0
    const ValueType::MatchResult res = ValueType::matchParameter(call, pvt);
7962
0
    if (callVar && ((res == ValueType::MatchResult::SAME && call->container) || res == ValueType::MatchResult::UNKNOWN)) {
7963
0
        const std::string type1 = getTypeString(callVar->typeStartToken());
7964
0
        const std::string type2 = getTypeString(funcVar->typeStartToken());
7965
0
        const bool templateVar =
7966
0
            funcVar->scope() && funcVar->scope()->function && funcVar->scope()->function->templateDef;
7967
0
        if (type1 == type2)
7968
0
            return ValueType::MatchResult::SAME;
7969
0
        if (!templateVar && type1.find("auto") == std::string::npos && type2.find("auto") == std::string::npos)
7970
0
            return ValueType::MatchResult::NOMATCH;
7971
0
    }
7972
0
    return res;
7973
0
}