From 491299048bc21ea8e0beb59d113cd44b18774528 Mon Sep 17 00:00:00 2001
From: chrchr-github <78114321+chrchr-github@users.noreply.github.com>
Date: Thu, 2 Mar 2023 21:45:15 +0100
Subject: [PATCH] Amend fix for #11449 Function call not recognized (#4838)
---
cfg/std.cfg | 14 +++++++
lib/astutils.cpp | 84 +++++++++++++++++++++---------------------
lib/valueflow.cpp | 16 ++++++--
test/cfg/std.cpp | 8 ++++
test/testcondition.cpp | 10 +++++
5 files changed, 85 insertions(+), 47 deletions(-)
diff --git a/cfg/std.cfg b/cfg/std.cfg
index dec4d8988..1e2544afb 100644
--- a/cfg/std.cfg
+++ b/cfg/std.cfg
@@ -6789,6 +6789,20 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
+
+
+
+
+ false
+
+ arg1
+
+
+
+
+
+
+
diff --git a/lib/astutils.cpp b/lib/astutils.cpp
index 07d052b96..cc28af023 100644
--- a/lib/astutils.cpp
+++ b/lib/astutils.cpp
@@ -1220,54 +1220,52 @@ SmallVector followAllReferences(const Token* tok,
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();
- if (f) {
- if (!Function::returnsReference(f)) {
- refs_result.push_back({tok, std::move(errors)});
- return refs_result;
- }
- std::set result;
- std::vector returns = Function::findReturns(f);
- for (const Token* returnTok : returns) {
- if (returnTok == tok)
- continue;
- for (const ReferenceToken& rt :
- followAllReferences(returnTok, temporary, inconclusive, errors, depth - returns.size())) {
- const Variable* argvar = rt.token->variable();
- if (!argvar) {
+ if (!Function::returnsReference(f)) {
+ refs_result.push_back({tok, std::move(errors)});
+ return refs_result;
+ }
+ std::set result;
+ std::vector returns = Function::findReturns(f);
+ for (const Token* returnTok : returns) {
+ if (returnTok == tok)
+ continue;
+ for (const ReferenceToken& rt :
+ followAllReferences(returnTok, temporary, inconclusive, errors, depth - returns.size())) {
+ const Variable* argvar = rt.token->variable();
+ 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)});
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)});
- return refs_result;
- }
- std::vector args = getArguments(tok->previous());
- if (n >= args.size()) {
- refs_result.push_back({tok, std::move(errors)});
- return refs_result;
- }
- const Token* argTok = args[n];
- ErrorPath er = errors;
- er.emplace_back(returnTok, "Return reference.");
- er.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'.");
- 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;
- }
+ std::vector args = getArguments(tok->previous());
+ if (n >= args.size()) {
+ refs_result.push_back({tok, std::move(errors)});
+ return refs_result;
+ }
+ const Token* argTok = args[n];
+ ErrorPath er = errors;
+ er.emplace_back(returnTok, "Return reference.");
+ er.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'.");
+ 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());
- return refs_result;
- }
+ }
+ if (!result.empty()) {
+ refs_result.insert(refs_result.end(), result.cbegin(), result.cend());
+ return refs_result;
}
}
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
- if ((Token::Match(tok1, "%name% <") && tok1->next()->link()) ||
- (Token::Match(tok2, "%name% <") && tok2->next()->link())) {
+ if ((tok1->next() && tok1->next()->link() && Token::Match(tok1, "%name% <")) ||
+ (tok2->next() && tok2->next()->link() && Token::Match(tok2, "%name% <"))) {
// non-const template function that is not a dynamic_cast => return false
if (pure && Token::simpleMatch(tok1->next()->link(), "> (") &&
diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp
index 524f60478..bfdf1eba6 100644
--- a/lib/valueflow.cpp
+++ b/lib/valueflow.cpp
@@ -471,9 +471,17 @@ static const Token *getCastTypeStartToken(const Token *parent, const Settings* s
return parent->astOperand1();
if (parent->str() != "(")
return nullptr;
- if (!parent->astOperand2() && Token::Match(parent, "( %name%") &&
- (parent->next()->isStandardType() || settings->library.isNotLibraryFunction(parent->next())))
- return parent->next();
+ if (!parent->astOperand2() && Token::Match(parent, "( %name%|::")) {
+ const Token* ftok = 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 <"))
return parent->astOperand1()->tokAt(2);
return nullptr;
@@ -7376,7 +7384,7 @@ static void valueFlowSubFunction(TokenList* tokenlist, SymbolDatabase* symboldat
if (!function)
continue;
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;
const Function * const calledFunction = tok->function();
diff --git a/test/cfg/std.cpp b/test/cfg/std.cpp
index 3eb781b13..bc7c3aee5 100644
--- a/test/cfg/std.cpp
+++ b/test/cfg/std.cpp
@@ -40,6 +40,7 @@
#include
#include
#include
+#include
#include
#include
#ifdef __cpp_lib_span
@@ -4561,6 +4562,13 @@ void stdbind()
auto f2 = std::bind(stdbind_helper, 10);
}
+int stdexchange() {
+ int i;
+ // cppcheck-suppress uninitvar
+ int j = std::exchange(i, 5);
+ return j;
+}
+
class A
{
std::vector m_str;
diff --git a/test/testcondition.cpp b/test/testcondition.cpp
index f46378a7b..f6b261adc 100644
--- a/test/testcondition.cpp
+++ b/test/testcondition.cpp
@@ -4492,6 +4492,16 @@ private:
" }\n"
"}\n");
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()