@@ -5297,23 +5297,48 @@ static bool isContainerEmpty(const Token* tok)
52975297 return false ;
52985298}
52995299
5300- static bool isContainerSizeChanged (nonneg int varId, const Token *start, const Token *end);
5300+ static bool isContainerSizeChanged (nonneg int varId, const Token *start, const Token *end, int depth = 20 );
53015301
5302- static bool isContainerSizeChangedByFunction (const Token *tok)
5302+ static bool isContainerSizeChangedByFunction (const Token *tok, int depth = 20 )
53035303{
5304- const Token *parent = tok->astParent ();
5305- if (parent && parent->str () == " &" )
5306- parent = parent->astParent ();
5307- while (parent && parent->str () == " ," )
5308- parent = parent->astParent ();
5309- if (!parent)
5304+ if (!tok->valueType () || !tok->valueType ()->container )
53105305 return false ;
5311- if (Token::Match (parent->previous (), " %name% (" ))
5312- return true ;
5313- // some unsimplified template function, assume it modifies the container.
5314- if (Token::simpleMatch (parent->previous (), " >" ) && parent->linkAt (-1 ))
5315- return true ;
5316- return false ;
5306+ // If we are accessing an element then we are not changing the container size
5307+ if (Token::Match (tok, " %name% . %name% (" )) {
5308+ Library::Container::Yield yield = tok->valueType ()->container ->getYield (tok->strAt (2 ));
5309+ if (yield != Library::Container::Yield::NO_YIELD )
5310+ return false ;
5311+ }
5312+ if (Token::simpleMatch (tok->astParent (), " [" ))
5313+ return false ;
5314+
5315+ // address of variable
5316+ const bool addressOf = tok->astParent () && tok->astParent ()->isUnaryOp (" &" );
5317+
5318+ int narg;
5319+ const Token * ftok = getTokenArgumentFunction (tok, narg);
5320+ if (!ftok)
5321+ return false ; // not a function => variable not changed
5322+ const Function * fun = ftok->function ();
5323+ if (fun) {
5324+ const Variable *arg = fun->getArgumentVar (narg);
5325+ if (!arg->isReference () && !addressOf)
5326+ return false ;
5327+ if (arg->isConst ())
5328+ return false ;
5329+ const Scope * scope = fun->functionScope ;
5330+ if (scope) {
5331+ // Argument not used
5332+ if (!arg->nameToken ())
5333+ return false ;
5334+ if (depth > 0 )
5335+ return isContainerSizeChanged (arg->declarationId (), scope->bodyStart , scope->bodyEnd , depth - 1 );
5336+ }
5337+ }
5338+
5339+ bool inconclusive = false ;
5340+ const bool isChanged = isVariableChangedByFunctionCall (tok, 0 , nullptr , &inconclusive);
5341+ return (isChanged || inconclusive);
53175342}
53185343
53195344static void valueFlowContainerReverse (Token *tok, nonneg int containerId, const ValueFlow::Value &value, const Settings *settings)
@@ -5398,7 +5423,7 @@ static void valueFlowContainerForward(Token *tok, nonneg int containerId, ValueF
53985423 }
53995424}
54005425
5401- static bool isContainerSizeChanged (nonneg int varId, const Token *start, const Token *end)
5426+ static bool isContainerSizeChanged (nonneg int varId, const Token *start, const Token *end, int depth )
54025427{
54035428 for (const Token *tok = start; tok != end; tok = tok->next ()) {
54045429 if (tok->varId () != varId)
@@ -5426,7 +5451,7 @@ static bool isContainerSizeChanged(nonneg int varId, const Token *start, const T
54265451 break ;
54275452 };
54285453 }
5429- if (isContainerSizeChangedByFunction (tok))
5454+ if (isContainerSizeChangedByFunction (tok, depth ))
54305455 return true ;
54315456 }
54325457 return false ;
0 commit comments