[clang-tools-extra] Add support for plain C structs in clang-reorder-fields

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
This commit is contained in:
Alexander Shaposhnikov
2017-07-20 21:41:20 +00:00
parent 6d8fb107b2
commit eaf833ca2b
2 changed files with 32 additions and 13 deletions

View 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))

View File

@@ -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;
}