From e8111502d8696896241132865c7a44c6f84f93c1 Mon Sep 17 00:00:00 2001 From: mydeveloperday Date: Mon, 13 Apr 2020 15:14:26 +0100 Subject: [PATCH] [clang-format] use spaces for alignment with UT_ForContinuationAndIndentation Summary: Use spaces instead of tabs for alignment with UT_ForContinuationAndIndentation to make the code aligned for any tab/indent width. Fixes https://bugs.llvm.org/show_bug.cgi?id=38381 Reviewed By: MyDeveloperDay Patch By: fickert Tags: #clang-format Differential Revision: https://reviews.llvm.org/D75034 --- clang/docs/ClangFormatStyleOptions.rst | 6 +- clang/include/clang/Format/Format.h | 6 +- clang/lib/Format/BreakableToken.cpp | 4 +- clang/lib/Format/ContinuationIndenter.cpp | 5 +- clang/lib/Format/ContinuationIndenter.h | 21 +- clang/lib/Format/Format.cpp | 1 + clang/lib/Format/UnwrappedLineFormatter.cpp | 4 +- clang/lib/Format/WhitespaceManager.cpp | 59 ++-- clang/lib/Format/WhitespaceManager.h | 10 +- clang/unittests/Format/FormatTest.cpp | 298 +++++++++++++++++++- 10 files changed, 363 insertions(+), 51 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 1c1d0142930f..6d486224e3c2 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -2534,7 +2534,11 @@ the configuration (without a prefix: ``Auto``). Use tabs only for indentation. * ``UT_ForContinuationAndIndentation`` (in configuration: ``ForContinuationAndIndentation``) - Use tabs only for line continuation and indentation. + Fill all leading whitespace with tabs, and use spaces for alignment that + appears within a line (e.g. consecutive assignments and declarations). + + * ``UT_AlignWithSpaces`` (in configuration: ``AlignWithSpaces``) + Use tabs for line continuation and indentation, and spaces for alignment. * ``UT_Always`` (in configuration: ``Always``) Use tabs whenever we need to fill whitespace that spans at least from diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index d4f76c87c14e..2b2edc4adc11 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -2129,8 +2129,12 @@ struct FormatStyle { UT_Never, /// Use tabs only for indentation. UT_ForIndentation, - /// Use tabs only for line continuation and indentation. + /// Fill all leading whitespace with tabs, and use spaces for alignment that + /// appears within a line (e.g. consecutive assignments and declarations). UT_ForContinuationAndIndentation, + /// Use tabs for line continuation and indentation, and spaces for + /// alignemnt. + UT_AlignWithSpaces, /// Use tabs whenever we need to fill whitespace that spans at least from /// one tab stop to the next one. UT_Always diff --git a/clang/lib/Format/BreakableToken.cpp b/clang/lib/Format/BreakableToken.cpp index 4294c2a653fa..15fbe3b6515d 100644 --- a/clang/lib/Format/BreakableToken.cpp +++ b/clang/lib/Format/BreakableToken.cpp @@ -863,7 +863,8 @@ void BreakableLineCommentSection::reflow(unsigned LineIndex, // tokens by the empty string. Whitespaces.replaceWhitespace( *Tokens[LineIndex], /*Newlines=*/0, /*Spaces=*/0, - /*StartOfTokenColumn=*/StartColumn, /*InPPDirective=*/false); + /*StartOfTokenColumn=*/StartColumn, /*IsAligned=*/true, + /*InPPDirective=*/false); } else if (LineIndex > 0) { // In case we're reflowing after the '\' in: // @@ -931,6 +932,7 @@ void BreakableLineCommentSection::adaptStartOfLine( /*Newlines=*/1, /*Spaces=*/LineColumn, /*StartOfTokenColumn=*/LineColumn, + /*IsAligned=*/true, /*InPPDirective=*/false); } if (OriginalPrefix[LineIndex] != Prefix[LineIndex]) { diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 2dda5d89a3ac..e70ae7efb0c3 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -642,8 +642,10 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, if (Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign && !State.Stack.back().IsCSharpGenericTypeConstraint && Previous.opensScope() && Previous.isNot(TT_ObjCMethodExpr) && - (Current.isNot(TT_LineComment) || Previous.BlockKind == BK_BracedInit)) + (Current.isNot(TT_LineComment) || Previous.BlockKind == BK_BracedInit)) { State.Stack.back().Indent = State.Column + Spaces; + State.Stack.back().IsAligned = true; + } if (State.Stack.back().AvoidBinPacking && startsNextParameter(Current, Style)) State.Stack.back().NoLineBreak = true; if (startsSegmentOfBuilderTypeCall(Current) && @@ -858,6 +860,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, bool ContinuePPDirective = State.Line->InPPDirective && State.Line->Type != LT_ImportStatement; Whitespaces.replaceWhitespace(Current, Newlines, State.Column, State.Column, + State.Stack.back().IsAligned, ContinuePPDirective); } diff --git a/clang/lib/Format/ContinuationIndenter.h b/clang/lib/Format/ContinuationIndenter.h index ab116d5468e8..5ad4548529d7 100644 --- a/clang/lib/Format/ContinuationIndenter.h +++ b/clang/lib/Format/ContinuationIndenter.h @@ -202,14 +202,14 @@ struct ParenState { ParenState(const FormatToken *Tok, unsigned Indent, unsigned LastSpace, bool AvoidBinPacking, bool NoLineBreak) : Tok(Tok), Indent(Indent), LastSpace(LastSpace), - NestedBlockIndent(Indent), BreakBeforeClosingBrace(false), - AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false), - NoLineBreak(NoLineBreak), NoLineBreakInOperand(false), - LastOperatorWrapped(true), ContainsLineBreak(false), - ContainsUnwrappedBuilder(false), AlignColons(true), - ObjCSelectorNameFound(false), HasMultipleNestedBlocks(false), - NestedBlockInlined(false), IsInsideObjCArrayLiteral(false), - IsCSharpGenericTypeConstraint(false) {} + NestedBlockIndent(Indent), IsAligned(false), + BreakBeforeClosingBrace(false), AvoidBinPacking(AvoidBinPacking), + BreakBeforeParameter(false), NoLineBreak(NoLineBreak), + NoLineBreakInOperand(false), LastOperatorWrapped(true), + ContainsLineBreak(false), ContainsUnwrappedBuilder(false), + AlignColons(true), ObjCSelectorNameFound(false), + HasMultipleNestedBlocks(false), NestedBlockInlined(false), + IsInsideObjCArrayLiteral(false), IsCSharpGenericTypeConstraint(false) {} /// \brief The token opening this parenthesis level, or nullptr if this level /// is opened by fake parenthesis. @@ -265,6 +265,9 @@ struct ParenState { /// Used to align further variables if necessary. unsigned VariablePos = 0; + /// Whether this block's indentation is used for alignment. + bool IsAligned : 1; + /// Whether a newline needs to be inserted before the block's closing /// brace. /// @@ -341,6 +344,8 @@ struct ParenState { return NestedBlockIndent < Other.NestedBlockIndent; if (FirstLessLess != Other.FirstLessLess) return FirstLessLess < Other.FirstLessLess; + if (IsAligned != Other.IsAligned) + return IsAligned; if (BreakBeforeClosingBrace != Other.BreakBeforeClosingBrace) return BreakBeforeClosingBrace; if (QuestionColumn != Other.QuestionColumn) diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 031312bd16d8..4a5626d42209 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -93,6 +93,7 @@ template <> struct ScalarEnumerationTraits { IO.enumCase(Value, "ForIndentation", FormatStyle::UT_ForIndentation); IO.enumCase(Value, "ForContinuationAndIndentation", FormatStyle::UT_ForContinuationAndIndentation); + IO.enumCase(Value, "AlignWithSpaces", FormatStyle::UT_AlignWithSpaces); } }; diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index a81d480c8e64..c16c16c4f26a 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -888,7 +888,8 @@ protected: if (!DryRun) { Whitespaces->replaceWhitespace( *Child->First, /*Newlines=*/0, /*Spaces=*/1, - /*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective); + /*StartOfTokenColumn=*/State.Column, /*IsAligned=*/false, + State.Line->InPPDirective); } Penalty += formatLine(*Child, State.Column + 1, /*FirstStartColumn=*/0, DryRun); @@ -1320,6 +1321,7 @@ void UnwrappedLineFormatter::formatFirstToken( Indent = 0; Whitespaces->replaceWhitespace(RootToken, Newlines, Indent, Indent, + /*IsAligned=*/false, Line.InPPDirective && !RootToken.HasUnescapedNewline); } diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index 5a44500d355f..bc71a89fc92b 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -30,13 +30,13 @@ WhitespaceManager::Change::Change(const FormatToken &Tok, int Spaces, unsigned StartOfTokenColumn, unsigned NewlinesBefore, StringRef PreviousLinePostfix, - StringRef CurrentLinePrefix, + StringRef CurrentLinePrefix, bool IsAligned, bool ContinuesPPDirective, bool IsInsideToken) : Tok(&Tok), CreateReplacement(CreateReplacement), OriginalWhitespaceRange(OriginalWhitespaceRange), StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore), PreviousLinePostfix(PreviousLinePostfix), - CurrentLinePrefix(CurrentLinePrefix), + CurrentLinePrefix(CurrentLinePrefix), IsAligned(IsAligned), ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces), IsInsideToken(IsInsideToken), IsTrailingComment(false), TokenLength(0), PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0), @@ -45,13 +45,13 @@ WhitespaceManager::Change::Change(const FormatToken &Tok, void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces, unsigned StartOfTokenColumn, - bool InPPDirective) { + bool IsAligned, bool InPPDirective) { if (Tok.Finalized) return; Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue; Changes.push_back(Change(Tok, /*CreateReplacement=*/true, Tok.WhitespaceRange, Spaces, StartOfTokenColumn, Newlines, "", "", - InPPDirective && !Tok.IsFirst, + IsAligned, InPPDirective && !Tok.IsFirst, /*IsInsideToken=*/false)); } @@ -62,7 +62,7 @@ void WhitespaceManager::addUntouchableToken(const FormatToken &Tok, Changes.push_back(Change(Tok, /*CreateReplacement=*/false, Tok.WhitespaceRange, /*Spaces=*/0, Tok.OriginalColumn, Tok.NewlinesBefore, "", "", - InPPDirective && !Tok.IsFirst, + /*IsAligned=*/false, InPPDirective && !Tok.IsFirst, /*IsInsideToken=*/false)); } @@ -82,7 +82,8 @@ void WhitespaceManager::replaceWhitespaceInToken( Change(Tok, /*CreateReplacement=*/true, SourceRange(Start, Start.getLocWithOffset(ReplaceChars)), Spaces, std::max(0, Spaces), Newlines, PreviousPostfix, CurrentPrefix, - InPPDirective && !Tok.IsFirst, /*IsInsideToken=*/true)); + /*IsAligned=*/true, InPPDirective && !Tok.IsFirst, + /*IsInsideToken=*/true)); } const tooling::Replacements &WhitespaceManager::generateReplacements() { @@ -761,9 +762,9 @@ void WhitespaceManager::generateChanges() { C.EscapedNewlineColumn); else appendNewlineText(ReplacementText, C.NewlinesBefore); - appendIndentText(ReplacementText, C.Tok->IndentLevel, - std::max(0, C.Spaces), - C.StartOfTokenColumn - std::max(0, C.Spaces)); + appendIndentText( + ReplacementText, C.Tok->IndentLevel, std::max(0, C.Spaces), + C.StartOfTokenColumn - std::max(0, C.Spaces), C.IsAligned); ReplacementText.append(C.CurrentLinePrefix); storeReplacement(C.OriginalWhitespaceRange, ReplacementText); } @@ -809,7 +810,8 @@ void WhitespaceManager::appendEscapedNewlineText( void WhitespaceManager::appendIndentText(std::string &Text, unsigned IndentLevel, unsigned Spaces, - unsigned WhitespaceStartColumn) { + unsigned WhitespaceStartColumn, + bool IsAligned) { switch (Style.UseTab) { case FormatStyle::UT_Never: Text.append(Spaces, ' '); @@ -838,28 +840,39 @@ void WhitespaceManager::appendIndentText(std::string &Text, case FormatStyle::UT_ForIndentation: if (WhitespaceStartColumn == 0) { unsigned Indentation = IndentLevel * Style.IndentWidth; - // This happens, e.g. when a line in a block comment is indented less than - // the first one. - if (Indentation > Spaces) - Indentation = Spaces; - if (Style.TabWidth) { - unsigned Tabs = Indentation / Style.TabWidth; - Text.append(Tabs, '\t'); - Spaces -= Tabs * Style.TabWidth; - } + Spaces = appendTabIndent(Text, Spaces, Indentation); } Text.append(Spaces, ' '); break; case FormatStyle::UT_ForContinuationAndIndentation: - if (WhitespaceStartColumn == 0 && Style.TabWidth) { - unsigned Tabs = Spaces / Style.TabWidth; - Text.append(Tabs, '\t'); - Spaces -= Tabs * Style.TabWidth; + if (WhitespaceStartColumn == 0) + Spaces = appendTabIndent(Text, Spaces, Spaces); + Text.append(Spaces, ' '); + break; + case FormatStyle::UT_AlignWithSpaces: + if (WhitespaceStartColumn == 0) { + unsigned Indentation = + IsAligned ? IndentLevel * Style.IndentWidth : Spaces; + Spaces = appendTabIndent(Text, Spaces, Indentation); } Text.append(Spaces, ' '); break; } } +unsigned WhitespaceManager::appendTabIndent(std::string &Text, unsigned Spaces, + unsigned Indentation) { + // This happens, e.g. when a line in a block comment is indented less than the + // first one. + if (Indentation > Spaces) + Indentation = Spaces; + if (Style.TabWidth) { + unsigned Tabs = Indentation / Style.TabWidth; + Text.append(Tabs, '\t'); + Spaces -= Tabs * Style.TabWidth; + } + return Spaces; +} + } // namespace format } // namespace clang diff --git a/clang/lib/Format/WhitespaceManager.h b/clang/lib/Format/WhitespaceManager.h index f47bf40204b3..a9f83920801f 100644 --- a/clang/lib/Format/WhitespaceManager.h +++ b/clang/lib/Format/WhitespaceManager.h @@ -49,7 +49,7 @@ public: /// this replacement. It is needed for determining how \p Spaces is turned /// into tabs and spaces for some format styles. void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces, - unsigned StartOfTokenColumn, + unsigned StartOfTokenColumn, bool isAligned = false, bool InPPDirective = false); /// Adds information about an unchangeable token's whitespace. @@ -109,7 +109,7 @@ public: SourceRange OriginalWhitespaceRange, int Spaces, unsigned StartOfTokenColumn, unsigned NewlinesBefore, StringRef PreviousLinePostfix, StringRef CurrentLinePrefix, - bool ContinuesPPDirective, bool IsInsideToken); + bool IsAligned, bool ContinuesPPDirective, bool IsInsideToken); // The kind of the token whose whitespace this change replaces, or in which // this change inserts whitespace. @@ -125,6 +125,7 @@ public: unsigned NewlinesBefore; std::string PreviousLinePostfix; std::string CurrentLinePrefix; + bool IsAligned; bool ContinuesPPDirective; // The number of spaces in front of the token or broken part of the token. @@ -204,7 +205,10 @@ private: unsigned PreviousEndOfTokenColumn, unsigned EscapedNewlineColumn); void appendIndentText(std::string &Text, unsigned IndentLevel, - unsigned Spaces, unsigned WhitespaceStartColumn); + unsigned Spaces, unsigned WhitespaceStartColumn, + bool IsAligned); + unsigned appendTabIndent(std::string &Text, unsigned Spaces, + unsigned Indentation); SmallVector Changes; const SourceManager &SourceMgr; diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index ece7c61a999c..69a2001cd995 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -10151,17 +10151,18 @@ TEST_F(FormatTest, ConfigurableUseOfTab) { " \t \t comment */", Tab)); EXPECT_EQ("{\n" - " /*\n" - " * Comment\n" - " */\n" - " int i;\n" + " /*\n" + " * Comment\n" + " */\n" + " int i;\n" "}", format("{\n" "\t/*\n" "\t * Comment\n" "\t */\n" "\t int i;\n" - "}")); + "}", + Tab)); Tab.UseTab = FormatStyle::UT_ForContinuationAndIndentation; Tab.TabWidth = 8; @@ -10332,15 +10333,245 @@ TEST_F(FormatTest, ConfigurableUseOfTab) { "\t*/\n" "}", Tab)); + EXPECT_EQ("/* some\n" + " comment */", + format(" \t \t /* some\n" + " \t \t comment */", + Tab)); + EXPECT_EQ("int a; /* some\n" + " comment */", + format(" \t \t int a; /* some\n" + " \t \t comment */", + Tab)); + EXPECT_EQ("int a; /* some\n" + "comment */", + format(" \t \t int\ta; /* some\n" + " \t \t comment */", + Tab)); + EXPECT_EQ("f(\"\t\t\"); /* some\n" + " comment */", + format(" \t \t f(\"\t\t\"); /* some\n" + " \t \t comment */", + Tab)); + EXPECT_EQ("{\n" + "\t/*\n" + "\t * Comment\n" + "\t */\n" + "\tint i;\n" + "}", + format("{\n" + "\t/*\n" + "\t * Comment\n" + "\t */\n" + "\t int i;\n" + "}", + Tab)); + Tab.TabWidth = 2; + Tab.IndentWidth = 2; + EXPECT_EQ("{\n" + "\t/* aaaa\n" + "\t\t bbbb */\n" + "}", + format("{\n" + "/* aaaa\n" + "\t bbbb */\n" + "}", + Tab)); + EXPECT_EQ("{\n" + "\t/*\n" + "\t\taaaaaaaaaaaaaaaaaaaaaaaaaa\n" + "\t\tbbbbbbbbbbbbb\n" + "\t*/\n" + "}", + format("{\n" + "/*\n" + "\taaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbb\n" + "*/\n" + "}", + Tab)); + Tab.AlignConsecutiveAssignments = true; + Tab.AlignConsecutiveDeclarations = true; + Tab.TabWidth = 4; + Tab.IndentWidth = 4; + verifyFormat("class Assign {\n" + "\tvoid f() {\n" + "\t\tint x = 123;\n" + "\t\tint random = 4;\n" + "\t\tstd::string alphabet =\n" + "\t\t\t\"abcdefghijklmnopqrstuvwxyz\";\n" + "\t}\n" + "};", + Tab); + + Tab.UseTab = FormatStyle::UT_AlignWithSpaces; + Tab.TabWidth = 8; + Tab.IndentWidth = 8; + EXPECT_EQ("if (aaaaaaaa && // q\n" + " bb) // w\n" + "\t;", + format("if (aaaaaaaa &&// q\n" + "bb)// w\n" + ";", + Tab)); + EXPECT_EQ("if (aaa && bbb) // w\n" + "\t;", + format("if(aaa&&bbb)// w\n" + ";", + Tab)); + verifyFormat("class X {\n" + "\tvoid f() {\n" + "\t\tsomeFunction(parameter1,\n" + "\t\t parameter2);\n" + "\t}\n" + "};", + Tab); + verifyFormat("#define A \\\n" + "\tvoid f() { \\\n" + "\t\tsomeFunction( \\\n" + "\t\t parameter1, \\\n" + "\t\t parameter2); \\\n" + "\t}", + Tab); + Tab.TabWidth = 4; + Tab.IndentWidth = 8; + verifyFormat("class TabWidth4Indent8 {\n" + "\t\tvoid f() {\n" + "\t\t\t\tsomeFunction(parameter1,\n" + "\t\t\t\t parameter2);\n" + "\t\t}\n" + "};", + Tab); + Tab.TabWidth = 4; + Tab.IndentWidth = 4; + verifyFormat("class TabWidth4Indent4 {\n" + "\tvoid f() {\n" + "\t\tsomeFunction(parameter1,\n" + "\t\t parameter2);\n" + "\t}\n" + "};", + Tab); + Tab.TabWidth = 8; + Tab.IndentWidth = 4; + verifyFormat("class TabWidth8Indent4 {\n" + " void f() {\n" + "\tsomeFunction(parameter1,\n" + "\t parameter2);\n" + " }\n" + "};", + Tab); + Tab.TabWidth = 8; + Tab.IndentWidth = 8; EXPECT_EQ("/*\n" - "\t a\t\tcomment\n" - "\t in multiple lines\n" + " a\t\tcomment\n" + " in multiple lines\n" " */", format(" /*\t \t \n" " \t \t a\t\tcomment\t \t\n" " \t \t in multiple lines\t\n" " \t */", Tab)); + verifyFormat("{\n" + "\taaaaaaaaaaaaaaaaaaaaaaaaaaaa();\n" + "\taaaaaaaaaaaaaaaaaaaaaaaaaaaa();\n" + "\taaaaaaaaaaaaaaaaaaaaaaaaaaaa();\n" + "\taaaaaaaaaaaaaaaaaaaaaaaaaaaa();\n" + "\taaaaaaaaaaaaaaaaaaaaaaaaaaaa();\n" + "\taaaaaaaaaaaaaaaaaaaaaaaaaaaa();\n" + "};", + Tab); + verifyFormat("enum AA {\n" + "\ta1, // Force multiple lines\n" + "\ta2,\n" + "\ta3\n" + "};", + Tab); + EXPECT_EQ("if (aaaaaaaa && // q\n" + " bb) // w\n" + "\t;", + format("if (aaaaaaaa &&// q\n" + "bb)// w\n" + ";", + Tab)); + verifyFormat("class X {\n" + "\tvoid f() {\n" + "\t\tsomeFunction(parameter1,\n" + "\t\t parameter2);\n" + "\t}\n" + "};", + Tab); + verifyFormat("{\n" + "\tQ(\n" + "\t {\n" + "\t\t int a;\n" + "\t\t someFunction(aaaaaaaa,\n" + "\t\t bbbbbbb);\n" + "\t },\n" + "\t p);\n" + "}", + Tab); + EXPECT_EQ("{\n" + "\t/* aaaa\n" + "\t bbbb */\n" + "}", + format("{\n" + "/* aaaa\n" + " bbbb */\n" + "}", + Tab)); + EXPECT_EQ("{\n" + "\t/*\n" + "\t aaaaaaaaaaaaaaaaaaaaaaaaaa\n" + "\t bbbbbbbbbbbbb\n" + "\t*/\n" + "}", + format("{\n" + "/*\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbb\n" + "*/\n" + "}", + Tab)); + EXPECT_EQ("{\n" + "\t// aaaaaaaaaaaaaaaaaaaaaaaaaa\n" + "\t// bbbbbbbbbbbbb\n" + "}", + format("{\n" + "\t// aaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbb\n" + "}", + Tab)); + EXPECT_EQ("{\n" + "\t/*\n" + "\t aaaaaaaaaaaaaaaaaaaaaaaaaa\n" + "\t bbbbbbbbbbbbb\n" + "\t*/\n" + "}", + format("{\n" + "\t/*\n" + "\t aaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbb\n" + "\t*/\n" + "}", + Tab)); + EXPECT_EQ("{\n" + "\t/*\n" + "\n" + "\t*/\n" + "}", + format("{\n" + "\t/*\n" + "\n" + "\t*/\n" + "}", + Tab)); + EXPECT_EQ("{\n" + "\t/*\n" + " asdf\n" + "\t*/\n" + "}", + format("{\n" + "\t/*\n" + " asdf\n" + "\t*/\n" + "}", + Tab)); EXPECT_EQ("/* some\n" " comment */", format(" \t \t /* some\n" @@ -10362,17 +10593,41 @@ TEST_F(FormatTest, ConfigurableUseOfTab) { " \t \t comment */", Tab)); EXPECT_EQ("{\n" - " /*\n" - " * Comment\n" - " */\n" - " int i;\n" + "\t/*\n" + "\t * Comment\n" + "\t */\n" + "\tint i;\n" "}", format("{\n" "\t/*\n" "\t * Comment\n" "\t */\n" "\t int i;\n" - "}")); + "}", + Tab)); + Tab.TabWidth = 2; + Tab.IndentWidth = 2; + EXPECT_EQ("{\n" + "\t/* aaaa\n" + "\t bbbb */\n" + "}", + format("{\n" + "/* aaaa\n" + " bbbb */\n" + "}", + Tab)); + EXPECT_EQ("{\n" + "\t/*\n" + "\t aaaaaaaaaaaaaaaaaaaaaaaaaa\n" + "\t bbbbbbbbbbbbb\n" + "\t*/\n" + "}", + format("{\n" + "/*\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbb\n" + "*/\n" + "}", + Tab)); Tab.AlignConsecutiveAssignments = true; Tab.AlignConsecutiveDeclarations = true; Tab.TabWidth = 4; @@ -10443,6 +10698,23 @@ TEST_F(FormatTest, ZeroTabWidth) { "};", Tab)); + Tab.UseTab = FormatStyle::UT_AlignWithSpaces; + EXPECT_EQ("void a(){\n" + " // line starts with '\t'\n" + "};", + format("void a(){\n" + "\t// line starts with '\t'\n" + "};", + Tab)); + + EXPECT_EQ("void a(){\n" + " // line starts with '\t'\n" + "};", + format("void a(){\n" + "\t\t// line starts with '\t'\n" + "};", + Tab)); + Tab.UseTab = FormatStyle::UT_Always; EXPECT_EQ("void a(){\n" "// line starts with '\t'\n" @@ -12843,6 +13115,8 @@ TEST_F(FormatTest, ParsesConfiguration) { CHECK_PARSE("UseTab: Always", UseTab, FormatStyle::UT_Always); CHECK_PARSE("UseTab: ForContinuationAndIndentation", UseTab, FormatStyle::UT_ForContinuationAndIndentation); + CHECK_PARSE("UseTab: AlignWithSpaces", UseTab, + FormatStyle::UT_AlignWithSpaces); // For backward compatibility: CHECK_PARSE("UseTab: false", UseTab, FormatStyle::UT_Never); CHECK_PARSE("UseTab: true", UseTab, FormatStyle::UT_Always);