/*
 * Cppcheck - A tool for static C/C++ code analysis
 * Copyright (C) 2007-2020 Cppcheck team.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

//---------------------------------------------------------------------------
#include "symboldatabase.h"

#include "astutils.h"
#include "errorlogger.h"
#include "library.h"
#include "mathlib.h"
#include "platform.h"
#include "settings.h"
#include "token.h"
#include "tokenize.h"
#include "tokenlist.h"
#include "utils.h"
#include "valueflow.h"

#include <algorithm>
#include <cassert>
#include <climits>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <unordered_map>
//---------------------------------------------------------------------------

SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
    : mTokenizer(tokenizer), mSettings(settings), mErrorLogger(errorLogger)
{
    if (!tokenizer || !tokenizer->tokens())
        return;

    mIsCpp = isCPP();

    if (mSettings->defaultSign == 's' || mSettings->defaultSign == 'S')
        mDefaultSignedness = ValueType::SIGNED;
    else if (mSettings->defaultSign == 'u' || mSettings->defaultSign == 'U')
        mDefaultSignedness = ValueType::UNSIGNED;
    else
        mDefaultSignedness = ValueType::UNKNOWN_SIGN;

    createSymbolDatabaseFindAllScopes();
    createSymbolDatabaseClassInfo();
    createSymbolDatabaseVariableInfo();
    createSymbolDatabaseCopyAndMoveConstructors();
    createSymbolDatabaseFunctionScopes();
    createSymbolDatabaseClassAndStructScopes();
    createSymbolDatabaseFunctionReturnTypes();
    createSymbolDatabaseNeedInitialization();
    createSymbolDatabaseVariableSymbolTable();
    createSymbolDatabaseSetScopePointers();
    createSymbolDatabaseSetVariablePointers();
    setValueTypeInTokenList(false);
    createSymbolDatabaseSetFunctionPointers(true);
    createSymbolDatabaseSetTypePointers();
    createSymbolDatabaseSetSmartPointerType();
    createSymbolDatabaseEnums();
    createSymbolDatabaseEscapeFunctions();
    createSymbolDatabaseIncompleteVars();
    createSymbolDatabaseExprIds();
}

static const Token* skipScopeIdentifiers(const Token* tok)
{
    if (tok && tok->str() == "::") {
        tok = tok->next();
    }
    while (Token::Match(tok, "%name% ::") ||
           (Token::Match(tok, "%name% <") && Token::simpleMatch(tok->linkAt(1), "> ::"))) {
        if (tok->strAt(1) == "::")
            tok = tok->tokAt(2);
        else
            tok = tok->linkAt(1)->tokAt(2);
    }

    return tok;
}

static bool isExecutableScope(const Token* tok)
{
    if (!Token::simpleMatch(tok, "{"))
        return false;
    const Token * tok2 = tok->link()->previous();
    if (Token::simpleMatch(tok2, "; }"))
        return true;
    if (Token::Match(tok2, "{|} }")) {
        const Token* startTok = tok2->str() == "{" ? tok2 : tok2->link();
        if (Token::Match(startTok->previous(), "do|try|else {"))
            return true;
        if (Token::simpleMatch(startTok->previous(), ") {"))
            return !findLambdaStartToken(tok2);
        if (tok->str() == "{")
            return false;
        else
            return isExecutableScope(startTok);
    }
    return false;
}

void SymbolDatabase::createSymbolDatabaseFindAllScopes()
{
    // create global scope
    scopeList.emplace_back(this, nullptr, nullptr);

    // pointer to current scope
    Scope *scope = &scopeList.back();

    // Store current access in each scope (depends on evaluation progress)
    std::map<const Scope*, AccessControl> access;

    // find all scopes
    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok ? tok->next() : nullptr) {
        // #5593 suggested to add here:
        if (mErrorLogger)
            mErrorLogger->reportProgress(mTokenizer->list.getSourceFilePath(),
                                         "SymbolDatabase",
                                         tok->progressValue());
        // Locate next class
        if ((mTokenizer->isCPP() && tok->isKeyword() &&
             ((Token::Match(tok, "class|struct|union|namespace ::| %name% {|:|::|<") &&
               !Token::Match(tok->previous(), "new|friend|const|enum|typedef|mutable|volatile|using|)|(|<")) ||
              (Token::Match(tok, "enum class| %name% {") ||
               Token::Match(tok, "enum class| %name% : %name% {"))))
            || (mTokenizer->isC() && tok->isKeyword() && Token::Match(tok, "struct|union|enum %name% {"))) {
            const Token *tok2 = tok->tokAt(2);

            if (tok->strAt(1) == "::")
                tok2 = tok2->next();
            else if (mTokenizer->isCPP() && tok->strAt(1) == "class")
                tok2 = tok2->next();

            while (Token::Match(tok2, ":: %name%"))
                tok2 = tok2->tokAt(2);
            while (Token::Match(tok2, "%name% :: %name%"))
                tok2 = tok2->tokAt(2);

            // skip over template args
            while (tok2 && tok2->str() == "<" && tok2->link()) {
                tok2 = tok2->link()->next();
                while (Token::Match(tok2, ":: %name%"))
                    tok2 = tok2->tokAt(2);
            }

            // skip over final
            if (mTokenizer->isCPP() && Token::simpleMatch(tok2, "final"))
                tok2 = tok2->next();

            // make sure we have valid code
            if (!Token::Match(tok2, "{|:")) {
                // check for qualified variable
                if (tok2 && tok2->next()) {
                    if (tok2->next()->str() == ";")
                        tok = tok2->next();
                    else if (Token::simpleMatch(tok2->next(), "= {") &&
                             Token::simpleMatch(tok2->linkAt(2), "} ;"))
                        tok = tok2->linkAt(2)->next();
                    else if (Token::Match(tok2->next(), "(|{") &&
                             tok2->next()->link()->strAt(1) == ";")
                        tok = tok2->next()->link()->next();
                    // skip variable declaration
                    else if (Token::Match(tok2, "*|&|>"))
                        continue;
                    else if (Token::Match(tok2, "%name% (") && mTokenizer->isFunctionHead(tok2->next(), "{;"))
                        continue;
                    else if (Token::Match(tok2, "%name% ["))
                        continue;
                    // skip template
                    else if (Token::simpleMatch(tok2, ";") &&
                             Token::Match(tok->previous(), "template|> class|struct")) {
                        tok = tok2;
                        continue;
                    }
                    // forward declaration
                    else if (Token::simpleMatch(tok2, ";") &&
                             Token::Match(tok, "class|struct|union")) {
                        // TODO: see if it can be used
                        tok = tok2;
                        continue;
                    }
                    // skip constructor
                    else if (Token::simpleMatch(tok2, "(") &&
                             Token::simpleMatch(tok2->link(), ") ;")) {
                        tok = tok2->link()->next();
                        continue;
                    } else
                        throw InternalError(tok2, "SymbolDatabase bailout; unhandled code", InternalError::SYNTAX);
                    continue;
                }
                break; // bail
            }

            const Token * name = tok->next();

            if (name->str() == "class" && name->strAt(-1) == "enum")
                name = name->next();

            Scope *new_scope = findScope(name, scope);

            if (new_scope) {
                // only create base list for classes and structures
                if (new_scope->isClassOrStruct()) {
                    // goto initial '{'
                    if (!new_scope->definedType)
                        mTokenizer->syntaxError(nullptr); // #6808
                    tok2 = new_scope->definedType->initBaseInfo(tok, tok2);
                    // make sure we have valid code
                    if (!tok2) {
                        break;
                    }
                }

                // definition may be different than declaration
                if (mTokenizer->isCPP() && tok->str() == "class") {
                    access[new_scope] = AccessControl::Private;
                    new_scope->type = Scope::eClass;
                } else if (tok->str() == "struct") {
                    access[new_scope] = AccessControl::Public;
                    new_scope->type = Scope::eStruct;
                }

                new_scope->classDef = tok;
                new_scope->bodyStart = tok2;
                new_scope->bodyEnd = tok2->link();
                // make sure we have valid code
                if (!new_scope->bodyEnd) {
                    mTokenizer->syntaxError(tok);
                }
                scope = new_scope;
                tok = tok2;
            } else {
                scopeList.emplace_back(this, tok, scope);
                new_scope = &scopeList.back();

                if (tok->str() == "class")
                    access[new_scope] = AccessControl::Private;
                else if (tok->str() == "struct" || tok->str() == "union")
                    access[new_scope] = AccessControl::Public;

                // fill typeList...
                if (new_scope->isClassOrStructOrUnion() || new_scope->type == Scope::eEnum) {
                    Type* new_type = findType(name, scope);
                    if (!new_type) {
                        typeList.emplace_back(new_scope->classDef, new_scope, scope);
                        new_type = &typeList.back();
                        scope->definedTypesMap[new_type->name()] = new_type;
                    } else
                        new_type->classScope = new_scope;
                    new_scope->definedType = new_type;
                }

                // only create base list for classes and structures
                if (new_scope->isClassOrStruct()) {
                    // goto initial '{'
                    tok2 = new_scope->definedType->initBaseInfo(tok, tok2);

                    // make sure we have valid code
                    if (!tok2) {
                        mTokenizer->syntaxError(tok);
                    }
                } else if (new_scope->type == Scope::eEnum) {
                    if (tok2->str() == ":")
                        tok2 = tok2->tokAt(2);
                }

                new_scope->bodyStart = tok2;
                new_scope->bodyEnd = tok2->link();

                // make sure we have valid code
                if (!new_scope->bodyEnd) {
                    mTokenizer->syntaxError(tok);
                }

                if (new_scope->type == Scope::eEnum) {
                    tok2 = new_scope->addEnum(tok, mTokenizer->isCPP());
                    scope->nestedList.push_back(new_scope);

                    if (!tok2)
                        mTokenizer->syntaxError(tok);
                } else {
                    // make the new scope the current scope
                    scope->nestedList.push_back(new_scope);
                    scope = new_scope;
                }

                tok = tok2;
            }
        }

        // Namespace and unknown macro (#3854)
        else if (mTokenizer->isCPP() && tok->isKeyword() &&
                 Token::Match(tok, "namespace %name% %type% (") &&
                 tok->tokAt(2)->isUpperCaseName() &&
                 Token::simpleMatch(tok->linkAt(3), ") {")) {
            scopeList.emplace_back(this, tok, scope);

            Scope *new_scope = &scopeList.back();
            access[new_scope] = AccessControl::Public;

            const Token *tok2 = tok->linkAt(3)->next();

            new_scope->bodyStart = tok2;
            new_scope->bodyEnd = tok2->link();

            // make sure we have valid code
            if (!new_scope->bodyEnd) {
                scopeList.pop_back();
                break;
            }

            // make the new scope the current scope
            scope->nestedList.push_back(new_scope);
            scope = &scopeList.back();

            tok = tok2;
        }

        // forward declaration
        else if (tok->isKeyword() && Token::Match(tok, "class|struct|union %name% ;") &&
                 tok->strAt(-1) != "friend") {
            if (!findType(tok->next(), scope)) {
                // fill typeList..
                typeList.emplace_back(tok, nullptr, scope);
                Type* new_type = &typeList.back();
                scope->definedTypesMap[new_type->name()] = new_type;
            }
            tok = tok->tokAt(2);
        }

        // using namespace
        else if (mTokenizer->isCPP() && tok->isKeyword() && Token::Match(tok, "using namespace ::| %type% ;|::")) {
            Scope::UsingInfo using_info;

            using_info.start = tok; // save location
            using_info.scope = findNamespace(tok->tokAt(2), scope);

            scope->usingList.push_back(using_info);

            // check for global namespace
            if (tok->strAt(2) == "::")
                tok = tok->tokAt(4);
            else
                tok = tok->tokAt(3);

            // skip over qualification
            while (Token::Match(tok, "%type% ::"))
                tok = tok->tokAt(2);
        }

        // using type alias
        else if (mTokenizer->isCPP() && tok->isKeyword() && Token::Match(tok, "using %name% =")) {
            if (tok->strAt(-1) != ">" && !findType(tok->next(), scope)) {
                // fill typeList..
                typeList.emplace_back(tok, nullptr, scope);
                Type* new_type = &typeList.back();
                scope->definedTypesMap[new_type->name()] = new_type;
            }

            tok = tok->tokAt(3);

            while (tok && tok->str() != ";")
                tok = tok->next();
        }

        // unnamed struct and union
        else if (tok->isKeyword() && Token::Match(tok, "struct|union {") &&
                 Token::Match(tok->next()->link(), "} *|&| %name% ;|[|=")) {
            scopeList.emplace_back(this, tok, scope);

            Scope *new_scope = &scopeList.back();
            access[new_scope] = AccessControl::Public;

            const Token* varNameTok = tok->next()->link()->next();
            if (varNameTok->str() == "*") {
                varNameTok = varNameTok->next();
            } else if (varNameTok->str() == "&") {
                varNameTok = varNameTok->next();
            }

            typeList.emplace_back(tok, new_scope, scope);
            {
                Type* new_type = &typeList.back();
                new_scope->definedType = new_type;
                scope->definedTypesMap[new_type->name()] = new_type;
            }

            scope->addVariable(varNameTok, tok, tok, access[scope], new_scope->definedType, scope, mSettings);

            const Token *tok2 = tok->next();

            new_scope->bodyStart = tok2;
            new_scope->bodyEnd = tok2->link();

            // make sure we have valid code
            if (!new_scope->bodyEnd) {
                scopeList.pop_back();
                break;
            }

            // make the new scope the current scope
            scope->nestedList.push_back(new_scope);
            scope = new_scope;

            tok = tok2;
        }

        // anonymous struct, union and namespace
        else if (tok->isKeyword() && ((Token::Match(tok, "struct|union {") &&
                                       Token::simpleMatch(tok->next()->link(), "} ;")) ||
                                      Token::simpleMatch(tok, "namespace {"))) {
            scopeList.emplace_back(this, tok, scope);

            Scope *new_scope = &scopeList.back();
            access[new_scope] = AccessControl::Public;

            const Token *tok2 = tok->next();

            new_scope->bodyStart = tok2;
            new_scope->bodyEnd = tok2->link();

            typeList.emplace_back(tok, new_scope, scope);
            {
                Type* new_type = &typeList.back();
                new_scope->definedType = new_type;
                scope->definedTypesMap[new_type->name()] = new_type;
            }

            // make sure we have valid code
            if (!new_scope->bodyEnd) {
                scopeList.pop_back();
                break;
            }

            // make the new scope the current scope
            scope->nestedList.push_back(new_scope);
            scope = new_scope;

            tok = tok2;
        }

        // forward declared enum
        else if (tok->isKeyword() && (Token::Match(tok, "enum class| %name% ;") || Token::Match(tok, "enum class| %name% : %name% ;"))) {
            typeList.emplace_back(tok, nullptr, scope);
            Type* new_type = &typeList.back();
            scope->definedTypesMap[new_type->name()] = new_type;
            tok = tok->tokAt(2);
        }

        // check for end of scope
        else if (tok == scope->bodyEnd) {
            access.erase(scope);
            scope = const_cast<Scope*>(scope->nestedIn);
            continue;
        }

        // check if in class or structure or union
        else if (scope->isClassOrStructOrUnion()) {
            const Token *funcStart = nullptr;
            const Token *argStart = nullptr;
            const Token *declEnd = nullptr;

            // What section are we in..
            if (tok->str() == "private:")
                access[scope] = AccessControl::Private;
            else if (tok->str() == "protected:")
                access[scope] = AccessControl::Protected;
            else if (tok->str() == "public:" || tok->str() == "__published:")
                access[scope] = AccessControl::Public;
            else if (Token::Match(tok, "public|protected|private %name% :")) {
                if (tok->str() == "private")
                    access[scope] = AccessControl::Private;
                else if (tok->str() == "protected")
                    access[scope] = AccessControl::Protected;
                else
                    access[scope] = AccessControl::Public;

                tok = tok->tokAt(2);
            }

            // class function?
            else if (isFunction(tok, scope, &funcStart, &argStart, &declEnd)) {
                if (tok->previous()->str() != "::" || tok->strAt(-2) == scope->className) {
                    Function function(mTokenizer, tok, scope, funcStart, argStart);

                    // save the access type
                    function.access = access[scope];

                    const Token *end = function.argDef->link();

                    // count the number of constructors
                    if (function.isConstructor())
                        scope->numConstructors++;

                    // assume implementation is inline (definition and implementation same)
                    function.token = function.tokenDef;
                    function.arg = function.argDef;

                    // out of line function
                    if (const Token *endTok = mTokenizer->isFunctionHead(end, ";")) {
                        tok = endTok;
                        scope->addFunction(function);
                    }

                    // inline function
                    else {
                        // find start of function '{'
                        bool foundInitList = false;
                        while (end && end->str() != "{" && end->str() != ";") {
                            if (end->link() && Token::Match(end, "(|<")) {
                                end = end->link();
                            } else if (foundInitList &&
                                       Token::Match(end, "%name%|> {") &&
                                       Token::Match(end->linkAt(1), "} ,|{")) {
                                end = end->linkAt(1);
                            } else {
                                if (end->str() == ":")
                                    foundInitList = true;
                                end = end->next();
                            }
                        }

                        if (!end || end->str() == ";")
                            continue;

                        scope->addFunction(function);

                        Function* funcptr = &scope->functionList.back();
                        const Token *tok2 = funcStart;

                        addNewFunction(&scope, &tok2);
                        if (scope) {
                            scope->functionOf = function.nestedIn;
                            scope->function = funcptr;
                            scope->function->functionScope = scope;
                        }

                        tok = tok2;
                    }
                }

                // nested class or friend function?
                else {
                    /** @todo check entire qualification for match */
                    const Scope * const nested = scope->findInNestedListRecursive(tok->strAt(-2));

                    if (nested)
                        addClassFunction(&scope, &tok, argStart);
                    else {
                        /** @todo handle friend functions */
                    }
                }
            }

            // friend class declaration?
            else if (mTokenizer->isCPP() && tok->isKeyword() && Token::Match(tok, "friend class| ::| %any% ;|::")) {
                Type::FriendInfo friendInfo;

                // save the name start
                friendInfo.nameStart = tok->strAt(1) == "class" ? tok->tokAt(2) : tok->next();
                friendInfo.nameEnd = friendInfo.nameStart;

                // skip leading "::"
                if (friendInfo.nameEnd->str() == "::")
                    friendInfo.nameEnd = friendInfo.nameEnd->next();

                // skip qualification "name ::"
                while (friendInfo.nameEnd && friendInfo.nameEnd->strAt(1) == "::")
                    friendInfo.nameEnd = friendInfo.nameEnd->tokAt(2);

                // fill this in after parsing is complete
                friendInfo.type = nullptr;

                if (!scope->definedType)
                    mTokenizer->syntaxError(tok);

                scope->definedType->friendList.push_back(friendInfo);
            }
        } else if (scope->type == Scope::eNamespace || scope->type == Scope::eGlobal) {
            const Token *funcStart = nullptr;
            const Token *argStart = nullptr;
            const Token *declEnd = nullptr;

            // function?
            if (isFunction(tok, scope, &funcStart, &argStart, &declEnd)) {
                // has body?
                if (declEnd && declEnd->str() == "{") {
                    tok = funcStart;

                    // class function
                    if (tok->previous() && tok->previous()->str() == "::")
                        addClassFunction(&scope, &tok, argStart);

                    // class destructor
                    else if (tok->previous() &&
                             tok->previous()->str() == "~" &&
                             tok->strAt(-2) == "::")
                        addClassFunction(&scope, &tok, argStart);

                    // regular function
                    else {
                        const Function* const function = addGlobalFunction(scope, tok, argStart, funcStart);

                        if (!function)
                            mTokenizer->syntaxError(tok);
                    }

                    // syntax error?
                    if (!scope)
                        mTokenizer->syntaxError(tok);
                }
                // function prototype?
                else if (declEnd && declEnd->str() == ";") {
                    if (tok->previous() && tok->previous()->str() == "::" &&
                        Token::Match(declEnd->previous(), "default|delete")) {
                        addClassFunction(&scope, &tok, argStart);
                        continue;
                    }

                    bool newFunc = true; // Is this function already in the database?
                    for (std::multimap<std::string, const Function *>::const_iterator i = scope->functionMap.find(tok->str()); i != scope->functionMap.end() && i->first == tok->str(); ++i) {
                        if (Function::argsMatch(scope, i->second->argDef, argStart, emptyString, 0)) {
                            newFunc = false;
                            break;
                        }
                    }

                    // save function prototype in database
                    if (newFunc) {
                        addGlobalFunctionDecl(scope, tok, argStart, funcStart);
                    }

                    tok = declEnd;
                    continue;
                }
            }
        } else if (scope->isExecutable()) {
            if (tok->isKeyword() && Token::Match(tok, "else|try|do {")) {
                const Token* tok1 = tok->next();
                if (tok->str() == "else")
                    scopeList.emplace_back(this, tok, scope, Scope::eElse, tok1);
                else if (tok->str() == "do")
                    scopeList.emplace_back(this, tok, scope, Scope::eDo, tok1);
                else //if (tok->str() == "try")
                    scopeList.emplace_back(this, tok, scope, Scope::eTry, tok1);

                tok = tok1;
                scope->nestedList.push_back(&scopeList.back());
                scope = &scopeList.back();
            } else if (tok->isKeyword() && Token::Match(tok, "if|for|while|catch|switch (") && Token::simpleMatch(tok->next()->link(), ") {")) {
                const Token *scopeStartTok = tok->next()->link()->next();
                if (tok->str() == "if")
                    scopeList.emplace_back(this, tok, scope, Scope::eIf, scopeStartTok);
                else if (tok->str() == "for") {
                    scopeList.emplace_back(this, tok, scope, Scope::eFor, scopeStartTok);
                } else if (tok->str() == "while")
                    scopeList.emplace_back(this, tok, scope, Scope::eWhile, scopeStartTok);
                else if (tok->str() == "catch") {
                    scopeList.emplace_back(this, tok, scope, Scope::eCatch, scopeStartTok);
                } else // if (tok->str() == "switch")
                    scopeList.emplace_back(this, tok, scope, Scope::eSwitch, scopeStartTok);

                scope->nestedList.push_back(&scopeList.back());
                scope = &scopeList.back();
                if (scope->type == Scope::eFor)
                    scope->checkVariable(tok->tokAt(2), AccessControl::Local, mSettings); // check for variable declaration and add it to new scope if found
                else if (scope->type == Scope::eCatch)
                    scope->checkVariable(tok->tokAt(2), AccessControl::Throw, mSettings); // check for variable declaration and add it to new scope if found
                tok = scopeStartTok;
            } else if (Token::Match(tok, "%var% {")) {
                tok = tok->linkAt(1);
            } else if (const Token *lambdaEndToken = findLambdaEndToken(tok)) {
                const Token *lambdaStartToken = lambdaEndToken->link();
                const Token * argStart = lambdaStartToken->astParent();
                const Token * funcStart = Token::simpleMatch(argStart, "[") ? argStart : argStart->astParent();
                const Function * function = addGlobalFunction(scope, tok, argStart, funcStart);
                if (!function)
                    mTokenizer->syntaxError(tok);
                tok = lambdaStartToken;
            } else if (tok->str() == "{") {
                if (isExecutableScope(tok)) {
                    scopeList.emplace_back(this, tok, scope, Scope::eUnconditional, tok);
                    scope->nestedList.push_back(&scopeList.back());
                    scope = &scopeList.back();
                } else {
                    tok = tok->link();
                }
            }
            // syntax error?
            if (!scope)
                mTokenizer->syntaxError(tok);
        }
    }
}

void SymbolDatabase::createSymbolDatabaseClassInfo()
{
    if (mTokenizer->isC())
        return;

    // fill in using info
    for (Scope& scope : scopeList) {
        for (Scope::UsingInfo& usingInfo : scope.usingList) {
            // only find if not already found
            if (usingInfo.scope == nullptr) {
                // check scope for match
                const Scope * const found = findScope(usingInfo.start->tokAt(2), &scope);
                if (found) {
                    // set found scope
                    usingInfo.scope = found;
                    break;
                }
            }
        }
    }

    // fill in base class info
    for (Type& type : typeList) {
        // finish filling in base class info
        for (Type::BaseInfo & i : type.derivedFrom) {
            const Type* found = findType(i.nameTok, type.enclosingScope);
            if (found && found->findDependency(&type)) {
                // circular dependency
                //mTokenizer->syntaxError(nullptr);
            } else {
                i.type = found;
            }
        }
    }

    // fill in friend info
    for (Type & type : typeList) {
        for (Type::FriendInfo &friendInfo : type.friendList) {
            friendInfo.type = findType(friendInfo.nameStart, type.enclosingScope);
        }
    }
}


void SymbolDatabase::createSymbolDatabaseVariableInfo()
{
    // fill in variable info
    for (Scope& scope : scopeList) {
        // find variables
        scope.getVariableList(mSettings);
    }

    // fill in function arguments
    for (Scope& scope : scopeList) {
        std::list<Function>::iterator func;

        for (func = scope.functionList.begin(); func != scope.functionList.end(); ++func) {
            // add arguments
            func->addArguments(this, &scope);
        }
    }
}

void SymbolDatabase::createSymbolDatabaseCopyAndMoveConstructors()
{
    // fill in class and struct copy/move constructors
    for (Scope& scope : scopeList) {
        if (!scope.isClassOrStruct())
            continue;

        std::list<Function>::iterator func;
        for (func = scope.functionList.begin(); func != scope.functionList.end(); ++func) {
            if (!func->isConstructor() || func->minArgCount() != 1)
                continue;

            const Variable* firstArg = func->getArgumentVar(0);
            if (firstArg->type() == scope.definedType) {
                if (firstArg->isRValueReference())
                    func->type = Function::eMoveConstructor;
                else if (firstArg->isReference() && !firstArg->isPointer())
                    func->type = Function::eCopyConstructor;
            }

            if (func->type == Function::eCopyConstructor ||
                func->type == Function::eMoveConstructor)
                scope.numCopyOrMoveConstructors++;
        }
    }
}

void SymbolDatabase::createSymbolDatabaseFunctionScopes()
{
    // fill in function scopes
    for (Scope & scope : scopeList) {
        if (scope.type == Scope::eFunction)
            functionScopes.push_back(&scope);
    }
}

void SymbolDatabase::createSymbolDatabaseClassAndStructScopes()
{
    // fill in class and struct scopes
    for (Scope& scope : scopeList) {
        if (scope.isClassOrStruct())
            classAndStructScopes.push_back(&scope);
    }
}

void SymbolDatabase::createSymbolDatabaseFunctionReturnTypes()
{
    // fill in function return types
    for (Scope& scope : scopeList) {
        std::list<Function>::iterator func;

        for (func = scope.functionList.begin(); func != scope.functionList.end(); ++func) {
            // add return types
            if (func->retDef) {
                const Token *type = func->retDef;
                while (Token::Match(type, "static|const|struct|union|enum"))
                    type = type->next();
                if (type) {
                    func->retType = findVariableTypeInBase(&scope, type);
                    if (!func->retType)
                        func->retType = findTypeInNested(type, func->nestedIn);
                }
            }
        }
    }
}

