Author: algol83
Date: 2026-10-07T08:15:52Z
New Revision: f2e7e3f1b81c57bdeddbe890f088b2e829b0956e

URL: 
https://github.com/llvm/llvm-project/commit/f2e7e3f1b81c57bdeddbe890f088b2e829b0956e
DIFF: 
https://github.com/llvm/llvm-project/commit/f2e7e3f1b81c57bdeddbe890f088b2e829b0956e.diff

LOG: [clang-tidy] Make range source classes configurable (#226193)

The check currently hardcodes the container types accepted as sources in
range-based for loops. This prevents it from recognizing
project-specific range-like containers even when they expose the
operations needed by the check.

Add a `ForRangeLoopClasses` option, analogous to `VectorLikeClasses`,
for configuring those source container classes. The existing
standard-library types remain the defaults, so the current behavior is
preserved.

The test covers a custom range-like source and verifies the generated
`reserve(range.size())` fix.

Tests:
- `ninja check-clang-extra-clang-tidy-checkers-performance` (48/48
passed)

**AI assistance:** I used OpenAI Codex to help implement, test, and
document this change. I reviewed the resulting code and text, understand
the changes, and take full responsibility for the contribution.

---------

Co-authored-by: EugeneZelenko <[email protected]>
Co-authored-by: Baranov Victor <[email protected]>

Added: 
    

Modified: 
    clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp
    clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.h
    clang-tools-extra/docs/ReleaseNotes.md
    
clang-tools-extra/docs/clang-tidy/checks/performance/inefficient-vector-operation.rst
    
clang-tools-extra/test/clang-tidy/checkers/performance/inefficient-vector-operation-vectorlike-classes.cpp

Removed: 
    


################################################################################
diff  --git 
a/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp 
b/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp
index 93cd3a2229a25a..744fa8486d21ff 100644
--- 
a/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp
+++ 
b/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.cpp
@@ -58,10 +58,9 @@ static constexpr char LoopInitVarName[] = "loop_init_var";
 static constexpr char LoopEndExprName[] = "loop_end_expr";
 static constexpr char RangeLoopName[] = "for_range_loop";
 
-static ast_matchers::internal::Matcher<Expr> supportedContainerTypesMatcher() {
-  return hasType(cxxRecordDecl(hasAnyName(
-      "::std::vector", "::std::set", "::std::unordered_set", "::std::map",
-      "::std::unordered_map", "::std::array", "::std::deque")));
+static ast_matchers::internal::Matcher<Expr>
+supportedContainerTypesMatcher(ArrayRef<StringRef> ContainerTypes) {
+  return hasType(cxxRecordDecl(hasAnyName(ContainerTypes)));
 }
 
 namespace {
@@ -77,12 +76,18 @@ 
InefficientVectorOperationCheck::InefficientVectorOperationCheck(
     : ClangTidyCheck(Name, Context),
       VectorLikeClasses(utils::options::parseStringList(
           Options.get("VectorLikeClasses", "::std::vector"))),
+      ForRangeLoopClasses(utils::options::parseStringList(Options.get(
+          "ForRangeLoopClasses",
+          "::std::array;::std::deque;::std::map;::std::set;"
+          "::std::unordered_map;::std::unordered_set;::std::vector"))),
       EnableProto(Options.get("EnableProto", false)) {}
 
 void InefficientVectorOperationCheck::storeOptions(
     ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "VectorLikeClasses",
                 utils::options::serializeStringList(VectorLikeClasses));
+  Options.store(Opts, "ForRangeLoopClasses",
+                utils::options::serializeStringList(ForRangeLoopClasses));
   Options.store(Opts, "EnableProto", EnableProto);
 }
 
@@ -146,10 +151,10 @@ void InefficientVectorOperationCheck::addMatcher(
   // FIXME: Support more complex range-expressions.
   Finder->addMatcher(
       cxxForRangeStmt(
-          hasRangeInit(
-              anyOf(declRefExpr(supportedContainerTypesMatcher()),
-                    memberExpr(hasObjectExpression(unless(hasSideEffects())),
-                               supportedContainerTypesMatcher()))),
+          hasRangeInit(anyOf(
+              declRefExpr(supportedContainerTypesMatcher(ForRangeLoopClasses)),
+              memberExpr(hasObjectExpression(unless(hasSideEffects())),
+                         
supportedContainerTypesMatcher(ForRangeLoopClasses)))),
           HasInterestingLoopBody, InInterestingCompoundStmt)
           .bind(RangeLoopName),
       this);

diff  --git 
a/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.h 
b/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.h
index 5f3b88f51d6260..d976f6b28e3637 100644
--- a/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.h
+++ b/clang-tools-extra/clang-tidy/performance/InefficientVectorOperationCheck.h
@@ -37,6 +37,7 @@ class InefficientVectorOperationCheck : public ClangTidyCheck 
{
                   const ast_matchers::DeclarationMatcher &AppendMethodDecl,
                   StringRef AppendCallName, ast_matchers::MatchFinder *Finder);
   const std::vector<StringRef> VectorLikeClasses;
+  const std::vector<StringRef> ForRangeLoopClasses;
 
   // If true, also check inefficient operations for proto repeated fields.
   bool EnableProto;

diff  --git a/clang-tools-extra/docs/ReleaseNotes.md 
b/clang-tools-extra/docs/ReleaseNotes.md
index 42451c45905928..20b612509d7f72 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -268,6 +268,11 @@ infrastructure are described first, followed by 
tool-specific sections.
   offered when an argument covers only part of a macro expansion, as it then
   has no source text of its own.
 
+- Improved {doc}`performance-inefficient-vector-operation
+  <clang-tidy/checks/performance/inefficient-vector-operation>` by adding the
+  {option}`ForRangeLoopClasses` to configure container classes that can be used
+  as sources in range-based `for` loops.
+
 - Improved {doc}`readability-convert-member-functions-to-static
   <clang-tidy/checks/readability/convert-member-functions-to-static>` check by
   fixing a crash when checking a const-qualified method declared with the

diff  --git 
a/clang-tools-extra/docs/clang-tidy/checks/performance/inefficient-vector-operation.rst
 
b/clang-tools-extra/docs/clang-tidy/checks/performance/inefficient-vector-operation.rst
index 75016eb72d279f..99a250c01a9f28 100644
--- 
a/clang-tools-extra/docs/clang-tidy/checks/performance/inefficient-vector-operation.rst
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/performance/inefficient-vector-operation.rst
@@ -34,9 +34,9 @@ statement body:
   }
 
 * For-range loops like ``for (range-declaration : range_expression)``, the type
-  of ``range_expression`` can be ``std::vector``, ``std::array``,
-  ``std::deque``, ``std::set``, ``std::unordered_set``, ``std::map``,
-  ``std::unordered_set``:
+  of ``range_expression`` can be ``std::array``, ``std::deque``, ``std::map``,
+  ``std::set``, ``std::unordered_map``, ``std::unordered_set``, or
+  ``std::vector``:
 
 .. code-block:: c++
 
@@ -59,6 +59,15 @@ Options
    Semicolon-separated list of names of vector-like classes. By default only
    ``::std::vector`` is considered.
 
+.. option:: ForRangeLoopClasses
+
+   Semicolon-separated list of names of container classes that can be used as
+   sources in range-based ``for`` loops. Each configured class must provide an
+   accessible ``size()`` method whose result is the number of elements visited
+   by the loop. Defaults to
+   ``::std::array``, ``::std::deque``, ``::std::map``, ``::std::set``,
+   ``::std::unordered_map``, ``::std::unordered_set``, and ``::std::vector``.
+
 .. option:: EnableProto
 
    When `true`, the check will also warn on inefficient operations for proto

diff  --git 
a/clang-tools-extra/test/clang-tidy/checkers/performance/inefficient-vector-operation-vectorlike-classes.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/performance/inefficient-vector-operation-vectorlike-classes.cpp
index 41d2d3733e07a1..75d2a760ef371f 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/performance/inefficient-vector-operation-vectorlike-classes.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/performance/inefficient-vector-operation-vectorlike-classes.cpp
@@ -1,7 +1,9 @@
 // RUN: %check_clang_tidy %s performance-inefficient-vector-operation %t -- \
 // RUN: -config='{CheckOptions: \
 // RUN:  {performance-inefficient-vector-operation.VectorLikeClasses: \
-// RUN:   
"VectorLikeInheritedPushBack;VectorLikeDirectPushBack;VectorLikeInheritedEmplaceBack"}}'
+// RUN:   
"VectorLikeInheritedPushBack;VectorLikeDirectPushBack;VectorLikeInheritedEmplaceBack",
 \
+// RUN:   performance-inefficient-vector-operation.ForRangeLoopClasses: \
+// RUN:   "RangeLike"}}'
 
 class VectorLikePushBackBase {
 public:
@@ -29,6 +31,25 @@ class VectorLikeInheritedEmplaceBack : public 
VectorLikeEmplaceBackBase {
   void reserve(int);
 };
 
+class RangeLike {
+public:
+  int *begin();
+  int *end();
+  int size() const;
+};
+
+class UnconfiguredRangeLike {
+public:
+  int *begin();
+  int *end();
+  int size() const;
+};
+
+class RangeHolder {
+public:
+  RangeLike range;
+};
+
 void testVectorLikeClasses() {
   {
     VectorLikeInheritedPushBack inheritedPushBackVector;
@@ -56,4 +77,34 @@ void testVectorLikeClasses() {
       // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'emplace_back' is called 
inside a loop; consider pre-allocating the container capacity before the loop
     }
   }
+
+  {
+    RangeLike range;
+    VectorLikeDirectPushBack vector;
+    // CHECK-FIXES: vector.reserve(range.size());
+    for (int value : range) {
+      vector.push_back(value);
+      // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside 
a loop; consider pre-allocating the container capacity before the loop
+    }
+  }
+
+  {
+    UnconfiguredRangeLike range;
+    VectorLikeDirectPushBack vector;
+    // CHECK-FIXES-NOT: vector.reserve(range.size());
+    for (int value : range) {
+      vector.push_back(value);
+      // CHECK-MESSAGES-NOT: :[[@LINE-1]]:7: warning: 'push_back' is called 
inside a loop
+    }
+  }
+
+  {
+    RangeHolder holder;
+    VectorLikeDirectPushBack vector;
+    // CHECK-FIXES: vector.reserve(holder.range.size());
+    for (int value : holder.range) {
+      vector.push_back(value);
+      // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called inside 
a loop; consider pre-allocating the container capacity before the loop
+    }
+  }
 }


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

Reply via email to