#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:
parent
effa38c322
commit
2c8087e34f
|
@ -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.");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue