[clang-tools-extra] r312166 - [cppcoreguidelines] Don't rely on SmallPtrSet iteration order.

Benjamin Kramer via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 30 13:18:40 PDT 2017


Author: d0k
Date: Wed Aug 30 13:18:40 2017
New Revision: 312166

URL: http://llvm.org/viewvc/llvm-project?rev=312166&view=rev
Log:
[cppcoreguidelines] Don't rely on SmallPtrSet iteration order.

The fixit emission breaks if the iteration order changes and also missed
to emit fixits for some edge cases.

Modified:
    clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.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=312166&r1=312165&r2=312166&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp Wed Aug 30 13:18:40 2017
@@ -32,22 +32,16 @@ AST_MATCHER(CXXRecordDecl, hasDefaultCon
 }
 
 // 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.
+// if the record contains an anonmyous struct).
 template <typename T, typename Func>
-void forEachField(const RecordDecl &Record, const T &Fields,
-                  bool OneFieldPerUnion, Func &&Fn) {
+void forEachField(const RecordDecl &Record, const T &Fields, Func &&Fn) {
   for (const FieldDecl *F : Fields) {
     if (F->isAnonymousStructOrUnion()) {
       if (const CXXRecordDecl *R = F->getType()->getAsCXXRecordDecl())
-        forEachField(*R, R->fields(), OneFieldPerUnion, Fn);
+        forEachField(*R, R->fields(), Fn);
     } else {
       Fn(F);
     }
-
-    if (OneFieldPerUnion && Record.isUnion())
-      break;
   }
 }
 
@@ -227,7 +221,7 @@ void getInitializationsInOrder(const CXX
       Decls.emplace_back(Decl);
     }
   }
-  forEachField(ClassDecl, ClassDecl.fields(), false,
+  forEachField(ClassDecl, ClassDecl.fields(),
                [&](const FieldDecl *F) { Decls.push_back(F); });
 }
 
@@ -353,7 +347,7 @@ void ProTypeMemberInitCheck::checkMissin
 
   // Gather all fields (direct and indirect) that need to be initialized.
   SmallPtrSet<const FieldDecl *, 16> FieldsToInit;
-  forEachField(ClassDecl, ClassDecl.fields(), false, [&](const FieldDecl *F) {
+  forEachField(ClassDecl, ClassDecl.fields(), [&](const FieldDecl *F) {
     if (!F->hasInClassInitializer() &&
         utils::type_traits::isTriviallyDefaultConstructible(F->getType(),
                                                             Context) &&
@@ -379,12 +373,12 @@ void ProTypeMemberInitCheck::checkMissin
   // Collect all fields in order, both direct fields and indirect fields from
   // anonmyous record types.
   SmallVector<const FieldDecl *, 16> OrderedFields;
-  forEachField(ClassDecl, ClassDecl.fields(), false,
+  forEachField(ClassDecl, ClassDecl.fields(),
                [&](const FieldDecl *F) { OrderedFields.push_back(F); });
 
   // Collect all the fields we need to initialize, including indirect fields.
   SmallPtrSet<const FieldDecl *, 16> AllFieldsToInit;
-  forEachField(ClassDecl, FieldsToInit, false,
+  forEachField(ClassDecl, FieldsToInit,
                [&](const FieldDecl *F) { AllFieldsToInit.insert(F); });
   if (AllFieldsToInit.empty())
     return;
@@ -404,11 +398,16 @@ void ProTypeMemberInitCheck::checkMissin
   // 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<const FieldDecl *, 16> FieldsToFix;
-  forEachField(ClassDecl, FieldsToInit, true, [&](const FieldDecl *F) {
+  SmallPtrSet<const RecordDecl *, 4> UnionsSeen;
+  forEachField(ClassDecl, OrderedFields, [&](const FieldDecl *F) {
+    if (!FieldsToInit.count(F))
+      return;
     // Don't suggest fixes for enums because we don't know a good default.
     // Don't suggest fixes for bitfields because in-class initialization is not
     // possible.
-    if (!F->getType()->isEnumeralType() && !F->isBitField())
+    if (F->getType()->isEnumeralType() || F->isBitField())
+      return;
+    if (!F->getParent()->isUnion() || UnionsSeen.insert(F->getParent()).second)
       FieldsToFix.insert(F);
   });
   if (FieldsToFix.empty())

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=312166&r1=312165&r2=312166&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 Wed Aug 30 13:18:40 2017
@@ -312,6 +312,19 @@ union PositiveUnion {
   // CHECK-FIXES-NOT: float Y{};
 };
 
+union PositiveUnionReversed {
+  PositiveUnionReversed() : X() {} // No message as a union can only initialize one member.
+  PositiveUnionReversed(int) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: union constructor should initialize one of these fields: Y, X
+
+  // Make sure we don't give Y an initializer.
+  TestEnum Y;
+  // CHECK-FIXES-NOT: TestEnum Y{};
+
+  int X;
+  // CHECK-FIXES: int X{};
+};
+
 struct PositiveAnonymousUnionAndStruct {
   PositiveAnonymousUnionAndStruct() {}
   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: A, B, Y, Z, C, D, E, F, X




More information about the cfe-commits mailing list