@@ -501,19 +501,52 @@ void DeclRewriter::rewriteMultiDecl(MultiDeclInfo &MDI, RSet &ToRewrite) {
501
501
}
502
502
}
503
503
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.
506
508
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
+ }
507
536
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;
517
550
}
518
551
}
519
552
@@ -548,10 +581,6 @@ void DeclRewriter::doDeclRewrite(SourceRange &SR, DeclReplacement *N) {
548
581
}
549
582
550
583
rewriteSourceRange (R, SR, Replacement);
551
-
552
- SourceLocation L = getLocationAfter (N->getDecl ()->getEndLoc (),
553
- A.getSourceManager (), A.getLangOpts ());
554
- emitSupplementaryDeclarations (N->getSupplementaryDecls (), L);
555
584
}
556
585
557
586
void DeclRewriter::rewriteFunctionDecl (FunctionDeclReplacement *N) {
@@ -561,8 +590,10 @@ void DeclRewriter::rewriteFunctionDecl(FunctionDeclReplacement *N) {
561
590
Stmt *S = N->getDecl ()->getBody ();
562
591
assert (" Supplementary declarations should only exist on rewritings for "
563
592
" function definitions." && S != nullptr );
593
+ // Insert supplementary declarations after the opening curly brace of the
594
+ // function body.
564
595
emitSupplementaryDeclarations (N->getSupplementaryDecls (),
565
- N-> getDecl ()-> getBody () ->getBeginLoc ());
596
+ S ->getBeginLoc ());
566
597
}
567
598
}
568
599
@@ -578,27 +609,24 @@ void DeclRewriter::emitSupplementaryDeclarations(
578
609
std::string AllDecls;
579
610
for (std::string D : SDecls)
580
611
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 " ;
584
612
585
- R.InsertTextAfter (getLocationAfter (Loc, R.getSourceMgr (), R.getLangOpts ()),
586
- AllDecls);
613
+ R.InsertText (getLocationAfter (Loc, R.getSourceMgr (), R.getLangOpts ()),
614
+ AllDecls);
587
615
}
588
616
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
590
618
// the given source location. This is used to find the end of each declaration
591
619
// within a multi-declaration.
592
- SourceRange DeclRewriter::getNextComma (SourceLocation L) {
620
+ SourceLocation DeclRewriter::getNextCommaOrSemicolon (SourceLocation L) {
593
621
SourceManager &SM = A.getSourceManager ();
594
622
auto Tok = Lexer::findNextToken (L, SM, A.getLangOpts ());
595
623
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 ();
598
626
Tok = Lexer::findNextToken (Tok->getEndLoc (), A.getSourceManager (),
599
627
A.getLangOpts ());
600
628
}
601
- llvm_unreachable (" Unable to find comma at source location." );
629
+ llvm_unreachable (" Unable to find comma or semicolon at source location." );
602
630
}
603
631
604
632
// This function checks how to re-write a function declaration.
0 commit comments