https://github.com/ayyYoSam updated https://github.com/llvm/llvm-project/pull/226742
>From 4ef080191328fa39e845391172c40ac6869e05f9 Mon Sep 17 00:00:00 2001 From: ayyYoSam <[email protected]> Date: Sat, 26 Sep 2026 22:47:25 -0300 Subject: [PATCH 1/2] clang-tidy: add misc-use-bulk-insert check --- .../clang-tidy/misc/CMakeLists.txt | 1 + .../clang-tidy/misc/MiscTidyModule.cpp | 3 + .../clang-tidy/misc/UseBulkInsertCheck.cpp | 97 +++++++++++++++++++ .../clang-tidy/misc/UseBulkInsertCheck.h | 26 +++++ .../checkers/misc/use-bulk-insert.cpp | 22 +++++ 5 files changed, 149 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.h create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/use-bulk-insert.cpp diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt index 68faf77fa1d5f..faa27bb5fa77e 100644 --- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt @@ -20,6 +20,7 @@ set_target_properties(genconfusable PROPERTIES FOLDER "Clang Tools Extra/Sourceg add_clang_library(clangTidyMiscModule STATIC AnonymousNamespaceInHeaderCheck.cpp ConfusableIdentifierCheck.cpp + UseBulkInsertCheck.cpp ConstCorrectnessCheck.cpp CoroutineHostileRAIICheck.cpp DefinitionsInHeadersCheck.cpp diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp index 52d3b4297ba26..07f1517eec661 100644 --- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "../ClangTidy.h" +#include "UseBulkInsertCheck.h" #include "../ClangTidyModule.h" #include "AnonymousNamespaceInHeaderCheck.h" #include "ConfusableIdentifierCheck.h" @@ -49,6 +50,8 @@ class MiscModule : public ClangTidyModule { "misc-anonymous-namespace-in-header"); CheckFactories.registerCheck<ConfusableIdentifierCheck>( "misc-confusable-identifiers"); + CheckFactories.registerCheck<UseBulkInsertCheck>( + "misc-use-bulk-insert"); CheckFactories.registerCheck<ConstCorrectnessCheck>( "misc-const-correctness"); CheckFactories.registerCheck<CoroutineHostileRAIICheck>( diff --git a/clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.cpp b/clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.cpp new file mode 100644 index 0000000000000..dbda841ee5e61 --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.cpp @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// 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 "UseBulkInsertCheck.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::misc { + +void UseBulkInsertCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + cxxForRangeStmt( + hasLoopVariable(varDecl().bind("loop_var")), + hasRangeInit(expr().bind("range")), + hasBody(compoundStmt( + statementCountIs(1), + hasAnySubstatement(cxxMemberCallExpr( + callee(memberExpr( + ofClass(cxxRecordDecl(hasAnyName( + "::std::set", "::std::map", "::std::multiset", + "::std::multimap", "::std::unordered_set", + "::std::unordered_map", + "::std::unordered_multiset", + "::std::unordered_multimap"))))), + argumentCountIs(1), + hasArgument( + 0, ignoringParenImpCasts( + declRefExpr(to(varDecl().bind("insert_arg")))))) + .bind("insert_call"))))) + .bind("for_range"), + this); +} + +void UseBulkInsertCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *Loop = + Result.Nodes.getNodeAs<CXXForRangeStmt>("for_range"); + const auto *LoopVar = + Result.Nodes.getNodeAs<VarDecl>("loop_var"); + const auto *InsertArg = + Result.Nodes.getNodeAs<VarDecl>("insert_arg"); + const auto *Range = + Result.Nodes.getNodeAs<Expr>("range"); + const auto *InsertCall = + Result.Nodes.getNodeAs<CXXMemberCallExpr>("insert_call"); + + if (!Loop || !LoopVar || !InsertArg || !Range || !InsertCall) + return; + + if (LoopVar != InsertArg) + return; + + const auto *Member = dyn_cast<MemberExpr>(InsertCall->getCallee()); + if (!Member) + return; + + const Expr *Object = Member->getBase(); + if (!Object) + return; + + const SourceManager &SM = *Result.SourceManager; + const LangOptions &LangOpts = Result.Context->getLangOpts(); + + StringRef ObjectText = Lexer::getSourceText( + CharSourceRange::getTokenRange(Object->getSourceRange()), SM, + LangOpts); + + StringRef RangeText = Lexer::getSourceText( + CharSourceRange::getTokenRange(Range->getSourceRange()), SM, + LangOpts); + + if (ObjectText.empty() || RangeText.empty()) + return; + + std::string Replacement = ObjectText.str(); + Replacement += ".insert("; + Replacement += RangeText; + Replacement += ".begin(), "; + Replacement += RangeText; + Replacement += ".end());"; + + diag(Loop->getForLoc(), + "use bulk insertion instead of inserting elements one at a time") + << FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(Loop->getBeginLoc(), + Loop->getEndLoc()), + Replacement); +} + +} // namespace clang::tidy::misc \ No newline at end of file diff --git a/clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.h b/clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.h new file mode 100644 index 0000000000000..502cf1d29a55e --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.h @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// 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_MISC_USEBULKINSERTCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USEBULKINSERTCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::misc { + +class UseBulkInsertCheck : public ClangTidyCheck { +public: + using ClangTidyCheck::ClangTidyCheck; + + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace clang::tidy::misc + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USEBULKINSERTCHECK_H \ No newline at end of file diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/use-bulk-insert.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/use-bulk-insert.cpp new file mode 100644 index 0000000000000..9b524ba3bcaaf --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/use-bulk-insert.cpp @@ -0,0 +1,22 @@ +// RUN: %check_clang_tidy %s misc-use-bulk-insert %t + +#include <set> +#include <vector> + +void test_set(const std::set<int> &In) { + std::set<int> Out; + + for (int I : In) { + Out.insert(I); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use bulk insertion instead of inserting elements one at a time [misc-use-bulk-insert] + // CHECK-FIXES: Out.insert(In.begin(), In.end()); + } +} + +void test_vector(const std::vector<int> &In) { + std::vector<int> Out; + + for (int I : In) { + Out.insert(I); + } +} \ No newline at end of file >From 1dcac3ecc2c855918dd4e0f7f3316758f78e4e68 Mon Sep 17 00:00:00 2001 From: ayyYoSam <[email protected]> Date: Sat, 26 Sep 2026 23:22:02 -0300 Subject: [PATCH 2/2] clang-tidy: add documentation for misc-use-bulk-insert --- .../clang-tidy/misc/CMakeLists.txt | 2 +- .../clang-tidy/misc/UseBulkInsertCheck.cpp | 2 +- .../clang-tidy/misc/UseBulkInsertCheck.h | 2 +- clang-tools-extra/docs/ReleaseNotes.md | 7 ++++++ .../checks/misc/use-bulk-insert.rst | 25 +++++++++++++++++++ .../checkers/misc/use-bulk-insert.cpp | 2 +- 6 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 clang-tools-extra/docs/clang-tidy/checks/misc/use-bulk-insert.rst diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt index faa27bb5fa77e..8c308f3a621fb 100644 --- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt @@ -20,7 +20,6 @@ set_target_properties(genconfusable PROPERTIES FOLDER "Clang Tools Extra/Sourceg add_clang_library(clangTidyMiscModule STATIC AnonymousNamespaceInHeaderCheck.cpp ConfusableIdentifierCheck.cpp - UseBulkInsertCheck.cpp ConstCorrectnessCheck.cpp CoroutineHostileRAIICheck.cpp DefinitionsInHeadersCheck.cpp @@ -48,6 +47,7 @@ add_clang_library(clangTidyMiscModule STATIC UnusedParametersCheck.cpp UnusedUsingDeclsCheck.cpp UseAnonymousNamespaceCheck.cpp + UseBulkInsertCheck.cpp UseInternalLinkageCheck.cpp LINK_LIBS diff --git a/clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.cpp b/clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.cpp index dbda841ee5e61..16111a05df2c4 100644 --- a/clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.cpp @@ -94,4 +94,4 @@ void UseBulkInsertCheck::check( Replacement); } -} // namespace clang::tidy::misc \ No newline at end of file +} // namespace clang::tidy::misc diff --git a/clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.h b/clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.h index 502cf1d29a55e..0e9ee0e033135 100644 --- a/clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.h +++ b/clang-tools-extra/clang-tidy/misc/UseBulkInsertCheck.h @@ -23,4 +23,4 @@ class UseBulkInsertCheck : public ClangTidyCheck { } // namespace clang::tidy::misc -#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USEBULKINSERTCHECK_H \ No newline at end of file +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USEBULKINSERTCHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md index 833638a47abc6..fc3970016ab65 100644 --- a/clang-tools-extra/docs/ReleaseNotes.md +++ b/clang-tools-extra/docs/ReleaseNotes.md @@ -134,6 +134,13 @@ infrastructure are described first, followed by tool-specific sections. Detects malformed regex patterns defined in a single string literal. +- New {doc}`misc-use-bulk-insert + <clang-tidy/checks/misc/use-bulk-insert>` check. + + Detects range-based ``for`` loops that insert elements into associative + containers one at a time and suggests replacing them with a bulk + ``insert()`` call. + - New {doc}`modernize-use-to-underlying <clang-tidy/checks/modernize/use-to-underlying>` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/use-bulk-insert.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/use-bulk-insert.rst new file mode 100644 index 0000000000000..37d43c43eb5d9 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/misc/use-bulk-insert.rst @@ -0,0 +1,25 @@ +.. title:: clang-tidy - misc-use-bulk-insert + +misc-use-bulk-insert +==================== + +Detects range-based ``for`` loops that insert elements into associative +containers one at a time and suggests replacing them with a bulk +``insert()`` call. + +For example: + +.. code-block:: c++ + + for (int i : in) { + out.insert(i); + } + +becomes: + +.. code-block:: c++ + + out.insert(in.begin(), in.end()); + +The initial implementation covers standard associative containers, +including ``std::set``, ``std::map``, and ``std::unordered_*`` variants. diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/use-bulk-insert.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/use-bulk-insert.cpp index 9b524ba3bcaaf..2c6f69b55d019 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/misc/use-bulk-insert.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/use-bulk-insert.cpp @@ -19,4 +19,4 @@ void test_vector(const std::vector<int> &In) { for (int I : In) { Out.insert(I); } -} \ No newline at end of file +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
