[clang-tools-extra] Add support for plain C structs in clang-reorder-fields
authorAlexander Shaposhnikov <shal1t712@gmail.com>
Thu, 20 Jul 2017 21:41:20 +0000 (21:41 +0000)
committerAlexander Shaposhnikov <shal1t712@gmail.com>
Thu, 20 Jul 2017 21:41:20 +0000 (21:41 +0000)
This diff updates the tool clang-reorder-fields
to enable reordering of fields of plain C structs.

Test plan: make check-all

Differential revision: https://reviews.llvm.org/D35329

llvm-svn: 308678

clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
clang-tools-extra/test/clang-reorder-fields/PlainCStructFieldsOrder.c [new file with mode: 0644]

index 1996380..ae22b34 100644 (file)
@@ -32,10 +32,10 @@ using namespace clang::ast_matchers;
 /// \brief Finds the definition of a record by name.
 ///
 /// \returns nullptr if the name is ambiguous or not found.
-static const CXXRecordDecl *findDefinition(StringRef RecordName,
-                                           ASTContext &Context) {
+static const RecordDecl *findDefinition(StringRef RecordName,
+                                        ASTContext &Context) {
   auto Results = match(
-      recordDecl(hasName(RecordName), isDefinition()).bind("cxxRecordDecl"),
+      recordDecl(hasName(RecordName), isDefinition()).bind("recordDecl"),
       Context);
   if (Results.empty()) {
     llvm::errs() << "Definition of " << RecordName << "  not found\n";
@@ -46,14 +46,14 @@ static const CXXRecordDecl *findDefinition(StringRef RecordName,
                  << " is ambiguous, several definitions found\n";
     return nullptr;
   }
-  return selectFirst<CXXRecordDecl>("cxxRecordDecl", Results);
+  return selectFirst<RecordDecl>("recordDecl", Results);
 }
 
 /// \brief Calculates the new order of fields.
 ///
 /// \returns empty vector if the list of fields doesn't match the definition.
 static SmallVector<unsigned, 4>
-getNewFieldsOrder(const CXXRecordDecl *Definition,
+getNewFieldsOrder(const RecordDecl *Definition,
                   ArrayRef<std::string> DesiredFieldsOrder) {
   assert(Definition && "Definition is null");
 
@@ -97,7 +97,7 @@ addReplacement(SourceRange Old, SourceRange New, const ASTContext &Context,
 /// different accesses (public/protected/private) is not supported.
 /// \returns true on success.
 static bool reorderFieldsInDefinition(
-    const CXXRecordDecl *Definition, ArrayRef<unsigned> NewFieldsOrder,
+    const RecordDecl *Definition, ArrayRef<unsigned> NewFieldsOrder,
     const ASTContext &Context,
     std::map<std::string, tooling::Replacements> &Replacements) {
   assert(Definition && "Definition is null");
@@ -223,7 +223,7 @@ public:
   ReorderingConsumer &operator=(const ReorderingConsumer &) = delete;
 
   void HandleTranslationUnit(ASTContext &Context) override {
-    const CXXRecordDecl *RD = findDefinition(RecordName, Context);
+    const RecordDecl *RD = findDefinition(RecordName, Context);
     if (!RD)
       return;
     SmallVector<unsigned, 4> NewFieldsOrder =
@@ -232,16 +232,21 @@ public:
       return;
     if (!reorderFieldsInDefinition(RD, NewFieldsOrder, Context, Replacements))
       return;
-    for (const auto *C : RD->ctors())
-      if (const auto *D = dyn_cast<CXXConstructorDecl>(C->getDefinition()))
-        reorderFieldsInConstructor(cast<const CXXConstructorDecl>(D),
-                                   NewFieldsOrder, Context, Replacements);
 
-    // We only need to reorder init list expressions for aggregate types.
+    // CXXRD will be nullptr if C code (not C++) is being processed.
+    const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD);
+    if (CXXRD)
+      for (const auto *C : CXXRD->ctors())
+        if (const auto *D = dyn_cast<CXXConstructorDecl>(C->getDefinition()))
+          reorderFieldsInConstructor(cast<const CXXConstructorDecl>(D),
+                                      NewFieldsOrder, Context, Replacements);
+
+    // We only need to reorder init list expressions for 
+    // plain C structs or C++ aggregate types.
     // For other types the order of constructor parameters is used,
     // which we don't change at the moment.
     // Now (v0) partial initialization is not supported.
-    if (RD->isAggregate())
+    if (!CXXRD || CXXRD->isAggregate())
       for (auto Result :
            match(initListExpr(hasType(equalsNode(RD))).bind("initListExpr"),
                  Context))
diff --git a/clang-tools-extra/test/clang-reorder-fields/PlainCStructFieldsOrder.c b/clang-tools-extra/test/clang-reorder-fields/PlainCStructFieldsOrder.c
new file mode 100644 (file)
index 0000000..5b4fe9e
--- /dev/null
@@ -0,0 +1,14 @@
+// RUN: clang-reorder-fields -record-name Foo -fields-order z,w,y,x %s -- | FileCheck %s
+
+struct Foo {
+  const int* x; // CHECK:      {{^  double z;}}
+  int y;        // CHECK-NEXT: {{^  int w;}}
+  double z;     // CHECK-NEXT: {{^  int y;}}
+  int w;        // CHECK-NEXT: {{^  const int\* x}}
+};
+
+int main() {
+  const int x = 13;
+  struct Foo foo = { &x, 0, 1.29, 17 }; // CHECK: {{^  struct Foo foo = { 1.29, 17, 0, &x };}} 
+  return 0;
+}