Skip to content

Commit 48fad85

Browse files
Use getNextComma to insert supplementary declarations in a multi-decl.
With this change, all callers of emitSupplementaryDeclarations want it to add a newline at the beginning and not the end, so we can remove the extra newline there. - Change getNextComma back to getNextCommaOrSemicolon as it was before PR #657. - Some other comment fixes and minor refactorings. Notably: in emitSupplementaryDeclarations, change the InsertTextAfter call to the equivalent InsertText to try to avoid confusion with InsertTextAfterToken.
1 parent 9dbcca8 commit 48fad85

File tree

2 files changed

+60
-27
lines changed

2 files changed

+60
-27
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,14 @@ class DeclRewriter {
6161
void rewriteMultiDecl(MultiDeclInfo &MDI, RSet &ToRewrite);
6262
void doDeclRewrite(SourceRange &SR, DeclReplacement *N);
6363
void rewriteFunctionDecl(FunctionDeclReplacement *N);
64+
// Emit supplementary declarations _after_ the token that begins at Loc.
65+
// Inserts a newline before the first supplementary declaration but not after
66+
// the last supplementary declaration. This is suitable if Loc is expected to
67+
// be the last token on a line or if rewriteMultiDecl will insert a newline
68+
// after the supplementary declarations later.
6469
void emitSupplementaryDeclarations(const std::vector<std::string> &SDecls,
6570
SourceLocation Loc);
66-
SourceRange getNextComma(SourceLocation L);
71+
SourceLocation getNextCommaOrSemicolon(SourceLocation L);
6772
void denestTagDecls();
6873
};
6974

clang/lib/3C/DeclRewriter.cpp

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -501,19 +501,52 @@ void DeclRewriter::rewriteMultiDecl(MultiDeclInfo &MDI, RSet &ToRewrite) {
501501
}
502502
}
503503

504-
// Variables in a multi-decl are delimited by commas. The rewritten decls
505-
// are separate statements separated by a semicolon and a newline.
504+
// Processing related to the comma or semicolon ("terminator") that follows
505+
// the multi-decl member. Members are separated by commas, and the last
506+
// member is terminated by a semicolon. The rewritten decls are each
507+
// terminated by a semicolon and are separated by newlines.
506508
bool IsLast = (MIt + 1 == MDI.Members.end());
509+
bool HaveSupplementaryDecls =
510+
(Replacement && !Replacement->getSupplementaryDecls().empty());
511+
// Unlike in ReplaceSR, we want to start searching for the terminator after
512+
// the entire multi-decl member, including any existing initializer.
513+
SourceRange FullSR =
514+
getDeclSourceRangeWithAnnotations(DL, /*IncludeInitializer=*/true);
515+
// Search for the terminator.
516+
//
517+
// FIXME: If the terminator is hidden inside a macro,
518+
// getNextCommaOrSemicolon will continue scanning and may return a comma or
519+
// semicolon later in the file (which has bizarre consequences if we try to
520+
// use it to rewrite this multi-decl) or fail an assertion if it doesn't
521+
// find one. As a stopgap for the existing regression test in
522+
// macro_rewrite_error.c that has a semicolon inside a macro, we only search
523+
// for the terminator if we actually need it.
524+
SourceLocation Terminator;
525+
if (!IsLast || HaveSupplementaryDecls) {
526+
Terminator = getNextCommaOrSemicolon(FullSR.getEnd());
527+
}
528+
if (!IsLast) {
529+
// We expect the terminator to be a comma. Change it to a semicolon.
530+
rewriteSourceRange(R, SourceRange(Terminator, Terminator), ";");
531+
}
532+
if (HaveSupplementaryDecls) {
533+
emitSupplementaryDeclarations(Replacement->getSupplementaryDecls(),
534+
Terminator);
535+
}
507536
if (!IsLast) {
508-
// This differs from ReplaceSR in that we want to advance past the entire
509-
// multi-decl member, _including_ any existing initializer.
510-
SourceRange SkipSR =
511-
getDeclSourceRangeWithAnnotations(DL, /*IncludeInitializer=*/true);
512-
SourceRange Comma = getNextComma(SkipSR.getEnd());
513-
rewriteSourceRange(R, Comma, ";\n");
514-
// Offset by one to skip past what we've just added so it isn't
515-
// overwritten.
516-
PrevEnd = Comma.getEnd().getLocWithOffset(1);
537+
// Insert a newline between this multi-decl member and the next. The
538+
// Rewriter preserves the order of insertions at the same location, so if
539+
// there are supplementary declarations, this newline will go between them
540+
// and the next member, which is what we want because
541+
// emitSupplementaryDeclarations by itself doesn't add a newline after the
542+
// supplementary declarations.
543+
SourceLocation AfterTerminator =
544+
getLocationAfter(Terminator, A.getSourceManager(), A.getLangOpts());
545+
R.InsertText(AfterTerminator, "\n");
546+
// When rewriting the next member, start after the terminator. The
547+
// Rewriter is smart enough not to mess with anything we already inserted
548+
// at that location.
549+
PrevEnd = AfterTerminator;
517550
}
518551
}
519552

@@ -548,10 +581,6 @@ void DeclRewriter::doDeclRewrite(SourceRange &SR, DeclReplacement *N) {
548581
}
549582

550583
rewriteSourceRange(R, SR, Replacement);
551-
552-
SourceLocation L = getLocationAfter(N->getDecl()->getEndLoc(),
553-
A.getSourceManager(), A.getLangOpts());
554-
emitSupplementaryDeclarations(N->getSupplementaryDecls(), L);
555584
}
556585

557586
void DeclRewriter::rewriteFunctionDecl(FunctionDeclReplacement *N) {
@@ -561,8 +590,10 @@ void DeclRewriter::rewriteFunctionDecl(FunctionDeclReplacement *N) {
561590
Stmt *S = N->getDecl()->getBody();
562591
assert("Supplementary declarations should only exist on rewritings for "
563592
"function definitions." && S != nullptr);
593+
// Insert supplementary declarations after the opening curly brace of the
594+
// function body.
564595
emitSupplementaryDeclarations(N->getSupplementaryDecls(),
565-
N->getDecl()->getBody()->getBeginLoc());
596+
S->getBeginLoc());
566597
}
567598
}
568599

@@ -578,27 +609,24 @@ void DeclRewriter::emitSupplementaryDeclarations(
578609
std::string AllDecls;
579610
for (std::string D : SDecls)
580611
AllDecls += "\n" + D;
581-
// FIXME: This adds an extra new line after the declaration(s), but is needed
582-
// for proper rewriting in multi-declarations.
583-
AllDecls += "\n";
584612

585-
R.InsertTextAfter(getLocationAfter(Loc, R.getSourceMgr(), R.getLangOpts()),
586-
AllDecls);
613+
R.InsertText(getLocationAfter(Loc, R.getSourceMgr(), R.getLangOpts()),
614+
AllDecls);
587615
}
588616

589-
// Uses clangs lexer to find the location of the next comma after
617+
// Uses clangs lexer to find the location of the next comma or semicolon after
590618
// the given source location. This is used to find the end of each declaration
591619
// within a multi-declaration.
592-
SourceRange DeclRewriter::getNextComma(SourceLocation L) {
620+
SourceLocation DeclRewriter::getNextCommaOrSemicolon(SourceLocation L) {
593621
SourceManager &SM = A.getSourceManager();
594622
auto Tok = Lexer::findNextToken(L, SM, A.getLangOpts());
595623
while (Tok.hasValue() && !Tok->is(clang::tok::eof)) {
596-
if (Tok->is(clang::tok::comma))
597-
return SourceRange(Tok->getLocation(), Tok->getLocation());
624+
if (Tok->is(clang::tok::comma) || Tok->is(clang::tok::semi))
625+
return Tok->getLocation();
598626
Tok = Lexer::findNextToken(Tok->getEndLoc(), A.getSourceManager(),
599627
A.getLangOpts());
600628
}
601-
llvm_unreachable("Unable to find comma at source location.");
629+
llvm_unreachable("Unable to find comma or semicolon at source location.");
602630
}
603631

604632
// This function checks how to re-write a function declaration.

0 commit comments

Comments
 (0)