#include "matchcompiler.h"
#include <string>
#include <cstring>
#include "errorlogger.h"
#include "token.h"
// pattern: = 0 ;
static bool match1(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("=")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("0")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: %var% = %var% !!;
static bool match2(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% %assign%
static bool match3(const Token* tok) {
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || !tok->isAssignmentOp())
        return false;
    return true;
}
// pattern: ( const| struct|union| %type% * ) ( (
static bool match4(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("struct")) || (tok->str() == MatchCompiler::makeConstString("union"))))
        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->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: ( [(<] const| struct|union| %type% *| [>)]
static bool match5(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;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("const"))))
        tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("union"))))
        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().size() != 1U || !strchr(">)", tok->str()[0]))
        return false;
    return true;
}
// pattern: (| &| %name%
static bool match6(const Token* tok) {
    if (tok && ((tok->str() == MatchCompiler::makeConstString("("))))
        tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("&"))))
        tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    return true;
}
// pattern: < const| struct|union| %type% *| > ( &| %name%
static bool match7(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("struct")) || (tok->str() == MatchCompiler::makeConstString("union"))))
        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(">")))
        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;
    return true;
}
// pattern: %var% .
static bool match8(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 match9(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("struct")) || (tok->str() == MatchCompiler::makeConstString("union"))))
        return false;
    return true;
}
// pattern: %cop% %var%
static bool match10(const Token* tok) {
    if (!tok || !tok->isConstOp())
        return false;
    tok = tok->next();
    if (!tok || !(tok->varId() != 0))
        return false;
    return true;
}
// pattern: %name% ?
static bool match11(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 match12(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
        return false;
    return true;
}
// pattern: %name% = %name% ;
static bool match13(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;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: . %name%
static bool match14(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    return true;
}
// pattern: [+:]
static bool match15(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr("+:", tok->str()[0]))
        return false;
    return true;
}
// pattern: * %var% ) (
static bool match16(const Token* tok) {
    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: %name% [ %var% ]
static bool match17(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->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || !(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: asm ( %str% )
static bool match19(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("asm")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->tokType() == Token::eString))
        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().size() != 1U || !strchr(";{}", tok->str()[0]))
        return false;
    return true;
}
// pattern: ( %name% )
static bool match21(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% ;
static bool match22(const Token* tok) {
    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: [;({=]
static bool match23(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr(";({=", tok->str()[0]))
        return false;
    return true;
}
// pattern: free|g_free|kfree|vfree ( %var% )
static bool match24(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("free")) || (tok->str() == MatchCompiler::makeConstString("g_free")) || (tok->str() == MatchCompiler::makeConstString("kfree")) || (tok->str() == MatchCompiler::makeConstString("vfree"))))
        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: delete %var% ;
static bool match25(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("delete")))
        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: delete [ ] %var% ;
static bool match26(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("delete")))
        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->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
// pattern: return|throw
static bool match27(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("return")) || (tok->str() == MatchCompiler::makeConstString("throw"))))
        return false;
    return true;
}
// pattern: *| ++|--| %name% ++|--| %assign%
static bool match28(const Token* tok) {
    if (tok && ((tok->str() == MatchCompiler::makeConstString("*"))))
        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 = tok->next();
    if (!tok || !tok->isAssignmentOp())
        return false;
    return true;
}
// pattern: *| ( const| %type% *| ) %name% %assign%
static bool match29(const Token* tok) {
    if (tok && ((tok->str() == MatchCompiler::makeConstString("*"))))
        tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    if (tok && ((tok->str() == MatchCompiler::makeConstString("const"))))
        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(")")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !tok->isAssignmentOp())
        return false;
    return true;
}
// pattern: ( const| %type% *| ) %name% %assign%
static bool match30(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->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(")")))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !tok->isAssignmentOp())
        return false;
    return true;
}
// pattern: while (
static bool match31(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("while")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: %assign% %name%
static bool match32(const Token* tok) {
    if (!tok || !tok->isAssignmentOp())
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        return false;
    return true;
}
// pattern: %name% =
static bool match33(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("=")))
        return false;
    return true;
}
// pattern: ( nothrow )
static bool match34(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    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: ( std :: nothrow )
static bool match35(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    tok = tok->next();
    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("nothrow")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    return true;
}
// pattern: %varid% .
static bool match36(const Token* tok, const int varid) {
    if (varid==0U)
        throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
    if (!tok || !(tok->isName() && tok->varId() == varid))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(".")))
        return false;
    return true;
}
// pattern: %name% ;
static bool match37(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 match38(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 match39(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 match40(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("=")))
        return false;
    return true;
}
// pattern: * (
static bool match41(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 match42(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: = new|malloc|calloc|kmalloc|kzalloc|kcalloc|strdup|strndup|vmalloc|g_new0|g_try_new|g_new|g_malloc|g_malloc0|g_try_malloc|g_try_malloc0|g_strdup|g_strndup|g_strdup_printf
static bool match43(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("=")))
        return false;
    tok = tok->next();
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("new")) || (tok->str() == MatchCompiler::makeConstString("malloc")) || (tok->str() == MatchCompiler::makeConstString("calloc")) || (tok->str() == MatchCompiler::makeConstString("kmalloc")) || (tok->str() == MatchCompiler::makeConstString("kzalloc")) || (tok->str() == MatchCompiler::makeConstString("kcalloc")) || (tok->str() == MatchCompiler::makeConstString("strdup")) || (tok->str() == MatchCompiler::makeConstString("strndup")) || (tok->str() == MatchCompiler::makeConstString("vmalloc")) || (tok->str() == MatchCompiler::makeConstString("g_new0")) || (tok->str() == MatchCompiler::makeConstString("g_try_new")) || (tok->str() == MatchCompiler::makeConstString("g_new")) || (tok->str() == MatchCompiler::makeConstString("g_malloc")) || (tok->str() == MatchCompiler::makeConstString("g_malloc0")) || (tok->str() == MatchCompiler::makeConstString("g_try_malloc")) || (tok->str() == MatchCompiler::makeConstString("g_try_malloc0")) || (tok->str() == MatchCompiler::makeConstString("g_strdup")) || (tok->str() == MatchCompiler::makeConstString("g_strndup")) || (tok->str() == MatchCompiler::makeConstString("g_strdup_printf"))))
        return false;
    return true;
}
// pattern: [;{}] %var% <<
static bool match44(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr(";{}", tok->str()[0]))
        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 match45(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("&")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->varId() != 0))
        return false;
    return true;
}
// pattern: >>|>>= %name%
static bool match46(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(">>")) || (tok->str() == MatchCompiler::makeConstString(">>="))))
        return false;
    tok = tok->next();
    if (!tok || !tok->isName())
        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(">>")) || (tok->str() == MatchCompiler::makeConstString("&"))))
        return false;
    return true;
}
// pattern: [{};:]
static bool match48(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr("{};:", tok->str()[0]))
        return false;
    return true;
}
// pattern: [(,] %var% [
static bool match49(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr("(,", tok->str()[0]))
        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 match50(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr("(,", tok->str()[0]))
        return false;
    tok = tok->next();
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || tok->str().size() != 1U || !strchr(",)", tok->str()[0]))
        return false;
    return true;
}
// pattern: [(,] & %var% [,)]
static bool match51(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;
    tok = tok->next();
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    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: ) %var% [,)]
static bool match53(const Token* tok) {
    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().size() != 1U || !strchr(",)", tok->str()[0]))
        return false;
    return true;
}
// pattern: [(,] *| %var% =
static bool match54(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr("(,", tok->str()[0]))
        return false;
    tok = tok->next();
    if (tok && ((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: %name% (
static bool match55(const Token* tok) {
    if (!tok || !tok->isName())
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: std :: ref ( %var% )
static bool match56(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("ref")))
        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 match57(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr("{,", tok->str()[0]))
        return false;
    tok = tok->next();
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || tok->str().size() != 1U || !strchr(",}", tok->str()[0]))
        return false;
    return true;
}
// pattern: %name% ( %var% [,)]
static bool match58(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->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || tok->str().size() != 1U || !strchr(",)", tok->str()[0]))
        return false;
    return true;
}
// pattern: %var% ;
static bool match59(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 match60(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr(";{}:", tok->str()[0]))
        return false;
    return true;
}
// pattern: try {
static bool match61(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("try")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("{")))
        return false;
    return true;
}
// pattern: [
static bool match62(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("[")))
        return false;
    return true;
}
// pattern: %var% (|{
static bool match63(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: %var% { }
static bool match64(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->str() == MatchCompiler::makeConstString("}")))
        return false;
    return true;
}
// pattern: %oror%|%comp%|!|&&
static bool match65(const Token* tok) {
    if (!tok || !((tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||")) || tok->isComparisonOp() || (tok->str() == MatchCompiler::makeConstString("!")) || (tok->str() == MatchCompiler::makeConstString("&&"))))
        return false;
    return true;
}
// pattern: if (
static bool match66(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("if")))
        return false;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        return false;
    return true;
}
// pattern: [.*]
static bool match67(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr(".*", tok->str()[0]))
        return false;
    return true;
}
// pattern: .|[|*
static bool match68(const Token* tok) {
    if (!tok || !((tok->str() == MatchCompiler::makeConstString(".")) || (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("(")) || (tok->str() == MatchCompiler::makeConstString("{"))))
        return false;
    return true;
}
// pattern: sizeof (
template<class T> static T * findmatch70(T * start_tok) {
    for (; start_tok; start_tok = start_tok->next()) {

    T * tok = start_tok;
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("sizeof")))
        continue;
    tok = tok->next();
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("(")))
        continue;
    return start_tok;
    }
    return nullptr;
}
// pattern: { }
static bool match71(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 match72(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: [:,] %var% [({]
static bool match73(const Token* tok) {
    if (!tok || tok->str().size() != 1U || !strchr(":,", tok->str()[0]))
        return false;
    tok = tok->next();
    if (!tok || !(tok->varId() != 0))
        return false;
    tok = tok->next();
    if (!tok || tok->str().size() != 1U || !strchr("({", tok->str()[0]))
        return false;
    return true;
}
// pattern: )
static bool match74(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(")")))
        return false;
    return true;
}
// pattern: &
static bool match75(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("&")))
        return false;
    return true;
}
// pattern: return
static bool match76(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString("return")))
        return false;
    return true;
}
// pattern: ;
static bool match77(const Token* tok) {
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
        return false;
    return true;
}
#line 1 "/build/cppcheck/src/cppcheck/lib/checkunusedvar.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 "checkunusedvar.h"

