diff options
Diffstat (limited to 'lib/Format/ContinuationIndenter.cpp')
-rw-r--r-- | lib/Format/ContinuationIndenter.cpp | 120 |
1 files changed, 79 insertions, 41 deletions
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index c369b94b99..b04ede6fa9 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -1,9 +1,8 @@ //===--- ContinuationIndenter.cpp - Format C++ code -----------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// @@ -404,8 +403,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { // FIXME: We should find a more generic solution to this problem. !(State.Column <= NewLineColumn && Style.Language == FormatStyle::LK_JavaScript) && - !(Previous.closesScopeAfterBlock() && - State.Column <= NewLineColumn)) + !(Previous.closesScopeAfterBlock() && State.Column <= NewLineColumn)) return true; // If the template declaration spans multiple lines, force wrap before the @@ -420,7 +418,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { if (Style.AlwaysBreakBeforeMultilineStrings && (NewLineColumn == State.FirstIndent + Style.ContinuationIndentWidth || Previous.is(tok::comma) || Current.NestingLevel < 2) && - !Previous.isOneOf(tok::kw_return, tok::lessless, tok::at) && + !Previous.isOneOf(tok::kw_return, tok::lessless, tok::at, + Keywords.kw_dollar) && !Previous.isOneOf(TT_InlineASMColon, TT_ConditionalExpr) && nextIsMultilineString(State)) return true; @@ -836,8 +835,8 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, // about removing empty lines on closing blocks. Special case them here. MaxEmptyLinesToKeep = 1; } - unsigned Newlines = std::max( - 1u, std::min(Current.NewlinesBefore, MaxEmptyLinesToKeep)); + unsigned Newlines = + std::max(1u, std::min(Current.NewlinesBefore, MaxEmptyLinesToKeep)); bool ContinuePPDirective = State.Line->InPPDirective && State.Line->Type != LT_ImportStatement; Whitespaces.replaceWhitespace(Current, Newlines, State.Column, State.Column, @@ -882,14 +881,30 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, State.Stack.back().BreakBeforeClosingBrace = true; if (State.Stack.back().AvoidBinPacking) { - // If we are breaking after '(', '{', '<', this is not bin packing - // unless AllowAllParametersOfDeclarationOnNextLine is false or this is a - // dict/object literal. - if (!Previous.isOneOf(tok::l_paren, tok::l_brace, TT_BinaryOperator) || + // If we are breaking after '(', '{', '<', or this is the break after a ':' + // to start a member initializater list in a constructor, this should not + // be considered bin packing unless the relevant AllowAll option is false or + // this is a dict/object literal. + bool PreviousIsBreakingCtorInitializerColon = + Previous.is(TT_CtorInitializerColon) && + Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon; + if (!(Previous.isOneOf(tok::l_paren, tok::l_brace, TT_BinaryOperator) || + PreviousIsBreakingCtorInitializerColon) || (!Style.AllowAllParametersOfDeclarationOnNextLine && State.Line->MustBeDeclaration) || + (!Style.AllowAllArgumentsOnNextLine && + !State.Line->MustBeDeclaration) || + (!Style.AllowAllConstructorInitializersOnNextLine && + PreviousIsBreakingCtorInitializerColon) || Previous.is(TT_DictLiteral)) State.Stack.back().BreakBeforeParameter = true; + + // If we are breaking after a ':' to start a member initializer list, + // and we allow all arguments on the next line, we should not break + // before the next parameter. + if (PreviousIsBreakingCtorInitializerColon && + Style.AllowAllConstructorInitializersOnNextLine) + State.Stack.back().BreakBeforeParameter = false; } return Penalty; @@ -930,18 +945,24 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { return State.Stack[State.Stack.size() - 2].LastSpace; return State.FirstIndent; } - // Indent a closing parenthesis at the previous level if followed by a semi or - // opening brace. This allows indentations such as: + // Indent a closing parenthesis at the previous level if followed by a semi, + // const, or opening brace. This allows indentations such as: // foo( // a, // ); + // int Foo::getter( + // // + // ) const { + // return foo; + // } // function foo( // a, // ) { // code(); // // } if (Current.is(tok::r_paren) && State.Stack.size() > 1 && - (!Current.Next || Current.Next->isOneOf(tok::semi, tok::l_brace))) + (!Current.Next || + Current.Next->isOneOf(tok::semi, tok::kw_const, tok::l_brace))) return State.Stack[State.Stack.size() - 2].LastSpace; if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope()) return State.Stack[State.Stack.size() - 2].LastSpace; @@ -1042,7 +1063,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { if (Current.is(TT_ProtoExtensionLSquare)) return State.Stack.back().Indent; if (State.Stack.back().Indent == State.FirstIndent && PreviousNonComment && - PreviousNonComment->isNot(tok::r_brace)) + !PreviousNonComment->isOneOf(tok::r_brace, TT_CtorInitializerComma)) // Ensure that we fall back to the continuation indent width instead of // just flushing continuations left. return State.Stack.back().Indent + Style.ContinuationIndentWidth; @@ -1103,9 +1124,13 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, ? 0 : 2); State.Stack.back().NestedBlockIndent = State.Stack.back().Indent; - if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) + if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) { State.Stack.back().AvoidBinPacking = true; - State.Stack.back().BreakBeforeParameter = false; + State.Stack.back().BreakBeforeParameter = + !Style.AllowAllConstructorInitializersOnNextLine; + } else { + State.Stack.back().BreakBeforeParameter = false; + } } if (Current.is(TT_CtorInitializerColon) && Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon) { @@ -1160,6 +1185,8 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, if (Current.is(TT_ObjCStringLiteral) && State.StartOfStringLiteral == 0) State.StartOfStringLiteral = State.Column + 1; + if (Current.is(TT_CSharpStringLiteral) && State.StartOfStringLiteral == 0) + State.StartOfStringLiteral = State.Column + 1; else if (Current.isStringLiteral() && State.StartOfStringLiteral == 0) State.StartOfStringLiteral = State.Column; else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash) && @@ -1170,7 +1197,7 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, State.NextToken = State.NextToken->Next; unsigned Penalty = - handleEndOfLine(Current, State, DryRun, AllowBreak); + handleEndOfLine(Current, State, DryRun, AllowBreak, Newline); if (Current.Role) Current.Role->formatFromToken(State, this, DryRun); @@ -1464,7 +1491,7 @@ static unsigned getLastLineEndColumn(StringRef Text, unsigned StartColumn, unsigned ContinuationIndenter::reformatRawStringLiteral( const FormatToken &Current, LineState &State, - const FormatStyle &RawStringStyle, bool DryRun) { + const FormatStyle &RawStringStyle, bool DryRun, bool Newline) { unsigned StartColumn = State.Column - Current.ColumnWidth; StringRef OldDelimiter = *getRawStringDelimiter(Current.TokenText); StringRef NewDelimiter = @@ -1504,8 +1531,10 @@ unsigned ContinuationIndenter::reformatRawStringLiteral( // source. bool ContentStartsOnNewline = Current.TokenText[OldPrefixSize] == '\n'; // If this token is the last parameter (checked by looking if it's followed by - // `)`, the base the indent off the line's nested block indent. Otherwise, - // base the indent off the arguments indent, so we can achieve: + // `)` and is not on a newline, the base the indent off the line's nested + // block indent. Otherwise, base the indent off the arguments indent, so we + // can achieve: + // // fffffffffff(1, 2, 3, R"pb( // key1: 1 # // key2: 2)pb"); @@ -1514,11 +1543,18 @@ unsigned ContinuationIndenter::reformatRawStringLiteral( // R"pb( // key1: 1 # // key2: 2 + // )pb"); + // + // fffffffffff(1, 2, 3, + // R"pb( + // key1: 1 # + // key2: 2 // )pb", // 5); - unsigned CurrentIndent = (Current.Next && Current.Next->is(tok::r_paren)) - ? State.Stack.back().NestedBlockIndent - : State.Stack.back().Indent; + unsigned CurrentIndent = + (!Newline && Current.Next && Current.Next->is(tok::r_paren)) + ? State.Stack.back().NestedBlockIndent + : State.Stack.back().Indent; unsigned NextStartColumn = ContentStartsOnNewline ? CurrentIndent + Style.IndentWidth : FirstStartColumn; @@ -1531,9 +1567,8 @@ unsigned ContinuationIndenter::reformatRawStringLiteral( // that raw string prefix starts, and // - if the raw string prefix does not start on a newline, it is the current // indent. - unsigned LastStartColumn = Current.NewlinesBefore - ? FirstStartColumn - NewPrefixSize - : CurrentIndent; + unsigned LastStartColumn = + Current.NewlinesBefore ? FirstStartColumn - NewPrefixSize : CurrentIndent; std::pair<tooling::Replacements, unsigned> Fixes = internal::reformat( RawStringStyle, RawText, {tooling::Range(0, RawText.size())}, @@ -1590,8 +1625,9 @@ unsigned ContinuationIndenter::reformatRawStringLiteral( // have to manually add the penalty for the prefix R"delim( over the column // limit. unsigned PrefixExcessCharacters = - StartColumn + NewPrefixSize > Style.ColumnLimit ? - StartColumn + NewPrefixSize - Style.ColumnLimit : 0; + StartColumn + NewPrefixSize > Style.ColumnLimit + ? StartColumn + NewPrefixSize - Style.ColumnLimit + : 0; bool IsMultiline = ContentStartsOnNewline || (NewCode->find('\n') != std::string::npos); if (IsMultiline) { @@ -1620,13 +1656,14 @@ unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current, unsigned ContinuationIndenter::handleEndOfLine(const FormatToken &Current, LineState &State, bool DryRun, - bool AllowBreak) { + bool AllowBreak, bool Newline) { unsigned Penalty = 0; // Compute the raw string style to use in case this is a raw string literal // that can be reformatted. auto RawStringStyle = getRawStringStyle(Current, State); if (RawStringStyle && !Current.Finalized) { - Penalty = reformatRawStringLiteral(Current, State, *RawStringStyle, DryRun); + Penalty = reformatRawStringLiteral(Current, State, *RawStringStyle, DryRun, + Newline); } else if (Current.IsMultiline && Current.isNot(TT_BlockComment)) { // Don't break multi-line tokens other than block comments and raw string // literals. Instead, just update the state. @@ -1709,16 +1746,17 @@ ContinuationIndenter::getRawStringStyle(const FormatToken &Current, return RawStringStyle; } -std::unique_ptr<BreakableToken> ContinuationIndenter::createBreakableToken( - const FormatToken &Current, LineState &State, bool AllowBreak) { +std::unique_ptr<BreakableToken> +ContinuationIndenter::createBreakableToken(const FormatToken &Current, + LineState &State, bool AllowBreak) { unsigned StartColumn = State.Column - Current.ColumnWidth; if (Current.isStringLiteral()) { - // FIXME: String literal breaking is currently disabled for Java and JS, as - // it requires strings to be merged using "+" which we don't support. + // FIXME: String literal breaking is currently disabled for C#,Java and + // JavaScript, as it requires strings to be merged using "+" which we + // don't support. if (Style.Language == FormatStyle::LK_Java || - Style.Language == FormatStyle::LK_JavaScript || - !Style.BreakStringLiterals || - !AllowBreak) + Style.Language == FormatStyle::LK_JavaScript || Style.isCSharp() || + !Style.BreakStringLiterals || !AllowBreak) return nullptr; // Don't break string literals inside preprocessor directives (except for @@ -1772,7 +1810,7 @@ std::unique_ptr<BreakableToken> ContinuationIndenter::createBreakableToken( } return llvm::make_unique<BreakableBlockComment>( Current, StartColumn, Current.OriginalColumn, !Current.Previous, - State.Line->InPPDirective, Encoding, Style); + State.Line->InPPDirective, Encoding, Style, Whitespaces.useCRLF()); } else if (Current.is(TT_LineComment) && (Current.Previous == nullptr || Current.Previous->isNot(TT_ImplicitStringLiteral))) { |