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); } } } } }
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); } } } } }
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); } } } } } }