[clang-tools-extra] r260873 - [clang-tidy] ClangTidy check to flag uninitialized builtin and pointer fields.

Felix Berger via cfe-commits cfe-commits at lists.llvm.org
Sun Feb 14 20:27:56 PST 2016


Author: flx
Date: Sun Feb 14 22:27:56 2016
New Revision: 260873

URL: http://llvm.org/viewvc/llvm-project?rev=260873&view=rev
Log:
[clang-tidy] ClangTidy check to flag uninitialized builtin and pointer fields.

Summary:
This patch is a continuation of http://reviews.llvm.org/D10553 by Jonathan B Coe.

The main additions are:

1. For C++11 the check suggests in-class field initialization as fix. This
makes the fields future proof towards the addition of new constructors.
2 For older language versions the fields are added in the right position
in the initializer list with more tests.
3. User documentation.

Reviewers: alexfh, jbcoe

Subscribers: cfe-commits

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

Added:
    clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
    clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
    clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst
    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/CMakeLists.txt
    clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
    clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst

Modified: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt?rev=260873&r1=260872&r2=260873&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt Sun Feb 14 22:27:56 2016
@@ -7,6 +7,7 @@ add_clang_library(clangTidyCppCoreGuidel
   ProBoundsPointerArithmeticCheck.cpp
   ProTypeConstCastCheck.cpp
   ProTypeCstyleCastCheck.cpp
+  ProTypeMemberInitCheck.cpp
   ProTypeReinterpretCastCheck.cpp
   ProTypeStaticCastDowncastCheck.cpp
   ProTypeUnionAccessCheck.cpp

Modified: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp?rev=260873&r1=260872&r2=260873&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp Sun Feb 14 22:27:56 2016
@@ -16,6 +16,7 @@
 #include "ProBoundsPointerArithmeticCheck.h"
 #include "ProTypeConstCastCheck.h"
 #include "ProTypeCstyleCastCheck.h"
+#include "ProTypeMemberInitCheck.h"
 #include "ProTypeReinterpretCastCheck.h"
 #include "ProTypeStaticCastDowncastCheck.h"
 #include "ProTypeUnionAccessCheck.h"
@@ -39,6 +40,8 @@ public:
         "cppcoreguidelines-pro-type-const-cast");
     CheckFactories.registerCheck<ProTypeCstyleCastCheck>(
         "cppcoreguidelines-pro-type-cstyle-cast");
