Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions lib/checkother.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,63 @@ void CheckOther::cstyleCastError(const Token *tok, bool isPtr)
"which kind of cast is expected.", CWE398, Certainty::normal);
}

void CheckOther::suspiciousFloatingPointCast()
{
if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("suspiciousFloatingPointCast"))
return;

logChecker("CheckOther::suspiciousFloatingPointCast"); // style

const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
for (const Scope * scope : symbolDatabase->functionScopes) {
const Token* tok = scope->bodyStart;
if (scope->function && scope->function->isConstructor())
tok = scope->classDef;
for (; tok && tok != scope->bodyEnd; tok = tok->next()) {

if (!tok->isCast())
continue;

const ValueType* vt = tok->valueType();
if (!vt || vt->pointer || vt->reference != Reference::None || (vt->type != ValueType::FLOAT && vt->type != ValueType::DOUBLE))
continue;

using VTT = std::vector<ValueType::Type>;
const VTT sourceTypes = vt->type == ValueType::FLOAT ? VTT{ ValueType::DOUBLE, ValueType::LONGDOUBLE } : VTT{ ValueType::LONGDOUBLE };

const Token* source = tok->astOperand2() ? tok->astOperand2() : tok->astOperand1();
if (!source || !source->valueType() || std::find(sourceTypes.begin(), sourceTypes.end(), source->valueType()->type) == sourceTypes.end())
continue;

const Token* parent = tok->astParent();
if (!parent)
continue;

const ValueType* parentVt = parent->valueType();
if (!parentVt || parent->str() == "(") {
int argn{};
if (const Token* ftok = getTokenArgumentFunction(tok, argn)) {
if (ftok->function()) {
if (const Variable* argVar = ftok->function()->getArgumentVar(argn))
parentVt = argVar->valueType();
}
}
}
if (!parentVt || std::find(sourceTypes.begin(), sourceTypes.end(), parentVt->type) == sourceTypes.end())
continue;

suspiciousFloatingPointCastError(tok);
}
}
}

void CheckOther::suspiciousFloatingPointCastError(const Token* tok)
{
reportError(tok, Severity::style, "suspiciousFloatingPointCast",
"Floating-point cast causes loss of precision.\n"
"If this cast is not intentional, remove it to avoid loss of precision", CWE398, Certainty::normal);
}

//---------------------------------------------------------------------------
// float* f; double* d = (double*)f; <-- Pointer cast to a type with an incompatible binary data representation
//---------------------------------------------------------------------------
Expand Down
5 changes: 5 additions & 0 deletions lib/checkother.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class CPPCHECKLIB CheckOther : public Check {

// Checks
checkOther.warningOldStylePointerCast();
checkOther.suspiciousFloatingPointCast();
checkOther.invalidPointerCast();
checkOther.checkCharVariable();
checkOther.redundantBitwiseOperationInSwitchError();
Expand Down Expand Up @@ -125,6 +126,8 @@ class CPPCHECKLIB CheckOther : public Check {
/** @brief Are there C-style pointer casts in a c++ file? */
void warningOldStylePointerCast();

void suspiciousFloatingPointCast();

/** @brief Check for pointer casts to a type with an incompatible binary data representation */
void invalidPointerCast();

Expand Down Expand Up @@ -241,6 +244,7 @@ class CPPCHECKLIB CheckOther : public Check {
void clarifyCalculationError(const Token *tok, const std::string &op);
void clarifyStatementError(const Token* tok);
void cstyleCastError(const Token *tok, bool isPtr = true);
void suspiciousFloatingPointCastError(const Token *tok);
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);
Expand Down Expand Up @@ -314,6 +318,7 @@ class CPPCHECKLIB CheckOther : public Check {
c.checkComparisonFunctionIsAlwaysTrueOrFalseError(nullptr, "isless","varName",false);
c.checkCastIntToCharAndBackError(nullptr, "func_name");
c.cstyleCastError(nullptr);
c.suspiciousFloatingPointCastError(nullptr);
c.passedByValueError(nullptr, false);
c.constVariableError(nullptr, nullptr);
c.constStatementError(nullptr, "type", false);
Expand Down
2 changes: 1 addition & 1 deletion releasenotes.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Release Notes for Cppcheck 2.15

New checks:
-
- suspiciousFloatingPointCast flags unnecessary floating point casts that cause loss of precision

Improved checking:
-
Expand Down
28 changes: 28 additions & 0 deletions test/testother.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ class TestOther : public TestFixture {
TEST_CASE(suspiciousCase);
TEST_CASE(suspiciousEqualityComparison);
TEST_CASE(suspiciousUnaryPlusMinus); // #8004
TEST_CASE(suspiciousFloatingPointCast);

TEST_CASE(selfAssignment);
TEST_CASE(trac1132);
Expand Down Expand Up @@ -5594,6 +5595,33 @@ class TestOther : public TestFixture {
errout_str());
}

void suspiciousFloatingPointCast() {
check("double f(double a, double b, float c) {\n"
" return a + (float)b + c;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Floating-point cast causes loss of precision.\n", errout_str());

check("double f(double a, double b, float c) {\n"
" return a + static_cast<float>(b) + c;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Floating-point cast causes loss of precision.\n", errout_str());

check("long double f(long double a, long double b, float c) {\n"
" return a + (double)b + c;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2]: (style) Floating-point cast causes loss of precision.\n", errout_str());

check("void g(int, double);\n"
"void h(double);\n"
"void f(double d) {\n"
" g(1, (float)d);\n"
" h((float)d);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (style) Floating-point cast causes loss of precision.\n"
"[test.cpp:5]: (style) Floating-point cast causes loss of precision.\n",
errout_str());
}

void selfAssignment() {
check("void foo()\n"
"{\n"
Expand Down