Skip to content

Commit 739bebc

Browse files
Work around Rewriter::ReplaceText bug with a previous insertion.
1 parent d7b3ade commit 739bebc

File tree

1 file changed

+26
-2
lines changed

1 file changed

+26
-2
lines changed

clang/lib/3C/RewriteUtils.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,37 @@ void rewriteSourceRange(Rewriter &R, const SourceRange &Range,
129129
ErrFail);
130130
}
131131

132+
// Wrapper for Rewriter::ReplaceText(CharSourceRange, StringRef) that works
133+
// around a bug that occurs when text has previously been inserted at the start
134+
// location of the specified range.
135+
//
136+
// When Rewriter::ReplaceText(CharSourceRange, StringRef) computes the range of
137+
// the rewrite buffer to replace, it sets the start location to be after the
138+
// previous insertion (RewriteBuffer::ReplaceText calls getMappedOffset with
139+
// AfterInserts = true) but sets the length to include the length of the
140+
// previous insertion (it calls getRangeSize with the default RewriteOptions
141+
// with IncludeInsertsAtBeginOfRange = true). This causes the range to extend
142+
// beyond the intended end location by an amount equal to the length of the
143+
// previous insertion. We avoid the problem by calling getRangeSize ourselves
144+
// with IncludeInsertsAtBeginOfRange = false.
145+
//
146+
// TODO: File an upstream Clang bug report if appropriate. As of this writing
147+
// (2021-11-24), we found some discussion of the problem
148+
// (https://reviews.llvm.org/D107503) but not a real entry in the bug tracker.
149+
static bool replaceTextWorkaround(Rewriter &R, const CharSourceRange &Range,
150+
const std::string &NewText) {
151+
Rewriter::RewriteOptions Opts;
152+
Opts.IncludeInsertsAtBeginOfRange = false;
153+
return R.ReplaceText(Range.getBegin(), R.getRangeSize(Range, Opts), NewText);
154+
}
155+
132156
void rewriteSourceRange(Rewriter &R, const CharSourceRange &Range,
133157
const std::string &NewText, bool ErrFail) {
134158
// Attempt to rewrite the source range. First use the source range directly
135159
// from the parameter.
136160
bool RewriteSuccess = false;
137161
if (canRewrite(R, Range))
138-
RewriteSuccess = !R.ReplaceText(Range, NewText);
162+
RewriteSuccess = !replaceTextWorkaround(R, Range, NewText);
139163

140164
// If initial rewriting attempt failed (either because canRewrite returned
141165
// false or because ReplaceText failed (returning true), try rewriting again
@@ -144,7 +168,7 @@ void rewriteSourceRange(Rewriter &R, const CharSourceRange &Range,
144168
CharSourceRange Expand = clang::Lexer::makeFileCharRange(
145169
Range, R.getSourceMgr(), R.getLangOpts());
146170
if (canRewrite(R, Expand))
147-
RewriteSuccess = !R.ReplaceText(Expand, NewText);
171+
RewriteSuccess = !replaceTextWorkaround(R, Expand, NewText);
148172
}
149173

150174
// Emit an error if we were unable to rewrite the source range. This is more

0 commit comments

Comments
 (0)