Fix crash in bugprone-redundant-branch-condition on ExprWithCleanups.
Details
Diff Detail
Event Timeline
Think this has an incorrect name, seems to have something to do with bugprone-redundant-branch-condition
clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.cpp | ||
---|---|---|
87 | Please fix warning. |
clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.cpp | ||
---|---|---|
85–87 | Under what circumstances does getCond() return nullptr? | |
90 | You can call ExprWithCleanupsCond->getSubExpr() to do this more cleanly -- but similar question here as above -- what circumstances lead to a null sub expression? | |
134–135 | Same feedback here as above. |
clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.cpp | ||
---|---|---|
85–87 | That's what I figured, but you changed dyn_cast<> to be dyn_cast_or_null<> and that seems incorrect -- getCond() doesn't return null so the dyn_cast<> was correct. |
clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.cpp | ||
---|---|---|
85–87 | dyn_cast asserts unless getCond() returns BinaryExpression, right? |
clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.cpp | ||
---|---|---|
85–87 |
Nope. cast<> asserts if the cast cannot be completed or if the cast input is null. |
clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.cpp | ||
---|---|---|
85–87 | Yes, you are right, I definitely need a vacation :-) |
clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.cpp | ||
---|---|---|
136 | The old code used to assert that CondOp was a BinaryOperator but the new code means that CondOp can be null -- should you add an assert in to ensure we have a valid CondOp still or will that assert trigger on some constructs? | |
clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp | ||
1077 | Can remove the newline here. |
Taking a step back, rather than worrying about if its an ExprWithCleanups. Shouldn't we just get the condition removing all implicit nodes.
const Expr* Cond = InnerIf->getCond()->ignoreImplicit();
This has to be simpler and will likely future proof this against any other implicit nodes potentially added in future that can appear between the Condition and the binary operator.
clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.cpp | ||
---|---|---|
136 | Reverted to cast. |
clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp | ||
---|---|---|
1092 | This line isn't really doing anything. CHECK-FIXES just runs FileCheck on the whole file after clang tidy has applied any fixes. You need to explicitly say what you are expecting it to be. |
clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.cpp | ||
---|---|---|
45 | Just noticed, as this is ignoring Parenthesis and implicit nodes/casts, maybe we should also be ignoring those when getting the condition in the check if (IsSet){ if ((OtherCond && IsSet)) ; } |
clang-tools-extra/clang-tidy/bugprone/RedundantBranchConditionCheck.cpp | ||
---|---|---|
45 | You are right, thanks! I fixed it. |
clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp | ||
---|---|---|
1092 | There's not a whole lot of context for FileCheck to determine if it's been correctly applied or not (same below) -- for instance, won't this pass even if no changes are applied because FileCheck is still going to find isSet in the file? |
clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp | ||
---|---|---|
1092 | Thanks. Fixed. |
clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp | ||
---|---|---|
1092 | Maybe it's just early in the morning for me, but... I was expecting the transformation to be: if (RetT::Test(isSet).Ok() && isSet) { if (RetT::Test(isSet).Ok() && isSet) { } } turns into if (RetT::Test(isSet).Ok() && isSet) { } Why does it remove the && isSet instead? That seems like it's changing the logic here from if (true && false) to if (true). |
clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp | ||
---|---|---|
1092 | IMO it's correct.
As I understand only the second if is transformed. |
clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp | ||
---|---|---|
1092 | Does this only trigger as a redundant branch condition if the definition of RetT::Test() is available? Because Test() takes a bool& so it sure seems like isSet could be modified between the branches if the definition isn't found because it's being passed as a non-const reference to Test(). |
clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp | ||
---|---|---|
1092 |
Removing the body from RetT::Test changes nothing.
|
LGTM!
clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp | ||
---|---|---|
1092 | Given the following four ways of declaring Test(): static RetT Test(bool &_isSet); // #1 static RetT Test(bool _isSet); // #2 static RetT Test(const bool &_isSet); // #3 static RetT Test(bool &_isSet) { return 0; } // #4 I would expect #2 and #3 to behave the same way -- the isSet argument could never be modified by calling Test() and so the second Test(isSet) && isSet is partially redundant and the second if statement can drop the && isSet. (Without dropping the Test(isSet) because the call could still modify some global somewhere, etc.) I would expect #1 to not modify the second if statement at all because there's no way of knowing whether Test(isSet) && isSet is the same between the first if statement and the second one (because the second call to Test(isSet) may modify isSet in a way the caller can observe). Ideally, #4 would be a case where we could remove the entire second if statement because we can identify that not only does isSet not get modified despite being passed by non-const reference, we can see that the Test() function doesn't modify any state at all. However, this seems like it would require data flow analysis and so I think it makes sense to treat #4 the same as #1. That said, I just realized the check isn't being very careful with reference parameters in the first place: https://godbolt.org/z/P1aP3W, so your changes aren't introducing a new problem, they just happened to highlight an existing issue. |
clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp | ||
---|---|---|
1092 | Please look at https://reviews.llvm.org/D91495 - there's a fix for it. |
Just noticed, as this is ignoring Parenthesis and implicit nodes/casts, maybe we should also be ignoring those when getting the condition in the check
InnerIf->getCond()->IgnoreParenImpCasts()
I reckon if that change isnt made this could fail on