[clang-tools-extra] r269024 - Fixed cppcoreguidelines-pro-type-member-init when checking records with indirect fields

Haojian Wu via cfe-commits cfe-commits at lists.llvm.org
Tue May 10 00:42:20 PDT 2016


Author: hokein
Date: Tue May 10 02:42:19 2016
New Revision: 269024

URL: http://llvm.org/viewvc/llvm-project?rev=269024&view=rev
Log:
Fixed cppcoreguidelines-pro-type-member-init when checking records with indirect fields

Summary:
Fixed a crash in cppcoreguidelines-pro-type-member-init when checking record types with indirect fields pre-C++11.
Fixed handling of indirect fields so they are properly checked and suggested fixes are proposed.

Patch by Michael Miller!

Reviewers: aaron.ballman, alexfh, hokein

Subscribers: cfe-commits

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

Modified:
    clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.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.cpp

Modified: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp?rev=269024&r1=269023&r2=269024&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp Tue May 10 02:42:19 2016
@@ -27,16 +27,23 @@ namespace cppcoreguidelines {
 
 namespace {
 
-void fieldsRequiringInit(const RecordDecl::field_range &Fields,
-                         ASTContext &Context,
-                         SmallPtrSetImpl<const FieldDecl *> &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 <typename T, typename Func>
+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 @@ computeInsertions(const CXXConstructorDe
       // Gets either the field or base class being initialized by the provided
       // initializer.
       const auto *InitDecl =
-          Init->isMemberInitializer()
-              ? static_cast<const NamedDecl *>(Init->getMember())
+          Init->isAnyMemberInitializer()
+              ? static_cast<const NamedDecl *>(Init->getAnyMember())
               : Init->getBaseClass()->getAsCXXRecordDecl();
 
       // Add all fields between current field up until the next intializer.
@@ -216,7 +223,8 @@ void getInitializationsInOrder(const CXX
       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 <typename T>
@@ -238,22 +246,6 @@ void fixInitializerList(const ASTContext
   }
 }
 
-template <typename T, typename Func>
-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 @@ void ProTypeMemberInitCheck::checkMissin
   if (IsUnion && ClassDecl->hasInClassInitializer())
     return;
 
+  // Gather all fields (direct and indirect) that need to be initialized.
   SmallPtrSet<const FieldDecl *, 16> 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 @@ void ProTypeMemberInitCheck::checkMissin
     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 @@ void ProTypeMemberInitCheck::checkMissin
     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);
     }
   }

Modified: clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp?rev=269024&r1=269023&r2=269024&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp (original)
+++ clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp Tue May 10 02:42:19 2016
@@ -103,3 +103,14 @@ public:
 
   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() {}
+};

Modified: clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp?rev=269024&r1=269023&r2=269024&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp (original)
+++ clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp Tue May 10 02:42:19 2016
@@ -357,3 +357,13 @@ class PositiveSelfInitialization : Negat
   // 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
+};




More information about the cfe-commits mailing list