Skip to content

Commit 2c8087e

Browse files
committed
cppcheck-opensource#4375 New check: add style warning about 'double d=false;' Add a new check to CheckBool. Also implement Variable::isFloatingType()
1 parent effa38c commit 2c8087e

5 files changed

Lines changed: 182 additions & 0 deletions

File tree

lib/checkbool.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,3 +472,29 @@ void CheckBool::pointerArithBoolError(const Token *tok)
472472
"Converting pointer arithmetic result to bool. The bool is always true unless there is undefined behaviour.\n"
473473
"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.");
474474
}
475+
476+
void CheckBool::checkAssignBoolToFloat()
477+
{
478+
if (!_tokenizer->isCPP())
479+
return;
480+
if (!_settings->isEnabled("style"))
481+
return;
482+
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
483+
const std::size_t functions = symbolDatabase->functionScopes.size();
484+
for (std::size_t i = 0; i < functions; ++i) {
485+
const Scope * scope = symbolDatabase->functionScopes[i];
486+
for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
487+
if (Token::Match(tok, "!!* %var% = %bool% ;")) {
488+
const Variable *var = symbolDatabase->getVariableFromVarId(tok->next()->varId());
489+
if (var->isFloatingType())
490+
assignBoolToFloatError(tok->next());
491+
}
492+
}
493+
}
494+
}
495+
496+
void CheckBool::assignBoolToFloatError(const Token *tok)
497+
{
498+
reportError(tok, Severity::style, "assignBoolToFloat",
499+
"Boolean value assigned to floating point variable.");
500+
}

lib/checkbool.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class CPPCHECKLIB CheckBool : public Check {
5252
// Checks
5353
checkBool.checkComparisonOfBoolExpressionWithInt();
5454
checkBool.checkComparisonOfBoolWithInt();
55+
checkBool.checkAssignBoolToFloat();
5556
checkBool.pointerArithBool();
5657
}
5758

@@ -82,6 +83,9 @@ class CPPCHECKLIB CheckBool : public Check {
8283
/** @brief assigning bool to pointer */
8384
void checkAssignBoolToPointer();
8485

86+
/** @brief assigning bool to float */
87+
void checkAssignBoolToFloat();
88+
8589
/** @brief %Check for using bool in bitwise expression */
8690
void checkBitwiseOnBoolean();
8791

@@ -101,6 +105,7 @@ class CPPCHECKLIB CheckBool : public Check {
101105
void comparisonOfBoolWithIntError(const Token *tok, const std::string &expression, bool n0o1);
102106
void comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression);
103107
void assignBoolToPointerError(const Token *tok);
108+
void assignBoolToFloatError(const Token *tok);
104109
void bitwiseOnBooleanError(const Token *tok, const std::string &varname, const std::string &op);
105110
void comparisonOfBoolExpressionWithIntError(const Token *tok, bool n0o1);
106111
void pointerArithBoolError(const Token *tok);

lib/symboldatabase.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,23 @@ class CPPCHECKLIB Variable {
471471
return isStlType() && std::binary_search(stlTypes, stlTypes + array_length, _start->strAt(2));
472472
}
473473

474+
/**
475+
* Determine whether it's a floating number type
476+
* @return true if the type is known and it's a floating type (float, double and long double)
477+
*/
478+
bool isFloatingType() const {
479+
return (typeStartToken()->str() == "float" || typeStartToken()->str() == "double") && !isArrayOrPointer() ;
480+
}
481+
482+
/**
483+
* Determine whether it's an integral number type
484+
* @return true if the type is known and it's an integral type (bool, char, short, int, long long and their unsigned counter parts)
485+
*/
486+
bool isIntegralType() const {
487+
return typeStartToken()->str() == "bool" || typeStartToken()->str() == "char" || typeStartToken()->str() == "short" || typeStartToken()->str() == "int" || typeStartToken()->str() == "long";
488+
}
489+
490+
474491
private:
475492
// only symbol database can change the type
476493
friend class SymbolDatabase;

test/testbool.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class TestBool : public TestFixture {
3636
TEST_CASE(bitwiseOnBoolean); // if (bool & bool)
3737
TEST_CASE(incrementBoolean);
3838
TEST_CASE(assignBoolToPointer);
39+
TEST_CASE(assignBoolToFloat);
3940

4041
TEST_CASE(comparisonOfBoolExpressionWithInt1);
4142
TEST_CASE(comparisonOfBoolExpressionWithInt2);
@@ -139,6 +140,23 @@ class TestBool : public TestFixture {
139140
ASSERT_EQUALS("", errout.str());
140141
}
141142

143+
void assignBoolToFloat() {
144+
check("void foo1() {\n"
145+
" double d = false;\n"
146+
"}");
147+
ASSERT_EQUALS("[test.cpp:2]: (style) Boolean value assigned to floating point variable.\n", errout.str());
148+
149+
check("void foo2() {\n"
150+
" float d = true;\n"
151+
"}");
152+
ASSERT_EQUALS("[test.cpp:2]: (style) Boolean value assigned to floating point variable.\n", errout.str());
153+
154+
check("void foo3() {\n"
155+
" long double d = (2>1);\n"
156+
"}");
157+
TODO_ASSERT_EQUALS("[test.cpp:2]: (style) Boolean value assigned to floating point variable.\n", "", errout.str());
158+
}
159+
142160
void comparisonOfBoolExpressionWithInt1() {
143161
check("void f(int x) {\n"
144162
" if ((x && 0x0f)==6)\n"

test/testsymboldatabase.cpp

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,10 @@ class TestSymbolDatabase: public TestFixture {
240240

241241
TEST_CASE(nothrowAttributeFunction);
242242
TEST_CASE(nothrowDeclspecFunction);
243+
244+
TEST_CASE(varTypesIntegral); // known integral
245+
TEST_CASE(varTypesFloating); // known floating
246+
TEST_CASE(varTypesOther); // (un)known
243247
}
244248

245249
void array() const {
@@ -2238,6 +2242,118 @@ class TestSymbolDatabase: public TestFixture {
22382242
}
22392243
}
22402244

2245+
void varTypesIntegral() {
2246+
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; }");
2247+
const Variable *b = db->getVariableFromVarId(1);
2248+
ASSERT(b);
2249+
ASSERT_EQUALS("b", b->nameToken()->str());
2250+
ASSERT_EQUALS(true, b->isIntegralType());
2251+
ASSERT_EQUALS(false, b->isFloatingType());
2252+
const Variable *c = db->getVariableFromVarId(2);
2253+
ASSERT(c);
2254+
ASSERT_EQUALS("c", c->nameToken()->str());
2255+
ASSERT_EQUALS(true, c->isIntegralType());
2256+
ASSERT_EQUALS(false, c->isFloatingType());
2257+
const Variable *uc = db->getVariableFromVarId(3);
2258+
ASSERT(uc);
2259+
ASSERT_EQUALS("uc", uc->nameToken()->str());
2260+
ASSERT_EQUALS(true, uc->isIntegralType());
2261+
ASSERT_EQUALS(false, uc->isFloatingType());
2262+
const Variable *s = db->getVariableFromVarId(4);
2263+
ASSERT(s);
2264+
ASSERT_EQUALS("s", s->nameToken()->str());
2265+
ASSERT_EQUALS(true, s->isIntegralType());
2266+
ASSERT_EQUALS(false, s->isFloatingType());
2267+
const Variable *us = db->getVariableFromVarId(5);
2268+
ASSERT(us);
2269+
ASSERT_EQUALS("us", us->nameToken()->str());
2270+
ASSERT_EQUALS(true, us->isIntegralType());
2271+
ASSERT_EQUALS(false, us->isFloatingType());
2272+
const Variable *i = db->getVariableFromVarId(6);
2273+
ASSERT(i);
2274+
ASSERT_EQUALS("i", i->nameToken()->str());
2275+
ASSERT_EQUALS(true, i->isIntegralType());
2276+
ASSERT_EQUALS(false, i->isFloatingType());
2277+
const Variable *u = db->getVariableFromVarId(7);
2278+
ASSERT(u);
2279+
ASSERT_EQUALS("u", u->nameToken()->str());
2280+
ASSERT_EQUALS(true, u->isIntegralType());
2281+
ASSERT_EQUALS(false, u->isFloatingType());
2282+
const Variable *ui = db->getVariableFromVarId(8);
2283+
ASSERT(ui);
2284+
ASSERT_EQUALS("ui", ui->nameToken()->str());
2285+
ASSERT_EQUALS(true, ui->isIntegralType());
2286+
ASSERT_EQUALS(false, ui->isFloatingType());
2287+
const Variable *l = db->getVariableFromVarId(9);
2288+
ASSERT(l);
2289+
ASSERT_EQUALS("l", l->nameToken()->str());
2290+
ASSERT_EQUALS(true, l->isIntegralType());
2291+
ASSERT_EQUALS(false, l->isFloatingType());
2292+
const Variable *ul = db->getVariableFromVarId(10);
2293+
ASSERT(ul);
2294+
ASSERT_EQUALS("ul", ul->nameToken()->str());
2295+
ASSERT_EQUALS(true, ul->isIntegralType());
2296+
ASSERT_EQUALS(false, ul->isFloatingType());
2297+
const Variable *ll = db->getVariableFromVarId(11);
2298+
ASSERT(ui);
2299+
ASSERT_EQUALS("ll", ll->nameToken()->str());
2300+
ASSERT_EQUALS(true, ll->isIntegralType());
2301+
ASSERT_EQUALS(false, ll->isFloatingType());
2302+
}
2303+
2304+
void varTypesFloating() {
2305+
{
2306+
GET_SYMBOL_DB("void f() { float f; double d; long double ld; }");
2307+
const Variable *f = db->getVariableFromVarId(1);
2308+
ASSERT(f);
2309+
ASSERT_EQUALS("f", f->nameToken()->str());
2310+
ASSERT_EQUALS(false, f->isIntegralType());
2311+
ASSERT_EQUALS(true, f->isFloatingType());
2312+
const Variable *d = db->getVariableFromVarId(2);
2313+
ASSERT(d);
2314+
ASSERT_EQUALS("d", d->nameToken()->str());
2315+
ASSERT_EQUALS(false, d->isIntegralType());
2316+
ASSERT_EQUALS(true, d->isFloatingType());
2317+
const Variable *ld = db->getVariableFromVarId(3);
2318+
ASSERT(ld);
2319+
ASSERT_EQUALS("ld", ld->nameToken()->str());
2320+
ASSERT_EQUALS(false, ld->isIntegralType());
2321+
ASSERT_EQUALS(true, ld->isFloatingType());
2322+
}
2323+
{
2324+
GET_SYMBOL_DB("void f() { float * f; static const float * scf; }");
2325+
const Variable *f = db->getVariableFromVarId(1);
2326+
ASSERT(f);
2327+
ASSERT_EQUALS("f", f->nameToken()->str());
2328+
ASSERT_EQUALS(false, f->isIntegralType());
2329+
ASSERT_EQUALS(false, f->isFloatingType());
2330+
const Variable *scf = db->getVariableFromVarId(2);
2331+
ASSERT(scf);
2332+
ASSERT_EQUALS("scf", scf->nameToken()->str());
2333+
ASSERT_EQUALS(false, scf->isIntegralType());
2334+
ASSERT_EQUALS(false, scf->isFloatingType());
2335+
}
2336+
{
2337+
GET_SYMBOL_DB("void f() { float fa[42]; }");
2338+
const Variable *fa = db->getVariableFromVarId(1);
2339+
ASSERT(fa);
2340+
ASSERT_EQUALS("fa", fa->nameToken()->str());
2341+
ASSERT_EQUALS(false, fa->isIntegralType());
2342+
ASSERT_EQUALS(false, fa->isFloatingType());
2343+
}
2344+
}
2345+
2346+
void varTypesOther() {
2347+
GET_SYMBOL_DB("void f() { class A {} a; void *b; }");
2348+
const Variable *a = db->getVariableFromVarId(1);
2349+
ASSERT_EQUALS("a", a->nameToken()->str());
2350+
ASSERT_EQUALS(false, a->isIntegralType());
2351+
ASSERT_EQUALS(false, a->isFloatingType());
2352+
const Variable *b = db->getVariableFromVarId(2);
2353+
ASSERT_EQUALS("b", b->nameToken()->str());
2354+
ASSERT_EQUALS(false, b->isIntegralType());
2355+
ASSERT_EQUALS(false, b->isFloatingType());
2356+
}
22412357
};
22422358

22432359
REGISTER_TEST(TestSymbolDatabase)

0 commit comments

Comments
 (0)