Refactoring: Move isScopeNoReturn implementation to library and reuse it both in ValueFlow and Tokenizer
This commit is contained in:
parent
c19fc08a68
commit
ae81b09b58
|
@ -376,3 +376,35 @@ const Library::ArgumentChecks * Library::getarg(const std::string &functionName,
|
||||||
return &it3->second;
|
return &it3->second;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Library::isScopeNoReturn(const Token *end, std::string *unknownFunc) const
|
||||||
|
{
|
||||||
|
if (unknownFunc)
|
||||||
|
unknownFunc->clear();
|
||||||
|
|
||||||
|
if (!Token::simpleMatch(end->tokAt(-2), ") ; }"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const Token *funcname = end->linkAt(-2)->previous();
|
||||||
|
const Token *start = funcname;
|
||||||
|
if (funcname && Token::Match(funcname->tokAt(-3),"( * %var% )")) {
|
||||||
|
funcname = funcname->previous();
|
||||||
|
start = funcname->tokAt(-3);
|
||||||
|
} else if (funcname->isName()) {
|
||||||
|
while (Token::Match(start, "%var%|.|::"))
|
||||||
|
start = start->previous();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Token::Match(start,"[;{}]") && Token::Match(funcname, "%var% )| (")) {
|
||||||
|
if (funcname->str() == "exit")
|
||||||
|
return true;
|
||||||
|
if (!isnotnoreturn(funcname->str())) {
|
||||||
|
if (unknownFunc && !isnoreturn(funcname->str()))
|
||||||
|
*unknownFunc = funcname->str();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,8 @@ public:
|
||||||
return (it != _noreturn.end() && !it->second);
|
return (it != _noreturn.end() && !it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isScopeNoReturn(const Token *end, std::string *unknownFunc) const;
|
||||||
|
|
||||||
class ArgumentChecks {
|
class ArgumentChecks {
|
||||||
public:
|
public:
|
||||||
ArgumentChecks() :
|
ArgumentChecks() :
|
||||||
|
|
|
@ -7834,50 +7834,17 @@ void Tokenizer::simplifyStd()
|
||||||
|
|
||||||
bool Tokenizer::IsScopeNoReturn(const Token *endScopeToken, bool *unknown) const
|
bool Tokenizer::IsScopeNoReturn(const Token *endScopeToken, bool *unknown) const
|
||||||
{
|
{
|
||||||
|
std::string unknownFunc;
|
||||||
|
bool ret = _settings->library.isScopeNoReturn(endScopeToken,&unknownFunc);
|
||||||
if (unknown)
|
if (unknown)
|
||||||
*unknown = false;
|
*unknown = !unknownFunc.empty();
|
||||||
|
if (!unknownFunc.empty() && _settings->checkLibrary && _settings->isEnabled("information")) {
|
||||||
if (Token::simpleMatch(endScopeToken->tokAt(-2), ") ; }")) {
|
reportError(endScopeToken->previous(),
|
||||||
const Token *tok = endScopeToken->linkAt(-2)->previous();
|
|
||||||
|
|
||||||
if (!tok)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// function pointer call..
|
|
||||||
if (Token::Match(tok->tokAt(-4), "[;{}] ( * %var% )"))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!tok->isName())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (tok->str() == "exit")
|
|
||||||
return true;
|
|
||||||
|
|
||||||
while (tok && (Token::Match(tok, "::|.") || tok->isName()))
|
|
||||||
tok = tok->previous();
|
|
||||||
|
|
||||||
if (Token::Match(tok, "[;{}] %var% (")) {
|
|
||||||
if (_settings->library.isnoreturn(tok->next()->str()))
|
|
||||||
return true;
|
|
||||||
if (_settings->library.isnotnoreturn(tok->next()->str()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (_settings->checkLibrary && _settings->isEnabled("information")) {
|
|
||||||
reportError(tok->next(),
|
|
||||||
Severity::information,
|
Severity::information,
|
||||||
"checkLibraryNoReturn",
|
"checkLibraryNoReturn",
|
||||||
"--check-library: Function " + tok->next()->str() + "() should have <noreturn> configuration");
|
"--check-library: Function " + unknownFunc + "() should have <noreturn> configuration");
|
||||||
}
|
}
|
||||||
}
|
return ret;
|
||||||
|
|
||||||
if (Token::Match(tok, "[;{}]")) {
|
|
||||||
if (unknown)
|
|
||||||
*unknown = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
|
@ -867,24 +867,12 @@ static void valueFlowAfterCondition(TokenList *tokenlist, ErrorLogger *errorLogg
|
||||||
// After conditional code..
|
// After conditional code..
|
||||||
if (ok && !scopeEnd.empty() && Token::simpleMatch(top->link(), ") {")) {
|
if (ok && !scopeEnd.empty() && Token::simpleMatch(top->link(), ") {")) {
|
||||||
Token *after = top->link()->linkAt(1);
|
Token *after = top->link()->linkAt(1);
|
||||||
if (Token::simpleMatch(after->tokAt(-2), ") ; }")) {
|
std::string unknownFunction;
|
||||||
const Token *funcname = after->linkAt(-2)->previous();
|
if (settings->library.isScopeNoReturn(after,&unknownFunction)) {
|
||||||
const Token *start = funcname;
|
if (settings->debugwarnings && !unknownFunction.empty())
|
||||||
if (funcname && Token::Match(funcname->tokAt(-3),"( * %var% )")) {
|
|
||||||
funcname = funcname->previous();
|
|
||||||
start = funcname->tokAt(-3);
|
|
||||||
} else {
|
|
||||||
while (Token::Match(start, "%var%|.|::"))
|
|
||||||
start = start->previous();
|
|
||||||
}
|
|
||||||
if (Token::Match(start,"[;{}]") && Token::Match(funcname, "%var% )| (")) {
|
|
||||||
if (!settings->library.isnotnoreturn(funcname->str())) {
|
|
||||||
if (settings->debugwarnings)
|
|
||||||
bailout(tokenlist, errorLogger, after, "possible noreturn scope");
|
bailout(tokenlist, errorLogger, after, "possible noreturn scope");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Token::simpleMatch(after, "} else {")) {
|
if (Token::simpleMatch(after, "} else {")) {
|
||||||
after = after->linkAt(2);
|
after = after->linkAt(2);
|
||||||
if (Token::simpleMatch(after->tokAt(-2), ") ; }")) {
|
if (Token::simpleMatch(after->tokAt(-2), ") ; }")) {
|
||||||
|
|
Loading…
Reference in New Issue