Repository navigation
Fix #6552: false constant value warnings after overloaded extraction #8835
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -129,6 +129,8 @@ class TestCondition : public TestFixture { | |
| TEST_CASE(knownConditionAfterBailout); // #12526 | ||
| TEST_CASE(knownConditionIncDecOperator); | ||
| TEST_CASE(knownConditionFloating); | ||
| TEST_CASE(knownConditionShiftAssignment); | ||
| TEST_CASE(knownConditionShiftAssignmentOverloads); | ||
| } | ||
|
|
||
| struct CheckOptions | ||
|
|
@@ -6687,6 +6689,238 @@ class TestCondition : public TestFixture { | |
| ASSERT_EQUALS("", errout_str()); | ||
| } | ||
|
|
||
| void knownConditionShiftAssignment() { // #6552 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is an AI review take it with a grain of salt. Please feel free to reject it by clicking on Resolve button FYI: since f99ea4b on main (#15056, "remove warnings for return result"), |
||
| check("struct Value { void operator>>=(double&) const; };\n" | ||
| "bool f(const Value& value, bool extract) {\n" | ||
| " double x = 0.5;\n" | ||
| " if (extract) value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(double) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x<0' is always false [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(const double&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x<0' is always false [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(const double&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " const double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x<0' is always false [knownConditionTrueFalse]\n", errout_str()); | ||
| } | ||
|
|
||
| void knownConditionShiftAssignmentOverloads() { | ||
| check("struct Value { void operator>>=(double) const; void operator>>=(int&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x<0' is always false [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(double) const; void operator>>=(float&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x<0' is always false [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(int) const; void operator>>=(unsigned int&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " int x = 1;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x<0' is always false [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("enum E { A };\n" | ||
| "struct Value { void operator>>=(int) const; void operator>>=(E&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " int x = 1;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:6:14]: (style) Return value 'x<0' is always false [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(double) const; void operator>>=(double&); };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x<0' is always false [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(double) volatile; void operator>>=(double&); };\n" | ||
| "bool f(volatile Value& value) {\n" | ||
| " double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x<0' is always false [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(double) const &; void operator>>=(double&) &&; };\n" | ||
| "bool f(Value& value) {\n" | ||
| " double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x<0' is always false [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(const double&) const; void operator>>=(double&&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x<0' is always false [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(int) const; void operator>>=(double&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(int) const; void operator>>=(volatile double&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(double) const; void operator>>=(double&); };\n" | ||
| "bool f(Value& value) {\n" | ||
| " double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("", errout_str()); | ||
|
|
||
| check("struct Value { template<class T> void operator>>=(T&& x) const { x = -1; } };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(double*) const; void operator>>=(int*&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " double* x = nullptr;\n" | ||
| " value >>= x;\n" | ||
| " return x == nullptr;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x==nullptr' is always true [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(double*) const; void operator>>=(void*&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " double* x = nullptr;\n" | ||
| " value >>= x;\n" | ||
| " return x == nullptr;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x==nullptr' is always true [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(double*) const; void operator>>=(const double*&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " double* x = nullptr;\n" | ||
| " value >>= x;\n" | ||
| " return x == nullptr;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x==nullptr' is always true [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(double*) const; void operator>>=(double**&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " double* x = nullptr;\n" | ||
| " value >>= x;\n" | ||
| " return x == nullptr;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x==nullptr' is always true [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(int*) const; void operator>>=(double*&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " double* x = nullptr;\n" | ||
| " value >>= x;\n" | ||
| " return x == nullptr;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(int*) const; void operator>>=(const double*&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " const double* x = nullptr;\n" | ||
| " value >>= x;\n" | ||
| " return x == nullptr;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("", errout_str()); | ||
|
|
||
| check("struct A {}; struct B {};\n" | ||
| "struct Value { void operator>>=(A*) const; void operator>>=(B*&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " A* x = nullptr;\n" | ||
| " value >>= x;\n" | ||
| " return x == nullptr;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:6:14]: (style) Return value 'x==nullptr' is always true [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Base {}; struct A : Base {};\n" | ||
| "struct Value { void operator>>=(A*) const; void operator>>=(Base*&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " A* x = nullptr;\n" | ||
| " value >>= x;\n" | ||
| " return x == nullptr;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:6:14]: (style) Return value 'x==nullptr' is always true [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct A {}; struct B {};\n" | ||
| "struct Value { void operator>>=(B*) const; void operator>>=(A*&) const; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " A* x = nullptr;\n" | ||
| " value >>= x;\n" | ||
| " return x == nullptr;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(double) ; void operator>>=(double&) const; };\n" | ||
| "bool f(Value& value) {\n" | ||
| " double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x<0' is always false [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(double) const; void operator>>=(double&) const volatile; };\n" | ||
| "bool f(const Value& value) {\n" | ||
| " double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x<0' is always false [knownConditionTrueFalse]\n", errout_str()); | ||
|
|
||
| check("struct Value { void operator>>=(double) volatile; void operator>>=(double&) const volatile; };\n" | ||
| "bool f(volatile Value& value) {\n" | ||
| " double x = 0.5;\n" | ||
| " value >>= x;\n" | ||
| " return x < 0;\n" | ||
| "}\n"); | ||
| ASSERT_EQUALS("[test.cpp:5:14]: (style) Return value 'x<0' is always false [knownConditionTrueFalse]\n", errout_str()); | ||
| } | ||
|
|
||
| void knownConditionFloating() { | ||
| check("void foo() {\n" // #11199 | ||
| " float f = 1.0;\n" | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an AI review take it with a grain of salt. Please feel free to reject it by clicking on Resolve button
Only member operators of the lhs class itself are looked at. When none is found, the loop does nothing and we fall through, so
xis still treated as unchanged. I built this branch and the false positive remains for:Since an FN is better than an FP here, a simpler and more robust rule might be: for a class-type lhs, assume the rhs is changed unless a member
operator>>=is found and all the candidates take the argument by value or by const reference. That would also make most of the overload-ranking logic below unnecessary. It's quite a lot of code to keep warnings in rare cases, and it is hard to be sure it matches C++ overload resolution.