#include "astutils.h"
#include "errortypes.h"
#include "library.h"
#include "preprocessor.h"
#include "settings.h"
#include "symboldatabase.h"
#include "token.h"
#include "tokenize.h"
#include "tokenlist.h"
#include "utils.h"

#include <algorithm>
#include <list>
#include <memory>
#include <set>
#include <utility>
#include <vector>
//---------------------------------------------------------------------------

// Register this check class (by creating a static instance of it)
namespace {
    CheckUnusedVar instance;
}

static const struct CWE CWE563(563U);   // Assignment to Variable without Use ('Unused Variable')
static const struct CWE CWE665(665U);   // Improper Initialization

/** Is scope a raii class scope */
static bool isRaiiClassScope(const Scope *classScope)
{
    return classScope && classScope->getDestructor() != nullptr;
}

/** Is ValueType a raii class? */
static bool isRaiiClass(const ValueType *valueType, bool cpp, bool defaultReturn = true)
{
    if (!cpp)
        return false;

    if (!valueType)
        return defaultReturn;

    if (valueType->smartPointerType && isRaiiClassScope(valueType->smartPointerType->classScope))
        return true;

    switch (valueType->type) {
    case ValueType::Type::UNKNOWN_TYPE:
    case ValueType::Type::NONSTD:
        return defaultReturn;

    case ValueType::Type::RECORD:
        if (isRaiiClassScope(valueType->typeScope))
            return true;
        return defaultReturn;

    case ValueType::Type::SMART_POINTER:
    case ValueType::Type::CONTAINER:
    case ValueType::Type::ITERATOR:
    case ValueType::Type::VOID:
    case ValueType::Type::BOOL:
    case ValueType::Type::CHAR:
    case ValueType::Type::SHORT:
    case ValueType::Type::WCHAR_T:
    case ValueType::Type::INT:
    case ValueType::Type::LONG:
    case ValueType::Type::LONGLONG:
    case ValueType::Type::UNKNOWN_INT:
    case ValueType::Type::FLOAT:
    case ValueType::Type::DOUBLE:
    case ValueType::Type::LONGDOUBLE:
        return false;
    }

    return defaultReturn;
}

/**
 * @brief This class is used create a list of variables within a function.
 */
class Variables {
public:
    enum VariableType { standard, array, pointer, reference, pointerArray, referenceArray, pointerPointer, none };

    /** Store information about variable usage */
    class VariableUsage {
    public:
        explicit VariableUsage(const Variable *var = nullptr,
                               VariableType type = standard,
                               bool read = false,
                               bool write = false,
                               bool modified = false,
                               bool allocateMemory = false) :
            _var(var),
            _lastAccess(var ? var->nameToken() : nullptr),
            mType(type),
            _read(read),
            _write(write),
            _modified(modified),
            _allocateMemory(allocateMemory) {}

        /** variable is used.. set both read+write */
        void use() {
            _read = true;
            _write = true;
        }

        /** is variable unused? */
        bool unused() const {
            return (!_read && !_write);
        }

        std::set<nonneg int> _aliases;
        std::set<const Scope*> _assignments;

        const Variable* _var;
        const Token* _lastAccess;
        VariableType mType;
        bool _read;
        bool _write;
        bool _modified; // read/modify/write
        bool _allocateMemory;
    };

    void clear() {
        mVarUsage.clear();
    }
    const std::map<nonneg int, VariableUsage> &varUsage() const {
        return mVarUsage;
    }
    void addVar(const Variable *var, VariableType type, bool write_);
    void allocateMemory(nonneg int varid, const Token* tok);
    void read(nonneg int varid, const Token* tok);
    void readAliases(nonneg int varid, const Token* tok);
    void readAll(nonneg int varid, const Token* tok);
    void write(nonneg int varid, const Token* tok);
    void writeAliases(nonneg int varid, const Token* tok);
    void writeAll(nonneg int varid, const Token* tok);
    void use(nonneg int varid, const Token* tok);
    void modified(nonneg int varid, const Token* tok);
    VariableUsage *find(nonneg int varid);
    void alias(nonneg int varid1, nonneg int varid2, bool replace);
    void erase(nonneg int varid) {
        mVarUsage.erase(varid);
    }
    void eraseAliases(nonneg int varid);
    void eraseAll(nonneg int varid);
    void clearAliases(nonneg int varid);

private:

    std::map<nonneg int, VariableUsage> mVarUsage;
};


/**
 * Alias the 2 given variables. Either replace the existing aliases if
 * they exist or merge them.  You would replace an existing alias when this
 * assignment is in the same scope as the previous assignment.  You might
 * merge the aliases when this assignment is in a different scope from the
 * previous assignment depending on the relationship of the 2 scopes.
 */
void Variables::alias(nonneg int varid1, nonneg int varid2, bool replace)
{
    VariableUsage *var1 = find(varid1);
    VariableUsage *var2 = find(varid2);

    if (!var1 || !var2)
        return;

    // alias to self
    if (varid1 == varid2) {
        var1->use();
        return;
    }

    if (replace) {
        // remove var1 from all aliases
        for (std::set<nonneg int>::const_iterator i = var1->_aliases.begin(); i != var1->_aliases.end(); ++i) {
            VariableUsage *temp = find(*i);

            if (temp)
                temp->_aliases.erase(var1->_var->declarationId());
        }

        // remove all aliases from var1
        var1->_aliases.clear();
    }

    // var1 gets all var2s aliases
    for (std::set<nonneg int>::const_iterator i = var2->_aliases.begin(); i != var2->_aliases.end(); ++i) {
        if (*i != varid1)
            var1->_aliases.insert(*i);
    }

    // var2 is an alias of var1
    var2->_aliases.insert(varid1);
    var1->_aliases.insert(varid2);

    if (var2->mType == Variables::pointer) {
        var2->_read = true;
    }
}

void Variables::clearAliases(nonneg int varid)
{
    VariableUsage *usage = find(varid);

    if (usage) {
        // remove usage from all aliases
        std::set<nonneg int>::const_iterator i;

        for (i = usage->_aliases.begin(); i != usage->_aliases.end(); ++i) {
            VariableUsage *temp = find(*i);

            if (temp)
                temp->_aliases.erase(usage->_var->declarationId());
        }

        // remove all aliases from usage
        usage->_aliases.clear();
    }
}

void Variables::eraseAliases(nonneg int varid)
{
    VariableUsage *usage = find(varid);

    if (usage) {
        for (std::set<nonneg int>::const_iterator aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases)
            erase(*aliases);
    }
}

void Variables::eraseAll(nonneg int varid)
{
    eraseAliases(varid);
    erase(varid);
}

void Variables::addVar(const Variable *var,
                       VariableType type,
                       bool write_)
{
    if (var->declarationId() > 0) {
        mVarUsage.insert(std::make_pair(var->declarationId(), VariableUsage(var, type, false, write_, false)));
    }
}

void Variables::allocateMemory(nonneg int varid, const Token* tok)
{
    VariableUsage *usage = find(varid);

    if (usage) {
        usage->_allocateMemory = true;
        usage->_lastAccess = tok;
    }
}

void Variables::read(nonneg int varid, const Token* tok)
{
    VariableUsage *usage = find(varid);

    if (usage) {
        usage->_read = true;
        if (tok)
            usage->_lastAccess = tok;
    }
}

void Variables::readAliases(nonneg int varid, const Token* tok)
{
    VariableUsage *usage = find(varid);

    if (usage) {
        for (nonneg int aliases : usage->_aliases) {
            VariableUsage *aliased = find(aliases);

            if (aliased) {
                aliased->_read = true;
                aliased->_lastAccess = tok;
            }
        }
    }
}

void Variables::readAll(nonneg int varid, const Token* tok)
{
    read(varid, tok);
    readAliases(varid, tok);
}

void Variables::write(nonneg int varid, const Token* tok)
{
    VariableUsage *usage = find(varid);

    if (usage) {
        usage->_write = true;
        if (!usage->_var->isStatic() && !match1(tok->next()))
            usage->_read = false;
        usage->_lastAccess = tok;
    }
}

void Variables::writeAliases(nonneg int varid, const Token* tok)
{
    VariableUsage *usage = find(varid);

    if (usage) {
        for (std::set<nonneg int>::const_iterator aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) {
            VariableUsage *aliased = find(*aliases);

            if (aliased) {
                aliased->_write = true;
                aliased->_lastAccess = tok;
            }
        }
    }
}

void Variables::writeAll(nonneg int varid, const Token* tok)
{
    write(varid, tok);
    writeAliases(varid, tok);
}

void Variables::use(nonneg int varid, const Token* tok)
{
    VariableUsage *usage = find(varid);

    if (usage) {
        usage->use();
        usage->_lastAccess = tok;

        for (std::set<nonneg int>::const_iterator aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) {
            VariableUsage *aliased = find(*aliases);

            if (aliased) {
                aliased->use();
                aliased->_lastAccess = tok;
            }
        }
    }
}

void Variables::modified(nonneg int varid, const Token* tok)
{
    VariableUsage *usage = find(varid);

    if (usage) {
        if (!usage->_var->isStatic())
            usage->_read = false;
        usage->_modified = true;
        usage->_lastAccess = tok;

        for (std::set<nonneg int>::const_iterator aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) {
            VariableUsage *aliased = find(*aliases);

            if (aliased) {
                aliased->_modified = true;
                aliased->_lastAccess = tok;
            }
        }
    }
}

Variables::VariableUsage *Variables::find(nonneg int varid)
{
    if (varid) {
        std::map<nonneg int, VariableUsage>::iterator i = mVarUsage.find(varid);
        if (i != mVarUsage.end())
            return &i->second;
    }
    return nullptr;
}

static const Token* doAssignment(Variables &variables, const Token *tok, bool dereference, const Scope *scope)
{
    // a = a + b;
    if (match2(tok)) {
        const Token* rhsVarTok = tok->tokAt(2);
        if (tok->varId() == rhsVarTok->varId()) {
            return rhsVarTok;
        }
    }

    if (match3(tok) && tok->strAt(1) != MatchCompiler::makeConstString("="))
        return tok->next();

    const Token* const tokOld = tok;

    // check for aliased variable
    const nonneg int varid1 = tok->varId();
    Variables::VariableUsage *var1 = variables.find(varid1);

    if (var1) {
        // jump behind '='
        tok = tok->next();
        while (!tok->isAssignmentOp()) {
            if (tok->varId())
                variables.read(tok->varId(), tok);
            tok = tok->next();
        }
        tok = tok->next();

        if (match4(tok))
            tok = tok->link()->next();

        if (match5(tok))
            tok = tok->next();

        if (match6(tok) ||
            (match7(tok->next()))) {
            bool addressOf = false;

            if (match8(tok))
                variables.use(tok->varId(), tok);   // use = read + write

            // check for C style cast
            if (tok->str() == MatchCompiler::makeConstString("(")) {
                tok = tok->next();
                if (tok->str() == MatchCompiler::makeConstString("const"))
                    tok = tok->next();

                if (match9(tok))
                    tok = tok->next();

                while ((tok->isName() && tok->varId() == 0) || (tok->str() == MatchCompiler::makeConstString("*")) || (tok->str() == MatchCompiler::makeConstString(")")))
                    tok = tok->next();

                if (tok->str() == MatchCompiler::makeConstString("&")) {
                    addressOf = true;
                    tok = tok->next();
                } else if (tok->str() == MatchCompiler::makeConstString("(")) {
                    tok = tok->next();
                    if (tok->str() == MatchCompiler::makeConstString("&")) {
                        addressOf = true;
                        tok = tok->next();
                    }
                } else if (match10(tok)) {
                    variables.read(tok->next()->varId(), tok);
                }
            }

            // check for C++ style cast
            else if (tok->str().find("cast") != std::string::npos &&
                     tok->strAt(1) == MatchCompiler::makeConstString("<")) {
                tok = tok->tokAt(2);
                if (tok->str() == MatchCompiler::makeConstString("const"))
                    tok = tok->next();

                if (match9(tok))
                    tok = tok->next();

                tok = tok->next();
                if (tok->str() == MatchCompiler::makeConstString("*"))
                    tok = tok->next();

                tok = tok->tokAt(2);
                if (!tok)
                    return tokOld;
                if (tok->str() == MatchCompiler::makeConstString("&")) {
                    addressOf = true;
                    tok = tok->next();
                }
            }

            // no cast, no ?
            else if (!match11(tok)) {
                if (tok->str() == MatchCompiler::makeConstString("&")) {
                    addressOf = true;
                    tok = tok->next();
                } else if (tok->str() == MatchCompiler::makeConstString("new"))
                    return tokOld;
            }

            // check if variable is local
            const nonneg int varid2 = tok->varId();
            const Variables::VariableUsage* var2 = variables.find(varid2);

            if (var2) { // local variable (alias or read it)
                if (var1->mType == Variables::pointer || var1->mType == Variables::pointerArray) {
                    if (dereference)
                        variables.read(varid2, tok);
                    else {
                        if (addressOf ||
                            var2->mType == Variables::array ||
                            var2->mType == Variables::pointer) {
                            bool replace = true;

                            // pointerArray => don't replace
                            if (var1->mType == Variables::pointerArray)
                                replace = false;

                            // check if variable declared in same scope
                            else if (scope == var1->_var->scope())
                                replace = true;

                            // not in same scope as declaration
                            else {
                                // no other assignment in this scope
                                if (var1->_assignments.find(scope) == var1->_assignments.end() ||
                                    scope->type == Scope::eSwitch) {
                                    // nothing to replace
                                    // cppcheck-suppress duplicateBranch - remove when TODO below is address
                                    if (var1->_assignments.empty())
                                        replace = false;

                                    // this variable has previous assignments
                                    else {
                                        // TODO: determine if existing aliases should be replaced or merged
                                        replace = false;
                                    }
                                }

                                // assignment in this scope
                                else {
                                    // replace when only one other assignment, merge them otherwise
                                    replace = (var1->_assignments.size() == 1);
                                }
                            }

                            variables.alias(varid1, varid2, replace);
                        } else if (tok->strAt(1) == MatchCompiler::makeConstString("?")) {
                            if (var2->mType == Variables::reference)
                                variables.readAliases(varid2, tok);
                            else
                                variables.read(varid2, tok);
                        } else {
                            variables.readAll(varid2, tok);
                        }
                    }
                } else if (var1->mType == Variables::reference) {
                    variables.alias(varid1, varid2, true);
                } else if (var1->mType == Variables::standard && addressOf) {
                    variables.alias(varid1, varid2, true);
                } else {
                    if ((var2->mType == Variables::pointer || var2->mType == Variables::pointerArray) && tok->strAt(1) == MatchCompiler::makeConstString("["))
                        variables.readAliases(varid2, tok);

                    variables.read(varid2, tok);
                }
            } else { // not a local variable (or an unsupported local variable)
                if (var1->mType == Variables::pointer && !dereference) {
                    // check if variable declaration is in this scope
                    if (var1->_var->scope() == scope) {
                        // If variable is used in RHS then "use" variable
                        for (const Token *rhs = tok; rhs && rhs->str() != MatchCompiler::makeConstString(";"); rhs = rhs->next()) {
                            if (rhs->varId() == varid1) {
                                variables.use(varid1, tok);
                                break;
                            }
                        }
                        variables.clearAliases(varid1);
                    } else {
                        // no other assignment in this scope
                        if (var1->_assignments.find(scope) == var1->_assignments.end()) {
                            /**
                             * @todo determine if existing aliases should be discarded
                             */
                        }

                        // this assignment replaces the last assignment in this scope
                        else {
                            // aliased variables in a larger scope are not supported
                            // remove all aliases
                            variables.clearAliases(varid1);
                        }
                    }
                }
            }
        } else
            tok = tokOld;

        var1->_assignments.insert(scope);
    }

    // check for alias to struct member
    // char c[10]; a.b = c;
    else if (match12(tok->tokAt(-2))) {
        const Token *rhsVarTok = tok->tokAt(2);
        if (rhsVarTok && rhsVarTok->varId()) {
            const nonneg int varid2 = rhsVarTok->varId();
            const Variables::VariableUsage *var2 = variables.find(varid2);

            // struct member aliased to local variable
            if (var2 && (var2->mType == Variables::array ||
                         var2->mType == Variables::pointer)) {
                // erase aliased variable and all variables that alias it
                // to prevent false positives
                variables.eraseAll(varid2);
            }
        }
    }

    // Possible pointer alias
    else if (match13(tok)) {
        const nonneg int varid2 = tok->tokAt(2)->varId();
        const Variables::VariableUsage *var2 = variables.find(varid2);
        if (var2 && (var2->mType == Variables::array ||
                     var2->mType == Variables::pointer)) {
            variables.use(varid2,tok);
        }
    }

    return tok;
}

