Refactor to use AST for isContainerSizeChanged (#4222)
This commit is contained in:
parent
e6fdcb9de2
commit
e735376f7d
|
@ -271,12 +271,23 @@ static const Token* getContainerFunction(const Token* tok)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Library::Container::Action astContainerAction(const Token* tok)
|
Library::Container::Action astContainerAction(const Token* tok, const Token** ftok)
|
||||||
{
|
{
|
||||||
const Token* ftok = getContainerFunction(tok);
|
const Token* ftok2 = getContainerFunction(tok);
|
||||||
if (!ftok)
|
if (ftok)
|
||||||
|
*ftok = ftok2;
|
||||||
|
if (!ftok2)
|
||||||
return Library::Container::Action::NO_ACTION;
|
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)
|
bool astIsRangeBasedForDecl(const Token* tok)
|
||||||
|
|
|
@ -139,7 +139,8 @@ bool astIsContainer(const Token *tok);
|
||||||
bool astIsContainerView(const Token* tok);
|
bool astIsContainerView(const Token* tok);
|
||||||
bool astIsContainerOwned(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 */
|
/** Is given token a range-declaration in a range-based for loop */
|
||||||
bool astIsRangeBasedForDecl(const Token* tok);
|
bool astIsRangeBasedForDecl(const Token* tok);
|
||||||
|
|
|
@ -7498,8 +7498,8 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
|
||||||
}))
|
}))
|
||||||
return Action::Read | Action::Write | Action::Incremental;
|
return Action::Read | Action::Write | Action::Incremental;
|
||||||
}
|
}
|
||||||
} else if (Token::Match(tok, "%name% . %name% (")) {
|
} else if (astIsLHS(tok) && Token::Match(tok->astParent(), ". %name% (")) {
|
||||||
Library::Container::Action action = container->getAction(tok->strAt(2));
|
Library::Container::Action action = container->getAction(tok->astParent()->strAt(1));
|
||||||
if (action == Library::Container::Action::PUSH || action == Library::Container::Action::POP) {
|
if (action == Library::Container::Action::PUSH || action == Library::Container::Action::POP) {
|
||||||
std::vector<const Token*> args = getArguments(tok->tokAt(3));
|
std::vector<const Token*> args = getArguments(tok->tokAt(3));
|
||||||
if (args.size() < 2)
|
if (args.size() < 2)
|
||||||
|
@ -7535,8 +7535,8 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (Token::Match(tok, "%name% . %name% (")) {
|
} else if (astIsLHS(tok) && Token::Match(tok->astParent(), ". %name% (")) {
|
||||||
Library::Container::Action action = container->getAction(tok->strAt(2));
|
Library::Container::Action action = container->getAction(tok->astParent()->strAt(1));
|
||||||
if (action == Library::Container::Action::PUSH)
|
if (action == Library::Container::Action::PUSH)
|
||||||
val->intvalue++;
|
val->intvalue++;
|
||||||
if (action == Library::Container::Action::POP)
|
if (action == Library::Container::Action::POP)
|
||||||
|
@ -7661,13 +7661,16 @@ bool isContainerSizeChanged(const Token* tok, const Settings* settings, int dept
|
||||||
return false;
|
return false;
|
||||||
if (!tok->valueType() || !tok->valueType()->container)
|
if (!tok->valueType() || !tok->valueType()->container)
|
||||||
return true;
|
return true;
|
||||||
if (Token::Match(tok, "%name% %assign%|<<"))
|
if (astIsLHS(tok) && Token::Match(tok->astParent(), "%assign%|<<"))
|
||||||
return true;
|
return true;
|
||||||
if (Token::Match(tok, "%var% [") && tok->valueType()->container->stdAssociativeLike)
|
const Library::Container* container = tok->valueType()->container;
|
||||||
return true;
|
// Views cannot change container size
|
||||||
if (Token::Match(tok, "%name% . %name% (")) {
|
if (container->view)
|
||||||
Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2));
|
return false;
|
||||||
Library::Container::Yield yield = tok->valueType()->container->getYield(tok->strAt(2));
|
if (astIsLHS(tok) && Token::simpleMatch(tok->astParent(), "["))
|
||||||
|
return container->stdAssociativeLike;
|
||||||
|
Library::Container::Action action = astContainerAction(tok);
|
||||||
|
Library::Container::Yield yield = astContainerYield(tok);
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case Library::Container::Action::RESIZE:
|
case Library::Container::Action::RESIZE:
|
||||||
case Library::Container::Action::CLEAR:
|
case Library::Container::Action::CLEAR:
|
||||||
|
@ -7677,14 +7680,16 @@ bool isContainerSizeChanged(const Token* tok, const Settings* settings, int dept
|
||||||
case Library::Container::Action::INSERT:
|
case Library::Container::Action::INSERT:
|
||||||
case Library::Container::Action::ERASE:
|
case Library::Container::Action::ERASE:
|
||||||
return true;
|
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;
|
return yield == Library::Container::Yield::NO_YIELD;
|
||||||
|
break;
|
||||||
case Library::Container::Action::FIND:
|
case Library::Container::Action::FIND:
|
||||||
case Library::Container::Action::CHANGE_CONTENT:
|
case Library::Container::Action::CHANGE_CONTENT:
|
||||||
case Library::Container::Action::CHANGE_INTERNAL:
|
case Library::Container::Action::CHANGE_INTERNAL:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (isContainerSizeChangedByFunction(tok, settings, depth))
|
if (isContainerSizeChangedByFunction(tok, settings, depth))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
|
@ -7795,16 +7800,17 @@ static void valueFlowIterators(TokenList *tokenlist, const Settings *settings)
|
||||||
continue;
|
continue;
|
||||||
if (!astIsContainer(tok))
|
if (!astIsContainer(tok))
|
||||||
continue;
|
continue;
|
||||||
if (Token::Match(tok->astParent(), ". %name% (")) {
|
const Token* ftok = nullptr;
|
||||||
Library::Container::Yield yield = getLibraryContainer(tok)->getYield(tok->astParent()->strAt(1));
|
Library::Container::Yield yield = astContainerYield(tok, &ftok);
|
||||||
|
if (ftok) {
|
||||||
ValueFlow::Value v(0);
|
ValueFlow::Value v(0);
|
||||||
v.setKnown();
|
v.setKnown();
|
||||||
if (yield == Library::Container::Yield::START_ITERATOR) {
|
if (yield == Library::Container::Yield::START_ITERATOR) {
|
||||||
v.valueType = ValueFlow::Value::ValueType::ITERATOR_START;
|
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) {
|
} else if (yield == Library::Container::Yield::END_ITERATOR) {
|
||||||
v.valueType = ValueFlow::Value::ValueType::ITERATOR_END;
|
v.valueType = ValueFlow::Value::ValueType::ITERATOR_END;
|
||||||
setTokenValue(tok->astParent()->tokAt(2), v, settings);
|
setTokenValue(ftok->next(), v, settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue