Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions clang/lib/Format/BreakableToken.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,10 +253,13 @@ unsigned BreakableStringLiteral::getContentStartColumn(unsigned LineIndex,

BreakableStringLiteral::BreakableStringLiteral(
const FormatToken &Tok, unsigned StartColumn, StringRef Prefix,
StringRef Postfix, unsigned UnbreakableTailLength, bool InPPDirective,
encoding::Encoding Encoding, const FormatStyle &Style)
StringRef Postfix, StringRef ContinuationPrefix,
StringRef ContinuationPostfix, unsigned UnbreakableTailLength,
bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style)
: BreakableToken(Tok, InPPDirective, Encoding, Style),
StartColumn(StartColumn), Prefix(Prefix), Postfix(Postfix),
ContinuationPrefix(ContinuationPrefix),
ContinuationPostfix(ContinuationPostfix),
UnbreakableTailLength(UnbreakableTailLength) {
assert(Tok.TokenText.starts_with(Prefix) && Tok.TokenText.ends_with(Postfix));
Line = Tok.TokenText.substr(
Expand All @@ -274,9 +277,14 @@ void BreakableStringLiteral::insertBreak(unsigned LineIndex,
unsigned TailOffset, Split Split,
unsigned ContentIndent,
WhitespaceManager &Whitespaces) const {

const unsigned SplitEnd = TailOffset + Split.first + Split.second;
const bool IsLastFragment = SplitEnd > Line.size() - UnbreakableTailLength;
StringRef LocalPostfix = (IsLastFragment) ? Postfix : ContinuationPostfix;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
StringRef LocalPostfix = (IsLastFragment) ? Postfix : ContinuationPostfix;
const StringRef LocalPostfix = IsLastFragment ? Postfix : ContinuationPostfix;


Whitespaces.replaceWhitespaceInToken(
Tok, Prefix.size() + TailOffset + Split.first, Split.second, Postfix,
Prefix, InPPDirective, 1, StartColumn);
Tok, ContinuationPrefix.size() + TailOffset + Split.first, Split.second,
LocalPostfix, ContinuationPrefix, InPPDirective, 1, StartColumn);
}

BreakableStringLiteralUsingOperators::BreakableStringLiteralUsingOperators(
Expand All @@ -288,6 +296,10 @@ BreakableStringLiteralUsingOperators::BreakableStringLiteralUsingOperators(
: QuoteStyle == AtDoubleQuotes ? "@\""
: "\"",
/*Postfix=*/QuoteStyle == SingleQuotes ? "'" : "\"",
/*ContinuationPrefix=*/QuoteStyle == SingleQuotes ? "'"
: QuoteStyle == AtDoubleQuotes ? "@\""
: "\"",
/*ContinuationPostfix=*/QuoteStyle == SingleQuotes ? "'" : "\"",
UnbreakableTailLength, InPPDirective, Encoding, Style),
BracesNeeded(Tok.isNot(TT_StringInConcatenation)),
QuoteStyle(QuoteStyle) {
Expand Down
12 changes: 10 additions & 2 deletions clang/lib/Format/BreakableToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ class BreakableStringLiteral : public BreakableToken {
/// after formatting.
BreakableStringLiteral(const FormatToken &Tok, unsigned StartColumn,
StringRef Prefix, StringRef Postfix,
StringRef ContinuationPrefix,
StringRef ContinuationPostfix,
unsigned UnbreakableTailLength, bool InPPDirective,
encoding::Encoding Encoding, const FormatStyle &Style);

Expand All @@ -274,15 +276,21 @@ class BreakableStringLiteral : public BreakableToken {
protected:
// The column in which the token starts.
unsigned StartColumn;
// The prefix a line needs after a break in the token.
// The prefix a line needs at the start
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// The prefix a line needs at the start
// The prefix a line needs at the start.

StringRef Prefix;
// The postfix a line needs before introducing a break.
// The postfix a line needs at the end
StringRef Postfix;
// The prefix every line except the first line needs
StringRef ContinuationPrefix;
// The postfix every line except the last line needs
StringRef ContinuationPostfix;
// The token text excluding the prefix and postfix.
StringRef Line;
// Length of the sequence of tokens after this string literal that cannot
// contain line breaks.
unsigned UnbreakableTailLength;
// Whether the string prefix and postfix should be repeated on each line
// when breaking the string.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover?

};

class BreakableStringLiteralUsingOperators : public BreakableStringLiteral {
Expand Down
44 changes: 34 additions & 10 deletions clang/lib/Format/ContinuationIndenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2540,22 +2540,46 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current,

StringRef Prefix;
StringRef Postfix;

// FIXME: Handle whitespace between '_T', '(', '"..."', and ')'.
// FIXME: Store Prefix and Suffix (or PrefixLength and SuffixLength to
// reduce the overhead) for each FormatToken, which is a string, so that we
// don't run multiple checks here on the hot path.
if ((Text.ends_with(Postfix = "\"") &&
(Text.starts_with(Prefix = "@\"") || Text.starts_with(Prefix = "\"") ||
Text.starts_with(Prefix = "u\"") ||
Text.starts_with(Prefix = "U\"") ||
Text.starts_with(Prefix = "u8\"") ||
Text.starts_with(Prefix = "L\""))) ||
(Text.starts_with(Prefix = "_T(\"") &&
Text.ends_with(Postfix = "\")"))) {
if (Text.starts_with(Prefix = "_T(\"") && Text.ends_with(Postfix = "\")")) {
// We need to put `_T("` and `")` on each line because it is a macro
llvm::StringRef ContinuationPrefix = Prefix;
llvm::StringRef ContinuationPostfix = Postfix;

return std::make_unique<BreakableStringLiteral>(
Current, StartColumn, Prefix, Postfix, UnbreakableTailLength,
State.Line->InPPDirective, Encoding, Style);
Current, StartColumn, Prefix, Postfix, ContinuationPrefix,
ContinuationPostfix, UnbreakableTailLength, State.Line->InPPDirective,
Encoding, Style);
}

static const auto PostfixRegex =
llvm::Regex(R"("(_[a-zA-Z_][a-zA-Z0-9_]*)?$)");
llvm::SmallVector<llvm::StringRef, 1> Matches;

if (PostfixRegex.match(Text, &Matches)) {
Comment on lines +2561 to +2563
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
llvm::SmallVector<llvm::StringRef, 1> Matches;
if (PostfixRegex.match(Text, &Matches)) {
if (llvm::SmallVector<llvm::StringRef, 1> Matches; PostfixRegex.match(Text, &Matches)) {

Postfix = Matches.front();

if ((Text.starts_with(Prefix = "@\"") ||
Text.starts_with(Prefix = "\"") ||
Text.starts_with(Prefix = "u\"") ||
Text.starts_with(Prefix = "U\"") ||
Text.starts_with(Prefix = "u8\"") ||
Text.starts_with(Prefix = "L\""))) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop empty line.

// Repeat the prefix on every line but don't repeat the suffix
llvm::StringRef ContinuationPrefix = Prefix;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
llvm::StringRef ContinuationPrefix = Prefix;
const StringRef ContinuationPrefix = Prefix;

llvm::StringRef ContinuationPostfix = "\"";
return std::make_unique<BreakableStringLiteral>(
Current, StartColumn, Prefix, Postfix, ContinuationPrefix,
ContinuationPostfix, UnbreakableTailLength,
State.Line->InPPDirective, Encoding, Style);
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop

} else if (Current.is(TT_BlockComment)) {
if (Style.ReflowComments == FormatStyle::RCS_Never ||
// If a comment token switches formatting, like
Expand Down
4 changes: 4 additions & 0 deletions clang/unittests/Format/FormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15838,6 +15838,10 @@ TEST_F(FormatTest, BreaksWideAndNSStringLiterals) {
"@\"NSString literal\";", getGoogleStyleWithColumns(19));
verifyFormat(R"(NSString *s = @"那那那那";)", getLLVMStyleWithColumns(26));

EXPECT_EQ("L\"suffixed \"\n"
"L\"string\"_s;",
format("L\"suffixed string\"_s;", getLLVMStyleWithColumns(19)));
Comment on lines +15841 to +15843
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
EXPECT_EQ("L\"suffixed \"\n"
"L\"string\"_s;",
format("L\"suffixed string\"_s;", getLLVMStyleWithColumns(19)));
verifyFormat("L\"suffixed \"\n"
"L\"string\"_s;",
"L\"suffixed string\"_s;", getLLVMStyleWithColumns(19)));


// This input makes clang-format try to split the incomplete unicode escape
// sequence, which used to lead to a crasher.
verifyNoCrash(
Expand Down