[clang-tools-extra] [clang-tidy] Enhance modernize-use-starts-ends-with to handle substr patterns (PR #116033)

Nicolas van Kempen via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 14 13:07:24 PST 2024


nicovank wrote:

> also, is it "ok" to change existing tidy's? like people opted in for one, and that changes now without them knowing?

They know by reading the Release Notes 😃. In this case it's a clear improvement anyway, people are getting what they signed up for plus more. Other changes are sometimes gated by an option that then needs to be enabled.

Consider the following diff that I quickly wrote, didn't test much (save to `diff.txt`, `git checkout main && git apply diff.txt`).
```
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
--- a/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
@@ -171,10 +171,26 @@
                              hasRHS(lengthExprForStringNode("needle")))))
           .bind("expr"),
       this);
+
+  // Case 6: X.substr(0, LEN(Y)) [!=]= Y -> starts_with.
+  Finder->addMatcher(
+      cxxOperatorCallExpr(
+          hasAnyOperatorName("==", "!="),
+          hasOperands(
+              expr().bind("needle"),
+              cxxMemberCallExpr(
+                  argumentCountIs(2), hasArgument(0, ZeroLiteral),
+                  hasArgument(1, lengthExprForStringNode("needle")),
+                  callee(cxxMethodDecl(hasName("substr"),
+                                       ofClass(OnClassWithStartsWithFunction))
+                             .bind("find_fun")))
+                  .bind("find_expr")))
+          .bind("expr"),
+      this);
 }
 
 void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *ComparisonExpr = Result.Nodes.getNodeAs<BinaryOperator>("expr");
+  const auto *ComparisonExpr = Result.Nodes.getNodeAs<Expr>("expr");
   const auto *FindExpr = Result.Nodes.getNodeAs<CXXMemberCallExpr>("find_expr");
   const auto *FindFun = Result.Nodes.getNodeAs<CXXMethodDecl>("find_fun");
   const auto *SearchExpr = Result.Nodes.getNodeAs<Expr>("needle");
@@ -189,7 +205,14 @@
   if (ComparisonExpr->getBeginLoc().isMacroID())
     return;
 
-  const bool Neg = ComparisonExpr->getOpcode() == BO_NE;
+  bool Neg;
+  if (const auto *BO = llvm::dyn_cast<BinaryOperator>(ComparisonExpr)) {
+    Neg = BO->getOpcode() == BO_NE;
+  } else {
+    assert(llvm::isa<CXXOperatorCallExpr>(ComparisonExpr));
+    Neg = llvm::cast<CXXOperatorCallExpr>(ComparisonExpr)->getOperator() ==
+          OO_ExclaimEqual;
+  }
 
   auto Diagnostic =
       diag(FindExpr->getExprLoc(), "use %0 instead of %1() %select{==|!=}2 0")
```

https://github.com/llvm/llvm-project/pull/116033


More information about the cfe-commits mailing list