aaron.ballman updated this revision to Diff 32697.
aaron.ballman added a comment.

In http://reviews.llvm.org/D11784#228764, @alexfh wrote:

> In http://reviews.llvm.org/D11784#227939, @aaron.ballman wrote:
>
> > Addressed review comments. I re-ran the updated patch against LLVM and 
> > Clang, and there were some more false positives that I would like to 
> > address if possible. It seems my previous run against the source base was 
> > before expanding the scope of the patch to include more than just base 
> > class initialization (sorry for the earlier misinformation).
> >
> > 1. SourceMgr.h:58 is an example where the checker issues a diagnostic (for 
> > IncludeLoc), but given the triviality of the type, I don't see a reason to 
> > diagnose. However, this requires support from Sema, so I think a FIXME may 
> > be the best I can do. Note, adding a call to std::move() in these instances 
> > is not wrong, it's just not particularly useful.
>
>
> Determining whether a type is trivially-copyable can be done on the AST level 
> without Sema (see QualType::isTriviallyCopyableType).


That should get us closer, but doesn't quite cut it. I think I may be able to 
combine this with CXXRecordDecl::isTriviallyCopyable() to get us close enough 
to cut down on the number of false positives. Thank you for pointing this out, 
it is implemented in this patch.

> > 2. we should not be warning on anything an implicit constructor does. For 
> > instance LiveQueryResult is triggering this because of SlotIndex. This 
> > should be fixed with this patch.

> 

> > 

> 

> >   Running over Clang and LLVM, there are 7 distinct false positives 
> > (repeated due to being in header files) and they all relate to triviality. 
> > The total false positive count was 832 of which two warnings (SourceMgr.h 
> > and Preprocessor.h) accounted for probably close to 90% of the diagnostics. 
> > This time around there were no true positives.

> 

> 

> Can you list the list of unique locations?


With the triviality implementation, I now get zero false positives (and zero 
true positives) in the Clang and LLVM source base.


http://reviews.llvm.org/D11784

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MiscTidyModule.cpp
  clang-tidy/misc/MoveConstructorInitCheck.cpp
  clang-tidy/misc/MoveConstructorInitCheck.h
  test/clang-tidy/misc-move-constructor-init.cpp

Index: test/clang-tidy/misc-move-constructor-init.cpp
===================================================================
--- test/clang-tidy/misc-move-constructor-init.cpp
+++ test/clang-tidy/misc-move-constructor-init.cpp
@@ -0,0 +1,78 @@
+// RUN: clang-tidy %s -checks=-*,misc-move-constructor-init -- -std=c++14 | FileCheck %s -implicit-check-not="{{warning|error}}:"
+
+template <class T> struct remove_reference      {typedef T type;};
+template <class T> struct remove_reference<T&>  {typedef T type;};
+template <class T> struct remove_reference<T&&> {typedef T type;};
+
+template <typename T>
+typename remove_reference<T>::type&& move(T&& arg) {
+  return static_cast<typename remove_reference<T>::type&&>(arg);
+}
+
+struct C {
+  C() = default;
+  C(const C&) = default;
+};
+
+struct B {
+  B() {}
+  B(const B&) {}
+  B(B &&) {}
+};
+
+struct D : B {
+  D() : B() {}
+  D(const D &RHS) : B(RHS) {}
+  // CHECK: :[[@LINE+3]]:16: warning: move constructor initializes base class by calling a copy constructor [misc-move-constructor-init]
+  // CHECK: 19:3: note: copy constructor being called
+  // CHECK: 20:3: note: candidate move constructor here
+  D(D &&RHS) : B(RHS) {}
+};
+
+struct E : B {
+  E() : B() {}
+  E(const E &RHS) : B(RHS) {}
+  E(E &&RHS) : B(move(RHS)) {} // ok
+};
+
+struct F {
+  C M;
+
+  F(F &&) : M(C()) {} // ok
+};
+
+struct G {
+  G() = default;
+  G(const G&) = default;
+  G(G&&) = delete;
+};
+
+struct H : G {
+  H() = default;
+  H(const H&) = default;
+  H(H &&RHS) : G(RHS) {} // ok
+};
+
+struct I {
+  I(const I &) = default; // suppresses move constructor creation
+};
+
+struct J : I {
+  J(J &&RHS) : I(RHS) {} // ok
+};
+
+struct K {}; // Has implicit copy and move constructors, is trivially copyable
+struct L : K {
+  L(L &&RHS) : K(RHS) {} // ok
+};
+
+struct M {
+  B Mem;
+  // CHECK: :[[@LINE+1]]:16: warning: move constructor initializes class member by calling a copy constructor [misc-move-constructor-init]
+  M(M &&RHS) : Mem(RHS.Mem) {}
+};
+
+struct N {
+  B Mem;
+  N(N &&RHS) : Mem(move(RHS.Mem)) {}
+};
Index: clang-tidy/misc/MoveConstructorInitCheck.h
===================================================================
--- clang-tidy/misc/MoveConstructorInitCheck.h
+++ clang-tidy/misc/MoveConstructorInitCheck.h
@@ -0,0 +1,32 @@
+//===--- MoveConstructorInitCheck.h - clang-tidy-----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTRUCTORINITCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTRUCTORINITCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+
+/// \brief The check flags user-defined move constructors that have a
+/// ctor-initializer initializing a member or base class through a copy
+/// constructor instead of a move constructor.
+class MoveConstructorInitCheck : public ClangTidyCheck {
+public:
+  MoveConstructorInitCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MOVECONSTRUCTORINITCHECK_H
Index: clang-tidy/misc/MoveConstructorInitCheck.cpp
===================================================================
--- clang-tidy/misc/MoveConstructorInitCheck.cpp
+++ clang-tidy/misc/MoveConstructorInitCheck.cpp
@@ -0,0 +1,77 @@
+//===--- MoveConstructorInitCheck.cpp - clang-tidy-------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MoveConstructorInitCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+
+void MoveConstructorInitCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+    constructorDecl(unless(isImplicit()), allOf(
+      isMoveConstructor(),
+      hasAnyConstructorInitializer(
+        ctorInitializer(withInitializer(constructExpr(hasDeclaration(
+          constructorDecl(isCopyConstructor()).bind("ctor")
+        )))).bind("init")
+      )
+    )), this);
+}
+
+void MoveConstructorInitCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *CopyCtor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
+  const auto *Initializer = Result.Nodes.getNodeAs<CXXCtorInitializer>("init");
+
+  // Do not diagnose if the expression used to perform the initialization is a
+  // trivially-copyable type.
+  QualType QT = Initializer->getInit()->getType();
+  if (QT.isTriviallyCopyableType(*Result.Context))
+    return;
+  
+  const auto *RD = QT->getAsCXXRecordDecl();
+  if (RD && RD->isTriviallyCopyable())
+    return;
+
+  // Diagnose when the class type has a move constructor available, but the
+  // ctor-initializer uses the copy constructor instead.
+  const CXXConstructorDecl *Candidate = nullptr;
+  for (const auto *Ctor : CopyCtor->getParent()->ctors()) {
+    if (Ctor->isMoveConstructor() && Ctor->getAccess() <= AS_protected &&
+        !Ctor->isDeleted()) {
+      // The type has a move constructor that is at least accessible to the
+      // initializer.
+      //
+      // FIXME: Determine whether the move constructor is a viable candidate
+      // for the ctor-initializer, perhaps provide a fixit that suggests
+      // using std::move().
+      Candidate = Ctor;
+      break;
+    }
+  }
+
+  if (Candidate) {
+    // There's a move constructor candidate that the caller probably intended
+    // to call instead.
+    diag(Initializer->getSourceLocation(),
+         "move constructor initializes %0 by calling a copy constructor")
+        << (Initializer->isBaseInitializer() ? "base class" : "class member");
+    diag(CopyCtor->getLocation(), "copy constructor being called",
+         DiagnosticIDs::Note);
+    diag(Candidate->getLocation(), "candidate move constructor here",
+         DiagnosticIDs::Note);
+  }
+}
+
+} // namespace tidy
+} // namespace clang
+
Index: clang-tidy/misc/MiscTidyModule.cpp
===================================================================
--- clang-tidy/misc/MiscTidyModule.cpp
+++ clang-tidy/misc/MiscTidyModule.cpp
@@ -18,6 +18,7 @@
 #include "InefficientAlgorithmCheck.h"
 #include "MacroParenthesesCheck.h"
 #include "MacroRepeatedSideEffectsCheck.h"
+#include "MoveConstructorInitCheck.h"
 #include "NoexceptMoveConstructorCheck.h"
 #include "StaticAssertCheck.h"
 #include "SwappedArgumentsCheck.h"
@@ -50,6 +51,8 @@
         "misc-macro-parentheses");
     CheckFactories.registerCheck<MacroRepeatedSideEffectsCheck>(
         "misc-macro-repeated-side-effects");
+    CheckFactories.registerCheck<MoveConstructorInitCheck>(
+        "misc-move-constructor-init");
     CheckFactories.registerCheck<NoexceptMoveConstructorCheck>(
         "misc-noexcept-move-constructor");
     CheckFactories.registerCheck<StaticAssertCheck>(
Index: clang-tidy/misc/CMakeLists.txt
===================================================================
--- clang-tidy/misc/CMakeLists.txt
+++ clang-tidy/misc/CMakeLists.txt
@@ -10,6 +10,7 @@
   MacroParenthesesCheck.cpp
   MacroRepeatedSideEffectsCheck.cpp
   MiscTidyModule.cpp
+  MoveConstructorInitCheck.cpp
   NoexceptMoveConstructorCheck.cpp
   StaticAssertCheck.cpp
   SwappedArgumentsCheck.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to