void SymbolDatabase::createSymbolDatabaseNeedInitialization()
{
    if (mTokenizer->isC()) {
        // For C code it is easy, as there are no constructors and no default values
        for (Scope& scope : scopeList) {
            if (scope.definedType)
                scope.definedType->needInitialization = Type::NeedInitialization::True;
        }
    } else {
        // For C++, it is more difficult: Determine if user defined type needs initialization...
        unsigned int unknowns = 0; // stop checking when there are no unknowns
        unsigned int retry = 0;    // bail if we don't resolve all the variable types for some reason

        do {
            unknowns = 0;

            for (Scope& scope : scopeList) {
                if (!scope.definedType) {
                    mBlankTypes.emplace_back();
                    scope.definedType = &mBlankTypes.back();
                }

                if (scope.isClassOrStruct() && scope.definedType->needInitialization == Type::NeedInitialization::Unknown) {
                    // check for default constructor
                    bool hasDefaultConstructor = false;

                    std::list<Function>::const_iterator func;

                    for (func = scope.functionList.begin(); func != scope.functionList.end(); ++func) {
                        if (func->type == Function::eConstructor) {
                            // check for no arguments: func ( )
                            if (func->argCount() == 0) {
                                hasDefaultConstructor = true;
                                break;
                            }

                            /** check for arguments with default values */
                            else if (func->argCount() == func->initializedArgCount()) {
                                hasDefaultConstructor = true;
                                break;
                            }
                        }
                    }

                    // User defined types with user defined default constructor doesn't need initialization.
                    // We assume the default constructor initializes everything.
                    // Another check will figure out if the constructor actually initializes everything.
                    if (hasDefaultConstructor)
                        scope.definedType->needInitialization = Type::NeedInitialization::False;

                    // check each member variable to see if it needs initialization
                    else {
                        bool needInitialization = false;
                        bool unknown = false;

                        std::list<Variable>::const_iterator var;
                        for (var = scope.varlist.begin(); var != scope.varlist.end() && !needInitialization; ++var) {
                            if (var->isClass()) {
                                if (var->type()) {
                                    // does this type need initialization?
                                    if (var->type()->needInitialization == Type::NeedInitialization::True)
                                        needInitialization = true;
                                    else if (var->type()->needInitialization == Type::NeedInitialization::Unknown) {
                                        if (!(var->valueType() && var->valueType()->type == ValueType::CONTAINER))
                                            unknown = true;
                                    }
                                }
                            } else if (!var->hasDefault())
                                needInitialization = true;
                        }

                        if (needInitialization)
                            scope.definedType->needInitialization = Type::NeedInitialization::True;
                        else if (!unknown)
                            scope.definedType->needInitialization = Type::NeedInitialization::False;
                        else {
                            if (scope.definedType->needInitialization == Type::NeedInitialization::Unknown)
                                unknowns++;
                        }
                    }
                } else if (scope.type == Scope::eUnion && scope.definedType->needInitialization == Type::NeedInitialization::Unknown)
                    scope.definedType->needInitialization = Type::NeedInitialization::True;
            }

            retry++;
        } while (unknowns && retry < 100);

        // this shouldn't happen so output a debug warning
        if (retry == 100 && mSettings->debugwarnings) {
            for (const Scope& scope : scopeList) {
                if (scope.isClassOrStruct() && scope.definedType->needInitialization == Type::NeedInitialization::Unknown)
                    debugMessage(scope.classDef, "SymbolDatabase::SymbolDatabase couldn't resolve all user defined types.");
            }
        }
    }
}

void SymbolDatabase::createSymbolDatabaseVariableSymbolTable()
{
    // create variable symbol table
    mVariableList.resize(mTokenizer->varIdCount() + 1);
    std::fill_n(mVariableList.begin(), mVariableList.size(), (const Variable*)nullptr);

    // check all scopes for variables
    for (Scope& scope : scopeList) {
        // add all variables
        for (std::list<Variable>::iterator var = scope.varlist.begin(); var != scope.varlist.end(); ++var) {
            const unsigned int varId = var->declarationId();
            if (varId)
                mVariableList[varId] = &(*var);
            // fix up variables without type
            if (!var->type() && !var->typeStartToken()->isStandardType()) {
                const Type *type = findType(var->typeStartToken(), &scope);
                if (type)
                    var->type(type);
            }
        }

        // add all function parameters
        for (Function& func : scope.functionList) {
            for (std::list<Variable>::iterator arg = func.argumentList.begin(); arg != func.argumentList.end(); ++arg) {
                // check for named parameters
                if (arg->nameToken() && arg->declarationId()) {
                    const unsigned int declarationId = arg->declarationId();
                    if (declarationId > 0U)
                        mVariableList[declarationId] = &(*arg);
                    // fix up parameters without type
                    if (!arg->type() && !arg->typeStartToken()->isStandardType()) {
                        const Type *type = findTypeInNested(arg->typeStartToken(), &scope);
                        if (type)
                            arg->type(type);
                    }
                }
            }
        }
    }

    // fill in missing variables if possible
    const std::size_t functions = functionScopes.size();
    for (std::size_t i = 0; i < functions; ++i) {
        const Scope *func = functionScopes[i];
        for (const Token *tok = func->bodyStart->next(); tok && tok != func->bodyEnd; tok = tok->next()) {
            // check for member variable
            if (tok->varId() && tok->next() &&
                (tok->next()->str() == "." ||
                 (tok->next()->str() == "[" && tok->linkAt(1)->strAt(1) == "."))) {
                const Token *tok1 = tok->next()->str() == "." ? tok->tokAt(2) : tok->linkAt(1)->tokAt(2);
                if (tok1 && tok1->varId() && mVariableList[tok1->varId()] == nullptr) {
                    const Variable *var = mVariableList[tok->varId()];
                    if (var && var->typeScope()) {
                        // find the member variable of this variable
                        const Variable *var1 = var->typeScope()->getVariable(tok1->str());
                        if (var1) {
                            // add this variable to the look up table
                            mVariableList[tok1->varId()] = var1;
                        }
                    }
                }
            }
        }
    }
}

void SymbolDatabase::createSymbolDatabaseSetScopePointers()
{
    // Set scope pointers
    for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) {
        Token* start = const_cast<Token*>(it->bodyStart);
        Token* end = const_cast<Token*>(it->bodyEnd);
        if (it->type == Scope::eGlobal) {
            start = const_cast<Token*>(mTokenizer->list.front());
            end = const_cast<Token*>(mTokenizer->list.back());
        }
        assert(start);
        assert(end);

        end->scope(&*it);

        for (Token* tok = start; tok != end; tok = tok->next()) {
            if (start != end && tok->str() == "{") {
                bool isEndOfScope = false;
                for (std::list<Scope*>::const_iterator innerScope = it->nestedList.begin(); innerScope != it->nestedList.end(); ++innerScope) {
                    if (tok == (*innerScope)->bodyStart) { // Is begin of inner scope
                        tok = tok->link();
                        if (tok->next() == end || !tok->next()) {
                            isEndOfScope = true;
                            break;
                        }
                        tok = tok->next();
                        break;
                    }
                }
                if (isEndOfScope)
                    break;
            }
            tok->scope(&*it);
        }
    }
}

void SymbolDatabase::createSymbolDatabaseSetFunctionPointers(bool firstPass)
{
    if (firstPass) {
        // Set function definition and declaration pointers
        for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) {
            for (std::list<Function>::const_iterator func = it->functionList.begin(); func != it->functionList.end(); ++func) {
                if (func->tokenDef)
                    const_cast<Token *>(func->tokenDef)->function(&*func);

                if (func->token)
                    const_cast<Token *>(func->token)->function(&*func);
            }
        }
    }

    // Set function call pointers
    for (const Token* tok = mTokenizer->list.front(); tok != mTokenizer->list.back(); tok = tok->next()) {
        if (tok->isName() && !tok->function() && tok->varId() == 0 && Token::Match(tok, "%name% [(,)>]") && !isReservedName(tok->str())) {
            if (tok->next()->str() == ">" && !tok->next()->link())
                continue;

            if (tok->next()->str() != "(") {
                const Token *start = tok;
                while (Token::Match(start->tokAt(-2), "%name% ::"))
                    start = start->tokAt(-2);
                if (!Token::Match(start->previous(), "[(,<]") && !Token::Match(start->tokAt(-2), "[(,<] &"))
                    continue;
            }

            const Function *function = findFunction(tok);
            if (!function)
                continue;

            const_cast<Token *>(tok)->function(function);

            if (tok->next()->str() != "(")
                const_cast<Function *>(function)->functionPointerUsage = tok;
        }
    }

    // Set C++ 11 delegate constructor function call pointers
    for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) {
        for (std::list<Function>::const_iterator func = it->functionList.begin(); func != it->functionList.end(); ++func) {
            // look for initializer list
            if (func->isConstructor() && func->functionScope && func->functionScope->functionOf && func->arg) {
                const Token * tok = func->arg->link()->next();
                if (tok->str() == "noexcept") {
                    const Token * closingParenTok = tok->linkAt(1);
                    if (!closingParenTok || !closingParenTok->next()) {
                        continue;
                    }
                    tok = closingParenTok->next();
                }
                if (tok->str() != ":") {
                    continue;
                }
                tok = tok->next();
                while (tok && tok != func->functionScope->bodyStart) {
                    if (Token::Match(tok, "%name% {|(")) {
                        if (tok->str() == func->tokenDef->str()) {
                            const Function *function = func->functionScope->functionOf->findFunction(tok);
                            if (function)
                                const_cast<Token *>(tok)->function(function);
                            break;
                        }
                        tok = tok->linkAt(1);
                    }
                    tok = tok->next();
                }
            }
        }
    }
}

void SymbolDatabase::createSymbolDatabaseSetTypePointers()
{
    std::set<std::string> typenames;
    for (const Type &t : typeList) {
        typenames.insert(t.name());
    }

    // Set type pointers
    for (const Token* tok = mTokenizer->list.front(); tok != mTokenizer->list.back(); tok = tok->next()) {
        if (!tok->isName() || tok->varId() || tok->function() || tok->type() || tok->enumerator())
            continue;

        if (typenames.find(tok->str()) == typenames.end())
            continue;

        const Type *type = findVariableType(tok->scope(), tok);
        if (type)
            const_cast<Token *>(tok)->type(type);
    }
}

void SymbolDatabase::createSymbolDatabaseSetSmartPointerType()
{
    for (Scope &scope: scopeList) {
        for (Variable &var: scope.varlist) {
            if (var.valueType() && var.valueType()->smartPointerTypeToken && !var.valueType()->smartPointerType) {
                ValueType vt(*var.valueType());
                vt.smartPointerType = vt.smartPointerTypeToken->type();
                var.setValueType(vt);
            }
        }
    }
}

void SymbolDatabase::fixVarId(VarIdMap & varIds, const Token * vartok, Token * membertok, const Variable * membervar)
{
    VarIdMap::iterator varId = varIds.find(vartok->varId());
    if (varId == varIds.end()) {
        MemberIdMap memberId;
        if (membertok->varId() == 0) {
            memberId[membervar->nameToken()->varId()] = const_cast<Tokenizer *>(mTokenizer)->newVarId();
            mVariableList.push_back(membervar);
        } else
            mVariableList[membertok->varId()] = membervar;
        varIds.insert(std::make_pair(vartok->varId(), memberId));
        varId = varIds.find(vartok->varId());
    }
    MemberIdMap::iterator memberId = varId->second.find(membervar->nameToken()->varId());
    if (memberId == varId->second.end()) {
        if (membertok->varId() == 0) {
            varId->second.insert(std::make_pair(membervar->nameToken()->varId(), const_cast<Tokenizer *>(mTokenizer)->newVarId()));
            mVariableList.push_back(membervar);
            memberId = varId->second.find(membervar->nameToken()->varId());
        } else
            mVariableList[membertok->varId()] = membervar;
    }
    if (membertok->varId() == 0)
        membertok->varId(memberId->second);
}

void SymbolDatabase::createSymbolDatabaseSetVariablePointers()
{
    VarIdMap varIds;

    // Set variable pointers
    for (const Token* tok = mTokenizer->list.front(); tok != mTokenizer->list.back(); tok = tok->next()) {
        if (tok->varId())
            const_cast<Token *>(tok)->variable(getVariableFromVarId(tok->varId()));

        // Set Token::variable pointer for array member variable
        // Since it doesn't point at a fixed location it doesn't have varid
        if (tok->variable() != nullptr &&
            (tok->variable()->typeScope() || tok->variable()->isSmartPointer() || (tok->valueType() && tok->valueType()->type == ValueType::CONTAINER)) &&
            Token::Match(tok, "%name% [|.")) {

            Token *tok2 = tok->next();
            // Locate "]"
            while (tok2 && tok2->str() == "[")
                tok2 = tok2->link()->next();

            Token *membertok = nullptr;
            if (Token::Match(tok2, ". %name%"))
                membertok = tok2->next();
            else if (Token::Match(tok2, ") . %name%") && tok->strAt(-1) == "(")
                membertok = tok2->tokAt(2);

            if (membertok) {
                const Variable *var = tok->variable();
                if (var->typeScope()) {
                    const Variable *membervar = var->typeScope()->getVariable(membertok->str());
                    if (membervar) {
                        membertok->variable(membervar);
                        if (membertok->varId() == 0 || mVariableList[membertok->varId()] == nullptr)
                            fixVarId(varIds, tok, const_cast<Token *>(membertok), membervar);
                    }
                } else if (const ::Type *type = var->smartPointerType()) {
                    const Scope *classScope = type->classScope;
                    const Variable *membervar = classScope ? classScope->getVariable(membertok->str()) : nullptr;
                    if (membervar) {
                        membertok->variable(membervar);
                        if (membertok->varId() == 0 || mVariableList[membertok->varId()] == nullptr)
                            fixVarId(varIds, tok, const_cast<Token *>(membertok), membervar);
                    }
                } else if (tok->valueType() && tok->valueType()->type == ValueType::CONTAINER) {
                    if (Token::Match(var->typeStartToken(), "std :: %type% < %type% *| *| >")) {
                        const Type * type2 = var->typeStartToken()->tokAt(4)->type();
                        if (type2 && type2->classScope && type2->classScope->definedType) {
                            const Variable *membervar = type2->classScope->getVariable(membertok->str());
                            if (membervar) {
                                membertok->variable(membervar);
                                if (membertok->varId() == 0 || mVariableList[membertok->varId()] == nullptr)
                                    fixVarId(varIds, tok, const_cast<Token *>(membertok), membervar);
                            }
                        }
                    }
                }
            }
        }

        // check for function returning record type
        // func(...).var
        // func(...)[...].var
        else if (tok->function() && tok->next()->str() == "(" &&
                 (Token::Match(tok->next()->link(), ") . %name% !!(") ||
                  (Token::Match(tok->next()->link(), ") [") && Token::Match(tok->next()->link()->next()->link(), "] . %name% !!(")))) {
            const Type *type = tok->function()->retType;
            if (type) {
                Token *membertok;
                if (tok->next()->link()->next()->str() == ".")
                    membertok = tok->next()->link()->next()->next();
                else
                    membertok = tok->next()->link()->next()->link()->next()->next();
                const Variable *membervar = membertok->variable();
                if (!membervar) {
                    if (type->classScope) {
                        membervar = type->classScope->getVariable(membertok->str());
                        if (membervar) {
                            membertok->variable(membervar);
                            if (membertok->varId() == 0 || mVariableList[membertok->varId()] == nullptr) {
                                if (tok->function()->retDef)
                                    fixVarId(varIds, tok->function()->retDef, const_cast<Token *>(membertok), membervar);
                            }
                        }
                    }
                }
            }
        }
    }
}

void SymbolDatabase::createSymbolDatabaseEnums()
{
    // fill in enumerators in enum
    for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) {
        if (it->type != Scope::eEnum)
            continue;

        // add enumerators to enumerator tokens
        for (Enumerator & i : it->enumeratorList)
            const_cast<Token *>(i.name)->enumerator(&i);
    }

    for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) {
        if (it->type != Scope::eEnum)
            continue;

        for (Enumerator & enumerator : it->enumeratorList) {
            // look for initialization tokens that can be converted to enumerators and convert them
            if (enumerator.start) {
                if (!enumerator.end)
                    mTokenizer->syntaxError(enumerator.start);
                for (const Token * tok3 = enumerator.start; tok3 && tok3 != enumerator.end->next(); tok3 = tok3->next()) {
                    if (tok3->tokType() == Token::eName) {
                        const Enumerator * e = findEnumerator(tok3);
                        if (e)
                            const_cast<Token *>(tok3)->enumerator(e);
                    }
                }
            }
        }
    }

    // find enumerators
    for (const Token* tok = mTokenizer->list.front(); tok != mTokenizer->list.back(); tok = tok->next()) {
        if (tok->tokType() != Token::eName)
            continue;
        const Enumerator * enumerator = findEnumerator(tok);
        if (enumerator)
            const_cast<Token *>(tok)->enumerator(enumerator);
    }
}

void SymbolDatabase::createSymbolDatabaseIncompleteVars()
{
    const std::set<std::string> cpp20keywords = {
        "alignas",
        "alignof",
        "axiom",
        "co_await",
        "co_return",
        "co_yield",
        "concept",
        "synchronized",
        "consteval",
        "reflexpr",
        "requires",
    };
    const std::set<std::string> cppkeywords = {
        "asm",
        "auto",
        "catch",
        "char",
        "class",
        "const",
        "constexpr",
        "decltype",
        "default",
        "do",
        "enum",
        "explicit",
        "export",
        "extern",
        "final",
        "friend",
        "inline",
        "mutable",
        "namespace",
        "new",
        "noexcept",
        "nullptr",
        "override",
        "private",
        "protected",
        "public",
        "register",
        "sizeof",
        "static",
        "static_assert",
        "struct",
        "template",
        "this",
        "thread_local",
        "throw",
        "try",
        "typedef",
        "typeid",
        "typename",
        "union",
        "using",
        "virtual",
        "void",
        "volatile",
        "NULL",
    };
    for (const Token* tok = mTokenizer->list.front(); tok != mTokenizer->list.back(); tok = tok->next()) {
        const Scope * scope = tok->scope();
        if (!scope)
            continue;
        if (!scope->isExecutable())
            continue;
        if (!Token::Match(tok, "%name%"))
            continue;
        if (!tok->isNameOnly())
            continue;
        if (Token::Match(tok, "%var%"))
            continue;
        if (tok->type())
            continue;
        if (Token::Match(tok->next(), "::|.|(|:|%var%"))
            continue;
        if (Token::Match(tok->next(), "&|&&|* )|%var%"))
            continue;
        if (Token::simpleMatch(tok->next(), ")") && Token::simpleMatch(tok->next()->link()->previous(), "catch ("))
            continue;
        // Very likely a typelist
        if (Token::Match(tok->tokAt(-2), "%type% ,"))
            continue;
        // Inside template brackets
        if (Token::Match(tok->next(), "<|>") && tok->next()->link())
            continue;
        if (Token::simpleMatch(tok->previous(), "<") && tok->previous()->link())
            continue;
        // Skip goto labels
        if (Token::simpleMatch(tok->previous(), "goto"))
            continue;
        if (cppkeywords.count(tok->str()) > 0)
            continue;
        if (mSettings->standards.cpp >= Standards::CPP20 && cpp20keywords.count(tok->str()) > 0)
            continue;
        const_cast<Token *>(tok)->isIncompleteVar(true);
    }
}

void SymbolDatabase::createSymbolDatabaseEscapeFunctions()
{
    for (Scope & scope : scopeList) {
        if (scope.type != Scope::eFunction)
            continue;
        Function * function = scope.function;
        if (!function)
            continue;
        function->isEscapeFunction(isReturnScope(scope.bodyEnd, &mSettings->library, nullptr, true));
    }
}

void SymbolDatabase::createSymbolDatabaseExprIds()
{
    MathLib::bigint base = 0;
    // Find highest varId
    for (const Variable *var : mVariableList) {
        if (!var)
            continue;
        base = std::max<MathLib::bigint>(base, var->declarationId());
    }
    MathLib::bigint id = base+1;
    for (const Scope * scope : functionScopes) {
        std::unordered_map<std::string, std::vector<Token*>> exprs;

        // Assign IDs
        for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
            if (tok->varId() > 0) {
                tok->exprId(tok->varId());
            } else if (Token::Match(tok, "(|.|%cop%")) {
                exprs[tok->str()].push_back(tok);
                tok->exprId(id++);
            }
        }

        // Apply CSE
        for (const auto& p:exprs) {
            const std::vector<Token*>& tokens = p.second;
            for (Token* tok1:tokens) {
                for (Token* tok2:tokens) {
                    if (tok1 == tok2)
                        continue;
                    if (tok1->exprId() == tok2->exprId())
                        continue;
                    if (!isSameExpression(isCPP(), true, tok1, tok2, mSettings->library, true, false))
                        continue;
                    MathLib::bigint cid = std::min(tok1->exprId(), tok2->exprId());
                    tok1->exprId(cid);
                    tok2->exprId(cid);
                }
            }
        }
    }
}

void SymbolDatabase::setArrayDimensionsUsingValueFlow()
{
    // set all unknown array dimensions
    for (const Variable *var : mVariableList) {
        // check each array variable
        if (!var || !var->isArray())
            continue;
        // check each array dimension
        for (const Dimension &const_dimension : var->dimensions()) {
            Dimension &dimension = const_cast<Dimension &>(const_dimension);
            if (dimension.num != 0 || !dimension.tok)
                continue;

            if (Token::Match(dimension.tok->previous(), "[<,]")) {
                if (dimension.known)
                    continue;
                if (!Token::Match(dimension.tok->previous(), "[<,]"))
                    continue;

                // In template arguments, there might not be AST
                // Determine size by using the "raw tokens"
                TokenList tokenList(mSettings);
                tokenList.addtoken(";", 0, 0, false);
                bool fail = false;
                for (const Token *tok = dimension.tok; tok && !Token::Match(tok, "[,>]"); tok = tok->next()) {
                    if (!tok->isName())
                        tokenList.addtoken(tok->str(), 0, 0, false);

                    else if (tok->hasKnownIntValue())
                        tokenList.addtoken(std::to_string(tok->getKnownIntValue()), 0, 0, false);

                    else {
                        fail = true;
                        break;
                    }
                }

                if (fail)
                    continue;

                tokenList.addtoken(";", 0, 0, false);

                for (Token *tok = tokenList.front(); tok;) {
                    if (TemplateSimplifier::simplifyNumericCalculations(tok, false))
                        tok = tokenList.front();
                    else
                        tok = tok->next();
                }

                if (Token::Match(tokenList.front(), "; %num% ;")) {
                    dimension.known = true;
                    dimension.num = MathLib::toLongNumber(tokenList.front()->next()->str());
                }

                continue;
            }

            // Normal array [..dimension..]
            dimension.known = false;

            // check for a single token dimension
            if (dimension.tok->hasKnownIntValue()) {
                dimension.known = true;
                dimension.num = dimension.tok->getKnownIntValue();
                continue;
            }

            else if (dimension.tok->valueType() && dimension.tok->valueType()->pointer == 0) {
                int bits = 0;
                switch (dimension.tok->valueType()->type) {
                case ValueType::Type::CHAR:
                    bits = mSettings->char_bit;
                    break;
                case ValueType::Type::SHORT:
                    bits = mSettings->short_bit;
                    break;
                case ValueType::Type::INT:
                    bits = mSettings->int_bit;
                    break;
                case ValueType::Type::LONG:
                    bits = mSettings->long_bit;
                    break;
                case ValueType::Type::LONGLONG:
                    bits = mSettings->long_long_bit;
                    break;
                default:
                    break;
                }

                if (bits > 0 && bits <= 62) {
                    if (dimension.tok->valueType()->sign == ValueType::Sign::UNSIGNED)
                        dimension.num = 1LL << bits;
                    else
                        dimension.num = 1LL << (bits - 1);
                }
            }
        }
    }
}

SymbolDatabase::~SymbolDatabase()
{
    // Clear scope, type, function and variable pointers
    for (const Token* tok = mTokenizer->list.front(); tok; tok = tok->next()) {
        const_cast<Token *>(tok)->scope(nullptr);
        const_cast<Token *>(tok)->type(nullptr);
        const_cast<Token *>(tok)->function(nullptr);
        const_cast<Token *>(tok)->variable(nullptr);
        const_cast<Token *>(tok)->enumerator(nullptr);
        const_cast<Token *>(tok)->setValueType(nullptr);
    }
}

bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const Token **funcStart, const Token **argStart, const Token** declEnd) const
{
    if (tok->varId())
        return false;

    // function returning function pointer? '... ( ... %name% ( ... ))( ... ) {'
    // function returning reference to array '... ( & %name% ( ... ))[ ... ] {'
    // TODO: Activate this again
    if (false && tok->str() == "(" && tok->strAt(1) != "*" &&
        (tok->link()->previous()->str() == ")" || Token::simpleMatch(tok->link()->tokAt(-2), ") const"))) {
        const Token* tok2 = tok->link()->next();
        if (tok2 && tok2->str() == "(" && Token::Match(tok2->link()->next(), "{|;|const|=")) {
            const Token* argStartTok;
            if (tok->link()->previous()->str() == "const")
                argStartTok = tok->link()->linkAt(-2);
            else
                argStartTok = tok->link()->linkAt(-1);
            *funcStart = argStartTok->previous();
            *argStart = argStartTok;
            *declEnd = Token::findmatch(tok2->link()->next(), "{|;");
            return true;
        } else if (tok2 && tok2->str() == "[") {
            while (tok2 && tok2->str() == "[")
                tok2 = tok2->link()->next();
            if (Token::Match(tok2, "{|;|const|=")) {
                const Token* argStartTok;
                if (tok->link()->previous()->str() == "const")
                    argStartTok = tok->link()->linkAt(-2);
                else
                    argStartTok = tok->link()->linkAt(-1);
                *funcStart = argStartTok->previous();
                *argStart = argStartTok;
                *declEnd = Token::findmatch(tok2, "{|;");
                return true;
            }
        }
    }

    else if (!tok->isName() || !tok->next() || !tok->next()->link())
        return false;

    // regular function?
    else if (Token::Match(tok, "%name% (") && !isReservedName(tok->str()) && tok->previous() &&
             (Token::Match(tok->previous(), "%name%|>|&|*|::|~") || // Either a return type or scope qualifier in front of tok
              outerScope->isClassOrStructOrUnion())) { // or a ctor/dtor
        const Token* tok1 = tok->previous();
        const Token* tok2 = tok->next()->link()->next();

        if (!mTokenizer->isFunctionHead(tok->next(), ";:{"))
            return false;

        // skip over destructor "~"
        if (tok1->str() == "~")
            tok1 = tok1->previous();

        // skip over qualification
        while (Token::simpleMatch(tok1, "::")) {
            tok1 = tok1->previous();
            if (Token::Match(tok1, "%name%"))
                tok1 = tok1->previous();
            else if (tok1 && tok1->str() == ">" && tok1->link() && Token::Match(tok1->link()->previous(), "%name%"))
                tok1 = tok1->link()->tokAt(-2);
        }

        // skip over const, noexcept, throw, override, final and volatile specifiers
        while (Token::Match(tok2, "const|noexcept|throw|override|final|volatile|&|&&")) {
            tok2 = tok2->next();
            if (tok2 && tok2->str() == "(")
                tok2 = tok2->link()->next();
        }

        // skip over trailing return type
        if (tok2 && tok2->str() == ".") {
            for (tok2 = tok2->next(); tok2; tok2 = tok2->next()) {
                if (Token::Match(tok2, ";|{|=|override|final"))
                    break;
                if (tok2->link() && Token::Match(tok2, "<|[|("))
                    tok2 = tok2->link();
            }
        }

        // done if constructor or destructor
        if (!Token::Match(tok1, "{|}|;|public:|protected:|private:") && tok1) {
            // skip over pointers and references
            while (Token::Match(tok1, "%type%|*|&") && !endsWith(tok1->str(), ':') && (!isReservedName(tok1->str()) || tok1->str() == "const"))
                tok1 = tok1->previous();

            // skip over template
            if (tok1 && tok1->str() == ">") {
                if (tok1->link())
                    tok1 = tok1->link()->previous();
                else
                    return false;
            }

            // function can't have number or variable as return type
            if (tok1 && (tok1->isNumber() || tok1->varId()))
                return false;

            // skip over return type
            if (Token::Match(tok1, "%name%")) {
                if (tok1->str() == "return")
                    return false;
                tok1 = tok1->previous();
            }

            // skip over qualification
            while (Token::simpleMatch(tok1, "::")) {
                tok1 = tok1->previous();
                if (Token::Match(tok1, "%name%"))
                    tok1 = tok1->previous();
                else if (tok1 && tok1->str() == ">" && tok1->link() && Token::Match(tok1->link()->previous(), "%name%"))
                    tok1 = tok1->link()->tokAt(-2);
            }

            // skip over modifiers and other stuff
            while (Token::Match(tok1, "const|static|extern|template|virtual|struct|class|enum|%name%")) {
                // friend type func(); is not a function
                if (isCPP() && tok1->str() == "friend" && tok2->str() == ";")
                    return false;
                tok1 = tok1->previous();
            }

            // should be at a sequence point if this is a function
            if (!Token::Match(tok1, ">|{|}|;|public:|protected:|private:") && tok1)
                return false;
        }

        if (tok2 &&
            (Token::Match(tok2, ";|{|=") ||
             (tok2->isUpperCaseName() && Token::Match(tok2, "%name% ;|{")) ||
             (tok2->isUpperCaseName() && Token::Match(tok2, "%name% (") && tok2->next()->link()->strAt(1) == "{") ||
             Token::Match(tok2, ": ::| %name% (|::|<|{") ||
             Token::Match(tok2, "&|&&| ;|{") ||
             Token::Match(tok2, "= delete|default ;"))) {
            *funcStart = tok;
            *argStart = tok->next();
            *declEnd = Token::findmatch(tok2, "{|;");
            return true;
        }
    }

    // UNKNOWN_MACRO(a,b) { ... }
    else if (outerScope->type == Scope::eGlobal &&
             Token::Match(tok, "%name% (") &&
             tok->isUpperCaseName() &&
             Token::simpleMatch(tok->linkAt(1), ") {") &&
             (!tok->previous() || Token::Match(tok->previous(), "[;{}]"))) {
        *funcStart = tok;
        *argStart = tok->next();
        *declEnd = tok->linkAt(1)->next();
        return true;
    }

    // template constructor?
    else if (Token::Match(tok, "%name% <") && Token::simpleMatch(tok->next()->link(), "> (")) {
        const Token* tok2 = tok->next()->link()->next()->link();
        if (Token::Match(tok2, ") const| ;|{|=") ||
            Token::Match(tok2, ") : ::| %name% (|::|<|{") ||
            Token::Match(tok2, ") const| noexcept {|;|(")) {
            *funcStart = tok;
            *argStart = tok2->link();
            *declEnd = Token::findmatch(tok2->next(), "{|;");
            return true;
        }
    }

    // regular C function with missing return or invalid C++ ?
    else if (Token::Match(tok, "%name% (") && !isReservedName(tok->str()) &&
             Token::simpleMatch(tok->linkAt(1), ") {") &&
             (!tok->previous() || Token::Match(tok->previous(), ";|}"))) {
        if (mTokenizer->isC()) {
            debugMessage(tok, "SymbolDatabase::isFunction found C function '" + tok->str() + "' without a return type.");
            *funcStart = tok;
            *argStart = tok->next();
            *declEnd = tok->linkAt(1)->next();
            return true;
        }
        mTokenizer->syntaxError(tok);
    }

    return false;
}

