/*
 * Cppcheck - A tool for static C/C++ code analysis
 * Copyright (C) 2007-2011 Daniel Marjamäki and 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 "checkother.h"
#include "mathlib.h"
#include "symboldatabase.h"

#include <cctype> // std::isupper
#include <cmath> // fabs()
//---------------------------------------------------------------------------

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

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


void CheckOther::clarifyCalculation()
{
    if (!_settings->_checkCodingStyle)
        return;
    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        if (tok->str() == "?")
        {
            // condition
            const Token *cond = tok->previous();
            if (cond->isName() || cond->isNumber())
                cond = cond->previous();
            else if (cond->str() == ")")
                cond = cond->link()->previous();
            else
                continue;

            // multiplication
            if (cond->str() == "*")
                cond = cond->previous();
            else
                continue;

            // skip previous multiplications..
            while (cond && cond->strAt(-1) == "*" && (cond->isName() || cond->isNumber()))
                cond = cond->tokAt(-2);

            if (!cond)
                continue;

            // first multiplication operand
            if (cond->str() == ")")
            {
                clarifyCalculationError(cond);
            }
            else if (cond->isName() || cond->isNumber())
            {
                if (Token::Match(cond->previous(),"return|+|-|,|("))
                    clarifyCalculationError(cond);
            }
        }
    }
}

void CheckOther::clarifyCalculationError(const Token *tok)
{
    reportError(tok,
                Severity::information,
                "clarifyCalculation",
                "Please clarify precedence: 'a*b?..'\n"
                "Found a suspicious multiplication of condition. Please use parantheses to clarify the code. "
                "The code 'a*b?1:2' should be written as either '(a*b)?1:2' or 'a*(b?1:2)'.");
}


void CheckOther::warningOldStylePointerCast()
{
    if (!_settings->_checkCodingStyle ||
        (_tokenizer->tokens() && _tokenizer->fileLine(_tokenizer->tokens()).find(".cpp") == std::string::npos))
        return;

    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        // Old style pointer casting..
        if (!Token::Match(tok, "( const| %type% * ) %var%") &&
            !Token::Match(tok, "( const| %type% * ) (| new"))
            continue;

        int addToIndex = 0;
        if (tok->tokAt(1)->str() == "const")
            addToIndex = 1;

        if (tok->tokAt(4 + addToIndex)->str() == "const")
            continue;

        // Is "type" a class?
        const std::string pattern("class " + tok->tokAt(1 + addToIndex)->str());
        if (!Token::findmatch(_tokenizer->tokens(), pattern.c_str()))
            continue;

        cstyleCastError(tok);
    }
}

//---------------------------------------------------------------------------
// fflush(stdin) <- fflush only applies to output streams in ANSI C
//---------------------------------------------------------------------------
void CheckOther::checkFflushOnInputStream()
{
    const Token *tok = _tokenizer->tokens();
    while (tok && ((tok = Token::findmatch(tok, "fflush ( stdin )")) != NULL))
    {
        fflushOnInputStreamError(tok, tok->strAt(2));
        tok = tok->tokAt(4);
    }
}


void CheckOther::checkSizeofForArrayParameter()
{
    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        if (Token::Match(tok, "sizeof ( %var% )") || Token::Match(tok, "sizeof %var% "))
        {
            int tokIdx = 1;
            if (tok->tokAt(tokIdx)->str() == "(")
            {
                ++tokIdx;
            }
            if (tok->tokAt(tokIdx)->varId() > 0)
            {
                const Token *declTok = Token::findmatch(_tokenizer->tokens(), "%varid%", tok->tokAt(tokIdx)->varId());
                if (declTok)
                {
                    if (Token::simpleMatch(declTok->next(), "["))
                    {
                        declTok = declTok->next()->link();
                        // multidimensional array
                        while (Token::simpleMatch(declTok->next(), "["))
                        {
                            declTok = declTok->next()->link();
                        }
                        if (!(Token::Match(declTok->next(), "= %str%")) && !(Token::simpleMatch(declTok->next(), "= {")) && !(Token::simpleMatch(declTok->next(), ";")))
                        {
                            if (Token::simpleMatch(declTok->next(), ","))
                            {
                                declTok = declTok->next();
                                while (!Token::simpleMatch(declTok, ";"))
                                {
                                    if (Token::simpleMatch(declTok, ")"))
                                    {
                                        sizeofForArrayParameterError(tok);
                                        break;
                                    }
                                    if (Token::Match(declTok, "(|[|{"))
                                    {
                                        declTok = declTok->link();
                                    }
                                    declTok = declTok->next();
                                }
                            }
                        }
                        if (Token::simpleMatch(declTok->next(), ")"))
                        {
                            sizeofForArrayParameterError(tok);
                        }
                    }
                }
            }
        }
    }
}



//---------------------------------------------------------------------------
//    switch (x)
//    {
//        case 2:
//            y = a;        // <- this assignment is redundant
//        case 3:
//            y = b;        // <- case 2 falls through and sets y twice
//    }
//---------------------------------------------------------------------------
void CheckOther::checkRedundantAssignmentInSwitch()
{
    const char switchPattern[] = "switch ( %any% ) { case";
    const char breakPattern[] = "break|continue|return|exit|goto";
    const char functionPattern[] = "%var% (";

    // Find the beginning of a switch. E.g.:
    //   switch (var) { ...
    const Token *tok = Token::findmatch(_tokenizer->tokens(), switchPattern);
    while (tok)
    {

        // Check the contents of the switch statement
        std::map<unsigned int, const Token*> varsAssigned;
        int indentLevel = 0;
        for (const Token *tok2 = tok->tokAt(5); tok2; tok2 = tok2->next())
        {
            if (tok2->str() == "{")
            {
                // Inside a conditional or loop. Don't mark variable accesses as being redundant. E.g.:
                //   case 3: b = 1;
                //   case 4: if (a) { b = 2; }    // Doesn't make the b=1 redundant because it's conditional
                if (Token::Match(tok2->previous(), ")|else {") && tok2->link())
                {
                    const Token* endOfConditional = tok2->link();
                    for (const Token* tok3 = tok2; tok3 != endOfConditional; tok3 = tok3->next())
                    {
                        if (tok3->varId() != 0)
                            varsAssigned.erase(tok3->varId());
                        else if (Token::Match(tok3, functionPattern) || Token::Match(tok3, breakPattern))
                            varsAssigned.clear();
                    }
                    tok2 = endOfConditional;
                }
                else
                    ++ indentLevel;
            }
            else if (tok2->str() == "}")
            {
                -- indentLevel;

                // End of the switch block
                if (indentLevel < 0)
                    break;
            }

            // Variable assignment. Report an error if it's assigned to twice before a break. E.g.:
            //    case 3: b = 1;    // <== redundant
            //    case 4: b = 2;
            if (Token::Match(tok2->previous(), ";|{|}|: %var% = %any% ;") && tok2->varId() != 0)
            {
                std::map<unsigned int, const Token*>::iterator i = varsAssigned.find(tok2->varId());
                if (i == varsAssigned.end())
                    varsAssigned[tok2->varId()] = tok2;
                else
                    redundantAssignmentInSwitchError(i->second, i->second->str());
            }
            // Not a simple assignment so there may be good reason if this variable is assigned to twice. E.g.:
            //    case 3: b = 1;
            //    case 4: b++;
            else if (tok2->varId() != 0)
                varsAssigned.erase(tok2->varId());

            // Reset our record of assignments if there is a break or function call. E.g.:
            //    case 3: b = 1; break;
            if (Token::Match(tok2, functionPattern) || Token::Match(tok2, breakPattern))
                varsAssigned.clear();

        }

        tok = Token::findmatch(tok->next(), switchPattern);
    }
}


//---------------------------------------------------------------------------
//    int x = 1;
//    x = x;            // <- redundant assignment to self
//
//    int y = y;        // <- redundant initialization to self
//---------------------------------------------------------------------------
void CheckOther::checkSelfAssignment()
{
    if (!_settings->_checkCodingStyle)
        return;

    const char selfAssignmentPattern[] = "%var% = %var% ;|=|)";
    const Token *tok = Token::findmatch(_tokenizer->tokens(), selfAssignmentPattern);
    while (tok)
    {
        if (tok->varId() && tok->varId() == tok->tokAt(2)->varId())
        {
            selfAssignmentError(tok, tok->str());
        }

        tok = Token::findmatch(tok->next(), selfAssignmentPattern);
    }
}

//---------------------------------------------------------------------------
//    int a = 1;
//    assert(a = 2);            // <- assert should not have a side-effect
//---------------------------------------------------------------------------
void CheckOther::checkAssignmentInAssert()
{
    if (!_settings->_checkCodingStyle)
        return;

    const char assertPattern[] = "assert ( %any%";
    const Token *tok = Token::findmatch(_tokenizer->tokens(), assertPattern);
    const Token *endTok = tok ? tok->next()->link() : NULL;

    while (tok && endTok)
    {
        const Token* varTok = Token::findmatch(tok->tokAt(2), "%var% --|++|+=|-=|*=|/=|&=|^=|=", endTok);
        if (varTok)
        {
            assignmentInAssertError(tok, varTok->str());
        }
        else if (NULL != (varTok = Token::findmatch(tok->tokAt(2), "--|++ %var%", endTok)))
        {
            assignmentInAssertError(tok, varTok->strAt(1));
        }

        tok = Token::findmatch(endTok->next(), assertPattern);
        endTok = tok ? tok->next()->link() : NULL;
    }
}

//---------------------------------------------------------------------------
//    if ((x != 1) || (x != 3))            // <- always true
//---------------------------------------------------------------------------
void CheckOther::checkIncorrectLogicOperator()
{
    if (!_settings->_checkCodingStyle)
        return;

    const char conditionPattern[] = "if|while (";
    const Token *tok = Token::findmatch(_tokenizer->tokens(), conditionPattern);
    const Token *endTok = tok ? tok->next()->link() : NULL;

    while (tok && endTok)
    {
        // Find a pair of OR'd terms, with or without parenthesis
        // e.g. if (x != 3 || x != 4)
        const Token *logicTok = NULL, *term1Tok = NULL, *term2Tok = NULL;
        if (NULL != (logicTok = Token::findmatch(tok, "( %any% != %any% ) %oror% ( %any% != %any% ) !!&&", endTok)))
        {
            term1Tok = logicTok->next();
            term2Tok = logicTok->tokAt(7);
        }
        else if (NULL != (logicTok = Token::findmatch(tok, "%any% != %any% %oror% %any% != %any% !!&&", endTok)))
        {
            term1Tok = logicTok;
            term2Tok = logicTok->tokAt(4);
        }

        // The terms must not be AND'd with anything, to prevent false positives
        if (logicTok && (logicTok->strAt(-1) != "&&"))
        {
            // Find the common variable and the two different-valued constants
            unsigned int variableTested = 0;
            std::string firstConstant, secondConstant;
            if (Token::Match(term1Tok, "%var% != %num%"))
            {
                const unsigned int varId = term1Tok->varId();
                if (!varId)
                {
                    tok = Token::findmatch(endTok->next(), conditionPattern);
                    endTok = tok ? tok->next()->link() : NULL;
                    continue;
                }
                firstConstant = term1Tok->tokAt(2)->str();

                if (Token::Match(term2Tok, "%varid% != %num%", varId))
                {
                    variableTested = varId;
                    secondConstant = term2Tok->tokAt(2)->str();
                }
                else if (Token::Match(term2Tok, "%num% != %varid%", varId))
                {
                    variableTested = varId;
                    secondConstant = term2Tok->str();
                }
            }
            else if (Token::Match(term1Tok, "%num% != %var%"))
            {
                const unsigned int varId = term1Tok->tokAt(2)->varId();
                firstConstant = term1Tok->str();

                if (Token::Match(term2Tok, "%varid% != %num%", varId))
                {
                    variableTested = varId;
                    secondConstant = term2Tok->tokAt(2)->str();
                }
                else if (Token::Match(term2Tok, "%num% != %varid%", varId))
                {
                    variableTested = varId;
                    secondConstant = term2Tok->str();
                }
            }

            // If there is a common variable tested for inequality against
            // either of two different-valued constants, then the expression
            // will always evaluate to true and the || probably should be an &&
            if (variableTested != 0 &&
                !firstConstant.empty() &&
                !secondConstant.empty() &&
                firstConstant != secondConstant)
            {
                incorrectLogicOperatorError(term1Tok);
            }
        }

        tok = Token::findmatch(endTok->next(), conditionPattern);
        endTok = tok ? tok->next()->link() : NULL;
    }
}

//---------------------------------------------------------------------------
//    try {} catch (std::exception err) {} <- Should be "std::exception& err"
//---------------------------------------------------------------------------
void CheckOther::checkCatchExceptionByValue()
{
    if (!_settings->_checkCodingStyle)
        return;

    const char catchPattern[] = "} catch (";
    const Token *tok = Token::findmatch(_tokenizer->tokens(), catchPattern);
    const Token *endTok = tok ? tok->tokAt(2)->link() : NULL;

    while (tok && endTok)
    {
        // Find a pass-by-value declaration in the catch(), excluding basic types
        // e.g. catch (std::exception err)
        const Token *tokType = Token::findmatch(tok, "%type% %var% )", endTok);
        if (tokType && !tokType->isStandardType())
        {
            catchExceptionByValueError(tokType);
        }

        tok = Token::findmatch(endTok->next(), catchPattern);
        endTok = tok ? tok->tokAt(2)->link() : NULL;
    }
}

//---------------------------------------------------------------------------
// strtol(str, 0, radix)  <- radix must be 0 or 2-36
//---------------------------------------------------------------------------

void CheckOther::invalidFunctionUsage()
{
    // strtol and strtoul..
    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        if (!Token::Match(tok, "strtol|strtoul ("))
            continue;

        // Locate the third parameter of the function call..
        int param = 1;
        for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next())
        {
            if (tok2->str() == "(")
                tok2 = tok2->link();
            else if (tok2->str() == ")")
                break;
            else if (tok2->str() == ",")
            {
                ++param;
                if (param == 3)
                {
                    if (Token::Match(tok2, ", %num% )"))
                    {
                        const MathLib::bigint radix = MathLib::toLongNumber(tok2->next()->str());
                        if (!(radix == 0 || (radix >= 2 && radix <= 36)))
                        {
                            dangerousUsageStrtolError(tok2);
                        }
                    }
                    break;
                }
            }
        }
    }

    // sprintf|snprintf overlapping data
    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        // Get variable id of target buffer..
        unsigned int varid = 0;

        if (Token::Match(tok, "sprintf|snprintf ( %var% ,"))
            varid = tok->tokAt(2)->varId();

        else if (Token::Match(tok, "sprintf|snprintf ( %var% . %var% ,"))
            varid = tok->tokAt(4)->varId();

        if (varid == 0)
            continue;

        // goto ","
        const Token *tok2 = tok->tokAt(3);
        while (tok2 && tok2->str() != ",")
            tok2 = tok2->next();

        // is any source buffer overlapping the target buffer?
        int parlevel = 0;
        while ((tok2 = tok2->next()) != NULL)
        {
            if (tok2->str() == "(")
                ++parlevel;
            else if (tok2->str() == ")")
            {
                --parlevel;
                if (parlevel < 0)
                    break;
            }
            else if (parlevel == 0 && Token::Match(tok2, ", %varid% [,)]", varid))
            {
                sprintfOverlappingDataError(tok2->next(), tok2->next()->str());
                break;
            }
        }
    }
}
//---------------------------------------------------------------------------

void CheckOther::invalidScanf()
{
    if (!_settings->_checkCodingStyle)
        return;
    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        const Token *formatToken = 0;
        if (Token::Match(tok, "scanf|vscanf ( %str% ,"))
            formatToken = tok->tokAt(2);
        else if (Token::Match(tok, "fscanf|vfscanf ( %var% , %str% ,"))
            formatToken = tok->tokAt(4);
        else
            continue;

        bool format = false;

        // scan the string backwards, so we dont need to keep states
        const std::string &formatstr(formatToken->str());
        for (unsigned int i = 1; i < formatstr.length(); i++)
        {
            if (formatstr[i] == '%')
                format = !format;

            else if (!format)
                continue;

            else if (std::isdigit(formatstr[i]))
            {
                format = false;
            }

            else if (std::isalpha(formatstr[i]))
            {
                invalidScanfError(tok);
                format = false;
            }
        }
    }
}

void CheckOther::sizeofForArrayParameterError(const Token *tok)
{
    reportError(tok, Severity::error,
                "sizeofwithsilentarraypointer", "Using sizeof for array given as function argument "
                "returns the size of pointer.\n"
                "Giving array as function parameter and then using sizeof-operator for the array "
                "argument. In this case the sizeof-operator returns the size of pointer (in the "
                "system). It does not return the size of the whole array in bytes as might be "
                "expected. For example, this code:\n"
                "     int f(char a[100]) {\n"
                "         return sizeof(a);\n"
                "     }\n"
                " returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 100 (the "
                "size of the array in bytes)."
               );
}
void CheckOther::invalidScanfError(const Token *tok)
{
    reportError(tok, Severity::warning,
                "invalidscanf", "scanf without field width limits can crash with huge input data\n"
                "scanf without field width limits can crash with huge input data. To fix this error "
                "message add a field width specifier:\n"
                "    %s => %20s\n"
                "    %i => %3i\n"
                "\n"
                "Sample program that can crash:\n"
                "\n"
                "#include <stdio.h>\n"
                "int main()\n"
                "{\n"
                "    int a;\n"
                "    scanf(\"%i\", &a);\n"
                "    return 0;\n"
                "}\n"
                "\n"
                "To make it crash:\n"
                "perl -e 'print \"5\"x2100000' | ./a.out");
}

//---------------------------------------------------------------------------
// Check for unsigned divisions
//---------------------------------------------------------------------------

void CheckOther::checkUnsignedDivision()
{
    if (!_settings->_checkCodingStyle)
        return;

    // Check for "ivar / uvar" and "uvar / ivar"
    std::map<unsigned int, char> varsign;
    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        if (Token::Match(tok, "[{};(,] %type% %var% [;=,)]"))
        {
            if (tok->tokAt(1)->isUnsigned())
                varsign[tok->tokAt(2)->varId()] = 'u';
            else
                varsign[tok->tokAt(2)->varId()] = 's';
        }

        else if (!Token::Match(tok, "[).]") && Token::Match(tok->next(), "%var% / %num%"))
        {
            if (tok->strAt(3)[0] == '-')
            {
                char sign1 = varsign[tok->tokAt(1)->varId()];
                if (sign1 == 'u')
                {
                    udivError(tok->next());
                }
            }
        }

        else if (Token::Match(tok, "[([=*/+-,] %num% / %var%"))
        {
            if (tok->strAt(1)[0] == '-')
            {
                char sign2 = varsign[tok->tokAt(3)->varId()];
                if (sign2 == 'u')
                {
                    udivError(tok->next());
                }
            }
        }
    }
}

//---------------------------------------------------------------------------
// memset(p, y, 0 /* bytes to fill */) <- 2nd and 3rd arguments inverted
//---------------------------------------------------------------------------
void CheckOther::checkMemsetZeroBytes()
{
    const Token *tok = _tokenizer->tokens();
    while (tok && ((tok = Token::findmatch(tok, "memset ( %var% , %num% , 0 )")) != NULL))
    {
        memsetZeroBytesError(tok, tok->strAt(2));
        tok = tok->tokAt(8);
    }
}
//---------------------------------------------------------------------------



//---------------------------------------------------------------------------
// Usage of function variables
//---------------------------------------------------------------------------

static bool isOp(const Token *tok)
{
    return bool(tok &&
                (tok->str() == "&&" ||
                 tok->str() == "||" ||
                 tok->str() == "==" ||
                 tok->str() == "!=" ||
                 tok->str() == "<" ||
                 tok->str() == "<=" ||
                 tok->str() == ">" ||
                 tok->str() == ">=" ||
                 tok->str() == "<<" ||
                 Token::Match(tok, "[+-*/%&!~|^,[])?:]")));
}

/**
 * @brief This class is used to capture the control flow within a function.
 */
class ScopeInfo
{
public:
    ScopeInfo() : _token(NULL), _parent(NULL) { }
    ScopeInfo(const Token *token, ScopeInfo *parent_) : _token(token), _parent(parent_) { }
    ~ScopeInfo();

