Updated to Clang 3.5a.
Change-Id: I8127eb568f674c2e72635b639a3295381fe8af82
diff --git a/lib/Format/Android.mk b/lib/Format/Android.mk
new file mode 100644
index 0000000..302f28f
--- /dev/null
+++ b/lib/Format/Android.mk
@@ -0,0 +1,43 @@
+LOCAL_PATH:= $(call my-dir)
+
+# For the host only
+# =====================================================
+include $(CLEAR_VARS)
+include $(CLEAR_TBLGEN_VARS)
+
+TBLGEN_TABLES := \
+ AttrHasAttributeImpl.inc \
+ DiagnosticASTKinds.inc \
+ DiagnosticAnalysisKinds.inc \
+ DiagnosticCommentKinds.inc \
+ DiagnosticCommonKinds.inc \
+ DiagnosticDriverKinds.inc \
+ DiagnosticFrontendKinds.inc \
+ DiagnosticGroups.inc \
+ DiagnosticIndexName.inc \
+ DiagnosticLexKinds.inc \
+ DiagnosticParseKinds.inc \
+ DiagnosticSemaKinds.inc \
+ DiagnosticSerializationKinds.inc \
+ arm_neon.inc
+
+clang_format_SRC_FILES := \
+ BreakableToken.cpp \
+ ContinuationIndenter.cpp \
+ Format.cpp \
+ FormatToken.cpp \
+ TokenAnnotator.cpp \
+ UnwrappedLineParser.cpp \
+ WhitespaceManager.cpp
+
+LOCAL_SRC_FILES := $(clang_format_SRC_FILES)
+
+LOCAL_MODULE:= libclangFormat
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_TAGS := optional
+
+include $(CLANG_HOST_BUILD_MK)
+include $(CLANG_VERSION_INC_MK)
+include $(CLANG_TBLGEN_RULES_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/lib/Format/BreakableToken.cpp b/lib/Format/BreakableToken.cpp
index d720ce9..d43a774 100644
--- a/lib/Format/BreakableToken.cpp
+++ b/lib/Format/BreakableToken.cpp
@@ -92,9 +92,7 @@
return BreakableToken::Split(StringRef::npos, 0);
if (ColumnLimit <= UsedColumns)
return BreakableToken::Split(StringRef::npos, 0);
- unsigned MaxSplit = std::min<unsigned>(
- ColumnLimit - UsedColumns,
- encoding::columnWidthWithTabs(Text, UsedColumns, TabWidth, Encoding) - 1);
+ unsigned MaxSplit = ColumnLimit - UsedColumns;
StringRef::size_type SpaceOffset = 0;
StringRef::size_type SlashOffset = 0;
StringRef::size_type WordStartOffset = 0;
@@ -110,7 +108,7 @@
Text.substr(0, Advance), UsedColumns + Chars, TabWidth, Encoding);
}
- if (Chars > MaxSplit)
+ if (Chars > MaxSplit || Text.size() == Advance)
break;
if (IsBlank(Text[0]))
@@ -151,7 +149,7 @@
encoding::Encoding Encoding, const FormatStyle &Style)
: BreakableToken(Tok, IndentLevel, InPPDirective, Encoding, Style),
StartColumn(StartColumn), Prefix(Prefix), Postfix(Postfix) {
- assert(Tok.TokenText.startswith(Prefix) && Tok.TokenText.endswith(Postfix));
+ assert(Tok.TokenText.endswith(Postfix));
Line = Tok.TokenText.substr(
Prefix.size(), Tok.TokenText.size() - Prefix.size() - Postfix.size());
}
@@ -174,24 +172,38 @@
void BreakableStringLiteral::insertBreak(unsigned LineIndex,
unsigned TailOffset, Split Split,
WhitespaceManager &Whitespaces) {
+ unsigned LeadingSpaces = StartColumn;
+ // The '@' of an ObjC string literal (@"Test") does not become part of the
+ // string token.
+ // FIXME: It might be a cleaner solution to merge the tokens as a
+ // precomputation step.
+ if (Prefix.startswith("@"))
+ --LeadingSpaces;
Whitespaces.replaceWhitespaceInToken(
Tok, Prefix.size() + TailOffset + Split.first, Split.second, Postfix,
- Prefix, InPPDirective, 1, IndentLevel, StartColumn);
+ Prefix, InPPDirective, 1, IndentLevel, LeadingSpaces);
}
-static StringRef getLineCommentPrefix(StringRef Comment) {
- static const char *const KnownPrefixes[] = { "/// ", "///", "// ", "//" };
- for (size_t i = 0, e = llvm::array_lengthof(KnownPrefixes); i != e; ++i)
- if (Comment.startswith(KnownPrefixes[i]))
- return KnownPrefixes[i];
- return "";
+static StringRef getLineCommentIndentPrefix(StringRef Comment) {
+ static const char *const KnownPrefixes[] = { "///", "//" };
+ StringRef LongestPrefix;
+ for (StringRef KnownPrefix : KnownPrefixes) {
+ if (Comment.startswith(KnownPrefix)) {
+ size_t PrefixLength = KnownPrefix.size();
+ while (PrefixLength < Comment.size() && Comment[PrefixLength] == ' ')
+ ++PrefixLength;
+ if (PrefixLength > LongestPrefix.size())
+ LongestPrefix = Comment.substr(0, PrefixLength);
+ }
+ }
+ return LongestPrefix;
}
BreakableLineComment::BreakableLineComment(
const FormatToken &Token, unsigned IndentLevel, unsigned StartColumn,
bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style)
: BreakableSingleLineToken(Token, IndentLevel, StartColumn,
- getLineCommentPrefix(Token.TokenText), "",
+ getLineCommentIndentPrefix(Token.TokenText), "",
InPPDirective, Encoding, Style) {
OriginalPrefix = Prefix;
if (Token.TokenText.size() > Prefix.size() &&
@@ -337,7 +349,7 @@
LeadingWhitespace[LineIndex] =
Lines[LineIndex].begin() - Lines[LineIndex - 1].end();
- // Adjust the start column uniformly accross all lines.
+ // Adjust the start column uniformly across all lines.
StartOfLineColumn[LineIndex] = std::max<int>(
0,
encoding::columnWidthWithTabs(Whitespace, 0, Style.TabWidth, Encoding) +
diff --git a/lib/Format/BreakableToken.h b/lib/Format/BreakableToken.h
index b965190..e294a50 100644
--- a/lib/Format/BreakableToken.h
+++ b/lib/Format/BreakableToken.h
@@ -90,10 +90,9 @@
/// \c getSplit() needs to be implemented by child classes.
class BreakableSingleLineToken : public BreakableToken {
public:
- virtual unsigned getLineCount() const;
- virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
- unsigned TailOffset,
- StringRef::size_type Length) const;
+ unsigned getLineCount() const override;
+ unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset,
+ StringRef::size_type Length) const override;
protected:
BreakableSingleLineToken(const FormatToken &Tok, unsigned IndentLevel,
@@ -123,13 +122,12 @@
StringRef Postfix, bool InPPDirective,
encoding::Encoding Encoding, const FormatStyle &Style);
- virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
- unsigned ColumnLimit) const;
- virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
- WhitespaceManager &Whitespaces);
- virtual void replaceWhitespace(unsigned LineIndex, unsigned TailOffset,
- Split Split,
- WhitespaceManager &Whitespaces) {}
+ Split getSplit(unsigned LineIndex, unsigned TailOffset,
+ unsigned ColumnLimit) const override;
+ void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) override;
+ void replaceWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) override {}
};
class BreakableLineComment : public BreakableSingleLineToken {
@@ -142,15 +140,14 @@
unsigned StartColumn, bool InPPDirective,
encoding::Encoding Encoding, const FormatStyle &Style);
- virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
- unsigned ColumnLimit) const;
- virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
- WhitespaceManager &Whitespaces);
- virtual void replaceWhitespace(unsigned LineIndex, unsigned TailOffset,
- Split Split,
- WhitespaceManager &Whitespaces);
- virtual void replaceWhitespaceBefore(unsigned LineIndex,
- WhitespaceManager &Whitespaces);
+ Split getSplit(unsigned LineIndex, unsigned TailOffset,
+ unsigned ColumnLimit) const override;
+ void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) override;
+ void replaceWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) override;
+ void replaceWhitespaceBefore(unsigned LineIndex,
+ WhitespaceManager &Whitespaces) override;
private:
// The prefix without an additional space if one was added.
@@ -170,19 +167,17 @@
bool FirstInLine, bool InPPDirective,
encoding::Encoding Encoding, const FormatStyle &Style);
- virtual unsigned getLineCount() const;
- virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
- unsigned TailOffset,
- StringRef::size_type Length) const;
- virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
- unsigned ColumnLimit) const;
- virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
- WhitespaceManager &Whitespaces);
- virtual void replaceWhitespace(unsigned LineIndex, unsigned TailOffset,
- Split Split,
- WhitespaceManager &Whitespaces);
- virtual void replaceWhitespaceBefore(unsigned LineIndex,
- WhitespaceManager &Whitespaces);
+ unsigned getLineCount() const override;
+ unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset,
+ StringRef::size_type Length) const override;
+ Split getSplit(unsigned LineIndex, unsigned TailOffset,
+ unsigned ColumnLimit) const override;
+ void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) override;
+ void replaceWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
+ WhitespaceManager &Whitespaces) override;
+ void replaceWhitespaceBefore(unsigned LineIndex,
+ WhitespaceManager &Whitespaces) override;
private:
// Rearranges the whitespace between Lines[LineIndex-1] and Lines[LineIndex],
diff --git a/lib/Format/CMakeLists.txt b/lib/Format/CMakeLists.txt
index e3ef5bd..47e15bd 100644
--- a/lib/Format/CMakeLists.txt
+++ b/lib/Format/CMakeLists.txt
@@ -8,23 +8,9 @@
TokenAnnotator.cpp
UnwrappedLineParser.cpp
WhitespaceManager.cpp
- )
-add_dependencies(clangFormat
- ClangAttrClasses
- ClangAttrList
- ClangDeclNodes
- ClangDiagnosticCommon
- ClangDiagnosticFrontend
- ClangStmtNodes
- )
-
-target_link_libraries(clangFormat
+ LINK_LIBS
clangBasic
- clangFrontend
- clangAST
- clangASTMatchers
- clangRewriteCore
- clangRewriteFrontend
+ clangLex
clangTooling
)
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index 971acc2..5a3dee6 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -63,7 +63,8 @@
bool BinPackInconclusiveFunctions)
: Style(Style), SourceMgr(SourceMgr), Whitespaces(Whitespaces),
Encoding(Encoding),
- BinPackInconclusiveFunctions(BinPackInconclusiveFunctions) {}
+ BinPackInconclusiveFunctions(BinPackInconclusiveFunctions),
+ CommentPragmasRegex(Style.CommentPragmas) {}
LineState ContinuationIndenter::getInitialState(unsigned FirstIndent,
const AnnotatedLine *Line,
@@ -107,7 +108,8 @@
// SomeParameter, OtherParameter).DoSomething(
// ...
// As they hide "DoSomething" and are generally bad for readability.
- if (Previous.opensScope() && State.LowestLevelOnLine < State.StartOfLineLevel)
+ if (Previous.opensScope() && Previous.isNot(tok::l_brace) &&
+ State.LowestLevelOnLine < State.StartOfLineLevel)
return false;
if (Current.isMemberAccess() && State.Stack.back().ContainsUnwrappedBuilder)
return false;
@@ -136,13 +138,19 @@
if (Style.AlwaysBreakBeforeMultilineStrings &&
State.Column > State.Stack.back().Indent && // Breaking saves columns.
!Previous.isOneOf(tok::kw_return, tok::lessless, tok::at) &&
- Previous.Type != TT_InlineASMColon && NextIsMultilineString(State))
+ Previous.Type != TT_InlineASMColon && nextIsMultilineString(State))
return true;
if (((Previous.Type == TT_DictLiteral && Previous.is(tok::l_brace)) ||
Previous.Type == TT_ArrayInitializerLSquare) &&
getLengthToMatchingParen(Previous) + State.Column > getColumnLimit(State))
return true;
+ if (Current.Type == TT_CtorInitializerColon &&
+ (!Style.AllowShortFunctionsOnASingleLine ||
+ Style.BreakConstructorInitializersBeforeComma || Style.ColumnLimit != 0))
+ return true;
+ if (State.Column < getNewLineColumn(State))
+ return false;
if (!Style.BreakBeforeBinaryOperators) {
// If we need to break somewhere inside the LHS of a binary expression, we
// should also break after the operator. Otherwise, the formatting would
@@ -173,19 +181,17 @@
}
// Same as above, but for the first "<<" operator.
- if (Current.is(tok::lessless) && State.Stack.back().BreakBeforeParameter &&
+ if (Current.is(tok::lessless) && Current.Type != TT_OverloadedOperator &&
+ State.Stack.back().BreakBeforeParameter &&
State.Stack.back().FirstLessLess == 0)
return true;
- // FIXME: Comparing LongestObjCSelectorName to 0 is a hacky way of finding
- // out whether it is the first parameter. Clean this up.
if (Current.Type == TT_ObjCSelectorName &&
- Current.LongestObjCSelectorName == 0 &&
+ State.Stack.back().ObjCSelectorNameFound &&
State.Stack.back().BreakBeforeParameter)
return true;
- if ((Current.Type == TT_CtorInitializerColon ||
- (Previous.ClosesTemplateDeclaration && State.ParenLevel == 0 &&
- !Current.isTrailingComment())))
+ if (Previous.ClosesTemplateDeclaration && State.ParenLevel == 0 &&
+ !Current.isTrailingComment())
return true;
if ((Current.Type == TT_StartOfName || Current.is(tok::kw_operator)) &&
@@ -197,6 +203,14 @@
(State.Stack.back().BreakBeforeParameter &&
State.Stack.back().ContainsUnwrappedBuilder)))
return true;
+
+ // The following could be precomputed as they do not depend on the state.
+ // However, as they should take effect only if the UnwrappedLine does not fit
+ // into the ColumnLimit, they are checked here in the ContinuationIndenter.
+ if (Previous.BlockKind == BK_Block && Previous.is(tok::l_brace) &&
+ !Current.isOneOf(tok::r_brace, tok::comment))
+ return true;
+
return false;
}
@@ -205,8 +219,8 @@
unsigned ExtraSpaces) {
const FormatToken &Current = *State.NextToken;
- if (State.Stack.size() == 0 ||
- (Current.Type == TT_ImplicitStringLiteral &&
+ assert(!State.Stack.empty());
+ if ((Current.Type == TT_ImplicitStringLiteral &&
(Current.Previous->Tok.getIdentifierInfo() == NULL ||
Current.Previous->Tok.getIdentifierInfo()->getPPKeywordID() ==
tok::pp_not_keyword))) {
@@ -215,8 +229,8 @@
State.NextToken->WhitespaceRange.getEnd()) -
SourceMgr.getSpellingColumnNumber(
State.NextToken->WhitespaceRange.getBegin());
- State.Column += WhitespaceLength + State.NextToken->ColumnWidth;
- State.NextToken = State.NextToken->Next;
+ State.Column += WhitespaceLength;
+ moveStateToNextToken(State, DryRun, /*Newline=*/false);
return 0;
}
@@ -255,9 +269,12 @@
Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, /*IndentLevel=*/0,
Spaces, State.Column + Spaces);
- if (Current.Type == TT_ObjCSelectorName && State.Stack.back().ColonPos == 0) {
- if (State.Stack.back().Indent + Current.LongestObjCSelectorName >
- State.Column + Spaces + Current.ColumnWidth)
+ if (Current.Type == TT_ObjCSelectorName &&
+ !State.Stack.back().ObjCSelectorNameFound) {
+ if (Current.LongestObjCSelectorName == 0)
+ State.Stack.back().AlignColons = false;
+ else if (State.Stack.back().Indent + Current.LongestObjCSelectorName >
+ State.Column + Spaces + Current.ColumnWidth)
State.Stack.back().ColonPos =
State.Stack.back().Indent + Current.LongestObjCSelectorName;
else
@@ -265,7 +282,7 @@
}
if (Previous.opensScope() && Previous.Type != TT_ObjCMethodExpr &&
- Current.Type != TT_LineComment)
+ (Current.Type != TT_LineComment || Previous.BlockKind == BK_BracedInit))
State.Stack.back().Indent = State.Column + Spaces;
if (State.Stack.back().AvoidBinPacking && startsNextParameter(Current, Style))
State.Stack.back().NoLineBreak = true;
@@ -277,11 +294,12 @@
// Treat the condition inside an if as if it was a second function
// parameter, i.e. let nested calls have a continuation indent.
State.Stack.back().LastSpace = State.Column + 1; // 1 is length of "(".
- else if (Previous.is(tok::comma) || Previous.Type == TT_ObjCMethodExpr)
+ else if (Current.isNot(tok::comment) &&
+ (Previous.is(tok::comma) ||
+ (Previous.is(tok::colon) && Previous.Type == TT_ObjCMethodExpr)))
State.Stack.back().LastSpace = State.Column;
else if ((Previous.Type == TT_BinaryOperator ||
Previous.Type == TT_ConditionalExpr ||
- Previous.Type == TT_UnaryOperator ||
Previous.Type == TT_CtorInitializerColon) &&
(Previous.getPrecedence() != prec::Assignment ||
Current.StartsBinaryExpression))
@@ -313,16 +331,15 @@
bool DryRun) {
FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *State.NextToken->Previous;
- // If we are continuing an expression, we want to use the continuation indent.
- unsigned ContinuationIndent =
- std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) +
- Style.ContinuationIndentWidth;
+
// Extra penalty that needs to be added because of the way certain line
// breaks are chosen.
unsigned Penalty = 0;
- const FormatToken *PreviousNonComment =
- State.NextToken->getPreviousNonComment();
+ const FormatToken *PreviousNonComment = Current.getPreviousNonComment();
+ const FormatToken *NextNonComment = Previous.getNextNonComment();
+ if (!NextNonComment)
+ NextNonComment = &Current;
// The first line break on any ParenLevel causes an extra penalty in order
// prefer similar line breaks.
if (!State.Stack.back().ContainsLineBreak)
@@ -332,79 +349,46 @@
Penalty += State.NextToken->SplitPenalty;
// Breaking before the first "<<" is generally not desirable if the LHS is
- // short.
- if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0 &&
- State.Column <= Style.ColumnLimit / 2)
+ // short. Also always add the penalty if the LHS is split over mutliple lines
+ // to avoid unnecessary line breaks that just work around this penalty.
+ if (NextNonComment->is(tok::lessless) &&
+ State.Stack.back().FirstLessLess == 0 &&
+ (State.Column <= Style.ColumnLimit / 3 ||
+ State.Stack.back().BreakBeforeParameter))
Penalty += Style.PenaltyBreakFirstLessLess;
- if (Current.is(tok::l_brace) && Current.BlockKind == BK_Block) {
- State.Column = State.FirstIndent;
- } else if (Current.isOneOf(tok::r_brace, tok::r_square)) {
- if (Current.closesBlockTypeList(Style) ||
- (Current.MatchingParen &&
- Current.MatchingParen->BlockKind == BK_BracedInit))
- State.Column = State.Stack[State.Stack.size() - 2].LastSpace;
- else
- State.Column = State.FirstIndent;
- } else if (Current.is(tok::string_literal) &&
- State.StartOfStringLiteral != 0) {
- State.Column = State.StartOfStringLiteral;
- State.Stack.back().BreakBeforeParameter = true;
- } else if (Current.is(tok::lessless) &&
- State.Stack.back().FirstLessLess != 0) {
- State.Column = State.Stack.back().FirstLessLess;
- } else if (Current.isMemberAccess()) {
- if (State.Stack.back().CallContinuation == 0) {
- State.Column = ContinuationIndent;
+ State.Column = getNewLineColumn(State);
+ if (NextNonComment->isMemberAccess()) {
+ if (State.Stack.back().CallContinuation == 0)
State.Stack.back().CallContinuation = State.Column;
- } else {
- State.Column = State.Stack.back().CallContinuation;
+ } else if (NextNonComment->Type == TT_ObjCSelectorName) {
+ if (!State.Stack.back().ObjCSelectorNameFound) {
+ if (NextNonComment->LongestObjCSelectorName == 0) {
+ State.Stack.back().AlignColons = false;
+ } else {
+ State.Stack.back().ColonPos =
+ State.Stack.back().Indent + NextNonComment->LongestObjCSelectorName;
+ }
+ } else if (State.Stack.back().AlignColons &&
+ State.Stack.back().ColonPos <= NextNonComment->ColumnWidth) {
+ State.Stack.back().ColonPos = State.Column + NextNonComment->ColumnWidth;
}
- } else if (State.Stack.back().QuestionColumn != 0 &&
- (Current.Type == TT_ConditionalExpr ||
- Previous.Type == TT_ConditionalExpr)) {
- State.Column = State.Stack.back().QuestionColumn;
- } else if (Previous.is(tok::comma) && State.Stack.back().VariablePos != 0) {
- State.Column = State.Stack.back().VariablePos;
- } else if ((PreviousNonComment &&
- PreviousNonComment->ClosesTemplateDeclaration) ||
- ((Current.Type == TT_StartOfName ||
- Current.is(tok::kw_operator)) &&
- State.ParenLevel == 0 &&
- (!Style.IndentFunctionDeclarationAfterType ||
- State.Line->StartsDefinition))) {
- State.Column = State.Stack.back().Indent;
- } else if (Current.Type == TT_ObjCSelectorName) {
- if (State.Stack.back().ColonPos == 0) {
- State.Stack.back().ColonPos =
- State.Stack.back().Indent + Current.LongestObjCSelectorName;
- State.Column = State.Stack.back().ColonPos - Current.ColumnWidth;
- } else if (State.Stack.back().ColonPos > Current.ColumnWidth) {
- State.Column = State.Stack.back().ColonPos - Current.ColumnWidth;
- } else {
- State.Column = State.Stack.back().Indent;
- State.Stack.back().ColonPos = State.Column + Current.ColumnWidth;
- }
- } else if (Current.Type == TT_ArraySubscriptLSquare) {
- if (State.Stack.back().StartOfArraySubscripts != 0)
- State.Column = State.Stack.back().StartOfArraySubscripts;
- else
- State.Column = ContinuationIndent;
- } else if (Current.Type == TT_StartOfName ||
- Previous.isOneOf(tok::coloncolon, tok::equal) ||
- Previous.Type == TT_ObjCMethodExpr) {
- State.Column = ContinuationIndent;
- } else if (Current.Type == TT_CtorInitializerColon) {
- State.Column = State.FirstIndent + Style.ConstructorInitializerIndentWidth;
- } else if (Current.Type == TT_CtorInitializerComma) {
- State.Column = State.Stack.back().Indent;
- } else {
- State.Column = State.Stack.back().Indent;
- // Ensure that we fall back to the continuation indent width instead of just
- // flushing continuations left.
- if (State.Column == State.FirstIndent &&
- PreviousNonComment->isNot(tok::r_brace))
- State.Column += Style.ContinuationIndentWidth;
+ } else if (PreviousNonComment && PreviousNonComment->is(tok::colon) &&
+ (PreviousNonComment->Type == TT_ObjCMethodExpr ||
+ PreviousNonComment->Type == TT_DictLiteral)) {
+ // FIXME: This is hacky, find a better way. The problem is that in an ObjC
+ // method expression, the block should be aligned to the line starting it,
+ // e.g.:
+ // [aaaaaaaaaaaaaaa aaaaaaaaa: \\ break for some reason
+ // ^(int *i) {
+ // // ...
+ // }];
+ // Thus, we set LastSpace of the next higher ParenLevel, to which we move
+ // when we consume all of the "}"'s FakeRParens at the "{".
+ if (State.Stack.size() > 1)
+ State.Stack[State.Stack.size() - 2].LastSpace =
+ std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) +
+ Style.ContinuationIndentWidth;
}
if ((Previous.isOneOf(tok::comma, tok::semi) &&
@@ -413,7 +397,7 @@
State.Stack.back().BreakBeforeParameter = false;
if (Previous.Type == TT_TemplateCloser && State.ParenLevel == 0)
State.Stack.back().BreakBeforeParameter = false;
- if (Current.is(tok::question) ||
+ if (NextNonComment->is(tok::question) ||
(PreviousNonComment && PreviousNonComment->is(tok::question)))
State.Stack.back().BreakBeforeParameter = true;
@@ -429,8 +413,6 @@
if (!Current.isTrailingComment())
State.Stack.back().LastSpace = State.Column;
- if (Current.isMemberAccess())
- State.Stack.back().LastSpace += Current.ColumnWidth;
State.StartOfLineLevel = State.ParenLevel;
State.LowestLevelOnLine = State.ParenLevel;
@@ -443,7 +425,7 @@
!PreviousNonComment->isOneOf(tok::comma, tok::semi) &&
PreviousNonComment->Type != TT_TemplateCloser &&
PreviousNonComment->Type != TT_BinaryOperator &&
- Current.Type != TT_BinaryOperator &&
+ Current.Type != TT_BinaryOperator &&
!PreviousNonComment->opensScope())
State.Stack.back().BreakBeforeParameter = true;
@@ -465,6 +447,99 @@
return Penalty;
}
+unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
+ if (!State.NextToken || !State.NextToken->Previous)
+ return 0;
+ FormatToken &Current = *State.NextToken;
+ const FormatToken &Previous = *State.NextToken->Previous;
+ // If we are continuing an expression, we want to use the continuation indent.
+ unsigned ContinuationIndent =
+ std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) +
+ Style.ContinuationIndentWidth;
+ const FormatToken *PreviousNonComment = Current.getPreviousNonComment();
+ const FormatToken *NextNonComment = Previous.getNextNonComment();
+ if (!NextNonComment)
+ NextNonComment = &Current;
+ if (NextNonComment->is(tok::l_brace) &&
+ NextNonComment->BlockKind == BK_Block)
+ return State.ParenLevel == 0 ? State.FirstIndent
+ : State.Stack.back().Indent;
+ if (Current.isOneOf(tok::r_brace, tok::r_square)) {
+ if (Current.closesBlockTypeList(Style) ||
+ (Current.MatchingParen &&
+ Current.MatchingParen->BlockKind == BK_BracedInit))
+ return State.Stack[State.Stack.size() - 2].LastSpace;
+ else
+ return State.FirstIndent;
+ }
+ if (NextNonComment->isStringLiteral() && State.StartOfStringLiteral != 0)
+ return State.StartOfStringLiteral;
+ if (NextNonComment->is(tok::lessless) &&
+ State.Stack.back().FirstLessLess != 0)
+ return State.Stack.back().FirstLessLess;
+ if (NextNonComment->isMemberAccess()) {
+ if (State.Stack.back().CallContinuation == 0) {
+ return ContinuationIndent;
+ } else {
+ return State.Stack.back().CallContinuation;
+ }
+ }
+ if (State.Stack.back().QuestionColumn != 0 &&
+ (NextNonComment->Type == TT_ConditionalExpr ||
+ Previous.Type == TT_ConditionalExpr))
+ return State.Stack.back().QuestionColumn;
+ if (Previous.is(tok::comma) && State.Stack.back().VariablePos != 0)
+ return State.Stack.back().VariablePos;
+ if ((PreviousNonComment && (PreviousNonComment->ClosesTemplateDeclaration ||
+ PreviousNonComment->Type == TT_AttributeParen)) ||
+ ((NextNonComment->Type == TT_StartOfName ||
+ NextNonComment->is(tok::kw_operator)) &&
+ State.ParenLevel == 0 && (!Style.IndentFunctionDeclarationAfterType ||
+ State.Line->StartsDefinition)))
+ return std::max(State.Stack.back().LastSpace, State.Stack.back().Indent);
+ if (NextNonComment->Type == TT_ObjCSelectorName) {
+ if (!State.Stack.back().ObjCSelectorNameFound) {
+ if (NextNonComment->LongestObjCSelectorName == 0) {
+ return State.Stack.back().Indent;
+ } else {
+ return State.Stack.back().Indent +
+ NextNonComment->LongestObjCSelectorName -
+ NextNonComment->ColumnWidth;
+ }
+ } else if (!State.Stack.back().AlignColons) {
+ return State.Stack.back().Indent;
+ } else if (State.Stack.back().ColonPos > NextNonComment->ColumnWidth) {
+ return State.Stack.back().ColonPos - NextNonComment->ColumnWidth;
+ } else {
+ return State.Stack.back().Indent;
+ }
+ }
+ if (NextNonComment->Type == TT_ArraySubscriptLSquare) {
+ if (State.Stack.back().StartOfArraySubscripts != 0)
+ return State.Stack.back().StartOfArraySubscripts;
+ else
+ return ContinuationIndent;
+ }
+ if (NextNonComment->Type == TT_StartOfName ||
+ Previous.isOneOf(tok::coloncolon, tok::equal)) {
+ return ContinuationIndent;
+ }
+ if (PreviousNonComment && PreviousNonComment->is(tok::colon) &&
+ (PreviousNonComment->Type == TT_ObjCMethodExpr ||
+ PreviousNonComment->Type == TT_DictLiteral))
+ return ContinuationIndent;
+ if (NextNonComment->Type == TT_CtorInitializerColon)
+ return State.FirstIndent + Style.ConstructorInitializerIndentWidth;
+ if (NextNonComment->Type == TT_CtorInitializerComma)
+ return State.Stack.back().Indent;
+ if (State.Stack.back().Indent == State.FirstIndent && PreviousNonComment &&
+ PreviousNonComment->isNot(tok::r_brace))
+ // Ensure that we fall back to the continuation indent width instead of
+ // just flushing continuations left.
+ return State.Stack.back().Indent + Style.ContinuationIndentWidth;
+ return State.Stack.back().Indent;
+}
+
unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
bool DryRun, bool Newline) {
const FormatToken &Current = *State.NextToken;
@@ -472,7 +547,8 @@
if (Current.Type == TT_InheritanceColon)
State.Stack.back().AvoidBinPacking = true;
- if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0)
+ if (Current.is(tok::lessless) && Current.Type != TT_OverloadedOperator &&
+ State.Stack.back().FirstLessLess == 0)
State.Stack.back().FirstLessLess = State.Column;
if (Current.Type == TT_ArraySubscriptLSquare &&
State.Stack.back().StartOfArraySubscripts == 0)
@@ -488,6 +564,8 @@
if (Current.isMemberAccess())
State.Stack.back().StartOfFunctionCall =
Current.LastInChainOfCalls ? 0 : State.Column + Current.ColumnWidth;
+ if (Current.Type == TT_ObjCSelectorName)
+ State.Stack.back().ObjCSelectorNameFound = true;
if (Current.Type == TT_CtorInitializerColon) {
// Indent 2 from the column, so:
// SomeClass::SomeClass()
@@ -531,6 +609,18 @@
std::max(std::max(State.Column, NewParenState.Indent),
State.Stack.back().LastSpace);
+ // Don't allow the RHS of an operator to be split over multiple lines unless
+ // there is a line-break right after the operator.
+ // Exclude relational operators, as there, it is always more desirable to
+ // have the LHS 'left' of the RHS.
+ // FIXME: Implement this for '<<' and BreakBeforeBinaryOperators.
+ if (!Newline && Previous && Previous->Type == TT_BinaryOperator &&
+ !Previous->isOneOf(tok::lessless, tok::question, tok::colon) &&
+ Previous->getPrecedence() > prec::Assignment &&
+ Previous->getPrecedence() != prec::Relational &&
+ !Style.BreakBeforeBinaryOperators)
+ NewParenState.NoLineBreak = true;
+
// Do not indent relative to the fake parentheses inserted for "." or "->".
// This is a special case to make the following to statements consistent:
// OuterFunction(InnerFunctionCall( // break
@@ -539,6 +629,7 @@
// ParameterToInnerFunction));
if (*I > prec::Unknown)
NewParenState.LastSpace = std::max(NewParenState.LastSpace, State.Column);
+ NewParenState.StartOfFunctionCall = State.Column;
// Always indent conditional expressions. Never indent expression where
// the 'operator' is ',', ';' or an assignment (i.e. *I <=
@@ -566,7 +657,7 @@
if (Current.MatchingParen && Current.BlockKind == BK_Block) {
// If this is an l_brace starting a nested block, we pretend (wrt. to
// indentation) that we already consumed the corresponding r_brace.
- // Thus, we remove all ParenStates caused bake fake parentheses that end
+ // Thus, we remove all ParenStates caused by fake parentheses that end
// at the r_brace. The net effect of this is that we don't indent
// relative to the l_brace, if the nested block is the last parameter of
// a function. For example, this formats:
@@ -577,20 +668,32 @@
//
// instead of:
// SomeFunction(a, [] {
- // f(); // break
- // });
- for (unsigned i = 0; i != Current.MatchingParen->FakeRParens; ++i)
+ // f(); // break
+ // });
+ for (unsigned i = 0; i != Current.MatchingParen->FakeRParens; ++i) {
+ assert(State.Stack.size() > 1);
+ if (State.Stack.size() == 1) {
+ // Do not pop the last element.
+ break;
+ }
State.Stack.pop_back();
- NewIndent = State.Stack.back().LastSpace + Style.IndentWidth;
+ }
+ // For some reason, ObjC blocks are indented like continuations.
+ NewIndent =
+ State.Stack.back().LastSpace + (Current.Type == TT_ObjCBlockLBrace
+ ? Style.ContinuationIndentWidth
+ : Style.IndentWidth);
++NewIndentLevel;
BreakBeforeParameter = true;
} else {
NewIndent = State.Stack.back().LastSpace;
if (Current.opensBlockTypeList(Style)) {
NewIndent += Style.IndentWidth;
+ NewIndent = std::min(State.Column + 2, NewIndent);
++NewIndentLevel;
} else {
NewIndent += Style.ContinuationIndentWidth;
+ NewIndent = std::min(State.Column + 1, NewIndent);
}
}
const FormatToken *NextNoComment = Current.getNextNonComment();
@@ -649,15 +752,20 @@
// as they will have been removed early (see above).
for (unsigned i = 0, e = Current.FakeRParens; i != e; ++i) {
unsigned VariablePos = State.Stack.back().VariablePos;
+ assert(State.Stack.size() > 1);
+ if (State.Stack.size() == 1) {
+ // Do not pop the last element.
+ break;
+ }
State.Stack.pop_back();
State.Stack.back().VariablePos = VariablePos;
}
}
- if (Current.is(tok::string_literal) && State.StartOfStringLiteral == 0) {
+ if (Current.isStringLiteral() && State.StartOfStringLiteral == 0) {
State.StartOfStringLiteral = State.Column;
- } else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash,
- tok::string_literal)) {
+ } else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash) &&
+ !Current.isStringLiteral()) {
State.StartOfStringLiteral = 0;
}
@@ -669,13 +777,15 @@
Penalty += Style.PenaltyExcessCharacter * ExcessCharacters;
}
+ if (Current.Role)
+ Current.Role->formatFromToken(State, this, DryRun);
// If the previous has a special role, let it consume tokens as appropriate.
// It is necessary to start at the previous token for the only implemented
// role (comma separated list). That way, the decision whether or not to break
// after the "{" is already done and both options are tried and evaluated.
// FIXME: This is ugly, find a better way.
if (Previous && Previous->Role)
- Penalty += Previous->Role->format(State, this, DryRun);
+ Penalty += Previous->Role->formatAfterToken(State, this, DryRun);
return Penalty;
}
@@ -727,19 +837,14 @@
if (Current.Type == TT_ImplicitStringLiteral)
return 0;
- if (!Current.isOneOf(tok::string_literal, tok::wide_string_literal,
- tok::utf8_string_literal, tok::utf16_string_literal,
- tok::utf32_string_literal, tok::comment))
+ if (!Current.isStringLiteral() && !Current.is(tok::comment))
return 0;
- llvm::OwningPtr<BreakableToken> Token;
+ std::unique_ptr<BreakableToken> Token;
unsigned StartColumn = State.Column - Current.ColumnWidth;
unsigned ColumnLimit = getColumnLimit(State);
- if (Current.isOneOf(tok::string_literal, tok::wide_string_literal,
- tok::utf8_string_literal, tok::utf16_string_literal,
- tok::utf32_string_literal) &&
- Current.Type != TT_ImplicitStringLiteral) {
+ if (Current.isStringLiteral()) {
// Don't break string literals inside preprocessor directives (except for
// #define directives, as their contents are stored in separate lines and
// are not affected by this check).
@@ -755,13 +860,20 @@
StringRef Text = Current.TokenText;
StringRef Prefix;
StringRef Postfix;
+ bool IsNSStringLiteral = false;
// 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.startswith("\"") && Current.Previous &&
+ Current.Previous->is(tok::at)) {
+ IsNSStringLiteral = true;
+ Prefix = "@\"";
+ }
if ((Text.endswith(Postfix = "\"") &&
- (Text.startswith(Prefix = "\"") || Text.startswith(Prefix = "u\"") ||
- Text.startswith(Prefix = "U\"") || Text.startswith(Prefix = "u8\"") ||
+ (IsNSStringLiteral || Text.startswith(Prefix = "\"") ||
+ Text.startswith(Prefix = "u\"") || Text.startswith(Prefix = "U\"") ||
+ Text.startswith(Prefix = "u8\"") ||
Text.startswith(Prefix = "L\""))) ||
(Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")")) ||
getRawStringLiteralPrefixPostfix(Text, Prefix, Postfix)) {
@@ -772,12 +884,16 @@
return 0;
}
} else if (Current.Type == TT_BlockComment && Current.isTrailingComment()) {
+ if (CommentPragmasRegex.match(Current.TokenText.substr(2)))
+ return 0;
Token.reset(new BreakableBlockComment(
Current, State.Line->Level, StartColumn, Current.OriginalColumn,
!Current.Previous, State.Line->InPPDirective, Encoding, Style));
} else if (Current.Type == TT_LineComment &&
(Current.Previous == NULL ||
Current.Previous->Type != TT_ImplicitStringLiteral)) {
+ if (CommentPragmasRegex.match(Current.TokenText.substr(2)))
+ return 0;
Token.reset(new BreakableLineComment(Current, State.Line->Level,
StartColumn, /*InPPDirective=*/false,
Encoding, Style));
@@ -848,8 +964,8 @@
State.Stack[i].BreakBeforeParameter = true;
}
- Penalty += Current.is(tok::string_literal) ? Style.PenaltyBreakString
- : Style.PenaltyBreakComment;
+ Penalty += Current.isStringLiteral() ? Style.PenaltyBreakString
+ : Style.PenaltyBreakComment;
State.Stack.back().LastSpace = StartColumn;
}
@@ -861,18 +977,19 @@
return Style.ColumnLimit - (State.Line->InPPDirective ? 2 : 0);
}
-bool ContinuationIndenter::NextIsMultilineString(const LineState &State) {
+bool ContinuationIndenter::nextIsMultilineString(const LineState &State) {
const FormatToken &Current = *State.NextToken;
- if (!Current.is(tok::string_literal))
+ if (!Current.isStringLiteral())
return false;
// We never consider raw string literals "multiline" for the purpose of
- // AlwaysBreakBeforeMultilineStrings implementation.
+ // AlwaysBreakBeforeMultilineStrings implementation as they are special-cased
+ // (see TokenAnnotator::mustBreakBefore().
if (Current.TokenText.startswith("R\""))
return false;
if (Current.IsMultiline)
return true;
if (Current.getNextNonComment() &&
- Current.getNextNonComment()->is(tok::string_literal))
+ Current.getNextNonComment()->isStringLiteral())
return true; // Implicit concatenation.
if (State.Column + Current.ColumnWidth + Current.UnbreakableTailLength >
Style.ColumnLimit)
diff --git a/lib/Format/ContinuationIndenter.h b/lib/Format/ContinuationIndenter.h
index b317565..9a3c118 100644
--- a/lib/Format/ContinuationIndenter.h
+++ b/lib/Format/ContinuationIndenter.h
@@ -18,6 +18,7 @@
#include "Encoding.h"
#include "clang/Format/Format.h"
+#include "llvm/Support/Regex.h"
namespace clang {
class SourceManager;
@@ -103,6 +104,9 @@
/// \c Replacement.
unsigned addTokenOnNewLine(LineState &State, bool DryRun);
+ /// \brief Calculate the new column for a line wrap before the next token.
+ unsigned getNewLineColumn(const LineState &State);
+
/// \brief Adds a multiline token to the \p State.
///
/// \returns Extra penalty for the first line of the literal: last line is
@@ -115,13 +119,14 @@
///
/// This includes implicitly concatenated strings, strings that will be broken
/// by clang-format and string literals with escaped newlines.
- bool NextIsMultilineString(const LineState &State);
+ bool nextIsMultilineString(const LineState &State);
FormatStyle Style;
SourceManager &SourceMgr;
WhitespaceManager &Whitespaces;
encoding::Encoding Encoding;
bool BinPackInconclusiveFunctions;
+ llvm::Regex CommentPragmasRegex;
};
struct ParenState {
@@ -133,7 +138,8 @@
NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0),
StartOfArraySubscripts(0), NestedNameSpecifierContinuation(0),
CallContinuation(0), VariablePos(0), ContainsLineBreak(false),
- ContainsUnwrappedBuilder(0) {}
+ ContainsUnwrappedBuilder(0), AlignColons(true),
+ ObjCSelectorNameFound(false) {}
/// \brief The position to which a specific parenthesis level needs to be
/// indented.
@@ -210,6 +216,20 @@
/// builder-type call on one line.
bool ContainsUnwrappedBuilder;
+ /// \brief \c true if the colons of the curren ObjC method expression should
+ /// be aligned.
+ ///
+ /// Not considered for memoization as it will always have the same value at
+ /// the same token.
+ bool AlignColons;
+
+ /// \brief \c true if at least one selector name was found in the current
+ /// ObjC method expression.
+ ///
+ /// Not considered for memoization as it will always have the same value at
+ /// the same token.
+ bool ObjCSelectorNameFound;
+
bool operator<(const ParenState &Other) const {
if (Indent != Other.Indent)
return Indent < Other.Indent;
diff --git a/lib/Format/Encoding.h b/lib/Format/Encoding.h
index 356334d..dba5174 100644
--- a/lib/Format/Encoding.h
+++ b/lib/Format/Encoding.h
@@ -64,6 +64,10 @@
inline unsigned columnWidth(StringRef Text, Encoding Encoding) {
if (Encoding == Encoding_UTF8) {
int ContentWidth = llvm::sys::unicode::columnWidthUTF8(Text);
+ // FIXME: Figure out the correct way to handle this in the presence of both
+ // printable and unprintable multi-byte UTF-8 characters. Falling back to
+ // returning the number of bytes may cause problems, as columnWidth suddenly
+ // becomes non-additive.
if (ContentWidth >= 0)
return ContentWidth;
}
@@ -81,9 +85,7 @@
StringRef::size_type TabPos = Tail.find('\t');
if (TabPos == StringRef::npos)
return TotalWidth + columnWidth(Tail, Encoding);
- int Width = columnWidth(Tail.substr(0, TabPos), Encoding);
- assert(Width >= 0);
- TotalWidth += Width;
+ TotalWidth += columnWidth(Tail.substr(0, TabPos), Encoding);
TotalWidth += TabWidth - (TotalWidth + StartColumn) % TabWidth;
Tail = Tail.substr(TabPos + 1);
}
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 01c122e..cb07cb5 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -26,71 +26,93 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Debug.h"
-#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/YAMLTraits.h"
#include <queue>
#include <string>
+using clang::format::FormatStyle;
+
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
+
namespace llvm {
namespace yaml {
+template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
+ static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) {
+ IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp);
+ IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript);
+ IO.enumCase(Value, "Proto", FormatStyle::LK_Proto);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<FormatStyle::LanguageStandard> {
+ static void enumeration(IO &IO, FormatStyle::LanguageStandard &Value) {
+ IO.enumCase(Value, "Cpp03", FormatStyle::LS_Cpp03);
+ IO.enumCase(Value, "C++03", FormatStyle::LS_Cpp03);
+ IO.enumCase(Value, "Cpp11", FormatStyle::LS_Cpp11);
+ IO.enumCase(Value, "C++11", FormatStyle::LS_Cpp11);
+ IO.enumCase(Value, "Auto", FormatStyle::LS_Auto);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> {
+ static void enumeration(IO &IO, FormatStyle::UseTabStyle &Value) {
+ IO.enumCase(Value, "Never", FormatStyle::UT_Never);
+ IO.enumCase(Value, "false", FormatStyle::UT_Never);
+ IO.enumCase(Value, "Always", FormatStyle::UT_Always);
+ IO.enumCase(Value, "true", FormatStyle::UT_Always);
+ IO.enumCase(Value, "ForIndentation", FormatStyle::UT_ForIndentation);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
+ static void enumeration(IO &IO, FormatStyle::BraceBreakingStyle &Value) {
+ IO.enumCase(Value, "Attach", FormatStyle::BS_Attach);
+ IO.enumCase(Value, "Linux", FormatStyle::BS_Linux);
+ IO.enumCase(Value, "Stroustrup", FormatStyle::BS_Stroustrup);
+ IO.enumCase(Value, "Allman", FormatStyle::BS_Allman);
+ IO.enumCase(Value, "GNU", FormatStyle::BS_GNU);
+ }
+};
+
template <>
-struct ScalarEnumerationTraits<clang::format::FormatStyle::LanguageStandard> {
+struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> {
static void enumeration(IO &IO,
- clang::format::FormatStyle::LanguageStandard &Value) {
- IO.enumCase(Value, "Cpp03", clang::format::FormatStyle::LS_Cpp03);
- IO.enumCase(Value, "C++03", clang::format::FormatStyle::LS_Cpp03);
- IO.enumCase(Value, "Cpp11", clang::format::FormatStyle::LS_Cpp11);
- IO.enumCase(Value, "C++11", clang::format::FormatStyle::LS_Cpp11);
- IO.enumCase(Value, "Auto", clang::format::FormatStyle::LS_Auto);
+ FormatStyle::NamespaceIndentationKind &Value) {
+ IO.enumCase(Value, "None", FormatStyle::NI_None);
+ IO.enumCase(Value, "Inner", FormatStyle::NI_Inner);
+ IO.enumCase(Value, "All", FormatStyle::NI_All);
}
};
template <>
-struct ScalarEnumerationTraits<clang::format::FormatStyle::UseTabStyle> {
+struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensOptions> {
static void enumeration(IO &IO,
- clang::format::FormatStyle::UseTabStyle &Value) {
- IO.enumCase(Value, "Never", clang::format::FormatStyle::UT_Never);
- IO.enumCase(Value, "false", clang::format::FormatStyle::UT_Never);
- IO.enumCase(Value, "Always", clang::format::FormatStyle::UT_Always);
- IO.enumCase(Value, "true", clang::format::FormatStyle::UT_Always);
- IO.enumCase(Value, "ForIndentation",
- clang::format::FormatStyle::UT_ForIndentation);
+ FormatStyle::SpaceBeforeParensOptions &Value) {
+ IO.enumCase(Value, "Never", FormatStyle::SBPO_Never);
+ IO.enumCase(Value, "ControlStatements",
+ FormatStyle::SBPO_ControlStatements);
+ IO.enumCase(Value, "Always", FormatStyle::SBPO_Always);
+
+ // For backward compatibility.
+ IO.enumCase(Value, "false", FormatStyle::SBPO_Never);
+ IO.enumCase(Value, "true", FormatStyle::SBPO_ControlStatements);
}
};
-template <>
-struct ScalarEnumerationTraits<clang::format::FormatStyle::BraceBreakingStyle> {
- static void
- enumeration(IO &IO, clang::format::FormatStyle::BraceBreakingStyle &Value) {
- IO.enumCase(Value, "Attach", clang::format::FormatStyle::BS_Attach);
- IO.enumCase(Value, "Linux", clang::format::FormatStyle::BS_Linux);
- IO.enumCase(Value, "Stroustrup", clang::format::FormatStyle::BS_Stroustrup);
- IO.enumCase(Value, "Allman", clang::format::FormatStyle::BS_Allman);
- }
-};
+template <> struct MappingTraits<FormatStyle> {
+ static void mapping(IO &IO, FormatStyle &Style) {
+ // When reading, read the language first, we need it for getPredefinedStyle.
+ IO.mapOptional("Language", Style.Language);
-template <>
-struct ScalarEnumerationTraits<
- clang::format::FormatStyle::NamespaceIndentationKind> {
- static void
- enumeration(IO &IO,
- clang::format::FormatStyle::NamespaceIndentationKind &Value) {
- IO.enumCase(Value, "None", clang::format::FormatStyle::NI_None);
- IO.enumCase(Value, "Inner", clang::format::FormatStyle::NI_Inner);
- IO.enumCase(Value, "All", clang::format::FormatStyle::NI_All);
- }
-};
-
-template <> struct MappingTraits<clang::format::FormatStyle> {
- static void mapping(llvm::yaml::IO &IO, clang::format::FormatStyle &Style) {
if (IO.outputting()) {
StringRef StylesArray[] = { "LLVM", "Google", "Chromium",
- "Mozilla", "WebKit" };
+ "Mozilla", "WebKit", "GNU" };
ArrayRef<StringRef> Styles(StylesArray);
for (size_t i = 0, e = Styles.size(); i < e; ++i) {
StringRef StyleName(Styles[i]);
- clang::format::FormatStyle PredefinedStyle;
- if (clang::format::getPredefinedStyle(StyleName, &PredefinedStyle) &&
+ FormatStyle PredefinedStyle;
+ if (getPredefinedStyle(StyleName, Style.Language, &PredefinedStyle) &&
Style == PredefinedStyle) {
IO.mapOptional("# BasedOnStyle", StyleName);
break;
@@ -99,11 +121,16 @@
} else {
StringRef BasedOnStyle;
IO.mapOptional("BasedOnStyle", BasedOnStyle);
- if (!BasedOnStyle.empty())
- if (!clang::format::getPredefinedStyle(BasedOnStyle, &Style)) {
+ if (!BasedOnStyle.empty()) {
+ FormatStyle::LanguageKind OldLanguage = Style.Language;
+ FormatStyle::LanguageKind Language =
+ ((FormatStyle *)IO.getContext())->Language;
+ if (!getPredefinedStyle(BasedOnStyle, Language, &Style)) {
IO.setError(Twine("Unknown value for BasedOnStyle: ", BasedOnStyle));
return;
}
+ Style.Language = OldLanguage;
+ }
}
IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
@@ -117,6 +144,8 @@
Style.AllowShortIfStatementsOnASingleLine);
IO.mapOptional("AllowShortLoopsOnASingleLine",
Style.AllowShortLoopsOnASingleLine);
+ IO.mapOptional("AllowShortFunctionsOnASingleLine",
+ Style.AllowShortFunctionsOnASingleLine);
IO.mapOptional("AlwaysBreakTemplateDeclarations",
Style.AlwaysBreakTemplateDeclarations);
IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
@@ -136,7 +165,10 @@
Style.ExperimentalAutoDetectBinPacking);
IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels);
IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
+ IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
+ Style.KeepEmptyLinesAtTheStartOfBlocks);
IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
+ IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
IO.mapOptional("ObjCSpaceBeforeProtocolList",
Style.ObjCSpaceBeforeProtocolList);
IO.mapOptional("PenaltyBreakBeforeFirstCallParameter",
@@ -164,11 +196,46 @@
IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses);
IO.mapOptional("SpacesInCStyleCastParentheses",
Style.SpacesInCStyleCastParentheses);
- IO.mapOptional("SpaceAfterControlStatementKeyword",
- Style.SpaceAfterControlStatementKeyword);
+ IO.mapOptional("SpacesInContainerLiterals",
+ Style.SpacesInContainerLiterals);
IO.mapOptional("SpaceBeforeAssignmentOperators",
Style.SpaceBeforeAssignmentOperators);
IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth);
+ IO.mapOptional("CommentPragmas", Style.CommentPragmas);
+ IO.mapOptional("ForEachMacros", Style.ForEachMacros);
+
+ // For backward compatibility.
+ if (!IO.outputting()) {
+ IO.mapOptional("SpaceAfterControlStatementKeyword",
+ Style.SpaceBeforeParens);
+ }
+ IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens);
+ }
+};
+
+// Allows to read vector<FormatStyle> while keeping default values.
+// IO.getContext() should contain a pointer to the FormatStyle structure, that
+// will be used to get default values for missing keys.
+// If the first element has no Language specified, it will be treated as the
+// default one for the following elements.
+template <> struct DocumentListTraits<std::vector<FormatStyle> > {
+ static size_t size(IO &IO, std::vector<FormatStyle> &Seq) {
+ return Seq.size();
+ }
+ static FormatStyle &element(IO &IO, std::vector<FormatStyle> &Seq,
+ size_t Index) {
+ if (Index >= Seq.size()) {
+ assert(Index == Seq.size());
+ FormatStyle Template;
+ if (Seq.size() > 0 && Seq[0].Language == FormatStyle::LK_None) {
+ Template = Seq[0];
+ } else {
+ Template = *((const FormatStyle*)IO.getContext());
+ Template.Language = FormatStyle::LK_None;
+ }
+ Seq.resize(Index + 1, Template);
+ }
+ return Seq[Index];
}
};
}
@@ -177,19 +244,14 @@
namespace clang {
namespace format {
-void setDefaultPenalties(FormatStyle &Style) {
- Style.PenaltyBreakComment = 60;
- Style.PenaltyBreakFirstLessLess = 120;
- Style.PenaltyBreakString = 1000;
- Style.PenaltyExcessCharacter = 1000000;
-}
-
FormatStyle getLLVMStyle() {
FormatStyle LLVMStyle;
+ LLVMStyle.Language = FormatStyle::LK_Cpp;
LLVMStyle.AccessModifierOffset = -2;
LLVMStyle.AlignEscapedNewlinesLeft = false;
LLVMStyle.AlignTrailingComments = true;
LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
+ LLVMStyle.AllowShortFunctionsOnASingleLine = true;
LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
LLVMStyle.AllowShortLoopsOnASingleLine = false;
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
@@ -200,86 +262,84 @@
LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
LLVMStyle.BreakConstructorInitializersBeforeComma = false;
LLVMStyle.ColumnLimit = 80;
+ LLVMStyle.CommentPragmas = "^ IWYU pragma:";
LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
LLVMStyle.ConstructorInitializerIndentWidth = 4;
- LLVMStyle.Cpp11BracedListStyle = false;
+ LLVMStyle.ContinuationIndentWidth = 4;
+ LLVMStyle.Cpp11BracedListStyle = true;
LLVMStyle.DerivePointerBinding = false;
LLVMStyle.ExperimentalAutoDetectBinPacking = false;
+ LLVMStyle.ForEachMacros.push_back("foreach");
+ LLVMStyle.ForEachMacros.push_back("Q_FOREACH");
+ LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");
LLVMStyle.IndentCaseLabels = false;
LLVMStyle.IndentFunctionDeclarationAfterType = false;
LLVMStyle.IndentWidth = 2;
LLVMStyle.TabWidth = 8;
LLVMStyle.MaxEmptyLinesToKeep = 1;
+ LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
+ LLVMStyle.ObjCSpaceAfterProperty = false;
LLVMStyle.ObjCSpaceBeforeProtocolList = true;
LLVMStyle.PointerBindsToType = false;
LLVMStyle.SpacesBeforeTrailingComments = 1;
- LLVMStyle.Standard = FormatStyle::LS_Cpp03;
+ LLVMStyle.Standard = FormatStyle::LS_Cpp11;
LLVMStyle.UseTab = FormatStyle::UT_Never;
LLVMStyle.SpacesInParentheses = false;
LLVMStyle.SpaceInEmptyParentheses = false;
+ LLVMStyle.SpacesInContainerLiterals = true;
LLVMStyle.SpacesInCStyleCastParentheses = false;
- LLVMStyle.SpaceAfterControlStatementKeyword = true;
+ LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
LLVMStyle.SpaceBeforeAssignmentOperators = true;
- LLVMStyle.ContinuationIndentWidth = 4;
LLVMStyle.SpacesInAngles = false;
- setDefaultPenalties(LLVMStyle);
+ LLVMStyle.PenaltyBreakComment = 300;
+ LLVMStyle.PenaltyBreakFirstLessLess = 120;
+ LLVMStyle.PenaltyBreakString = 1000;
+ LLVMStyle.PenaltyExcessCharacter = 1000000;
LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;
LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;
return LLVMStyle;
}
-FormatStyle getGoogleStyle() {
- FormatStyle GoogleStyle;
+FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
+ FormatStyle GoogleStyle = getLLVMStyle();
+ GoogleStyle.Language = Language;
+
GoogleStyle.AccessModifierOffset = -1;
GoogleStyle.AlignEscapedNewlinesLeft = true;
- GoogleStyle.AlignTrailingComments = true;
- GoogleStyle.AllowAllParametersOfDeclarationOnNextLine = true;
GoogleStyle.AllowShortIfStatementsOnASingleLine = true;
GoogleStyle.AllowShortLoopsOnASingleLine = true;
GoogleStyle.AlwaysBreakBeforeMultilineStrings = true;
GoogleStyle.AlwaysBreakTemplateDeclarations = true;
- GoogleStyle.BinPackParameters = true;
- GoogleStyle.BreakBeforeBinaryOperators = false;
- GoogleStyle.BreakBeforeTernaryOperators = true;
- GoogleStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
- GoogleStyle.BreakConstructorInitializersBeforeComma = false;
- GoogleStyle.ColumnLimit = 80;
GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
- GoogleStyle.ConstructorInitializerIndentWidth = 4;
- GoogleStyle.Cpp11BracedListStyle = true;
GoogleStyle.DerivePointerBinding = true;
- GoogleStyle.ExperimentalAutoDetectBinPacking = false;
GoogleStyle.IndentCaseLabels = true;
GoogleStyle.IndentFunctionDeclarationAfterType = true;
- GoogleStyle.IndentWidth = 2;
- GoogleStyle.TabWidth = 8;
- GoogleStyle.MaxEmptyLinesToKeep = 1;
- GoogleStyle.NamespaceIndentation = FormatStyle::NI_None;
+ GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false;
+ GoogleStyle.ObjCSpaceAfterProperty = false;
GoogleStyle.ObjCSpaceBeforeProtocolList = false;
GoogleStyle.PointerBindsToType = true;
GoogleStyle.SpacesBeforeTrailingComments = 2;
GoogleStyle.Standard = FormatStyle::LS_Auto;
- GoogleStyle.UseTab = FormatStyle::UT_Never;
- GoogleStyle.SpacesInParentheses = false;
- GoogleStyle.SpaceInEmptyParentheses = false;
- GoogleStyle.SpacesInCStyleCastParentheses = false;
- GoogleStyle.SpaceAfterControlStatementKeyword = true;
- GoogleStyle.SpaceBeforeAssignmentOperators = true;
- GoogleStyle.ContinuationIndentWidth = 4;
- GoogleStyle.SpacesInAngles = false;
- setDefaultPenalties(GoogleStyle);
GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200;
GoogleStyle.PenaltyBreakBeforeFirstCallParameter = 1;
+ if (Language == FormatStyle::LK_JavaScript) {
+ GoogleStyle.BreakBeforeTernaryOperators = false;
+ GoogleStyle.MaxEmptyLinesToKeep = 2;
+ GoogleStyle.SpacesInContainerLiterals = false;
+ } else if (Language == FormatStyle::LK_Proto) {
+ GoogleStyle.AllowShortFunctionsOnASingleLine = false;
+ }
+
return GoogleStyle;
}
-FormatStyle getChromiumStyle() {
- FormatStyle ChromiumStyle = getGoogleStyle();
+FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
+ FormatStyle ChromiumStyle = getGoogleStyle(Language);
ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
ChromiumStyle.AllowShortLoopsOnASingleLine = false;
@@ -292,12 +352,15 @@
FormatStyle getMozillaStyle() {
FormatStyle MozillaStyle = getLLVMStyle();
MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false;
+ MozillaStyle.Cpp11BracedListStyle = false;
MozillaStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
MozillaStyle.DerivePointerBinding = true;
MozillaStyle.IndentCaseLabels = true;
+ MozillaStyle.ObjCSpaceAfterProperty = true;
MozillaStyle.ObjCSpaceBeforeProtocolList = false;
MozillaStyle.PenaltyReturnTypeOnItsOwnLine = 200;
MozillaStyle.PointerBindsToType = true;
+ MozillaStyle.Standard = FormatStyle::LS_Cpp03;
return MozillaStyle;
}
@@ -308,36 +371,94 @@
Style.BreakBeforeBinaryOperators = true;
Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup;
Style.BreakConstructorInitializersBeforeComma = true;
+ Style.Cpp11BracedListStyle = false;
Style.ColumnLimit = 0;
Style.IndentWidth = 4;
Style.NamespaceIndentation = FormatStyle::NI_Inner;
+ Style.ObjCSpaceAfterProperty = true;
Style.PointerBindsToType = true;
+ Style.Standard = FormatStyle::LS_Cpp03;
return Style;
}
-bool getPredefinedStyle(StringRef Name, FormatStyle *Style) {
- if (Name.equals_lower("llvm"))
- *Style = getLLVMStyle();
- else if (Name.equals_lower("chromium"))
- *Style = getChromiumStyle();
- else if (Name.equals_lower("mozilla"))
- *Style = getMozillaStyle();
- else if (Name.equals_lower("google"))
- *Style = getGoogleStyle();
- else if (Name.equals_lower("webkit"))
- *Style = getWebKitStyle();
- else
- return false;
+FormatStyle getGNUStyle() {
+ FormatStyle Style = getLLVMStyle();
+ Style.BreakBeforeBinaryOperators = true;
+ Style.BreakBeforeBraces = FormatStyle::BS_GNU;
+ Style.BreakBeforeTernaryOperators = true;
+ Style.Cpp11BracedListStyle = false;
+ Style.ColumnLimit = 79;
+ Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
+ Style.Standard = FormatStyle::LS_Cpp03;
+ return Style;
+}
+bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language,
+ FormatStyle *Style) {
+ if (Name.equals_lower("llvm")) {
+ *Style = getLLVMStyle();
+ } else if (Name.equals_lower("chromium")) {
+ *Style = getChromiumStyle(Language);
+ } else if (Name.equals_lower("mozilla")) {
+ *Style = getMozillaStyle();
+ } else if (Name.equals_lower("google")) {
+ *Style = getGoogleStyle(Language);
+ } else if (Name.equals_lower("webkit")) {
+ *Style = getWebKitStyle();
+ } else if (Name.equals_lower("gnu")) {
+ *Style = getGNUStyle();
+ } else {
+ return false;
+ }
+
+ Style->Language = Language;
return true;
}
llvm::error_code parseConfiguration(StringRef Text, FormatStyle *Style) {
+ assert(Style);
+ FormatStyle::LanguageKind Language = Style->Language;
+ assert(Language != FormatStyle::LK_None);
if (Text.trim().empty())
return llvm::make_error_code(llvm::errc::invalid_argument);
+
+ std::vector<FormatStyle> Styles;
llvm::yaml::Input Input(Text);
- Input >> *Style;
- return Input.error();
+ // DocumentListTraits<vector<FormatStyle>> uses the context to get default
+ // values for the fields, keys for which are missing from the configuration.
+ // Mapping also uses the context to get the language to find the correct
+ // base style.
+ Input.setContext(Style);
+ Input >> Styles;
+ if (Input.error())
+ return Input.error();
+
+ for (unsigned i = 0; i < Styles.size(); ++i) {
+ // Ensures that only the first configuration can skip the Language option.
+ if (Styles[i].Language == FormatStyle::LK_None && i != 0)
+ return llvm::make_error_code(llvm::errc::invalid_argument);
+ // Ensure that each language is configured at most once.
+ for (unsigned j = 0; j < i; ++j) {
+ if (Styles[i].Language == Styles[j].Language) {
+ DEBUG(llvm::dbgs()
+ << "Duplicate languages in the config file on positions " << j
+ << " and " << i << "\n");
+ return llvm::make_error_code(llvm::errc::invalid_argument);
+ }
+ }
+ }
+ // Look for a suitable configuration starting from the end, so we can
+ // find the configuration for the specific language first, and the default
+ // configuration (which can only be at slot 0) after it.
+ for (int i = Styles.size() - 1; i >= 0; --i) {
+ if (Styles[i].Language == Language ||
+ Styles[i].Language == FormatStyle::LK_None) {
+ *Style = Styles[i];
+ Style->Language = Language;
+ return llvm::make_error_code(llvm::errc::success);
+ }
+ }
+ return llvm::make_error_code(llvm::errc::not_supported);
}
std::string configurationAsText(const FormatStyle &Style) {
@@ -381,14 +502,14 @@
/// \brief Calculates how many lines can be merged into 1 starting at \p I.
unsigned
tryFitMultipleLinesInOne(unsigned Indent,
- SmallVectorImpl<AnnotatedLine *>::const_iterator &I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
// We can never merge stuff if there are trailing line comments.
- AnnotatedLine *TheLine = *I;
+ const AnnotatedLine *TheLine = *I;
if (TheLine->Last->Type == TT_LineComment)
return 0;
- if (Indent > Style.ColumnLimit)
+ if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)
return 0;
unsigned Limit =
@@ -402,16 +523,46 @@
if (I + 1 == E || I[1]->Type == LT_Invalid)
return 0;
+ if (TheLine->Last->Type == TT_FunctionLBrace &&
+ TheLine->First != TheLine->Last) {
+ return Style.AllowShortFunctionsOnASingleLine
+ ? tryMergeSimpleBlock(I, E, Limit)
+ : 0;
+ }
if (TheLine->Last->is(tok::l_brace)) {
- return tryMergeSimpleBlock(I, E, Limit);
- } else if (Style.AllowShortIfStatementsOnASingleLine &&
- TheLine->First->is(tok::kw_if)) {
- return tryMergeSimpleControlStatement(I, E, Limit);
- } else if (Style.AllowShortLoopsOnASingleLine &&
- TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) {
- return tryMergeSimpleControlStatement(I, E, Limit);
- } else if (TheLine->InPPDirective && (TheLine->First->HasUnescapedNewline ||
- TheLine->First->IsFirst)) {
+ return Style.BreakBeforeBraces == FormatStyle::BS_Attach
+ ? tryMergeSimpleBlock(I, E, Limit)
+ : 0;
+ }
+ if (I[1]->First->Type == TT_FunctionLBrace &&
+ Style.BreakBeforeBraces != FormatStyle::BS_Attach) {
+ // Check for Limit <= 2 to account for the " {".
+ if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(TheLine)))
+ return 0;
+ Limit -= 2;
+
+ unsigned MergedLines = 0;
+ if (Style.AllowShortFunctionsOnASingleLine) {
+ MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
+ // If we managed to merge the block, count the function header, which is
+ // on a separate line.
+ if (MergedLines > 0)
+ ++MergedLines;
+ }
+ return MergedLines;
+ }
+ if (TheLine->First->is(tok::kw_if)) {
+ return Style.AllowShortIfStatementsOnASingleLine
+ ? tryMergeSimpleControlStatement(I, E, Limit)
+ : 0;
+ }
+ if (TheLine->First->isOneOf(tok::kw_for, tok::kw_while)) {
+ return Style.AllowShortLoopsOnASingleLine
+ ? tryMergeSimpleControlStatement(I, E, Limit)
+ : 0;
+ }
+ if (TheLine->InPPDirective &&
+ (TheLine->First->HasUnescapedNewline || TheLine->First->IsFirst)) {
return tryMergeSimplePPDirective(I, E, Limit);
}
return 0;
@@ -419,7 +570,7 @@
private:
unsigned
- tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator &I,
+ tryMergeSimplePPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E,
unsigned Limit) {
if (Limit == 0)
@@ -434,23 +585,25 @@
}
unsigned tryMergeSimpleControlStatement(
- SmallVectorImpl<AnnotatedLine *>::const_iterator &I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
if (Limit == 0)
return 0;
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman &&
+ if ((Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU) &&
I[1]->First->is(tok::l_brace))
return 0;
if (I[1]->InPPDirective != (*I)->InPPDirective ||
(I[1]->InPPDirective && I[1]->First->HasUnescapedNewline))
return 0;
+ Limit = limitConsideringMacros(I + 1, E, Limit);
AnnotatedLine &Line = **I;
if (Line.Last->isNot(tok::r_paren))
return 0;
if (1 + I[1]->Last->TotalLength > Limit)
return 0;
if (I[1]->First->isOneOf(tok::semi, tok::kw_if, tok::kw_for,
- tok::kw_while) ||
+ tok::kw_while) ||
I[1]->First->Type == TT_LineComment)
return 0;
// Only inline simple if's (no nested if or else).
@@ -461,13 +614,9 @@
}
unsigned
- tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator &I,
+ tryMergeSimpleBlock(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
SmallVectorImpl<AnnotatedLine *>::const_iterator E,
unsigned Limit) {
- // No merging if the brace already is on the next line.
- if (Style.BreakBeforeBraces != FormatStyle::BS_Attach)
- return 0;
-
// First, check that the current line allows merging. This is the case if
// we're not in a control flow statement and the last token is an opening
// brace.
@@ -491,6 +640,7 @@
// Check that we still have three lines and they fit into the limit.
if (I + 2 == E || I[2]->Type == LT_Invalid)
return 0;
+ Limit = limitConsideringMacros(I + 2, E, Limit);
if (!nextTwoLinesFitInto(I, Limit))
return 0;
@@ -516,34 +666,51 @@
return 0;
}
+ /// Returns the modified column limit for \p I if it is inside a macro and
+ /// needs a trailing '\'.
+ unsigned
+ limitConsideringMacros(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
+ SmallVectorImpl<AnnotatedLine *>::const_iterator E,
+ unsigned Limit) {
+ if (I[0]->InPPDirective && I + 1 != E &&
+ !I[1]->First->HasUnescapedNewline && !I[1]->First->is(tok::eof)) {
+ return Limit < 2 ? 0 : Limit - 2;
+ }
+ return Limit;
+ }
+
bool nextTwoLinesFitInto(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
unsigned Limit) {
return 1 + I[1]->Last->TotalLength + 1 + I[2]->Last->TotalLength <= Limit;
}
+ bool containsMustBreak(const AnnotatedLine *Line) {
+ for (const FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
+ if (Tok->MustBreakBefore)
+ return true;
+ }
+ return false;
+ }
+
const FormatStyle &Style;
};
class UnwrappedLineFormatter {
public:
- UnwrappedLineFormatter(SourceManager &SourceMgr,
- SmallVectorImpl<CharSourceRange> &Ranges,
- ContinuationIndenter *Indenter,
+ UnwrappedLineFormatter(ContinuationIndenter *Indenter,
WhitespaceManager *Whitespaces,
const FormatStyle &Style)
- : SourceMgr(SourceMgr), Ranges(Ranges), Indenter(Indenter),
- Whitespaces(Whitespaces), Style(Style), Joiner(Style) {}
+ : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
+ Joiner(Style) {}
unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,
- int AdditionalIndent = 0) {
+ int AdditionalIndent = 0, bool FixBadIndentation = false) {
assert(!Lines.empty());
unsigned Penalty = 0;
std::vector<int> IndentForLevel;
for (unsigned i = 0, e = Lines[0]->Level; i != e; ++i)
IndentForLevel.push_back(Style.IndentWidth * i + AdditionalIndent);
- bool PreviousLineWasTouched = false;
const AnnotatedLine *PreviousLine = NULL;
- bool FormatPPDirective = false;
for (SmallVectorImpl<AnnotatedLine *>::const_iterator I = Lines.begin(),
E = Lines.end();
I != E; ++I) {
@@ -551,21 +718,30 @@
const FormatToken *FirstTok = TheLine.First;
int Offset = getIndentOffset(*FirstTok);
- // Check whether this line is part of a formatted preprocessor directive.
- if (FirstTok->HasUnescapedNewline)
- FormatPPDirective = false;
- if (!FormatPPDirective && TheLine.InPPDirective &&
- (touchesLine(TheLine) || touchesPPDirective(I + 1, E)))
- FormatPPDirective = true;
-
// Determine indent and try to merge multiple unwrapped lines.
- while (IndentForLevel.size() <= TheLine.Level)
- IndentForLevel.push_back(-1);
- IndentForLevel.resize(TheLine.Level + 1);
- unsigned Indent = getIndent(IndentForLevel, TheLine.Level);
+ unsigned Indent;
+ if (TheLine.InPPDirective) {
+ Indent = TheLine.Level * Style.IndentWidth;
+ } else {
+ while (IndentForLevel.size() <= TheLine.Level)
+ IndentForLevel.push_back(-1);
+ IndentForLevel.resize(TheLine.Level + 1);
+ Indent = getIndent(IndentForLevel, TheLine.Level);
+ }
+ unsigned LevelIndent = Indent;
if (static_cast<int>(Indent) + Offset >= 0)
Indent += Offset;
+
+ // Merge multiple lines if possible.
unsigned MergedLines = Joiner.tryFitMultipleLinesInOne(Indent, I, E);
+ if (MergedLines > 0 && Style.ColumnLimit == 0) {
+ // Disallow line merging if there is a break at the start of one of the
+ // input lines.
+ for (unsigned i = 0; i < MergedLines; ++i) {
+ if (I[i + 1]->First->NewlinesBefore > 0)
+ MergedLines = 0;
+ }
+ }
if (!DryRun) {
for (unsigned i = 0; i < MergedLines; ++i) {
join(*I[i], *I[i + 1]);
@@ -573,18 +749,18 @@
}
I += MergedLines;
- bool WasMoved = PreviousLineWasTouched && FirstTok->NewlinesBefore == 0;
+ bool FixIndentation =
+ FixBadIndentation && (LevelIndent != FirstTok->OriginalColumn);
if (TheLine.First->is(tok::eof)) {
- if (PreviousLineWasTouched && !DryRun) {
+ if (PreviousLine && PreviousLine->Affected && !DryRun) {
+ // Remove the file's trailing whitespace.
unsigned Newlines = std::min(FirstTok->NewlinesBefore, 1u);
Whitespaces->replaceWhitespace(*TheLine.First, Newlines,
/*IndentLevel=*/0, /*Spaces=*/0,
/*TargetColumn=*/0);
}
} else if (TheLine.Type != LT_Invalid &&
- (WasMoved || FormatPPDirective || touchesLine(TheLine))) {
- unsigned LevelIndent =
- getIndent(IndentForLevel, TheLine.Level);
+ (TheLine.Affected || FixIndentation)) {
if (FirstTok->WhitespaceRange.isValid()) {
if (!DryRun)
formatFirstToken(*TheLine.First, PreviousLine, TheLine.Level,
@@ -606,6 +782,7 @@
while (State.NextToken != NULL)
Indenter->addTokenToState(State, /*Newline=*/false, DryRun);
} else if (Style.ColumnLimit == 0) {
+ // FIXME: Implement nested blocks for ColumnLimit = 0.
NoColumnLimitFormatter Formatter(Indenter);
if (!DryRun)
Formatter.format(Indent, &TheLine);
@@ -613,8 +790,10 @@
Penalty += format(TheLine, Indent, DryRun);
}
- IndentForLevel[TheLine.Level] = LevelIndent;
- PreviousLineWasTouched = true;
+ if (!TheLine.InPPDirective)
+ IndentForLevel[TheLine.Level] = LevelIndent;
+ } else if (TheLine.ChildrenAffected) {
+ format(TheLine.Children, DryRun);
} else {
// Format the first token if necessary, and notify the WhitespaceManager
// about the unchanged whitespace.
@@ -623,9 +802,9 @@
(Tok->NewlinesBefore > 0 || Tok->IsFirst)) {
unsigned LevelIndent = Tok->OriginalColumn;
if (!DryRun) {
- // Remove trailing whitespace of the previous line if it was
- // touched.
- if (PreviousLineWasTouched || touchesEmptyLineBefore(TheLine)) {
+ // Remove trailing whitespace of the previous line.
+ if ((PreviousLine && PreviousLine->Affected) ||
+ TheLine.LeadingEmptyLinesAffected) {
formatFirstToken(*Tok, PreviousLine, TheLine.Level, LevelIndent,
TheLine.InPPDirective);
} else {
@@ -635,16 +814,12 @@
if (static_cast<int>(LevelIndent) - Offset >= 0)
LevelIndent -= Offset;
- if (Tok->isNot(tok::comment))
+ if (Tok->isNot(tok::comment) && !TheLine.InPPDirective)
IndentForLevel[TheLine.Level] = LevelIndent;
} else if (!DryRun) {
Whitespaces->addUntouchableToken(*Tok, TheLine.InPPDirective);
}
}
- // If we did not reformat this unwrapped line, the column at the end of
- // the last token is unchanged - thus, we can calculate the end of the
- // last token.
- PreviousLineWasTouched = false;
}
if (!DryRun) {
for (FormatToken *Tok = TheLine.First; Tok != NULL; Tok = Tok->Next) {
@@ -723,6 +898,12 @@
if (Newlines == 0 && !RootToken.IsFirst)
Newlines = 1;
+ // Remove empty lines after "{".
+ if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
+ PreviousLine->Last->is(tok::l_brace) &&
+ PreviousLine->First->isNot(tok::kw_namespace))
+ Newlines = 1;
+
// Insert extra new line before access specifiers.
if (PreviousLine && PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) &&
RootToken.isAccessSpecifier() && RootToken.NewlinesBefore == 1)
@@ -732,9 +913,9 @@
if (PreviousLine && PreviousLine->First->isAccessSpecifier())
Newlines = std::min(1u, Newlines);
- Whitespaces->replaceWhitespace(
- RootToken, Newlines, IndentLevel, Indent, Indent,
- InPPDirective && !RootToken.HasUnescapedNewline);
+ Whitespaces->replaceWhitespace(RootToken, Newlines, IndentLevel, Indent,
+ Indent, InPPDirective &&
+ !RootToken.HasUnescapedNewline);
}
/// \brief Get the indent of \p Level from \p IndentForLevel.
@@ -753,6 +934,8 @@
void join(AnnotatedLine &A, const AnnotatedLine &B) {
assert(!A.Last->Next);
assert(!B.First->Previous);
+ if (B.Affected)
+ A.Affected = true;
A.Last->Next = B.First;
B.First->Previous = A.Last;
B.First->CanBreakBefore = true;
@@ -768,48 +951,6 @@
return Style.ColumnLimit - (InPPDirective ? 2 : 0);
}
- bool touchesRanges(const CharSourceRange &Range) {
- for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(),
- E = Ranges.end();
- I != E; ++I) {
- if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) &&
- !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin()))
- return true;
- }
- return false;
- }
-
- bool touchesLine(const AnnotatedLine &TheLine) {
- const FormatToken *First = TheLine.First;
- const FormatToken *Last = TheLine.Last;
- CharSourceRange LineRange = CharSourceRange::getCharRange(
- First->WhitespaceRange.getBegin().getLocWithOffset(
- First->LastNewlineOffset),
- Last->getStartOfNonWhitespace().getLocWithOffset(
- Last->TokenText.size() - 1));
- return touchesRanges(LineRange);
- }
-
- bool touchesPPDirective(SmallVectorImpl<AnnotatedLine *>::const_iterator I,
- SmallVectorImpl<AnnotatedLine *>::const_iterator E) {
- for (; I != E; ++I) {
- if ((*I)->First->HasUnescapedNewline)
- return false;
- if (touchesLine(**I))
- return true;
- }
- return false;
- }
-
- bool touchesEmptyLineBefore(const AnnotatedLine &TheLine) {
- const FormatToken *First = TheLine.First;
- CharSourceRange LineRange = CharSourceRange::getCharRange(
- First->WhitespaceRange.getBegin(),
- First->WhitespaceRange.getBegin().getLocWithOffset(
- First->LastNewlineOffset));
- return touchesRanges(LineRange);
- }
-
/// \brief Analyze the entire solution space starting from \p InitialState.
///
/// This implements a variant of Dijkstra's algorithm on the graph that spans
@@ -955,13 +1096,14 @@
if (NewLine) {
int AdditionalIndent = State.Stack.back().Indent -
Previous.Children[0]->Level * Style.IndentWidth;
- Penalty += format(Previous.Children, DryRun, AdditionalIndent);
+ Penalty += format(Previous.Children, DryRun, AdditionalIndent,
+ /*FixBadIndentation=*/true);
return true;
}
// Cannot merge multiple statements into a single line.
if (Previous.Children.size() > 1)
- return false;
+ return false;
// We can't put the closing "}" on a line with a trailing comment.
if (Previous.Children[0]->Last->isTrailingComment())
@@ -979,8 +1121,6 @@
return true;
}
- SourceManager &SourceMgr;
- SmallVectorImpl<CharSourceRange> &Ranges;
ContinuationIndenter *Indenter;
WhitespaceManager *Whitespaces;
FormatStyle Style;
@@ -997,13 +1137,17 @@
TrailingWhitespace(0), Lex(Lex), SourceMgr(SourceMgr), Style(Style),
IdentTable(getFormattingLangOpts()), Encoding(Encoding) {
Lex.SetKeepWhitespaceMode(true);
+
+ for (const std::string& ForEachMacro : Style.ForEachMacros)
+ ForEachMacros.push_back(&IdentTable.get(ForEachMacro));
+ std::sort(ForEachMacros.begin(), ForEachMacros.end());
}
ArrayRef<FormatToken *> lex() {
assert(Tokens.empty());
do {
Tokens.push_back(getNextToken());
- maybeJoinPreviousTokens();
+ tryMergePreviousTokens();
} while (Tokens.back()->Tok.isNot(tok::eof));
return Tokens;
}
@@ -1011,23 +1155,65 @@
IdentifierTable &getIdentTable() { return IdentTable; }
private:
- void maybeJoinPreviousTokens() {
- if (Tokens.size() < 4)
+ void tryMergePreviousTokens() {
+ if (tryMerge_TMacro())
return;
+
+ if (Style.Language == FormatStyle::LK_JavaScript) {
+ static tok::TokenKind JSIdentity[] = { tok::equalequal, tok::equal };
+ static tok::TokenKind JSNotIdentity[] = { tok::exclaimequal, tok::equal };
+ static tok::TokenKind JSShiftEqual[] = { tok::greater, tok::greater,
+ tok::greaterequal };
+ // FIXME: We probably need to change token type to mimic operator with the
+ // correct priority.
+ if (tryMergeTokens(JSIdentity))
+ return;
+ if (tryMergeTokens(JSNotIdentity))
+ return;
+ if (tryMergeTokens(JSShiftEqual))
+ return;
+ }
+ }
+
+ bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds) {
+ if (Tokens.size() < Kinds.size())
+ return false;
+
+ SmallVectorImpl<FormatToken *>::const_iterator First =
+ Tokens.end() - Kinds.size();
+ if (!First[0]->is(Kinds[0]))
+ return false;
+ unsigned AddLength = 0;
+ for (unsigned i = 1; i < Kinds.size(); ++i) {
+ if (!First[i]->is(Kinds[i]) || First[i]->WhitespaceRange.getBegin() !=
+ First[i]->WhitespaceRange.getEnd())
+ return false;
+ AddLength += First[i]->TokenText.size();
+ }
+ Tokens.resize(Tokens.size() - Kinds.size() + 1);
+ First[0]->TokenText = StringRef(First[0]->TokenText.data(),
+ First[0]->TokenText.size() + AddLength);
+ First[0]->ColumnWidth += AddLength;
+ return true;
+ }
+
+ bool tryMerge_TMacro() {
+ if (Tokens.size() < 4)
+ return false;
FormatToken *Last = Tokens.back();
if (!Last->is(tok::r_paren))
- return;
+ return false;
FormatToken *String = Tokens[Tokens.size() - 2];
if (!String->is(tok::string_literal) || String->IsMultiline)
- return;
+ return false;
if (!Tokens[Tokens.size() - 3]->is(tok::l_paren))
- return;
+ return false;
FormatToken *Macro = Tokens[Tokens.size() - 4];
if (Macro->TokenText != "_T")
- return;
+ return false;
const char *Start = Macro->TokenText.data();
const char *End = Last->TokenText.data() + Last->TokenText.size();
@@ -1043,6 +1229,7 @@
Tokens.pop_back();
Tokens.pop_back();
Tokens.back() = String;
+ return true;
}
FormatToken *getNextToken() {
@@ -1174,6 +1361,10 @@
Column = FormatTok->LastLineColumnWidth;
}
+ FormatTok->IsForEachMacro =
+ std::binary_search(ForEachMacros.begin(), ForEachMacros.end(),
+ FormatTok->Tok.getIdentifierInfo());
+
return FormatTok;
}
@@ -1189,6 +1380,7 @@
encoding::Encoding Encoding;
llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
SmallVector<FormatToken *, 16> Tokens;
+ SmallVector<IdentifierInfo*, 8> ForEachMacros;
void readRawToken(FormatToken &Tok) {
Lex.LexFromRawLexer(Tok.Tok);
@@ -1196,14 +1388,31 @@
Tok.Tok.getLength());
// For formatting, treat unterminated string literals like normal string
// literals.
- if (Tok.is(tok::unknown) && !Tok.TokenText.empty() &&
- Tok.TokenText[0] == '"') {
- Tok.Tok.setKind(tok::string_literal);
- Tok.IsUnterminatedLiteral = true;
+ if (Tok.is(tok::unknown)) {
+ if (!Tok.TokenText.empty() && Tok.TokenText[0] == '"') {
+ Tok.Tok.setKind(tok::string_literal);
+ Tok.IsUnterminatedLiteral = true;
+ } else if (Style.Language == FormatStyle::LK_JavaScript &&
+ Tok.TokenText == "''") {
+ Tok.Tok.setKind(tok::char_constant);
+ }
}
}
};
+static StringRef getLanguageName(FormatStyle::LanguageKind Language) {
+ switch (Language) {
+ case FormatStyle::LK_Cpp:
+ return "C++";
+ case FormatStyle::LK_JavaScript:
+ return "JavaScript";
+ case FormatStyle::LK_Proto:
+ return "Proto";
+ default:
+ return "Unknown";
+ }
+}
+
class Formatter : public UnwrappedLineConsumer {
public:
Formatter(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr,
@@ -1216,6 +1425,8 @@
<< (Encoding == encoding::Encoding_UTF8 ? "UTF8"
: "unknown")
<< "\n");
+ DEBUG(llvm::dbgs() << "Language: " << getLanguageName(Style.Language)
+ << "\n");
}
tooling::Replacements format() {
@@ -1261,17 +1472,152 @@
for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
Annotator.calculateFormattingInformation(*AnnotatedLines[i]);
}
+ computeAffectedLines(AnnotatedLines.begin(), AnnotatedLines.end());
Annotator.setCommentLineLevels(AnnotatedLines);
ContinuationIndenter Indenter(Style, SourceMgr, Whitespaces, Encoding,
BinPackInconclusiveFunctions);
- UnwrappedLineFormatter Formatter(SourceMgr, Ranges, &Indenter, &Whitespaces,
- Style);
+ UnwrappedLineFormatter Formatter(&Indenter, &Whitespaces, Style);
Formatter.format(AnnotatedLines, /*DryRun=*/false);
return Whitespaces.generateReplacements();
}
private:
+ // Determines which lines are affected by the SourceRanges given as input.
+ // Returns \c true if at least one line between I and E or one of their
+ // children is affected.
+ bool computeAffectedLines(SmallVectorImpl<AnnotatedLine *>::iterator I,
+ SmallVectorImpl<AnnotatedLine *>::iterator E) {
+ bool SomeLineAffected = false;
+ const AnnotatedLine *PreviousLine = NULL;
+ while (I != E) {
+ AnnotatedLine *Line = *I;
+ Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First);
+
+ // If a line is part of a preprocessor directive, it needs to be formatted
+ // if any token within the directive is affected.
+ if (Line->InPPDirective) {
+ FormatToken *Last = Line->Last;
+ SmallVectorImpl<AnnotatedLine *>::iterator PPEnd = I + 1;
+ while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) {
+ Last = (*PPEnd)->Last;
+ ++PPEnd;
+ }
+
+ if (affectsTokenRange(*Line->First, *Last,
+ /*IncludeLeadingNewlines=*/false)) {
+ SomeLineAffected = true;
+ markAllAsAffected(I, PPEnd);
+ }
+ I = PPEnd;
+ continue;
+ }
+
+ if (nonPPLineAffected(Line, PreviousLine))
+ SomeLineAffected = true;
+
+ PreviousLine = Line;
+ ++I;
+ }
+ return SomeLineAffected;
+ }
+
+ // Determines whether 'Line' is affected by the SourceRanges given as input.
+ // Returns \c true if line or one if its children is affected.
+ bool nonPPLineAffected(AnnotatedLine *Line,
+ const AnnotatedLine *PreviousLine) {
+ bool SomeLineAffected = false;
+ Line->ChildrenAffected =
+ computeAffectedLines(Line->Children.begin(), Line->Children.end());
+ if (Line->ChildrenAffected)
+ SomeLineAffected = true;
+
+ // Stores whether one of the line's tokens is directly affected.
+ bool SomeTokenAffected = false;
+ // Stores whether we need to look at the leading newlines of the next token
+ // in order to determine whether it was affected.
+ bool IncludeLeadingNewlines = false;
+
+ // Stores whether the first child line of any of this line's tokens is
+ // affected.
+ bool SomeFirstChildAffected = false;
+
+ for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
+ // Determine whether 'Tok' was affected.
+ if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines))
+ SomeTokenAffected = true;
+
+ // Determine whether the first child of 'Tok' was affected.
+ if (!Tok->Children.empty() && Tok->Children.front()->Affected)
+ SomeFirstChildAffected = true;
+
+ IncludeLeadingNewlines = Tok->Children.empty();
+ }
+
+ // Was this line moved, i.e. has it previously been on the same line as an
+ // affected line?
+ bool LineMoved = PreviousLine && PreviousLine->Affected &&
+ Line->First->NewlinesBefore == 0;
+
+ bool IsContinuedComment = Line->First->is(tok::comment) &&
+ Line->First->Next == NULL &&
+ Line->First->NewlinesBefore < 2 && PreviousLine &&
+ PreviousLine->Affected &&
+ PreviousLine->Last->is(tok::comment);
+
+ if (SomeTokenAffected || SomeFirstChildAffected || LineMoved ||
+ IsContinuedComment) {
+ Line->Affected = true;
+ SomeLineAffected = true;
+ }
+ return SomeLineAffected;
+ }
+
+ // Marks all lines between I and E as well as all their children as affected.
+ void markAllAsAffected(SmallVectorImpl<AnnotatedLine *>::iterator I,
+ SmallVectorImpl<AnnotatedLine *>::iterator E) {
+ while (I != E) {
+ (*I)->Affected = true;
+ markAllAsAffected((*I)->Children.begin(), (*I)->Children.end());
+ ++I;
+ }
+ }
+
+ // Returns true if the range from 'First' to 'Last' intersects with one of the
+ // input ranges.
+ bool affectsTokenRange(const FormatToken &First, const FormatToken &Last,
+ bool IncludeLeadingNewlines) {
+ SourceLocation Start = First.WhitespaceRange.getBegin();
+ if (!IncludeLeadingNewlines)
+ Start = Start.getLocWithOffset(First.LastNewlineOffset);
+ SourceLocation End = Last.getStartOfNonWhitespace();
+ if (Last.TokenText.size() > 0)
+ End = End.getLocWithOffset(Last.TokenText.size() - 1);
+ CharSourceRange Range = CharSourceRange::getCharRange(Start, End);
+ return affectsCharSourceRange(Range);
+ }
+
+ // Returns true if one of the input ranges intersect the leading empty lines
+ // before 'Tok'.
+ bool affectsLeadingEmptyLines(const FormatToken &Tok) {
+ CharSourceRange EmptyLineRange = CharSourceRange::getCharRange(
+ Tok.WhitespaceRange.getBegin(),
+ Tok.WhitespaceRange.getBegin().getLocWithOffset(Tok.LastNewlineOffset));
+ return affectsCharSourceRange(EmptyLineRange);
+ }
+
+ // Returns true if 'Range' intersects with one of the input ranges.
+ bool affectsCharSourceRange(const CharSourceRange &Range) {
+ for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(),
+ E = Ranges.end();
+ I != E; ++I) {
+ if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) &&
+ !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin()))
+ return true;
+ }
+ return false;
+ }
+
static bool inputUsesCRLF(StringRef Text) {
return Text.count('\r') * 2 > Text.count('\n');
}
@@ -1330,12 +1676,12 @@
HasBinPackedFunction || !HasOnePerLineFunction;
}
- virtual void consumeUnwrappedLine(const UnwrappedLine &TheLine) {
+ void consumeUnwrappedLine(const UnwrappedLine &TheLine) override {
assert(!UnwrappedLines.empty());
UnwrappedLines.back().push_back(TheLine);
}
- virtual void finishRun() {
+ void finishRun() override {
UnwrappedLines.push_back(SmallVector<UnwrappedLine, 16>());
}
@@ -1407,11 +1753,25 @@
"parameters, e.g.:\n"
" -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
-FormatStyle getStyle(StringRef StyleName, StringRef FileName) {
- // Fallback style in case the rest of this function can't determine a style.
- StringRef FallbackStyle = "LLVM";
- FormatStyle Style;
- getPredefinedStyle(FallbackStyle, &Style);
+static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
+ if (FileName.endswith_lower(".js")) {
+ return FormatStyle::LK_JavaScript;
+ } else if (FileName.endswith_lower(".proto") ||
+ FileName.endswith_lower(".protodevel")) {
+ return FormatStyle::LK_Proto;
+ }
+ return FormatStyle::LK_Cpp;
+}
+
+FormatStyle getStyle(StringRef StyleName, StringRef FileName,
+ StringRef FallbackStyle) {
+ FormatStyle Style = getLLVMStyle();
+ Style.Language = getLanguageByFileName(FileName);
+ if (!getPredefinedStyle(FallbackStyle, Style.Language, &Style)) {
+ llvm::errs() << "Invalid fallback style \"" << FallbackStyle
+ << "\" using LLVM style\n";
+ return Style;
+ }
if (StyleName.startswith("{")) {
// Parse YAML/JSON style from the command line.
@@ -1423,12 +1783,14 @@
}
if (!StyleName.equals_lower("file")) {
- if (!getPredefinedStyle(StyleName, &Style))
+ if (!getPredefinedStyle(StyleName, Style.Language, &Style))
llvm::errs() << "Invalid value for -style, using " << FallbackStyle
<< " style\n";
return Style;
}
+ // Look for .clang-format/_clang-format file in the file's parent directories.
+ SmallString<128> UnsuitableConfigFiles;
SmallString<128> Path(FileName);
llvm::sys::fs::make_absolute(Path);
for (StringRef Directory = Path; !Directory.empty();
@@ -1453,16 +1815,22 @@
}
if (IsFile) {
- OwningPtr<llvm::MemoryBuffer> Text;
+ std::unique_ptr<llvm::MemoryBuffer> Text;
if (llvm::error_code ec =
llvm::MemoryBuffer::getFile(ConfigFile.c_str(), Text)) {
llvm::errs() << ec.message() << "\n";
- continue;
+ break;
}
if (llvm::error_code ec = parseConfiguration(Text->getBuffer(), &Style)) {
+ if (ec == llvm::errc::not_supported) {
+ if (!UnsuitableConfigFiles.empty())
+ UnsuitableConfigFiles.append(", ");
+ UnsuitableConfigFiles.append(ConfigFile);
+ continue;
+ }
llvm::errs() << "Error reading " << ConfigFile << ": " << ec.message()
<< "\n";
- continue;
+ break;
}
DEBUG(llvm::dbgs() << "Using configuration file " << ConfigFile << "\n");
return Style;
@@ -1470,6 +1838,11 @@
}
llvm::errs() << "Can't find usable .clang-format, using " << FallbackStyle
<< " style\n";
+ if (!UnsuitableConfigFiles.empty()) {
+ llvm::errs() << "Configuration file(s) do(es) not support "
+ << getLanguageName(Style.Language) << ": "
+ << UnsuitableConfigFiles << "\n";
+ }
return Style;
}
diff --git a/lib/Format/FormatToken.cpp b/lib/Format/FormatToken.cpp
index 8ac704a..c147dbb 100644
--- a/lib/Format/FormatToken.cpp
+++ b/lib/Format/FormatToken.cpp
@@ -22,15 +22,44 @@
namespace clang {
namespace format {
+// FIXME: This is copy&pasted from Sema. Put it in a common place and remove
+// duplication.
+bool FormatToken::isSimpleTypeSpecifier() const {
+ switch (Tok.getKind()) {
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw___int64:
+ case tok::kw___int128:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_int:
+ case tok::kw_half:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_wchar_t:
+ case tok::kw_bool:
+ case tok::kw___underlying_type:
+ case tok::annot_typename:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ case tok::kw_typeof:
+ case tok::kw_decltype:
+ return true;
+ default:
+ return false;
+ }
+}
+
TokenRole::~TokenRole() {}
void TokenRole::precomputeFormattingInfos(const FormatToken *Token) {}
-unsigned CommaSeparatedList::format(LineState &State,
- ContinuationIndenter *Indenter,
- bool DryRun) {
- if (!State.NextToken->Previous || !State.NextToken->Previous->Previous ||
- Commas.size() <= 2)
+unsigned CommaSeparatedList::formatAfterToken(LineState &State,
+ ContinuationIndenter *Indenter,
+ bool DryRun) {
+ if (!State.NextToken->Previous || !State.NextToken->Previous->Previous)
return 0;
// Ensure that we start on the opening brace.
@@ -48,8 +77,11 @@
// Find the best ColumnFormat, i.e. the best number of columns to use.
const ColumnFormat *Format = getColumnFormat(RemainingCodePoints);
+ // If no ColumnFormat can be used, the braced list would generally be
+ // bin-packed. Add a severe penalty to this so that column layouts are
+ // preferred if possible.
if (!Format)
- return 0;
+ return 10000;
// Format the entire list.
unsigned Penalty = 0;
@@ -79,6 +111,14 @@
return Penalty;
}
+unsigned CommaSeparatedList::formatFromToken(LineState &State,
+ ContinuationIndenter *Indenter,
+ bool DryRun) {
+ if (HasNestedBracedList)
+ State.Stack.back().AvoidBinPacking = true;
+ return 0;
+}
+
// Returns the lengths in code points between Begin and End (both included),
// assuming that the entire sequence is put on a single line.
static unsigned CodePointsBetween(const FormatToken *Begin,
@@ -99,7 +139,6 @@
// trailing comments which are otherwise ignored for column alignment.
SmallVector<unsigned, 8> EndOfLineItemLength;
- bool HasNestedBracedList = false;
for (unsigned i = 0, e = Commas.size() + 1; i != e; ++i) {
// Skip comments on their own line.
while (ItemBegin->HasUnescapedNewline && ItemBegin->isTrailingComment())
@@ -139,6 +178,13 @@
ItemBegin = ItemEnd->Next;
}
+ // If this doesn't have a nested list, we require at least 6 elements in order
+ // create a column layout. If it has a nested list, column layout ensures one
+ // list element per line.
+ if (HasNestedBracedList || Commas.size() < 5 ||
+ Token->NestingLevel != 0)
+ return;
+
// We can never place more than ColumnLimit / 3 items in a row (because of the
// spaces and the comma).
for (unsigned Columns = 1; Columns <= Style.ColumnLimit / 3; ++Columns) {
@@ -175,11 +221,6 @@
if (Format.TotalWidth > Style.ColumnLimit)
continue;
- // If this braced list has nested braced list, we format it either with one
- // element per line or with all elements on one line.
- if (HasNestedBracedList && Columns > 1 && Format.LineCount > 1)
- continue;
-
Formats.push_back(Format);
}
}
diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h
index 2145ee2..a5aaa6f 100644
--- a/lib/Format/FormatToken.h
+++ b/lib/Format/FormatToken.h
@@ -19,7 +19,7 @@
#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
-#include "llvm/ADT/OwningPtr.h"
+#include <memory>
namespace clang {
namespace format {
@@ -27,6 +27,7 @@
enum TokenType {
TT_ArrayInitializerLSquare,
TT_ArraySubscriptLSquare,
+ TT_AttributeParen,
TT_BinaryOperator,
TT_BitFieldColon,
TT_BlockComment,
@@ -39,10 +40,12 @@
TT_ImplicitStringLiteral,
TT_InlineASMColon,
TT_InheritanceColon,
+ TT_FunctionLBrace,
TT_FunctionTypeLParen,
TT_LambdaLSquare,
TT_LineComment,
TT_ObjCBlockLParen,
+ TT_ObjCBlockLBrace,
TT_ObjCDecl,
TT_ObjCForIn,
TT_ObjCMethodExpr,
@@ -57,6 +60,7 @@
TT_StartOfName,
TT_TemplateCloser,
TT_TemplateOpener,
+ TT_TrailingAnnotation,
TT_TrailingReturnArrow,
TT_TrailingUnaryOperator,
TT_UnaryOperator,
@@ -87,7 +91,7 @@
class AnnotatedLine;
/// \brief A wrapper around a \c Token storing information about the
-/// whitespace characters preceeding it.
+/// whitespace characters preceding it.
struct FormatToken {
FormatToken()
: NewlinesBefore(0), HasUnescapedNewline(false), LastNewlineOffset(0),
@@ -96,11 +100,11 @@
BlockKind(BK_Unknown), Type(TT_Unknown), SpacesRequiredBefore(0),
CanBreakBefore(false), ClosesTemplateDeclaration(false),
ParameterCount(0), PackingKind(PPK_Inconclusive), TotalLength(0),
- UnbreakableTailLength(0), BindingStrength(0), SplitPenalty(0),
- LongestObjCSelectorName(0), FakeRParens(0),
+ UnbreakableTailLength(0), BindingStrength(0), NestingLevel(0),
+ SplitPenalty(0), LongestObjCSelectorName(0), FakeRParens(0),
StartsBinaryExpression(false), EndsBinaryExpression(false),
LastInChainOfCalls(false), PartOfMultiVariableDeclStmt(false),
- MatchingParen(NULL), Previous(NULL), Next(NULL),
+ IsForEachMacro(false), MatchingParen(NULL), Previous(NULL), Next(NULL),
Decision(FD_Unformatted), Finalized(false) {}
/// \brief The \c Token.
@@ -116,7 +120,7 @@
/// Token.
bool HasUnescapedNewline;
- /// \brief The range of the whitespace immediately preceeding the \c Token.
+ /// \brief The range of the whitespace immediately preceding the \c Token.
SourceRange WhitespaceRange;
/// \brief The offset just past the last '\n' in this token's leading
@@ -184,7 +188,7 @@
/// \brief A token can have a special role that can carry extra information
/// about the token's formatting.
- llvm::OwningPtr<TokenRole> Role;
+ std::unique_ptr<TokenRole> Role;
/// \brief If this is an opening parenthesis, how are the parameters packed?
ParameterPackingKind PackingKind;
@@ -206,11 +210,18 @@
/// operator precedence, parenthesis nesting, etc.
unsigned BindingStrength;
+ /// \brief The nesting level of this token, i.e. the number of surrounding (),
+ /// [], {} or <>.
+ unsigned NestingLevel;
+
/// \brief Penalty for inserting a line break before this token.
unsigned SplitPenalty;
/// \brief If this is the first ObjC selector name in an ObjC method
/// definition or call, this contains the length of the longest name.
+ ///
+ /// This being set to 0 means that the selectors should not be colon-aligned,
+ /// e.g. because several of them are block-type.
unsigned LongestObjCSelectorName;
/// \brief Stores the number of required fake parentheses and the
@@ -236,6 +247,9 @@
/// Only set if \c Type == \c TT_StartOfName.
bool PartOfMultiVariableDeclStmt;
+ /// \brief Is this a foreach macro?
+ bool IsForEachMacro;
+
bool is(tok::TokenKind Kind) const { return Tok.is(Kind); }
bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const {
@@ -260,6 +274,7 @@
}
bool isNot(tok::TokenKind Kind) const { return Tok.isNot(Kind); }
+ bool isStringLiteral() const { return tok::isStringLiteral(Tok.getKind()); }
bool isObjCAtKeyword(tok::ObjCKeywordKind Kind) const {
return Tok.isObjCAtKeyword(Kind);
@@ -270,6 +285,9 @@
(!ColonRequired || (Next && Next->is(tok::colon)));
}
+ /// \brief Determine whether the token is a simple-type-specifier.
+ bool isSimpleTypeSpecifier() const;
+
bool isObjCAccessSpecifier() const {
return is(tok::at) && Next && (Next->isObjCAtKeyword(tok::objc_public) ||
Next->isObjCAtKeyword(tok::objc_protected) ||
@@ -388,10 +406,21 @@
/// \brief Apply the special formatting that the given role demands.
///
+ /// Assumes that the token having this role is already formatted.
+ ///
/// Continues formatting from \p State leaving indentation to \p Indenter and
/// returns the total penalty that this formatting incurs.
- virtual unsigned format(LineState &State, ContinuationIndenter *Indenter,
- bool DryRun) {
+ virtual unsigned formatFromToken(LineState &State,
+ ContinuationIndenter *Indenter,
+ bool DryRun) {
+ return 0;
+ }
+
+ /// \brief Same as \c formatFromToken, but assumes that the first token has
+ /// already been set thereby deciding on the first line break.
+ virtual unsigned formatAfterToken(LineState &State,
+ ContinuationIndenter *Indenter,
+ bool DryRun) {
return 0;
}
@@ -404,15 +433,19 @@
class CommaSeparatedList : public TokenRole {
public:
- CommaSeparatedList(const FormatStyle &Style) : TokenRole(Style) {}
+ CommaSeparatedList(const FormatStyle &Style)
+ : TokenRole(Style), HasNestedBracedList(false) {}
- virtual void precomputeFormattingInfos(const FormatToken *Token);
+ void precomputeFormattingInfos(const FormatToken *Token) override;
- virtual unsigned format(LineState &State, ContinuationIndenter *Indenter,
- bool DryRun);
+ unsigned formatAfterToken(LineState &State, ContinuationIndenter *Indenter,
+ bool DryRun) override;
+
+ unsigned formatFromToken(LineState &State, ContinuationIndenter *Indenter,
+ bool DryRun) override;
/// \brief Adds \p Token as the next comma to the \c CommaSeparated list.
- virtual void CommaFound(const FormatToken *Token) { Commas.push_back(Token); }
+ void CommaFound(const FormatToken *Token) override { Commas.push_back(Token);}
private:
/// \brief A struct that holds information on how to format a given list with
@@ -444,6 +477,8 @@
/// \brief Precomputed formats that can be used for this list.
SmallVector<ColumnFormat, 4> Formats;
+
+ bool HasNestedBracedList;
};
} // namespace format
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 074e1d7..0034235 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -34,6 +34,7 @@
: Style(Style), Line(Line), CurrentToken(Line.First),
KeywordVirtualFound(false), AutoFound(false), Ident_in(Ident_in) {
Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
+ resetTokenMetadata(CurrentToken);
}
private:
@@ -43,6 +44,11 @@
ScopedContextCreator ContextCreator(*this, tok::less, 10);
FormatToken *Left = CurrentToken->Previous;
Contexts.back().IsExpression = false;
+ // If there's a template keyword before the opening angle bracket, this is a
+ // template parameter, not an argument.
+ Contexts.back().InTemplateArgument =
+ Left->Previous != NULL && Left->Previous->Tok.isNot(tok::kw_template);
+
while (CurrentToken != NULL) {
if (CurrentToken->is(tok::greater)) {
Left->MatchingParen = CurrentToken;
@@ -61,7 +67,11 @@
// parameters.
// FIXME: This is getting out of hand, write a decent parser.
if (CurrentToken->Previous->isOneOf(tok::pipepipe, tok::ampamp) &&
- (CurrentToken->Previous->Type == TT_BinaryOperator ||
+ ((CurrentToken->Previous->Type == TT_BinaryOperator &&
+ // Toplevel bool expressions do not make lots of sense;
+ // If we're on the top level, it contains only the base context and
+ // the context for the current opening angle bracket.
+ Contexts.size() > 2) ||
Contexts[Contexts.size() - 2].IsExpression) &&
Line.First->isNot(tok::kw_template))
return false;
@@ -84,7 +94,7 @@
bool StartsObjCMethodExpr = false;
FormatToken *Left = CurrentToken->Previous;
if (CurrentToken->is(tok::caret)) {
- // ^( starts a block.
+ // (^ can start a block type.
Left->Type = TT_ObjCBlockLParen;
} else if (FormatToken *MaybeSel = Left->Previous) {
// @selector( starts a selector.
@@ -94,8 +104,10 @@
}
}
- if (Left->Previous && Left->Previous->isOneOf(tok::kw_static_assert,
- tok::kw_if, tok::kw_while)) {
+ if (Left->Previous &&
+ (Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_if,
+ tok::kw_while, tok::l_paren, tok::comma) ||
+ Left->Previous->Type == TT_BinaryOperator)) {
// static_assert, if and while usually contain expressions.
Contexts.back().IsExpression = true;
} else if (Left->Previous && Left->Previous->is(tok::r_square) &&
@@ -103,6 +115,15 @@
Left->Previous->MatchingParen->Type == TT_LambdaLSquare) {
// This is a parameter list of a lambda expression.
Contexts.back().IsExpression = false;
+ } else if (Contexts[Contexts.size() - 2].CaretFound) {
+ // This is the parameter list of an ObjC block.
+ Contexts.back().IsExpression = false;
+ } else if (Left->Previous && Left->Previous->is(tok::kw___attribute)) {
+ Left->Type = TT_AttributeParen;
+ } else if (Left->Previous && Left->Previous->IsForEachMacro) {
+ // The first argument to a foreach macro is a declaration.
+ Contexts.back().IsForEachMacro = true;
+ Contexts.back().IsExpression = false;
}
if (StartsObjCMethodExpr) {
@@ -153,6 +174,9 @@
}
}
+ if (Left->Type == TT_AttributeParen)
+ CurrentToken->Type = TT_AttributeParen;
+
if (!HasMultipleLines)
Left->PackingKind = PPK_Inconclusive;
else if (HasMultipleParametersOnALine)
@@ -165,11 +189,16 @@
}
if (CurrentToken->isOneOf(tok::r_square, tok::r_brace))
return false;
+ else if (CurrentToken->is(tok::l_brace))
+ Left->Type = TT_Unknown; // Not TT_ObjCBlockLParen
updateParameterCount(Left, CurrentToken);
if (CurrentToken->is(tok::comma) && CurrentToken->Next &&
!CurrentToken->Next->HasUnescapedNewline &&
!CurrentToken->Next->isTrailingComment())
HasMultipleParametersOnALine = true;
+ if (CurrentToken->isOneOf(tok::kw_const, tok::kw_auto) ||
+ CurrentToken->isSimpleTypeSpecifier())
+ Contexts.back().IsExpression = false;
if (!consumeToken())
return false;
if (CurrentToken && CurrentToken->HasUnescapedNewline)
@@ -226,9 +255,12 @@
}
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
- if (Contexts.back().FirstObjCSelectorName != NULL)
+ if (Contexts.back().FirstObjCSelectorName != NULL) {
Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
Contexts.back().LongestObjCSelectorName;
+ if (Contexts.back().NumBlockParameters > 1)
+ Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = 0;
+ }
next();
return true;
}
@@ -237,6 +269,7 @@
if (CurrentToken->is(tok::colon))
ColonFound = true;
if (CurrentToken->is(tok::comma) &&
+ Style.Language != FormatStyle::LK_Proto &&
(Left->Type == TT_ArraySubscriptLSquare ||
(Left->Type == TT_ObjCMethodExpr && !ColonFound)))
Left->Type = TT_ArrayInitializerLSquare;
@@ -250,6 +283,11 @@
bool parseBrace() {
if (CurrentToken != NULL) {
FormatToken *Left = CurrentToken->Previous;
+
+ if (Contexts.back().CaretFound)
+ Left->Type = TT_ObjCBlockLBrace;
+ Contexts.back().CaretFound = false;
+
ScopedContextCreator ContextCreator(*this, tok::l_brace, 1);
Contexts.back().ColonIsDictLiteral = true;
@@ -263,7 +301,8 @@
if (CurrentToken->isOneOf(tok::r_paren, tok::r_square))
return false;
updateParameterCount(Left, CurrentToken);
- if (CurrentToken->is(tok::colon))
+ if (CurrentToken->is(tok::colon) &&
+ Style.Language != FormatStyle::LK_Proto)
Left->Type = TT_DictLiteral;
if (!consumeToken())
return false;
@@ -367,7 +406,7 @@
if (!parseParens())
return false;
if (Line.MustBeDeclaration && Contexts.size() == 1 &&
- !Contexts.back().IsExpression)
+ !Contexts.back().IsExpression && Line.First->Type != TT_ObjCProperty)
Line.MightBeFunctionDecl = true;
break;
case tok::l_square:
@@ -429,6 +468,8 @@
Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true;
if (Contexts.back().InCtorInitializer)
Tok->Type = TT_CtorInitializerComma;
+ if (Contexts.back().IsForEachMacro)
+ Contexts.back().IsExpression = true;
break;
default:
break;
@@ -467,6 +508,18 @@
}
}
+ void parsePragma() {
+ next(); // Consume "pragma".
+ if (CurrentToken && CurrentToken->TokenText == "mark") {
+ next(); // Consume "mark".
+ next(); // Consume first token (so we fix leading whitespace).
+ while (CurrentToken != NULL) {
+ CurrentToken->Type = TT_ImplicitStringLiteral;
+ next();
+ }
+ }
+ }
+
void parsePreprocessorDirective() {
next();
if (CurrentToken == NULL)
@@ -488,8 +541,12 @@
case tok::pp_warning:
parseWarningOrError();
break;
+ case tok::pp_pragma:
+ parsePragma();
+ break;
case tok::pp_if:
case tok::pp_elif:
+ Contexts.back().IsExpression = true;
parseLine();
break;
default:
@@ -505,6 +562,15 @@
parsePreprocessorDirective();
return LT_PreprocessorDirective;
}
+
+ // Directly allow to 'import <string-literal>' to support protocol buffer
+ // definitions (code.google.com/p/protobuf) or missing "#" (either way we
+ // should not break the line).
+ IdentifierInfo *Info = CurrentToken->Tok.getIdentifierInfo();
+ if (Info && Info->getPPKeywordID() == tok::pp_import &&
+ CurrentToken->Next && CurrentToken->Next->is(tok::string_literal))
+ parseIncludeDirective();
+
while (CurrentToken != NULL) {
if (CurrentToken->is(tok::kw_virtual))
KeywordVirtualFound = true;
@@ -525,26 +591,33 @@
}
private:
+ void resetTokenMetadata(FormatToken *Token) {
+ if (Token == nullptr) return;
+
+ // Reset token type in case we have already looked at it and then
+ // recovered from an error (e.g. failure to find the matching >).
+ if (CurrentToken->Type != TT_LambdaLSquare &&
+ CurrentToken->Type != TT_FunctionLBrace &&
+ CurrentToken->Type != TT_ImplicitStringLiteral &&
+ CurrentToken->Type != TT_TrailingReturnArrow)
+ CurrentToken->Type = TT_Unknown;
+ if (CurrentToken->Role)
+ CurrentToken->Role.reset(NULL);
+ CurrentToken->FakeLParens.clear();
+ CurrentToken->FakeRParens = 0;
+ }
+
void next() {
if (CurrentToken != NULL) {
determineTokenType(*CurrentToken);
CurrentToken->BindingStrength = Contexts.back().BindingStrength;
+ CurrentToken->NestingLevel = Contexts.size() - 1;
}
if (CurrentToken != NULL)
CurrentToken = CurrentToken->Next;
- if (CurrentToken != NULL) {
- // Reset token type in case we have already looked at it and then
- // recovered from an error (e.g. failure to find the matching >).
- if (CurrentToken->Type != TT_LambdaLSquare &&
- CurrentToken->Type != TT_ImplicitStringLiteral)
- CurrentToken->Type = TT_Unknown;
- if (CurrentToken->Role)
- CurrentToken->Role.reset(NULL);
- CurrentToken->FakeLParens.clear();
- CurrentToken->FakeRParens = 0;
- }
+ resetTokenMetadata(CurrentToken);
}
/// \brief A struct to hold information valid in a specific context, e.g.
@@ -553,15 +626,17 @@
Context(tok::TokenKind ContextKind, unsigned BindingStrength,
bool IsExpression)
: ContextKind(ContextKind), BindingStrength(BindingStrength),
- LongestObjCSelectorName(0), ColonIsForRangeExpr(false),
- ColonIsDictLiteral(false), ColonIsObjCMethodExpr(false),
- FirstObjCSelectorName(NULL), FirstStartOfName(NULL),
- IsExpression(IsExpression), CanBeExpression(true),
- InCtorInitializer(false) {}
+ LongestObjCSelectorName(0), NumBlockParameters(0),
+ ColonIsForRangeExpr(false), ColonIsDictLiteral(false),
+ ColonIsObjCMethodExpr(false), FirstObjCSelectorName(NULL),
+ FirstStartOfName(NULL), IsExpression(IsExpression),
+ CanBeExpression(true), InTemplateArgument(false),
+ InCtorInitializer(false), CaretFound(false), IsForEachMacro(false) {}
tok::TokenKind ContextKind;
unsigned BindingStrength;
unsigned LongestObjCSelectorName;
+ unsigned NumBlockParameters;
bool ColonIsForRangeExpr;
bool ColonIsDictLiteral;
bool ColonIsObjCMethodExpr;
@@ -569,7 +644,10 @@
FormatToken *FirstStartOfName;
bool IsExpression;
bool CanBeExpression;
+ bool InTemplateArgument;
bool InCtorInitializer;
+ bool CaretFound;
+ bool IsForEachMacro;
};
/// \brief Puts a new \c Context onto the stack \c Contexts for the lifetime
@@ -603,12 +681,17 @@
Previous->Type = TT_PointerOrReference;
}
}
- } else if (Current.isOneOf(tok::kw_return, tok::kw_throw) ||
- (Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
- !Line.InPPDirective &&
- (!Current.Previous ||
- !Current.Previous->isOneOf(tok::kw_for, tok::kw_catch)))) {
+ } else if (Current.isOneOf(tok::kw_return, tok::kw_throw)) {
Contexts.back().IsExpression = true;
+ } else if (Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
+ !Line.InPPDirective) {
+ bool ParametersOfFunctionType =
+ Current.Previous && Current.Previous->is(tok::r_paren) &&
+ Current.Previous->MatchingParen &&
+ Current.Previous->MatchingParen->Type == TT_FunctionTypeLParen;
+ bool IsForOrCatch = Current.Previous &&
+ Current.Previous->isOneOf(tok::kw_for, tok::kw_catch);
+ Contexts.back().IsExpression = !ParametersOfFunctionType && !IsForOrCatch;
} else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) {
for (FormatToken *Previous = Current.Previous;
Previous && Previous->isOneOf(tok::star, tok::amp);
@@ -640,9 +723,15 @@
} else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) {
Current.Type =
determineStarAmpUsage(Current, Contexts.back().CanBeExpression &&
- Contexts.back().IsExpression);
+ Contexts.back().IsExpression,
+ Contexts.back().InTemplateArgument);
} else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) {
Current.Type = determinePlusMinusCaretUsage(Current);
+ if (Current.Type == TT_UnaryOperator) {
+ ++Contexts.back().NumBlockParameters;
+ if (Current.is(tok::caret))
+ Contexts.back().CaretFound = true;
+ }
} else if (Current.isOneOf(tok::minusminus, tok::plusplus)) {
Current.Type = determineIncrementUsage(Current);
} else if (Current.is(tok::exclaim)) {
@@ -665,7 +754,7 @@
bool ParensAreType = !Current.Previous ||
Current.Previous->Type == TT_PointerOrReference ||
Current.Previous->Type == TT_TemplateCloser ||
- isSimpleTypeSpecifier(*Current.Previous);
+ Current.Previous->isSimpleTypeSpecifier();
bool ParensCouldEndDecl =
Current.Next &&
Current.Next->isOneOf(tok::equal, tok::semi, tok::l_brace);
@@ -673,7 +762,8 @@
LeftOfParens &&
LeftOfParens->isOneOf(tok::kw_sizeof, tok::kw_alignof);
if (ParensAreType && !ParensCouldEndDecl && !IsSizeOfOrAlignOf &&
- (Contexts.back().IsExpression ||
+ ((Contexts.size() > 1 &&
+ Contexts[Contexts.size() - 2].IsExpression) ||
(Current.Next && Current.Next->isBinaryOperator())))
IsCast = true;
if (Current.Next && Current.Next->isNot(tok::string_literal) &&
@@ -685,6 +775,7 @@
if (LeftOfParens && (LeftOfParens->Tok.getIdentifierInfo() == NULL ||
LeftOfParens->is(tok::kw_return)) &&
LeftOfParens->Type != TT_OverloadedOperator &&
+ LeftOfParens->isNot(tok::at) &&
LeftOfParens->Type != TT_TemplateCloser && Current.Next &&
Current.Next->is(tok::identifier))
IsCast = true;
@@ -708,6 +799,11 @@
if (PreviousNoComment &&
PreviousNoComment->isOneOf(tok::comma, tok::l_brace))
Current.Type = TT_DesignatedInitializerPeriod;
+ } else if (Current.isOneOf(tok::identifier, tok::kw_const) &&
+ Line.MightBeFunctionDecl && Contexts.size() == 1) {
+ // Line.MightBeFunctionDecl can only be true after the parentheses of a
+ // function declaration have been found.
+ Current.Type = TT_TrailingAnnotation;
}
}
}
@@ -740,11 +836,12 @@
return (!IsPPKeyword && PreviousNotConst->is(tok::identifier)) ||
PreviousNotConst->Type == TT_PointerOrReference ||
- isSimpleTypeSpecifier(*PreviousNotConst);
+ PreviousNotConst->isSimpleTypeSpecifier();
}
/// \brief Return the type of the given token assuming it is * or &.
- TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression) {
+ TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression,
+ bool InTemplateArgument) {
const FormatToken *PrevToken = Tok.getPreviousNonComment();
if (PrevToken == NULL)
return TT_UnaryOperator;
@@ -773,8 +870,15 @@
return TT_PointerOrReference;
if (PrevToken->Tok.isLiteral() ||
- PrevToken->isOneOf(tok::r_paren, tok::r_square) ||
- NextToken->Tok.isLiteral() || NextToken->isUnaryOperator())
+ PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::kw_true,
+ tok::kw_false) ||
+ NextToken->Tok.isLiteral() ||
+ NextToken->isOneOf(tok::kw_true, tok::kw_false) ||
+ NextToken->isUnaryOperator() ||
+ // If we know we're in a template argument, there are no named
+ // declarations. Thus, having an identifier on the right-hand side
+ // indicates a binary operator.
+ (InTemplateArgument && NextToken->Tok.isAnyIdentifier()))
return TT_BinaryOperator;
// It is very unlikely that we are going to find a pointer or reference type
@@ -815,36 +919,6 @@
return TT_UnaryOperator;
}
- // FIXME: This is copy&pasted from Sema. Put it in a common place and remove
- // duplication.
- /// \brief Determine whether the token kind starts a simple-type-specifier.
- bool isSimpleTypeSpecifier(const FormatToken &Tok) const {
- switch (Tok.Tok.getKind()) {
- case tok::kw_short:
- case tok::kw_long:
- case tok::kw___int64:
- case tok::kw___int128:
- case tok::kw_signed:
- case tok::kw_unsigned:
- case tok::kw_void:
- case tok::kw_char:
- case tok::kw_int:
- case tok::kw_half:
- case tok::kw_float:
- case tok::kw_double:
- case tok::kw_wchar_t:
- case tok::kw_bool:
- case tok::kw___underlying_type:
- case tok::annot_typename:
- case tok::kw_char16_t:
- case tok::kw_char32_t:
- case tok::kw_typeof:
- case tok::kw_decltype:
- return true;
- default:
- return false;
- }
- }
SmallVector<Context, 8> Contexts;
@@ -904,8 +978,11 @@
int CurrentPrecedence = getCurrentPrecedence();
if (Current && Current->Type == TT_ObjCSelectorName &&
- Precedence == CurrentPrecedence)
+ Precedence == CurrentPrecedence) {
+ if (LatestOperator)
+ addFakeParenthesis(Start, prec::Level(Precedence));
Start = Current;
+ }
// At the end of the line or when an operator with higher precedence is
// found, insert fake parenthesis and return.
@@ -950,6 +1027,8 @@
else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon ||
Current->Type == TT_ObjCSelectorName)
return 0;
+ else if (Current->Type == TT_RangeBasedForLoopColon)
+ return prec::Comma;
else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma))
return Current->getPrecedence();
else if (Current->isOneOf(tok::period, tok::arrow))
@@ -1060,11 +1139,37 @@
FormatToken *Current = Line.First->Next;
bool InFunctionDecl = Line.MightBeFunctionDecl;
while (Current != NULL) {
- if (Current->Type == TT_LineComment)
- Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments;
- else if (Current->SpacesRequiredBefore == 0 &&
- spaceRequiredBefore(Line, *Current))
+ if (Current->Type == TT_LineComment) {
+ if (Current->Previous->BlockKind == BK_BracedInit &&
+ Current->Previous->opensScope())
+ Current->SpacesRequiredBefore = Style.Cpp11BracedListStyle ? 0 : 1;
+ else
+ Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments;
+
+ // If we find a trailing comment, iterate backwards to determine whether
+ // it seems to relate to a specific parameter. If so, break before that
+ // parameter to avoid changing the comment's meaning. E.g. don't move 'b'
+ // to the previous line in:
+ // SomeFunction(a,
+ // b, // comment
+ // c);
+ if (!Current->HasUnescapedNewline) {
+ for (FormatToken *Parameter = Current->Previous; Parameter;
+ Parameter = Parameter->Previous) {
+ if (Parameter->isOneOf(tok::comment, tok::r_brace))
+ break;
+ if (Parameter->Previous && Parameter->Previous->is(tok::comma)) {
+ if (Parameter->Previous->Type != TT_CtorInitializerComma &&
+ Parameter->HasUnescapedNewline)
+ Parameter->MustBreakBefore = true;
+ break;
+ }
+ }
+ }
+ } else if (Current->SpacesRequiredBefore == 0 &&
+ spaceRequiredBefore(Line, *Current)) {
Current->SpacesRequiredBefore = 1;
+ }
Current->MustBreakBefore =
Current->MustBreakBefore || mustBreakBefore(Line, *Current);
@@ -1132,16 +1237,18 @@
return 0;
if (Left.is(tok::comma))
return 1;
- if (Right.is(tok::l_square))
- return 150;
-
+ if (Right.is(tok::l_square)) {
+ if (Style.Language == FormatStyle::LK_Proto)
+ return 1;
+ if (Right.Type != TT_ObjCMethodExpr)
+ return 250;
+ }
if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator)) {
if (Line.First->is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt)
return 3;
if (Left.Type == TT_StartOfName)
return 20;
- if (InFunctionDecl && Right.BindingStrength == 1)
- // FIXME: Clean up hack of using BindingStrength to find top-level names.
+ if (InFunctionDecl && Right.NestingLevel == 0)
return Style.PenaltyReturnTypeOnItsOwnLine;
return 200;
}
@@ -1149,7 +1256,8 @@
return 150;
if (Left.Type == TT_CastRParen)
return 100;
- if (Left.is(tok::coloncolon))
+ if (Left.is(tok::coloncolon) ||
+ (Right.is(tok::period) && Style.Language == FormatStyle::LK_Proto))
return 500;
if (Left.isOneOf(tok::kw_class, tok::kw_struct))
return 5000;
@@ -1159,17 +1267,25 @@
return 2;
if (Right.isMemberAccess()) {
- if (Left.isOneOf(tok::r_paren, tok::r_square) && Left.MatchingParen &&
+ if (Left.is(tok::r_paren) && Left.MatchingParen &&
Left.MatchingParen->ParameterCount > 0)
return 20; // Should be smaller than breaking at a nested comma.
return 150;
}
- // Breaking before a trailing 'const' or not-function-like annotation is bad.
- if (Left.is(tok::r_paren) && Line.Type != LT_ObjCProperty &&
- (Right.is(tok::kw_const) || (Right.is(tok::identifier) && Right.Next &&
- Right.Next->isNot(tok::l_paren))))
- return 100;
+ if (Right.Type == TT_TrailingAnnotation && Right.Next &&
+ Right.Next->isNot(tok::l_paren)) {
+ // Generally, breaking before a trailing annotation is bad unless it is
+ // function-like. It seems to be especially preferable to keep standard
+ // annotations (i.e. "const", "final" and "override") on the same line.
+ // Use a slightly higher penalty after ")" so that annotations like
+ // "const override" are kept together.
+ bool is_standard_annotation = Right.is(tok::kw_const) ||
+ Right.TokenText == "override" ||
+ Right.TokenText == "final";
+ return (Left.is(tok::r_paren) ? 100 : 120) +
+ (is_standard_annotation ? 50 : 0);
+ }
// In for-loops, prefer breaking at ',' and ';'.
if (Line.First->is(tok::kw_for) && Left.is(tok::equal))
@@ -1180,10 +1296,12 @@
if (Right.Type == TT_ObjCSelectorName)
return 0;
if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
- return 50;
+ return Line.MightBeFunctionDecl ? 50 : 500;
if (Left.is(tok::l_paren) && InFunctionDecl)
return 100;
+ if (Left.is(tok::equal) && InFunctionDecl)
+ return 110;
if (Left.opensScope())
return Left.ParameterCount > 1 ? Style.PenaltyBreakBeforeFirstCallParameter
: 19;
@@ -1215,6 +1333,14 @@
bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
const FormatToken &Left,
const FormatToken &Right) {
+ if (Style.Language == FormatStyle::LK_Proto) {
+ if (Right.is(tok::l_paren) &&
+ (Left.TokenText == "returns" || Left.TokenText == "option"))
+ return true;
+ }
+ if (Style.ObjCSpaceAfterProperty && Line.Type == LT_ObjCProperty &&
+ Left.Tok.getObjCKeywordID() == tok::objc_property)
+ return true;
if (Right.is(tok::hashhash))
return Left.is(tok::hash);
if (Left.isOneOf(tok::hashhash, tok::hash))
@@ -1246,7 +1372,7 @@
return false;
if (Left.is(tok::coloncolon))
return false;
- if (Right.is(tok::coloncolon))
+ if (Right.is(tok::coloncolon) && Left.isNot(tok::l_brace))
return (Left.is(tok::less) && Style.Standard == FormatStyle::LS_Cpp03) ||
!Left.isOneOf(tok::identifier, tok::greater, tok::l_paren,
tok::r_paren, tok::less);
@@ -1273,35 +1399,39 @@
return false;
if (Left.is(tok::l_square))
return Left.Type == TT_ArrayInitializerLSquare &&
- Right.isNot(tok::r_square);
+ Style.SpacesInContainerLiterals && Right.isNot(tok::r_square);
if (Right.is(tok::r_square))
- return Right.MatchingParen &&
+ return Right.MatchingParen && Style.SpacesInContainerLiterals &&
Right.MatchingParen->Type == TT_ArrayInitializerLSquare;
if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr &&
Right.Type != TT_LambdaLSquare && Left.isNot(tok::numeric_constant))
return false;
if (Left.is(tok::colon))
return Left.Type != TT_ObjCMethodExpr;
- if (Right.is(tok::colon))
- return Right.Type != TT_ObjCMethodExpr && !Left.is(tok::question);
if (Right.is(tok::l_paren)) {
- if (Left.is(tok::r_paren) && Left.MatchingParen &&
- Left.MatchingParen->Previous &&
- Left.MatchingParen->Previous->is(tok::kw___attribute))
+ if (Left.is(tok::r_paren) && Left.Type == TT_AttributeParen)
return true;
return Line.Type == LT_ObjCDecl ||
Left.isOneOf(tok::kw_return, tok::kw_new, tok::kw_delete,
tok::semi) ||
- (Style.SpaceAfterControlStatementKeyword &&
- Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch,
- tok::kw_catch));
+ (Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&
+ (Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while,
+ tok::kw_switch, tok::kw_catch) ||
+ Left.IsForEachMacro)) ||
+ (Style.SpaceBeforeParens == FormatStyle::SBPO_Always &&
+ Left.isOneOf(tok::identifier, tok::kw___attribute) &&
+ Line.Type != LT_PreprocessorDirective);
}
if (Left.is(tok::at) && Right.Tok.getObjCKeywordID() != tok::objc_not_keyword)
return false;
if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
return !Left.Children.empty(); // No spaces in "{}".
- if (Left.is(tok::l_brace) || Right.is(tok::r_brace))
+ if ((Left.is(tok::l_brace) && Left.BlockKind != BK_Block) ||
+ (Right.is(tok::r_brace) && Right.MatchingParen &&
+ Right.MatchingParen->BlockKind != BK_Block))
return !Style.Cpp11BracedListStyle;
+ if (Left.Type == TT_BlockComment && Left.TokenText.endswith("=*/"))
+ return false;
if (Right.Type == TT_UnaryOperator)
return !Left.isOneOf(tok::l_paren, tok::l_square, tok::at) &&
(Left.isNot(tok::colon) || Left.Type != TT_ObjCMethodExpr);
@@ -1311,8 +1441,6 @@
return false;
if (Left.is(tok::period) || Right.is(tok::period))
return false;
- if (Left.Type == TT_BlockComment && Left.TokenText.endswith("=*/"))
- return false;
if (Right.is(tok::hash) && Left.is(tok::identifier) && Left.TokenText == "L")
return false;
return true;
@@ -1351,10 +1479,11 @@
if (Tok.is(tok::colon))
return !Line.First->isOneOf(tok::kw_case, tok::kw_default) &&
Tok.getNextNonComment() != NULL && Tok.Type != TT_ObjCMethodExpr &&
- !Tok.Previous->is(tok::question);
+ !Tok.Previous->is(tok::question) &&
+ (Tok.Type != TT_DictLiteral || Style.SpacesInContainerLiterals);
if (Tok.Previous->Type == TT_UnaryOperator ||
Tok.Previous->Type == TT_CastRParen)
- return false;
+ return Tok.Type == TT_BinaryOperator;
if (Tok.Previous->is(tok::greater) && Tok.is(tok::greater)) {
return Tok.Type == TT_TemplateCloser &&
Tok.Previous->Type == TT_TemplateCloser &&
@@ -1381,11 +1510,13 @@
bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
const FormatToken &Right) {
+ const FormatToken &Left = *Right.Previous;
if (Right.is(tok::comment)) {
- return Right.NewlinesBefore > 0;
+ return Right.Previous->BlockKind != BK_BracedInit &&
+ Right.Previous->Type != TT_CtorInitializerColon &&
+ Right.NewlinesBefore > 0;
} else if (Right.Previous->isTrailingComment() ||
- (Right.is(tok::string_literal) &&
- Right.Previous->is(tok::string_literal))) {
+ (Right.isStringLiteral() && Right.Previous->isStringLiteral())) {
return true;
} else if (Right.Previous->IsUnterminatedLiteral) {
return true;
@@ -1395,19 +1526,34 @@
return true;
} else if (Right.Previous->ClosesTemplateDeclaration &&
Right.Previous->MatchingParen &&
- Right.Previous->MatchingParen->BindingStrength == 1 &&
+ Right.Previous->MatchingParen->NestingLevel == 0 &&
Style.AlwaysBreakTemplateDeclarations) {
- // FIXME: Fix horrible hack of using BindingStrength to find top-level <>.
return true;
- } else if (Right.Type == TT_CtorInitializerComma &&
+ } else if ((Right.Type == TT_CtorInitializerComma ||
+ Right.Type == TT_CtorInitializerColon) &&
Style.BreakConstructorInitializersBeforeComma &&
!Style.ConstructorInitializerAllOnOneLineOrOnePerLine) {
return true;
- } else if (Right.Previous->BlockKind == BK_Block &&
- Right.Previous->isNot(tok::r_brace) && Right.isNot(tok::r_brace)) {
- return true;
} else if (Right.is(tok::l_brace) && (Right.BlockKind == BK_Block)) {
- return Style.BreakBeforeBraces == FormatStyle::BS_Allman;
+ return Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU;
+ } else if (Right.is(tok::string_literal) &&
+ Right.TokenText.startswith("R\"")) {
+ // Raw string literals are special wrt. line breaks. The author has made a
+ // deliberate choice and might have aligned the contents of the string
+ // literal accordingly. Thus, we try keep existing line breaks.
+ return Right.NewlinesBefore > 0;
+ } else if (Right.Previous->is(tok::l_brace) && Right.NestingLevel == 1 &&
+ Style.Language == FormatStyle::LK_Proto) {
+ // Don't enums onto single lines in protocol buffers.
+ return true;
+ } else if ((Left.is(tok::l_brace) && Left.MatchingParen &&
+ Left.MatchingParen->Previous &&
+ Left.MatchingParen->Previous->is(tok::comma)) ||
+ (Right.is(tok::r_brace) && Left.is(tok::comma))) {
+ // If the last token before a '}' is a comma, the intention is to insert a
+ // line break after it in order to make shuffling around entries easier.
+ return true;
}
return false;
}
@@ -1415,12 +1561,17 @@
bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
const FormatToken &Right) {
const FormatToken &Left = *Right.Previous;
+ if (Left.is(tok::at))
+ return false;
if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator))
return true;
if (Right.isTrailingComment())
// We rely on MustBreakBefore being set correctly here as we should not
// change the "binding" behavior of a comment.
- return false;
+ // The first comment in a braced lists is always interpreted as belonging to
+ // the first list element. Otherwise, it should be placed outside of the
+ // list.
+ return Left.BlockKind == BK_BracedInit;
if (Left.is(tok::question) && Right.is(tok::colon))
return false;
if (Right.Type == TT_ConditionalExpr || Right.is(tok::question))
@@ -1430,6 +1581,8 @@
if (Right.is(tok::colon) &&
(Right.Type == TT_DictLiteral || Right.Type == TT_ObjCMethodExpr))
return false;
+ if (Right.Type == TT_InheritanceColon)
+ return true;
if (Left.is(tok::colon) &&
(Left.Type == TT_DictLiteral || Left.Type == TT_ObjCMethodExpr))
return true;
@@ -1452,14 +1605,12 @@
return false;
if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl)
return false;
- if (Left.Previous) {
- if (Left.is(tok::l_paren) && Right.is(tok::l_paren) &&
- Left.Previous->is(tok::kw___attribute))
- return false;
- if (Left.is(tok::l_paren) && (Left.Previous->Type == TT_BinaryOperator ||
- Left.Previous->Type == TT_CastRParen))
- return false;
- }
+ if (Left.is(tok::l_paren) && Left.Type == TT_AttributeParen)
+ return false;
+ if (Left.is(tok::l_paren) && Left.Previous &&
+ (Left.Previous->Type == TT_BinaryOperator ||
+ Left.Previous->Type == TT_CastRParen))
+ return false;
if (Right.Type == TT_ImplicitStringLiteral)
return false;
@@ -1489,7 +1640,7 @@
if (Right.Type == TT_CtorInitializerComma &&
Style.BreakConstructorInitializersBeforeComma)
return true;
- if (Right.isBinaryOperator() && Style.BreakBeforeBinaryOperators)
+ if (Right.Type == TT_BinaryOperator && Style.BreakBeforeBinaryOperators)
return true;
if (Left.is(tok::greater) && Right.is(tok::greater) &&
Left.Type != TT_TemplateCloser)
@@ -1503,7 +1654,7 @@
Right.isOneOf(tok::lessless, tok::arrow, tok::period, tok::colon,
tok::l_square, tok::at) ||
(Left.is(tok::r_paren) &&
- Right.isOneOf(tok::identifier, tok::kw_const, tok::kw___attribute)) ||
+ Right.isOneOf(tok::identifier, tok::kw_const)) ||
(Left.is(tok::l_paren) && !Right.is(tok::r_paren));
}
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
index aa49b2a..bd91980 100644
--- a/lib/Format/TokenAnnotator.h
+++ b/lib/Format/TokenAnnotator.h
@@ -41,7 +41,8 @@
: First(Line.Tokens.front().Tok), Level(Line.Level),
InPPDirective(Line.InPPDirective),
MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false),
- StartsDefinition(false) {
+ StartsDefinition(false), Affected(false),
+ LeadingEmptyLinesAffected(false), ChildrenAffected(false) {
assert(!Line.Tokens.empty());
// Calculate Next and Previous for all tokens. Note that we must overwrite
@@ -87,6 +88,17 @@
bool MightBeFunctionDecl;
bool StartsDefinition;
+ /// \c True if this line should be formatted, i.e. intersects directly or
+ /// indirectly with one of the input ranges.
+ bool Affected;
+
+ /// \c True if the leading empty lines of this line intersect with one of the
+ /// input ranges.
+ bool LeadingEmptyLinesAffected;
+
+ /// \c True if a one of this line's children intersects with an input range.
+ bool ChildrenAffected;
+
private:
// Disallow copying.
AnnotatedLine(const AnnotatedLine &) LLVM_DELETED_FUNCTION;
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index e0b090f..96d8155 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -74,7 +74,7 @@
StructuralError = PreviousStructuralError;
}
- virtual FormatToken *getNextToken() {
+ FormatToken *getNextToken() override {
// The \c UnwrappedLineParser guards against this by never calling
// \c getNextToken() after it has encountered the first eof token.
assert(!eof());
@@ -84,9 +84,9 @@
return Token;
}
- virtual unsigned getPosition() { return PreviousTokenSource->getPosition(); }
+ unsigned getPosition() override { return PreviousTokenSource->getPosition(); }
- virtual FormatToken *setPosition(unsigned Position) {
+ FormatToken *setPosition(unsigned Position) override {
Token = PreviousTokenSource->setPosition(Position);
return Token;
}
@@ -128,7 +128,7 @@
Parser.CurrentLines = &Parser.PreprocessorDirectives;
else if (!Parser.Line->Tokens.empty())
Parser.CurrentLines = &Parser.Line->Tokens.back().Children;
- PreBlockLine = Parser.Line.take();
+ PreBlockLine = Parser.Line.release();
Parser.Line.reset(new UnwrappedLine());
Parser.Line->Level = PreBlockLine->Level;
Parser.Line->InPPDirective = PreBlockLine->InPPDirective;
@@ -152,6 +152,27 @@
SmallVectorImpl<UnwrappedLine> *OriginalLines;
};
+class CompoundStatementIndenter {
+public:
+ CompoundStatementIndenter(UnwrappedLineParser *Parser,
+ const FormatStyle &Style, unsigned &LineLevel)
+ : LineLevel(LineLevel), OldLineLevel(LineLevel) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman) {
+ Parser->addUnwrappedLine();
+ } else if (Style.BreakBeforeBraces == FormatStyle::BS_GNU) {
+ Parser->addUnwrappedLine();
+ ++LineLevel;
+ }
+ }
+ ~CompoundStatementIndenter() {
+ LineLevel = OldLineLevel;
+ }
+
+private:
+ unsigned &LineLevel;
+ unsigned OldLineLevel;
+};
+
namespace {
class IndexedTokenSource : public FormatTokenSource {
@@ -159,17 +180,17 @@
IndexedTokenSource(ArrayRef<FormatToken *> Tokens)
: Tokens(Tokens), Position(-1) {}
- virtual FormatToken *getNextToken() {
+ FormatToken *getNextToken() override {
++Position;
return Tokens[Position];
}
- virtual unsigned getPosition() {
+ unsigned getPosition() override {
assert(Position >= 0);
return Position;
}
- virtual FormatToken *setPosition(unsigned P) {
+ FormatToken *setPosition(unsigned P) override {
Position = P;
return Tokens[Position];
}
@@ -322,7 +343,7 @@
// (for example while parsing lambdas).
//
// We exclude + and - as they can be ObjC visibility modifiers.
- if (NextTok->isOneOf(tok::comma, tok::semi, tok::r_paren,
+ if (NextTok->isOneOf(tok::comma, tok::semi, tok::r_paren, tok::period,
tok::r_square, tok::l_brace, tok::colon) ||
(NextTok->isBinaryOperator() &&
!NextTok->isOneOf(tok::plus, tok::minus))) {
@@ -336,6 +357,7 @@
LBraceStack.pop_back();
}
break;
+ case tok::at:
case tok::semi:
case tok::kw_if:
case tok::kw_while:
@@ -488,7 +510,9 @@
PPLevelBranchCount[PPBranchLevel] = PPChainBranchIndex.top() + 1;
}
}
- --PPBranchLevel;
+ // Guard against #endif's without #if.
+ if (PPBranchLevel > 0)
+ --PPBranchLevel;
if (!PPChainBranchIndex.empty())
PPChainBranchIndex.pop();
if (!PPStack.empty())
@@ -620,9 +644,6 @@
case tok::kw_case:
parseCaseLabel();
return;
- case tok::kw_return:
- parseReturn();
- return;
case tok::kw_extern:
nextToken();
if (FormatTok->Tok.is(tok::string_literal)) {
@@ -633,6 +654,12 @@
return;
}
}
+ break;
+ case tok::identifier:
+ if (FormatTok->IsForEachMacro) {
+ parseForOrWhileLoop();
+ return;
+ }
// In all other cases, parse the declaration.
break;
default:
@@ -648,6 +675,12 @@
case tok::kw_enum:
parseEnum();
break;
+ case tok::kw_typedef:
+ nextToken();
+ // FIXME: Use the IdentifierTable instead.
+ if (FormatTok->TokenText == "NS_ENUM")
+ parseEnum();
+ break;
case tok::kw_struct:
case tok::kw_union:
case tok::kw_class:
@@ -667,9 +700,13 @@
break;
case tok::caret:
nextToken();
- if (FormatTok->is(tok::l_brace)) {
+ if (FormatTok->Tok.isAnyIdentifier() ||
+ FormatTok->isSimpleTypeSpecifier())
+ nextToken();
+ if (FormatTok->is(tok::l_paren))
+ parseParens();
+ if (FormatTok->is(tok::l_brace))
parseChildBlock();
- }
break;
case tok::l_brace:
if (!tryToParseBracedList()) {
@@ -677,10 +714,9 @@
// structural element.
// FIXME: Figure out cases where this is not true, and add projections
// for them (the one we know is missing are lambdas).
- if (Style.BreakBeforeBraces == FormatStyle::BS_Linux ||
- Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup ||
- Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ if (Style.BreakBeforeBraces != FormatStyle::BS_Attach)
addUnwrappedLine();
+ FormatTok->Type = TT_FunctionLBrace;
parseBlock(/*MustBeDeclaration=*/false);
addUnwrappedLine();
return;
@@ -699,8 +735,8 @@
// Recognize function-like macro usages without trailing semicolon.
if (FormatTok->Tok.is(tok::l_paren)) {
parseParens();
- if (FormatTok->HasUnescapedNewline &&
- tokenCanStartNewLine(FormatTok->Tok)) {
+ if (FormatTok->NewlinesBefore > 0 &&
+ tokenCanStartNewLine(FormatTok->Tok) && Text == Text.upper()) {
addUnwrappedLine();
return;
}
@@ -720,7 +756,7 @@
}
break;
case tok::l_square:
- tryToParseLambda();
+ parseSquare();
break;
default:
nextToken();
@@ -729,36 +765,50 @@
} while (!eof());
}
-void UnwrappedLineParser::tryToParseLambda() {
+bool UnwrappedLineParser::tryToParseLambda() {
// FIXME: This is a dirty way to access the previous token. Find a better
// solution.
if (!Line->Tokens.empty() &&
- Line->Tokens.back().Tok->isOneOf(tok::identifier, tok::kw_operator)) {
+ (Line->Tokens.back().Tok->isOneOf(tok::identifier, tok::kw_operator) ||
+ Line->Tokens.back().Tok->closesScope() ||
+ Line->Tokens.back().Tok->isSimpleTypeSpecifier())) {
nextToken();
- return;
+ return false;
}
assert(FormatTok->is(tok::l_square));
FormatToken &LSquare = *FormatTok;
if (!tryToParseLambdaIntroducer())
- return;
+ return false;
while (FormatTok->isNot(tok::l_brace)) {
+ if (FormatTok->isSimpleTypeSpecifier()) {
+ nextToken();
+ continue;
+ }
switch (FormatTok->Tok.getKind()) {
case tok::l_brace:
break;
case tok::l_paren:
parseParens();
break;
+ case tok::less:
+ case tok::greater:
case tok::identifier:
+ case tok::coloncolon:
case tok::kw_mutable:
nextToken();
break;
+ case tok::arrow:
+ FormatTok->Type = TT_TrailingReturnArrow;
+ nextToken();
+ break;
default:
- return;
+ return true;
}
}
LSquare.Type = TT_LambdaLSquare;
parseChildBlock();
+ return true;
}
bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
@@ -861,40 +911,6 @@
return false;
}
-void UnwrappedLineParser::parseReturn() {
- nextToken();
-
- do {
- switch (FormatTok->Tok.getKind()) {
- case tok::l_brace:
- parseBracedList();
- if (FormatTok->Tok.isNot(tok::semi)) {
- // Assume missing ';'.
- addUnwrappedLine();
- return;
- }
- break;
- case tok::l_paren:
- parseParens();
- break;
- case tok::r_brace:
- // Assume missing ';'.
- addUnwrappedLine();
- return;
- case tok::semi:
- nextToken();
- addUnwrappedLine();
- return;
- case tok::l_square:
- tryToParseLambda();
- break;
- default:
- nextToken();
- break;
- }
- } while (!eof());
-}
-
void UnwrappedLineParser::parseParens() {
assert(FormatTok->Tok.is(tok::l_paren) && "'(' expected.");
nextToken();
@@ -930,6 +946,42 @@
} while (!eof());
}
+void UnwrappedLineParser::parseSquare() {
+ assert(FormatTok->Tok.is(tok::l_square) && "'[' expected.");
+ if (tryToParseLambda())
+ return;
+ do {
+ switch (FormatTok->Tok.getKind()) {
+ case tok::l_paren:
+ parseParens();
+ break;
+ case tok::r_square:
+ nextToken();
+ return;
+ case tok::r_brace:
+ // A "}" inside parenthesis is an error if there wasn't a matching "{".
+ return;
+ case tok::l_square:
+ parseSquare();
+ break;
+ case tok::l_brace: {
+ if (!tryToParseBracedList()) {
+ parseChildBlock();
+ }
+ break;
+ }
+ case tok::at:
+ nextToken();
+ if (FormatTok->Tok.is(tok::l_brace))
+ parseBracedList();
+ break;
+ default:
+ nextToken();
+ break;
+ }
+ } while (!eof());
+}
+
void UnwrappedLineParser::parseIfThenElse() {
assert(FormatTok->Tok.is(tok::kw_if) && "'if' expected");
nextToken();
@@ -937,13 +989,14 @@
parseParens();
bool NeedsUnwrappedLine = false;
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
- addUnwrappedLine();
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU) {
addUnwrappedLine();
- else
+ } else {
NeedsUnwrappedLine = true;
+ }
} else {
addUnwrappedLine();
++Line->Level;
@@ -953,8 +1006,7 @@
if (FormatTok->Tok.is(tok::kw_else)) {
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
- addUnwrappedLine();
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
addUnwrappedLine();
} else if (FormatTok->Tok.is(tok::kw_if)) {
@@ -977,7 +1029,8 @@
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
if (Style.BreakBeforeBraces == FormatStyle::BS_Linux ||
- Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU)
addUnwrappedLine();
bool AddLevel = Style.NamespaceIndentation == FormatStyle::NI_All ||
@@ -994,14 +1047,14 @@
}
void UnwrappedLineParser::parseForOrWhileLoop() {
- assert((FormatTok->Tok.is(tok::kw_for) || FormatTok->Tok.is(tok::kw_while)) &&
- "'for' or 'while' expected");
+ assert((FormatTok->Tok.is(tok::kw_for) || FormatTok->Tok.is(tok::kw_while) ||
+ FormatTok->IsForEachMacro) &&
+ "'for', 'while' or foreach macro expected");
nextToken();
if (FormatTok->Tok.is(tok::l_paren))
parseParens();
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
- addUnwrappedLine();
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
addUnwrappedLine();
} else {
@@ -1016,9 +1069,10 @@
assert(FormatTok->Tok.is(tok::kw_do) && "'do' expected");
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
- addUnwrappedLine();
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
+ if (Style.BreakBeforeBraces == FormatStyle::BS_GNU)
+ addUnwrappedLine();
} else {
addUnwrappedLine();
++Line->Level;
@@ -1042,17 +1096,20 @@
if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0))
--Line->Level;
if (CommentsBeforeNextToken.empty() && FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
- addUnwrappedLine();
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
if (FormatTok->Tok.is(tok::kw_break)) {
- // "break;" after "}" on its own line only for BS_Allman
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ // "break;" after "}" on its own line only for BS_Allman and BS_GNU
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU) {
addUnwrappedLine();
+ }
parseStructuralElement();
}
+ addUnwrappedLine();
+ } else {
+ addUnwrappedLine();
}
- addUnwrappedLine();
Line->Level = OldLineLevel;
}
@@ -1071,8 +1128,7 @@
if (FormatTok->Tok.is(tok::l_paren))
parseParens();
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Allman)
- addUnwrappedLine();
+ CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
addUnwrappedLine();
} else {
@@ -1085,6 +1141,10 @@
void UnwrappedLineParser::parseAccessSpecifier() {
nextToken();
+ // Understand Qt's slots.
+ if (FormatTok->is(tok::identifier) &&
+ (FormatTok->TokenText == "slots" || FormatTok->TokenText == "Q_SLOTS"))
+ nextToken();
// Otherwise, we don't know what it is, and we'd better keep the next token.
if (FormatTok->Tok.is(tok::colon))
nextToken();
@@ -1092,7 +1152,10 @@
}
void UnwrappedLineParser::parseEnum() {
- nextToken();
+ if (FormatTok->Tok.is(tok::kw_enum)) {
+ // Won't be 'enum' for NS_ENUMs.
+ nextToken();
+ }
// Eat up enum class ...
if (FormatTok->Tok.is(tok::kw_class) ||
FormatTok->Tok.is(tok::kw_struct))
@@ -1159,10 +1222,11 @@
}
if (FormatTok->Tok.is(tok::l_brace)) {
if (Style.BreakBeforeBraces == FormatStyle::BS_Linux ||
- Style.BreakBeforeBraces == FormatStyle::BS_Allman)
+ Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
+ Style.BreakBeforeBraces == FormatStyle::BS_GNU)
addUnwrappedLine();
- parseBlock(/*MustBeDeclaration=*/true, /*Addlevel=*/true,
+ parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/true,
/*MunchSemi=*/false);
}
// We fall through to parsing a structural element afterwards, so
@@ -1189,6 +1253,10 @@
parseBlock(/*MustBeDeclaration=*/false);
// In ObjC interfaces, nothing should be following the "}".
addUnwrappedLine();
+ } else if (FormatTok->is(tok::r_brace)) {
+ // Ignore stray "}". parseStructuralElement doesn't consume them.
+ nextToken();
+ addUnwrappedLine();
} else {
parseStructuralElement();
}
@@ -1312,6 +1380,7 @@
bool CommentsInCurrentLine = true;
do {
FormatTok = Tokens->getNextToken();
+ assert(FormatTok);
while (!Line->InPPDirective && FormatTok->Tok.is(tok::hash) &&
(FormatTok->HasUnescapedNewline || FormatTok->IsFirst)) {
// If there is an unfinished unwrapped line, we flush the preprocessor
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index f1f4e57..62e0b58 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -16,9 +16,9 @@
#ifndef LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
#define LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
+#include "FormatToken.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Format/Format.h"
-#include "FormatToken.h"
#include <list>
namespace clang {
@@ -82,8 +82,8 @@
void parseStructuralElement();
bool tryToParseBracedList();
bool parseBracedList(bool ContinueOnSemicolons = false);
- void parseReturn();
void parseParens();
+ void parseSquare();
void parseIfThenElse();
void parseForOrWhileLoop();
void parseDoWhile();
@@ -98,7 +98,7 @@
void parseObjCUntilAtEnd();
void parseObjCInterfaceOrImplementation();
void parseObjCProtocol();
- void tryToParseLambda();
+ bool tryToParseLambda();
bool tryToParseLambdaIntroducer();
void addUnwrappedLine();
bool eof() const;
@@ -112,7 +112,7 @@
// FIXME: We are constantly running into bugs where Line.Level is incorrectly
// subtracted from beyond 0. Introduce a method to subtract from Line.Level
// and use that everywhere in the Parser.
- OwningPtr<UnwrappedLine> Line;
+ std::unique_ptr<UnwrappedLine> Line;
// Comments are sorted into unwrapped lines by whether they are in the same
// line as the previous token, or not. If not, they belong to the next token.
@@ -185,6 +185,7 @@
std::stack<int> PPChainBranchIndex;
friend class ScopedLineState;
+ friend class CompoundStatementIndenter;
};
struct UnwrappedLineNode {
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index 26a8d41..4c393ed 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -193,6 +193,10 @@
if (Changes[i].IsTrailingComment) {
assert(Column >= Changes[i].StartOfTokenColumn);
Changes[i].Spaces += Column - Changes[i].StartOfTokenColumn;
+ if (i + 1 != End) {
+ Changes[i + 1].PreviousEndOfTokenColumn +=
+ Column - Changes[i].StartOfTokenColumn;
+ }
Changes[i].StartOfTokenColumn = Column;
}
}
diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h
index ae62023..f94464f 100644
--- a/lib/Format/WhitespaceManager.h
+++ b/lib/Format/WhitespaceManager.h
@@ -51,7 +51,7 @@
unsigned StartOfTokenColumn,
bool InPPDirective = false);
- /// \brief Adds information about an unchangable token's whitespace.
+ /// \brief Adds information about an unchangeable token's whitespace.
///
/// Needs to be called for every token for which \c replaceWhitespace
/// was not called.