void SymbolDatabase::validateExecutableScopes() const
{
    const std::size_t functions = functionScopes.size();
    for (std::size_t i = 0; i < functions; ++i) {
        const Scope* const scope = functionScopes[i];
        const Function* const function = scope->function;
        if (scope->isExecutable() && !function) {
            const std::list<const Token*> callstack(1, scope->classDef);
            const std::string msg = std::string("Executable scope '") + scope->classDef->str() + "' with unknown function.";
            const ErrorMessage errmsg(callstack, &mTokenizer->list, Severity::debug,
                                      "symbolDatabaseWarning",
                                      msg,
                                      false);
            mErrorLogger->reportErr(errmsg);
        }
    }
}

namespace {
    const Function* getFunctionForArgumentvariable(const Variable * const var, const std::vector<const Scope *>& functionScopes)
    {
        const std::size_t functions = functionScopes.size();
        for (std::size_t i = 0; i < functions; ++i) {
            const Scope* const scope = functionScopes[i];
            const Function* const function = scope->function;
            if (function) {
                for (std::size_t arg=0; arg < function->argCount(); ++arg) {
                    if (var==function->getArgumentVar(arg))
                        return function;
                }
            }
        }
        return nullptr;
    }
}

void SymbolDatabase::validateVariables() const
{
    for (std::vector<const Variable *>::const_iterator iter = mVariableList.begin(); iter!=mVariableList.end(); ++iter) {
        const Variable * const var = *iter;
        if (var) {
            if (!var->scope()) {
                const Function* function = getFunctionForArgumentvariable(var, functionScopes);
                if (!var->isArgument() || (function && function->hasBody())) {
                    throw InternalError(var->nameToken(), "Analysis failed (variable without scope). If the code is valid then please report this failure.", InternalError::INTERNAL);
                    //std::cout << "!!!Variable found without scope: " << var->nameToken()->str() << std::endl;
                }
            }
        }
    }
}

void SymbolDatabase::validate() const
{
    if (mSettings->debugwarnings) {
        validateExecutableScopes();
    }
    //validateVariables();
}

void SymbolDatabase::clangSetVariables(const std::vector<const Variable *> &variableList)
{
    mVariableList = variableList;
}

Variable::Variable(const Token *name_, const std::string &clangType, const Token *typeStart,
                   const Token *typeEnd, nonneg int index_, AccessControl access_,
                   const Type *type_, const Scope *scope_)
    : mNameToken(name_),
      mTypeStartToken(typeStart),
      mTypeEndToken(typeEnd),
      mIndex(index_),
      mAccess(access_),
      mFlags(0),
      mType(type_),
      mScope(scope_),
      mValueType(nullptr)
{
    if (!mTypeStartToken && mTypeEndToken) {
        mTypeStartToken = mTypeEndToken;
        while (Token::Match(mTypeStartToken->previous(), "%type%|*|&"))
            mTypeStartToken = mTypeStartToken->previous();
        if (mTypeStartToken->str() == "const")
            mTypeStartToken = mTypeStartToken->next();
        if (mTypeStartToken->str() == "struct")
            mTypeStartToken = mTypeStartToken->next();
    }
    if (Token::simpleMatch(mTypeStartToken, "static"))
        setFlag(fIsStatic, true);

    if (endsWith(clangType, " &", 2))
        setFlag(fIsReference, true);

    std::string::size_type pos = clangType.find("[");
    if (pos != std::string::npos) {
        setFlag(fIsArray, true);
        do {
            const std::string::size_type pos1 = pos+1;
            pos = clangType.find("]", pos1);
            Dimension dim;
            dim.tok = nullptr;
            dim.known = pos > pos1;
            if (pos > pos1)
                dim.num = MathLib::toLongNumber(clangType.substr(pos1, pos-pos1));
            else
                dim.num = 0;
            mDimensions.push_back(dim);
            ++pos;
        } while (pos < clangType.size() && clangType[pos] == '[');
    }

    // Is there initialization in variable declaration
    const Token *initTok = mNameToken ? mNameToken->next() : nullptr;
    while (initTok && initTok->str() == "[")
        initTok = initTok->link()->next();
    if (Token::Match(initTok, "=|{") || (initTok && initTok->isSplittedVarDeclEq()))
        setFlag(fIsInit, true);
}

Variable::~Variable()
{
    delete mValueType;
}

bool Variable::isPointerArray() const
{
    return isArray() && nameToken() && nameToken()->previous() && (nameToken()->previous()->str() == "*");
}

bool Variable::isUnsigned() const
{
    return mValueType ? (mValueType->sign == ValueType::Sign::UNSIGNED) : mTypeStartToken->isUnsigned();
}

const Token * Variable::declEndToken() const
{
    Token const * declEnd = typeStartToken();
    while (declEnd && !Token::Match(declEnd, "[;,)={]")) {
        if (declEnd->link() && Token::Match(declEnd,"(|["))
            declEnd = declEnd->link();
        declEnd = declEnd->next();
    }
    return declEnd;
}

void Variable::evaluate(const Settings* settings)
{
    // Is there initialization in variable declaration
    const Token *initTok = mNameToken ? mNameToken->next() : nullptr;
    while (initTok && initTok->str() == "[")
        initTok = initTok->link()->next();
    if (Token::Match(initTok, "=|{") || (initTok && initTok->isSplittedVarDeclEq()))
        setFlag(fIsInit, true);

    if (!settings)
        return;

    const Library * const lib = &settings->library;

    if (mNameToken)
        setFlag(fIsArray, arrayDimensions(settings));

    if (mTypeStartToken)
        setValueType(ValueType::parseDecl(mTypeStartToken,settings));

    const Token* tok = mTypeStartToken;
    while (tok && tok->previous() && tok->previous()->isName())
        tok = tok->previous();
    const Token* end = mTypeEndToken;
    if (end)
        end = end->next();
    while (tok != end) {
        if (tok->str() == "static")
            setFlag(fIsStatic, true);
        else if (tok->str() == "extern")
            setFlag(fIsExtern, true);
        else if (tok->str() == "volatile" || Token::simpleMatch(tok, "std :: atomic <"))
            setFlag(fIsVolatile, true);
        else if (tok->str() == "mutable")
            setFlag(fIsMutable, true);
        else if (tok->str() == "const")
            setFlag(fIsConst, true);
        else if (tok->str() == "*") {
            setFlag(fIsPointer, !isArray() || Token::Match(tok->previous(), "( * %name% )"));
            setFlag(fIsConst, false); // Points to const, isn't necessarily const itself
        } else if (tok->str() == "&") {
            if (isReference())
                setFlag(fIsRValueRef, true);
            setFlag(fIsReference, true);
        } else if (tok->str() == "&&") { // Before simplification, && isn't split up
            setFlag(fIsRValueRef, true);
            setFlag(fIsReference, true); // Set also fIsReference
        }

        if (tok->isAttributeMaybeUnused()) {
            setFlag(fIsMaybeUnused, true);
        }

        if (tok->str() == "<" && tok->link())
            tok = tok->link();
        else
            tok = tok->next();
    }

    while (Token::Match(mTypeStartToken, "static|const|volatile %any%"))
        mTypeStartToken = mTypeStartToken->next();
    while (mTypeEndToken && mTypeEndToken->previous() && Token::Match(mTypeEndToken, "const|volatile"))
        mTypeEndToken = mTypeEndToken->previous();

    if (mTypeStartToken) {
        std::string strtype = mTypeStartToken->str();
        for (const Token *typeToken = mTypeStartToken; Token::Match(typeToken, "%type% :: %type%"); typeToken = typeToken->tokAt(2))
            strtype += "::" + typeToken->strAt(2);
        setFlag(fIsClass, !lib->podtype(strtype) && !mTypeStartToken->isStandardType() && !isEnumType() && !isPointer() && !isReference() && strtype != "...");
        setFlag(fIsStlType, Token::simpleMatch(mTypeStartToken, "std ::"));
        setFlag(fIsStlString, isStlType() && (Token::Match(mTypeStartToken->tokAt(2), "string|wstring|u16string|u32string !!::") || (Token::simpleMatch(mTypeStartToken->tokAt(2), "basic_string <") && !Token::simpleMatch(mTypeStartToken->linkAt(3), "> ::"))));
        setFlag(fIsSmartPointer, lib->isSmartPointer(mTypeStartToken));
    }
    if (mAccess == AccessControl::Argument) {
        tok = mNameToken;
        if (!tok) {
            // Argument without name
            tok = mTypeEndToken;
            // back up to start of array dimensions
            while (tok && tok->str() == "]")
                tok = tok->link()->previous();
            // add array dimensions if present
            if (tok && tok->next()->str() == "[")
                setFlag(fIsArray, arrayDimensions(settings));
        }
        if (!tok)
            return;
        tok = tok->next();
        while (tok->str() == "[")
            tok = tok->link();
        setFlag(fHasDefault, tok->str() == "=");
    }
    // check for C++11 member initialization
    if (mScope && mScope->isClassOrStruct()) {
        // type var = x or
        // type var = {x}
        // type var = x; gets simplified to: type var ; var = x ;
        Token const * declEnd = declEndToken();
        if ((Token::Match(declEnd, "; %name% =") && declEnd->strAt(1) == mNameToken->str()) ||
            Token::Match(declEnd, "=|{"))
            setFlag(fHasDefault, true);
    }

    if (mTypeStartToken) {
        if (Token::Match(mTypeStartToken, "float|double"))
            setFlag(fIsFloatType, true);
    }
}

void Variable::setValueType(const ValueType &valueType)
{
    delete mValueType;
    mValueType = new ValueType(valueType);
    if ((mValueType->pointer > 0) && (!isArray() || Token::Match(mNameToken->previous(), "( * %name% )")))
        setFlag(fIsPointer, true);
    setFlag(fIsConst, mValueType->constness & (1U << mValueType->pointer));
    if (mValueType->smartPointerType)
        setFlag(fIsSmartPointer, true);
}

const Type *Variable::smartPointerType() const
{
    if (!isSmartPointer())
        return nullptr;

    if (mValueType->smartPointerType)
        return mValueType->smartPointerType;

    // TODO: Cache result
    const Token *ptrType = typeStartToken();
    while (Token::Match(ptrType, "%name%|::"))
        ptrType = ptrType->next();
    if (Token::Match(ptrType, "< %name% >"))
        return ptrType->scope()->findType(ptrType->next()->str());
    return nullptr;
}

std::string Variable::getTypeName() const
{
    std::string ret;
    // TODO: For known types, generate the full type name
    for (const Token *typeTok = mTypeStartToken; Token::Match(typeTok, "%name%|::") && typeTok->varId() == 0; typeTok = typeTok->next())
        ret += typeTok->str();
    return ret;
}

static bool isOperator(const Token *tokenDef)
{
    if (!tokenDef)
        return false;
    if (tokenDef->isOperatorKeyword())
        return true;
    const std::string &name = tokenDef->str();
    return name.size() > 8 && name.compare(0,8,"operator")==0 && std::strchr("+-*/%&|~^<>!=[(", name[8]);
}

Function::Function(const Tokenizer *mTokenizer,
                   const Token *tok,
                   const Scope *scope,
                   const Token *tokDef,
                   const Token *tokArgDef)
    : tokenDef(tokDef),
      argDef(tokArgDef),
      token(nullptr),
      arg(nullptr),
      retDef(nullptr),
      retType(nullptr),
      functionScope(nullptr),
      nestedIn(scope),
      initArgCount(0),
      type(eFunction),
      access(AccessControl::Public),
      noexceptArg(nullptr),
      throwArg(nullptr),
      templateDef(nullptr),
      functionPointerUsage(nullptr),
      mFlags(0)
{
    // operator function
    if (::isOperator(tokenDef)) {
        isOperator(true);

        // 'operator =' is special
        if (tokenDef->str() == "operator=")
            type = Function::eOperatorEqual;
    }

    else if (tokenDef->str() == "[") {
        type = Function::eLambda;
    }

    // class constructor/destructor
    else if (tokenDef->str() == scope->className && scope->type != Scope::ScopeType::eNamespace) {
        // destructor
        if (tokenDef->previous()->str() == "~")
            type = Function::eDestructor;
        // constructor of any kind
        else
            type = Function::eConstructor;

        isExplicit(tokenDef->previous()->str() == "explicit");
    }

    const Token *tok1 = setFlags(tok, scope);

    // find the return type
    if (!isConstructor() && !isDestructor() && !isLambda()) {
        // @todo auto type deduction should be checked
        // @todo attributes and exception specification can also precede trailing return type
        if (Token::Match(argDef->link()->next(), "const|volatile| &|&&| .")) { // Trailing return type
            hasTrailingReturnType(true);
            if (argDef->link()->strAt(1) == ".")
                retDef = argDef->link()->tokAt(2);
            else if (argDef->link()->strAt(2) == ".")
                retDef = argDef->link()->tokAt(3);
            else if (argDef->link()->strAt(3) == ".")
                retDef = argDef->link()->tokAt(4);
        } else {
            if (tok1->str() == ">")
                tok1 = tok1->next();
            while (Token::Match(tok1, "extern|virtual|static|friend|struct|union|enum"))
                tok1 = tok1->next();
            retDef = tok1;
        }
    }

    const Token *end = argDef->link();

    // parse function attributes..
    tok = end->next();
    while (tok) {
        if (tok->str() == "const")
            isConst(true);
        else if (tok->str() == "&")
            hasLvalRefQualifier(true);
        else if (tok->str() == "&&")
            hasRvalRefQualifier(true);
        else if (tok->str() == "override")
            setFlag(fHasOverrideSpecifier, true);
        else if (tok->str() == "final")
            setFlag(fHasFinalSpecifier, true);
        else if (tok->str() == "volatile")
            isVolatile(true);
        else if (tok->str() == "noexcept") {
            isNoExcept(!Token::simpleMatch(tok->next(), "( false )"));
            if (tok->next()->str() == "(")
                tok = tok->linkAt(1);
        } else if (Token::simpleMatch(tok, "throw (")) {
            isThrow(true);
            if (tok->strAt(2) != ")")
                throwArg = tok->next();
            tok = tok->linkAt(1);
        } else if (Token::Match(tok, "= 0|default|delete ;")) {
            const std::string& modifier = tok->strAt(1);
            isPure(modifier == "0");
            isDefault(modifier == "default");
            isDelete(modifier == "delete");
        } else if (tok->str() == ".") { // trailing return type
            // skip over return type
            while (tok && !Token::Match(tok->next(), ";|{|override|final"))
                tok = tok->next();
        } else
            break;
        if (tok)
            tok = tok->next();
    }

    if (mTokenizer->isFunctionHead(end, ":{")) {
        // assume implementation is inline (definition and implementation same)
        token = tokenDef;
        arg = argDef;
        isInline(true);
        hasBody(true);
    }
}

Function::Function(const Token *tokenDef)
    : tokenDef(tokenDef),
      argDef(nullptr),
      token(nullptr),
      arg(nullptr),
      retDef(nullptr),
      retType(nullptr),
      functionScope(nullptr),
      nestedIn(nullptr),
      initArgCount(0),
      type(eFunction),
      access(AccessControl::Public),
      noexceptArg(nullptr),
      throwArg(nullptr),
      templateDef(nullptr),
      functionPointerUsage(nullptr),
      mFlags(0)
{
    // operator function
    if (::isOperator(tokenDef)) {
        isOperator(true);

        // 'operator =' is special
        if (tokenDef->str() == "operator=")
            type = Function::eOperatorEqual;
    }

    setFlags(tokenDef, tokenDef->scope());
}

const Token *Function::setFlags(const Token *tok1, const Scope *scope)
{
    // look for end of previous statement
    while (tok1->previous() && !Token::Match(tok1->previous(), ";|}|{|public:|protected:|private:")) {
        tok1 = tok1->previous();

        // extern function
        if (tok1->str() == "extern") {
            isExtern(true);
        }

        // virtual function
        else if (tok1->str() == "virtual") {
            hasVirtualSpecifier(true);
        }

        // static function
        else if (tok1->str() == "static") {
            isStatic(true);
            if (scope->type == Scope::eNamespace || scope->type == Scope::eGlobal)
                isStaticLocal(true);
        }

        // friend function
        else if (tok1->str() == "friend") {
            isFriend(true);
        }

        // Function template
        else if (tok1->link() && tok1->str() == ">" && Token::simpleMatch(tok1->link()->previous(), "template <")) {
            templateDef = tok1->link()->previous();
            break;
        }
    }
    return tok1;
}

std::string Function::fullName() const
{
    std::string ret = name();
    for (const Scope *s = nestedIn; s; s = s->nestedIn) {
        if (!s->className.empty())
            ret = s->className + "::" + ret;
    }
    ret += "(";
    for (const Variable &a : argumentList)
        ret += (a.index() == 0 ? "" : ",") + a.name();
    return ret + ")";
}

static std::string qualifiedName(const Scope *scope)
{
    std::string name = scope->className;
    while (scope->nestedIn) {
        if (!scope->nestedIn->className.empty())
            name = (scope->nestedIn->className + " :: ") + name;
        scope = scope->nestedIn;
    }
    return name;
}

static bool usingNamespace(const Scope *scope, const Token *first, const Token *second, int &offset)
{
    offset = 0;
    std::string name = first->str();

    while (Token::Match(first, "%type% :: %type%")) {
        if (offset)
            name += (" :: " + first->str());
        offset += 2;
        first = first->tokAt(2);
        if (first->str() == second->str()) {
            break;
        }
    }

    if (offset) {
        while (scope) {
            for (const auto & info : scope->usingList) {
                if (info.scope) {
                    if (name == qualifiedName(info.scope))
                        return true;
                }
                // no scope so get name from using
                else {
                    const Token *start = info.start->tokAt(2);
                    std::string nsName;
                    while (start && start->str() != ";") {
                        if (!nsName.empty())
                            nsName += " ";
                        nsName += start->str();
                        start = start->next();
                    }
                    if (nsName == name)
                        return true;
                }
            }
            scope = scope->nestedIn;
        }
    }

    return false;
}

bool Function::argsMatch(const Scope *scope, const Token *first, const Token *second, const std::string &path, nonneg int path_length)
{
    const bool isCPP = scope->check->isCPP();
    if (!isCPP) // C does not support overloads
        return true;

    int arg_path_length = path_length;
    int offset = 0;

    while (first->str() == second->str() &&
           first->isLong() == second->isLong() &&
           first->isUnsigned() == second->isUnsigned()) {

        // skip optional type information
        if (Token::Match(first->next(), "struct|enum|union|class"))
            first = first->next();
        if (Token::Match(second->next(), "struct|enum|union|class"))
            second = second->next();

        // skip const on type passed by value
        if (Token::Match(first->next(), "const %type% %name%|,|)") &&
            !Token::Match(first->next(), "const %type% %name%| ["))
            first = first->next();
        if (Token::Match(second->next(), "const %type% %name%|,|)") &&
            !Token::Match(second->next(), "const %type% %name%| ["))
            second = second->next();

        // at end of argument list
        if (first->str() == ")") {
            return true;
        }

        // skip default value assignment
        else if (first->next()->str() == "=") {
            first = first->nextArgument();
            if (first)
                first = first->tokAt(-2);
            if (second->next()->str() == "=") {
                second = second->nextArgument();
                if (second)
                    second = second->tokAt(-2);
                if (!first || !second) { // End of argument list (first or second)
                    return !first && !second;
                }
            } else if (!first) { // End of argument list (first)
                return !second->nextArgument(); // End of argument list (second)
            }
        } else if (second->next()->str() == "=") {
            second = second->nextArgument();
            if (second)
                second = second->tokAt(-2);
            if (!second) { // End of argument list (second)
                return false;
            }
        }

        // definition missing variable name
        else if ((first->next()->str() == "," && second->next()->str() != ",") ||
                 (Token::Match(first, "!!( )") && second->next()->str() != ")")) {
            second = second->next();
            // skip default value assignment
            if (second->next()->str() == "=") {
                do {
                    second = second->next();
                } while (!Token::Match(second->next(), ",|)"));
            }
        } else if (first->next()->str() == "[" && second->next()->str() != "[")
            second = second->next();

        // function missing variable name
        else if ((second->next()->str() == "," && first->next()->str() != ",") ||
                 (Token::Match(second, "!!( )") && first->next()->str() != ")")) {
            first = first->next();
            // skip default value assignment
            if (first->next()->str() == "=") {
                do {
                    first = first->next();
                } while (!Token::Match(first->next(), ",|)"));
            }
        } else if (second->next()->str() == "[" && first->next()->str() != "[")
            first = first->next();

        // argument list has different number of arguments
        else if (second->str() == ")")
            break;

        // ckeck for type * x == type x[]
        else if (Token::Match(first->next(), "* %name%| ,|)|=") &&
                 Token::Match(second->next(), "%name%| [ ] ,|)")) {
            do {
                first = first->next();
            } while (!Token::Match(first->next(), ",|)"));
            do {
                second = second->next();
            } while (!Token::Match(second->next(), ",|)"));
        }

        // const after *
        else if (first->next()->str() == "*" && first->strAt(2) != "const" &&
                 second->next()->str() == "*" && second->strAt(2) == "const") {
            first = first->next();
            second = second->tokAt(2);
        }

        // variable names are different
        else if ((Token::Match(first->next(), "%name% ,|)|=|[") &&
                  Token::Match(second->next(), "%name% ,|)|[")) &&
                 (first->next()->str() != second->next()->str())) {
            // skip variable names
            first = first->next();
            second = second->next();

            // skip default value assignment
            if (first->next()->str() == "=") {
                do {
                    first = first->next();
                } while (!Token::Match(first->next(), ",|)"));
            }
        }

        // using namespace
        else if (usingNamespace(scope, first->next(), second->next(), offset))
            first = first->tokAt(offset);

        // variable with class path
        else if (arg_path_length && Token::Match(first->next(), "%name%") && first->strAt(1) != "const") {
            std::string param = path;

            if (Token::simpleMatch(second->next(), param.c_str(), param.size())) {
                second = second->tokAt(int(arg_path_length));
                arg_path_length = 0;
            }

            // nested or base class variable
            else if (arg_path_length <= 2 && Token::Match(first->next(), "%name%") &&
                     (Token::Match(second->next(), "%name% :: %name%") ||
                      (Token::Match(second->next(), "%name% <") &&
                       Token::Match(second->linkAt(1), "> :: %name%"))) &&
                     ((second->next()->str() == scope->className) ||
                      (scope->definedType && scope->definedType->isDerivedFrom(second->next()->str()))) &&
                     (first->next()->str() == second->strAt(3))) {
                if (Token::Match(second->next(), "%name% <"))
                    second = second->linkAt(1)->next();
                else
                    second = second->tokAt(2);
            }

            // remove class name
            else if (arg_path_length > 2 && first->strAt(1) != second->strAt(1)) {
                std::string short_path = path;
                unsigned int short_path_length = arg_path_length;

                // remove last " :: "
                short_path.resize(short_path.size() - 4);
                short_path_length--;

                // remove last name
                std::string::size_type lastSpace = short_path.find_last_of(' ');
                if (lastSpace != std::string::npos) {
                    short_path.resize(lastSpace+1);
                    short_path_length--;
                    if (short_path[short_path.size() - 1] == '>') {
                        short_path.resize(short_path.size() - 3);
                        while (short_path[short_path.size() - 1] == '<') {
                            lastSpace = short_path.find_last_of(' ');
                            short_path.resize(lastSpace+1);
                            short_path_length--;
                        }
                    }
                }

                param = short_path;
                if (Token::simpleMatch(second->next(), param.c_str(), param.size())) {
                    second = second->tokAt(int(short_path_length));
                    arg_path_length = 0;
                }
            }
        }

        first = first->next();
        second = second->next();

        // reset path length
        if (first->str() == "," || second->str() == ",")
            arg_path_length = path_length;
    }

    return false;
}

bool Function::returnsReference(const Function* function, bool unknown)
{
    if (!function)
        return false;
    if (function->type != Function::eFunction)
        return false;
    const Token* defEnd = function->returnDefEnd();
    if (defEnd->strAt(-1) == "&")
        return true;
    // Check for unknown types, which could be a reference
    const Token* start = function->retDef;
    while (Token::Match(start, "const|volatile"))
        start = start->next();
    if (start->tokAt(1) == defEnd && !start->type() && !start->isStandardType())
        return unknown;
    // TODO: Try to deduce the type of the expression
    if (Token::Match(start, "decltype|typeof"))
        return unknown;
    return false;
}

std::vector<const Token*> Function::findReturns(const Function* f)
{
    std::vector<const Token*> result;
    if (!f)
        return result;
    const Scope* scope = f->functionScope;
    if (!scope)
        return result;
    for (const Token* tok = scope->bodyStart->next(); tok && tok != scope->bodyEnd; tok = tok->next()) {
        if (tok->str() == "{" && tok->scope() &&
            (tok->scope()->type == Scope::eLambda || tok->scope()->type == Scope::eClass)) {
            tok = tok->link();
            continue;
        }
        if (Token::simpleMatch(tok->astParent(), "return")) {
            result.push_back(tok);
        }
        // Skip lambda functions since the scope may not be set correctly
        const Token* lambdaEndToken = findLambdaEndToken(tok);
        if (lambdaEndToken) {
            tok = lambdaEndToken;
        }
    }
    return result;
}

const Token * Function::constructorMemberInitialization() const
{
    if (!isConstructor() || !functionScope || !functionScope->bodyStart)
        return nullptr;
    if (Token::Match(token, "%name% (") && Token::simpleMatch(token->linkAt(1), ") :"))
        return token->linkAt(1)->next();
    return nullptr;
}

bool Function::isSafe(const Settings *settings) const
{
    if (settings->safeChecks.externalFunctions) {
        if (nestedIn->type == Scope::ScopeType::eNamespace && token->fileIndex() != 0)
            return true;
        if (nestedIn->type == Scope::ScopeType::eGlobal && (token->fileIndex() != 0 || !isStatic()))
            return true;
    }

    if (settings->safeChecks.internalFunctions) {
        if (nestedIn->type == Scope::ScopeType::eNamespace && token->fileIndex() == 0)
            return true;
        if (nestedIn->type == Scope::ScopeType::eGlobal && (token->fileIndex() == 0 || isStatic()))
            return true;
    }

    if (settings->safeChecks.classes && access == AccessControl::Public && (nestedIn->type == Scope::ScopeType::eClass || nestedIn->type == Scope::ScopeType::eStruct))
        return true;

    return false;
}

Function* SymbolDatabase::addGlobalFunction(Scope*& scope, const Token*& tok, const Token *argStart, const Token* funcStart)
{
    Function* function = nullptr;
    // Lambda functions are always unique
    if (tok->str() != "[") {
        for (std::multimap<std::string, const Function *>::iterator i = scope->functionMap.find(tok->str()); i != scope->functionMap.end() && i->first == tok->str(); ++i) {
            const Function *f = i->second;
            if (f->hasBody())
                continue;
            if (Function::argsMatch(scope, f->argDef, argStart, emptyString, 0)) {
                function = const_cast<Function *>(i->second);
                break;
            }
        }
    }

    if (!function)
        function = addGlobalFunctionDecl(scope, tok, argStart, funcStart);

    function->arg = argStart;
    function->token = funcStart;
    function->hasBody(true);

    addNewFunction(&scope, &tok);

    if (scope) {
        scope->function = function;
        function->functionScope = scope;
        return function;
    }
    return nullptr;
}

Function* SymbolDatabase::addGlobalFunctionDecl(Scope*& scope, const Token *tok, const Token *argStart, const Token* funcStart)
{
    Function function(mTokenizer, tok, scope, funcStart, argStart);
    scope->addFunction(function);
    return &scope->functionList.back();
}

void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const Token *argStart)
{
    const bool destructor((*tok)->previous()->str() == "~");
    const bool has_const(argStart->link()->strAt(1) == "const");
    const bool lval(argStart->link()->strAt(has_const ? 2 : 1) == "&");
    const bool rval(argStart->link()->strAt(has_const ? 2 : 1) == "&&");
    int count = 0;
    std::string path;
    unsigned int path_length = 0;
    const Token *tok1 = (*tok);

    if (destructor)
        tok1 = tok1->previous();

    // back up to head of path
    while (tok1 && tok1->previous() && tok1->previous()->str() == "::" && tok1->tokAt(-2) &&
           (tok1->tokAt(-2)->isName() ||
            (tok1->strAt(-2) == ">" && tok1->linkAt(-2) && Token::Match(tok1->linkAt(-2)->previous(), "%name%")))) {
        count++;
        const Token * tok2 = tok1->tokAt(-2);
        if (tok2->str() == ">")
            tok2 = tok2->link()->previous();

        if (tok2) {
            do {
                path = tok1->previous()->str() + " " + path;
                tok1 = tok1->previous();
                path_length++;
            } while (tok1 != tok2);
        } else
            return; // syntax error ?
    }

    // syntax error?
    if (!tok1)
        return;

    std::list<Scope>::iterator it1;

    // search for match
    for (it1 = scopeList.begin(); it1 != scopeList.end(); ++it1) {
        Scope *scope1 = &(*it1);

        bool match = false;

        // check in namespace if using found
        if (*scope == scope1 && !scope1->usingList.empty()) {
            std::list<Scope::UsingInfo>::const_iterator it2;
            for (it2 = scope1->usingList.begin(); it2 != scope1->usingList.end(); ++it2) {
                if (it2->scope) {
                    Function * func = findFunctionInScope(tok1, it2->scope, path, path_length);
                    if (func) {
                        if (!func->hasBody()) {
                            const Token *closeParen = (*tok)->next()->link();
                            if (closeParen) {
                                const Token *eq = mTokenizer->isFunctionHead(closeParen, ";");
                                if (eq && Token::simpleMatch(eq->tokAt(-2), "= default ;")) {
                                    func->isDefault(true);
                                    return;
                                }
                            }
                            func->hasBody(true);
                            func->token = *tok;
                            func->arg = argStart;
                            addNewFunction(scope, tok);
                            if (*scope) {
                                (*scope)->functionOf = func->nestedIn;
                                (*scope)->function = func;
                                (*scope)->function->functionScope = *scope;
                            }
                            return;
                        }
                    }
                }
            }
        }

        if (scope1->className == tok1->str() && (scope1->type != Scope::eFunction)) {
            // do the scopes match (same scope) or do their names match (multiple namespaces)
            if ((*scope == scope1->nestedIn) || (*scope &&
                                                 (*scope)->className == scope1->nestedIn->className &&
                                                 !(*scope)->className.empty() &&
                                                 (*scope)->type == scope1->nestedIn->type)) {

                // nested scopes => check that they match
                {
                    const Scope *s1 = *scope;
                    const Scope *s2 = scope1->nestedIn;
                    while (s1 && s2) {
                        if (s1->className != s2->className)
                            break;
                        s1 = s1->nestedIn;
                        s2 = s2->nestedIn;
                    }
                    // Not matching scopes
                    if (s1 || s2)
                        continue;
                }

                Scope *scope2 = scope1;

                while (scope2 && count > 1) {
                    count--;
                    if (tok1->strAt(1) == "<")
                        tok1 = tok1->linkAt(1)->tokAt(2);
                    else
                        tok1 = tok1->tokAt(2);
                    scope2 = scope2->findRecordInNestedList(tok1->str());
                }

                if (count == 1 && scope2) {
                    match = true;
                    scope1 = scope2;
                }
            }
        }

        if (match) {
            for (std::multimap<std::string, const Function *>::iterator it = scope1->functionMap.find((*tok)->str()); it != scope1->functionMap.end() && it->first == (*tok)->str(); ++it) {
                Function * func = const_cast<Function *>(it->second);
                if (!func->hasBody()) {
                    if (Function::argsMatch(scope1, func->argDef, (*tok)->next(), path, path_length)) {
                        if (func->type == Function::eDestructor && destructor) {
                            func->hasBody(true);
                        } else if (func->type != Function::eDestructor && !destructor) {
                            // normal function?
                            const Token *closeParen = (*tok)->next()->link();
                            if (closeParen) {
                                const Token *eq = mTokenizer->isFunctionHead(closeParen, ";");
                                if (eq && Token::simpleMatch(eq->tokAt(-2), "= default ;")) {
                                    func->isDefault(true);
                                    return;
                                }

                                const bool hasConstKeyword = closeParen->next()->str() == "const";
                                if ((func->isConst() == hasConstKeyword) &&
                                    (func->hasLvalRefQualifier() == lval) &&
                                    (func->hasRvalRefQualifier() == rval)) {
                                    func->hasBody(true);
                                }
                            }
                        }

                        if (func->hasBody()) {
                            func->token = *tok;
                            func->arg = argStart;
                            addNewFunction(scope, tok);
                            if (*scope) {
                                (*scope)->functionOf = scope1;
                                (*scope)->function = func;
                                (*scope)->function->functionScope = *scope;
                            }
                            return;
                        }
                    }
                }
            }
        }
    }

    // class function of unknown class
    addNewFunction(scope, tok);
}

void SymbolDatabase::addNewFunction(Scope **scope, const Token **tok)
{
    const Token *tok1 = *tok;
    scopeList.emplace_back(this, tok1, *scope);
    Scope *newScope = &scopeList.back();

    // find start of function '{'
    bool foundInitList = false;
    while (tok1 && tok1->str() != "{" && tok1->str() != ";") {
        if (tok1->link() && Token::Match(tok1, "(|<")) {
            tok1 = tok1->link();
        } else if (foundInitList &&
                   Token::Match(tok1, "%name%|> {") &&
                   Token::Match(tok1->linkAt(1), "} ,|{")) {
            tok1 = tok1->linkAt(1);
        } else {
            if (tok1->str() == ":")
                foundInitList = true;
            tok1 = tok1->next();
        }
    }

    if (tok1 && tok1->str() == "{") {
        newScope->bodyStart = tok1;
        newScope->bodyEnd = tok1->link();

        // syntax error?
        if (!newScope->bodyEnd) {
            scopeList.pop_back();
            while (tok1->next())
                tok1 = tok1->next();
            *scope = nullptr;
            *tok = tok1;
            return;
        }

        (*scope)->nestedList.push_back(newScope);
        *scope = newScope;
        *tok = tok1;
    } else {
        scopeList.pop_back();
        *scope = nullptr;
        *tok = nullptr;
    }
}

bool Type::isClassType() const
{
    return classScope && classScope->type == Scope::ScopeType::eClass;
}

bool Type::isEnumType() const
{
    //We explicitly check for "enum" because a forward declared enum doesn't get its own scope
    return (classDef && classDef->str() == "enum") ||
           (classScope && classScope->type == Scope::ScopeType::eEnum);
}

bool Type::isStructType() const
{
    return classScope && classScope->type == Scope::ScopeType::eStruct;
}

bool Type::isUnionType() const
{
    return classScope && classScope->type == Scope::ScopeType::eUnion;
}

const Token *Type::initBaseInfo(const Token *tok, const Token *tok1)
{
    // goto initial '{'
    const Token *tok2 = tok1;
    while (tok2 && tok2->str() != "{") {
        // skip unsupported templates
        if (tok2->str() == "<")
            tok2 = tok2->link();

        // check for base classes
        else if (Token::Match(tok2, ":|,")) {
            tok2 = tok2->next();

            // check for invalid code
            if (!tok2 || !tok2->next())
                return nullptr;

            Type::BaseInfo base;

            if (tok2->str() == "virtual") {
                base.isVirtual = true;
                tok2 = tok2->next();
            }

            if (tok2->str() == "public") {
                base.access = AccessControl::Public;
                tok2 = tok2->next();
            } else if (tok2->str() == "protected") {
                base.access = AccessControl::Protected;
                tok2 = tok2->next();
            } else if (tok2->str() == "private") {
                base.access = AccessControl::Private;
                tok2 = tok2->next();
            } else {
                if (tok->str() == "class")
                    base.access = AccessControl::Private;
                else if (tok->str() == "struct")
                    base.access = AccessControl::Public;
            }
            if (!tok2)
                return nullptr;
            if (tok2->str() == "virtual") {
                base.isVirtual = true;
                tok2 = tok2->next();
            }
            if (!tok2)
                return nullptr;

            base.nameTok = tok2;
            // handle global namespace
            if (tok2->str() == "::") {
                tok2 = tok2->next();
            }

            // handle derived base classes
            while (Token::Match(tok2, "%name% ::")) {
                tok2 = tok2->tokAt(2);
            }
            if (!tok2)
                return nullptr;

            base.name = tok2->str();

            tok2 = tok2->next();
            // add unhandled templates
            if (tok2 && tok2->link() && tok2->str() == "<") {
                for (const Token* const end = tok2->link()->next(); tok2 != end; tok2 = tok2->next()) {
                    base.name += tok2->str();
                }
            }

            // save pattern for base class name
            derivedFrom.push_back(base);
        } else
            tok2 = tok2->next();
    }

    return tok2;
}

const std::string& Type::name() const
{
    const Token* next = classDef->next();
    if (classScope && classScope->enumClass && isEnumType())
        return next->strAt(1);
    else if (next->str() == "class")
        return next->strAt(1);
    else if (next->isName())
        return next->str();
    return emptyString;
}

void SymbolDatabase::debugMessage(const Token *tok, const std::string &msg) const
{
    if (tok && mSettings->debugwarnings) {
        const std::list<const Token*> locationList(1, tok);
        const ErrorMessage errmsg(locationList, &mTokenizer->list,
                                  Severity::debug,
                                  "debug",
                                  msg,
                                  false);
        if (mErrorLogger)
            mErrorLogger->reportErr(errmsg);
    }
}

const Function* Type::getFunction(const std::string& funcName) const
{
    if (classScope) {
        const std::multimap<std::string, const Function *>::const_iterator it = classScope->functionMap.find(funcName);

        if (it != classScope->functionMap.end())
            return it->second;
    }

    for (const Type::BaseInfo & i : derivedFrom) {
        if (i.type) {
            const Function* const func = i.type->getFunction(funcName);
            if (func)
                return func;
        }
    }
    return nullptr;
}

bool Type::hasCircularDependencies(std::set<BaseInfo>* ancestors) const
{
    std::set<BaseInfo> knownAncestors;
    if (!ancestors) {
        ancestors=&knownAncestors;
    }
    for (std::vector<BaseInfo>::const_iterator parent=derivedFrom.begin(); parent!=derivedFrom.end(); ++parent) {
        if (!parent->type)
            continue;
        else if (this==parent->type)
            return true;
        else if (ancestors->find(*parent)!=ancestors->end())
            return true;
        else {
            ancestors->insert(*parent);
            if (parent->type->hasCircularDependencies(ancestors))
                return true;
        }
    }
    return false;
}

bool Type::findDependency(const Type* ancestor) const
{
    if (this==ancestor)
        return true;
    for (std::vector<BaseInfo>::const_iterator parent=derivedFrom.begin(); parent!=derivedFrom.end(); ++parent) {
        if (parent->type && parent->type->findDependency(ancestor))
            return true;
    }
    return false;
}

bool Type::isDerivedFrom(const std::string & ancestor) const
{
    for (std::vector<BaseInfo>::const_iterator parent=derivedFrom.begin(); parent!=derivedFrom.end(); ++parent) {
        if (parent->name == ancestor)
            return true;
        if (parent->type && parent->type->isDerivedFrom(ancestor))
            return true;
    }
    return false;
}

bool Variable::arrayDimensions(const Settings* settings)
{
    const Library::Container* container = settings->library.detectContainer(mTypeStartToken);
    if (container && container->arrayLike_indexOp && container->size_templateArgNo > 0) {
        const Token* tok = Token::findsimplematch(mTypeStartToken, "<");
        if (tok) {
            Dimension dimension_;
            tok = tok->next();
            for (int i = 0; i < container->size_templateArgNo && tok; i++) {
                tok = tok->nextTemplateArgument();
            }
            if (Token::Match(tok, "%num% [,>]")) {
                dimension_.tok = tok;
                dimension_.known = true;
                dimension_.num = MathLib::toLongNumber(tok->str());
            } else if (tok) {
                dimension_.tok = tok;
                dimension_.known = false;
            }
            mDimensions.push_back(dimension_);
            return true;
        }
    }

    const Token *dim = mNameToken;
    if (!dim) {
        // Argument without name
        dim = mTypeEndToken;
        // back up to start of array dimensions
        while (dim && dim->str() == "]")
            dim = dim->link()->previous();
    }
    if (dim)
        dim = dim->next();
    if (dim && dim->str() == ")")
        dim = dim->next();

    bool arr = false;
    while (dim && dim->next() && dim->str() == "[") {
        Dimension dimension_;
        dimension_.known = false;
        // check for empty array dimension []
        if (dim->next()->str() != "]") {
            dimension_.tok = dim->astOperand2();
            ValueFlow::valueFlowConstantFoldAST(const_cast<Token *>(dimension_.tok), settings);
            if (dimension_.tok && dimension_.tok->hasKnownIntValue()) {
                dimension_.num = dimension_.tok->getKnownIntValue();
                dimension_.known = true;
            }
        }
        mDimensions.push_back(dimension_);
        dim = dim->link()->next();
        arr = true;
    }
    return arr;
}

static std::ostream & operator << (std::ostream & s, Scope::ScopeType type)
{
    s << (type == Scope::eGlobal ? "Global" :
          type == Scope::eClass ? "Class" :
          type == Scope::eStruct ? "Struct" :
          type == Scope::eUnion ? "Union" :
          type == Scope::eNamespace ? "Namespace" :
          type == Scope::eFunction ? "Function" :
          type == Scope::eIf ? "If" :
          type == Scope::eElse ? "Else" :
          type == Scope::eFor ? "For" :
          type == Scope::eWhile ? "While" :
          type == Scope::eDo ? "Do" :
          type == Scope::eSwitch ? "Switch" :
          type == Scope::eTry ? "Try" :
          type == Scope::eCatch ? "Catch" :
          type == Scope::eUnconditional ? "Unconditional" :
          type == Scope::eLambda ? "Lambda" :
          type == Scope::eEnum ? "Enum" :
          "Unknown");
    return s;
}

static std::string accessControlToString(const AccessControl& access)
{
    switch (access) {
    case AccessControl::Public:
        return "Public";
    case AccessControl::Protected:
        return "Protected";
    case AccessControl::Private:
        return "Private";
    case AccessControl::Global:
        return "Global";
    case AccessControl::Namespace:
        return "Namespace";
    case AccessControl::Argument:
        return "Argument";
    case AccessControl::Local:
        return "Local";
    case AccessControl::Throw:
        return "Throw";
    }
    return "Unknown";
}

static std::string tokenToString(const Token* tok, const Tokenizer* tokenizer)
{
    std::ostringstream oss;
    if (tok) {
        oss << tok->str() << " ";
        oss << tokenizer->list.fileLine(tok) << " ";
    }
    oss << tok;
    return oss.str();
}

static std::string scopeToString(const Scope* scope, const Tokenizer* tokenizer)
{
    std::ostringstream oss;
    if (scope) {
        oss << scope->type << " ";
        if (scope->classDef)
            oss << tokenizer->list.fileLine(scope->classDef) << " ";
    }
    oss << scope;
    return oss.str();
}

static std::string tokenType(const Token * tok)
{
    std::ostringstream oss;
    if (tok) {
        if (tok->isUnsigned())
            oss << "unsigned ";
        else if (tok->isSigned())
            oss << "signed ";
        if (tok->isComplex())
            oss << "_Complex ";
        if (tok->isLong())
            oss << "long ";
        oss << tok->str();
    }
    return oss.str();
}

void SymbolDatabase::printVariable(const Variable *var, const char *indent) const
{
    std::cout << indent << "mNameToken: " << tokenToString(var->nameToken(), mTokenizer) << std::endl;
    if (var->nameToken()) {
        std::cout << indent << "    declarationId: " << var->declarationId() << std::endl;
    }
    std::cout << indent << "mTypeStartToken: " << tokenToString(var->typeStartToken(), mTokenizer) << std::endl;
    std::cout << indent << "mTypeEndToken: " << tokenToString(var->typeEndToken(), mTokenizer) << std::endl;

    if (var->typeStartToken()) {
        const Token * autoTok = nullptr;
        std::cout << indent << "   ";
        for (const Token * tok = var->typeStartToken(); tok != var->typeEndToken()->next(); tok = tok->next()) {
            std::cout << " " << tokenType(tok);
            if (tok->str() == "auto")
                autoTok = tok;
        }
        std::cout << std::endl;
        if (autoTok) {
            const ValueType * valueType = autoTok->valueType();
            std::cout << indent << "    auto valueType: " << valueType << std::endl;
            if (var->typeStartToken()->valueType()) {
                std::cout << indent << "        " << valueType->str() << std::endl;
            }
        }
    } else if (var->valueType()) {
        std::cout << indent << "   " << var->valueType()->str() << std::endl;
    }
    std::cout << indent << "mIndex: " << var->index() << std::endl;
    std::cout << indent << "mAccess: " << accessControlToString(var->accessControl()) << std::endl;
    std::cout << indent << "mFlags: " << std::endl;
    std::cout << indent << "    isMutable: " << var->isMutable() << std::endl;
    std::cout << indent << "    isStatic: " << var->isStatic() << std::endl;
    std::cout << indent << "    isExtern: " << var->isExtern() << std::endl;
    std::cout << indent << "    isLocal: " << var->isLocal() << std::endl;
    std::cout << indent << "    isConst: " << var->isConst() << std::endl;
    std::cout << indent << "    isClass: " << var->isClass() << std::endl;
    std::cout << indent << "    isArray: " << var->isArray() << std::endl;
    std::cout << indent << "    isPointer: " << var->isPointer() << std::endl;
    std::cout << indent << "    isReference: " << var->isReference() << std::endl;
    std::cout << indent << "    isRValueRef: " << var->isRValueReference() << std::endl;
    std::cout << indent << "    hasDefault: " << var->hasDefault() << std::endl;
    std::cout << indent << "    isStlType: " << var->isStlType() << std::endl;
    std::cout << indent << "mType: ";
    if (var->type()) {
        std::cout << var->type()->type() << " " << var->type()->name();
        std::cout << " " << mTokenizer->list.fileLine(var->type()->classDef);
        std::cout << " " << var->type() << std::endl;
    } else
        std::cout << "none" << std::endl;

    if (var->nameToken()) {
        const ValueType * valueType = var->nameToken()->valueType();
        std::cout << indent << "valueType: " << valueType << std::endl;
        if (valueType) {
            std::cout << indent << "    " << valueType->str() << std::endl;
        }
    }

    std::cout << indent << "mScope: " << scopeToString(var->scope(), mTokenizer) << std::endl;

    std::cout << indent << "mDimensions:";
    for (std::size_t i = 0; i < var->dimensions().size(); i++) {
        std::cout << " " << var->dimension(i);
        if (!var->dimensions()[i].known)
            std::cout << "?";
    }
    std::cout << std::endl;
}

void SymbolDatabase::printOut(const char *title) const
{
    std::cout << std::setiosflags(std::ios::boolalpha);
    if (title)
        std::cout << "\n### " << title << " ###\n";

    for (std::list<Scope>::const_iterator scope = scopeList.begin(); scope != scopeList.end(); ++scope) {
        std::cout << "Scope: " << &*scope << " " << scope->type << std::endl;
        std::cout << "    className: " << scope->className << std::endl;
        std::cout << "    classDef: " << tokenToString(scope->classDef, mTokenizer) << std::endl;
        std::cout << "    bodyStart: " << tokenToString(scope->bodyStart, mTokenizer) << std::endl;
        std::cout << "    bodyEnd: " << tokenToString(scope->bodyEnd, mTokenizer) << std::endl;

        std::list<Function>::const_iterator func;

        // find the function body if not implemented inline
        for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
            std::cout << "    Function: " << &*func << std::endl;
            std::cout << "        name: " << tokenToString(func->tokenDef, mTokenizer) << std::endl;
            std::cout << "        type: " << (func->type == Function::eConstructor? "Constructor" :
                                              func->type == Function::eCopyConstructor ? "CopyConstructor" :
                                              func->type == Function::eMoveConstructor ? "MoveConstructor" :
                                              func->type == Function::eOperatorEqual ? "OperatorEqual" :
                                              func->type == Function::eDestructor ? "Destructor" :
                                              func->type == Function::eFunction ? "Function" :
                                              func->type == Function::eLambda ? "Lambda" :
                                              "Unknown") << std::endl;
            std::cout << "        access: " << accessControlToString(func->access) << std::endl;
            std::cout << "        hasBody: " << func->hasBody() << std::endl;
            std::cout << "        isInline: " << func->isInline() << std::endl;
            std::cout << "        isConst: " << func->isConst() << std::endl;
            std::cout << "        hasVirtualSpecifier: " << func->hasVirtualSpecifier() << std::endl;
            std::cout << "        isPure: " << func->isPure() << std::endl;
            std::cout << "        isStatic: " << func->isStatic() << std::endl;
            std::cout << "        isStaticLocal: " << func->isStaticLocal() << std::endl;
            std::cout << "        isExtern: " << func->isExtern() << std::endl;
            std::cout << "        isFriend: " << func->isFriend() << std::endl;
            std::cout << "        isExplicit: " << func->isExplicit() << std::endl;
            std::cout << "        isDefault: " << func->isDefault() << std::endl;
            std::cout << "        isDelete: " << func->isDelete() << std::endl;
            std::cout << "        hasOverrideSpecifier: " << func->hasOverrideSpecifier() << std::endl;
            std::cout << "        hasFinalSpecifier: " << func->hasFinalSpecifier() << std::endl;
            std::cout << "        isNoExcept: " << func->isNoExcept() << std::endl;
            std::cout << "        isThrow: " << func->isThrow() << std::endl;
            std::cout << "        isOperator: " << func->isOperator() << std::endl;
            std::cout << "        hasLvalRefQual: " << func->hasLvalRefQualifier() << std::endl;
            std::cout << "        hasRvalRefQual: " << func->hasRvalRefQualifier() << std::endl;
            std::cout << "        isVariadic: " << func->isVariadic() << std::endl;
            std::cout << "        isVolatile: " << func->isVolatile() << std::endl;
            std::cout << "        hasTrailingReturnType: " << func->hasTrailingReturnType() << std::endl;
            std::cout << "        attributes:";
            if (func->isAttributeConst())
                std::cout << " const ";
            if (func->isAttributePure())
                std::cout << " pure ";
            if (func->isAttributeNoreturn())
                std::cout << " noreturn ";
            if (func->isAttributeNothrow())
                std::cout << " nothrow ";
            if (func->isAttributeConstructor())
                std::cout << " constructor ";
            if (func->isAttributeDestructor())
                std::cout << " destructor ";
            if (func->isAttributeNodiscard())
                std::cout << " nodiscard ";
            std::cout << std::endl;
            std::cout << "        noexceptArg: " << (func->noexceptArg ? func->noexceptArg->str() : "none") << std::endl;
            std::cout << "        throwArg: " << (func->throwArg ? func->throwArg->str() : "none") << std::endl;
            std::cout << "        tokenDef: " << tokenToString(func->tokenDef, mTokenizer) << std::endl;
            std::cout << "        argDef: " << tokenToString(func->argDef, mTokenizer) << std::endl;
            if (!func->isConstructor() && !func->isDestructor())
                std::cout << "        retDef: " << tokenToString(func->retDef, mTokenizer) << std::endl;
            if (func->retDef) {
                std::cout << "           ";
                for (const Token * tok = func->retDef; tok && tok != func->tokenDef && !Token::Match(tok, "{|;|override|final"); tok = tok->next())
                    std::cout << " " << tokenType(tok);
                std::cout << std::endl;
            }
            std::cout << "        retType: " << func->retType << std::endl;

            if (func->tokenDef->next()->valueType()) {
                const ValueType * valueType = func->tokenDef->next()->valueType();
                std::cout << "        valueType: " << valueType << std::endl;
                if (valueType) {
                    std::cout << "            " << valueType->str() << std::endl;
                }
            }

            if (func->hasBody()) {
                std::cout << "        token: " << tokenToString(func->token, mTokenizer) << std::endl;
                std::cout << "        arg: " << tokenToString(func->arg, mTokenizer) << std::endl;
            }
            std::cout << "        nestedIn: " << scopeToString(func->nestedIn, mTokenizer) << std::endl;
            std::cout << "        functionScope: " << scopeToString(func->functionScope, mTokenizer) << std::endl;

            std::list<Variable>::const_iterator var;

            for (var = func->argumentList.begin(); var != func->argumentList.end(); ++var) {
                std::cout << "        Variable: " << &*var << std::endl;
                printVariable(&*var, "            ");
            }
        }

        std::list<Variable>::const_iterator var;

        for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var) {
            std::cout << "    Variable: " << &*var << std::endl;
            printVariable(&*var, "        ");
        }

        if (scope->type == Scope::eEnum) {
            std::cout << "    enumType: ";
            if (scope->enumType)
                scope->enumType->stringify(std::cout, false, true, false);
            else
                std::cout << "int";
            std::cout << std::endl;
            std::cout << "    enumClass: " << scope->enumClass << std::endl;
            for (const Enumerator &enumerator : scope->enumeratorList) {
                std::cout << "        Enumerator: " << enumerator.name->str() << " = ";
                if (enumerator.value_known)
                    std::cout << enumerator.value;

                if (enumerator.start) {
                    const Token * tok = enumerator.start;
                    std::cout << (enumerator.value_known ? " " : "") << "[" << tok->str();
                    while (tok && tok != enumerator.end) {
                        if (tok->next())
                            std::cout << " " << tok->next()->str();
                        tok = tok->next();
                    }

                    std::cout << "]";
                }

                std::cout << std::endl;
            }
        }

        std::cout << "    nestedIn: " << scope->nestedIn;
        if (scope->nestedIn) {
            std::cout << " " << scope->nestedIn->type << " "
                      << scope->nestedIn->className;
        }
        std::cout << std::endl;

        std::cout << "    definedType: " << scope->definedType << std::endl;

        std::cout << "    nestedList[" << scope->nestedList.size() << "] = (";

        std::list<Scope *>::const_iterator nsi;

        std::size_t count = scope->nestedList.size();
        for (nsi = scope->nestedList.begin(); nsi != scope->nestedList.end(); ++nsi) {
            std::cout << " " << (*nsi) << " " << (*nsi)->type << " " << (*nsi)->className;
            if (count-- > 1)
                std::cout << ",";
        }

        std::cout << " )" << std::endl;

        std::list<Scope::UsingInfo>::const_iterator use;

        for (use = scope->usingList.begin(); use != scope->usingList.end(); ++use) {
            std::cout << "    using: " << use->scope << " " << use->start->strAt(2);
            const Token *tok1 = use->start->tokAt(3);
            while (tok1 && tok1->str() == "::") {
                std::cout << "::" << tok1->strAt(1);
                tok1 = tok1->tokAt(2);
            }
            std::cout << " " << mTokenizer->list.fileLine(use->start) << std::endl;
        }

        std::cout << "    functionOf: " << scopeToString(scope->functionOf, mTokenizer) << std::endl;

        std::cout << "    function: " << scope->function;
        if (scope->function)
            std::cout << " " << scope->function->name();
        std::cout << std::endl;
    }

    for (std::list<Type>::const_iterator type = typeList.begin(); type != typeList.end(); ++type) {
        std::cout << "Type: " << &(*type) << std::endl;
        std::cout << "    name: " << type->name() << std::endl;
        std::cout << "    classDef: " << tokenToString(type->classDef, mTokenizer) << std::endl;
        std::cout << "    classScope: " << type->classScope << std::endl;
        std::cout << "    enclosingScope: " << type->enclosingScope;
        if (type->enclosingScope) {
            std::cout << " " << type->enclosingScope->type << " "
                      << type->enclosingScope->className;
        }
        std::cout << std::endl;
        std::cout << "    needInitialization: " << (type->needInitialization == Type::NeedInitialization::Unknown ? "Unknown" :
                  type->needInitialization == Type::NeedInitialization::True ? "True" :
                  type->needInitialization == Type::NeedInitialization::False ? "False" :
                  "Invalid") << std::endl;

        std::cout << "    derivedFrom[" << type->derivedFrom.size() << "] = (";
        std::size_t count = type->derivedFrom.size();
        for (const Type::BaseInfo & i : type->derivedFrom) {
            if (i.isVirtual)
                std::cout << "Virtual ";

            std::cout << (i.access == AccessControl::Public    ? " Public" :
                          i.access == AccessControl::Protected ? " Protected" :
                          i.access == AccessControl::Private   ? " Private" :
                          " Unknown");

            if (i.type)
                std::cout << " " << i.type;
            else
                std::cout << " Unknown";

            std::cout << " " << i.name;
            if (count-- > 1)
                std::cout << ",";
        }

        std::cout << " )" << std::endl;

        std::cout << "    friendList[" << type->friendList.size() << "] = (";
        for (size_t i = 0; i < type->friendList.size(); i++) {
            if (type->friendList[i].type)
                std::cout << type->friendList[i].type;
            else
                std::cout << " Unknown";

            std::cout << ' ';
            if (type->friendList[i].nameEnd)
                std::cout << type->friendList[i].nameEnd->str();
            if (i+1 < type->friendList.size())
                std::cout << ',';
        }

        std::cout << " )" << std::endl;
    }

    for (std::size_t i = 1; i < mVariableList.size(); i++) {
        std::cout << "mVariableList[" << i << "]: " << mVariableList[i];
        if (mVariableList[i]) {
            std::cout << " " << mVariableList[i]->name() << " "
                      << mTokenizer->list.fileLine(mVariableList[i]->nameToken());
        }
        std::cout << std::endl;
    }
    std::cout << std::resetiosflags(std::ios::boolalpha);
}

void SymbolDatabase::printXml(std::ostream &out) const
{
    out << std::setiosflags(std::ios::boolalpha);

    std::set<const Variable *> variables;

    // Scopes..
    out << "  <scopes>" << std::endl;
    for (std::list<Scope>::const_iterator scope = scopeList.begin(); scope != scopeList.end(); ++scope) {
        out << "    <scope";
        out << " id=\"" << &*scope << "\"";
        out << " type=\"" << scope->type << "\"";
        if (!scope->className.empty())
            out << " className=\"" << ErrorLogger::toxml(scope->className) << "\"";
        if (scope->bodyStart)
            out << " bodyStart=\"" << scope->bodyStart << '\"';
        if (scope->bodyEnd)
            out << " bodyEnd=\"" << scope->bodyEnd << '\"';
        if (scope->nestedIn)
            out << " nestedIn=\"" << scope->nestedIn << "\"";
        if (scope->function)
            out << " function=\"" << scope->function << "\"";
        if (scope->functionList.empty() && scope->varlist.empty())
            out << "/>" << std::endl;
        else {
            out << '>' << std::endl;
            if (!scope->functionList.empty()) {
                out << "      <functionList>" << std::endl;
                for (std::list<Function>::const_iterator function = scope->functionList.begin(); function != scope->functionList.end(); ++function) {
                    out << "        <function id=\"" << &*function << "\" tokenDef=\"" << function->tokenDef << "\" name=\"" << ErrorLogger::toxml(function->name()) << '\"';
                    out << " type=\"" << (function->type == Function::eConstructor? "Constructor" :
                                          function->type == Function::eCopyConstructor ? "CopyConstructor" :
                                          function->type == Function::eMoveConstructor ? "MoveConstructor" :
                                          function->type == Function::eOperatorEqual ? "OperatorEqual" :
                                          function->type == Function::eDestructor ? "Destructor" :
                                          function->type == Function::eFunction ? "Function" :
                                          function->type == Function::eLambda ? "Lambda" :
                                          "Unknown") << '\"';
                    if (function->nestedIn->definedType) {
                        if (function->hasVirtualSpecifier())
                            out << " hasVirtualSpecifier=\"true\"";
                        else if (function->isImplicitlyVirtual())
                            out << " isImplicitlyVirtual=\"true\"";
                    }
                    if (function->isStatic())
                        out << " isStatic=\"true\"";
                    if (function->argCount() == 0U)
                        out << "/>" << std::endl;
                    else {
                        out << ">" << std::endl;
                        for (unsigned int argnr = 0; argnr < function->argCount(); ++argnr) {
                            const Variable *arg = function->getArgumentVar(argnr);
                            out << "          <arg nr=\"" << argnr+1 << "\" variable=\"" << arg << "\"/>" << std::endl;
                            variables.insert(arg);
                        }
                        out << "        </function>" << std::endl;
                    }
                }
                out << "      </functionList>" << std::endl;
            }
            if (!scope->varlist.empty()) {
                out << "      <varlist>" << std::endl;
                for (std::list<Variable>::const_iterator var = scope->varlist.begin(); var != scope->varlist.end(); ++var)
                    out << "        <var id=\""   << &*var << "\"/>" << std::endl;
                out << "      </varlist>" << std::endl;
            }
            out << "    </scope>" << std::endl;
        }
    }
    out << "  </scopes>" << std::endl;

    // Variables..
    for (const Variable *var : mVariableList)
        variables.insert(var);
    out << "  <variables>" << std::endl;
    for (const Variable *var : variables) {
        if (!var)
            continue;
        out << "    <var id=\""   << var << '\"';
        out << " nameToken=\""      << var->nameToken() << '\"';
        out << " typeStartToken=\"" << var->typeStartToken() << '\"';
        out << " typeEndToken=\""   << var->typeEndToken() << '\"';
        out << " access=\""         << accessControlToString(var->mAccess) << '\"';
        out << " scope=\""          << var->scope() << '\"';
        out << " constness=\""      << var->valueType()->constness << '\"';
        out << " isArgument=\""     << var->isArgument() << '\"';
        out << " isArray=\""        << var->isArray() << '\"';
        out << " isClass=\""        << var->isClass() << '\"';
        out << " isConst=\""        << var->isConst() << '\"';
        out << " isExtern=\""       << var->isExtern() << '\"';
        out << " isLocal=\""        << var->isLocal() << '\"';
        out << " isPointer=\""      << var->isPointer() << '\"';
        out << " isReference=\""    << var->isReference() << '\"';
        out << " isStatic=\""       << var->isStatic() << '\"';
        out << "/>" << std::endl;
    }
    out << "  </variables>" << std::endl;
    out << std::resetiosflags(std::ios::boolalpha);
}

//---------------------------------------------------------------------------

static const Type* findVariableTypeIncludingUsedNamespaces(const SymbolDatabase* symbolDatabase, const Scope* scope, const Token* typeTok)
{
    const Type* argType = symbolDatabase->findVariableType(scope, typeTok);
    if (argType)
        return argType;

    // look for variable type in any using namespace in this scope or above
    while (scope) {
        for (const Scope::UsingInfo &ui : scope->usingList) {
            if (ui.scope) {
                argType = symbolDatabase->findVariableType(ui.scope, typeTok);
                if (argType)
                    return argType;
            }
        }
        scope = scope->nestedIn;
    }
    return nullptr;
}

//---------------------------------------------------------------------------

void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *scope)
{
    // check for non-empty argument list "( ... )"
    const Token * start = arg ? arg : argDef;
    if (!Token::simpleMatch(start, "("))
        return;
    if (!(start && start->link() != start->next() && !Token::simpleMatch(start, "( void )")))
        return;

    unsigned int count = 0;

    for (const Token* tok = start->next(); tok; tok = tok->next()) {
        if (Token::Match(tok, ",|)"))
            return; // Syntax error

        const Token* startTok = tok;
        const Token* endTok   = nullptr;
        const Token* nameTok  = nullptr;

        do {
            if (Token::simpleMatch(tok, "decltype (")) {
                tok = tok->linkAt(1)->next();
                continue;
            }
            if (tok != startTok && !nameTok && Token::Match(tok, "( & %var% ) [")) {
                nameTok = tok->tokAt(2);
                endTok = nameTok->previous();
                tok = tok->link();
            } else if (tok != startTok && !nameTok && Token::Match(tok, "( * %var% ) ( ) [,)]")) {
                nameTok = tok->tokAt(2);
                endTok = nameTok->previous();
                tok = tok->link()->tokAt(2);
            } else if (tok->varId() != 0) {
                nameTok = tok;
                endTok = tok->previous();
            } else if (tok->str() == "[") {
                // skip array dimension(s)
                tok = tok->link();
                while (tok->next()->str() == "[")
                    tok = tok->next()->link();
            } else if (tok->str() == "<") {
                tok = tok->link();
                if (!tok) // something is wrong so just bail out
                    return;
            }

            tok = tok->next();

            if (!tok) // something is wrong so just bail
                return;
        } while (tok->str() != "," && tok->str() != ")" && tok->str() != "=");

        const Token *typeTok = startTok;
        // skip over stuff to get to type
        while (Token::Match(typeTok, "const|volatile|enum|struct|::"))
            typeTok = typeTok->next();
        if (Token::Match(typeTok, ",|)")) { // #8333
            symbolDatabase->mTokenizer->syntaxError(typeTok);
        }
        // skip over qualification
        while (Token::Match(typeTok, "%type% ::"))
            typeTok = typeTok->tokAt(2);

        // check for argument with no name or missing varid
        if (!endTok) {
            if (tok->previous()->isName() && !Token::Match(tok->tokAt(-1), "const|volatile")) {
                if (tok->previous() != typeTok) {
                    nameTok = tok->previous();
                    endTok = nameTok->previous();

                    if (hasBody())
                        symbolDatabase->debugMessage(nameTok, "Function::addArguments found argument \'" + nameTok->str() + "\' with varid 0.");
                } else
                    endTok = typeTok;
            } else
                endTok = tok->previous();
        }

        const ::Type *argType = nullptr;
        if (!typeTok->isStandardType()) {
            argType = findVariableTypeIncludingUsedNamespaces(symbolDatabase, scope, typeTok);

            // save type
            const_cast<Token *>(typeTok)->type(argType);
        }

        // skip default values
        if (tok->str() == "=") {
            do {
                if (tok->link() && Token::Match(tok, "[{[(<]"))
                    tok = tok->link();
                tok = tok->next();
            } while (tok->str() != "," && tok->str() != ")");
        }

        // skip over stuff before type
        while (Token::Match(startTok, "enum|struct|const|volatile"))
            startTok = startTok->next();

        if (startTok == nameTok)
            break;

        argumentList.emplace_back(nameTok, startTok, endTok, count++, AccessControl::Argument, argType, functionScope, symbolDatabase->mSettings);

        if (tok->str() == ")") {
            // check for a variadic function or a variadic template function
            if (Token::simpleMatch(endTok, "..."))
                isVariadic(true);

            break;
        }
    }

    // count default arguments
    for (const Token* tok = argDef->next(); tok && tok != argDef->link(); tok = tok->next()) {
        if (tok->str() == "=") {
            initArgCount++;
            if (tok->strAt(1) == "[") {
                const Token* lambdaStart = tok->next();
                tok = findLambdaEndToken(lambdaStart);
                if (!tok)
                    throw InternalError(lambdaStart, "Analysis failed (lambda not recognized). If the code is valid then please report this failure.", InternalError::INTERNAL);
            }
        }
    }
}

bool Function::isImplicitlyVirtual(bool defaultVal) const
{
    if (hasVirtualSpecifier()) //If it has the virtual specifier it's definitely virtual
        return true;
    if (hasOverrideSpecifier()) //If it has the override specifier then it's either virtual or not going to compile
        return true;
    bool foundAllBaseClasses = true;
    if (getOverriddenFunction(&foundAllBaseClasses)) //If it overrides a base class's method then it's virtual
        return true;
    if (foundAllBaseClasses) //If we've seen all the base classes and none of the above were true then it must not be virtual
        return false;
    return defaultVal; //If we can't see all the bases classes then we can't say conclusively
}

const Function *Function::getOverriddenFunction(bool *foundAllBaseClasses) const
{
    if (foundAllBaseClasses)
        *foundAllBaseClasses = true;
    if (!nestedIn->isClassOrStruct())
        return nullptr;
    return getOverriddenFunctionRecursive(nestedIn->definedType, foundAllBaseClasses);
}

const Function * Function::getOverriddenFunctionRecursive(const ::Type* baseType, bool *foundAllBaseClasses) const
{
    // check each base class
    for (const ::Type::BaseInfo & i : baseType->derivedFrom) {
        const ::Type* derivedFromType = i.type;
        // check if base class exists in database
        if (!derivedFromType || !derivedFromType->classScope) {
            if (foundAllBaseClasses)
                *foundAllBaseClasses = false;
            continue;
        }

        const Scope *parent = derivedFromType->classScope;

        // check if function defined in base class
        for (std::multimap<std::string, const Function *>::const_iterator it = parent->functionMap.find(tokenDef->str()); it != parent->functionMap.end() && it->first == tokenDef->str(); ++it) {
            const Function * func = it->second;
            if (func->hasVirtualSpecifier()) { // Base is virtual and of same name
                const Token *temp1 = func->tokenDef->previous();
                const Token *temp2 = tokenDef->previous();
                bool match = true;

                // check for matching return parameters
                while (temp1->str() != "virtual") {
                    if (temp1->str() != temp2->str() &&
                        !(temp1->str() == derivedFromType->name() &&
                          temp2->str() == baseType->name())) {
                        match = false;
                        break;
                    }

                    temp1 = temp1->previous();
                    temp2 = temp2->previous();
                }

                // check for matching function parameters
                match = match && argsMatch(baseType->classScope, func->argDef, argDef, emptyString, 0);

                // check for matching cv-ref qualifiers
                match = match
                        && isConst() == func->isConst()
                        && isVolatile() == func->isVolatile()
                        && hasRvalRefQualifier() == func->hasRvalRefQualifier()
                        && hasLvalRefQualifier() == func->hasLvalRefQualifier();

                // it's a match
                if (match) {
                    return func;
                }
            }
        }

        if (!derivedFromType->derivedFrom.empty() && !derivedFromType->hasCircularDependencies()) {
            // avoid endless recursion, see #5289 Crash: Stack overflow in isImplicitlyVirtual_rec when checking SVN and
            // #5590 with a loop within the class hierarchy.
            const Function *func = getOverriddenFunctionRecursive(derivedFromType, foundAllBaseClasses);
            if (func)  {
                return func;
            }
        }
    }
    return nullptr;
}

const Variable* Function::getArgumentVar(nonneg int num) const
{
    for (std::list<Variable>::const_iterator i = argumentList.begin(); i != argumentList.end(); ++i) {
        if (i->index() == num)
            return (&*i);
        else if (i->index() > num)
            return nullptr;
    }
    return nullptr;
}


//---------------------------------------------------------------------------

Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *nestedIn_, ScopeType type_, const Token *start_) :
    check(check_),
    classDef(classDef_),
    bodyStart(start_),
    bodyEnd(start_->link()),
    nestedIn(nestedIn_),
    numConstructors(0),
    numCopyOrMoveConstructors(0),
    type(type_),
    definedType(nullptr),
    functionOf(nullptr),
    function(nullptr),
    enumType(nullptr),
    enumClass(false)
{
}

Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *nestedIn_) :
    check(check_),
    classDef(classDef_),
    bodyStart(nullptr),
    bodyEnd(nullptr),
    nestedIn(nestedIn_),
    numConstructors(0),
    numCopyOrMoveConstructors(0),
    definedType(nullptr),
    functionOf(nullptr),
    function(nullptr),
    enumType(nullptr),
    enumClass(false)
{
    const Token *nameTok = classDef;
    if (!classDef) {
        type = Scope::eGlobal;
    } else if (classDef->str() == "class" && check && check->isCPP()) {
        type = Scope::eClass;
        nameTok = nameTok->next();
    } else if (classDef->str() == "struct") {
        type = Scope::eStruct;
        nameTok = nameTok->next();
    } else if (classDef->str() == "union") {
        type = Scope::eUnion;
        nameTok = nameTok->next();
    } else if (classDef->str() == "namespace") {
        type = Scope::eNamespace;
        nameTok = nameTok->next();
    } else if (classDef->str() == "enum") {
        type = Scope::eEnum;
        nameTok = nameTok->next();
        if (nameTok->str() == "class") {
            enumClass = true;
            nameTok = nameTok->next();
        }
    } else if (classDef->str() == "[") {
        type = Scope::eLambda;
    } else {
        type = Scope::eFunction;
    }
    // skip over qualification if present
    nameTok = skipScopeIdentifiers(nameTok);
    if (nameTok && ((type == Scope::eEnum && Token::Match(nameTok, ":|{")) || nameTok->str() != "{")) // anonymous and unnamed structs/unions don't have a name
        className = nameTok->str();
}

bool Scope::hasDefaultConstructor() const
{
    if (numConstructors) {
        std::list<Function>::const_iterator func;

        for (func = functionList.begin(); func != functionList.end(); ++func) {
            if (func->type == Function::eConstructor && func->argCount() == 0)
                return true;
        }
    }
    return false;
}

AccessControl Scope::defaultAccess() const
{
    switch (type) {
    case eGlobal:
        return AccessControl::Global;
    case eClass:
        return AccessControl::Private;
    case eStruct:
        return AccessControl::Public;
    case eUnion:
        return AccessControl::Public;
    case eNamespace:
        return AccessControl::Namespace;
    default:
        return AccessControl::Local;
    }
}

void Scope::addVariable(const Token *token_, const Token *start_, const Token *end_,
                        AccessControl access_, const Type *type_, const Scope *scope_, const Settings* settings)
{
    // keep possible size_t -> int truncation outside emplace_back() to have a single line
    // C4267 VC++ warning instead of several dozens lines
    const int varIndex = varlist.size();
    varlist.emplace_back(token_, start_, end_, varIndex, access_, type_, scope_, settings);
}

// Get variable list..
void Scope::getVariableList(const Settings* settings)
{
    const Token *start;

    if (bodyStart)
        start = bodyStart->next();

    // global scope
    else if (className.empty())
        start = check->mTokenizer->tokens();

    // forward declaration
    else
        return;

    // Variable declared in condition: if (auto x = bar())
    if (Token::Match(classDef, "if|while ( %type%") && Token::simpleMatch(classDef->next()->astOperand2(), "=")) {
        checkVariable(classDef->tokAt(2), defaultAccess(), settings);
    }

    AccessControl varaccess = defaultAccess();
    for (const Token *tok = start; tok && tok != bodyEnd; tok = tok->next()) {
        // syntax error?
        if (tok->next() == nullptr)
            break;

        // Is it a function?
        else if (tok->str() == "{") {

            tok = tok->link();
            continue;
        }

        // Is it a nested class or structure?
        else if (tok->isKeyword() && Token::Match(tok, "class|struct|union|namespace %type% :|{")) {
            tok = tok->tokAt(2);
            while (tok && tok->str() != "{")
                tok = tok->next();
            if (tok) {
                // skip implementation
                tok = tok->link();
                continue;
            } else
                break;
        } else if (tok->isKeyword() && Token::Match(tok, "struct|union {")) {
            if (Token::Match(tok->next()->link(), "} %name% ;|[")) {
                tok = tok->next()->link()->tokAt(2);
                continue;
            } else if (Token::simpleMatch(tok->next()->link(), "} ;")) {
                tok = tok->next();
                continue;
            }
        }

        // Borland C++: Skip all variables in the __published section.
        // These are automatically initialized.
        else if (tok->str() == "__published:") {
            for (; tok; tok = tok->next()) {
                if (tok->str() == "{")
                    tok = tok->link();
                if (Token::Match(tok->next(), "private:|protected:|public:"))
                    break;
            }
            if (tok)
                continue;
            else
                break;
        }

        // "private:" "public:" "protected:" etc
        else if (tok->str() == "public:") {
            varaccess = AccessControl::Public;
            continue;
        } else if (tok->str() == "protected:") {
            varaccess = AccessControl::Protected;
            continue;
        } else if (tok->str() == "private:") {
            varaccess = AccessControl::Private;
            continue;
        }

        // Is it a forward declaration?
        else if (tok->isKeyword() && Token::Match(tok, "class|struct|union %name% ;")) {
            tok = tok->tokAt(2);
            continue;
        }

        // Borland C++: Ignore properties..
        else if (tok->str() == "__property")
            continue;

        // skip return, goto and delete
        else if (tok->isKeyword() && Token::Match(tok, "return|delete|goto")) {
            while (tok->next() &&
                   tok->next()->str() != ";" &&
                   tok->next()->str() != "}" /* ticket #4994 */) {
                tok = tok->next();
            }
            continue;
        }

        // skip case/default
        if (tok->isKeyword() && Token::Match(tok, "case|default")) {
            while (tok->next() && !Token::Match(tok->next(), "[:;{}]"))
                tok = tok->next();
            continue;
        }

        // Search for start of statement..
        else if (tok->previous() && !Token::Match(tok->previous(), ";|{|}|public:|protected:|private:"))
            continue;
        else if (tok->str() == ";")
            continue;

        tok = checkVariable(tok, varaccess, settings);

        if (!tok)
            break;
    }
}

const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess, const Settings* settings)
{
    // Is it a throw..?
    if (tok->isKeyword() && Token::Match(tok, "throw %any% (") &&
        Token::simpleMatch(tok->linkAt(2), ") ;")) {
        return tok->linkAt(2);
    }

    if (tok->isKeyword() && Token::Match(tok, "throw %any% :: %any% (") &&
        Token::simpleMatch(tok->linkAt(4), ") ;")) {
        return tok->linkAt(4);
    }

    // friend?
    if (tok->isKeyword() && Token::Match(tok, "friend %type%") && tok->next()->varId() == 0) {
        const Token *next = Token::findmatch(tok->tokAt(2), ";|{");
        if (next && next->str() == "{")
            next = next->link();
        return next;
    }

    // skip const|volatile|static|mutable|extern
    while (tok->isKeyword() && Token::Match(tok, "const|volatile|static|mutable|extern")) {
        tok = tok->next();
    }

    // the start of the type tokens does not include the above modifiers
    const Token *typestart = tok;

    if (tok->isKeyword() && Token::Match(tok, "class|struct|union|enum")) {
        tok = tok->next();
    }

    // This is the start of a statement
    const Token *vartok = nullptr;
    const Token *typetok = nullptr;

    if (tok && isVariableDeclaration(tok, vartok, typetok)) {
        // If the vartok was set in the if-blocks above, create a entry for this variable..
        tok = vartok->next();
        while (Token::Match(tok, "[|{"))
            tok = tok->link()->next();

        if (vartok->varId() == 0) {
            if (!vartok->isBoolean())
                check->debugMessage(vartok, "Scope::checkVariable found variable \'" + vartok->str() + "\' with varid 0.");
            return tok;
        }

        const Type *vType = nullptr;

        if (typetok) {
            vType = findVariableTypeIncludingUsedNamespaces(check, this, typetok);

            const_cast<Token *>(typetok)->type(vType);
        }

        // skip "enum" or "struct"
        if (Token::Match(typestart, "enum|struct"))
            typestart = typestart->next();

        addVariable(vartok, typestart, vartok->previous(), varaccess, vType, this, settings);
    }

    return tok;
}

const Variable *Scope::getVariable(const std::string &varname) const
{
    std::list<Variable>::const_iterator iter;

    for (iter = varlist.begin(); iter != varlist.end(); ++iter) {
        if (iter->name() == varname)
            return &*iter;
    }

    return nullptr;
}

static const Token* skipPointers(const Token* tok)
{
    while (Token::Match(tok, "*|&|&&")  || (Token::Match(tok, "( [*&]") && Token::Match(tok->link()->next(), "(|["))) {
        tok = tok->next();
        if (tok->strAt(-1) == "(" && Token::Match(tok, "%type% ::"))
            tok = tok->tokAt(2);
    }

    if (Token::simpleMatch(tok, "( *") && Token::simpleMatch(tok->link()->previous(), "] ) ;")) {
        const Token *tok2 = skipPointers(tok->next());
        if (Token::Match(tok2, "%name% [") && Token::simpleMatch(tok2->linkAt(1), "] ) ;"))
            return tok2;
    }

    return tok;
}

static const Token* skipPointersAndQualifiers(const Token* tok)
{
    tok = skipPointers(tok);
    while (Token::Match(tok, "const|volatile")) {
        tok = tok->next();
        tok = skipPointers(tok);
    }

    return tok;
}

bool Scope::isVariableDeclaration(const Token* const tok, const Token*& vartok, const Token*& typetok) const
{
    const bool isCPP = check && check->mTokenizer->isCPP();

    if (isCPP && Token::Match(tok, "throw|new"))
        return false;

    const bool isCPP11 = isCPP && check->mSettings->standards.cpp >= Standards::CPP11;

    if (isCPP11 && tok->str() == "using")
        return false;

    const Token* localTypeTok = skipScopeIdentifiers(tok);
    const Token* localVarTok = nullptr;

    if (Token::Match(localTypeTok, "%type% <")) {
        if (Token::Match(tok, "const_cast|dynamic_cast|reinterpret_cast|static_cast <"))
            return false;

        const Token* closeTok = localTypeTok->next()->link();
        if (closeTok) {
            localVarTok = skipPointers(closeTok->next());

            if (Token::Match(localVarTok, ":: %type% %name% [;=({]")) {
                if (localVarTok->strAt(3) != "(" ||
                    Token::Match(localVarTok->linkAt(3), "[)}] ;")) {
                    localTypeTok = localVarTok->next();
                    localVarTok = localVarTok->tokAt(2);
                }
            }
        }
    } else if (Token::Match(localTypeTok, "%type%")) {
        localVarTok = skipPointersAndQualifiers(localTypeTok->next());
    }

    if (!localVarTok)
        return false;

    if (localVarTok->str() == "const")
        localVarTok = localVarTok->next();

    if (Token::Match(localVarTok, "%name% ;|=") || (localVarTok && localVarTok->varId() && localVarTok->strAt(1) == ":")) {
        vartok = localVarTok;
        typetok = localTypeTok;
    } else if (Token::Match(localVarTok, "%name% )|[") && localVarTok->str() != "operator") {
        vartok = localVarTok;
        typetok = localTypeTok;
    } else if (localVarTok && localVarTok->varId() && Token::Match(localVarTok, "%name% (|{") &&
               Token::Match(localVarTok->next()->link(), ")|} ;")) {
        vartok = localVarTok;
        typetok = localTypeTok;
    } else if (type == eCatch &&
               Token::Match(localVarTok, "%name% )")) {
        vartok = localVarTok;
        typetok = localTypeTok;
    }

    return nullptr != vartok;
}

