https://github.com/kuhar updated 
https://github.com/llvm/llvm-project/pull/177722

>From caebed302b534f4aa1e788ac05f9c5d1d9642012 Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <[email protected]>
Date: Fri, 23 Jan 2026 20:10:03 -0500
Subject: [PATCH 01/10] [clang-tidy] Add llvm-use-vector-utils

This new check suggests the following replacements:
*  `llvm::to_vector(llvm::map_range(X, Fn))` -> `llvm::map_to_vector(X, Fn)`
*  `llvm::to_vector(llvm::make_filter_range(X, Fn))` -> 
`llvm::filter_to_vector(X, Fn)`

and add the `SmallVectorExtras.h` include when necessary.
---
 .../clang-tidy/llvm/CMakeLists.txt            |   1 +
 .../clang-tidy/llvm/LLVMTidyModule.cpp        |   2 +
 .../clang-tidy/llvm/UseVectorUtilsCheck.cpp   | 128 ++++++++++++++++++
 .../clang-tidy/llvm/UseVectorUtilsCheck.h     |  41 ++++++
 clang-tools-extra/docs/ReleaseNotes.rst       |   7 +
 .../docs/clang-tidy/checks/list.rst           |   1 +
 .../checks/llvm/use-vector-utils.rst          |  32 +++++
 .../checkers/llvm/use-vector-utils.cpp        | 103 ++++++++++++++
 8 files changed, 315 insertions(+)
 create mode 100644 clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/llvm/use-vector-utils.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp

diff --git a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
index 78ef0444305ff..56bf4f31bd0e8 100644
--- a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
@@ -13,6 +13,7 @@ add_clang_library(clangTidyLLVMModule STATIC
   TwineLocalCheck.cpp
   UseNewMLIROpBuilderCheck.cpp
   UseRangesCheck.cpp
+  UseVectorUtilsCheck.cpp
 
   LINK_LIBS
   clangTidy
diff --git a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp 
b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
index 56c6db05e9792..eb1ae820dabf8 100644
--- a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
@@ -19,6 +19,7 @@
 #include "TwineLocalCheck.h"
 #include "UseNewMLIROpBuilderCheck.h"
 #include "UseRangesCheck.h"
+#include "UseVectorUtilsCheck.h"
 
 namespace clang::tidy {
 namespace llvm_check {
@@ -45,6 +46,7 @@ class LLVMModule : public ClangTidyModule {
     CheckFactories.registerCheck<UseNewMlirOpBuilderCheck>(
         "llvm-use-new-mlir-op-builder");
     CheckFactories.registerCheck<UseRangesCheck>("llvm-use-ranges");
+    CheckFactories.registerCheck<UseVectorUtilsCheck>("llvm-use-vector-utils");
   }
 
   ClangTidyOptions getModuleOptions() override {
diff --git a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp 
b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
new file mode 100644
index 0000000000000..ba377339c1cd5
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
@@ -0,0 +1,128 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "UseVectorUtilsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::llvm_check {
+
+UseVectorUtilsCheck::UseVectorUtilsCheck(StringRef Name,
+                                         ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      Inserter(Options.getLocalOrGlobal("IncludeStyle",
+                                        utils::IncludeSorter::IS_LLVM),
+               areDiagsSelfContained()) {}
+
+void UseVectorUtilsCheck::registerPPCallbacks(const SourceManager &SM,
+                                              Preprocessor *PP,
+                                              Preprocessor *ModuleExpanderPP) {
+  Inserter.registerPreprocessor(PP);
+}
+
+void UseVectorUtilsCheck::registerMatchers(MatchFinder *Finder) {
+  // Match `llvm::to_vector(llvm::map_range(X, F))`.
+  Finder->addMatcher(
+      callExpr(
+          callee(functionDecl(hasName("::llvm::to_vector"))),
+          hasArgument(
+              0, callExpr(callee(functionDecl(hasName("::llvm::map_range"))))
+                     .bind("inner_call")))
+          .bind("map_range_call"),
+      this);
+
+  // Match `llvm::to_vector(llvm::make_filter_range(X, Pred))`.
+  Finder->addMatcher(
+      callExpr(
+          callee(functionDecl(hasName("::llvm::to_vector"))),
+          hasArgument(0, callExpr(callee(functionDecl(
+                                      hasName("::llvm::make_filter_range"))))
+                             .bind("inner_call")))
+          .bind("filter_range_call"),
+      this);
+}
+
+void UseVectorUtilsCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *MapRangeCall =
+      Result.Nodes.getNodeAs<CallExpr>("map_range_call");
+  const auto *FilterRangeCall =
+      Result.Nodes.getNodeAs<CallExpr>("filter_range_call");
+  if (!MapRangeCall && !FilterRangeCall)
+    return;
+
+  const auto *InnerCall = Result.Nodes.getNodeAs<CallExpr>("inner_call");
+  assert(InnerCall && "inner_call must be bound if map_range_call or "
+                      "filter_range_call matched");
+  // Only handle the 2-argument overloads of `map_range`/`make_filter_range`, 
to
+  // future-proof against additional overloads.
+  if (InnerCall->getNumArgs() != 2)
+    return;
+
+  const CallExpr *OuterCall = MapRangeCall ? MapRangeCall : FilterRangeCall;
+
+  const SourceManager &SM = *Result.SourceManager;
+  const LangOptions &LangOpts = getLangOpts();
+
+  // Determine the base replacement function name.
+  const StringRef ReplacementFuncBase =
+      MapRangeCall ? "llvm::map_to_vector" : "llvm::filter_to_vector";
+  const StringRef InnerFuncName =
+      MapRangeCall ? "llvm::map_range" : "llvm::make_filter_range";
+
+  // Check if `to_vector` was called with an explicit size template argument.
+  std::string SizeTemplateArg;
+  if (const auto *DRE =
+          dyn_cast<DeclRefExpr>(OuterCall->getCallee()->IgnoreImplicit())) {
+    if (DRE->hasExplicitTemplateArgs()) {
+      // Extract the template argument text (e.g., `<4>`).
+      const auto TemplateArgsCharRange = CharSourceRange::getTokenRange(
+          DRE->getLAngleLoc(), DRE->getRAngleLoc());
+      SizeTemplateArg =
+          Lexer::getSourceText(TemplateArgsCharRange, SM, LangOpts).str();
+    }
+  }
+
+  const std::string ReplacementFunc =
+      (ReplacementFuncBase + SizeTemplateArg).str();
+  const std::string ToVectorFunc = "llvm::to_vector" + SizeTemplateArg;
+
+  // Build the replacement: Replace the whole expression with the new function
+  // and the arguments from the inner call.
+  auto Diag = diag(OuterCall->getBeginLoc(),
+                   "use '%0' instead of '%1(%2(...))'")
+              << ReplacementFunc << ToVectorFunc << InnerFuncName;
+
+  // Get the range argument.
+  const SourceRange RangeArgRange = InnerCall->getArg(0)->getSourceRange();
+  const auto RangeArgCharRange = CharSourceRange::getTokenRange(RangeArgRange);
+  const StringRef RangeArgText =
+      Lexer::getSourceText(RangeArgCharRange, SM, LangOpts);
+
+  // Get the function/predicate argument.
+  const SourceRange FuncArgRange = InnerCall->getArg(1)->getSourceRange();
+  const auto FuncArgCharRange = CharSourceRange::getTokenRange(FuncArgRange);
+  const StringRef FuncArgText =
+      Lexer::getSourceText(FuncArgCharRange, SM, LangOpts);
+
+  // Create the replacement text.
+  const std::string Replacement =
+      (ReplacementFunc + "(" + RangeArgText + ", " + FuncArgText + ")").str();
+
+  Diag << FixItHint::CreateReplacement(OuterCall->getSourceRange(), 
Replacement);
+
+  // Add include for `SmallVectorExtras.h` if needed.
+  if (auto IncludeFixit = Inserter.createIncludeInsertion(
+          SM.getFileID(OuterCall->getBeginLoc()),
+          "llvm/ADT/SmallVectorExtras.h"))
+    Diag << *IncludeFixit;
+}
+
+} // namespace clang::tidy::llvm_check
diff --git a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.h 
b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.h
new file mode 100644
index 0000000000000..e2a2d2fe663a1
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.h
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_LLVM_USEVECTORUTILSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_USEVECTORUTILSCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include "../utils/IncludeInserter.h"
+
+namespace clang::tidy::llvm_check {
+
+/// Finds calls to `llvm::to_vector(llvm::map_range(...))` and
+/// `llvm::to_vector(llvm::make_filter_range(...))` that can be replaced with
+/// `llvm::map_to_vector` and `llvm::filter_to_vector` from 
`SmallVectorExtras.h`.
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/llvm/use-vector-utils.html
+class UseVectorUtilsCheck : public ClangTidyCheck {
+public:
+  UseVectorUtilsCheck(StringRef Name, ClangTidyContext *Context);
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus;
+  }
+  void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
+                           Preprocessor *ModuleExpanderPP) override;
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  utils::IncludeInserter Inserter;
+};
+
+} // namespace clang::tidy::llvm_check
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_USEVECTORUTILSCHECK_H
+
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 1e5d4ef5dbb3b..3b3a033f069ef 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -97,6 +97,13 @@ Improvements to clang-tidy
 New checks
 ^^^^^^^^^^
 
+- New :doc:`llvm-use-vector-utils
+  <clang-tidy/checks/llvm/use-vector-utils>` check.
+
+  Finds calls to ``llvm::to_vector(llvm::map_range(...))`` and
+  ``llvm::to_vector(llvm::make_filter_range(...))`` that can be replaced with
+  ``llvm::map_to_vector`` and ``llvm::filter_to_vector``.
+
 - New :doc:`modernize-use-string-view
   <clang-tidy/checks/modernize/use-string-view>` check.
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst 
b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index a34fade4b8027..25d1354fc4c20 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -258,6 +258,7 @@ Clang-Tidy Checks
    :doc:`llvm-twine-local <llvm/twine-local>`, "Yes"
    :doc:`llvm-use-new-mlir-op-builder <llvm/use-new-mlir-op-builder>`, "Yes"
    :doc:`llvm-use-ranges <llvm/use-ranges>`, "Yes"
+   :doc:`llvm-use-vector-utils <llvm/use-vector-utils>`, "Yes"
    :doc:`llvmlibc-callee-namespace <llvmlibc/callee-namespace>`,
    :doc:`llvmlibc-implementation-in-namespace 
<llvmlibc/implementation-in-namespace>`,
    :doc:`llvmlibc-inline-function-decl <llvmlibc/inline-function-decl>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm/use-vector-utils.rst 
b/clang-tools-extra/docs/clang-tidy/checks/llvm/use-vector-utils.rst
new file mode 100644
index 0000000000000..2c0d429be7fca
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/llvm/use-vector-utils.rst
@@ -0,0 +1,32 @@
+.. title:: clang-tidy - llvm-use-vector-utils
+
+llvm-use-vector-utils
+=====================
+
+Finds calls to ``llvm::to_vector`` with ``llvm::map_range`` or
+``llvm::make_filter_range`` that can be replaced with the more concise
+``llvm::map_to_vector`` and ``llvm::filter_to_vector`` utilities from
+``llvm/ADT/SmallVectorExtras.h``.
+
+The check will add the necessary ``#include "llvm/ADT/SmallVectorExtras.h"``
+directive when applying fixes.
+
+Example
+-------
+
+.. code-block:: c++
+
+  auto v1 = llvm::to_vector(llvm::map_range(container, func));
+  auto v2 = llvm::to_vector(llvm::make_filter_range(container, pred));
+  auto v3 = llvm::to_vector<4>(llvm::map_range(container, func));
+  auto v4 = llvm::to_vector<4>(llvm::make_filter_range(container, pred));
+
+Transforms to:
+
+.. code-block:: c++
+
+  auto v1 = llvm::map_to_vector(container, func);
+  auto v2 = llvm::filter_to_vector(container, pred);
+  auto v3 = llvm::map_to_vector<4>(container, func);
+  auto v4 = llvm::filter_to_vector<4>(container, pred);
+
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
new file mode 100644
index 0000000000000..b69f6824d13a4
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
@@ -0,0 +1,103 @@
+// RUN: %check_clang_tidy %s llvm-use-vector-utils %t
+
+// CHECK-FIXES: #include "llvm/ADT/SmallVectorExtras.h"
+
+namespace llvm {
+
+template <typename T> class SmallVector {};
+
+template <typename RangeT>
+SmallVector<int> to_vector(RangeT &&Range);
+
+template <unsigned Size, typename RangeT>
+SmallVector<int> to_vector(RangeT &&Range);
+
+template <typename Out, typename RangeT>
+SmallVector<Out> to_vector_of(RangeT &&Range);
+
+template <typename Out, unsigned Size, typename RangeT>
+SmallVector<Out> to_vector_of(RangeT &&Range);
+
+template <typename ContainerT, typename FuncT>
+struct mapped_range {};
+
+template <typename ContainerT, typename FuncT>
+mapped_range<ContainerT, FuncT> map_range(ContainerT &&C, FuncT &&F);
+
+// Hypothetical 3-arg overload (for future-proofing).
+template <typename ContainerT, typename FuncT, typename ExtraT>
+mapped_range<ContainerT, FuncT> map_range(ContainerT &&C, FuncT &&F, ExtraT 
&&E);
+
+template <typename ContainerT, typename PredT>
+struct filter_range {};
+
+template <typename ContainerT, typename PredT>
+filter_range<ContainerT, PredT> make_filter_range(ContainerT &&C, PredT &&P);
+
+// Hypothetical 3-arg overload (for future-proofing).
+template <typename ContainerT, typename PredT, typename ExtraT>
+filter_range<ContainerT, PredT> make_filter_range(ContainerT &&C, PredT &&P, 
ExtraT &&E);
+
+} // namespace llvm
+
+int transform(int x);
+bool is_even(int x);
+
+void test_map_range() {
+  llvm::SmallVector<int> vec;
+
+  auto result = llvm::to_vector(llvm::map_range(vec, transform));
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'llvm::map_to_vector' 
instead of 'llvm::to_vector(llvm::map_range(...))'
+  // CHECK-FIXES: auto result = llvm::map_to_vector(vec, transform);
+
+  auto result_sized = llvm::to_vector<4>(llvm::map_range(vec, transform));
+  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use 'llvm::map_to_vector<4>' 
instead of 'llvm::to_vector<4>(llvm::map_range(...))'
+  // CHECK-FIXES: auto result_sized = llvm::map_to_vector<4>(vec, transform);
+}
+
+void test_filter_range() {
+  llvm::SmallVector<int> vec;
+
+  auto result = llvm::to_vector(llvm::make_filter_range(vec, is_even));
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'llvm::filter_to_vector' 
instead of 'llvm::to_vector(llvm::make_filter_range(...))'
+  // CHECK-FIXES: auto result = llvm::filter_to_vector(vec, is_even);
+
+  auto result_sized = llvm::to_vector<6>(llvm::make_filter_range(vec, 
is_even));
+  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use 'llvm::filter_to_vector<6>' 
instead of 'llvm::to_vector<6>(llvm::make_filter_range(...))'
+  // CHECK-FIXES: auto result_sized = llvm::filter_to_vector<6>(vec, is_even);
+}
+
+namespace llvm {
+
+void test_inside_llvm_namespace() {
+  SmallVector<int> vec;
+
+  // Unprefixed calls inside the `llvm` namespace should also be detected.
+  auto result = to_vector(map_range(vec, transform));
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'llvm::map_to_vector' 
instead of 'llvm::to_vector(llvm::map_range(...))'
+  // CHECK-FIXES: auto result = llvm::map_to_vector(vec, transform);
+}
+
+} // namespace llvm
+
+void test_negative() {
+  llvm::SmallVector<int> vec;
+
+  // `to_vector` without inner `map_range`/`make_filter_range` should not 
trigger.
+  auto result1 = llvm::to_vector(vec);
+  auto result2 = llvm::to_vector<4>(vec);
+
+  // Direct use of `map_range`/`make_filter_range` without `to_vector` should 
not trigger.
+  auto mapped = llvm::map_range(vec, transform);
+  auto filtered = llvm::make_filter_range(vec, is_even);
+
+  // `to_vector_of` variants should not trigger (no `map_to_vector_of` exists).
+  auto result3 = llvm::to_vector_of<long>(llvm::map_range(vec, transform));
+  auto result4 = llvm::to_vector_of<long, 4>(llvm::map_range(vec, transform));
+  auto result5 = llvm::to_vector_of<long>(llvm::make_filter_range(vec, 
is_even));
+  auto result6 = llvm::to_vector_of<long, 4>(llvm::make_filter_range(vec, 
is_even));
+
+  // Hypothetical 3-arg overloads should not trigger.
+  auto result7 = llvm::to_vector(llvm::map_range(vec, transform, 0));
+  auto result8 = llvm::to_vector(llvm::make_filter_range(vec, is_even, 0));
+}

>From 28447e42ba1abf2c2f16b275f5d14bf55509fb2a Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <[email protected]>
Date: Fri, 23 Jan 2026 20:21:47 -0500
Subject: [PATCH 02/10] Format

---
 .../clang-tidy/llvm/UseVectorUtilsCheck.cpp   | 30 +++++++++----------
 .../clang-tidy/llvm/UseVectorUtilsCheck.h     |  4 +--
 2 files changed, 16 insertions(+), 18 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp 
b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
index ba377339c1cd5..2727f91e63fd4 100644
--- a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
@@ -31,28 +31,25 @@ void UseVectorUtilsCheck::registerPPCallbacks(const 
SourceManager &SM,
 void UseVectorUtilsCheck::registerMatchers(MatchFinder *Finder) {
   // Match `llvm::to_vector(llvm::map_range(X, F))`.
   Finder->addMatcher(
-      callExpr(
-          callee(functionDecl(hasName("::llvm::to_vector"))),
-          hasArgument(
-              0, callExpr(callee(functionDecl(hasName("::llvm::map_range"))))
-                     .bind("inner_call")))
+      callExpr(callee(functionDecl(hasName("::llvm::to_vector"))),
+               hasArgument(0, callExpr(callee(functionDecl(
+                                           hasName("::llvm::map_range"))))
+                                  .bind("inner_call")))
           .bind("map_range_call"),
       this);
 
   // Match `llvm::to_vector(llvm::make_filter_range(X, Pred))`.
   Finder->addMatcher(
-      callExpr(
-          callee(functionDecl(hasName("::llvm::to_vector"))),
-          hasArgument(0, callExpr(callee(functionDecl(
-                                      hasName("::llvm::make_filter_range"))))
-                             .bind("inner_call")))
+      callExpr(callee(functionDecl(hasName("::llvm::to_vector"))),
+               hasArgument(0, callExpr(callee(functionDecl(hasName(
+                                           "::llvm::make_filter_range"))))
+                                  .bind("inner_call")))
           .bind("filter_range_call"),
       this);
 }
 
 void UseVectorUtilsCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *MapRangeCall =
-      Result.Nodes.getNodeAs<CallExpr>("map_range_call");
+  const auto *MapRangeCall = 
Result.Nodes.getNodeAs<CallExpr>("map_range_call");
   const auto *FilterRangeCall =
       Result.Nodes.getNodeAs<CallExpr>("filter_range_call");
   if (!MapRangeCall && !FilterRangeCall)
@@ -96,9 +93,9 @@ void UseVectorUtilsCheck::check(const 
MatchFinder::MatchResult &Result) {
 
   // Build the replacement: Replace the whole expression with the new function
   // and the arguments from the inner call.
-  auto Diag = diag(OuterCall->getBeginLoc(),
-                   "use '%0' instead of '%1(%2(...))'")
-              << ReplacementFunc << ToVectorFunc << InnerFuncName;
+  auto Diag =
+      diag(OuterCall->getBeginLoc(), "use '%0' instead of '%1(%2(...))'")
+      << ReplacementFunc << ToVectorFunc << InnerFuncName;
 
   // Get the range argument.
   const SourceRange RangeArgRange = InnerCall->getArg(0)->getSourceRange();
@@ -116,7 +113,8 @@ void UseVectorUtilsCheck::check(const 
MatchFinder::MatchResult &Result) {
   const std::string Replacement =
       (ReplacementFunc + "(" + RangeArgText + ", " + FuncArgText + ")").str();
 
-  Diag << FixItHint::CreateReplacement(OuterCall->getSourceRange(), 
Replacement);
+  Diag << FixItHint::CreateReplacement(OuterCall->getSourceRange(),
+                                       Replacement);
 
   // Add include for `SmallVectorExtras.h` if needed.
   if (auto IncludeFixit = Inserter.createIncludeInsertion(
diff --git a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.h 
b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.h
index e2a2d2fe663a1..557025856a09a 100644
--- a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.h
+++ b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.h
@@ -16,7 +16,8 @@ namespace clang::tidy::llvm_check {
 
 /// Finds calls to `llvm::to_vector(llvm::map_range(...))` and
 /// `llvm::to_vector(llvm::make_filter_range(...))` that can be replaced with
-/// `llvm::map_to_vector` and `llvm::filter_to_vector` from 
`SmallVectorExtras.h`.
+/// `llvm::map_to_vector` and `llvm::filter_to_vector` from
+/// `SmallVectorExtras.h`.
 ///
 /// For the user-facing documentation see:
 /// https://clang.llvm.org/extra/clang-tidy/checks/llvm/use-vector-utils.html
@@ -38,4 +39,3 @@ class UseVectorUtilsCheck : public ClangTidyCheck {
 } // namespace clang::tidy::llvm_check
 
 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_USEVECTORUTILSCHECK_H
-

>From dbd41413b38c3cf7cd0cb8f36de680122dad7382 Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <[email protected]>
Date: Fri, 23 Jan 2026 20:37:55 -0500
Subject: [PATCH 03/10] Format

---
 .../docs/clang-tidy/checks/llvm/use-vector-utils.rst             | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvm/use-vector-utils.rst 
b/clang-tools-extra/docs/clang-tidy/checks/llvm/use-vector-utils.rst
index 2c0d429be7fca..5fddc68f4a614 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/llvm/use-vector-utils.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/llvm/use-vector-utils.rst
@@ -29,4 +29,3 @@ Transforms to:
   auto v2 = llvm::filter_to_vector(container, pred);
   auto v3 = llvm::map_to_vector<4>(container, func);
   auto v4 = llvm::filter_to_vector<4>(container, pred);
-

>From 616337da3b0f61d9049fad2ef41b2b28ed58b433 Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <[email protected]>
Date: Sat, 24 Jan 2026 09:26:38 -0500
Subject: [PATCH 04/10] Address comments

---
 .../clang-tidy/llvm/UseVectorUtilsCheck.cpp   | 130 +++++++-----------
 .../checkers/llvm/use-vector-utils.cpp        |  16 ++-
 2 files changed, 63 insertions(+), 83 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp 
b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
index 2727f91e63fd4..78543d9b58144 100644
--- a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
@@ -18,9 +18,7 @@ namespace clang::tidy::llvm_check {
 UseVectorUtilsCheck::UseVectorUtilsCheck(StringRef Name,
                                          ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
-      Inserter(Options.getLocalOrGlobal("IncludeStyle",
-                                        utils::IncludeSorter::IS_LLVM),
-               areDiagsSelfContained()) {}
+      Inserter(utils::IncludeSorter::IS_LLVM, areDiagsSelfContained()) {}
 
 void UseVectorUtilsCheck::registerPPCallbacks(const SourceManager &SM,
                                               Preprocessor *PP,
@@ -29,94 +27,72 @@ void UseVectorUtilsCheck::registerPPCallbacks(const 
SourceManager &SM,
 }
 
 void UseVectorUtilsCheck::registerMatchers(MatchFinder *Finder) {
-  // Match `llvm::to_vector(llvm::map_range(X, F))`.
+  // Match `llvm::to_vector(llvm::map_range(X, F))` or
+  // `llvm::to_vector(llvm::make_filter_range(X, Pred))`.
   Finder->addMatcher(
       callExpr(callee(functionDecl(hasName("::llvm::to_vector"))),
-               hasArgument(0, callExpr(callee(functionDecl(
-                                           hasName("::llvm::map_range"))))
-                                  .bind("inner_call")))
-          .bind("map_range_call"),
+               hasArgument(0, callExpr(callee(functionDecl(hasAnyName(
+                                           "::llvm::map_range",
+                                           "::llvm::make_filter_range"))),
+                                       argumentCountIs(2))
+                                  .bind("inner_call")),
+               argumentCountIs(1))
+          .bind("outer_call"),
       this);
+}
 
-  // Match `llvm::to_vector(llvm::make_filter_range(X, Pred))`.
-  Finder->addMatcher(
-      callExpr(callee(functionDecl(hasName("::llvm::to_vector"))),
-               hasArgument(0, callExpr(callee(functionDecl(hasName(
-                                           "::llvm::make_filter_range"))))
-                                  .bind("inner_call")))
-          .bind("filter_range_call"),
-      this);
+// Returns the original qualifier spelling (e.g., `llvm::` or `::llvm::`) for
+// the diagnostic message.
+static StringRef getQualifierSpelling(const DeclRefExpr *DeclRef,
+                                      const MatchFinder::MatchResult &Result) {
+  if (const auto QualifierLoc = DeclRef->getQualifierLoc()) {
+    return Lexer::getSourceText(
+        CharSourceRange::getTokenRange(QualifierLoc.getSourceRange()),
+        *Result.SourceManager, Result.Context->getLangOpts());
+  }
+  return "";
 }
 
 void UseVectorUtilsCheck::check(const MatchFinder::MatchResult &Result) {
-  const auto *MapRangeCall = 
Result.Nodes.getNodeAs<CallExpr>("map_range_call");
-  const auto *FilterRangeCall =
-      Result.Nodes.getNodeAs<CallExpr>("filter_range_call");
-  if (!MapRangeCall && !FilterRangeCall)
-    return;
+  const auto *OuterCall = Result.Nodes.getNodeAs<CallExpr>("outer_call");
+  assert(OuterCall);
 
   const auto *InnerCall = Result.Nodes.getNodeAs<CallExpr>("inner_call");
-  assert(InnerCall && "inner_call must be bound if map_range_call or "
-                      "filter_range_call matched");
-  // Only handle the 2-argument overloads of `map_range`/`make_filter_range`, 
to
-  // future-proof against additional overloads.
-  if (InnerCall->getNumArgs() != 2)
-    return;
-
-  const CallExpr *OuterCall = MapRangeCall ? MapRangeCall : FilterRangeCall;
+  assert(InnerCall);
 
-  const SourceManager &SM = *Result.SourceManager;
-  const LangOptions &LangOpts = getLangOpts();
+  const auto *OuterCallee =
+      cast<DeclRefExpr>(OuterCall->getCallee()->IgnoreImplicit());
+  const auto *InnerCallee =
+      cast<DeclRefExpr>(InnerCall->getCallee()->IgnoreImplicit());
 
-  // Determine the base replacement function name.
-  const StringRef ReplacementFuncBase =
-      MapRangeCall ? "llvm::map_to_vector" : "llvm::filter_to_vector";
   const StringRef InnerFuncName =
-      MapRangeCall ? "llvm::map_range" : "llvm::make_filter_range";
-
-  // Check if `to_vector` was called with an explicit size template argument.
-  std::string SizeTemplateArg;
-  if (const auto *DRE =
-          dyn_cast<DeclRefExpr>(OuterCall->getCallee()->IgnoreImplicit())) {
-    if (DRE->hasExplicitTemplateArgs()) {
-      // Extract the template argument text (e.g., `<4>`).
-      const auto TemplateArgsCharRange = CharSourceRange::getTokenRange(
-          DRE->getLAngleLoc(), DRE->getRAngleLoc());
-      SizeTemplateArg =
-          Lexer::getSourceText(TemplateArgsCharRange, SM, LangOpts).str();
-    }
-  }
-
-  const std::string ReplacementFunc =
-      (ReplacementFuncBase + SizeTemplateArg).str();
-  const std::string ToVectorFunc = "llvm::to_vector" + SizeTemplateArg;
-
-  // Build the replacement: Replace the whole expression with the new function
-  // and the arguments from the inner call.
-  auto Diag =
-      diag(OuterCall->getBeginLoc(), "use '%0' instead of '%1(%2(...))'")
-      << ReplacementFunc << ToVectorFunc << InnerFuncName;
-
-  // Get the range argument.
-  const SourceRange RangeArgRange = InnerCall->getArg(0)->getSourceRange();
-  const auto RangeArgCharRange = CharSourceRange::getTokenRange(RangeArgRange);
-  const StringRef RangeArgText =
-      Lexer::getSourceText(RangeArgCharRange, SM, LangOpts);
-
-  // Get the function/predicate argument.
-  const SourceRange FuncArgRange = InnerCall->getArg(1)->getSourceRange();
-  const auto FuncArgCharRange = CharSourceRange::getTokenRange(FuncArgRange);
-  const StringRef FuncArgText =
-      Lexer::getSourceText(FuncArgCharRange, SM, LangOpts);
-
-  // Create the replacement text.
-  const std::string Replacement =
-      (ReplacementFunc + "(" + RangeArgText + ", " + FuncArgText + ")").str();
-
-  Diag << FixItHint::CreateReplacement(OuterCall->getSourceRange(),
-                                       Replacement);
+      cast<NamedDecl>(InnerCallee->getDecl())->getName();
+
+  // Determine the replacement function name (unqualified).
+  const llvm::SmallDenseMap<StringRef, StringRef, 2>
+      InnerFuncNameToReplacementFuncName = {
+          {"map_range", "map_to_vector"},
+          {"make_filter_range", "filter_to_vector"},
+      };
+  const StringRef ReplacementFuncName =
+      InnerFuncNameToReplacementFuncName.lookup(InnerFuncName);
+  assert(!ReplacementFuncName.empty() && "Unhandled function?");
+
+  auto Diag = diag(OuterCall->getBeginLoc(), "use '%0%1'")
+              << getQualifierSpelling(OuterCallee, Result)
+              << ReplacementFuncName;
+
+  // Replace only the unqualified function name, preserving qualifier and
+  // template arguments.
+  const auto InnerCallUntilFirstArg = CharSourceRange::getCharRange(
+      InnerCall->getBeginLoc(), InnerCall->getArg(0)->getBeginLoc());
+  Diag << FixItHint::CreateReplacement(
+              OuterCallee->getNameInfo().getSourceRange(), ReplacementFuncName)
+       << FixItHint::CreateRemoval(InnerCallUntilFirstArg)
+       << FixItHint::CreateRemoval(InnerCall->getRParenLoc());
 
   // Add include for `SmallVectorExtras.h` if needed.
+  const SourceManager &SM = *Result.SourceManager;
   if (auto IncludeFixit = Inserter.createIncludeInsertion(
           SM.getFileID(OuterCall->getBeginLoc()),
           "llvm/ADT/SmallVectorExtras.h"))
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
index b69f6824d13a4..b0f71614f7bec 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
@@ -47,23 +47,27 @@ void test_map_range() {
   llvm::SmallVector<int> vec;
 
   auto result = llvm::to_vector(llvm::map_range(vec, transform));
-  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'llvm::map_to_vector' 
instead of 'llvm::to_vector(llvm::map_range(...))'
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'llvm::map_to_vector'
   // CHECK-FIXES: auto result = llvm::map_to_vector(vec, transform);
 
   auto result_sized = llvm::to_vector<4>(llvm::map_range(vec, transform));
-  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use 'llvm::map_to_vector<4>' 
instead of 'llvm::to_vector<4>(llvm::map_range(...))'
+  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use 'llvm::map_to_vector'
   // CHECK-FIXES: auto result_sized = llvm::map_to_vector<4>(vec, transform);
+
+  auto result_global = ::llvm::to_vector(::llvm::map_range(vec, transform));
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use '::llvm::map_to_vector'
+  // CHECK-FIXES: auto result_global = ::llvm::map_to_vector(vec, transform);
 }
 
 void test_filter_range() {
   llvm::SmallVector<int> vec;
 
   auto result = llvm::to_vector(llvm::make_filter_range(vec, is_even));
-  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'llvm::filter_to_vector' 
instead of 'llvm::to_vector(llvm::make_filter_range(...))'
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'llvm::filter_to_vector'
   // CHECK-FIXES: auto result = llvm::filter_to_vector(vec, is_even);
 
   auto result_sized = llvm::to_vector<6>(llvm::make_filter_range(vec, 
is_even));
-  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use 'llvm::filter_to_vector<6>' 
instead of 'llvm::to_vector<6>(llvm::make_filter_range(...))'
+  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use 'llvm::filter_to_vector'
   // CHECK-FIXES: auto result_sized = llvm::filter_to_vector<6>(vec, is_even);
 }
 
@@ -74,8 +78,8 @@ void test_inside_llvm_namespace() {
 
   // Unprefixed calls inside the `llvm` namespace should also be detected.
   auto result = to_vector(map_range(vec, transform));
-  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'llvm::map_to_vector' 
instead of 'llvm::to_vector(llvm::map_range(...))'
-  // CHECK-FIXES: auto result = llvm::map_to_vector(vec, transform);
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'map_to_vector'
+  // CHECK-FIXES: auto result = map_to_vector(vec, transform);
 }
 
 } // namespace llvm

>From 0363df9b347f8d0866d2661519c2663aeacb05ee Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <[email protected]>
Date: Sat, 24 Jan 2026 09:37:00 -0500
Subject: [PATCH 05/10] Simplify diagnostic

---
 .../clang-tidy/llvm/UseVectorUtilsCheck.cpp   | 31 +++++--------------
 .../checkers/llvm/use-vector-utils.cpp        | 10 +++---
 2 files changed, 12 insertions(+), 29 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp 
b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
index 78543d9b58144..a6de8630172c8 100644
--- a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
@@ -9,7 +9,6 @@
 #include "UseVectorUtilsCheck.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/Lex/Lexer.h"
 
 using namespace clang::ast_matchers;
 
@@ -41,18 +40,6 @@ void UseVectorUtilsCheck::registerMatchers(MatchFinder 
*Finder) {
       this);
 }
 
-// Returns the original qualifier spelling (e.g., `llvm::` or `::llvm::`) for
-// the diagnostic message.
-static StringRef getQualifierSpelling(const DeclRefExpr *DeclRef,
-                                      const MatchFinder::MatchResult &Result) {
-  if (const auto QualifierLoc = DeclRef->getQualifierLoc()) {
-    return Lexer::getSourceText(
-        CharSourceRange::getTokenRange(QualifierLoc.getSourceRange()),
-        *Result.SourceManager, Result.Context->getLangOpts());
-  }
-  return "";
-}
-
 void UseVectorUtilsCheck::check(const MatchFinder::MatchResult &Result) {
   const auto *OuterCall = Result.Nodes.getNodeAs<CallExpr>("outer_call");
   assert(OuterCall);
@@ -62,11 +49,9 @@ void UseVectorUtilsCheck::check(const 
MatchFinder::MatchResult &Result) {
 
   const auto *OuterCallee =
       cast<DeclRefExpr>(OuterCall->getCallee()->IgnoreImplicit());
-  const auto *InnerCallee =
-      cast<DeclRefExpr>(InnerCall->getCallee()->IgnoreImplicit());
 
   const StringRef InnerFuncName =
-      cast<NamedDecl>(InnerCallee->getDecl())->getName();
+      cast<NamedDecl>(InnerCall->getCalleeDecl())->getName();
 
   // Determine the replacement function name (unqualified).
   const llvm::SmallDenseMap<StringRef, StringRef, 2>
@@ -78,17 +63,15 @@ void UseVectorUtilsCheck::check(const 
MatchFinder::MatchResult &Result) {
       InnerFuncNameToReplacementFuncName.lookup(InnerFuncName);
   assert(!ReplacementFuncName.empty() && "Unhandled function?");
 
-  auto Diag = diag(OuterCall->getBeginLoc(), "use '%0%1'")
-              << getQualifierSpelling(OuterCallee, Result)
-              << ReplacementFuncName;
+  auto Diag = diag(OuterCall->getBeginLoc(), "use '%0'") << 
ReplacementFuncName;
 
-  // Replace only the unqualified function name, preserving qualifier and
-  // template arguments.
-  const auto InnerCallUntilFirstArg = CharSourceRange::getCharRange(
-      InnerCall->getBeginLoc(), InnerCall->getArg(0)->getBeginLoc());
+  // Replace the outer function name (preserving qualifier and template args),
+  // and then remove the inner call's callee and opening paren and closing
+  // paren.
   Diag << FixItHint::CreateReplacement(
               OuterCallee->getNameInfo().getSourceRange(), ReplacementFuncName)
-       << FixItHint::CreateRemoval(InnerCallUntilFirstArg)
+       << FixItHint::CreateRemoval(CharSourceRange::getCharRange(
+              InnerCall->getBeginLoc(), InnerCall->getArg(0)->getBeginLoc()))
        << FixItHint::CreateRemoval(InnerCall->getRParenLoc());
 
   // Add include for `SmallVectorExtras.h` if needed.
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
index b0f71614f7bec..817db689378ee 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
@@ -47,15 +47,15 @@ void test_map_range() {
   llvm::SmallVector<int> vec;
 
   auto result = llvm::to_vector(llvm::map_range(vec, transform));
-  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'llvm::map_to_vector'
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'map_to_vector'
   // CHECK-FIXES: auto result = llvm::map_to_vector(vec, transform);
 
   auto result_sized = llvm::to_vector<4>(llvm::map_range(vec, transform));
-  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use 'llvm::map_to_vector'
+  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use 'map_to_vector'
   // CHECK-FIXES: auto result_sized = llvm::map_to_vector<4>(vec, transform);
 
   auto result_global = ::llvm::to_vector(::llvm::map_range(vec, transform));
-  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use '::llvm::map_to_vector'
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use 'map_to_vector'
   // CHECK-FIXES: auto result_global = ::llvm::map_to_vector(vec, transform);
 }
 
@@ -63,11 +63,11 @@ void test_filter_range() {
   llvm::SmallVector<int> vec;
 
   auto result = llvm::to_vector(llvm::make_filter_range(vec, is_even));
-  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'llvm::filter_to_vector'
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'filter_to_vector'
   // CHECK-FIXES: auto result = llvm::filter_to_vector(vec, is_even);
 
   auto result_sized = llvm::to_vector<6>(llvm::make_filter_range(vec, 
is_even));
-  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use 'llvm::filter_to_vector'
+  // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use 'filter_to_vector'
   // CHECK-FIXES: auto result_sized = llvm::filter_to_vector<6>(vec, is_even);
 }
 

>From a3b31bd76107a8ff773d14157db9f59b68389559 Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <[email protected]>
Date: Sat, 24 Jan 2026 09:48:15 -0500
Subject: [PATCH 06/10] Add example

---
 clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp 
b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
index a6de8630172c8..a5519429f9f73 100644
--- a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
@@ -67,7 +67,12 @@ void UseVectorUtilsCheck::check(const 
MatchFinder::MatchResult &Result) {
 
   // Replace the outer function name (preserving qualifier and template args),
   // and then remove the inner call's callee and opening paren and closing
-  // paren.
+  // paren. Example:
+  // ```
+  // llvm::to_vector<4>(llvm::map_range(X, F))
+  //       ^replace~^   ^----remove-----^   ^
+  //                                      remove
+  // ```
   Diag << FixItHint::CreateReplacement(
               OuterCallee->getNameInfo().getSourceRange(), ReplacementFuncName)
        << FixItHint::CreateRemoval(CharSourceRange::getCharRange(

>From 8980bd26874dd51d1f69dc96f7fc29028a780aee Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <[email protected]>
Date: Sat, 24 Jan 2026 10:41:46 -0500
Subject: [PATCH 07/10] Preserve comments

---
 .../clang-tidy/llvm/UseVectorUtilsCheck.cpp       |  7 +++++--
 .../clang-tidy/checkers/llvm/use-vector-utils.cpp | 15 +++++++++++++++
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp 
b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
index a5519429f9f73..e4e1717816b23 100644
--- a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
@@ -9,6 +9,7 @@
 #include "UseVectorUtilsCheck.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
 
 using namespace clang::ast_matchers;
 
@@ -73,14 +74,16 @@ void UseVectorUtilsCheck::check(const 
MatchFinder::MatchResult &Result) {
   //       ^replace~^   ^----remove-----^   ^
   //                                      remove
   // ```
+  const SourceManager &SM = *Result.SourceManager;
+  const SourceLocation InnerLParenEnd = Lexer::getLocForEndOfToken(
+      InnerCall->getCallee()->getEndLoc(), 0, SM, getLangOpts());
   Diag << FixItHint::CreateReplacement(
               OuterCallee->getNameInfo().getSourceRange(), ReplacementFuncName)
        << FixItHint::CreateRemoval(CharSourceRange::getCharRange(
-              InnerCall->getBeginLoc(), InnerCall->getArg(0)->getBeginLoc()))
+              InnerCall->getBeginLoc(), InnerLParenEnd.getLocWithOffset(1)))
        << FixItHint::CreateRemoval(InnerCall->getRParenLoc());
 
   // Add include for `SmallVectorExtras.h` if needed.
-  const SourceManager &SM = *Result.SourceManager;
   if (auto IncludeFixit = Inserter.createIncludeInsertion(
           SM.getFileID(OuterCall->getBeginLoc()),
           "llvm/ADT/SmallVectorExtras.h"))
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
index 817db689378ee..788b5e835c80e 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
@@ -57,6 +57,21 @@ void test_map_range() {
   auto result_global = ::llvm::to_vector(::llvm::map_range(vec, transform));
   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use 'map_to_vector'
   // CHECK-FIXES: auto result_global = ::llvm::map_to_vector(vec, transform);
+
+  // Check that comments between `to_vector(` and `map_range(` are preserved.
+  auto result_comment1 = llvm::to_vector(/*keep_me*/ llvm::map_range(vec, 
transform));
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: use 'map_to_vector'
+  // CHECK-FIXES: auto result_comment1 = llvm::map_to_vector(/*keep_me*/ vec, 
transform);
+
+  // Check that comments between `to_vector<9>(` and `map_range(` are 
preserved.
+  auto result_comment2 = llvm::to_vector<9>(/*keep_me*/ llvm::map_range(vec, 
transform));
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: use 'map_to_vector'
+  // CHECK-FIXES: auto result_comment2 = llvm::map_to_vector<9>(/*keep_me*/ 
vec, transform);
+
+  // Check that comments inside `map_range(` are also preserved.
+  auto result_comment3 = llvm::to_vector(llvm::map_range(/*keep_me*/ vec, 
transform));
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: use 'map_to_vector'
+  // CHECK-FIXES: auto result_comment3 = llvm::map_to_vector(/*keep_me*/ vec, 
transform);
 }
 
 void test_filter_range() {

>From f8d98e840c26e51ec66c3435ced47d3c437b9bc4 Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <[email protected]>
Date: Sat, 24 Jan 2026 10:44:29 -0500
Subject: [PATCH 08/10] Nit

---
 clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.h | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.h 
b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.h
index 557025856a09a..64de81110f6c2 100644
--- a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.h
+++ b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.h
@@ -24,14 +24,15 @@ namespace clang::tidy::llvm_check {
 class UseVectorUtilsCheck : public ClangTidyCheck {
 public:
   UseVectorUtilsCheck(StringRef Name, ClangTidyContext *Context);
-  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
-    return LangOpts.CPlusPlus;
-  }
   void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
                            Preprocessor *ModuleExpanderPP) override;
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
 
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus;
+  }
+
 private:
   utils::IncludeInserter Inserter;
 };

>From 92954462eb343d8d98c0559d92212d2e5ecf35c1 Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <[email protected]>
Date: Sat, 24 Jan 2026 10:47:14 -0500
Subject: [PATCH 09/10] Add test for comments in explicit template arguments

---
 .../test/clang-tidy/checkers/llvm/use-vector-utils.cpp       | 5 +++++
 1 file changed, 5 insertions(+)

diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
index 788b5e835c80e..cfe1fd10e11ec 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
@@ -72,6 +72,11 @@ void test_map_range() {
   auto result_comment3 = llvm::to_vector(llvm::map_range(/*keep_me*/ vec, 
transform));
   // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: use 'map_to_vector'
   // CHECK-FIXES: auto result_comment3 = llvm::map_to_vector(/*keep_me*/ vec, 
transform);
+
+  // Check that comments inside explicit template argument are preserved.
+  auto result_comment4 = llvm::to_vector</*keep_me*/ 7>(llvm::map_range(vec, 
transform));
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: use 'map_to_vector'
+  // CHECK-FIXES: auto result_comment4 = llvm::map_to_vector</*keep_me*/ 
7>(vec, transform);
 }
 
 void test_filter_range() {

>From 29a88f070336b9fe305d548c46c009ea08f500a8 Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <[email protected]>
Date: Sat, 24 Jan 2026 11:09:33 -0500
Subject: [PATCH 10/10] Fix L paren identification logic

---
 .../clang-tidy/llvm/UseVectorUtilsCheck.cpp   | 12 ++++++----
 .../checkers/llvm/use-vector-utils.cpp        | 22 +++++++++++++++++++
 2 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp 
b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
index e4e1717816b23..bd915eb55b448 100644
--- a/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/UseVectorUtilsCheck.cpp
@@ -7,9 +7,9 @@
 
//===----------------------------------------------------------------------===//
 
 #include "UseVectorUtilsCheck.h"
+#include "../utils/LexerUtils.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/Lex/Lexer.h"
 
 using namespace clang::ast_matchers;
 
@@ -75,12 +75,16 @@ void UseVectorUtilsCheck::check(const 
MatchFinder::MatchResult &Result) {
   //                                      remove
   // ```
   const SourceManager &SM = *Result.SourceManager;
-  const SourceLocation InnerLParenEnd = Lexer::getLocForEndOfToken(
-      InnerCall->getCallee()->getEndLoc(), 0, SM, getLangOpts());
+  const std::optional<Token> InnerLParen =
+      utils::lexer::findNextTokenSkippingComments(
+          InnerCall->getCallee()->getEndLoc(), SM, getLangOpts());
+  if (!InnerLParen || InnerLParen->isNot(tok::l_paren))
+    return; // Unexpected token, possibly a macro?
+
   Diag << FixItHint::CreateReplacement(
               OuterCallee->getNameInfo().getSourceRange(), ReplacementFuncName)
        << FixItHint::CreateRemoval(CharSourceRange::getCharRange(
-              InnerCall->getBeginLoc(), InnerLParenEnd.getLocWithOffset(1)))
+              InnerCall->getBeginLoc(), InnerLParen->getEndLoc()))
        << FixItHint::CreateRemoval(InnerCall->getRParenLoc());
 
   // Add include for `SmallVectorExtras.h` if needed.
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
index cfe1fd10e11ec..25847bd8d0cd4 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/llvm/use-vector-utils.cpp
@@ -77,6 +77,16 @@ void test_map_range() {
   auto result_comment4 = llvm::to_vector</*keep_me*/ 7>(llvm::map_range(vec, 
transform));
   // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: use 'map_to_vector'
   // CHECK-FIXES: auto result_comment4 = llvm::map_to_vector</*keep_me*/ 
7>(vec, transform);
+
+  // Check that whitespace between callee and `(` is handled correctly.
+  auto result_whitespace1 = llvm::to_vector(llvm::map_range  (vec, transform));
+  // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use 'map_to_vector'
+  // CHECK-FIXES: auto result_whitespace1 = llvm::map_to_vector(vec, 
transform);
+
+  // Check that comments between callee and `(` are handled correctly.
+  auto result_whitespace2 = llvm::to_vector(llvm::map_range /*weird but ok*/ 
(vec, transform));
+  // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: use 'map_to_vector'
+  // CHECK-FIXES: auto result_whitespace2 = llvm::map_to_vector(vec, 
transform);
 }
 
 void test_filter_range() {
@@ -104,6 +114,18 @@ void test_inside_llvm_namespace() {
 
 } // namespace llvm
 
+// Check that an empty macro between callee and `(` is handled.
+void test_macro() {
+  llvm::SmallVector<int> vec;
+
+#define EMPTY
+  // No fix-it when a macro appears between callee and `(`.
+  auto result = llvm::to_vector(llvm::map_range EMPTY (vec, transform));
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'map_to_vector'
+
+#undef EMPTY
+}
+
 void test_negative() {
   llvm::SmallVector<int> vec;
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to