You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.
Dismiss alert
ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:4:8]: (style) Mismatching assignment and comparison, comparison 'y==3' is always false. [assignIfError]\n", errout_str());
check("void foo(int x)\n"
"{\n"
" int y = x & 4;\n"
" if (y != 3);\n"
"}");
ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:4:8]: (style) Mismatching assignment and comparison, comparison 'y!=3' is always true. [assignIfError]\n", errout_str());
// |
check("void foo(int x) {\n"
" int y = x | 0x14;\n"
" if (y == 0x710);\n"
"}");
ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:8]: (style) Mismatching assignment and comparison, comparison 'y==0x710' is always false. [assignIfError]\n", errout_str());
check("void foo(int x) {\n"
" int y = x | 0x14;\n"
" if (y == 0x71f);\n"
"}");
ASSERT_EQUALS("", errout_str());
// various simple assignments
check("void foo(int x) {\n"
" int y = (x+1) | 1;\n"
" if (y == 2);\n"
"}");
ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:8]: (style) Mismatching assignment and comparison, comparison 'y==2' is always false. [assignIfError]\n", errout_str());
check("void foo() {\n"
" int y = 1 | x();\n"
" if (y == 2);\n"
"}");
ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:8]: (style) Mismatching assignment and comparison, comparison 'y==2' is always false. [assignIfError]\n", errout_str());
// multiple conditions
check("void foo(int x) {\n"
" int y = x & 4;\n"
" if ((y == 3) && (z == 1));\n"
"}");
ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:9]: (style) Mismatching assignment and comparison, comparison 'y==3' is always false. [assignIfError]\n", errout_str());
check("void foo(int x) {\n"
" int y = x & 4;\n"
" if ((x==123) || ((y == 3) && (z == 1)));\n"
"}");
ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:22]: (style) Mismatching assignment and comparison, comparison 'y==3' is always false. [assignIfError]\n", errout_str());
check("void f(int x) {\n"
" int y = x & 7;\n"
" if (setvalue(&y) && y != 8);\n"
"}");
ASSERT_EQUALS("", errout_str());
// recursive checking into scopes
check("void f(int x) {\n"
" int y = x & 7;\n"
" if (z) y=0;\n"
" else { if (y==8); }\n"// always false
"}");
ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:4:15]: (style) Mismatching assignment and comparison, comparison 'y==8' is always false. [assignIfError]\n", errout_str());
// while
check("void f(int x) {\n"
" int y = x & 7;\n"
" while (y==8);\n"// local variable => always false
"}");
ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:11]: (style) Mismatching assignment and comparison, comparison 'y==8' is always false. [assignIfError]\n", errout_str());
check("void f(int x) {\n"
" extern int y; y = x & 7;\n"
" while (y==8);\n"// non-local variable => no error
"}");
ASSERT_EQUALS("", errout_str());
check("void f(int x) {\n"
" int a = 100;\n"
" while (x) {\n"
" int y = 16 | a;\n"
" while (y != 0) y--;\n"
" }\n"
"}");
ASSERT_EQUALS("", errout_str());
check("void g(int x);\n"
"void f(int x) {\n"
" int a = 100;\n"
" while (x) {\n"
" int y = 16 | a;\n"
" while (y != 0) g(y);\n"
" }\n"
"}");
ASSERT_EQUALS(
"[test.cpp:5:15] -> [test.cpp:6:15]: (style) Mismatching assignment and comparison, comparison 'y!=0' is always true. [assignIfError]\n",
errout_str());
check("void g(int &x);\n"
"void f(int x) {\n"
" int a = 100;\n"
" while (x) {\n"
" int y = 16 | a;\n"
" while (y != 0) g(y);\n"
" }\n"
"}");
ASSERT_EQUALS("", errout_str());
// calling function
check("void f(int x) {\n"
" int y = x & 7;\n"
" do_something();\n"
" if (y==8);\n"// local variable => always false
"}");
ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:4:8]: (style) Mismatching assignment and comparison, comparison 'y==8' is always false. [assignIfError]\n", errout_str());
check("void f(int x) {\n"
" int y = x & 7;\n"
" do_something(&y);\n"// passing variable => no error
" if (y==8);\n"
"}");
ASSERT_EQUALS("", errout_str());
check("void do_something(int);\n"
"void f(int x) {\n"
" int y = x & 7;\n"
" do_something(y);\n"
" if (y==8);\n"
"}");
ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:5:8]: (style) Mismatching assignment and comparison, comparison 'y==8' is always false. [assignIfError]\n", errout_str());
check("void f(int x) {\n"
" extern int y; y = x & 7;\n"
" do_something();\n"
" if (y==8);\n"// non-local variable => no error
"}");
ASSERT_EQUALS("", errout_str());
// #4434 : false positive: ?:
check("void f(int x) {\n"
" x = x & 1;\n"
" x = x & 1 ? 1 : -1;\n"
" if(x != -1) { }\n"
"}");
ASSERT_EQUALS("", errout_str());
// #4735
check("void f() {\n"
" int x = *(char*)&0x12345678;\n"
" if (x==18) { }\n"
"}");
ASSERT_EQUALS("", errout_str());
// bailout: no variable info
check("void foo(int x) {\n"
" y = 2 | x;\n"// y not declared => no error
" if(y == 1) {}\n"
"}");
ASSERT_EQUALS("", errout_str());
// bailout: negative number
check("void foo(int x) {\n"
" int y = -2 | x;\n"// negative number => no error
" if (y==1) {}\n"
"}");
ASSERT_EQUALS("", errout_str());
// bailout: pass variable to function
check("void foo(int x) {\n"
" int y = 2 | x;\n"
" bar(&y);\n"// pass variable to function => no error
" if (y==1) {}\n"
"}");
ASSERT_EQUALS("", errout_str());
// no crash on unary operator& (#5643)
// #11610
check("SdrObject* ApplyGraphicToObject() {\n"
" if (&rHitObject) {}\n"
" else if (rHitObject.IsClosedObj() && !&rHitObject) { }\n"
"}");
ASSERT_EQUALS("[test.cpp:2:9]: (style) Condition '&rHitObject' is always true [knownConditionTrueFalse]\n"
"[test.cpp:3:42]: (style) Condition '!&rHitObject' is always false [knownConditionTrueFalse]\n",
errout_str());
// #5695: increment
check("void f(int a0, int n) {\n"
" int c = a0 & 3;\n"
" for (int a = 0; a < n; a++) {\n"
" c++;\n"
" if (c == 4)\n"
" c = 0;\n"
" }\n"
"}");
ASSERT_EQUALS("", errout_str());
check("void f(int a) {\n"// #6662
" int x = a & 1;\n"
" while (x <= 4) {\n"
" if (x != 5) {}\n"
" }\n"
"}");
ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:8]: (style) Mismatching assignment and comparison, comparison 'x!=5' is always true. [assignIfError]\n", errout_str());
check("void f(int a) {\n"// #6662
" int x = a & 1;\n"
" while ((x += 4) < 10) {\n"
" if (x != 5) {}\n"
" }\n"
"}");
ASSERT_EQUALS("", errout_str());
check("void f() {\n"
" int x = 100;\n"
" while (x) {\n"
" g(x);\n"
" }\n"
"}");
ASSERT_EQUALS("", errout_str());
check("void g(int x);\n"
"void f() {\n"
" int x = 100;\n"
" while (x) {\n"
" g(x);\n"
" }\n"
"}");
ASSERT_EQUALS("[test.cpp:4:12]: (style) Condition 'x' is always true [knownConditionTrueFalse]\n", errout_str());
check("void g(int & x);\n"
"void f() {\n"
" int x = 100;\n"
" while (x) {\n"
" g(x);\n"
" }\n"
"}");
ASSERT_EQUALS("", errout_str());
}
voidmismatchingBitAnd() {
check("void f(int a) {\n"
" int b = a & 0xf0;\n"
" b &= 1;\n"
"}");
ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:5]: (style) Mismatching bitmasks. Result is always 0 (X = Y & 0xf0; Z = X & 0x1; => Z=0). [mismatchingBitAnd]\n", errout_str());
check("void f(int a) {\n"
" int b = a & 0xf0;\n"
" int c = b & 1;\n"
"}");
ASSERT_EQUALS("[test.cpp:2:11] -> [test.cpp:3:9]: (style) Mismatching bitmasks. Result is always 0 (X = Y & 0xf0; Z = X & 0x1; => Z=0). [mismatchingBitAnd]\n", errout_str());
check("void f(int a) {\n"
" int b = a;"
" switch (x) {\n"
" case 1: b &= 1; break;\n"
" case 2: b &= 2; break;\n"
" };\n"
"}");
ASSERT_EQUALS("", errout_str());
}
voidcomparison() {
// CheckCondition::comparison test cases
// '=='
check("void f(int a) {\n assert( (a & 0x07) == 8U );\n}");
voidcheckPureFunction_(constchar* file, int line, constchar (&code)[size]) {
// Tokenize..
SimpleTokenizer tokenizer(settings1, *this);
ASSERT_LOC(tokenizer.tokenize(code), file, line);
runChecks<CheckCondition>(tokenizer, this);
}
voidmulticompare() {
check("void foo(int x)\n"
"{\n"
" if (x & 7);\n"
" else { if (x == 1); }\n"
"}");
ASSERT_EQUALS("[test.cpp:4:18]: (style) Expression is always false because 'else if' condition matches previous condition at line 3. [multiCondition]\n", errout_str());
check("void foo(int x)\n"
"{\n"
" if (x & 7);\n"
" else { if (x & 1); }\n"
"}");
ASSERT_EQUALS("[test.cpp:4:18]: (style) Expression is always false because 'else if' condition matches previous condition at line 3. [multiCondition]\n", errout_str());
check("extern int bar() __attribute__((pure));\n"
"void foo(int x)\n"
"{\n"
" if ( bar() >1 && b) {}\n"
" else if (bar() >1 && b) {}\n"
"}");
ASSERT_EQUALS("[test.cpp:5:23]: (style) Expression is always false because 'else if' condition matches previous condition at line 4. [multiCondition]\n", errout_str());
checkPureFunction("extern int bar();\n"
"void foo(int x)\n"
"{\n"
" if ( bar() >1 && b) {}\n"
" else if (bar() >1 && b) {}\n"
"}");
ASSERT_EQUALS("[test.cpp:5:23]: (style) Expression is always false because 'else if' condition matches previous condition at line 4. [multiCondition]\n", errout_str());
// 7284
check("void foo() {\n"
" if (a) {}\n"
" else if (!!a) {}\n"
"}");
ASSERT_EQUALS("[test.cpp:3:14]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str());
// #11059
check("int f();\n"
"void g() {\n"
" int i = f();\n"
" if (i == 3) {}\n"
" else if ((i = f()) == 5) {}\n"
" else if (i == 3) {}\n"
"}\n");
ASSERT_EQUALS("", errout_str());
check("int f();\n"
"void g() {\n"
" int i = f();\n"
" if (i == 3) {}\n"
" else if ((i = f()) == 5) {}\n"
" else if (i != 3) {}\n"
"}\n");
ASSERT_EQUALS("", errout_str());
}
voidoverlappingElseIfCondition() {
check("void f(int a, int &b) {\n"
" if (a) { b = 1; }\n"
" else { if (a) { b = 2; } }\n"
"}");
ASSERT_EQUALS("[test.cpp:3:16]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str());
check("void f(int a, int &b) {\n"
" if (a) { b = 1; }\n"
" else { if (a) { b = 2; } }\n"
"}");
ASSERT_EQUALS("[test.cpp:3:16]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str());
check("void f(int a, int &b) {\n"
" if (a == 1) { b = 1; }\n"
" else { if (a == 2) { b = 2; }\n"
" else { if (a == 1) { b = 3; } } }\n"
"}");
ASSERT_EQUALS("[test.cpp:4:18]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str());
check("void f(int a, int &b) {\n"
" if (a == 1) { b = 1; }\n"
" else { if (a == 2) { b = 2; }\n"
" else { if (a == 2) { b = 3; } } }\n"
"}");
ASSERT_EQUALS("[test.cpp:4:18]: (style) Expression is always false because 'else if' condition matches previous condition at line 3. [multiCondition]\n", errout_str());
check("void f(int a, int &b) {\n"
" if (a++) { b = 1; }\n"
" else { if (a++) { b = 2; }\n"
" else { if (a++) { b = 3; } } }\n"
"}");
ASSERT_EQUALS("", errout_str());
check("void f(int a, int &b) {\n"
" if (!strtok(NULL, \"\")) { b = 1; }\n"
" else { if (!strtok(NULL, \"\")) { b = 2; } }\n"
"}");
ASSERT_EQUALS("", errout_str());
{
check("void f(Class &c) {\n"
" if (c.dostuff() == 3) {}\n"
" else { if (c.dostuff() == 3) {} }\n"
"}");
ASSERT_EQUALS("", errout_str());
check("void f(const Class &c) {\n"
" if (c.dostuff() == 3) {}\n"
" else { if (c.dostuff() == 3) {} }\n"
"}");
ASSERT_EQUALS("[test.cpp:3:28]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str());
}
check("void f(int a, int &b) {\n"
" x = x / 2;\n"
" if (x < 100) { b = 1; }\n"
" else { x = x / 2; if (x < 100) { b = 2; } }\n"
"}");
ASSERT_EQUALS("", errout_str());
check("void f(int64_t i) {\n"
" if(i == 0x02e2000000 || i == 0xa0c6000000)\n"
" foo(i);\n"
"}");
ASSERT_EQUALS("", errout_str());
// ticket 3689 ( avoid false positive )
check("int fitInt(long long int nValue){\n"
" if( nValue < 0x7fffffffLL )\n"
" {\n"
" return 32;\n"
" }\n"
" if( nValue < 0x7fffffffffffLL )\n"
" {\n"
" return 48;\n"
" }\n"
" else {\n"
" if( nValue < 0x7fffffffffffffffLL )\n"
" {\n"
" return 64;\n"
" } else\n"
" {\n"
" return -1;\n"
" }\n"
" }\n"
"}");
ASSERT_EQUALS("", errout_str());
check("void f(WIDGET *widget) {\n"
" if (dynamic_cast<BUTTON*>(widget)){}\n"
" else if (dynamic_cast<LABEL*>(widget)){}\n"
"}");
ASSERT_EQUALS("", errout_str());
check("class B { virtual void v() {} };\n"// #11037
"class D1 : public B {};\n"
"class D2 : public B {};\n"
"void f(const std::shared_ptr<B>&p) {\n"
" const auto d1 = dynamic_cast<D1*>(p.get());\n"
" const auto d2 = dynamic_cast<D2*>(p.get());\n"
" if (d1) {}\n"
" else if (d2) {}\n"
"}\n");
ASSERT_EQUALS("", errout_str());
check("void f(int x) {\n"// #6482
" if (x & 1) {}\n"
" else if (x == 0) {}\n"
"}");
ASSERT_EQUALS("", errout_str());
check("void f(int x) {\n"
" if (x & 15) {}\n"
" else if (x == 40) {}\n"
"}");
ASSERT_EQUALS("[test.cpp:3:14]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str());
check("void f(int x) {\n"
" if (x == sizeof(double)) {}\n"
" else { if (x == sizeof(long double)) {} }"
"}");
ASSERT_EQUALS("", errout_str());
check("void f(int x) {\n"
" if (x & 0x08) {}\n"
" else if (x & 0xF8) {}\n"
"}");
ASSERT_EQUALS("", errout_str());
check("void f(int x) {\n"
" if (x & 0xF8) {}\n"
" else if (x & 0x08) {}\n"
"}");
ASSERT_EQUALS("[test.cpp:3:14]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str());
check("void f(bool a, bool b) {\n"
" if(a && b){}\n"
" else if( !!b && !!a){}\n"
"}");
ASSERT_EQUALS("[test.cpp:3:17]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str());
check("void f(bool a, bool b) {\n"
" if(a && b){}\n"
" else if( !!b && a){}\n"
"}");
ASSERT_EQUALS("[test.cpp:3:17]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str());
check("void f(bool a, bool b) {\n"
" if(a && b){}\n"
" else if( b && !!a){}\n"
"}");
ASSERT_EQUALS("[test.cpp:3:15]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str());
check("void f(bool a, bool b) {\n"
" if(a && b){}\n"
" else if( b && !(!a)){}\n"
"}");
ASSERT_EQUALS("[test.cpp:3:15]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str());
check("void f(bool a, bool b) {\n"
" if(a && b){}\n"
" else if( !!b && !(!a)){}\n"
"}");
ASSERT_EQUALS("[test.cpp:3:17]: (style) Expression is always false because 'else if' condition matches previous condition at line 2. [multiCondition]\n", errout_str());
check("void f(bool a, bool b) {\n"
" if(a && b){}\n"
" else if( !!(b) && !!(a+b)){}\n"
"}");
ASSERT_EQUALS("", errout_str());
// #8168
check("enum MaskValues\n"
"{\n"
" Value1 = 0x00000001,\n"
" Value2 = 0x00000002\n"
"};\n"
"void TestFunction(int value) {\n"
" if ( value & (int)Value1 ) {}\n"
" else if ( value & (int)Value2 ) {}\n"
"}");
ASSERT_EQUALS("", errout_str());
check("void f(size_t x) {\n"
" if (x == sizeof(int)) {}\n"
" else { if (x == sizeof(long)) {} }\n"
"}\n");
ASSERT_EQUALS("", errout_str());
check("void f(size_t x) {\n"
" if (x == sizeof(long)) {}\n"
" else { if (x == sizeof(long long)) {} }\n"
"}\n");
ASSERT_EQUALS("", errout_str());
}
voidoppositeElseIfCondition() {
setMultiline();
check("void f(int x) {\n"
" if (x) {}\n"
" else if (!x) {}\n"
"}");
ASSERT_EQUALS("[test.cpp:3:14]: style: Expression is always true because 'else if' condition is opposite to previous condition at line 2. [multiCondition]\n"
"[test.cpp:2:9]: note: first condition\n"
"[test.cpp:3:14]: note: else if condition is opposite to first condition\n", errout_str());
check("void f(int x) {\n"
" int y = x;\n"
" if (x) {}\n"
" else if (!y) {}\n"
"}");
ASSERT_EQUALS("[test.cpp:4:14]: style: Expression is always true because 'else if' condition is opposite to previous condition at line 3. [multiCondition]\n"
"[test.cpp:2:13]: note: 'y' is assigned value 'x' here.\n"
"[test.cpp:3:9]: note: first condition\n"
"[test.cpp:4:14]: note: else if condition is opposite to first condition\n", errout_str());
}
voidcheckBadBitmaskCheck() {
check("bool f(int x) {\n"
" bool b = x | 0x02;\n"
" return b;\n"
"}");
ASSERT_EQUALS("[test.cpp:2:16]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str());
check("bool f(int x) {\n"
" bool b = 0x02 | x;\n"
" return b;\n"
"}");
ASSERT_EQUALS("[test.cpp:2:19]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str());
check("int f(int x) {\n"
" int b = x | 0x02;\n"
" return b;\n"
"}");
ASSERT_EQUALS("", errout_str());
check("bool f(int x) {\n"
" bool b = x & 0x02;\n"
" return b;\n"
"}");
ASSERT_EQUALS("", errout_str());
check("bool f(int x) {\n"
" if(x | 0x02)\n"
" return b;\n"
"}");
ASSERT_EQUALS("[test.cpp:2:10]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str());
check("bool f(int x) {\n"
" int y = 0x1;\n"
" if(b) y = 0;\n"
" if(x | y)\n"
" return b;\n"
"}");
ASSERT_EQUALS("", errout_str());
check("bool f(int x) {\n"
" foo(a && (x | 0x02));\n"
"}");
ASSERT_EQUALS("[test.cpp:2:17]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str());
check("int f(int x) {\n"
" return (x | 0x02) ? 0 : 5;\n"
"}");
ASSERT_EQUALS("[test.cpp:2:15]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str());
check("int f(int x) {\n"
" return x ? (x | 0x02) : 5;\n"
"}");
ASSERT_EQUALS("", errout_str());
check("bool f(int x) {\n"
" return x | 0x02;\n"
"}");
ASSERT_EQUALS("[test.cpp:2:14]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str());
check("bool f(int x) {\n"
" if (x) {\n"
" return x | 0x02;\n"
" }\n"
" return 0;\n"
"}");
ASSERT_EQUALS("[test.cpp:3:14]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str());
check("const bool f(int x) {\n"
" return x | 0x02;\n"
"}");
ASSERT_EQUALS("[test.cpp:2:14]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str());
check("struct F {\n"
" static const bool f(int x) {\n"
" return x | 0x02;\n"
" }\n"
"};");
ASSERT_EQUALS("[test.cpp:3:16]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str());
check("struct F {\n"
" typedef bool b_t;\n"
"};\n"
"F::b_t f(int x) {\n"
" return x | 0x02;\n"
"}");
ASSERT_EQUALS("[test.cpp:5:12]: (warning) Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'? [badBitmaskCheck]\n", errout_str());