parent
7c73ecfec7
commit
491299048b
14
cfg/std.cfg
14
cfg/std.cfg
|
@ -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">
|
||||||
|
|
|
@ -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(), "> (") &&
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue