diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp index 66508da89f0dd..f2676468b6871 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp @@ -361,7 +361,8 @@ void ProTypeMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { } // FIXME: Copied from clang/lib/Sema/SemaDeclCXX.cpp. -static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) { +static bool isIncompleteOrZeroLengthArrayType(const ASTContext &Context, + QualType T) { if (T->isIncompleteArrayType()) return true; @@ -375,7 +376,7 @@ static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) { return false; } -static bool isEmpty(ASTContext &Context, const QualType &Type) { +static bool isEmpty(const ASTContext &Context, const QualType &Type) { if (const CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl()) { return ClassDecl->isEmpty(); } @@ -431,19 +432,13 @@ static llvm::StringLiteral getInitializer(QualType QT, bool UseAssignment) { } } -void ProTypeMemberInitCheck::checkMissingMemberInitializer( - ASTContext &Context, const CXXRecordDecl &ClassDecl, - const CXXConstructorDecl *Ctor) { - const bool IsUnion = ClassDecl.isUnion(); - - if (IsUnion && ClassDecl.hasInClassInitializer()) - return; - - // Gather all fields (direct and indirect) that need to be initialized. - SmallPtrSet FieldsToInit; +static void +computeFieldsToInit(const ASTContext &Context, const RecordDecl &Record, + bool IgnoreArrays, + SmallPtrSetImpl &FieldsToInit) { bool AnyMemberHasInitPerUnion = false; forEachFieldWithFilter( - ClassDecl, ClassDecl.fields(), AnyMemberHasInitPerUnion, + Record, Record.fields(), AnyMemberHasInitPerUnion, [&](const FieldDecl *F) { if (IgnoreArrays && F->getType()->isArrayType()) return; @@ -458,6 +453,19 @@ void ProTypeMemberInitCheck::checkMissingMemberInitializer( !AnyMemberHasInitPerUnion) FieldsToInit.insert(F); }); +} + +void ProTypeMemberInitCheck::checkMissingMemberInitializer( + ASTContext &Context, const CXXRecordDecl &ClassDecl, + const CXXConstructorDecl *Ctor) { + const bool IsUnion = ClassDecl.isUnion(); + + if (IsUnion && ClassDecl.hasInClassInitializer()) + return; + + // Gather all fields (direct and indirect) that need to be initialized. + SmallPtrSet FieldsToInit; + computeFieldsToInit(Context, ClassDecl, IgnoreArrays, FieldsToInit); if (FieldsToInit.empty()) return; @@ -507,7 +515,7 @@ void ProTypeMemberInitCheck::checkMissingMemberInitializer( // Collect all fields but only suggest a fix for the first member of unions, // as initializing more than one union member is an error. SmallPtrSet FieldsToFix; - AnyMemberHasInitPerUnion = false; + bool AnyMemberHasInitPerUnion = false; forEachFieldWithFilter(ClassDecl, ClassDecl.fields(), AnyMemberHasInitPerUnion, [&](const FieldDecl *F) { if (!FieldsToInit.contains(F)) @@ -582,6 +590,17 @@ void ProTypeMemberInitCheck::checkMissingBaseClassInitializer( void ProTypeMemberInitCheck::checkUninitializedTrivialType( const ASTContext &Context, const VarDecl *Var) { + // Verify that the record actually needs initialization + const CXXRecordDecl *Record = Var->getType()->getAsCXXRecordDecl(); + if (!Record) + return; + + SmallPtrSet FieldsToInit; + computeFieldsToInit(Context, *Record, IgnoreArrays, FieldsToInit); + + if (FieldsToInit.empty()) + return; + const DiagnosticBuilder Diag = diag(Var->getBeginLoc(), "uninitialized record type: %0") << Var; diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index a6f80e3721db1..27c47f3790ab4 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -424,6 +424,11 @@ Changes in existing checks adding an option to allow pointer arithmetic via prefix/postfix increment or decrement operators. +- Improved :doc:`cppcoreguidelines-pro-type-member-init + ` check to + correctly ignore ``std::array`` and other array-like containers when + `IgnoreArrays` option is set to `true`. + - Improved :doc:`google-readability-casting ` check by adding fix-it notes for downcasts and casts to void pointer. diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.ignorearrays.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.ignorearrays.cpp index 01859b3ad98f4..e4cfe679cfce9 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.ignorearrays.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.ignorearrays.cpp @@ -14,3 +14,39 @@ struct HasArrayMember { int RawArray[4]; int Number; }; + +namespace std { +template +struct array { + T _Elems[N]; + void fill(const T &); +}; +} + +void test_local_std_array() { + std::array a; +} + +struct OnlyArray { + int a[4]; +}; + +void test_local_only_array() { + OnlyArray a; +} + +struct Mixed { + int a[4]; + int b; +}; + +void test_local_mixed() { + Mixed m; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: uninitialized record type: 'm' +} + +void test_std_array_fill() { + std::array someArray; + // CHECK-MESSAGES-NOT: warning: uninitialized record type: 'someArray' + someArray.fill('n'); +}