    ScopeInfo *parent()
    {
        return _parent;
    }
    ScopeInfo *addChild(const Token *token);
    void remove(ScopeInfo *scope);

private:
    const Token *_token;
    ScopeInfo *_parent;
    std::list<ScopeInfo *> _children;
};

ScopeInfo::~ScopeInfo()
{
    while (!_children.empty())
    {
        delete *_children.begin();
        _children.pop_front();
    }
}

ScopeInfo *ScopeInfo::addChild(const Token *token)
{
    ScopeInfo *temp = new ScopeInfo(token, this);

    _children.push_back(temp);

    return temp;
}

void ScopeInfo::remove(ScopeInfo *scope)
{
    std::list<ScopeInfo *>::iterator it;

    for (it = _children.begin(); it != _children.end(); ++it)
    {
        if (*it == scope)
        {
            delete *it;
            _children.erase(it);
            break;
        }
    }
}

/**
 * @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 };

    /** Store information about variable usage */
    class VariableUsage
    {
    public:
        VariableUsage(const Token *name = 0,
                      VariableType type = standard,
                      ScopeInfo *scope = NULL,
                      bool read = false,
                      bool write = false,
                      bool modified = false,
                      bool allocateMemory = false) :
            _name(name),
            _type(type),
            _scope(scope),
            _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 == false && _write == false);
        }

        const Token *_name;
        VariableType _type;
        ScopeInfo *_scope;
        bool _read;
        bool _write;
        bool _modified; // read/modify/write
        bool _allocateMemory;
        std::set<unsigned int> _aliases;
        std::set<ScopeInfo *> _assignments;
    };

    typedef std::map<unsigned int, VariableUsage> VariableMap;

    void clear()
    {
        _varUsage.clear();
    }
    VariableMap &varUsage()
    {
        return _varUsage;
    }
    void addVar(const Token *name, VariableType type, ScopeInfo *scope, bool write_);
    void allocateMemory(unsigned int varid);
    void read(unsigned int varid);
    void readAliases(unsigned int varid);
    void readAll(unsigned int varid);
    void write(unsigned int varid);
    void writeAliases(unsigned int varid);
    void writeAll(unsigned int varid);
    void use(unsigned int varid);
    void modified(unsigned int varid);
    VariableUsage *find(unsigned int varid);
    void alias(unsigned int varid1, unsigned int varid2, bool replace);
    void erase(unsigned int varid)
    {
        _varUsage.erase(varid);
    }
    void eraseAliases(unsigned int varid);
    void eraseAll(unsigned int varid);
    void clearAliases(unsigned int varid);

private:
    VariableMap _varUsage;
};

