Skip to content

Commit 43ed897

Browse files
zeyi2EugeneZelenko
authored andcommitted
[clang-tidy] Fix cppcoreguidelines-pro-type-member-init check (llvm#169832)
Closes [llvm#169677](llvm#169677) --------- Co-authored-by: EugeneZelenko <[email protected]>
1 parent d8298d1 commit 43ed897

File tree

3 files changed

+74
-14
lines changed

3 files changed

+74
-14
lines changed

clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,8 @@ void ProTypeMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
361361
}
362362

363363
// FIXME: Copied from clang/lib/Sema/SemaDeclCXX.cpp.
364-
static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) {
364+
static bool isIncompleteOrZeroLengthArrayType(const ASTContext &Context,
365+
QualType T) {
365366
if (T->isIncompleteArrayType())
366367
return true;
367368

@@ -375,7 +376,7 @@ static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) {
375376
return false;
376377
}
377378

378-
static bool isEmpty(ASTContext &Context, const QualType &Type) {
379+
static bool isEmpty(const ASTContext &Context, const QualType &Type) {
379380
if (const CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl()) {
380381
return ClassDecl->isEmpty();
381382
}
@@ -431,19 +432,13 @@ static llvm::StringLiteral getInitializer(QualType QT, bool UseAssignment) {
431432
}
432433
}
433434

434-
void ProTypeMemberInitCheck::checkMissingMemberInitializer(
435-
ASTContext &Context, const CXXRecordDecl &ClassDecl,
436-
const CXXConstructorDecl *Ctor) {
437-
const bool IsUnion = ClassDecl.isUnion();
438-
439-
if (IsUnion && ClassDecl.hasInClassInitializer())
440-
return;
441-
442-
// Gather all fields (direct and indirect) that need to be initialized.
443-
SmallPtrSet<const FieldDecl *, 16> FieldsToInit;
435+
static void
436+
computeFieldsToInit(const ASTContext &Context, const RecordDecl &Record,
437+
bool IgnoreArrays,
438+
SmallPtrSetImpl<const FieldDecl *> &FieldsToInit) {
444439
bool AnyMemberHasInitPerUnion = false;
445440
forEachFieldWithFilter(
446-
ClassDecl, ClassDecl.fields(), AnyMemberHasInitPerUnion,
441+
Record, Record.fields(), AnyMemberHasInitPerUnion,
447442
[&](const FieldDecl *F) {
448443
if (IgnoreArrays && F->getType()->isArrayType())
449444
return;
@@ -458,6 +453,19 @@ void ProTypeMemberInitCheck::checkMissingMemberInitializer(
458453
!AnyMemberHasInitPerUnion)
459454
FieldsToInit.insert(F);
460455
});
456+
}
457+
458+
void ProTypeMemberInitCheck::checkMissingMemberInitializer(
459+
ASTContext &Context, const CXXRecordDecl &ClassDecl,
460+
const CXXConstructorDecl *Ctor) {
461+
const bool IsUnion = ClassDecl.isUnion();
462+
463+
if (IsUnion && ClassDecl.hasInClassInitializer())
464+
return;
465+
466+
// Gather all fields (direct and indirect) that need to be initialized.
467+
SmallPtrSet<const FieldDecl *, 16> FieldsToInit;
468+
computeFieldsToInit(Context, ClassDecl, IgnoreArrays, FieldsToInit);
461469
if (FieldsToInit.empty())
462470
return;
463471

@@ -507,7 +515,7 @@ void ProTypeMemberInitCheck::checkMissingMemberInitializer(
507515
// Collect all fields but only suggest a fix for the first member of unions,
508516
// as initializing more than one union member is an error.
509517
SmallPtrSet<const FieldDecl *, 16> FieldsToFix;
510-
AnyMemberHasInitPerUnion = false;
518+
bool AnyMemberHasInitPerUnion = false;
511519
forEachFieldWithFilter(ClassDecl, ClassDecl.fields(),
512520
AnyMemberHasInitPerUnion, [&](const FieldDecl *F) {
513521
if (!FieldsToInit.contains(F))
@@ -582,6 +590,17 @@ void ProTypeMemberInitCheck::checkMissingBaseClassInitializer(
582590

583591
void ProTypeMemberInitCheck::checkUninitializedTrivialType(
584592
const ASTContext &Context, const VarDecl *Var) {
593+
// Verify that the record actually needs initialization
594+
const CXXRecordDecl *Record = Var->getType()->getAsCXXRecordDecl();
595+
if (!Record)
596+
return;
597+
598+
SmallPtrSet<const FieldDecl *, 16> FieldsToInit;
599+
computeFieldsToInit(Context, *Record, IgnoreArrays, FieldsToInit);
600+
601+
if (FieldsToInit.empty())
602+
return;
603+
585604
const DiagnosticBuilder Diag =
586605
diag(Var->getBeginLoc(), "uninitialized record type: %0") << Var;
587606

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,11 @@ Changes in existing checks
424424
adding an option to allow pointer arithmetic via prefix/postfix increment or
425425
decrement operators.
426426

427+
- Improved :doc:`cppcoreguidelines-pro-type-member-init
428+
<clang-tidy/checks/cppcoreguidelines/pro-type-member-init>` check to
429+
correctly ignore ``std::array`` and other array-like containers when
430+
`IgnoreArrays` option is set to `true`.
431+
427432
- Improved :doc:`google-readability-casting
428433
<clang-tidy/checks/google/readability-casting>` check by adding fix-it
429434
notes for downcasts and casts to void pointer.

clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.ignorearrays.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,39 @@ struct HasArrayMember {
1414
int RawArray[4];
1515
int Number;
1616
};
17+
18+
namespace std {
19+
template <typename T, int N>
20+
struct array {
21+
T _Elems[N];
22+
void fill(const T &);
23+
};
24+
}
25+
26+
void test_local_std_array() {
27+
std::array<int, 4> a;
28+
}
29+
30+
struct OnlyArray {
31+
int a[4];
32+
};
33+
34+
void test_local_only_array() {
35+
OnlyArray a;
36+
}
37+
38+
struct Mixed {
39+
int a[4];
40+
int b;
41+
};
42+
43+
void test_local_mixed() {
44+
Mixed m;
45+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: uninitialized record type: 'm'
46+
}
47+
48+
void test_std_array_fill() {
49+
std::array<char, 10> someArray;
50+
// CHECK-MESSAGES-NOT: warning: uninitialized record type: 'someArray'
51+
someArray.fill('n');
52+
}

0 commit comments

Comments
 (0)