diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 871d7c63cdace..3b3f6f2860906 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -2722,8 +2722,6 @@ the configuration (without a prefix: ``Auto``). **BreakStringLiterals** (``Boolean``) :versionbadge:`clang-format 3.9` :ref:`ΒΆ ` Allow breaking string literals when formatting. - In C, C++, and Objective-C: - .. code-block:: c++ true: @@ -2733,34 +2731,7 @@ the configuration (without a prefix: ``Auto``). false: const char* x = - "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString"; - - In C#, Java, and JavaScript: - - .. code-block:: c++ - - true: - var x = "veryVeryVeryVeryVeryVe" + - "ryVeryVeryVeryVeryVery" + - "VeryLongString"; - - false: - var x = - "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString"; - C# and JavaScript interpolated strings are not broken. - - In Verilog: - - .. code-block:: c++ - - true: - string x = {"veryVeryVeryVeryVeryVe", - "ryVeryVeryVeryVeryVery", - "VeryLongString"}; - - false: - string x = - "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString"; + "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString"; .. _ColumnLimit: diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index b7b25657927aa..192cc68e51fad 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -2008,8 +2008,6 @@ struct FormatStyle { bool BreakAfterJavaFieldAnnotations; /// Allow breaking string literals when formatting. - /// - /// In C, C++, and Objective-C: /// \code /// true: /// const char* x = "veryVeryVeryVeryVeryVe" @@ -2018,34 +2016,8 @@ struct FormatStyle { /// /// false: /// const char* x = - /// "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString"; - /// \endcode - /// - /// In C#, Java, and JavaScript: - /// \code - /// true: - /// var x = "veryVeryVeryVeryVeryVe" + - /// "ryVeryVeryVeryVeryVery" + - /// "VeryLongString"; - /// - /// false: - /// var x = - /// "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString"; + /// "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString"; /// \endcode - /// C# and JavaScript interpolated strings are not broken. - /// - /// In Verilog: - /// \code - /// true: - /// string x = {"veryVeryVeryVeryVeryVe", - /// "ryVeryVeryVeryVeryVery", - /// "VeryLongString"}; - /// - /// false: - /// string x = - /// "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString"; - /// \endcode - /// /// \version 3.9 bool BreakStringLiterals; diff --git a/clang/lib/Format/BreakableToken.cpp b/clang/lib/Format/BreakableToken.cpp index 4264ea188c215..af1e0748fafa9 100644 --- a/clang/lib/Format/BreakableToken.cpp +++ b/clang/lib/Format/BreakableToken.cpp @@ -292,120 +292,6 @@ void BreakableStringLiteral::insertBreak(unsigned LineIndex, Prefix, InPPDirective, 1, StartColumn); } -BreakableStringLiteralUsingOperators::BreakableStringLiteralUsingOperators( - const FormatToken &Tok, QuoteStyleType QuoteStyle, bool UnindentPlus, - unsigned StartColumn, unsigned UnbreakableTailLength, bool InPPDirective, - encoding::Encoding Encoding, const FormatStyle &Style) - : BreakableStringLiteral( - Tok, StartColumn, /*Prefix=*/QuoteStyle == SingleQuotes ? "'" - : QuoteStyle == AtDoubleQuotes ? "@\"" - : "\"", - /*Postfix=*/QuoteStyle == SingleQuotes ? "'" : "\"", - UnbreakableTailLength, InPPDirective, Encoding, Style), - BracesNeeded(Tok.isNot(TT_StringInConcatenation)), - QuoteStyle(QuoteStyle) { - // Find the replacement text for inserting braces and quotes and line breaks. - // We don't create an allocated string concatenated from parts here because it - // has to outlive the BreakableStringliteral object. The brace replacements - // include a quote so that WhitespaceManager can tell it apart from whitespace - // replacements between the string and surrounding tokens. - - // The option is not implemented in JavaScript. - bool SignOnNewLine = - !Style.isJavaScript() && - Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None; - - if (Style.isVerilog()) { - // In Verilog, all strings are quoted by double quotes, joined by commas, - // and wrapped in braces. The comma is always before the newline. - assert(QuoteStyle == DoubleQuotes); - LeftBraceQuote = Style.Cpp11BracedListStyle ? "{\"" : "{ \""; - RightBraceQuote = Style.Cpp11BracedListStyle ? "\"}" : "\" }"; - Postfix = "\","; - Prefix = "\""; - } else { - // The plus sign may be on either line. And also C# and JavaScript have - // different quoting styles. - if (QuoteStyle == SingleQuotes) { - LeftBraceQuote = Style.SpacesInParensOptions.Other ? "( '" : "('"; - RightBraceQuote = Style.SpacesInParensOptions.Other ? "' )" : "')"; - Postfix = SignOnNewLine ? "'" : "' +"; - Prefix = SignOnNewLine ? "+ '" : "'"; - } else { - if (QuoteStyle == AtDoubleQuotes) { - LeftBraceQuote = Style.SpacesInParensOptions.Other ? "( @" : "(@"; - Prefix = SignOnNewLine ? "+ @\"" : "@\""; - } else { - LeftBraceQuote = Style.SpacesInParensOptions.Other ? "( \"" : "(\""; - Prefix = SignOnNewLine ? "+ \"" : "\""; - } - RightBraceQuote = Style.SpacesInParensOptions.Other ? "\" )" : "\")"; - Postfix = SignOnNewLine ? "\"" : "\" +"; - } - } - - // Following lines are indented by the width of the brace and space if any. - ContinuationIndent = BracesNeeded ? LeftBraceQuote.size() - 1 : 0; - // The plus sign may need to be unindented depending on the style. - // FIXME: Add support for DontAlign. - if (!Style.isVerilog() && SignOnNewLine && !BracesNeeded && UnindentPlus && - Style.AlignOperands == FormatStyle::OAS_AlignAfterOperator) { - ContinuationIndent -= 2; - } -} - -unsigned BreakableStringLiteralUsingOperators::getRemainingLength( - unsigned LineIndex, unsigned Offset, unsigned StartColumn) const { - return UnbreakableTailLength + (BracesNeeded ? RightBraceQuote.size() : 1) + - encoding::columnWidthWithTabs(Line.substr(Offset), StartColumn, - Style.TabWidth, Encoding); -} - -unsigned -BreakableStringLiteralUsingOperators::getContentStartColumn(unsigned LineIndex, - bool Break) const { - return std::max( - 0, - static_cast(StartColumn) + - (Break ? ContinuationIndent + static_cast(Prefix.size()) - : (BracesNeeded ? static_cast(LeftBraceQuote.size()) - 1 - : 0) + - (QuoteStyle == AtDoubleQuotes ? 2 : 1))); -} - -void BreakableStringLiteralUsingOperators::insertBreak( - unsigned LineIndex, unsigned TailOffset, Split Split, - unsigned ContentIndent, WhitespaceManager &Whitespaces) const { - Whitespaces.replaceWhitespaceInToken( - Tok, /*Offset=*/(QuoteStyle == AtDoubleQuotes ? 2 : 1) + TailOffset + - Split.first, - /*ReplaceChars=*/Split.second, /*PreviousPostfix=*/Postfix, - /*CurrentPrefix=*/Prefix, InPPDirective, /*NewLines=*/1, - /*Spaces=*/ - std::max(0, static_cast(StartColumn) + ContinuationIndent)); -} - -void BreakableStringLiteralUsingOperators::updateAfterBroken( - WhitespaceManager &Whitespaces) const { - // Add the braces required for breaking the token if they are needed. - if (!BracesNeeded) - return; - - // To add a brace or parenthesis, we replace the quote (or the at sign) with a - // brace and another quote. This is because the rest of the program requires - // one replacement for each source range. If we replace the empty strings - // around the string, it may conflict with whitespace replacements between the - // string and adjacent tokens. - Whitespaces.replaceWhitespaceInToken( - Tok, /*Offset=*/0, /*ReplaceChars=*/1, /*PreviousPostfix=*/"", - /*CurrentPrefix=*/LeftBraceQuote, InPPDirective, /*NewLines=*/0, - /*Spaces=*/0); - Whitespaces.replaceWhitespaceInToken( - Tok, /*Offset=*/Tok.TokenText.size() - 1, /*ReplaceChars=*/1, - /*PreviousPostfix=*/RightBraceQuote, - /*CurrentPrefix=*/"", InPPDirective, /*NewLines=*/0, /*Spaces=*/0); -} - BreakableComment::BreakableComment(const FormatToken &Token, unsigned StartColumn, bool InPPDirective, encoding::Encoding Encoding, diff --git a/clang/lib/Format/BreakableToken.h b/clang/lib/Format/BreakableToken.h index 0c6ee1b097216..190144ad1be93 100644 --- a/clang/lib/Format/BreakableToken.h +++ b/clang/lib/Format/BreakableToken.h @@ -230,11 +230,6 @@ class BreakableToken { /// as a unit and is responsible for the formatting of the them. virtual void updateNextToken(LineState &State) const {} - /// Adds replacements that are needed when the token is broken. Such as - /// wrapping a JavaScript string in parentheses after it gets broken with plus - /// signs. - virtual void updateAfterBroken(WhitespaceManager &Whitespaces) const {} - protected: BreakableToken(const FormatToken &Tok, bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style) @@ -288,44 +283,6 @@ class BreakableStringLiteral : public BreakableToken { unsigned UnbreakableTailLength; }; -class BreakableStringLiteralUsingOperators : public BreakableStringLiteral { -public: - enum QuoteStyleType { - DoubleQuotes, // The string is quoted with double quotes. - SingleQuotes, // The JavaScript string is quoted with single quotes. - AtDoubleQuotes, // The C# verbatim string is quoted with the at sign and - // double quotes. - }; - /// Creates a breakable token for a single line string literal for C#, Java, - /// JavaScript, or Verilog. - /// - /// \p StartColumn specifies the column in which the token will start - /// after formatting. - BreakableStringLiteralUsingOperators( - const FormatToken &Tok, QuoteStyleType QuoteStyle, bool UnindentPlus, - unsigned StartColumn, unsigned UnbreakableTailLength, bool InPPDirective, - encoding::Encoding Encoding, const FormatStyle &Style); - unsigned getRemainingLength(unsigned LineIndex, unsigned Offset, - unsigned StartColumn) const override; - unsigned getContentStartColumn(unsigned LineIndex, bool Break) const override; - void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, - unsigned ContentIndent, - WhitespaceManager &Whitespaces) const override; - void updateAfterBroken(WhitespaceManager &Whitespaces) const override; - -protected: - // Whether braces or parentheses should be inserted around the string to form - // a concatenation. - bool BracesNeeded; - QuoteStyleType QuoteStyle; - // The braces or parentheses along with the first character which they - // replace, either a quote or at sign. - StringRef LeftBraceQuote; - StringRef RightBraceQuote; - // Width added to the left due to the added. Does not apply to the first line. - int ContinuationIndent; -}; - class BreakableComment : public BreakableToken { protected: /// Creates a breakable token for a comment. diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 3a6575d03ae18..b23eb549650a7 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -36,14 +36,6 @@ static bool shouldIndentWrappedSelectorName(const FormatStyle &Style, return Style.IndentWrappedFunctionNames || LineType == LT_ObjCMethodDecl; } -// Returns true if a binary operator following \p Tok should be unindented when -// the style permits it. -static bool shouldUnindentNextOperator(const FormatToken &Tok) { - const FormatToken *Previous = Tok.getPreviousNonComment(); - return Previous && (Previous->getPrecedence() == prec::Assignment || - Previous->isOneOf(tok::kw_return, TT_RequiresClause)); -} - // Returns the length of everything up to the first possible line break after // the ), ], } or > matching \c Tok. static unsigned getLengthToMatchingParen(const FormatToken &Tok, @@ -1626,10 +1618,11 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State, if (Previous && Previous->endsSequence(tok::l_paren, tok::kw__Generic)) NewParenState.Indent = CurrentState.LastSpace; - if ((shouldUnindentNextOperator(Current) || - (Previous && - (PrecedenceLevel == prec::Conditional && - Previous->is(tok::question) && Previous->is(TT_ConditionalExpr)))) && + if (Previous && + (Previous->getPrecedence() == prec::Assignment || + Previous->isOneOf(tok::kw_return, TT_RequiresClause) || + (PrecedenceLevel == prec::Conditional && Previous->is(tok::question) && + Previous->is(TT_ConditionalExpr))) && !Newline) { // If BreakBeforeBinaryOperators is set, un-indent a bit to account for // the operator and keep the operands aligned. @@ -2192,9 +2185,14 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current, LineState &State, bool AllowBreak) { unsigned StartColumn = State.Column - Current.ColumnWidth; if (Current.isStringLiteral()) { - // Strings in JSON can not be broken. - if (Style.isJson() || !Style.BreakStringLiterals || !AllowBreak) + // FIXME: String literal breaking is currently disabled for C#, Java, Json + // and JavaScript, as it requires strings to be merged using "+" which we + // don't support. + if (Style.Language == FormatStyle::LK_Java || Style.isJavaScript() || + Style.isCSharp() || Style.isJson() || !Style.BreakStringLiterals || + !AllowBreak) { return nullptr; + } // Don't break string literals inside preprocessor directives (except for // #define directives, as their contents are stored in separate lines and @@ -2213,33 +2211,6 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current, return nullptr; StringRef Text = Current.TokenText; - // We need this to address the case where there is an unbreakable tail only - // if certain other formatting decisions have been taken. The - // UnbreakableTailLength of Current is an overapproximation is that case and - // we need to be correct here. - unsigned UnbreakableTailLength = (State.NextToken && canBreak(State)) - ? 0 - : Current.UnbreakableTailLength; - - if (Style.isVerilog() || Style.Language == FormatStyle::LK_Java || - Style.isJavaScript() || Style.isCSharp()) { - BreakableStringLiteralUsingOperators::QuoteStyleType QuoteStyle; - if (Style.isJavaScript() && Text.startswith("'") && Text.endswith("'")) { - QuoteStyle = BreakableStringLiteralUsingOperators::SingleQuotes; - } else if (Style.isCSharp() && Text.startswith("@\"") && - Text.endswith("\"")) { - QuoteStyle = BreakableStringLiteralUsingOperators::AtDoubleQuotes; - } else if (Text.startswith("\"") && Text.endswith("\"")) { - QuoteStyle = BreakableStringLiteralUsingOperators::DoubleQuotes; - } else { - return nullptr; - } - return std::make_unique( - Current, QuoteStyle, - /*UnindentPlus=*/shouldUnindentNextOperator(Current), StartColumn, - UnbreakableTailLength, State.Line->InPPDirective, Encoding, Style); - } - StringRef Prefix; StringRef Postfix; // FIXME: Handle whitespace between '_T', '(', '"..."', and ')'. @@ -2252,6 +2223,13 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current, Text.startswith(Prefix = "u8\"") || Text.startswith(Prefix = "L\""))) || (Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")"))) { + // We need this to address the case where there is an unbreakable tail + // only if certain other formatting decisions have been taken. The + // UnbreakableTailLength of Current is an overapproximation is that case + // and we need to be correct here. + unsigned UnbreakableTailLength = (State.NextToken && canBreak(State)) + ? 0 + : Current.UnbreakableTailLength; return std::make_unique( Current, StartColumn, Prefix, Postfix, UnbreakableTailLength, State.Line->InPPDirective, Encoding, Style); @@ -2652,9 +2630,6 @@ ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, Current.UnbreakableTailLength; if (BreakInserted) { - if (!DryRun) - Token->updateAfterBroken(Whitespaces); - // If we break the token inside a parameter list, we need to break before // the next parameter on all levels, so that the next parameter is clearly // visible. Line comments already introduce a break. diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index b15871acdfd16..6ce9249c24cdc 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -134,11 +134,6 @@ namespace format { TYPE(StartOfName) \ TYPE(StatementAttributeLikeMacro) \ TYPE(StatementMacro) \ - /* A string that is part of a string concatenation. For C#, JavaScript, and \ - * Java, it is used for marking whether a string needs parentheses around it \ - * if it is to be split into parts joined by `+`. For Verilog, whether \ - * braces need to be added to split it. Not used for other languages. */ \ - TYPE(StringInConcatenation) \ TYPE(StructLBrace) \ TYPE(StructuredBindingLSquare) \ TYPE(TemplateCloser) \ diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 0b92412dcdd87..2f71cc8dab6ed 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -863,11 +863,6 @@ class AnnotatingParser { OpeningBrace.Previous->is(TT_JsTypeColon)) { Contexts.back().IsExpression = false; } - if (Style.isVerilog() && - (!OpeningBrace.getPreviousNonComment() || - OpeningBrace.getPreviousNonComment()->isNot(Keywords.kw_apostrophe))) { - Contexts.back().VerilogMayBeConcatenation = true; - } unsigned CommaCount = 0; while (CurrentToken) { @@ -1742,9 +1737,6 @@ class AnnotatingParser { bool InCpp11AttributeSpecifier = false; bool InCSharpAttributeSpecifier = false; bool VerilogAssignmentFound = false; - // Whether the braces may mean concatenation instead of structure or array - // literal. - bool VerilogMayBeConcatenation = false; enum { Unknown, // Like the part after `:` in a constructor. @@ -2077,14 +2069,6 @@ class AnnotatingParser { } else { Current.setType(TT_LineComment); } - } else if (Current.is(tok::string_literal)) { - if (Style.isVerilog() && Contexts.back().VerilogMayBeConcatenation && - Current.getPreviousNonComment() && - Current.getPreviousNonComment()->isOneOf(tok::comma, tok::l_brace) && - Current.getNextNonComment() && - Current.getNextNonComment()->isOneOf(tok::comma, tok::r_brace)) { - Current.setType(TT_StringInConcatenation); - } } else if (Current.is(tok::l_paren)) { if (lParenStartsCppCast(Current)) Current.setType(TT_CppCastLParen); @@ -2755,19 +2739,6 @@ class ExpressionParser { Start = Current; } - if ((Style.isCSharp() || Style.isJavaScript() || - Style.Language == FormatStyle::LK_Java) && - Precedence == prec::Additive && Current) { - // A string can be broken without parentheses around it when it is - // already in a sequence of strings joined by `+` signs. - FormatToken *Prev = Current->getPreviousNonComment(); - if (Prev && Prev->is(tok::string_literal) && - (Prev == Start || Prev->endsSequence(tok::string_literal, tok::plus, - TT_StringInConcatenation))) { - Prev->setType(TT_StringInConcatenation); - } - } - // At the end of the line or when an operator with lower precedence is // found, insert fake parenthesis and return. if (!Current || diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index 4c5e81a7af94e..61e59d042b14c 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -22,13 +22,8 @@ namespace format { bool WhitespaceManager::Change::IsBeforeInFile::operator()( const Change &C1, const Change &C2) const { return SourceMgr.isBeforeInTranslationUnit( - C1.OriginalWhitespaceRange.getBegin(), - C2.OriginalWhitespaceRange.getBegin()) || - (C1.OriginalWhitespaceRange.getBegin() == - C2.OriginalWhitespaceRange.getBegin() && - SourceMgr.isBeforeInTranslationUnit( - C1.OriginalWhitespaceRange.getEnd(), - C2.OriginalWhitespaceRange.getEnd())); + C1.OriginalWhitespaceRange.getBegin(), + C2.OriginalWhitespaceRange.getBegin()); } WhitespaceManager::Change::Change(const FormatToken &Tok, @@ -1514,55 +1509,10 @@ WhitespaceManager::linkCells(CellDescriptions &&CellDesc) { void WhitespaceManager::generateChanges() { for (unsigned i = 0, e = Changes.size(); i != e; ++i) { const Change &C = Changes[i]; - if (i > 0) { - auto Last = Changes[i - 1].OriginalWhitespaceRange; - auto New = Changes[i].OriginalWhitespaceRange; - // Do not generate two replacements for the same location. As a special - // case, it is allowed if there is a replacement for the empty range - // between 2 tokens and another non-empty range at the start of the second - // token. We didn't implement logic to combine replacements for 2 - // consecutive source ranges into a single replacement, because the - // program works fine without it. - // - // We can't eliminate empty original whitespace ranges. They appear when - // 2 tokens have no whitespace in between in the input. It does not - // matter whether whitespace is to be added. If no whitespace is to be - // added, the replacement will be empty, and it gets eliminated after this - // step in storeReplacement. For example, if the input is `foo();`, - // there will be a replacement for the range between every consecutive - // pair of tokens. - // - // A replacement at the start of a token can be added by - // BreakableStringLiteralUsingOperators::insertBreak when it adds braces - // around the string literal. Say Verilog code is being formatted and the - // first line is to become the next 2 lines. - // x("long string"); - // x({"long ", - // "string"}); - // There will be a replacement for the empty range between the parenthesis - // and the string and another replacement for the quote character. The - // replacement for the empty range between the parenthesis and the quote - // comes from ContinuationIndenter::addTokenOnCurrentLine when it changes - // the original empty range between the parenthesis and the string to - // another empty one. The replacement for the quote character comes from - // BreakableStringLiteralUsingOperators::insertBreak when it adds the - // brace. In the example, the replacement for the empty range is the same - // as the original text. However, eliminating replacements that are same - // as the original does not help in general. For example, a newline can - // be inserted, causing the first line to become the next 3 lines. - // xxxxxxxxxxx("long string"); - // xxxxxxxxxxx( - // {"long ", - // "string"}); - // In that case, the empty range between the parenthesis and the string - // will be replaced by a newline and 4 spaces. So we will still have to - // deal with a replacement for an empty source range followed by a - // replacement for a non-empty source range. - if (Last.getBegin() == New.getBegin() && - (Last.getEnd() != Last.getBegin() || - New.getEnd() == New.getBegin())) { - continue; - } + if (i > 0 && Changes[i - 1].OriginalWhitespaceRange.getBegin() == + C.OriginalWhitespaceRange.getBegin()) { + // Do not generate two replacements for the same location. + continue; } if (C.CreateReplacement) { std::string ReplacementText = C.PreviousLinePostfix; diff --git a/clang/unittests/Format/FormatTestCSharp.cpp b/clang/unittests/Format/FormatTestCSharp.cpp index 05d20c5ef1922..9f912624d1658 100644 --- a/clang/unittests/Format/FormatTestCSharp.cpp +++ b/clang/unittests/Format/FormatTestCSharp.cpp @@ -6,21 +6,18 @@ // //===----------------------------------------------------------------------===// -#include "FormatTestBase.h" +#include "FormatTestUtils.h" +#include "clang/Format/Format.h" +#include "llvm/Support/Debug.h" +#include "gtest/gtest.h" #define DEBUG_TYPE "format-test" namespace clang { namespace format { -namespace test { -namespace { -class FormatTestCSharp : public test::FormatTestBase { +class FormatTestCSharp : public ::testing::Test { protected: - FormatStyle getDefaultStyle() const override { - return getMicrosoftStyle(FormatStyle::LK_CSharp); - } - static std::string format(llvm::StringRef Code, unsigned Offset, unsigned Length, const FormatStyle &Style) { LLVM_DEBUG(llvm::errs() << "---\n"); @@ -44,6 +41,13 @@ class FormatTestCSharp : public test::FormatTestBase { Style.ColumnLimit = ColumnLimit; return Style; } + + static void verifyFormat( + llvm::StringRef Code, + const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) { + EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable"; + EXPECT_EQ(Code.str(), format(test::messUp(Code), Style)); + } }; TEST_F(FormatTestCSharp, CSharpClass) { @@ -125,65 +129,9 @@ TEST_F(FormatTestCSharp, AccessModifiers) { } TEST_F(FormatTestCSharp, NoStringLiteralBreaks) { - // Breaking of interpolated strings is not implemented. - auto Style = getDefaultStyle(); - Style.ColumnLimit = 40; - Style.BreakStringLiterals = true; - verifyFormat("foo(" - "$\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaa\");", - Style); -} - -TEST_F(FormatTestCSharp, StringLiteralBreaks) { - // The line is 75 characters long. The default limit for the Microsoft style - // is 120. - auto Style = getDefaultStyle(); - Style.BreakStringLiterals = true; verifyFormat("foo(" "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaa\");", - Style); - // When the column limit is smaller, the string should get broken. - Style.ColumnLimit = 40; - verifyFormat(R"(foo("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + - "aaa");)", - "foo(" - "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaa\");", - Style); - // The new quotes should be the same as the original. - verifyFormat(R"(foo(@"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + - @"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + - @"aaaaa");)", - "foo(" - "@\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaaa\");", - Style); - // The operators can be on either line. - Style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment; - verifyFormat(R"(foo("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - + "a");)", - "foo(" - "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaa\");", - Style); - Style.AlignOperands = FormatStyle::OAS_AlignAfterOperator; - verifyFormat(R"(foo("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - + "a");)", - "foo(" - "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaa\");", - Style); - verifyFormat(R"(x = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";)", - "x = " - "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - "aaaaaa\";", - Style); + "aaaaaa\");"); } TEST_F(FormatTestCSharp, CSharpVerbatiumStringLiterals) { @@ -218,7 +166,7 @@ TEST_F(FormatTestCSharp, CSharpInterpolatedStringLiterals) { } TEST_F(FormatTestCSharp, CSharpFatArrows) { - verifyIncompleteFormat("Task serverTask = Task.Run(async() => {"); + verifyFormat("Task serverTask = Task.Run(async() => {"); verifyFormat("public override string ToString() => \"{Name}\\{Age}\";"); } @@ -334,7 +282,7 @@ TEST_F(FormatTestCSharp, Attributes) { "listening on provided host\")]\n" "public string Host { set; get; }"); - verifyIncompleteFormat( + verifyFormat( "[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n" "// The const char* returned by hello_world must not be deleted.\n" "private static extern IntPtr HelloFromCpp();)"); @@ -1190,8 +1138,7 @@ TEST_F(FormatTestCSharp, CSharpSpaces) { Style); verifyFormat(R"(Apply(x => x.Name, x => () => x.ID);)", Style); verifyFormat(R"(bool[] xs = { true, true };)", Style); - verifyIncompleteFormat( - R"(taskContext.Factory.Run(async () => doThing(args);)", Style); + verifyFormat(R"(taskContext.Factory.Run(async () => doThing(args);)", Style); verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style); verifyFormat(R"(private float[,] Values;)", Style); verifyFormat(R"(Result this[Index x] => Foo(x);)", Style); @@ -1665,7 +1612,5 @@ TEST_F(FormatTestCSharp, BrokenBrackets) { EXPECT_NE("", format("int where b <")); // reduced from crasher } -} // namespace -} // namespace test } // namespace format -} // namespace clang +} // end namespace clang diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp index 6c0228c2dca88..1df7859e715ba 100644 --- a/clang/unittests/Format/FormatTestJS.cpp +++ b/clang/unittests/Format/FormatTestJS.cpp @@ -1505,97 +1505,6 @@ TEST_F(FormatTestJS, TryCatch) { TEST_F(FormatTestJS, StringLiteralConcatenation) { verifyFormat("var literal = 'hello ' +\n" " 'world';"); - - // Long strings should be broken. - verifyFormat("var literal =\n" - " 'xxxxxxxx ' +\n" - " 'xxxxxxxx';", - "var literal = 'xxxxxxxx xxxxxxxx';", - getGoogleJSStyleWithColumns(17)); - verifyFormat("var literal =\n" - " 'xxxxxxxx ' +\n" - " 'xxxxxxxx';", - "var literal = 'xxxxxxxx xxxxxxxx';", - getGoogleJSStyleWithColumns(18)); - verifyFormat("var literal =\n" - " 'xxxxxxxx' +\n" - " ' xxxxxxxx';", - "var literal = 'xxxxxxxx xxxxxxxx';", - getGoogleJSStyleWithColumns(16)); - // The quotes should be correct. - for (char OriginalQuote : {'\'', '"'}) { - auto VerifyQuotes = [=](FormatStyle::JavaScriptQuoteStyle StyleQuote, - char TargetQuote) { - auto Style = getGoogleJSStyleWithColumns(17); - Style.JavaScriptQuotes = StyleQuote; - SmallString<48> Target{"var literal =\n" - " \"xxxxxxxx \" +\n" - " \"xxxxxxxx\";"}; - SmallString<34> Original{"var literal = \"xxxxxxxx xxxxxxxx\";"}; - std::replace(Target.begin(), Target.end(), '"', TargetQuote); - std::replace(Original.begin(), Original.end(), '"', OriginalQuote); - verifyFormat(Target, Original, Style); - }; - VerifyQuotes(FormatStyle::JSQS_Leave, OriginalQuote); - VerifyQuotes(FormatStyle::JSQS_Single, '\''); - VerifyQuotes(FormatStyle::JSQS_Double, '"'); - } - // Parentheses should be added when necessary. - verifyFormat("var literal =\n" - " ('xxxxxxxx ' +\n" - " 'xxxxxx')[0];", - "var literal = 'xxxxxxxx xxxxxx'[0];", - getGoogleJSStyleWithColumns(18)); - auto Style = getGoogleJSStyleWithColumns(20); - Style.SpacesInParens = FormatStyle::SIPO_Custom; - Style.SpacesInParensOptions.Other = true; - verifyFormat("var literal =\n" - " ( 'xxxxxxxx ' +\n" - " 'xxxxxx' )[0];", - "var literal = 'xxxxxxxx xxxxxx'[0];", Style); - // FIXME: When the part before the string literal is shorter than the - // continuation indentation, and the option AlignAfterOpenBracket is set to - // AlwaysBreak which is the default for the Google style, the unbroken string - // does not get to a new line while the broken string does due to the added - // parentheses. The formatter does not do it in one pass. - EXPECT_EQ( - "x = ('xxxxxxxx ' +\n" - " 'xxxxxx')[0];", - format("x = 'xxxxxxxx xxxxxx'[0];", getGoogleJSStyleWithColumns(18))); - verifyFormat("x =\n" - " ('xxxxxxxx ' +\n" - " 'xxxxxx')[0];", - getGoogleJSStyleWithColumns(18)); - // Breaking of template strings ans regular expressions is not implemented. - verifyFormat("var literal =\n" - " `xxxxxxxx xxxxxxxx`;", - getGoogleJSStyleWithColumns(18)); - verifyFormat("var literal =\n" - " /xxxxxxxx xxxxxxxx/;", - getGoogleJSStyleWithColumns(18)); - // There can be breaks in the code inside a template string. - verifyFormat("var literal = `xxxxxx ${\n" - " xxxxxxxxxx} xxxxxx`;", - "var literal = `xxxxxx ${xxxxxxxxxx} xxxxxx`;", - getGoogleJSStyleWithColumns(14)); - verifyFormat("var literal = `xxxxxx ${\n" - " xxxxxxxxxx} xxxxxx`;", - "var literal = `xxxxxx ${xxxxxxxxxx} xxxxxx`;", - getGoogleJSStyleWithColumns(15)); - // Identifiers inside the code inside a template string should not be broken - // even if the column limit is exceeded. This following behavior is not - // optimal. The part after the closing brace which exceeds the column limit - // can be put on a new line. Change this test when it is implemented. - verifyFormat("var literal = `xxxxxx ${\n" - " xxxxxxxxxxxxxxxxxxxxxx} xxxxxx`;", - "var literal = `xxxxxx ${xxxxxxxxxxxxxxxxxxxxxx} xxxxxx`;", - getGoogleJSStyleWithColumns(14)); - verifyFormat("var literal = `xxxxxx ${\n" - " xxxxxxxxxxxxxxxxxxxxxx +\n" - " xxxxxxxxxxxxxxxxxxxxxx} xxxxxx`;", - "var literal = `xxxxxx ${xxxxxxxxxxxxxxxxxxxxxx + " - "xxxxxxxxxxxxxxxxxxxxxx} xxxxxx`;", - getGoogleJSStyleWithColumns(14)); } TEST_F(FormatTestJS, RegexLiteralClassification) { diff --git a/clang/unittests/Format/FormatTestJava.cpp b/clang/unittests/Format/FormatTestJava.cpp index f3bf70ab40b37..51afe79859ec0 100644 --- a/clang/unittests/Format/FormatTestJava.cpp +++ b/clang/unittests/Format/FormatTestJava.cpp @@ -6,19 +6,34 @@ // //===----------------------------------------------------------------------===// -#include "FormatTestBase.h" +#include "FormatTestUtils.h" +#include "clang/Format/Format.h" +#include "llvm/Support/Debug.h" +#include "gtest/gtest.h" #define DEBUG_TYPE "format-test" namespace clang { namespace format { -namespace test { -namespace { -class FormatTestJava : public test::FormatTestBase { +class FormatTestJava : public ::testing::Test { protected: - FormatStyle getDefaultStyle() const override { - return getGoogleStyle(FormatStyle::LK_Java); + static std::string format(llvm::StringRef Code, unsigned Offset, + unsigned Length, const FormatStyle &Style) { + LLVM_DEBUG(llvm::errs() << "---\n"); + LLVM_DEBUG(llvm::errs() << Code << "\n\n"); + std::vector Ranges(1, tooling::Range(Offset, Length)); + tooling::Replacements Replaces = reformat(Style, Code, Ranges); + auto Result = applyAllReplacements(Code, Replaces); + EXPECT_TRUE(static_cast(Result)); + LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n"); + return *Result; + } + + static std::string + format(llvm::StringRef Code, + const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_Java)) { + return format(Code, 0, Code.size(), Style); } static FormatStyle getStyleWithColumns(unsigned ColumnLimit) { @@ -26,6 +41,13 @@ class FormatTestJava : public test::FormatTestBase { Style.ColumnLimit = ColumnLimit; return Style; } + + static void verifyFormat( + llvm::StringRef Code, + const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_Java)) { + EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable"; + EXPECT_EQ(Code.str(), format(test::messUp(Code), Style)); + } }; TEST_F(FormatTestJava, NoAlternativeOperatorNames) { @@ -543,9 +565,9 @@ TEST_F(FormatTestJava, FormatsLambdas) { } TEST_F(FormatTestJava, BreaksStringLiterals) { - verifyFormat("x = \"some text \"\n" - " + \"other\";", - "x = \"some text other\";", getStyleWithColumns(18)); + // FIXME: String literal breaking is currently disabled for Java and JS, as it + // requires strings to be merged using "+" which we don't support. + verifyFormat("\"some text other\";", getStyleWithColumns(14)); } TEST_F(FormatTestJava, AlignsBlockComments) { @@ -603,7 +625,5 @@ TEST_F(FormatTestJava, ShortFunctions) { Style); } -} // namespace -} // namespace test } // namespace format -} // namespace clang +} // end namespace clang diff --git a/clang/unittests/Format/FormatTestVerilog.cpp b/clang/unittests/Format/FormatTestVerilog.cpp index 9b090aa74f714..24a3ffc109269 100644 --- a/clang/unittests/Format/FormatTestVerilog.cpp +++ b/clang/unittests/Format/FormatTestVerilog.cpp @@ -1157,66 +1157,6 @@ TEST_F(FormatTestVerilog, Streaming) { verifyFormat("{<