#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 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.");
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue