[clang-tools-extra] [clang-tidy] Add modernize-use-span-first-last check (PR #118074)

Helmut Januschka via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 29 01:36:50 PST 2024


https://github.com/hjanuschka updated https://github.com/llvm/llvm-project/pull/118074

>From cb748c34d35b8c0c9ca93a67b111dcf5d7665b34 Mon Sep 17 00:00:00 2001
From: Helmut Januschka <helmut at januschka.com>
Date: Fri, 29 Nov 2024 10:17:49 +0100
Subject: [PATCH 1/4] [clang-tidy] Add modernize-use-span-first-last check

Add new check that modernizes std::span::subspan() calls to use the more
expressive first() and last() member functions where applicable.
---
 .../clang-tidy/modernize/CMakeLists.txt       |  1 +
 .../modernize/ModernizeTidyModule.cpp         |  3 +
 .../modernize/UseSpanFirstLastCheck.cpp       | 97 +++++++++++++++++++
 .../modernize/UseSpanFirstLastCheck.h         | 40 ++++++++
 clang-tools-extra/docs/ReleaseNotes.rst       |  4 +
 .../checks/modernize/use-span-first-last.rst  | 19 ++++
 .../modernize-subspan-conversion.cpp          | 50 ++++++++++
 7 files changed, 214 insertions(+)
 create mode 100644 clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
 create mode 100644 clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index c919d49b42873a..47dd12a2640b6c 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,6 +49,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..6fc5de5aad20b7 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,6 +42,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -122,6 +123,8 @@ class ModernizeModule : public ClangTidyModule {
     CheckFactories.registerCheck<UseUncaughtExceptionsCheck>(
         "modernize-use-uncaught-exceptions");
     CheckFactories.registerCheck<UseUsingCheck>("modernize-use-using");
+    CheckFactories.registerCheck<UseSpanFirstLastCheck>("modernize-use-span-first-last");
+
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
new file mode 100644
index 00000000000000..f57571f2aa7c86
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -0,0 +1,97 @@
+//===--- UseSpanFirstLastCheck.cpp - clang-tidy-----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseSpanFirstLastCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
+  // Match span::subspan calls
+  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
+      recordType(hasDeclaration(classTemplateSpecializationDecl(
+          hasName("::std::span"))))));
+
+  Finder->addMatcher(
+      cxxMemberCallExpr(
+          callee(memberExpr(hasDeclaration(
+              cxxMethodDecl(hasName("subspan"))))),
+          on(expr(HasSpanType)))
+          .bind("subspan"),
+      this);
+}
+
+void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs<CXXMemberCallExpr>("subspan");
+  if (!Call)
+    return;
+
+  handleSubspanCall(Result, Call);
+}
+
+void UseSpanFirstLastCheck::handleSubspanCall(
+    const MatchFinder::MatchResult &Result, const CXXMemberCallExpr *Call) {
+  // Get arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if (NumArgs == 0 || NumArgs > 2)
+    return;
+
+  const Expr *Offset = Call->getArg(0);
+  const Expr *Count = NumArgs > 1 ? Call->getArg(1) : nullptr;
+  auto &Context = *Result.Context;
+  bool IsZeroOffset = false;
+
+  // Check if offset is zero through any implicit casts
+  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  if (const auto *IL = dyn_cast<IntegerLiteral>(OffsetE)) {
+    IsZeroOffset = IL->getValue() == 0;
+  }
+
+  // Build replacement text
+  std::string Replacement;
+  if (IsZeroOffset && Count) {
+    // subspan(0, count) -> first(count)
+    auto CountStr = Lexer::getSourceText(
+        CharSourceRange::getTokenRange(Count->getSourceRange()),
+        Context.getSourceManager(), Context.getLangOpts());
+    const auto *Base = cast<CXXMemberCallExpr>(Call)->getImplicitObjectArgument();
+    auto BaseStr = Lexer::getSourceText(
+        CharSourceRange::getTokenRange(Base->getSourceRange()),
+        Context.getSourceManager(), Context.getLangOpts());
+    Replacement = BaseStr.str() + ".first(" + CountStr.str() + ")";
+  } else if (NumArgs == 1) {
+    // subspan(n) -> last(size() - n)
+    auto OffsetStr = Lexer::getSourceText(
+        CharSourceRange::getTokenRange(Offset->getSourceRange()),
+        Context.getSourceManager(), Context.getLangOpts());
+    
+    const auto *Base = cast<CXXMemberCallExpr>(Call)->getImplicitObjectArgument();
+    auto BaseStr = Lexer::getSourceText(
+        CharSourceRange::getTokenRange(Base->getSourceRange()),
+        Context.getSourceManager(), Context.getLangOpts());
+    
+    Replacement = BaseStr.str() + ".last(" + BaseStr.str() + ".size() - " + OffsetStr.str() + ")";
+  }
+
+  if (!Replacement.empty()) {
+    if (IsZeroOffset && Count) {
+        diag(Call->getBeginLoc(), "prefer span::first() over subspan()")
+            << FixItHint::CreateReplacement(Call->getSourceRange(), Replacement);
+    } else {
+        diag(Call->getBeginLoc(), "prefer span::last() over subspan()")
+            << FixItHint::CreateReplacement(Call->getSourceRange(), Replacement);
+    }
+  }
+}
+
+} // namespace clang::tidy::modernize
\ No newline at end of file
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
new file mode 100644
index 00000000000000..141b848be9abbb
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
@@ -0,0 +1,40 @@
+//===--- UseSpanFirstLastCheck.h - clang-tidy-------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESPANFIRSTLASTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESPANFIRSTLASTCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::modernize {
+
+/// Converts std::span::subspan() calls to the more modern first()/last() methods
+/// where applicable.
+///
+/// For example:
+/// \code
+///   std::span<int> s = ...;
+///   auto sub = s.subspan(0, n);    // ->  auto sub = s.first(n);
+///   auto sub2 = s.subspan(n);      // ->  auto sub2 = s.last(s.size() - n);
+/// \endcode
+class UseSpanFirstLastCheck : public ClangTidyCheck {
+public:
+  UseSpanFirstLastCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  void handleSubspanCall(const ast_matchers::MatchFinder::MatchResult &Result,
+                        const CXXMemberCallExpr *Call);
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESPANFIRSTLASTCHECK_H
\ No newline at end of file
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index f050391110385e..04a45d002c0d1d 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -145,6 +145,10 @@ New checks
 New check aliases
 ^^^^^^^^^^^^^^^^^
 
+- New check `modernize-use-span-first-last` has been added that suggests using
+  ``std::span::first()`` and ``std::span::last()`` member functions instead of
+  equivalent ``subspan()``.
+
 - New alias :doc:`cert-arr39-c <clang-tidy/checks/cert/arr39-c>` to
   :doc:`bugprone-sizeof-expression
   <clang-tidy/checks/bugprone/sizeof-expression>` was added.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
new file mode 100644
index 00000000000000..e8aad59bb2264f
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-span-first-last.rst
@@ -0,0 +1,19 @@
+.. title:: clang-tidy - modernize-use-span-first-last
+
+modernize-use-span-first-last
+============================
+
+Checks for uses of ``std::span::subspan()`` that can be replaced with clearer
+``first()`` or ``last()`` member functions.
+
+Covered scenarios:
+
+==================================== ==================================
+Expression                           Replacement
+------------------------------------ ----------------------------------
+``s.subspan(0, n)``                  ``s.first(n)``
+``s.subspan(n)``                     ``s.last(s.size() - n)``
+==================================== ==================================
+
+Non-zero offset with count (like ``subspan(1, n)``) has no direct equivalent
+using ``first()`` or ``last()``, so these cases are not transformed.
\ No newline at end of file
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp
new file mode 100644
index 00000000000000..cb78bc02f22d4f
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp
@@ -0,0 +1,50 @@
+// RUN: %check_clang_tidy %s modernize-use-span-first-last %t
+
+namespace std {
+template <typename T>
+class span {
+  T* ptr;
+  __SIZE_TYPE__ len;
+
+public:
+  span(T* p, __SIZE_TYPE__ l) : ptr(p), len(l) {}
+  
+  span<T> subspan(__SIZE_TYPE__ offset) const {
+    return span(ptr + offset, len - offset);
+  }
+  
+  span<T> subspan(__SIZE_TYPE__ offset, __SIZE_TYPE__ count) const {
+    return span(ptr + offset, count);
+  }
+
+  span<T> first(__SIZE_TYPE__ count) const {
+    return span(ptr, count);
+  }
+
+  span<T> last(__SIZE_TYPE__ count) const {
+    return span(ptr + (len - count), count);
+  }
+
+  __SIZE_TYPE__ size() const { return len; }
+};
+} // namespace std
+
+void test() {
+  int arr[] = {1, 2, 3, 4, 5};
+  std::span<int> s(arr, 5);
+
+  auto sub1 = s.subspan(0, 3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: prefer span::first() over subspan()
+  // CHECK-FIXES: auto sub1 = s.first(3);
+
+  auto sub2 = s.subspan(2);
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: prefer span::last() over subspan()
+  // CHECK-FIXES: auto sub2 = s.last(s.size() - 2);
+
+  __SIZE_TYPE__ n = 2;
+  auto sub3 = s.subspan(0, n);
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: prefer span::first() over subspan()
+  // CHECK-FIXES: auto sub3 = s.first(n);
+
+  auto sub4 = s.subspan(1, 2);  // No warning
+}
\ No newline at end of file

>From ec5a6b0ceb0fbbf03ea36a38fb627b25ab4e62de Mon Sep 17 00:00:00 2001
From: Helmut Januschka <helmut at januschka.com>
Date: Fri, 29 Nov 2024 10:19:21 +0100
Subject: [PATCH 2/4] format

---
 .../modernize/UseSpanFirstLastCheck.cpp       | 41 ++++++++++---------
 .../modernize/UseSpanFirstLastCheck.h         |  6 +--
 2 files changed, 24 insertions(+), 23 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
index f57571f2aa7c86..6cf01386b0c3fb 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
@@ -18,17 +18,15 @@ namespace clang::tidy::modernize {
 
 void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
   // Match span::subspan calls
-  const auto HasSpanType = hasType(hasUnqualifiedDesugaredType(
-      recordType(hasDeclaration(classTemplateSpecializationDecl(
-          hasName("::std::span"))))));
+  const auto HasSpanType =
+      hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(
+          classTemplateSpecializationDecl(hasName("::std::span"))))));
 
-  Finder->addMatcher(
-      cxxMemberCallExpr(
-          callee(memberExpr(hasDeclaration(
-              cxxMethodDecl(hasName("subspan"))))),
-          on(expr(HasSpanType)))
-          .bind("subspan"),
-      this);
+  Finder->addMatcher(cxxMemberCallExpr(callee(memberExpr(hasDeclaration(
+                                           cxxMethodDecl(hasName("subspan"))))),
+                                       on(expr(HasSpanType)))
+                         .bind("subspan"),
+                     this);
 }
 
 void UseSpanFirstLastCheck::check(const MatchFinder::MatchResult &Result) {
@@ -52,7 +50,7 @@ void UseSpanFirstLastCheck::handleSubspanCall(
   bool IsZeroOffset = false;
 
   // Check if offset is zero through any implicit casts
-  const Expr* OffsetE = Offset->IgnoreImpCasts();
+  const Expr *OffsetE = Offset->IgnoreImpCasts();
   if (const auto *IL = dyn_cast<IntegerLiteral>(OffsetE)) {
     IsZeroOffset = IL->getValue() == 0;
   }
@@ -64,7 +62,8 @@ void UseSpanFirstLastCheck::handleSubspanCall(
     auto CountStr = Lexer::getSourceText(
         CharSourceRange::getTokenRange(Count->getSourceRange()),
         Context.getSourceManager(), Context.getLangOpts());
-    const auto *Base = cast<CXXMemberCallExpr>(Call)->getImplicitObjectArgument();
+    const auto *Base =
+        cast<CXXMemberCallExpr>(Call)->getImplicitObjectArgument();
     auto BaseStr = Lexer::getSourceText(
         CharSourceRange::getTokenRange(Base->getSourceRange()),
         Context.getSourceManager(), Context.getLangOpts());
@@ -74,22 +73,24 @@ void UseSpanFirstLastCheck::handleSubspanCall(
     auto OffsetStr = Lexer::getSourceText(
         CharSourceRange::getTokenRange(Offset->getSourceRange()),
         Context.getSourceManager(), Context.getLangOpts());
-    
-    const auto *Base = cast<CXXMemberCallExpr>(Call)->getImplicitObjectArgument();
+
+    const auto *Base =
+        cast<CXXMemberCallExpr>(Call)->getImplicitObjectArgument();
     auto BaseStr = Lexer::getSourceText(
         CharSourceRange::getTokenRange(Base->getSourceRange()),
         Context.getSourceManager(), Context.getLangOpts());
-    
-    Replacement = BaseStr.str() + ".last(" + BaseStr.str() + ".size() - " + OffsetStr.str() + ")";
+
+    Replacement = BaseStr.str() + ".last(" + BaseStr.str() + ".size() - " +
+                  OffsetStr.str() + ")";
   }
 
   if (!Replacement.empty()) {
     if (IsZeroOffset && Count) {
-        diag(Call->getBeginLoc(), "prefer span::first() over subspan()")
-            << FixItHint::CreateReplacement(Call->getSourceRange(), Replacement);
+      diag(Call->getBeginLoc(), "prefer span::first() over subspan()")
+          << FixItHint::CreateReplacement(Call->getSourceRange(), Replacement);
     } else {
-        diag(Call->getBeginLoc(), "prefer span::last() over subspan()")
-            << FixItHint::CreateReplacement(Call->getSourceRange(), Replacement);
+      diag(Call->getBeginLoc(), "prefer span::last() over subspan()")
+          << FixItHint::CreateReplacement(Call->getSourceRange(), Replacement);
     }
   }
 }
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
index 141b848be9abbb..8d4c6035f7ec76 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
@@ -13,8 +13,8 @@
 
 namespace clang::tidy::modernize {
 
-/// Converts std::span::subspan() calls to the more modern first()/last() methods
-/// where applicable.
+/// Converts std::span::subspan() calls to the more modern first()/last()
+/// methods where applicable.
 ///
 /// For example:
 /// \code
@@ -32,7 +32,7 @@ class UseSpanFirstLastCheck : public ClangTidyCheck {
 
 private:
   void handleSubspanCall(const ast_matchers::MatchFinder::MatchResult &Result,
-                        const CXXMemberCallExpr *Call);
+                         const CXXMemberCallExpr *Call);
 };
 
 } // namespace clang::tidy::modernize

>From 5cf1b7ce1fcaf87a26f1ad1ff0d265a47613c144 Mon Sep 17 00:00:00 2001
From: Helmut Januschka <helmut at januschka.com>
Date: Fri, 29 Nov 2024 10:28:42 +0100
Subject: [PATCH 3/4] format

---
 clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 6fc5de5aad20b7..c473c80e3cd0eb 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -123,7 +123,8 @@ class ModernizeModule : public ClangTidyModule {
     CheckFactories.registerCheck<UseUncaughtExceptionsCheck>(
         "modernize-use-uncaught-exceptions");
     CheckFactories.registerCheck<UseUsingCheck>("modernize-use-using");
-    CheckFactories.registerCheck<UseSpanFirstLastCheck>("modernize-use-span-first-last");
+    CheckFactories.registerCheck<UseSpanFirstLastCheck>(
+        "modernize-use-span-first-last");
 
   }
 };

>From b357f8c8fe607924ba6c5537f42ebfffaa09c011 Mon Sep 17 00:00:00 2001
From: Helmut Januschka <helmut at januschka.com>
Date: Fri, 29 Nov 2024 10:36:31 +0100
Subject: [PATCH 4/4] format

---
 clang-tools-extra/clang-tidy/modernize/CMakeLists.txt  |  1 -
 .../clang-tidy/modernize/ModernizeTidyModule.cpp       |  3 ---
 .../clang-tidy/readability/CMakeLists.txt              |  1 +
 .../clang-tidy/readability/ReadabilityTidyModule.cpp   |  3 +++
 .../UseSpanFirstLastCheck.cpp                          |  4 ++--
 .../{modernize => readability}/UseSpanFirstLastCheck.h | 10 +++++-----
 clang-tools-extra/docs/ReleaseNotes.rst                |  2 +-
 .../use-starts-ends-with.rst                           |  4 ++--
 .../use-span-first-last.cpp}                           |  2 +-
 9 files changed, 15 insertions(+), 15 deletions(-)
 rename clang-tools-extra/clang-tidy/{modernize => readability}/UseSpanFirstLastCheck.cpp (97%)
 rename clang-tools-extra/clang-tidy/{modernize => readability}/UseSpanFirstLastCheck.h (79%)
 rename clang-tools-extra/docs/clang-tidy/checks/{modernize => readability}/use-starts-ends-with.rst (92%)
 rename clang-tools-extra/test/clang-tidy/checkers/{modernize/modernize-subspan-conversion.cpp => readability/use-span-first-last.cpp} (95%)

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index 47dd12a2640b6c..c919d49b42873a 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -49,7 +49,6 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
-  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index c473c80e3cd0eb..b2a8f9dd20adba 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -42,7 +42,6 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
-#include "UseSpanFirstLastCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -123,8 +122,6 @@ class ModernizeModule : public ClangTidyModule {
     CheckFactories.registerCheck<UseUncaughtExceptionsCheck>(
         "modernize-use-uncaught-exceptions");
     CheckFactories.registerCheck<UseUsingCheck>("modernize-use-using");
-    CheckFactories.registerCheck<UseSpanFirstLastCheck>(
-        "modernize-use-span-first-last");
 
   }
 };
diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index 8f303c51e1b0da..f9f9e8e7f19685 100644
--- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -58,6 +58,7 @@ add_clang_library(clangTidyReadabilityModule STATIC
   UppercaseLiteralSuffixCheck.cpp
   UseAnyOfAllOfCheck.cpp
   UseStdMinMaxCheck.cpp
+  UseSpanFirstLastCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index d61c0ba39658e5..9729d080f63a84 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -60,6 +60,7 @@
 #include "UniqueptrDeleteReleaseCheck.h"
 #include "UppercaseLiteralSuffixCheck.h"
 #include "UseAnyOfAllOfCheck.h"
+#include "UseSpanFirstLastCheck.h"
 #include "UseStdMinMaxCheck.h"
 
 namespace clang::tidy {
@@ -172,6 +173,8 @@ class ReadabilityModule : public ClangTidyModule {
         "readability-use-anyofallof");
     CheckFactories.registerCheck<UseStdMinMaxCheck>(
         "readability-use-std-min-max");
+    CheckFactories.registerCheck<UseSpanFirstLastCheck>(
+        "readability-use-span-first-last");
   }
 };
 
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp b/clang-tools-extra/clang-tidy/readability/UseSpanFirstLastCheck.cpp
similarity index 97%
rename from clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
rename to clang-tools-extra/clang-tidy/readability/UseSpanFirstLastCheck.cpp
index 6cf01386b0c3fb..da7d147565fbdf 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/UseSpanFirstLastCheck.cpp
@@ -14,7 +14,7 @@
 
 using namespace clang::ast_matchers;
 
-namespace clang::tidy::modernize {
+namespace clang::tidy::readability {
 
 void UseSpanFirstLastCheck::registerMatchers(MatchFinder *Finder) {
   // Match span::subspan calls
@@ -95,4 +95,4 @@ void UseSpanFirstLastCheck::handleSubspanCall(
   }
 }
 
-} // namespace clang::tidy::modernize
\ No newline at end of file
+} // namespace clang::tidy::readability
\ No newline at end of file
diff --git a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h b/clang-tools-extra/clang-tidy/readability/UseSpanFirstLastCheck.h
similarity index 79%
rename from clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
rename to clang-tools-extra/clang-tidy/readability/UseSpanFirstLastCheck.h
index 8d4c6035f7ec76..271730ed4985a3 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseSpanFirstLastCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/UseSpanFirstLastCheck.h
@@ -6,12 +6,12 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESPANFIRSTLASTCHECK_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESPANFIRSTLASTCHECK_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_USESPANFIRSTLASTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_USESPANFIRSTLASTCHECK_H
 
 #include "../ClangTidyCheck.h"
 
-namespace clang::tidy::modernize {
+namespace clang::tidy::readability {
 
 /// Converts std::span::subspan() calls to the more modern first()/last()
 /// methods where applicable.
@@ -35,6 +35,6 @@ class UseSpanFirstLastCheck : public ClangTidyCheck {
                          const CXXMemberCallExpr *Call);
 };
 
-} // namespace clang::tidy::modernize
+} // namespace clang::tidy::readability
 
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESPANFIRSTLASTCHECK_H
\ No newline at end of file
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_USESPANFIRSTLASTCHECK_H
\ No newline at end of file
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 04a45d002c0d1d..a52b778a27b5f4 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -145,7 +145,7 @@ New checks
 New check aliases
 ^^^^^^^^^^^^^^^^^
 
-- New check `modernize-use-span-first-last` has been added that suggests using
+- New check `readability-use-span-first-last` has been added that suggests using
   ``std::span::first()`` and ``std::span::last()`` member functions instead of
   equivalent ``subspan()``.
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-starts-ends-with.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/use-starts-ends-with.rst
similarity index 92%
rename from clang-tools-extra/docs/clang-tidy/checks/modernize/use-starts-ends-with.rst
rename to clang-tools-extra/docs/clang-tidy/checks/readability/use-starts-ends-with.rst
index 78cd900885ac3f..ff5c0d53feeb15 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-starts-ends-with.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/use-starts-ends-with.rst
@@ -1,6 +1,6 @@
-.. title:: clang-tidy - modernize-use-starts-ends-with
+.. title:: clang-tidy - readability-use-starts-ends-with
 
-modernize-use-starts-ends-with
+readability-use-starts-ends-with
 ==============================
 
 Checks for common roundabout ways to express ``starts_with`` and ``ends_with``
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/use-span-first-last.cpp
similarity index 95%
rename from clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp
rename to clang-tools-extra/test/clang-tidy/checkers/readability/use-span-first-last.cpp
index cb78bc02f22d4f..93ae95bdd8b6b4 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/modernize-subspan-conversion.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/use-span-first-last.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s modernize-use-span-first-last %t
+// RUN: %check_clang_tidy %s readability-use-span-first-last %t
 
 namespace std {
 template <typename T>



More information about the cfe-commits mailing list