Skip to content

Commit 2878425

Browse files
When a struct is split from a multi-decl, de-nest it too.
1 parent 8a69fa4 commit 2878425

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
@@ -60,6 +60,11 @@ class DeclRewriter {
6060
// declaration in the containing multi-decl is visited.
6161
RSet VisitedMultiDeclMembers;
6262

63+
// List of RecordDecls that were split from multi-decls and should be moved
64+
// out of an enclosing RecordDecl to avoid a compiler warning. Filled during
65+
// multi-decl rewriting and processed by denestRecordDecls.
66+
std::vector<RecordDecl *> RecordDeclsToDenest;
67+
6368
// Visit each Decl in ToRewrite and apply the appropriate pointer type
6469
// to that Decl. ToRewrite is the set of all declarations to rewrite.
6570
void rewrite(RSet &ToRewrite);
@@ -82,6 +87,7 @@ class DeclRewriter {
8287
bool isSingleDeclaration(DeclReplacement *N);
8388
bool areDeclarationsOnSameLine(DeclReplacement *N1, DeclReplacement *N2);
8489
SourceRange getNextCommaOrSemicolon(SourceLocation L);
90+
void denestRecordDecls();
8591
};
8692

8793
// 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
@@ -221,6 +221,8 @@ void DeclRewriter::rewriteDecls(ASTContext &Context, ProgramInfo &Info,
221221

222222
for (const auto *R : RewriteThese)
223223
delete R;
224+
225+
DeclR.denestRecordDecls();
224226
}
225227

226228
void DeclRewriter::rewrite(RSet &ToRewrite) {
@@ -251,6 +253,46 @@ void DeclRewriter::rewrite(RSet &ToRewrite) {
251253
}
252254
}
253255

256+
void DeclRewriter::denestRecordDecls() {
257+
// When there are multiple levels of nested RecordDecls, we need to process
258+
// all the children of a RecordDecl RD before RD itself so that (1) the
259+
// definitions of the children end up before the definition of RD (since the
260+
// rewriter preserves order of insertions) and (2) the definitions of the
261+
// children have been removed from the body of RD before we read the body of
262+
// RD to move it. In effect, we want to process the RecordDecls in postorder.
263+
// The easiest way to achieve this is to process them in order of their _end_
264+
// locations.
265+
std::sort(RecordDeclsToDenest.begin(), RecordDeclsToDenest.end(),
266+
[&](RecordDecl *RD1, RecordDecl *RD2) {
267+
return A.getSourceManager().isBeforeInTranslationUnit(
268+
RD1->getEndLoc(), RD2->getEndLoc());
269+
});
270+
for (RecordDecl *RD : RecordDeclsToDenest) {
271+
// rewriteMultiDecl replaced the final "}" in the original source range with
272+
// "};\n", so the new content of the source range should include the ";\n",
273+
// which is what we want here. Except the rewriter has a bug where it
274+
// adjusts the token range to include the final token _after_ mapping the
275+
// offset to account for previous edits (it should be before). We work
276+
// around the bug by adjusting the token range before calling the rewriter
277+
// at all.
278+
CharSourceRange CSR = Lexer::makeFileCharRange(
279+
CharSourceRange::getTokenRange(RD->getSourceRange()), R.getSourceMgr(),
280+
R.getLangOpts());
281+
std::string DefinitionStr = R.getRewrittenText(CSR);
282+
// Delete the definition from the old location.
283+
rewriteSourceRange(R, CSR, "");
284+
// We want to insert RD as a new child of its original semantic DeclContext,
285+
// just before the existing child of that DeclContext of which RD was
286+
// originally a descendant.
287+
DeclContext *TopChild = RD;
288+
while (TopChild->getLexicalParent() != RD->getDeclContext()) {
289+
TopChild = TopChild->getLexicalParent();
290+
}
291+
// TODO: Use a wrapper like rewriteSourceRange.
292+
R.InsertText(cast<Decl>(TopChild)->getBeginLoc(), DefinitionStr);
293+
}
294+
}
295+
254296
void DeclRewriter::rewriteParmVarDecl(ParmVarDeclReplacement *N) {
255297
// First, find all the declarations of the containing function.
256298
DeclContext *DF = N->getDecl()->getParentFunctionOrMethod();
@@ -398,6 +440,9 @@ void DeclRewriter::rewriteMultiDecl(DeclReplacement *N, RSet &ToRewrite,
398440
R.InsertTextAfterToken(DL->getBeginLoc(), " " + Iter->second);
399441
}
400442
}
443+
// Make a note if the RecordDecl needs to be de-nested later.
444+
if (RD->getLexicalDeclContext() != RD->getDeclContext())
445+
RecordDeclsToDenest.push_back(RD);
401446
} else if (IsFirst) {
402447
// Rewriting the first declaration is easy. Nothing should change if its
403448
// type does not to be rewritten. When rewriting is required, it is

0 commit comments

Comments
 (0)