@@ -102,6 +102,18 @@ static llvm::Optional<StringRef> getRawStringDelimiter(StringRef TokenText) {
102
102
return Delimiter;
103
103
}
104
104
105
+ // Returns the canonical delimiter for \p Language, or the empty string if no
106
+ // canonical delimiter is specified.
107
+ static StringRef
108
+ getCanonicalRawStringDelimiter (const FormatStyle &Style ,
109
+ FormatStyle::LanguageKind Language) {
110
+ for (const auto &Format : Style .RawStringFormats ) {
111
+ if (Format.Language == Language)
112
+ return StringRef (Format.CanonicalDelimiter );
113
+ }
114
+ return " " ;
115
+ }
116
+
105
117
RawStringFormatStyleManager::RawStringFormatStyleManager (
106
118
const FormatStyle &CodeStyle) {
107
119
for (const auto &RawStringFormat : CodeStyle.RawStringFormats ) {
@@ -1312,14 +1324,32 @@ unsigned ContinuationIndenter::reformatRawStringLiteral(
1312
1324
const FormatToken &Current, LineState &State,
1313
1325
const FormatStyle &RawStringStyle, bool DryRun) {
1314
1326
unsigned StartColumn = State.Column - Current.ColumnWidth ;
1315
- auto Delimiter = *getRawStringDelimiter (Current.TokenText );
1327
+ StringRef OldDelimiter = *getRawStringDelimiter (Current.TokenText );
1328
+ StringRef NewDelimiter =
1329
+ getCanonicalRawStringDelimiter (Style , RawStringStyle.Language );
1330
+ if (NewDelimiter.empty () || OldDelimiter.empty ())
1331
+ NewDelimiter = OldDelimiter;
1316
1332
// The text of a raw string is between the leading 'R"delimiter(' and the
1317
1333
// trailing 'delimiter)"'.
1318
- unsigned PrefixSize = 3 + Delimiter.size ();
1319
- unsigned SuffixSize = 2 + Delimiter.size ();
1334
+ unsigned OldPrefixSize = 3 + OldDelimiter.size ();
1335
+ unsigned OldSuffixSize = 2 + OldDelimiter.size ();
1336
+ // We create a virtual text environment which expects a null-terminated
1337
+ // string, so we cannot use StringRef.
1338
+ std::string RawText =
1339
+ Current.TokenText .substr (OldPrefixSize).drop_back (OldSuffixSize);
1340
+ if (NewDelimiter != OldDelimiter) {
1341
+ // Don't update to the canonical delimiter 'deli' if ')deli"' occurs in the
1342
+ // raw string.
1343
+ std::string CanonicalDelimiterSuffix = (" )" + NewDelimiter + " \" " ).str ();
1344
+ if (StringRef (RawText).contains (CanonicalDelimiterSuffix))
1345
+ NewDelimiter = OldDelimiter;
1346
+ }
1347
+
1348
+ unsigned NewPrefixSize = 3 + NewDelimiter.size ();
1349
+ unsigned NewSuffixSize = 2 + NewDelimiter.size ();
1320
1350
1321
- // The first start column is the column the raw text starts.
1322
- unsigned FirstStartColumn = StartColumn + PrefixSize ;
1351
+ // The first start column is the column the raw text starts after formatting .
1352
+ unsigned FirstStartColumn = StartColumn + NewPrefixSize ;
1323
1353
1324
1354
// The next start column is the intended indentation a line break inside
1325
1355
// the raw string at level 0. It is determined by the following rules:
@@ -1330,7 +1360,7 @@ unsigned ContinuationIndenter::reformatRawStringLiteral(
1330
1360
// These rules have the advantage that the formatted content both does not
1331
1361
// violate the rectangle rule and visually flows within the surrounding
1332
1362
// source.
1333
- bool ContentStartsOnNewline = Current.TokenText [PrefixSize ] == ' \n ' ;
1363
+ bool ContentStartsOnNewline = Current.TokenText [OldPrefixSize ] == ' \n ' ;
1334
1364
unsigned NextStartColumn = ContentStartsOnNewline
1335
1365
? State.Stack .back ().Indent + Style .IndentWidth
1336
1366
: FirstStartColumn;
@@ -1344,12 +1374,9 @@ unsigned ContinuationIndenter::reformatRawStringLiteral(
1344
1374
// - if the raw string prefix does not start on a newline, it is the current
1345
1375
// indent.
1346
1376
unsigned LastStartColumn = Current.NewlinesBefore
1347
- ? FirstStartColumn - PrefixSize
1377
+ ? FirstStartColumn - NewPrefixSize
1348
1378
: State.Stack .back ().Indent ;
1349
1379
1350
- std::string RawText =
1351
- Current.TokenText .substr (PrefixSize).drop_back (SuffixSize);
1352
-
1353
1380
std::pair<tooling::Replacements, unsigned > Fixes = internal::reformat (
1354
1381
RawStringStyle, RawText, {tooling::Range (0 , RawText.size ())},
1355
1382
FirstStartColumn, NextStartColumn, LastStartColumn, " <stdin>" ,
@@ -1362,8 +1389,33 @@ unsigned ContinuationIndenter::reformatRawStringLiteral(
1362
1389
return 0 ;
1363
1390
}
1364
1391
if (!DryRun) {
1392
+ if (NewDelimiter != OldDelimiter) {
1393
+ // In 'R"delimiter(...', the delimiter starts 2 characters after the start
1394
+ // of the token.
1395
+ SourceLocation PrefixDelimiterStart =
1396
+ Current.Tok .getLocation ().getLocWithOffset (2 );
1397
+ auto PrefixErr = Whitespaces.addReplacement (tooling::Replacement (
1398
+ SourceMgr, PrefixDelimiterStart, OldDelimiter.size (), NewDelimiter));
1399
+ if (PrefixErr) {
1400
+ llvm::errs ()
1401
+ << " Failed to update the prefix delimiter of a raw string: "
1402
+ << llvm::toString (std::move (PrefixErr)) << " \n " ;
1403
+ }
1404
+ // In 'R"delimiter(...)delimiter"', the suffix delimiter starts at
1405
+ // position length - 1 - |delimiter|.
1406
+ SourceLocation SuffixDelimiterStart =
1407
+ Current.Tok .getLocation ().getLocWithOffset (Current.TokenText .size () -
1408
+ 1 - OldDelimiter.size ());
1409
+ auto SuffixErr = Whitespaces.addReplacement (tooling::Replacement (
1410
+ SourceMgr, SuffixDelimiterStart, OldDelimiter.size (), NewDelimiter));
1411
+ if (SuffixErr) {
1412
+ llvm::errs ()
1413
+ << " Failed to update the suffix delimiter of a raw string: "
1414
+ << llvm::toString (std::move (SuffixErr)) << " \n " ;
1415
+ }
1416
+ }
1365
1417
SourceLocation OriginLoc =
1366
- Current.Tok .getLocation ().getLocWithOffset (PrefixSize );
1418
+ Current.Tok .getLocation ().getLocWithOffset (OldPrefixSize );
1367
1419
for (const tooling::Replacement &Fix : Fixes.first ) {
1368
1420
auto Err = Whitespaces.addReplacement (tooling::Replacement (
1369
1421
SourceMgr, OriginLoc.getLocWithOffset (Fix.getOffset ()),
@@ -1376,7 +1428,7 @@ unsigned ContinuationIndenter::reformatRawStringLiteral(
1376
1428
}
1377
1429
unsigned RawLastLineEndColumn = getLastLineEndColumn (
1378
1430
*NewCode, FirstStartColumn, Style .TabWidth , Encoding);
1379
- State.Column = RawLastLineEndColumn + SuffixSize ;
1431
+ State.Column = RawLastLineEndColumn + NewSuffixSize ;
1380
1432
return Fixes.second ;
1381
1433
}
1382
1434
0 commit comments