Ejemplo n.º 1
0
//---------------------------------------------------------------------------
// Usage of function variables
//---------------------------------------------------------------------------
void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const scope, Variables& variables, bool insideLoop)
{
    Variables::ScopeGuard scopeGuard=variables.newScope(insideLoop);

    // Find declarations if the scope is executable..
    if (scope->isExecutable()) {
        // Find declarations
        for (std::list<Variable>::const_iterator i = scope->varlist.begin(); i != scope->varlist.end(); ++i) {
            if (i->isThrow() || i->isExtern())
                continue;
            Variables::VariableType type = Variables::none;
            if (i->isArray() && (i->nameToken()->previous()->str() == "*" || i->nameToken()->strAt(-2) == "*"))
                type = Variables::pointerArray;
            else if (i->isArray() && i->nameToken()->previous()->str() == "&")
                type = Variables::referenceArray;
            else if (i->isArray())
                type = Variables::array;
            else if (i->isReference())
                type = Variables::reference;
            else if (i->nameToken()->previous()->str() == "*" && i->nameToken()->strAt(-2) == "*")
                type = Variables::pointerPointer;
            else if (i->isPointer())
                type = Variables::pointer;
            else if (_tokenizer->isC() ||
                     i->typeEndToken()->isStandardType() ||
                     isRecordTypeWithoutSideEffects(i->type()) ||
                     (i->isStlType() &&
                      !Token::Match(i->typeStartToken()->tokAt(2), "lock_guard|unique_lock|shared_ptr|unique_ptr|auto_ptr|shared_lock")))
                type = Variables::standard;
            if (type == Variables::none || isPartOfClassStructUnion(i->typeStartToken()))
                continue;
            const Token* defValTok = i->nameToken()->next();
            for (; defValTok; defValTok = defValTok->next()) {
                if (defValTok->str() == "[")
                    defValTok = defValTok->link();
                else if (defValTok->str() == "(" || defValTok->str() == "{" || defValTok->str() == "=") {
                    variables.addVar(&*i, type, true);
                    break;
                } else if (defValTok->str() == ";" || defValTok->str() == "," || defValTok->str() == ")") {
                    variables.addVar(&*i, type, i->isStatic());
                    break;
                }
            }
            if (i->isArray() && i->isClass()) // Array of class/struct members. Initialized by ctor.
                variables.write(i->declarationId(), i->nameToken());
            if (i->isArray() && Token::Match(i->nameToken(), "%name% [ %var% ]")) // Array index variable read.
                variables.read(i->nameToken()->tokAt(2)->varId(), i->nameToken());

            if (defValTok && defValTok->str() == "=") {
                if (defValTok->next() && defValTok->next()->str() == "{") {
                    for (const Token* tok = defValTok; tok && tok != defValTok->linkAt(1); tok = tok->next())
                        if (tok->varId()) // Variables used to initialize the array read.
                            variables.read(tok->varId(), i->nameToken());
                } else
                    doAssignment(variables, i->nameToken(), false, scope);
            }
        }
    }

    // Check variable usage
    const Token *tok;
    if (scope->type == Scope::eFunction)
        tok = scope->classStart->next();
    else
        tok = scope->classDef->next();
    for (; tok && tok != scope->classEnd; tok = tok->next()) {
        if (tok->str() == "for" || tok->str() == "while" || tok->str() == "do") {
            for (std::list<Scope*>::const_iterator i = scope->nestedList.begin(); i != scope->nestedList.end(); ++i) {
                if ((*i)->classDef == tok) { // Find associated scope
                    checkFunctionVariableUsage_iterateScopes(*i, variables, true); // Scan child scope
                    tok = (*i)->classStart->link();
                    break;
                }
            }
            if (!tok)
                break;
        }
        if (tok->str() == "{" && tok != scope->classStart && !tok->previous()->varId()) {
            for (std::list<Scope*>::const_iterator i = scope->nestedList.begin(); i != scope->nestedList.end(); ++i) {
                if ((*i)->classStart == tok) { // Find associated scope
                    checkFunctionVariableUsage_iterateScopes(*i, variables, false); // Scan child scope
                    tok = tok->link();
                    break;
                }
            }
            if (!tok)
                break;
        }

        if (Token::Match(tok, "asm ( %str% )")) {
            variables.clear();
            break;
        }
        if (Token::simpleMatch(tok, "goto")) { // https://sourceforge.net/apps/trac/cppcheck/ticket/4447
            variables.clear();
            break;
        }


        // bailout when for_each is used
        if (Token::Match(tok, "%name% (") && Token::simpleMatch(tok->linkAt(1), ") {") && !Token::Match(tok, "if|for|while|switch")) {
            // does the name contain "for_each" or "foreach"?
            std::string nameTok;
            nameTok.resize(tok->str().size());
            std::transform(tok->str().begin(), tok->str().end(), nameTok.begin(), ::tolower);
            if (nameTok.find("foreach") != std::string::npos || nameTok.find("for_each") != std::string::npos) {
                // bailout all variables in the body that are used more than once.
                // TODO: there is no need to bailout if variable is only read or only written
                std::set<unsigned int> varid;
                const Token * const endTok = tok->linkAt(1)->linkAt(1);
                for (const Token *tok2 = endTok->link(); tok2 && tok2 != endTok; tok2 = tok2->next()) {
                    if (tok2->varId()) {
                        if (varid.find(tok2->varId()) == varid.end())
                            varid.insert(tok2->varId());
                        else
                            variables.erase(tok2->varId());
                    }
                }
            }
        }

        // C++11 std::for_each
        // No warning should be written if a variable is first read and
        // then written in the body.
        else if (Token::simpleMatch(tok, "for_each (") && Token::simpleMatch(tok->linkAt(1), ") ;")) {
            const Token *end = tok->linkAt(1);
            if (end->previous()->str() == "}") {
                std::set<unsigned int> readvar;
                for (const Token *body = end->linkAt(-1); body != end; body = body->next()) {
                    if (body->varId() == 0U)
                        continue;
                    if (!Token::simpleMatch(body->next(),"="))
                        readvar.insert(body->varId());
                    else if (readvar.find(body->varId()) != readvar.end())
                        variables.erase(body->varId());
                }
            }
        }

        else if (Token::Match(tok->previous(), "[;{}]")) {
            for (const Token* tok2 = tok->next(); tok2; tok2 = tok2->next()) {
                if (tok2->varId()) {
                    const Variable *var = tok2->variable();
                    if (var && var->nameToken() == tok2) { // Declaration: Skip
                        tok = tok2->next();
                        if (Token::Match(tok, "( %name% )")) // Simple initialization through copy ctor
                            tok = tok->next();
                        else if (Token::Match(tok, "= %var% ;")) { // Simple initialization
                            tok = tok->next();
                            if (!var->isReference())
                                variables.read(tok->varId(), tok);
                        } else if (var->typeEndToken()->str() == ">") // Be careful with types like std::vector
                            tok = tok->previous();
                        break;
                    }
                } else if (Token::Match(tok2, "[;({=]"))
                    break;
            }
        }
        // Freeing memory (not considered "using" the pointer if it was also allocated in this function)
        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(3);
            } else {
                varid = tok->next()->varId();
                tok = tok->next();
            }

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

        else if (Token::Match(tok, "return|throw")) {
            for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
                if (tok2->varId())
                    variables.readAll(tok2->varId(), tok);
                else if (tok2->str() == ";")
                    break;
            }
        }

        else if (Token::Match(tok->tokAt(-2), "while|if") && tok->strAt(1) == "=" && tok->varId() && tok->varId() == tok->tokAt(2)->varId()) {
            variables.use(tok->tokAt(2)->varId(), tok);
        }
        // assignment
        else if (Token::Match(tok, "*| ++|--| %name% ++|--| =") ||
                 Token::Match(tok, "*| ( const| %type% *| ) %name% =")) {
            bool dereference = false;
            bool pre = false;
            bool post = false;

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

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

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

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

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

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

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

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

            if (dereference) {
                Variables::VariableUsage *var = variables.find(varid1);
                if (var && var->_type == Variables::array)
                    variables.write(varid1, tok);
                variables.writeAliases(varid1, tok);
                variables.read(varid1, tok);
            } else {
                Variables::VariableUsage *var = variables.find(varid1);
                if (var && start->strAt(-1) == ",") {
                    variables.use(varid1, tok);
                } else if (var && var->_type == Variables::reference) {
                    variables.writeAliases(varid1, tok);
                    variables.read(varid1, tok);
                }
                // Consider allocating memory separately because allocating/freeing alone does not constitute using the variable
                else if (var && var->_type == Variables::pointer &&
                         Token::Match(start, "%name% = new|malloc|calloc|kmalloc|kzalloc|kcalloc|strdup|strndup|vmalloc|g_new0|g_try_new|g_new|g_malloc|g_malloc0|g_try_malloc|g_try_malloc0|g_strdup|g_strndup|g_strdup_printf")) {
                    bool allocate = true;

                    if (start->strAt(2) == "new") {
                        const Token *type = start->tokAt(3);

                        // skip nothrow
                        if (Token::simpleMatch(type, "( nothrow )") ||
                            Token::simpleMatch(type, "( std :: nothrow )"))
                            type = type->link()->next();

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

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

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

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

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

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

                tok = tok->previous();
            }
        }

        // assignment
        else if ((Token::Match(tok, "%name% [") && Token::simpleMatch(skipBracketsAndMembers(tok->next()), "=")) ||
                 (Token::simpleMatch(tok, "* (") && Token::simpleMatch(tok->next()->link(), ") ="))) {
            if (tok->str() == "*") {
                tok = tok->tokAt(2);
                if (tok->str() == "(")
                    tok = tok->link()->next();
            }

            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(skipBrackets(tok->next()), "= new|malloc|calloc|kmalloc|kzalloc|kcalloc|strdup|strndup|vmalloc|g_new0|g_try_new|g_new|g_malloc|g_malloc0|g_try_malloc|g_try_malloc0|g_strdup|g_strndup|g_strdup_printf")) {
                    variables.allocateMemory(varid, tok);
                } else if (var->_type == Variables::pointer || var->_type == Variables::reference) {
                    variables.read(varid, tok);
                    variables.writeAliases(varid, tok);
                } else if (var->_type == Variables::pointerArray) {
                    tok = doAssignment(variables, tok, false, scope);
                } else
                    variables.writeAll(varid, tok);
            }
        }

        else if (_tokenizer->isCPP() && Token::Match(tok, "[;{}] %var% <<")) {
            variables.erase(tok->next()->varId());
        }

        else if (Token::Match(tok, "& %var%")) {
            if (tok->astOperand2()) { // bitop
                variables.read(tok->next()->varId(), tok);
            } else // addressof
                variables.use(tok->next()->varId(), tok); // use = read + write
        } else if (Token::Match(tok, ">>|>>= %name%")) {
            if (_tokenizer->isC() || (tok->previous()->variable() && tok->previous()->variable()->typeEndToken()->isStandardType() && tok->astOperand1() && tok->astOperand1()->str() != ">>"))
                variables.read(tok->next()->varId(), tok);
            else
                variables.use(tok->next()->varId(), tok); // use = read + write
        } else if (Token::Match(tok, "%var% >>|&") && Token::Match(tok->previous(), "[{};:]")) {
            variables.read(tok->varId(), tok);
        }

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

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

        else if (Token::Match(tok->previous(), "[{,] %var% [,}]")) {
            variables.read(tok->varId(), tok);
        }

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

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

        else if (tok->varId() && tok->next() && (tok->next()->str() == ")" || tok->next()->isExtendedOp())) {
            variables.readAll(tok->varId(), tok);
        }

        else if (Token::Match(tok, "%var% ;") && Token::Match(tok->previous(), "[;{}:]")) {
            variables.readAll(tok->varId(), tok);
        }

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

        else if (tok->isAssignmentOp()) {
            for (const Token *tok2 = tok->next(); tok2 && tok2->str() != ";"; tok2 = tok2->next()) {
                if (tok2->varId()) {
                    if (tok2->strAt(1) == "=")
                        variables.write(tok2->varId(), tok);
                    else if (tok2->next()->isAssignmentOp())
                        variables.use(tok2->varId(), tok);
                    else
                        variables.read(tok2->varId(), tok);
                }
            }
        }
    }
}
Ejemplo n.º 2
0
//---------------------------------------------------------------------------
// Usage of function variables
//---------------------------------------------------------------------------
void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const scope, Variables& variables)
{
    if (scope->type == Scope::eClass || scope->type == Scope::eUnion || scope->type == Scope::eStruct)
        return;

    // Find declarations
    for (std::list<Variable>::const_iterator i = scope->varlist.begin(); i != scope->varlist.end(); ++i) {
        Variables::VariableType type = Variables::none;
        if (i->isArray() && (i->nameToken()->previous()->str() == "*" || i->nameToken()->strAt(-2) == "*"))
            type = Variables::pointerArray;
        else if (i->isArray() && i->nameToken()->previous()->str() == "&")
            type = Variables::referenceArray;
        else if (i->isArray())
            type = Variables::array;
        else if (i->nameToken()->previous()->str() == "&")
            type = Variables::reference;
        else if (i->nameToken()->previous()->str() == "*" && i->nameToken()->strAt(-2) == "*")
            type = Variables::pointerPointer;
        else if (i->nameToken()->previous()->str() == "*" || Token::Match(i->nameToken()->tokAt(-2), "* %type%"))
            type = Variables::pointer;
        else if (i->typeEndToken()->isStandardType() || isRecordTypeWithoutSideEffects(*i) || Token::simpleMatch(i->nameToken()->tokAt(-3), "std :: string"))
            type = Variables::standard;
        if (type == Variables::none || isPartOfClassStructUnion(i->typeStartToken()))
            continue;
        const Token* defValTok = i->nameToken()->next();
        for (; defValTok; defValTok = defValTok->next()) {
            if (defValTok->str() == "[")
                defValTok = defValTok->link();
            else if (defValTok->str() == "(" || defValTok->str() == "=") {
                variables.addVar(i->nameToken(), type, scope, true);
                break;
            } else if (defValTok->str() == ";" || defValTok->str() == "," || defValTok->str() == ")") {
                variables.addVar(i->nameToken(), type, scope, i->isStatic());
                break;
            }
        }
        if (i->isArray() && Token::Match(i->nameToken(), "%var% [ %var% ]")) // Array index variable read.
            variables.read(i->nameToken()->tokAt(2)->varId());

        if (defValTok && defValTok->str() == "=") {
            if (defValTok->next() && defValTok->next()->str() == "{") {
                for (const Token* tok = defValTok; tok && tok != defValTok->linkAt(1); tok = tok->next())
                    if (Token::Match(tok, "%var%")) // Variables used to initialize the array read.
                        variables.read(tok->varId());
            } else
                doAssignment(variables, i->nameToken(), false, scope);
        } else if (Token::Match(defValTok, "( %var% )")) // Variables used to initialize the variable read.
            variables.readAll(defValTok->next()->varId()); // ReadAll?
    }

    // Check variable usage
    for (const Token *tok = scope->classDef->next(); tok && tok != scope->classEnd; tok = tok->next()) {
        if (tok->str() == "for" || tok->str() == "catch") {
            for (std::list<Scope*>::const_iterator i = scope->nestedList.begin(); i != scope->nestedList.end(); ++i) {
                if ((*i)->classDef == tok) { // Find associated scope
                    checkFunctionVariableUsage_iterateScopes(*i, variables); // Scan child scope
                    tok = (*i)->classStart->link();
                    break;
                }
            }
            if (!tok)
                break;
        }
        if (tok->str() == "{") {
            for (std::list<Scope*>::const_iterator i = scope->nestedList.begin(); i != scope->nestedList.end(); ++i) {
                if ((*i)->classStart == tok) { // Find associated scope
                    checkFunctionVariableUsage_iterateScopes(*i, variables); // Scan child scope
                    tok = tok->link();
                    break;
                }
            }
            if (!tok)
                break;
        }

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

        if (Token::Match(tok, "%type% const| *|&| const| *| const| %var% [;=[(]") && tok->str() != "return" && tok->str() != "throw") { // Declaration: Skip
            tok = tok->next();
            while (Token::Match(tok, "const|*|&"))
                tok = tok->next();
            tok = Token::findmatch(tok, "[;=[(]");
            if (tok && Token::Match(tok, "( %var% )")) // Simple initialization through copy ctor
                tok = tok->next();
            else if (tok && Token::Match(tok, "= %var% ;")) // Simple initialization
                tok = tok->next();
            if (!tok)
                break;
        }
        // Freeing memory (not considered "using" the pointer if it was also allocated in this function)
        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(3);
            } else {
                varid = tok->next()->varId();
                tok = tok->next();
            }

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

        else if (Token::Match(tok, "return|throw %var%")) {
            for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
                if (tok2->varId())
                    variables.readAll(tok2->varId());
                else if (tok2->str() == ";")
                    break;
            }
        }

        // assignment
        else if (!Token::Match(tok->tokAt(-2), "[;{}.] %var% (") &&
                 (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::VariableUsage *var = variables.find(varid1);
                if (var && var->_type == Variables::array)
                    variables.write(varid1);
                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") {
                        const Token *type = start->tokAt(3);

                        // skip nothrow
                        if (Token::simpleMatch(type, "( nothrow )") ||
                            Token::simpleMatch(type, "( std :: nothrow )"))
                            type = type->link()->next();

                        // is it a user defined type?
                        if (!type->isStandardType()) {
                            const Variable* variable = _tokenizer->getSymbolDatabase()->getVariableFromVarId(start->varId());
                            if (!variable || !isRecordTypeWithoutSideEffects(*variable))
                                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.read(tok->varId());
                    else if (tok->varId() != varid1 &&
                             var2->_type == Variables::standard &&
                             tok->strAt(-1) != "&")
                        variables.use(tok->varId());
                }
            }

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

            // checked for chained assignments
            if (tok != start && equal && 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::simpleMatch(skipBrackets(tok->next()), "=")) {
            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(skipBrackets(tok->next()), "= 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% >>|&") && Token::Match(tok->previous(), "[{};:]"))
            variables.read(tok->varId());

        // 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.read(tok->next()->varId());

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

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

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

        else if (Token::Match(tok, "%var% ;") && Token::Match(tok->previous(), "[;{}:]"))
            variables.readAll(tok->varId());

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

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

        else if (tok->isAssignmentOp()) {
            for (const Token *tok2 = tok->next(); tok2 && tok2->str() != ";"; tok2 = tok2->next()) {
                if (tok2->varId()) {
                    variables.read(tok2->varId());
                    if (tok2->next()->isAssignmentOp())
                        variables.write(tok2->varId());
                }
            }
        }
    }
}