#4375 New check: add style warning about 'double d=false;' Add a new check to CheckBool. Also implement Variable::isFloatingType()

This commit is contained in:
Alexander Mai 2014-05-24 18:35:49 +02:00
parent effa38c322
commit 2c8087e34f
5 changed files with 182 additions and 0 deletions

View File

@ -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 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."); "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.");
}

View File

@ -52,6 +52,7 @@ public:
// Checks // Checks
checkBool.checkComparisonOfBoolExpressionWithInt(); checkBool.checkComparisonOfBoolExpressionWithInt();
checkBool.checkComparisonOfBoolWithInt(); checkBool.checkComparisonOfBoolWithInt();
checkBool.checkAssignBoolToFloat();
checkBool.pointerArithBool(); checkBool.pointerArithBool();
} }
@ -82,6 +83,9 @@ public:
/** @brief assigning bool to pointer */ /** @brief assigning bool to pointer */
void checkAssignBoolToPointer(); void checkAssignBoolToPointer();
/** @brief assigning bool to float */
void checkAssignBoolToFloat();
/** @brief %Check for using bool in bitwise expression */ /** @brief %Check for using bool in bitwise expression */
void checkBitwiseOnBoolean(); void checkBitwiseOnBoolean();
@ -101,6 +105,7 @@ private:
void comparisonOfBoolWithIntError(const Token *tok, const std::string &expression, bool n0o1); void comparisonOfBoolWithIntError(const Token *tok, const std::string &expression, bool n0o1);
void comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression); void comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression);
void assignBoolToPointerError(const Token *tok); void assignBoolToPointerError(const Token *tok);
void assignBoolToFloatError(const Token *tok);
void bitwiseOnBooleanError(const Token *tok, const std::string &varname, const std::string &op); void bitwiseOnBooleanError(const Token *tok, const std::string &varname, const std::string &op);
void comparisonOfBoolExpressionWithIntError(const Token *tok, bool n0o1); void comparisonOfBoolExpressionWithIntError(const Token *tok, bool n0o1);
void pointerArithBoolError(const Token *tok); void pointerArithBoolError(const Token *tok);

View File

@ -471,6 +471,23 @@ public:
return isStlType() && std::binary_search(stlTypes, stlTypes + array_length, _start->strAt(2)); 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: private:
// only symbol database can change the type // only symbol database can change the type
friend class SymbolDatabase; friend class SymbolDatabase;

View File

@ -36,6 +36,7 @@ private:
TEST_CASE(bitwiseOnBoolean); // if (bool & bool) TEST_CASE(bitwiseOnBoolean); // if (bool & bool)
TEST_CASE(incrementBoolean); TEST_CASE(incrementBoolean);
TEST_CASE(assignBoolToPointer); TEST_CASE(assignBoolToPointer);
TEST_CASE(assignBoolToFloat);
TEST_CASE(comparisonOfBoolExpressionWithInt1); TEST_CASE(comparisonOfBoolExpressionWithInt1);
TEST_CASE(comparisonOfBoolExpressionWithInt2); TEST_CASE(comparisonOfBoolExpressionWithInt2);
@ -139,6 +140,23 @@ private:
ASSERT_EQUALS("", errout.str()); 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() { void comparisonOfBoolExpressionWithInt1() {
check("void f(int x) {\n" check("void f(int x) {\n"
" if ((x && 0x0f)==6)\n" " if ((x && 0x0f)==6)\n"

View File

@ -240,6 +240,10 @@ private:
TEST_CASE(nothrowAttributeFunction); TEST_CASE(nothrowAttributeFunction);
TEST_CASE(nothrowDeclspecFunction); TEST_CASE(nothrowDeclspecFunction);
TEST_CASE(varTypesIntegral); // known integral
TEST_CASE(varTypesFloating); // known floating
TEST_CASE(varTypesOther); // (un)known
} }
void array() const { 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) REGISTER_TEST(TestSymbolDatabase)