diff options
Diffstat (limited to 'lib/Format/ContinuationIndenter.cpp')
| -rw-r--r-- | lib/Format/ContinuationIndenter.cpp | 184 | 
1 files changed, 123 insertions, 61 deletions
| diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index 4cc92b02a9e5..4e8f5af263d2 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -143,11 +143,10 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {    if (Previous.is(tok::semi) && State.LineContainsContinuedForLoopSection)      return true;    if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) || -       (Style.BreakBeforeTernaryOperators && -        (Current.is(tok::question) || -         (Current.is(TT_ConditionalExpr) && Previous.isNot(tok::question)))) || +       (Style.BreakBeforeTernaryOperators && Current.is(TT_ConditionalExpr) && +        Previous.isNot(tok::question)) ||         (!Style.BreakBeforeTernaryOperators && -        (Previous.is(tok::question) || Previous.is(TT_ConditionalExpr)))) && +        Previous.is(TT_ConditionalExpr))) &&        State.Stack.back().BreakBeforeParameter && !Current.isTrailingComment() &&        !Current.isOneOf(tok::r_paren, tok::r_brace))      return true; @@ -166,10 +165,17 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {        ((Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All) ||         Style.BreakConstructorInitializersBeforeComma || Style.ColumnLimit != 0))      return true; +  if (Current.is(TT_SelectorName) && State.Stack.back().ObjCSelectorNameFound && +      State.Stack.back().BreakBeforeParameter) +    return true;    if (State.Column < getNewLineColumn(State))      return false; -  if (Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None) { + +  // Using CanBreakBefore here and below takes care of the decision whether the +  // current style uses wrapping before or after operators for the given +  // operator. +  if (Previous.is(TT_BinaryOperator) && Current.CanBreakBefore) {      // If we need to break somewhere inside the LHS of a binary expression, we      // should also break after the operator. Otherwise, the formatting would      // hide the operator precedence, e.g. in: @@ -185,16 +191,13 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {                          Previous.Previous->isNot(TT_BinaryOperator); // For >>.      bool LHSIsBinaryExpr =          Previous.Previous && Previous.Previous->EndsBinaryExpression; -    if (Previous.is(TT_BinaryOperator) && (!IsComparison || LHSIsBinaryExpr) && -        Current.isNot(TT_BinaryOperator) && // For >>. -        !Current.isTrailingComment() && !Previous.is(tok::lessless) && +    if ((!IsComparison || LHSIsBinaryExpr) && !Current.isTrailingComment() &&          Previous.getPrecedence() != prec::Assignment &&          State.Stack.back().BreakBeforeParameter)        return true; -  } else { -    if (Current.is(TT_BinaryOperator) && Previous.EndsBinaryExpression && -        State.Stack.back().BreakBeforeParameter) -      return true; +  } else if (Current.is(TT_BinaryOperator) && Current.CanBreakBefore && +             State.Stack.back().BreakBeforeParameter) { +    return true;    }    // Same as above, but for the first "<<" operator. @@ -203,12 +206,14 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {        State.Stack.back().FirstLessLess == 0)      return true; -  if (Current.is(TT_SelectorName) && State.Stack.back().ObjCSelectorNameFound && -      State.Stack.back().BreakBeforeParameter) -    return true;    if (Current.NestingLevel == 0 && !Current.isTrailingComment()) { +    // Always break after "template <...>" and leading annotations. This is only +    // for cases where the entire line does not fit on a single line as a +    // different LineFormatter would be used otherwise.      if (Previous.ClosesTemplateDeclaration)        return true; +    if (Previous.is(TT_FunctionAnnotationRParen)) +      return true;      if (Previous.is(TT_LeadingJavaAnnotation) && Current.isNot(tok::l_paren) &&          Current.isNot(TT_LeadingJavaAnnotation))        return true; @@ -221,8 +226,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {    if (startsSegmentOfBuilderTypeCall(Current) &&        (State.Stack.back().CallContinuation != 0 || -       (State.Stack.back().BreakBeforeParameter && -        State.Stack.back().ContainsUnwrappedBuilder))) +       State.Stack.back().BreakBeforeParameter))      return true;    // The following could be precomputed as they do not depend on the state. @@ -232,6 +236,10 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {        Previous.is(tok::l_brace) && !Current.isOneOf(tok::r_brace, tok::comment))      return true; +  if (Current.is(tok::lessless) && Previous.is(tok::identifier) && +      Previous.TokenText == "endl") +    return true; +    return false;  } @@ -245,12 +253,18 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline,         (Current.Previous->Tok.getIdentifierInfo() == nullptr ||          Current.Previous->Tok.getIdentifierInfo()->getPPKeywordID() ==              tok::pp_not_keyword))) { -    // FIXME: Is this correct? -    int WhitespaceLength = SourceMgr.getSpellingColumnNumber( -                               State.NextToken->WhitespaceRange.getEnd()) - -                           SourceMgr.getSpellingColumnNumber( -                               State.NextToken->WhitespaceRange.getBegin()); -    State.Column += WhitespaceLength; +    unsigned EndColumn = +        SourceMgr.getSpellingColumnNumber(Current.WhitespaceRange.getEnd()); +    if (Current.LastNewlineOffset != 0) { +      // If there is a newline within this token, the final column will solely +      // determined by the current end column. +      State.Column = EndColumn; +    } else { +      unsigned StartColumn = +          SourceMgr.getSpellingColumnNumber(Current.WhitespaceRange.getBegin()); +      assert(EndColumn >= StartColumn); +      State.Column += EndColumn - StartColumn; +    }      moveStateToNextToken(State, DryRun, /*Newline=*/false);      return 0;    } @@ -297,7 +311,9 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,      else if (State.Stack.back().Indent + Current.LongestObjCSelectorName >               State.Column + Spaces + Current.ColumnWidth)        State.Stack.back().ColonPos = -          State.Stack.back().Indent + Current.LongestObjCSelectorName; +          std::max(State.FirstIndent + Style.ContinuationIndentWidth, +                   State.Stack.back().Indent) + +          Current.LongestObjCSelectorName;      else        State.Stack.back().ColonPos = State.Column + Spaces + Current.ColumnWidth;    } @@ -308,9 +324,12 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,      State.Stack.back().Indent = State.Column + Spaces;    if (State.Stack.back().AvoidBinPacking && startsNextParameter(Current, Style))      State.Stack.back().NoLineBreak = true; -  if (startsSegmentOfBuilderTypeCall(Current)) +  if (startsSegmentOfBuilderTypeCall(Current) && +      State.Column > getNewLineColumn(State))      State.Stack.back().ContainsUnwrappedBuilder = true; +  if (Current.is(TT_LambdaArrow)) +    State.Stack.back().NoLineBreak = true;    if (Current.isMemberAccess() && Previous.is(tok::r_paren) &&        (Previous.MatchingParen &&         (Previous.TotalLength - Previous.MatchingParen->TotalLength > 10))) { @@ -359,7 +378,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,        const FormatToken *Next = Previous.MatchingParen->getNextNonComment();        HasTrailingCall = Next && Next->isMemberAccess();      } -    if (HasTrailingCall && +    if (HasTrailingCall && State.Stack.size() > 1 &&          State.Stack[State.Stack.size() - 2].CallContinuation == 0)        State.Stack.back().LastSpace = State.Column;    } @@ -406,7 +425,11 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,          State.Stack.back().AlignColons = false;        } else {          State.Stack.back().ColonPos = -            State.Stack.back().Indent + NextNonComment->LongestObjCSelectorName; +            (Style.IndentWrappedFunctionNames +                 ? std::max(State.Stack.back().Indent, +                            State.FirstIndent + Style.ContinuationIndentWidth) +                 : State.Stack.back().Indent) + +            NextNonComment->LongestObjCSelectorName;        }      } else if (State.Stack.back().AlignColons &&                 State.Stack.back().ColonPos <= NextNonComment->ColumnWidth) { @@ -468,8 +491,9 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,        !PreviousNonComment->isOneOf(tok::comma, tok::semi) &&        (PreviousNonComment->isNot(TT_TemplateCloser) ||         Current.NestingLevel != 0) && -      !PreviousNonComment->isOneOf(TT_BinaryOperator, TT_JavaAnnotation, -                                   TT_LeadingJavaAnnotation) && +      !PreviousNonComment->isOneOf( +          TT_BinaryOperator, TT_FunctionAnnotationRParen, TT_JavaAnnotation, +          TT_LeadingJavaAnnotation) &&        Current.isNot(TT_BinaryOperator) && !PreviousNonComment->opensScope())      State.Stack.back().BreakBeforeParameter = true; @@ -516,7 +540,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {    if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block)      return Current.NestingLevel == 0 ? State.FirstIndent                                       : State.Stack.back().Indent; -  if (Current.isOneOf(tok::r_brace, tok::r_square)) { +  if (Current.isOneOf(tok::r_brace, tok::r_square) && State.Stack.size() > 1) {      if (Current.closesBlockTypeList(Style))        return State.Stack[State.Stack.size() - 2].NestedBlockIndent;      if (Current.MatchingParen && @@ -529,6 +553,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {      return State.Stack.back().Indent;    if (NextNonComment->isStringLiteral() && State.StartOfStringLiteral != 0)      return State.StartOfStringLiteral; +  if (NextNonComment->is(TT_ObjCStringLiteral) && +      State.StartOfStringLiteral != 0) +    return State.StartOfStringLiteral - 1;    if (NextNonComment->is(tok::lessless) &&        State.Stack.back().FirstLessLess != 0)      return State.Stack.back().FirstLessLess; @@ -546,8 +573,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {      return State.Stack.back().VariablePos;    if ((PreviousNonComment &&         (PreviousNonComment->ClosesTemplateDeclaration || -        PreviousNonComment->isOneOf(TT_AttributeParen, TT_JavaAnnotation, -                                    TT_LeadingJavaAnnotation))) || +        PreviousNonComment->isOneOf( +            TT_AttributeParen, TT_FunctionAnnotationRParen, TT_JavaAnnotation, +            TT_LeadingJavaAnnotation))) ||        (!Style.IndentWrappedFunctionNames &&         NextNonComment->isOneOf(tok::kw_operator, TT_FunctionDeclarationName)))      return std::max(State.Stack.back().LastSpace, State.Stack.back().Indent); @@ -555,7 +583,10 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {      if (!State.Stack.back().ObjCSelectorNameFound) {        if (NextNonComment->LongestObjCSelectorName == 0)          return State.Stack.back().Indent; -      return State.Stack.back().Indent + +      return (Style.IndentWrappedFunctionNames +                  ? std::max(State.Stack.back().Indent, +                             State.FirstIndent + Style.ContinuationIndentWidth) +                  : State.Stack.back().Indent) +               NextNonComment->LongestObjCSelectorName -               NextNonComment->ColumnWidth;      } @@ -570,10 +601,16 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {        return State.Stack.back().StartOfArraySubscripts;      return ContinuationIndent;    } -  if (NextNonComment->is(TT_StartOfName) || -      Previous.isOneOf(tok::coloncolon, tok::equal)) { + +  // This ensure that we correctly format ObjC methods calls without inputs, +  // i.e. where the last element isn't selector like: [callee method]; +  if (NextNonComment->is(tok::identifier) && NextNonComment->FakeRParens == 0 && +      NextNonComment->Next && NextNonComment->Next->is(TT_ObjCMethodExpr)) +    return State.Stack.back().Indent; + +  if (NextNonComment->isOneOf(TT_StartOfName, TT_PointerOrReference) || +      Previous.isOneOf(tok::coloncolon, tok::equal))      return ContinuationIndent; -  }    if (PreviousNonComment && PreviousNonComment->is(tok::colon) &&        PreviousNonComment->isOneOf(TT_ObjCMethodExpr, TT_DictLiteral))      return ContinuationIndent; @@ -621,7 +658,7 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,          std::min(State.LowestLevelOnLine, Current.NestingLevel);    if (Current.isMemberAccess())      State.Stack.back().StartOfFunctionCall = -        Current.LastOperator ? 0 : State.Column + Current.ColumnWidth; +        Current.LastOperator ? 0 : State.Column;    if (Current.is(TT_SelectorName))      State.Stack.back().ObjCSelectorNameFound = true;    if (Current.is(TT_CtorInitializerColon)) { @@ -637,12 +674,9 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,        State.Stack.back().AvoidBinPacking = true;      State.Stack.back().BreakBeforeParameter = false;    } - -  // In ObjC method declaration we align on the ":" of parameters, but we need -  // to ensure that we indent parameters on subsequent lines by at least our -  // continuation indent width. -  if (Current.is(TT_ObjCMethodSpecifier)) -    State.Stack.back().Indent += Style.ContinuationIndentWidth; +  if (Current.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) && Newline) +    State.Stack.back().NestedBlockIndent = +        State.Column + Current.ColumnWidth + 1;    // Insert scopes created by fake parenthesis.    const FormatToken *Previous = Current.getPreviousNonComment(); @@ -675,12 +709,13 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,    moveStatePastScopeCloser(State);    moveStatePastFakeRParens(State); -  if (Current.isStringLiteral() && State.StartOfStringLiteral == 0) { +  if (Current.isStringLiteral() && State.StartOfStringLiteral == 0)      State.StartOfStringLiteral = State.Column; -  } else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash) && -             !Current.isStringLiteral()) { +  if (Current.is(TT_ObjCStringLiteral) && State.StartOfStringLiteral == 0) +    State.StartOfStringLiteral = State.Column + 1; +  else if (!Current.isOneOf(tok::comment, tok::identifier, tok::hash) && +             !Current.isStringLiteral())      State.StartOfStringLiteral = 0; -  }    State.Column += Current.ColumnWidth;    State.NextToken = State.NextToken->Next; @@ -712,7 +747,8 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,    // 'return', assignments or opening <({[. The indentation for these cases    // is special cased.    bool SkipFirstExtraIndent = -      (Previous && (Previous->opensScope() || Previous->is(tok::kw_return) || +      (Previous && (Previous->opensScope() || +                    Previous->isOneOf(tok::semi, tok::kw_return) ||                      (Previous->getPrecedence() == prec::Assignment &&                       Style.AlignOperands) ||                      Previous->is(TT_ObjCMethodExpr))); @@ -783,7 +819,6 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,  void ContinuationIndenter::moveStatePastFakeRParens(LineState &State) {    for (unsigned i = 0, e = State.NextToken->FakeRParens; i != e; ++i) {      unsigned VariablePos = State.Stack.back().VariablePos; -    assert(State.Stack.size() > 1);      if (State.Stack.size() == 1) {        // Do not pop the last element.        break; @@ -806,6 +841,7 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,    unsigned NewIndent;    unsigned NewIndentLevel = State.Stack.back().IndentLevel; +  unsigned LastSpace = State.Stack.back().LastSpace;    bool AvoidBinPacking;    bool BreakBeforeParameter = false;    if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)) { @@ -815,17 +851,28 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,        ++NewIndentLevel;      } else {        NewIndent = State.Stack.back().LastSpace + Style.ContinuationIndentWidth; -      NewIndent = std::min(State.Column + 1, NewIndent);      }      const FormatToken *NextNoComment = Current.getNextNonComment();      AvoidBinPacking =          Current.isOneOf(TT_ArrayInitializerLSquare, TT_DictLiteral) || -        Style.Language == FormatStyle::LK_Proto || !Style.BinPackParameters || +        Style.Language == FormatStyle::LK_Proto || !Style.BinPackArguments ||          (NextNoComment && NextNoComment->is(TT_DesignatedInitializerPeriod));    } else {      NewIndent = Style.ContinuationIndentWidth +                  std::max(State.Stack.back().LastSpace,                           State.Stack.back().StartOfFunctionCall); + +    // Ensure that different different brackets force relative alignment, e.g.: +    // void SomeFunction(vector<  // break +    //                       int> v); +    // FIXME: We likely want to do this for more combinations of brackets. +    // Verify that it is wanted for ObjC, too. +    if (Current.Tok.getKind() == tok::less && +        Current.ParentBracket == tok::l_paren) { +      NewIndent = std::max(NewIndent, State.Stack.back().Indent); +      LastSpace = std::max(LastSpace, State.Stack.back().Indent); +    } +      AvoidBinPacking =          (State.Line->MustBeDeclaration && !Style.BinPackParameters) ||          (!State.Line->MustBeDeclaration && !Style.BinPackArguments) || @@ -833,19 +880,33 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,           (Current.PackingKind == PPK_OnePerLine ||            (!BinPackInconclusiveFunctions &&             Current.PackingKind == PPK_Inconclusive))); -    // If this '[' opens an ObjC call, determine whether all parameters fit -    // into one line and put one per line if they don't. -    if (Current.is(TT_ObjCMethodExpr) && Style.ColumnLimit != 0 && -        getLengthToMatchingParen(Current) + State.Column > +    if (Current.is(TT_ObjCMethodExpr) && Current.MatchingParen) { +      if (Style.ColumnLimit) { +        // If this '[' opens an ObjC call, determine whether all parameters fit +        // into one line and put one per line if they don't. +        if (getLengthToMatchingParen(Current) + State.Column >              getColumnLimit(State)) -      BreakBeforeParameter = true; +          BreakBeforeParameter = true; +      } else { +        // For ColumnLimit = 0, we have to figure out whether there is or has to +        // be a line break within this call. +        for (const FormatToken *Tok = &Current; +             Tok && Tok != Current.MatchingParen; Tok = Tok->Next) { +          if (Tok->MustBreakBefore ||  +              (Tok->CanBreakBefore && Tok->NewlinesBefore > 0)) { +            BreakBeforeParameter = true; +            break; +          } +        } +      } +    }    }    bool NoLineBreak = State.Stack.back().NoLineBreak ||                       (Current.is(TT_TemplateOpener) &&                        State.Stack.back().ContainsUnwrappedBuilder); -  unsigned NestedBlockIndent = State.Stack.back().NestedBlockIndent; -  State.Stack.push_back(ParenState(NewIndent, NewIndentLevel, -                                   State.Stack.back().LastSpace, +  unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall, +                                        State.Stack.back().NestedBlockIndent); +  State.Stack.push_back(ParenState(NewIndent, NewIndentLevel, LastSpace,                                     AvoidBinPacking, NoLineBreak));    State.Stack.back().NestedBlockIndent = NestedBlockIndent;    State.Stack.back().BreakBeforeParameter = BreakBeforeParameter; @@ -1082,8 +1143,9 @@ bool ContinuationIndenter::nextIsMultilineString(const LineState &State) {    if (Current.getNextNonComment() &&        Current.getNextNonComment()->isStringLiteral())      return true; // Implicit concatenation. -  if (State.Column + Current.ColumnWidth + Current.UnbreakableTailLength > -      Style.ColumnLimit) +  if (Style.ColumnLimit != 0 && +      State.Column + Current.ColumnWidth + Current.UnbreakableTailLength > +          Style.ColumnLimit)      return true; // String will be split.    return false;  } | 
