Amend fix for #11449 Function call not recognized (#4838)

This commit is contained in:
chrchr-github 2023-03-02 21:45:15 +01:00 committed by GitHub
parent 7c73ecfec7
commit 491299048b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 85 additions and 47 deletions

View File

@ -6789,6 +6789,20 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<not-uninit/> <not-uninit/>
</arg> </arg>
</function> </function>
<!-- https://en.cppreference.com/w/cpp/utility/exchange -->
<!-- template< class T, class U = T > constexpr T exchange( T& obj, U&& new_value ) -->
<function name="std::exchange">
<leak-ignore/>
<noreturn>false</noreturn>
<use-retval/>
<returnValue>arg1</returnValue>
<arg nr="1">
<not-uninit/>
</arg>
<arg nr="2">
<not-uninit/>
</arg>
</function>
<!-- https://en.cppreference.com/w/cpp/memory/addressof --> <!-- https://en.cppreference.com/w/cpp/memory/addressof -->
<!-- template< class T > constexpr T* addressof( T& arg ) noexcept; --> <!-- template< class T > constexpr T* addressof( T& arg ) noexcept; -->
<function name="std::addressof"> <function name="std::addressof">

View File

@ -1220,54 +1220,52 @@ SmallVector<ReferenceToken> followAllReferences(const Token* tok,
return refs_result; return refs_result;
} }
} else if (Token::Match(tok->previous(), "%name% (")) { } else if (tok->previous() && tok->previous()->function() && Token::Match(tok->previous(), "%name% (")) {
const Function *f = tok->previous()->function(); const Function *f = tok->previous()->function();
if (f) { if (!Function::returnsReference(f)) {
if (!Function::returnsReference(f)) { refs_result.push_back({tok, std::move(errors)});
refs_result.push_back({tok, std::move(errors)}); return refs_result;
return refs_result; }
} std::set<ReferenceToken, ReferenceTokenLess> result;
std::set<ReferenceToken, ReferenceTokenLess> result; std::vector<const Token*> returns = Function::findReturns(f);
std::vector<const Token*> returns = Function::findReturns(f); for (const Token* returnTok : returns) {
for (const Token* returnTok : returns) { if (returnTok == tok)
if (returnTok == tok) continue;
continue; for (const ReferenceToken& rt :
for (const ReferenceToken& rt : followAllReferences(returnTok, temporary, inconclusive, errors, depth - returns.size())) {
followAllReferences(returnTok, temporary, inconclusive, errors, depth - returns.size())) { const Variable* argvar = rt.token->variable();
const Variable* argvar = rt.token->variable(); if (!argvar) {
if (!argvar) { refs_result.push_back({tok, std::move(errors)});
return refs_result;
}
if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) {
const int n = getArgumentPos(argvar, f);
if (n < 0) {
refs_result.push_back({tok, std::move(errors)}); refs_result.push_back({tok, std::move(errors)});
return refs_result; return refs_result;
} }
if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) { std::vector<const Token*> args = getArguments(tok->previous());
const int n = getArgumentPos(argvar, f); if (n >= args.size()) {
if (n < 0) { refs_result.push_back({tok, std::move(errors)});
refs_result.push_back({tok, std::move(errors)}); return refs_result;
return refs_result; }
} const Token* argTok = args[n];
std::vector<const Token*> args = getArguments(tok->previous()); ErrorPath er = errors;
if (n >= args.size()) { er.emplace_back(returnTok, "Return reference.");
refs_result.push_back({tok, std::move(errors)}); er.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'.");
return refs_result; auto refs =
} followAllReferences(argTok, temporary, inconclusive, std::move(er), depth - returns.size());
const Token* argTok = args[n]; result.insert(refs.cbegin(), refs.cend());
ErrorPath er = errors; if (!inconclusive && result.size() > 1) {
er.emplace_back(returnTok, "Return reference."); refs_result.push_back({tok, std::move(errors)});
er.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'."); return refs_result;
auto refs =
followAllReferences(argTok, temporary, inconclusive, std::move(er), depth - returns.size());
result.insert(refs.cbegin(), refs.cend());
if (!inconclusive && result.size() > 1) {
refs_result.push_back({tok, std::move(errors)});
return refs_result;
}
} }
} }
} }
if (!result.empty()) { }
refs_result.insert(refs_result.end(), result.cbegin(), result.cend()); if (!result.empty()) {
return refs_result; refs_result.insert(refs_result.end(), result.cbegin(), result.cend());
} return refs_result;
} }
} }
refs_result.push_back({tok, std::move(errors)}); refs_result.push_back({tok, std::move(errors)});
@ -1583,8 +1581,8 @@ bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2
} }
} }
// templates/casts // templates/casts
if ((Token::Match(tok1, "%name% <") && tok1->next()->link()) || if ((tok1->next() && tok1->next()->link() && Token::Match(tok1, "%name% <")) ||
(Token::Match(tok2, "%name% <") && tok2->next()->link())) { (tok2->next() && tok2->next()->link() && Token::Match(tok2, "%name% <"))) {
// non-const template function that is not a dynamic_cast => return false // non-const template function that is not a dynamic_cast => return false
if (pure && Token::simpleMatch(tok1->next()->link(), "> (") && if (pure && Token::simpleMatch(tok1->next()->link(), "> (") &&

View File

@ -471,9 +471,17 @@ static const Token *getCastTypeStartToken(const Token *parent, const Settings* s
return parent->astOperand1(); return parent->astOperand1();
if (parent->str() != "(") if (parent->str() != "(")
return nullptr; return nullptr;
if (!parent->astOperand2() && Token::Match(parent, "( %name%") && if (!parent->astOperand2() && Token::Match(parent, "( %name%|::")) {
(parent->next()->isStandardType() || settings->library.isNotLibraryFunction(parent->next()))) const Token* ftok = parent->next();
return parent->next(); if (ftok->isStandardType())
return ftok;
if (Token::simpleMatch(ftok, "::"))
ftok = ftok->next();
while (Token::Match(ftok, "%name% ::"))
ftok = ftok->tokAt(2);
if (settings->library.isNotLibraryFunction(ftok))
return parent->next();
}
if (parent->astOperand2() && Token::Match(parent->astOperand1(), "const_cast|dynamic_cast|reinterpret_cast|static_cast <")) if (parent->astOperand2() && Token::Match(parent->astOperand1(), "const_cast|dynamic_cast|reinterpret_cast|static_cast <"))
return parent->astOperand1()->tokAt(2); return parent->astOperand1()->tokAt(2);
return nullptr; return nullptr;
@ -7376,7 +7384,7 @@ static void valueFlowSubFunction(TokenList* tokenlist, SymbolDatabase* symboldat
if (!function) if (!function)
continue; continue;
for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) { for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
if (!Token::Match(tok, "%name% (")) if (tok->isKeyword() || !Token::Match(tok, "%name% ("))
continue; continue;
const Function * const calledFunction = tok->function(); const Function * const calledFunction = tok->function();

View File

@ -40,6 +40,7 @@
#include <string_view> #include <string_view>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <utility>
#include <vector> #include <vector>
#include <version> #include <version>
#ifdef __cpp_lib_span #ifdef __cpp_lib_span
@ -4561,6 +4562,13 @@ void stdbind()
auto f2 = std::bind(stdbind_helper, 10); auto f2 = std::bind(stdbind_helper, 10);
} }
int stdexchange() {
int i;
// cppcheck-suppress uninitvar
int j = std::exchange(i, 5);
return j;
}
class A class A
{ {
std::vector<std::string> m_str; std::vector<std::string> m_str;

View File

@ -4492,6 +4492,16 @@ private:
" }\n" " }\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:6]: (style) Condition 'o[1]=='\\0'' is always false\n", errout.str()); ASSERT_EQUALS("[test.cpp:6]: (style) Condition 'o[1]=='\\0'' is always false\n", errout.str());
check("void f(int x) {\n" // #11449
" int i = x;\n"
" i = (std::min)(i, 1);\n"
" if (i == 1) {}\n"
" int j = x;\n"
" j = (::std::min)(j, 1);\n"
" if (j == 1) {}\n"
"}\n");
ASSERT_EQUALS("", errout.str());
} }
void alwaysTrueSymbolic() void alwaysTrueSymbolic()