summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Format/ContinuationIndenter.cpp24
-rw-r--r--clang/lib/Format/ContinuationIndenter.h9
-rw-r--r--clang/lib/Format/FormatToken.h8
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp6
-rw-r--r--clang/unittests/Format/FormatTest.cpp22
5 files changed, 54 insertions, 15 deletions
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index ed5098bf48f..199fc022048 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -47,6 +47,12 @@ static bool startsBinaryExpression(const FormatToken &Tok) {
return false;
}
+// Returns \c true if \c Tok is the "." or "->" of a call and starts the next
+// segment of a builder type call.
+static bool startsSegmentOfBuilderTypeCall(const FormatToken &Tok) {
+ return Tok.isMemberAccess() && Tok.Previous && Tok.Previous->closesScope();
+}
+
ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
SourceManager &SourceMgr,
const AnnotatedLine &Line,
@@ -99,6 +105,8 @@ bool ContinuationIndenter::canBreak(const LineState &State) {
// As they hide "DoSomething" and are generally bad for readability.
if (Previous.opensScope() && State.LowestLevelOnLine < State.StartOfLineLevel)
return false;
+ if (Current.isMemberAccess() && State.Stack.back().ContainsUnwrappedBuilder)
+ return false;
return !State.Stack.back().NoLineBreak;
}
@@ -178,6 +186,9 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
Line.MightBeFunctionDecl && State.Stack.back().BreakBeforeParameter &&
State.ParenLevel == 0)
return true;
+ if (startsSegmentOfBuilderTypeCall(Current) &&
+ State.Stack.back().CallContinuation != 0)
+ return true;
return false;
}
@@ -232,8 +243,7 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline,
} else if (Current.is(tok::lessless) &&
State.Stack.back().FirstLessLess != 0) {
State.Column = State.Stack.back().FirstLessLess;
- } else if (Current.isOneOf(tok::period, tok::arrow) &&
- Current.Type != TT_DesignatedInitializerPeriod) {
+ } else if (Current.isMemberAccess()) {
if (State.Stack.back().CallContinuation == 0) {
State.Column = ContinuationIndent;
State.Stack.back().CallContinuation = State.Column;
@@ -299,8 +309,7 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline,
if (!Current.isTrailingComment())
State.Stack.back().LastSpace = State.Column;
- if (Current.isOneOf(tok::arrow, tok::period) &&
- Current.Type != TT_DesignatedInitializerPeriod)
+ if (Current.isMemberAccess())
State.Stack.back().LastSpace += Current.CodePointCount;
State.StartOfLineLevel = State.ParenLevel;
State.LowestLevelOnLine = State.ParenLevel;
@@ -369,6 +378,8 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline,
if (Previous.is(tok::comma) && !Current.isTrailingComment() &&
State.Stack.back().AvoidBinPacking)
State.Stack.back().NoLineBreak = true;
+ if (startsSegmentOfBuilderTypeCall(Current))
+ State.Stack.back().ContainsUnwrappedBuilder = true;
State.Column += Spaces;
if (Current.is(tok::l_paren) && Previous.isOneOf(tok::kw_if, tok::kw_for))
@@ -401,8 +412,7 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline,
bool HasTrailingCall = false;
if (Previous.MatchingParen) {
const FormatToken *Next = Previous.MatchingParen->getNextNonComment();
- if (Next && Next->isOneOf(tok::period, tok::arrow))
- HasTrailingCall = true;
+ HasTrailingCall = Next && Next->isMemberAccess();
}
if (HasMultipleParameters ||
(HasTrailingCall &&
@@ -431,7 +441,7 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
if (!Current.opensScope() && !Current.closesScope())
State.LowestLevelOnLine =
std::min(State.LowestLevelOnLine, State.ParenLevel);
- if (Current.isOneOf(tok::period, tok::arrow))
+ if (Current.isMemberAccess())
State.Stack.back().StartOfFunctionCall =
Current.LastInChainOfCalls ? 0 : State.Column + Current.CodePointCount;
if (Current.Type == TT_CtorInitializerColon) {
diff --git a/clang/lib/Format/ContinuationIndenter.h b/clang/lib/Format/ContinuationIndenter.h
index e234c3e7efd..81d14ad0a22 100644
--- a/clang/lib/Format/ContinuationIndenter.h
+++ b/clang/lib/Format/ContinuationIndenter.h
@@ -108,7 +108,8 @@ struct ParenState {
AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0),
StartOfArraySubscripts(0), NestedNameSpecifierContinuation(0),
- CallContinuation(0), VariablePos(0), ContainsLineBreak(false) {}
+ CallContinuation(0), VariablePos(0), ContainsLineBreak(false),
+ ContainsUnwrappedBuilder(0) {}
/// \brief The position to which a specific parenthesis level needs to be
/// indented.
@@ -178,6 +179,10 @@ struct ParenState {
/// parenthesis.
bool ContainsLineBreak;
+ /// \brief \c true if this \c ParenState contains multiple segments of a
+ /// builder-type call on one line.
+ bool ContainsUnwrappedBuilder;
+
bool operator<(const ParenState &Other) const {
if (Indent != Other.Indent)
return Indent < Other.Indent;
@@ -207,6 +212,8 @@ struct ParenState {
return VariablePos < Other.VariablePos;
if (ContainsLineBreak != Other.ContainsLineBreak)
return ContainsLineBreak < Other.ContainsLineBreak;
+ if (ContainsUnwrappedBuilder != Other.ContainsUnwrappedBuilder)
+ return ContainsUnwrappedBuilder < Other.ContainsUnwrappedBuilder;
return false;
}
};
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index 150a9755e22..62b0ba6adf2 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -257,6 +257,12 @@ struct FormatToken {
Type == TT_TemplateCloser;
}
+ /// \brief Returns \c true if this is a "." or "->" accessing a member.
+ bool isMemberAccess() const {
+ return isOneOf(tok::arrow, tok::period) &&
+ Type != TT_DesignatedInitializerPeriod;
+ }
+
bool isUnaryOperator() const {
switch (Tok.getKind()) {
case tok::plus:
@@ -272,10 +278,12 @@ struct FormatToken {
return false;
}
}
+
bool isBinaryOperator() const {
// Comma is a binary operator, but does not behave as such wrt. formatting.
return getPrecedence() > prec::Comma;
}
+
bool isTrailingComment() const {
return is(tok::comment) && (!Next || Next->NewlinesBefore > 0);
}
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index c8dfb13d78a..7f298555079 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -1100,10 +1100,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
Left.Type == TT_InheritanceColon)
return 2;
- if (Right.isOneOf(tok::arrow, tok::period) &&
- Right.Type != TT_DesignatedInitializerPeriod) {
- if (Left.isOneOf(tok::r_paren, tok::r_square) && Left.MatchingParen &&
- Left.MatchingParen->ParameterCount > 0)
+ if (Right.isMemberAccess()) {
+ if (Left.isOneOf(tok::r_paren, tok::r_square))
return 20; // Should be smaller than breaking at a nested comma.
return 150;
}
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 99a703a03df..1cc4389f3aa 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -2837,9 +2837,10 @@ TEST_F(FormatTest, FormatsBuilderPattern) {
"return llvm::StringSwitch<Reference::Kind>(name)\n"
" .StartsWith(\".eh_frame_hdr\", ORDER_EH_FRAMEHDR)\n"
" .StartsWith(\".eh_frame\", ORDER_EH_FRAME)\n"
- " .StartsWith(\".init\", ORDER_INIT).StartsWith(\".fini\", "
- "ORDER_FINI)\n"
- " .StartsWith(\".hash\", ORDER_HASH).Default(ORDER_TEXT);\n");
+ " .StartsWith(\".init\", ORDER_INIT)\n"
+ " .StartsWith(\".fini\", ORDER_FINI)\n"
+ " .StartsWith(\".hash\", ORDER_HASH)\n"
+ " .Default(ORDER_TEXT);\n");
verifyFormat("return aaaaaaaaaaaaaaaaa->aaaaa().aaaaaaaaaaaaa().aaaaaa() <\n"
" aaaaaaaaaaaaaaa->aaaaa().aaaaaaaaaaaaa().aaaaaa();");
@@ -2868,6 +2869,21 @@ TEST_F(FormatTest, FormatsBuilderPattern) {
" this, &HandlerHolderClass::EventHandlerCBD))\n"
" ->OnEvent6(NewPermanentCallback(\n"
" this, &HandlerHolderClass::EventHandlerCBE)));");
+
+ verifyFormat(
+ "aaaaaaaaaaa().aaaaaaaaaaa().aaaaaaaaaaa().aaaaaaaaaaa().aaaaaaaaaaa();");
+ verifyFormat("aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa();");
+ verifyFormat("aaaaaaaaaaaaaaa.aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa();");
+ verifyFormat("aaaaaaaaaaaaaaa.aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa.aaaaaaaaaaaaaaa()\n"
+ " .aaaaaaaaaaaaaaa();");
}
TEST_F(FormatTest, BreaksAccordingToOperatorPrecedence) {
OpenPOWER on IntegriCloud