From bf3c84cff7fdd767bb8228bb0dfde3b385eedf04 Mon Sep 17 00:00:00 2001 From: Alexander Shaposhnikov Date: Fri, 2 Sep 2016 02:56:07 +0000 Subject: [PATCH] Add clang-reorder-fields to clang-tools-extra This diff adds v0 of clang-reorder-fields tool to clang/tools/extra. The main idea behind this tool is to simplify and make less error-prone refactoring of large codebases when someone needs to change the order fields of a struct/class (for example to remove excessive padding). Differential revision: https://reviews.llvm.org/D23279 llvm-svn: 280456 --- clang-tools-extra/CMakeLists.txt | 1 + .../clang-reorder-fields/CMakeLists.txt | 15 ++ .../clang-reorder-fields/ReorderFieldsAction.cpp | 264 +++++++++++++++++++++ .../clang-reorder-fields/ReorderFieldsAction.h | 47 ++++ .../clang-reorder-fields/tool/CMakeLists.txt | 12 + .../tool/ClangReorderFields.cpp | 93 ++++++++ clang-tools-extra/test/CMakeLists.txt | 1 + .../AggregatePartialInitialization.cpp | 14 ++ .../clang-reorder-fields/CStructAmbiguousName.cpp | 18 ++ .../clang-reorder-fields/CStructFieldsOrder.cpp | 16 ++ .../ClassDifferentFieldsAccesses.cpp | 16 ++ .../ClassMixedInitialization.cpp | 24 ++ .../test/clang-reorder-fields/ClassSimpleCtor.cpp | 24 ++ 13 files changed, 545 insertions(+) create mode 100644 clang-tools-extra/clang-reorder-fields/CMakeLists.txt create mode 100644 clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp create mode 100644 clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.h create mode 100644 clang-tools-extra/clang-reorder-fields/tool/CMakeLists.txt create mode 100644 clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp create mode 100644 clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.cpp create mode 100644 clang-tools-extra/test/clang-reorder-fields/CStructAmbiguousName.cpp create mode 100644 clang-tools-extra/test/clang-reorder-fields/CStructFieldsOrder.cpp create mode 100644 clang-tools-extra/test/clang-reorder-fields/ClassDifferentFieldsAccesses.cpp create mode 100644 clang-tools-extra/test/clang-reorder-fields/ClassMixedInitialization.cpp create mode 100644 clang-tools-extra/test/clang-reorder-fields/ClassSimpleCtor.cpp diff --git a/clang-tools-extra/CMakeLists.txt b/clang-tools-extra/CMakeLists.txt index 171e9ee..db11305 100644 --- a/clang-tools-extra/CMakeLists.txt +++ b/clang-tools-extra/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(clang-apply-replacements) add_subdirectory(clang-rename) +add_subdirectory(clang-reorder-fields) add_subdirectory(modularize) if(CLANG_ENABLE_STATIC_ANALYZER) add_subdirectory(clang-tidy) diff --git a/clang-tools-extra/clang-reorder-fields/CMakeLists.txt b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt new file mode 100644 index 0000000..51cd4af --- /dev/null +++ b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt @@ -0,0 +1,15 @@ +set(LLVM_LINK_COMPONENTS support) + +add_clang_library(clangReorderFields + ReorderFieldsAction.cpp + + LINK_LIBS + clangAST + clangASTMatchers + clangBasic + clangIndex + clangLex + clangToolingCore + ) + +add_subdirectory(tool) diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp new file mode 100644 index 0000000..1996380 --- /dev/null +++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp @@ -0,0 +1,264 @@ +//===-- tools/extra/clang-reorder-fields/ReorderFieldsAction.cpp -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the definition of the +/// ReorderFieldsAction::newASTConsumer method +/// +//===----------------------------------------------------------------------===// + +#include "ReorderFieldsAction.h" +#include "clang/AST/AST.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" +#include "clang/Tooling/Refactoring.h" +#include +#include + +namespace clang { +namespace reorder_fields { +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) { + auto Results = match( + recordDecl(hasName(RecordName), isDefinition()).bind("cxxRecordDecl"), + Context); + if (Results.empty()) { + llvm::errs() << "Definition of " << RecordName << " not found\n"; + return nullptr; + } + if (Results.size() > 1) { + llvm::errs() << "The name " << RecordName + << " is ambiguous, several definitions found\n"; + return nullptr; + } + return selectFirst("cxxRecordDecl", Results); +} + +/// \brief Calculates the new order of fields. +/// +/// \returns empty vector if the list of fields doesn't match the definition. +static SmallVector +getNewFieldsOrder(const CXXRecordDecl *Definition, + ArrayRef DesiredFieldsOrder) { + assert(Definition && "Definition is null"); + + llvm::StringMap NameToIndex; + for (const auto *Field : Definition->fields()) + NameToIndex[Field->getName()] = Field->getFieldIndex(); + + if (DesiredFieldsOrder.size() != NameToIndex.size()) { + llvm::errs() << "Number of provided fields doesn't match definition.\n"; + return {}; + } + SmallVector NewFieldsOrder; + for (const auto &Name : DesiredFieldsOrder) { + if (!NameToIndex.count(Name)) { + llvm::errs() << "Field " << Name << " not found in definition.\n"; + return {}; + } + NewFieldsOrder.push_back(NameToIndex[Name]); + } + assert(NewFieldsOrder.size() == NameToIndex.size()); + return NewFieldsOrder; +} + +// FIXME: error-handling +/// \brief Replaces one range of source code by another. +static void +addReplacement(SourceRange Old, SourceRange New, const ASTContext &Context, + std::map &Replacements) { + StringRef NewText = + Lexer::getSourceText(CharSourceRange::getTokenRange(New), + Context.getSourceManager(), Context.getLangOpts()); + tooling::Replacement R(Context.getSourceManager(), + CharSourceRange::getTokenRange(Old), NewText, + Context.getLangOpts()); + consumeError(Replacements[R.getFilePath()].add(R)); +} + +/// \brief Reorders fields in the definition of a struct/class. +/// +/// At the moment reodering of fields with +/// different accesses (public/protected/private) is not supported. +/// \returns true on success. +static bool reorderFieldsInDefinition( + const CXXRecordDecl *Definition, ArrayRef NewFieldsOrder, + const ASTContext &Context, + std::map &Replacements) { + assert(Definition && "Definition is null"); + + SmallVector Fields; + for (const auto *Field : Definition->fields()) + Fields.push_back(Field); + + // Check that the permutation of the fields doesn't change the accesses + for (const auto *Field : Definition->fields()) { + const auto FieldIndex = Field->getFieldIndex(); + if (Field->getAccess() != Fields[NewFieldsOrder[FieldIndex]]->getAccess()) { + llvm::errs() << "Currently reodering of fields with different accesses " + "is not supported\n"; + return false; + } + } + + for (const auto *Field : Definition->fields()) { + const auto FieldIndex = Field->getFieldIndex(); + if (FieldIndex == NewFieldsOrder[FieldIndex]) + continue; + addReplacement(Field->getSourceRange(), + Fields[NewFieldsOrder[FieldIndex]]->getSourceRange(), + Context, Replacements); + } + return true; +} + +/// \brief Reorders initializers in a C++ struct/class constructor. +/// +/// A constructor can have initializers for an arbitrary subset of the class's fields. +/// Thus, we need to ensure that we reorder just the initializers that are present. +static void reorderFieldsInConstructor( + const CXXConstructorDecl *CtorDecl, ArrayRef NewFieldsOrder, + const ASTContext &Context, + std::map &Replacements) { + assert(CtorDecl && "Constructor declaration is null"); + if (CtorDecl->isImplicit() || CtorDecl->getNumCtorInitializers() <= 1) + return; + + // The method FunctionDecl::isThisDeclarationADefinition returns false + // for a defaulted function unless that function has been implicitly defined. + // Thus this assert needs to be after the previous checks. + assert(CtorDecl->isThisDeclarationADefinition() && "Not a definition"); + + SmallVector NewFieldsPositions(NewFieldsOrder.size()); + for (unsigned i = 0, e = NewFieldsOrder.size(); i < e; ++i) + NewFieldsPositions[NewFieldsOrder[i]] = i; + + SmallVector OldWrittenInitializersOrder; + SmallVector NewWrittenInitializersOrder; + for (const auto *Initializer : CtorDecl->inits()) { + if (!Initializer->isWritten()) + continue; + OldWrittenInitializersOrder.push_back(Initializer); + NewWrittenInitializersOrder.push_back(Initializer); + } + auto ByFieldNewPosition = [&](const CXXCtorInitializer *LHS, + const CXXCtorInitializer *RHS) { + assert(LHS && RHS); + return NewFieldsPositions[LHS->getMember()->getFieldIndex()] < + NewFieldsPositions[RHS->getMember()->getFieldIndex()]; + }; + std::sort(std::begin(NewWrittenInitializersOrder), + std::end(NewWrittenInitializersOrder), ByFieldNewPosition); + assert(OldWrittenInitializersOrder.size() == + NewWrittenInitializersOrder.size()); + for (unsigned i = 0, e = NewWrittenInitializersOrder.size(); i < e; ++i) + if (OldWrittenInitializersOrder[i] != NewWrittenInitializersOrder[i]) + addReplacement(OldWrittenInitializersOrder[i]->getSourceRange(), + NewWrittenInitializersOrder[i]->getSourceRange(), Context, + Replacements); +} + +/// \brief Reorders initializers in the brace initialization of an aggregate. +/// +/// At the moment partial initialization is not supported. +/// \returns true on success +static bool reorderFieldsInInitListExpr( + const InitListExpr *InitListEx, ArrayRef NewFieldsOrder, + const ASTContext &Context, + std::map &Replacements) { + assert(InitListEx && "Init list expression is null"); + // We care only about InitListExprs which originate from source code. + // Implicit InitListExprs are created by the semantic analyzer. + if (!InitListEx->isExplicit()) + return true; + // The method InitListExpr::getSyntacticForm may return nullptr indicating that + // the current initializer list also serves as its syntactic form. + if (const auto *SyntacticForm = InitListEx->getSyntacticForm()) + InitListEx = SyntacticForm; + // If there are no initializers we do not need to change anything. + if (!InitListEx->getNumInits()) + return true; + if (InitListEx->getNumInits() != NewFieldsOrder.size()) { + llvm::errs() << "Currently only full initialization is supported\n"; + return false; + } + for (unsigned i = 0, e = InitListEx->getNumInits(); i < e; ++i) + if (i != NewFieldsOrder[i]) + addReplacement( + InitListEx->getInit(i)->getSourceRange(), + InitListEx->getInit(NewFieldsOrder[i])->getSourceRange(), Context, + Replacements); + return true; +} + +namespace { +class ReorderingConsumer : public ASTConsumer { + StringRef RecordName; + ArrayRef DesiredFieldsOrder; + std::map &Replacements; + +public: + ReorderingConsumer(StringRef RecordName, + ArrayRef DesiredFieldsOrder, + std::map &Replacements) + : RecordName(RecordName), DesiredFieldsOrder(DesiredFieldsOrder), + Replacements(Replacements) {} + + ReorderingConsumer(const ReorderingConsumer &) = delete; + ReorderingConsumer &operator=(const ReorderingConsumer &) = delete; + + void HandleTranslationUnit(ASTContext &Context) override { + const CXXRecordDecl *RD = findDefinition(RecordName, Context); + if (!RD) + return; + SmallVector NewFieldsOrder = + getNewFieldsOrder(RD, DesiredFieldsOrder); + if (NewFieldsOrder.empty()) + return; + if (!reorderFieldsInDefinition(RD, NewFieldsOrder, Context, Replacements)) + return; + for (const auto *C : RD->ctors()) + if (const auto *D = dyn_cast(C->getDefinition())) + reorderFieldsInConstructor(cast(D), + NewFieldsOrder, Context, Replacements); + + // We only need to reorder init list expressions for 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()) + for (auto Result : + match(initListExpr(hasType(equalsNode(RD))).bind("initListExpr"), + Context)) + if (!reorderFieldsInInitListExpr( + Result.getNodeAs("initListExpr"), NewFieldsOrder, + Context, Replacements)) { + Replacements.clear(); + return; + } + } +}; +} // end anonymous namespace + +std::unique_ptr ReorderFieldsAction::newASTConsumer() { + return llvm::make_unique(RecordName, DesiredFieldsOrder, + Replacements); +} + +} // namespace reorder_fields +} // namespace clang diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.h b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.h new file mode 100644 index 0000000..f08c632 --- /dev/null +++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.h @@ -0,0 +1,47 @@ +//===-- tools/extra/clang-reorder-fields/ReorderFieldsAction.h -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the declarations of the ReorderFieldsAction class and +/// the FieldPosition struct. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_ACTION_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_ACTION_H + +#include "clang/Tooling/Refactoring.h" + +namespace clang { +class ASTConsumer; + +namespace reorder_fields { + +class ReorderFieldsAction { + llvm::StringRef RecordName; + llvm::ArrayRef DesiredFieldsOrder; + std::map &Replacements; + +public: + ReorderFieldsAction( + llvm::StringRef RecordName, + llvm::ArrayRef DesiredFieldsOrder, + std::map &Replacements) + : RecordName(RecordName), DesiredFieldsOrder(DesiredFieldsOrder), + Replacements(Replacements) {} + + ReorderFieldsAction(const ReorderFieldsAction &) = delete; + ReorderFieldsAction &operator=(const ReorderFieldsAction &) = delete; + + std::unique_ptr newASTConsumer(); +}; +} // namespace reorder_fields +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_ACTION_H diff --git a/clang-tools-extra/clang-reorder-fields/tool/CMakeLists.txt b/clang-tools-extra/clang-reorder-fields/tool/CMakeLists.txt new file mode 100644 index 0000000..174e71a --- /dev/null +++ b/clang-tools-extra/clang-reorder-fields/tool/CMakeLists.txt @@ -0,0 +1,12 @@ +add_clang_executable(clang-reorder-fields ClangReorderFields.cpp) + +target_link_libraries(clang-reorder-fields + clangBasic + clangFrontend + clangReorderFields + clangRewrite + clangTooling + clangToolingCore + ) + +install(TARGETS clang-reorder-fields RUNTIME DESTINATION bin) diff --git a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp new file mode 100644 index 0000000..3061876 --- /dev/null +++ b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp @@ -0,0 +1,93 @@ +//===-- tools/extra/clang-reorder-fields/tool/ClangReorderFields.cpp -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the implementation of clang-reorder-fields tool +/// +//===----------------------------------------------------------------------===// + +#include "../ReorderFieldsAction.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Refactoring.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include +#include +#include + +using namespace llvm; +using namespace clang; + +cl::OptionCategory ClangReorderFieldsCategory("clang-reorder-fields options"); + +static cl::opt + RecordName("record-name", cl::Required, + cl::desc("The name of the struct/class."), + cl::cat(ClangReorderFieldsCategory)); + +static cl::list FieldsOrder("fields-order", cl::CommaSeparated, + cl::OneOrMore, + cl::desc("The desired fields order."), + cl::cat(ClangReorderFieldsCategory)); + +static cl::opt Inplace("i", cl::desc("Overwrite edited files."), + cl::cat(ClangReorderFieldsCategory)); + +const char Usage[] = "A tool to reorder fields in C/C++ structs/classes.\n"; + +int main(int argc, const char **argv) { + tooling::CommonOptionsParser OP(argc, argv, ClangReorderFieldsCategory, + Usage); + + auto Files = OP.getSourcePathList(); + tooling::RefactoringTool Tool(OP.getCompilations(), Files); + + reorder_fields::ReorderFieldsAction Action(RecordName, FieldsOrder, + Tool.getReplacements()); + + auto Factory = tooling::newFrontendActionFactory(&Action); + + if (Inplace) + return Tool.runAndSave(Factory.get()); + + int ExitCode = Tool.run(Factory.get()); + LangOptions DefaultLangOptions; + IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions()); + TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts); + DiagnosticsEngine Diagnostics( + IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, + &DiagnosticPrinter, false); + + auto &FileMgr = Tool.getFiles(); + SourceManager Sources(Diagnostics, FileMgr); + Rewriter Rewrite(Sources, DefaultLangOptions); + Tool.applyAllReplacements(Rewrite); + + for (const auto &File : Files) { + const auto *Entry = FileMgr.getFile(File); + const auto ID = Sources.translateFile(Entry); + // The method Rewriter::getRewriteBufferFor returns nullptr if + // the file has not been changed. + if (const auto *RB = Rewrite.getRewriteBufferFor(ID)) + RB->write(outs()); + else + outs() << Sources.getMemoryBufferForFile(Entry)->getBuffer(); + } + + return ExitCode; +} diff --git a/clang-tools-extra/test/CMakeLists.txt b/clang-tools-extra/test/CMakeLists.txt index 22ee4ee..228076c 100644 --- a/clang-tools-extra/test/CMakeLists.txt +++ b/clang-tools-extra/test/CMakeLists.txt @@ -45,6 +45,7 @@ set(CLANG_TOOLS_TEST_DEPS clang-include-fixer clang-query clang-rename + clang-reorder-fields clang-tidy find-all-symbols modularize diff --git a/clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.cpp b/clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.cpp new file mode 100644 index 0000000..9d09c81 --- /dev/null +++ b/clang-tools-extra/test/clang-reorder-fields/AggregatePartialInitialization.cpp @@ -0,0 +1,14 @@ +// RUN: clang-reorder-fields -record-name Foo -fields-order z,y,x %s -- | FileCheck %s + +// The order of fields should not change. +class Foo { +public: + int x; // CHECK: {{^ int x;}} + int y; // CHECK-NEXT: {{^ int y;}} + int z; // CHECK-NEXT: {{^ int z;}} +}; + +int main() { + Foo foo = { 0, 1 }; // CHECK: {{^ Foo foo = { 0, 1 };}} + return 0; +} diff --git a/clang-tools-extra/test/clang-reorder-fields/CStructAmbiguousName.cpp b/clang-tools-extra/test/clang-reorder-fields/CStructAmbiguousName.cpp new file mode 100644 index 0000000..e1e6645 --- /dev/null +++ b/clang-tools-extra/test/clang-reorder-fields/CStructAmbiguousName.cpp @@ -0,0 +1,18 @@ +// RUN: clang-reorder-fields -record-name ::Foo -fields-order y,x %s -- | FileCheck %s + +struct Foo { + int x; // CHECK: {{^ double y;}} + double y; // CHECK-NEXT: {{^ int x;}} +}; + +namespace bar { +struct Foo { + int x; // CHECK: {{^ int x;}} + double y; // CHECK-NEXT: {{^ double y;}} +}; +} // end namespace bar + +int main() { + bar::Foo foo = { 1, 1.7 }; // CHECK: {{^ bar::Foo foo = { 1, 1.7 };}} + return 0; +} diff --git a/clang-tools-extra/test/clang-reorder-fields/CStructFieldsOrder.cpp b/clang-tools-extra/test/clang-reorder-fields/CStructFieldsOrder.cpp new file mode 100644 index 0000000..2ed3578 --- /dev/null +++ b/clang-tools-extra/test/clang-reorder-fields/CStructFieldsOrder.cpp @@ -0,0 +1,16 @@ +// RUN: clang-reorder-fields -record-name ::bar::Foo -fields-order z,w,y,x %s -- | FileCheck %s + +namespace bar { +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}} +}; +} // end namespace bar + +int main() { + const int x = 13; + bar::Foo foo = { &x, 0, 1.29, 17 }; // CHECK: {{^ bar::Foo foo = { 1.29, 17, 0, &x };}} + return 0; +} diff --git a/clang-tools-extra/test/clang-reorder-fields/ClassDifferentFieldsAccesses.cpp b/clang-tools-extra/test/clang-reorder-fields/ClassDifferentFieldsAccesses.cpp new file mode 100644 index 0000000..dd0a555 --- /dev/null +++ b/clang-tools-extra/test/clang-reorder-fields/ClassDifferentFieldsAccesses.cpp @@ -0,0 +1,16 @@ +// RUN: clang-reorder-fields -record-name Foo -fields-order z,y,x %s -- | FileCheck %s + +// The order of fields should not change. +class Foo { +public: + int x; // CHECK: {{^ int x;}} + +private: + int y; // CHECK: {{^ int y;}} + int z; // CHECK-NEXT: {{^ int z;}} +}; + +int main() { + Foo foo; + return 0; +} diff --git a/clang-tools-extra/test/clang-reorder-fields/ClassMixedInitialization.cpp b/clang-tools-extra/test/clang-reorder-fields/ClassMixedInitialization.cpp new file mode 100644 index 0000000..888649a --- /dev/null +++ b/clang-tools-extra/test/clang-reorder-fields/ClassMixedInitialization.cpp @@ -0,0 +1,24 @@ +// RUN: clang-reorder-fields -record-name Foo -fields-order e,x,pi,s2,s1 %s -- -std=c++11 | FileCheck %s + +class Foo { +public: + Foo(); + +private: + int x; // CHECK: {{^ double e = 2.71;}} + const char *s1; // CHECK-NEXT: {{^ int x;}} + const char *s2; // CHECK-NEXT: {{^ double pi = 3.14;}} + double pi = 3.14; // CHECK-NEXT: {{^ const char \*s2;}} + double e = 2.71; // CHECK-NEXT: {{^ const char \*s1;}} +}; + +Foo::Foo(): + x(12), // CHECK: {{^ x\(12\)}}, + s1("abc"), // CHECK-NEXT: {{^ s2\("def"\)}}, + s2("def") // CHECK-NEXT: {{^ s1\("abc"\)}} +{} + +int main() { + Foo foo; + return 0; +} diff --git a/clang-tools-extra/test/clang-reorder-fields/ClassSimpleCtor.cpp b/clang-tools-extra/test/clang-reorder-fields/ClassSimpleCtor.cpp new file mode 100644 index 0000000..6dc2722 --- /dev/null +++ b/clang-tools-extra/test/clang-reorder-fields/ClassSimpleCtor.cpp @@ -0,0 +1,24 @@ +// RUN: clang-reorder-fields -record-name Foo -fields-order s1,x,z,s2 %s -- | FileCheck %s + +class Foo { +public: + Foo(); + +private: + int x; // CHECK: {{^ const char \*s1;}} + const char *s1; // CHECK-NEXT: {{^ int x;}} + const char *s2; // CHECK-NEXT: {{^ double z;}} + double z; // CHECK-NEXT: {{^ const char \*s2;}} +}; + +Foo::Foo(): + x(12), // CHECK: {{^ s1\("abc"\),}} + s1("abc"), // CHECK-NEXT: {{^ x\(12\),}} + s2("def"), // CHECK-NEXT: {{^ z\(3.14\),}} + z(3.14) // CHECK-NEXT: {{^ s2\("def"\)}} +{} + +int main() { + Foo foo; + return 0; +} -- 2.7.4