static bool isPartOfClassStructUnion(const Token* tok)
{
    for (; tok; tok = tok->previous()) {
        if (tok->str() == MatchCompiler::makeConstString("}") || tok->str() == MatchCompiler::makeConstString(")"))
            tok = tok->link();
        else if (tok->str() == MatchCompiler::makeConstString("("))
            return (false);
        else if (tok->str() == MatchCompiler::makeConstString("{")) {
            return (tok->strAt(-1) == MatchCompiler::makeConstString("struct") || tok->strAt(-2) == MatchCompiler::makeConstString("struct") || tok->strAt(-1) == MatchCompiler::makeConstString("class") || tok->strAt(-2) == MatchCompiler::makeConstString("class") || tok->strAt(-1) == MatchCompiler::makeConstString("union") || tok->strAt(-2) == MatchCompiler::makeConstString("union"));
        }
    }
    return false;
}

static bool isVarDecl(const Token *tok)
{
    return tok && tok->variable() && tok->variable()->nameToken() == tok;
}

// Skip [ .. ]
static const Token * skipBrackets(const Token *tok)
{
    while (tok && tok->str() == MatchCompiler::makeConstString("["))
        tok = tok->link()->next();
    return tok;
}


// Skip [ .. ] . x
static const Token * skipBracketsAndMembers(const Token *tok)
{
    while (tok) {
        if (tok->str() == MatchCompiler::makeConstString("["))
            tok = tok->link()->next();
        else if (match14(tok))
            tok = tok->tokAt(2);
        else
            break;
    }
    return tok;
}

static void useFunctionArgs(const Token *tok, Variables& variables)
{
    // TODO: Match function args to see if they are const or not. Assume that const data is not written.
    if (!tok)
        return;
    if (tok->str() == MatchCompiler::makeConstString(",")) {
        useFunctionArgs(tok->astOperand1(), variables);
        useFunctionArgs(tok->astOperand2(), variables);
    } else if (match15(tok) && (!tok->valueType() || tok->valueType()->pointer)) {
        useFunctionArgs(tok->astOperand1(), variables);
        useFunctionArgs(tok->astOperand2(), variables);
    } else if (tok->variable() && tok->variable()->isArray()) {
        variables.use(tok->varId(), tok);
    }
}

//---------------------------------------------------------------------------
// Usage of function variables
//---------------------------------------------------------------------------
void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const scope, Variables& variables)
{
    // Find declarations if the scope is executable..
    if (scope->isExecutable()) {
        // Find declarations
        for (std::list<Variable>::const_iterator i = scope->varlist.begin(); i != scope->varlist.end(); ++i) {
            if (i->isThrow() || i->isExtern())
                continue;
            Variables::VariableType type = Variables::none;
            if (i->isArray() && (i->nameToken()->previous()->str() == MatchCompiler::makeConstString("*") || i->nameToken()->strAt(-2) == MatchCompiler::makeConstString("*")))
                type = Variables::pointerArray;
            else if (i->isArray() && i->nameToken()->previous()->str() == MatchCompiler::makeConstString("&"))
                type = Variables::referenceArray;
            else if (i->isArray())
                type = (i->dimensions().size() == 1U) ? Variables::array : Variables::pointerArray;
            else if (i->isReference())
                type = Variables::reference;
            else if (i->nameToken()->previous()->str() == MatchCompiler::makeConstString("*") && i->nameToken()->strAt(-2) == MatchCompiler::makeConstString("*"))
                type = Variables::pointerPointer;
            else if (i->isPointerToArray())
                type = Variables::pointerPointer;
            else if (i->isPointer())
                type = Variables::pointer;
            else if (mTokenizer->isC() ||
                     i->typeEndToken()->isStandardType() ||
                     isRecordTypeWithoutSideEffects(i->type()) ||
                     mSettings->library.detectContainer(i->typeStartToken(), /*iterator*/ false) ||
                     i->isStlType())
                type = Variables::standard;
            if (type == Variables::none || isPartOfClassStructUnion(i->typeStartToken()))
                continue;
            const Token* defValTok = i->nameToken()->next();
            if (match16(i->nameToken()->previous())) // function pointer. Jump behind parameter list.
                defValTok = defValTok->linkAt(1)->next();
            for (; defValTok; defValTok = defValTok->next()) {
                if (defValTok->str() == MatchCompiler::makeConstString("["))
                    defValTok = defValTok->link();
                else if (defValTok->str() == MatchCompiler::makeConstString("(") || defValTok->str() == MatchCompiler::makeConstString("{") || defValTok->str() == MatchCompiler::makeConstString("=") || defValTok->str() == MatchCompiler::makeConstString(":")) {
                    variables.addVar(&*i, type, true);
                    break;
                } else if (defValTok->str() == MatchCompiler::makeConstString(";") || defValTok->str() == MatchCompiler::makeConstString(",") || defValTok->str() == MatchCompiler::makeConstString(")")) {
                    variables.addVar(&*i, type, i->isStatic());
                    break;
                }
            }
            if (i->isArray() && i->isClass() && // Array of class/struct members. Initialized by ctor except for std::array
                !(i->isStlType() && i->valueType() && i->valueType()->containerTypeToken && i->valueType()->containerTypeToken->isStandardType()))
                variables.write(i->declarationId(), i->nameToken());
            if (i->isArray() && match17(i->nameToken())) // Array index variable read.
                variables.read(i->nameToken()->tokAt(2)->varId(), i->nameToken());

            if (defValTok && defValTok->next()) {
                // simple assignment "var = 123"
                if (defValTok->str() == MatchCompiler::makeConstString("=") && defValTok->next()->str() != MatchCompiler::makeConstString("{")) {
                    doAssignment(variables, i->nameToken(), false, scope);
                } else {
                    // could be "var = {...}" OR "var{...}" (since C++11)
                    const Token* tokBraceStart = nullptr;
                    if (match18(defValTok)) {
                        // "var = {...}"
                        tokBraceStart = defValTok->next();
                    } else if (defValTok->str() == MatchCompiler::makeConstString("{")) {
                        // "var{...}"
                        tokBraceStart = defValTok;
                    }
                    if (tokBraceStart) {
                        for (const Token* tok = tokBraceStart->next(); tok && tok != tokBraceStart->link(); tok = tok->next()) {
                            if (tok->varId()) {
                                // Variables used to initialize the array read.
                                variables.read(tok->varId(), i->nameToken());
                            }
                        }
                    }
                }
            }
        }
    }

    // Check variable usage
    const Token *tok;
    if (scope->type == Scope::eFunction)
        tok = scope->bodyStart->next();
    else
        tok = scope->classDef->next();
    for (; tok && tok != scope->bodyEnd; tok = tok->next()) {
        if (tok->str() == MatchCompiler::makeConstString("{") && tok != scope->bodyStart && !tok->previous()->varId()) {
            for (const Scope *i : scope->nestedList) {
                if (i->bodyStart == tok) { // Find associated scope
                    checkFunctionVariableUsage_iterateScopes(tok->scope(), variables); // Scan child scope
                    tok = tok->link();
                    break;
                }
            }
            if (!tok)
                break;
        }

        if (match19(tok)) {
            variables.clear();
            break;
        }

        // templates
        if (tok->isName() && endsWith(tok->str(), '>')) {
            // TODO: This is a quick fix to handle when constants are used
            // as template parameters. Try to handle this better, perhaps
            // only remove constants.
            variables.clear();
        }

        else if (match20(tok->previous())) {
            for (const Token* tok2 = tok->next(); tok2; tok2 = tok2->next()) {
                if (tok2->varId()) {
                    // Is this a variable declaration?
                    const Variable *var = tok2->variable();
                    if (!var || var->nameToken() != tok2)
                        continue;

                    // Mark template parameters used in declaration as use..
                    if (tok2->strAt(-1) == MatchCompiler::makeConstString(">")) {
                        for (const Token *tok3 = tok; tok3 != tok2; tok3 = tok3->next()) {
                            if (tok3->varId())
                                variables.use(tok3->varId(), tok3);
                        }
                    }

                    // Skip variable declaration..
                    tok = tok2->next();
                    if (match21(tok)) // Simple initialization through copy ctor
                        tok = tok->next();
                    else if (match22(tok)) { // Simple initialization
                        tok = tok->next();
                        if (!var->isReference())
                            variables.read(tok->varId(), tok);
                    } else if (tok->str() == MatchCompiler::makeConstString("[") && match18(skipBrackets(tok))) {
                        const Token * const rhs1 = skipBrackets(tok)->next();
                        for (const Token *rhs = rhs1->link(); rhs != rhs1; rhs = rhs->previous()) {
                            if (rhs->varId())
                                variables.readAll(rhs->varId(), rhs);
                        }
                    } else if (var->typeEndToken()->str() == MatchCompiler::makeConstString(">")) // Be careful with types like std::vector
                        tok = tok->previous();
                    break;
                } else if (match23(tok2))
                    break;
            }
        }
        // Freeing memory (not considered "using" the pointer if it was also allocated in this function)
        if (match24(tok) ||
            (mTokenizer->isCPP() && (match25(tok) || match26(tok)))) {
            nonneg int varid = 0;
            if (tok->str() != MatchCompiler::makeConstString("delete")) {
                const Token *varTok = tok->tokAt(2);
                varid = varTok->varId();
                tok = varTok->next();
            } else if (tok->strAt(1) == MatchCompiler::makeConstString("[")) {
                const Token *varTok = tok->tokAt(3);
                varid = varTok->varId();
                tok = varTok;
            } else {
                varid = tok->next()->varId();
                tok = tok->next();
            }

            const Variables::VariableUsage *const var = variables.find(varid);
            if (var) {
                if (!var->_aliases.empty())
                    variables.use(varid, tok);
                else if (!var->_allocateMemory)
                    variables.readAll(varid, tok);
            }
        }

        else if (match27(tok)) {
            for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
                if (tok2->varId())
                    variables.readAll(tok2->varId(), tok);
                else if (tok2->str() == MatchCompiler::makeConstString(";"))
                    break;
            }
        }

        // assignment
        else if (match28(tok) ||
                 match29(tok)) {
            bool dereference = false;
            bool pre = false;
            bool post = false;

            if (tok->str() == MatchCompiler::makeConstString("*")) {
                dereference = true;
                tok = tok->next();
            }

            if (match30(tok))
                tok = tok->link()->next();

            else if (tok->str() == MatchCompiler::makeConstString("("))
                tok = tok->next();

            if (tok->tokType() == Token::eIncDecOp) {
                pre = true;
                tok = tok->next();
            }

            if (tok->next()->tokType() == Token::eIncDecOp)
                post = true;

            const nonneg int varid1 = tok->varId();
            const Token * const start = tok;

            // assignment in while head..
            bool inwhile = false;
            {
                const Token *parent = tok->astParent();
                while (parent) {
                    if (match31(parent->previous())) {
                        inwhile = true;
                        break;
                    }
                    parent = parent->astParent();
                }
            }

            tok = doAssignment(variables, tok, dereference, scope);

            if (tok && tok->isAssignmentOp() && tok->str() != MatchCompiler::makeConstString("=")) {
                variables.use(varid1, tok);
                if (match32(tok)) {
                    tok = tok->next();
                    variables.read(tok->varId(), tok);
                }
            }

            if (pre || post)
                variables.use(varid1, tok);

            if (dereference) {
                const Variables::VariableUsage *const var = variables.find(varid1);
                if (var && var->mType == Variables::array)
                    variables.write(varid1, tok);
                variables.writeAliases(varid1, tok);
                variables.read(varid1, tok);
            } else {
                const Variables::VariableUsage *const var = variables.find(varid1);
                if (var && (inwhile || start->strAt(-1) == MatchCompiler::makeConstString(","))) {
                    variables.use(varid1, tok);
                } else if (var && var->mType == Variables::reference) {
                    variables.writeAliases(varid1, tok);
                    variables.read(varid1, tok);
                }
                // Consider allocating memory separately because allocating/freeing alone does not constitute using the variable
                else if (var && var->mType == Variables::pointer &&
                         match33(start) &&
                         findAllocFuncCallToken(start->next()->astOperand2(), mSettings->library)) {

                    const Token *allocFuncCallToken = findAllocFuncCallToken(start->next()->astOperand2(), mSettings->library);
                    const Library::AllocFunc *allocFunc = mSettings->library.getAllocFuncInfo(allocFuncCallToken);

                    bool allocateMemory = !allocFunc || Library::ismemory(allocFunc->groupId);

                    if (allocFuncCallToken->str() == MatchCompiler::makeConstString("new")) {
                        const Token *type = allocFuncCallToken->next();

                        // skip nothrow
                        if (mTokenizer->isCPP() && (match34(type) ||
                                                    match35(type)))
                            type = type->link()->next();

                        // is it a user defined type?
                        if (!type->isStandardType()) {
                            const Variable *variable = start->variable();
                            if (!variable || !isRecordTypeWithoutSideEffects(variable->type()))
                                allocateMemory = false;
                        }
                    }

                    if (allocateMemory)
                        variables.allocateMemory(varid1, tok);
                    else
                        variables.write(varid1, tok);
                } else if (varid1 && match36(tok, varid1)) {
                    variables.read(varid1, tok);
                    variables.write(varid1, start);
                } else if (var &&
                           var->mType == Variables::pointer &&
                           match37(tok) &&
                           tok->varId() == 0 &&
                           tok->hasKnownIntValue() &&
                           tok->values().front().intvalue == 0) {
                    variables.use(varid1, tok);
                } else {
                    variables.write(varid1, tok);
                }
            }

            const Variables::VariableUsage * const var2 = variables.find(tok->varId());
            if (var2) {
                if (var2->mType == Variables::reference) {
                    variables.writeAliases(tok->varId(), tok);
                    variables.read(tok->varId(), tok);
                } else if (tok->varId() != varid1 && match38(tok))
                    variables.read(tok->varId(), tok);
                else if (tok->varId() != varid1 &&
                         var2->mType == Variables::standard &&
                         tok->strAt(-1) != MatchCompiler::makeConstString("&"))
                    variables.use(tok->varId(), tok);
            }

            const Token * const equal = skipBracketsAndMembers(tok->next());

            // checked for chained assignments
            if (tok != start && equal && equal->str() == MatchCompiler::makeConstString("=")) {
                const nonneg int varId = tok->varId();
                const Variables::VariableUsage * const var = variables.find(varId);

                if (var && var->mType != Variables::reference) {
                    variables.read(varId,tok);
                }

                tok = tok->previous();
            }
        }

        // assignment
        else if ((match39(tok) && match40(skipBracketsAndMembers(tok->next()))) ||
                 (match41(tok) && match42(tok->next()->link()))) {
            const Token *eq = tok;
            while (eq && !eq->isAssignmentOp())
                eq = eq->astParent();

            const bool deref = eq && eq->astOperand1() && eq->astOperand1()->valueType() && eq->astOperand1()->valueType()->pointer == 0U;

            if (tok->str() == MatchCompiler::makeConstString("*")) {
                tok = tok->tokAt(2);
                if (tok->str() == MatchCompiler::makeConstString("("))
                    tok = tok->link()->next();
            }

            const nonneg int varid = tok->varId();
            const Variables::VariableUsage *var = variables.find(varid);

            if (var) {
                // Consider allocating memory separately because allocating/freeing alone does not constitute using the variable
                if (var->mType == Variables::pointer &&
                    match43(skipBrackets(tok->next()))) {
                    variables.allocateMemory(varid, tok);
                } else if (var->mType == Variables::pointer || var->mType == Variables::reference) {
                    variables.read(varid, tok);
                    variables.writeAliases(varid, tok);
                } else if (var->mType == Variables::pointerArray) {
                    tok = doAssignment(variables, tok, deref, scope);
                } else
                    variables.writeAll(varid, tok);
            }
        }

        else if (mTokenizer->isCPP() && match44(tok)) {
            variables.erase(tok->next()->varId());
        }

        else if (match45(tok)) {
            if (tok->astOperand2()) { // bitop
                variables.read(tok->next()->varId(), tok);
            } else // addressof
                variables.use(tok->next()->varId(), tok); // use = read + write
        } else if (match46(tok)) {
            if (isLikelyStreamRead(mTokenizer->isCPP(), tok))
                variables.use(tok->next()->varId(), tok); // use = read + write
            else
                variables.read(tok->next()->varId(), tok);
        } else if (match47(tok) && match48(tok->previous())) {
            variables.read(tok->varId(), tok);
        } else if (isLikelyStreamRead(mTokenizer->isCPP(),tok->previous())) {
            variables.use(tok->varId(), tok);
        }

        // function parameter
        else if (match49(tok)) {
            variables.use(tok->next()->varId(), tok);   // use = read + write
        } else if (match50(tok) && tok->previous()->str() != MatchCompiler::makeConstString("*")) {
            variables.use(tok->next()->varId(), tok);   // use = read + write
        } else if (match51(tok)) {
            variables.eraseAll(tok->tokAt(2)->varId());
        } else if (match52(tok) &&
                   match53(tok->next()->link())) {
            variables.use(tok->next()->link()->next()->varId(), tok);   // use = read + write
        } else if (match54(tok)) {
            tok = tok->next();
            if (tok->str() == MatchCompiler::makeConstString("*"))
                tok = tok->next();
            variables.use(tok->varId(), tok);
        }

        // function
        else if (match55(tok)) {
            variables.read(tok->varId(), tok);
            useFunctionArgs(tok->next()->astOperand2(), variables);
        } else if (match56(tok)) {
            variables.eraseAll(tok->tokAt(4)->varId());
        }

        else if (match57(tok->previous())) {
            variables.read(tok->varId(), tok);
        }

        else if (tok->varId() && match8(tok)) {
            variables.use(tok->varId(), tok);   // use = read + write
        }

        else if (tok->str() == MatchCompiler::makeConstString(":") && (!tok->valueType() || tok->valueType()->pointer)) {
            if (tok->astOperand1())
                variables.use(tok->astOperand1()->varId(), tok->astOperand1());
            if (tok->astOperand2())
                variables.use(tok->astOperand2()->varId(), tok->astOperand2());
        }

        else if (tok->isExtendedOp() && tok->next() && tok->next()->varId() && tok->strAt(2) != MatchCompiler::makeConstString("=") && !isVarDecl(tok->next())) {
            variables.readAll(tok->next()->varId(), tok);
        }

        else if (tok->varId() && !isVarDecl(tok) && tok->next() && (tok->next()->str() == MatchCompiler::makeConstString(")") || tok->next()->isExtendedOp())) {
            if (match58(tok->tokAt(-2)) &&
                !(tok->tokAt(-2)->variable() && tok->tokAt(-2)->variable()->isReference()))
                variables.use(tok->varId(), tok);
            else
                variables.readAll(tok->varId(), tok);
        }

        else if (match59(tok) && match60(tok->previous())) {
            variables.readAll(tok->varId(), tok);
        }

        // ++|--
        else if (tok->next() && tok->next()->tokType() == Token::eIncDecOp && tok->next()->astOperand1() && tok->next()->astOperand1()->varId()) {
            if (tok->next()->astParent())
                variables.use(tok->next()->astOperand1()->varId(), tok);
            else
                variables.modified(tok->next()->astOperand1()->varId(), tok);
        }

        else if (tok->isAssignmentOp()) {
            for (const Token *tok2 = tok->next(); tok2 && tok2->str() != MatchCompiler::makeConstString(";"); tok2 = tok2->next()) {
                if (tok2->varId()) {
                    if (tok2->strAt(1) == MatchCompiler::makeConstString("="))
                        variables.write(tok2->varId(), tok);
                    else if (tok2->next() && tok2->next()->isAssignmentOp())
                        variables.use(tok2->varId(), tok);
                    else
                        variables.read(tok2->varId(), tok);
                }
            }
        } else if (tok->variable() && tok->variable()->isClass() && tok->variable()->type() &&
                   (tok->variable()->type()->needInitialization == Type::NeedInitialization::False) &&
                   tok->next()->str() == MatchCompiler::makeConstString(";")) {
            variables.write(tok->varId(), tok);
        }
    }
}

