forked from OSchip/llvm-project
[clang-tidy] Ignore empty members and bases in cppcoreguidelines-pro-type-member-init
Summary: Empty/incomplete variables/members/bases don't need to be initialized Reviewers: mgehre, aaron.ballman, alexfh Subscribers: nemanjai, cfe-commits Differential Revision: https://reviews.llvm.org/D25238 llvm-svn: 283886
This commit is contained in:
parent
38a42e4bfa
commit
66b7014092
|
@ -317,6 +317,28 @@ void ProTypeMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
|
||||||
Options.store(Opts, "IgnoreArrays", IgnoreArrays);
|
Options.store(Opts, "IgnoreArrays", IgnoreArrays);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Copied from clang/lib/Sema/SemaDeclCXX.cpp.
|
||||||
|
static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) {
|
||||||
|
if (T->isIncompleteArrayType())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
while (const ConstantArrayType *ArrayT = Context.getAsConstantArrayType(T)) {
|
||||||
|
if (!ArrayT->getSize())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
T = ArrayT->getElementType();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isEmpty(ASTContext &Context, const QualType &Type) {
|
||||||
|
if (const CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl()) {
|
||||||
|
return ClassDecl->isEmpty();
|
||||||
|
}
|
||||||
|
return isIncompleteOrZeroLengthArrayType(Context, Type);
|
||||||
|
}
|
||||||
|
|
||||||
void ProTypeMemberInitCheck::checkMissingMemberInitializer(
|
void ProTypeMemberInitCheck::checkMissingMemberInitializer(
|
||||||
ASTContext &Context, const CXXRecordDecl &ClassDecl,
|
ASTContext &Context, const CXXRecordDecl &ClassDecl,
|
||||||
const CXXConstructorDecl *Ctor) {
|
const CXXConstructorDecl *Ctor) {
|
||||||
|
@ -330,7 +352,8 @@ void ProTypeMemberInitCheck::checkMissingMemberInitializer(
|
||||||
forEachField(ClassDecl, ClassDecl.fields(), false, [&](const FieldDecl *F) {
|
forEachField(ClassDecl, ClassDecl.fields(), false, [&](const FieldDecl *F) {
|
||||||
if (!F->hasInClassInitializer() &&
|
if (!F->hasInClassInitializer() &&
|
||||||
utils::type_traits::isTriviallyDefaultConstructible(F->getType(),
|
utils::type_traits::isTriviallyDefaultConstructible(F->getType(),
|
||||||
Context))
|
Context) &&
|
||||||
|
!isEmpty(Context, F->getType()))
|
||||||
FieldsToInit.insert(F);
|
FieldsToInit.insert(F);
|
||||||
});
|
});
|
||||||
if (FieldsToInit.empty())
|
if (FieldsToInit.empty())
|
||||||
|
|
|
@ -423,3 +423,30 @@ UNINITIALIZED_FIELD_IN_MACRO_BODY_VIRTUAL(F);
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: F
|
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: F
|
||||||
UNINITIALIZED_FIELD_IN_MACRO_BODY_VIRTUAL(G);
|
UNINITIALIZED_FIELD_IN_MACRO_BODY_VIRTUAL(G);
|
||||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: G
|
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these fields: G
|
||||||
|
|
||||||
|
struct NegativeEmpty {
|
||||||
|
};
|
||||||
|
|
||||||
|
static void NegativeEmptyVar() {
|
||||||
|
NegativeEmpty e;
|
||||||
|
(void)e;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NegativeEmptyMember {
|
||||||
|
NegativeEmptyMember() {}
|
||||||
|
NegativeEmpty e;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NegativeEmptyBase : NegativeEmpty {
|
||||||
|
NegativeEmptyBase() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NegativeEmptyArrayMember {
|
||||||
|
NegativeEmptyArrayMember() {}
|
||||||
|
char e[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NegativeIncompleteArrayMember {
|
||||||
|
NegativeIncompleteArrayMember() {}
|
||||||
|
char e[];
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue