NoQ created this revision.
NoQ added reviewers: alexfh, gribozavr2, aaron.ballman, stephenkelly, 
xazax.hun, vsavchenko.
Herald added subscribers: martong, mgehre, rnkovacs.
NoQ requested review of this revision.
Herald added a project: clang-tools-extra.

This patch takes advantage of the new ASTMatcher added in D102213 
<https://reviews.llvm.org/D102213> to fix massive false negatives of the 
infinite loop checker on Objective-C.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D102214

Files:
  clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
  clang-tools-extra/clang-tidy/utils/Aliasing.cpp
  clang-tools-extra/clang-tidy/utils/Aliasing.h
  clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.mm

Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.mm
===================================================================
--- /dev/null
+++ 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
Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp
+++ 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();
     }
   };
Index: clang-tools-extra/clang-tidy/utils/Aliasing.h
===================================================================
--- clang-tools-extra/clang-tidy/utils/Aliasing.h
+++ 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
Index: clang-tools-extra/clang-tidy/utils/Aliasing.cpp
===================================================================
--- clang-tools-extra/clang-tidy/utils/Aliasing.cpp
+++ 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<CXXMethodDecl>(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);
 }
Index: clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
@@ -21,6 +21,7 @@
 
 static internal::Matcher<Stmt>
 loopEndingStmt(internal::Matcher<Stmt> 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<DeclRefExpr>(Cond)) {
     if (const auto *Var = dyn_cast<VarDecl>(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<Expr>("condition");
   const auto *LoopStmt = Result.Nodes.getNodeAs<Stmt>("loop-stmt");
-  const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
+  const auto *Func = Result.Nodes.getNodeAs<Decl>("func");
 
   if (isKnownFalse(*Cond, *Result.Context))
     return;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D102214: [clang-... Artem Dergachev via Phabricator via cfe-commits

Reply via email to