void CheckUnusedVar::checkFunctionVariableUsage()
{
    if (!mSettings->severity.isEnabled(Severity::style))
        return;

    // Parse all executing scopes..
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();

    // only check functions
    for (const Scope * scope : symbolDatabase->functionScopes) {
        // Bailout when there are lambdas or inline functions
        // TODO: Handle lambdas and inline functions properly
        if (scope->hasInlineOrLambdaFunction())
            continue;

        for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
            if (findLambdaEndToken(tok))
                // todo: handle lambdas
                break;
            if (match61(tok))
                // todo: check try blocks
                tok = tok->linkAt(1);
            const Token *varDecl = nullptr;
            if (tok->variable() && tok->variable()->nameToken() == tok) {
                const Token * eq = tok->next();
                while (match62(eq))
                    eq = eq->link()->next();
                if (match40(eq)) {
                    varDecl = tok;
                    tok = eq;
                }
            }
            // not assignment/initialization/increment => continue
            const bool isAssignment = tok->isAssignmentOp() && tok->astOperand1();
            const bool isInitialization = (match63(tok) && tok->variable() && tok->variable()->nameToken() == tok);
            const bool isIncrementOrDecrement = (tok->tokType() == Token::Type::eIncDecOp);
            if (!isAssignment && !isInitialization && !isIncrementOrDecrement)
                continue;

            if (isInitialization && match64(tok)) // don't warn for trivial initialization
                continue;

            if (isIncrementOrDecrement && tok->astParent() && precedes(tok, tok->astOperand1()))
                continue;

            if (tok->str() == MatchCompiler::makeConstString("=") && isRaiiClass(tok->valueType(), mTokenizer->isCPP(), false))
                continue;

            if (tok->isName()) {
                if (isRaiiClass(tok->valueType(), mTokenizer->isCPP(), false))
                    continue;
                tok = tok->next();
            }
            if (tok->astParent() && tok->str() != MatchCompiler::makeConstString("(")) {
                const Token *parent = tok->astParent();
                while (match65(parent))
                    parent = parent->astParent();
                if (!parent)
                    continue;
                if (!match66(parent->previous()))
                    continue;
            }
            // Do not warn about assignment with NULL
            if (isNullOperand(tok->astOperand2()))
                continue;

            if (!tok->astOperand1())
                continue;

            const Token *iteratorToken = tok->astOperand1();
            while (match67(iteratorToken))
                iteratorToken = iteratorToken->astOperand1();
            if (iteratorToken && iteratorToken->variable() && iteratorToken->variable()->typeEndToken()->str().find("iterator") != std::string::npos)
                continue;

            const Token *op1tok = tok->astOperand1();
            while (match68(op1tok))
                op1tok = op1tok->astOperand1();

            const Variable *op1Var = op1tok ? op1tok->variable() : nullptr;
            if (!op1Var && match69(tok) && tok->previous() && tok->previous()->variable())
                op1Var = tok->previous()->variable();
            std::string bailoutTypeName;
            if (op1Var) {
                if (op1Var->isReference() && op1Var->nameToken() != tok->astOperand1())
                    // todo: check references
                    continue;

                if (op1Var->isStatic())
                    // todo: check static variables
                    continue;

                if (op1Var->nameToken()->isAttributeUnused())
                    continue;

                // Avoid FP for union..
                if (op1Var->type() && op1Var->type()->isUnionType())
                    continue;

                // Bailout for unknown template classes, we have no idea what side effects such assignments have
                if (mTokenizer->isCPP() &&
                    op1Var->isClass() &&
                    (!op1Var->valueType() || op1Var->valueType()->type == ValueType::Type::UNKNOWN_TYPE)) {
                    // Check in the library if we should bailout or not..
                    const std::string typeName = op1Var->getTypeName();
                    switch (mSettings->library.getTypeCheck("unusedvar", typeName)) {
                    case Library::TypeCheck::def:
                        bailoutTypeName = typeName;
                        break;
                    case Library::TypeCheck::check:
                        break;
                    case Library::TypeCheck::suppress:
                        continue;
                    }
                }
            }

            // Is there a redundant assignment?
            const Token *start = tok->findExpressionStartEndTokens().second->next();

            const Token *expr = varDecl ? varDecl : tok->astOperand1();

            if (isInitialization)
                expr = tok->previous();

            // Is variable in lhs a union member?
            if (tok->previous() && tok->previous()->variable() && tok->previous()->variable()->nameToken()->scope()->type == Scope::eUnion)
                continue;

            FwdAnalysis fwdAnalysis(mTokenizer->isCPP(), mSettings->library);
            if (fwdAnalysis.unusedValue(expr, start, scope->bodyEnd)) {
                if (!bailoutTypeName.empty() && bailoutTypeName != MatchCompiler::makeConstString("auto")) {
                    if (mSettings->checkLibrary && mSettings->severity.isEnabled(Severity::information)) {
                        reportError(tok,
                                    Severity::information,
                                    "checkLibraryCheckType",
                                    "--check-library: Provide <type-checks><unusedvar> configuration for " + bailoutTypeName);
                    }
                    continue;
                }

                // warn
                if (!expr->variable() || !expr->variable()->isMaybeUnused())
                    unreadVariableError(tok, expr->expressionString(), false);
            }
        }

        // varId, usage {read, write, modified}
        Variables variables;

        checkFunctionVariableUsage_iterateScopes(scope, variables);


        // Check usage of all variables in the current scope..
        for (std::map<nonneg int, Variables::VariableUsage>::const_iterator it = variables.varUsage().begin();
             it != variables.varUsage().end();
             ++it) {
            const Variables::VariableUsage &usage = it->second;

            // variable has been marked as unused so ignore it
            if (usage._var->nameToken()->isAttributeUnused() || usage._var->nameToken()->isAttributeUsed())
                continue;

            // skip things that are only partially implemented to prevent false positives
            if (usage.mType == Variables::pointerPointer ||
                usage.mType == Variables::pointerArray ||
                usage.mType == Variables::referenceArray)
                continue;

            const std::string &varname = usage._var->name();
            const Variable* var = symbolDatabase->getVariableFromVarId(it->first);

            // variable has had memory allocated for it, but hasn't done
            // anything with that memory other than, perhaps, freeing it
            if (usage.unused() && !usage._modified && usage._allocateMemory)
                allocatedButUnusedVariableError(usage._lastAccess, varname);

            // variable has not been written, read, or modified
            else if (usage.unused() && !usage._modified) {
                if (!usage._var->isMaybeUnused()) {
                    unusedVariableError(usage._var->nameToken(), varname);
                }
            }
            // variable has not been written but has been modified
            else if (usage._modified && !usage._write && !usage._allocateMemory && var && !var->isStlType())
                unassignedVariableError(usage._var->nameToken(), varname);

            // variable has been read but not written
            else if (!usage._write && !usage._allocateMemory && var && !var->isStlType() && !isEmptyType(var->type()))
                unassignedVariableError(usage._var->nameToken(), varname);
        }
    }
}

void CheckUnusedVar::unusedVariableError(const Token *tok, const std::string &varname)
{
    reportError(tok, Severity::style, "unusedVariable", "$symbol:" + varname + "\nUnused variable: $symbol", CWE563, Certainty::normal);
}

void CheckUnusedVar::allocatedButUnusedVariableError(const Token *tok, const std::string &varname)
{
    reportError(tok, Severity::style, "unusedAllocatedMemory", "$symbol:" + varname + "\nVariable '$symbol' is allocated memory that is never used.", CWE563, Certainty::normal);
}

void CheckUnusedVar::unreadVariableError(const Token *tok, const std::string &varname, bool modified)
{
    if (modified)
        reportError(tok, Severity::style, "unreadVariable", "$symbol:" + varname + "\nVariable '$symbol' is modified but its new value is never used.", CWE563, Certainty::normal);
    else
        reportError(tok, Severity::style, "unreadVariable", "$symbol:" + varname + "\nVariable '$symbol' is assigned a value that is never used.", CWE563, Certainty::normal);
}

void CheckUnusedVar::unassignedVariableError(const Token *tok, const std::string &varname)
{
    reportError(tok, Severity::style, "unassignedVariable", "$symbol:" + varname + "\nVariable '$symbol' is not assigned a value.", CWE665, Certainty::normal);
}

//---------------------------------------------------------------------------
// Check that all struct members are used
//---------------------------------------------------------------------------
void CheckUnusedVar::checkStructMemberUsage()
{
    if (!mSettings->severity.isEnabled(Severity::style))
        return;

    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();

    for (const Scope &scope : symbolDatabase->scopeList) {
        if (scope.type != Scope::eStruct && scope.type != Scope::eUnion)
            continue;

        if (scope.bodyStart->fileIndex() != 0 || scope.className.empty())
            continue;

        // Packed struct => possibly used by lowlevel code. Struct members might be required by hardware.
        if (scope.bodyEnd->isAttributePacked())
            continue;
        if (const Preprocessor *preprocessor = mTokenizer->getPreprocessor()) {
            bool isPacked = false;
            for (const Directive &d: preprocessor->getDirectives()) {
                if (d.str == MatchCompiler::makeConstString("#pragma pack(1)") && d.file == mTokenizer->list.getFiles().front() && d.linenr < scope.bodyStart->linenr()) {
                    isPacked=true;
                    break;
                }
            }
            if (isPacked)
                continue;
        }

        // Bail out if struct/union contains any functions
        if (!scope.functionList.empty())
            continue;

        // Bail out for template struct, members might be used in non-matching instantiations
        if (scope.className.find("<") != std::string::npos)
            continue;

        // bail out if struct is inherited
        bool bailout = false;
        for (const Scope &derivedScope : symbolDatabase->scopeList) {
            if (derivedScope.definedType) {
                for (const Type::BaseInfo &derivedFrom : derivedScope.definedType->derivedFrom) {
                    if (derivedFrom.type == scope.definedType) {
                        bailout = true;
                        break;
                    }
                }
            }
        }
        if (bailout)
            continue;

        // bail out for extern/global struct
        for (const Variable* var : symbolDatabase->variableList()) {
            if (var && (var->isExtern() || (var->isGlobal() && !var->isStatic())) && var->typeEndToken()->str() == scope.className) {
                bailout = true;
                break;
            }
            if (var && (var->typeStartToken()->str() == scope.className || var->typeEndToken()->str() == scope.className)) {
                const std::string addressPattern("!!" + scope.className + " & " + var->name()); // cast from struct
                const Token* addrTok = scope.bodyEnd;
                do {
                    addrTok = Token::findmatch(addrTok, addressPattern.c_str());
                    if ((addrTok && addrTok->str() == MatchCompiler::makeConstString(")") && addrTok->link()->isCast()) || isCPPCast(addrTok)) {
                        bailout = true;
                        break;
                    }
                    if (addrTok)
                        addrTok = addrTok->next();
                } while (addrTok);
            }
        }
        if (bailout)
            continue;

        // Bail out if some data is casted to struct..
        const std::string castPattern("( struct| " + scope.className + " * ) & %name% [");
        if (Token::findmatch(scope.bodyEnd, castPattern.c_str()))
            continue;

        // (struct S){..}
        const std::string initPattern("( struct| " + scope.className + " ) {");
        if (Token::findmatch(scope.bodyEnd, initPattern.c_str()))
            continue;

        // Bail out if struct is used in sizeof..
        for (const Token *tok = scope.bodyEnd; nullptr != (tok = findmatch70(tok) );) {
            tok = tok->tokAt(2);
            if (Token::Match(tok, ("struct| " + scope.className).c_str())) {
                bailout = true;
                break;
            }
        }
        if (bailout)
            continue;

        // Try to prevent false positives when struct members are not used directly.
        if (Token::findmatch(scope.bodyEnd, (scope.className + " %type%| *").c_str()))
            continue;

        for (const Variable &var : scope.varlist) {
            // declaring a POD member variable?
            if (!var.typeStartToken()->isStandardType() && !var.isPointer())
                continue;

            // Check if the struct member variable is used anywhere in the file
            bool use = false;
            for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
                if (tok->variable() != &var)
                    continue;
                if (tok != var.nameToken()) {
                    use = true;
                    break;
                }
            }
            if (!use)
                unusedStructMemberError(var.nameToken(), scope.className, var.name(), scope.type == Scope::eUnion);
        }
    }
}

