-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[clang-tidy] Add check performance-lost-std-move #139525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang-tools-extra Author: Vasiliy Kulikov (segoon) ChangesFull diff: https://github.com/llvm/llvm-project/pull/139525.diff 8 Files Affected:
diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
index 81128ff086021..333abd10a583a 100644
--- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
@@ -12,6 +12,7 @@ add_clang_library(clangTidyPerformanceModule
InefficientAlgorithmCheck.cpp
InefficientStringConcatenationCheck.cpp
InefficientVectorOperationCheck.cpp
+ LostStdMoveCheck.cpp
MoveConstArgCheck.cpp
MoveConstructorInitCheck.cpp
NoAutomaticMoveCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp
new file mode 100644
index 0000000000000..26148e1d26de9
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp
@@ -0,0 +1,96 @@
+//===--- LostStdMoveCheck.cpp - clang-tidy --------------------------------===//
+//
+// 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 "LostStdMoveCheck.h"
+#include "../utils/DeclRefExprUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::performance {
+
+using utils::decl_ref_expr::allDeclRefExprs;
+
+AST_MATCHER(CXXRecordDecl, hasTrivialMoveConstructor) {
+ return Node.hasDefinition() && Node.hasTrivialMoveConstructor();
+}
+
+void LostStdMoveCheck::registerMatchers(MatchFinder *Finder) {
+ auto returnParent =
+ hasParent(expr(hasParent(cxxConstructExpr(hasParent(returnStmt())))));
+
+ Finder->addMatcher(
+ declRefExpr(
+ // not "return x;"
+ unless(returnParent),
+
+ unless(hasType(namedDecl(hasName("::std::string_view")))),
+
+ // non-trivial type
+ hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl()))),
+
+ // non-trivial X(X&&)
+ unless(hasType(hasCanonicalType(
+ hasDeclaration(cxxRecordDecl(hasTrivialMoveConstructor()))))),
+
+ // Not in a cycle
+ unless(hasAncestor(forStmt())), unless(hasAncestor(doStmt())),
+ unless(hasAncestor(whileStmt())),
+
+ // only non-X&
+ unless(hasDeclaration(
+ varDecl(hasType(qualType(lValueReferenceType()))))),
+
+ hasDeclaration(
+ varDecl(hasAncestor(functionDecl().bind("func"))).bind("decl")),
+
+ hasParent(expr(hasParent(cxxConstructExpr())).bind("use_parent")))
+ .bind("use"),
+ this);
+}
+
+const Expr *LostStdMoveCheck::getLastVarUsage(const VarDecl &Var,
+ const Decl &Func,
+ ASTContext &Context) {
+ auto Exprs = allDeclRefExprs(Var, Func, Context);
+
+ const Expr *LastExpr = nullptr;
+ for (const auto &Expr : Exprs) {
+ if (!LastExpr)
+ LastExpr = Expr;
+
+ if (LastExpr->getBeginLoc() < Expr->getBeginLoc())
+ LastExpr = Expr;
+ }
+
+ return LastExpr;
+}
+
+void LostStdMoveCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("decl");
+ const auto *MatchedFunc = Result.Nodes.getNodeAs<FunctionDecl>("func");
+ const auto *MatchedUse = Result.Nodes.getNodeAs<Expr>("use");
+ const auto *MatchedUseCall = Result.Nodes.getNodeAs<CallExpr>("use_parent");
+
+ if (MatchedUseCall)
+ return;
+
+ const auto *LastUsage =
+ getLastVarUsage(*MatchedDecl, *MatchedFunc, *Result.Context);
+ if (LastUsage == nullptr)
+ return;
+
+ if (LastUsage->getBeginLoc() > MatchedUse->getBeginLoc()) {
+ // "use" is not the last reference to x
+ return;
+ }
+
+ diag(LastUsage->getBeginLoc(), "Could be std::move()");
+}
+
+} // namespace clang::tidy::performance
diff --git a/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.h b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.h
new file mode 100644
index 0000000000000..c62c3f6448a82
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.h
@@ -0,0 +1,37 @@
+//===--- LostStdMoveCheck.h - clang-tidy ------------------------*- C++ -*-===//
+//
+// 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_PERFORMANCE_LOSTSTDMOVECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_LOSTSTDMOVECHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::performance {
+
+/// Search for lost std::move().
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/performance/lost-std-move.html
+class LostStdMoveCheck : public ClangTidyCheck {
+public:
+ LostStdMoveCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ 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:
+ const Expr *getLastVarUsage(const VarDecl &Var, const Decl &Func,
+ ASTContext &Context);
+};
+
+} // namespace clang::tidy::performance
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_LOSTSTDMOVECHECK_H
diff --git a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
index 9e0fa6f88b36a..6c45f8678fe63 100644
--- a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
@@ -17,6 +17,7 @@
#include "InefficientAlgorithmCheck.h"
#include "InefficientStringConcatenationCheck.h"
#include "InefficientVectorOperationCheck.h"
+#include "LostStdMoveCheck.h"
#include "MoveConstArgCheck.h"
#include "MoveConstructorInitCheck.h"
#include "NoAutomaticMoveCheck.h"
@@ -49,6 +50,7 @@ class PerformanceModule : public ClangTidyModule {
"performance-inefficient-string-concatenation");
CheckFactories.registerCheck<InefficientVectorOperationCheck>(
"performance-inefficient-vector-operation");
+ CheckFactories.registerCheck<LostStdMoveCheck>("performance-lost-std-move");
CheckFactories.registerCheck<MoveConstArgCheck>(
"performance-move-const-arg");
CheckFactories.registerCheck<MoveConstructorInitCheck>(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 6d91748e4cef1..17da163ff041c 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -212,6 +212,11 @@ New checks
Recommends the smallest possible underlying type for an ``enum`` or ``enum``
class based on the range of its enumerators.
+- New :doc:`performance-lost-std-move
+ <clang-tidy/checks/performance/lost-std-move>` check.
+
+ Searches for lost std::move().
+
- New :doc:`readability-reference-to-constructed-temporary
<clang-tidy/checks/readability/reference-to-constructed-temporary>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 31f0e090db1d7..2eba4aacb2c33 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -321,6 +321,7 @@ Clang-Tidy Checks
:doc:`performance-inefficient-algorithm <performance/inefficient-algorithm>`, "Yes"
:doc:`performance-inefficient-string-concatenation <performance/inefficient-string-concatenation>`,
:doc:`performance-inefficient-vector-operation <performance/inefficient-vector-operation>`, "Yes"
+ :doc:`performance-lost-std-move <performance/lost-std-move>`, "Yes"
:doc:`performance-move-const-arg <performance/move-const-arg>`, "Yes"
:doc:`performance-move-constructor-init <performance/move-constructor-init>`,
:doc:`performance-no-automatic-move <performance/no-automatic-move>`,
diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance/lost-std-move.rst b/clang-tools-extra/docs/clang-tidy/checks/performance/lost-std-move.rst
new file mode 100644
index 0000000000000..ded49de7b8126
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/performance/lost-std-move.rst
@@ -0,0 +1,14 @@
+.. title:: clang-tidy - performance-lost-std-move
+
+performance-lost-std-move
+=========================
+
+The check warns if copy constructor is used instead of std::move().
+
+.. code-block:: c++
+
+ void f(X);
+
+ void g(X x) {
+ f(x); // warning: Could be std::move() [performance-lost-std-move]
+ }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/lost-std-move.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/lost-std-move.cpp
new file mode 100644
index 0000000000000..ce2d1b972dbd5
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/performance/lost-std-move.cpp
@@ -0,0 +1,108 @@
+// RUN: %check_clang_tidy %s performance-lost-std-move %t
+
+namespace std {
+
+template<typename T>
+class shared_ptr {
+public:
+ T& operator*() { return reinterpret_cast<T&>(*this); }
+ shared_ptr() {}
+ shared_ptr(const shared_ptr<T>&) {}
+};
+
+template<typename T>
+T&& move(T&)
+{
+}
+
+} // namespace std
+
+int f(std::shared_ptr<int>);
+
+void f_arg(std::shared_ptr<int> ptr)
+{
+ if (*ptr)
+ f(ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: Could be std::move() [performance-lost-std-move]
+}
+
+void f_rvalue_ref(std::shared_ptr<int>&& ptr)
+{
+ if (*ptr)
+ f(ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: Could be std::move() [performance-lost-std-move]
+}
+
+using SharedPtr = std::shared_ptr<int>;
+void f_using(SharedPtr ptr)
+{
+ if (*ptr)
+ f(ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: Could be std::move() [performance-lost-std-move]
+}
+
+void f_local()
+{
+ std::shared_ptr<int> ptr;
+ if (*ptr)
+ f(ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: Could be std::move() [performance-lost-std-move]
+}
+
+void f_move()
+{
+ std::shared_ptr<int> ptr;
+ if (*ptr)
+ f(std::move(ptr));
+}
+
+void f_ref(std::shared_ptr<int> &ptr)
+{
+ if (*ptr)
+ f(ptr);
+}
+
+std::shared_ptr<int> f_return()
+{
+ std::shared_ptr<int> ptr;
+ return ptr;
+}
+
+void f_still_used(std::shared_ptr<int> ptr)
+{
+ if (*ptr)
+ f(ptr);
+
+ *ptr = 1;
+ *ptr = *ptr;
+}
+
+void f_cycle1()
+{
+ std::shared_ptr<int> ptr;
+ for(;;)
+ f(ptr);
+}
+
+void f_cycle2()
+{
+ std::shared_ptr<int> ptr;
+ for(int i=0; i<5; i++)
+ f(ptr);
+}
+
+void f_cycle3()
+{
+ std::shared_ptr<int> ptr;
+ while (*ptr) {
+ f(ptr);
+ }
+}
+
+void f_cycle4()
+{
+ std::shared_ptr<int> ptr;
+ do {
+ f(ptr);
+ } while (*ptr);
+}
|
@llvm/pr-subscribers-clang-tidy Author: Vasiliy Kulikov (segoon) ChangesFull diff: https://github.com/llvm/llvm-project/pull/139525.diff 8 Files Affected:
diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
index 81128ff086021..333abd10a583a 100644
--- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
@@ -12,6 +12,7 @@ add_clang_library(clangTidyPerformanceModule
InefficientAlgorithmCheck.cpp
InefficientStringConcatenationCheck.cpp
InefficientVectorOperationCheck.cpp
+ LostStdMoveCheck.cpp
MoveConstArgCheck.cpp
MoveConstructorInitCheck.cpp
NoAutomaticMoveCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp
new file mode 100644
index 0000000000000..26148e1d26de9
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.cpp
@@ -0,0 +1,96 @@
+//===--- LostStdMoveCheck.cpp - clang-tidy --------------------------------===//
+//
+// 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 "LostStdMoveCheck.h"
+#include "../utils/DeclRefExprUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::performance {
+
+using utils::decl_ref_expr::allDeclRefExprs;
+
+AST_MATCHER(CXXRecordDecl, hasTrivialMoveConstructor) {
+ return Node.hasDefinition() && Node.hasTrivialMoveConstructor();
+}
+
+void LostStdMoveCheck::registerMatchers(MatchFinder *Finder) {
+ auto returnParent =
+ hasParent(expr(hasParent(cxxConstructExpr(hasParent(returnStmt())))));
+
+ Finder->addMatcher(
+ declRefExpr(
+ // not "return x;"
+ unless(returnParent),
+
+ unless(hasType(namedDecl(hasName("::std::string_view")))),
+
+ // non-trivial type
+ hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl()))),
+
+ // non-trivial X(X&&)
+ unless(hasType(hasCanonicalType(
+ hasDeclaration(cxxRecordDecl(hasTrivialMoveConstructor()))))),
+
+ // Not in a cycle
+ unless(hasAncestor(forStmt())), unless(hasAncestor(doStmt())),
+ unless(hasAncestor(whileStmt())),
+
+ // only non-X&
+ unless(hasDeclaration(
+ varDecl(hasType(qualType(lValueReferenceType()))))),
+
+ hasDeclaration(
+ varDecl(hasAncestor(functionDecl().bind("func"))).bind("decl")),
+
+ hasParent(expr(hasParent(cxxConstructExpr())).bind("use_parent")))
+ .bind("use"),
+ this);
+}
+
+const Expr *LostStdMoveCheck::getLastVarUsage(const VarDecl &Var,
+ const Decl &Func,
+ ASTContext &Context) {
+ auto Exprs = allDeclRefExprs(Var, Func, Context);
+
+ const Expr *LastExpr = nullptr;
+ for (const auto &Expr : Exprs) {
+ if (!LastExpr)
+ LastExpr = Expr;
+
+ if (LastExpr->getBeginLoc() < Expr->getBeginLoc())
+ LastExpr = Expr;
+ }
+
+ return LastExpr;
+}
+
+void LostStdMoveCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("decl");
+ const auto *MatchedFunc = Result.Nodes.getNodeAs<FunctionDecl>("func");
+ const auto *MatchedUse = Result.Nodes.getNodeAs<Expr>("use");
+ const auto *MatchedUseCall = Result.Nodes.getNodeAs<CallExpr>("use_parent");
+
+ if (MatchedUseCall)
+ return;
+
+ const auto *LastUsage =
+ getLastVarUsage(*MatchedDecl, *MatchedFunc, *Result.Context);
+ if (LastUsage == nullptr)
+ return;
+
+ if (LastUsage->getBeginLoc() > MatchedUse->getBeginLoc()) {
+ // "use" is not the last reference to x
+ return;
+ }
+
+ diag(LastUsage->getBeginLoc(), "Could be std::move()");
+}
+
+} // namespace clang::tidy::performance
diff --git a/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.h b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.h
new file mode 100644
index 0000000000000..c62c3f6448a82
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/performance/LostStdMoveCheck.h
@@ -0,0 +1,37 @@
+//===--- LostStdMoveCheck.h - clang-tidy ------------------------*- C++ -*-===//
+//
+// 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_PERFORMANCE_LOSTSTDMOVECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_LOSTSTDMOVECHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::performance {
+
+/// Search for lost std::move().
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/performance/lost-std-move.html
+class LostStdMoveCheck : public ClangTidyCheck {
+public:
+ LostStdMoveCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ 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:
+ const Expr *getLastVarUsage(const VarDecl &Var, const Decl &Func,
+ ASTContext &Context);
+};
+
+} // namespace clang::tidy::performance
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_LOSTSTDMOVECHECK_H
diff --git a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
index 9e0fa6f88b36a..6c45f8678fe63 100644
--- a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
@@ -17,6 +17,7 @@
#include "InefficientAlgorithmCheck.h"
#include "InefficientStringConcatenationCheck.h"
#include "InefficientVectorOperationCheck.h"
+#include "LostStdMoveCheck.h"
#include "MoveConstArgCheck.h"
#include "MoveConstructorInitCheck.h"
#include "NoAutomaticMoveCheck.h"
@@ -49,6 +50,7 @@ class PerformanceModule : public ClangTidyModule {
"performance-inefficient-string-concatenation");
CheckFactories.registerCheck<InefficientVectorOperationCheck>(
"performance-inefficient-vector-operation");
+ CheckFactories.registerCheck<LostStdMoveCheck>("performance-lost-std-move");
CheckFactories.registerCheck<MoveConstArgCheck>(
"performance-move-const-arg");
CheckFactories.registerCheck<MoveConstructorInitCheck>(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 6d91748e4cef1..17da163ff041c 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -212,6 +212,11 @@ New checks
Recommends the smallest possible underlying type for an ``enum`` or ``enum``
class based on the range of its enumerators.
+- New :doc:`performance-lost-std-move
+ <clang-tidy/checks/performance/lost-std-move>` check.
+
+ Searches for lost std::move().
+
- New :doc:`readability-reference-to-constructed-temporary
<clang-tidy/checks/readability/reference-to-constructed-temporary>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 31f0e090db1d7..2eba4aacb2c33 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -321,6 +321,7 @@ Clang-Tidy Checks
:doc:`performance-inefficient-algorithm <performance/inefficient-algorithm>`, "Yes"
:doc:`performance-inefficient-string-concatenation <performance/inefficient-string-concatenation>`,
:doc:`performance-inefficient-vector-operation <performance/inefficient-vector-operation>`, "Yes"
+ :doc:`performance-lost-std-move <performance/lost-std-move>`, "Yes"
:doc:`performance-move-const-arg <performance/move-const-arg>`, "Yes"
:doc:`performance-move-constructor-init <performance/move-constructor-init>`,
:doc:`performance-no-automatic-move <performance/no-automatic-move>`,
diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance/lost-std-move.rst b/clang-tools-extra/docs/clang-tidy/checks/performance/lost-std-move.rst
new file mode 100644
index 0000000000000..ded49de7b8126
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/performance/lost-std-move.rst
@@ -0,0 +1,14 @@
+.. title:: clang-tidy - performance-lost-std-move
+
+performance-lost-std-move
+=========================
+
+The check warns if copy constructor is used instead of std::move().
+
+.. code-block:: c++
+
+ void f(X);
+
+ void g(X x) {
+ f(x); // warning: Could be std::move() [performance-lost-std-move]
+ }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/lost-std-move.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/lost-std-move.cpp
new file mode 100644
index 0000000000000..ce2d1b972dbd5
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/performance/lost-std-move.cpp
@@ -0,0 +1,108 @@
+// RUN: %check_clang_tidy %s performance-lost-std-move %t
+
+namespace std {
+
+template<typename T>
+class shared_ptr {
+public:
+ T& operator*() { return reinterpret_cast<T&>(*this); }
+ shared_ptr() {}
+ shared_ptr(const shared_ptr<T>&) {}
+};
+
+template<typename T>
+T&& move(T&)
+{
+}
+
+} // namespace std
+
+int f(std::shared_ptr<int>);
+
+void f_arg(std::shared_ptr<int> ptr)
+{
+ if (*ptr)
+ f(ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: Could be std::move() [performance-lost-std-move]
+}
+
+void f_rvalue_ref(std::shared_ptr<int>&& ptr)
+{
+ if (*ptr)
+ f(ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: Could be std::move() [performance-lost-std-move]
+}
+
+using SharedPtr = std::shared_ptr<int>;
+void f_using(SharedPtr ptr)
+{
+ if (*ptr)
+ f(ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: Could be std::move() [performance-lost-std-move]
+}
+
+void f_local()
+{
+ std::shared_ptr<int> ptr;
+ if (*ptr)
+ f(ptr);
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: Could be std::move() [performance-lost-std-move]
+}
+
+void f_move()
+{
+ std::shared_ptr<int> ptr;
+ if (*ptr)
+ f(std::move(ptr));
+}
+
+void f_ref(std::shared_ptr<int> &ptr)
+{
+ if (*ptr)
+ f(ptr);
+}
+
+std::shared_ptr<int> f_return()
+{
+ std::shared_ptr<int> ptr;
+ return ptr;
+}
+
+void f_still_used(std::shared_ptr<int> ptr)
+{
+ if (*ptr)
+ f(ptr);
+
+ *ptr = 1;
+ *ptr = *ptr;
+}
+
+void f_cycle1()
+{
+ std::shared_ptr<int> ptr;
+ for(;;)
+ f(ptr);
+}
+
+void f_cycle2()
+{
+ std::shared_ptr<int> ptr;
+ for(int i=0; i<5; i++)
+ f(ptr);
+}
+
+void f_cycle3()
+{
+ std::shared_ptr<int> ptr;
+ while (*ptr) {
+ f(ptr);
+ }
+}
+
+void f_cycle4()
+{
+ std::shared_ptr<int> ptr;
+ do {
+ f(ptr);
+ } while (*ptr);
+}
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do not use auto
unless type is explicitly states in same statement or iterator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Searches for lost std::move(). | |
Searches for lost ``std::move()``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unintended change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please synchronize with statement in Release Notes. This check
should be omitted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented general suggestions/improvements for the check without deep dive into matchers/tests.
Please look at tests in previous attempt in creating such check https://reviews.llvm.org/D137205.
Check that all test cases from that PR are covered in your tests.
If some cases are not covered and you can't address them, please add them to Limitations
in docs and leave a fixme.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return LangOpts.CPlusPlus; | |
return LangOpts.CPlusPlus11; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be converted to static
function and move to .cpp file if no fields of check class are needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use explicit type instead of auto
if it isn't written explicitly in code line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try to provide fixits with the insertion of std::move
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be synced with release notes and check docs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This need a little more description when the check will warn, e.g when this will fire, with what types?
Look for reference at https://reviews.llvm.org/D137205
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit suggestion: try make the description similar to already existing new checks in ReleaseNotes.rst.
Description should start with "Finds ..."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Give examples when check will not warn
d3b8c17
to
6aacd41
Compare
const auto* MatchedLeafStatement = | ||
Result.Nodes.getNodeAs<Stmt>("leaf_statement"); | ||
|
||
if (!MatchedDecl->hasLocalStorage()) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be two lines as next statement.
- New :doc:`readability-ambiguous-smartptr-reset-call | ||
<clang-tidy/checks/readability/ambiguous-smartptr-reset-call>` check. | ||
|
||
<<<<<<< HEAD |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rebase artifact.
|
||
.. option:: StrictMode | ||
|
||
A variable ``X`` can be referenced by another variable ``R``. In this case the last |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please follow 80 characters limit.
declRefExpr( | ||
// not "return x;" | ||
unless(ReturnParent), | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that such newlines improve code readability. Same in other places.
|
||
SmallVector<BoundNodes, 1> Matches = match( | ||
findAll(declRefExpr( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same below.
|
||
} // namespace std | ||
|
||
int f(std::shared_ptr<int>); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test this check will not fix for
int f(std::shared_ptr<int> &);
int f(std::shared_ptr<int> const &);
anyOf( | ||
// f(x) | ||
hasParent(expr(hasParent(cxxConstructExpr())).bind("use_parent")), | ||
// f((x)) | ||
hasParent(parenExpr(hasParent( | ||
expr(hasParent(cxxConstructExpr())).bind("use_parent")))))) | ||
.bind("use"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am worry about the performance of this matcher because it will check all DeclRefExpr
. Could we check the child of CXXConstructExpr
instead.
Then for parenExpr
, we can simply use ignoreParen
✅ With the latest revision this PR passed the C/C++ code linter. |
@@ -0,0 +1,196 @@ | |||
//===--- LostStdMoveCheck.cpp - clang-tidy --------------------------------===// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//===--- LostStdMoveCheck.cpp - clang-tidy --------------------------------===// | |
//===----------------------------------------------------------------------===//``` |
@@ -0,0 +1,38 @@ | |||
//===--- LostStdMoveCheck.h - clang-tidy ------------------------*- C++ -*-===// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
//===--- LostStdMoveCheck.h - clang-tidy ------------------------*- C++ -*-===// | |
//===----------------------------------------------------------------------===// |
/// expressions. | ||
/// | ||
/// For the user-facing documentation see: | ||
/// http://clang.llvm.org/extra/clang-tidy/checks/performance/lost-std-move.html |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// http://clang.llvm.org/extra/clang-tidy/checks/performance/lost-std-move.html | |
/// https://clang.llvm.org/extra/clang-tidy/checks/performance/lost-std-move.html |
If you want to ignore assigns to reference variables, set ``StrictMode`` | ||
to ``false``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you want to ignore assigns to reference variables, set ``StrictMode`` | |
to ``false``. | |
If you want to ignore assigns to reference variables, set :option:`StrictMode` | |
to `false`. |
If you want to ignore assigns to reference variables, set ::option:: | ||
`StrictMode` to `true`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you want to ignore assigns to reference variables, set ::option:: | |
`StrictMode` to `true`. | |
If you want to ignore assigns to reference variables, set :option:`StrictMode` | |
to `true`. |
y.f(); // because x is still used via y | ||
} | ||
|
||
If you want to ignore assigns to reference variables, set :option: `StrictMode` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you want to ignore assigns to reference variables, set :option: `StrictMode` | |
If you want to ignore assigns to reference variables, set :option:`StrictMode` |
This is statement. See :program:
in clang-tools-extra/docs/ReleaseNotes.rst
as example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks! sorry for so many small typos :(
references ``X``, then it will not emit a warning for ``X`` not to provoke | ||
false positive. If you're sure that such references don't extend ``X`` | ||
lifetime and ready to handle possible false positives, then set `StrictMode` | ||
to `true`. Defaults to `false`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to `true`. Defaults to `false`. | |
to `true`. Default is `false`. |
No description provided.