const Token * Scope::addEnum(const Token * tok, bool isCpp)
{
    const Token * tok2 = tok->next();

    // skip over class if present
    if (isCpp && tok2->str() == "class")
        tok2 = tok2->next();

    // skip over name
    tok2 = tok2->next();

    // save type if present
    if (tok2->str() == ":") {
        tok2 = tok2->next();

        enumType = tok2;
        tok2 = tok2->next();
    }

    // add enumerators
    if (tok2->str() == "{") {
        const Token * end = tok2->link();
        tok2 = tok2->next();

        while (Token::Match(tok2, "%name% =|,|}") ||
               (Token::Match(tok2, "%name% (") && Token::Match(tok2->linkAt(1), ") ,|}"))) {
            Enumerator enumerator(this);

            // save enumerator name
            enumerator.name = tok2;

            // skip over name
            tok2 = tok2->next();

            if (tok2->str() == "=") {
                // skip over "="
                tok2 = tok2->next();

                if (tok2->str() == "}")
                    return nullptr;

                enumerator.start = tok2;

                while (!Token::Match(tok2, ",|}")) {
                    if (tok2->link())
                        tok2 = tok2->link();
                    enumerator.end = tok2;
                    tok2 = tok2->next();
                }
            } else if (tok2->str() == "(") {
                // skip over unknown macro
                tok2 = tok2->link()->next();
            }

            if (tok2->str() == ",") {
                enumeratorList.push_back(enumerator);
                tok2 = tok2->next();
            } else if (tok2->str() == "}") {
                enumeratorList.push_back(enumerator);
                break;
            }
        }

        if (tok2 == end) {
            tok2 = tok2->next();

            if (tok2 && tok2->str() != ";")
                tok2 = nullptr;
        } else
            tok2 = nullptr;
    } else
        tok2 = nullptr;

    return tok2;
}

const Enumerator * SymbolDatabase::findEnumerator(const Token * tok) const
{
    const Scope * scope = tok->scope();

    const std::string &tokStr = tok->str();

    if (mTokensThatAreNotEnumeratorValues.find(tokStr) != mTokensThatAreNotEnumeratorValues.end()) {
        return nullptr;
    }

    // check for qualified name
    if (tok->strAt(-1) == "::") {
        // find first scope
        const Token *tok1 = tok;
        while (Token::Match(tok1->tokAt(-2), "%name% ::"))
            tok1 = tok1->tokAt(-2);

        if (tok1->strAt(-1) == "::")
            scope = &scopeList.front();
        else {
            // FIXME search base class here

            // find first scope
            while (scope && scope->nestedIn) {
                const Scope * temp = scope->nestedIn->findRecordInNestedList(tok1->str());
                if (temp) {
                    scope = temp;
                    break;
                }
                scope = scope->nestedIn;
            }
        }

        if (scope) {
            tok1 = tok1->tokAt(2);
            while (scope && Token::Match(tok1, "%name% ::")) {
                scope = scope->findRecordInNestedList(tok1->str());
                tok1 = tok1->tokAt(2);
            }

            if (scope) {
                const Enumerator * enumerator = scope->findEnumerator(tokStr);

                if (enumerator) // enum class
                    return enumerator;
                // enum
                else {
                    for (std::list<Scope *>::const_iterator it = scope->nestedList.begin(), end = scope->nestedList.end(); it != end; ++it) {
                        enumerator = (*it)->findEnumerator(tokStr);

                        if (enumerator)
                            return enumerator;
                    }
                }
            }
        }
    } else {
        const Enumerator * enumerator = scope->findEnumerator(tokStr);

        if (enumerator)
            return enumerator;

        for (std::list<Scope *>::const_iterator s = scope->nestedList.begin(); s != scope->nestedList.end(); ++s) {
            enumerator = (*s)->findEnumerator(tokStr);

            if (enumerator)
                return enumerator;
        }

        if (scope->definedType) {
            const std::vector<Type::BaseInfo> & derivedFrom = scope->definedType->derivedFrom;
            for (const Type::BaseInfo & i : derivedFrom) {
                const Type *derivedFromType = i.type;
                if (derivedFromType && derivedFromType ->classScope) {
                    enumerator = derivedFromType->classScope->findEnumerator(tokStr);

                    if (enumerator)
                        return enumerator;
                }
            }
        }

        while (scope->nestedIn) {
            if (scope->type == Scope::eFunction && scope->functionOf)
                scope = scope->functionOf;
            else
                scope = scope->nestedIn;

            enumerator = scope->findEnumerator(tokStr);

            if (enumerator)
                return enumerator;

            for (std::list<Scope*>::const_iterator s = scope->nestedList.begin(); s != scope->nestedList.end(); ++s) {
                enumerator = (*s)->findEnumerator(tokStr);

                if (enumerator)
                    return enumerator;
            }
        }
    }

    mTokensThatAreNotEnumeratorValues.insert(tokStr);

    return nullptr;
}

//---------------------------------------------------------------------------

const Type* SymbolDatabase::findVariableTypeInBase(const Scope* scope, const Token* typeTok) const
{
    if (scope && scope->definedType && !scope->definedType->derivedFrom.empty()) {
        const std::vector<Type::BaseInfo> &derivedFrom = scope->definedType->derivedFrom;
        for (const Type::BaseInfo & i : derivedFrom) {
            const Type *base = i.type;
            if (base && base->classScope) {
                const Type * type = base->classScope->findType(typeTok->str());
                if (type)
                    return type;
                type = findVariableTypeInBase(base->classScope, typeTok);
                if (type)
                    return type;
            }
        }
    }

    return nullptr;
}

//---------------------------------------------------------------------------

const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *typeTok) const
{
    const Scope *scope = start;

    // check if type does not have a namespace
    if (typeTok->strAt(-1) != "::" && typeTok->strAt(1) != "::") {
        // check if type same as scope
        if (start->isClassOrStruct() && typeTok->str() == start->className)
            return start->definedType;

        while (scope) {
            // look for type in this scope
            const Type * type = scope->findType(typeTok->str());

            if (type)
                return type;

            // look for type in base classes if possible
            if (scope->isClassOrStruct()) {
                type = findVariableTypeInBase(scope, typeTok);

                if (type)
                    return type;
            }

            // check if in member function class to see if it's present in class
            if (scope->type == Scope::eFunction && scope->functionOf) {
                const Scope *scope1 = scope->functionOf;

                type = scope1->findType(typeTok->str());

                if (type)
                    return type;

                type = findVariableTypeInBase(scope1, typeTok);

                if (type)
                    return type;
            }

            scope = scope->nestedIn;
        }
    }

    // check for a qualified name and use it when given
    else if (typeTok->strAt(-1) == "::") {
        // check if type is not part of qualification
        if (typeTok->strAt(1) == "::")
            return nullptr;

        // find start of qualified function name
        const Token *tok1 = typeTok;

        while (Token::Match(tok1->tokAt(-2), "%type% ::") ||
               (Token::simpleMatch(tok1->tokAt(-2), "> ::") && tok1->linkAt(-2) && Token::Match(tok1->linkAt(-2)->tokAt(-1), "%type%"))) {
            if (tok1->strAt(-1) == "::")
                tok1 = tok1->tokAt(-2);
            else
                tok1 = tok1->linkAt(-2)->tokAt(-1);
        }

        // check for global scope
        if (tok1->strAt(-1) == "::") {
            scope = &scopeList.front();

            scope = scope->findRecordInNestedList(tok1->str());
        }

        // find start of qualification
        else {
            while (scope) {
                if (scope->className == tok1->str())
                    break;
                else {
                    const Scope *scope1 = scope->findRecordInNestedList(tok1->str());

                    if (scope1) {
                        scope = scope1;
                        break;
                    } else if (scope->type == Scope::eFunction && scope->functionOf)
                        scope = scope->functionOf;
                    else
                        scope = scope->nestedIn;
                }
            }
        }

        if (scope) {
            // follow qualification
            while (scope && (Token::Match(tok1, "%type% ::") ||
                             (Token::Match(tok1, "%type% <") && Token::simpleMatch(tok1->linkAt(1), "> ::")))) {
                if (tok1->strAt(1) == "::")
                    tok1 = tok1->tokAt(2);
                else
                    tok1 = tok1->linkAt(1)->tokAt(2);
                const Scope * temp = scope->findRecordInNestedList(tok1->str());
                if (!temp) {
                    // look in base classes
                    const Type * type = findVariableTypeInBase(scope, tok1);

                    if (type)
                        return type;
                }
                scope = temp;
            }

            if (scope && scope->definedType)
                return scope->definedType;
        }
    }

    return nullptr;
}

bool Scope::hasInlineOrLambdaFunction() const
{
    for (const Scope *s : nestedList) {
        // Inline function
        if (s->type == Scope::eUnconditional && Token::simpleMatch(s->bodyStart->previous(), ") {"))
            return true;
        // Lambda function
        if (s->type == Scope::eLambda)
            return true;
        if (s->hasInlineOrLambdaFunction())
            return true;
    }
    return false;
}

void Scope::findFunctionInBase(const std::string & name, nonneg int args, std::vector<const Function *> & matches) const
{
    if (isClassOrStruct() && definedType && !definedType->derivedFrom.empty()) {
        const std::vector<Type::BaseInfo> &derivedFrom = definedType->derivedFrom;
        for (const Type::BaseInfo & i : derivedFrom) {
            const Type *base = i.type;
            if (base && base->classScope) {
                if (base->classScope == this) // Ticket #5120, #5125: Recursive class; tok should have been found already
                    continue;

                for (std::multimap<std::string, const Function *>::const_iterator it = base->classScope->functionMap.find(name); it != base->classScope->functionMap.end() && it->first == name; ++it) {
                    const Function *func = it->second;
                    if (args == func->argCount() || (args < func->argCount() && args >= func->minArgCount())) {
                        matches.push_back(func);
                    }
                }

                base->classScope->findFunctionInBase(name, args, matches);
            }
        }
    }
}

//---------------------------------------------------------------------------

static void checkVariableCallMatch(const Variable* callarg, const Variable* funcarg, size_t& same, size_t& fallback1, size_t& fallback2)
{
    if (callarg) {
        ValueType::MatchResult res = ValueType::matchParameter(callarg->valueType(), callarg, funcarg);
        if (res == ValueType::MatchResult::SAME) {
            same++;
            return;
        }
        if (res == ValueType::MatchResult::FALLBACK1) {
            fallback1++;
            return;
        }
        if (res == ValueType::MatchResult::FALLBACK2) {
            fallback2++;
            return;
        }
        if (res == ValueType::MatchResult::NOMATCH)
            return;

        bool ptrequals = callarg->isArrayOrPointer() == funcarg->isArrayOrPointer();
        bool constEquals = !callarg->isArrayOrPointer() || ((callarg->typeStartToken()->strAt(-1) == "const") == (funcarg->typeStartToken()->strAt(-1) == "const"));
        if (ptrequals && constEquals &&
            callarg->typeStartToken()->str() == funcarg->typeStartToken()->str() &&
            callarg->typeStartToken()->isUnsigned() == funcarg->typeStartToken()->isUnsigned() &&
            callarg->typeStartToken()->isLong() == funcarg->typeStartToken()->isLong()) {
            same++;
        } else if (callarg->isArrayOrPointer()) {
            if (ptrequals && constEquals && funcarg->typeStartToken()->str() == "void")
                fallback1++;
            else if (constEquals && funcarg->isStlStringType() && Token::Match(callarg->typeStartToken(), "char|wchar_t"))
                fallback2++;
        } else if (ptrequals) {
            const bool takesInt = Token::Match(funcarg->typeStartToken(), "char|short|int|long");
            const bool takesFloat = Token::Match(funcarg->typeStartToken(), "float|double");
            const bool passesInt = Token::Match(callarg->typeStartToken(), "char|short|int|long");
            const bool passesFloat = Token::Match(callarg->typeStartToken(), "float|double");
            if ((takesInt && passesInt) || (takesFloat && passesFloat))
                fallback1++;
            else if ((takesInt && passesFloat) || (takesFloat && passesInt))
                fallback2++;
        }
    }
}

static std::string getTypeString(const Token *typeToken)
{
    if (!typeToken)
        return "";
    while (Token::Match(typeToken, "%name%|*|&|::")) {
        if (typeToken->str() == "::") {
            std::string ret;
            while (Token::Match(typeToken, ":: %name%")) {
                ret += "::" + typeToken->strAt(1);
                typeToken = typeToken->tokAt(2);
            }
            if (typeToken->str() == "<") {
                for (const Token *tok = typeToken; tok != typeToken->link(); tok = tok->next())
                    ret += tok->str();
                ret += ">";
            }
            return ret;
        }
        if (Token::Match(typeToken, "%name% const| %var%|*|&")) {
            return typeToken->str();
        }
        typeToken = typeToken->next();
    }
    return "";
}

const Function* Scope::findFunction(const Token *tok, bool requireConst) const
{
    const bool isCall = Token::Match(tok->next(), "(|{");

    const std::vector<const Token *> arguments = getArguments(tok);

    std::vector<const Function *> matches;

    // find all the possible functions that could match
    const std::size_t args = arguments.size();

    auto addMatchingFunctions = [&](const Scope *scope) {
        for (std::multimap<std::string, const Function *>::const_iterator it = scope->functionMap.find(tok->str()); it != scope->functionMap.cend() && it->first == tok->str(); ++it) {
            const Function *func = it->second;
            if (!isCall || args == func->argCount() ||
                (func->isVariadic() && args >= (func->argCount() - 1)) ||
                (args < func->argCount() && args >= func->minArgCount())) {
                matches.push_back(func);
            }
        }
    };

    addMatchingFunctions(this);

    // check in anonumous namespaces
    for (const Scope *nestedScope : nestedList) {
        if (nestedScope->type == eNamespace && nestedScope->className.empty())
            addMatchingFunctions(nestedScope);
    }

    // check in base classes
    findFunctionInBase(tok->str(), args, matches);

    // Non-call => Do not match parameters
    if (!isCall) {
        return matches.empty() ? nullptr : matches[0];
    }

    const Function* fallback1Func = nullptr;
    const Function* fallback2Func = nullptr;

    // check each function against the arguments in the function call for a match
    for (std::size_t i = 0; i < matches.size();) {
        bool constFallback = false;
        const Function * func = matches[i];
        size_t same = 0;

        if (requireConst && !func->isConst()) {
            i++;
            continue;
        }

        if (!requireConst || !func->isConst()) {
            // get the function this call is in
            const Scope * scope = tok->scope();

            // check if this function is a member function
            if (scope && scope->functionOf && scope->functionOf->isClassOrStruct() && scope->function) {
                // check if isConst mismatches
                if (scope->function->isConst() != func->isConst()) {
                    if (scope->function->isConst()) {
                        ++i;
                        continue;
                    }
                    constFallback = true;
                }
            }
        }

        size_t fallback1 = 0;
        size_t fallback2 = 0;
        bool erased = false;
        for (std::size_t j = 0; j < args; ++j) {

            // don't check variadic arguments
            if (func->isVariadic() && j > (func->argCount() - 1)) {
                break;
            }
            const Variable *funcarg = func->getArgumentVar(j);

            if (!arguments[j]->valueType()) {
                const Token *vartok = arguments[j];
                int pointer = 0;
                while (vartok && (vartok->isUnaryOp("&") || vartok->isUnaryOp("*"))) {
                    pointer += vartok->isUnaryOp("&") ? 1 : -1;
                    vartok = vartok->astOperand1();
                }
                if (vartok && vartok->variable()) {
                    const Token *callArgTypeToken = vartok->variable()->typeStartToken();
                    const Token *funcArgTypeToken = funcarg->typeStartToken();

                    auto parseDecl = [](const Token *typeToken) -> ValueType {
                        ValueType ret;
                        while (Token::Match(typeToken->previous(), "%name%"))
                            typeToken = typeToken->previous();
                        while (Token::Match(typeToken, "%name%|*|&|::|<"))
                        {
                            if (typeToken->str() == "const")
                                ret.constness |= (1 << ret.pointer);
                            else if (typeToken->str() == "*")
                                ret.pointer++;
                            else if (typeToken->str() == "<") {
                                if (!typeToken->link())
                                    break;
                                typeToken = typeToken->link();
                            }
                            typeToken = typeToken->next();
                        }
                        return ret;
                    };

                    const std::string type1 = getTypeString(callArgTypeToken);
                    const std::string type2 = getTypeString(funcArgTypeToken);
                    if (!type1.empty() && type1 == type2) {
                        ValueType callArgType = parseDecl(callArgTypeToken);
                        callArgType.pointer += pointer;
                        ValueType funcArgType = parseDecl(funcArgTypeToken);

                        callArgType.sign = funcArgType.sign = ValueType::Sign::SIGNED;
                        callArgType.type = funcArgType.type = ValueType::Type::INT;

                        ValueType::MatchResult res = ValueType::matchParameter(&callArgType, &funcArgType);
                        if (res == ValueType::MatchResult::SAME)
                            ++same;
                        else if (res == ValueType::MatchResult::FALLBACK1)
                            ++fallback1;
                        else if (res == ValueType::MatchResult::FALLBACK2)
                            ++fallback2;
                        continue;
                    }
                }
            }

            // check for a match with a variable
            if (Token::Match(arguments[j], "%var% ,|)")) {
                const Variable * callarg = arguments[j]->variable();
                checkVariableCallMatch(callarg, funcarg, same, fallback1, fallback2);
            }

            else if (funcarg->isStlStringType() && arguments[j]->valueType() && arguments[j]->valueType()->pointer == 1 && arguments[j]->valueType()->type == ValueType::Type::CHAR)
                fallback2++;

            // check for a match with nullptr
            else if (funcarg->isPointer() && Token::Match(arguments[j], "nullptr|NULL ,|)"))
                same++;

            else if (funcarg->isPointer() && MathLib::isNullValue(arguments[j]->str()))
                fallback1++;

            // Try to evaluate the apparently more complex expression
            else if (check->isCPP()) {
                const Token *vartok = arguments[j];
                while (vartok->isUnaryOp("&") || vartok->isUnaryOp("*"))
                    vartok = vartok->astOperand1();
                ValueType::MatchResult res = ValueType::matchParameter(arguments[j]->valueType(), vartok->variable(), funcarg);
                if (res == ValueType::MatchResult::SAME)
                    ++same;
                else if (res == ValueType::MatchResult::FALLBACK1)
                    ++fallback1;
                else if (res == ValueType::MatchResult::FALLBACK2)
                    ++fallback2;
                else if (res == ValueType::MatchResult::NOMATCH) {
                    // can't match so remove this function from possible matches
                    matches.erase(matches.begin() + i);
                    erased = true;
                    break;
                }
            }

            else
                // C code: if number of arguments match then do not match types
                fallback1++;
        }

        const size_t hasToBe = func->isVariadic() ? (func->argCount() - 1) : args;

        // check if all arguments matched
        if (same == hasToBe) {
            if (constFallback || (!requireConst && func->isConst()))
                fallback1Func = func;
            else
                return func;
        }

        else if (!fallback1Func) {
            if (same + fallback1 == hasToBe)
                fallback1Func = func;
            else if (!fallback2Func && same + fallback2 + fallback1 == hasToBe)
                fallback2Func = func;
        }

        if (!erased)
            ++i;
    }

    // Fallback cases
    if (fallback1Func)
        return fallback1Func;

    if (fallback2Func)
        return fallback2Func;

    // Only one candidate left
    if (matches.size() == 1)
        return matches[0];

    return nullptr;
}

//---------------------------------------------------------------------------

const Function* SymbolDatabase::findFunction(const Token *tok) const
{
    // find the scope this function is in
    const Scope *currScope = tok->scope();
    while (currScope && currScope->isExecutable()) {
        if (currScope->functionOf)
            currScope = currScope->functionOf;
        else
            currScope = currScope->nestedIn;
    }

    // check for a qualified name and use it when given
    if (tok->strAt(-1) == "::") {
        // find start of qualified function name
        const Token *tok1 = tok;

        while (Token::Match(tok1->tokAt(-2), ">|%type% ::")) {
            if (tok1->strAt(-2) == ">") {
                if (tok1->linkAt(-2))
                    tok1 = tok1->linkAt(-2)->tokAt(-1);
                else {
                    if (mSettings->debugwarnings)
                        debugMessage(tok1->tokAt(-2), "SymbolDatabase::findFunction found '>' without link.");
                    return nullptr;
                }
            } else
                tok1 = tok1->tokAt(-2);
        }

        // check for global scope
        if (tok1->strAt(-1) == "::") {
            currScope = &scopeList.front();

            if (Token::Match(tok1, "%name% ("))
                return currScope->findFunction(tok);

            currScope = currScope->findRecordInNestedList(tok1->str());
        }

        // find start of qualification
        else {
            while (currScope) {
                if (currScope->className == tok1->str())
                    break;
                else {
                    const Scope *scope = currScope->findRecordInNestedList(tok1->str());

                    if (scope) {
                        currScope = scope;
                        break;
                    } else
                        currScope = currScope->nestedIn;
                }
            }
        }

        if (currScope) {
            while (currScope && !(Token::Match(tok1, "%type% :: %name% [(),>]") ||
                                  (Token::Match(tok1, "%type% <") && Token::Match(tok1->linkAt(1), "> :: %name% (")))) {
                if (tok1->strAt(1) == "::")
                    tok1 = tok1->tokAt(2);
                else
                    tok1 = tok1->linkAt(1)->tokAt(2);
                currScope = currScope->findRecordInNestedList(tok1->str());
            }

            tok1 = tok1->tokAt(2);

            if (currScope && tok1)
                return currScope->findFunction(tok1);
        }
    }

    // check for member function
    else if (Token::Match(tok->tokAt(-2), "!!this .")) {
        const Token *tok1 = tok->tokAt(-2);
        if (Token::Match(tok1, "%var% .")) {
            const Variable *var = getVariableFromVarId(tok1->varId());
            if (var && var->typeScope())
                return var->typeScope()->findFunction(tok, var->valueType()->constness == 1);
            if (var && var->smartPointerType() && var->smartPointerType()->classScope && tok1->next()->originalName() == "->")
                return var->smartPointerType()->classScope->findFunction(tok, var->valueType()->constness == 1);
        } else if (Token::simpleMatch(tok->previous()->astOperand1(), "(")) {
            const Token *castTok = tok->previous()->astOperand1();
            if (castTok->isCast()) {
                ValueType vt = ValueType::parseDecl(castTok->next(),mSettings);
                if (vt.typeScope)
                    return vt.typeScope->findFunction(tok, vt.constness == 1);
            }
        }
    }

    // check in enclosing scopes
    else {
        while (currScope) {
            const Function *func = currScope->findFunction(tok);
            if (func)
                return func;
            currScope = currScope->nestedIn;
        }
    }
    return nullptr;
}

//---------------------------------------------------------------------------

const Scope *SymbolDatabase::findScopeByName(const std::string& name) const
{
    for (std::list<Scope>::const_iterator it = scopeList.begin(); it != scopeList.end(); ++it) {
        if (it->className == name)
            return &*it;
    }
    return nullptr;
}

//---------------------------------------------------------------------------

Scope *Scope::findInNestedList(const std::string & name)
{
    std::list<Scope *>::iterator it;

    for (it = nestedList.begin(); it != nestedList.end(); ++it) {
        if ((*it)->className == name)
            return (*it);
    }
    return nullptr;
}

//---------------------------------------------------------------------------

const Scope *Scope::findRecordInNestedList(const std::string & name) const
{
    std::list<Scope *>::const_iterator it;

    for (it = nestedList.begin(); it != nestedList.end(); ++it) {
        if ((*it)->className == name && (*it)->type != eFunction)
            return (*it);
    }

    const Type * nested_type = findType(name);

    if (nested_type) {
        if (nested_type->isTypeAlias()) {
            if (nested_type->typeStart == nested_type->typeEnd)
                return findRecordInNestedList(nested_type->typeStart->str());
        } else
            return nested_type->classScope;
    }

    return nullptr;
}

//---------------------------------------------------------------------------

const Type* Scope::findType(const std::string & name) const
{
    auto it = definedTypesMap.find(name);

    // Type was found
    if (definedTypesMap.end() != it)
        return (*it).second;

    // is type defined in anonymous namespace..
    it = definedTypesMap.find("");
    if (it != definedTypesMap.end()) {
        for (const Scope *scope : nestedList) {
            if (scope->className.empty() && (scope->type == eNamespace || scope->isClassOrStructOrUnion())) {
                const Type *t = scope->findType(name);
                if (t)
                    return t;
            }
        }
    }

    // Type was not found
    return nullptr;
}

//---------------------------------------------------------------------------

Scope *Scope::findInNestedListRecursive(const std::string & name)
{
    std::list<Scope *>::iterator it;

    for (it = nestedList.begin(); it != nestedList.end(); ++it) {
        if ((*it)->className == name)
            return (*it);
    }

    for (it = nestedList.begin(); it != nestedList.end(); ++it) {
        Scope *child = (*it)->findInNestedListRecursive(name);
        if (child)
            return child;
    }
    return nullptr;
}

//---------------------------------------------------------------------------

const Function *Scope::getDestructor() const
{
    std::list<Function>::const_iterator it;
    for (it = functionList.begin(); it != functionList.end(); ++it) {
        if (it->type == Function::eDestructor)
            return &(*it);
    }
    return nullptr;
}

//---------------------------------------------------------------------------

bool SymbolDatabase::isCPP() const
{
    return mTokenizer->isCPP();
}

//---------------------------------------------------------------------------

const Scope *SymbolDatabase::findScope(const Token *tok, const Scope *startScope) const
{
    const Scope *scope = nullptr;
    // absolute path
    if (tok->str() == "::") {
        tok = tok->next();
        scope = &scopeList.front();
    }
    // relative path
    else if (tok->isName()) {
        scope = startScope;
    }

    while (scope && tok && tok->isName()) {
        if (tok->strAt(1) == "::") {
            scope = scope->findRecordInNestedList(tok->str());
            tok = tok->tokAt(2);
        } else if (tok->strAt(1) == "<" && Token::simpleMatch(tok->linkAt(1), "> ::")) {
            scope = scope->findRecordInNestedList(tok->str());
            tok = tok->linkAt(1)->tokAt(2);
        } else
            return scope->findRecordInNestedList(tok->str());
    }

    // not a valid path
    return nullptr;
}

//---------------------------------------------------------------------------

const Type* SymbolDatabase::findType(const Token *startTok, const Scope *startScope) const
{
    // skip over struct or union
    if (Token::Match(startTok, "struct|union"))
        startTok = startTok->next();

    // type same as scope
    if (startTok->str() == startScope->className && startScope->isClassOrStruct() && startTok->strAt(1) != "::")
        return startScope->definedType;

    const Scope* start_scope = startScope;

    // absolute path - directly start in global scope
    if (startTok->str() == "::") {
        startTok = startTok->next();
        start_scope = &scopeList.front();
    }

    const Token* tok = startTok;
    const Scope* scope = start_scope;

    while (scope && tok && tok->isName()) {
        if (tok->strAt(1) == "::" || (tok->strAt(1) == "<" && Token::simpleMatch(tok->linkAt(1), "> ::"))) {
            scope = scope->findRecordInNestedList(tok->str());
            if (scope) {
                if (tok->strAt(1) == "::")
                    tok = tok->tokAt(2);
                else
                    tok = tok->linkAt(1)->tokAt(2);
            } else {
                start_scope = start_scope->nestedIn;
                if (!start_scope)
                    break;
                scope = start_scope;
                tok = startTok;
            }
        } else {
            const Type * type = scope->findType(tok->str());
            if (type)
                return type;
            else
                break;
        }
    }

    // check using namespaces
    while (startScope) {
        for (std::list<Scope::UsingInfo>::const_iterator it = startScope->usingList.begin();
             it != startScope->usingList.end(); ++it) {
            tok = startTok;
            scope = it->scope;
            start_scope = startScope;

            while (scope && tok && tok->isName()) {
                if (tok->strAt(1) == "::" || (tok->strAt(1) == "<" && Token::simpleMatch(tok->linkAt(1), "> ::"))) {
                    scope = scope->findRecordInNestedList(tok->str());
                    if (scope) {
                        if (tok->strAt(1) == "::")
                            tok = tok->tokAt(2);
                        else
                            tok = tok->linkAt(1)->tokAt(2);
                    } else {
                        start_scope = start_scope->nestedIn;
                        if (!start_scope)
                            break;
                        scope = start_scope;
                        tok = startTok;
                    }
                } else {
                    const Type * type = scope->findType(tok->str());
                    if (type)
                        return type;
                    else
                        break;
                }
            }
        }
        startScope = startScope->nestedIn;
    }

    // not a valid path
    return nullptr;
}

//---------------------------------------------------------------------------

