[clang-tools-extra] r222878 - [clang-tidy] Support initializer_list in google-explicit-constructor check

Alexander Kornienko alexfh at google.com
Thu Nov 27 03:11:47 PST 2014


Author: alexfh
Date: Thu Nov 27 05:11:47 2014
New Revision: 222878

URL: http://llvm.org/viewvc/llvm-project?rev=222878&view=rev
Log:
[clang-tidy] Support initializer_list in google-explicit-constructor check

Summary:
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.

Reviewers: djasper

Reviewed By: djasper

Subscribers: curdeius, cfe-commits

Differential Revision: http://reviews.llvm.org/D6427

Added:
    clang-tools-extra/trunk/test/clang-tidy/google-explicit-constructor.cpp
Modified:
    clang-tools-extra/trunk/clang-tidy/google/ExplicitConstructorCheck.cpp
    clang-tools-extra/trunk/test/clang-tidy/deduplication.cpp
    clang-tools-extra/trunk/test/clang-tidy/diagnostic.cpp
    clang-tools-extra/trunk/test/clang-tidy/file-filter.cpp
    clang-tools-extra/trunk/test/clang-tidy/line-filter.cpp
    clang-tools-extra/trunk/test/clang-tidy/macros.cpp
    clang-tools-extra/trunk/test/clang-tidy/nolint.cpp

Modified: clang-tools-extra/trunk/clang-tidy/google/ExplicitConstructorCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/google/ExplicitConstructorCheck.cpp?rev=222878&r1=222877&r2=222878&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/google/ExplicitConstructorCheck.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/google/ExplicitConstructorCheck.cpp Thu Nov 27 05:11:47 2014
@@ -47,15 +47,33 @@ SourceRange FindToken(const SourceManage
   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";
@@ -63,21 +81,31 @@ void ExplicitConstructorCheck::check(con
     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 should not be 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 ");
 }
 

Modified: clang-tools-extra/trunk/test/clang-tidy/deduplication.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/deduplication.cpp?rev=222878&r1=222877&r2=222878&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/deduplication.cpp (original)
+++ clang-tools-extra/trunk/test/clang-tidy/deduplication.cpp Thu Nov 27 05:11:47 2014
@@ -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:
 
 

Modified: clang-tools-extra/trunk/test/clang-tidy/diagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/diagnostic.cpp?rev=222878&r1=222877&r2=222878&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/diagnostic.cpp (original)
+++ clang-tools-extra/trunk/test/clang-tidy/diagnostic.cpp Thu Nov 27 05:11:47 2014
@@ -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:

Modified: clang-tools-extra/trunk/test/clang-tidy/file-filter.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/file-filter.cpp?rev=222878&r1=222877&r2=222878&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/file-filter.cpp (original)
+++ clang-tools-extra/trunk/test/clang-tidy/file-filter.cpp Thu Nov 27 05:11:47 2014
@@ -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:

Added: clang-tools-extra/trunk/test/clang-tidy/google-explicit-constructor.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/google-explicit-constructor.cpp?rev=222878&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/google-explicit-constructor.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/google-explicit-constructor.cpp Thu Nov 27 05:11:47 2014
@@ -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 should not be 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 should not be 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) {}
+};

Modified: clang-tools-extra/trunk/test/clang-tidy/line-filter.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/line-filter.cpp?rev=222878&r1=222877&r2=222878&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/line-filter.cpp (original)
+++ clang-tools-extra/trunk/test/clang-tidy/line-filter.cpp Thu Nov 27 05:11:47 2014
@@ -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:
 

Modified: clang-tools-extra/trunk/test/clang-tidy/macros.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/macros.cpp?rev=222878&r1=222877&r2=222878&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/macros.cpp (original)
+++ clang-tools-extra/trunk/test/clang-tidy/macros.cpp Thu Nov 27 05:11:47 2014
@@ -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'

Modified: clang-tools-extra/trunk/test/clang-tidy/nolint.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/nolint.cpp?rev=222878&r1=222877&r2=222878&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/nolint.cpp (original)
+++ clang-tools-extra/trunk/test/clang-tidy/nolint.cpp Thu Nov 27 05:11:47 2014
@@ -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)





More information about the cfe-commits mailing list