From 2c8087e34f3e7b6f9a2ee259aa27e5f221a11327 Mon Sep 17 00:00:00 2001 From: Alexander Mai Date: Sat, 24 May 2014 18:35:49 +0200 Subject: [PATCH] #4375 New check: add style warning about 'double d=false;' Add a new check to CheckBool. Also implement Variable::isFloatingType() --- lib/checkbool.cpp | 26 ++++++++ lib/checkbool.h | 5 ++ lib/symboldatabase.h | 17 ++++++ test/testbool.cpp | 18 ++++++ test/testsymboldatabase.cpp | 116 ++++++++++++++++++++++++++++++++++++ 5 files changed, 182 insertions(+) diff --git a/lib/checkbool.cpp b/lib/checkbool.cpp index c4ade234a..d3853532a 100644 --- a/lib/checkbool.cpp +++ b/lib/checkbool.cpp @@ -472,3 +472,29 @@ void CheckBool::pointerArithBoolError(const Token *tok) "Converting pointer arithmetic result to bool. The bool is always true unless there is undefined behaviour.\n" "Converting pointer arithmetic result to bool. The boolean result is always true unless there is pointer arithmetic overflow, and overflow is undefined behaviour. Probably a dereference is forgotten."); } + +void CheckBool::checkAssignBoolToFloat() +{ + if (!_tokenizer->isCPP()) + return; + if (!_settings->isEnabled("style")) + return; + const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); + const std::size_t functions = symbolDatabase->functionScopes.size(); + for (std::size_t i = 0; i < functions; ++i) { + const Scope * scope = symbolDatabase->functionScopes[i]; + for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) { + if (Token::Match(tok, "!!* %var% = %bool% ;")) { + const Variable *var = symbolDatabase->getVariableFromVarId(tok->next()->varId()); + if (var->isFloatingType()) + assignBoolToFloatError(tok->next()); + } + } + } +} + +void CheckBool::assignBoolToFloatError(const Token *tok) +{ + reportError(tok, Severity::style, "assignBoolToFloat", + "Boolean value assigned to floating point variable."); +} diff --git a/lib/checkbool.h b/lib/checkbool.h index c773a5445..05fb33875 100644 --- a/lib/checkbool.h +++ b/lib/checkbool.h @@ -52,6 +52,7 @@ public: // Checks checkBool.checkComparisonOfBoolExpressionWithInt(); checkBool.checkComparisonOfBoolWithInt(); + checkBool.checkAssignBoolToFloat(); checkBool.pointerArithBool(); } @@ -82,6 +83,9 @@ public: /** @brief assigning bool to pointer */ void checkAssignBoolToPointer(); + /** @brief assigning bool to float */ + void checkAssignBoolToFloat(); + /** @brief %Check for using bool in bitwise expression */ void checkBitwiseOnBoolean(); @@ -101,6 +105,7 @@ private: void comparisonOfBoolWithIntError(const Token *tok, const std::string &expression, bool n0o1); void comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression); void assignBoolToPointerError(const Token *tok); + void assignBoolToFloatError(const Token *tok); void bitwiseOnBooleanError(const Token *tok, const std::string &varname, const std::string &op); void comparisonOfBoolExpressionWithIntError(const Token *tok, bool n0o1); void pointerArithBoolError(const Token *tok); diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index cc806b813..53ce30eb1 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -471,6 +471,23 @@ public: return isStlType() && std::binary_search(stlTypes, stlTypes + array_length, _start->strAt(2)); } + /** + * Determine whether it's a floating number type + * @return true if the type is known and it's a floating type (float, double and long double) + */ + bool isFloatingType() const { + return (typeStartToken()->str() == "float" || typeStartToken()->str() == "double") && !isArrayOrPointer() ; + } + + /** + * Determine whether it's an integral number type + * @return true if the type is known and it's an integral type (bool, char, short, int, long long and their unsigned counter parts) + */ + bool isIntegralType() const { + return typeStartToken()->str() == "bool" || typeStartToken()->str() == "char" || typeStartToken()->str() == "short" || typeStartToken()->str() == "int" || typeStartToken()->str() == "long"; + } + + private: // only symbol database can change the type friend class SymbolDatabase; diff --git a/test/testbool.cpp b/test/testbool.cpp index eff43c244..8c725f01b 100644 --- a/test/testbool.cpp +++ b/test/testbool.cpp @@ -36,6 +36,7 @@ private: TEST_CASE(bitwiseOnBoolean); // if (bool & bool) TEST_CASE(incrementBoolean); TEST_CASE(assignBoolToPointer); + TEST_CASE(assignBoolToFloat); TEST_CASE(comparisonOfBoolExpressionWithInt1); TEST_CASE(comparisonOfBoolExpressionWithInt2); @@ -139,6 +140,23 @@ private: ASSERT_EQUALS("", errout.str()); } + void assignBoolToFloat() { + check("void foo1() {\n" + " double d = false;\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (style) Boolean value assigned to floating point variable.\n", errout.str()); + + check("void foo2() {\n" + " float d = true;\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (style) Boolean value assigned to floating point variable.\n", errout.str()); + + check("void foo3() {\n" + " long double d = (2>1);\n" + "}"); + TODO_ASSERT_EQUALS("[test.cpp:2]: (style) Boolean value assigned to floating point variable.\n", "", errout.str()); + } + void comparisonOfBoolExpressionWithInt1() { check("void f(int x) {\n" " if ((x && 0x0f)==6)\n" diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 293dda82d..49b2b4a35 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -240,6 +240,10 @@ private: TEST_CASE(nothrowAttributeFunction); TEST_CASE(nothrowDeclspecFunction); + + TEST_CASE(varTypesIntegral); // known integral + TEST_CASE(varTypesFloating); // known floating + TEST_CASE(varTypesOther); // (un)known } void array() const { @@ -2238,6 +2242,118 @@ private: } } + void varTypesIntegral() { + GET_SYMBOL_DB("void f() { bool b; char c; unsigned char uc; short s; unsigned short us; int i; unsigned u; unsigned int ui; long l; unsigned long ul; long long ll; }"); + const Variable *b = db->getVariableFromVarId(1); + ASSERT(b); + ASSERT_EQUALS("b", b->nameToken()->str()); + ASSERT_EQUALS(true, b->isIntegralType()); + ASSERT_EQUALS(false, b->isFloatingType()); + const Variable *c = db->getVariableFromVarId(2); + ASSERT(c); + ASSERT_EQUALS("c", c->nameToken()->str()); + ASSERT_EQUALS(true, c->isIntegralType()); + ASSERT_EQUALS(false, c->isFloatingType()); + const Variable *uc = db->getVariableFromVarId(3); + ASSERT(uc); + ASSERT_EQUALS("uc", uc->nameToken()->str()); + ASSERT_EQUALS(true, uc->isIntegralType()); + ASSERT_EQUALS(false, uc->isFloatingType()); + const Variable *s = db->getVariableFromVarId(4); + ASSERT(s); + ASSERT_EQUALS("s", s->nameToken()->str()); + ASSERT_EQUALS(true, s->isIntegralType()); + ASSERT_EQUALS(false, s->isFloatingType()); + const Variable *us = db->getVariableFromVarId(5); + ASSERT(us); + ASSERT_EQUALS("us", us->nameToken()->str()); + ASSERT_EQUALS(true, us->isIntegralType()); + ASSERT_EQUALS(false, us->isFloatingType()); + const Variable *i = db->getVariableFromVarId(6); + ASSERT(i); + ASSERT_EQUALS("i", i->nameToken()->str()); + ASSERT_EQUALS(true, i->isIntegralType()); + ASSERT_EQUALS(false, i->isFloatingType()); + const Variable *u = db->getVariableFromVarId(7); + ASSERT(u); + ASSERT_EQUALS("u", u->nameToken()->str()); + ASSERT_EQUALS(true, u->isIntegralType()); + ASSERT_EQUALS(false, u->isFloatingType()); + const Variable *ui = db->getVariableFromVarId(8); + ASSERT(ui); + ASSERT_EQUALS("ui", ui->nameToken()->str()); + ASSERT_EQUALS(true, ui->isIntegralType()); + ASSERT_EQUALS(false, ui->isFloatingType()); + const Variable *l = db->getVariableFromVarId(9); + ASSERT(l); + ASSERT_EQUALS("l", l->nameToken()->str()); + ASSERT_EQUALS(true, l->isIntegralType()); + ASSERT_EQUALS(false, l->isFloatingType()); + const Variable *ul = db->getVariableFromVarId(10); + ASSERT(ul); + ASSERT_EQUALS("ul", ul->nameToken()->str()); + ASSERT_EQUALS(true, ul->isIntegralType()); + ASSERT_EQUALS(false, ul->isFloatingType()); + const Variable *ll = db->getVariableFromVarId(11); + ASSERT(ui); + ASSERT_EQUALS("ll", ll->nameToken()->str()); + ASSERT_EQUALS(true, ll->isIntegralType()); + ASSERT_EQUALS(false, ll->isFloatingType()); + } + + void varTypesFloating() { + { + GET_SYMBOL_DB("void f() { float f; double d; long double ld; }"); + const Variable *f = db->getVariableFromVarId(1); + ASSERT(f); + ASSERT_EQUALS("f", f->nameToken()->str()); + ASSERT_EQUALS(false, f->isIntegralType()); + ASSERT_EQUALS(true, f->isFloatingType()); + const Variable *d = db->getVariableFromVarId(2); + ASSERT(d); + ASSERT_EQUALS("d", d->nameToken()->str()); + ASSERT_EQUALS(false, d->isIntegralType()); + ASSERT_EQUALS(true, d->isFloatingType()); + const Variable *ld = db->getVariableFromVarId(3); + ASSERT(ld); + ASSERT_EQUALS("ld", ld->nameToken()->str()); + ASSERT_EQUALS(false, ld->isIntegralType()); + ASSERT_EQUALS(true, ld->isFloatingType()); + } + { + GET_SYMBOL_DB("void f() { float * f; static const float * scf; }"); + const Variable *f = db->getVariableFromVarId(1); + ASSERT(f); + ASSERT_EQUALS("f", f->nameToken()->str()); + ASSERT_EQUALS(false, f->isIntegralType()); + ASSERT_EQUALS(false, f->isFloatingType()); + const Variable *scf = db->getVariableFromVarId(2); + ASSERT(scf); + ASSERT_EQUALS("scf", scf->nameToken()->str()); + ASSERT_EQUALS(false, scf->isIntegralType()); + ASSERT_EQUALS(false, scf->isFloatingType()); + } + { + GET_SYMBOL_DB("void f() { float fa[42]; }"); + const Variable *fa = db->getVariableFromVarId(1); + ASSERT(fa); + ASSERT_EQUALS("fa", fa->nameToken()->str()); + ASSERT_EQUALS(false, fa->isIntegralType()); + ASSERT_EQUALS(false, fa->isFloatingType()); + } + } + + void varTypesOther() { + GET_SYMBOL_DB("void f() { class A {} a; void *b; }"); + const Variable *a = db->getVariableFromVarId(1); + ASSERT_EQUALS("a", a->nameToken()->str()); + ASSERT_EQUALS(false, a->isIntegralType()); + ASSERT_EQUALS(false, a->isFloatingType()); + const Variable *b = db->getVariableFromVarId(2); + ASSERT_EQUALS("b", b->nameToken()->str()); + ASSERT_EQUALS(false, b->isIntegralType()); + ASSERT_EQUALS(false, b->isFloatingType()); + } }; REGISTER_TEST(TestSymbolDatabase)