Skip to content

Commit d211fd1

Browse files
committed
Add splitting for user-defined suffixes
1 parent c2fe1d9 commit d211fd1

File tree

3 files changed

+61
-16
lines changed

3 files changed

+61
-16
lines changed

clang/lib/Format/BreakableToken.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,10 +253,13 @@ unsigned BreakableStringLiteral::getContentStartColumn(unsigned LineIndex,
253253

254254
BreakableStringLiteral::BreakableStringLiteral(
255255
const FormatToken &Tok, unsigned StartColumn, StringRef Prefix,
256-
StringRef Postfix, unsigned UnbreakableTailLength, bool InPPDirective,
257-
encoding::Encoding Encoding, const FormatStyle &Style)
256+
StringRef Postfix, StringRef ContinuationPrefix,
257+
StringRef ContinuationPostfix, unsigned UnbreakableTailLength,
258+
bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style)
258259
: BreakableToken(Tok, InPPDirective, Encoding, Style),
259260
StartColumn(StartColumn), Prefix(Prefix), Postfix(Postfix),
261+
ContinuationPrefix(ContinuationPrefix),
262+
ContinuationPostfix(ContinuationPostfix),
260263
UnbreakableTailLength(UnbreakableTailLength) {
261264
assert(Tok.TokenText.starts_with(Prefix) && Tok.TokenText.ends_with(Postfix));
262265
Line = Tok.TokenText.substr(
@@ -274,9 +277,15 @@ void BreakableStringLiteral::insertBreak(unsigned LineIndex,
274277
unsigned TailOffset, Split Split,
275278
unsigned ContentIndent,
276279
WhitespaceManager &Whitespaces) const {
280+
281+
const unsigned SplitEnd = TailOffset + Split.first + Split.second;
282+
const bool IsLastFragment = SplitEnd >= Line.size() - UnbreakableTailLength;
283+
284+
StringRef LocalPostfix = (IsLastFragment) ? Postfix : ContinuationPostfix;
285+
277286
Whitespaces.replaceWhitespaceInToken(
278-
Tok, Prefix.size() + TailOffset + Split.first, Split.second, Postfix,
279-
Prefix, InPPDirective, 1, StartColumn);
287+
Tok, ContinuationPrefix.size() + TailOffset + Split.first, Split.second,
288+
LocalPostfix, ContinuationPrefix, InPPDirective, 1, StartColumn);
280289
}
281290

282291
BreakableStringLiteralUsingOperators::BreakableStringLiteralUsingOperators(
@@ -288,6 +297,10 @@ BreakableStringLiteralUsingOperators::BreakableStringLiteralUsingOperators(
288297
: QuoteStyle == AtDoubleQuotes ? "@\""
289298
: "\"",
290299
/*Postfix=*/QuoteStyle == SingleQuotes ? "'" : "\"",
300+
/*ContinuationPrefix=*/QuoteStyle == SingleQuotes ? "'"
301+
: QuoteStyle == AtDoubleQuotes ? "@\""
302+
: "\"",
303+
/*ContinuationPostfix=*/QuoteStyle == SingleQuotes ? "'" : "\"",
291304
UnbreakableTailLength, InPPDirective, Encoding, Style),
292305
BracesNeeded(Tok.isNot(TT_StringInConcatenation)),
293306
QuoteStyle(QuoteStyle) {

clang/lib/Format/BreakableToken.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,8 @@ class BreakableStringLiteral : public BreakableToken {
252252
/// after formatting.
253253
BreakableStringLiteral(const FormatToken &Tok, unsigned StartColumn,
254254
StringRef Prefix, StringRef Postfix,
255+
StringRef ContinuationPrefix,
256+
StringRef ContinuationPostfix,
255257
unsigned UnbreakableTailLength, bool InPPDirective,
256258
encoding::Encoding Encoding, const FormatStyle &Style);
257259

@@ -274,15 +276,21 @@ class BreakableStringLiteral : public BreakableToken {
274276
protected:
275277
// The column in which the token starts.
276278
unsigned StartColumn;
277-
// The prefix a line needs after a break in the token.
279+
// The prefix a line needs at the start
278280
StringRef Prefix;
279-
// The postfix a line needs before introducing a break.
281+
// The postfix a line needs at the end
280282
StringRef Postfix;
283+
// The prefix every line except the first line needs
284+
StringRef ContinuationPrefix;
285+
// The postfix every line except the last line needs
286+
StringRef ContinuationPostfix;
281287
// The token text excluding the prefix and postfix.
282288
StringRef Line;
283289
// Length of the sequence of tokens after this string literal that cannot
284290
// contain line breaks.
285291
unsigned UnbreakableTailLength;
292+
// Whether the string prefix and postfix should be repeated on each line
293+
// when breaking the string.
286294
};
287295

288296
class BreakableStringLiteralUsingOperators : public BreakableStringLiteral {

clang/lib/Format/ContinuationIndenter.cpp

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2540,22 +2540,46 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current,
25402540

25412541
StringRef Prefix;
25422542
StringRef Postfix;
2543+
25432544
// FIXME: Handle whitespace between '_T', '(', '"..."', and ')'.
25442545
// FIXME: Store Prefix and Suffix (or PrefixLength and SuffixLength to
25452546
// reduce the overhead) for each FormatToken, which is a string, so that we
25462547
// don't run multiple checks here on the hot path.
2547-
if ((Text.ends_with(Postfix = "\"") &&
2548-
(Text.starts_with(Prefix = "@\"") || Text.starts_with(Prefix = "\"") ||
2549-
Text.starts_with(Prefix = "u\"") ||
2550-
Text.starts_with(Prefix = "U\"") ||
2551-
Text.starts_with(Prefix = "u8\"") ||
2552-
Text.starts_with(Prefix = "L\""))) ||
2553-
(Text.starts_with(Prefix = "_T(\"") &&
2554-
Text.ends_with(Postfix = "\")"))) {
2548+
if (Text.starts_with(Prefix = "_T(\"") && Text.ends_with(Postfix = "\")")) {
2549+
// We need to put `_T("` and `")` on each line because it is a macro
2550+
llvm::StringRef ContinuationPrefix = Prefix;
2551+
llvm::StringRef ContinuationPostfix = Postfix;
2552+
25552553
return std::make_unique<BreakableStringLiteral>(
2556-
Current, StartColumn, Prefix, Postfix, UnbreakableTailLength,
2557-
State.Line->InPPDirective, Encoding, Style);
2554+
Current, StartColumn, Prefix, Postfix, ContinuationPrefix,
2555+
ContinuationPostfix, UnbreakableTailLength, State.Line->InPPDirective,
2556+
Encoding, Style);
2557+
}
2558+
2559+
static const auto PostfixRegex =
2560+
llvm::Regex(R"("(_[a-zA-Z_][a-zA-Z0-9_]*)?$)");
2561+
llvm::SmallVector<llvm::StringRef, 1> Matches;
2562+
2563+
if (PostfixRegex.match(Text, &Matches)) {
2564+
Postfix = Matches.front();
2565+
2566+
if ((Text.starts_with(Prefix = "@\"") ||
2567+
Text.starts_with(Prefix = "\"") ||
2568+
Text.starts_with(Prefix = "u\"") ||
2569+
Text.starts_with(Prefix = "U\"") ||
2570+
Text.starts_with(Prefix = "u8\"") ||
2571+
Text.starts_with(Prefix = "L\""))) {
2572+
2573+
// Use quotes when breaking the string
2574+
llvm::StringRef ContinuationPrefix = "\"";
2575+
llvm::StringRef ContinuationPostfix = "\"";
2576+
return std::make_unique<BreakableStringLiteral>(
2577+
Current, StartColumn, Prefix, Postfix, ContinuationPrefix,
2578+
ContinuationPostfix, UnbreakableTailLength,
2579+
State.Line->InPPDirective, Encoding, Style);
2580+
}
25582581
}
2582+
25592583
} else if (Current.is(TT_BlockComment)) {
25602584
if (Style.ReflowComments == FormatStyle::RCS_Never ||
25612585
// If a comment token switches formatting, like

0 commit comments

Comments
 (0)