[PATCH] D16517: ClangTidy check to flag uninitialized builtin and pointer fields.

Alexander Kornienko via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 5 05:28:16 PST 2016


alexfh added a comment.

In http://reviews.llvm.org/D16517#336157, @flx wrote:

> In http://reviews.llvm.org/D16517#336148, @alexfh wrote:
>
> > A high-level comment: I think, this comment <http://reviews.llvm.org/D10553#267535> still applies. I'm also slightly concerned about having this check in misc-, since the check isn't universally applicable (e.g. based on a couple of discussions, I guess LLVM community would likely not welcome this rule), but I'd like to leave misc- enabled by default. So moving the check to cppcoreguidelines- makes sense to me.
> >
> > More substantial comments later.
>
>
> Sounds good to me. If I'm reading the original comment correctly what's missing would be this part:
>
> "Issue a diagnostic when constructing an object of a trivially constructible type without () or {} to initialize its members. To fix: Add () or {}. "


Yes. I think, we might want to either add a separate check for this or make this part configurable. Adding a FIXME for now would be enough.

> Please let me know if that changes the name of the check and whether the next step should be moving the check or we'll do that after a detailed review of the specifics.


I'd call the check `cppcoreguidelines-pro-type-memberinit` to be consistent with the anchor name of this rule used in the CppCoreGuidelines document (https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Pro-type-memberinit). These anchor names are usually short enough, but still quite descriptive, so it makes sense to use them when there are no significantly better alternatives.


================
Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:29
@@ +28,3 @@
+    const Stmt &Stmt, ASTContext &Context,
+    std::unordered_set<const FieldDecl *> &FieldDecls) {
+  auto Matches =
----------------
Once you switch to `SmallPtrSet`, this should be changed to `SmallPtrSetImpl&`.

================
Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:104
@@ +103,3 @@
+    }
+    Code = Stream.str();
+    // The initializer list is created, replace leading comma with colon.
----------------
That's a self-assignment, basically. Just use `Stream.flush()` or put the `Stream` definition into a nested scope.

================
Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:106
@@ +105,3 @@
+    // The initializer list is created, replace leading comma with colon.
+    if (InitializerBefore == nullptr && InitializerAfter == nullptr) {
+      Code[1] = ':';
----------------
nit: No braces around single-line `if/for` bodies.

================
Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:123
@@ +122,3 @@
+  }
+  std::vector<FieldsInsertion> OrderedFields;
+  OrderedFields.push_back({LastWrittenNonMemberInit, nullptr, {}});
----------------
`SmallVector`?

================
Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:124
@@ +123,3 @@
+  std::vector<FieldsInsertion> OrderedFields;
+  OrderedFields.push_back({LastWrittenNonMemberInit, nullptr, {}});
+
----------------
`.emplace_back(...)`?

================
Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:163
@@ +162,3 @@
+  const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
+  if (!Ctor->isUserProvided())
+    return;
----------------
I'd make a local matcher for this and push this check to the matcher.

================
Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:169
@@ +168,3 @@
+
+  std::unordered_set<const FieldDecl *> FieldsToInit;
+  std::copy_if(MemberFields.begin(), MemberFields.end(),
----------------
This should probably use SmallPtrSet.

================
Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:170
@@ +169,3 @@
+  std::unordered_set<const FieldDecl *> FieldsToInit;
+  std::copy_if(MemberFields.begin(), MemberFields.end(),
+               std::inserter(FieldsToInit, FieldsToInit.end()),
----------------
Consider this as a simpler alternative with fewer dependencies:

  for (const auto &Field : ParentClass->fields()) {
    if (fieldRequiresInit(Field))
      FieldsToInit.insert(Field);
  }

Also, might be reasonable to expand the `fieldRequiresInit` function:

  for (const auto &Field : ParentClass->fields()) {
    if (Field->getType()->isPointerType() || Field->getType()->isBuiltinType())
      FieldsToInit.insert(Field);
  }


================
Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:177
@@ +176,3 @@
+  for (CXXCtorInitializer *Init : Ctor->inits()) {
+    if (Init->isDelegatingInitializer())
+      return;
----------------
I think, this is superfluous. `isMemberInitializer()` should be enough.

================
Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:181
@@ +180,3 @@
+      continue;
+    const FieldDecl *MemberField = Init->getMember();
+    FieldsToInit.erase(MemberField);
----------------
The variable does not make code cleaner, please remove it.

================
Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:199
@@ +198,3 @@
+
+    for (const auto *Field : FieldsToInit)
+      Builder << FixItHint::CreateInsertion(
----------------
nit: We don't use braces only for single-line `if/for` bodies. Same below.

================
Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:207
@@ +206,3 @@
+
+  DiagnosticBuilder Builder =
+      diag(Ctor->getLocStart(),
----------------
s/Builder/Diag/, which is more common in this code.

================
Comment at: clang-tidy/misc/UninitializedFieldCheck.cpp:208
@@ +207,3 @@
+  DiagnosticBuilder Builder =
+      diag(Ctor->getLocStart(),
+           "constructor does not initialize these built-in/pointer fields: %0")
----------------
No need to duplicate this code. Only the insertion of fixes should be conditional.

================
Comment at: test/clang-tidy/misc-uninitialized-field.cpp:1
@@ +1,2 @@
+// RUN: %check_clang_tidy %s misc-uninitialized-field %t
+
----------------
As usual: tests with templates and macros, please ;)

================
Comment at: test/clang-tidy/misc-uninitialized-field.cpp:6
@@ +5,3 @@
+  // CHECK-FIXES: int F{};
+  PositiveFieldBeforeConstructor() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F
----------------
Also check that the constructor is left intact?


http://reviews.llvm.org/D16517





More information about the cfe-commits mailing list