diff options
-rw-r--r-- | clang/include/clang/Format/Format.h | 14 | ||||
-rw-r--r-- | clang/lib/Format/BreakableToken.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Format/BreakableToken.h | 22 | ||||
-rw-r--r-- | clang/lib/Format/Format.cpp | 22 | ||||
-rw-r--r-- | clang/lib/Format/TokenAnnotator.cpp | 17 | ||||
-rw-r--r-- | clang/unittests/Format/FormatTest.cpp | 93 |
6 files changed, 121 insertions, 63 deletions
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 73258cd64b1..595e798dd3c 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -33,12 +33,18 @@ struct FormatStyle { /// \brief The column limit. unsigned ColumnLimit; - /// \brief The penalty for each character outside of the column limit. - unsigned PenaltyExcessCharacter; - /// \brief The maximum number of consecutive empty lines to keep. unsigned MaxEmptyLinesToKeep; + /// \brief The penalty for each line break introduced inside a comment. + unsigned PenaltyBreakComment; + + /// \brief The penalty for each line break introduced inside a string literal. + unsigned PenaltyBreakString; + + /// \brief The penalty for each character outside of the column limit. + unsigned PenaltyExcessCharacter; + /// \brief Set whether & and * bind to the type as opposed to the variable. bool PointerBindsToType; @@ -144,6 +150,8 @@ struct FormatStyle { IndentWidth == R.IndentWidth && MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep && ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList && + PenaltyBreakString == R.PenaltyBreakString && + PenaltyBreakComment == R.PenaltyBreakComment && PenaltyExcessCharacter == R.PenaltyExcessCharacter && PenaltyReturnTypeOnItsOwnLine == R.PenaltyReturnTypeOnItsOwnLine && PointerBindsToType == R.PointerBindsToType && diff --git a/clang/lib/Format/BreakableToken.cpp b/clang/lib/Format/BreakableToken.cpp index 5e5604c597f..94b4322e7e0 100644 --- a/clang/lib/Format/BreakableToken.cpp +++ b/clang/lib/Format/BreakableToken.cpp @@ -112,11 +112,10 @@ BreakableToken::Split getStringSplit(StringRef Text, unsigned BreakableSingleLineToken::getLineCount() const { return 1; } -unsigned -BreakableSingleLineToken::getLineLengthAfterSplit(unsigned LineIndex, - unsigned TailOffset) const { +unsigned BreakableSingleLineToken::getLineLengthAfterSplit( + unsigned LineIndex, unsigned Offset, StringRef::size_type Length) const { return StartColumn + Prefix.size() + Postfix.size() + - encoding::getCodePointCount(Line.substr(TailOffset), Encoding); + encoding::getCodePointCount(Line.substr(Offset, Length), Encoding); } void BreakableSingleLineToken::insertBreak(unsigned LineIndex, @@ -268,11 +267,10 @@ void BreakableBlockComment::adjustWhitespace(const FormatStyle &Style, unsigned BreakableBlockComment::getLineCount() const { return Lines.size(); } -unsigned -BreakableBlockComment::getLineLengthAfterSplit(unsigned LineIndex, - unsigned TailOffset) const { - return getContentStartColumn(LineIndex, TailOffset) + - encoding::getCodePointCount(Lines[LineIndex].substr(TailOffset), +unsigned BreakableBlockComment::getLineLengthAfterSplit( + unsigned LineIndex, unsigned Offset, StringRef::size_type Length) const { + return getContentStartColumn(LineIndex, Offset) + + encoding::getCodePointCount(Lines[LineIndex].substr(Offset, Length), Encoding) + // The last line gets a "*/" postfix. (LineIndex + 1 == Lines.size() ? 2 : 0); diff --git a/clang/lib/Format/BreakableToken.h b/clang/lib/Format/BreakableToken.h index 157bff4c42f..100bb19dc5d 100644 --- a/clang/lib/Format/BreakableToken.h +++ b/clang/lib/Format/BreakableToken.h @@ -33,7 +33,7 @@ struct FormatStyle; /// strategy into the class, instead of controlling it from the outside. class BreakableToken { public: - // Contains starting character index and length of split. + /// \brief Contains starting character index and length of split. typedef std::pair<StringRef::size_type, unsigned> Split; virtual ~BreakableToken() {} @@ -41,13 +41,15 @@ public: /// \brief Returns the number of lines in this token in the original code. virtual unsigned getLineCount() const = 0; - /// \brief Returns the rest of the length of the line at \p LineIndex, - /// when broken at \p TailOffset. + /// \brief Returns the number of columns required to format the piece of line + /// at \p LineIndex, from byte offset \p Offset with length \p Length. /// - /// Note that previous breaks are not taken into account. \p TailOffset - /// is always specified from the start of the (original) line. - virtual unsigned getLineLengthAfterSplit(unsigned LineIndex, - unsigned TailOffset) const = 0; + /// Note that previous breaks are not taken into account. \p Offset is always + /// specified from the start of the (original) line. + /// \p Length can be set to StringRef::npos, which means "to the end of line". + virtual unsigned + getLineLengthAfterSplit(unsigned LineIndex, unsigned Offset, + StringRef::size_type Length) const = 0; /// \brief Returns a range (offset, length) at which to break the line at /// \p LineIndex, if previously broken at \p TailOffset. If possible, do not @@ -80,7 +82,8 @@ class BreakableSingleLineToken : public BreakableToken { public: virtual unsigned getLineCount() const; virtual unsigned getLineLengthAfterSplit(unsigned LineIndex, - unsigned TailOffset) const; + unsigned TailOffset, + StringRef::size_type Length) const; virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, bool InPPDirective, WhitespaceManager &Whitespaces); @@ -139,7 +142,8 @@ public: virtual unsigned getLineCount() const; virtual unsigned getLineLengthAfterSplit(unsigned LineIndex, - unsigned TailOffset) const; + 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, diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 9dd5e4a0f21..f61f1fbb3fb 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -96,6 +96,8 @@ template <> struct MappingTraits<clang::format::FormatStyle> { IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep); IO.mapOptional("ObjCSpaceBeforeProtocolList", Style.ObjCSpaceBeforeProtocolList); + IO.mapOptional("PenaltyBreakComment", Style.PenaltyBreakComment); + IO.mapOptional("PenaltyBreakString", Style.PenaltyBreakString); IO.mapOptional("PenaltyExcessCharacter", Style.PenaltyExcessCharacter); IO.mapOptional("PenaltyReturnTypeOnItsOwnLine", Style.PenaltyReturnTypeOnItsOwnLine); @@ -130,6 +132,8 @@ FormatStyle getLLVMStyle() { LLVMStyle.IndentCaseLabels = false; LLVMStyle.MaxEmptyLinesToKeep = 1; LLVMStyle.ObjCSpaceBeforeProtocolList = true; + LLVMStyle.PenaltyBreakComment = 45; + LLVMStyle.PenaltyBreakString = 1000; LLVMStyle.PenaltyExcessCharacter = 1000000; LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 75; LLVMStyle.PointerBindsToType = false; @@ -157,6 +161,8 @@ FormatStyle getGoogleStyle() { GoogleStyle.IndentCaseLabels = true; GoogleStyle.MaxEmptyLinesToKeep = 1; GoogleStyle.ObjCSpaceBeforeProtocolList = false; + GoogleStyle.PenaltyBreakComment = 45; + GoogleStyle.PenaltyBreakString = 1000; GoogleStyle.PenaltyExcessCharacter = 1000000; GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200; GoogleStyle.PointerBindsToType = true; @@ -840,8 +846,8 @@ private: Whitespaces); } unsigned TailOffset = 0; - unsigned RemainingTokenColumns = - Token->getLineLengthAfterSplit(LineIndex, TailOffset); + unsigned RemainingTokenColumns = Token->getLineLengthAfterSplit( + LineIndex, TailOffset, StringRef::npos); while (RemainingTokenColumns > RemainingSpace) { BreakableToken::Split Split = Token->getSplit(LineIndex, TailOffset, getColumnLimit()); @@ -849,15 +855,23 @@ private: break; assert(Split.first != 0); unsigned NewRemainingTokenColumns = Token->getLineLengthAfterSplit( - LineIndex, TailOffset + Split.first + Split.second); + LineIndex, TailOffset + Split.first + Split.second, + StringRef::npos); assert(NewRemainingTokenColumns < RemainingTokenColumns); if (!DryRun) { Token->insertBreak(LineIndex, TailOffset, Split, Line.InPPDirective, Whitespaces); } + Penalty += Current.is(tok::string_literal) ? Style.PenaltyBreakString + : Style.PenaltyBreakComment; + unsigned ColumnsUsed = + Token->getLineLengthAfterSplit(LineIndex, TailOffset, Split.first); + if (ColumnsUsed > getColumnLimit()) { + Penalty += + Style.PenaltyExcessCharacter * (ColumnsUsed - getColumnLimit()); + } TailOffset += Split.first + Split.second; RemainingTokenColumns = NewRemainingTokenColumns; - Penalty += Style.PenaltyExcessCharacter; BreakInserted = true; } PositionAfterLastLineInToken = RemainingTokenColumns; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 8b1382ed7c6..20709bbb306 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -103,13 +103,16 @@ private: // '*' has to be a binary operator but determineStarAmpUsage() will // categorize it as an unary operator, so set the right type here. if (LookForDecls && CurrentToken->Next) { - FormatToken *Prev = CurrentToken->Previous; - FormatToken *Next = CurrentToken->Next; - if (Prev->Previous->is(tok::identifier) && - Prev->isOneOf(tok::star, tok::amp, tok::ampamp) && - CurrentToken->is(tok::identifier) && Next->isNot(tok::equal)) { - Prev->Type = TT_BinaryOperator; - LookForDecls = false; + FormatToken *Prev = CurrentToken->getPreviousNoneComment(); + if (Prev) { + FormatToken *PrevPrev = Prev->getPreviousNoneComment(); + FormatToken *Next = CurrentToken->Next; + if (PrevPrev && PrevPrev->is(tok::identifier) && + Prev->isOneOf(tok::star, tok::amp, tok::ampamp) && + CurrentToken->is(tok::identifier) && Next->isNot(tok::equal)) { + Prev->Type = TT_BinaryOperator; + LookForDecls = false; + } } } diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index f5204b45768..6a2edc0f99e 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -675,7 +675,7 @@ TEST_F(FormatTest, UnderstandsSingleLineComments) { "};"); verifyGoogleFormat( "aaaaaaaaaaaaaaaaaaaaaaaaaa(\n" - " aaaaaaaaaaaaaaaaaaaaaa); // 81 cols with this comment"); + " aaaaaaaaaaaaaaaaaaaaaa); // 81_cols_with_this_comment"); EXPECT_EQ("D(a, {\n" " // test\n" " int a;\n" @@ -871,37 +871,36 @@ TEST_F(FormatTest, SplitsLongCxxComments) { format("// A comment before a macro definition\n" "#define a b", getLLVMStyleWithColumns(20))); +} - EXPECT_EQ("/* A comment before\n" - " * a macro\n" - " * definition */\n" - "#define a b", - format("/* A comment before a macro definition */\n" - "#define a b", - getLLVMStyleWithColumns(20))); - - EXPECT_EQ("/* some comment\n" - " * a comment\n" - "* that we break\n" - " * another comment\n" - "* we have to break\n" - "* a left comment\n" - " */", - format(" /* some comment\n" - " * a comment that we break\n" - " * another comment we have to break\n" - "* a left comment\n" - " */", - getLLVMStyleWithColumns(20))); - - EXPECT_EQ("/*\n" - "\n" - "\n" - " */\n", - format(" /* \n" - " \n" - " \n" - " */\n")); +TEST_F(FormatTest, PriorityOfCommentBreaking) { + EXPECT_EQ("if (xxx == yyy && // aaaaaaaaaaaa\n" + " // bbbbbbbbb\n" + " zzz)\n" + " q();", + format("if (xxx == yyy && // aaaaaaaaaaaa bbbbbbbbb\n" + " zzz) q();", + getLLVMStyleWithColumns(40))); + EXPECT_EQ("if (xxxxxxxxxx ==\n" + " yyy && // aaaaaa bbbbbbbb cccc\n" + " zzz)\n" + " q();", + format("if (xxxxxxxxxx == yyy && // aaaaaa bbbbbbbb cccc\n" + " zzz) q();", + getLLVMStyleWithColumns(40))); + EXPECT_EQ("if (xxxxxxxxxx &&\n" + " yyy || // aaaaaa bbbbbbbb cccc\n" + " zzz)\n" + " q();", + format("if (xxxxxxxxxx && yyy || // aaaaaa bbbbbbbb cccc\n" + " zzz) q();", + getLLVMStyleWithColumns(40))); + EXPECT_EQ("fffffffff(&xxx, // aaaaaaaaaaaa\n" + " // bbbbbbbbbbb\n" + " zzz);", + format("fffffffff(&xxx, // aaaaaaaaaaaa bbbbbbbbbbb\n" + " zzz);", + getLLVMStyleWithColumns(40))); } TEST_F(FormatTest, MultiLineCommentsInDefines) { @@ -1059,6 +1058,37 @@ TEST_F(FormatTest, SplitsLongLinesInComments) { " ;\n" "}", getLLVMStyleWithColumns(30))); + + EXPECT_EQ("/* A comment before\n" + " * a macro\n" + " * definition */\n" + "#define a b", + format("/* A comment before a macro definition */\n" + "#define a b", + getLLVMStyleWithColumns(20))); + + EXPECT_EQ("/* some comment\n" + " * a comment\n" + "* that we break\n" + " * another comment\n" + "* we have to break\n" + "* a left comment\n" + " */", + format(" /* some comment\n" + " * a comment that we break\n" + " * another comment we have to break\n" + "* a left comment\n" + " */", + getLLVMStyleWithColumns(20))); + + EXPECT_EQ("/*\n" + "\n" + "\n" + " */\n", + format(" /* \n" + " \n" + " \n" + " */\n")); } TEST_F(FormatTest, SplitsLongLinesInCommentsInPreprocessor) { @@ -3263,6 +3293,7 @@ TEST_F(FormatTest, FormatsCasts) { // FIXME: Without type knowledge, this can still fall apart miserably. verifyFormat("void f() { my_int a = (my_int) * b; }"); + verifyFormat("void f() { return P ? (my_int) * P : (my_int)0; }"); verifyFormat("my_int a = (my_int) ~0;"); verifyFormat("my_int a = (my_int)++ a;"); verifyFormat("my_int a = (my_int) + 2;"); |