[clang-tools-extra] [clang-tidy][modernize-use-starts-ends-with] Add support for compare() (PR #89530)

Piotr Zegar via cfe-commits cfe-commits at lists.llvm.org
Sun Apr 21 14:20:47 PDT 2024


================
@@ -16,6 +16,75 @@
 using namespace clang::ast_matchers;
 
 namespace clang::tidy::modernize {
+namespace {
+// Given two argument indices X and Y, matches when a call expression has a
+// string at index X with an expression representing that string's length at
+// index Y. The string can be a string literal or a variable. The length can be
+// matched via an integer literal or a call to strlen() in the case of a string
+// literal, and by a call to size() or length() in the string variable case.
+AST_POLYMORPHIC_MATCHER_P2(hasStringAndLengthArguments,
+                           AST_POLYMORPHIC_SUPPORTED_TYPES(
+                               CallExpr, CXXConstructExpr,
+                               CXXUnresolvedConstructExpr, ObjCMessageExpr),
+                           unsigned, StringArgIndex, unsigned, LengthArgIndex) {
+  if (StringArgIndex >= Node.getNumArgs() ||
+      LengthArgIndex >= Node.getNumArgs()) {
+    return false;
+  }
+
+  const Expr *StringArgExpr =
+      Node.getArg(StringArgIndex)->IgnoreParenImpCasts();
+  const Expr *LengthArgExpr =
+      Node.getArg(LengthArgIndex)->IgnoreParenImpCasts();
+
+  if (const auto *StringArg = dyn_cast<StringLiteral>(StringArgExpr)) {
+    // Match an integer literal equal to the string length or a call to strlen.
+
+    static const auto Matcher = expr(anyOf(
+        integerLiteral().bind("integer_literal_size"),
+        callExpr(callee(functionDecl(hasName("strlen"))), argumentCountIs(1),
+                 hasArgument(0, stringLiteral().bind("strlen_arg")))));
+
+    if (!Matcher.matches(*LengthArgExpr, Finder, Builder)) {
+      return false;
+    }
+
+    return Builder->removeBindings(
+        [&](const ast_matchers::internal::BoundNodesMap &Nodes) {
+          const auto *IntegerLiteralSize =
+              Nodes.getNodeAs<IntegerLiteral>("integer_literal_size");
+          const auto *StrlenArg = Nodes.getNodeAs<StringLiteral>("strlen_arg");
+          if (IntegerLiteralSize) {
+            return IntegerLiteralSize->getValue().getZExtValue() !=
+                   StringArg->getLength();
+          }
+          return StrlenArg->getLength() != StringArg->getLength();
+        });
+  }
+
+  if (const auto *StringArg = dyn_cast<DeclRefExpr>(StringArgExpr)) {
+    // Match a call to size() or length() on the same variable.
+
+    static const auto Matcher = cxxMemberCallExpr(
+        on(declRefExpr(to(varDecl().bind("string_var_decl")))),
+        callee(cxxMethodDecl(hasAnyName("size", "length"), isConst(),
+                             parameterCountIs(0))));
----------------
PiotrZSL wrote:

instead of making them static, pass them to this matcher as two "InnerMatcher", check how other checks/matchers do that. Static matchers could make problems with object lifetime, and code like this is not allowed per codding standard.

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


More information about the cfe-commits mailing list