Sockke updated this revision to Diff 365455.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D107450/new/

https://reviews.llvm.org/D107450

Files:
  clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp
  clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.h
  clang-tools-extra/test/clang-tidy/checkers/performance-move-const-arg.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance-move-const-arg.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/checkers/performance-move-const-arg.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance-move-const-arg.cpp
@@ -70,7 +70,11 @@
   // CHECK-FIXES: return x3;
 }
 
-A f4(A x4) { return std::move(x4); }
+A f4(A x4) { 
+  return std::move(x4); 
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: it's superfluous; a move will happen, with or without the std::move
+  // CHECK-FIXES: return x4;
+}
 
 A f5(const A x5) {
   return std::move(x5);
@@ -246,3 +250,82 @@
   };
   f(MoveSemantics());
 }
+
+void showInt(int &&) {}
+int testInt() {
+  int a = 10;
+  int b = std::move(a);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: std::move of the variable 'a' of the trivially-copyable type 'int' has no effect; remove std::move()
+  // CHECK-FIXES: int b = a;
+  showInt(std::move(a));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: std::move of the variable 'a' of the trivially-copyable type 'int' has no effect; consider changing showInt's parameter from 'int'&& to 'int'&
+  return std::move(a);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the variable 'a' of the trivially-copyable type 'int' has no effect; remove std::move()
+  // CHECK-FIXES: return a;
+}
+template <class T>
+void forwardToShowInt(T &&t) {
+  showInt(static_cast<T &&>(t));
+}
+void testTemplate() {
+  int a = 10;
+  forwardToShowInt(std::move(a));
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: std::move of the variable 'a' of the trivially-copyable type 'int' has no effect; consider changing forwardToShowInt's parameter from 'int'&& to 'int'&
+}
+
+struct Tmp {};
+void showTmp(Tmp &&) {}
+Tmp testTmp() {
+  Tmp t;
+  Tmp t1 = std::move(t);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: std::move of the variable 't' of the trivially-copyable type 'Tmp' has no effect; remove std::move()
+  // CHECK-FIXES: Tmp t1 = t;
+  Tmp t2 = std::move(Tmp());
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: std::move of the expression of the trivially-copyable type 'Tmp' has no effect; remove std::move()
+  // CHECK-FIXES: Tmp t2 = Tmp();
+  showTmp(std::move(t));
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: std::move of the variable 't' of the trivially-copyable type 'Tmp' has no effect; consider changing showTmp's parameter from 'Tmp'&& to 'Tmp'&
+  return std::move(t);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: std::move of the variable 't' of the trivially-copyable type 'Tmp' has no effect; remove std::move()
+  // CHECK-FIXES: return t;
+}
+
+struct Tmp_UnTriviallyC {
+  Tmp_UnTriviallyC() {}
+  Tmp_UnTriviallyC(const Tmp_UnTriviallyC &) {}
+};
+void showTmp_UnTriviallyC(Tmp_UnTriviallyC &&) {}
+Tmp_UnTriviallyC testTmp_UnTriviallyC() {
+  Tmp_UnTriviallyC tn;
+  Tmp_UnTriviallyC tn1 = std::move(tn);
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: passing result of std::move() as a const reference argument; no move will actually happen
+  // CHECK-FIXES: Tmp_UnTriviallyC tn1 = tn;
+  Tmp_UnTriviallyC tn2 = std::move(Tmp_UnTriviallyC());
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: passing result of std::move() as a const reference argument; no move will actually happen
+  // CHECK-FIXES: Tmp_UnTriviallyC tn2 = Tmp_UnTriviallyC();
+  showTmp_UnTriviallyC(std::move(tn));
+  // Expect no warning given here.
+  return std::move(tn);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: passing result of std::move() as a const reference argument; no move will actually happen 
+  // CHECK-FIXES: return tn;
+}
+
+struct Tmp_UnTriviallyCR {
+  Tmp_UnTriviallyCR() {}
+  Tmp_UnTriviallyCR(const Tmp_UnTriviallyCR &) {}
+  Tmp_UnTriviallyCR(Tmp_UnTriviallyCR &&) {}
+};
+void showTmp_UnTriviallyCR(Tmp_UnTriviallyCR &&) {}
+Tmp_UnTriviallyCR testTmp_UnTriviallyCR() {
+  Tmp_UnTriviallyCR tnr;
+  Tmp_UnTriviallyCR tnr1 = std::move(tnr);
+  // Expect no warning given here.
+  Tmp_UnTriviallyCR tnr2 = std::move(Tmp_UnTriviallyCR());
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: it's superfluous; a move will happen, with or without the std::move
+  // CHECK-FIXES: Tmp_UnTriviallyCR tnr2 = Tmp_UnTriviallyCR();
+  showTmp_UnTriviallyCR(std::move(tnr));
+  // Expect no warning given here.
+  return std::move(tnr);
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: it's superfluous; a move will happen, with or without the std::move
+  // CHECK-FIXES: return tnr;
+}
Index: clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.h
===================================================================
--- clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.h
+++ clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTANTARGUMENTCHECK_H
 
 #include "../ClangTidyCheck.h"
+#include "llvm/ADT/DenseSet.h"
 
 namespace clang {
 namespace tidy {
@@ -36,6 +37,7 @@
 
 private:
   const bool CheckTriviallyCopyableMove;
+  llvm::DenseSet<const CallExpr*> HasCheckedMoveSet;
 };
 
 } // namespace performance
Index: clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp
+++ clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp
@@ -47,17 +47,41 @@
 
   Finder->addMatcher(MoveCallMatcher, this);
 
+  Finder->addMatcher(
+      returnStmt(
+          hasReturnValue(anyOf(
+              ignoringParenImpCasts(MoveCallMatcher),
+              cxxConstructExpr(
+                  hasDeclaration(cxxConstructorDecl(
+                      allOf(isUserProvided(), isMoveConstructor()))),
+                  hasAnyArgument(ignoringParenImpCasts(MoveCallMatcher))))))
+          .bind("return-call-move"),
+      this);
+
   Finder->addMatcher(
       invocation(forEachArgumentWithParam(
                      MoveCallMatcher,
-                     parmVarDecl(hasType(references(isConstQualified())))))
+                     parmVarDecl(anyOf(hasType(references(isConstQualified())),
+                                       hasType(rValueReferenceType())))
+                         .bind("invocation-parm")))
           .bind("receiving-expr"),
       this);
 }
 
 void MoveConstArgCheck::check(const MatchFinder::MatchResult &Result) {
   const auto *CallMove = Result.Nodes.getNodeAs<CallExpr>("call-move");
+  const auto *ReturnCallMove =
+      Result.Nodes.getNodeAs<ReturnStmt>("return-call-move");
   const auto *ReceivingExpr = Result.Nodes.getNodeAs<Expr>("receiving-expr");
+  const auto *InvocationParm =
+      Result.Nodes.getNodeAs<ParmVarDecl>("invocation-parm");
+
+  if (!ReturnCallMove && !ReceivingExpr && HasCheckedMoveSet.count(CallMove))
+    return;
+
+  if (ReturnCallMove || ReceivingExpr)
+    HasCheckedMoveSet.insert(CallMove);
+
   const Expr *Arg = CallMove->getArg(0);
   SourceManager &SM = Result.Context->getSourceManager();
 
@@ -90,23 +114,51 @@
       return;
 
     bool IsVariable = isa<DeclRefExpr>(Arg);
+    bool IsInvocationArg = false;
+    StringRef FuncName;
     const auto *Var =
         IsVariable ? dyn_cast<DeclRefExpr>(Arg)->getDecl() : nullptr;
-    auto Diag = diag(FileMoveRange.getBegin(),
-                     "std::move of the %select{|const }0"
-                     "%select{expression|variable %4}1 "
-                     "%select{|of the trivially-copyable type %5 }2"
-                     "has no effect; remove std::move()"
-                     "%select{| or make the variable non-const}3")
-                << IsConstArg << IsVariable << IsTriviallyCopyable
-                << (IsConstArg && IsVariable && !IsTriviallyCopyable) << Var
-                << Arg->getType();
+    if (ReceivingExpr &&
+        InvocationParm->getOriginalType()->isRValueReferenceType() &&
+        !ReceivingExpr->getType()->isRecordType() && Arg->isLValue()) {
+      IsInvocationArg = true;
+      const auto *ReceivingCallExpr = dyn_cast<CallExpr>(ReceivingExpr);
+      if (!ReceivingCallExpr)
+        return;
+      const auto *FD = ReceivingCallExpr->getDirectCallee();
+      FuncName = FD->getName();
+    }
+    auto Diag =
+        diag(FileMoveRange.getBegin(),
+             "std::move of the %select{|const }0"
+             "%select{expression|variable %5}1 "
+             "%select{|of the trivially-copyable type %6 }2"
+             "has no effect; %select{remove std::move()|}3"
+             "%select{| or make the variable non-const}4"
+             "%select{|consider changing %7's parameter from %6&& to %6&}3")
+        << IsConstArg << IsVariable << IsTriviallyCopyable << IsInvocationArg
+        << (IsConstArg && IsVariable && !IsTriviallyCopyable &&
+            !IsInvocationArg)
+        << Var << Arg->getType() << FuncName;
+
+    if (!IsInvocationArg)
+      replaceCallWithArg(CallMove, Diag, SM, getLangOpts());
+  } else if (ReturnCallMove || ReceivingExpr) {
+    if (ReceivingExpr &&
+        InvocationParm->getOriginalType()->isRValueReferenceType() &&
+        Arg->isLValue())
+      return;
 
-    replaceCallWithArg(CallMove, Diag, SM, getLangOpts());
-  } else if (ReceivingExpr) {
-    auto Diag = diag(FileMoveRange.getBegin(),
-                     "passing result of std::move() as a const reference "
-                     "argument; no move will actually happen");
+    bool IsMoveConstruct = false;
+    if (ReturnCallMove ||
+        InvocationParm->getOriginalType()->isRValueReferenceType())
+      IsMoveConstruct = true;
+    auto Diag =
+        diag(FileMoveRange.getBegin(),
+             "%select{passing result of std::move() as a const reference "
+             "argument; no move will actually happen|it's superfluous; a move "
+             "will happen, with or without the std::move}0")
+        << IsMoveConstruct;
 
     replaceCallWithArg(CallMove, Diag, SM, getLangOpts());
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to