Refactor to use AST for isContainerSizeChanged (#4222)

This commit is contained in:
Paul Fultz II 2022-06-19 01:17:05 -05:00 committed by GitHub
parent e6fdcb9de2
commit e735376f7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 33 deletions

View File

@ -271,12 +271,23 @@ static const Token* getContainerFunction(const Token* tok)
return nullptr;
}
Library::Container::Action astContainerAction(const Token* tok)
Library::Container::Action astContainerAction(const Token* tok, const Token** ftok)
{
const Token* ftok = getContainerFunction(tok);
if (!ftok)
const Token* ftok2 = getContainerFunction(tok);
if (ftok)
*ftok = ftok2;
if (!ftok2)
return Library::Container::Action::NO_ACTION;
return tok->valueType()->container->getAction(ftok->str());
return tok->valueType()->container->getAction(ftok2->str());
}
Library::Container::Yield astContainerYield(const Token* tok, const Token** ftok)
{
const Token* ftok2 = getContainerFunction(tok);
if (ftok)
*ftok = ftok2;
if (!ftok2)
return Library::Container::Yield::NO_YIELD;
return tok->valueType()->container->getYield(ftok2->str());
}
bool astIsRangeBasedForDecl(const Token* tok)

View File

@ -139,7 +139,8 @@ bool astIsContainer(const Token *tok);
bool astIsContainerView(const Token* tok);
bool astIsContainerOwned(const Token* tok);
Library::Container::Action astContainerAction(const Token* tok);
Library::Container::Action astContainerAction(const Token* tok, const Token** ftok = nullptr);
Library::Container::Yield astContainerYield(const Token* tok, const Token** ftok = nullptr);
/** Is given token a range-declaration in a range-based for loop */
bool astIsRangeBasedForDecl(const Token* tok);

View File

@ -7498,8 +7498,8 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
}))
return Action::Read | Action::Write | Action::Incremental;
}
} else if (Token::Match(tok, "%name% . %name% (")) {
Library::Container::Action action = container->getAction(tok->strAt(2));
} else if (astIsLHS(tok) && Token::Match(tok->astParent(), ". %name% (")) {
Library::Container::Action action = container->getAction(tok->astParent()->strAt(1));
if (action == Library::Container::Action::PUSH || action == Library::Container::Action::POP) {
std::vector<const Token*> args = getArguments(tok->tokAt(3));
if (args.size() < 2)
@ -7535,8 +7535,8 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
}
}
}
} else if (Token::Match(tok, "%name% . %name% (")) {
Library::Container::Action action = container->getAction(tok->strAt(2));
} else if (astIsLHS(tok) && Token::Match(tok->astParent(), ". %name% (")) {
Library::Container::Action action = container->getAction(tok->astParent()->strAt(1));
if (action == Library::Container::Action::PUSH)
val->intvalue++;
if (action == Library::Container::Action::POP)
@ -7661,29 +7661,34 @@ bool isContainerSizeChanged(const Token* tok, const Settings* settings, int dept
return false;
if (!tok->valueType() || !tok->valueType()->container)
return true;
if (Token::Match(tok, "%name% %assign%|<<"))
if (astIsLHS(tok) && Token::Match(tok->astParent(), "%assign%|<<"))
return true;
if (Token::Match(tok, "%var% [") && tok->valueType()->container->stdAssociativeLike)
const Library::Container* container = tok->valueType()->container;
// Views cannot change container size
if (container->view)
return false;
if (astIsLHS(tok) && Token::simpleMatch(tok->astParent(), "["))
return container->stdAssociativeLike;
Library::Container::Action action = astContainerAction(tok);
Library::Container::Yield yield = astContainerYield(tok);
switch (action) {
case Library::Container::Action::RESIZE:
case Library::Container::Action::CLEAR:
case Library::Container::Action::PUSH:
case Library::Container::Action::POP:
case Library::Container::Action::CHANGE:
case Library::Container::Action::INSERT:
case Library::Container::Action::ERASE:
return true;
if (Token::Match(tok, "%name% . %name% (")) {
Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2));
Library::Container::Yield yield = tok->valueType()->container->getYield(tok->strAt(2));
switch (action) {
case Library::Container::Action::RESIZE:
case Library::Container::Action::CLEAR:
case Library::Container::Action::PUSH:
case Library::Container::Action::POP:
case Library::Container::Action::CHANGE:
case Library::Container::Action::INSERT:
case Library::Container::Action::ERASE:
return true;
case Library::Container::Action::NO_ACTION: // might be unknown action
case Library::Container::Action::NO_ACTION:
// Is this an unknown member function call?
if (astIsLHS(tok) && Token::Match(tok->astParent(), ". %name% ("))
return yield == Library::Container::Yield::NO_YIELD;
case Library::Container::Action::FIND:
case Library::Container::Action::CHANGE_CONTENT:
case Library::Container::Action::CHANGE_INTERNAL:
break;
}
break;
case Library::Container::Action::FIND:
case Library::Container::Action::CHANGE_CONTENT:
case Library::Container::Action::CHANGE_INTERNAL:
break;
}
if (isContainerSizeChangedByFunction(tok, settings, depth))
return true;
@ -7795,16 +7800,17 @@ static void valueFlowIterators(TokenList *tokenlist, const Settings *settings)
continue;
if (!astIsContainer(tok))
continue;
if (Token::Match(tok->astParent(), ". %name% (")) {
Library::Container::Yield yield = getLibraryContainer(tok)->getYield(tok->astParent()->strAt(1));
const Token* ftok = nullptr;
Library::Container::Yield yield = astContainerYield(tok, &ftok);
if (ftok) {
ValueFlow::Value v(0);
v.setKnown();
if (yield == Library::Container::Yield::START_ITERATOR) {
v.valueType = ValueFlow::Value::ValueType::ITERATOR_START;
setTokenValue(tok->astParent()->tokAt(2), v, settings);
setTokenValue(ftok->next(), v, settings);
} else if (yield == Library::Container::Yield::END_ITERATOR) {
v.valueType = ValueFlow::Value::ValueType::ITERATOR_END;
setTokenValue(tok->astParent()->tokAt(2), v, settings);
setTokenValue(ftok->next(), v, settings);
}
}
}