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
