void CheckAutoVariables::returnReference()
{
    if (_tokenizer->isC())
        return;

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

    const std::size_t functions = symbolDatabase->functionScopes.size();
    for (std::size_t i = 0; i < functions; ++i) {
        const Scope * scope = symbolDatabase->functionScopes[i];
        if (!scope->function)
            continue;

        const Token *tok = scope->function->tokenDef;

        // have we reached a function that returns a reference?
        if (tok->previous() && tok->previous()->str() == "&") {
            for (const Token *tok2 = scope->classStart->next(); tok2 && tok2 != scope->classEnd; tok2 = tok2->next()) {
                if (tok2->str() != "return")
                    continue;

                // return..
                if (Token::Match(tok2, "return %var% ;")) {
                    // is the returned variable a local variable?
                    if (isAutoVar(tok2->next())) {
                        const Variable *var1 = tok2->next()->variable();
                        // If reference variable is used, check what it references
                        if (Token::Match(var1->nameToken(), "%var% [=(]")) {
                            const Token *tok3 = var1->nameToken()->tokAt(2);
                            if (!Token::Match(tok3, "%var% [);.]"))
                                continue;

                            // Only report error if variable that is referenced is
                            // a auto variable
                            if (!isAutoVar(tok3))
                                continue;
                        }

                        // report error..
                        errorReturnReference(tok2);
                    }
                }

                // return reference to temporary..
                else if (Token::Match(tok2, "return %var% (") &&
                         Token::simpleMatch(tok2->linkAt(2), ") ;")) {
                    if (returnTemporary(tok2->next())) {
                        // report error..
                        errorReturnTempReference(tok2);
                    }
                }

                // Return reference to a literal or the result of a calculation
                else if (tok2->astOperand1() && (tok2->astOperand1()->isCalculation() || tok2->next()->isLiteral()) && astHasAutoResult(tok2->astOperand1())) {
                    errorReturnTempReference(tok2);
                }
            }
        }
    }
}
示例#2
0
void CheckAutoVariables::returnReference()
{
    const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();

    std::list<Scope>::const_iterator scope;

    for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
        // only check functions
        if (scope->type != Scope::eFunction)
            continue;

        const Token *tok = scope->classDef;

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

        // have we reached a function that returns a reference?
        if (Token::Match(tok->tokAt(-2), "%type% &") ||
            Token::Match(tok->tokAt(-2), "> &")) {
            // go to the '('
            const Token *tok2 = scope->classDef->next();

            // go to the ')'
            tok2 = tok2->link();

            unsigned int indentlevel = 0;
            for (; tok2; tok2 = tok2->next()) {
                // indentlevel..
                if (tok2->str() == "{")
                    ++indentlevel;
                else if (tok2->str() == "}") {
                    if (indentlevel <= 1)
                        break;
                    --indentlevel;
                }

                // return..
                if (Token::Match(tok2, "return %var% ;")) {
                    // is the returned variable a local variable?
                    const unsigned int varid = tok2->next()->varId();
                    const Variable *var = symbolDatabase->getVariableFromVarId(varid);

                    if (var && var->isLocal() && !var->isStatic()) {
                        // report error..
                        errorReturnReference(tok2);
                    }
                }

                // return reference to temporary..
                else if (returnTemporary(tok2)) {
                    // report error..
                    errorReturnTempReference(tok2);
                }
            }
        }
    }
}
示例#3
0
void CheckAutoVariables::returnReference()
{
    const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();

    std::list<Scope>::const_iterator scope;

    for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
        // only check functions
        if (scope->type != Scope::eFunction)
            continue;

        const Token *tok = scope->classDef;

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

        // have we reached a function that returns a reference?
        if (tok->previous() && tok->previous()->str() == "&") {
            for (const Token *tok2 = scope->classStart; tok2 && tok2 != scope->classEnd; tok2 = tok2->next()) {
                // return..
                if (Token::Match(tok2, "return %var% ;")) {
                    // is the returned variable a local variable?
                    const unsigned int varid1 = tok2->next()->varId();
                    const Variable *var1 = symbolDatabase->getVariableFromVarId(varid1);

                    if (var1 && var1->isLocal() && !var1->isStatic()) {
                        // If reference variable is used, check what it references
                        if (Token::Match(var1->nameToken(), "%var% =")) {
                            const Token *tok3 = var1->nameToken()->tokAt(2);
                            if (!Token::Match(tok3, "%var% [;.]"))
                                continue;

                            // Only report error if variable that is referenced is
                            // a auto variable
                            const Variable *var2 = symbolDatabase->getVariableFromVarId(tok3->varId());
                            if (!var2 || !var2->isLocal() || var2->isStatic() || (var2->isPointer() && tok3->strAt(1) == "."))
                                continue;
                        }

                        // report error..
                        errorReturnReference(tok2);
                    }
                }

                // return reference to temporary..
                else if (returnTemporary(tok2)) {
                    // report error..
                    errorReturnTempReference(tok2);
                }
            }
        }
    }
}
void CheckAutoVariables::returnReference()
{
    // locate function that returns a reference..
    for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
    {
        // Skip executable scopes..
        if (Token::Match(tok, ") const| {"))
        {
            tok = tok->next();
            if (tok->str() == "const")
                tok = tok->next();
            tok = tok->link();
            continue;
        }

        // have we reached a function that returns a reference?
        if (Token::Match(tok, "%type% & %var% (") ||
            Token::Match(tok, "> & %var% ("))
        {
            // go to the '('
            const Token *tok2 = tok->tokAt(3);

            // go to the ')'
            tok2 = tok2->link();

            // is this a function implementation?
            if (Token::Match(tok2, ") const| {"))
            {
                unsigned int indentlevel = 0;
                std::set<unsigned int> localvar;    // local variables in function
                while (0 != (tok2 = tok2->next()))
                {
                    // indentlevel..
                    if (tok2->str() == "{")
                        ++indentlevel;
                    else if (tok2->str() == "}")
                    {
                        if (indentlevel <= 1)
                            break;
                        --indentlevel;
                    }

                    // declare local variable..
                    if (Token::Match(tok2, "[{};] %type%") && tok2->next()->str() != "return")
                    {
                        // goto next token..
                        tok2 = tok2->next();

                        // skip "const"
                        if (Token::Match(tok2, "const %type%"))
                            tok2 = tok2->next();

                        // skip "std::" if it is seen
                        if (Token::simpleMatch(tok2, "std ::"))
                            tok2 = tok2->tokAt(2);

                        // is it a variable declaration?
                        if (Token::Match(tok2, "%type% %var% ;"))
                            localvar.insert(tok2->next()->varId());
                        else if (Token::Match(tok2, "%type% < %any% > %var% ;"))
                            localvar.insert(tok2->tokAt(4)->varId());
                    }

                    // return..
                    else if (Token::Match(tok2, "return %var% ;"))
                    {
                        // is the returned variable a local variable?
                        if ((tok2->next()->varId() > 0) &&
                            (localvar.find(tok2->next()->varId()) != localvar.end()))
                        {
                            // report error..
                            errorReturnReference(tok2);
                        }
                    }

                    // return reference to temporary..
                    else if (returnTemporary(tok2))
                    {
                        // report error..
                        errorReturnTempReference(tok2);
                    }
                }
            }
        }
    }
}