/**
 * 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(unsigned int varid1, unsigned int varid2, bool replace)
{
    VariableUsage *var1 = find(varid1);
    VariableUsage *var2 = find(varid2);

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

    std::set<unsigned int>::iterator i;

    if (replace)
    {
        // remove var1 from all aliases
        for (i = var1->_aliases.begin(); i != var1->_aliases.end(); ++i)
        {
            VariableUsage *temp = find(*i);

            if (temp)
                temp->_aliases.erase(var1->_name->varId());
        }

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

    // var1 gets all var2s aliases
    for (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->_type == Variables::pointer)
        var2->_read = true;
}

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

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

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

            if (temp)
                temp->_aliases.erase(usage->_name->varId());
        }

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

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

    if (usage)
    {
        std::set<unsigned int>::iterator aliases;

        for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases)
            erase(*aliases);
    }
}

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

void Variables::addVar(const Token *name,
                       VariableType type,
                       ScopeInfo *scope,
                       bool write_)
{
    if (name->varId() > 0)
        _varUsage.insert(std::make_pair(name->varId(), VariableUsage(name, type, scope, false, write_, false)));
}

void Variables::allocateMemory(unsigned int varid)
{
    VariableUsage *usage = find(varid);

    if (usage)
        usage->_allocateMemory = true;
}

void Variables::read(unsigned int varid)
{
    VariableUsage *usage = find(varid);

    if (usage)
        usage->_read = true;
}

void Variables::readAliases(unsigned int varid)
{
    VariableUsage *usage = find(varid);

    if (usage)
    {
        std::set<unsigned int>::iterator aliases;

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

            if (aliased)
                aliased->_read = true;
        }
    }
}

void Variables::readAll(unsigned int varid)
{
    VariableUsage *usage = find(varid);

    if (usage)
    {
        usage->_read = true;

        std::set<unsigned int>::iterator aliases;

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

            if (aliased)
                aliased->_read = true;
        }
    }
}

void Variables::write(unsigned int varid)
{
    VariableUsage *usage = find(varid);

    if (usage)
        usage->_write = true;
}

void Variables::writeAliases(unsigned int varid)
{
    VariableUsage *usage = find(varid);

    if (usage)
    {
        std::set<unsigned int>::iterator aliases;

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

            if (aliased)
                aliased->_write = true;
        }
    }
}

void Variables::writeAll(unsigned int varid)
{
    VariableUsage *usage = find(varid);

    if (usage)
    {
        usage->_write = true;

        std::set<unsigned int>::iterator aliases;

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

            if (aliased)
                aliased->_write = true;
        }
    }
}

void Variables::use(unsigned int varid)
{
    VariableUsage *usage = find(varid);

    if (usage)
    {
        usage->use();

        std::set<unsigned int>::iterator aliases;

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

            if (aliased)
                aliased->use();
        }
    }
}

void Variables::modified(unsigned int varid)
{
    VariableUsage *usage = find(varid);

    if (usage)
    {
        usage->_modified = true;

        std::set<unsigned int>::iterator aliases;

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

            if (aliased)
                aliased->_modified = true;
        }
    }
}

Variables::VariableUsage *Variables::find(unsigned int varid)
{
    if (varid)
    {
        VariableMap::iterator i = _varUsage.find(varid);
        if (i != _varUsage.end())
            return &i->second;
    }
    return 0;
}

static int doAssignment(Variables &variables, const Token *tok, bool dereference, ScopeInfo *scope)
{
    int next = 0;

    // a = a + b;
    if (Token::Match(tok, "%var% = %var% !!;") && tok->str() == tok->strAt(2))
    {
        return 2;
    }

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

    if (var1)
    {
        Variables::VariableUsage *var2 = 0;
        int start = 1;

        // search for '='
        while (tok->tokAt(start)->str() != "=")
            start++;

        start++;

        if (Token::Match(tok->tokAt(start), "&| %var%") ||
            Token::Match(tok->tokAt(start), "( const| struct|union| %type% *| ) &| %var%") ||
            Token::Match(tok->tokAt(start), "( const| struct|union| %type% *| ) ( &| %var%") ||
            Token::Match(tok->tokAt(start), "%any% < const| struct|union| %type% *| > ( &| %var%"))
        {
            unsigned char offset = 0;
            unsigned int varid2;
            bool addressOf = false;

            if (Token::Match(tok->tokAt(start), "%var% ."))
                variables.use(tok->tokAt(start)->varId());   // use = read + write

            // check for C style cast
            if (tok->tokAt(start)->str() == "(")
            {
                if (tok->tokAt(start + 1)->str() == "const")
                    offset++;

                if (Token::Match(tok->tokAt(start + 1 + offset), "struct|union"))
                    offset++;

                if (tok->tokAt(start + 2 + offset)->str() == "*")
                    offset++;

                if (tok->tokAt(start + 3 + offset)->str() == "&")
                {
                    addressOf = true;
                    next = start + 4 + offset;
                }
                else if (tok->tokAt(start + 3 + offset)->str() == "(")
                {
                    if (tok->tokAt(start + 4 + offset)->str() == "&")
                    {
                        addressOf = true;
                        next = start + 5 + offset;
                    }
                    else
                        next = start + 4 + offset;
                }
                else
                    next = start + 3 + offset;
            }

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

                if (Token::Match(tok->tokAt(start + 2 + offset), "struct|union"))
                    offset++;

                if (tok->tokAt(start + 3 + offset)->str() == "*")
                    offset++;

                if (tok->tokAt(start + 5 + offset)->str() == "&")
                {
                    addressOf = true;
                    next = start + 6 + offset;
                }
                else
                    next = start + 5 + offset;
            }

            // check for var ? ...
            else if (Token::Match(tok->tokAt(start), "%var% ?"))
            {
                next = start;
            }

            // no cast
            else
            {
                if (tok->tokAt(start)->str() == "&")
                {
                    addressOf = true;
                    next = start + 1;
                }
                else if (tok->tokAt(start)->str() == "new")
                    return 0;
                else
                    next = start;
            }

            // check if variable is local
            varid2 = tok->tokAt(next)->varId();
            var2 = variables.find(varid2);

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

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

                            // not in same scope as declaration
                            else
                            {
                                std::set<ScopeInfo *>::iterator assignment;

                                // check for an assignment in this scope
                                assignment = var1->_assignments.find(scope);

                                // no other assignment in this scope
                                if (assignment == var1->_assignments.end())
                                {
                                    // nothing to replace
                                    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
                                    if (var1->_assignments.size() == 1)
                                        replace = true;

                                    // otherwise, merge them
                                    else
                                        replace = false;
                                }
                            }

                            variables.alias(varid1, varid2, replace);
                        }
                        else if (tok->tokAt(next + 1)->str() == "?")
                        {
                            if (var2->_type == Variables::reference)
                                variables.readAliases(varid2);
                            else
                                variables.read(varid2);
                        }
                    }
                }
                else if (var1->_type == Variables::reference)
                {
                    variables.alias(varid1, varid2, true);
                }
                else
                {
                    if (var2->_type == Variables::pointer && tok->tokAt(next + 1)->str() == "[")
                        variables.readAliases(varid2);

                    variables.read(varid2);
                }
            }
            else // not a local variable (or an unsupported local variable)
            {
                if (var1->_type == Variables::pointer && !dereference)
                {
                    // check if variable declaration is in this scope
                    if (var1->_scope == scope)
                        variables.clearAliases(varid1);
                    else
                    {
                        std::set<ScopeInfo *>::iterator assignment;

                        // check for an assignment in this scope
                        assignment = var1->_assignments.find(scope);

                        // no other assignment in this scope
                        if (assignment == 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);
                        }
                    }
                }
            }
        }

        var1->_assignments.insert(scope);
    }

    // check for alias to struct member
    // char c[10]; a.b = c;
    else if (Token::Match(tok->tokAt(-2), "%var% ."))
    {
        if (Token::Match(tok->tokAt(2), "%var%"))
        {
            unsigned int varid2 = tok->tokAt(2)->varId();
            Variables::VariableUsage *var2 = variables.find(varid2);

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

    return next;
}

static bool nextIsStandardType(const Token *tok)
{
    tok = tok->next();

    if (tok->str() == "static")
        tok = tok->next();

    return tok->isStandardType();
}

static bool nextIsStandardTypeOrVoid(const Token *tok)
{
    tok = tok->next();

    if (tok->str() == "static")
        tok = tok->next();

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

    return tok->isStandardType() || tok->str() == "void";
}

void CheckOther::functionVariableUsage()
{
    if (!_settings->_checkCodingStyle)
        return;

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

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

    for (i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i)
    {
        const Scope *info = *i;

        // only check functions
        if (info->type != Scope::eFunction)
            continue;

        // First token for the current scope..
        const Token *const tok1 = info->classStart;

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

        // scopes
        ScopeInfo scopes;
        ScopeInfo *scope = &scopes;

        unsigned int indentlevel = 0;
        for (const Token *tok = tok1; tok; tok = tok->next())
        {
            if (tok->str() == "{")
            {
                // replace the head node when found
                if (indentlevel == 0)
                    scopes = ScopeInfo(tok, NULL);
                // add the new scope
                else
                    scope = scope->addChild(tok);
                ++indentlevel;
            }
            else if (tok->str() == "}")
            {
                --indentlevel;

                scope = scope->parent();

                if (indentlevel == 0)
                    break;
            }
            else if (Token::Match(tok, "struct|union|class {") ||
                     Token::Match(tok, "struct|union|class %type% {|:"))
            {
                while (tok->str() != "{")
                    tok = tok->next();
                tok = tok->link();
                if (! tok)
                    break;
            }

            if (Token::Match(tok, "[;{}] asm ( ) ;"))
            {
                variables.clear();
                break;
            }

            // standard type declaration with possible initialization
            // int i; int j = 0; static int k;
            if (Token::Match(tok, "[;{}] static| %type% %var% ;|=") &&
                nextIsStandardType(tok))
            {
                tok = tok->next();

                if (tok->str() == "static")
                    tok = tok->next();

                variables.addVar(tok->next(), Variables::standard, scope,
                                 tok->tokAt(2)->str() == "=" ||
                                 tok->previous()->str() == "static");
                tok = tok->next();
            }

            // standard type declaration and initialization using constructor
            // int i(0); static int j(0);
            else if (Token::Match(tok, "[;{}] static| %type% %var% ( %any% ) ;") &&
                     nextIsStandardType(tok))
            {
                tok = tok->next();

                if (tok->str() == "static")
                    tok = tok->next();

                variables.addVar(tok->next(), Variables::standard, scope, true);

                // check if a local variable is used to initialize this variable
                if (tok->tokAt(3)->varId() > 0)
                    variables.readAll(tok->tokAt(3)->varId());
                tok = tok->tokAt(4);
            }

            // standard type declaration of array of with possible initialization
            // int i[10]; int j[2] = { 0, 1 }; static int k[2] = { 2, 3 };
            else if (Token::Match(tok, "[;{}] static| const| %type% *| %var% [ %any% ] ;|=") &&
                     nextIsStandardType(tok))
            {
                bool isStatic = false;

                tok = tok->next();

                if (tok->str() == "static")
                {
                    tok = tok->next();
                    isStatic = true;
                }

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

                if (tok->str() != "return" && tok->str() != "throw")
                {
                    bool isPointer = bool(tok->strAt(1) == "*");
                    const Token * const nametok = tok->tokAt(isPointer ? 2 : 1);

                    variables.addVar(nametok, isPointer ? Variables::pointerArray : Variables::array, scope,
                                     nametok->tokAt(4)->str() == "=" || isStatic);

                    // check for reading array size from local variable
                    if (nametok->tokAt(2)->varId() != 0)
                        variables.read(nametok->tokAt(2)->varId());

                    // look at initializers
                    if (Token::Match(nametok->tokAt(4), "= {"))
                    {
                        tok = nametok->tokAt(6);
                        while (tok->str() != "}")
                        {
                            if (Token::Match(tok, "%var%"))
                                variables.read(tok->varId());
                            tok = tok->next();
                        }
                    }
                    else
                        tok = nametok->tokAt(3);
                }
            }

            // pointer or reference declaration with possible initialization
            // int * i; int * j = 0; static int * k = 0;
            else if (Token::Match(tok, "[;{}] static| const| %type% *|& %var% ;|="))
            {
                bool isStatic = false;

                tok = tok->next();

                if (tok->str() == "static")
                {
                    tok = tok->next();
                    isStatic = true;
                }

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

                if (tok->strAt(1) == "::")
                    tok = tok->tokAt(2);

                if (tok->str() != "return" && tok->str() != "throw")
                {
                    Variables::VariableType type;

                    if (tok->next()->str() == "*")
                        type = Variables::pointer;
                    else
                        type = Variables::reference;

                    bool written = tok->tokAt(3)->str() == "=";

                    variables.addVar(tok->tokAt(2), type, scope, written || isStatic);

                    int offset = 0;

                    // check for assignment
                    if (written)
                        offset = doAssignment(variables, tok->tokAt(2), false, scope);

                    tok = tok->tokAt(2 + offset);
                }
            }

            // pointer to pointer declaration with possible initialization
            // int ** i; int ** j = 0; static int ** k = 0;
            else if (Token::Match(tok, "[;{}] static| const| %type% * * %var% ;|="))
            {
                bool isStatic = false;

                tok = tok->next();

                if (tok->str() == "static")
                {
                    tok = tok->next();
                    isStatic = true;
                }

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

                if (tok->str() != "return")
                {
                    bool written = tok->tokAt(4)->str() == "=";

                    variables.addVar(tok->tokAt(3), Variables::pointerPointer, scope, written || isStatic);

                    int offset = 0;

                    // check for assignment
                    if (written)
                        offset = doAssignment(variables, tok->tokAt(3), false, scope);

                    tok = tok->tokAt(3 + offset);
                }
            }

            // pointer or reference of struct or union declaration with possible initialization
            // struct s * i; struct s * j = 0; static struct s * k = 0;
            else if (Token::Match(tok, "[;{}] static| const| struct|union %type% *|& %var% ;|="))
            {
                Variables::VariableType type;
                bool isStatic = false;

                tok = tok->next();

                if (tok->str() == "static")
                {
                    tok = tok->next();
                    isStatic = true;
                }

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

                if (tok->strAt(2) == "*")
                    type = Variables::pointer;
                else
                    type = Variables::reference;

                const bool written = tok->strAt(4) == "=";

                variables.addVar(tok->tokAt(3), type, scope, written || isStatic);

                int offset = 0;

                // check for assignment
                if (written)
                    offset = doAssignment(variables, tok->tokAt(3), false, scope);

                tok = tok->tokAt(3 + offset);
            }

            // pointer or reference declaration with initialization using constructor
            // int * i(j); int * k(i); static int * l(i);
            else if (Token::Match(tok, "[;{}] static| const| %type% &|* %var% ( %any% ) ;") &&
                     nextIsStandardTypeOrVoid(tok))
            {
                Variables::VariableType type;

                tok = tok->next();

                if (tok->str() == "static")
                    tok = tok->next();

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

                if (tok->next()->str() == "*")
                    type = Variables::pointer;
                else
                    type = Variables::reference;

                unsigned int varid = 0;

                // check for aliased variable
                if (Token::Match(tok->tokAt(4), "%var%"))
                    varid = tok->tokAt(4)->varId();

                variables.addVar(tok->tokAt(2), type, scope, true);

                // check if a local variable is used to initialize this variable
                if (varid > 0)
                {
                    Variables::VariableUsage	*var = variables.find(varid);

                    if (type == Variables::pointer)
                    {
                        variables.use(tok->tokAt(4)->varId());

                        if (var && (var->_type == Variables::array ||
                                    var->_type == Variables::pointer))
                            var->_aliases.insert(tok->varId());
                    }
                    else
                    {
                        variables.readAll(tok->tokAt(4)->varId());
                        if (var)
                            var->_aliases.insert(tok->varId());
                    }
                }
                tok = tok->tokAt(5);
            }

            // array of pointer or reference declaration with possible initialization
            // int * p[10]; int * q[10] = { 0 }; static int * * r[10] = { 0 };
            else if (Token::Match(tok, "[;{}] static| const| %type% *|& %var% [ %any% ] ;|="))
            {
                bool isStatic = false;

                tok = tok->next();

                if (tok->str() == "static")
                {
                    tok = tok->next();
                    isStatic = true;
                }

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

                if (tok->str() != "return")
                {
                    variables.addVar(tok->tokAt(2),
                                     tok->next()->str() == "*" ? Variables::pointerArray : Variables::referenceArray, scope,
                                     tok->tokAt(6)->str() == "=" || isStatic);

                    // check for reading array size from local variable
                    if (tok->tokAt(4)->varId() != 0)
                        variables.read(tok->tokAt(4)->varId());

                    tok = tok->tokAt(5);
                }
            }

            // array of pointer or reference of struct or union declaration with possible initialization
            // struct S * p[10]; struct T * q[10] = { 0 }; static struct S * r[10] = { 0 };
            else if (Token::Match(tok, "[;{}] static| const| struct|union %type% *|& %var% [ %any% ] ;|="))
            {
                bool isStatic = false;

                tok = tok->next();

                if (tok->str() == "static")
                {
                    tok = tok->next();
                    isStatic = true;
                }

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

                variables.addVar(tok->tokAt(3),
                                 tok->tokAt(2)->str() == "*" ? Variables::pointerArray : Variables::referenceArray, scope,
                                 tok->tokAt(7)->str() == "=" || isStatic);

                // check for reading array size from local variable
                if (tok->tokAt(5)->varId() != 0)
                    variables.read(tok->tokAt(5)->varId());

                tok = tok->tokAt(6);
            }

            // Freeing memory (not considered "using" the pointer if it was also allocated in this function)
            else if (Token::Match(tok, "free|g_free|kfree|vfree ( %var% )") ||
                     Token::Match(tok, "delete %var% ;") ||
                     Token::Match(tok, "delete [ ] %var% ;"))
            {
                unsigned int varid = 0;
                if (tok->str() != "delete")
                {
                    varid = tok->tokAt(2)->varId();
                    tok = tok->tokAt(3);
                }
                else if (tok->strAt(1) == "[")
                {
                    varid = tok->tokAt(3)->varId();
                    tok = tok->tokAt(4);
                }
                else
                {
                    varid = tok->next()->varId();
                    tok = tok->tokAt(2);
                }

                Variables::VariableUsage *var = variables.find(varid);
                if (var && !var->_allocateMemory)
                {
                    variables.readAll(varid);
                }
            }

            else if (Token::Match(tok, "return|throw %var%"))
                variables.readAll(tok->next()->varId());

            // assignment
            else if (Token::Match(tok, "*| (| ++|--| %var% ++|--| )| =") ||
                     Token::Match(tok, "*| ( const| %type% *| ) %var% ="))
            {
                bool dereference = false;
                bool pre = false;
                bool post = false;

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

                if (Token::Match(tok, "( const| %type% *| ) %var% ="))
                    tok = tok->link()->next();

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

                if (Token::Match(tok, "++|--"))
                {
                    pre = true;
                    tok = tok->next();
                }

                if (Token::Match(tok->next(), "++|--"))
                    post = true;

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

                tok = tok->tokAt(doAssignment(variables, tok, dereference, scope));

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

                if (dereference)
                {
                    variables.writeAliases(varid1);
                    variables.read(varid1);
                }
                else
                {
                    Variables::VariableUsage *var = variables.find(varid1);
                    if (var && var->_type == Variables::reference)
                    {
                        variables.writeAliases(varid1);
                        variables.read(varid1);
                    }
                    // Consider allocating memory separately because allocating/freeing alone does not constitute using the variable
                    else if (var && var->_type == Variables::pointer &&
                             Token::Match(start, "%var% = new|malloc|calloc|g_malloc|kmalloc|vmalloc"))
                    {
                        bool allocate = true;

                        if (start->strAt(2) == "new")
                        {
                            // is it a user defined type?
                            if (!start->tokAt(3)->isStandardType())
                            {
                                // lookup the type
                                const Scope *type = symbolDatabase->findVariableType(info, start->tokAt(3));

                                // unknown type?
                                if (!type)
                                    allocate = false;

                                // has default constructor or
                                // has members with unknown type or default constructor
                                else if (type->needInitialization == Scope::False)
                                    allocate = false;
                            }
                        }

                        if (allocate)
                            variables.allocateMemory(varid1);
                        else
                            variables.write(varid1);
                    }
                    else if (varid1 && Token::Match(tok, "%varid% .", varid1))
                    {
                        variables.use(varid1);
                    }
                    else
                    {
                        variables.write(varid1);
                    }

                    Variables::VariableUsage *var2 = variables.find(tok->varId());
                    if (var2)
                    {
                        if (var2->_type == Variables::reference)
                        {
                            variables.writeAliases(tok->varId());
                            variables.read(tok->varId());
                        }
                        else if (tok->varId() != varid1 && Token::Match(tok, "%var% ."))
                            variables.use(tok->varId());
                        else if (tok->varId() != varid1 &&
                                 var2->_type == Variables::standard &&
                                 tok->strAt(-1) != "&")
                            variables.use(tok->varId());
                    }
                }

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

                if (Token::Match(tok->next(), "[ %any% ]"))
                    equal = tok->tokAt(4);

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

                    if (var && var->_type != Variables::reference)
                        var->_read = true;

                    tok = tok->previous();
                }
            }

            // assignment
            else if (Token::Match(tok, "%var% [") && Token::Match(tok->next()->link(), "] ="))
            {
                unsigned 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->_type == Variables::pointer &&
                        Token::Match(tok->next()->link(), "] = new|malloc|calloc|g_malloc|kmalloc|vmalloc"))
                    {
                        variables.allocateMemory(varid);
                    }
                    else if (var->_type == Variables::pointer || var->_type == Variables::reference)
                    {
                        variables.read(varid);
                        variables.writeAliases(varid);
                    }
                    else
                        variables.writeAll(varid);
                }
            }

            else if (Token::Match(tok, ">>|& %var%"))
                variables.use(tok->next()->varId());    // use = read + write
            else if (Token::Match(tok, "[;{}] %var% >>"))
                variables.use(tok->next()->varId());    // use = read + write

            // function parameter
            else if (Token::Match(tok, "[(,] %var% ["))
                variables.use(tok->next()->varId());   // use = read + write
            else if (Token::Match(tok, "[(,] %var% [,)]") && tok->previous()->str() != "*")
                variables.use(tok->next()->varId());   // use = read + write
            else if (Token::Match(tok, "[(,] (") &&
                     Token::Match(tok->next()->link(), ") %var% [,)]"))
                variables.use(tok->next()->link()->next()->varId());   // use = read + write

            // function
            else if (Token::Match(tok, " %var% ("))
            {
                variables.read(tok->varId());
                if (Token::Match(tok->tokAt(2), "%var% ="))
                    variables.read(tok->tokAt(2)->varId());
            }

            else if (Token::Match(tok, " %var% ."))
                variables.use(tok->varId());   // use = read + write

            else if ((Token::Match(tok, "[(=&!]") || isOp(tok)) &&
                     (Token::Match(tok->next(), "%var%") && !Token::Match(tok->next(), "true|false|new")))
                variables.readAll(tok->next()->varId());

            else if (Token::Match(tok, "%var%") && (tok->next()->str() == ")" || isOp(tok->next())))
                variables.readAll(tok->varId());

            else if (Token::Match(tok, "; %var% ;"))
                variables.readAll(tok->next()->varId());

            if (Token::Match(tok, "++|-- %var%"))
            {
                if (tok->strAt(-1) != ";")
                    variables.use(tok->next()->varId());
                else
                    variables.modified(tok->next()->varId());
            }

            else if (Token::Match(tok, "%var% ++|--"))
            {
                if (tok->strAt(-1) != ";")
                    variables.use(tok->varId());
                else
                    variables.modified(tok->varId());
            }
        }

        // Check usage of all variables in the current scope..
        Variables::VariableMap::const_iterator it;
        for (it = variables.varUsage().begin(); it != variables.varUsage().end(); ++it)
        {
            const Variables::VariableUsage &usage = it->second;
            const std::string &varname = usage._name->str();

            // variable has been marked as unused so ignore it
            if (usage._name->isUnused())
                continue;

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

            // 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._name, varname);

            // variable has not been written, read, or modified
            else if (usage.unused() && !usage._modified)
                unusedVariableError(usage._name, varname);

            // variable has not been written but has been modified
            else if (usage._modified & !usage._write)
                unassignedVariableError(usage._name, varname);

            // variable has been written but not read
            else if (!usage._read && !usage._modified)
                unreadVariableError(usage._name, varname);

            // variable has been read but not written
            else if (!usage._write && !usage._allocateMemory)
                unassignedVariableError(usage._name, varname);
        }
    }
}

void CheckOther::unusedVariableError(const Token *tok, const std::string &varname)
{
    reportError(tok, Severity::style, "unusedVariable", "Unused variable: " + varname);
}

void CheckOther::allocatedButUnusedVariableError(const Token *tok, const std::string &varname)
{
    reportError(tok, Severity::style, "unusedAllocatedMemory", "Variable '" + varname + "' is allocated memory that is never used");
}

void CheckOther::unreadVariableError(const Token *tok, const std::string &varname)
{
    reportError(tok, Severity::style, "unreadVariable", "Variable '" + varname + "' is assigned a value that is never used");
}

void CheckOther::unassignedVariableError(const Token *tok, const std::string &varname)
{
    reportError(tok, Severity::style, "unassignedVariable", "Variable '" + varname + "' is not assigned a value");
}
//---------------------------------------------------------------------------





//---------------------------------------------------------------------------
// Check scope of variables..
//---------------------------------------------------------------------------

void CheckOther::checkVariableScope()
{
    if (!_settings->isEnabled("information"))
        return;

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

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

    for (i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i)
    {
        const Scope *scope = *i;

        // only check functions
        if (scope->type != Scope::eFunction)
            continue;

        // Walk through all tokens..
        int indentlevel = 0;
        for (const Token *tok = scope->classStart; tok; tok = tok->next())
        {
            // Skip function local class and struct declarations..
            if ((tok->str() == "class") || (tok->str() == "struct") || (tok->str() == "union"))
            {
                for (const Token *tok2 = tok; tok2; tok2 = tok2->next())
                {
                    if (tok2->str() == "{")
                    {
                        tok = tok2->link();
                        break;
                    }
                    if (Token::Match(tok2, "[,);]"))
                    {
                        break;
                    }
                }
                if (! tok)
                    break;
            }

            else if (tok->str() == "{")
            {
                ++indentlevel;
            }
            else if (tok->str() == "}")
            {
                --indentlevel;
                if (indentlevel == 0)
                    break;;
            }

            if (indentlevel > 0 && Token::Match(tok, "[{};]"))
            {
                // First token of statement..
                const Token *tok1 = tok->next();
                if (! tok1)
                    continue;

                if ((tok1->str() == "return") ||
                    (tok1->str() == "throw") ||
                    (tok1->str() == "delete") ||
                    (tok1->str() == "goto") ||
                    (tok1->str() == "else"))
                    continue;

                // Variable declaration?
                if (Token::Match(tok1, "%type% %var% ; %var% = %num% ;"))
                {
                    // Tokenizer modify "int i = 0;" to "int i; i = 0;",
                    // so to handle this situation we just skip
                    // initialization (see ticket #272).
                    const unsigned int firstVarId = tok1->next()->varId();
                    const unsigned int secondVarId = tok1->tokAt(3)->varId();
                    if (firstVarId > 0 && firstVarId == secondVarId)
                    {
                        lookupVar(tok1->tokAt(6), tok1->strAt(1));
                    }
                }
                else if (tok1->isStandardType() && Token::Match(tok1, "%type% %var% [;=]"))
                {
                    lookupVar(tok1, tok1->strAt(1));
                }
            }
        }
    }

}
//---------------------------------------------------------------------------

void CheckOther::lookupVar(const Token *tok1, const std::string &varname)
{
    const Token *tok = tok1;

    // Skip the variable declaration..
    while (tok && tok->str() != ";")
        tok = tok->next();

    // Check if the variable is used in this indentlevel..
    bool used1 = false;   // used in one sub-scope -> reducable
    bool used2 = false;   // used in more sub-scopes -> not reducable
    int indentlevel = 0;
    int parlevel = 0;
    bool for_or_while = false;  // is sub-scope a "for/while/etc". anything that is not "if"
    while (tok)
    {
        if (tok->str() == "{")
        {
            if (tok->strAt(-1) == "=")
            {
                if (Token::findmatch(tok, varname.c_str(), tok->link()))
                {
                    return;
                }

                tok = tok->link();
            }
            else
                ++indentlevel;
        }

        else if (tok->str() == "}")
        {
            if (indentlevel == 0)
                break;
            --indentlevel;
            if (indentlevel == 0)
            {
                if (for_or_while && used2)
                    return;
                used2 |= used1;
                used1 = false;
            }
        }

        else if (tok->str() == "(")
        {
            ++parlevel;
        }

        else if (tok->str() == ")")
        {
            --parlevel;
        }

        // Bail out if references are used
        else if (Token::simpleMatch(tok, (std::string("& ") + varname).c_str()))
        {
            return;
        }

        else if (tok->str() == varname)
        {
            if (indentlevel == 0)
                return;
            used1 = true;
            if (for_or_while && !Token::simpleMatch(tok->next(), "="))
                used2 = true;
            if (used1 && used2)
                return;
        }

        else if (indentlevel == 0)
        {
            // %unknown% ( %any% ) {
            // If %unknown% is anything except if, we assume
            // that it is a for or while loop or a macro hiding either one
            if (Token::simpleMatch(tok->next(), "(") &&
                Token::simpleMatch(tok->next()->link(), ") {"))
            {
                if (tok->str() != "if")
                    for_or_while = true;
            }

            if (Token::simpleMatch(tok, "do {"))
                for_or_while = true;

            // possible unexpanded macro hiding for/while..
            if (Token::Match(tok->previous(), "[;{}] %type% {"))
            {
                bool upper = true;
                for (unsigned int i = 0; i < tok->str().length(); ++i)
                {
                    if (!std::isupper(tok->str()[i]))
                        upper = false;
                }
                for_or_while |= upper;
            }

            if (parlevel == 0 && (tok->str() == ";"))
                for_or_while = false;
        }

        tok = tok->next();
    }

    // Warning if this variable:
    // * not used in this indentlevel
    // * used in lower indentlevel
    if (used1 || used2)
        variableScopeError(tok1, varname);
}
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
// Check for constant function parameters
//---------------------------------------------------------------------------

void CheckOther::checkConstantFunctionParameter()
{
    if (!_settings->_checkCodingStyle)
        return;

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

    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        if (Token::Match(tok, "[,(] const std :: %type% %var% [,)]"))
        {
            passedByValueError(tok, tok->strAt(5));
        }

        else if (Token::Match(tok, "[,(] const std :: %type% < %type% > %var% [,)]"))
        {
            passedByValueError(tok, tok->strAt(8));
        }

        else if (Token::Match(tok, "[,(] const std :: %type% < std :: %type% > %var% [,)]"))
        {
            passedByValueError(tok, tok->strAt(10));
        }

        else if (Token::Match(tok, "[,(] const std :: %type% < std :: %type% , std :: %type% > %var% [,)]"))
        {
            passedByValueError(tok, tok->strAt(14));
        }

        else if (Token::Match(tok, "[,(] const std :: %type% < %type% , std :: %type% > %var% [,)]"))
        {
            passedByValueError(tok, tok->strAt(12));
        }

        else if (Token::Match(tok, "[,(] const std :: %type% < std :: %type% , %type% > %var% [,)]"))
        {
            passedByValueError(tok, tok->strAt(12));
        }

        else if (Token::Match(tok, "[,(] const std :: %type% < %type% , %type% > %var% [,)]"))
        {
            passedByValueError(tok, tok->strAt(10));
        }

        else if (Token::Match(tok, "[,(] const %type% %var% [,)]"))
        {
            // Check if type is a struct or class.
            if (symbolDatabase->isClassOrStruct(tok->strAt(2)))
            {
                passedByValueError(tok, tok->strAt(3));
            }
        }
    }
}
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
// Check that all struct members are used
//---------------------------------------------------------------------------

void CheckOther::checkStructMemberUsage()
{
    if (!_settings->_checkCodingStyle)
        return;

    std::string structname;
    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        if (tok->fileIndex() != 0)
            continue;

        if (Token::Match(tok, "struct|union %type% {"))
        {
            structname.clear();
            if (Token::simpleMatch(tok->previous(), "extern"))
                continue;
            if ((!tok->previous() || Token::simpleMatch(tok->previous(), ";")) && Token::Match(tok->tokAt(2)->link(), ("} ; " + tok->strAt(1) + " %var% ;").c_str()))
                continue;

            structname = tok->strAt(1);

            // Bail out if struct/union contain any functions
            for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next())
            {
                if (tok2->str() == "(")
                {
                    structname.clear();
                    break;
                }

                if (tok2->str() == "}")
                    break;
            }

            // bail out if struct is inherited
            if (!structname.empty() && Token::findmatch(tok, (",|private|protected|public " + structname).c_str()))
                structname.clear();

            // Bail out if some data is casted to struct..
            const std::string s("( struct| " + tok->next()->str() + " * ) & %var% [");
            if (Token::findmatch(tok, s.c_str()))
                structname.clear();

            // Try to prevent false positives when struct members are not used directly.
            if (Token::findmatch(tok, (structname + " *").c_str()))
                structname.clear();
            else if (Token::findmatch(tok, (structname + " %type% *").c_str()))
                structname = "";
        }

        if (tok->str() == "}")
            structname.clear();

        if (!structname.empty() && Token::Match(tok, "[{;]"))
        {
            // Declaring struct variable..
            std::string varname;

            // declaring a POD variable?
            if (!tok->next()->isStandardType())
                continue;

            if (Token::Match(tok->next(), "%type% %var% [;[]"))
                varname = tok->strAt(2);
            else if (Token::Match(tok->next(), "%type% %type% %var% [;[]"))
                varname = tok->strAt(3);
            else if (Token::Match(tok->next(), "%type% * %var% [;[]"))
                varname = tok->strAt(3);
            else if (Token::Match(tok->next(), "%type% %type% * %var% [;[]"))
                varname = tok->strAt(4);
            else
                continue;

            // Check if the struct variable is used anywhere in the file
            const std::string usagePattern(". " + varname);
            bool used = false;
            for (const Token *tok2 = _tokenizer->tokens(); tok2; tok2 = tok2->next())
            {
                if (Token::simpleMatch(tok2, usagePattern.c_str()))
                {
                    used = true;
                    break;
                }
            }

            if (! used)
            {
                unusedStructMemberError(tok->next(), structname, varname);
            }
        }
    }
}





//---------------------------------------------------------------------------
// Check usage of char variables..
//---------------------------------------------------------------------------

void CheckOther::checkCharVariable()
{
    if (!_settings->_checkCodingStyle)
        return;

    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        // Declaring the variable..
        if (Token::Match(tok, "[{};(,] char %var% [;=,)]"))
        {
            // Check for unsigned char
            if (tok->tokAt(1)->isUnsigned())
                continue;

            // Set tok to point to the variable name
            tok = tok->tokAt(2);
            if (tok->str() == "char")
                tok = tok->next();

            // Check usage of char variable..
            int indentlevel = 0;
            for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next())
            {
                if (tok2->str() == "{")
                    ++indentlevel;

                else if (tok2->str() == "}")
                {
                    --indentlevel;
                    if (indentlevel <= 0)
                        break;
                }

                else if (tok2->str() == "return")
                    continue;

                std::string temp = "%var% [ " + tok->str() + " ]";
                if ((tok2->str() != ".") && Token::Match(tok2->next(), temp.c_str()))
                {
                    charArrayIndexError(tok2->next());
                    break;
                }

                if (Token::Match(tok2, "[;{}] %var% = %any% [&|] %any% ;"))
                {
                    // is the char variable used in the calculation?
                    if (tok2->tokAt(3)->varId() != tok->varId() && tok2->tokAt(5)->varId() != tok->varId())
                        continue;

                    // it's ok with a bitwise and where the other operand is 0xff or less..
                    if (std::string(tok2->strAt(4)) == "&")
                    {
                        if (tok2->tokAt(3)->isNumber() && MathLib::isGreater("0x100", tok2->strAt(3)))
                            continue;
                        if (tok2->tokAt(5)->isNumber() && MathLib::isGreater("0x100", tok2->strAt(5)))
                            continue;
                    }

                    // is the result stored in a short|int|long?
                    if (!Token::findmatch(_tokenizer->tokens(), "short|int|long %varid%", tok2->next()->varId()))
                        continue;

                    // This is an error..
                    charBitOpError(tok2);
                    break;
                }
            }
        }
    }
}
//---------------------------------------------------------------------------






//---------------------------------------------------------------------------
// Incomplete statement..
//---------------------------------------------------------------------------

void CheckOther::checkIncompleteStatement()
{
    if (!_settings->_checkCodingStyle)
        return;

    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        if (tok->str() == "(")
            tok = tok->link();

        else if (Token::simpleMatch(tok, "= {"))
            tok = tok->next()->link();

        else if (tok->str() == "{" && Token::Match(tok->tokAt(-2), "%type% %var%"))
            tok = tok->link();

        else if (Token::Match(tok, "[;{}] %str%") || Token::Match(tok, "[;{}] %num%"))
        {
            // bailout if there is a "? :" in this statement
            bool bailout = false;
            for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next())
            {
                if (tok2->str() == "?")
                    bailout = true;
                else if (tok2->str() == ";")
                    break;
            }
            if (bailout)
                continue;

            constStatementError(tok->next(), tok->next()->isNumber() ? "numeric" : "string");
        }
    }
}
//---------------------------------------------------------------------------






//---------------------------------------------------------------------------
// str plus char
//---------------------------------------------------------------------------

void CheckOther::strPlusChar()
{
    // Don't use this check for Java and C# programs..
    if (_tokenizer->isJavaOrCSharp())
    {
        return;
    }

    bool charVars[10000] = {0};

    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        // Declaring char variable..
        if (Token::Match(tok, "char|int|short %var% [;=]"))
        {
            unsigned int varid = tok->next()->varId();
            if (varid > 0 && varid < 10000)
                charVars[varid] = true;
        }

        //
        else if (Token::Match(tok, "[=(] %str% + %any%"))
        {
            // char constant..
            const std::string s = tok->strAt(3);
            if (s[0] == '\'')
                strPlusChar(tok->next());

            // char variable..
            unsigned int varid = tok->tokAt(3)->varId();
            if (varid > 0 && varid < 10000 && charVars[varid])
                strPlusChar(tok->next());
        }
    }
}

void CheckOther::checkZeroDivision()
{
    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {

        if (Token::Match(tok, "/ %num%") &&
            MathLib::isInt(tok->next()->str()) &&
            MathLib::toLongNumber(tok->next()->str()) == 0L)
        {
            zerodivError(tok);
        }
        else if (Token::Match(tok, "div|ldiv|lldiv|imaxdiv ( %num% , %num% )") &&
                 MathLib::isInt(tok->tokAt(4)->str()) &&
                 MathLib::toLongNumber(tok->tokAt(4)->str()) == 0L)
        {
            zerodivError(tok);
        }
    }
}


void CheckOther::checkMathFunctions()
{
    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        // case log(-2)
        if (tok->varId() == 0 &&
            Token::Match(tok, "log|log10 ( %num% )") &&
            MathLib::isNegative(tok->tokAt(2)->str()) &&
            MathLib::isInt(tok->tokAt(2)->str()) &&
            MathLib::toLongNumber(tok->tokAt(2)->str()) <= 0)
        {
            mathfunctionCallError(tok);
        }
        // case log(-2.0)
        else if (tok->varId() == 0 &&
                 Token::Match(tok, "log|log10 ( %num% )") &&
                 MathLib::isNegative(tok->tokAt(2)->str()) &&
                 MathLib::isFloat(tok->tokAt(2)->str()) &&
                 MathLib::toDoubleNumber(tok->tokAt(2)->str()) <= 0.)
        {
            mathfunctionCallError(tok);
        }

        // case log(0.0)
        else if (tok->varId() == 0 &&
                 Token::Match(tok, "log|log10 ( %num% )") &&
                 !MathLib::isNegative(tok->tokAt(2)->str()) &&
                 MathLib::isFloat(tok->tokAt(2)->str()) &&
                 MathLib::toDoubleNumber(tok->tokAt(2)->str()) <= 0.)
        {
            mathfunctionCallError(tok);
        }

        // case log(0)
        else if (tok->varId() == 0 &&
                 Token::Match(tok, "log|log10 ( %num% )") &&
                 !MathLib::isNegative(tok->tokAt(2)->str()) &&
                 MathLib::isInt(tok->tokAt(2)->str()) &&
                 MathLib::toLongNumber(tok->tokAt(2)->str()) <= 0)
        {
            mathfunctionCallError(tok);
        }
        // acos( x ), asin( x )  where x is defined for intervall [-1,+1], but not beyound
        else if (tok->varId() == 0 &&
                 Token::Match(tok, "acos|asin ( %num% )") &&
                 std::fabs(MathLib::toDoubleNumber(tok->tokAt(2)->str())) > 1.0)
        {
            mathfunctionCallError(tok);
        }
        // sqrt( x ): if x is negative the result is undefined
        else if (tok->varId() == 0 &&
                 Token::Match(tok, "sqrt ( %num% )") &&
                 MathLib::isNegative(tok->tokAt(2)->str()))
        {
            mathfunctionCallError(tok);
        }
        // atan2 ( x , y): x and y can not be zero, because this is mathematically not defined
        else if (tok->varId() == 0 &&
                 Token::Match(tok, "atan2 ( %num% , %num% )") &&
                 MathLib::isNullValue(tok->tokAt(2)->str()) &&
                 MathLib::isNullValue(tok->tokAt(4)->str()))
        {
            mathfunctionCallError(tok, 2);
        }
        // fmod ( x , y) If y is zero, then either a range error will occur or the function will return zero (implementation-defined).
        else if (tok->varId() == 0 &&
                 Token::Match(tok, "fmod ( %num% , %num% )") &&
                 MathLib::isNullValue(tok->tokAt(4)->str()))
        {
            mathfunctionCallError(tok, 2);
        }
        // pow ( x , y) If x is zero, and y is negative --> division by zero
        else if (tok->varId() == 0 &&
                 Token::Match(tok, "pow ( %num% , %num% )") &&
                 MathLib::isNullValue(tok->tokAt(2)->str())  &&
                 MathLib::isNegative(tok->tokAt(4)->str()))
        {
            mathfunctionCallError(tok, 2);
        }

    }
}

void CheckOther::checkMisusedScopedObject()
{
    // Skip this check for .c files
    {
        const std::string fname = _tokenizer->getFiles()->at(0);
        const std::string ext = fname.substr(fname.rfind("."));
        if (ext == ".c" || ext == ".C")
            return;
    }

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

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

    for (i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i)
    {
        const Scope *scope = *i;

        // only check functions
        if (scope->type != Scope::eFunction)
            continue;

        unsigned int depth = 0;

        for (const Token *tok = scope->classStart; tok; tok = tok->next())
        {
            if (tok->str() == "{")
            {
                ++depth;
            }
            else if (tok->str() == "}")
            {
                --depth;
                if (depth == 0)
                    break;
            }

            if (Token::Match(tok, "[;{}] %var% (")
                && Token::Match(tok->tokAt(2)->link(), ") ;")
                && symbolDatabase->isClassOrStruct(tok->next()->str())
               )
            {
                tok = tok->next();
                misusedScopeObjectError(tok, tok->str());
                tok = tok->next();
            }
        }
    }
}

void CheckOther::cstyleCastError(const Token *tok)
{
    reportError(tok, Severity::style, "cstyleCast", "C-style pointer casting");
}

void CheckOther::dangerousUsageStrtolError(const Token *tok)
{
    reportError(tok, Severity::error, "dangerousUsageStrtol", "Invalid radix in call to strtol or strtoul. Must be 0 or 2-36");
}

void CheckOther::sprintfOverlappingDataError(const Token *tok, const std::string &varname)
{
    reportError(tok, Severity::error, "sprintfOverlappingData",
                "Undefined behavior: variable is used as parameter and destination in s[n]printf().\n"
                "The variable '" + varname + "' is used both as parameter and destination in "
                "and destination buffer overlap. Quote from glibc (C-library) documentation "
                "(http://www.gnu.org/software/libc/manual/html_mono/libc.html#Formatted-Output-Functions): "
                "'If copying takes place between objects that overlap as a result of a call "
                "to sprintf() or snprintf(), the results are undefined.'");
}

void CheckOther::udivError(const Token *tok)
{
    reportError(tok, Severity::error, "udivError", "Unsigned division. The result will be wrong.");
}

void CheckOther::unusedStructMemberError(const Token *tok, const std::string &structname, const std::string &varname)
{
    reportError(tok, Severity::style, "unusedStructMember", "struct or union member '" + structname + "::" + varname + "' is never used");
}

void CheckOther::passedByValueError(const Token *tok, const std::string &parname)
{
    reportError(tok, Severity::performance, "passedByValue",
                "Function parameter '" + parname + "' should be passed by reference.\n"
                "Parameter '" +  parname + "' is passed as a value. It could be passed "
                "as a (const) reference which is usually faster and recommended in C++.");
}

void CheckOther::constStatementError(const Token *tok, const std::string &type)
{
    reportError(tok, Severity::warning, "constStatement", "Redundant code: Found a statement that begins with " + type + " constant");
}

void CheckOther::charArrayIndexError(const Token *tok)
{
    reportError(tok, Severity::warning, "charArrayIndex", "Warning - using char variable as array index");
}

void CheckOther::charBitOpError(const Token *tok)
{
    reportError(tok, Severity::warning, "charBitOp", "Warning - using char variable in bit operation");
}

void CheckOther::variableScopeError(const Token *tok, const std::string &varname)
{
    reportError(tok,
                Severity::information,
                "variableScope",
                "The scope of the variable " + varname + " can be reduced\n"
                "The scope of the variable " + varname + " can be reduced. Warning: It can be unsafe "
                "to fix this message. Be careful. Especially when there are inner loops. Here is an "
                "example where cppcheck will write that the scope for 'i' can be reduced:\n"
                "void f(int x)\n"
                "{\n"
                "    int i = 0;\n"
                "    if (x) {\n"
                "        // it's safe to move 'int i = 0' here\n"
                "        for (int n = 0; n < 10; ++n) {\n"
                "            // it is possible but not safe to move 'int i = 0' here\n"
                "            do_something(&i);\n"
                "        }\n"
                "    }\n"
                "}\n"
                "When you see this message it is always safe to reduce the variable scope 1 level.");
}

void CheckOther::conditionAlwaysTrueFalse(const Token *tok, const std::string &truefalse)
{
    reportError(tok, Severity::style, "conditionAlwaysTrueFalse", "Condition is always " + truefalse);
}

void CheckOther::strPlusChar(const Token *tok)
{
    reportError(tok, Severity::error, "strPlusChar", "Unusual pointer arithmetic");
}

void CheckOther::zerodivError(const Token *tok)
{
    reportError(tok, Severity::error, "zerodiv", "Division by zero");
}

void CheckOther::mathfunctionCallError(const Token *tok, const unsigned int numParam)
{
    if (tok)
    {
        if (numParam == 1)
            reportError(tok, Severity::error, "wrongmathcall", "Passing value " + tok->tokAt(2)->str() + " to " + tok->str() + "() leads to undefined result");
        else if (numParam == 2)
            reportError(tok, Severity::error, "wrongmathcall", "Passing value " + tok->tokAt(2)->str() + " and " + tok->tokAt(4)->str() + " to " + tok->str() + "() leads to undefined result");
    }
    else
        reportError(tok, Severity::error, "wrongmathcall", "Passing value " " to " "() leads to undefined result");
}

void CheckOther::fflushOnInputStreamError(const Token *tok, const std::string &varname)
{
    reportError(tok, Severity::error,
                "fflushOnInputStream", "fflush() called on input stream \"" + varname + "\" may result in undefined behaviour");
}

void CheckOther::sizeofsizeof()
{
    if (!_settings->_checkCodingStyle)
        return;
    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        if (Token::simpleMatch(tok, "sizeof sizeof"))
            sizeofsizeofError(tok);
    }
}

void CheckOther::sizeofsizeofError(const Token *tok)
{
    reportError(tok, Severity::warning,
                "sizeofsizeof", "Calling sizeof for 'sizeof'.\n"
                "This is suspicious code and most likely there should be just"
                "one 'sizeof'. The current code is equivalent to 'sizeof(size_t)'");
}

void CheckOther::sizeofCalculation()
{
    if (!_settings->_checkCodingStyle)
        return;
    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        if (Token::simpleMatch(tok, "sizeof ("))
        {
            unsigned int parlevel = 0;
            for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next())
            {
                if (tok2->str() == "(")
                    ++parlevel;
                else if (tok2->str() == ")")
                {
                    if (parlevel <= 1)
                        break;
                    --parlevel;
                }
                else if (Token::Match(tok2, "+|/"))
                {
                    sizeofCalculationError(tok2);
                    break;
                }
            }
        }
    }
}

void CheckOther::sizeofCalculationError(const Token *tok)
{
    reportError(tok, Severity::warning,
                "sizeofCalculation", "Found calculation inside sizeof()");
}

void CheckOther::redundantAssignmentInSwitchError(const Token *tok, const std::string &varname)
{
    reportError(tok, Severity::warning,
                "redundantAssignInSwitch", "Redundant assignment of \"" + varname + "\" in switch");
}

void CheckOther::selfAssignmentError(const Token *tok, const std::string &varname)
{
    reportError(tok, Severity::warning,
                "selfAssignment", "Redundant assignment of \"" + varname + "\" to itself");
}

void CheckOther::assignmentInAssertError(const Token *tok, const std::string &varname)
{
    reportError(tok, Severity::warning,
                "assignmentInAssert", "Assert statement modifies '" + varname + "'.\n"
                "Assert statements are removed from release builds so the code inside "
                "assert statement is not run. If the code is needed also in release "
                "builds this is a bug.");
}

void CheckOther::incorrectLogicOperatorError(const Token *tok)
{
    reportError(tok, Severity::warning,
                "incorrectLogicOperator", "Mutual exclusion over || always evaluates to true. Did you intend to use && instead?");
}

void CheckOther::misusedScopeObjectError(const Token *tok, const std::string& varname)
{
    reportError(tok, Severity::error,
                "unusedScopedObject", "instance of \"" + varname + "\" object destroyed immediately");
}

void CheckOther::catchExceptionByValueError(const Token *tok)
{
    reportError(tok, Severity::style,
                "catchExceptionByValue", "Exception should be caught by reference.\n"
                "The exception is caught as a value. It could be caught "
                "as a (const) reference which is usually recommended in C++.");
}

void CheckOther::memsetZeroBytesError(const Token *tok, const std::string &varname)
{
    const std::string summary("memset() called to fill 0 bytes of \'" + varname + "\'");
    const std::string verbose(summary + ". Second and third arguments might be inverted.");
    reportError(tok, Severity::warning, "memsetZeroBytes", summary + "\n" + verbose);
}