void CheckUnusedVar::unusedStructMemberError(const Token *tok, const std::string &structname, const std::string &varname, bool isUnion)
{
    const std::string prefix = isUnion ? "union member " : "struct member ";
    reportError(tok, Severity::style, "unusedStructMember", "$symbol:" + structname + "::" + varname + '\n' + prefix + "'$symbol' is never used.", CWE563, Certainty::normal);
}

bool CheckUnusedVar::isRecordTypeWithoutSideEffects(const Type* type)
{
    // a type that has no side effects (no constructors and no members with constructors)
    /** @todo false negative: check constructors for side effects */
    const std::pair<std::map<const Type *,bool>::iterator,bool> found=mIsRecordTypeWithoutSideEffectsMap.insert(
        std::pair<const Type *,bool>(type,false));         //Initialize with side effects for possible recursions
    bool & withoutSideEffects = found.first->second;
    if (!found.second)
        return withoutSideEffects;

    // unknown types are assumed to have side effects
    if (!type || !type->classScope)
        return (withoutSideEffects = false);

    // Non-empty constructors => possible side effects
    for (const Function& f : type->classScope->functionList) {
        if (!f.isConstructor())
            continue;
        if (f.argDef && match42(f.argDef->link()))
            continue; // ignore default/deleted constructors
        const bool emptyBody = (f.functionScope && match71(f.functionScope->bodyStart));

        Token* nextToken = f.argDef->link();
        if (match72(nextToken)) {
            // validating initialization list
            nextToken = nextToken->next(); // goto ":"

            for (const Token *initListToken = nextToken; match73(initListToken); initListToken = initListToken->linkAt(2)->next()) {
                const Token* varToken = initListToken->next();
                const Variable* variable = varToken->variable();
                if (variable && !isVariableWithoutSideEffects(*variable)) {
                    return withoutSideEffects = false;
                }

                const Token* valueEnd = initListToken->linkAt(2);
                for (const Token* valueToken = initListToken->tokAt(3); valueToken != valueEnd; valueToken = valueToken->next()) {
                    const Variable* initValueVar = valueToken->variable();
                    if (initValueVar && !isVariableWithoutSideEffects(*initValueVar)) {
                        return withoutSideEffects = false;
                    }
                    if ((valueToken->tokType() == Token::Type::eName) ||
                        (valueToken->tokType() == Token::Type::eLambda) ||
                        (valueToken->tokType() == Token::Type::eOther)) {
                        return withoutSideEffects = false;
                    }
                    const Function* initValueFunc = valueToken->function();
                    if (initValueFunc && !isFunctionWithoutSideEffects(*initValueFunc, valueToken,
                                                                       std::list<const Function*> {})) {
                        return withoutSideEffects = false;
                    }
                }
            }
        }

        if (!emptyBody)
            return (withoutSideEffects = false);
    }

    // Derived from type that has side effects?
    for (const Type::BaseInfo& derivedFrom : type->derivedFrom) {
        if (!isRecordTypeWithoutSideEffects(derivedFrom.type))
            return (withoutSideEffects = false);
    }

    // Is there a member variable with possible side effects
    for (const Variable& var : type->classScope->varlist) {
        withoutSideEffects = isVariableWithoutSideEffects(var);
        if (!withoutSideEffects) {
            return withoutSideEffects;
        }
    }


    return (withoutSideEffects = true);
}

bool CheckUnusedVar::isVariableWithoutSideEffects(const Variable& var)
{
    if (var.isPointer())
        return true;

    const Type* variableType = var.type();
    if (variableType) {
        if (!isRecordTypeWithoutSideEffects(variableType))
            return false;
    } else {
        if (WRONG_DATA(!var.valueType(), var.typeStartToken()))
            return false;
        ValueType::Type valueType = var.valueType()->type;
        if ((valueType == ValueType::Type::UNKNOWN_TYPE) || (valueType == ValueType::Type::NONSTD))
            return false;
    }

    return true;
}

bool CheckUnusedVar::isEmptyType(const Type* type)
{
    // a type that has no variables and no constructor

    const std::pair<std::map<const Type *,bool>::iterator,bool> found=mIsEmptyTypeMap.insert(
        std::pair<const Type *,bool>(type,false));
    bool & emptyType=found.first->second;
    if (!found.second)
        return emptyType;

    if (type && type->classScope && type->classScope->numConstructors == 0 &&
        (type->classScope->varlist.empty())) {
        for (std::vector<Type::BaseInfo>::const_iterator i = type->derivedFrom.begin(); i != type->derivedFrom.end(); ++i) {
            if (!isEmptyType(i->type)) {
                emptyType=false;
                return emptyType;
            }
        }
        emptyType=true;
        return emptyType;
    }

    emptyType=false;   // unknown types are assumed to be nonempty
    return emptyType;
}

bool CheckUnusedVar::isFunctionWithoutSideEffects(const Function& func, const Token* functionUsageToken,
                                                  std::list<const Function*> checkedFuncs)
{
    // no body to analyze
    if (!func.hasBody()) {
        return false;
    }

    for (const Token* argsToken = functionUsageToken->next(); !match74(argsToken); argsToken = argsToken->next()) {
        const Variable* argVar = argsToken->variable();
        if (argVar && argVar->isGlobal()) {
            return false; // TODO: analyze global variable usage
        }
    }

    bool sideEffectReturnFound = false;
    std::set<const Variable*> pointersToGlobals;
    for (Token* bodyToken = func.functionScope->bodyStart->next(); bodyToken != func.functionScope->bodyEnd;
         bodyToken = bodyToken->next()) {
        // check variable inside function body
        const Variable* bodyVariable = bodyToken->variable();
        if (bodyVariable) {
            if (!isVariableWithoutSideEffects(*bodyVariable)) {
                return false;
            }
            // check if global variable is changed
            if (bodyVariable->isGlobal() || (pointersToGlobals.find(bodyVariable) != pointersToGlobals.end())) {
                const int depth = 20;
                if (isVariableChanged(bodyToken, depth, mSettings, mTokenizer->isCPP())) {
                    return false;
                }
                // check if pointer to global variable assigned to another variable (another_var = &global_var)
                if (match75(bodyToken->tokAt(-1)) && match40(bodyToken->tokAt(-2))) {
                    const Token* assigned_var_token = bodyToken->tokAt(-3);
                    if (assigned_var_token && assigned_var_token->variable()) {
                        pointersToGlobals.insert(assigned_var_token->variable());
                    }
                }
            }
        }

        // check nested function
        const Function* bodyFunction = bodyToken->function();
        if (bodyFunction) {
            if (std::find(checkedFuncs.begin(), checkedFuncs.end(), bodyFunction) != checkedFuncs.end()) { // recursion found
                continue;
            }
            checkedFuncs.push_back(bodyFunction);
            if (!isFunctionWithoutSideEffects(*bodyFunction, bodyToken, checkedFuncs)) {
                return false;
            }
        }

        // check returned value
        if (match76(bodyToken)) {
            const Token* returnValueToken = bodyToken->next();
            // TODO: handle complex return expressions
            if (!match77(returnValueToken->next())) {
                sideEffectReturnFound = true;
                continue;
            }
            // simple one-token return
            const Variable* returnVariable = returnValueToken->variable();
            if (returnValueToken->isLiteral() ||
                (returnVariable && isVariableWithoutSideEffects(*returnVariable))) {
                continue;
            }
            sideEffectReturnFound = true;
        }

        // unknown name
        if (bodyToken->isNameOnly()) {
            return false;
        }
    }

    return !sideEffectReturnFound;
}