const Type* SymbolDatabase::findTypeInNested(const Token *startTok, const Scope *startScope) const
{
    // skip over struct or union
    if (Token::Match(startTok, "struct|union|enum"))
        startTok = startTok->next();

    // type same as scope
    if (startTok->str() == startScope->className && startScope->isClassOrStruct())
        return startScope->definedType;

    bool hasPath = false;

    // absolute path - directly start in global scope
    if (startTok->str() == "::") {
        hasPath = true;
        startTok = startTok->next();
        startScope = &scopeList.front();
    }

    const Token* tok = startTok;
    const Scope* scope = startScope;

    while (scope && tok && tok->isName()) {
        if (tok->strAt(1) == "::" || (tok->strAt(1) == "<" && Token::simpleMatch(tok->linkAt(1), "> ::"))) {
            hasPath = true;
            scope = scope->findRecordInNestedList(tok->str());
            if (scope) {
                if (tok->strAt(1) == "::")
                    tok = tok->tokAt(2);
                else
                    tok = tok->linkAt(1)->tokAt(2);
            } else {
                startScope = startScope->nestedIn;
                if (!startScope)
                    break;
                scope = startScope;
                tok = startTok;
            }
        } else {
            const Type * type = scope->findType(tok->str());
            if (hasPath || type)
                return type;
            else {
                scope = scope->nestedIn;
                if (!scope)
                    break;
            }
        }
    }

    // not a valid path
    return nullptr;
}

//---------------------------------------------------------------------------

const Scope * SymbolDatabase::findNamespace(const Token * tok, const Scope * scope) const
{
    const Scope * s = findScope(tok, scope);

    if (s)
        return s;
    else if (scope->nestedIn)
        return findNamespace(tok, scope->nestedIn);

    return nullptr;
}

//---------------------------------------------------------------------------

Function * SymbolDatabase::findFunctionInScope(const Token *func, const Scope *ns, const std::string & path, nonneg int path_length)
{
    const Function * function = nullptr;
    const bool destructor = func->strAt(-1) == "~";

    for (std::multimap<std::string, const Function *>::const_iterator it = ns->functionMap.find(func->str());
         it != ns->functionMap.end() && it->first == func->str(); ++it) {

        if (Function::argsMatch(ns, it->second->argDef, func->next(), path, path_length) &&
            it->second->isDestructor() == destructor) {
            function = it->second;
            break;
        }
    }

    if (!function) {
        const Scope * scope = ns->findRecordInNestedList(func->str());
        if (scope && Token::Match(func->tokAt(1), "::|<")) {
            if (func->strAt(1) == "::")
                func = func->tokAt(2);
            else if (func->linkAt(1))
                func = func->linkAt(1)->tokAt(2);
            else
                return nullptr;
            if (func->str() == "~")
                func = func->next();
            function = findFunctionInScope(func, scope, path, path_length);
        }
    }

    return const_cast<Function *>(function);
}

//---------------------------------------------------------------------------

namespace {

#define C_KEYWORDS\
    "_Bool", "auto", "break", "case", "char", "const", "continue", "default", "do",\
        "double", "else", "enum", "extern", "float", "for", "goto", "if", "inline",\
        "int", "long", "register", "restrict", "return", "short", "signed", "sizeof",\
        "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile",\
        "while"

    const std::set<std::string> c_keywords = { C_KEYWORDS };
    const std::set<std::string> cpp_keywords = {
        C_KEYWORDS,
        "alignas", "alignof", "and", "and_eq", "asm", "bitand", "bitor", "bool", "catch", "class", "compl",
        "concept", "constexpr", "const_cast", "decltype",
        "delete", "dynamic_cast", "explicit", "export", "false", "friend",
        "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator",
        "or", "or_eq", "private", "protected", "public", "reinterpret_cast",
        "requires", "static_assert",
        "static_cast", "template", "this", "thread_local", "throw",
        "true", "try", "typeid", "typename", "using",
        "virtual", "wchar_t", "xor", "xor_eq"
    };
}

bool SymbolDatabase::isReservedName(const std::string& iName) const
{
    if (isCPP())
        return cpp_keywords.find(iName) != cpp_keywords.cend();
    else
        return c_keywords.find(iName) != c_keywords.cend();
}

nonneg int SymbolDatabase::sizeOfType(const Token *type) const
{
    int size = mTokenizer->sizeOfType(type);

    if (size == 0 && type->type() && type->type()->isEnumType() && type->type()->classScope) {
        size = mSettings->sizeof_int;
        const Token * enum_type = type->type()->classScope->enumType;
        if (enum_type)
            size = mTokenizer->sizeOfType(enum_type);
    }

    return size;
}

static const Token * parsedecl(const Token *type, ValueType * const valuetype, ValueType::Sign defaultSignedness, const Settings* settings);

void SymbolDatabase::setValueType(Token *tok, const Variable &var)
{
    ValueType valuetype;
    if (var.nameToken())
        valuetype.bits = var.nameToken()->bits();
    valuetype.pointer = var.dimensions().size();
    valuetype.typeScope = var.typeScope();
    if (var.valueType()) {
        valuetype.container = var.valueType()->container;
    }
    valuetype.smartPointerType = var.smartPointerType();
    if (parsedecl(var.typeStartToken(), &valuetype, mDefaultSignedness, mSettings)) {
        if (tok->str() == "." && tok->astOperand1()) {
            const ValueType * const vt = tok->astOperand1()->valueType();
            if (vt && (vt->constness & 1) != 0)
                valuetype.constness |= 1;
        }
        setValueType(tok, valuetype);
    }
}

void SymbolDatabase::setValueType(Token *tok, const Enumerator &enumerator)
{
    ValueType valuetype;
    valuetype.typeScope = enumerator.scope;
    const Token * type = enumerator.scope->enumType;
    if (type) {
        valuetype.type = ValueType::typeFromString(type->str(), type->isLong());
        if (valuetype.type == ValueType::Type::UNKNOWN_TYPE && type->isStandardType())
            valuetype.fromLibraryType(type->str(), mSettings);

        if (valuetype.isIntegral()) {
            if (type->isSigned())
                valuetype.sign = ValueType::Sign::SIGNED;
            else if (type->isUnsigned())
                valuetype.sign = ValueType::Sign::UNSIGNED;
            else if (valuetype.type == ValueType::Type::CHAR)
                valuetype.sign = mDefaultSignedness;
            else
                valuetype.sign = ValueType::Sign::SIGNED;
        }

        setValueType(tok, valuetype);
    } else {
        valuetype.sign = ValueType::SIGNED;
        valuetype.type = ValueType::INT;
        setValueType(tok, valuetype);
    }
}

static void setAutoTokenProperties(Token * const autoTok)
{
    const ValueType *valuetype = autoTok->valueType();
    if (valuetype->isIntegral() || valuetype->isFloat())
        autoTok->isStandardType(true);
}

void SymbolDatabase::setValueType(Token *tok, const ValueType &valuetype)
{
    tok->setValueType(new ValueType(valuetype));
    Token *parent = tok->astParent();
    if (!parent || parent->valueType())
        return;
    if (!parent->astOperand1())
        return;

    const ValueType *vt1 = parent->astOperand1() ? parent->astOperand1()->valueType() : nullptr;
    const ValueType *vt2 = parent->astOperand2() ? parent->astOperand2()->valueType() : nullptr;

    if (vt1 && Token::Match(parent, "<<|>>")) {
        if (!mIsCpp || (vt2 && vt2->isIntegral())) {
            if (vt1->type < ValueType::Type::BOOL || vt1->type >= ValueType::Type::INT) {
                ValueType vt(*vt1);
                vt.reference = Reference::None;
                setValueType(parent, vt);
            } else {
                ValueType vt(*vt1);
                vt.type = ValueType::Type::INT; // Integer promotion
                vt.sign = ValueType::Sign::SIGNED;
                vt.reference = Reference::None;
                setValueType(parent, vt);
            }

        }
        return;
    }

    if (vt1 && vt1->container && vt1->containerTypeToken && Token::Match(parent, ". %name% (") && vt1->container->getYield(parent->next()->str()) == Library::Container::Yield::ITEM) {
        ValueType item;
        if (parsedecl(vt1->containerTypeToken, &item, mDefaultSignedness, mSettings))
            setValueType(parent->tokAt(2), item);
    }

    if (vt1 && vt1->smartPointerType && Token::Match(parent, ". %name% (") && parent->originalName() == "->" && !parent->next()->function()) {
        const Scope *scope = vt1->smartPointerType->classScope;
        const Function *f = scope ? scope->findFunction(parent->next(), false) : nullptr;
        if (f)
            parent->next()->function(f);
    }

    if (parent->isAssignmentOp()) {
        if (vt1) {
            auto vt = *vt1;
            vt.reference = Reference::None;
            setValueType(parent, vt);
        } else if (mIsCpp && ((Token::Match(parent->tokAt(-3), "%var% ; %var% =") && parent->strAt(-3) == parent->strAt(-1)) ||
                              Token::Match(parent->tokAt(-1), "%var% ="))) {
            Token *var1Tok = parent->strAt(-2) == ";" ? parent->tokAt(-3) : parent->tokAt(-1);
            Token *autoTok = nullptr;
            if (Token::Match(var1Tok->tokAt(-2), ";|{|}|(|const auto"))
                autoTok = var1Tok->previous();
            else if (Token::Match(var1Tok->tokAt(-3), ";|{|}|(|const auto *"))
                autoTok = var1Tok->tokAt(-2);
            if (autoTok) {
                ValueType vt(*vt2);
                if (vt.constness & (1 << vt.pointer))
                    vt.constness &= ~(1 << vt.pointer);
                if (autoTok->strAt(1) == "*" && vt.pointer)
                    vt.pointer--;
                if (autoTok->strAt(-1) == "const")
                    vt.constness |= 1;
                setValueType(autoTok, vt);
                setAutoTokenProperties(autoTok);
                if (vt2->pointer > vt.pointer)
                    vt.pointer++;
                setValueType(var1Tok, vt);
                if (var1Tok != parent->previous())
                    setValueType(parent->previous(), vt);
                Variable *var = const_cast<Variable *>(parent->previous()->variable());
                if (var) {
                    ValueType vt2_(*vt2);
                    if (vt2_.pointer == 0 && autoTok->strAt(1) == "*")
                        vt2_.pointer = 1;
                    if ((vt.constness & (1 << vt2->pointer)) != 0)
                        vt2_.constness |= (1 << vt2->pointer);
                    if (!Token::Match(autoTok->tokAt(1), "*|&"))
                        vt2_.constness = vt.constness;
                    var->setValueType(vt2_);
                    if (vt2->typeScope && vt2->typeScope->definedType) {
                        var->type(vt2->typeScope->definedType);
                        if (autoTok->valueType()->pointer == 0)
                            autoTok->type(vt2->typeScope->definedType);
                    }
                }
            }
        }
        return;
    }

    if (parent->str() == "[" && (!mIsCpp || parent->astOperand1() == tok) && valuetype.pointer > 0U && !Token::Match(parent->previous(), "[{,]")) {
        const Token *op1 = parent->astOperand1();
        while (op1 && op1->str() == "[")
            op1 = op1->astOperand1();

        ValueType vt(valuetype);
        // the "[" is a dereference unless this is a variable declaration
        if (!(op1 && op1->variable() && op1->variable()->nameToken() == op1))
            vt.pointer -= 1U;
        setValueType(parent, vt);
        return;
    }
    if (Token::Match(parent->previous(), "%name% (") && parent->astOperand1() == tok && valuetype.pointer > 0U) {
        ValueType vt(valuetype);
        vt.pointer -= 1U;
        setValueType(parent, vt);
        return;
    }
    // std::move
    if (vt2 && parent->str() == "(" && Token::simpleMatch(parent->tokAt(-3), "std :: move (")) {
        ValueType vt = valuetype;
        vt.reference = Reference::RValue;
        setValueType(parent, vt);
        return;
    }
    if (parent->str() == "*" && !parent->astOperand2() && valuetype.pointer > 0U) {
        ValueType vt(valuetype);
        vt.pointer -= 1U;
        setValueType(parent, vt);
        return;
    }
    if (parent->str() == "*" && Token::simpleMatch(parent->astOperand2(), "[") && valuetype.pointer > 0U) {
        const Token *op1 = parent->astOperand2()->astOperand1();
        while (op1 && op1->str() == "[")
            op1 = op1->astOperand1();
        ValueType vt(valuetype);
        if (op1 && op1->variable() && op1->variable()->nameToken() == op1) {
            setValueType(parent, vt);
            return;
        }
    }
    if (parent->str() == "&" && !parent->astOperand2()) {
        ValueType vt(valuetype);
        vt.reference = Reference::None; //Given int& x; the type of &x is int* not int&*
        vt.pointer += 1U;
        setValueType(parent, vt);
        return;
    }

    if ((parent->str() == "." || parent->str() == "::") &&
        parent->astOperand2() && parent->astOperand2()->isName()) {
        const Variable* var = parent->astOperand2()->variable();
        if (!var && valuetype.typeScope && vt1) {
            const std::string &name = parent->astOperand2()->str();
            const Scope *typeScope = vt1->typeScope;
            if (!typeScope)
                return;
            for (std::list<Variable>::const_iterator it = typeScope->varlist.begin(); it != typeScope->varlist.end(); ++it) {
                if (it->nameToken()->str() == name) {
                    var = &*it;
                    break;
                }
            }
        }
        if (var)
            setValueType(parent, *var);
        return;
    }

    // range for loop, auto
    if (vt2 &&
        parent->str() == ":" &&
        Token::Match(parent->astParent(), "( const| auto *|&| %var% :") &&
        !parent->previous()->valueType() &&
        Token::simpleMatch(parent->astParent()->astOperand1(), "for")) {
        const bool isconst = Token::simpleMatch(parent->astParent()->next(), "const");
        Token * const autoToken = parent->astParent()->tokAt(isconst ? 2 : 1);
        if (vt2->pointer) {
            ValueType autovt(*vt2);
            autovt.pointer--;
            autovt.constness = 0;
            setValueType(autoToken, autovt);
            setAutoTokenProperties(autoToken);
            ValueType varvt(*vt2);
            varvt.pointer--;
            if (isconst)
                varvt.constness |= 1;
            setValueType(parent->previous(), varvt);
            Variable *var = const_cast<Variable *>(parent->previous()->variable());
            if (var) {
                var->setValueType(varvt);
                if (vt2->typeScope && vt2->typeScope->definedType) {
                    var->type(vt2->typeScope->definedType);
                    autoToken->type(vt2->typeScope->definedType);
                }
            }
        } else if (vt2->container) {
            // TODO: Determine exact type of RHS
            const Token *typeStart = parent->astOperand2();
            while (typeStart) {
                if (typeStart->variable())
                    typeStart = typeStart->variable()->typeStartToken();
                else if (typeStart->str() == "(" && typeStart->previous() && typeStart->previous()->function())
                    typeStart = typeStart->previous()->function()->retDef;
                else
                    break;
            }

            // Try to determine type of "auto" token.
            // TODO: Get type better
            bool setType = false;
            ValueType autovt;
            const Type *templateArgType = nullptr; // container element type / smart pointer type
            if (vt2->containerTypeToken) {
                if (mSettings->library.isSmartPointer(vt2->containerTypeToken)) {
                    const Token *smartPointerTypeTok = vt2->containerTypeToken;
                    while (Token::Match(smartPointerTypeTok, "%name%|::"))
                        smartPointerTypeTok = smartPointerTypeTok->next();
                    if (Token::Match(smartPointerTypeTok, "< %name% > >") && smartPointerTypeTok->next()->type()) {
                        setType = true;
                        templateArgType = smartPointerTypeTok->next()->type();
                        autovt.smartPointerType = templateArgType;
                        autovt.type = ValueType::Type::NONSTD;
                    }
                } else if (parsedecl(vt2->containerTypeToken, &autovt, mDefaultSignedness, mSettings)) {
                    setType = true;
                    templateArgType = vt2->containerTypeToken->type();
                }

            }

            if (setType) {
                // Type of "auto" has been determined.. set type information for "auto" and variable tokens
                setValueType(autoToken, autovt);
                setAutoTokenProperties(autoToken);
                ValueType varvt(autovt);
                if (isconst)
                    varvt.constness |= 1;
                setValueType(parent->previous(), varvt);
                Variable * var = const_cast<Variable *>(parent->previous()->variable());
                if (var) {
                    var->setValueType(varvt);
                    if (templateArgType && templateArgType->classScope && templateArgType->classScope->definedType) {
                        autoToken->type(templateArgType->classScope->definedType);
                        var->type(templateArgType->classScope->definedType);
                    }
                }
            }
        }
    }

    if (vt1 && vt1->containerTypeToken && parent->str() == "[") {
        ValueType vtParent;
        if (parsedecl(vt1->containerTypeToken, &vtParent, mDefaultSignedness, mSettings)) {
            setValueType(parent, vtParent);
            return;
        }
    }

    if (!vt1)
        return;
    if (parent->astOperand2() && !vt2)
        return;

    const bool ternary = parent->str() == ":" && parent->astParent() && parent->astParent()->str() == "?";
    if (ternary) {
        if (vt2 && vt1->pointer == vt2->pointer && vt1->type == vt2->type && vt1->sign == vt2->sign)
            setValueType(parent, *vt2);
        parent = parent->astParent();
    }

    if (ternary || parent->isArithmeticalOp() || parent->tokType() == Token::eIncDecOp) {
        if (vt1->pointer != 0U && vt2 && vt2->pointer == 0U) {
            setValueType(parent, *vt1);
            return;
        }

        if (vt1->pointer == 0U && vt2 && vt2->pointer != 0U) {
            setValueType(parent, *vt2);
            return;
        }

        if (vt1->pointer != 0U) {
            if (ternary || parent->tokType() == Token::eIncDecOp) // result is pointer
                setValueType(parent, *vt1);
            else // result is pointer diff
                setValueType(parent, ValueType(ValueType::Sign::SIGNED, ValueType::Type::INT, 0U, 0U, "ptrdiff_t"));
            return;
        }

        if (vt1->type == ValueType::Type::LONGDOUBLE || (vt2 && vt2->type == ValueType::Type::LONGDOUBLE)) {
            setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::LONGDOUBLE, 0U));
            return;
        }
        if (vt1->type == ValueType::Type::DOUBLE || (vt2 && vt2->type == ValueType::Type::DOUBLE)) {
            setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::DOUBLE, 0U));
            return;
        }
        if (vt1->type == ValueType::Type::FLOAT || (vt2 && vt2->type == ValueType::Type::FLOAT)) {
            setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::FLOAT, 0U));
            return;
        }

        // iterator +/- integral = iterator
        if (vt1->type == ValueType::Type::ITERATOR && vt2 && vt2->isIntegral() &&
            (parent->str() == "+" || parent->str() == "-")) {
            setValueType(parent, *vt1);
            return;
        }

        if (parent->str() == "+" && vt1->type == ValueType::Type::CONTAINER && vt2 && vt2->type == ValueType::Type::CONTAINER && vt1->container == vt2->container) {
            setValueType(parent, *vt1);
            return;
        }
    }

    if (vt1->isIntegral() && vt1->pointer == 0U &&
        (!vt2 || (vt2->isIntegral() && vt2->pointer == 0U)) &&
        (ternary || parent->isArithmeticalOp() || parent->tokType() == Token::eBitOp || parent->tokType() == Token::eIncDecOp || parent->isAssignmentOp())) {

        ValueType vt;
        if (!vt2 || vt1->type > vt2->type) {
            vt.type = vt1->type;
            vt.sign = vt1->sign;
            vt.originalTypeName = vt1->originalTypeName;
        } else if (vt1->type == vt2->type) {
            vt.type = vt1->type;
            if (vt1->sign == ValueType::Sign::UNSIGNED || vt2->sign == ValueType::Sign::UNSIGNED)
                vt.sign = ValueType::Sign::UNSIGNED;
            else if (vt1->sign == ValueType::Sign::UNKNOWN_SIGN || vt2->sign == ValueType::Sign::UNKNOWN_SIGN)
                vt.sign = ValueType::Sign::UNKNOWN_SIGN;
            else
                vt.sign = ValueType::Sign::SIGNED;
            vt.originalTypeName = (vt1->originalTypeName.empty() ? vt2 : vt1)->originalTypeName;
        } else {
            vt.type = vt2->type;
            vt.sign = vt2->sign;
            vt.originalTypeName = vt2->originalTypeName;
        }
        if (vt.type < ValueType::Type::INT && !(ternary && vt.type==ValueType::Type::BOOL)) {
            vt.type = ValueType::Type::INT;
            vt.sign = ValueType::Sign::SIGNED;
            vt.originalTypeName.clear();
        }

        setValueType(parent, vt);
        return;
    }
}

static const Token * parsedecl(const Token *type, ValueType * const valuetype, ValueType::Sign defaultSignedness, const Settings* settings)
{
    const Token * const previousType = type;
    const unsigned int pointer0 = valuetype->pointer;
    while (Token::Match(type->previous(), "%name%") && !endsWith(type->previous()->str(), ':'))
        type = type->previous();
    valuetype->sign = ValueType::Sign::UNKNOWN_SIGN;
    if (!valuetype->typeScope && !valuetype->smartPointerType)
        valuetype->type = ValueType::Type::UNKNOWN_TYPE;
    else if (valuetype->smartPointerType)
        valuetype->type = ValueType::Type::NONSTD;
    else if (valuetype->typeScope->type == Scope::eEnum) {
        const Token * enum_type = valuetype->typeScope->enumType;
        if (enum_type) {
            if (enum_type->isSigned())
                valuetype->sign = ValueType::Sign::SIGNED;
            else if (enum_type->isUnsigned())
                valuetype->sign = ValueType::Sign::UNSIGNED;
            else
                valuetype->sign = defaultSignedness;
            const ValueType::Type t = ValueType::typeFromString(enum_type->str(), enum_type->isLong());
            if (t != ValueType::Type::UNKNOWN_TYPE)
                valuetype->type = t;
            else if (enum_type->isStandardType())
                valuetype->fromLibraryType(enum_type->str(), settings);
        } else
            valuetype->type = ValueType::Type::INT;
    } else
        valuetype->type = ValueType::Type::RECORD;
    bool par = false;
    while (Token::Match(type, "%name%|*|&|&&|::|(") && !Token::Match(type, "typename|template") && type->varId() == 0 &&
           !type->variable() && !type->function()) {
        if (type->str() == "(") {
            if (Token::Match(type->link(), ") const| {"))
                break;
            if (par)
                break;
            par = true;
        }
        if (type->isSigned())
            valuetype->sign = ValueType::Sign::SIGNED;
        else if (type->isUnsigned())
            valuetype->sign = ValueType::Sign::UNSIGNED;
        if (valuetype->type == ValueType::Type::UNKNOWN_TYPE &&
            type->type() && type->type()->isTypeAlias() && type->type()->typeStart &&
            type->type()->typeStart->str() != type->str() && type->type()->typeStart != previousType)
            parsedecl(type->type()->typeStart, valuetype, defaultSignedness, settings);
        else if (type->str() == "const")
            valuetype->constness |= (1 << (valuetype->pointer - pointer0));
        else if (settings->clang && type->str().size() > 2 && type->str().find("::") < type->str().find("<")) {
            TokenList typeTokens(settings);
            std::string::size_type pos1 = 0;
            do {
                std::string::size_type pos2 = type->str().find("::", pos1);
                if (pos2 == std::string::npos) {
                    typeTokens.addtoken(type->str().substr(pos1), 0, 0, false);
                    break;
                }
                typeTokens.addtoken(type->str().substr(pos1, pos2 - pos1), 0, 0, false);
                typeTokens.addtoken("::", 0, 0, false);
                pos1 = pos2 + 2;
            } while (pos1 < type->str().size());
            const Library::Container *container = settings->library.detectContainer(typeTokens.front());
            if (container) {
                valuetype->type = ValueType::Type::CONTAINER;
                valuetype->container = container;
            } else {
                const Scope *scope = type->scope();
                valuetype->typeScope = scope->check->findScope(typeTokens.front(), scope);
                if (valuetype->typeScope)
                    valuetype->type = (scope->type == Scope::ScopeType::eClass) ? ValueType::Type::RECORD : ValueType::Type::NONSTD;
            }
        } else if (const Library::Container *container = settings->library.detectContainer(type)) {
            valuetype->type = ValueType::Type::CONTAINER;
            valuetype->container = container;
            while (Token::Match(type, "%name%|::|<")) {
                if (type->str() == "<" && type->link()) {
                    if (container->type_templateArgNo >= 0) {
                        const Token *templateType = type->next();
                        for (int j = 0; templateType && j < container->type_templateArgNo; j++)
                            templateType = templateType->nextTemplateArgument();
                        valuetype->containerTypeToken = templateType;
                    }
                    type = type->link();
                }
                type = type->next();
            }
            continue;
        } else if (settings->library.isSmartPointer(type)) {
            const Token* argTok = Token::findsimplematch(type, "<");
            if (!argTok)
                continue;
            valuetype->smartPointerTypeToken = argTok->next();
            valuetype->smartPointerType = argTok->next()->type();
            valuetype->type = ValueType::Type::NONSTD;
            type = argTok->link();
            if (type)
                type = type->next();
            continue;
        } else if (Token::Match(type, "%name% :: %name%")) {
            std::string typestr;
            const Token *end = type;
            while (Token::Match(end, "%name% :: %name%")) {
                typestr += end->str() + "::";
                end = end->tokAt(2);
            }
            typestr += end->str();
            if (valuetype->fromLibraryType(typestr, settings))
                type = end;
        } else if (ValueType::Type::UNKNOWN_TYPE != ValueType::typeFromString(type->str(), type->isLong())) {
            ValueType::Type t0 = valuetype->type;
            valuetype->type = ValueType::typeFromString(type->str(), type->isLong());
            if (t0 == ValueType::Type::LONG) {
                if (valuetype->type == ValueType::Type::LONG)
                    valuetype->type = ValueType::Type::LONGLONG;
                else if (valuetype->type == ValueType::Type::DOUBLE)
                    valuetype->type = ValueType::Type::LONGDOUBLE;
            }
        } else if (type->str() == "auto") {
            const ValueType *vt = type->valueType();
            if (!vt)
                return nullptr;
            valuetype->type = vt->type;
            valuetype->pointer = vt->pointer;
            if (vt->sign != ValueType::Sign::UNKNOWN_SIGN)
                valuetype->sign = vt->sign;
            valuetype->constness = vt->constness;
            valuetype->originalTypeName = vt->originalTypeName;
            while (Token::Match(type, "%name%|*|&|::") && !type->variable()) {
                if (type->str() == "*")
                    valuetype->pointer++;
                if (type->str() == "const")
                    valuetype->constness |= (1 << valuetype->pointer);
                type = type->next();
            }
            break;
        } else if (!valuetype->typeScope && (type->str() == "struct" || type->str() == "enum"))
            valuetype->type = type->str() == "struct" ? ValueType::Type::RECORD : ValueType::Type::NONSTD;
        else if (!valuetype->typeScope && type->type() && type->type()->classScope) {
            if (type->type()->classScope->type == Scope::ScopeType::eEnum) {
                valuetype->type = ValueType::Type::INT;
                valuetype->sign = ValueType::Sign::SIGNED;
            } else {
                valuetype->type = ValueType::Type::RECORD;
            }
            valuetype->typeScope = type->type()->classScope;
        } else if (type->isName() && valuetype->sign != ValueType::Sign::UNKNOWN_SIGN && valuetype->pointer == 0U)
            return nullptr;
        else if (type->str() == "*")
            valuetype->pointer++;
        else if (type->str() == "&")
            valuetype->reference = Reference::LValue;
        else if (type->str() == "&&")
            valuetype->reference = Reference::RValue;
        else if (type->isStandardType())
            valuetype->fromLibraryType(type->str(), settings);
        else if (Token::Match(type->previous(), "!!:: %name% !!::"))
            valuetype->fromLibraryType(type->str(), settings);
        if (!type->originalName().empty())
            valuetype->originalTypeName = type->originalName();
        type = type->next();
    }

    // Set signedness for integral types..
    if (valuetype->isIntegral() && valuetype->sign == ValueType::Sign::UNKNOWN_SIGN) {
        if (valuetype->type == ValueType::Type::CHAR)
            valuetype->sign = defaultSignedness;
        else if (valuetype->type >= ValueType::Type::SHORT)
            valuetype->sign = ValueType::Sign::SIGNED;
    }

    return (type && (valuetype->type != ValueType::Type::UNKNOWN_TYPE || valuetype->pointer > 0 || valuetype->reference != Reference::None)) ? type : nullptr;
}

