forked from OSchip/llvm-project
[clang-tidy] Reduce false positives for `bugprone-infinite-loop` with dependent expressions
Fixes https://github.com/llvm/llvm-project/issues/51423. Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D113499
This commit is contained in:
parent
3659780d58
commit
cce79514ff
|
@ -117,12 +117,32 @@ static std::string getCondVarNames(const Stmt *Cond) {
|
|||
return Result;
|
||||
}
|
||||
|
||||
static bool isKnownFalse(const Expr &Cond, const ASTContext &Ctx) {
|
||||
if (Cond.isValueDependent())
|
||||
static bool isKnownToHaveValue(const Expr &Cond, const ASTContext &Ctx,
|
||||
bool ExpectedValue) {
|
||||
if (Cond.isValueDependent()) {
|
||||
if (const auto *BinOp = dyn_cast<BinaryOperator>(&Cond)) {
|
||||
// Conjunctions (disjunctions) can still be handled if at least one
|
||||
// conjunct (disjunct) is known to be false (true).
|
||||
if (!ExpectedValue && BinOp->getOpcode() == BO_LAnd)
|
||||
return isKnownToHaveValue(*BinOp->getLHS(), Ctx, false) ||
|
||||
isKnownToHaveValue(*BinOp->getRHS(), Ctx, false);
|
||||
if (ExpectedValue && BinOp->getOpcode() == BO_LOr)
|
||||
return isKnownToHaveValue(*BinOp->getLHS(), Ctx, true) ||
|
||||
isKnownToHaveValue(*BinOp->getRHS(), Ctx, true);
|
||||
if (BinOp->getOpcode() == BO_Comma)
|
||||
return isKnownToHaveValue(*BinOp->getRHS(), Ctx, ExpectedValue);
|
||||
} else if (const auto *UnOp = dyn_cast<UnaryOperator>(&Cond)) {
|
||||
if (UnOp->getOpcode() == UO_LNot)
|
||||
return isKnownToHaveValue(*UnOp->getSubExpr(), Ctx, !ExpectedValue);
|
||||
} else if (const auto *Paren = dyn_cast<ParenExpr>(&Cond))
|
||||
return isKnownToHaveValue(*Paren->getSubExpr(), Ctx, ExpectedValue);
|
||||
else if (const auto *ImplCast = dyn_cast<ImplicitCastExpr>(&Cond))
|
||||
return isKnownToHaveValue(*ImplCast->getSubExpr(), Ctx, ExpectedValue);
|
||||
return false;
|
||||
}
|
||||
bool Result = false;
|
||||
if (Cond.EvaluateAsBooleanCondition(Result, Ctx))
|
||||
return !Result;
|
||||
return Result == ExpectedValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -144,7 +164,7 @@ void InfiniteLoopCheck::check(const MatchFinder::MatchResult &Result) {
|
|||
const auto *LoopStmt = Result.Nodes.getNodeAs<Stmt>("loop-stmt");
|
||||
const auto *Func = Result.Nodes.getNodeAs<Decl>("func");
|
||||
|
||||
if (isKnownFalse(*Cond, *Result.Context))
|
||||
if (isKnownToHaveValue(*Cond, *Result.Context, false))
|
||||
return;
|
||||
|
||||
bool ShouldHaveConditionVariables = true;
|
||||
|
|
|
@ -176,6 +176,9 @@ Changes in existing checks
|
|||
- Fixed incorrect suggestions for :doc:`readability-container-size-empty
|
||||
<clang-tidy/checks/readability-container-size-empty>` when smart pointers are involved.
|
||||
|
||||
- Fixed some false positives in :doc:`bugprone-infinite-loop
|
||||
<clang-tidy/checks/bugprone-infinite-loop>` involving dependent expressions.
|
||||
|
||||
Removed checks
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %check_clang_tidy %s bugprone-infinite-loop %t \
|
||||
// RUN: -- -- -fexceptions -fblocks
|
||||
// RUN: -- -- -fexceptions -fblocks -fno-delayed-template-parsing
|
||||
|
||||
void simple_infinite_loop1() {
|
||||
int i = 0;
|
||||
|
@ -622,3 +622,31 @@ void test_volatile_concrete_address(int i, int size) {
|
|||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (size) are updated in the loop body [bugprone-infinite-loop]
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int some_template_fn() { return 1; }
|
||||
|
||||
template <typename T>
|
||||
void test_dependent_condition() {
|
||||
const int error = some_template_fn<T>();
|
||||
do {
|
||||
} while (false && error == 0);
|
||||
|
||||
const int val = some_template_fn<T>();
|
||||
for (; !(val == 0 || true);) {
|
||||
}
|
||||
|
||||
const int val2 = some_template_fn<T>();
|
||||
for (; !(val2 == 0 || false);) {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (val2) are updated in the loop body [bugprone-infinite-loop]
|
||||
}
|
||||
|
||||
const int val3 = some_template_fn<T>();
|
||||
do {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (val3) are updated in the loop body [bugprone-infinite-loop]
|
||||
} while (1, (true) && val3 == 1);
|
||||
|
||||
const int val4 = some_template_fn<T>();
|
||||
do {
|
||||
} while (1, (false) && val4 == 1);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue