[clang-tidy] Detect dependent initializer_lists in google-explicit-constructor.

Summary:
Detect constructors taking a single std::initializer_list even when it
is instantiation-dependent.

Reviewers: djasper

Reviewed By: djasper

Subscribers: curdeius, cfe-commits

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

llvm-svn: 228289
This commit is contained in:
Alexander Kornienko 2015-02-05 12:49:07 +00:00
parent 30029c6b58
commit dd2dad0d24
2 changed files with 48 additions and 12 deletions

View File

@ -48,16 +48,23 @@ SourceRange FindToken(const SourceManager &Sources, LangOptions LangOpts,
return SourceRange();
}
bool declIsStdInitializerList(const NamedDecl *D) {
// First use the fast getName() method to avoid unnecessary calls to the
// slow getQualifiedNameAsString().
return D->getName() == "initializer_list" &&
D->getQualifiedNameAsString() == "std::initializer_list";
}
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";
}
Type = Type.getCanonicalType();
if (const auto *TS = Type->getAs<TemplateSpecializationType>()) {
if (const TemplateDecl *TD = TS->getTemplateName().getAsTemplateDecl())
return declIsStdInitializerList(TD);
}
if (const auto *RT = Type->getAs<RecordType>()) {
if (const auto *Specialization =
dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()))
return declIsStdInitializerList(Specialization->getSpecializedTemplate());
}
return false;
}

View File

@ -49,7 +49,7 @@ struct A {
// 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-MESSAGES: :[[@LINE-1]]:3: warning: single-argument constructors
// CHECK-FIXES: {{^ }}explicit A(double x2, double y = 3.14) {}
};
@ -63,11 +63,11 @@ struct B {
// CHECK-FIXES: {{^ }}B(::std::initializer_list<double> list4) {}
explicit B(const ::std::initializer_list<char> &list5) {}
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initializer-list constructor should not be declared explicit [google-explicit-constructor]
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initializer-list constructor
// CHECK-FIXES: {{^ }}B(const ::std::initializer_list<char> &list5) {}
explicit B(::std::initializer_list<char> &&list6) {}
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initializer-list constructor should not be declared explicit [google-explicit-constructor]
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initializer-list constructor
// CHECK-FIXES: {{^ }}B(::std::initializer_list<char> &&list6) {}
};
@ -79,6 +79,27 @@ struct C {
C(initializer_list<unsigned> &&list3) {}
};
template <typename T>
struct C2 {
C2(initializer_list<int> list1) {}
C2(const initializer_list<unsigned> &list2) {}
C2(initializer_list<unsigned> &&list3) {}
explicit C2(initializer_list<double> list4) {}
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: initializer-list constructor
// CHECK-FIXES: {{^ }}C2(initializer_list<double> list4) {}
};
template <typename T>
struct C3 {
C3(initializer_list<T> list1) {}
C3(const std::initializer_list<T*> &list2) {}
C3(::std::initializer_list<T**> &&list3) {}
template <typename U>
C3(initializer_list<U> list3) {}
};
struct D {
template <typename T>
explicit D(T t) {}
@ -86,6 +107,14 @@ struct D {
template <typename T>
struct E {
E(T *pt) {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: single-argument constructors
// CHECK-FIXES: {{^ }}explicit E(T *pt) {}
template <typename U>
E(U *pu) {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: single-argument constructors
// CHECK-FIXES: {{^ }}explicit E(U *pu) {}
explicit E(T t) {}
template <typename U>
explicit E(U u) {}