Hi djasper,

According to the Google C++ Style Guide, constructors taking a single
std::initializer_list<> should not be marked explicit.

This change also changes the messages according to conventions used in Clang
diagnostics: no capitalization of the first letter, no trailing dot.

http://reviews.llvm.org/D6427

Files:
  clang-tidy/google/ExplicitConstructorCheck.cpp
  test/clang-tidy/deduplication.cpp
  test/clang-tidy/diagnostic.cpp
  test/clang-tidy/file-filter.cpp
  test/clang-tidy/google-explicit-constructor.cpp
  test/clang-tidy/line-filter.cpp
  test/clang-tidy/macros.cpp
  test/clang-tidy/nolint.cpp
  test/clang-tidy/serialize-diagnostics.cpp
Index: clang-tidy/google/ExplicitConstructorCheck.cpp
===================================================================
--- clang-tidy/google/ExplicitConstructorCheck.cpp
+++ clang-tidy/google/ExplicitConstructorCheck.cpp
@@ -47,37 +47,64 @@
   return SourceRange();
 }
 
+bool isStdInitializerList(QualType Type) {
+  if (const RecordType *RT = Type.getCanonicalType()->getAs<RecordType>()) {
+    if (ClassTemplateSpecializationDecl *Specialization =
+            dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl())) {
+      ClassTemplateDecl *Template = Specialization->getSpecializedTemplate();
+      // First use the fast getName() method to avoid unnecessary calls to the
+      // slow getQualifiedNameAsString().
+      return Template->getName() == "initializer_list" &&
+             Template->getQualifiedNameAsString() == "std::initializer_list";
+    }
+  }
+  return false;
+}
+
 void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) {
   const CXXConstructorDecl *Ctor =
       Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
   // Do not be confused: isExplicit means 'explicit' keyword is present,
   // isImplicit means that it's a compiler-generated constructor.
-  if (Ctor->isOutOfLine() || Ctor->isImplicit() || Ctor->isDeleted())
+  if (Ctor->isOutOfLine() || Ctor->isImplicit() || Ctor->isDeleted() ||
+      Ctor->getNumParams() == 0 || Ctor->getMinRequiredArguments() > 1)
     return;
 
-  if (Ctor->isExplicit() && Ctor->isCopyOrMoveConstructor()) {
+  bool takesInitializerList = isStdInitializerList(
+      Ctor->getParamDecl(0)->getType().getNonReferenceType());
+  if (Ctor->isExplicit() &&
+      (Ctor->isCopyOrMoveConstructor() || takesInitializerList)) {
     auto isKWExplicit = [](const Token &Tok) {
       return Tok.is(tok::raw_identifier) &&
              Tok.getRawIdentifier() == "explicit";
     };
     SourceRange ExplicitTokenRange =
         FindToken(*Result.SourceManager, Result.Context->getLangOpts(),
                   Ctor->getOuterLocStart(), Ctor->getLocEnd(), isKWExplicit);
+    StringRef ConstructorDescription;
+    if (Ctor->isMoveConstructor())
+      ConstructorDescription = "move";
+    else if (Ctor->isCopyConstructor())
+      ConstructorDescription = "copy";
+    else
+      ConstructorDescription = "initializer-list";
+
     DiagnosticBuilder Diag =
-        diag(Ctor->getLocation(), "%0 constructor declared explicit.")
-        << (Ctor->isMoveConstructor() ? "Move" : "Copy");
+        diag(Ctor->getLocation(), "%0 constructor declared explicit")
+        << ConstructorDescription;
     if (ExplicitTokenRange.isValid()) {
       Diag << FixItHint::CreateRemoval(
           CharSourceRange::getCharRange(ExplicitTokenRange));
     }
+    return;
   }
 
   if (Ctor->isExplicit() || Ctor->isCopyOrMoveConstructor() ||
-      Ctor->getNumParams() == 0 || Ctor->getMinRequiredArguments() > 1)
+      takesInitializerList)
     return;
 
   SourceLocation Loc = Ctor->getLocation();
-  diag(Loc, "Single-argument constructors must be explicit")
+  diag(Loc, "single-argument constructors must be explicit")
       << FixItHint::CreateInsertion(Loc, "explicit ");
 }
 
Index: test/clang-tidy/deduplication.cpp
===================================================================
--- test/clang-tidy/deduplication.cpp
+++ test/clang-tidy/deduplication.cpp
@@ -2,7 +2,7 @@
 
 template<typename T>
 struct A { A(T); };
-// CHECK: :[[@LINE-1]]:12: warning: Single-argument constructors must be explicit [google-explicit-constructor]
+// CHECK: :[[@LINE-1]]:12: warning: single-argument constructors must be explicit [google-explicit-constructor]
 // CHECK-NOT: warning:
 
 
Index: test/clang-tidy/diagnostic.cpp
===================================================================
--- test/clang-tidy/diagnostic.cpp
+++ test/clang-tidy/diagnostic.cpp
@@ -14,8 +14,8 @@
 // CHECK3: :[[@LINE+1]]:9: warning: implicit conversion from 'double' to 'int' changes value
 int a = 1.5;
 
-// CHECK2: :[[@LINE+2]]:11: warning: Single-argument constructors must be explicit [google-explicit-constructor]
-// CHECK3: :[[@LINE+1]]:11: warning: Single-argument constructors must be explicit [google-explicit-constructor]
+// CHECK2: :[[@LINE+2]]:11: warning: single-argument constructors must be explicit [google-explicit-constructor]
+// CHECK3: :[[@LINE+1]]:11: warning: single-argument constructors must be explicit [google-explicit-constructor]
 class A { A(int) {} };
 
 // CHECK2-NOT: warning:
Index: test/clang-tidy/file-filter.cpp
===================================================================
--- test/clang-tidy/file-filter.cpp
+++ test/clang-tidy/file-filter.cpp
@@ -5,27 +5,27 @@
 
 #include "header1.h"
 // CHECK-NOT: warning:
-// CHECK2: header1.h:1:12: warning: Single-argument constructors must be explicit [google-explicit-constructor]
+// CHECK2: header1.h:1:12: warning: single-argument constructors must be explicit [google-explicit-constructor]
 // CHECK3-NOT: warning:
-// CHECK4: header1.h:1:12: warning: Single-argument constructors
+// CHECK4: header1.h:1:12: warning: single-argument constructors
 
 #include "header2.h"
 // CHECK-NOT: warning:
-// CHECK2: header2.h:1:12: warning: Single-argument constructors
-// CHECK3: header2.h:1:12: warning: Single-argument constructors
-// CHECK4: header2.h:1:12: warning: Single-argument constructors
+// CHECK2: header2.h:1:12: warning: single-argument constructors
+// CHECK3: header2.h:1:12: warning: single-argument constructors
+// CHECK4: header2.h:1:12: warning: single-argument constructors
 
 #include <system-header.h>
 // CHECK-NOT: warning:
 // CHECK2-NOT: warning:
 // CHECK3-NOT: warning:
-// CHECK4: system-header.h:1:12: warning: Single-argument constructors
+// CHECK4: system-header.h:1:12: warning: single-argument constructors
 
 class A { A(int); };
-// CHECK: :[[@LINE-1]]:11: warning: Single-argument constructors
-// CHECK2: :[[@LINE-2]]:11: warning: Single-argument constructors
-// CHECK3: :[[@LINE-3]]:11: warning: Single-argument constructors
-// CHECK4: :[[@LINE-4]]:11: warning: Single-argument constructors
+// CHECK: :[[@LINE-1]]:11: warning: single-argument constructors
+// CHECK2: :[[@LINE-2]]:11: warning: single-argument constructors
+// CHECK3: :[[@LINE-3]]:11: warning: single-argument constructors
+// CHECK4: :[[@LINE-4]]:11: warning: single-argument constructors
 
 // CHECK-NOT: warning:
 // CHECK2-NOT: warning:
Index: test/clang-tidy/google-explicit-constructor.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/google-explicit-constructor.cpp
@@ -0,0 +1,59 @@
+// RUN: $(dirname %s)/check_clang_tidy.sh %s google-explicit-constructor %t
+// REQUIRES: shell
+
+namespace std {
+  typedef decltype(sizeof(int)) size_t;
+
+  // libc++'s implementation
+  template <class _E>
+  class initializer_list
+  {
+    const _E* __begin_;
+    size_t    __size_;
+
+    initializer_list(const _E* __b, size_t __s)
+      : __begin_(__b),
+        __size_(__s)
+    {}
+
+  public:
+    typedef _E        value_type;
+    typedef const _E& reference;
+    typedef const _E& const_reference;
+    typedef size_t    size_type;
+
+    typedef const _E* iterator;
+    typedef const _E* const_iterator;
+
+    initializer_list() : __begin_(nullptr), __size_(0) {}
+
+    size_t    size()  const {return __size_;}
+    const _E* begin() const {return __begin_;}
+    const _E* end()   const {return __begin_ + __size_;}
+  };
+}
+
+struct A {
+  A() {}
+  A(int x, int y) {}
+  A(std::initializer_list<int> list1) {}
+
+  explicit A(void *x) {}
+  explicit A(void *x, void *y) {}
+
+  explicit A(const A& a) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: copy constructor declared explicit [google-explicit-constructor]
+  // CHECK-FIXES: {{^  }}A(const A& a) {}
+
+  explicit A(std::initializer_list<double> list2) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initializer-list constructor declared explicit [google-explicit-constructor]
+  // CHECK-FIXES: {{^  }}A(std::initializer_list<double> list2) {}
+
+  A(int x1) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: single-argument constructors must be explicit [google-explicit-constructor]
+  // CHECK-FIXES: {{^  }}explicit A(int x1) {}
+
+  A(double x2, double y = 3.14) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: single-argument constructors must be explicit
+  // CHECK-FIXES: {{^  }}explicit A(double x2, double y = 3.14) {}
+};
Index: test/clang-tidy/line-filter.cpp
===================================================================
--- test/clang-tidy/line-filter.cpp
+++ test/clang-tidy/line-filter.cpp
@@ -2,25 +2,25 @@
 
 #include "header1.h"
 // CHECK-NOT: header1.h:{{.*}} warning
-// CHECK: header1.h:1:12: warning: Single-argument constructors must be explicit [google-explicit-constructor]
-// CHECK: header1.h:2:12: warning: Single-argument constructors {{.*}}
+// CHECK: header1.h:1:12: warning: single-argument constructors must be explicit [google-explicit-constructor]
+// CHECK: header1.h:2:12: warning: single-argument constructors {{.*}}
 // CHECK-NOT: header1.h:{{.*}} warning
 
 #include "header2.h"
-// CHECK: header2.h:1:12: warning: Single-argument constructors {{.*}}
-// CHECK: header2.h:2:12: warning: Single-argument constructors {{.*}}
-// CHECK: header2.h:3:12: warning: Single-argument constructors {{.*}}
+// CHECK: header2.h:1:12: warning: single-argument constructors {{.*}}
+// CHECK: header2.h:2:12: warning: single-argument constructors {{.*}}
+// CHECK: header2.h:3:12: warning: single-argument constructors {{.*}}
 // CHECK-NOT: header2.h:{{.*}} warning
 
 #include "header3.h"
 // CHECK-NOT: header3.h:{{.*}} warning
 
 class A { A(int); };
-// CHECK: :[[@LINE-1]]:11: warning: Single-argument constructors {{.*}}
+// CHECK: :[[@LINE-1]]:11: warning: single-argument constructors {{.*}}
 class B { B(int); };
 // CHECK-NOT: :[[@LINE-1]]:{{.*}} warning
 class C { C(int); };
-// CHECK: :[[@LINE-1]]:11: warning: Single-argument constructors {{.*}}
+// CHECK: :[[@LINE-1]]:11: warning: single-argument constructors {{.*}}
 
 // CHECK-NOT: warning:
 
Index: test/clang-tidy/macros.cpp
===================================================================
--- test/clang-tidy/macros.cpp
+++ test/clang-tidy/macros.cpp
@@ -3,5 +3,5 @@
 #define Q(name) class name { name(int i); }
 
 Q(A);
-// CHECK: :[[@LINE-1]]:3: warning: Single-argument constructors must be explicit [google-explicit-constructor]
+// CHECK: :[[@LINE-1]]:3: warning: single-argument constructors must be explicit [google-explicit-constructor]
 // CHECK: :3:30: note: expanded from macro 'Q'
Index: test/clang-tidy/nolint.cpp
===================================================================
--- test/clang-tidy/nolint.cpp
+++ test/clang-tidy/nolint.cpp
@@ -1,11 +1,11 @@
 // RUN: clang-tidy -checks='-*,google-explicit-constructor' %s -- 2>&1 | FileCheck %s
 
 class A { A(int i); };
-// CHECK: :[[@LINE-1]]:11: warning: Single-argument constructors must be explicit [google-explicit-constructor]
+// CHECK: :[[@LINE-1]]:11: warning: single-argument constructors must be explicit [google-explicit-constructor]
 
 class B { B(int i); }; // NOLINT
-// CHECK-NOT: :[[@LINE-1]]:11: warning: Single-argument constructors must be explicit [google-explicit-constructor]
+// CHECK-NOT: :[[@LINE-1]]:11: warning: single-argument constructors must be explicit [google-explicit-constructor]
 
 class C { C(int i); }; // NOLINT(we-dont-care-about-categories-yet)
-// CHECK-NOT: :[[@LINE-1]]:11: warning: Single-argument constructors must be explicit [google-explicit-constructor]
+// CHECK-NOT: :[[@LINE-1]]:11: warning: single-argument constructors must be explicit [google-explicit-constructor]
 // CHECK: Suppressed 2 warnings (2 NOLINT)
Index: test/clang-tidy/serialize-diagnostics.cpp
===================================================================
--- test/clang-tidy/serialize-diagnostics.cpp
+++ test/clang-tidy/serialize-diagnostics.cpp
@@ -1,3 +1,4 @@
-// RUN: clang-tidy %s -- --serialize-diagnostics %t | FileCheck %s
+// RUN: clang-tidy %s -- -serialize-diagnostics %t | FileCheck %s
+// RUN: clang-tidy %s -- -diagnostic-log-file %t | FileCheck %s
 // CHECK: :[[@LINE+1]]:12: error: expected ';' after struct [clang-diagnostic-error]
 struct A {}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to