[PATCH] D35972: Add warning to clang-reorder-fields when reordering breaks member init list dependencies

2017-07-29 Thread Sam Conrad via Phabricator via cfe-commits
sameconrad added a comment.

In https://reviews.llvm.org/D35972#825348, @alexshap wrote:

> LGTM, thanks! 
>  do you have commit access ? (if not i can commit this patch for you)


I don't have commit access, so you will have to commit it.
Thank you


https://reviews.llvm.org/D35972



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35972: Add warning to clang-reorder-fields when reordering breaks member init list dependencies

2017-07-29 Thread Sam Conrad via Phabricator via cfe-commits
sameconrad added inline comments.



Comment at: clang-reorder-fields/ReorderFieldsAction.cpp:178
   for (const auto *Initializer : CtorDecl->inits()) {
-if (!Initializer->isWritten())
+if (!Initializer->isMemberInitializer() || !Initializer->isWritten())
   continue;

While adding tests for emitting warnings about base class members I found 
another bug here- non-member initializers don't have a field decl and so would 
result in undefind behavior further down when accessing field indexes (I added 
the test case ClassDerived which would cause a segfault before this change).



Comment at: clang-reorder-fields/ReorderFieldsAction.cpp:111
+Results.insert(FD);
+  return Results;
+}

compnerd wrote:
> What if the `FieldDecl` belongs to a base class?  Can you add a test case for 
> that scenario?
I've added tests for this scenario and an explanatory comment.  It doesn't seem 
this is actually a problem due to the way Clang constructs the AST.  
Sema::PerformObjectMemberConversion always inserts an implicit 
UncheckedDerivedToBase cast when accessing a base class member which means that 
hasObjectExpression(cxxThisExpr()) won't actually match against such an 
expression. 



Comment at: test/clang-reorder-fields/FieldDependencyWarning.cpp:3
+
+#include 
+

alexshap wrote:
> tests should not depend on STL (for good examples see how things are done in 
> clang-tidy tests), so simply remove this include and define a small class 
> with a constructor right here 
This has been updated to use a simple struct.


https://reviews.llvm.org/D35972



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D35972: Add warning to clang-reorder-fields when reordering breaks member init list dependencies

2017-07-29 Thread Sam Conrad via Phabricator via cfe-commits
sameconrad updated this revision to Diff 108812.
sameconrad added a comment.

Add additional tests for cases with base and derived classes.
Add clarifying comments about emitting warnings for base class members during 
reordering checks.
Add fix for bug where reordering in init lists that contain non-member 
initializers causes segfault.


https://reviews.llvm.org/D35972

Files:
  clang-reorder-fields/ReorderFieldsAction.cpp
  test/clang-reorder-fields/ClassDerived.cpp
  test/clang-reorder-fields/FieldDependencyWarning.cpp
  test/clang-reorder-fields/FieldDependencyWarningDerived.cpp

Index: test/clang-reorder-fields/FieldDependencyWarningDerived.cpp
===
--- test/clang-reorder-fields/FieldDependencyWarningDerived.cpp
+++ test/clang-reorder-fields/FieldDependencyWarningDerived.cpp
@@ -0,0 +1,34 @@
+// RUN: clang-reorder-fields -record-name bar::Derived -fields-order z,y %s -- 2>&1 | FileCheck %s
+
+namespace bar {
+struct Base {
+  int x;
+  int p;
+};
+
+
+class Derived : public Base {
+public:
+  Derived(long ny);
+  Derived(char nz);
+private:
+  long y;
+  char z;
+};
+
+Derived::Derived(long ny) : 
+Base(),
+y(ny), 
+z(static_cast(y)) // CHECK: [[@LINE]]: Warning: reordering field y after z makes y uninitialized when used in init expression
+{}
+
+Derived::Derived(char nz) : 
+Base(),
+y(nz),
+// Check that base class fields are correctly ignored in reordering checks
+// x has field index 1 and so would improperly warn if this wasn't the case since the command for this file swaps field indexes 1 and 2
+z(x) // CHECK-NOT: [[@LINE]]: Warning: reordering field x after z makes x uninitialized when used in init expression
+
+{}
+
+} // namespace bar
Index: test/clang-reorder-fields/FieldDependencyWarning.cpp
===
--- test/clang-reorder-fields/FieldDependencyWarning.cpp
+++ test/clang-reorder-fields/FieldDependencyWarning.cpp
@@ -0,0 +1,49 @@
+// RUN: clang-reorder-fields -record-name bar::Foo -fields-order y,z,c,x %s -- 2>&1 | FileCheck %s
+
+namespace bar {
+
+struct Dummy {
+  Dummy(int x, char c) : x(x), c(c) {}
+  int x;
+  char c;
+};
+
+class Foo {
+public:
+  Foo(int x, double y, char cin);
+  Foo(int nx);
+  Foo();
+  int x;
+  double y;
+  char c;
+  Dummy z;
+};
+
+static char bar(char c) {
+  return c + 1;
+}
+
+Foo::Foo() : x(), y(), c(), z(0, 'a') {}
+
+Foo::Foo(int x, double y, char cin) :  
+  x(x), 
+  y(y), 
+  c(cin),   
+  z(this->x, bar(c))// CHECK:  [[@LINE]]: Warning: reordering field x after z makes x uninitialized when used in init expression
+// CHECK-NEXT: [[@LINE-1]]: Warning: reordering field c after z makes c uninitialized when used in init expression
+{}
+
+Foo::Foo(int nx) :
+  x(nx),  
+  y(x), // CHECK-NEXT: [[@LINE]]: Warning: reordering field x after y makes x uninitialized when used in init expression
+  c(0),   
+  z(bar(bar(x)), c) // CHECK-NEXT: [[@LINE]]: Warning: reordering field x after z makes x uninitialized when used in init expression
+// CHECK-NEXT: [[@LINE-1]]: Warning: reordering field c after z makes c uninitialized when used in init expression
+{}
+
+} // namespace bar
+
+int main() {
+  bar::Foo F(5, 12.8, 'c');
+  return 0;
+}
Index: test/clang-reorder-fields/ClassDerived.cpp
===
--- test/clang-reorder-fields/ClassDerived.cpp
+++ test/clang-reorder-fields/ClassDerived.cpp
@@ -0,0 +1,33 @@
+// RUN: clang-reorder-fields -record-name bar::Derived -fields-order z,y %s -- | FileCheck %s
+
+namespace bar {
+class Base {
+public:
+  Base(int nx, int np) : x(nx), p(np) {}
+  int x;
+  int p;
+};
+
+
+class Derived : public Base {
+public:
+  Derived(long ny);
+  Derived(char nz);
+private:
+  long y;
+  char z;
+};
+
+Derived::Derived(long ny) : 
+Base(ny, 0),
+y(ny),   // CHECK:   {{^  z\(static_cast\(ny\)\),}}
+z(static_cast(ny)) // CHECK-NEXT:  {{^  y\(ny\)}}
+{}
+
+Derived::Derived(char nz) : 
+Base(1, 2),
+y(nz),  // CHECK:   {{^  z\(x\),}}
+z(x)// CHECK-NEXT:  {{^  y\(nz\)}}
+{}
+
+} // namespace bar
Index: clang-reorder-fields/ReorderFieldsAction.cpp
===
--- clang-reorder-fields/ReorderFieldsAction.cpp
+++ clang-reorder-fields/ReorderFieldsAction.cpp
@@ -22,12 +22,14 @@
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Lex/Lexer.h"
 #include "clang/Tooling/Refactoring.h"
+#include "llvm/ADT/SetVector.h"
 #include 
 #include 
 
 namespace clang {
 namespace reorder_fields {
 using namespace clang::ast_matchers;
+using llvm::SmallSetVector;
 
 /// \brief Finds the definition of a record by name.
 ///
@@ -91,6 +93,28 @@
   

[PATCH] D35972: Add warning to clang-reorder-fields when reordering breaks member init list dependencies

2017-07-27 Thread Sam Conrad via Phabricator via cfe-commits
sameconrad created this revision.
sameconrad added a project: clang-tools-extra.

This adds a warning emitted by clang-reorder-fields when the reordering fields 
breaks dependencies in the initializer list (such that -Wuninitialized would 
warn when compiling).  For example, given:
Foo::Foo(int x)

  : a(x)
  , b(a) {}

Reordering fields to [b,a] gives:
Foo::Foo(int x)

  : b(a)
  , a(x) {}

Emits the warning:
2: Warning: reordering field a after b makes a uninitialized when used in init 
expression.


https://reviews.llvm.org/D35972

Files:
  clang-reorder-fields/ReorderFieldsAction.cpp
  test/clang-reorder-fields/FieldDependencyWarning.cpp

Index: test/clang-reorder-fields/FieldDependencyWarning.cpp
===
--- test/clang-reorder-fields/FieldDependencyWarning.cpp
+++ test/clang-reorder-fields/FieldDependencyWarning.cpp
@@ -0,0 +1,42 @@
+// RUN: clang-reorder-fields -record-name bar::Foo -fields-order y,z,c,x %s -- 2>&1 | FileCheck %s
+
+#include 
+
+namespace bar {
+class Foo { 
+public:
+  Foo(int x, double y, char cin);
+  Foo(int nx);
+  Foo();
+  int x;
+  double y;
+  char c;
+  std::string z;
+};
+
+static char bar(char c) {
+  return c + 1;
+}
+
+Foo::Foo(int x, double y, char cin) :  
+  x(x), 
+  y(y), 
+  c(cin),   
+  z(this->x, bar(c))// CHECK:  [[@LINE]]: Warning: reordering field x after z makes x uninitialized when used in init expression
+// CHECK-NEXT: [[@LINE-1]]: Warning: reordering field c after z makes c uninitialized when used in init expression
+{}
+
+Foo::Foo(int nx) :
+  x(nx),  
+  y(x), // CHECK-NEXT: [[@LINE]]: Warning: reordering field x after y makes x uninitialized when used in init expression
+  c(0),   
+  z(bar(bar(x)), c) // CHECK-NEXT: [[@LINE]]: Warning: reordering field x after z makes x uninitialized when used in init expression
+// CHECK-NEXT: [[@LINE-1]]: Warning: reordering field c after z makes c uninitialized when used in init expression
+{}
+
+} // namespace bar
+
+int main() {
+  bar::Foo F(5, 12.8, 'c');
+  return 0;
+}
Index: clang-reorder-fields/ReorderFieldsAction.cpp
===
--- clang-reorder-fields/ReorderFieldsAction.cpp
+++ clang-reorder-fields/ReorderFieldsAction.cpp
@@ -22,12 +22,14 @@
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Lex/Lexer.h"
 #include "clang/Tooling/Refactoring.h"
+#include "llvm/ADT/SetVector.h"
 #include 
 #include 
 
 namespace clang {
 namespace reorder_fields {
 using namespace clang::ast_matchers;
+using llvm::SmallSetVector;
 
 /// \brief Finds the definition of a record by name.
 ///
@@ -91,6 +93,24 @@
   consumeError(Replacements[R.getFilePath()].add(R));
 }
 
+/// \brief Find all member fields used in the given init-list initializer expr
+/// that belong to the same record
+///
+/// \returns a set of field declarations, empty if none were present
+static SmallSetVector
+findMembersUsedInInitExpr(const CXXCtorInitializer *Initializer,
+  ASTContext ) {
+  SmallSetVector Results;
+  auto FoundExprs =
+  match(findAll(memberExpr(hasObjectExpression(cxxThisExpr())).bind("ME")),
+*Initializer->getInit(), Context);
+  for (BoundNodes  : FoundExprs)
+if (auto *MemExpr = BN.getNodeAs("ME"))
+  if (auto *FD = dyn_cast(MemExpr->getMemberDecl()))
+Results.insert(FD);
+  return Results;
+}
+
 /// \brief Reorders fields in the definition of a struct/class.
 ///
 /// At the moment reodering of fields with
@@ -133,7 +153,7 @@
 /// Thus, we need to ensure that we reorder just the initializers that are present.
 static void reorderFieldsInConstructor(
 const CXXConstructorDecl *CtorDecl, ArrayRef NewFieldsOrder,
-const ASTContext ,
+ASTContext ,
 std::map ) {
   assert(CtorDecl && "Constructor declaration is null");
   if (CtorDecl->isImplicit() || CtorDecl->getNumCtorInitializers() <= 1)
@@ -153,6 +173,22 @@
   for (const auto *Initializer : CtorDecl->inits()) {
 if (!Initializer->isWritten())
   continue;
+
+// Warn if this reordering violates initialization expr dependencies
+const auto UsedMembers = findMembersUsedInInitExpr(Initializer, Context);
+const FieldDecl *ThisM = Initializer->getMember();
+for (const FieldDecl *UM : UsedMembers) {
+  if (NewFieldsPositions[UM->getFieldIndex()] >
+  NewFieldsPositions[ThisM->getFieldIndex()]) {
+llvm::errs() << Context.getSourceManager().getSpellingLineNumber(
+Initializer->getSourceLocation())
+ << ": Warning: reordering field " << UM->getName()
+ << " after " << ThisM->getName() << " makes "
+ << UM->getName()
+ << " uninitialized when used in init