static const Scope *getClassScope(const Token *tok)
{
    return tok && tok->valueType() && tok->valueType()->typeScope && tok->valueType()->typeScope->isClassOrStruct() ?
           tok->valueType()->typeScope :
           nullptr;
}

static const Function *getOperatorFunction(const Token * const tok)
{
    const std::string functionName("operator" + tok->str());
    std::multimap<std::string, const Function *>::const_iterator it;

    const Scope *classScope = getClassScope(tok->astOperand1());
    if (classScope) {
        it = classScope->functionMap.find(functionName);
        if (it != classScope->functionMap.end())
            return it->second;
    }

    classScope = getClassScope(tok->astOperand2());
    if (classScope) {
        it = classScope->functionMap.find(functionName);
        if (it != classScope->functionMap.end())
            return it->second;
    }

    return nullptr;
}

void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *tokens)
{
    if (!tokens)
        tokens = const_cast<Tokenizer *>(mTokenizer)->list.front();

    for (Token *tok = tokens; tok; tok = tok->next())
        tok->setValueType(nullptr);

    for (Token *tok = tokens; tok; tok = tok->next()) {
        if (tok->isNumber()) {
            if (MathLib::isFloat(tok->str())) {
                ValueType::Type type = ValueType::Type::DOUBLE;
                const char suffix = tok->str()[tok->str().size() - 1];
                if (suffix == 'f' || suffix == 'F')
                    type = ValueType::Type::FLOAT;
                else if (suffix == 'L' || suffix == 'l')
                    type = ValueType::Type::LONGDOUBLE;
                setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, type, 0U));
            } else if (MathLib::isInt(tok->str())) {
                const std::string tokStr = MathLib::abs(tok->str());
                const bool unsignedSuffix = (tokStr.find_last_of("uU") != std::string::npos);
                ValueType::Sign sign = unsignedSuffix ? ValueType::Sign::UNSIGNED : ValueType::Sign::SIGNED;
                ValueType::Type type = ValueType::Type::INT;
                const MathLib::biguint value = MathLib::toULongNumber(tokStr);
                for (std::size_t pos = tokStr.size() - 1U; pos > 0U; --pos) {
                    const char suffix = tokStr[pos];
                    if (suffix == 'u' || suffix == 'U')
                        sign = ValueType::Sign::UNSIGNED;
                    else if (suffix == 'l' || suffix == 'L')
                        type = (type == ValueType::Type::INT) ? ValueType::Type::LONG : ValueType::Type::LONGLONG;
                    else if (pos > 2U && suffix == '4' && tokStr[pos - 1] == '6' && tokStr[pos - 2] == 'i') {
                        type = ValueType::Type::LONGLONG;
                        pos -= 2;
                    } else break;
                }
                if (mSettings->platformType != cppcheck::Platform::Unspecified) {
                    if (type <= ValueType::Type::INT && mSettings->isIntValue(unsignedSuffix ? (value >> 1) : value))
                        type = ValueType::Type::INT;
                    else if (type <= ValueType::Type::INT && !MathLib::isDec(tokStr) && mSettings->isIntValue(value >> 2)) {
                        type = ValueType::Type::INT;
                        sign = ValueType::Sign::UNSIGNED;
                    } else if (type <= ValueType::Type::LONG && mSettings->isLongValue(unsignedSuffix ? (value >> 1) : value))
                        type = ValueType::Type::LONG;
                    else if (type <= ValueType::Type::LONG && !MathLib::isDec(tokStr) && mSettings->isLongValue(value >> 2)) {
                        type = ValueType::Type::LONG;
                        sign = ValueType::Sign::UNSIGNED;
                    } else if (mSettings->isLongLongValue(unsignedSuffix ? (value >> 1) : value))
                        type = ValueType::Type::LONGLONG;
                    else {
                        type = ValueType::Type::LONGLONG;
                        sign = ValueType::Sign::UNSIGNED;
                    }
                }

                setValueType(tok, ValueType(sign, type, 0U));
            }
        } else if (tok->isComparisonOp() || tok->tokType() == Token::eLogicalOp) {
            if (mIsCpp && tok->isComparisonOp() && (getClassScope(tok->astOperand1()) || getClassScope(tok->astOperand2()))) {
                const Function *function = getOperatorFunction(tok);
                if (function) {
                    ValueType vt;
                    parsedecl(function->retDef, &vt, mDefaultSignedness, mSettings);
                    setValueType(tok, vt);
                    continue;
                }
            }
            setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0U));
        } else if (tok->isBoolean()) {
            setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0U));
        } else if (tok->tokType() == Token::eChar || tok->tokType() == Token::eString) {
            nonneg int pointer = tok->tokType() == Token::eChar ? 0U : 1U;
            nonneg int constness = tok->tokType() == Token::eChar ? 0U : 1U;
            ValueType valuetype(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, pointer, constness);

            if (mIsCpp && mSettings->standards.cpp >= Standards::CPP20 && tok->isUtf8()) {
                valuetype.originalTypeName = "char8_t";
                valuetype.fromLibraryType(valuetype.originalTypeName, mSettings);
            } else if (tok->isUtf16()) {
                valuetype.originalTypeName = "char16_t";
                valuetype.fromLibraryType(valuetype.originalTypeName, mSettings);
            } else if (tok->isUtf32()) {
                valuetype.originalTypeName = "char32_t";
                valuetype.fromLibraryType(valuetype.originalTypeName, mSettings);
            } else if (tok->isLong()) {
                valuetype.originalTypeName = "wchar_t";
                valuetype.type = ValueType::Type::WCHAR_T;
            } else if ((tok->tokType() == Token::eChar) && ((tok->isCChar() && !mIsCpp) || (tok->isCMultiChar()))) {
                valuetype.type = ValueType::Type::INT;
                valuetype.sign = ValueType::Sign::SIGNED;
            }
            setValueType(tok, valuetype);
        } else if (tok->link() && Token::Match(tok, "(|{")) {
            const Token* start = tok->astOperand1() ? tok->astOperand1()->findExpressionStartEndTokens().first : nullptr;
            // cast
            if (tok->isCast() && !tok->astOperand2() && Token::Match(tok, "( %name%")) {
                ValueType valuetype;
                if (Token::simpleMatch(parsedecl(tok->next(), &valuetype, mDefaultSignedness, mSettings), ")"))
                    setValueType(tok, valuetype);
            }

            // C++ cast
            else if (tok->astOperand2() && Token::Match(tok->astOperand1(), "static_cast|const_cast|dynamic_cast|reinterpret_cast < %name%") && tok->astOperand1()->linkAt(1)) {
                ValueType valuetype;
                if (Token::simpleMatch(parsedecl(tok->astOperand1()->tokAt(2), &valuetype, mDefaultSignedness, mSettings), ">"))
                    setValueType(tok, valuetype);
            }

            // Construct smart pointer
            else if (mSettings->library.isSmartPointer(start)) {
                ValueType valuetype;
                if (parsedecl(start, &valuetype, mDefaultSignedness, mSettings)) {
                    setValueType(tok, valuetype);
                    setValueType(tok->astOperand1(), valuetype);
                }

            }

            // function
            else if (tok->previous() && tok->previous()->function() && tok->previous()->function()->retDef) {
                ValueType valuetype;
                if (parsedecl(tok->previous()->function()->retDef, &valuetype, mDefaultSignedness, mSettings))
                    setValueType(tok, valuetype);
            }

            else if (Token::simpleMatch(tok->previous(), "sizeof (")) {
                // TODO: use specified size_t type
                ValueType valuetype(ValueType::Sign::UNSIGNED, ValueType::Type::LONG, 0U);
                valuetype.originalTypeName = "size_t";
                setValueType(tok, valuetype);

                if (Token::Match(tok, "( %type% %type%| *| *| )")) {
                    ValueType vt;
                    if (parsedecl(tok->next(), &vt, mDefaultSignedness, mSettings)) {
                        setValueType(tok->next(), vt);
                    }
                }
            }

            // function style cast
            else if (tok->previous() && tok->previous()->isStandardType()) {
                ValueType valuetype;
                if (tok->astOperand1() && valuetype.fromLibraryType(tok->astOperand1()->expressionString(), mSettings)) {
                    setValueType(tok, valuetype);
                    continue;
                }

                valuetype.type = ValueType::typeFromString(tok->previous()->str(), tok->previous()->isLong());
                if (tok->previous()->isUnsigned())
                    valuetype.sign = ValueType::Sign::UNSIGNED;
                else if (tok->previous()->isSigned())
                    valuetype.sign = ValueType::Sign::SIGNED;
                setValueType(tok, valuetype);
            }

            // constructor call
            else if (tok->previous() && tok->previous()->function() && tok->previous()->function()->isConstructor()) {
                ValueType valuetype;
                valuetype.type = ValueType::RECORD;
                valuetype.typeScope = tok->previous()->function()->token->scope();
                setValueType(tok, valuetype);
            }

            // library type/function
            else if (tok->previous()) {
                if (tok->astParent() && Token::Match(tok->astOperand1(), "%name%|::")) {
                    const Token *typeStartToken = tok->astOperand1();
                    while (typeStartToken && typeStartToken->str() == "::")
                        typeStartToken = typeStartToken->astOperand1();
                    if (const Library::Container *c = mSettings->library.detectContainer(typeStartToken)) {
                        ValueType vt;
                        vt.pointer = 0;
                        vt.container = c;
                        vt.type = ValueType::Type::CONTAINER;
                        setValueType(tok, vt);
                        continue;
                    }

                    const std::string e = tok->astOperand1()->expressionString();

                    if ((e == "std::make_shared" || e == "std::make_unique") && Token::Match(tok->astOperand1(), ":: %name% < %name%")) {
                        ValueType vt;
                        parsedecl(tok->astOperand1()->tokAt(3), &vt, mDefaultSignedness, mSettings);
                        if (vt.typeScope) {
                            vt.smartPointerType = vt.typeScope->definedType;
                            vt.typeScope = nullptr;
                            setValueType(tok, vt);
                            continue;
                        }
                    }

                    ValueType podtype;
                    if (podtype.fromLibraryType(e, mSettings)) {
                        setValueType(tok, podtype);
                        continue;
                    }
                }

                const std::string& typestr(mSettings->library.returnValueType(tok->previous()));
                if (!typestr.empty()) {
                    ValueType valuetype;
                    TokenList tokenList(mSettings);
                    std::istringstream istr(typestr+";");
                    tokenList.createTokens(istr);
                    tokenList.simplifyStdType();
                    if (parsedecl(tokenList.front(), &valuetype, mDefaultSignedness, mSettings)) {
                        valuetype.originalTypeName = typestr;
                        setValueType(tok, valuetype);
                    }
                }

                if (typestr.empty() || typestr == "iterator") {
                    if (Token::simpleMatch(tok->astOperand1(), ".") &&
                        tok->astOperand1()->astOperand1() &&
                        tok->astOperand1()->astOperand2() &&
                        tok->astOperand1()->astOperand1()->valueType() &&
                        tok->astOperand1()->astOperand1()->valueType()->container) {
                        const Library::Container *cont = tok->astOperand1()->astOperand1()->valueType()->container;
                        const std::map<std::string, Library::Container::Function>::const_iterator it = cont->functions.find(tok->astOperand1()->astOperand2()->str());
                        if (it != cont->functions.end()) {
                            if (it->second.yield == Library::Container::Yield::START_ITERATOR ||
                                it->second.yield == Library::Container::Yield::END_ITERATOR ||
                                it->second.yield == Library::Container::Yield::ITERATOR) {
                                ValueType vt;
                                vt.type = ValueType::Type::ITERATOR;
                                vt.container = cont;
                                setValueType(tok, vt);
                            }
                        }
                    }
                    continue;
                }
                TokenList tokenList(mSettings);
                std::istringstream istr(typestr+";");
                if (tokenList.createTokens(istr)) {
                    ValueType vt;
                    tokenList.simplifyPlatformTypes();
                    tokenList.simplifyStdType();
                    if (parsedecl(tokenList.front(), &vt, mDefaultSignedness, mSettings)) {
                        vt.originalTypeName = typestr;
                        setValueType(tok, vt);
                    }
                }
            }
        } else if (tok->str() == "return") {
            const Scope *functionScope = tok->scope();
            while (functionScope && functionScope->isExecutable() && functionScope->type != Scope::eLambda && functionScope->type != Scope::eFunction)
                functionScope = functionScope->nestedIn;
            if (functionScope && functionScope->type == Scope::eFunction && functionScope->function && functionScope->function->retDef)
                setValueType(tok, ValueType::parseDecl(functionScope->function->retDef, mSettings));
        } else if (tok->variable()) {
            setValueType(tok, *tok->variable());
        } else if (tok->enumerator()) {
            setValueType(tok, *tok->enumerator());
        } else if (tok->isKeyword() && tok->str() == "new") {
            const Token *typeTok = tok->next();
            if (Token::Match(typeTok, "( std| ::| nothrow )"))
                typeTok = typeTok->link()->next();
            if (const Library::Container *c = mSettings->library.detectContainer(typeTok)) {
                ValueType vt;
                vt.pointer = 1;
                vt.container = c;
                vt.type = ValueType::Type::CONTAINER;
                setValueType(tok, vt);
                continue;
            }
            std::string typestr;
            while (Token::Match(typeTok, "%name% :: %name%")) {
                typestr += typeTok->str() + "::";
                typeTok = typeTok->tokAt(2);
            }
            if (!Token::Match(typeTok, "%type% ;|[|("))
                continue;
            typestr += typeTok->str();
            ValueType vt;
            vt.pointer = 1;
            if (typeTok->type() && typeTok->type()->classScope) {
                vt.type = ValueType::Type::RECORD;
                vt.typeScope = typeTok->type()->classScope;
            } else {
                vt.type = ValueType::typeFromString(typestr, typeTok->isLong());
                if (vt.type == ValueType::Type::UNKNOWN_TYPE)
                    vt.fromLibraryType(typestr, mSettings);
                if (vt.type == ValueType::Type::UNKNOWN_TYPE)
                    continue;
                if (typeTok->isUnsigned())
                    vt.sign = ValueType::Sign::UNSIGNED;
                else if (typeTok->isSigned())
                    vt.sign = ValueType::Sign::SIGNED;
                if (vt.sign == ValueType::Sign::UNKNOWN_SIGN && vt.isIntegral())
                    vt.sign = (vt.type == ValueType::Type::CHAR) ? mDefaultSignedness : ValueType::Sign::SIGNED;
            }
            setValueType(tok, vt);
        } else if (tok->isKeyword() && tok->str() == "return" && tok->scope()) {
            const Scope* fscope = tok->scope();
            while (fscope && !fscope->function)
                fscope = fscope->nestedIn;
            if (fscope && fscope->function && fscope->function->retDef) {
                ValueType vt;
                parsedecl(fscope->function->retDef, &vt, mDefaultSignedness, mSettings);
                setValueType(tok, vt);
            }
        }
    }

    if (reportDebugWarnings && mSettings->debugwarnings) {
        for (Token *tok = tokens; tok; tok = tok->next()) {
            if (tok->str() == "auto" && !tok->valueType())
                debugMessage(tok, "auto token with no type.");
        }
    }

    // Update functions with new type information.
    createSymbolDatabaseSetFunctionPointers(false);

    // Update auto variables with new type information.
    createSymbolDatabaseSetVariablePointers();
}

ValueType ValueType::parseDecl(const Token *type, const Settings *settings)
{
    ValueType vt;
    parsedecl(type, &vt, settings->defaultSign == 'u' ? Sign::UNSIGNED : Sign::SIGNED, settings);
    return vt;
}

ValueType::Type ValueType::typeFromString(const std::string &typestr, bool longType)
{
    if (typestr == "void")
        return ValueType::Type::VOID;
    if (typestr == "bool" || typestr == "_Bool")
        return ValueType::Type::BOOL;
    if (typestr== "char")
        return ValueType::Type::CHAR;
    if (typestr == "short")
        return ValueType::Type::SHORT;
    if (typestr == "wchar_t")
        return ValueType::Type::WCHAR_T;
    if (typestr == "int")
        return ValueType::Type::INT;
    if (typestr == "long")
        return longType ? ValueType::Type::LONGLONG : ValueType::Type::LONG;
    if (typestr == "float")
        return ValueType::Type::FLOAT;
    if (typestr == "double")
        return longType ? ValueType::Type::LONGDOUBLE : ValueType::Type::DOUBLE;
    return ValueType::Type::UNKNOWN_TYPE;
}

bool ValueType::fromLibraryType(const std::string &typestr, const Settings *settings)
{
    const Library::PodType* podtype = settings->library.podtype(typestr);
    if (podtype && (podtype->sign == 's' || podtype->sign == 'u')) {
        if (podtype->size == 1)
            type = ValueType::Type::CHAR;
        else if (podtype->size == settings->sizeof_int)
            type = ValueType::Type::INT;
        else if (podtype->size == settings->sizeof_short)
            type = ValueType::Type::SHORT;
        else if (podtype->size == settings->sizeof_long)
            type = ValueType::Type::LONG;
        else if (podtype->size == settings->sizeof_long_long)
            type = ValueType::Type::LONGLONG;
        else if (podtype->stdtype == Library::PodType::BOOL)
            type = ValueType::Type::BOOL;
        else if (podtype->stdtype == Library::PodType::CHAR)
            type = ValueType::Type::CHAR;
        else if (podtype->stdtype == Library::PodType::SHORT)
            type = ValueType::Type::SHORT;
        else if (podtype->stdtype == Library::PodType::INT)
            type = ValueType::Type::INT;
        else if (podtype->stdtype == Library::PodType::LONG)
            type = ValueType::Type::LONG;
        else if (podtype->stdtype == Library::PodType::LONGLONG)
            type = ValueType::Type::LONGLONG;
        else
            type = ValueType::Type::UNKNOWN_INT;
        sign = (podtype->sign == 'u') ? ValueType::UNSIGNED : ValueType::SIGNED;
        return true;
    }

    const Library::PlatformType *platformType = settings->library.platform_type(typestr, settings->platformString());
    if (platformType) {
        if (platformType->mType == "char")
            type = ValueType::Type::CHAR;
        else if (platformType->mType == "short")
            type = ValueType::Type::SHORT;
        else if (platformType->mType == "wchar_t")
            type = ValueType::Type::WCHAR_T;
        else if (platformType->mType == "int")
            type = platformType->mLong ? ValueType::Type::LONG : ValueType::Type::INT;
        else if (platformType->mType == "long")
            type = platformType->mLong ? ValueType::Type::LONGLONG : ValueType::Type::LONG;
        if (platformType->mSigned)
            sign = ValueType::SIGNED;
        else if (platformType->mUnsigned)
            sign = ValueType::UNSIGNED;
        if (platformType->mPointer)
            pointer = 1;
        if (platformType->mPtrPtr)
            pointer = 2;
        if (platformType->mConstPtr)
            constness = 1;
        return true;
    } else if (!podtype && (typestr == "size_t" || typestr == "std::size_t")) {
        originalTypeName = "size_t";
        sign = ValueType::UNSIGNED;
        if (settings->sizeof_size_t == settings->sizeof_long)
            type = ValueType::Type::LONG;
        else if (settings->sizeof_size_t == settings->sizeof_long_long)
            type = ValueType::Type::LONGLONG;
        else if (settings->sizeof_size_t == settings->sizeof_int)
            type = ValueType::Type::INT;
        else
            type = ValueType::Type::UNKNOWN_INT;
        return true;
    }

    return false;
}

std::string ValueType::dump() const
{
    std::ostringstream ret;
    switch (type) {
    case UNKNOWN_TYPE:
        return "";
    case NONSTD:
        ret << "valueType-type=\"nonstd\"";
        break;
    case RECORD:
        ret << "valueType-type=\"record\"";
        break;
    case CONTAINER:
        ret << "valueType-type=\"container\"";
        break;
    case ITERATOR:
        ret << "valueType-type=\"iterator\"";
        break;
    case VOID:
        ret << "valueType-type=\"void\"";
        break;
    case BOOL:
        ret << "valueType-type=\"bool\"";
        break;
    case CHAR:
        ret << "valueType-type=\"char\"";
        break;
    case SHORT:
        ret << "valueType-type=\"short\"";
        break;
    case WCHAR_T:
        ret << "valueType-type=\"wchar_t\"";
        break;
    case INT:
        ret << "valueType-type=\"int\"";
        break;
    case LONG:
        ret << "valueType-type=\"long\"";
        break;
    case LONGLONG:
        ret << "valueType-type=\"long long\"";
        break;
    case UNKNOWN_INT:
        ret << "valueType-type=\"unknown int\"";
        break;
    case FLOAT:
        ret << "valueType-type=\"float\"";
        break;
    case DOUBLE:
        ret << "valueType-type=\"double\"";
        break;
    case LONGDOUBLE:
        ret << "valueType-type=\"long double\"";
        break;
    }

    switch (sign) {
    case Sign::UNKNOWN_SIGN:
        break;
    case Sign::SIGNED:
        ret << " valueType-sign=\"signed\"";
        break;
    case Sign::UNSIGNED:
        ret << " valueType-sign=\"unsigned\"";
        break;
    }

    if (bits > 0)
        ret << " valueType-bits=\"" << bits << '\"';

    if (pointer > 0)
        ret << " valueType-pointer=\"" << pointer << '\"';

    if (constness > 0)
        ret << " valueType-constness=\"" << constness << '\"';

    if (reference == Reference::None)
        ret << " valueType-reference=\"None\"";
    else if (reference == Reference::LValue)
        ret << " valueType-reference=\"LValue\"";
    else if (reference == Reference::RValue)
        ret << " valueType-reference=\"RValue\"";

    if (typeScope)
        ret << " valueType-typeScope=\"" << typeScope << '\"';

    if (!originalTypeName.empty())
        ret << " valueType-originalTypeName=\"" << ErrorLogger::toxml(originalTypeName) << '\"';

    return ret.str();
}

MathLib::bigint ValueType::typeSize(const cppcheck::Platform &platform, bool p) const
{
    if (p && pointer)
        return platform.sizeof_pointer;

    if (typeScope && typeScope->definedType && typeScope->definedType->sizeOf)
        return typeScope->definedType->sizeOf;

    switch (type) {
    case ValueType::Type::BOOL:
        return platform.sizeof_bool;
    case ValueType::Type::CHAR:
        return 1;
    case ValueType::Type::SHORT:
        return platform.sizeof_short;
    case ValueType::Type::WCHAR_T:
        return platform.sizeof_wchar_t;
    case ValueType::Type::INT:
        return platform.sizeof_int;
    case ValueType::Type::LONG:
        return platform.sizeof_long;
    case ValueType::Type::LONGLONG:
        return platform.sizeof_long_long;
    case ValueType::Type::FLOAT:
        return platform.sizeof_float;
    case ValueType::Type::DOUBLE:
        return platform.sizeof_double;
    case ValueType::Type::LONGDOUBLE:
        return platform.sizeof_long_double;
    default:
        break;
    }

    // Unknown invalid size
    return 0;
}

std::string ValueType::str() const
{
    std::string ret;
    if (constness & 1)
        ret = " const";
    if (type == VOID)
        ret += " void";
    else if (isIntegral()) {
        if (sign == SIGNED)
            ret += " signed";
        else if (sign == UNSIGNED)
            ret += " unsigned";
        if (type == BOOL)
            ret += " bool";
        else if (type == CHAR)
            ret += " char";
        else if (type == SHORT)
            ret += " short";
        else if (type == WCHAR_T)
            ret += " wchar_t";
        else if (type == INT)
            ret += " int";
        else if (type == LONG)
            ret += " long";
        else if (type == LONGLONG)
            ret += " long long";
        else if (type == UNKNOWN_INT)
            ret += " unknown_int";
    } else if (type == FLOAT)
        ret += " float";
    else if (type == DOUBLE)
        ret += " double";
    else if (type == LONGDOUBLE)
        ret += " long double";
    else if ((type == ValueType::Type::NONSTD || type == ValueType::Type::RECORD) && typeScope) {
        std::string className(typeScope->className);
        const Scope *scope = typeScope->definedType ? typeScope->definedType->enclosingScope : typeScope->nestedIn;
        while (scope && scope->type != Scope::eGlobal) {
            if (scope->type == Scope::eClass || scope->type == Scope::eStruct || scope->type == Scope::eNamespace)
                className = scope->className + "::" + className;
            scope = scope->definedType ? scope->definedType->enclosingScope : scope->nestedIn;
        }
        ret += ' ' + className;
    } else if (type == ValueType::Type::CONTAINER && container) {
        ret += " container(" + container->startPattern + ')';
    } else if (type == ValueType::Type::ITERATOR && container) {
        ret += " iterator(" + container->startPattern + ')';
    } else if (smartPointerType) {
        ret += " smart-pointer<" + smartPointerType->name() + ">";
    }
    for (unsigned int p = 0; p < pointer; p++) {
        ret += " *";
        if (constness & (2 << p))
            ret += " const";
    }
    if (reference == Reference::LValue)
        ret += " &";
    else if (reference == Reference::RValue)
        ret += " &&";
    return ret.empty() ? ret : ret.substr(1);
}

ValueType::MatchResult ValueType::matchParameter(const ValueType *call, const ValueType *func)
{
    if (!call || !func)
        return ValueType::MatchResult::UNKNOWN;
    if (call->pointer != func->pointer) {
        if (call->pointer > 1 && func->pointer == 1 && func->type == ValueType::Type::VOID)
            return ValueType::MatchResult::FALLBACK1;
        if (call->pointer == 1 && func->pointer == 0 && func->isIntegral() && func->sign != ValueType::Sign::SIGNED)
            return ValueType::MatchResult::FALLBACK1;
        if (call->pointer == 1 && call->type == ValueType::Type::CHAR && func->pointer == 0 && func->container && func->container->stdStringLike)
            return ValueType::MatchResult::FALLBACK2;
        return ValueType::MatchResult::NOMATCH; // TODO
    }
    if (call->pointer > 0 && ((call->constness | func->constness) != func->constness))
        return ValueType::MatchResult::NOMATCH;
    if (call->type != func->type) {
        if (call->type == ValueType::Type::VOID || func->type == ValueType::Type::VOID)
            return ValueType::MatchResult::FALLBACK1;
        if (call->pointer > 0 && func->pointer > 0)
            return func->type == ValueType::UNKNOWN_TYPE ? ValueType::MatchResult::UNKNOWN : ValueType::MatchResult::NOMATCH;
        if (call->isIntegral() && func->isIntegral())
            return call->type < func->type ?
                   ValueType::MatchResult::FALLBACK1 :
                   ValueType::MatchResult::FALLBACK2;
        else if (call->isFloat() && func->isFloat())
            return ValueType::MatchResult::FALLBACK1;
        else if (call->isIntegral() && func->isFloat())
            return ValueType::MatchResult::FALLBACK2;
        else if (call->isFloat() && func->isIntegral())
            return ValueType::MatchResult::FALLBACK2;
        return ValueType::MatchResult::UNKNOWN; // TODO
    }

    if (call->typeScope != nullptr || func->typeScope != nullptr)
        return call->typeScope == func->typeScope ? ValueType::MatchResult::SAME : ValueType::MatchResult::NOMATCH;

    if (call->container != nullptr || func->container != nullptr) {
        if (call->container != func->container)
            return ValueType::MatchResult::NOMATCH;
    }

    else if (func->type < ValueType::Type::VOID || func->type == ValueType::Type::UNKNOWN_INT)
        return ValueType::MatchResult::UNKNOWN;

    if (call->isIntegral() && func->isIntegral() && call->sign != ValueType::Sign::UNKNOWN_SIGN && func->sign != ValueType::Sign::UNKNOWN_SIGN && call->sign != func->sign)
        return ValueType::MatchResult::FALLBACK1;

    return ValueType::MatchResult::SAME;
}

ValueType::MatchResult ValueType::matchParameter(const ValueType *call, const Variable *callVar, const Variable *funcVar)
{
    ValueType::MatchResult res = ValueType::matchParameter(call, funcVar->valueType());
    if (res == ValueType::MatchResult::SAME && callVar && call->container) {
        const std::string type1 = getTypeString(callVar->typeStartToken());
        const std::string type2 = getTypeString(funcVar->typeStartToken());
        if (type1 != type2)
            return ValueType::MatchResult::NOMATCH;
    }
    return res;
}