@@ -689,7 +689,7 @@ static void useFunctionArgs(const Token *tok, Variables& variables)
689689// ---------------------------------------------------------------------------
690690// Usage of function variables
691691// ---------------------------------------------------------------------------
692- void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes (const Scope* const scope, Variables& variables)
692+ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes (const Scope* const scope, Variables& variables) const
693693{
694694 // Find declarations if the scope is executable..
695695 if (scope->isExecutable ()) {
@@ -715,7 +715,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
715715 else if (mTokenizer ->isC () ||
716716 i->typeEndToken ()->isStandardType () ||
717717 i->isStlType () ||
718- isRecordTypeWithoutSideEffects (i->type ()) ||
718+ mTokenizer -> getSymbolDatabase ()-> isRecordTypeWithoutSideEffects (i->type ()) ||
719719 mSettings ->library .detectContainer (i->typeStartToken ()) ||
720720 mSettings ->library .getTypeCheck (" unusedvar" , i->typeStartToken ()->str ()) == Library::TypeCheck::check)
721721 type = Variables::standard;
@@ -963,7 +963,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const
963963 // is it a user defined type?
964964 if (!type->isStandardType ()) {
965965 const Variable *variable = start->variable ();
966- if (!variable || !isRecordTypeWithoutSideEffects (variable->type ()))
966+ if (!variable || !mTokenizer -> getSymbolDatabase ()-> isRecordTypeWithoutSideEffects (variable->type ()))
967967 allocateMemory = false ;
968968 }
969969 }
@@ -1254,7 +1254,7 @@ void CheckUnusedVar::checkFunctionVariableUsage()
12541254 if (tok->isName ()) {
12551255 if (isRaiiClass (tok->valueType (), tok->isCpp (), false ) ||
12561256 (tok->valueType () && tok->valueType ()->type == ValueType::RECORD &&
1257- (!tok->valueType ()->typeScope || !isRecordTypeWithoutSideEffects (tok->valueType ()->typeScope ->definedType ))))
1257+ (!tok->valueType ()->typeScope || !symbolDatabase-> isRecordTypeWithoutSideEffects (tok->valueType ()->typeScope ->definedType ))))
12581258 continue ;
12591259 tok = tok->next ();
12601260 }
@@ -1618,7 +1618,7 @@ void CheckUnusedVar::checkStructMemberUsage()
16181618
16191619 for (const Variable &var : scope.varlist ) {
16201620 // only warn for variables without side effects
1621- if (!var.typeStartToken ()->isStandardType () && !var.isPointer () && !astIsContainer (var.nameToken ()) && !isRecordTypeWithoutSideEffects (var.type ()))
1621+ if (!var.typeStartToken ()->isStandardType () && !var.isPointer () && !astIsContainer (var.nameToken ()) && !mTokenizer -> getSymbolDatabase ()-> isRecordTypeWithoutSideEffects (var.type ()))
16221622 continue ;
16231623 if (isInherited && !var.isPrivate ())
16241624 continue ;
@@ -1680,99 +1680,6 @@ void CheckUnusedVar::unusedStructMemberError(const Token* tok, const std::string
16801680 reportError (tok, Severity::style, " unusedStructMember" , " $symbol:" + structname + " ::" + varname + ' \n ' + prefix + " member '$symbol' is never used." , CWE563, Certainty::normal);
16811681}
16821682
1683- bool CheckUnusedVar::isRecordTypeWithoutSideEffects (const Type* type)
1684- {
1685- // a type that has no side effects (no constructors and no members with constructors)
1686- /* * @todo false negative: check constructors for side effects */
1687- const std::pair<std::map<const Type *,bool >::iterator,bool > found=mIsRecordTypeWithoutSideEffectsMap .insert (
1688- std::pair<const Type *,bool >(type,false )); // Initialize with side effects for possible recursions
1689- bool & withoutSideEffects = found.first ->second ;
1690- if (!found.second )
1691- return withoutSideEffects;
1692-
1693- // unknown types are assumed to have side effects
1694- if (!type || !type->classScope )
1695- return (withoutSideEffects = false );
1696-
1697- // Non-empty constructors => possible side effects
1698- for (const Function& f : type->classScope ->functionList ) {
1699- if (!f.isConstructor () && !f.isDestructor ())
1700- continue ;
1701- if (f.argDef && Token::simpleMatch (f.argDef ->link (), " ) =" ))
1702- continue ; // ignore default/deleted constructors
1703- const bool emptyBody = (f.functionScope && Token::simpleMatch (f.functionScope ->bodyStart , " { }" ));
1704-
1705- const Token* nextToken = f.argDef ? f.argDef ->link () : nullptr ;
1706- if (Token::simpleMatch (nextToken, " ) :" )) {
1707- // validating initialization list
1708- nextToken = nextToken->next (); // goto ":"
1709-
1710- for (const Token *initListToken = nextToken; Token::Match (initListToken, " [:,] %var% [({]" ); initListToken = initListToken->linkAt (2 )->next ()) {
1711- const Token* varToken = initListToken->next ();
1712- const Variable* variable = varToken->variable ();
1713- if (variable && !isVariableWithoutSideEffects (*variable)) {
1714- return withoutSideEffects = false ;
1715- }
1716-
1717- const Token* valueEnd = initListToken->linkAt (2 );
1718- for (const Token* valueToken = initListToken->tokAt (3 ); valueToken != valueEnd; valueToken = valueToken->next ()) {
1719- const Variable* initValueVar = valueToken->variable ();
1720- if (initValueVar && !isVariableWithoutSideEffects (*initValueVar)) {
1721- return withoutSideEffects = false ;
1722- }
1723- if ((valueToken->tokType () == Token::Type::eName) ||
1724- (valueToken->tokType () == Token::Type::eLambda) ||
1725- (valueToken->tokType () == Token::Type::eOther)) {
1726- return withoutSideEffects = false ;
1727- }
1728- const Function* initValueFunc = valueToken->function ();
1729- if (initValueFunc && !isFunctionWithoutSideEffects (*initValueFunc, valueToken,
1730- std::list<const Function*> {})) {
1731- return withoutSideEffects = false ;
1732- }
1733- }
1734- }
1735- }
1736-
1737- if (!emptyBody)
1738- return (withoutSideEffects = false );
1739- }
1740-
1741- // Derived from type that has side effects?
1742- if (std::any_of (type->derivedFrom .cbegin (), type->derivedFrom .cend (), [this ](const Type::BaseInfo& derivedFrom) {
1743- return !isRecordTypeWithoutSideEffects (derivedFrom.type );
1744- }))
1745- return (withoutSideEffects = false );
1746-
1747- // Is there a member variable with possible side effects
1748- for (const Variable& var : type->classScope ->varlist ) {
1749- withoutSideEffects = isVariableWithoutSideEffects (var, type);
1750- if (!withoutSideEffects) {
1751- return withoutSideEffects;
1752- }
1753- }
1754-
1755-
1756- return (withoutSideEffects = true );
1757- }
1758-
1759- bool CheckUnusedVar::isVariableWithoutSideEffects (const Variable& var, const Type* type)
1760- {
1761- const Type* variableType = var.type ();
1762- if (variableType && variableType != type) {
1763- if (!isRecordTypeWithoutSideEffects (variableType))
1764- return false ;
1765- } else {
1766- if (WRONG_DATA (!var.valueType (), var.typeStartToken ()))
1767- return false ;
1768- const ValueType::Type valueType = var.valueType ()->type ;
1769- if ((valueType == ValueType::Type::UNKNOWN_TYPE) || (valueType == ValueType::Type::NONSTD))
1770- return false ;
1771- }
1772-
1773- return true ;
1774- }
1775-
17761683bool CheckUnusedVar::isEmptyType (const Type* type)
17771684{
17781685 // a type that has no variables and no constructor
@@ -1794,85 +1701,6 @@ bool CheckUnusedVar::isEmptyType(const Type* type)
17941701 return (emptyType = false );
17951702}
17961703
1797- bool CheckUnusedVar::isFunctionWithoutSideEffects (const Function& func, const Token* functionUsageToken,
1798- std::list<const Function*> checkedFuncs)
1799- {
1800- // no body to analyze
1801- if (!func.hasBody ()) {
1802- return false ;
1803- }
1804-
1805- for (const Token* argsToken = functionUsageToken->next (); !Token::simpleMatch (argsToken, " )" ); argsToken = argsToken->next ()) {
1806- const Variable* argVar = argsToken->variable ();
1807- if (argVar && argVar->isGlobal ()) {
1808- return false ; // TODO: analyze global variable usage
1809- }
1810- }
1811-
1812- bool sideEffectReturnFound = false ;
1813- std::set<const Variable*> pointersToGlobals;
1814- for (const Token* bodyToken = func.functionScope ->bodyStart ->next (); bodyToken != func.functionScope ->bodyEnd ;
1815- bodyToken = bodyToken->next ()) {
1816- // check variable inside function body
1817- const Variable* bodyVariable = bodyToken->variable ();
1818- if (bodyVariable) {
1819- if (!isVariableWithoutSideEffects (*bodyVariable)) {
1820- return false ;
1821- }
1822- // check if global variable is changed
1823- if (bodyVariable->isGlobal () || (pointersToGlobals.find (bodyVariable) != pointersToGlobals.end ())) {
1824- const int indirect = bodyVariable->isArray () ? bodyVariable->dimensions ().size () : bodyVariable->isPointer ();
1825- if (isVariableChanged (bodyToken, indirect, *mSettings )) {
1826- return false ;
1827- }
1828- // check if pointer to global variable assigned to another variable (another_var = &global_var)
1829- if (Token::simpleMatch (bodyToken->tokAt (-1 ), " &" ) && Token::simpleMatch (bodyToken->tokAt (-2 ), " =" )) {
1830- const Token* assigned_var_token = bodyToken->tokAt (-3 );
1831- if (assigned_var_token && assigned_var_token->variable ()) {
1832- pointersToGlobals.insert (assigned_var_token->variable ());
1833- }
1834- }
1835- }
1836- }
1837-
1838- // check nested function
1839- const Function* bodyFunction = bodyToken->function ();
1840- if (bodyFunction) {
1841- if (std::find (checkedFuncs.cbegin (), checkedFuncs.cend (), bodyFunction) != checkedFuncs.cend ()) { // recursion found
1842- continue ;
1843- }
1844- checkedFuncs.push_back (bodyFunction);
1845- if (!isFunctionWithoutSideEffects (*bodyFunction, bodyToken, checkedFuncs)) {
1846- return false ;
1847- }
1848- }
1849-
1850- // check returned value
1851- if (Token::simpleMatch (bodyToken, " return" )) {
1852- const Token* returnValueToken = bodyToken->next ();
1853- // TODO: handle complex return expressions
1854- if (!Token::simpleMatch (returnValueToken->next (), " ;" )) {
1855- sideEffectReturnFound = true ;
1856- continue ;
1857- }
1858- // simple one-token return
1859- const Variable* returnVariable = returnValueToken->variable ();
1860- if (returnValueToken->isLiteral () ||
1861- (returnVariable && isVariableWithoutSideEffects (*returnVariable))) {
1862- continue ;
1863- }
1864- sideEffectReturnFound = true ;
1865- }
1866-
1867- // unknown name
1868- if (bodyToken->isNameOnly ()) {
1869- return false ;
1870- }
1871- }
1872-
1873- return !sideEffectReturnFound;
1874- }
1875-
18761704void CheckUnusedVar::runChecks (const Tokenizer &tokenizer, ErrorLogger *errorLogger)
18771705{
18781706 CheckUnusedVar checkUnusedVar (&tokenizer, &tokenizer.getSettings (), errorLogger);
0 commit comments