+    CheckFactories.registerCheck<ProTypeMemberInitCheck>(
+        "cppcoreguidelines-pro-type-member-init");
     CheckFactories.registerCheck<ProTypeReinterpretCastCheck>(
         "cppcoreguidelines-pro-type-reinterpret-cast");
     CheckFactories.registerCheck<ProTypeStaticCastDowncastCheck>(

Added: 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=260873&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp Sun Feb 14 22:27:56 2016
@@ -0,0 +1,231 @@
+//===--- ProTypeMemberInitCheck.cpp - clang-tidy---------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProTypeMemberInitCheck.h"
+#include "../utils/LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+using namespace clang::ast_matchers;
+using llvm::SmallPtrSet;
+using llvm::SmallPtrSetImpl;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+namespace {
+
+AST_MATCHER(CXXConstructorDecl, isUserProvided) {
+  return Node.isUserProvided();
+}
+
+static void
+fieldsRequiringInit(const RecordDecl::field_range &Fields,
+                    SmallPtrSetImpl<const FieldDecl *> &FieldsToInit) {
+  for (const FieldDecl *F : Fields) {
+    QualType Type = F->getType();
+    if (Type->isPointerType() || Type->isBuiltinType())
+      FieldsToInit.insert(F);
+  }
+}
+
+void removeFieldsInitializedInBody(
+    const Stmt &Stmt, ASTContext &Context,
+    SmallPtrSetImpl<const FieldDecl *> &FieldDecls) {
+  auto Matches =
+      match(findAll(binaryOperator(
+                hasOperatorName("="),
+                hasLHS(memberExpr(member(fieldDecl().bind("fieldDecl")))))),
+            Stmt, Context);
+  for (const auto &Match : Matches)
+    FieldDecls.erase(Match.getNodeAs<FieldDecl>("fieldDecl"));
+}
+
+// Creates comma separated list of fields requiring initialization in order of
+// declaration.
+std::string toCommaSeparatedString(
+    const RecordDecl::field_range &FieldRange,
+    const SmallPtrSetImpl<const FieldDecl *> &FieldsRequiringInit) {
+  std::string List;
+  llvm::raw_string_ostream Stream(List);
+  size_t AddedFields = 0;
+  for (const FieldDecl *Field : FieldRange) {
+    if (FieldsRequiringInit.count(Field) > 0) {
+      Stream << Field->getName();
+      if (++AddedFields < FieldsRequiringInit.size())
+        Stream << ", ";
+    }
+  }
+  return Stream.str();
+}
+
+// Contains all fields in correct order that need to be inserted at the same
+// location for pre C++11.
+// There are 3 kinds of insertions:
+// 1. The fields are inserted after an existing CXXCtorInitializer stored in
+// InitializerBefore. This will be the case whenever there is a written
+// initializer before the fields available.
+// 2. The fields are inserted before the first existing initializer stored in
+// InitializerAfter.
+// 3. There are no written initializers and the fields will be inserted before
+// the constructor's body creating a new initializer list including the ':'.
+struct FieldsInsertion {
+  const CXXCtorInitializer *InitializerBefore;
+  const CXXCtorInitializer *InitializerAfter;
+  SmallVector<const FieldDecl *, 4> Fields;
+
+  SourceLocation getLocation(const ASTContext &Context,
+                             const CXXConstructorDecl &Constructor) const {
+    if (InitializerBefore != nullptr) {
+      return Lexer::getLocForEndOfToken(InitializerBefore->getRParenLoc(), 0,
+                                        Context.getSourceManager(),
+                                        Context.getLangOpts());
+    }
+    auto StartLocation = InitializerAfter != nullptr
+                             ? InitializerAfter->getSourceRange().getBegin()
+                             : Constructor.getBody()->getLocStart();
+    auto Token =
+        lexer_utils::getPreviousNonCommentToken(Context, StartLocation);
+    return Lexer::getLocForEndOfToken(Token.getLocation(), 0,
+                                      Context.getSourceManager(),
+                                      Context.getLangOpts());
+  }
+
+  std::string codeToInsert() const {
+    assert(!Fields.empty() && "No fields to insert");
+    std::string Code;
+    llvm::raw_string_ostream Stream(Code);
+    // Code will be inserted before the first written initializer after ':',
+    // append commas.
+    if (InitializerAfter != nullptr) {
+      for (const auto *Field : Fields)
+        Stream << " " << Field->getName() << "(),";
+    } else {
+      // The full initializer list is created, add extra space after
+      // constructor's rparens.
+      if (InitializerBefore == nullptr)
+        Stream << " ";
+      for (const auto *Field : Fields)
+        Stream << ", " << Field->getName() << "()";
+    }
+    Stream.flush();
+    // The initializer list is created, replace leading comma with colon.
+    if (InitializerBefore == nullptr && InitializerAfter == nullptr)
+      Code[1] = ':';
+    return Code;
+  }
+};
+
+SmallVector<FieldsInsertion, 16> computeInsertions(
+    const CXXConstructorDecl::init_const_range &Inits,
+    const RecordDecl::field_range &Fields,
+    const SmallPtrSetImpl<const FieldDecl *> &FieldsRequiringInit) {
+  // Find last written non-member initializer or null.
+  const CXXCtorInitializer *LastWrittenNonMemberInit = nullptr;
+  for (const CXXCtorInitializer *Init : Inits) {
+    if (Init->isWritten() && !Init->isMemberInitializer())
+      LastWrittenNonMemberInit = Init;
+  }
+  SmallVector<FieldsInsertion, 16> OrderedFields;
+  OrderedFields.push_back({LastWrittenNonMemberInit, nullptr, {}});
+
+  auto CurrentField = Fields.begin();
+  for (const CXXCtorInitializer *Init : Inits) {
+    if (Init->isWritten() && Init->isMemberInitializer()) {
+      const FieldDecl *MemberField = Init->getMember();
+      // Add all fields between current field and this member field the previous
+      // FieldsInsertion if the field requires initialization.
+      for (; CurrentField != Fields.end() && *CurrentField != MemberField;
+           ++CurrentField) {
+        if (FieldsRequiringInit.count(*CurrentField) > 0)
+          OrderedFields.back().Fields.push_back(*CurrentField);
+      }
+      // If this is the first written member initializer and there was no
+      // written non-member initializer set this initializer as
+      // InitializerAfter.
+      if (OrderedFields.size() == 1 &&
+          OrderedFields.back().InitializerBefore == nullptr)
+        OrderedFields.back().InitializerAfter = Init;
+      OrderedFields.push_back({Init, nullptr, {}});
+    }
+  }
+  // Add remaining fields that require initialization to last FieldsInsertion.
+  for (; CurrentField != Fields.end(); ++CurrentField) {
+    if (FieldsRequiringInit.count(*CurrentField) > 0)
+      OrderedFields.back().Fields.push_back(*CurrentField);
+  }
+  return OrderedFields;
+}
+
+} // namespace
+
+void ProTypeMemberInitCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(cxxConstructorDecl(isDefinition(), isUserProvided(),
+                                        unless(isInstantiated()))
+                         .bind("ctor"),
+                     this);
+}
+
+void ProTypeMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
+  const auto &MemberFields = Ctor->getParent()->fields();
+
+  SmallPtrSet<const FieldDecl *, 16> FieldsToInit;
+  fieldsRequiringInit(MemberFields, FieldsToInit);
+  if (FieldsToInit.empty())
+    return;
+
+  for (CXXCtorInitializer *Init : Ctor->inits()) {
+    // Return early if this constructor simply delegates to another constructor
+    // in the same class.
+    if (Init->isDelegatingInitializer())
+      return;
+    if (!Init->isMemberInitializer())
+      continue;
+    FieldsToInit.erase(Init->getMember());
+  }
+  removeFieldsInitializedInBody(*Ctor->getBody(), *Result.Context,
+                                FieldsToInit);
+  if (FieldsToInit.empty())
+    return;
+
+  DiagnosticBuilder Diag =
+      diag(Ctor->getLocStart(),
+           "constructor does not initialize these built-in/pointer fields: %0")
+      << toCommaSeparatedString(MemberFields, FieldsToInit);
+  // Do not propose fixes in macros since we cannot place them correctly.
+  if (Ctor->getLocStart().isMacroID())
+    return;
+  // For C+11 use in-class initialization which covers all future constructors
+  // as well.
+  if (Result.Context->getLangOpts().CPlusPlus11) {
+    for (const auto *Field : FieldsToInit) {
+      Diag << FixItHint::CreateInsertion(
+          Lexer::getLocForEndOfToken(Field->getSourceRange().getEnd(), 0,
+                                     Result.Context->getSourceManager(),
+                                     Result.Context->getLangOpts()),
+          "{}");
+    }
+    return;
+  }
+  for (const auto &FieldsInsertion :
+       computeInsertions(Ctor->inits(), MemberFields, FieldsToInit)) {
+    if (!FieldsInsertion.Fields.empty())
+      Diag << FixItHint::CreateInsertion(
+          FieldsInsertion.getLocation(*Result.Context, *Ctor),
+          FieldsInsertion.codeToInsert());
+  }
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang

Added: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h?rev=260873&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.h Sun Feb 14 22:27:56 2016
@@ -0,0 +1,43 @@
+//===--- ProTypeMemberInitCheck.h - clang-tidy-------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_MEMBER_INIT_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_MEMBER_INIT_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// \brief Checks that builtin or pointer fields are initialized by
+/// user-defined constructors.
+///
+/// Members initialized through function calls in the body of the constructor
+/// will result in false positives.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.html
+/// TODO: See if 'fixes' for false positives are optimized away by the compiler.
+/// TODO: "Issue a diagnostic when constructing an object of a trivially
+/// constructible type without () or {} to initialize its members. To fix: Add
+/// () or {}."
+class ProTypeMemberInitCheck : public ClangTidyCheck {
+public:
+  ProTypeMemberInitCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_PRO_TYPE_MEMBER_INIT_H

Added: clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst?rev=260873&view=auto
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst (added)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-pro-type-member-init.rst Sun Feb 14 22:27:56 2016
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - cppcoreguidelines-pro-type-member-init
+
+cppcoreguidelines-pro-type-member-init
+======================================
+
+The check flags user-defined constructor definitions that do not initialize all
+builtin and pointer fields which leaves their memory in an undefined state.
+
+For C++11 it suggests fixes to add in-class field initializers. For older
+versions it inserts the field initializers into the constructor initializer
+list.
+
+The check takes assignment of fields in the constructor body into account but
+generates false positives for fields initialized in methods invoked in the
+constructor body.
+
+This rule is part of the "Type safety" profile of the C++ Core Guidelines, see
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Pro-type-memberinit.

Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst?rev=260873&r1=260872&r2=260873&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst (original)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst Sun Feb 14 22:27:56 2016
@@ -19,6 +19,7 @@ Clang-Tidy Checks
    cppcoreguidelines-pro-bounds-pointer-arithmetic
    cppcoreguidelines-pro-type-const-cast
    cppcoreguidelines-pro-type-cstyle-cast
+   cppcoreguidelines-pro-type-member-init
    cppcoreguidelines-pro-type-reinterpret-cast
    cppcoreguidelines-pro-type-static-cast-downcast
    cppcoreguidelines-pro-type-union-access

Added: 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=260873&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init-cxx98.cpp Sun Feb 14 22:27:56 2016
@@ -0,0 +1,67 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t -- -- -std=c++98
+
+struct PositiveFieldBeforeConstructor {
+  int F;
+  PositiveFieldBeforeConstructor() /* some comment */ {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F
+  // CHECK-FIXES: PositiveFieldBeforeConstructor() : F() /* some comment */ {}
+};
+
+struct PositiveFieldAfterConstructor {
+  PositiveFieldAfterConstructor() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F, G, H
+  // CHECK-FIXES: PositiveFieldAfterConstructor() : F(), G(), H() {}
+  int F;
+  bool G /* with comment */;
+  int *H;
+  PositiveFieldBeforeConstructor IgnoredField;
+};
+
+struct PositiveSeparateDefinition {
+  PositiveSeparateDefinition();
+  int F;
+};
+
+PositiveSeparateDefinition::PositiveSeparateDefinition() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: F
+// CHECK-FIXES: PositiveSeparateDefinition::PositiveSeparateDefinition() : F() {}
+
+struct PositiveMixedFieldOrder {
+  PositiveMixedFieldOrder() : /* some comment */ J(0), L(0), M(0) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: I, K, N
+  // CHECK-FIXES: PositiveMixedFieldOrder() : I(), /* some comment */ J(0), K(), L(0), M(0), N() {}
+  int I;
+  int J;
+  int K;
+  int L;
+  int M;
+  int N;
+};
+
+struct PositiveAfterBaseInitializer : public PositiveMixedFieldOrder {
+  PositiveAfterBaseInitializer() : PositiveMixedFieldOrder() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F
+  // CHECK-FIXES: PositiveAfterBaseInitializer() : PositiveMixedFieldOrder(), F() {}
+  int F;
+};
+
+struct NegativeFieldInitialized {
+  int F;
+
+  NegativeFieldInitialized() : F() {}
+};
+
+struct NegativeFieldInitializedInDefinition {
+  int F;
+
+  NegativeFieldInitializedInDefinition();
+};
+
+NegativeFieldInitializedInDefinition::NegativeFieldInitializedInDefinition() : F() {}
+
+struct NegativeInitializedInBody {
+  NegativeInitializedInBody() { I = 0; }
+  int I;
+};
+
+

Added: 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=260873&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-pro-type-member-init.cpp Sun Feb 14 22:27:56 2016
@@ -0,0 +1,111 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-member-init %t
+
+struct PositiveFieldBeforeConstructor {
+  int F;
+  // CHECK-FIXES: int F{};
+  PositiveFieldBeforeConstructor() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F
+  // CHECK-FIXES: PositiveFieldBeforeConstructor() {}
+};
+
+struct PositiveFieldAfterConstructor {
+  PositiveFieldAfterConstructor() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F, G
+  // CHECK-FIXES: PositiveFieldAfterConstructor() {}
+  int F;
+  // CHECK-FIXES: int F{};
+  bool G /* with comment */;
+  // CHECK-FIXES: bool G{} /* with comment */;
+  PositiveFieldBeforeConstructor IgnoredField;
+};
+
+struct PositiveSeparateDefinition {
+  PositiveSeparateDefinition();
+  int F;
+  // CHECK-FIXES: int F{};
+};
+
+PositiveSeparateDefinition::PositiveSeparateDefinition() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: F
+// CHECK-FIXES: PositiveSeparateDefinition::PositiveSeparateDefinition() {}
+
+struct PositiveMixedFieldOrder {
+  PositiveMixedFieldOrder() : J(0) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: I, K
+  // CHECK-FIXES: PositiveMixedFieldOrder() : J(0) {}
+  int I;
+  // CHECK-FIXES: int I{};
+  int J;
+  int K;
+  // CHECK-FIXES: int K{};
+};
+
+template <typename T>
+struct Template {
+  Template() {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these built-in/pointer fields: F
+  int F;
+  // CHECK-FIXES: int F{};
+  T T1;
+  // CHECK-FIXES: T T1;
+};
+
+void instantiate() {
+  Template<int> TInt;
+}
+
+struct NegativeFieldInitialized {
+  int F;
+
+  NegativeFieldInitialized() : F() {}
+};
+
+struct NegativeFieldInitializedInDefinition {
+  int F;
+
+  NegativeFieldInitializedInDefinition();
+};
+NegativeFieldInitializedInDefinition::NegativeFieldInitializedInDefinition() : F() {}
+
+
+struct NegativeInClassInitialized {
+  int F = 0;
+
+  NegativeInClassInitialized() {}
+};
+
+struct NegativeConstructorDelegated {
+  int F;
+
+  NegativeConstructorDelegated(int F) : F(F) {}
+  NegativeConstructorDelegated() : NegativeConstructorDelegated(0) {}
+};
+
+struct NegativeInitializedInBody {
+  NegativeInitializedInBody() { I = 0; }
+  int I;
+};
+
+#define UNINITIALIZED_FIELD_IN_MACRO_BODY(FIELD) \
+  struct UninitializedField##FIELD {		 \
+    UninitializedField##FIELD() {}		 \
+    int FIELD;					 \
+  };						 \
+// Ensure FIELD is not initialized since fixes inside of macros are disabled.
+// CHECK-FIXES: int FIELD;
+
+UNINITIALIZED_FIELD_IN_MACRO_BODY(F);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: F
+UNINITIALIZED_FIELD_IN_MACRO_BODY(G);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: constructor does not initialize these built-in/pointer fields: G
+
+#define UNINITIALIZED_FIELD_IN_MACRO_ARGUMENT(ARGUMENT) \
+  ARGUMENT						\
+
+UNINITIALIZED_FIELD_IN_MACRO_ARGUMENT(struct UninitializedFieldInMacroArg {
+  UninitializedFieldInMacroArg() {}
+  int Field;
+});
+// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: constructor does not initialize these built-in/pointer fields: Field
+// Ensure FIELD is not initialized since fixes inside of macros are disabled.
+// CHECK-FIXES: int Field;




More information about the cfe-commits mailing list