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