Index: clang-tidy/performance/InefficientVectorOperationCheck.cpp =================================================================== --- clang-tidy/performance/InefficientVectorOperationCheck.cpp +++ clang-tidy/performance/InefficientVectorOperationCheck.cpp @@ -39,14 +39,15 @@ // - VectorVarDeclName: 'v' in (as VarDecl). // - VectorVarDeclStmatName: The entire 'std::vector v;' statement (as // DeclStmt). -// - PushBackCallName: 'v.push_back(i)' (as cxxMemberCallExpr). +// - PushBackOrEmplaceBackCallName: 'v.push_back(i)' (as cxxMemberCallExpr). // - LoopInitVarName: 'i' (as VarDecl). // - LoopEndExpr: '10+1' (as Expr). static const char LoopCounterName[] = "for_loop_counter"; static const char LoopParentName[] = "loop_parent"; static const char VectorVarDeclName[] = "vector_var_decl"; static const char VectorVarDeclStmtName[] = "vector_var_decl_stmt"; -static const char PushBackCallName[] = "push_back_call"; +static const char PushBackOrEmplaceBackCallName[] = + "push_back_or_emplace_back_call"; static const char LoopInitVarName[] = "loop_init_var"; static const char LoopEndExprName[] = "loop_end_expr"; @@ -81,13 +82,13 @@ const auto VectorVarDecl = varDecl(hasInitializer(VectorDefaultConstructorCall)) .bind(VectorVarDeclName); - const auto PushBackCallExpr = + const auto VectorAppendCallExpr = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("push_back"))), on(hasType(VectorDecl)), + callee(cxxMethodDecl(hasAnyName("push_back", "emplace_back"))), + on(hasType(VectorDecl)), onImplicitObjectArgument(declRefExpr(to(VectorVarDecl)))) - .bind(PushBackCallName); - const auto PushBackCall = - expr(anyOf(PushBackCallExpr, exprWithCleanups(has(PushBackCallExpr)))); + .bind(PushBackOrEmplaceBackCallName); + const auto VectorAppendCall = expr(ignoringImplicit(VectorAppendCallExpr)); const auto VectorVarDefStmt = declStmt(hasSingleDecl(equalsBoundNode(VectorVarDeclName))) .bind(VectorVarDeclStmtName); @@ -98,9 +99,11 @@ const auto RefersToLoopVar = ignoringParenImpCasts( declRefExpr(to(varDecl(equalsBoundNode(LoopInitVarName))))); - // Matchers for the loop whose body has only 1 push_back calling statement. - const auto HasInterestingLoopBody = hasBody(anyOf( - compoundStmt(statementCountIs(1), has(PushBackCall)), PushBackCall)); + // Matchers for the loop whose body has only 1 push_back/emplace_back calling + // statement. + const auto HasInterestingLoopBody = + hasBody(anyOf(compoundStmt(statementCountIs(1), has(VectorAppendCall)), + VectorAppendCall)); const auto InInterestingCompoundStmt = hasParent(compoundStmt(has(VectorVarDefStmt)).bind(LoopParentName)); @@ -145,8 +148,8 @@ const auto *ForLoop = Result.Nodes.getNodeAs(LoopCounterName); const auto *RangeLoop = Result.Nodes.getNodeAs(RangeLoopName); - const auto *PushBackCall = - Result.Nodes.getNodeAs(PushBackCallName); + const auto *VectorAppendCall = + Result.Nodes.getNodeAs(PushBackOrEmplaceBackCallName); const auto *LoopEndExpr = Result.Nodes.getNodeAs(LoopEndExprName); const auto *LoopParent = Result.Nodes.getNodeAs(LoopParentName); @@ -173,7 +176,7 @@ llvm::StringRef VectorVarName = Lexer::getSourceText( CharSourceRange::getTokenRange( - PushBackCall->getImplicitObjectArgument()->getSourceRange()), + VectorAppendCall->getImplicitObjectArgument()->getSourceRange()), SM, Context->getLangOpts()); std::string ReserveStmt; @@ -197,9 +200,11 @@ ReserveStmt = (VectorVarName + ".reserve(" + LoopEndSource + ");\n").str(); } - auto Diag = diag(PushBackCall->getLocStart(), - "'push_back' is called inside a loop; " - "consider pre-allocating the vector capacity before the loop"); + auto Diag = + diag(VectorAppendCall->getLocStart(), + "%0 is called inside a loop; " + "consider pre-allocating the vector capacity before the loop") + << VectorAppendCall->getMethodDecl()->getDeclName(); if (!ReserveStmt.empty()) Diag << FixItHint::CreateInsertion(LoopStmt->getLocStart(), ReserveStmt); Index: docs/clang-tidy/checks/performance-inefficient-vector-operation.rst =================================================================== --- docs/clang-tidy/checks/performance-inefficient-vector-operation.rst +++ docs/clang-tidy/checks/performance-inefficient-vector-operation.rst @@ -3,8 +3,8 @@ performance-inefficient-vector-operation ======================================== -Finds possible inefficient ``std::vector`` operations (e.g. ``push_back``) that -may cause unnecessary memory reallocations. +Finds possible inefficient ``std::vector`` operations (e.g. ``push_back``, +``emplace_back``) that may cause unnecessary memory reallocations. Currently, the check only detects following kinds of loops with a single statement body: @@ -24,7 +24,7 @@ * For-range loops like ``for (range-declaration : range_expression)``, the type of ``range_expression`` can be ``std::vector``, ``std::array``, - ``std::dequeue``, ``std::set``, ``std::unordered_set``, ``std::map``, + ``std::deque``, ``std::set``, ``std::unordered_set``, ``std::map``, ``std::unordered_set``: .. code-block:: c++ Index: test/clang-tidy/performance-inefficient-vector-operation.cpp =================================================================== --- test/clang-tidy/performance-inefficient-vector-operation.cpp +++ test/clang-tidy/performance-inefficient-vector-operation.cpp @@ -35,6 +35,9 @@ explicit vector(size_type n); void push_back(const T& val); + + template void emplace_back(Args &&... args); + void reserve(size_t n); void resize(size_t n); @@ -150,6 +153,14 @@ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'push_back' is called } } + { + std::vector v; + // CHECK-FIXES: v.reserve(t.size()); + for (const auto &e : t) { + v.emplace_back(e); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: 'emplace_back' is called + } + } // ---- Non-fixed Cases ---- { std::vector v;