diff --git a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp --- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp @@ -21,6 +21,7 @@ static internal::Matcher loopEndingStmt(internal::Matcher Internal) { + // FIXME: Cover noreturn ObjC methods (and blocks?). return stmt(anyOf( mapAnyOf(breakStmt, returnStmt, gotoStmt, cxxThrowExpr).with(Internal), callExpr(Internal, callee(functionDecl(isNoReturn()))))); @@ -43,9 +44,8 @@ } /// Return whether `Cond` is a variable that is possibly changed in `LoopStmt`. -static bool isVarThatIsPossiblyChanged(const FunctionDecl *Func, - const Stmt *LoopStmt, const Stmt *Cond, - ASTContext *Context) { +static bool isVarThatIsPossiblyChanged(const Decl *Func, const Stmt *LoopStmt, + const Stmt *Cond, ASTContext *Context) { if (const auto *DRE = dyn_cast(Cond)) { if (const auto *Var = dyn_cast(DRE->getDecl())) { if (!Var->isLocalVarDeclOrParm()) @@ -70,9 +70,8 @@ } /// Return whether at least one variable of `Cond` changed in `LoopStmt`. -static bool isAtLeastOneCondVarChanged(const FunctionDecl *Func, - const Stmt *LoopStmt, const Stmt *Cond, - ASTContext *Context) { +static bool isAtLeastOneCondVarChanged(const Decl *Func, const Stmt *LoopStmt, + const Stmt *Cond, ASTContext *Context) { if (isVarThatIsPossiblyChanged(Func, LoopStmt, Cond, Context)) return true; @@ -118,9 +117,9 @@ void InfiniteLoopCheck::registerMatchers(MatchFinder *Finder) { const auto LoopCondition = allOf( hasCondition( - expr(forFunction(functionDecl().bind("func"))).bind("condition")), + expr(forCallable(decl().bind("func"))).bind("condition")), unless(hasBody(hasDescendant( - loopEndingStmt(forFunction(equalsBoundNode("func"))))))); + loopEndingStmt(forCallable(equalsBoundNode("func"))))))); Finder->addMatcher(mapAnyOf(whileStmt, doStmt, forStmt) .with(LoopCondition) @@ -131,7 +130,7 @@ void InfiniteLoopCheck::check(const MatchFinder::MatchResult &Result) { const auto *Cond = Result.Nodes.getNodeAs("condition"); const auto *LoopStmt = Result.Nodes.getNodeAs("loop-stmt"); - const auto *Func = Result.Nodes.getNodeAs("func"); + const auto *Func = Result.Nodes.getNodeAs("func"); if (isKnownFalse(*Cond, *Result.Context)) return; diff --git a/clang-tools-extra/clang-tidy/utils/Aliasing.h b/clang-tools-extra/clang-tidy/utils/Aliasing.h --- a/clang-tools-extra/clang-tidy/utils/Aliasing.h +++ b/clang-tools-extra/clang-tidy/utils/Aliasing.h @@ -27,7 +27,7 @@ /// For `f()` and `n` the function returns ``true`` because `p` is a /// pointer to `n` created in `f()`. -bool hasPtrOrReferenceInFunc(const FunctionDecl *Func, const VarDecl *Var); +bool hasPtrOrReferenceInFunc(const Decl *Func, const VarDecl *Var); } // namespace utils } // namespace tidy diff --git a/clang-tools-extra/clang-tidy/utils/Aliasing.cpp b/clang-tools-extra/clang-tidy/utils/Aliasing.cpp --- a/clang-tools-extra/clang-tidy/utils/Aliasing.cpp +++ b/clang-tools-extra/clang-tidy/utils/Aliasing.cpp @@ -78,7 +78,7 @@ return false; } -static bool refersToEnclosingLambdaCaptureByRef(const FunctionDecl *Func, +static bool refersToEnclosingLambdaCaptureByRef(const Decl *Func, const VarDecl *Var) { const auto *MD = dyn_cast(Func); if (!MD) @@ -91,7 +91,7 @@ return capturesByRef(RD, Var); } -bool hasPtrOrReferenceInFunc(const FunctionDecl *Func, const VarDecl *Var) { +bool hasPtrOrReferenceInFunc(const Decl *Func, const VarDecl *Var) { return hasPtrOrReferenceInStmt(Func->getBody(), Var) || refersToEnclosingLambdaCaptureByRef(Func, Var); } diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp @@ -511,8 +511,7 @@ bool finished = false; auto block = ^() { while (!finished) { - // FIXME: This should warn. It currently reacts to &finished - // outside the block which ideally shouldn't have any effect. + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: this loop is infinite; none of its condition variables (finished) are updated in the loop body [bugprone-infinite-loop] wait(); } }; diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.mm b/clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.mm new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.mm @@ -0,0 +1,35 @@ +// RUN: %check_clang_tidy %s bugprone-infinite-loop %t -- -- -fblocks + +@interface I +-(void) instanceMethod; ++(void) classMethod; +@end + +void plainCFunction() { + int i = 0; + int j = 0; + while (i < 10) { + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop] + j++; + } +} + +@implementation I +- (void)instanceMethod { + int i = 0; + int j = 0; + while (i < 10) { + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop] + j++; + } +} + ++ (void)classMethod { + int i = 0; + int j = 0; + while (i < 10) { + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this loop is infinite; none of its condition variables (i) are updated in the loop body [bugprone-infinite-loop] + j++; + } +} +@end