Fix #11513 FN functionConst with comparison as argument (#4738)

This commit is contained in:
chrchr-github 2023-03-12 11:39:18 +01:00 committed by GitHub
parent 809430631f
commit 9ed21fb917
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 48 additions and 14 deletions

View File

@ -2306,6 +2306,19 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool&
return false; return false;
memberAccessed = true; memberAccessed = true;
} }
bool mayModifyArgs = true;
if (const Function* f = funcTok->function()) { // TODO: improve (we bail out if there is any possible modification of any argument)
const std::vector<const Token*> args = getArguments(funcTok);
const auto argMax = std::min<nonneg int>(args.size(), f->argCount());
mayModifyArgs = false;
for (nonneg int argIndex = 0; argIndex < argMax; ++argIndex) {
const Variable* const argVar = f->getArgumentVar(argIndex);
if (!argVar || !argVar->valueType() || ((argVar->valueType()->pointer || argVar->valueType()->reference != Reference::None) && !argVar->isConst())) {
mayModifyArgs = true;
break;
}
}
}
// Member variable given as parameter // Member variable given as parameter
const Token *lpar = funcTok->next(); const Token *lpar = funcTok->next();
if (Token::simpleMatch(lpar, "( ) (")) if (Token::simpleMatch(lpar, "( ) ("))
@ -2313,9 +2326,9 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool&
for (const Token* tok = lpar->next(); tok && tok != funcTok->next()->link(); tok = tok->next()) { for (const Token* tok = lpar->next(); tok && tok != funcTok->next()->link(); tok = tok->next()) {
if (tok->str() == "(") if (tok->str() == "(")
tok = tok->link(); tok = tok->link();
else if ((tok->isName() && isMemberVar(scope, tok)) || (tok->isUnaryOp("&") && (tok = tok->astOperand1()))) { else if ((tok->isName() && isMemberVar(scope, tok)) || (tok->isUnaryOp("&") && (tok = tok->astOperand1()) && isMemberVar(scope, tok))) {
const Variable* var = tok->variable(); const Variable* var = tok->variable();
if (!var || !var->isMutable()) if ((!var || !var->isMutable()) && mayModifyArgs)
return false; // TODO: Only bailout if function takes argument as non-const reference return false; // TODO: Only bailout if function takes argument as non-const reference
} }
} }

View File

@ -145,7 +145,7 @@ public:
bool isUnusedFunctionCheckEnabled() const; bool isUnusedFunctionCheckEnabled() const;
/** Remove *.ctu-info files */ /** Remove *.ctu-info files */
void removeCtuInfoFiles(const std::map<std::string, std::size_t>& files); void removeCtuInfoFiles(const std::map<std::string, std::size_t>& files); // cppcheck-suppress functionConst // has side effects
private: private:
/** Are there "simple" rules */ /** Are there "simple" rules */

View File

@ -1474,12 +1474,12 @@ private:
void createSymbolDatabaseNeedInitialization(); void createSymbolDatabaseNeedInitialization();
void createSymbolDatabaseVariableSymbolTable(); void createSymbolDatabaseVariableSymbolTable();
void createSymbolDatabaseSetScopePointers(); void createSymbolDatabaseSetScopePointers();
void createSymbolDatabaseSetFunctionPointers(bool firstPass); void createSymbolDatabaseSetFunctionPointers(bool firstPass); // cppcheck-suppress functionConst // has side effects
void createSymbolDatabaseSetVariablePointers(); void createSymbolDatabaseSetVariablePointers();
// cppcheck-suppress functionConst // cppcheck-suppress functionConst
void createSymbolDatabaseSetTypePointers(); void createSymbolDatabaseSetTypePointers();
void createSymbolDatabaseSetSmartPointerType(); void createSymbolDatabaseSetSmartPointerType();
void createSymbolDatabaseEnums(); void createSymbolDatabaseEnums(); // cppcheck-suppress functionConst // has side effects
void createSymbolDatabaseEscapeFunctions(); void createSymbolDatabaseEscapeFunctions();
// cppcheck-suppress functionConst // cppcheck-suppress functionConst
void createSymbolDatabaseIncompleteVars(); void createSymbolDatabaseIncompleteVars();

View File

@ -586,7 +586,7 @@ private:
void unsupportedTypedef(const Token *tok) const; void unsupportedTypedef(const Token *tok) const;
void setVarIdClassDeclaration(const Token * const startToken, void setVarIdClassDeclaration(const Token * const startToken, // cppcheck-suppress functionConst // has side effects
VariableMap &variableMap, VariableMap &variableMap,
const nonneg int scopeStartVarId, const nonneg int scopeStartVarId,
std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers); std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers);
@ -595,7 +595,7 @@ private:
std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers, std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
nonneg int &varId) const; nonneg int &varId) const;
void setVarIdClassFunction(const std::string &classname, void setVarIdClassFunction(const std::string &classname, // cppcheck-suppress functionConst // has side effects
Token * const startToken, Token * const startToken,
const Token * const endToken, const Token * const endToken,
const std::map<std::string, nonneg int> &varlist, const std::map<std::string, nonneg int> &varlist,

View File

@ -195,7 +195,9 @@ private:
TEST_CASE(const79); // ticket #9861 TEST_CASE(const79); // ticket #9861
TEST_CASE(const80); // ticket #11328 TEST_CASE(const80); // ticket #11328
TEST_CASE(const81); // ticket #11330 TEST_CASE(const81); // ticket #11330
TEST_CASE(const82); TEST_CASE(const82); // ticket #11513
TEST_CASE(const83);
TEST_CASE(const_handleDefaultParameters); TEST_CASE(const_handleDefaultParameters);
TEST_CASE(const_passThisToMemberOfOtherClass); TEST_CASE(const_passThisToMemberOfOtherClass);
TEST_CASE(assigningPointerToPointerIsNotAConstOperation); TEST_CASE(assigningPointerToPointerIsNotAConstOperation);
@ -6322,7 +6324,26 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void const82() { void const82() { // #11513
checkConst("struct S {\n"
" int i;\n"
" void h(bool) const;\n"
" void g() { h(i == 1); }\n"
"};\n");
ASSERT_EQUALS("[test.cpp:4]: (style, inconclusive) Technically the member function 'S::g' can be const.\n",
errout.str());
checkConst("struct S {\n"
" int i;\n"
" void h(int, int*) const;\n"
" void g() { int a; h(i, &a); }\n"
"};\n");
TODO_ASSERT_EQUALS("[test.cpp:4]: (style, inconclusive) Technically the member function 'S::g' can be const.\n",
"",
errout.str());
}
void const83() {
checkConst("struct S {\n" checkConst("struct S {\n"
" int i1, i2;\n" " int i1, i2;\n"
" void f(bool b);\n" " void f(bool b);\n"

View File

@ -561,7 +561,7 @@ private:
ASSERT_EQUALS(true, suppressions6.isSuppressed(errorMessage("abc", "test.cpp", 123))); ASSERT_EQUALS(true, suppressions6.isSuppressed(errorMessage("abc", "test.cpp", 123)));
} }
void inlinesuppress() { void inlinesuppress() const {
Suppressions::Suppression s; Suppressions::Suppression s;
std::string msg; std::string msg;
ASSERT_EQUALS(false, s.parseComment("/* some text */", &msg)); ASSERT_EQUALS(false, s.parseComment("/* some text */", &msg));
@ -593,7 +593,7 @@ private:
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: a\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: a\n", errout.str());
} }
void inlinesuppress_comment() { void inlinesuppress_comment() const {
Suppressions::Suppression s; Suppressions::Suppression s;
std::string errMsg; std::string errMsg;
ASSERT_EQUALS(true, s.parseComment("// cppcheck-suppress abc ; some comment", &errMsg)); ASSERT_EQUALS(true, s.parseComment("// cppcheck-suppress abc ; some comment", &errMsg));
@ -604,7 +604,7 @@ private:
ASSERT_EQUALS("", errMsg); ASSERT_EQUALS("", errMsg);
} }
void multi_inlinesuppress() { void multi_inlinesuppress() const {
std::vector<Suppressions::Suppression> suppressions; std::vector<Suppressions::Suppression> suppressions;
std::string errMsg; std::string errMsg;
@ -669,7 +669,7 @@ private:
ASSERT_EQUALS(false, errMsg.empty()); ASSERT_EQUALS(false, errMsg.empty());
} }
void multi_inlinesuppress_comment() { void multi_inlinesuppress_comment() const {
std::vector<Suppressions::Suppression> suppressions; std::vector<Suppressions::Suppression> suppressions;
std::string errMsg; std::string errMsg;

View File

@ -7171,7 +7171,7 @@ private:
ASSERT(tok->tokAt(2)->function()); ASSERT(tok->tokAt(2)->function());
} }
void valueTypeMatchParameter() { void valueTypeMatchParameter() const {
ValueType vt_int(ValueType::Sign::SIGNED, ValueType::Type::INT, 0); ValueType vt_int(ValueType::Sign::SIGNED, ValueType::Type::INT, 0);
ValueType vt_const_int(ValueType::Sign::SIGNED, ValueType::Type::INT, 0, 1); ValueType vt_const_int(ValueType::Sign::SIGNED, ValueType::Type::INT, 0, 1);
ASSERT_EQUALS((int)ValueType::MatchResult::SAME, (int)ValueType::matchParameter(&vt_int, &vt_int)); ASSERT_EQUALS((int)ValueType::MatchResult::SAME, (int)ValueType::matchParameter(&vt_int, &vt_int));