diff options
Diffstat (limited to 'lib/Format')
-rw-r--r-- | lib/Format/BreakableToken.cpp | 11 | ||||
-rw-r--r-- | lib/Format/ContinuationIndenter.cpp | 23 | ||||
-rw-r--r-- | lib/Format/Encoding.h | 3 | ||||
-rw-r--r-- | lib/Format/Format.cpp | 246 | ||||
-rw-r--r-- | lib/Format/FormatToken.h | 13 | ||||
-rw-r--r-- | lib/Format/FormatTokenLexer.cpp | 20 | ||||
-rw-r--r-- | lib/Format/FormatTokenLexer.h | 1 | ||||
-rw-r--r-- | lib/Format/NamespaceEndCommentsFixer.cpp | 16 | ||||
-rw-r--r-- | lib/Format/TokenAnnotator.cpp | 132 | ||||
-rw-r--r-- | lib/Format/TokenAnnotator.h | 3 | ||||
-rw-r--r-- | lib/Format/UnwrappedLineFormatter.cpp | 63 | ||||
-rw-r--r-- | lib/Format/UnwrappedLineParser.cpp | 41 | ||||
-rw-r--r-- | lib/Format/UnwrappedLineParser.h | 2 | ||||
-rw-r--r-- | lib/Format/WhitespaceManager.cpp | 41 |
14 files changed, 468 insertions, 147 deletions
diff --git a/lib/Format/BreakableToken.cpp b/lib/Format/BreakableToken.cpp index 72886ed00736..09ea5473c0c1 100644 --- a/lib/Format/BreakableToken.cpp +++ b/lib/Format/BreakableToken.cpp @@ -342,8 +342,8 @@ BreakableBlockComment::BreakableBlockComment( StringRef TokenText(Tok.TokenText); assert(TokenText.startswith("/*") && TokenText.endswith("*/")); - TokenText.substr(2, TokenText.size() - 4).split(Lines, - UseCRLF ? "\r\n" : "\n"); + TokenText.substr(2, TokenText.size() - 4) + .split(Lines, UseCRLF ? "\r\n" : "\n"); int IndentDelta = StartColumn - OriginalStartColumn; Content.resize(Lines.size()); @@ -456,10 +456,9 @@ BreakableBlockComment::BreakableBlockComment( }); } -BreakableToken::Split -BreakableBlockComment::getSplit(unsigned LineIndex, unsigned TailOffset, - unsigned ColumnLimit, unsigned ContentStartColumn, - llvm::Regex &CommentPragmasRegex) const { +BreakableToken::Split BreakableBlockComment::getSplit( + unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, + unsigned ContentStartColumn, llvm::Regex &CommentPragmasRegex) const { // Don't break lines matching the comment pragmas regex. if (CommentPragmasRegex.match(Content[LineIndex])) return Split(StringRef::npos, 0); diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index b04ede6fa939..2ff6e5ec2344 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -473,7 +473,10 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { } // If the return type spans multiple lines, wrap before the function name. - if ((Current.is(TT_FunctionDeclarationName) || + if (((Current.is(TT_FunctionDeclarationName) && + // Don't break before a C# function when no break after return type + (!Style.isCSharp() || + Style.AlwaysBreakAfterReturnType != FormatStyle::RTBS_None)) || (Current.is(tok::kw_operator) && !Previous.is(tok::coloncolon))) && !Previous.is(tok::kw_template) && State.Stack.back().BreakBeforeParameter) return true; @@ -606,7 +609,9 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, // disallowing any further line breaks if there is no line break after the // opening parenthesis. Don't break if it doesn't conserve columns. if (Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak && - Previous.isOneOf(tok::l_paren, TT_TemplateOpener, tok::l_square) && + (Previous.isOneOf(tok::l_paren, TT_TemplateOpener, tok::l_square) || + (Previous.is(tok::l_brace) && Previous.BlockKind != BK_Block && + Style.Cpp11BracedListStyle)) && State.Column > getNewLineColumn(State) && (!Previous.Previous || !Previous.Previous->isOneOf( tok::kw_for, tok::kw_while, tok::kw_switch)) && @@ -676,8 +681,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, State.Column += Spaces; if (Current.isNot(tok::comment) && Previous.is(tok::l_paren) && Previous.Previous && - (Previous.Previous->isOneOf(tok::kw_if, tok::kw_for) || - Previous.Previous->endsSequence(tok::kw_constexpr, tok::kw_if))) { + (Previous.Previous->is(tok::kw_for) || Previous.Previous->isIf())) { // 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; @@ -930,6 +934,11 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { return std::max(State.Stack.back().LastSpace, State.Stack.back().Indent + Style.ContinuationIndentWidth); + if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths && + State.Line->First->is(tok::kw_enum)) + return (Style.IndentWidth * State.Line->First->IndentLevel) + + Style.IndentWidth; + if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block) return Current.NestingLevel == 0 ? State.FirstIndent : State.Stack.back().Indent; @@ -1796,7 +1805,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current, unsigned UnbreakableTailLength = (State.NextToken && canBreak(State)) ? 0 : Current.UnbreakableTailLength; - return llvm::make_unique<BreakableStringLiteral>( + return std::make_unique<BreakableStringLiteral>( Current, StartColumn, Prefix, Postfix, UnbreakableTailLength, State.Line->InPPDirective, Encoding, Style); } @@ -1808,7 +1817,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current, switchesFormatting(Current)) { return nullptr; } - return llvm::make_unique<BreakableBlockComment>( + return std::make_unique<BreakableBlockComment>( Current, StartColumn, Current.OriginalColumn, !Current.Previous, State.Line->InPPDirective, Encoding, Style, Whitespaces.useCRLF()); } else if (Current.is(TT_LineComment) && @@ -1818,7 +1827,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current, CommentPragmasRegex.match(Current.TokenText.substr(2)) || switchesFormatting(Current)) return nullptr; - return llvm::make_unique<BreakableLineCommentSection>( + return std::make_unique<BreakableLineCommentSection>( Current, StartColumn, Current.OriginalColumn, !Current.Previous, /*InPPDirective=*/false, Encoding, Style); } diff --git a/lib/Format/Encoding.h b/lib/Format/Encoding.h index fe3d5f019858..a0d664121b2b 100644 --- a/lib/Format/Encoding.h +++ b/lib/Format/Encoding.h @@ -67,7 +67,8 @@ inline unsigned columnWidthWithTabs(StringRef Text, unsigned StartColumn, if (TabPos == StringRef::npos) return TotalWidth + columnWidth(Tail, Encoding); TotalWidth += columnWidth(Tail.substr(0, TabPos), Encoding); - TotalWidth += TabWidth - (TotalWidth + StartColumn) % TabWidth; + if (TabWidth) + TotalWidth += TabWidth - (TotalWidth + StartColumn) % TabWidth; Tail = Tail.substr(TabPos + 1); } } diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index c48182976b04..cd44c0be85f0 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -67,10 +67,19 @@ template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> { 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, "c++03", FormatStyle::LS_Cpp03); + IO.enumCase(Value, "C++03", FormatStyle::LS_Cpp03); // Legacy alias + IO.enumCase(Value, "Cpp03", FormatStyle::LS_Cpp03); // Legacy alias + + IO.enumCase(Value, "c++11", FormatStyle::LS_Cpp11); + IO.enumCase(Value, "C++11", FormatStyle::LS_Cpp11); // Legacy alias + + IO.enumCase(Value, "c++14", FormatStyle::LS_Cpp14); + IO.enumCase(Value, "c++17", FormatStyle::LS_Cpp17); + IO.enumCase(Value, "c++20", FormatStyle::LS_Cpp20); + + IO.enumCase(Value, "Latest", FormatStyle::LS_Latest); + IO.enumCase(Value, "Cpp11", FormatStyle::LS_Latest); // Legacy alias IO.enumCase(Value, "Auto", FormatStyle::LS_Auto); } }; @@ -95,6 +104,16 @@ template <> struct ScalarEnumerationTraits<FormatStyle::JavaScriptQuoteStyle> { } }; +template <> struct ScalarEnumerationTraits<FormatStyle::ShortBlockStyle> { + static void enumeration(IO &IO, FormatStyle::ShortBlockStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::SBS_Never); + IO.enumCase(Value, "false", FormatStyle::SBS_Never); + IO.enumCase(Value, "Always", FormatStyle::SBS_Always); + IO.enumCase(Value, "true", FormatStyle::SBS_Always); + IO.enumCase(Value, "Empty", FormatStyle::SBS_Empty); + } +}; + template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> { static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) { IO.enumCase(Value, "None", FormatStyle::SFS_None); @@ -155,6 +174,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> { IO.enumCase(Value, "Mozilla", FormatStyle::BS_Mozilla); IO.enumCase(Value, "Stroustrup", FormatStyle::BS_Stroustrup); IO.enumCase(Value, "Allman", FormatStyle::BS_Allman); + IO.enumCase(Value, "Whitesmiths", FormatStyle::BS_Whitesmiths); IO.enumCase(Value, "GNU", FormatStyle::BS_GNU); IO.enumCase(Value, "WebKit", FormatStyle::BS_WebKit); IO.enumCase(Value, "Custom", FormatStyle::BS_Custom); @@ -162,6 +182,20 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> { }; template <> +struct ScalarEnumerationTraits< + FormatStyle::BraceWrappingAfterControlStatementStyle> { + static void + enumeration(IO &IO, + FormatStyle::BraceWrappingAfterControlStatementStyle &Value) { + IO.enumCase(Value, "false", FormatStyle::BWACS_Never); + IO.enumCase(Value, "true", FormatStyle::BWACS_Always); + IO.enumCase(Value, "Never", FormatStyle::BWACS_Never); + IO.enumCase(Value, "MultiLine", FormatStyle::BWACS_MultiLine); + IO.enumCase(Value, "Always", FormatStyle::BWACS_Always); + } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> { static void enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) { @@ -443,6 +477,7 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("IncludeCategories", Style.IncludeStyle.IncludeCategories); IO.mapOptional("IncludeIsMainRegex", Style.IncludeStyle.IncludeIsMainRegex); IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); + IO.mapOptional("IndentGotoLabels", Style.IndentGotoLabels); IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives); IO.mapOptional("IndentWidth", Style.IndentWidth); IO.mapOptional("IndentWrappedFunctionNames", @@ -494,6 +529,7 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens); IO.mapOptional("SpaceBeforeRangeBasedForLoopColon", Style.SpaceBeforeRangeBasedForLoopColon); + IO.mapOptional("SpaceInEmptyBlock", Style.SpaceInEmptyBlock); IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses); IO.mapOptional("SpacesBeforeTrailingComments", Style.SpacesBeforeTrailingComments); @@ -607,9 +643,12 @@ static FormatStyle expandPresets(const FormatStyle &Style) { if (Style.BreakBeforeBraces == FormatStyle::BS_Custom) return Style; FormatStyle Expanded = Style; - Expanded.BraceWrapping = {false, false, false, false, false, false, - false, false, false, false, false, - false, false, true, true, true}; + Expanded.BraceWrapping = {false, false, FormatStyle::BWACS_Never, + false, false, false, + false, false, false, + false, false, false, + false, true, true, + true}; switch (Style.BreakBeforeBraces) { case FormatStyle::BS_Linux: Expanded.BraceWrapping.AfterClass = true; @@ -634,7 +673,21 @@ static FormatStyle expandPresets(const FormatStyle &Style) { case FormatStyle::BS_Allman: Expanded.BraceWrapping.AfterCaseLabel = true; Expanded.BraceWrapping.AfterClass = true; - Expanded.BraceWrapping.AfterControlStatement = true; + Expanded.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always; + Expanded.BraceWrapping.AfterEnum = true; + Expanded.BraceWrapping.AfterFunction = true; + Expanded.BraceWrapping.AfterNamespace = true; + Expanded.BraceWrapping.AfterObjCDeclaration = true; + Expanded.BraceWrapping.AfterStruct = true; + Expanded.BraceWrapping.AfterUnion = true; + Expanded.BraceWrapping.AfterExternBlock = true; + Expanded.BraceWrapping.BeforeCatch = true; + Expanded.BraceWrapping.BeforeElse = true; + break; + case FormatStyle::BS_Whitesmiths: + Expanded.BraceWrapping.AfterCaseLabel = true; + Expanded.BraceWrapping.AfterClass = true; + Expanded.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always; Expanded.BraceWrapping.AfterEnum = true; Expanded.BraceWrapping.AfterFunction = true; Expanded.BraceWrapping.AfterNamespace = true; @@ -645,8 +698,12 @@ static FormatStyle expandPresets(const FormatStyle &Style) { Expanded.BraceWrapping.BeforeElse = true; break; case FormatStyle::BS_GNU: - Expanded.BraceWrapping = {true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true}; + Expanded.BraceWrapping = {true, true, FormatStyle::BWACS_Always, + true, true, true, + true, true, true, + true, true, true, + true, true, true, + true}; break; case FormatStyle::BS_WebKit: Expanded.BraceWrapping.AfterFunction = true; @@ -672,7 +729,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.AllowAllConstructorInitializersOnNextLine = true; LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true; LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All; - LLVMStyle.AllowShortBlocksOnASingleLine = false; + LLVMStyle.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never; LLVMStyle.AllowShortCaseLabelsOnASingleLine = false; LLVMStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; LLVMStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_All; @@ -686,9 +743,12 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None; LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; - LLVMStyle.BraceWrapping = {false, false, false, false, false, false, - false, false, false, false, false, - false, false, true, true, true}; + LLVMStyle.BraceWrapping = {false, false, FormatStyle::BWACS_Never, + false, false, false, + false, false, false, + false, false, false, + false, true, true, + true}; LLVMStyle.BreakAfterJavaFieldAnnotations = false; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon; @@ -707,12 +767,13 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.ForEachMacros.push_back("Q_FOREACH"); LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH"); LLVMStyle.IncludeStyle.IncludeCategories = { - {"^\"(llvm|llvm-c|clang|clang-c)/", 2}, - {"^(<|\"(gtest|gmock|isl|json)/)", 3}, - {".*", 1}}; + {"^\"(llvm|llvm-c|clang|clang-c)/", 2, 0}, + {"^(<|\"(gtest|gmock|isl|json)/)", 3, 0}, + {".*", 1, 0}}; LLVMStyle.IncludeStyle.IncludeIsMainRegex = "(Test)?$"; LLVMStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Preserve; LLVMStyle.IndentCaseLabels = false; + LLVMStyle.IndentGotoLabels = true; LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None; LLVMStyle.IndentWrappedFunctionNames = false; LLVMStyle.IndentWidth = 2; @@ -728,11 +789,12 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.ObjCSpaceBeforeProtocolList = true; LLVMStyle.PointerAlignment = FormatStyle::PAS_Right; LLVMStyle.SpacesBeforeTrailingComments = 1; - LLVMStyle.Standard = FormatStyle::LS_Cpp11; + LLVMStyle.Standard = FormatStyle::LS_Latest; LLVMStyle.UseTab = FormatStyle::UT_Never; LLVMStyle.ReflowComments = true; LLVMStyle.SpacesInParentheses = false; LLVMStyle.SpacesInSquareBrackets = false; + LLVMStyle.SpaceInEmptyBlock = false; LLVMStyle.SpaceInEmptyParentheses = false; LLVMStyle.SpacesInContainerLiterals = true; LLVMStyle.SpacesInCStyleCastParentheses = false; @@ -789,8 +851,10 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { GoogleStyle.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes; GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true; GoogleStyle.DerivePointerAlignment = true; - GoogleStyle.IncludeStyle.IncludeCategories = { - {"^<ext/.*\\.h>", 2}, {"^<.*\\.h>", 1}, {"^<.*", 2}, {".*", 3}}; + GoogleStyle.IncludeStyle.IncludeCategories = {{"^<ext/.*\\.h>", 2, 0}, + {"^<.*\\.h>", 1, 0}, + {"^<.*", 2, 0}, + {".*", 3, 0}}; GoogleStyle.IncludeStyle.IncludeIsMainRegex = "([-_](test|unittest))?$"; GoogleStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup; GoogleStyle.IndentCaseLabels = true; @@ -897,6 +961,27 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) { FormatStyle ChromiumStyle = getGoogleStyle(Language); + + // Disable include reordering across blocks in Chromium code. + // - clang-format tries to detect that foo.h is the "main" header for + // foo.cc and foo_unittest.cc via IncludeIsMainRegex. However, Chromium + // uses many other suffices (_win.cc, _mac.mm, _posix.cc, _browsertest.cc, + // _private.cc, _impl.cc etc) in different permutations + // (_win_browsertest.cc) so disable this until IncludeIsMainRegex has a + // better default for Chromium code. + // - The default for .cc and .mm files is different (r357695) for Google style + // for the same reason. The plan is to unify this again once the main + // header detection works for Google's ObjC code, but this hasn't happened + // yet. Since Chromium has some ObjC code, switching Chromium is blocked + // on that. + // - Finally, "If include reordering is harmful, put things in different + // blocks to prevent it" has been a recommendation for a long time that + // people are used to. We'll need a dev education push to change this to + // "If include reordering is harmful, put things in a different block and + // _prepend that with a comment_ to prevent it" before changing behavior. + ChromiumStyle.IncludeStyle.IncludeBlocks = + tooling::IncludeStyle::IBS_Preserve; + if (Language == FormatStyle::LK_Java) { ChromiumStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_WithoutElse; @@ -966,6 +1051,7 @@ FormatStyle getWebKitStyle() { Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign; Style.AlignOperands = false; Style.AlignTrailingComments = false; + Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty; Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; Style.BreakBeforeBraces = FormatStyle::BS_WebKit; Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma; @@ -978,6 +1064,7 @@ FormatStyle getWebKitStyle() { Style.ObjCSpaceAfterProperty = true; Style.PointerAlignment = FormatStyle::PAS_Left; Style.SpaceBeforeCpp11BracedList = true; + Style.SpaceInEmptyBlock = true; return Style; } @@ -997,14 +1084,14 @@ FormatStyle getGNUStyle() { } FormatStyle getMicrosoftStyle(FormatStyle::LanguageKind Language) { - FormatStyle Style = getLLVMStyle(); + FormatStyle Style = getLLVMStyle(Language); Style.ColumnLimit = 120; Style.TabWidth = 4; Style.IndentWidth = 4; Style.UseTab = FormatStyle::UT_Never; Style.BreakBeforeBraces = FormatStyle::BS_Custom; Style.BraceWrapping.AfterClass = true; - Style.BraceWrapping.AfterControlStatement = true; + Style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always; Style.BraceWrapping.AfterEnum = true; Style.BraceWrapping.AfterFunction = true; Style.BraceWrapping.AfterNamespace = true; @@ -1015,10 +1102,11 @@ FormatStyle getMicrosoftStyle(FormatStyle::LanguageKind Language) { Style.BraceWrapping.BeforeElse = true; Style.PenaltyReturnTypeOnItsOwnLine = 1000; Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None; - Style.AllowShortBlocksOnASingleLine = false; Style.AllowShortCaseLabelsOnASingleLine = false; Style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; Style.AllowShortLoopsOnASingleLine = false; + Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None; + Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; return Style; } @@ -1346,7 +1434,7 @@ private: : FormatStyle::PAS_Right; if (Style.Standard == FormatStyle::LS_Auto) Style.Standard = hasCpp03IncompatibleFormat(AnnotatedLines) - ? FormatStyle::LS_Cpp11 + ? FormatStyle::LS_Latest : FormatStyle::LS_Cpp03; BinPackInconclusiveFunctions = HasBinPackedFunction || !HasOnePerLineFunction; @@ -1380,22 +1468,29 @@ public: checkEmptyNamespace(AnnotatedLines); - for (auto &Line : AnnotatedLines) { - if (Line->Affected) { - cleanupRight(Line->First, tok::comma, tok::comma); - cleanupRight(Line->First, TT_CtorInitializerColon, tok::comma); - cleanupRight(Line->First, tok::l_paren, tok::comma); - cleanupLeft(Line->First, tok::comma, tok::r_paren); - cleanupLeft(Line->First, TT_CtorInitializerComma, tok::l_brace); - cleanupLeft(Line->First, TT_CtorInitializerColon, tok::l_brace); - cleanupLeft(Line->First, TT_CtorInitializerColon, tok::equal); - } - } + for (auto *Line : AnnotatedLines) + cleanupLine(Line); return {generateFixes(), 0}; } private: + void cleanupLine(AnnotatedLine *Line) { + for (auto *Child : Line->Children) { + cleanupLine(Child); + } + + if (Line->Affected) { + cleanupRight(Line->First, tok::comma, tok::comma); + cleanupRight(Line->First, TT_CtorInitializerColon, tok::comma); + cleanupRight(Line->First, tok::l_paren, tok::comma); + cleanupLeft(Line->First, tok::comma, tok::r_paren); + cleanupLeft(Line->First, TT_CtorInitializerComma, tok::l_brace); + cleanupLeft(Line->First, TT_CtorInitializerColon, tok::l_brace); + cleanupLeft(Line->First, TT_CtorInitializerColon, tok::equal); + } + } + bool containsOnlyComments(const AnnotatedLine &Line) { for (FormatToken *Tok = Line.First; Tok != nullptr; Tok = Tok->Next) { if (Tok->isNot(tok::comment)) @@ -1685,10 +1780,11 @@ private: std::end(FoundationIdentifiers), FormatTok->TokenText)) || FormatTok->is(TT_ObjCStringLiteral) || - FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS, - TT_ObjCBlockLBrace, TT_ObjCBlockLParen, - TT_ObjCDecl, TT_ObjCForIn, TT_ObjCMethodExpr, - TT_ObjCMethodSpecifier, TT_ObjCProperty)) { + FormatTok->isOneOf(Keywords.kw_NS_CLOSED_ENUM, Keywords.kw_NS_ENUM, + Keywords.kw_NS_OPTIONS, TT_ObjCBlockLBrace, + TT_ObjCBlockLParen, TT_ObjCDecl, TT_ObjCForIn, + TT_ObjCMethodExpr, TT_ObjCMethodSpecifier, + TT_ObjCProperty)) { LLVM_DEBUG(llvm::dbgs() << "Detected ObjC at location " << FormatTok->Tok.getLocation().printToString( @@ -1712,6 +1808,7 @@ struct IncludeDirective { StringRef Text; unsigned Offset; int Category; + int Priority; }; struct JavaImportDirective { @@ -1763,6 +1860,28 @@ FindCursorIndex(const SmallVectorImpl<IncludeDirective> &Includes, return std::make_pair(CursorIndex, OffsetToEOL); } +// Replace all "\r\n" with "\n". +std::string replaceCRLF(const std::string &Code) { + std::string NewCode; + size_t Pos = 0, LastPos = 0; + + do { + Pos = Code.find("\r\n", LastPos); + if (Pos == LastPos) { + LastPos++; + continue; + } + if (Pos == std::string::npos) { + NewCode += Code.substr(LastPos); + break; + } + NewCode += Code.substr(LastPos, Pos - LastPos) + "\n"; + LastPos = Pos + 2; + } while (Pos != std::string::npos); + + return NewCode; +} + // Sorts and deduplicate a block of includes given by 'Includes' alphabetically // adding the necessary replacement to 'Replaces'. 'Includes' must be in strict // source order. @@ -1773,8 +1892,9 @@ FindCursorIndex(const SmallVectorImpl<IncludeDirective> &Includes, static void sortCppIncludes(const FormatStyle &Style, const SmallVectorImpl<IncludeDirective> &Includes, ArrayRef<tooling::Range> Ranges, StringRef FileName, - StringRef Code, - tooling::Replacements &Replaces, unsigned *Cursor) { + StringRef Code, tooling::Replacements &Replaces, + unsigned *Cursor) { + tooling::IncludeCategoryManager Categories(Style.IncludeStyle, FileName); unsigned IncludesBeginOffset = Includes.front().Offset; unsigned IncludesEndOffset = Includes.back().Offset + Includes.back().Text.size(); @@ -1782,11 +1902,12 @@ static void sortCppIncludes(const FormatStyle &Style, if (!affectsRange(Ranges, IncludesBeginOffset, IncludesEndOffset)) return; SmallVector<unsigned, 16> Indices; - for (unsigned i = 0, e = Includes.size(); i != e; ++i) + for (unsigned i = 0, e = Includes.size(); i != e; ++i) { Indices.push_back(i); + } llvm::stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - return std::tie(Includes[LHSI].Category, Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Category, Includes[RHSI].Filename); + return std::tie(Includes[LHSI].Priority, Includes[LHSI].Filename) < + std::tie(Includes[RHSI].Priority, Includes[RHSI].Filename); }); // The index of the include on which the cursor will be put after // sorting/deduplicating. @@ -1834,7 +1955,8 @@ static void sortCppIncludes(const FormatStyle &Style, // If the #includes are out of order, we generate a single replacement fixing // the entire range of blocks. Otherwise, no replacement is generated. - if (result == Code.substr(IncludesBeginOffset, IncludesBlockSize)) + if (replaceCRLF(result) == + replaceCRLF(Code.substr(IncludesBeginOffset, IncludesBlockSize))) return; auto Err = Replaces.add(tooling::Replacement( @@ -1901,9 +2023,12 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code, int Category = Categories.getIncludePriority( IncludeName, /*CheckMainHeader=*/!MainIncludeFound && FirstIncludeBlock); + int Priority = Categories.getSortIncludePriority( + IncludeName, !MainIncludeFound && FirstIncludeBlock); if (Category == 0) MainIncludeFound = true; - IncludesInBlock.push_back({IncludeName, Line, Prev, Category}); + IncludesInBlock.push_back( + {IncludeName, Line, Prev, Category, Priority}); } else if (!IncludesInBlock.empty() && !EmptyLineSkipped) { sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Code, Replaces, Cursor); @@ -1999,7 +2124,8 @@ static void sortJavaImports(const FormatStyle &Style, // If the imports are out of order, we generate a single replacement fixing // the entire block. Otherwise, no replacement is generated. - if (result == Code.substr(Imports.front().Offset, ImportsBlockSize)) + if (replaceCRLF(result) == + replaceCRLF(Code.substr(Imports.front().Offset, ImportsBlockSize))) return; auto Err = Replaces.add(tooling::Replacement(FileName, Imports.front().Offset, @@ -2288,8 +2414,8 @@ reformat(const FormatStyle &Style, StringRef Code, }); auto Env = - llvm::make_unique<Environment>(Code, FileName, Ranges, FirstStartColumn, - NextStartColumn, LastStartColumn); + std::make_unique<Environment>(Code, FileName, Ranges, FirstStartColumn, + NextStartColumn, LastStartColumn); llvm::Optional<std::string> CurrentCode = None; tooling::Replacements Fixes; unsigned Penalty = 0; @@ -2302,7 +2428,7 @@ reformat(const FormatStyle &Style, StringRef Code, Penalty += PassFixes.second; if (I + 1 < E) { CurrentCode = std::move(*NewCode); - Env = llvm::make_unique<Environment>( + Env = std::make_unique<Environment>( *CurrentCode, FileName, tooling::calculateRangesAfterReplacements(Fixes, Ranges), FirstStartColumn, NextStartColumn, LastStartColumn); @@ -2364,11 +2490,18 @@ tooling::Replacements sortUsingDeclarations(const FormatStyle &Style, LangOptions getFormattingLangOpts(const FormatStyle &Style) { LangOptions LangOpts; + + FormatStyle::LanguageStandard LexingStd = Style.Standard; + if (LexingStd == FormatStyle::LS_Auto) + LexingStd = FormatStyle::LS_Latest; + if (LexingStd == FormatStyle::LS_Latest) + LexingStd = FormatStyle::LS_Cpp20; LangOpts.CPlusPlus = 1; - LangOpts.CPlusPlus11 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1; - LangOpts.CPlusPlus14 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1; - LangOpts.CPlusPlus17 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1; - LangOpts.CPlusPlus2a = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1; + LangOpts.CPlusPlus11 = LexingStd >= FormatStyle::LS_Cpp11; + LangOpts.CPlusPlus14 = LexingStd >= FormatStyle::LS_Cpp14; + LangOpts.CPlusPlus17 = LexingStd >= FormatStyle::LS_Cpp17; + LangOpts.CPlusPlus2a = LexingStd >= FormatStyle::LS_Cpp20; + LangOpts.LineComment = 1; bool AlternativeOperators = Style.isCpp(); LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0; @@ -2393,8 +2526,9 @@ const char *StyleOptionHelpDescription = static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) { if (FileName.endswith(".java")) return FormatStyle::LK_Java; - if (FileName.endswith_lower(".js") || FileName.endswith_lower(".ts")) - return FormatStyle::LK_JavaScript; // JavaScript or TypeScript. + if (FileName.endswith_lower(".js") || FileName.endswith_lower(".mjs") || + FileName.endswith_lower(".ts")) + return FormatStyle::LK_JavaScript; // (module) JavaScript or TypeScript. if (FileName.endswith(".m") || FileName.endswith(".mm")) return FormatStyle::LK_ObjC; if (FileName.endswith_lower(".proto") || diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h index df7493742025..b11f36559a8b 100644 --- a/lib/Format/FormatToken.h +++ b/lib/Format/FormatToken.h @@ -327,6 +327,11 @@ struct FormatToken { } template <typename T> bool isNot(T Kind) const { return !is(Kind); } + bool isIf(bool AllowConstexprMacro = true) const { + return is(tok::kw_if) || endsSequence(tok::kw_constexpr, tok::kw_if) || + (endsSequence(tok::identifier, tok::kw_if) && AllowConstexprMacro); + } + bool closesScopeAfterBlock() const { if (BlockKind == BK_Block) return true; @@ -344,6 +349,10 @@ struct FormatToken { /// \c true if this token ends a sequence with the given tokens in order, /// following the ``Previous`` pointers, ignoring comments. + /// For example, given tokens [T1, T2, T3], the function returns true if + /// 3 tokens ending at this (ignoring comments) are [T3, T2, T1]. In other + /// words, the tokens passed to this function need to the reverse of the + /// order the tokens appear in code. template <typename A, typename... Ts> bool endsSequence(A K1, Ts... Tokens) const { return endsSequenceInternal(K1, Tokens...); @@ -677,8 +686,10 @@ struct AdditionalKeywords { kw_override = &IdentTable.get("override"); kw_in = &IdentTable.get("in"); kw_of = &IdentTable.get("of"); + kw_CF_CLOSED_ENUM = &IdentTable.get("CF_CLOSED_ENUM"); kw_CF_ENUM = &IdentTable.get("CF_ENUM"); kw_CF_OPTIONS = &IdentTable.get("CF_OPTIONS"); + kw_NS_CLOSED_ENUM = &IdentTable.get("NS_CLOSED_ENUM"); kw_NS_ENUM = &IdentTable.get("NS_ENUM"); kw_NS_OPTIONS = &IdentTable.get("NS_OPTIONS"); @@ -787,8 +798,10 @@ struct AdditionalKeywords { IdentifierInfo *kw_override; IdentifierInfo *kw_in; IdentifierInfo *kw_of; + IdentifierInfo *kw_CF_CLOSED_ENUM; IdentifierInfo *kw_CF_ENUM; IdentifierInfo *kw_CF_OPTIONS; + IdentifierInfo *kw_NS_CLOSED_ENUM; IdentifierInfo *kw_NS_ENUM; IdentifierInfo *kw_NS_OPTIONS; IdentifierInfo *kw___except; diff --git a/lib/Format/FormatTokenLexer.cpp b/lib/Format/FormatTokenLexer.cpp index 009b8849753c..5d8a77577c0b 100644 --- a/lib/Format/FormatTokenLexer.cpp +++ b/lib/Format/FormatTokenLexer.cpp @@ -80,6 +80,8 @@ void FormatTokenLexer::tryMergePreviousTokens() { return; if (tryMergeCSharpNullConditionals()) return; + if (tryTransformCSharpForEach()) + return; static const tok::TokenKind JSRightArrow[] = {tok::equal, tok::greater}; if (tryMergeTokens(JSRightArrow, TT_JsFatArrow)) return; @@ -254,6 +256,21 @@ bool FormatTokenLexer::tryMergeCSharpNullConditionals() { return true; } +// In C# transform identifier foreach into kw_foreach +bool FormatTokenLexer::tryTransformCSharpForEach() { + if (Tokens.size() < 1) + return false; + auto &Identifier = *(Tokens.end() - 1); + if (!Identifier->is(tok::identifier)) + return false; + if (Identifier->TokenText != "foreach") + return false; + + Identifier->Type = TT_ForEachMacro; + Identifier->Tok.setKind(tok::kw_for); + return true; +} + bool FormatTokenLexer::tryMergeLessLess() { // Merge X,less,less,Y into X,lessless,Y unless X or Y is less. if (Tokens.size() < 3) @@ -657,7 +674,8 @@ FormatToken *FormatTokenLexer::getNextToken() { ++Column; break; case '\t': - Column += Style.TabWidth - Column % Style.TabWidth; + Column += + Style.TabWidth - (Style.TabWidth ? Column % Style.TabWidth : 0); break; case '\\': if (i + 1 == e || (Text[i + 1] != '\r' && Text[i + 1] != '\n')) diff --git a/lib/Format/FormatTokenLexer.h b/lib/Format/FormatTokenLexer.h index 1e096fc50205..611211be055a 100644 --- a/lib/Format/FormatTokenLexer.h +++ b/lib/Format/FormatTokenLexer.h @@ -53,6 +53,7 @@ private: bool tryMergeCSharpKeywordVariables(); bool tryMergeCSharpNullConditionals(); bool tryMergeCSharpDoubleQuestion(); + bool tryTransformCSharpForEach(); bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds, TokenType NewType); diff --git a/lib/Format/NamespaceEndCommentsFixer.cpp b/lib/Format/NamespaceEndCommentsFixer.cpp index d04fc8f115fb..98901cff2681 100644 --- a/lib/Format/NamespaceEndCommentsFixer.cpp +++ b/lib/Format/NamespaceEndCommentsFixer.cpp @@ -36,7 +36,7 @@ std::string computeName(const FormatToken *NamespaceTok) { const FormatToken *Tok = NamespaceTok->getNextNonComment(); if (NamespaceTok->is(TT_NamespaceMacro)) { // Collects all the non-comment tokens between opening parenthesis - // and closing parenthesis or comma + // and closing parenthesis or comma. assert(Tok && Tok->is(tok::l_paren) && "expected an opening parenthesis"); Tok = Tok->getNextNonComment(); while (Tok && !Tok->isOneOf(tok::r_paren, tok::comma)) { @@ -44,9 +44,21 @@ std::string computeName(const FormatToken *NamespaceTok) { Tok = Tok->getNextNonComment(); } } else { - // Collects all the non-comment tokens between 'namespace' and '{'. + // For `namespace [[foo]] A::B::inline C {` or + // `namespace MACRO1 MACRO2 A::B::inline C {`, returns "A::B::inline C". + // Peek for the first '::' (or '{') and then return all tokens from one + // token before that up until the '{'. + const FormatToken *FirstNSTok = Tok; + while (Tok && !Tok->is(tok::l_brace) && !Tok->is(tok::coloncolon)) { + FirstNSTok = Tok; + Tok = Tok->getNextNonComment(); + } + + Tok = FirstNSTok; while (Tok && !Tok->is(tok::l_brace)) { name += Tok->TokenText; + if (Tok->is(tok::kw_inline)) + name += " "; Tok = Tok->getNextNonComment(); } } diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 490c4f46135e..1ed35597d075 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -15,6 +15,7 @@ #include "TokenAnnotator.h" #include "FormatToken.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/TokenKinds.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/Debug.h" @@ -40,6 +41,21 @@ static bool canBeObjCSelectorComponent(const FormatToken &Tok) { return Tok.Tok.getIdentifierInfo() != nullptr; } +/// With `Left` being '(', check if we're at either `[...](` or +/// `[...]<...>(`, where the [ opens a lambda capture list. +static bool isLambdaParameterList(const FormatToken *Left) { + // Skip <...> if present. + if (Left->Previous && Left->Previous->is(tok::greater) && + Left->Previous->MatchingParen && + Left->Previous->MatchingParen->is(TT_TemplateOpener)) + Left = Left->Previous->MatchingParen; + + // Check for `[...]`. + return Left->Previous && Left->Previous->is(tok::r_square) && + Left->Previous->MatchingParen && + Left->Previous->MatchingParen->is(TT_LambdaLSquare); +} + /// A parser that gathers additional information about tokens. /// /// The \c TokenAnnotator tries to match parenthesis and square brakets and @@ -175,9 +191,9 @@ private: Contexts.back().IsExpression = false; } else if (Left->Previous && (Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_decltype, - tok::kw_if, tok::kw_while, tok::l_paren, + tok::kw_while, tok::l_paren, tok::comma) || - Left->Previous->endsSequence(tok::kw_constexpr, tok::kw_if) || + Left->Previous->isIf() || Left->Previous->is(TT_BinaryOperator))) { // static_assert, if and while usually contain expressions. Contexts.back().IsExpression = true; @@ -191,9 +207,7 @@ private: Left->Previous->is(TT_JsTypeColon)) { // let x: (SomeType); Contexts.back().IsExpression = false; - } else if (Left->Previous && Left->Previous->is(tok::r_square) && - Left->Previous->MatchingParen && - Left->Previous->MatchingParen->is(TT_LambdaLSquare)) { + } else if (isLambdaParameterList(Left)) { // This is a parameter list of a lambda expression. Contexts.back().IsExpression = false; } else if (Line.InPPDirective && @@ -382,6 +396,12 @@ private: Keywords.kw_internal)) { return true; } + + // incase its a [XXX] retval func(.... + if (AttrTok->Next && + AttrTok->Next->startsSequence(tok::identifier, tok::l_paren)) + return true; + return false; } @@ -476,6 +496,8 @@ private: } else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace && Parent && Parent->isOneOf(tok::l_brace, tok::comma)) { Left->Type = TT_DesignatedInitializerLSquare; + } else if (IsCSharp11AttributeSpecifier) { + Left->Type = TT_AttributeSquare; } else if (CurrentToken->is(tok::r_square) && Parent && Parent->is(TT_TemplateCloser)) { Left->Type = TT_ArraySubscriptLSquare; @@ -523,8 +545,6 @@ private: // Should only be relevant to JavaScript: tok::kw_default)) { Left->Type = TT_ArrayInitializerLSquare; - } else if (IsCSharp11AttributeSpecifier) { - Left->Type = TT_AttributeSquare; } else { BindingIncrease = 10; Left->Type = TT_ArraySubscriptLSquare; @@ -826,7 +846,7 @@ private: case tok::kw_if: case tok::kw_while: if (Tok->is(tok::kw_if) && CurrentToken && - CurrentToken->is(tok::kw_constexpr)) + CurrentToken->isOneOf(tok::kw_constexpr, tok::identifier)) next(); if (CurrentToken && CurrentToken->is(tok::l_paren)) { next(); @@ -918,6 +938,8 @@ private: case tok::greater: if (Style.Language != FormatStyle::LK_TextProto) Tok->Type = TT_BinaryOperator; + if (Tok->Previous && Tok->Previous->is(TT_TemplateCloser)) + Tok->SpacesRequiredBefore = 1; break; case tok::kw_operator: if (Style.Language == FormatStyle::LK_TextProto || @@ -1078,6 +1100,7 @@ private: case tok::pp_if: case tok::pp_elif: Contexts.back().IsExpression = true; + next(); parseLine(); break; default: @@ -1097,6 +1120,8 @@ private: public: LineType parseLine() { + if (!CurrentToken) + return LT_Invalid; NonTemplateLess.clear(); if (CurrentToken->is(tok::hash)) return parsePreprocessorDirective(); @@ -1368,7 +1393,9 @@ private: Style.Language == FormatStyle::LK_Java) { Current.Type = TT_LambdaArrow; } else if (Current.is(tok::arrow) && AutoFound && Line.MustBeDeclaration && - Current.NestingLevel == 0) { + Current.NestingLevel == 0 && + !Current.Previous->is(tok::kw_operator)) { + // not auto operator->() -> xxx; Current.Type = TT_TrailingReturnArrow; } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) { Current.Type = determineStarAmpUsage(Current, @@ -1467,7 +1494,8 @@ private: // colon after this, this is the only place which annotates the identifier // as a selector.) Current.Type = TT_SelectorName; - } else if (Current.isOneOf(tok::identifier, tok::kw_const) && + } else if (Current.isOneOf(tok::identifier, tok::kw_const, + tok::kw_noexcept) && Current.Previous && !Current.Previous->isOneOf(tok::equal, tok::at) && Line.MightBeFunctionDecl && Contexts.size() == 1) { @@ -1576,6 +1604,14 @@ private: if (Tok.Next->is(tok::question)) return false; + // Functions which end with decorations like volatile, noexcept are unlikely + // to be casts. + if (Tok.Next->isOneOf(tok::kw_noexcept, tok::kw_volatile, tok::kw_const, + tok::kw_throw, tok::arrow, Keywords.kw_override, + Keywords.kw_final) || + isCpp11AttributeSpecifier(*Tok.Next)) + return false; + // As Java has no function types, a "(" after the ")" likely means that this // is a cast. if (Style.Language == FormatStyle::LK_Java && Tok.Next->is(tok::l_paren)) @@ -1647,7 +1683,8 @@ private: const FormatToken *NextToken = Tok.getNextNonComment(); if (!NextToken || - NextToken->isOneOf(tok::arrow, tok::equal, tok::kw_const) || + NextToken->isOneOf(tok::arrow, tok::equal, tok::kw_const, + tok::kw_noexcept) || (NextToken->is(tok::l_brace) && !NextToken->getNextNonComment())) return TT_PointerOrReference; @@ -1720,7 +1757,7 @@ private: // Use heuristics to recognize unary operators. if (PrevToken->isOneOf(tok::equal, tok::l_paren, tok::comma, tok::l_square, tok::question, tok::colon, tok::kw_return, - tok::kw_case, tok::at, tok::l_brace)) + tok::kw_case, tok::at, tok::l_brace, tok::kw_throw)) return TT_UnaryOperator; // There can't be two consecutive binary operators. @@ -2160,7 +2197,8 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { if (Current->is(TT_LineComment)) { if (Current->Previous->BlockKind == BK_BracedInit && Current->Previous->opensScope()) - Current->SpacesRequiredBefore = Style.Cpp11BracedListStyle ? 0 : 1; + Current->SpacesRequiredBefore = + (Style.Cpp11BracedListStyle && !Style.SpacesInParentheses) ? 0 : 1; else Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments; @@ -2409,8 +2447,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign) return 100; if (Left.is(tok::l_paren) && Left.Previous && - (Left.Previous->isOneOf(tok::kw_if, tok::kw_for) || - Left.Previous->endsSequence(tok::kw_constexpr, tok::kw_if))) + (Left.Previous->is(tok::kw_for) || Left.Previous->isIf())) return 1000; if (Left.is(tok::equal) && InFunctionDecl) return 110; @@ -2429,6 +2466,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if (Left.is(TT_JavaAnnotation)) return 50; + if (Left.is(TT_UnaryOperator)) + return 60; if (Left.isOneOf(tok::plus, tok::comma) && Left.Previous && Left.Previous->isLabelString() && (Left.NextOperator || Left.OperatorIndex != 0)) @@ -2483,7 +2522,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return Left.is(tok::hash); if (Left.isOneOf(tok::hashhash, tok::hash)) return Right.is(tok::hash); - if (Left.is(tok::l_paren) && Right.is(tok::r_paren)) + if ((Left.is(tok::l_paren) && Right.is(tok::r_paren)) || + (Left.is(tok::l_brace) && Left.BlockKind != BK_Block && + Right.is(tok::r_brace) && Right.BlockKind != BK_Block)) return Style.SpaceInEmptyParentheses; if (Left.is(tok::l_paren) || Right.is(tok::r_paren)) return (Right.is(TT_CastRParen) || @@ -2560,7 +2601,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, (Style.PointerAlignment != FormatStyle::PAS_Right && !Line.IsMultiVariableDeclStmt) && Left.Previous && - !Left.Previous->isOneOf(tok::l_paren, tok::coloncolon)); + !Left.Previous->isOneOf(tok::l_paren, tok::coloncolon, + tok::l_square)); if (Right.is(tok::star) && Left.is(tok::l_paren)) return false; const auto SpaceRequiredForArrayInitializerLSquare = @@ -2575,8 +2617,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Left.is(tok::l_square)) return (Left.is(TT_ArrayInitializerLSquare) && Right.isNot(tok::r_square) && SpaceRequiredForArrayInitializerLSquare(Left, Style)) || - (Left.isOneOf(TT_ArraySubscriptLSquare, - TT_StructuredBindingLSquare) && + (Left.isOneOf(TT_ArraySubscriptLSquare, TT_StructuredBindingLSquare, + TT_LambdaLSquare) && Style.SpacesInSquareBrackets && Right.isNot(tok::r_square)); if (Right.is(tok::r_square)) return Right.MatchingParen && @@ -2585,7 +2627,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, Style)) || (Style.SpacesInSquareBrackets && Right.MatchingParen->isOneOf(TT_ArraySubscriptLSquare, - TT_StructuredBindingLSquare)) || + TT_StructuredBindingLSquare, + TT_LambdaLSquare)) || Right.MatchingParen->is(TT_AttributeParen)); if (Right.is(tok::l_square) && !Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare, @@ -2598,7 +2641,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, 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; + return Style.Cpp11BracedListStyle ? Style.SpacesInParentheses : true; if (Left.is(TT_BlockComment)) // No whitespace in x(/*foo=*/1), except for JavaScript. return Style.Language == FormatStyle::LK_JavaScript || @@ -2609,10 +2652,10 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return true; return Line.Type == LT_ObjCDecl || Left.is(tok::semi) || (Style.SpaceBeforeParens != FormatStyle::SBPO_Never && - (Left.isOneOf(tok::kw_if, tok::pp_elif, tok::kw_for, tok::kw_while, + (Left.isOneOf(tok::pp_elif, tok::kw_for, tok::kw_while, tok::kw_switch, tok::kw_case, TT_ForEachMacro, TT_ObjCForIn) || - Left.endsSequence(tok::kw_constexpr, tok::kw_if) || + Left.isIf(Line.Type != LT_PreprocessorDirective) || (Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch, tok::kw_new, tok::kw_delete) && (!Left.Previous || Left.Previous->isNot(tok::period))))) || @@ -2655,6 +2698,14 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, Right.MatchingParen->endsSequence(TT_DictLiteral, tok::at)) // Objective-C dictionary literal -> no space before closing brace. return false; + if (Right.Type == TT_TrailingAnnotation && + Right.isOneOf(tok::amp, tok::ampamp) && + Left.isOneOf(tok::kw_const, tok::kw_volatile) && + (!Right.Next || Right.Next->is(tok::semi))) + // Match const and volatile ref-qualifiers without any additional + // qualifiers such as + // void Fn() const &; + return Style.PointerAlignment != FormatStyle::PAS_Left; return true; } @@ -2694,7 +2745,15 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, // and "%d %d" if (Left.is(tok::numeric_constant) && Right.is(tok::percent)) return Right.WhitespaceRange.getEnd() != Right.WhitespaceRange.getBegin(); - } else if (Style.Language == FormatStyle::LK_JavaScript || Style.isCSharp()) { + } else if (Style.isCSharp()) { + // space between type and variable e.g. Dictionary<string,string> foo; + if (Left.is(TT_TemplateCloser) && Right.is(TT_StartOfName)) + return true; + // space between keywords and paren e.g. "using (" + if (Right.is(tok::l_paren)) + if (Left.is(tok::kw_using)) + return spaceRequiredBeforeParens(Left); + } else if (Style.Language == FormatStyle::LK_JavaScript) { if (Left.is(TT_JsFatArrow)) return true; // for await ( ... @@ -2739,6 +2798,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, tok::kw_void)) return true; } + // `foo as const;` casts into a const type. + if (Left.endsSequence(tok::kw_const, Keywords.kw_as)) { + return false; + } if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in, tok::kw_const) || // "of" is only a keyword if it appears after another identifier @@ -2842,9 +2905,19 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return false; return true; } - if (Left.is(TT_UnaryOperator)) + if (Left.is(TT_UnaryOperator)) { + // The alternative operators for ~ and ! are "compl" and "not". + // If they are used instead, we do not want to combine them with + // the token to the right, unless that is a left paren. + if (!Right.is(tok::l_paren)) { + if (Left.is(tok::exclaim) && Left.TokenText == "not") + return true; + if (Left.is(tok::tilde) && Left.TokenText == "compl") + return true; + } return (Style.SpaceAfterLogicalNot && Left.is(tok::exclaim)) || Right.is(TT_BinaryOperator); + } // If the next token is a binary operator or a selector name, we have // incorrectly classified the parenthesis as a cast. FIXME: Detect correctly. @@ -2857,13 +2930,13 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, (Style.Language == FormatStyle::LK_Proto && Left.is(TT_DictLiteral))) return !Style.Cpp11BracedListStyle; return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) && - (Style.Standard != FormatStyle::LS_Cpp11 || Style.SpacesInAngles); + (Style.Standard < FormatStyle::LS_Cpp11 || Style.SpacesInAngles); } if (Right.isOneOf(tok::arrow, tok::arrowstar, tok::periodstar) || Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) || (Right.is(tok::period) && Right.isNot(TT_DesignatedInitializerPeriod))) return false; - if (!Style.SpaceBeforeAssignmentOperators && + if (!Style.SpaceBeforeAssignmentOperators && Left.isNot(TT_TemplateCloser) && Right.getPrecedence() == prec::Assignment) return false; if (Style.Language == FormatStyle::LK_Java && Right.is(tok::coloncolon) && @@ -2876,7 +2949,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd(); if (Right.is(tok::coloncolon) && !Left.isOneOf(tok::l_brace, tok::comment)) return (Left.is(TT_TemplateOpener) && - Style.Standard == FormatStyle::LS_Cpp03) || + Style.Standard < FormatStyle::LS_Cpp11) || !(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square, tok::kw___super, TT_TemplateCloser, TT_TemplateOpener)) || @@ -3039,7 +3112,8 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, Style.BraceWrapping.AfterEnum) || (Line.startsWith(tok::kw_class) && Style.BraceWrapping.AfterClass) || (Line.startsWith(tok::kw_struct) && Style.BraceWrapping.AfterStruct); - if (Left.is(TT_ObjCBlockLBrace) && !Style.AllowShortBlocksOnASingleLine) + if (Left.is(TT_ObjCBlockLBrace) && + Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never) return true; if (Left.is(TT_LambdaLBrace)) { diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h index 702ac6c0d76e..537710029b00 100644 --- a/lib/Format/TokenAnnotator.h +++ b/lib/Format/TokenAnnotator.h @@ -114,8 +114,7 @@ public: /// \c true if this line starts a namespace definition. bool startsWithNamespace() const { - return startsWith(tok::kw_namespace) || - startsWith(TT_NamespaceMacro) || + return startsWith(tok::kw_namespace) || startsWith(TT_NamespaceMacro) || startsWith(tok::kw_inline, tok::kw_namespace) || startsWith(tok::kw_export, tok::kw_namespace); } diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp index 3f3c80bc1ccf..8b8d357d9cbe 100644 --- a/lib/Format/UnwrappedLineFormatter.cpp +++ b/lib/Format/UnwrappedLineFormatter.cpp @@ -300,14 +300,30 @@ private: // Try to merge a control statement block with left brace unwrapped if (TheLine->Last->is(tok::l_brace) && TheLine->First != TheLine->Last && TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) { - return Style.AllowShortBlocksOnASingleLine + return Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never ? tryMergeSimpleBlock(I, E, Limit) : 0; } // Try to merge a control statement block with left brace wrapped if (I[1]->First->is(tok::l_brace) && - TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) { - return Style.BraceWrapping.AfterControlStatement + (TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for, + tok::kw_switch, tok::kw_try, tok::kw_do) || + (TheLine->First->is(tok::r_brace) && TheLine->First->Next && + TheLine->First->Next->isOneOf(tok::kw_else, tok::kw_catch))) && + Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_MultiLine) { + // If possible, merge the next line's wrapped left brace with the current + // line. Otherwise, leave it on the next line, as this is a multi-line + // control statement. + return (Style.ColumnLimit == 0 || + TheLine->Last->TotalLength <= Style.ColumnLimit) + ? 1 + : 0; + } else if (I[1]->First->is(tok::l_brace) && + TheLine->First->isOneOf(tok::kw_if, tok::kw_while, + tok::kw_for)) { + return (Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_Always) ? tryMergeSimpleBlock(I, E, Limit) : 0; } @@ -317,7 +333,7 @@ private: I != AnnotatedLines.begin() && I[-1]->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) { unsigned MergedLines = 0; - if (Style.AllowShortBlocksOnASingleLine) { + if (Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never) { MergedLines = tryMergeSimpleBlock(I - 1, E, Limit); // If we managed to merge the block, discard the first merged line // since we are merging starting from I. @@ -410,8 +426,10 @@ private: SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) { if (Limit == 0) return 0; - if (Style.BraceWrapping.AfterControlStatement && - (I[1]->First->is(tok::l_brace) && !Style.AllowShortBlocksOnASingleLine)) + if (Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_Always && + I[1]->First->is(tok::l_brace) && + Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never) return 0; if (I[1]->InPPDirective != (*I)->InPPDirective || (I[1]->InPPDirective && I[1]->First->HasUnescapedNewline)) @@ -511,7 +529,7 @@ private: if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::kw_try, tok::kw___try, tok::kw_catch, tok::kw___finally, tok::kw_for, tok::r_brace, Keywords.kw___except)) { - if (!Style.AllowShortBlocksOnASingleLine) + if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never) return 0; // Don't merge when we can't except the case when // the control statement block is empty @@ -522,8 +540,9 @@ private: return 0; if (!Style.AllowShortIfStatementsOnASingleLine && Line.startsWith(tok::kw_if) && - Style.BraceWrapping.AfterControlStatement && I + 2 != E && - !I[2]->First->is(tok::r_brace)) + Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_Always && + I + 2 != E && !I[2]->First->is(tok::r_brace)) return 0; if (!Style.AllowShortLoopsOnASingleLine && Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) && @@ -532,8 +551,9 @@ private: return 0; if (!Style.AllowShortLoopsOnASingleLine && Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) && - Style.BraceWrapping.AfterControlStatement && I + 2 != E && - !I[2]->First->is(tok::r_brace)) + Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_Always && + I + 2 != E && !I[2]->First->is(tok::r_brace)) return 0; // FIXME: Consider an option to allow short exception handling clauses on // a single line. @@ -551,7 +571,7 @@ private: (Tok->getNextNonComment() == nullptr || Tok->getNextNonComment()->is(tok::semi))) { // We merge empty blocks even if the line exceeds the column limit. - Tok->SpacesRequiredBefore = 0; + Tok->SpacesRequiredBefore = Style.SpaceInEmptyBlock ? 1 : 0; Tok->CanBreakBefore = true; return 1; } else if (Limit != 0 && !Line.startsWithNamespace() && @@ -596,6 +616,17 @@ private: if (Tok->Next && Tok->Next->is(tok::kw_else)) return 0; + // Don't merge a trailing multi-line control statement block like: + // } else if (foo && + // bar) + // { <-- current Line + // baz(); + // } + if (Line.First == Line.Last && + Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_MultiLine) + return 0; + return 2; } } else if (I[1]->First->is(tok::l_brace)) { @@ -607,7 +638,7 @@ private: return 0; Limit -= 2; unsigned MergedLines = 0; - if (Style.AllowShortBlocksOnASingleLine || + if (Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never || (I[1]->First == I[1]->Last && I + 2 != E && I[2]->First->is(tok::r_brace))) { MergedLines = tryMergeSimpleBlock(I + 1, E, Limit); @@ -1192,6 +1223,12 @@ void UnwrappedLineFormatter::formatFirstToken( if (Newlines) Indent = NewlineIndent; + // If in Whitemsmiths mode, indent start and end of blocks + if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) { + if (RootToken.isOneOf(tok::l_brace, tok::r_brace, tok::kw_case)) + Indent += Style.IndentWidth; + } + // Preprocessor directives get indented before the hash only if specified if (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash && (Line.Type == LT_PreprocessorDirective || diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index a35e98ae5503..bbe05602f6da 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -145,7 +145,7 @@ public: else if (!Parser.Line->Tokens.empty()) Parser.CurrentLines = &Parser.Line->Tokens.back().Children; PreBlockLine = std::move(Parser.Line); - Parser.Line = llvm::make_unique<UnwrappedLine>(); + Parser.Line = std::make_unique<UnwrappedLine>(); Parser.Line->Level = PreBlockLine->Level; Parser.Line->InPPDirective = PreBlockLine->InPPDirective; } @@ -174,8 +174,7 @@ public: const FormatStyle &Style, unsigned &LineLevel) : CompoundStatementIndenter(Parser, LineLevel, Style.BraceWrapping.AfterControlStatement, - Style.BraceWrapping.IndentBraces) { - } + Style.BraceWrapping.IndentBraces) {} CompoundStatementIndenter(UnwrappedLineParser *Parser, unsigned &LineLevel, bool WrapBrace, bool IndentBrace) : LineLevel(LineLevel), OldLineLevel(LineLevel) { @@ -1168,7 +1167,8 @@ void UnwrappedLineParser::parseStructuralElement() { case tok::objc_autoreleasepool: nextToken(); if (FormatTok->Tok.is(tok::l_brace)) { - if (Style.BraceWrapping.AfterControlStatement) + if (Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_Always) addUnwrappedLine(); parseBlock(/*MustBeDeclaration=*/false); } @@ -1180,7 +1180,8 @@ void UnwrappedLineParser::parseStructuralElement() { // Skip synchronization object parseParens(); if (FormatTok->Tok.is(tok::l_brace)) { - if (Style.BraceWrapping.AfterControlStatement) + if (Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_Always) addUnwrappedLine(); parseBlock(/*MustBeDeclaration=*/false); } @@ -1215,7 +1216,9 @@ void UnwrappedLineParser::parseStructuralElement() { case tok::kw_typedef: nextToken(); if (FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS, - Keywords.kw_CF_ENUM, Keywords.kw_CF_OPTIONS)) + Keywords.kw_CF_ENUM, Keywords.kw_CF_OPTIONS, + Keywords.kw_CF_CLOSED_ENUM, + Keywords.kw_NS_CLOSED_ENUM)) parseEnum(); break; case tok::kw_struct: @@ -1350,7 +1353,7 @@ void UnwrappedLineParser::parseStructuralElement() { (TokenCount == 2 && Line->Tokens.front().Tok->is(tok::comment))) { if (FormatTok->Tok.is(tok::colon) && !Line->MustBeDeclaration) { Line->Tokens.begin()->Tok->MustBreakBefore = true; - parseLabel(); + parseLabel(!Style.IndentGotoLabels); return; } // Recognize function-like macro usages without trailing semicolon as @@ -1439,8 +1442,11 @@ bool UnwrappedLineParser::tryToParseLambda() { case tok::identifier: case tok::numeric_constant: case tok::coloncolon: + case tok::kw_class: case tok::kw_mutable: case tok::kw_noexcept: + case tok::kw_template: + case tok::kw_typename: nextToken(); break; // Specialization of a template with an integer parameter can contain @@ -1454,6 +1460,9 @@ bool UnwrappedLineParser::tryToParseLambda() { // followed by an `a->b` expression, such as: // ([obj func:arg] + a->b) // Otherwise the code below would parse as a lambda. + // + // FIXME: This heuristic is incorrect for C++20 generic lambdas with + // explicit template lists: []<bool b = true && false>(U &&u){} case tok::plus: case tok::minus: case tok::exclaim: @@ -1755,7 +1764,7 @@ void UnwrappedLineParser::parseSquare(bool LambdaIntroducer) { void UnwrappedLineParser::parseIfThenElse() { assert(FormatTok->Tok.is(tok::kw_if) && "'if' expected"); nextToken(); - if (FormatTok->Tok.is(tok::kw_constexpr)) + if (FormatTok->Tok.isOneOf(tok::kw_constexpr, tok::identifier)) nextToken(); if (FormatTok->Tok.is(tok::l_paren)) parseParens(); @@ -1872,8 +1881,13 @@ void UnwrappedLineParser::parseNamespace() { if (InitialToken.is(TT_NamespaceMacro)) { parseParens(); } else { - while (FormatTok->isOneOf(tok::identifier, tok::coloncolon)) - nextToken(); + while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw_inline, + tok::l_square)) { + if (FormatTok->is(tok::l_square)) + parseSquare(); + else + nextToken(); + } } if (FormatTok->Tok.is(tok::l_brace)) { if (ShouldBreakBeforeBrace(Style, InitialToken)) @@ -1964,18 +1978,21 @@ void UnwrappedLineParser::parseDoWhile() { parseStructuralElement(); } -void UnwrappedLineParser::parseLabel() { +void UnwrappedLineParser::parseLabel(bool LeftAlignLabel) { nextToken(); unsigned OldLineLevel = Line->Level; if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0)) --Line->Level; + if (LeftAlignLabel) + Line->Level = 0; if (CommentsBeforeNextToken.empty() && FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Line->Level, Style.BraceWrapping.AfterCaseLabel, Style.BraceWrapping.IndentBraces); parseBlock(/*MustBeDeclaration=*/false); if (FormatTok->Tok.is(tok::kw_break)) { - if (Style.BraceWrapping.AfterControlStatement) + if (Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_Always) addUnwrappedLine(); parseStructuralElement(); } diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h index e1b35317c7c0..5d9bafc429a7 100644 --- a/lib/Format/UnwrappedLineParser.h +++ b/lib/Format/UnwrappedLineParser.h @@ -106,7 +106,7 @@ private: void parseTryCatch(); void parseForOrWhileLoop(); void parseDoWhile(); - void parseLabel(); + void parseLabel(bool LeftAlignLabel = false); void parseCaseLabel(); void parseSwitch(); void parseNamespace(); diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp index 23fbf94c7588..5a44500d355f 100644 --- a/lib/Format/WhitespaceManager.cpp +++ b/lib/Format/WhitespaceManager.cpp @@ -17,8 +17,8 @@ namespace clang { namespace format { -bool WhitespaceManager::Change::IsBeforeInFile:: -operator()(const Change &C1, const Change &C2) const { +bool WhitespaceManager::Change::IsBeforeInFile::operator()( + const Change &C1, const Change &C2) const { return SourceMgr.isBeforeInTranslationUnit( C1.OriginalWhitespaceRange.getBegin(), C2.OriginalWhitespaceRange.getBegin()); @@ -815,19 +815,24 @@ void WhitespaceManager::appendIndentText(std::string &Text, Text.append(Spaces, ' '); break; case FormatStyle::UT_Always: { - unsigned FirstTabWidth = - Style.TabWidth - WhitespaceStartColumn % Style.TabWidth; - // Insert only spaces when we want to end up before the next tab. - if (Spaces < FirstTabWidth || Spaces == 1) { + if (Style.TabWidth) { + unsigned FirstTabWidth = + Style.TabWidth - WhitespaceStartColumn % Style.TabWidth; + + // Insert only spaces when we want to end up before the next tab. + if (Spaces < FirstTabWidth || Spaces == 1) { + Text.append(Spaces, ' '); + break; + } + // Align to the next tab. + Spaces -= FirstTabWidth; + Text.append("\t"); + + Text.append(Spaces / Style.TabWidth, '\t'); + Text.append(Spaces % Style.TabWidth, ' '); + } else if (Spaces == 1) { Text.append(Spaces, ' '); - break; } - // Align to the next tab. - Spaces -= FirstTabWidth; - Text.append("\t"); - - Text.append(Spaces / Style.TabWidth, '\t'); - Text.append(Spaces % Style.TabWidth, ' '); break; } case FormatStyle::UT_ForIndentation: @@ -837,14 +842,16 @@ void WhitespaceManager::appendIndentText(std::string &Text, // the first one. if (Indentation > Spaces) Indentation = Spaces; - unsigned Tabs = Indentation / Style.TabWidth; - Text.append(Tabs, '\t'); - Spaces -= Tabs * Style.TabWidth; + if (Style.TabWidth) { + unsigned Tabs = Indentation / Style.TabWidth; + Text.append(Tabs, '\t'); + Spaces -= Tabs * Style.TabWidth; + } } Text.append(Spaces, ' '); break; case FormatStyle::UT_ForContinuationAndIndentation: - if (WhitespaceStartColumn == 0) { + if (WhitespaceStartColumn == 0 && Style.TabWidth) { unsigned Tabs = Spaces / Style.TabWidth; Text.append(Tabs, '\t'); Spaces -= Tabs * Style.TabWidth; |