Skip to content

Commit 9af2fe9

Browse files
When a struct is split from a multi-decl, de-nest it too.
1 parent 20b23b8 commit 9af2fe9

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

clang/include/clang/3C/DeclRewriter.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ class DeclRewriter {
5959
// declaration in the containing multi-decl is visited.
6060
std::set<Decl *> VisitedMultiDeclMembers;
6161

62+
// List of RecordDecls that were split from multi-decls and should be moved
63+
// out of an enclosing RecordDecl to avoid a compiler warning. Filled during
64+
// multi-decl rewriting and processed by denestRecordDecls.
65+
std::vector<RecordDecl *> RecordDeclsToDenest;
66+
6267
// Visit each Decl in ToRewrite and apply the appropriate pointer type
6368
// to that Decl. ToRewrite is the set of all declarations to rewrite.
6469
void rewrite(RSet &ToRewrite);
@@ -78,6 +83,7 @@ class DeclRewriter {
7883
void getDeclsOnSameLine(DeclReplacement *N, std::vector<Decl *> &Decls);
7984
bool isSingleDeclaration(DeclReplacement *N);
8085
SourceRange getNextCommaOrSemicolon(SourceLocation L);
86+
void denestRecordDecls();
8187
};
8288

8389
// Visits function declarations and adds entries with their new rewritten

clang/lib/3C/DeclRewriter.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,8 @@ void DeclRewriter::rewriteDecls(ASTContext &Context, ProgramInfo &Info,
238238

239239
for (auto Pair : RewriteThese)
240240
delete Pair.second;
241+
242+
DeclR.denestRecordDecls();
241243
}
242244

243245
void DeclRewriter::rewrite(RSet &ToRewrite) {
@@ -266,6 +268,46 @@ void DeclRewriter::rewrite(RSet &ToRewrite) {
266268
}
267269
}
268270

271+
void DeclRewriter::denestRecordDecls() {
272+
// When there are multiple levels of nested RecordDecls, we need to process
273+
// all the children of a RecordDecl RD before RD itself so that (1) the
274+
// definitions of the children end up before the definition of RD (since the
275+
// rewriter preserves order of insertions) and (2) the definitions of the
276+
// children have been removed from the body of RD before we read the body of
277+
// RD to move it. In effect, we want to process the RecordDecls in postorder.
278+
// The easiest way to achieve this is to process them in order of their _end_
279+
// locations.
280+
std::sort(RecordDeclsToDenest.begin(), RecordDeclsToDenest.end(),
281+
[&](RecordDecl *RD1, RecordDecl *RD2) {
282+
return A.getSourceManager().isBeforeInTranslationUnit(
283+
RD1->getEndLoc(), RD2->getEndLoc());
284+
});
285+
for (RecordDecl *RD : RecordDeclsToDenest) {
286+
// rewriteMultiDecl replaced the final "}" in the original source range with
287+
// "};\n", so the new content of the source range should include the ";\n",
288+
// which is what we want here. Except the rewriter has a bug where it
289+
// adjusts the token range to include the final token _after_ mapping the
290+
// offset to account for previous edits (it should be before). We work
291+
// around the bug by adjusting the token range before calling the rewriter
292+
// at all.
293+
CharSourceRange CSR = Lexer::makeFileCharRange(
294+
CharSourceRange::getTokenRange(RD->getSourceRange()), R.getSourceMgr(),
295+
R.getLangOpts());
296+
std::string DefinitionStr = R.getRewrittenText(CSR);
297+
// Delete the definition from the old location.
298+
rewriteSourceRange(R, CSR, "");
299+
// We want to insert RD as a new child of its original semantic DeclContext,
300+
// just before the existing child of that DeclContext of which RD was
301+
// originally a descendant.
302+
DeclContext *TopChild = RD;
303+
while (TopChild->getLexicalParent() != RD->getDeclContext()) {
304+
TopChild = TopChild->getLexicalParent();
305+
}
306+
// TODO: Use a wrapper like rewriteSourceRange.
307+
R.InsertText(cast<Decl>(TopChild)->getBeginLoc(), DefinitionStr);
308+
}
309+
}
310+
269311
void DeclRewriter::rewriteTypedefDecl(TypedefDeclReplacement *TDR,
270312
RSet &ToRewrite) {
271313
rewriteSingleDecl(TDR, ToRewrite);
@@ -381,6 +423,9 @@ void DeclRewriter::rewriteMultiDecl(DeclReplacement *N, RSet &ToRewrite,
381423
R.InsertTextAfterToken(DL->getBeginLoc(), " " + Iter->second);
382424
}
383425
}
426+
// Make a note if the RecordDecl needs to be de-nested later.
427+
if (RD->getLexicalDeclContext() != RD->getDeclContext())
428+
RecordDeclsToDenest.push_back(RD);
384429
} else if (IsFirst) {
385430
// Rewriting the first declaration is easy. Nothing should change if its
386431
// type does not to be rewritten. When rewriting is required, it is

0 commit comments

Comments
 (0)