Skip to content

Commit 04f49c7

Browse files
When a struct is split from a multi-decl, de-nest it too.
1 parent 9da76c0 commit 04f49c7

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
@@ -240,6 +240,8 @@ void DeclRewriter::rewriteDecls(ASTContext &Context, ProgramInfo &Info,
240240

241241
for (auto Pair : RewriteThese)
242242
delete Pair.second;
243+
244+
DeclR.denestRecordDecls();
243245
}
244246

245247
void DeclRewriter::rewrite(RSet &ToRewrite) {
@@ -268,6 +270,46 @@ void DeclRewriter::rewrite(RSet &ToRewrite) {
268270
}
269271
}
270272

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

0 commit comments

Comments
 (0)