|
19 | 19 | #include "clang/AST/Decl.h"
|
20 | 20 | #include "clang/AST/RecursiveASTVisitor.h"
|
21 | 21 | #include "clang/ASTMatchers/ASTMatchFinder.h"
|
| 22 | +#include "clang/Basic/LangOptions.h" |
| 23 | +#include "clang/Basic/SourceLocation.h" |
22 | 24 | #include "clang/Lex/Lexer.h"
|
23 | 25 | #include "clang/Tooling/Refactoring.h"
|
24 | 26 | #include "llvm/ADT/STLExtras.h"
|
@@ -50,6 +52,85 @@ static const RecordDecl *findDefinition(StringRef RecordName,
|
50 | 52 | return selectFirst<RecordDecl>("recordDecl", Results);
|
51 | 53 | }
|
52 | 54 |
|
| 55 | +static bool declaresMultipleFieldsInStatement(const RecordDecl *Decl) { |
| 56 | + SourceLocation LastTypeLoc; |
| 57 | + for (const auto &Field : Decl->fields()) { |
| 58 | + SourceLocation TypeLoc = |
| 59 | + Field->getTypeSourceInfo()->getTypeLoc().getBeginLoc(); |
| 60 | + if (LastTypeLoc.isValid() && TypeLoc == LastTypeLoc) |
| 61 | + return true; |
| 62 | + LastTypeLoc = TypeLoc; |
| 63 | + } |
| 64 | + return false; |
| 65 | +} |
| 66 | + |
| 67 | +static bool declaresMultipleFieldsInMacro(const RecordDecl *Decl, |
| 68 | + const SourceManager &SrcMgr) { |
| 69 | + SourceLocation LastMacroLoc; |
| 70 | + for (const auto &Field : Decl->fields()) { |
| 71 | + if (!Field->getLocation().isMacroID()) |
| 72 | + continue; |
| 73 | + SourceLocation MacroLoc = SrcMgr.getExpansionLoc(Field->getLocation()); |
| 74 | + if (LastMacroLoc.isValid() && MacroLoc == LastMacroLoc) |
| 75 | + return true; |
| 76 | + LastMacroLoc = MacroLoc; |
| 77 | + } |
| 78 | + return false; |
| 79 | +} |
| 80 | + |
| 81 | +static bool containsPreprocessorDirectives(const RecordDecl *Decl, |
| 82 | + const SourceManager &SrcMgr, |
| 83 | + const LangOptions &LangOpts) { |
| 84 | + std::pair<FileID, unsigned> FileAndOffset = |
| 85 | + SrcMgr.getDecomposedLoc(Decl->field_begin()->getBeginLoc()); |
| 86 | + assert(!Decl->field_empty()); |
| 87 | + auto LastField = Decl->field_begin(); |
| 88 | + while (std::next(LastField) != Decl->field_end()) |
| 89 | + ++LastField; |
| 90 | + unsigned EndOffset = SrcMgr.getFileOffset(LastField->getEndLoc()); |
| 91 | + StringRef SrcBuffer = SrcMgr.getBufferData(FileAndOffset.first); |
| 92 | + Lexer L(SrcMgr.getLocForStartOfFile(FileAndOffset.first), LangOpts, |
| 93 | + SrcBuffer.data(), SrcBuffer.data() + FileAndOffset.second, |
| 94 | + SrcBuffer.data() + SrcBuffer.size()); |
| 95 | + IdentifierTable Identifiers(LangOpts); |
| 96 | + clang::Token T; |
| 97 | + while (!L.LexFromRawLexer(T) && L.getCurrentBufferOffset() < EndOffset) { |
| 98 | + if (T.getKind() == tok::hash) { |
| 99 | + L.LexFromRawLexer(T); |
| 100 | + if (T.getKind() == tok::raw_identifier) { |
| 101 | + clang::IdentifierInfo &II = Identifiers.get(T.getRawIdentifier()); |
| 102 | + if (II.getPPKeywordID() != clang::tok::pp_not_keyword) |
| 103 | + return true; |
| 104 | + } |
| 105 | + } |
| 106 | + } |
| 107 | + return false; |
| 108 | +} |
| 109 | + |
| 110 | +static bool isSafeToRewrite(const RecordDecl *Decl, const ASTContext &Context) { |
| 111 | + // All following checks expect at least one field declaration. |
| 112 | + if (Decl->field_empty()) |
| 113 | + return true; |
| 114 | + |
| 115 | + // Don't attempt to rewrite if there is a declaration like 'int a, b;'. |
| 116 | + if (declaresMultipleFieldsInStatement(Decl)) |
| 117 | + return false; |
| 118 | + |
| 119 | + const SourceManager &SrcMgr = Context.getSourceManager(); |
| 120 | + |
| 121 | + // Don't attempt to rewrite if a single macro expansion creates multiple |
| 122 | + // fields. |
| 123 | + if (declaresMultipleFieldsInMacro(Decl, SrcMgr)) |
| 124 | + return false; |
| 125 | + |
| 126 | + // Prevent rewriting if there are preprocessor directives present between the |
| 127 | + // start of the first field and the end of last field. |
| 128 | + if (containsPreprocessorDirectives(Decl, SrcMgr, Context.getLangOpts())) |
| 129 | + return false; |
| 130 | + |
| 131 | + return true; |
| 132 | +} |
| 133 | + |
53 | 134 | /// Calculates the new order of fields.
|
54 | 135 | ///
|
55 | 136 | /// \returns empty vector if the list of fields doesn't match the definition.
|
@@ -345,6 +426,8 @@ class ReorderingConsumer : public ASTConsumer {
|
345 | 426 | const RecordDecl *RD = findDefinition(RecordName, Context);
|
346 | 427 | if (!RD)
|
347 | 428 | return;
|
| 429 | + if (!isSafeToRewrite(RD, Context)) |
| 430 | + return; |
348 | 431 | SmallVector<unsigned, 4> NewFieldsOrder =
|
349 | 432 | getNewFieldsOrder(RD, DesiredFieldsOrder);
|
350 | 433 | if (NewFieldsOrder.empty())
|
|
0 commit comments