#include "matchcompiler.h"
#include <string>
#include <cstring>
#include "errorlogger.h"
#include "token.h"
// pattern: :: %name%
static bool match1(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    return true;
}
// pattern: %name% ::
static bool match2(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    return true;
}
// pattern: %name% <
static bool match3(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("<")))
        return false;
    return true;
}
// pattern: >|>> ::
static bool match4(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(">")) || (tok->str() == MatchCompiler::makeConstString(">>"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    return true;
}
// pattern: {
static bool match5(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: ; }
static bool match6(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("}")))
        return false;
    return true;
}
// pattern: {|} }
static bool match7(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString("}"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("}")))
        return false;
    return true;
}
// pattern: do|try|else {
static bool match8(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("do")) || (tok->str() == MatchCompiler::makeConstString("try")) || (tok->str() == MatchCompiler::makeConstString("else"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: ) {
static bool match9(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: class|struct|union|namespace ::| %name% final| {|:|::|<
static bool match10(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("class")) || (tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("union")) || (tok->str() == MatchCompiler::makeConstString("namespace"))))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("::"))))
        tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("final"))))
        tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString(":")) || (tok->str() == MatchCompiler::makeConstString("::")) || (tok->str() == MatchCompiler::makeConstString("<"))))
        return false;
    return true;
}
// pattern: new|friend|const|enum|typedef|mutable|volatile|using|)|(|<
static bool match11(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("new")) || (tok->str() == MatchCompiler::makeConstString("friend")) || (tok->str() == MatchCompiler::makeConstString("const")) || (tok->str() == MatchCompiler::makeConstString("enum")) || (tok->str() == MatchCompiler::makeConstString("typedef")) || (tok->str() == MatchCompiler::makeConstString("mutable")) || (tok->str() == MatchCompiler::makeConstString("volatile")) || (tok->str() == MatchCompiler::makeConstString("using")) || (tok->str() == MatchCompiler::makeConstString(")")) || (tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString("<"))))
        return false;
    return true;
}
// pattern: enum class| %name% {
static bool match12(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("enum")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("class"))))
        tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: enum class| %name% : %name% {
static bool match13(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("enum")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("class"))))
        tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(":")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: struct|union|enum %name% {
static bool match14(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("union")) || (tok->str() == MatchCompiler::makeConstString("enum"))))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: %name% :: %name%
static bool match15(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    return true;
}
// pattern: final
static bool match16(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("final")))
        return false;
    return true;
}
// pattern: {|:
static bool match17(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString(":"))))
        return false;
    return true;
}
// pattern: = {
static bool match18(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("=")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: } ;
static bool match19(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("}")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: (|{
static bool match20(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString("{"))))
        return false;
    return true;
}
// pattern: *|&|>
static bool match21(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("*")) || (tok->str() == MatchCompiler::makeConstString("&")) || (tok->str() == MatchCompiler::makeConstString(">"))))
        return false;
    return true;
}
// pattern: %name% (
static bool match22(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: %name% [
static bool match23(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("[")))
        return false;
    return true;
}
// pattern: ;
static bool match24(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: template|> class|struct
static bool match25(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("template")) || (tok->str() == MatchCompiler::makeConstString(">"))))
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("class")) || (tok->str() == MatchCompiler::makeConstString("struct"))))
        return false;
    return true;
}
// pattern: class|struct|union
static bool match26(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("class")) || (tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("union"))))
        return false;
    return true;
}
// pattern: (
static bool match27(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: ) ;
static bool match28(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: namespace %name% %type% (
static bool match29(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("namespace")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: class|struct|union %name% ;
static bool match30(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("class")) || (tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("union"))))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: using namespace ::| %type% ;|::
static bool match31(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("using")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("namespace")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("::"))))
        tok = tok->next();
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("::"))))
        return false;
    return true;
}
// pattern: %type% ::
static bool match32(const Token* tok) {
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    return true;
}
// pattern: using %name% =
static bool match33(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("using")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("=")))
        return false;
    return true;
}
// pattern: struct|union {
static bool match34(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("union"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: } *|&| %name% ;|[|=
static bool match35(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("}")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("*")) || (tok->str() == MatchCompiler::makeConstString("&"))))
        tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("[")) || (tok->str() == MatchCompiler::makeConstString("="))))
        return false;
    return true;
}
// pattern: namespace {
static bool match36(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("namespace")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: enum class| %name% ;
static bool match37(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("enum")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("class"))))
        tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: enum class| %name% : %name% ;
static bool match38(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("enum")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("class"))))
        tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(":")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: public|protected|private %name% :
static bool match39(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("public")) || (tok->str() == MatchCompiler::makeConstString("protected")) || (tok->str() == MatchCompiler::makeConstString("private"))))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(":")))
        return false;
    return true;
}
// pattern: (|<
static bool match40(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString("<"))))
        return false;
    return true;
}
// pattern: %name%|> {
static bool match41(const Token* tok) {
    if (!tok || !(tok->isName() || (tok->str() == MatchCompiler::makeConstString(">"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: } ,|{
static bool match42(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("}")))
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(",")) || (tok->str() == MatchCompiler::makeConstString("{"))))
        return false;
    return true;
}
// pattern: friend class| ::| %any% ;|::
static bool match43(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("friend")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("class"))))
        tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("::"))))
        tok = tok->next();
    if (!tok || false)
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("::"))))
        return false;
    return true;
}
// pattern: default|delete
static bool match44(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("default")) || (tok->str() == MatchCompiler::makeConstString("delete"))))
        return false;
    return true;
}
// pattern: else|try|do {
static bool match45(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("else")) || (tok->str() == MatchCompiler::makeConstString("try")) || (tok->str() == MatchCompiler::makeConstString("do"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: if|for|while|catch|switch (
static bool match46(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("if")) || (tok->str() == MatchCompiler::makeConstString("for")) || (tok->str() == MatchCompiler::makeConstString("while")) || (tok->str() == MatchCompiler::makeConstString("catch")) || (tok->str() == MatchCompiler::makeConstString("switch"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: %var% {
static bool match47(const Token* tok) {
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: [
static bool match48(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("[")))
        return false;
    return true;
}
// pattern: static|const|struct|union|enum
static bool match49(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("static")) || (tok->str() == MatchCompiler::makeConstString("const")) || (tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("union")) || (tok->str() == MatchCompiler::makeConstString("enum"))))
        return false;
    return true;
}
// pattern: %name% [(,)>]
static bool match50(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || tok->str().size() != 1U || !strchr("(,)>", tok->str()[0]))
        return false;
    return true;
}
// pattern: [(,<]
static bool match51(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr("(,<", tok->str()[0]))
        return false;
    return true;
}
// pattern: [(,<] &
static bool match52(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr("(,<", tok->str()[0]))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("&")))
        return false;
    return true;
}
// pattern: %name% {|(
static bool match53(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString("("))))
        return false;
    return true;
}
// pattern: %name% [|.
static bool match54(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("[")) || (tok->str() == MatchCompiler::makeConstString("."))))
        return false;
    return true;
}
// pattern: . %name%
static bool match55(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    return true;
}
// pattern: ) . %name%
static bool match56(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    return true;
}
// pattern: std :: %type% < %type% *| *| >
static bool match57(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("std")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("<")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("*"))))
        tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("*"))))
        tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(">")))
        return false;
    return true;
}
// pattern: ) . %name% !!(
static bool match58(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (tok && tok->str() == MatchCompiler::makeConstString("("))
        return false;
    return true;
}
// pattern: ) [
static bool match59(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("[")))
        return false;
    return true;
}
// pattern: ] . %name% !!(
static bool match60(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("]")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (tok && tok->str() == MatchCompiler::makeConstString("("))
        return false;
    return true;
}
// pattern: %name%
static bool match61(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    return true;
}
// pattern: %var%
static bool match62(const Token* tok) {
    if (!tok || !(tok->varId() != 0))
        return false;
    return true;
}
// pattern: ::|.|(|:|%var%
static bool match63(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("::")) || (tok->str() == MatchCompiler::makeConstString(".")) || (tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString(":")) || (tok->varId() != 0)))
        return false;
    return true;
}
// pattern: &|&&|* )|%var%
static bool match64(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("&")) || (tok->str() == MatchCompiler::makeConstString("&&")) || (tok->str() == MatchCompiler::makeConstString("*"))))
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(")")) || (tok->varId() != 0)))
        return false;
    return true;
}
// pattern: )
static bool match65(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    return true;
}
// pattern: catch (
static bool match66(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("catch")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: %type% ,
static bool match67(const Token* tok) {
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(",")))
        return false;
    return true;
}
// pattern: <|>
static bool match68(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("<")) || (tok->str() == MatchCompiler::makeConstString(">"))))
        return false;
    return true;
}
// pattern: <
static bool match69(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("<")))
        return false;
    return true;
}
// pattern: goto
static bool match70(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("goto")))
        return false;
    return true;
}
// pattern: (|.|[|::|?|:|++|--|%cop%|%assign%
static bool match71(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString(".")) || (tok->str() == MatchCompiler::makeConstString("[")) || (tok->str() == MatchCompiler::makeConstString("::")) || (tok->str() == MatchCompiler::makeConstString("?")) || (tok->str() == MatchCompiler::makeConstString(":")) || (tok->str() == MatchCompiler::makeConstString("++")) || (tok->str() == MatchCompiler::makeConstString("--")) || tok->isConstOp() || tok->isAssignmentOp()))
        return false;
    return true;
}
// pattern: *|&|&&
static bool match72(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("*")) || (tok->str() == MatchCompiler::makeConstString("&")) || (tok->str() == MatchCompiler::makeConstString("&&"))))
        return false;
    return true;
}
// pattern: this
static bool match73(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("this")))
        return false;
    return true;
}
// pattern: [<,]
static bool match74(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr("<,", tok->str()[0]))
        return false;
    return true;
}
// pattern: [,>]
static bool match75(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr(",>", tok->str()[0]))
        return false;
    return true;
}
// pattern: ; %num% ;
static bool match76(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isNumber())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: ) const
static bool match77(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("const")))
        return false;
    return true;
}
// pattern: {|;|const|=
static bool match78(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("const")) || (tok->str() == MatchCompiler::makeConstString("="))))
        return false;
    return true;
}
// pattern: {|;
template<class T> static T * findmatch79(T * start_tok) {
    for (; start_tok; start_tok = start_tok->next()) {

    T * tok = start_tok;
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString(";"))))
        continue;
    return start_tok;
    }
    return nullptr;
}
// pattern: %name%|>|&|*|::|~
static bool match80(const Token* tok) {
    if (!tok || !(tok->isName() || (tok->str() == MatchCompiler::makeConstString(">")) || (tok->str() == MatchCompiler::makeConstString("&")) || (tok->str() == MatchCompiler::makeConstString("*")) || (tok->str() == MatchCompiler::makeConstString("::")) || (tok->str() == MatchCompiler::makeConstString("~"))))
        return false;
    return true;
}
// pattern: ::
static bool match81(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    return true;
}
// pattern: const|noexcept|throw|override|final|volatile|&|&&
static bool match82(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("const")) || (tok->str() == MatchCompiler::makeConstString("noexcept")) || (tok->str() == MatchCompiler::makeConstString("throw")) || (tok->str() == MatchCompiler::makeConstString("override")) || (tok->str() == MatchCompiler::makeConstString("final")) || (tok->str() == MatchCompiler::makeConstString("volatile")) || (tok->str() == MatchCompiler::makeConstString("&")) || (tok->str() == MatchCompiler::makeConstString("&&"))))
        return false;
    return true;
}
// pattern: ;|{|=|override|final
static bool match83(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString("=")) || (tok->str() == MatchCompiler::makeConstString("override")) || (tok->str() == MatchCompiler::makeConstString("final"))))
        return false;
    return true;
}
// pattern: <|[|(
static bool match84(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("<")) || (tok->str() == MatchCompiler::makeConstString("[")) || (tok->str() == MatchCompiler::makeConstString("("))))
        return false;
    return true;
}
// pattern: {|}|;|public:|protected:|private:
static bool match85(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString("}")) || (tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("public:")) || (tok->str() == MatchCompiler::makeConstString("protected:")) || (tok->str() == MatchCompiler::makeConstString("private:"))))
        return false;
    return true;
}
// pattern: %type%|*|&
static bool match86(const Token* tok) {
    if (!tok || !((tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())) || (tok->str() == MatchCompiler::makeConstString("*")) || (tok->str() == MatchCompiler::makeConstString("&"))))
        return false;
    return true;
}
// pattern: decltype (
static bool match87(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("decltype")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: const|static|extern|template|virtual|struct|class|enum|%name%
static bool match88(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("const")) || (tok->str() == MatchCompiler::makeConstString("static")) || (tok->str() == MatchCompiler::makeConstString("extern")) || (tok->str() == MatchCompiler::makeConstString("template")) || (tok->str() == MatchCompiler::makeConstString("virtual")) || (tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("class")) || (tok->str() == MatchCompiler::makeConstString("enum")) || tok->isName()))
        return false;
    return true;
}
// pattern: >|{|}|;|public:|protected:|private:
static bool match89(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(">")) || (tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString("}")) || (tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("public:")) || (tok->str() == MatchCompiler::makeConstString("protected:")) || (tok->str() == MatchCompiler::makeConstString("private:"))))
        return false;
    return true;
}
// pattern: ;|{|=
static bool match90(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString("="))))
        return false;
    return true;
}
// pattern: %name% ;|{
static bool match91(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("{"))))
        return false;
    return true;
}
// pattern: : ::| %name% (|::|<|{
static bool match92(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(":")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("::"))))
        tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString("::")) || (tok->str() == MatchCompiler::makeConstString("<")) || (tok->str() == MatchCompiler::makeConstString("{"))))
        return false;
    return true;
}
// pattern: &|&&| ;|{
static bool match93(const Token* tok) {
    if (tok && ((tok->str() == MatchCompiler::makeConstString("&")) || (tok->str() == MatchCompiler::makeConstString("&&"))))
        tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("{"))))
        return false;
    return true;
}
// pattern: = delete|default ;
static bool match94(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("=")))
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("delete")) || (tok->str() == MatchCompiler::makeConstString("default"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: [;{}]
static bool match95(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr(";{}", tok->str()[0]))
        return false;
    return true;
}
// pattern: > (
static bool match96(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(">")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: ) const| ;|{|=
static bool match97(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("const"))))
        tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString("="))))
        return false;
    return true;
}
// pattern: ) : ::| %name% (|::|<|{
static bool match98(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(":")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("::"))))
        tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString("::")) || (tok->str() == MatchCompiler::makeConstString("<")) || (tok->str() == MatchCompiler::makeConstString("{"))))
        return false;
    return true;
}
// pattern: ) const| noexcept {|;|(
static bool match99(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("const"))))
        tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("noexcept")))
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("("))))
        return false;
    return true;
}
// pattern: ;|}
static bool match100(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("}"))))
        return false;
    return true;
}
// pattern: const|struct|static
static bool match101(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("const")) || (tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("static"))))
        return false;
    return true;
}
// pattern: &
static bool match102(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("&")))
        return false;
    return true;
}
// pattern: &&
static bool match103(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("&&")))
        return false;
    return true;
}
// pattern: =|{
static bool match104(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("=")) || (tok->str() == MatchCompiler::makeConstString("{"))))
        return false;
    return true;
}
// pattern: [;,)={]
static bool match105(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr(";,)={", tok->str()[0]))
        return false;
    return true;
}
// pattern: (|[|<
static bool match106(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString("[")) || (tok->str() == MatchCompiler::makeConstString("<"))))
        return false;
    return true;
}
// pattern: std :: atomic <
static bool match107(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("std")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("atomic")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("<")))
        return false;
    return true;
}
// pattern: ( * %name% )
static bool match108(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("*")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    return true;
}
// pattern: static|const|constexpr|volatile %any%
static bool match109(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("static")) || (tok->str() == MatchCompiler::makeConstString("const")) || (tok->str() == MatchCompiler::makeConstString("constexpr")) || (tok->str() == MatchCompiler::makeConstString("volatile"))))
        return false;
    tok = tok->next();
    if (!tok || false)
        return false;
    return true;
}
// pattern: const|volatile
static bool match110(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("const")) || (tok->str() == MatchCompiler::makeConstString("volatile"))))
        return false;
    return true;
}
// pattern: %type% :: %type%
static bool match111(const Token* tok) {
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    return true;
}
// pattern: std ::
static bool match112(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("std")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    return true;
}
// pattern: string|wstring|u16string|u32string !!::
static bool match113(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("string")) || (tok->str() == MatchCompiler::makeConstString("wstring")) || (tok->str() == MatchCompiler::makeConstString("u16string")) || (tok->str() == MatchCompiler::makeConstString("u32string"))))
        return false;
    tok = tok->next();
    if (tok && tok->str() == MatchCompiler::makeConstString("::"))
        return false;
    return true;
}
// pattern: basic_string <
static bool match114(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("basic_string")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("<")))
        return false;
    return true;
}
// pattern: > ::
static bool match115(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(">")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    return true;
}
// pattern: ; %name% =
static bool match116(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("=")))
        return false;
    return true;
}
// pattern: float|double
static bool match117(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("float")) || (tok->str() == MatchCompiler::makeConstString("double"))))
        return false;
    return true;
}
// pattern: decltype (
template<class T> static T * findmatch118(T * start_tok, const Token * end) {
    for (; start_tok && start_tok != end; start_tok = start_tok->next()) {

    T * tok = start_tok;
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("decltype")))
        continue;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        continue;
    return start_tok;
    }
    return nullptr;
}
// pattern: %name%|::
static bool match119(const Token* tok) {
    if (!tok || !(tok->isName() || (tok->str() == MatchCompiler::makeConstString("::"))))
        return false;
    return true;
}
// pattern: < %name% >
static bool match120(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("<")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(">")))
        return false;
    return true;
}
// pattern: const|volatile| &|&&| .
static bool match121(const Token* tok) {
    if (tok && ((tok->str() == MatchCompiler::makeConstString("const")) || (tok->str() == MatchCompiler::makeConstString("volatile"))))
        tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("&")) || (tok->str() == MatchCompiler::makeConstString("&&"))))
        tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
        return false;
    return true;
}
// pattern: extern|virtual|static|friend|struct|union|enum
static bool match122(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("extern")) || (tok->str() == MatchCompiler::makeConstString("virtual")) || (tok->str() == MatchCompiler::makeConstString("static")) || (tok->str() == MatchCompiler::makeConstString("friend")) || (tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("union")) || (tok->str() == MatchCompiler::makeConstString("enum"))))
        return false;
    return true;
}
// pattern: ( false )
static bool match123(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("false")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    return true;
}
// pattern: throw (
static bool match124(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("throw")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: = 0|default|delete ;
static bool match125(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("=")))
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("0")) || (tok->str() == MatchCompiler::makeConstString("default")) || (tok->str() == MatchCompiler::makeConstString("delete"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: ;|{|override|final
static bool match126(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString("override")) || (tok->str() == MatchCompiler::makeConstString("final"))))
        return false;
    return true;
}
// pattern: ;|}|{|public:|protected:|private:
static bool match127(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("}")) || (tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString("public:")) || (tok->str() == MatchCompiler::makeConstString("protected:")) || (tok->str() == MatchCompiler::makeConstString("private:"))))
        return false;
    return true;
}
// pattern: template <
static bool match128(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("template")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("<")))
        return false;
    return true;
}
// pattern: ( )
static bool match129(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    return true;
}
// pattern: ( void )
static bool match130(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("void")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    return true;
}
// pattern: struct|enum|union|class
static bool match131(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("enum")) || (tok->str() == MatchCompiler::makeConstString("union")) || (tok->str() == MatchCompiler::makeConstString("class"))))
        return false;
    return true;
}
// pattern: const %type% %name%|,|)
static bool match132(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("const")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    tok = tok->next();
    if (!tok || !(tok->isName() || (tok->str() == MatchCompiler::makeConstString(",")) || (tok->str() == MatchCompiler::makeConstString(")"))))
        return false;
    return true;
}
// pattern: const %type% %name%| [
static bool match133(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("const")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    tok = tok->next();
    if (tok && (tok->isName()))
        tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("[")))
        return false;
    return true;
}
// pattern: !!( )
static bool match134(const Token* tok) {
    if (tok && tok->str() == MatchCompiler::makeConstString("("))
        return false;
    tok = tok ? tok->next() : nullptr;
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    return true;
}
// pattern: ,|)
static bool match135(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(",")) || (tok->str() == MatchCompiler::makeConstString(")"))))
        return false;
    return true;
}
// pattern: * %name%| ,|)|=
static bool match136(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("*")))
        return false;
    tok = tok->next();
    if (tok && (tok->isName()))
        tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(",")) || (tok->str() == MatchCompiler::makeConstString(")")) || (tok->str() == MatchCompiler::makeConstString("="))))
        return false;
    return true;
}
// pattern: %name%| [ ] ,|)
static bool match137(const Token* tok) {
    if (tok && (tok->isName()))
        tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("[")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("]")))
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(",")) || (tok->str() == MatchCompiler::makeConstString(")"))))
        return false;
    return true;
}
// pattern: %name% ,|)|=|[
static bool match138(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(",")) || (tok->str() == MatchCompiler::makeConstString(")")) || (tok->str() == MatchCompiler::makeConstString("=")) || (tok->str() == MatchCompiler::makeConstString("["))))
        return false;
    return true;
}
// pattern: %name% ,|)|[
static bool match139(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(",")) || (tok->str() == MatchCompiler::makeConstString(")")) || (tok->str() == MatchCompiler::makeConstString("["))))
        return false;
    return true;
}
// pattern: > :: %name%
static bool match140(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(">")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    return true;
}
// pattern: decltype|typeof
static bool match141(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("decltype")) || (tok->str() == MatchCompiler::makeConstString("typeof"))))
        return false;
    return true;
}
// pattern: const
template<class T> static T * findmatch142(T * start_tok, const Token * end) {
    for (; start_tok && start_tok != end; start_tok = start_tok->next()) {

    T * tok = start_tok;
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("const")))
        continue;
    return start_tok;
    }
    return nullptr;
}
// pattern: return
static bool match143(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("return")))
        return false;
    return true;
}
// pattern: ) :
static bool match144(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(":")))
        return false;
    return true;
}
// pattern: ) noexcept (
static bool match145(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("noexcept")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: = default ;
static bool match146(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("=")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("default")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: :|,
static bool match147(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(":")) || (tok->str() == MatchCompiler::makeConstString(","))))
        return false;
    return true;
}
// pattern: <
template<class T> static T * findmatch148(T * start_tok) {
    for (; start_tok; start_tok = start_tok->next()) {

    T * tok = start_tok;
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("<")))
        continue;
    return start_tok;
    }
    return nullptr;
}
// pattern: %num% [,>]
static bool match149(const Token* tok) {
    if (!tok || !tok->isNumber())
        return false;
    tok = tok->next();
    if (!tok || tok->str().size() != 1U || !strchr(",>", tok->str()[0]))
        return false;
    return true;
}
// pattern: {|;|override|final
static bool match150(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("override")) || (tok->str() == MatchCompiler::makeConstString("final"))))
        return false;
    return true;
}
// pattern: ( & %var% ) [
static bool match151(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("&")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("[")))
        return false;
    return true;
}
// pattern: ( * %var% ) ( ) [,)]
static bool match152(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("*")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || tok->str().size() != 1U || !strchr(",)", tok->str()[0]))
        return false;
    return true;
}
// pattern: ( * %var% ) [
static bool match153(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("*")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("[")))
        return false;
    return true;
}
// pattern: const|volatile|enum|struct|::
static bool match154(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("const")) || (tok->str() == MatchCompiler::makeConstString("volatile")) || (tok->str() == MatchCompiler::makeConstString("enum")) || (tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("::"))))
        return false;
    return true;
}
// pattern: [{[(<]
static bool match155(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr("{[(<", tok->str()[0]))
        return false;
    return true;
}
// pattern: enum|struct|const|volatile
static bool match156(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("enum")) || (tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("const")) || (tok->str() == MatchCompiler::makeConstString("volatile"))))
        return false;
    return true;
}
// pattern: ...
static bool match157(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("...")))
        return false;
    return true;
}
// pattern: :|{
static bool match158(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(":")) || (tok->str() == MatchCompiler::makeConstString("{"))))
        return false;
    return true;
}
// pattern: if|while ( %type%
static bool match159(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("if")) || (tok->str() == MatchCompiler::makeConstString("while"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    return true;
}
// pattern: =
static bool match160(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("=")))
        return false;
    return true;
}
// pattern: class|struct|union|namespace %type% :|{
static bool match161(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("class")) || (tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("union")) || (tok->str() == MatchCompiler::makeConstString("namespace"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(":")) || (tok->str() == MatchCompiler::makeConstString("{"))))
        return false;
    return true;
}
// pattern: } %name% ;|[
static bool match162(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("}")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("["))))
        return false;
    return true;
}
// pattern: private:|protected:|public:
static bool match163(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("private:")) || (tok->str() == MatchCompiler::makeConstString("protected:")) || (tok->str() == MatchCompiler::makeConstString("public:"))))
        return false;
    return true;
}
// pattern: return|delete|goto
static bool match164(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("return")) || (tok->str() == MatchCompiler::makeConstString("delete")) || (tok->str() == MatchCompiler::makeConstString("goto"))))
        return false;
    return true;
}
// pattern: case|default
static bool match165(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("case")) || (tok->str() == MatchCompiler::makeConstString("default"))))
        return false;
    return true;
}
// pattern: [:;{}]
static bool match166(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr(":;{}", tok->str()[0]))
        return false;
    return true;
}
// pattern: ;|{|}|public:|protected:|private:
static bool match167(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString("}")) || (tok->str() == MatchCompiler::makeConstString("public:")) || (tok->str() == MatchCompiler::makeConstString("protected:")) || (tok->str() == MatchCompiler::makeConstString("private:"))))
        return false;
    return true;
}
// pattern: throw %any% (
static bool match168(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("throw")))
        return false;
    tok = tok->next();
    if (!tok || false)
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: throw %any% :: %any% (
static bool match169(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("throw")))
        return false;
    tok = tok->next();
    if (!tok || false)
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    tok = tok->next();
    if (!tok || false)
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: friend %type%
static bool match170(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("friend")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    return true;
}
// pattern: ;|{
template<class T> static T * findmatch171(T * start_tok) {
    for (; start_tok; start_tok = start_tok->next()) {

    T * tok = start_tok;
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("{"))))
        continue;
    return start_tok;
    }
    return nullptr;
}
// pattern: const|constexpr|volatile|static|mutable|extern
static bool match172(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("const")) || (tok->str() == MatchCompiler::makeConstString("constexpr")) || (tok->str() == MatchCompiler::makeConstString("volatile")) || (tok->str() == MatchCompiler::makeConstString("static")) || (tok->str() == MatchCompiler::makeConstString("mutable")) || (tok->str() == MatchCompiler::makeConstString("extern"))))
        return false;
    return true;
}
// pattern: auto &|&&| [
static bool match173(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("auto")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("&")) || (tok->str() == MatchCompiler::makeConstString("&&"))))
        tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("[")))
        return false;
    return true;
}
// pattern: [
template<class T> static T * findmatch174(T * start_tok) {
    for (; start_tok; start_tok = start_tok->next()) {

    T * tok = start_tok;
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("[")))
        continue;
    return start_tok;
    }
    return nullptr;
}
// pattern: %name%|,
static bool match175(const Token* tok) {
    if (!tok || !(tok->isName() || (tok->str() == MatchCompiler::makeConstString(","))))
        return false;
    return true;
}
// pattern: class|struct|union|enum
static bool match176(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("class")) || (tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("union")) || (tok->str() == MatchCompiler::makeConstString("enum"))))
        return false;
    return true;
}
// pattern: [|{
static bool match177(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("[")) || (tok->str() == MatchCompiler::makeConstString("{"))))
        return false;
    return true;
}
// pattern: enum|struct
static bool match178(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("enum")) || (tok->str() == MatchCompiler::makeConstString("struct"))))
        return false;
    return true;
}
// pattern: ( [*&]
static bool match179(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (!tok || tok->str().size() != 1U || !strchr("*&", tok->str()[0]))
        return false;
    return true;
}
// pattern: (|[
static bool match180(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString("["))))
        return false;
    return true;
}
// pattern: ( *
static bool match181(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("*")))
        return false;
    return true;
}
// pattern: ] ) ;
static bool match182(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("]")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: throw|new
static bool match183(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("throw")) || (tok->str() == MatchCompiler::makeConstString("new"))))
        return false;
    return true;
}
// pattern: %type% <
static bool match184(const Token* tok) {
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("<")))
        return false;
    return true;
}
// pattern: const_cast|dynamic_cast|reinterpret_cast|static_cast <
static bool match185(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("const_cast")) || (tok->str() == MatchCompiler::makeConstString("dynamic_cast")) || (tok->str() == MatchCompiler::makeConstString("reinterpret_cast")) || (tok->str() == MatchCompiler::makeConstString("static_cast"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("<")))
        return false;
    return true;
}
// pattern: :: %type% %name% [;=({]
static bool match186(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || tok->str().size() != 1U || !strchr(";=({", tok->str()[0]))
        return false;
    return true;
}
// pattern: [)}] ;
static bool match187(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr(")}", tok->str()[0]))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: %type%
static bool match188(const Token* tok) {
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    return true;
}
// pattern: ) %name%|*|&|&&
static bool match189(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->isName() || (tok->str() == MatchCompiler::makeConstString("*")) || (tok->str() == MatchCompiler::makeConstString("&")) || (tok->str() == MatchCompiler::makeConstString("&&"))))
        return false;
    return true;
}
// pattern: %name% ;|=
static bool match190(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("="))))
        return false;
    return true;
}
// pattern: %name% )|[
static bool match191(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(")")) || (tok->str() == MatchCompiler::makeConstString("["))))
        return false;
    return true;
}
// pattern: %name% (|{
static bool match192(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString("{"))))
        return false;
    return true;
}
// pattern: )|} ;
static bool match193(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(")")) || (tok->str() == MatchCompiler::makeConstString("}"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: %name% )
static bool match194(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    return true;
}
// pattern: %name% =|,|}
static bool match195(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("=")) || (tok->str() == MatchCompiler::makeConstString(",")) || (tok->str() == MatchCompiler::makeConstString("}"))))
        return false;
    return true;
}
// pattern: ) ,|}
static bool match196(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(",")) || (tok->str() == MatchCompiler::makeConstString("}"))))
        return false;
    return true;
}
// pattern: ,|}
static bool match197(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(",")) || (tok->str() == MatchCompiler::makeConstString("}"))))
        return false;
    return true;
}
// pattern: char|wchar_t
static bool match198(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("char")) || (tok->str() == MatchCompiler::makeConstString("wchar_t"))))
        return false;
    return true;
}
// pattern: char|short|int|long
static bool match199(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("char")) || (tok->str() == MatchCompiler::makeConstString("short")) || (tok->str() == MatchCompiler::makeConstString("int")) || (tok->str() == MatchCompiler::makeConstString("long"))))
        return false;
    return true;
}
// pattern: %name%|*|&|::
static bool match200(const Token* tok) {
    if (!tok || !(tok->isName() || (tok->str() == MatchCompiler::makeConstString("*")) || (tok->str() == MatchCompiler::makeConstString("&")) || (tok->str() == MatchCompiler::makeConstString("::"))))
        return false;
    return true;
}
// pattern: %name% const| %var%|*|&
static bool match201(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("const"))))
        tok = tok->next();
    if (!tok || !((tok->varId() != 0) || (tok->str() == MatchCompiler::makeConstString("*")) || (tok->str() == MatchCompiler::makeConstString("&"))))
        return false;
    return true;
}
// pattern: %name%|*|&|::|<
static bool match202(const Token* tok) {
    if (!tok || !(tok->isName() || (tok->str() == MatchCompiler::makeConstString("*")) || (tok->str() == MatchCompiler::makeConstString("&")) || (tok->str() == MatchCompiler::makeConstString("::")) || (tok->str() == MatchCompiler::makeConstString("<"))))
        return false;
    return true;
}
// pattern: %var% ,|)
static bool match203(const Token* tok) {
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(",")) || (tok->str() == MatchCompiler::makeConstString(")"))))
        return false;
    return true;
}
// pattern: nullptr|NULL ,|)
static bool match204(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("nullptr")) || (tok->str() == MatchCompiler::makeConstString("NULL"))))
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(",")) || (tok->str() == MatchCompiler::makeConstString(")"))))
        return false;
    return true;
}
// pattern: >|%type% ::
static bool match205(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(">")) || (tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword()))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    return true;
}
// pattern: %type% :: %name% [(),>]
static bool match206(const Token* tok) {
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || tok->str().size() != 1U || !strchr("(),>", tok->str()[0]))
        return false;
    return true;
}
// pattern: > :: %name% (
static bool match207(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(">")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: !!this .
static bool match208(const Token* tok) {
    if (tok && tok->str() == MatchCompiler::makeConstString("this"))
        return false;
    tok = tok ? tok->next() : nullptr;
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
        return false;
    return true;
}
// pattern: %var% .
static bool match209(const Token* tok) {
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
        return false;
    return true;
}
// pattern: struct|union
static bool match210(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("union"))))
        return false;
    return true;
}
// pattern: struct|union|enum
static bool match211(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("union")) || (tok->str() == MatchCompiler::makeConstString("enum"))))
        return false;
    return true;
}
// pattern: ::|<
static bool match212(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("::")) || (tok->str() == MatchCompiler::makeConstString("<"))))
        return false;
    return true;
}
// pattern: <<|>>
static bool match213(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("<<")) || (tok->str() == MatchCompiler::makeConstString(">>"))))
        return false;
    return true;
}
// pattern: . %name% (
static bool match214(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: %var% ; %var% =
static bool match215(const Token* tok) {
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("=")))
        return false;
    return true;
}
// pattern: %var% =
static bool match216(const Token* tok) {
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("=")))
        return false;
    return true;
}
// pattern: ;|{|}|(|const|constexpr auto
static bool match217(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString("}")) || (tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString("const")) || (tok->str() == MatchCompiler::makeConstString("constexpr"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("auto")))
        return false;
    return true;
}
// pattern: ;|{|}|(|const|constexpr auto *|&|&&
static bool match218(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("{")) || (tok->str() == MatchCompiler::makeConstString("}")) || (tok->str() == MatchCompiler::makeConstString("(")) || (tok->str() == MatchCompiler::makeConstString("const")) || (tok->str() == MatchCompiler::makeConstString("constexpr"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("auto")))
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("*")) || (tok->str() == MatchCompiler::makeConstString("&")) || (tok->str() == MatchCompiler::makeConstString("&&"))))
        return false;
    return true;
}
// pattern: const|constexpr
static bool match219(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("const")) || (tok->str() == MatchCompiler::makeConstString("constexpr"))))
        return false;
    return true;
}
// pattern: *|&
static bool match220(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("*")) || (tok->str() == MatchCompiler::makeConstString("&"))))
        return false;
    return true;
}
// pattern: [{,]
static bool match221(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr("{,", tok->str()[0]))
        return false;
    return true;
}
// pattern: std :: move (
static bool match222(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("std")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("move")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: ( const| auto *|&| %var% :
static bool match223(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("const"))))
        tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("auto")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("*")) || (tok->str() == MatchCompiler::makeConstString("&"))))
        tok = tok->next();
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(":")))
        return false;
    return true;
}
// pattern: for
static bool match224(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("for")))
        return false;
    return true;
}
// pattern: const
static bool match225(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("const")))
        return false;
    return true;
}
// pattern: < %name% > >
static bool match226(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("<")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(">")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(">")))
        return false;
    return true;
}
// pattern: auto %var% {
static bool match227(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("auto")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: %name%|*|&|&&|::|(
static bool match228(const Token* tok) {
    if (!tok || !(tok->isName() || (tok->str() == MatchCompiler::makeConstString("*")) || (tok->str() == MatchCompiler::makeConstString("&")) || (tok->str() == MatchCompiler::makeConstString("&&")) || (tok->str() == MatchCompiler::makeConstString("::")) || (tok->str() == MatchCompiler::makeConstString("("))))
        return false;
    return true;
}
// pattern: typename|template
static bool match229(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("typename")) || (tok->str() == MatchCompiler::makeConstString("template"))))
        return false;
    return true;
}
// pattern: ) const| {
static bool match230(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("const"))))
        tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: %type%|::|<
static bool match231(const Token* tok) {
    if (!tok || !((tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())) || (tok->str() == MatchCompiler::makeConstString("::")) || (tok->str() == MatchCompiler::makeConstString("<"))))
        return false;
    return true;
}
// pattern: !!:: %name% !!::
static bool match232(const Token* tok) {
    if (tok && tok->str() == MatchCompiler::makeConstString("::"))
        return false;
    tok = tok ? tok->next() : nullptr;
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (tok && tok->str() == MatchCompiler::makeConstString("::"))
        return false;
    return true;
}
// pattern: ( %name%
static bool match233(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    return true;
}
// pattern: static_cast|const_cast|dynamic_cast|reinterpret_cast < %name%
static bool match234(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("static_cast")) || (tok->str() == MatchCompiler::makeConstString("const_cast")) || (tok->str() == MatchCompiler::makeConstString("dynamic_cast")) || (tok->str() == MatchCompiler::makeConstString("reinterpret_cast"))))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("<")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    return true;
}
// pattern: >
static bool match235(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(">")))
        return false;
    return true;
}
// pattern: sizeof (
static bool match236(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("sizeof")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: ( %type% %type%| *| *| )
static bool match237(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    tok = tok->next();
    if (tok && ((tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword()))))
        tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("*"))))
        tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("*"))))
        tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    return true;
}
// pattern: :: %name% < %name%
static bool match238(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("<")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    return true;
}
// pattern: .
static bool match239(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
        return false;
    return true;
}
// pattern: return {
static bool match240(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("return")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: ( std| ::| nothrow )
static bool match241(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("std"))))
        tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("::"))))
        tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("nothrow")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    return true;
}
// pattern: %type% ;|[|(
static bool match242(const Token* tok) {
    if (!tok || !(tok->isName() && tok->varId() == 0U && (tok->str() != "delete" || !tok->isKeyword())))
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(";")) || (tok->str() == MatchCompiler::makeConstString("[")) || (tok->str() == MatchCompiler::makeConstString("("))))
        return false;
    return true;
}
// pattern: std :: array
static bool match243(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("std")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("::")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("array")))
        return false;
    return true;
}
#line 1 "/build/cppcheck/src/cppcheck/lib/symboldatabase.cpp"
/*
 * Cppcheck - A tool for static C/C++ code analysis
 * Copyright (C) 2007-2022 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 "errortypes.h"
#include "library.h"
#include "mathlib.h"
#include "platform.h"
#include "settings.h"
#include "standards.h"
#include "templatesimplifier.h"
#include "token.h"
#include "tokenize.h"
#include "tokenlist.h"
#include "utils.h"
#include "valueflow.h"

#include <algorithm>
#include <cassert>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <limits>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
//---------------------------------------------------------------------------

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);
    createSymbolDatabaseSetTypePointers();
    createSymbolDatabaseSetFunctionPointers(true);
    createSymbolDatabaseSetSmartPointerType();
    setValueTypeInTokenList(false);
    createSymbolDatabaseEnums();
    createSymbolDatabaseEscapeFunctions();
    createSymbolDatabaseIncompleteVars();
    createSymbolDatabaseExprIds();
}

static const Token* skipScopeIdentifiers(const Token* tok)
{
    if (match1(tok))
        tok = tok->next();
    while (match2(tok) ||
           (match3(tok) && match4(tok->linkAt(1)))) {
        if (tok->strAt(1) == MatchCompiler::makeConstString("::"))
            tok = tok->tokAt(2);
        else
            tok = tok->linkAt(1)->tokAt(2);
    }

    return tok;
}

static bool isExecutableScope(const Token* tok)
{
    if (!match5(tok))
        return false;
    const Token * tok2 = tok->link()->previous();
    if (match6(tok2))
        return true;
    if (match7(tok2)) {
        const Token* startTok = tok2->str() == MatchCompiler::makeConstString("{") ? tok2 : tok2->link();
        if (match8(startTok->previous()))
            return true;
        if (match9(startTok->previous()))
            return !findLambdaStartToken(tok2);
        if (tok->str() == MatchCompiler::makeConstString("{"))
            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 the edning of init lists
    std::stack<std::pair<const Token*, const Scope*>> endInitList;
    auto inInitList = [&] {
        if (endInitList.empty())
            return false;
        return endInitList.top().second == scope;
    };

    // 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() &&
             ((match10(tok) &&
               !match11(tok->previous())) ||
              (match12(tok) ||
               match13(tok))))
            || (mTokenizer->isC() && tok->isKeyword() && match14(tok))) {
            const Token *tok2 = tok->tokAt(2);

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

            while (match1(tok2))
                tok2 = tok2->tokAt(2);
            while (match15(tok2))
                tok2 = tok2->tokAt(2);

            // skip over template args
            while (tok2 && tok2->str() == MatchCompiler::makeConstString("<") && tok2->link()) {
                tok2 = tok2->link()->next();
                while (match1(tok2))
                    tok2 = tok2->tokAt(2);
            }

            // skip over final
            if (mTokenizer->isCPP() && match16(tok2))
                tok2 = tok2->next();

            // make sure we have valid code
            if (!match17(tok2)) {
                // check for qualified variable
                if (tok2 && tok2->next()) {
                    if (tok2->next()->str() == MatchCompiler::makeConstString(";"))
                        tok = tok2->next();
                    else if (match18(tok2->next()) &&
                             match19(tok2->linkAt(2)))
                        tok = tok2->linkAt(2)->next();
                    else if (match20(tok2->next()) &&
                             tok2->next()->link()->strAt(1) == MatchCompiler::makeConstString(";"))
                        tok = tok2->next()->link()->next();
                    // skip variable declaration
                    else if (match21(tok2))
                        continue;
                    else if (match22(tok2) && mTokenizer->isFunctionHead(tok2->next(), "{;"))
                        continue;
                    else if (match23(tok2))
                        continue;
                    // skip template
                    else if (match24(tok2) &&
                             match25(tok->previous())) {
                        tok = tok2;
                        continue;
                    }
                    // forward declaration
                    else if (match24(tok2) &&
                             match26(tok)) {
                        // TODO: see if it can be used
                        tok = tok2;
                        continue;
                    }
                    // skip constructor
                    else if (match27(tok2) &&
                             match28(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() == MatchCompiler::makeConstString("class") && name->strAt(-1) == MatchCompiler::makeConstString("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() == MatchCompiler::makeConstString("class")) {
                    access[new_scope] = AccessControl::Private;
                    new_scope->type = Scope::eClass;
                } else if (tok->str() == MatchCompiler::makeConstString("struct")) {
                    access[new_scope] = AccessControl::Public;
                    new_scope->type = Scope::eStruct;
                }

                new_scope->classDef = tok;
                new_scope->setBodyStartEnd(tok2);
                // 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() == MatchCompiler::makeConstString("class"))
                    access[new_scope] = AccessControl::Private;
                else if (tok->str() == MatchCompiler::makeConstString("struct") || tok->str() == MatchCompiler::makeConstString("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() == MatchCompiler::makeConstString(":"))
                        tok2 = tok2->tokAt(2);
                }

                new_scope->setBodyStartEnd(tok2);

                // 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() &&
                 match29(tok) &&
                 tok->tokAt(2)->isUpperCaseName() &&
                 match9(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->setBodyStartEnd(tok2);

            // 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() && match30(tok) &&
                 tok->strAt(-1) != MatchCompiler::makeConstString("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() && match31(tok)) {
            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) == MatchCompiler::makeConstString("::"))
                tok = tok->tokAt(4);
            else
                tok = tok->tokAt(3);

            // skip over qualification
            while (match32(tok))
                tok = tok->tokAt(2);
        }

        // using type alias
        else if (mTokenizer->isCPP() && tok->isKeyword() && match33(tok)) {
            if (tok->strAt(-1) != MatchCompiler::makeConstString(">") && !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() != MatchCompiler::makeConstString(";"))
                tok = tok->next();
        }

        // unnamed struct and union
        else if (tok->isKeyword() && match34(tok) &&
                 match35(tok->next()->link())) {
            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() == MatchCompiler::makeConstString("*")) {
                varNameTok = varNameTok->next();
            } else if (varNameTok->str() == MatchCompiler::makeConstString("&")) {
                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->setBodyStartEnd(tok2);

            // 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() && ((match34(tok) &&
                                       match19(tok->next()->link())) ||
                                      match36(tok))) {
            scopeList.emplace_back(this, tok, scope);

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

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

            new_scope->setBodyStartEnd(tok2);

            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() && (match37(tok) || match38(tok))) {
            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 for end of init list
        else if (inInitList() && tok == endInitList.top().first) {
            endInitList.pop();
            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() == MatchCompiler::makeConstString("private:"))
                access[scope] = AccessControl::Private;
            else if (tok->str() == MatchCompiler::makeConstString("protected:"))
                access[scope] = AccessControl::Protected;
            else if (tok->str() == MatchCompiler::makeConstString("public:") || tok->str() == MatchCompiler::makeConstString("__published:"))
                access[scope] = AccessControl::Public;
            else if (match39(tok)) {
                if (tok->str() == MatchCompiler::makeConstString("private"))
                    access[scope] = AccessControl::Private;
                else if (tok->str() == MatchCompiler::makeConstString("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() != MatchCompiler::makeConstString("::") || 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() != MatchCompiler::makeConstString("{") && end->str() != MatchCompiler::makeConstString(";")) {
                            if (end->link() && match40(end)) {
                                end = end->link();
                            } else if (foundInitList &&
                                       match41(end) &&
                                       match42(end->linkAt(1))) {
                                end = end->linkAt(1);
                            } else {
                                if (end->str() == MatchCompiler::makeConstString(":"))
                                    foundInitList = true;
                                end = end->next();
                            }
                        }

                        if (!end || end->str() == MatchCompiler::makeConstString(";"))
                            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() && match43(tok)) {
                Type::FriendInfo friendInfo;

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

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

                // skip qualification "name ::"
                while (friendInfo.nameEnd && friendInfo.nameEnd->strAt(1) == MatchCompiler::makeConstString("::"))
                    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() == MatchCompiler::makeConstString("{")) {
                    tok = funcStart;

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

                    // class destructor
                    else if (tok->previous() &&
                             tok->previous()->str() == MatchCompiler::makeConstString("~") &&
                             tok->strAt(-2) == MatchCompiler::makeConstString("::"))
                        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() == MatchCompiler::makeConstString(";")) {
                    if (tok->astParent() && tok->astParent()->str() == MatchCompiler::makeConstString("::") &&
                        match44(declEnd->previous())) {
                        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 (i->second->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() && match45(tok)) {
                const Token* tok1 = tok->next();
                if (tok->str() == MatchCompiler::makeConstString("else"))
                    scopeList.emplace_back(this, tok, scope, Scope::eElse, tok1);
                else if (tok->str() == MatchCompiler::makeConstString("do"))
                    scopeList.emplace_back(this, tok, scope, Scope::eDo, tok1);
                else //if (tok->str() == MatchCompiler::makeConstString("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() && match46(tok) && match9(tok->next()->link())) {
                const Token *scopeStartTok = tok->next()->link()->next();
                if (tok->str() == MatchCompiler::makeConstString("if"))
                    scopeList.emplace_back(this, tok, scope, Scope::eIf, scopeStartTok);
                else if (tok->str() == MatchCompiler::makeConstString("for")) {
                    scopeList.emplace_back(this, tok, scope, Scope::eFor, scopeStartTok);
                } else if (tok->str() == MatchCompiler::makeConstString("while"))
                    scopeList.emplace_back(this, tok, scope, Scope::eWhile, scopeStartTok);
                else if (tok->str() == MatchCompiler::makeConstString("catch")) {
                    scopeList.emplace_back(this, tok, scope, Scope::eCatch, scopeStartTok);
                } else // if (tok->str() == MatchCompiler::makeConstString("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 (match47(tok)) {
                endInitList.push(std::make_pair(tok->next()->link(), scope));
                tok = tok->next();
            } else if (const Token *lambdaEndToken = findLambdaEndToken(tok)) {
                const Token *lambdaStartToken = lambdaEndToken->link();
                const Token * argStart = lambdaStartToken->astParent();
                const Token * funcStart = match48(argStart) ? argStart : argStart->astParent();
                const Function * function = addGlobalFunction(scope, tok, argStart, funcStart);
                if (!function)
                    mTokenizer->syntaxError(tok);
                tok = lambdaStartToken;
            } else if (tok->str() == MatchCompiler::makeConstString("{")) {
                if (inInitList()) {
                    endInitList.push(std::make_pair(tok->link(), scope));
                } else if (isExecutableScope(tok)) {
                    scopeList.emplace_back(this, tok, scope, Scope::eUnconditional, tok);
                    scope->nestedList.push_back(&scopeList.back());
                    scope = &scopeList.back();
                } else if (scope->isExecutable()) {
                    endInitList.push(std::make_pair(tok->link(), scope));
                } else {
                    tok = tok->link();
                }
            }
            // syntax error?
            if (!scope)
                mTokenizer->syntaxError(tok);
            // End of scope or list should be handled above
            if (tok->str() == MatchCompiler::makeConstString("}"))
                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 (match49(type))
                    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.isClassOrStructOrUnion())
                    continue;

                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;

                    for (Function& func: scope.functionList) {
                        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;

                        for (const Variable& var: scope.varlist) {
                            if (var.isClass()) {
                                if (var.type()) {
                                    // does this type need initialization?
                                    if (var.type()->needInitialization == Type::NeedInitialization::True && !var.hasDefault())
                                        needInitialization = true;
                                    else if (var.type()->needInitialization == Type::NeedInitialization::Unknown) {
                                        if (!(var.valueType() && var.valueType()->type == ValueType::CONTAINER))
                                            unknown = true;
                                    }
                                }
                            } else if (!var.hasDefault() && !var.isStatic()) {
                                needInitialization = true;
                                break;
                            }
                        }

                        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, "debug", "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 (Variable& var: scope.varlist) {
            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 (Variable& arg: func.argumentList) {
                // check for named parameters
                if (arg.nameToken() && arg.declarationId()) {
                    const unsigned int declarationId = arg.declarationId();
                    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() == MatchCompiler::makeConstString(".") ||
                 (tok->next()->str() == MatchCompiler::makeConstString("[") && tok->linkAt(1)->strAt(1) == MatchCompiler::makeConstString(".")))) {
                const Token *tok1 = tok->next()->str() == MatchCompiler::makeConstString(".") ? 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()
{
    auto setScopePointers = [](const Scope &scope, const Token *bodyStart, const Token *bodyEnd) {
        assert(bodyStart);
        assert(bodyEnd);

        const_cast<Token *>(bodyEnd)->scope(&scope);

        for (Token* tok = const_cast<Token *>(bodyStart); tok != bodyEnd; tok = tok->next()) {
            if (bodyStart != bodyEnd && tok->str() == MatchCompiler::makeConstString("{")) {
                bool isEndOfScope = false;
                for (Scope* innerScope: scope.nestedList) {
                    const auto &list = innerScope->bodyStartList;
                    if (std::find(list.begin(), list.end(), tok) != list.end()) {     // Is begin of inner scope
                        tok = tok->link();
                        if (tok->next() == bodyEnd || !tok->next()) {
                            isEndOfScope = true;
                            break;
                        }
                        tok = tok->next();
                        break;
                    }
                }
                if (isEndOfScope)
                    break;
            }
            tok->scope(&scope);
        }
    };

    // Set scope pointers
    for (Scope& scope: scopeList) {
        if (scope.type == Scope::eGlobal)
            setScopePointers(scope, mTokenizer->list.front(), mTokenizer->list.back());
        else {
            for (const Token *bodyStart: scope.bodyStartList)
                setScopePointers(scope, bodyStart, bodyStart->link());
        }
    }
}

void SymbolDatabase::createSymbolDatabaseSetFunctionPointers(bool firstPass)
{
    if (firstPass) {
        // Set function definition and declaration pointers
        for (const Scope& scope: scopeList) {
            for (const Function& func: scope.functionList) {
                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 && match50(tok) && !isReservedName(tok->str())) {
            if (tok->next()->str() == MatchCompiler::makeConstString(">") && !tok->next()->link())
                continue;

            if (tok->next()->str() != MatchCompiler::makeConstString("(")) {
                const Token *start = tok;
                while (match2(start->tokAt(-2)))
                    start = start->tokAt(-2);
                if (!match51(start->previous()) && !match52(start->tokAt(-2)))
                    continue;
            }

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

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

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

    // Set C++ 11 delegate constructor function call pointers
    for (const Scope& scope: scopeList) {
        for (const Function& func: scope.functionList) {
            // look for initializer list
            if (func.isConstructor() && func.functionScope && func.functionScope->functionOf && func.arg) {
                const Token * tok = func.arg->link()->next();
                if (tok->str() == MatchCompiler::makeConstString("noexcept")) {
                    const Token * closingParenTok = tok->linkAt(1);
                    if (!closingParenTok || !closingParenTok->next()) {
                        continue;
                    }
                    tok = closingParenTok->next();
                }
                if (tok->str() != MatchCompiler::makeConstString(":")) {
                    continue;
                }
                tok = tok->next();
                while (tok && tok != func.functionScope->bodyStart) {
                    if (match53(tok)) {
                        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)) &&
            match54(tok)) {

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

            Token *membertok = nullptr;
            if (match55(tok2))
                membertok = tok2->next();
            else if (match56(tok2) && tok->strAt(-1) == MatchCompiler::makeConstString("("))
                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 (match57(var->typeStartToken())) {
                        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() == MatchCompiler::makeConstString("(") &&
                 (match58(tok->next()->link()) ||
                  (match59(tok->next()->link()) && match60(tok->next()->link()->next()->link())))) {
            const Type *type = tok->function()->retType;
            if (type) {
                Token *membertok;
                if (tok->next()->link()->next()->str() == MatchCompiler::makeConstString("."))
                    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()
{
    static const std::unordered_set<std::string> cpp20keywords = {
        "alignas",
        "alignof",
        "axiom",
        "co_await",
        "co_return",
        "co_yield",
        "concept",
        "synchronized",
        "consteval",
        "reflexpr",
        "requires",
    };
    static const std::unordered_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 (!match61(tok))
            continue;
        if (!tok->isNameOnly())
            continue;
        if (match62(tok))
            continue;
        if (tok->type())
            continue;
        if (match63(tok->next()))
            continue;
        if (match64(tok->next()))
            continue;
        if (match65(tok->next()) && match66(tok->next()->link()->previous()))
            continue;
        // Very likely a typelist
        if (match67(tok->tokAt(-2)))
            continue;
        // Inside template brackets
        if (match68(tok->next()) && tok->next()->link())
            continue;
        if (match69(tok->previous()) && tok->previous()->link())
            continue;
        // Skip goto labels
        if (match70(tok->previous()))
            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));
    }
}

static bool isExpression(const Token* tok)
{
    if (!match71(tok))
        return false;
    if (match72(tok)) {
        const Token* vartok = findAstNode(tok, [&](const Token* tok2) {
            const Variable* var = tok2->variable();
            if (!var)
                return false;
            return var->nameToken() == tok2;
        });
        if (vartok)
            return false;
    }
    return true;
}

void SymbolDatabase::createSymbolDatabaseExprIds()
{
    nonneg int base = 0;
    // Find highest varId
    for (const Variable *var : mVariableList) {
        if (!var)
            continue;
        base = std::max<MathLib::bigint>(base, var->declarationId());
    }
    nonneg int id = base + 1;
    for (const Scope * scope : functionScopes) {
        nonneg int thisId = 0;
        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 (isExpression(tok)) {
                exprs[tok->str()].push_back(tok);
                tok->exprId(id++);

                if (id == std::numeric_limits<nonneg int>::max()) {
                    throw InternalError(nullptr, "Ran out of expression ids.", InternalError::INTERNAL);
                }
            } else if (isCPP() && match73(tok)) {
                if (thisId == 0)
                    thisId = id++;
                tok->exprId(thisId);
            }
        }

        // 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, false, false))
                        continue;
                    nonneg int 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 (match74(dimension.tok->previous())) {
                if (dimension.known)
                    continue;
                if (!match74(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, 0, false);
                bool fail = false;
                for (const Token *tok = dimension.tok; tok && !match75(tok); tok = tok->next()) {
                    if (!tok->isName())
                        tokenList.addtoken(tok->str(), 0, 0, 0, false);

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

                    else {
                        fail = true;
                        break;
                    }
                }

                if (fail)
                    continue;

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

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

                if (match76(tokenList.front())) {
                    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() == MatchCompiler::makeConstString("(") && tok->strAt(1) != MatchCompiler::makeConstString("*") &&
        (tok->link()->previous()->str() == MatchCompiler::makeConstString(")") || match77(tok->link()->tokAt(-2)))) {
        const Token* tok2 = tok->link()->next();
        if (tok2 && tok2->str() == MatchCompiler::makeConstString("(") && match78(tok2->link()->next())) {
            const Token* argStartTok;
            if (tok->link()->previous()->str() == MatchCompiler::makeConstString("const"))
                argStartTok = tok->link()->linkAt(-2);
            else
                argStartTok = tok->link()->linkAt(-1);
            *funcStart = argStartTok->previous();
            *argStart = argStartTok;
            *declEnd = findmatch79(tok2->link()->next()) ;
            return true;
        } else if (tok2 && tok2->str() == MatchCompiler::makeConstString("[")) {
            while (tok2 && tok2->str() == MatchCompiler::makeConstString("["))
                tok2 = tok2->link()->next();
            if (match78(tok2)) {
                const Token* argStartTok;
                if (tok->link()->previous()->str() == MatchCompiler::makeConstString("const"))
                    argStartTok = tok->link()->linkAt(-2);
                else
                    argStartTok = tok->link()->linkAt(-1);
                *funcStart = argStartTok->previous();
                *argStart = argStartTok;
                *declEnd = findmatch79(tok2) ;
                return true;
            }
        }
    }

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

    // regular function?
    else if (match22(tok) && !isReservedName(tok->str()) && tok->previous() &&
             (match80(tok->previous()) || // 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() == MatchCompiler::makeConstString("~"))
            tok1 = tok1->previous();

        // skip over qualification
        while (match81(tok1)) {
            tok1 = tok1->previous();
            if (match61(tok1))
                tok1 = tok1->previous();
            else if (tok1 && tok1->str() == MatchCompiler::makeConstString(">") && tok1->link() && match61(tok1->link()->previous()))
                tok1 = tok1->link()->tokAt(-2);
        }

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

        // skip over trailing return type
        if (tok2 && tok2->str() == MatchCompiler::makeConstString(".")) {
            for (tok2 = tok2->next(); tok2; tok2 = tok2->next()) {
                if (match83(tok2))
                    break;
                if (tok2->link() && match84(tok2))
                    tok2 = tok2->link();
            }
        }

        // done if constructor or destructor
        if (!match85(tok1) && tok1) {
            // skip over pointers and references
            while (match86(tok1) && !endsWith(tok1->str(), ':') && (!isReservedName(tok1->str()) || tok1->str() == MatchCompiler::makeConstString("const")))
                tok1 = tok1->previous();

            // skip over decltype
            if (match65(tok1) && tok1->link() &&
                match87(tok1->link()->previous()))
                tok1 = tok1->link()->tokAt(-2);

            // skip over template
            if (tok1 && tok1->str() == MatchCompiler::makeConstString(">")) {
                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 (match61(tok1)) {
                if (tok1->str() == MatchCompiler::makeConstString("return"))
                    return false;
                tok1 = tok1->previous();
            }

            // skip over qualification
            while (match81(tok1)) {
                tok1 = tok1->previous();
                if (match61(tok1))
                    tok1 = tok1->previous();
                else if (tok1 && tok1->str() == MatchCompiler::makeConstString(">") && tok1->link() && match61(tok1->link()->previous()))
                    tok1 = tok1->link()->tokAt(-2);
                else if (match65(tok1) && tok1->link() &&
                         match87(tok1->link()->previous()))
                    tok1 = tok1->link()->tokAt(-2);
            }

            // skip over modifiers and other stuff
            while (match88(tok1)) {
                // friend type func(); is not a function
                if (isCPP() && tok1->str() == MatchCompiler::makeConstString("friend") && tok2->str() == MatchCompiler::makeConstString(";"))
                    return false;
                tok1 = tok1->previous();
            }

            // should be at a sequence point if this is a function
            if (!match89(tok1) && tok1)
                return false;
        }

        if (tok2 &&
            (match90(tok2) ||
             (tok2->isUpperCaseName() && match91(tok2)) ||
             (tok2->isUpperCaseName() && match22(tok2) && tok2->next()->link()->strAt(1) == MatchCompiler::makeConstString("{")) ||
             match92(tok2) ||
             match93(tok2) ||
             match94(tok2))) {
            *funcStart = tok;
            *argStart = tok->next();
            *declEnd = findmatch79(tok2) ;
            return true;
        }
    }

    // UNKNOWN_MACRO(a,b) { ... }
    else if (outerScope->type == Scope::eGlobal &&
             match22(tok) &&
             tok->isUpperCaseName() &&
             match9(tok->linkAt(1)) &&
             (!tok->previous() || match95(tok->previous()))) {
        *funcStart = tok;
        *argStart = tok->next();
        *declEnd = tok->linkAt(1)->next();
        return true;
    }

    // template constructor?
    else if (match3(tok) && match96(tok->next()->link())) {
        const Token* tok2 = tok->next()->link()->next()->link();
        if (match97(tok2) ||
            match98(tok2) ||
            match99(tok2)) {
            *funcStart = tok;
            *argStart = tok2->link();
            *declEnd = findmatch79(tok2->next()) ;
            return true;
        }
    }

    // regular C function with missing return or invalid C++ ?
    else if (match22(tok) && !isReservedName(tok->str()) &&
             match9(tok->linkAt(1)) &&
             (!tok->previous() || match100(tok->previous()))) {
        if (mTokenizer->isC()) {
            debugMessage(tok, "debug", "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,
                                      Certainty::normal);
            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();
    }
    // TODO
    //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 (match86(mTypeStartToken->previous()))
            mTypeStartToken = mTypeStartToken->previous();
    }

    while (match101(mTypeStartToken)) {
        if (mTypeStartToken->str() == MatchCompiler::makeConstString("static"))
            setFlag(fIsStatic, true);
        mTypeStartToken = mTypeStartToken->next();
    }

    if (match102(mTypeEndToken))
        setFlag(fIsReference, true);
    else if (match103(mTypeEndToken)) {
        setFlag(fIsReference, true);
        setFlag(fIsRValueRef, 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() == MatchCompiler::makeConstString("["))
        initTok = initTok->link()->next();
    if (match104(initTok) || (initTok && initTok->isSplittedVarDeclEq()))
        setFlag(fIsInit, true);
}

Variable::Variable(const Variable &var, const Scope *scope)
    : mValueType(nullptr)
{
    *this = var;
    mScope = scope;
}

Variable::Variable(const Variable &var)
    : mValueType(nullptr)
{
    *this = var;
}

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

Variable& Variable::operator=(const Variable &var)
{
    if (this == &var)
        return *this;

    mNameToken = var.mNameToken;
    mTypeStartToken = var.mTypeStartToken;
    mTypeEndToken = var.mTypeEndToken;
    mIndex = var.mIndex;
    mAccess = var.mAccess;
    mFlags = var.mFlags;
    mType = var.mType;
    mScope = var.mScope;
    mDimensions = var.mDimensions;
    delete mValueType;
    if (var.mValueType)
        mValueType = new ValueType(*var.mValueType);
    else
        mValueType = nullptr;

    return *this;
}

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

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

const Token * Variable::declEndToken() const
{
    Token const * declEnd = typeStartToken();
    while (declEnd && !match105(declEnd)) {
        if (declEnd->link() && match106(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() == MatchCompiler::makeConstString("["))
        initTok = initTok->link()->next();
    if (match104(initTok) || (initTok && initTok->isSplittedVarDeclEq()))
        setFlag(fIsInit, true);

    if (!settings)
        return;

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

    bool isContainer = false;
    if (mNameToken)
        setFlag(fIsArray, arrayDimensions(settings, &isContainer));

    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() == MatchCompiler::makeConstString("static"))
            setFlag(fIsStatic, true);
        else if (tok->str() == MatchCompiler::makeConstString("extern"))
            setFlag(fIsExtern, true);
        else if (tok->str() == MatchCompiler::makeConstString("volatile") || match107(tok))
            setFlag(fIsVolatile, true);
        else if (tok->str() == MatchCompiler::makeConstString("mutable"))
            setFlag(fIsMutable, true);
        else if (tok->str() == MatchCompiler::makeConstString("const"))
            setFlag(fIsConst, true);
        else if (tok->str() == MatchCompiler::makeConstString("constexpr")) {
            setFlag(fIsConst, true);
            setFlag(fIsStatic, true);
        } else if (tok->str() == MatchCompiler::makeConstString("*")) {
            setFlag(fIsPointer, !isArray() || (isContainer && !match23(tok->next())) || match108(tok->previous()));
            setFlag(fIsConst, false); // Points to const, isn't necessarily const itself
        } else if (tok->str() == MatchCompiler::makeConstString("&")) {
            if (isReference())
                setFlag(fIsRValueRef, true);
            setFlag(fIsReference, true);
        } else if (tok->str() == MatchCompiler::makeConstString("&&")) { // Before simplification, && isn't split up
            setFlag(fIsRValueRef, true);
            setFlag(fIsReference, true); // Set also fIsReference
        }

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

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

    while (match109(mTypeStartToken))
        mTypeStartToken = mTypeStartToken->next();
    while (mTypeEndToken && mTypeEndToken->previous() && match110(mTypeEndToken))
        mTypeEndToken = mTypeEndToken->previous();

    if (mTypeStartToken) {
        std::string strtype = mTypeStartToken->str();
        for (const Token *typeToken = mTypeStartToken; match111(typeToken); typeToken = typeToken->tokAt(2))
            strtype += "::" + typeToken->strAt(2);
        setFlag(fIsClass, !lib->podtype(strtype) && !mTypeStartToken->isStandardType() && !isEnumType() && !isPointer() && !isReference() && strtype != MatchCompiler::makeConstString("..."));
        setFlag(fIsStlType, match112(mTypeStartToken));
        setFlag(fIsStlString, isStlType() && (match113(mTypeStartToken->tokAt(2)) || (match114(mTypeStartToken->tokAt(2)) && !match115(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() == MatchCompiler::makeConstString("]"))
                tok = tok->link()->previous();
            // add array dimensions if present
            if (tok && tok->next()->str() == MatchCompiler::makeConstString("["))
                setFlag(fIsArray, arrayDimensions(settings, &isContainer));
        }
        if (!tok)
            return;
        tok = tok->next();
        while (tok->str() == MatchCompiler::makeConstString("["))
            tok = tok->link();
        setFlag(fHasDefault, tok->str() == MatchCompiler::makeConstString("="));
    }
    // 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 ((match116(declEnd) && declEnd->strAt(1) == mNameToken->str()) ||
            match104(declEnd))
            setFlag(fHasDefault, true);
    }

    if (mTypeStartToken) {
        if (match117(mTypeStartToken))
            setFlag(fIsFloatType, true);
    }
}

void Variable::setValueType(const ValueType &valueType)
{
    if (valueType.type == ValueType::Type::UNKNOWN_TYPE) {
        const Token *declType = findmatch118(mTypeStartToken, mTypeEndToken) ;
        if (declType && !declType->next()->valueType())
            return;
    }
    delete mValueType;
    mValueType = new ValueType(valueType);
    if ((mValueType->pointer > 0) && (!isArray() || match108(mNameToken->previous())))
        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 (match119(ptrType))
        ptrType = ptrType->next();
    if (match120(ptrType))
        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; match119(typeTok) && 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() == MatchCompiler::makeConstString("operator="))
            type = Function::eOperatorEqual;
    }

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

    // class constructor/destructor
    else if (((tokenDef->str() == scope->className) ||
              (tokenDef->str().substr(0, scope->className.size()) == scope->className &&
               tokenDef->str().size() > scope->className.size() + 1 &&
               tokenDef->str()[scope->className.size() + 1] == '<')) &&
             scope->type != Scope::ScopeType::eNamespace) {
        // destructor
        if (tokenDef->previous()->str() == MatchCompiler::makeConstString("~"))
            type = Function::eDestructor;
        // constructor of any kind
        else
            type = Function::eConstructor;

        isExplicit(tokenDef->strAt(-1) == MatchCompiler::makeConstString("explicit") || tokenDef->strAt(-2) == MatchCompiler::makeConstString("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 (match121(argDef->link()->next())) { // Trailing return type
            hasTrailingReturnType(true);
            if (argDef->link()->strAt(1) == MatchCompiler::makeConstString("."))
                retDef = argDef->link()->tokAt(2);
            else if (argDef->link()->strAt(2) == MatchCompiler::makeConstString("."))
                retDef = argDef->link()->tokAt(3);
            else if (argDef->link()->strAt(3) == MatchCompiler::makeConstString("."))
                retDef = argDef->link()->tokAt(4);
        } else {
            if (tok1->str() == MatchCompiler::makeConstString(">"))
                tok1 = tok1->next();
            while (match122(tok1))
                tok1 = tok1->next();
            retDef = tok1;
        }
    }

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

    // parse function attributes..
    tok = end->next();
    while (tok) {
        if (tok->str() == MatchCompiler::makeConstString("const"))
            isConst(true);
        else if (tok->str() == MatchCompiler::makeConstString("&"))
            hasLvalRefQualifier(true);
        else if (tok->str() == MatchCompiler::makeConstString("&&"))
            hasRvalRefQualifier(true);
        else if (tok->str() == MatchCompiler::makeConstString("override"))
            setFlag(fHasOverrideSpecifier, true);
        else if (tok->str() == MatchCompiler::makeConstString("final"))
            setFlag(fHasFinalSpecifier, true);
        else if (tok->str() == MatchCompiler::makeConstString("volatile"))
            isVolatile(true);
        else if (tok->str() == MatchCompiler::makeConstString("noexcept")) {
            isNoExcept(!match123(tok->next()));
            if (tok->next()->str() == MatchCompiler::makeConstString("("))
                tok = tok->linkAt(1);
        } else if (match124(tok)) {
            isThrow(true);
            if (tok->strAt(2) != MatchCompiler::makeConstString(")"))
                throwArg = tok->next();
            tok = tok->linkAt(1);
        } else if (match125(tok)) {
            const std::string& modifier = tok->strAt(1);
            isPure(modifier == MatchCompiler::makeConstString("0"));
            isDefault(modifier == MatchCompiler::makeConstString("default"));
            isDelete(modifier == MatchCompiler::makeConstString("delete"));
        } else if (tok->str() == MatchCompiler::makeConstString(".")) { // trailing return type
            // skip over return type
            while (tok && !match126(tok->next()))
                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, const std::string &clangType)
    : 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() == MatchCompiler::makeConstString("operator="))
            type = Function::eOperatorEqual;
    }

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

    if (endsWith(clangType, " const"))
        isConst(true);
}

const Token *Function::setFlags(const Token *tok1, const Scope *scope)
{
    if (tok1->isInline())
        isInlineKeyword(true);

    // look for end of previous statement
    while (tok1->previous() && !match127(tok1->previous())) {
        tok1 = tok1->previous();

        if (tok1->isInline())
            isInlineKeyword(true);

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

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

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

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

        // constexpr function
        else if (tok1->str() == MatchCompiler::makeConstString("constexpr")) {
            isConstexpr(true);
        }

        // decltype
        else if (tok1->str() == MatchCompiler::makeConstString(")") && match87(tok1->link()->previous())) {
            tok1 = tok1->link()->previous();
        }

        // Function template
        else if (tok1->link() && tok1->str() == MatchCompiler::makeConstString(">") && match128(tok1->link()->previous())) {
            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)
{
    // check if qualifications match first before checking if using is needed
    const Token *tok1 = first;
    const Token *tok2 = second;
    bool match = false;
    while (match111(tok1) && match111(tok2)) {
        if (tok1->str() == tok2->str()) {
            tok1 = tok1->tokAt(2);
            tok2 = tok2->tokAt(2);
            match = true;
        } else {
            match = false;
            break;
        }
    }

    if (match)
        return false;

    offset = 0;
    std::string name = first->str();

    while (match111(first)) {
        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() != MatchCompiler::makeConstString(";")) {
                        if (!nsName.empty())
                            nsName += " ";
                        nsName += start->str();
                        start = start->next();
                    }
                    if (nsName == name)
                        return true;
                }
            }
            scope = scope->nestedIn;
        }
    }

    return false;
}

static bool typesMatch(
    const Scope *first_scope,
    const Token *first_token,
    const Scope *second_scope,
    const Token *second_token,
    const Token **new_first,
    const Token **new_second)
{
    // get first type
    const Type * first_type = first_scope->check->findType(first_token, first_scope);
    if (first_type) {
        // get second type
        const Type * second_type = second_scope->check->findType(second_token, second_scope);
        // check if types match
        if (first_type == second_type) {
            const Token* tok1 = first_token;
            while (tok1 && tok1->str() != first_type->name())
                tok1 = tok1->next();
            const Token *tok2 = second_token;
            while (tok2 && tok2->str() != second_type->name())
                tok2 = tok2->next();
            // update parser token positions
            if (tok1 && tok2) {
                *new_first = tok1->previous();
                *new_second = tok2->previous();
                return true;
            }
        }
    }
    return false;
}

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

    int arg_path_length = path_length;
    int offset = 0;
    int openParen = 0;

    // check for () == (void) and (void) == ()
    if ((match129(first) && match130(second)) ||
        (match130(first) && match129(second)))
        return true;

    while (first->str() == second->str() &&
           first->isLong() == second->isLong() &&
           first->isUnsigned() == second->isUnsigned()) {
        if (first->str() == MatchCompiler::makeConstString("("))
            openParen++;

        // at end of argument list
        else if (first->str() == MatchCompiler::makeConstString(")")) {
            if (openParen == 1)
                return true;
            else
                --openParen;
        }

        // skip optional type information
        if (match131(first->next()))
            first = first->next();
        if (match131(second->next()))
            second = second->next();

        // skip const on type passed by value
        if (match132(first->next()) &&
            !match133(first->next()))
            first = first->next();
        if (match132(second->next()) &&
            !match133(second->next()))
            second = second->next();

        // skip default value assignment
        else if (first->next()->str() == MatchCompiler::makeConstString("=")) {
            first = first->nextArgument();
            if (first)
                first = first->tokAt(-2);
            if (second->next()->str() == MatchCompiler::makeConstString("=")) {
                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() == MatchCompiler::makeConstString("=")) {
            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() == MatchCompiler::makeConstString(",") && second->next()->str() != MatchCompiler::makeConstString(",")) ||
                 (match134(first) && second->next()->str() != MatchCompiler::makeConstString(")"))) {
            second = second->next();
            // skip default value assignment
            if (second->next()->str() == MatchCompiler::makeConstString("=")) {
                do {
                    second = second->next();
                } while (!match135(second->next()));
            }
        } else if (first->next()->str() == MatchCompiler::makeConstString("[") && second->next()->str() != MatchCompiler::makeConstString("["))
            second = second->next();

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

        // argument list has different number of arguments
        else if (openParen == 1 && second->str() == MatchCompiler::makeConstString(")") && first->str() != MatchCompiler::makeConstString(")"))
            break;

        // ckeck for type * x == type x[]
        else if (match136(first->next()) &&
                 match137(second->next())) {
            do {
                first = first->next();
            } while (!match135(first->next()));
            do {
                second = second->next();
            } while (!match135(second->next()));
        }

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

        // variable names are different
        else if ((match138(first->next()) &&
                  match139(second->next())) &&
                 (first->next()->str() != second->next()->str())) {
            // skip variable names
            first = first->next();
            second = second->next();

            // skip default value assignment
            if (first->next()->str() == MatchCompiler::makeConstString("=")) {
                do {
                    first = first->next();
                } while (!match135(first->next()));
            }
        }

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

        // same type with different qualification
        else if (typesMatch(scope, first->next(), nestedIn, second->next(), &first, &second))
            ;

        // variable with class path
        else if (arg_path_length && match61(first->next()) && first->strAt(1) != MatchCompiler::makeConstString("const")) {
            std::string param = path;

            if (Token::simpleMatch(second->next(), param.c_str(), param.size())) {
                // check for redundant qualification before skipping it
                if (!Token::simpleMatch(first->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 && match61(first->next()) &&
                     (match15(second->next()) ||
                      (match3(second->next()) &&
                       match140(second->linkAt(1)))) &&
                     ((second->next()->str() == scope->className) ||
                      (scope->definedType && scope->definedType->isDerivedFrom(second->next()->str()))) &&
                     (first->next()->str() == second->strAt(3))) {
                if (match3(second->next()))
                    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() == MatchCompiler::makeConstString(",") || second->str() == MatchCompiler::makeConstString(","))
            arg_path_length = path_length;
    }

    return false;
}

static bool isUnknownType(const Token* start, const Token* end)
{
    while (match110(start))
        start = start->next();
    start = skipScopeIdentifiers(start);
    if (start->tokAt(1) == end && !start->type() && !start->isStandardType())
        return true;
    // TODO: Try to deduce the type of the expression
    if (match141(start))
        return true;
    return false;
}

bool Function::returnsConst(const Function* function, bool unknown)
{
    if (!function)
        return false;
    if (function->type != Function::eFunction)
        return false;
    const Token* defEnd = function->returnDefEnd();
    if (findmatch142(function->retDef, defEnd) )
        return true;
    // Check for unknown types, which could be a const
    if (isUnknownType(function->retDef, defEnd))
        return unknown;
    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) == MatchCompiler::makeConstString("&"))
        return true;
    // Check for unknown types, which could be a reference
    if (isUnknownType(function->retDef, defEnd))
        return unknown;
    return false;
}

bool Function::returnsVoid(const Function* function, bool unknown)
{
    if (!function)
        return false;
    if (function->type != Function::eFunction && function->type != Function::eOperatorEqual)
        return false;
    const Token* defEnd = function->returnDefEnd();
    if (defEnd->strAt(-1) == MatchCompiler::makeConstString("void"))
        return true;
    // Check for unknown types, which could be a void type
    if (isUnknownType(function->retDef, defEnd))
        return unknown;
    if (unknown) {
        // void STDCALL foo()
        const Token *def;
        bool isVoid = false;
        for (def = function->retDef; def && def->isName(); def = def->next())
            isVoid |= (def->str() == MatchCompiler::makeConstString("void"));
        if (isVoid && def && !match72(def))
            return true;
    }
    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() == MatchCompiler::makeConstString("{") && tok->scope() &&
            (tok->scope()->type == Scope::eLambda || tok->scope()->type == Scope::eClass)) {
            tok = tok->link();
            continue;
        }
        if (match143(tok->astParent())) {
            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() || !arg)
        return nullptr;
    if (match144(arg->link()))
        return arg->link()->next();
    if (match145(arg->link()) && arg->link()->linkAt(2)->strAt(1) == MatchCompiler::makeConstString(":"))
        return arg->link()->linkAt(2)->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() != MatchCompiler::makeConstString("[")) {
        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 (f->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() == MatchCompiler::makeConstString("~"));
    const bool has_const(argStart->link()->strAt(1) == MatchCompiler::makeConstString("const"));
    const bool lval(argStart->link()->strAt(has_const ? 2 : 1) == MatchCompiler::makeConstString("&"));
    const bool rval(argStart->link()->strAt(has_const ? 2 : 1) == MatchCompiler::makeConstString("&&"));
    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() == MatchCompiler::makeConstString("::") && tok1->tokAt(-2) &&
           ((tok1->tokAt(-2)->isName() && !tok1->tokAt(-2)->isStandardType()) ||
            (tok1->strAt(-2) == MatchCompiler::makeConstString(">") && tok1->linkAt(-2) && match61(tok1->linkAt(-2)->previous())))) {
        count++;
        const Token * tok2 = tok1->tokAt(-2);
        if (tok2->str() == MatchCompiler::makeConstString(">"))
            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;

    // add global namespace if present
    if (tok1->strAt(-1) == MatchCompiler::makeConstString("::")) {
        path_length++;
        path.insert(0, ":: ");
    }

    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 && match146(eq->tokAt(-2))) {
                                    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) == MatchCompiler::makeConstString("<"))
                        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 (func->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 && match146(eq->tokAt(-2))) {
                                    func->isDefault(true);
                                    return;
                                }

                                const bool hasConstKeyword = closeParen->next()->str() == MatchCompiler::makeConstString("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() != MatchCompiler::makeConstString("{") && tok1->str() != MatchCompiler::makeConstString(";")) {
        if (tok1->link() && match106(tok1)) {
            tok1 = tok1->link();
        } else if (foundInitList && match41(tok1) && match42(tok1->linkAt(1))) {
            tok1 = tok1->linkAt(1);
        } else {
            if (tok1->str() == MatchCompiler::makeConstString(":"))
                foundInitList = true;
            tok1 = tok1->next();
        }
    }

    if (tok1 && tok1->str() == MatchCompiler::makeConstString("{")) {
        newScope->setBodyStartEnd(tok1);

        // 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() == MatchCompiler::makeConstString("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() != MatchCompiler::makeConstString("{")) {
        // skip unsupported templates
        if (tok2->str() == MatchCompiler::makeConstString("<"))
            tok2 = tok2->link();

        // check for base classes
        else if (match147(tok2)) {
            tok2 = tok2->next();

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

            Type::BaseInfo base;

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

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

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

            // handle derived base classes
            while (match2(tok2)) {
                tok2 = tok2->tokAt(2);
            }
            if (!tok2)
                return nullptr;

            base.name = tok2->str();

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

            const Type * baseType = classScope->check->findType(base.nameTok, enclosingScope);
            if (baseType && !baseType->findDependency(this))
                base.type = baseType;

            // 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() == MatchCompiler::makeConstString("class"))
        return next->strAt(1);
    else if (next->isName())
        return next->str();
    return emptyString;
}

void SymbolDatabase::debugMessage(const Token *tok, const std::string &type, 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,
                                  type,
                                  msg,
                                  Certainty::normal);
        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 == this || 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, bool* isContainer)
{
    *isContainer = false;
    const Library::Container* container = settings->library.detectContainer(mTypeStartToken);
    if (container && container->arrayLike_indexOp && container->size_templateArgNo > 0) {
        const Token* tok = findmatch148(mTypeStartToken) ;
        if (tok) {
            *isContainer = true;
            Dimension dimension_;
            tok = tok->next();
            for (int i = 0; i < container->size_templateArgNo && tok; i++) {
                tok = tok->nextTemplateArgument();
            }
            if (match149(tok)) {
                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() == MatchCompiler::makeConstString("]"))
            dim = dim->link()->previous();
    }
    if (dim)
        dim = dim->next();
    if (dim && dim->str() == MatchCompiler::makeConstString(")"))
        dim = dim->next();

    bool arr = false;
    while (dim && dim->next() && dim->str() == MatchCompiler::makeConstString("[")) {
        Dimension dimension_;
        dimension_.known = false;
        // check for empty array dimension []
        if (dim->next()->str() != MatchCompiler::makeConstString("]")) {
            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->className.empty())
            oss << scope->className << " ";
        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() == MatchCompiler::makeConstString("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 && !match150(tok); 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) {
                std::cout << scope->enumType->stringify(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() == MatchCompiler::makeConstString("::")) {
                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
                        << "\" token=\"" << function->token
                        << "\" 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->isInlineKeyword())
                        out << " isInlineKeyword=\"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() << '\"';
        if (var->valueType())
            out << " constness=\""      << var->valueType()->constness << '\"';
        out << " isArray=\""        << var->isArray() << '\"';
        out << " isClass=\""        << var->isClass() << '\"';
        out << " isConst=\""        << var->isConst() << '\"';
        out << " isExtern=\""       << var->isExtern() << '\"';
        out << " isPointer=\""      << var->isPointer() << '\"';
        out << " isReference=\""    << var->isReference() << '\"';
        out << " isStatic=\""       << var->isStatic() << '\"';
        out << " isVolatile=\""     << var->isVolatile() << '\"';
        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 (!match27(start))
        return;
    if (!(start && start->link() != start->next() && !match130(start)))
        return;

    unsigned int count = 0;

    for (const Token* tok = start->next(); tok; tok = tok->next()) {
        if (match135(tok))
            return; // Syntax error

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

        do {
            if (match87(tok)) {
                tok = tok->linkAt(1)->next();
                continue;
            }
            if (tok != startTok && !nameTok && match151(tok)) {
                nameTok = tok->tokAt(2);
                endTok = nameTok->previous();
                tok = tok->link();
            } else if (tok != startTok && !nameTok && match152(tok)) {
                nameTok = tok->tokAt(2);
                endTok = nameTok->previous();
                tok = tok->link()->tokAt(2);
            } else if (tok != startTok && !nameTok && match153(tok)) {
                nameTok = tok->tokAt(2);
                endTok = nameTok->previous();
                tok = tok->link();
            } else if (tok->varId() != 0) {
                nameTok = tok;
                endTok = tok->previous();
            } else if (tok->str() == MatchCompiler::makeConstString("[")) {
                // skip array dimension(s)
                tok = tok->link();
                while (tok->next()->str() == MatchCompiler::makeConstString("["))
                    tok = tok->next()->link();
            } else if (tok->str() == MatchCompiler::makeConstString("<")) {
                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() != MatchCompiler::makeConstString(",") && tok->str() != MatchCompiler::makeConstString(")") && tok->str() != MatchCompiler::makeConstString("="));

        const Token *typeTok = startTok;
        // skip over stuff to get to type
        while (match154(typeTok))
            typeTok = typeTok->next();
        if (match135(typeTok)) { // #8333
            symbolDatabase->mTokenizer->syntaxError(typeTok);
        }
        // skip over qualification
        while (match32(typeTok))
            typeTok = typeTok->tokAt(2);

        // check for argument with no name or missing varid
        if (!endTok) {
            if (tok->previous()->isName() && !match110(tok->tokAt(-1))) {
                if (tok->previous() != typeTok) {
                    nameTok = tok->previous();
                    endTok = nameTok->previous();

                    if (hasBody())
                        symbolDatabase->debugMessage(nameTok, "varid0", "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() == MatchCompiler::makeConstString("=")) {
            do {
                if (tok->link() && match155(tok))
                    tok = tok->link();
                tok = tok->next();
            } while (tok->str() != MatchCompiler::makeConstString(",") && tok->str() != MatchCompiler::makeConstString(")"));
        }

        // skip over stuff before type
        while (match156(startTok))
            startTok = startTok->next();

        if (startTok == nameTok)
            break;

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

        if (tok->str() == MatchCompiler::makeConstString(")")) {
            // check for a variadic function or a variadic template function
            if (match157(endTok))
                isVariadic(true);

            break;
        }
    }

    // count default arguments
    for (const Token* tok = argDef->next(); tok && tok != argDef->link(); tok = tok->next()) {
        if (tok->str() == MatchCompiler::makeConstString("=")) {
            initArgCount++;
            if (tok->strAt(1) == MatchCompiler::makeConstString("[")) {
                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
}

std::vector<const Function*> Function::getOverloadedFunctions() const
{
    std::vector<const Function*> result;
    const Scope* scope = nestedIn;

    while (scope) {
        const bool isMemberFunction = scope->isClassOrStruct() && !isStatic();
        for (std::multimap<std::string, const Function*>::const_iterator it = scope->functionMap.find(tokenDef->str());
             it != scope->functionMap.end() && it->first == tokenDef->str();
             ++it) {
            const Function* func = it->second;
            if (isMemberFunction == func->isStatic())
                continue;
            result.push_back(func);
        }
        if (isMemberFunction)
            break;
        scope = scope->nestedIn;
    }

    return result;
}

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() != MatchCompiler::makeConstString("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_),
    nestedIn(nestedIn_),
    numConstructors(0),
    numCopyOrMoveConstructors(0),
    type(type_),
    definedType(nullptr),
    functionOf(nullptr),
    function(nullptr),
    enumType(nullptr),
    enumClass(false)
{
    setBodyStartEnd(start_);
}

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() == MatchCompiler::makeConstString("class") && check && check->isCPP()) {
        type = Scope::eClass;
        nameTok = nameTok->next();
    } else if (classDef->str() == MatchCompiler::makeConstString("struct")) {
        type = Scope::eStruct;
        nameTok = nameTok->next();
    } else if (classDef->str() == MatchCompiler::makeConstString("union")) {
        type = Scope::eUnion;
        nameTok = nameTok->next();
    } else if (classDef->str() == MatchCompiler::makeConstString("namespace")) {
        type = Scope::eNamespace;
        nameTok = nameTok->next();
    } else if (classDef->str() == MatchCompiler::makeConstString("enum")) {
        type = Scope::eEnum;
        nameTok = nameTok->next();
        if (nameTok->str() == MatchCompiler::makeConstString("class")) {
            enumClass = true;
            nameTok = nameTok->next();
        }
    } else if (classDef->str() == MatchCompiler::makeConstString("[")) {
        type = Scope::eLambda;
    } else {
        type = Scope::eFunction;
    }
    // skip over qualification if present
    nameTok = skipScopeIdentifiers(nameTok);
    if (nameTok && ((type == Scope::eEnum && match158(nameTok)) || nameTok->str() != MatchCompiler::makeConstString("{"))) // 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)
{
    if (!bodyStartList.empty()) {
        for (const Token *bs: bodyStartList)
            getVariableList(settings, bs->next(), bs->link());
    }

    // global scope
    else if (type == Scope::eGlobal)
        getVariableList(settings, check->mTokenizer->tokens(), nullptr);

    // forward declaration
    else
        return;
}

void Scope::getVariableList(const Settings* settings, const Token* start, const Token* end)
{
    // Variable declared in condition: if (auto x = bar())
    if (match159(classDef) && match160(classDef->next()->astOperand2())) {
        checkVariable(classDef->tokAt(2), defaultAccess(), settings);
    }

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

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

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

        // Is it a nested class or structure?
        else if (tok->isKeyword() && match161(tok)) {
            tok = tok->tokAt(2);
            while (tok && tok->str() != MatchCompiler::makeConstString("{"))
                tok = tok->next();
            if (tok) {
                // skip implementation
                tok = tok->link();
                continue;
            } else
                break;
        } else if (tok->isKeyword() && match34(tok)) {
            if (match162(tok->next()->link())) {
                tok = tok->next()->link()->tokAt(2);
                continue;
            } else if (match19(tok->next()->link())) {
                tok = tok->next();
                continue;
            }
        }

        // Borland C++: Skip all variables in the __published section.
        // These are automatically initialized.
        else if (tok->str() == MatchCompiler::makeConstString("__published:")) {
            for (; tok; tok = tok->next()) {
                if (tok->str() == MatchCompiler::makeConstString("{"))
                    tok = tok->link();
                if (match163(tok->next()))
                    break;
            }
            if (tok)
                continue;
            else
                break;
        }

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

        // Is it a forward declaration?
        else if (tok->isKeyword() && match30(tok)) {
            tok = tok->tokAt(2);
            continue;
        }

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

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

        // skip case/default
        if (tok->isKeyword() && match165(tok)) {
            while (tok->next() && !match166(tok->next()))
                tok = tok->next();
            continue;
        }

        // Search for start of statement..
        else if (tok->previous() && !match167(tok->previous()))
            continue;
        else if (tok->str() == MatchCompiler::makeConstString(";"))
            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() && match168(tok) &&
        match28(tok->linkAt(2))) {
        return tok->linkAt(2);
    }

    if (tok->isKeyword() && match169(tok) &&
        match28(tok->linkAt(4))) {
        return tok->linkAt(4);
    }

    // friend?
    if (tok->isKeyword() && match170(tok) && tok->next()->varId() == 0) {
        const Token *next = findmatch171(tok->tokAt(2)) ;
        if (next && next->str() == MatchCompiler::makeConstString("{"))
            next = next->link();
        return next;
    }

    // skip const|volatile|static|mutable|extern
    while (tok->isKeyword() && match172(tok)) {
        tok = tok->next();
    }

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

    // C++17 structured bindings
    if (settings->standards.cpp >= Standards::CPP17 && match173(tok)) {
        const Token *typeend = findmatch174(typestart) ->previous();
        for (tok = typeend->tokAt(2); match175(tok); tok = tok->next()) {
            if (tok->varId())
                addVariable(tok, typestart, typeend, varaccess, nullptr, this, settings);
        }
        return typeend->linkAt(1);
    }

    if (tok->isKeyword() && match176(tok)) {
        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 (match177(tok))
            tok = tok->link()->next();

        if (vartok->varId() == 0) {
            if (!vartok->isBoolean())
                check->debugMessage(vartok, "varid0", "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 (match178(typestart))
            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 (match72(tok) || (match179(tok) && match180(tok->link()->next()))) {
        tok = tok->next();
        if (tok->strAt(-1) == MatchCompiler::makeConstString("(") && match32(tok))
            tok = tok->tokAt(2);
    }

    if (match181(tok) && match182(tok->link()->previous())) {
        const Token *tok2 = skipPointers(tok->next());
        if (match23(tok2) && match182(tok2->linkAt(1)))
            return tok2;
    }

    return tok;
}

static const Token* skipPointersAndQualifiers(const Token* tok)
{
    tok = skipPointers(tok);
    while (match110(tok)) {
        tok = tok->next();
        tok = skipPointers(tok);
    }

    return tok;
}

bool Scope::isVariableDeclaration(const Token* const tok, const Token*& vartok, const Token*& typetok) const
{
    if (!tok)
        return false;

    const bool isCPP = check && check->mTokenizer->isCPP();

    if (isCPP && match183(tok))
        return false;

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

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

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

    if (match184(localTypeTok)) {
        if (match185(tok))
            return false;

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

            if (match186(localVarTok)) {
                if (localVarTok->strAt(3) != MatchCompiler::makeConstString("(") ||
                    match187(localVarTok->linkAt(3))) {
                    localTypeTok = localVarTok->next();
                    localVarTok = localVarTok->tokAt(2);
                }
            }
        }
    } else if (match188(localTypeTok)) {

        if (isCPP11 && match87(localTypeTok) && match189(localTypeTok->linkAt(1)))
            localVarTok = skipPointersAndQualifiers(localTypeTok->linkAt(1)->next());
        else {
            localVarTok = skipPointersAndQualifiers(localTypeTok->next());
            if (isCPP11 && match87(localVarTok) && match189(localVarTok->linkAt(1)))
                localVarTok = skipPointersAndQualifiers(localVarTok->linkAt(1)->next());
        }
    }

    if (!localVarTok)
        return false;

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

    if (match190(localVarTok) || (localVarTok && localVarTok->varId() && localVarTok->strAt(1) == MatchCompiler::makeConstString(":"))) {
        vartok = localVarTok;
        typetok = localTypeTok;
    } else if (match191(localVarTok) && localVarTok->str() != MatchCompiler::makeConstString("operator")) {
        vartok = localVarTok;
        typetok = localTypeTok;
    } else if (localVarTok && localVarTok->varId() && match192(localVarTok) &&
               match193(localVarTok->next()->link())) {
        vartok = localVarTok;
        typetok = localTypeTok;
    } else if (type == eCatch &&
               match194(localVarTok)) {
        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() == MatchCompiler::makeConstString("class"))
        tok2 = tok2->next();

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

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

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

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

        while (match195(tok2) ||
               (match22(tok2) && match196(tok2->linkAt(1)))) {
            Enumerator enumerator(this);

            // save enumerator name
            enumerator.name = tok2;

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

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

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

                enumerator.start = tok2;

                while (!match197(tok2)) {
                    if (tok2->link())
                        tok2 = tok2->link();
                    enumerator.end = tok2;
                    tok2 = tok2->next();
                }
            } else if (tok2->str() == MatchCompiler::makeConstString("(")) {
                // skip over unknown macro
                tok2 = tok2->link()->next();
            }

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

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

            if (tok2 && tok2->str() != MatchCompiler::makeConstString(";"))
                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) == MatchCompiler::makeConstString("::")) {
        // find first scope
        const Token *tok1 = tok;
        while (match2(tok1->tokAt(-2)))
            tok1 = tok1->tokAt(-2);

        if (tok1->strAt(-1) == MatchCompiler::makeConstString("::"))
            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 && match2(tok1)) {
                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) {
                if (base->classScope == scope)
                    return nullptr;
                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) != MatchCompiler::makeConstString("::") && typeTok->strAt(1) != MatchCompiler::makeConstString("::")) {
        // 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) == MatchCompiler::makeConstString("::")) {
        // check if type is not part of qualification
        if (typeTok->strAt(1) == MatchCompiler::makeConstString("::"))
            return nullptr;

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

        while (match32(tok1->tokAt(-2)) ||
               (match115(tok1->tokAt(-2)) && tok1->linkAt(-2) && match188(tok1->linkAt(-2)->tokAt(-1)))) {
            if (tok1->strAt(-1) == MatchCompiler::makeConstString("::"))
                tok1 = tok1->tokAt(-2);
            else
                tok1 = tok1->linkAt(-2)->tokAt(-1);
        }

        // check for global scope
        if (tok1->strAt(-1) == MatchCompiler::makeConstString("::")) {
            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 && (match32(tok1) ||
                             (match184(tok1) && match115(tok1->linkAt(1))))) {
                if (tok1->strAt(1) == MatchCompiler::makeConstString("::"))
                    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 && match9(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 ((func->isVariadic() && args >= (func->argCount() - 1)) ||
                        (args == func->argCount() || (args < func->argCount() && args >= func->minArgCount()))) {
                        matches.push_back(func);
                    }
                }

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

const Scope *Scope::findRecordInBase(const std::string & name) 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) // Recursive class; tok should have been found already
                    continue;

                if (base->name() == name) {
                    return base->classScope;
                }

                const ::Type * t = base->classScope->findType(name);
                if (t)
                    return t->classScope;
            }
        }
    }

    return nullptr;
}

std::vector<const Scope*> Scope::findAssociatedScopes() const
{
    std::vector<const Scope*> result = {this};
    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 (contains(result, base->classScope))
                    continue;
                std::vector<const Scope*> baseScopes = base->classScope->findAssociatedScopes();
                result.insert(result.end(), baseScopes.begin(), baseScopes.end());
            }
        }
    }
    return result;
}

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

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) == MatchCompiler::makeConstString("const")) == (funcarg->typeStartToken()->strAt(-1) == MatchCompiler::makeConstString("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() == MatchCompiler::makeConstString("void"))
                fallback1++;
            else if (constEquals && funcarg->isStlStringType() && match198(callarg->typeStartToken()))
                fallback2++;
        } else if (ptrequals) {
            const bool takesInt = match199(funcarg->typeStartToken());
            const bool takesFloat = match117(funcarg->typeStartToken());
            const bool passesInt = match199(callarg->typeStartToken());
            const bool passesFloat = match117(callarg->typeStartToken());
            if ((takesInt && passesInt) || (takesFloat && passesFloat))
                fallback1++;
            else if ((takesInt && passesFloat) || (takesFloat && passesInt))
                fallback2++;
        }
    }
}

static std::string getTypeString(const Token *typeToken)
{
    if (!typeToken)
        return "";
    while (match200(typeToken)) {
        if (typeToken->str() == MatchCompiler::makeConstString("::")) {
            std::string ret;
            while (match1(typeToken)) {
                ret += "::" + typeToken->strAt(1);
                typeToken = typeToken->tokAt(2);
                if (typeToken->str() == MatchCompiler::makeConstString("<")) {
                    for (const Token *tok = typeToken; tok != typeToken->link(); tok = tok->next())
                        ret += tok->str();
                    ret += ">";
                    typeToken = typeToken->link()->next();
                }
            }
            return ret;
        }
        if (match201(typeToken)) {
            return typeToken->str();
        }
        typeToken = typeToken->next();
    }
    return "";
}

const Function* Scope::findFunction(const Token *tok, bool requireConst) const
{
    const bool isCall = match20(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 (match61(typeToken->previous()))
                            typeToken = typeToken->previous();
                        while (match202(typeToken))
                        {
                            if (typeToken->str() == MatchCompiler::makeConstString("const"))
                                ret.constness |= (1 << ret.pointer);
                            else if (typeToken->str() == MatchCompiler::makeConstString("*"))
                                ret.pointer++;
                            else if (typeToken->str() == MatchCompiler::makeConstString("<")) {
                                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 (match203(arguments[j])) {
                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() && match204(arguments[j]))
                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];
                if (vartok->str() == MatchCompiler::makeConstString(".")) {
                    const Token* rml = nextAfterAstRightmostLeaf(vartok);
                    if (rml)
                        vartok = rml->previous();
                }
                while (vartok->isUnaryOp("&") || vartok->isUnaryOp("*"))
                    vartok = vartok->astOperand1();
                const Variable* var = vartok->variable();
                // smart pointer deref?
                if (var && vartok->astParent() && vartok->astParent()->str() == MatchCompiler::makeConstString("*") &&
                    var->isSmartPointer() && var->valueType() && var->valueType()->smartPointerTypeToken)
                    var = var->valueType()->smartPointerTypeToken->variable();
                ValueType::MatchResult res = ValueType::matchParameter(arguments[j]->valueType(), var, 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) == MatchCompiler::makeConstString("::")) {
        // find start of qualified function name
        const Token *tok1 = tok;

        while (match205(tok1->tokAt(-2))) {
            if (tok1->strAt(-2) == MatchCompiler::makeConstString(">")) {
                if (tok1->linkAt(-2))
                    tok1 = tok1->linkAt(-2)->tokAt(-1);
                else {
                    if (mSettings->debugwarnings)
                        debugMessage(tok1->tokAt(-2), "debug", "SymbolDatabase::findFunction found '>' without link.");
                    return nullptr;
                }
            } else
                tok1 = tok1->tokAt(-2);
        }

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

            if (match22(tok1))
                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 && tok1 && !(match206(tok1) ||
                                          (match184(tok1) && match207(tok1->linkAt(1))))) {
                if (tok1->strAt(1) == MatchCompiler::makeConstString("::"))
                    tok1 = tok1->tokAt(2);
                else if (tok1->strAt(1) == MatchCompiler::makeConstString("<"))
                    tok1 = tok1->linkAt(1)->tokAt(2);
                else
                    tok1 = nullptr;

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

            if (tok1)
                tok1 = tok1->tokAt(2);

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

    // check for member function
    else if (match208(tok->tokAt(-2))) {
        const Token* tok1 = tok->previous()->astOperand1();
        if (tok1 && tok1->valueType() && tok1->valueType()->typeScope) {
            return tok1->valueType()->typeScope->findFunction(tok, tok1->valueType()->constness == 1);
        } else if (tok1 && match22(tok1->previous()) && tok1->previous()->function() &&
                   tok1->previous()->function()->retDef) {
            ValueType vt = ValueType::parseDecl(tok1->previous()->function()->retDef, mSettings);
            if (vt.typeScope)
                return vt.typeScope->findFunction(tok, vt.constness == 1);
        } else if (match209(tok1)) {
            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() == MatchCompiler::makeConstString("->"))
                return var->smartPointerType()->classScope->findFunction(tok, var->valueType()->constness == 1);
        } else if (match27(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;
        }
    }
    // Check for constructor
    if (match192(tok)) {
        ValueType vt = ValueType::parseDecl(tok, mSettings);
        if (vt.typeScope)
            return vt.typeScope->findFunction(tok, false);
    }
    return nullptr;
}

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

const Scope *SymbolDatabase::findScopeByName(const std::string& name) const
{
    for (const Scope &scope: scopeList) {
        if (scope.className == name)
            return &scope;
    }
    return nullptr;
}

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

const Scope *Scope::findRecordInNestedList(const std::string & name) const
{
    for (const Scope* scope: nestedList) {
        if (scope->className == name && scope->type != eFunction)
            return scope;
    }

    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)
{
    for (Scope *scope: nestedList) {
        if (scope->className == name)
            return scope;
    }

    for (Scope* scope: nestedList) {
        Scope *child = scope->findInNestedListRecursive(name);
        if (child)
            return child;
    }
    return nullptr;
}

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

const Function *Scope::getDestructor() const
{
    for (const Function &f: functionList) {
        if (f.type == Function::eDestructor)
            return &f;
    }
    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() == MatchCompiler::makeConstString("::")) {
        tok = tok->next();
        scope = &scopeList.front();
    }
    // relative path
    else if (tok->isName()) {
        scope = startScope;
    }

    while (scope && tok && tok->isName()) {
        if (tok->strAt(1) == MatchCompiler::makeConstString("::")) {
            scope = scope->findRecordInNestedList(tok->str());
            tok = tok->tokAt(2);
        } else if (tok->strAt(1) == MatchCompiler::makeConstString("<") && match115(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 (match210(startTok))
        startTok = startTok->next();

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

    const Scope* start_scope = startScope;

    // absolute path - directly start in global scope
    if (startTok->str() == MatchCompiler::makeConstString("::")) {
        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) == MatchCompiler::makeConstString("::") || (tok->strAt(1) == MatchCompiler::makeConstString("<") && match115(tok->linkAt(1)))) {
            scope = scope->findRecordInNestedList(tok->str());
            if (scope) {
                if (tok->strAt(1) == MatchCompiler::makeConstString("::"))
                    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());
            const Scope *scope1;
            if (type)
                return type;
            else if ((scope1 = scope->findRecordInBase(tok->str()))) {
                type = scope1->definedType;
                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) == MatchCompiler::makeConstString("::") || (tok->strAt(1) == MatchCompiler::makeConstString("<") && match115(tok->linkAt(1)))) {
                    scope = scope->findRecordInNestedList(tok->str());
                    if (scope) {
                        if (tok->strAt(1) == MatchCompiler::makeConstString("::"))
                            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());
                    const Scope *scope1;
                    if (type)
                        return type;
                    else if ((scope1 = scope->findRecordInBase(tok->str()))) {
                        type = scope1->definedType;
                        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 (match211(startTok))
        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() == MatchCompiler::makeConstString("::")) {
        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) == MatchCompiler::makeConstString("::") || (tok->strAt(1) == MatchCompiler::makeConstString("<") && match115(tok->linkAt(1)))) {
            hasPath = true;
            scope = scope->findRecordInNestedList(tok->str());
            if (scope) {
                if (tok->strAt(1) == MatchCompiler::makeConstString("::"))
                    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) == MatchCompiler::makeConstString("~");

    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 (it->second->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 && match212(func->tokAt(1))) {
            if (func->strAt(1) == MatchCompiler::makeConstString("::"))
                func = func->tokAt(2);
            else if (func->linkAt(1))
                func = func->linkAt(1)->tokAt(2);
            else
                return nullptr;
            if (func->str() == MatchCompiler::makeConstString("~"))
                func = func->next();
            function = findFunctionInScope(func, scope, path, path_length);
        }
    }

    return const_cast<Function *>(function);
}

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

namespace {

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

    const std::unordered_set<std::string> c_keywords = { C_KEYWORDS, "restrict" };
    const std::unordered_set<std::string> cpp_keywords = {
        C_KEYWORDS,
        "alignas", "alignof", "and", "and_eq", "asm", "bitand", "bitor", "bool", "catch", "char8_t", "char16_t",
        "char32_t", "class", "compl", "concept", "consteval", "constexpr", "constinit", "const_cast", "co_await",
        "co_return", "co_yield", "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.containerTypeToken = var.valueType()->containerTypeToken;
    }
    valuetype.smartPointerType = var.smartPointerType();
    if (parsedecl(var.typeStartToken(), &valuetype, mDefaultSignedness, mSettings)) {
        if (tok->str() == MatchCompiler::makeConstString(".") && 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);
}

static bool isContainerYieldElement(Library::Container::Yield yield)
{
    return yield == Library::Container::Yield::ITEM || yield == Library::Container::Yield::AT_INDEX ||
           yield == Library::Container::Yield::BUFFER || yield == Library::Container::Yield::BUFFER_NT;
}

static bool isContainerYieldPointer(Library::Container::Yield yield)
{
    return yield == Library::Container::Yield::BUFFER || yield == Library::Container::Yield::BUFFER_NT;
}

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 && match213(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 && match214(parent) &&
        isContainerYieldElement(vt1->container->getYield(parent->next()->str()))) {
        ValueType item;
        if (parsedecl(vt1->containerTypeToken, &item, mDefaultSignedness, mSettings)) {
            if (item.constness == 0)
                item.constness = vt1->constness;
            if (isContainerYieldPointer(vt1->container->getYield(parent->next()->str())))
                item.pointer += 1;
            else
                item.reference = Reference::LValue;
            setValueType(parent->tokAt(2), item);
        }
    }

    if (vt1 && vt1->smartPointerType && match214(parent) && parent->originalName() == MatchCompiler::makeConstString("->") && !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 && ((match215(parent->tokAt(-3)) && parent->strAt(-3) == parent->strAt(-1)) ||
                              match216(parent->tokAt(-1)))) {
            Token *var1Tok = parent->strAt(-2) == MatchCompiler::makeConstString(";") ? parent->tokAt(-3) : parent->tokAt(-1);
            Token *autoTok = nullptr;
            if (match217(var1Tok->tokAt(-2)))
                autoTok = var1Tok->previous();
            else if (match218(var1Tok->tokAt(-3)))
                autoTok = var1Tok->tokAt(-2);
            if (autoTok) {
                ValueType vt(*vt2);
                if (vt.constness & (1 << vt.pointer))
                    vt.constness &= ~(1 << vt.pointer);
                if (autoTok->strAt(1) == MatchCompiler::makeConstString("*") && vt.pointer)
                    vt.pointer--;
                if (match219(autoTok->tokAt(-1)))
                    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) == MatchCompiler::makeConstString("*"))
                        vt2_.pointer = 1;
                    if ((vt.constness & (1 << vt2->pointer)) != 0)
                        vt2_.constness |= (1 << vt2->pointer);
                    if (!match220(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() == MatchCompiler::makeConstString("[") && (!mIsCpp || parent->astOperand1() == tok) && valuetype.pointer > 0U && !match221(parent->previous())) {
        const Token *op1 = parent->astOperand1();
        while (op1 && op1->str() == MatchCompiler::makeConstString("["))
            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 (match22(parent->previous()) && parent->astOperand1() == tok && valuetype.pointer > 0U) {
        ValueType vt(valuetype);
        vt.pointer -= 1U;
        setValueType(parent, vt);
        return;
    }
    // std::move
    if (vt2 && parent->str() == MatchCompiler::makeConstString("(") && match222(parent->tokAt(-3))) {
        ValueType vt = valuetype;
        vt.reference = Reference::RValue;
        setValueType(parent, vt);
        return;
    }
    if (parent->str() == MatchCompiler::makeConstString("*") && !parent->astOperand2() && valuetype.pointer > 0U) {
        ValueType vt(valuetype);
        vt.pointer -= 1U;
        setValueType(parent, vt);
        return;
    }
    // Dereference iterator
    if (parent->str() == MatchCompiler::makeConstString("*") && !parent->astOperand2() && valuetype.type == ValueType::Type::ITERATOR &&
        valuetype.containerTypeToken) {
        ValueType vt;
        if (parsedecl(valuetype.containerTypeToken, &vt, mDefaultSignedness, mSettings)) {
            if (vt.constness == 0)
                vt.constness = valuetype.constness;
            vt.reference = Reference::LValue;
            setValueType(parent, vt);
            return;
        }
    }
    // Dereference smart pointer
    if (parent->str() == MatchCompiler::makeConstString("*") && !parent->astOperand2() && valuetype.type == ValueType::Type::SMART_POINTER &&
        valuetype.smartPointerTypeToken) {
        ValueType vt;
        if (parsedecl(valuetype.smartPointerTypeToken, &vt, mDefaultSignedness, mSettings)) {
            if (vt.constness == 0)
                vt.constness = valuetype.constness;
            setValueType(parent, vt);
            return;
        }
    }
    if (parent->str() == MatchCompiler::makeConstString("*") && match48(parent->astOperand2()) && valuetype.pointer > 0U) {
        const Token *op1 = parent->astOperand2()->astOperand1();
        while (op1 && op1->str() == MatchCompiler::makeConstString("["))
            op1 = op1->astOperand1();
        const ValueType& vt(valuetype);
        if (op1 && op1->variable() && op1->variable()->nameToken() == op1) {
            setValueType(parent, vt);
            return;
        }
    }
    if (parent->str() == MatchCompiler::makeConstString("&") && !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() == MatchCompiler::makeConstString(".") || parent->str() == MatchCompiler::makeConstString("::")) &&
        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() == MatchCompiler::makeConstString(":") &&
        match223(parent->astParent()) &&
        !parent->previous()->valueType() &&
        match224(parent->astParent()->astOperand1())) {
        const bool isconst = match225(parent->astParent()->next());
        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() == MatchCompiler::makeConstString("(") && 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->container->rangeItemRecordType.empty()) {
                setType = true;
                autovt.type = ValueType::Type::RECORD;
            } else if (vt2->containerTypeToken) {
                if (mSettings->library.isSmartPointer(vt2->containerTypeToken)) {
                    const Token *smartPointerTypeTok = vt2->containerTypeToken;
                    while (match119(smartPointerTypeTok))
                        smartPointerTypeTok = smartPointerTypeTok->next();
                    if (match226(smartPointerTypeTok) && 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() == MatchCompiler::makeConstString("[")) {
        ValueType vtParent;
        if (parsedecl(vt1->containerTypeToken, &vtParent, mDefaultSignedness, mSettings)) {
            setValueType(parent, vtParent);
            return;
        }
    }

    if (mIsCpp && vt2 && match87(parent->previous())) {
        setValueType(parent, *vt2);
        return;
    }

    // c++17 auto type deduction of braced init list
    if (mIsCpp && mSettings->standards.cpp >= Standards::CPP17 && vt2 && match227(parent->tokAt(-2))) {
        Token *autoTok = parent->tokAt(-2);
        setValueType(autoTok, *vt2);
        setAutoTokenProperties(autoTok);
        if (parent->previous()->variable())
            const_cast<Variable*>(parent->previous()->variable())->setValueType(*vt2);
        else
            debugMessage(parent->previous(), "debug", "Missing variable class for variable with varid");
        return;
    }

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

    const bool ternary = parent->str() == MatchCompiler::makeConstString(":") && parent->astParent() && parent->astParent()->str() == MatchCompiler::makeConstString("?");
    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) {

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

        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() == MatchCompiler::makeConstString("+") || parent->str() == MatchCompiler::makeConstString("-"))) {
            setValueType(parent, *vt1);
            return;
        }

        if (parent->str() == MatchCompiler::makeConstString("+") && 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 (match61(type->previous()) && !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::SMART_POINTER;
    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 (match228(type) && !match229(type) && type->varId() == 0 &&
           !type->variable() && !type->function()) {
        if (type->str() == MatchCompiler::makeConstString("(")) {
            if (match230(type->link()))
                break;
            if (par)
                break;
            par = true;
        }
        if (match87(type) && type->next()->valueType()) {
            const ValueType *vt2 = type->next()->valueType();
            if (valuetype->sign == ValueType::Sign::UNKNOWN_SIGN)
                valuetype->sign = vt2->sign;
            if (valuetype->type == ValueType::Type::UNKNOWN_TYPE)
                valuetype->type = vt2->type;
            valuetype->constness += vt2->constness;
            valuetype->pointer += vt2->pointer;
            type = type->linkAt(1)->next();
            continue;
        } else 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 (match219(type))
            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, 0, false);
                    break;
                }
                typeTokens.addtoken(type->str().substr(pos1, pos2 - pos1), 0, 0, 0, false);
                typeTokens.addtoken("::", 0, 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 (match231(type)) {
                if (type->str() == MatchCompiler::makeConstString("<") && 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();
            }
            if (type && type->str() == MatchCompiler::makeConstString("(") && type->previous()->function())
                // we are past the end of the type
                type = type->previous();
            continue;
        } else if (const Library::SmartPointer* smartPointer = settings->library.detectSmartPointer(type)) {
            const Token* argTok = findmatch148(type) ;
            if (!argTok)
                continue;
            valuetype->smartPointer = smartPointer;
            valuetype->smartPointerTypeToken = argTok->next();
            valuetype->smartPointerType = argTok->next()->type();
            valuetype->type = ValueType::Type::SMART_POINTER;
            type = argTok->link();
            if (type)
                type = type->next();
            continue;
        } else if (match15(type)) {
            std::string typestr;
            const Token *end = type;
            while (match15(end)) {
                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() == MatchCompiler::makeConstString("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 (match200(type) && !type->variable()) {
                if (type->str() == MatchCompiler::makeConstString("*"))
                    valuetype->pointer++;
                if (type->str() == MatchCompiler::makeConstString("const"))
                    valuetype->constness |= (1 << valuetype->pointer);
                type = type->next();
            }
            break;
        } else if (!valuetype->typeScope && (type->str() == MatchCompiler::makeConstString("struct") || type->str() == MatchCompiler::makeConstString("enum")))
            valuetype->type = type->str() == MatchCompiler::makeConstString("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() == MatchCompiler::makeConstString("*"))
            valuetype->pointer++;
        else if (type->str() == MatchCompiler::makeConstString("&"))
            valuetype->reference = Reference::LValue;
        else if (type->str() == MatchCompiler::makeConstString("&&"))
            valuetype->reference = Reference::RValue;
        else if (type->isStandardType())
            valuetype->fromLibraryType(type->str(), settings);
        else if (match232(type->previous()))
            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() && match20(tok)) {
            const Token* start = tok->astOperand1() ? tok->astOperand1()->findExpressionStartEndTokens().first : nullptr;
            // cast
            if (tok->isCast() && !tok->astOperand2() && match233(tok)) {
                ValueType valuetype;
                if (match65(parsedecl(tok->next(), &valuetype, mDefaultSignedness, mSettings)))
                    setValueType(tok, valuetype);
            }

            // C++ cast
            else if (tok->astOperand2() && match234(tok->astOperand1()) && tok->astOperand1()->linkAt(1)) {
                ValueType valuetype;
                if (match235(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 (match236(tok->previous())) {
                ValueType valuetype(ValueType::Sign::UNSIGNED, ValueType::Type::LONG, 0U);
                if (mSettings->platformType == cppcheck::Platform::Win64)
                    valuetype.type = ValueType::Type::LONGLONG;

                valuetype.originalTypeName = "size_t";
                setValueType(tok, valuetype);

                if (match237(tok)) {
                    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;
                else if (valuetype.isIntegral() && valuetype.type != ValueType::UNKNOWN_INT)
                    valuetype.sign = mDefaultSignedness;
                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);
            }

            else if (match18(tok->previous()) && tok->tokAt(-2) && tok->tokAt(-2)->valueType()) {
                ValueType vt = *tok->tokAt(-2)->valueType();
                setValueType(tok, vt);
            }

            // library type/function
            else if (tok->previous()) {
                // Aggregate constructor
                if (match61(tok->previous())) {
                    ValueType valuetype;
                    if (parsedecl(tok->previous(), &valuetype, mDefaultSignedness, mSettings)) {
                        if (valuetype.typeScope) {
                            setValueType(tok, valuetype);
                            continue;
                        }
                    }
                }
                if (tok->astParent() && match119(tok->astOperand1())) {
                    const Token *typeStartToken = tok->astOperand1();
                    while (typeStartToken && typeStartToken->str() == MatchCompiler::makeConstString("::"))
                        typeStartToken = typeStartToken->astOperand1();
                    if (mSettings->library.detectContainer(typeStartToken) ||
                        mSettings->library.detectSmartPointer(typeStartToken)) {
                        ValueType vt;
                        if (parsedecl(typeStartToken, &vt, mDefaultSignedness, mSettings)) {
                            setValueType(tok, vt);
                            continue;
                        }
                    }

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

                    if ((e == MatchCompiler::makeConstString("std::make_shared") || e == MatchCompiler::makeConstString("std::make_unique")) && match238(tok->astOperand1())) {
                        ValueType vt;
                        parsedecl(tok->astOperand1()->tokAt(3), &vt, mDefaultSignedness, mSettings);
                        if (vt.typeScope) {
                            vt.smartPointerType = vt.typeScope->definedType;
                            vt.typeScope = nullptr;
                        }
                        if (e == MatchCompiler::makeConstString("std::make_shared") && mSettings->library.smartPointers.count("std::shared_ptr") > 0)
                            vt.smartPointer = &mSettings->library.smartPointers.at("std::shared_ptr");
                        if (e == MatchCompiler::makeConstString("std::make_unique") && mSettings->library.smartPointers.count("std::unique_ptr") > 0)
                            vt.smartPointer = &mSettings->library.smartPointers.at("std::unique_ptr");
                        vt.type = ValueType::Type::SMART_POINTER;
                        vt.smartPointerTypeToken = tok->astOperand1()->tokAt(3);
                        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 == MatchCompiler::makeConstString("iterator")) {
                    if (match239(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;
                                vt.containerTypeToken =
                                    tok->astOperand1()->astOperand1()->valueType()->containerTypeToken;
                                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() == MatchCompiler::makeConstString("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) {
                ValueType vt = ValueType::parseDecl(functionScope->function->retDef, mSettings);
                setValueType(tok, vt);
                if (match240(tok))
                    setValueType(tok->next(), vt);
            }
        } else if (tok->variable()) {
            setValueType(tok, *tok->variable());
            if (!tok->variable()->valueType() && tok->valueType())
                const_cast<Variable*>(tok->variable())->setValueType(*tok->valueType());
        } else if (tok->enumerator()) {
            setValueType(tok, *tok->enumerator());
        } else if (tok->isKeyword() && tok->str() == MatchCompiler::makeConstString("new")) {
            const Token *typeTok = tok->next();
            if (match241(typeTok))
                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 (match15(typeTok)) {
                typestr += typeTok->str() + "::";
                typeTok = typeTok->tokAt(2);
            }
            if (!match242(typeTok))
                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);
            if (match27(tok->astOperand1())) {
                vt.pointer--;
                setValueType(tok->astOperand1(), vt);
            }
        } else if (tok->isKeyword() && tok->str() == MatchCompiler::makeConstString("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() == MatchCompiler::makeConstString("auto") && !tok->valueType())
                debugMessage(tok, "autoNoType", "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 == MatchCompiler::makeConstString("void"))
        return ValueType::Type::VOID;
    if (typestr == MatchCompiler::makeConstString("bool") || typestr == MatchCompiler::makeConstString("_Bool"))
        return ValueType::Type::BOOL;
    if (typestr== MatchCompiler::makeConstString("char"))
        return ValueType::Type::CHAR;
    if (typestr == MatchCompiler::makeConstString("short"))
        return ValueType::Type::SHORT;
    if (typestr == MatchCompiler::makeConstString("wchar_t"))
        return ValueType::Type::WCHAR_T;
    if (typestr == MatchCompiler::makeConstString("int"))
        return ValueType::Type::INT;
    if (typestr == MatchCompiler::makeConstString("long"))
        return longType ? ValueType::Type::LONGLONG : ValueType::Type::LONG;
    if (typestr == MatchCompiler::makeConstString("float"))
        return ValueType::Type::FLOAT;
    if (typestr == MatchCompiler::makeConstString("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::Type::BOOL)
            type = ValueType::Type::BOOL;
        else if (podtype->stdtype == Library::PodType::Type::CHAR)
            type = ValueType::Type::CHAR;
        else if (podtype->stdtype == Library::PodType::Type::SHORT)
            type = ValueType::Type::SHORT;
        else if (podtype->stdtype == Library::PodType::Type::INT)
            type = ValueType::Type::INT;
        else if (podtype->stdtype == Library::PodType::Type::LONG)
            type = ValueType::Type::LONG;
        else if (podtype->stdtype == Library::PodType::Type::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 == MatchCompiler::makeConstString("char"))
            type = ValueType::Type::CHAR;
        else if (platformType->mType == MatchCompiler::makeConstString("short"))
            type = ValueType::Type::SHORT;
        else if (platformType->mType == MatchCompiler::makeConstString("wchar_t"))
            type = ValueType::Type::WCHAR_T;
        else if (platformType->mType == MatchCompiler::makeConstString("int"))
            type = platformType->mLong ? ValueType::Type::LONG : ValueType::Type::INT;
        else if (platformType->mType == MatchCompiler::makeConstString("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 == MatchCompiler::makeConstString("size_t") || typestr == MatchCompiler::makeConstString("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 SMART_POINTER:
        ret << "valueType-type=\"smart-pointer\"";
        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->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 (type == ValueType::Type::SMART_POINTER && smartPointer) {
        ret += " smart-pointer(" + smartPointer->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) {
        if ((call->constness | func->constness) != func->constness)
            return ValueType::MatchResult::NOMATCH;
        if (call->constness == 0 && func->constness != 0 && func->reference != Reference::None)
            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)
            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) {
        if (call->typeScope != func->typeScope)
            return ValueType::MatchResult::NOMATCH;
    }

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

    if (func->typeScope != nullptr && func->container != nullptr) {
        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;

    if (func->reference != Reference::None && func->constness > call->constness)
        return ValueType::MatchResult::FALLBACK1;

    return ValueType::MatchResult::SAME;
}

ValueType::MatchResult ValueType::matchParameter(const ValueType *call, const Variable *callVar, const Variable *funcVar)
{
    ValueType vt;
    const ValueType* pvt = funcVar->valueType();
    if (pvt && funcVar->isArray() && !(funcVar->isStlType() && match243(funcVar->typeStartToken()))) { // std::array doesn't decay to a pointer
        vt = *pvt;
        if (vt.pointer == 0) // don't bump array of pointers
            ++vt.pointer;
        pvt = &vt;
    }
    ValueType::MatchResult res = ValueType::matchParameter(call, pvt);
    if (callVar && ((res == ValueType::MatchResult::SAME && call->container) || res == ValueType::MatchResult::UNKNOWN)) {
        const std::string type1 = getTypeString(callVar->typeStartToken());
        const std::string type2 = getTypeString(funcVar->typeStartToken());
        const bool templateVar =
            funcVar->scope() && funcVar->scope()->function && funcVar->scope()->function->templateDef;
        if (type1 == type2)
            return ValueType::MatchResult::SAME;
        if (!templateVar && type1.find("auto") == std::string::npos && type2.find("auto") == std::string::npos)
            return ValueType::MatchResult::NOMATCH;
    }
    return res;
}
