diff options
Diffstat (limited to 'clang/lib/Format')
| -rw-r--r-- | clang/lib/Format/ContinuationIndenter.cpp | 121 | ||||
| -rw-r--r-- | clang/lib/Format/ContinuationIndenter.h | 51 | ||||
| -rw-r--r-- | clang/lib/Format/Format.cpp | 33 | ||||
| -rw-r--r-- | clang/lib/Format/FormatToken.h | 182 | ||||
| -rw-r--r-- | clang/lib/Format/FormatTokenLexer.cpp | 15 | ||||
| -rw-r--r-- | clang/lib/Format/IntegerLiteralSeparatorFixer.cpp | 35 | ||||
| -rw-r--r-- | clang/lib/Format/QualifierAlignmentFixer.cpp | 17 | ||||
| -rw-r--r-- | clang/lib/Format/TokenAnnotator.cpp | 38 | ||||
| -rw-r--r-- | clang/lib/Format/UnwrappedLineFormatter.cpp | 14 | ||||
| -rw-r--r-- | clang/lib/Format/UnwrappedLineParser.cpp | 145 | ||||
| -rw-r--r-- | clang/lib/Format/UnwrappedLineParser.h | 6 | ||||
| -rw-r--r-- | clang/lib/Format/WhitespaceManager.cpp | 81 | ||||
| -rw-r--r-- | clang/lib/Format/WhitespaceManager.h | 25 |
13 files changed, 531 insertions, 232 deletions
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 9ab024a..1272bb7 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -240,6 +240,45 @@ RawStringFormatStyleManager::getEnclosingFunctionStyle( return It->second; } +IndentationAndAlignment +IndentationAndAlignment::addPadding(unsigned Spaces) const { + return IndentationAndAlignment(Total + Spaces, IndentedFrom); +} + +IndentationAndAlignment +IndentationAndAlignment::operator+(unsigned Spaces) const { + return IndentationAndAlignment(Total + Spaces, Total); +} + +IndentationAndAlignment +IndentationAndAlignment::operator-(unsigned Spaces) const { + return IndentationAndAlignment(Total - Spaces, Total); +} + +IndentationAndAlignment &IndentationAndAlignment::operator+=(unsigned Spaces) { + *this = *this + Spaces; + return *this; +} + +IndentationAndAlignment::IndentationAndAlignment(unsigned Total, + unsigned IndentedFrom) + : Total(Total), IndentedFrom(IndentedFrom) {} + +IndentationAndAlignment::IndentationAndAlignment(unsigned Spaces) + : Total(Spaces), IndentedFrom(Spaces) {} + +bool IndentationAndAlignment::operator<( + const IndentationAndAlignment &Other) const { + if (Total != Other.Total) + return Total < Other.Total; + // The sign to use here was decided arbitrarily. This operator is mostly used + // when a line's indentation should be the max of 2 things. Using this sign + // here makes the program prefer alignment over continuation indentation. That + // is, it makes the alignment step that follows prefer to move the line when + // aligning the previous line. + return IndentedFrom > Other.IndentedFrom; +} + ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style, const AdditionalKeywords &Keywords, const SourceManager &SourceMgr, @@ -491,7 +530,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { return true; } - unsigned NewLineColumn = getNewLineColumn(State); + unsigned NewLineColumn = getNewLineColumn(State).Total; if (Current.isMemberAccess() && Style.ColumnLimit != 0 && State.Column + getLengthToNextOperator(Current) > Style.ColumnLimit && (State.Column > NewLineColumn || @@ -819,8 +858,9 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, } if (Current.is(TT_SelectorName) && !CurrentState.ObjCSelectorNameFound) { - unsigned MinIndent = std::max( - State.FirstIndent + Style.ContinuationIndentWidth, CurrentState.Indent); + unsigned MinIndent = + std::max(State.FirstIndent + Style.ContinuationIndentWidth, + CurrentState.Indent.Total); unsigned FirstColonPos = State.Column + Spaces + Current.ColumnWidth; if (Current.LongestObjCSelectorName == 0) CurrentState.AlignColons = false; @@ -910,7 +950,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, return !Next || Next->isMemberAccess() || Next->is(TT_FunctionDeclarationLParen) || IsFunctionCallParen(*Next); }; - if (IsOpeningBracket(Previous) && State.Column > getNewLineColumn(State) && + if (IsOpeningBracket(Previous) && + State.Column > getNewLineColumn(State).Total && // Don't do this for simple (no expressions) one-argument function calls // as that feels like needlessly wasting whitespace, e.g.: // @@ -955,7 +996,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, CurrentState.NoLineBreak = true; if (startsSegmentOfBuilderTypeCall(Current) && - State.Column > getNewLineColumn(State)) { + State.Column > getNewLineColumn(State).Total) { CurrentState.ContainsUnwrappedBuilder = true; } @@ -1086,7 +1127,8 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, Penalty += Style.PenaltyBreakFirstLessLess; } - State.Column = getNewLineColumn(State); + const auto [TotalColumn, IndentedFromColumn] = getNewLineColumn(State); + State.Column = TotalColumn; // Add Penalty proportional to amount of whitespace away from FirstColumn // This tends to penalize several lines that are far-right indented, @@ -1132,9 +1174,9 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, } else { CurrentState.ColonPos = (shouldIndentWrappedSelectorName(Style, State.Line->Type) - ? std::max(CurrentState.Indent, + ? std::max(CurrentState.Indent.Total, State.FirstIndent + Style.ContinuationIndentWidth) - : CurrentState.Indent) + + : CurrentState.Indent.Total) + std::max(NextNonComment->LongestObjCSelectorName, NextNonComment->ColumnWidth); } @@ -1155,7 +1197,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, // when we consume all of the "}"'s FakeRParens at the "{". if (State.Stack.size() > 1) { State.Stack[State.Stack.size() - 2].LastSpace = - std::max(CurrentState.LastSpace, CurrentState.Indent) + + std::max(CurrentState.LastSpace, CurrentState.Indent.Total) + Style.ContinuationIndentWidth; } } @@ -1196,7 +1238,8 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, State.Line->Type != LT_ImportStatement && Current.isNot(TT_LineComment); Whitespaces.replaceWhitespace(Current, Newlines, State.Column, State.Column, - CurrentState.IsAligned, ContinuePPDirective); + CurrentState.IsAligned, ContinuePPDirective, + IndentedFromColumn); } if (!Current.isTrailingComment()) @@ -1340,7 +1383,8 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, return Penalty; } -unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { +IndentationAndAlignment +ContinuationIndenter::getNewLineColumn(const LineState &State) { if (!State.NextToken || !State.NextToken->Previous) return 0; @@ -1354,8 +1398,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { const FormatToken &Previous = *Current.Previous; // If we are continuing an expression, we want to use the continuation indent. - unsigned ContinuationIndent = - std::max(CurrentState.LastSpace, CurrentState.Indent) + + const auto ContinuationIndent = + std::max(IndentationAndAlignment(CurrentState.LastSpace), + CurrentState.Indent) + Style.ContinuationIndentWidth; const FormatToken *PreviousNonComment = Current.getPreviousNonComment(); const FormatToken *NextNonComment = Previous.getNextNonComment(); @@ -1365,7 +1410,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { // Java specific bits. if (Style.isJava() && Current.isOneOf(Keywords.kw_implements, Keywords.kw_extends)) { - return std::max(CurrentState.LastSpace, + return std::max(IndentationAndAlignment(CurrentState.LastSpace), CurrentState.Indent + Style.ContinuationIndentWidth); } @@ -1378,7 +1423,8 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths && State.Line->First->is(tok::kw_enum)) { - return (Style.IndentWidth * State.Line->First->IndentLevel) + + return IndentationAndAlignment(Style.IndentWidth * + State.Line->First->IndentLevel) + Style.IndentWidth; } @@ -1497,7 +1543,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { // * not remove the 'lead' ContinuationIndentWidth // * always un-indent by the operator when // BreakBeforeTernaryOperators=true - unsigned Indent = CurrentState.Indent; + unsigned Indent = CurrentState.Indent.Total; if (Style.AlignOperands != FormatStyle::OAS_DontAlign) Indent -= Style.ContinuationIndentWidth; if (Style.BreakBeforeTernaryOperators && CurrentState.UnindentOperator) @@ -1537,14 +1583,16 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { TT_LeadingJavaAnnotation))) || (!Style.IndentWrappedFunctionNames && NextNonComment->isOneOf(tok::kw_operator, TT_FunctionDeclarationName))) { - return std::max(CurrentState.LastSpace, CurrentState.Indent); + return std::max(IndentationAndAlignment(CurrentState.LastSpace), + CurrentState.Indent); } if (NextNonComment->is(TT_SelectorName)) { if (!CurrentState.ObjCSelectorNameFound) { - unsigned MinIndent = CurrentState.Indent; + auto MinIndent = CurrentState.Indent; if (shouldIndentWrappedSelectorName(Style, State.Line->Type)) { - MinIndent = std::max(MinIndent, - State.FirstIndent + Style.ContinuationIndentWidth); + MinIndent = + std::max(MinIndent, IndentationAndAlignment(State.FirstIndent) + + Style.ContinuationIndentWidth); } // If LongestObjCSelectorName is 0, we are indenting the first // part of an ObjC selector (or a selector component which is @@ -1555,10 +1603,10 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { // component of the ObjC selector. // // In either case, we want to respect Style.IndentWrappedFunctionNames. - return MinIndent + - std::max(NextNonComment->LongestObjCSelectorName, - NextNonComment->ColumnWidth) - - NextNonComment->ColumnWidth; + return MinIndent.addPadding( + std::max(NextNonComment->LongestObjCSelectorName, + NextNonComment->ColumnWidth) - + NextNonComment->ColumnWidth); } if (!CurrentState.AlignColons) return CurrentState.Indent; @@ -1628,7 +1676,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { return CurrentState.Indent - NextNonComment->Tok.getLength() - NextNonComment->SpacesRequiredBefore; } - if (CurrentState.Indent == State.FirstIndent && PreviousNonComment && + if (CurrentState.Indent.Total == State.FirstIndent && PreviousNonComment && PreviousNonComment->isNoneOf(tok::r_brace, TT_CtorInitializerComma)) { // Ensure that we fall back to the continuation indent width instead of // just flushing continuations left. @@ -1718,7 +1766,7 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, FormatStyle::BCIS_BeforeComma ? 0 : 2); - CurrentState.NestedBlockIndent = CurrentState.Indent; + CurrentState.NestedBlockIndent = CurrentState.Indent.Total; if (Style.PackConstructorInitializers > FormatStyle::PCIS_BinPack) { CurrentState.AvoidBinPacking = true; CurrentState.BreakBeforeParameter = @@ -1733,7 +1781,7 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon) { CurrentState.Indent = State.FirstIndent + Style.ConstructorInitializerIndentWidth; - CurrentState.NestedBlockIndent = CurrentState.Indent; + CurrentState.NestedBlockIndent = CurrentState.Indent.Total; if (Style.PackConstructorInitializers > FormatStyle::PCIS_BinPack) CurrentState.AvoidBinPacking = true; else @@ -1877,8 +1925,9 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State, (!Style.isTableGen() || (Previous && Previous->isOneOf(TT_TableGenDAGArgListComma, TT_TableGenDAGArgListCommaToBreak)))) { - NewParenState.Indent = std::max( - std::max(State.Column, NewParenState.Indent), CurrentState.LastSpace); + NewParenState.Indent = + std::max({IndentationAndAlignment(State.Column), NewParenState.Indent, + IndentationAndAlignment(CurrentState.LastSpace)}); } // Special case for generic selection expressions, its comma-separated @@ -1986,7 +2035,7 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, return Prev->is(tok::comma); }(Current.MatchingParen); - unsigned NewIndent; + IndentationAndAlignment NewIndent = 0; unsigned LastSpace = CurrentState.LastSpace; bool AvoidBinPacking; bool BreakBeforeParameter = false; @@ -1999,7 +2048,7 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, std::min(State.Column, CurrentState.NestedBlockIndent); } else if (Current.is(tok::l_brace)) { const auto Width = Style.BracedInitializerIndentWidth; - NewIndent = CurrentState.LastSpace + + NewIndent = IndentationAndAlignment(CurrentState.LastSpace) + (Width < 0 ? Style.ContinuationIndentWidth : Width); } else { NewIndent = CurrentState.LastSpace + Style.ContinuationIndentWidth; @@ -2014,9 +2063,9 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, if (Current.ParameterCount > 1) NestedBlockIndent = std::max(NestedBlockIndent, State.Column + 1); } else { - NewIndent = - Style.ContinuationIndentWidth + - std::max(CurrentState.LastSpace, CurrentState.StartOfFunctionCall); + NewIndent = IndentationAndAlignment(std::max( + CurrentState.LastSpace, CurrentState.StartOfFunctionCall)) + + Style.ContinuationIndentWidth; if (Style.isTableGen() && Current.is(TT_TableGenDAGArgOpenerToBreak) && Style.TableGenBreakInsideDAGArg == FormatStyle::DAS_BreakElements) { @@ -2035,7 +2084,7 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, // FIXME: We likely want to do this for more combinations of brackets. if (Current.is(tok::less) && Current.ParentBracket == tok::l_paren) { NewIndent = std::max(NewIndent, CurrentState.Indent); - LastSpace = std::max(LastSpace, CurrentState.Indent); + LastSpace = std::max(LastSpace, CurrentState.Indent.Total); } // If ObjCBinPackProtocolList is unspecified, fall back to BinPackParameters @@ -2281,7 +2330,7 @@ unsigned ContinuationIndenter::reformatRawStringLiteral( unsigned CurrentIndent = (!Newline && Current.Next && Current.Next->is(tok::r_paren)) ? State.Stack.back().NestedBlockIndent - : State.Stack.back().Indent; + : State.Stack.back().Indent.Total; unsigned NextStartColumn = ContentStartsOnNewline ? CurrentIndent + Style.IndentWidth : FirstStartColumn; diff --git a/clang/lib/Format/ContinuationIndenter.h b/clang/lib/Format/ContinuationIndenter.h index fe957cf..1554fb4 100644 --- a/clang/lib/Format/ContinuationIndenter.h +++ b/clang/lib/Format/ContinuationIndenter.h @@ -43,6 +43,41 @@ struct RawStringFormatStyleManager { getEnclosingFunctionStyle(StringRef EnclosingFunction) const; }; +/// Represents the spaces at the start of a line, keeping track of what the +/// spaces are for. +struct IndentationAndAlignment { + unsigned Total; + + /// The column that the position of the start of the line is calculated + /// from. It can be more than Total. + unsigned IndentedFrom; + + /// Add spaces for right-justifying the token. The IndentedFrom field does not + /// change. + /// + /// This example in Objective-C shows why the field should not change. The + /// token `xx` is right-justified with this method to align the `:` + /// symbols. The `:` symbols should remain aligned through the step that + /// aligns assignments. That step uses the IndentedFrom field to tell what + /// lines to move. Not changing the field in this method ensures that the 2 + /// lines move together. + /// + /// [x // + /// xxxx:0 + /// xx:0]; + IndentationAndAlignment addPadding(unsigned Spaces) const; + /// Adding indentation is more common than padding. So the operator does that. + IndentationAndAlignment operator+(unsigned Spaces) const; + IndentationAndAlignment operator-(unsigned Spaces) const; + IndentationAndAlignment &operator+=(unsigned Spaces); + + IndentationAndAlignment(unsigned Total, unsigned IndentedFrom); + + IndentationAndAlignment(unsigned Spaces); + + bool operator<(const IndentationAndAlignment &Other) const; +}; + class ContinuationIndenter { public: /// Constructs a \c ContinuationIndenter to format \p Line starting in @@ -168,7 +203,7 @@ private: unsigned addTokenOnNewLine(LineState &State, bool DryRun); /// Calculate the new column for a line wrap before the next token. - unsigned getNewLineColumn(const LineState &State); + IndentationAndAlignment getNewLineColumn(const LineState &State); /// Adds a multiline token to the \p State. /// @@ -195,10 +230,10 @@ private: }; struct ParenState { - ParenState(const FormatToken *Tok, unsigned Indent, unsigned LastSpace, - bool AvoidBinPacking, bool NoLineBreak) + ParenState(const FormatToken *Tok, IndentationAndAlignment Indent, + unsigned LastSpace, bool AvoidBinPacking, bool NoLineBreak) : Tok(Tok), Indent(Indent), LastSpace(LastSpace), - NestedBlockIndent(Indent), IsAligned(false), + NestedBlockIndent(Indent.Total), IsAligned(false), BreakBeforeClosingBrace(false), BreakBeforeClosingParen(false), BreakBeforeClosingAngle(false), AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false), NoLineBreak(NoLineBreak), @@ -219,7 +254,7 @@ struct ParenState { /// The position to which a specific parenthesis level needs to be /// indented. - unsigned Indent; + IndentationAndAlignment Indent; /// The position of the last space on each level. /// @@ -356,8 +391,8 @@ struct ParenState { bool UnindentOperator : 1; bool operator<(const ParenState &Other) const { - if (Indent != Other.Indent) - return Indent < Other.Indent; + if (Indent.Total != Other.Indent.Total) + return Indent.Total < Other.Indent.Total; if (LastSpace != Other.LastSpace) return LastSpace < Other.LastSpace; if (NestedBlockIndent != Other.NestedBlockIndent) @@ -406,7 +441,7 @@ struct ParenState { return IsWrappedConditional; if (UnindentOperator != Other.UnindentOperator) return UnindentOperator; - return false; + return Indent < Other.Indent; } }; diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index dd14fcd..f0e9aff 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -405,11 +405,19 @@ struct ScalarEnumerationTraits<FormatStyle::IndentExternBlockStyle> { template <> struct MappingTraits<FormatStyle::IntegerLiteralSeparatorStyle> { static void mapping(IO &IO, FormatStyle::IntegerLiteralSeparatorStyle &Base) { IO.mapOptional("Binary", Base.Binary); - IO.mapOptional("BinaryMinDigits", Base.BinaryMinDigits); + IO.mapOptional("BinaryMinDigitsInsert", Base.BinaryMinDigitsInsert); + IO.mapOptional("BinaryMaxDigitsRemove", Base.BinaryMaxDigitsRemove); IO.mapOptional("Decimal", Base.Decimal); - IO.mapOptional("DecimalMinDigits", Base.DecimalMinDigits); + IO.mapOptional("DecimalMinDigitsInsert", Base.DecimalMinDigitsInsert); + IO.mapOptional("DecimalMaxDigitsRemove", Base.DecimalMaxDigitsRemove); IO.mapOptional("Hex", Base.Hex); - IO.mapOptional("HexMinDigits", Base.HexMinDigits); + IO.mapOptional("HexMinDigitsInsert", Base.HexMinDigitsInsert); + IO.mapOptional("HexMaxDigitsRemove", Base.HexMaxDigitsRemove); + + // For backward compatibility. + IO.mapOptional("BinaryMinDigits", Base.BinaryMinDigitsInsert); + IO.mapOptional("DecimalMinDigits", Base.DecimalMinDigitsInsert); + IO.mapOptional("HexMinDigits", Base.HexMinDigitsInsert); } }; @@ -876,27 +884,28 @@ template <> struct MappingTraits<FormatStyle::TrailingCommentsAlignmentStyle> { FormatStyle::TrailingCommentsAlignmentStyle &Value) { IO.enumCase(Value, "Leave", FormatStyle::TrailingCommentsAlignmentStyle( - {FormatStyle::TCAS_Leave, 0})); + {FormatStyle::TCAS_Leave, 0, true})); IO.enumCase(Value, "Always", FormatStyle::TrailingCommentsAlignmentStyle( - {FormatStyle::TCAS_Always, 0})); + {FormatStyle::TCAS_Always, 0, true})); IO.enumCase(Value, "Never", FormatStyle::TrailingCommentsAlignmentStyle( - {FormatStyle::TCAS_Never, 0})); + {FormatStyle::TCAS_Never, 0, true})); // For backwards compatibility IO.enumCase(Value, "true", FormatStyle::TrailingCommentsAlignmentStyle( - {FormatStyle::TCAS_Always, 0})); + {FormatStyle::TCAS_Always, 0, true})); IO.enumCase(Value, "false", FormatStyle::TrailingCommentsAlignmentStyle( - {FormatStyle::TCAS_Never, 0})); + {FormatStyle::TCAS_Never, 0, true})); } static void mapping(IO &IO, FormatStyle::TrailingCommentsAlignmentStyle &Value) { + IO.mapOptional("AlignPPAndNotPP", Value.AlignPPAndNotPP); IO.mapOptional("Kind", Value.Kind); IO.mapOptional("OverEmptyLines", Value.OverEmptyLines); } @@ -1651,6 +1660,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.AlignTrailingComments = {}; LLVMStyle.AlignTrailingComments.Kind = FormatStyle::TCAS_Always; LLVMStyle.AlignTrailingComments.OverEmptyLines = 0; + LLVMStyle.AlignTrailingComments.AlignPPAndNotPP = true; LLVMStyle.AllowAllArgumentsOnNextLine = true; LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true; LLVMStyle.AllowBreakBeforeNoexceptSpecifier = FormatStyle::BBNSS_Never; @@ -1756,10 +1766,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.InsertBraces = false; LLVMStyle.InsertNewlineAtEOF = false; LLVMStyle.InsertTrailingCommas = FormatStyle::TCS_None; - LLVMStyle.IntegerLiteralSeparator = { - /*Binary=*/0, /*BinaryMinDigits=*/0, - /*Decimal=*/0, /*DecimalMinDigits=*/0, - /*Hex=*/0, /*HexMinDigits=*/0}; + LLVMStyle.IntegerLiteralSeparator = {}; LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave; LLVMStyle.JavaScriptWrapImports = true; LLVMStyle.KeepEmptyLines = { @@ -2181,7 +2188,7 @@ FormatStyle getClangFormatStyle() { Style.InsertBraces = true; Style.InsertNewlineAtEOF = true; Style.IntegerLiteralSeparator.Decimal = 3; - Style.IntegerLiteralSeparator.DecimalMinDigits = 5; + Style.IntegerLiteralSeparator.DecimalMinDigitsInsert = 5; Style.LineEnding = FormatStyle::LE_LF; Style.RemoveBracesLLVM = true; Style.RemoveEmptyLinesInUnwrappedLines = true; diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index d833130..56abd70 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -1170,6 +1170,7 @@ struct AdditionalKeywords { kw_checker = &IdentTable.get("checker"); kw_clocking = &IdentTable.get("clocking"); kw_constraint = &IdentTable.get("constraint"); + kw_context = &IdentTable.get("context"); kw_cover = &IdentTable.get("cover"); kw_covergroup = &IdentTable.get("covergroup"); kw_coverpoint = &IdentTable.get("coverpoint"); @@ -1325,50 +1326,138 @@ struct AdditionalKeywords { // Some keywords are not included here because they don't need special // treatment like `showcancelled` or they should be treated as identifiers // like `int` and `logic`. - VerilogExtraKeywords = std::unordered_set<IdentifierInfo *>( - {kw_always, kw_always_comb, kw_always_ff, - kw_always_latch, kw_assert, kw_assign, - kw_assume, kw_automatic, kw_before, - kw_begin, kw_bins, kw_binsof, - kw_casex, kw_casez, kw_celldefine, - kw_checker, kw_clocking, kw_constraint, - kw_cover, kw_covergroup, kw_coverpoint, - kw_disable, kw_dist, kw_edge, - kw_end, kw_endcase, kw_endchecker, - kw_endclass, kw_endclocking, kw_endfunction, - kw_endgenerate, kw_endgroup, kw_endinterface, - kw_endmodule, kw_endpackage, kw_endprimitive, - kw_endprogram, kw_endproperty, kw_endsequence, - kw_endspecify, kw_endtable, kw_endtask, - kw_extends, kw_final, kw_foreach, - kw_forever, kw_fork, kw_function, - kw_generate, kw_highz0, kw_highz1, - kw_iff, kw_ifnone, kw_ignore_bins, - kw_illegal_bins, kw_implements, kw_import, - kw_initial, kw_inout, kw_input, - kw_inside, kw_interconnect, kw_interface, - kw_intersect, kw_join, kw_join_any, - kw_join_none, kw_large, kw_let, - kw_local, kw_localparam, kw_macromodule, - kw_matches, kw_medium, kw_negedge, - kw_output, kw_package, kw_packed, - kw_parameter, kw_posedge, kw_primitive, - kw_priority, kw_program, kw_property, - kw_pull0, kw_pull1, kw_pure, - kw_rand, kw_randc, kw_randcase, - kw_randsequence, kw_ref, kw_repeat, - kw_sample, kw_scalared, kw_sequence, - kw_small, kw_soft, kw_solve, - kw_specify, kw_specparam, kw_strong0, - kw_strong1, kw_supply0, kw_supply1, - kw_table, kw_tagged, kw_task, - kw_tri, kw_tri0, kw_tri1, - kw_triand, kw_trior, kw_trireg, - kw_unique, kw_unique0, kw_uwire, - kw_var, kw_vectored, kw_wait, - kw_wand, kw_weak0, kw_weak1, - kw_wildcard, kw_wire, kw_with, - kw_wor, kw_verilogHash, kw_verilogHashHash}); + VerilogExtraKeywords = + std::unordered_set<IdentifierInfo *>({kw_always, + kw_always_comb, + kw_always_ff, + kw_always_latch, + kw_assert, + kw_assign, + kw_assume, + kw_automatic, + kw_before, + kw_begin, + kw_bins, + kw_binsof, + kw_casex, + kw_casez, + kw_celldefine, + kw_checker, + kw_clocking, + kw_constraint, + kw_context, + kw_cover, + kw_covergroup, + kw_coverpoint, + kw_disable, + kw_dist, + kw_edge, + kw_end, + kw_endcase, + kw_endchecker, + kw_endclass, + kw_endclocking, + kw_endfunction, + kw_endgenerate, + kw_endgroup, + kw_endinterface, + kw_endmodule, + kw_endpackage, + kw_endprimitive, + kw_endprogram, + kw_endproperty, + kw_endsequence, + kw_endspecify, + kw_endtable, + kw_endtask, + kw_extends, + kw_final, + kw_foreach, + kw_forever, + kw_fork, + kw_function, + kw_generate, + kw_highz0, + kw_highz1, + kw_iff, + kw_ifnone, + kw_ignore_bins, + kw_illegal_bins, + kw_implements, + kw_import, + kw_initial, + kw_inout, + kw_input, + kw_inside, + kw_interconnect, + kw_interface, + kw_intersect, + kw_join, + kw_join_any, + kw_join_none, + kw_large, + kw_let, + kw_local, + kw_localparam, + kw_macromodule, + kw_matches, + kw_medium, + kw_module, + kw_negedge, + kw_output, + kw_package, + kw_packed, + kw_parameter, + kw_posedge, + kw_primitive, + kw_priority, + kw_program, + kw_property, + kw_pull0, + kw_pull1, + kw_pure, + kw_rand, + kw_randc, + kw_randcase, + kw_randsequence, + kw_ref, + kw_repeat, + kw_sample, + kw_scalared, + kw_sequence, + kw_small, + kw_soft, + kw_solve, + kw_specify, + kw_specparam, + kw_strong0, + kw_strong1, + kw_supply0, + kw_supply1, + kw_table, + kw_tagged, + kw_task, + kw_tri, + kw_tri0, + kw_tri1, + kw_triand, + kw_trior, + kw_trireg, + kw_unique, + kw_unique0, + kw_uwire, + kw_var, + kw_vectored, + kw_wait, + kw_wand, + kw_weak0, + kw_weak1, + kw_wildcard, + kw_wire, + kw_with, + kw_wor, + kw_verilogHash, + kw_verilogHashHash}); TableGenExtraKeywords = std::unordered_set<IdentifierInfo *>({ kw_assert, @@ -1516,6 +1605,7 @@ struct AdditionalKeywords { IdentifierInfo *kw_checker; IdentifierInfo *kw_clocking; IdentifierInfo *kw_constraint; + IdentifierInfo *kw_context; IdentifierInfo *kw_cover; IdentifierInfo *kw_covergroup; IdentifierInfo *kw_coverpoint; @@ -1800,11 +1890,13 @@ struct AdditionalKeywords { case tok::kw_continue: case tok::kw_default: case tok::kw_do: - case tok::kw_extern: case tok::kw_else: case tok::kw_enum: + case tok::kw_export: + case tok::kw_extern: case tok::kw_for: case tok::kw_if: + case tok::kw_import: case tok::kw_restrict: case tok::kw_signed: case tok::kw_static: diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index ab32938..eb86583 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -318,14 +318,21 @@ void FormatTokenLexer::tryMergePreviousTokens() { {tok::equal, tok::greater}, {tok::star, tok::greater}, {tok::pipeequal, tok::greater}, - {tok::pipe, tok::arrow}, - {tok::hash, tok::minus, tok::hash}, - {tok::hash, tok::equal, tok::hash}}, + {tok::pipe, tok::arrow}}, TT_BinaryOperator) || Tokens.back()->is(tok::arrow)) { Tokens.back()->ForcedPrecedence = prec::Comma; return; } + if (Tokens.size() >= 3 && + Tokens[Tokens.size() - 3]->is(Keywords.kw_verilogHash) && + Tokens[Tokens.size() - 2]->isOneOf(tok::minus, tok::equal) && + Tokens[Tokens.size() - 1]->is(Keywords.kw_verilogHash) && + tryMergeTokens(3, TT_BinaryOperator)) { + Tokens.back()->setFinalizedType(TT_BinaryOperator); + Tokens.back()->ForcedPrecedence = prec::Comma; + return; + } } else if (Style.isTableGen()) { // TableGen's Multi line string starts with [{ if (tryMergeTokens({tok::l_square, tok::l_brace}, @@ -1401,6 +1408,8 @@ FormatToken *FormatTokenLexer::getNextToken() { FormatTok->Tok.setKind(tok::identifier); } else if (Style.isTableGen() && !Keywords.isTableGenKeyword(*FormatTok)) { FormatTok->Tok.setKind(tok::identifier); + } else if (Style.isVerilog() && Keywords.isVerilogIdentifier(*FormatTok)) { + FormatTok->Tok.setKind(tok::identifier); } } else if (const bool Greater = FormatTok->is(tok::greatergreater); Greater || FormatTok->is(tok::lessless)) { diff --git a/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp b/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp index b51991bf..a283884 100644 --- a/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp +++ b/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp @@ -72,11 +72,22 @@ IntegerLiteralSeparatorFixer::process(const Environment &Env, if (SkipBinary && SkipDecimal && SkipHex) return {}; - const auto BinaryMinDigits = - std::max((int)Option.BinaryMinDigits, Binary + 1); - const auto DecimalMinDigits = - std::max((int)Option.DecimalMinDigits, Decimal + 1); - const auto HexMinDigits = std::max((int)Option.HexMinDigits, Hex + 1); + auto CalcMinAndMax = [](int DigitsPerGroup, int MinDigitsInsert, + int MaxDigitsRemove) { + MinDigitsInsert = std::max(MinDigitsInsert, DigitsPerGroup + 1); + if (MinDigitsInsert < 1) + MaxDigitsRemove = 0; + else if (MaxDigitsRemove < 1 || MaxDigitsRemove >= MinDigitsInsert) + MaxDigitsRemove = MinDigitsInsert - 1; + return std::pair(MinDigitsInsert, MaxDigitsRemove); + }; + + const auto [BinaryMinDigitsInsert, BinaryMaxDigitsRemove] = CalcMinAndMax( + Binary, Option.BinaryMinDigitsInsert, Option.BinaryMaxDigitsRemove); + const auto [DecimalMinDigitsInsert, DecimalMaxDigitsRemove] = CalcMinAndMax( + Decimal, Option.DecimalMinDigitsInsert, Option.DecimalMaxDigitsRemove); + const auto [HexMinDigitsInsert, HexMaxDigitsRemove] = + CalcMinAndMax(Hex, Option.HexMinDigitsInsert, Option.HexMaxDigitsRemove); const auto &SourceMgr = Env.getSourceManager(); AffectedRangeManager AffectedRangeMgr(SourceMgr, Env.getCharRanges()); @@ -138,17 +149,23 @@ IntegerLiteralSeparatorFixer::process(const Environment &Env, Text = Text.substr(Start, Length); } auto DigitsPerGroup = Decimal; - auto MinDigits = DecimalMinDigits; + auto MinDigitsInsert = DecimalMinDigitsInsert; + auto MaxDigitsRemove = DecimalMaxDigitsRemove; if (IsBase2) { DigitsPerGroup = Binary; - MinDigits = BinaryMinDigits; + MinDigitsInsert = BinaryMinDigitsInsert; + MaxDigitsRemove = BinaryMaxDigitsRemove; } else if (IsBase16) { DigitsPerGroup = Hex; - MinDigits = HexMinDigits; + MinDigitsInsert = HexMinDigitsInsert; + MaxDigitsRemove = HexMaxDigitsRemove; } const auto SeparatorCount = Text.count(Separator); const int DigitCount = Length - SeparatorCount; - const bool RemoveSeparator = DigitsPerGroup < 0 || DigitCount < MinDigits; + if (DigitCount > MaxDigitsRemove && DigitCount < MinDigitsInsert) + continue; + const bool RemoveSeparator = + DigitsPerGroup < 0 || DigitCount <= MaxDigitsRemove; if (RemoveSeparator && SeparatorCount == 0) continue; if (!RemoveSeparator && SeparatorCount > 0 && diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp index e3e30ca..eb0f886 100644 --- a/clang/lib/Format/QualifierAlignmentFixer.cpp +++ b/clang/lib/Format/QualifierAlignmentFixer.cpp @@ -182,8 +182,11 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( // We only need to think about streams that begin with a qualifier. if (Tok->isNot(QualifierType)) return Tok; + + const auto *Next = Tok->getNextNonComment(); + // Don't concern yourself if nothing follows the qualifier. - if (!Tok->Next) + if (!Next) return Tok; // Skip qualifiers to the left to find what preceeds the qualifiers. @@ -247,9 +250,15 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( }(); // Find the last qualifier to the right. - const FormatToken *LastQual = Tok; - while (isQualifier(LastQual->getNextNonComment())) - LastQual = LastQual->getNextNonComment(); + const auto *LastQual = Tok; + for (; isQualifier(Next); Next = Next->getNextNonComment()) + LastQual = Next; + + if (!LastQual || !Next || + (LastQual->isOneOf(tok::kw_const, tok::kw_volatile) && + Next->isOneOf(Keywords.kw_override, Keywords.kw_final))) { + return Tok; + } // If this qualifier is to the right of a type or pointer do a partial sort // and return. diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 8e227da..79cfa73 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -358,11 +358,11 @@ private: Contexts.back().IsExpression = false; } else if (OpeningParen.Previous && (OpeningParen.Previous->isOneOf( - tok::kw_static_assert, tok::kw_noexcept, tok::kw_explicit, - tok::kw_while, tok::l_paren, tok::comma, TT_CastRParen, + tok::kw_noexcept, tok::kw_explicit, tok::kw_while, + tok::l_paren, tok::comma, TT_CastRParen, TT_BinaryOperator) || OpeningParen.Previous->isIf())) { - // static_assert, if and while usually contain expressions. + // if and while usually contain expressions. Contexts.back().IsExpression = true; } else if (Style.isJavaScript() && OpeningParen.Previous && (OpeningParen.Previous->is(Keywords.kw_function) || @@ -454,6 +454,11 @@ private: if (StartsObjCSelector) OpeningParen.setType(TT_ObjCSelector); + const bool IsStaticAssert = + PrevNonComment && PrevNonComment->is(tok::kw_static_assert); + if (IsStaticAssert) + Contexts.back().InStaticAssertFirstArgument = true; + // MightBeFunctionType and ProbablyFunctionType are used for // function pointer and reference types as well as Objective-C // block types: @@ -583,8 +588,12 @@ private: } // When we discover a 'new', we set CanBeExpression to 'false' in order to // parse the type correctly. Reset that after a comma. - if (CurrentToken->is(tok::comma)) - Contexts.back().CanBeExpression = true; + if (CurrentToken->is(tok::comma)) { + if (IsStaticAssert) + Contexts.back().InStaticAssertFirstArgument = false; + else + Contexts.back().CanBeExpression = true; + } if (Style.isTableGen()) { if (CurrentToken->is(tok::comma)) { @@ -699,6 +708,11 @@ private: IsCpp && !IsCpp11AttributeSpecifier && !IsCSharpAttributeSpecifier && Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) && CurrentToken->isNoneOf(tok::l_brace, tok::r_square) && + // Do not consider '[' after a comma inside a braced initializer the + // start of an ObjC method expression. In braced initializer lists, + // commas are list separators and should not trigger ObjC parsing. + (!Parent || !Parent->is(tok::comma) || + Contexts.back().ContextKind != tok::l_brace) && (!Parent || Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren, tok::kw_return, tok::kw_throw) || @@ -2144,6 +2158,7 @@ private: bool CaretFound = false; bool InCpp11AttributeSpecifier = false; bool InCSharpAttributeSpecifier = false; + bool InStaticAssertFirstArgument = false; bool VerilogAssignmentFound = false; // Whether the braces may mean concatenation instead of structure or array // literal. @@ -2440,7 +2455,8 @@ private: } else if (Current.isPointerOrReference()) { Current.setType(determineStarAmpUsage( Current, - Contexts.back().CanBeExpression && Contexts.back().IsExpression, + (Contexts.back().CanBeExpression && Contexts.back().IsExpression) || + Contexts.back().InStaticAssertFirstArgument, Contexts.back().ContextType == Context::TemplateArgument)); } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret) || (Style.isVerilog() && Current.is(tok::pipe))) { @@ -3118,8 +3134,11 @@ private: // It is very unlikely that we are going to find a pointer or reference type // definition on the RHS of an assignment. - if (IsExpression && !Contexts.back().CaretFound) + if (IsExpression && !Contexts.back().CaretFound && + Line.getFirstNonComment()->isNot( + TT_RequiresClauseInARequiresExpression)) { return TT_BinaryOperator; + } // Opeartors at class scope are likely pointer or reference members. if (!Scopes.empty() && Scopes.back() == ST_Class) @@ -5019,8 +5038,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return true; // Space between import <iostream>. // or import .....; - if (Left.is(Keywords.kw_import) && Right.isOneOf(tok::less, tok::ellipsis)) + if (Left.is(Keywords.kw_import) && + Right.isOneOf(tok::less, tok::ellipsis) && + (!BeforeLeft || BeforeLeft->is(tok::kw_export))) { return true; + } // Space between `module :` and `import :`. if (Left.isOneOf(Keywords.kw_module, Keywords.kw_import) && Right.is(TT_ModulePartitionColon)) { diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index ac9c81d..913789a 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -285,7 +285,8 @@ private: if (Tok && Tok->is(tok::kw_typedef)) Tok = Tok->getNextNonComment(); if (Tok && Tok->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union, - tok::kw_extern, Keywords.kw_interface)) { + tok::kw_extern, Keywords.kw_interface, + Keywords.kw_record)) { return !Style.BraceWrapping.SplitEmptyRecord && EmptyBlock ? tryMergeSimpleBlock(I, E, Limit) : 0; @@ -498,7 +499,8 @@ private: ShouldMerge = Style.AllowShortEnumsOnASingleLine; } else if (TheLine->Last->is(TT_CompoundRequirementLBrace)) { ShouldMerge = Style.AllowShortCompoundRequirementOnASingleLine; - } else if (TheLine->Last->isOneOf(TT_ClassLBrace, TT_StructLBrace)) { + } else if (TheLine->Last->isOneOf(TT_ClassLBrace, TT_StructLBrace, + TT_RecordLBrace)) { // NOTE: We use AfterClass (whereas AfterStruct exists) for both classes // and structs, but it seems that wrapping is still handled correctly // elsewhere. @@ -507,7 +509,7 @@ private: !Style.BraceWrapping.SplitEmptyRecord); } else if (TheLine->InPPDirective || TheLine->First->isNoneOf(tok::kw_class, tok::kw_enum, - tok::kw_struct)) { + tok::kw_struct, Keywords.kw_record)) { // Try to merge a block with left brace unwrapped that wasn't yet // covered. ShouldMerge = !Style.BraceWrapping.AfterFunction || @@ -1050,8 +1052,8 @@ static void markFinalized(FormatToken *Tok) { static void printLineState(const LineState &State) { llvm::dbgs() << "State: "; for (const ParenState &P : State.Stack) { - llvm::dbgs() << (P.Tok ? P.Tok->TokenText : "F") << "|" << P.Indent << "|" - << P.LastSpace << "|" << P.NestedBlockIndent << " "; + llvm::dbgs() << (P.Tok ? P.Tok->TokenText : "F") << "|" << P.Indent.Total + << "|" << P.LastSpace << "|" << P.NestedBlockIndent << " "; } llvm::dbgs() << State.NextToken->TokenText << "\n"; } @@ -1109,7 +1111,7 @@ protected: const ParenState &P = State.Stack.back(); int AdditionalIndent = - P.Indent - Previous.Children[0]->Level * Style.IndentWidth; + P.Indent.Total - Previous.Children[0]->Level * Style.IndentWidth; Penalty += BlockFormatter->format(Previous.Children, DryRun, AdditionalIndent, /*FixBadIndentation=*/true); diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 5e2584e..c1a9161 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -948,7 +948,11 @@ static bool isIIFE(const UnwrappedLine &Line, } static bool ShouldBreakBeforeBrace(const FormatStyle &Style, - const FormatToken &InitialToken) { + const FormatToken &InitialToken, + const bool IsJavaRecord) { + if (IsJavaRecord) + return Style.BraceWrapping.AfterClass; + tok::TokenKind Kind = InitialToken.Tok.getKind(); if (InitialToken.is(TT_NamespaceMacro)) Kind = tok::kw_namespace; @@ -1588,15 +1592,14 @@ void UnwrappedLineParser::parseStructuralElement( parseTryCatch(); return; case tok::kw_extern: - nextToken(); if (Style.isVerilog()) { - // In Verilog and extern module declaration looks like a start of module. + // In Verilog an extern module declaration looks like a start of module. // But there is no body and endmodule. So we handle it separately. - if (Keywords.isVerilogHierarchy(*FormatTok)) { - parseVerilogHierarchyHeader(); - return; - } - } else if (FormatTok->is(tok::string_literal)) { + parseVerilogExtern(); + return; + } + nextToken(); + if (FormatTok->is(tok::string_literal)) { nextToken(); if (FormatTok->is(tok::l_brace)) { if (Style.BraceWrapping.AfterExternBlock) @@ -1621,6 +1624,10 @@ void UnwrappedLineParser::parseStructuralElement( parseJavaScriptEs6ImportExport(); return; } + if (Style.isVerilog()) { + parseVerilogExtern(); + return; + } if (IsCpp) { nextToken(); if (FormatTok->is(tok::kw_namespace)) { @@ -1669,6 +1676,10 @@ void UnwrappedLineParser::parseStructuralElement( addUnwrappedLine(); return; } + if (Style.isVerilog()) { + parseVerilogExtern(); + return; + } if (IsCpp && parseModuleImport()) return; } @@ -2352,12 +2363,9 @@ bool UnwrappedLineParser::tryToParseLambda() { Arrow = FormatTok; nextToken(); break; - case tok::kw_requires: { - auto *RequiresToken = FormatTok; - nextToken(); - parseRequiresClause(RequiresToken); + case tok::kw_requires: + parseRequiresClause(); break; - } case tok::equal: if (!InTemplateParameterList) return true; @@ -2387,17 +2395,17 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() { const FormatToken *LeftSquare = FormatTok; nextToken(); if (Previous) { + const auto *PrevPrev = Previous->getPreviousNonComment(); + if (Previous->is(tok::star) && PrevPrev && PrevPrev->isTypeName(LangOpts)) + return false; if (Previous->closesScope()) { // Not a potential C-style cast. if (Previous->isNot(tok::r_paren)) return false; - const auto *BeforeRParen = Previous->getPreviousNonComment(); // Lambdas can be cast to function types only, e.g. `std::function<int()>` // and `int (*)()`. - if (!BeforeRParen || BeforeRParen->isNoneOf(tok::greater, tok::r_paren)) + if (!PrevPrev || PrevPrev->isNoneOf(tok::greater, tok::r_paren)) return false; - } else if (Previous->is(tok::star)) { - Previous = Previous->getPreviousNonComment(); } if (Previous && Previous->Tok.getIdentifierInfo() && Previous->isNoneOf(tok::kw_return, tok::kw_co_await, tok::kw_co_yield, @@ -2569,12 +2577,9 @@ bool UnwrappedLineParser::parseBracedList(bool IsAngleBracket, bool IsEnum) { if (IsEnum && !Style.AllowShortEnumsOnASingleLine) addUnwrappedLine(); break; - case tok::kw_requires: { - auto *RequiresToken = FormatTok; - nextToken(); - parseRequiresExpression(RequiresToken); + case tok::kw_requires: + parseRequiresExpression(); break; - } default: nextToken(); break; @@ -2716,12 +2721,9 @@ bool UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType, else nextToken(); break; - case tok::kw_requires: { - auto RequiresToken = FormatTok; - nextToken(); - parseRequiresExpression(RequiresToken); + case tok::kw_requires: + parseRequiresExpression(); break; - } case tok::ampamp: if (AmpAmpTokenType != TT_Unknown) FormatTok->setFinalizedType(AmpAmpTokenType); @@ -3200,7 +3202,7 @@ void UnwrappedLineParser::parseNamespace() { if (FormatTok->is(tok::l_brace)) { FormatTok->setFinalizedType(TT_NamespaceLBrace); - if (ShouldBreakBeforeBrace(Style, InitialToken)) + if (ShouldBreakBeforeBrace(Style, InitialToken, /*IsJavaRecord=*/false)) addUnwrappedLine(); unsigned AddLevels = @@ -3456,23 +3458,20 @@ void UnwrappedLineParser::parseAccessSpecifier() { /// \returns true if it parsed a clause. bool UnwrappedLineParser::parseRequires(bool SeenEqual) { assert(FormatTok->is(tok::kw_requires) && "'requires' expected"); - auto RequiresToken = FormatTok; // We try to guess if it is a requires clause, or a requires expression. For - // that we first consume the keyword and check the next token. - nextToken(); - - switch (FormatTok->Tok.getKind()) { + // that we first check the next token. + switch (Tokens->peekNextToken(/*SkipComment=*/true)->Tok.getKind()) { case tok::l_brace: // This can only be an expression, never a clause. - parseRequiresExpression(RequiresToken); + parseRequiresExpression(); return false; case tok::l_paren: // Clauses and expression can start with a paren, it's unclear what we have. break; default: // All other tokens can only be a clause. - parseRequiresClause(RequiresToken); + parseRequiresClause(); return true; } @@ -3483,13 +3482,13 @@ bool UnwrappedLineParser::parseRequires(bool SeenEqual) { // requires (C<T> && ... // But first let's look behind. - auto *PreviousNonComment = RequiresToken->getPreviousNonComment(); + auto *PreviousNonComment = FormatTok->getPreviousNonComment(); if (!PreviousNonComment || PreviousNonComment->is(TT_RequiresExpressionLBrace)) { // If there is no token, or an expression left brace, we are a requires // clause within a requires expression. - parseRequiresClause(RequiresToken); + parseRequiresClause(); return true; } @@ -3501,7 +3500,7 @@ bool UnwrappedLineParser::parseRequires(bool SeenEqual) { case tok::star: case tok::amp: // This is a requires clause. - parseRequiresClause(RequiresToken); + parseRequiresClause(); return true; case tok::ampamp: { // This can be either: @@ -3512,7 +3511,7 @@ bool UnwrappedLineParser::parseRequires(bool SeenEqual) { // void member(...) const && requires (C<T> ... auto PrevPrev = PreviousNonComment->getPreviousNonComment(); if ((PrevPrev && PrevPrev->is(tok::kw_const)) || !SeenEqual) { - parseRequiresClause(RequiresToken); + parseRequiresClause(); return true; } break; @@ -3520,11 +3519,11 @@ bool UnwrappedLineParser::parseRequires(bool SeenEqual) { default: if (PreviousNonComment->isTypeOrIdentifier(LangOpts)) { // This is a requires clause. - parseRequiresClause(RequiresToken); + parseRequiresClause(); return true; } // It's an expression. - parseRequiresExpression(RequiresToken); + parseRequiresExpression(); return false; } @@ -3553,7 +3552,7 @@ bool UnwrappedLineParser::parseRequires(bool SeenEqual) { case tok::comma: if (OpenAngles == 0) { FormatTok = Tokens->setPosition(StoredPosition); - parseRequiresExpression(RequiresToken); + parseRequiresExpression(); return false; } break; @@ -3568,7 +3567,7 @@ bool UnwrappedLineParser::parseRequires(bool SeenEqual) { case tok::identifier: if (FoundType && !LastWasColonColon && OpenAngles == 0) { FormatTok = Tokens->setPosition(StoredPosition); - parseRequiresExpression(RequiresToken); + parseRequiresExpression(); return false; } FoundType = true; @@ -3583,7 +3582,7 @@ bool UnwrappedLineParser::parseRequires(bool SeenEqual) { default: if (NextToken->isTypeName(LangOpts)) { FormatTok = Tokens->setPosition(StoredPosition); - parseRequiresExpression(RequiresToken); + parseRequiresExpression(); return false; } break; @@ -3591,31 +3590,29 @@ bool UnwrappedLineParser::parseRequires(bool SeenEqual) { } // This seems to be a complicated expression, just assume it's a clause. FormatTok = Tokens->setPosition(StoredPosition); - parseRequiresClause(RequiresToken); + parseRequiresClause(); return true; } /// Parses a requires clause. -/// \param RequiresToken The requires keyword token, which starts this clause. -/// \pre We need to be on the next token after the requires keyword. /// \sa parseRequiresExpression /// /// Returns if it either has finished parsing the clause, or it detects, that /// the clause is incorrect. -void UnwrappedLineParser::parseRequiresClause(FormatToken *RequiresToken) { - assert(FormatTok->getPreviousNonComment() == RequiresToken); - assert(RequiresToken->is(tok::kw_requires) && "'requires' expected"); +void UnwrappedLineParser::parseRequiresClause() { + assert(FormatTok->is(tok::kw_requires) && "'requires' expected"); // If there is no previous token, we are within a requires expression, // otherwise we will always have the template or function declaration in front // of it. bool InRequiresExpression = - !RequiresToken->Previous || - RequiresToken->Previous->is(TT_RequiresExpressionLBrace); + !FormatTok->Previous || + FormatTok->Previous->is(TT_RequiresExpressionLBrace); - RequiresToken->setFinalizedType(InRequiresExpression - ? TT_RequiresClauseInARequiresExpression - : TT_RequiresClause); + FormatTok->setFinalizedType(InRequiresExpression + ? TT_RequiresClauseInARequiresExpression + : TT_RequiresClause); + nextToken(); // NOTE: parseConstraintExpression is only ever called from this function. // It could be inlined into here. @@ -3626,17 +3623,15 @@ void UnwrappedLineParser::parseRequiresClause(FormatToken *RequiresToken) { } /// Parses a requires expression. -/// \param RequiresToken The requires keyword token, which starts this clause. -/// \pre We need to be on the next token after the requires keyword. /// \sa parseRequiresClause /// /// Returns if it either has finished parsing the expression, or it detects, /// that the expression is incorrect. -void UnwrappedLineParser::parseRequiresExpression(FormatToken *RequiresToken) { - assert(FormatTok->getPreviousNonComment() == RequiresToken); - assert(RequiresToken->is(tok::kw_requires) && "'requires' expected"); +void UnwrappedLineParser::parseRequiresExpression() { + assert(FormatTok->is(tok::kw_requires) && "'requires' expected"); - RequiresToken->setFinalizedType(TT_RequiresExpression); + FormatTok->setFinalizedType(TT_RequiresExpression); + nextToken(); if (FormatTok->is(tok::l_paren)) { FormatTok->setFinalizedType(TT_RequiresExpressionLParen); @@ -3676,12 +3671,9 @@ void UnwrappedLineParser::parseConstraintExpression() { bool LambdaThisTimeAllowed = std::exchange(LambdaNextTimeAllowed, false); switch (FormatTok->Tok.getKind()) { - case tok::kw_requires: { - auto RequiresToken = FormatTok; - nextToken(); - parseRequiresExpression(RequiresToken); + case tok::kw_requires: + parseRequiresExpression(); break; - } case tok::l_paren: if (!TopLevelParensAllowed) @@ -3865,7 +3857,7 @@ bool UnwrappedLineParser::parseEnum() { } if (!Style.AllowShortEnumsOnASingleLine && - ShouldBreakBeforeBrace(Style, InitialToken)) { + ShouldBreakBeforeBrace(Style, InitialToken, /*IsJavaRecord=*/false)) { addUnwrappedLine(); } // Parse enum body. @@ -4160,7 +4152,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr, bool IsJavaRecord) { if (ParseAsExpr) { parseChildBlock(); } else { - if (ShouldBreakBeforeBrace(Style, InitialToken)) + if (ShouldBreakBeforeBrace(Style, InitialToken, IsJavaRecord)) addUnwrappedLine(); unsigned AddLevels = Style.IndentAccessModifiers ? 2u : 1u; @@ -4555,6 +4547,23 @@ void UnwrappedLineParser::parseVerilogCaseLabel() { Line->Level = OrigLevel; } +void UnwrappedLineParser::parseVerilogExtern() { + assert( + FormatTok->isOneOf(tok::kw_extern, tok::kw_export, Keywords.kw_import)); + nextToken(); + // "DPI-C" + if (FormatTok->is(tok::string_literal)) + nextToken(); + if (FormatTok->isOneOf(Keywords.kw_context, Keywords.kw_pure)) + nextToken(); + if (Keywords.isVerilogIdentifier(*FormatTok)) + nextToken(); + if (FormatTok->is(tok::equal)) + nextToken(); + if (Keywords.isVerilogHierarchy(*FormatTok)) + parseVerilogHierarchyHeader(); +} + bool UnwrappedLineParser::containsExpansion(const UnwrappedLine &Line) const { for (const auto &N : Line.Tokens) { if (N.Tok->MacroCtx) diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index 8b8ad84..86022d9 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -169,8 +169,8 @@ private: bool parseEnum(); bool parseStructLike(); bool parseRequires(bool SeenEqual); - void parseRequiresClause(FormatToken *RequiresToken); - void parseRequiresExpression(FormatToken *RequiresToken); + void parseRequiresClause(); + void parseRequiresExpression(); void parseConstraintExpression(); void parseCppExportBlock(); void parseNamespaceOrExportBlock(unsigned AddLevels); @@ -205,6 +205,8 @@ private: unsigned parseVerilogHierarchyHeader(); void parseVerilogTable(); void parseVerilogCaseLabel(); + // For import, export, and extern. + void parseVerilogExtern(); std::optional<llvm::SmallVector<llvm::SmallVector<FormatToken *, 8>, 1>> parseMacroCall(); diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index f24b8ab..805bb78 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -35,13 +35,15 @@ WhitespaceManager::Change::Change(const FormatToken &Tok, bool CreateReplacement, SourceRange OriginalWhitespaceRange, int Spaces, unsigned StartOfTokenColumn, + unsigned IndentedFromColumn, unsigned NewlinesBefore, StringRef PreviousLinePostfix, StringRef CurrentLinePrefix, bool IsAligned, bool ContinuesPPDirective, bool IsInsideToken) : Tok(&Tok), CreateReplacement(CreateReplacement), OriginalWhitespaceRange(OriginalWhitespaceRange), - StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore), + StartOfTokenColumn(StartOfTokenColumn), + IndentedFromColumn(IndentedFromColumn), NewlinesBefore(NewlinesBefore), PreviousLinePostfix(PreviousLinePostfix), CurrentLinePrefix(CurrentLinePrefix), IsAligned(IsAligned), ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces), @@ -53,13 +55,15 @@ WhitespaceManager::Change::Change(const FormatToken &Tok, void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces, unsigned StartOfTokenColumn, - bool IsAligned, bool InPPDirective) { + bool IsAligned, bool InPPDirective, + unsigned IndentedFromColumn) { if (Tok.Finalized || (Tok.MacroCtx && Tok.MacroCtx->Role == MR_ExpandedArg)) return; Tok.setDecision((Newlines > 0) ? FD_Break : FD_Continue); Changes.push_back(Change(Tok, /*CreateReplacement=*/true, Tok.WhitespaceRange, - Spaces, StartOfTokenColumn, Newlines, "", "", - IsAligned, InPPDirective && !Tok.IsFirst, + Spaces, StartOfTokenColumn, IndentedFromColumn, + Newlines, "", "", IsAligned, + InPPDirective && !Tok.IsFirst, /*IsInsideToken=*/false)); } @@ -67,11 +71,11 @@ void WhitespaceManager::addUntouchableToken(const FormatToken &Tok, bool InPPDirective) { if (Tok.Finalized || (Tok.MacroCtx && Tok.MacroCtx->Role == MR_ExpandedArg)) return; - Changes.push_back(Change(Tok, /*CreateReplacement=*/false, - Tok.WhitespaceRange, /*Spaces=*/0, - Tok.OriginalColumn, Tok.NewlinesBefore, "", "", - /*IsAligned=*/false, InPPDirective && !Tok.IsFirst, - /*IsInsideToken=*/false)); + Changes.push_back(Change( + Tok, /*CreateReplacement=*/false, Tok.WhitespaceRange, /*Spaces=*/0, + Tok.OriginalColumn, /*IndentedFromColumn=*/0, Tok.NewlinesBefore, "", "", + /*IsAligned=*/false, InPPDirective && !Tok.IsFirst, + /*IsInsideToken=*/false)); } llvm::Error @@ -95,7 +99,8 @@ void WhitespaceManager::replaceWhitespaceInToken( Changes.push_back( Change(Tok, /*CreateReplacement=*/true, SourceRange(Start, Start.getLocWithOffset(ReplaceChars)), Spaces, - std::max(0, Spaces), Newlines, PreviousPostfix, CurrentPrefix, + std::max(0, Spaces), /*IndentedFromColumn=*/0, Newlines, + PreviousPostfix, CurrentPrefix, /*IsAligned=*/true, InPPDirective && !Tok.IsFirst, /*IsInsideToken=*/true)); } @@ -287,6 +292,7 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, unsigned Column, bool RightJustify, ArrayRef<unsigned> Matches, SmallVector<WhitespaceManager::Change, 16> &Changes) { + unsigned OriginalMatchColumn = 0; int Shift = 0; // Set when the shift is applied anywhere in the line. Cleared when the line // ends. @@ -330,21 +336,19 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, // Keep track of the level that should not move with the aligned token. if (ScopeStack.size() == 1u && CurrentChange.NewlinesBefore != 0u && CurrentChange.indentAndNestingLevel() > ScopeStack[0] && - !CurrentChange.IsAligned) { + CurrentChange.IndentedFromColumn < OriginalMatchColumn) { ScopeStack.push_back(CurrentChange.indentAndNestingLevel()); } bool InsideNestedScope = !ScopeStack.empty() && - CurrentChange.indentAndNestingLevel() > ScopeStack[0]; - bool ContinuedStringLiteral = i > Start && - CurrentChange.Tok->is(tok::string_literal) && - Changes[i - 1].Tok->is(tok::string_literal); - bool SkipMatchCheck = InsideNestedScope || ContinuedStringLiteral; + (CurrentChange.indentAndNestingLevel() > ScopeStack[0] || + (CurrentChange.indentAndNestingLevel() == ScopeStack[0] && + CurrentChange.IndentedFromColumn >= OriginalMatchColumn)); if (CurrentChange.NewlinesBefore > 0) { LineShifted = false; - if (!SkipMatchCheck) + if (!InsideNestedScope) Shift = 0; } @@ -352,6 +356,7 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, // spaces it has to be shifted, so the rest of the changes on the line are // shifted by the same amount if (!Matches.empty() && Matches[0] == i) { + OriginalMatchColumn = CurrentChange.StartOfTokenColumn; Shift = Column - (RightJustify ? CurrentChange.TokenLength : 0) - CurrentChange.StartOfTokenColumn; ScopeStack = {CurrentChange.indentAndNestingLevel()}; @@ -365,7 +370,7 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, // not in a scope that should not move. if ((!Matches.empty() && Matches[0] == i) || (ScopeStack.size() == 1u && CurrentChange.NewlinesBefore > 0 && - (ContinuedStringLiteral || InsideNestedScope))) { + InsideNestedScope)) { LineShifted = true; CurrentChange.Spaces += Shift; } @@ -516,7 +521,8 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, }; unsigned I = StartAt; - for (unsigned E = Changes.size(); I != E; ++I) { + const auto E = Changes.size(); + for (; I != E; ++I) { auto &CurrentChange = Changes[I]; if (CurrentChange.indentAndNestingLevel() < IndentAndNestingLevel) break; @@ -591,7 +597,8 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, CurrentChangeWidthRight = CurrentChange.TokenLength; const FormatToken *MatchingParenToEncounter = nullptr; for (unsigned J = I + 1; - J != E && (Changes[J].NewlinesBefore == 0 || MatchingParenToEncounter); + J != E && (Changes[J].NewlinesBefore == 0 || + MatchingParenToEncounter || Changes[J].IsAligned); ++J) { const auto &Change = Changes[J]; const auto *Tok = Change.Tok; @@ -621,7 +628,7 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, // int k = bar( | We still want to align the = | int k = bar( // argument1, | here, even if we can't move | argument1, // argument2); | the following lines. | argument2); - if (static_cast<unsigned>(Change.Spaces) < ChangeWidthStart) + if (Change.IndentedFromColumn < ChangeWidthStart) break; CurrentChangeWidthRight = Change.Spaces - ChangeWidthStart; } else { @@ -659,8 +666,15 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, MatchedIndices.push_back(I); } - EndOfSequence = I; + // Pass entire lines to the function so that it can update the state of all + // tokens that move. + for (EndOfSequence = I; + EndOfSequence < E && Changes[EndOfSequence].NewlinesBefore == 0; + ++EndOfSequence) { + } AlignCurrentSequence(); + // The return value should still be where the level ends. The rest of the line + // may contain stuff to be aligned within an outer level. return I; } @@ -1006,9 +1020,13 @@ void WhitespaceManager::alignTrailingComments() { return; const int Size = Changes.size(); + if (Size == 0) + return; + int MinColumn = 0; int StartOfSequence = 0; bool BreakBeforeNext = false; + bool IsInPP = Changes.front().Tok->Tok.is(tok::hash); int NewLineThreshold = 1; if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Always) NewLineThreshold = Style.AlignTrailingComments.OverEmptyLines + 1; @@ -1017,7 +1035,19 @@ void WhitespaceManager::alignTrailingComments() { auto &C = Changes[I]; if (C.StartOfBlockComment) continue; - Newlines += C.NewlinesBefore; + if (C.NewlinesBefore != 0) { + Newlines += C.NewlinesBefore; + const bool WasInPP = std::exchange( + IsInPP, C.Tok->Tok.is(tok::hash) || (IsInPP && C.IsTrailingComment) || + C.ContinuesPPDirective); + if (IsInPP != WasInPP && !Style.AlignTrailingComments.AlignPPAndNotPP) { + alignTrailingComments(StartOfSequence, I, MinColumn); + MinColumn = 0; + MaxColumn = INT_MAX; + StartOfSequence = I; + Newlines = 0; + } + } if (!C.IsTrailingComment) continue; @@ -1215,7 +1245,10 @@ void WhitespaceManager::alignArrayInitializers() { bool FoundComplete = false; for (unsigned InsideIndex = ChangeIndex + 1; InsideIndex < ChangeEnd; ++InsideIndex) { - if (Changes[InsideIndex].Tok == C.Tok->MatchingParen) { + const auto *Tok = Changes[InsideIndex].Tok; + if (Tok->is(tok::pp_define)) + break; + if (Tok == C.Tok->MatchingParen) { alignArrayInitializers(ChangeIndex, InsideIndex + 1); ChangeIndex = InsideIndex + 1; FoundComplete = true; diff --git a/clang/lib/Format/WhitespaceManager.h b/clang/lib/Format/WhitespaceManager.h index 6d18db7..3e6fa9d 100644 --- a/clang/lib/Format/WhitespaceManager.h +++ b/clang/lib/Format/WhitespaceManager.h @@ -49,9 +49,15 @@ public: /// \p StartOfTokenColumn is the column at which the token will start after /// this replacement. It is needed for determining how \p Spaces is turned /// into tabs and spaces for some format styles. + /// + /// \p IndentedFromColumn is only used when the replacement starts a new + /// line. It should be the column that the position of the line is derived + /// from. It is used for determining what lines the alignment process should + /// move. void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces, unsigned StartOfTokenColumn, bool IsAligned = false, - bool InPPDirective = false); + bool InPPDirective = false, + unsigned IndentedFromColumn = 0); /// Adds information about an unchangeable token's whitespace. /// @@ -104,13 +110,15 @@ public: /// \p PreviousLinePostfix, \p NewlinesBefore line breaks, \p Spaces spaces /// and \p CurrentLinePrefix. /// - /// \p StartOfTokenColumn and \p InPPDirective will be used to lay out - /// trailing comments and escaped newlines. + /// \p StartOfTokenColumn and \p ContinuesPPDirective will be used to lay + /// out trailing comments and escaped newlines. \p IndentedFromColumn will + /// be used to continue aligned lines. Change(const FormatToken &Tok, bool CreateReplacement, SourceRange OriginalWhitespaceRange, int Spaces, - unsigned StartOfTokenColumn, unsigned NewlinesBefore, - StringRef PreviousLinePostfix, StringRef CurrentLinePrefix, - bool IsAligned, bool ContinuesPPDirective, bool IsInsideToken); + unsigned StartOfTokenColumn, unsigned IndentedFromColumn, + unsigned NewlinesBefore, StringRef PreviousLinePostfix, + StringRef CurrentLinePrefix, bool IsAligned, + bool ContinuesPPDirective, bool IsInsideToken); // The kind of the token whose whitespace this change replaces, or in which // this change inserts whitespace. @@ -123,6 +131,11 @@ public: // FormatToken around to query its information. SourceRange OriginalWhitespaceRange; unsigned StartOfTokenColumn; + // Only used when the token is at the start of a line. The column that the + // position of the line is derived from. The alignment procedure moves the + // line when it moves a token in the same unwrapped line that is to the left + // of said column. + unsigned IndentedFromColumn; unsigned NewlinesBefore; std::string PreviousLinePostfix; std::string CurrentLinePrefix; |
