From cec4b11ce261866fc47089c4f6b92435eac70878 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 21 Feb 2024 17:16:15 +0100 Subject: [PATCH] Fix #12447 FN cstyleCast when casting to reference (#5998) --- lib/checkother.cpp | 23 +++++++++++++++-------- lib/checkother.h | 2 +- test/testother.cpp | 19 +++++++++++++++---- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 4438338b7bc..b588bfae75b 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -321,11 +321,17 @@ void CheckOther::warningOldStylePointerCast() if (Token::simpleMatch(castTok, "<") && castTok->link()) castTok = castTok->link()->next(); } - if (castTok == tok->next() || !Token::simpleMatch(castTok, "*")) - continue; - while (Token::Match(castTok, "*|const|&")) + if (castTok == tok->next()) + continue; + bool isPtr = false, isRef = false; + while (Token::Match(castTok, "*|const|&")) { + if (castTok->str() == "*") + isPtr = true; + else if (castTok->str() == "&") + isRef = true; castTok = castTok->next(); - if (!Token::Match(castTok, ") (| %name%|%num%|%bool%|%char%|%str%|&")) + } + if ((!isPtr && !isRef) || !Token::Match(castTok, ") (| %name%|%num%|%bool%|%char%|%str%|&")) continue; if (Token::Match(tok->previous(), "%type%")) @@ -344,16 +350,17 @@ void CheckOther::warningOldStylePointerCast() continue; if (typeTok->tokType() == Token::eType || typeTok->tokType() == Token::eName) - cstyleCastError(tok); + cstyleCastError(tok, isPtr); } } } -void CheckOther::cstyleCastError(const Token *tok) +void CheckOther::cstyleCastError(const Token *tok, bool isPtr) { + const std::string type = isPtr ? "pointer" : "reference"; reportError(tok, Severity::style, "cstyleCast", - "C-style pointer casting\n" - "C-style pointer casting detected. C++ offers four different kinds of casts as replacements: " + "C-style " + type + " casting\n" + "C-style " + type + " casting detected. C++ offers four different kinds of casts as replacements: " "static_cast, const_cast, dynamic_cast and reinterpret_cast. A C-style cast could evaluate to " "any of those automatically, thus it is considered safer if the programmer explicitly states " "which kind of cast is expected.", CWE398, Certainty::normal); diff --git a/lib/checkother.h b/lib/checkother.h index 5f52e3092d9..1b7d080e7e5 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -239,7 +239,7 @@ class CPPCHECKLIB CheckOther : public Check { void checkCastIntToCharAndBackError(const Token *tok, const std::string &strFunctionName); void clarifyCalculationError(const Token *tok, const std::string &op); void clarifyStatementError(const Token* tok); - void cstyleCastError(const Token *tok); + void cstyleCastError(const Token *tok, bool isPtr = true); void invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive, bool toIsInt); void passedByValueError(const Variable* var, bool inconclusive, bool isRangeBasedFor = false); void constVariableError(const Variable *var, const Function *function); diff --git a/test/testother.cpp b/test/testother.cpp index fd0bd743878..c1b7260e9ac 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -1911,6 +1911,13 @@ class TestOther : public TestFixture { "[test.cpp:8]: (style) C-style pointer casting\n" "[test.cpp:9]: (style) C-style pointer casting\n", errout.str()); + + // #12447 + checkOldStylePointerCast("void f(const int& i) {\n" + " int& r = (int&)i;\n" + " r = 0;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2]: (style) C-style reference casting\n", errout.str()); } #define checkInvalidPointerCast(...) checkInvalidPointerCast_(__FILE__, __LINE__, __VA_ARGS__) @@ -2884,27 +2891,31 @@ class TestOther : public TestFixture { " x.dostuff();\n" " const U& y = (const U&)(x);\n" "}"); - ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (style) C-style reference casting\n" + "[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", + errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " U& y = (U&)(x);\n" " y.mutate();\n" // to avoid warnings that y can be const "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (style) C-style reference casting\n", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " const U& y = (typename const U&)(x);\n" "}"); - ASSERT_EQUALS("[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (style) C-style reference casting\n" + "[test.cpp:2]: (style) Parameter 'x' can be declared as reference to const\n", + errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n" " U& y = (typename U&)(x);\n" " y.mutate();\n" // to avoid warnings that y can be const "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:4]: (style) C-style reference casting\n", errout.str()); check("struct T : public U { void dostuff() const {}};\n" "void a(T& x) {\n" " x.dostuff();\n"