Index: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp @@ -27,16 +27,23 @@ namespace { -void fieldsRequiringInit(const RecordDecl::field_range &Fields, - ASTContext &Context, - SmallPtrSetImpl &FieldsToInit) { +// Iterate over all the fields in a record type, both direct and indirect (e.g. +// if the record contains an anonmyous struct). If OneFieldPerUnion is true and +// the record type (or indirect field) is a union, forEachField will stop after +// the first field. +template +void forEachField(const RecordDecl *Record, const T &Fields, + bool OneFieldPerUnion, Func &&Fn) { for (const FieldDecl *F : Fields) { - if (F->hasInClassInitializer()) - continue; - QualType Type = F->getType(); - if (!F->hasInClassInitializer() && - utils::type_traits::isTriviallyDefaultConstructible(Type, Context)) - FieldsToInit.insert(F); + if (F->isAnonymousStructOrUnion()) { + if (const CXXRecordDecl *R = F->getType()->getAsCXXRecordDecl()) + forEachField(R, R->fields(), OneFieldPerUnion, Fn); + } else { + Fn(F); + } + + if (OneFieldPerUnion && Record->isUnion()) + break; } } @@ -179,8 +186,8 @@ // Gets either the field or base class being initialized by the provided // initializer. const auto *InitDecl = - Init->isMemberInitializer() - ? static_cast(Init->getMember()) + Init->isAnyMemberInitializer() + ? static_cast(Init->getAnyMember()) : Init->getBaseClass()->getAsCXXRecordDecl(); // Add all fields between current field up until the next intializer. @@ -216,7 +223,8 @@ Decls.emplace_back(Decl); } } - Decls.append(ClassDecl->fields().begin(), ClassDecl->fields().end()); + forEachField(ClassDecl, ClassDecl->fields(), false, + [&](const FieldDecl *F) { Decls.push_back(F); }); } template @@ -238,22 +246,6 @@ } } -template -void forEachField(const RecordDecl *Record, const T &Fields, - bool OneFieldPerUnion, Func &&Fn) { - for (const FieldDecl *F : Fields) { - if (F->isAnonymousStructOrUnion()) { - if (const RecordDecl *R = getCanonicalRecordDecl(F->getType())) - forEachField(R, R->fields(), OneFieldPerUnion, Fn); - } else { - Fn(F); - } - - if (OneFieldPerUnion && Record->isUnion()) - break; - } -} - } // anonymous namespace ProTypeMemberInitCheck::ProTypeMemberInitCheck(StringRef Name, @@ -314,8 +306,14 @@ if (IsUnion && ClassDecl->hasInClassInitializer()) return; + // Gather all fields (direct and indirect) that need to be initialized. SmallPtrSet FieldsToInit; - fieldsRequiringInit(ClassDecl->fields(), Context, FieldsToInit); + forEachField(ClassDecl, ClassDecl->fields(), false, [&](const FieldDecl *F) { + if (!F->hasInClassInitializer() && + utils::type_traits::isTriviallyDefaultConstructible(F->getType(), + Context)) + FieldsToInit.insert(F); + }); if (FieldsToInit.empty()) return; @@ -325,7 +323,7 @@ if (Init->isAnyMemberInitializer() && Init->isWritten()) { if (IsUnion) return; // We can only initialize one member of a union. - FieldsToInit.erase(Init->getMember()); + FieldsToInit.erase(Init->getAnyMember()); } } removeFieldsInitializedInBody(*Ctor->getBody(), Context, FieldsToInit); @@ -389,8 +387,8 @@ if (const auto *BaseClassDecl = getCanonicalRecordDecl(Base.getType())) { AllBases.emplace_back(BaseClassDecl); if (!BaseClassDecl->field_empty() && - utils::type_traits::isTriviallyDefaultConstructible( - Base.getType(), Context)) + utils::type_traits::isTriviallyDefaultConstructible(Base.getType(), + Context)) BasesToInit.insert(BaseClassDecl); } } Index: clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp +++ clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp @@ -103,3 +103,14 @@ int X; }; + +class PositiveIndirectMember { + struct { + int *A; + }; + + PositiveIndirectMember() : A() {} + PositiveIndirectMember(int) {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A + // CHECK-FIXES: PositiveIndirectMember(int) : A() {} +}; Index: clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp +++ clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp @@ -357,3 +357,13 @@ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these bases: NegativeAggregateType // CHECK-FIXES: PositiveSelfInitialization() : NegativeAggregateType(), PositiveSelfInitialization() {} }; + +class PositiveIndirectMember { + struct { + int *A; + // CHECK-FIXES: int *A{}; + }; + + PositiveIndirectMember() {} + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A +};