diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Format')
15 files changed, 1398 insertions, 325 deletions
diff --git a/contrib/llvm-project/clang/lib/Format/BreakableToken.cpp b/contrib/llvm-project/clang/lib/Format/BreakableToken.cpp index 15fbe3b6515d..f179ac64de17 100644 --- a/contrib/llvm-project/clang/lib/Format/BreakableToken.cpp +++ b/contrib/llvm-project/clang/lib/Format/BreakableToken.cpp @@ -25,7 +25,7 @@ namespace clang { namespace format { -static const char *const Blanks = " \t\v\f\r"; +static constexpr StringRef Blanks = " \t\v\f\r"; static bool IsBlank(char C) { switch (C) { case ' ': @@ -41,25 +41,27 @@ static bool IsBlank(char C) { static StringRef getLineCommentIndentPrefix(StringRef Comment, const FormatStyle &Style) { - static const char *const KnownCStylePrefixes[] = {"///<", "//!<", "///", "//", - "//!"}; - static const char *const KnownTextProtoPrefixes[] = {"//", "#", "##", "###", - "####"}; - ArrayRef<const char *> KnownPrefixes(KnownCStylePrefixes); + static constexpr StringRef KnownCStylePrefixes[] = {"///<", "//!<", "///", + "//!", "//:", "//"}; + static constexpr StringRef KnownTextProtoPrefixes[] = {"####", "###", "##", + "//", "#"}; + ArrayRef<StringRef> KnownPrefixes(KnownCStylePrefixes); if (Style.Language == FormatStyle::LK_TextProto) KnownPrefixes = KnownTextProtoPrefixes; - StringRef LongestPrefix; + assert(std::is_sorted(KnownPrefixes.begin(), KnownPrefixes.end(), + [](StringRef Lhs, StringRef Rhs) noexcept { + return Lhs.size() > Rhs.size(); + })); + for (StringRef KnownPrefix : KnownPrefixes) { if (Comment.startswith(KnownPrefix)) { - size_t PrefixLength = KnownPrefix.size(); - while (PrefixLength < Comment.size() && Comment[PrefixLength] == ' ') - ++PrefixLength; - if (PrefixLength > LongestPrefix.size()) - LongestPrefix = Comment.substr(0, PrefixLength); + const auto PrefixLength = + Comment.find_first_not_of(' ', KnownPrefix.size()); + return Comment.substr(0, PrefixLength); } } - return LongestPrefix; + return {}; } static BreakableToken::Split @@ -86,22 +88,53 @@ getCommentSplit(StringRef Text, unsigned ContentStartColumn, MaxSplitBytes += BytesInChar; } + // In JavaScript, some @tags can be followed by {, and machinery that parses + // these comments will fail to understand the comment if followed by a line + // break. So avoid ever breaking before a {. + if (Style.Language == FormatStyle::LK_JavaScript) { + StringRef::size_type SpaceOffset = + Text.find_first_of(Blanks, MaxSplitBytes); + if (SpaceOffset != StringRef::npos && SpaceOffset + 1 < Text.size() && + Text[SpaceOffset + 1] == '{') { + MaxSplitBytes = SpaceOffset + 1; + } + } + StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes); static const auto kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\."); + // Some spaces are unacceptable to break on, rewind past them. while (SpaceOffset != StringRef::npos) { + // If a line-comment ends with `\`, the next line continues the comment, + // whether or not it starts with `//`. This is confusing and triggers + // -Wcomment. + // Avoid introducing multiline comments by not allowing a break right + // after '\'. + if (Style.isCpp()) { + StringRef::size_type LastNonBlank = + Text.find_last_not_of(Blanks, SpaceOffset); + if (LastNonBlank != StringRef::npos && Text[LastNonBlank] == '\\') { + SpaceOffset = Text.find_last_of(Blanks, LastNonBlank); + continue; + } + } + // Do not split before a number followed by a dot: this would be interpreted // as a numbered list, which would prevent re-flowing in subsequent passes. - if (kNumberedListRegexp.match(Text.substr(SpaceOffset).ltrim(Blanks))) + if (kNumberedListRegexp.match(Text.substr(SpaceOffset).ltrim(Blanks))) { SpaceOffset = Text.find_last_of(Blanks, SpaceOffset); - // In JavaScript, some @tags can be followed by {, and machinery that parses - // these comments will fail to understand the comment if followed by a line - // break. So avoid ever breaking before a {. - else if (Style.Language == FormatStyle::LK_JavaScript && - SpaceOffset + 1 < Text.size() && Text[SpaceOffset + 1] == '{') + continue; + } + + // Avoid ever breaking before a @tag or a { in JavaScript. + if (Style.Language == FormatStyle::LK_JavaScript && + SpaceOffset + 1 < Text.size() && + (Text[SpaceOffset + 1] == '{' || Text[SpaceOffset + 1] == '@')) { SpaceOffset = Text.find_last_of(Blanks, SpaceOffset); - else - break; + continue; + } + + break; } if (SpaceOffset == StringRef::npos || @@ -718,8 +751,7 @@ bool BreakableBlockComment::mayReflow( } BreakableLineCommentSection::BreakableLineCommentSection( - const FormatToken &Token, unsigned StartColumn, - unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective, + const FormatToken &Token, unsigned StartColumn, bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style) : BreakableComment(Token, StartColumn, InPPDirective, Encoding, Style) { assert(Tok.is(TT_LineComment) && @@ -742,10 +774,7 @@ BreakableLineCommentSection::BreakableLineCommentSection( OriginalPrefix.resize(Lines.size()); for (size_t i = FirstLineIndex, e = Lines.size(); i < e; ++i) { Lines[i] = Lines[i].ltrim(Blanks); - // We need to trim the blanks in case this is not the first line in a - // multiline comment. Then the indent is included in Lines[i]. - StringRef IndentPrefix = - getLineCommentIndentPrefix(Lines[i].ltrim(Blanks), Style); + StringRef IndentPrefix = getLineCommentIndentPrefix(Lines[i], Style); assert((TokenText.startswith("//") || TokenText.startswith("#")) && "unsupported line comment prefix, '//' and '#' are supported"); OriginalPrefix[i] = Prefix[i] = IndentPrefix; @@ -761,9 +790,14 @@ BreakableLineCommentSection::BreakableLineCommentSection( Prefix[i] = "///< "; else if (Prefix[i] == "//!<") Prefix[i] = "//!< "; - else if (Prefix[i] == "#" && - Style.Language == FormatStyle::LK_TextProto) + else if (Prefix[i] == "#") Prefix[i] = "# "; + else if (Prefix[i] == "##") + Prefix[i] = "## "; + else if (Prefix[i] == "###") + Prefix[i] = "### "; + else if (Prefix[i] == "####") + Prefix[i] = "#### "; } Tokens[i] = LineTok; diff --git a/contrib/llvm-project/clang/lib/Format/BreakableToken.h b/contrib/llvm-project/clang/lib/Format/BreakableToken.h index a6691300de3b..41b19f82e9df 100644 --- a/contrib/llvm-project/clang/lib/Format/BreakableToken.h +++ b/contrib/llvm-project/clang/lib/Format/BreakableToken.h @@ -436,7 +436,6 @@ private: class BreakableLineCommentSection : public BreakableComment { public: BreakableLineCommentSection(const FormatToken &Token, unsigned StartColumn, - unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style); diff --git a/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.cpp b/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.cpp index b1497651a8fe..7198671901f3 100644 --- a/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.cpp +++ b/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.cpp @@ -284,7 +284,7 @@ bool ContinuationIndenter::canBreak(const LineState &State) { // The opening "{" of a braced list has to be on the same line as the first // element if it is nested in another braced init list or function call. if (!Current.MustBreakBefore && Previous.is(tok::l_brace) && - Previous.isNot(TT_DictLiteral) && Previous.BlockKind == BK_BracedInit && + Previous.isNot(TT_DictLiteral) && Previous.is(BK_BracedInit) && Previous.Previous && Previous.Previous->isOneOf(tok::l_brace, tok::l_paren, tok::comma)) return false; @@ -400,7 +400,9 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { return true; if (Current.is(TT_SelectorName) && !Previous.is(tok::at) && State.Stack.back().ObjCSelectorNameFound && - State.Stack.back().BreakBeforeParameter) + State.Stack.back().BreakBeforeParameter && + (Style.ObjCBreakBeforeNestedBlockParam || + !Current.startsSequence(TT_SelectorName, tok::colon, tok::caret))) return true; unsigned NewLineColumn = getNewLineColumn(State); @@ -501,7 +503,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { // The following could be precomputed as they do not depend on the state. // However, as they should take effect only if the UnwrappedLine does not fit // into the ColumnLimit, they are checked here in the ContinuationIndenter. - if (Style.ColumnLimit != 0 && Previous.BlockKind == BK_Block && + if (Style.ColumnLimit != 0 && Previous.is(BK_Block) && Previous.is(tok::l_brace) && !Current.isOneOf(tok::r_brace, tok::comment)) return true; @@ -627,7 +629,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, // opening parenthesis. Don't break if it doesn't conserve columns. if (Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak && (Previous.isOneOf(tok::l_paren, TT_TemplateOpener, tok::l_square) || - (Previous.is(tok::l_brace) && Previous.BlockKind != BK_Block && + (Previous.is(tok::l_brace) && Previous.isNot(BK_Block) && Style.Cpp11BracedListStyle)) && State.Column > getNewLineColumn(State) && (!Previous.Previous || !Previous.Previous->isOneOf( @@ -648,7 +650,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, if (Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign && !State.Stack.back().IsCSharpGenericTypeConstraint && Previous.opensScope() && Previous.isNot(TT_ObjCMethodExpr) && - (Current.isNot(TT_LineComment) || Previous.BlockKind == BK_BracedInit)) { + (Current.isNot(TT_LineComment) || Previous.is(BK_BracedInit))) { State.Stack.back().Indent = State.Column + Spaces; State.Stack.back().IsAligned = true; } @@ -783,6 +785,22 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, State.Column = getNewLineColumn(State); + // Add Penalty proportional to amount of whitespace away from FirstColumn + // This tends to penalize several lines that are far-right indented, + // and prefers a line-break prior to such a block, e.g: + // + // Constructor() : + // member(value), looooooooooooooooong_member( + // looooooooooong_call(param_1, param_2, param_3)) + // would then become + // Constructor() : + // member(value), + // looooooooooooooooong_member( + // looooooooooong_call(param_1, param_2, param_3)) + if (State.Column > State.FirstIndent) + Penalty += + Style.PenaltyIndentedWhitespace * (State.Column - State.FirstIndent); + // Indent nested blocks relative to this column, unless in a very specific // JavaScript special case where: // @@ -972,7 +990,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { return (Style.IndentWidth * State.Line->First->IndentLevel) + Style.IndentWidth; - if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block) + if (NextNonComment->is(tok::l_brace) && NextNonComment->is(BK_Block)) return Current.NestingLevel == 0 ? State.FirstIndent : State.Stack.back().Indent; if ((Current.isOneOf(tok::r_brace, tok::r_square) || @@ -982,8 +1000,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { State.Stack.size() > 1) { if (Current.closesBlockOrBlockTypeList(Style)) return State.Stack[State.Stack.size() - 2].NestedBlockIndent; - if (Current.MatchingParen && - Current.MatchingParen->BlockKind == BK_BracedInit) + if (Current.MatchingParen && Current.MatchingParen->is(BK_BracedInit)) return State.Stack[State.Stack.size() - 2].LastSpace; return State.FirstIndent; } @@ -1349,16 +1366,20 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State, State.Stack.back().LastSpace); } - // If BreakBeforeBinaryOperators is set, un-indent a bit to account for - // the operator and keep the operands aligned - if (Style.AlignOperands == FormatStyle::OAS_AlignAfterOperator && - Previous && + if (Previous && (Previous->getPrecedence() == prec::Assignment || Previous->is(tok::kw_return) || (*I == prec::Conditional && Previous->is(tok::question) && Previous->is(TT_ConditionalExpr))) && - !Newline) - NewParenState.UnindentOperator = true; + !Newline) { + // If BreakBeforeBinaryOperators is set, un-indent a bit to account for + // the operator and keep the operands aligned + if (Style.AlignOperands == FormatStyle::OAS_AlignAfterOperator) + NewParenState.UnindentOperator = true; + // Mark indentation as alignment if the expression is aligned. + if (Style.AlignOperands != FormatStyle::OAS_DontAlign) + NewParenState.IsAligned = true; + } // Do not indent relative to the fake parentheses inserted for "." or "->". // This is a special case to make the following to statements consistent: @@ -1417,7 +1438,7 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, State.Stack.back().IsCSharpGenericTypeConstraint) return; - if (Current.MatchingParen && Current.BlockKind == BK_Block) { + if (Current.MatchingParen && Current.is(BK_Block)) { moveStateToNewBlock(State); return; } @@ -1486,9 +1507,8 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, (State.Line->MustBeDeclaration && !BinPackDeclaration) || (!State.Line->MustBeDeclaration && !Style.BinPackArguments) || (Style.ExperimentalAutoDetectBinPacking && - (Current.PackingKind == PPK_OnePerLine || - (!BinPackInconclusiveFunctions && - Current.PackingKind == PPK_Inconclusive))); + (Current.is(PPK_OnePerLine) || + (!BinPackInconclusiveFunctions && Current.is(PPK_Inconclusive)))); if (Current.is(TT_ObjCMethodExpr) && Current.MatchingParen && Style.ObjCBreakBeforeNestedBlockParam) { @@ -1954,8 +1974,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current, switchesFormatting(Current)) return nullptr; return std::make_unique<BreakableLineCommentSection>( - Current, StartColumn, Current.OriginalColumn, !Current.Previous, - /*InPPDirective=*/false, Encoding, Style); + Current, StartColumn, /*InPPDirective=*/false, Encoding, Style); } return nullptr; } diff --git a/contrib/llvm-project/clang/lib/Format/Format.cpp b/contrib/llvm-project/clang/lib/Format/Format.cpp index 0d277a6464af..5f5bb8585ac1 100644 --- a/contrib/llvm-project/clang/lib/Format/Format.cpp +++ b/contrib/llvm-project/clang/lib/Format/Format.cpp @@ -128,6 +128,21 @@ template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> { } }; +template <> struct ScalarEnumerationTraits<FormatStyle::AlignConsecutiveStyle> { + static void enumeration(IO &IO, FormatStyle::AlignConsecutiveStyle &Value) { + IO.enumCase(Value, "None", FormatStyle::ACS_None); + IO.enumCase(Value, "Consecutive", FormatStyle::ACS_Consecutive); + IO.enumCase(Value, "AcrossEmptyLines", FormatStyle::ACS_AcrossEmptyLines); + IO.enumCase(Value, "AcrossComments", FormatStyle::ACS_AcrossComments); + IO.enumCase(Value, "AcrossEmptyLinesAndComments", + FormatStyle::ACS_AcrossEmptyLinesAndComments); + + // For backward compability. + IO.enumCase(Value, "true", FormatStyle::ACS_Consecutive); + IO.enumCase(Value, "false", FormatStyle::ACS_None); + } +}; + template <> struct ScalarEnumerationTraits<FormatStyle::ShortIfStyle> { static void enumeration(IO &IO, FormatStyle::ShortIfStyle &Value) { IO.enumCase(Value, "Never", FormatStyle::SIS_Never); @@ -227,6 +242,18 @@ struct ScalarEnumerationTraits<FormatStyle::BreakInheritanceListStyle> { }; template <> +struct ScalarEnumerationTraits< + FormatStyle::EmptyLineBeforeAccessModifierStyle> { + static void + enumeration(IO &IO, FormatStyle::EmptyLineBeforeAccessModifierStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::ELBAMS_Never); + IO.enumCase(Value, "Leave", FormatStyle::ELBAMS_Leave); + IO.enumCase(Value, "LogicalBlock", FormatStyle::ELBAMS_LogicalBlock); + IO.enumCase(Value, "Always", FormatStyle::ELBAMS_Always); + } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> { static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) { IO.enumCase(Value, "None", FormatStyle::PPDIS_None); @@ -348,6 +375,17 @@ template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> { }; template <> +struct ScalarEnumerationTraits<FormatStyle::SpaceAroundPointerQualifiersStyle> { + static void + enumeration(IO &IO, FormatStyle::SpaceAroundPointerQualifiersStyle &Value) { + IO.enumCase(Value, "Default", FormatStyle::SAPQ_Default); + IO.enumCase(Value, "Before", FormatStyle::SAPQ_Before); + IO.enumCase(Value, "After", FormatStyle::SAPQ_After); + IO.enumCase(Value, "Both", FormatStyle::SAPQ_Both); + } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensOptions> { static void enumeration(IO &IO, FormatStyle::SpaceBeforeParensOptions &Value) { @@ -366,6 +404,26 @@ struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensOptions> { } }; +template <> +struct ScalarEnumerationTraits<FormatStyle::BitFieldColonSpacingStyle> { + static void enumeration(IO &IO, + FormatStyle::BitFieldColonSpacingStyle &Value) { + IO.enumCase(Value, "Both", FormatStyle::BFCS_Both); + IO.enumCase(Value, "None", FormatStyle::BFCS_None); + IO.enumCase(Value, "Before", FormatStyle::BFCS_Before); + IO.enumCase(Value, "After", FormatStyle::BFCS_After); + } +}; + +template <> +struct ScalarEnumerationTraits<FormatStyle::SortJavaStaticImportOptions> { + static void enumeration(IO &IO, + FormatStyle::SortJavaStaticImportOptions &Value) { + IO.enumCase(Value, "Before", FormatStyle::SJSIO_Before); + IO.enumCase(Value, "After", FormatStyle::SJSIO_After); + } +}; + template <> struct MappingTraits<FormatStyle> { static void mapping(IO &IO, FormatStyle &Style) { // When reading, read the language first, we need it for getPredefinedStyle. @@ -464,11 +522,14 @@ template <> struct MappingTraits<FormatStyle> { Style.AlwaysBreakBeforeMultilineStrings); IO.mapOptional("AlwaysBreakTemplateDeclarations", Style.AlwaysBreakTemplateDeclarations); + IO.mapOptional("AttributeMacros", Style.AttributeMacros); IO.mapOptional("BinPackArguments", Style.BinPackArguments); IO.mapOptional("BinPackParameters", Style.BinPackParameters); IO.mapOptional("BraceWrapping", Style.BraceWrapping); IO.mapOptional("BreakBeforeBinaryOperators", Style.BreakBeforeBinaryOperators); + IO.mapOptional("BreakBeforeConceptDeclarations", + Style.BreakBeforeConceptDeclarations); IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces); bool BreakBeforeInheritanceComma = false; @@ -511,10 +572,14 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("DeriveLineEnding", Style.DeriveLineEnding); IO.mapOptional("DerivePointerAlignment", Style.DerivePointerAlignment); IO.mapOptional("DisableFormat", Style.DisableFormat); + IO.mapOptional("EmptyLineBeforeAccessModifier", + Style.EmptyLineBeforeAccessModifier); IO.mapOptional("ExperimentalAutoDetectBinPacking", Style.ExperimentalAutoDetectBinPacking); IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments); IO.mapOptional("ForEachMacros", Style.ForEachMacros); + IO.mapOptional("StatementAttributeLikeMacros", + Style.StatementAttributeLikeMacros); IO.mapOptional("IncludeBlocks", Style.IncludeStyle.IncludeBlocks); IO.mapOptional("IncludeCategories", Style.IncludeStyle.IncludeCategories); IO.mapOptional("IncludeIsMainRegex", Style.IncludeStyle.IncludeIsMainRegex); @@ -525,6 +590,7 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("IndentGotoLabels", Style.IndentGotoLabels); IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives); IO.mapOptional("IndentExternBlock", Style.IndentExternBlock); + IO.mapOptional("IndentRequires", Style.IndentRequires); IO.mapOptional("IndentWidth", Style.IndentWidth); IO.mapOptional("IndentWrappedFunctionNames", Style.IndentWrappedFunctionNames); @@ -558,10 +624,13 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("PenaltyExcessCharacter", Style.PenaltyExcessCharacter); IO.mapOptional("PenaltyReturnTypeOnItsOwnLine", Style.PenaltyReturnTypeOnItsOwnLine); + IO.mapOptional("PenaltyIndentedWhitespace", + Style.PenaltyIndentedWhitespace); IO.mapOptional("PointerAlignment", Style.PointerAlignment); IO.mapOptional("RawStringFormats", Style.RawStringFormats); IO.mapOptional("ReflowComments", Style.ReflowComments); IO.mapOptional("SortIncludes", Style.SortIncludes); + IO.mapOptional("SortJavaStaticImport", Style.SortJavaStaticImport); IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations); IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast); IO.mapOptional("SpaceAfterLogicalNot", Style.SpaceAfterLogicalNot); @@ -569,6 +638,7 @@ template <> struct MappingTraits<FormatStyle> { Style.SpaceAfterTemplateKeyword); IO.mapOptional("SpaceBeforeAssignmentOperators", Style.SpaceBeforeAssignmentOperators); + IO.mapOptional("SpaceBeforeCaseColon", Style.SpaceBeforeCaseColon); IO.mapOptional("SpaceBeforeCpp11BracedList", Style.SpaceBeforeCpp11BracedList); IO.mapOptional("SpaceBeforeCtorInitializerColon", @@ -576,6 +646,8 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("SpaceBeforeInheritanceColon", Style.SpaceBeforeInheritanceColon); IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens); + IO.mapOptional("SpaceAroundPointerQualifiers", + Style.SpaceAroundPointerQualifiers); IO.mapOptional("SpaceBeforeRangeBasedForLoopColon", Style.SpaceBeforeRangeBasedForLoopColon); IO.mapOptional("SpaceInEmptyBlock", Style.SpaceInEmptyBlock); @@ -593,6 +665,7 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets); IO.mapOptional("SpaceBeforeSquareBrackets", Style.SpaceBeforeSquareBrackets); + IO.mapOptional("BitFieldColonSpacing", Style.BitFieldColonSpacing); IO.mapOptional("Standard", Style.Standard); IO.mapOptional("StatementMacros", Style.StatementMacros); IO.mapOptional("TabWidth", Style.TabWidth); @@ -757,6 +830,7 @@ static FormatStyle expandPresets(const FormatStyle &Style) { Expanded.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; Expanded.BraceWrapping.BeforeCatch = true; Expanded.BraceWrapping.BeforeElse = true; + Expanded.BraceWrapping.BeforeLambdaBody = true; break; case FormatStyle::BS_Whitesmiths: Expanded.BraceWrapping.AfterCaseLabel = true; @@ -812,10 +886,10 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align; LLVMStyle.AlignOperands = FormatStyle::OAS_Align; LLVMStyle.AlignTrailingComments = true; - LLVMStyle.AlignConsecutiveAssignments = false; - LLVMStyle.AlignConsecutiveBitFields = false; - LLVMStyle.AlignConsecutiveDeclarations = false; - LLVMStyle.AlignConsecutiveMacros = false; + LLVMStyle.AlignConsecutiveAssignments = FormatStyle::ACS_None; + LLVMStyle.AlignConsecutiveBitFields = FormatStyle::ACS_None; + LLVMStyle.AlignConsecutiveDeclarations = FormatStyle::ACS_None; + LLVMStyle.AlignConsecutiveMacros = FormatStyle::ACS_None; LLVMStyle.AllowAllArgumentsOnNextLine = true; LLVMStyle.AllowAllConstructorInitializersOnNextLine = true; LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true; @@ -830,9 +904,11 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None; LLVMStyle.AlwaysBreakBeforeMultilineStrings = false; LLVMStyle.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_MultiLine; + LLVMStyle.AttributeMacros.push_back("__capability"); LLVMStyle.BinPackArguments = true; LLVMStyle.BinPackParameters = true; LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None; + LLVMStyle.BreakBeforeConceptDeclarations = true; LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; LLVMStyle.BraceWrapping = {/*AfterCaseLabel=*/false, @@ -867,21 +943,23 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.Cpp11BracedListStyle = true; LLVMStyle.DeriveLineEnding = true; LLVMStyle.DerivePointerAlignment = false; + LLVMStyle.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_LogicalBlock; LLVMStyle.ExperimentalAutoDetectBinPacking = false; LLVMStyle.FixNamespaceComments = true; LLVMStyle.ForEachMacros.push_back("foreach"); LLVMStyle.ForEachMacros.push_back("Q_FOREACH"); LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH"); LLVMStyle.IncludeStyle.IncludeCategories = { - {"^\"(llvm|llvm-c|clang|clang-c)/", 2, 0}, - {"^(<|\"(gtest|gmock|isl|json)/)", 3, 0}, - {".*", 1, 0}}; + {"^\"(llvm|llvm-c|clang|clang-c)/", 2, 0, false}, + {"^(<|\"(gtest|gmock|isl|json)/)", 3, 0, false}, + {".*", 1, 0, false}}; LLVMStyle.IncludeStyle.IncludeIsMainRegex = "(Test)?$"; LLVMStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Preserve; LLVMStyle.IndentCaseLabels = false; LLVMStyle.IndentCaseBlocks = false; LLVMStyle.IndentGotoLabels = true; LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None; + LLVMStyle.IndentRequires = false; LLVMStyle.IndentWrappedFunctionNames = false; LLVMStyle.IndentWidth = 2; LLVMStyle.InsertTrailingCommas = FormatStyle::TCS_None; @@ -911,6 +989,8 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SpaceAfterCStyleCast = false; LLVMStyle.SpaceAfterLogicalNot = false; LLVMStyle.SpaceAfterTemplateKeyword = true; + LLVMStyle.SpaceAroundPointerQualifiers = FormatStyle::SAPQ_Default; + LLVMStyle.SpaceBeforeCaseColon = false; LLVMStyle.SpaceBeforeCtorInitializerColon = true; LLVMStyle.SpaceBeforeInheritanceColon = true; LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements; @@ -918,6 +998,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SpaceBeforeAssignmentOperators = true; LLVMStyle.SpaceBeforeCpp11BracedList = false; LLVMStyle.SpaceBeforeSquareBrackets = false; + LLVMStyle.BitFieldColonSpacing = FormatStyle::BFCS_Both; LLVMStyle.SpacesInAngles = false; LLVMStyle.SpacesInConditionalStatement = false; @@ -929,15 +1010,20 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60; LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19; LLVMStyle.PenaltyBreakTemplateDeclaration = prec::Relational; + LLVMStyle.PenaltyIndentedWhitespace = 0; LLVMStyle.DisableFormat = false; LLVMStyle.SortIncludes = true; + LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before; LLVMStyle.SortUsingDeclarations = true; + LLVMStyle.StatementAttributeLikeMacros.push_back("Q_EMIT"); LLVMStyle.StatementMacros.push_back("Q_UNUSED"); LLVMStyle.StatementMacros.push_back("QT_REQUIRE_VERSION"); LLVMStyle.WhitespaceSensitiveMacros.push_back("STRINGIZE"); LLVMStyle.WhitespaceSensitiveMacros.push_back("PP_STRINGIZE"); LLVMStyle.WhitespaceSensitiveMacros.push_back("BOOST_PP_STRINGIZE"); + LLVMStyle.WhitespaceSensitiveMacros.push_back("NS_SWIFT_NAME"); + LLVMStyle.WhitespaceSensitiveMacros.push_back("CF_SWIFT_NAME"); // Defaults that differ when not C++. if (Language == FormatStyle::LK_TableGen) { @@ -966,10 +1052,10 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { GoogleStyle.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes; GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true; GoogleStyle.DerivePointerAlignment = true; - GoogleStyle.IncludeStyle.IncludeCategories = {{"^<ext/.*\\.h>", 2, 0}, - {"^<.*\\.h>", 1, 0}, - {"^<.*", 2, 0}, - {".*", 3, 0}}; + GoogleStyle.IncludeStyle.IncludeCategories = {{"^<ext/.*\\.h>", 2, 0, false}, + {"^<.*\\.h>", 1, 0, false}, + {"^<.*", 2, 0, false}, + {".*", 3, 0, false}}; GoogleStyle.IncludeStyle.IncludeIsMainRegex = "([-_](test|unittest))?$"; GoogleStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup; GoogleStyle.IndentCaseLabels = true; @@ -1275,20 +1361,23 @@ bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language, return true; } -std::error_code parseConfiguration(StringRef Text, FormatStyle *Style) { +std::error_code parseConfiguration(llvm::MemoryBufferRef Config, + FormatStyle *Style, + bool AllowUnknownOptions) { assert(Style); FormatStyle::LanguageKind Language = Style->Language; assert(Language != FormatStyle::LK_None); - if (Text.trim().empty()) + if (Config.getBuffer().trim().empty()) return make_error_code(ParseError::Error); Style->StyleSet.Clear(); std::vector<FormatStyle> Styles; - llvm::yaml::Input Input(Text); + llvm::yaml::Input Input(Config); // DocumentListTraits<vector<FormatStyle>> uses the context to get default // values for the fields, keys for which are missing from the configuration. // Mapping also uses the context to get the language to find the correct // base style. Input.setContext(Style); + Input.setAllowUnknownKeys(AllowUnknownOptions); Input >> Styles; if (Input.error()) return Input.error(); @@ -1562,9 +1651,9 @@ private: continue; FormatToken *Tok = AnnotatedLines[i]->First->Next; while (Tok->Next) { - if (Tok->PackingKind == PPK_BinPacked) + if (Tok->is(PPK_BinPacked)) HasBinPackedFunction = true; - if (Tok->PackingKind == PPK_OnePerLine) + if (Tok->is(PPK_OnePerLine)) HasOnePerLineFunction = true; Tok = Tok->Next; @@ -1980,6 +2069,10 @@ private: }; for (auto Line : AnnotatedLines) { + if (Line->First && (Line->First->TokenText.startswith("#") || + Line->First->TokenText == "__pragma" || + Line->First->TokenText == "_Pragma")) + continue; for (const FormatToken *FormatTok = Line->First; FormatTok; FormatTok = FormatTok->Next) { if ((FormatTok->Previous && FormatTok->Previous->is(tok::at) && @@ -2132,7 +2225,8 @@ static void sortCppIncludes(const FormatStyle &Style, // Deduplicate #includes. Indices.erase(std::unique(Indices.begin(), Indices.end(), [&](unsigned LHSI, unsigned RHSI) { - return Includes[LHSI].Text == Includes[RHSI].Text; + return Includes[LHSI].Text.trim() == + Includes[RHSI].Text.trim(); }), Indices.end()); @@ -2191,7 +2285,9 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code, StringRef FileName, tooling::Replacements &Replaces, unsigned *Cursor) { - unsigned Prev = 0; + unsigned Prev = llvm::StringSwitch<size_t>(Code) + .StartsWith("\xEF\xBB\xBF", 3) // UTF-8 BOM + .Default(0); unsigned SearchFrom = 0; llvm::Regex IncludeRegex(CppIncludeRegexPattern); SmallVector<StringRef, 4> Matches; @@ -2227,7 +2323,8 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code, Style.IncludeStyle.IncludeBlocks == tooling::IncludeStyle::IBS_Regroup); - if (!FormattingOff && !Line.endswith("\\")) { + bool MergeWithNextLine = Trimmed.endswith("\\"); + if (!FormattingOff && !MergeWithNextLine) { if (IncludeRegex.match(Line, &Matches)) { StringRef IncludeName = Matches[2]; int Category = Categories.getIncludePriority( @@ -2243,12 +2340,17 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code, sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Code, Replaces, Cursor); IncludesInBlock.clear(); - FirstIncludeBlock = false; + if (Trimmed.startswith("#pragma hdrstop")) // Precompiled headers. + FirstIncludeBlock = true; + else + FirstIncludeBlock = false; } - Prev = Pos + 1; } if (Pos == StringRef::npos || Pos + 1 == Code.size()) break; + + if (!MergeWithNextLine) + Prev = Pos + 1; SearchFrom = Pos + 1; } if (!IncludesInBlock.empty()) { @@ -2297,12 +2399,16 @@ static void sortJavaImports(const FormatStyle &Style, JavaImportGroups.push_back( findJavaImportGroup(Style, Imports[i].Identifier)); } + bool StaticImportAfterNormalImport = + Style.SortJavaStaticImport == FormatStyle::SJSIO_After; llvm::sort(Indices, [&](unsigned LHSI, unsigned RHSI) { // Negating IsStatic to push static imports above non-static imports. - return std::make_tuple(!Imports[LHSI].IsStatic, JavaImportGroups[LHSI], - Imports[LHSI].Identifier) < - std::make_tuple(!Imports[RHSI].IsStatic, JavaImportGroups[RHSI], - Imports[RHSI].Identifier); + return std::make_tuple(!Imports[LHSI].IsStatic ^ + StaticImportAfterNormalImport, + JavaImportGroups[LHSI], Imports[LHSI].Identifier) < + std::make_tuple(!Imports[RHSI].IsStatic ^ + StaticImportAfterNormalImport, + JavaImportGroups[RHSI], Imports[RHSI].Identifier); }); // Deduplicate imports. @@ -2726,6 +2832,7 @@ LangOptions getFormattingLangOpts(const FormatStyle &Style) { LangOpts.ObjC = 1; LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally. LangOpts.DeclSpecKeyword = 1; // To get __declspec. + LangOpts.C99 = 1; // To get kw_restrict for non-underscore-prefixed restrict. return LangOpts; } @@ -2787,8 +2894,8 @@ const char *DefaultFallbackStyle = "LLVM"; llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, StringRef FallbackStyleName, - StringRef Code, - llvm::vfs::FileSystem *FS) { + StringRef Code, llvm::vfs::FileSystem *FS, + bool AllowUnknownOptions) { if (!FS) { FS = llvm::vfs::getRealFileSystem().get(); } @@ -2800,7 +2907,9 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, if (StyleName.startswith("{")) { // Parse YAML/JSON style from the command line. - if (std::error_code ec = parseConfiguration(StyleName, &Style)) + if (std::error_code ec = parseConfiguration( + llvm::MemoryBufferRef(StyleName, "<command-line>"), &Style, + AllowUnknownOptions)) return make_string_error("Error parsing -style: " + ec.message()); return Style; } @@ -2845,7 +2954,7 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, if (std::error_code EC = Text.getError()) return make_string_error(EC.message()); if (std::error_code ec = - parseConfiguration(Text.get()->getBuffer(), &Style)) { + parseConfiguration(*Text.get(), &Style, AllowUnknownOptions)) { if (ec == ParseError::Unsuitable) { if (!UnsuitableConfigFiles.empty()) UnsuitableConfigFiles.append(", "); diff --git a/contrib/llvm-project/clang/lib/Format/FormatInternal.h b/contrib/llvm-project/clang/lib/Format/FormatInternal.h index 3aa616da23d8..9043ce32e9e3 100644 --- a/contrib/llvm-project/clang/lib/Format/FormatInternal.h +++ b/contrib/llvm-project/clang/lib/Format/FormatInternal.h @@ -16,7 +16,6 @@ #define LLVM_CLANG_LIB_FORMAT_FORMATINTERNAL_H #include "BreakableToken.h" -#include "clang/Tooling/Core/Lookup.h" #include <utility> namespace clang { diff --git a/contrib/llvm-project/clang/lib/Format/FormatToken.cpp b/contrib/llvm-project/clang/lib/Format/FormatToken.cpp index 7d792974cd57..8e4994f4c0d5 100644 --- a/contrib/llvm-project/clang/lib/Format/FormatToken.cpp +++ b/contrib/llvm-project/clang/lib/Format/FormatToken.cpp @@ -62,6 +62,7 @@ bool FormatToken::isSimpleTypeSpecifier() const { case tok::kw_char32_t: case tok::kw_typeof: case tok::kw_decltype: + case tok::kw__Atomic: return true; default: return false; @@ -85,8 +86,8 @@ unsigned CommaSeparatedList::formatAfterToken(LineState &State, const FormatToken *LBrace = State.NextToken->Previous->getPreviousNonComment(); if (!LBrace || !LBrace->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || - LBrace->BlockKind == BK_Block || LBrace->getType() == TT_DictLiteral || - LBrace->Next->getType() == TT_DesignatedInitializerPeriod) + LBrace->is(BK_Block) || LBrace->is(TT_DictLiteral) || + LBrace->Next->is(TT_DesignatedInitializerPeriod)) return 0; // Calculate the number of code points we have to format this list. As the diff --git a/contrib/llvm-project/clang/lib/Format/FormatToken.h b/contrib/llvm-project/clang/lib/Format/FormatToken.h index b132a3e84da5..2f53b338379d 100644 --- a/contrib/llvm-project/clang/lib/Format/FormatToken.h +++ b/contrib/llvm-project/clang/lib/Format/FormatToken.h @@ -29,6 +29,7 @@ namespace format { TYPE(ArrayInitializerLSquare) \ TYPE(ArraySubscriptLSquare) \ TYPE(AttributeColon) \ + TYPE(AttributeMacro) \ TYPE(AttributeParen) \ TYPE(AttributeSquare) \ TYPE(BinaryOperator) \ @@ -39,6 +40,7 @@ namespace format { TYPE(ConflictAlternative) \ TYPE(ConflictEnd) \ TYPE(ConflictStart) \ + TYPE(ConstraintJunctions) \ TYPE(CtorInitializerColon) \ TYPE(CtorInitializerComma) \ TYPE(DesignatedInitializerLSquare) \ @@ -67,6 +69,9 @@ namespace format { TYPE(JsTypeColon) \ TYPE(JsTypeOperator) \ TYPE(JsTypeOptionalQuestion) \ + TYPE(JsAndAndEqual) \ + TYPE(JsPipePipeEqual) \ + TYPE(JsNullishCoalescingEqual) \ TYPE(LambdaArrow) \ TYPE(LambdaLBrace) \ TYPE(LambdaLSquare) \ @@ -91,6 +96,7 @@ namespace format { TYPE(RegexLiteral) \ TYPE(SelectorName) \ TYPE(StartOfName) \ + TYPE(StatementAttributeLikeMacro) \ TYPE(StatementMacro) \ TYPE(StructuredBindingLSquare) \ TYPE(TemplateCloser) \ @@ -100,6 +106,7 @@ namespace format { TYPE(TrailingAnnotation) \ TYPE(TrailingReturnArrow) \ TYPE(TrailingUnaryOperator) \ + TYPE(TypeDeclarationParen) \ TYPE(TypenameMacro) \ TYPE(UnaryOperator) \ TYPE(UntouchableMacroFunc) \ @@ -116,7 +123,7 @@ namespace format { /// Determines the semantic type of a syntactic token, e.g. whether "<" is a /// template opener or binary operator. -enum TokenType { +enum TokenType : uint8_t { #define TYPE(X) TT_##X, LIST_TOKEN_TYPES #undef TYPE @@ -134,80 +141,216 @@ enum ParameterPackingKind { PPK_BinPacked, PPK_OnePerLine, PPK_Inconclusive }; enum FormatDecision { FD_Unformatted, FD_Continue, FD_Break }; +/// Roles a token can take in a configured macro expansion. +enum MacroRole { + /// The token was expanded from a macro argument when formatting the expanded + /// token sequence. + MR_ExpandedArg, + /// The token is part of a macro argument that was previously formatted as + /// expansion when formatting the unexpanded macro call. + MR_UnexpandedArg, + /// The token was expanded from a macro definition, and is not visible as part + /// of the macro call. + MR_Hidden, +}; + +struct FormatToken; + +/// Contains information on the token's role in a macro expansion. +/// +/// Given the following definitions: +/// A(X) = [ X ] +/// B(X) = < X > +/// C(X) = X +/// +/// Consider the macro call: +/// A({B(C(C(x)))}) -> [{<x>}] +/// +/// In this case, the tokens of the unexpanded macro call will have the +/// following relevant entries in their macro context (note that formatting +/// the unexpanded macro call happens *after* formatting the expanded macro +/// call): +/// A( { B( C( C(x) ) ) } ) +/// Role: NN U NN NN NNUN N N U N (N=None, U=UnexpandedArg) +/// +/// [ { < x > } ] +/// Role: H E H E H E H (H=Hidden, E=ExpandedArg) +/// ExpandedFrom[0]: A A A A A A A +/// ExpandedFrom[1]: B B B +/// ExpandedFrom[2]: C +/// ExpandedFrom[3]: C +/// StartOfExpansion: 1 0 1 2 0 0 0 +/// EndOfExpansion: 0 0 0 2 1 0 1 +struct MacroExpansion { + MacroExpansion(MacroRole Role) : Role(Role) {} + + /// The token's role in the macro expansion. + /// When formatting an expanded macro, all tokens that are part of macro + /// arguments will be MR_ExpandedArg, while all tokens that are not visible in + /// the macro call will be MR_Hidden. + /// When formatting an unexpanded macro call, all tokens that are part of + /// macro arguments will be MR_UnexpandedArg. + MacroRole Role; + + /// The stack of macro call identifier tokens this token was expanded from. + llvm::SmallVector<FormatToken *, 1> ExpandedFrom; + + /// The number of expansions of which this macro is the first entry. + unsigned StartOfExpansion = 0; + + /// The number of currently open expansions in \c ExpandedFrom this macro is + /// the last token in. + unsigned EndOfExpansion = 0; +}; + class TokenRole; class AnnotatedLine; /// A wrapper around a \c Token storing information about the /// whitespace characters preceding it. struct FormatToken { - FormatToken() {} + FormatToken() + : HasUnescapedNewline(false), IsMultiline(false), IsFirst(false), + MustBreakBefore(false), IsUnterminatedLiteral(false), + CanBreakBefore(false), ClosesTemplateDeclaration(false), + StartsBinaryExpression(false), EndsBinaryExpression(false), + PartOfMultiVariableDeclStmt(false), ContinuesLineCommentSection(false), + Finalized(false), BlockKind(BK_Unknown), Decision(FD_Unformatted), + PackingKind(PPK_Inconclusive), Type(TT_Unknown) {} /// The \c Token. Token Tok; - /// The number of newlines immediately before the \c Token. + /// The raw text of the token. /// - /// This can be used to determine what the user wrote in the original code - /// and thereby e.g. leave an empty line between two function definitions. - unsigned NewlinesBefore = 0; + /// Contains the raw token text without leading whitespace and without leading + /// escaped newlines. + StringRef TokenText; - /// Whether there is at least one unescaped newline before the \c - /// Token. - bool HasUnescapedNewline = false; + /// A token can have a special role that can carry extra information + /// about the token's formatting. + /// FIXME: Make FormatToken for parsing and AnnotatedToken two different + /// classes and make this a unique_ptr in the AnnotatedToken class. + std::shared_ptr<TokenRole> Role; /// The range of the whitespace immediately preceding the \c Token. SourceRange WhitespaceRange; - /// The offset just past the last '\n' in this token's leading - /// whitespace (relative to \c WhiteSpaceStart). 0 if there is no '\n'. - unsigned LastNewlineOffset = 0; - - /// The width of the non-whitespace parts of the token (or its first - /// line for multi-line tokens) in columns. - /// We need this to correctly measure number of columns a token spans. - unsigned ColumnWidth = 0; - - /// Contains the width in columns of the last line of a multi-line - /// token. - unsigned LastLineColumnWidth = 0; + /// Whether there is at least one unescaped newline before the \c + /// Token. + unsigned HasUnescapedNewline : 1; /// Whether the token text contains newlines (escaped or not). - bool IsMultiline = false; + unsigned IsMultiline : 1; /// Indicates that this is the first token of the file. - bool IsFirst = false; + unsigned IsFirst : 1; /// Whether there must be a line break before this token. /// /// This happens for example when a preprocessor directive ended directly /// before the token. - bool MustBreakBefore = false; + unsigned MustBreakBefore : 1; - /// The raw text of the token. + /// Set to \c true if this token is an unterminated literal. + unsigned IsUnterminatedLiteral : 1; + + /// \c true if it is allowed to break before this token. + unsigned CanBreakBefore : 1; + + /// \c true if this is the ">" of "template<..>". + unsigned ClosesTemplateDeclaration : 1; + + /// \c true if this token starts a binary expression, i.e. has at least + /// one fake l_paren with a precedence greater than prec::Unknown. + unsigned StartsBinaryExpression : 1; + /// \c true if this token ends a binary expression. + unsigned EndsBinaryExpression : 1; + + /// Is this token part of a \c DeclStmt defining multiple variables? /// - /// Contains the raw token text without leading whitespace and without leading - /// escaped newlines. - StringRef TokenText; + /// Only set if \c Type == \c TT_StartOfName. + unsigned PartOfMultiVariableDeclStmt : 1; - /// Set to \c true if this token is an unterminated literal. - bool IsUnterminatedLiteral = 0; + /// Does this line comment continue a line comment section? + /// + /// Only set to true if \c Type == \c TT_LineComment. + unsigned ContinuesLineCommentSection : 1; + + /// If \c true, this token has been fully formatted (indented and + /// potentially re-formatted inside), and we do not allow further formatting + /// changes. + unsigned Finalized : 1; +private: /// Contains the kind of block if this token is a brace. - BraceBlockKind BlockKind = BK_Unknown; + unsigned BlockKind : 2; + +public: + BraceBlockKind getBlockKind() const { + return static_cast<BraceBlockKind>(BlockKind); + } + void setBlockKind(BraceBlockKind BBK) { + BlockKind = BBK; + assert(getBlockKind() == BBK && "BraceBlockKind overflow!"); + } +private: + /// Stores the formatting decision for the token once it was made. + unsigned Decision : 2; + +public: + FormatDecision getDecision() const { + return static_cast<FormatDecision>(Decision); + } + void setDecision(FormatDecision D) { + Decision = D; + assert(getDecision() == D && "FormatDecision overflow!"); + } + +private: + /// If this is an opening parenthesis, how are the parameters packed? + unsigned PackingKind : 2; + +public: + ParameterPackingKind getPackingKind() const { + return static_cast<ParameterPackingKind>(PackingKind); + } + void setPackingKind(ParameterPackingKind K) { + PackingKind = K; + assert(getPackingKind() == K && "ParameterPackingKind overflow!"); + } + +private: + TokenType Type; + +public: /// Returns the token's type, e.g. whether "<" is a template opener or /// binary operator. TokenType getType() const { return Type; } void setType(TokenType T) { Type = T; } - /// The number of spaces that should be inserted before this token. - unsigned SpacesRequiredBefore = 0; + /// The number of newlines immediately before the \c Token. + /// + /// This can be used to determine what the user wrote in the original code + /// and thereby e.g. leave an empty line between two function definitions. + unsigned NewlinesBefore = 0; - /// \c true if it is allowed to break before this token. - bool CanBreakBefore = false; + /// The offset just past the last '\n' in this token's leading + /// whitespace (relative to \c WhiteSpaceStart). 0 if there is no '\n'. + unsigned LastNewlineOffset = 0; - /// \c true if this is the ">" of "template<..>". - bool ClosesTemplateDeclaration = false; + /// The width of the non-whitespace parts of the token (or its first + /// line for multi-line tokens) in columns. + /// We need this to correctly measure number of columns a token spans. + unsigned ColumnWidth = 0; + + /// Contains the width in columns of the last line of a multi-line + /// token. + unsigned LastLineColumnWidth = 0; + + /// The number of spaces that should be inserted before this token. + unsigned SpacesRequiredBefore = 0; /// Number of parameters, if this is "(", "[" or "<". unsigned ParameterCount = 0; @@ -220,13 +363,6 @@ struct FormatToken { /// the surrounding bracket. tok::TokenKind ParentBracket = tok::unknown; - /// A token can have a special role that can carry extra information - /// about the token's formatting. - std::unique_ptr<TokenRole> Role; - - /// If this is an opening parenthesis, how are the parameters packed? - ParameterPackingKind PackingKind = PPK_Inconclusive; - /// The total length of the unwrapped line up to and including this /// token. unsigned TotalLength = 0; @@ -280,12 +416,6 @@ struct FormatToken { /// Insert this many fake ) after this token for correct indentation. unsigned FakeRParens = 0; - /// \c true if this token starts a binary expression, i.e. has at least - /// one fake l_paren with a precedence greater than prec::Unknown. - bool StartsBinaryExpression = false; - /// \c true if this token ends a binary expression. - bool EndsBinaryExpression = false; - /// If this is an operator (or "."/"->") in a sequence of operators /// with the same precedence, contains the 0-based operator index. unsigned OperatorIndex = 0; @@ -294,16 +424,6 @@ struct FormatToken { /// with the same precedence, points to the next operator. FormatToken *NextOperator = nullptr; - /// Is this token part of a \c DeclStmt defining multiple variables? - /// - /// Only set if \c Type == \c TT_StartOfName. - bool PartOfMultiVariableDeclStmt = false; - - /// Does this line comment continue a line comment section? - /// - /// Only set to true if \c Type == \c TT_LineComment. - bool ContinuesLineCommentSection = false; - /// If this is a bracket, this points to the matching one. FormatToken *MatchingParen = nullptr; @@ -317,16 +437,12 @@ struct FormatToken { /// in it. SmallVector<AnnotatedLine *, 1> Children; - /// Stores the formatting decision for the token once it was made. - FormatDecision Decision = FD_Unformatted; - - /// If \c true, this token has been fully formatted (indented and - /// potentially re-formatted inside), and we do not allow further formatting - /// changes. - bool Finalized = false; + // Contains all attributes related to how this token takes part + // in a configured macro expansion. + llvm::Optional<MacroExpansion> MacroCtx; bool is(tok::TokenKind Kind) const { return Tok.is(Kind); } - bool is(TokenType TT) const { return Type == TT; } + bool is(TokenType TT) const { return getType() == TT; } bool is(const IdentifierInfo *II) const { return II && II == Tok.getIdentifierInfo(); } @@ -334,6 +450,9 @@ struct FormatToken { return Tok.getIdentifierInfo() && Tok.getIdentifierInfo()->getPPKeywordID() == Kind; } + bool is(BraceBlockKind BBK) const { return getBlockKind() == BBK; } + bool is(ParameterPackingKind PPK) const { return getPackingKind() == PPK; } + template <typename A, typename B> bool isOneOf(A K1, B K2) const { return is(K1) || is(K2); } @@ -349,7 +468,7 @@ struct FormatToken { } bool closesScopeAfterBlock() const { - if (BlockKind == BK_Block) + if (getBlockKind() == BK_Block) return true; if (closesScope()) return Previous->closesScopeAfterBlock(); @@ -385,6 +504,13 @@ struct FormatToken { (!ColonRequired || (Next && Next->is(tok::colon))); } + bool canBePointerOrReferenceQualifier() const { + return isOneOf(tok::kw_const, tok::kw_restrict, tok::kw_volatile, + tok::kw___attribute, tok::kw__Nonnull, tok::kw__Nullable, + tok::kw__Null_unspecified, tok::kw___ptr32, tok::kw___ptr64, + TT_AttributeMacro); + } + /// Determine whether the token is a simple-type-specifier. bool isSimpleTypeSpecifier() const; @@ -463,7 +589,10 @@ struct FormatToken { case tok::kw_decltype: case tok::kw_noexcept: case tok::kw_static_assert: + case tok::kw__Atomic: case tok::kw___attribute: + case tok::kw___underlying_type: + case tok::kw_requires: return true; default: return false; @@ -519,13 +648,13 @@ struct FormatToken { /// list that should be indented with a block indent. bool opensBlockOrBlockTypeList(const FormatStyle &Style) const { // C# Does not indent object initialisers as continuations. - if (is(tok::l_brace) && BlockKind == BK_BracedInit && Style.isCSharp()) + if (is(tok::l_brace) && getBlockKind() == BK_BracedInit && Style.isCSharp()) return true; if (is(TT_TemplateString) && opensScope()) return true; return is(TT_ArrayInitializerLSquare) || is(TT_ProtoExtensionLSquare) || (is(tok::l_brace) && - (BlockKind == BK_Block || is(TT_DictLiteral) || + (getBlockKind() == BK_Block || is(TT_DictLiteral) || (!Style.Cpp11BracedListStyle && NestingLevel == 0))) || (is(tok::less) && (Style.Language == FormatStyle::LK_Proto || Style.Language == FormatStyle::LK_TextProto)); @@ -566,10 +695,12 @@ struct FormatToken { : nullptr; } + void copyFrom(const FormatToken &Tok) { *this = Tok; } + private: - // Disallow copying. + // Only allow copying via the explicit copyFrom method. FormatToken(const FormatToken &) = delete; - void operator=(const FormatToken &) = delete; + FormatToken &operator=(const FormatToken &) = default; template <typename A, typename... Ts> bool startsSequenceInternal(A K1, Ts... Tokens) const { @@ -596,8 +727,6 @@ private: return Previous->endsSequenceInternal(K1, Tokens...); return is(K1) && Previous && Previous->endsSequenceInternal(Tokens...); } - - TokenType Type = TT_Unknown; }; class ContinuationIndenter; diff --git a/contrib/llvm-project/clang/lib/Format/FormatTokenLexer.cpp b/contrib/llvm-project/clang/lib/Format/FormatTokenLexer.cpp index 1fd153d1112e..e9b096370dbb 100644 --- a/contrib/llvm-project/clang/lib/Format/FormatTokenLexer.cpp +++ b/contrib/llvm-project/clang/lib/Format/FormatTokenLexer.cpp @@ -33,12 +33,14 @@ FormatTokenLexer::FormatTokenLexer( Encoding(Encoding), Allocator(Allocator), FirstInLineIndex(0), FormattingDisabled(false), MacroBlockBeginRegex(Style.MacroBlockBegin), MacroBlockEndRegex(Style.MacroBlockEnd) { - Lex.reset(new Lexer(ID, SourceMgr.getBuffer(ID), SourceMgr, + Lex.reset(new Lexer(ID, SourceMgr.getBufferOrFake(ID), SourceMgr, getFormattingLangOpts(Style))); Lex->SetKeepWhitespaceMode(true); for (const std::string &ForEachMacro : Style.ForEachMacros) Macros.insert({&IdentTable.get(ForEachMacro), TT_ForEachMacro}); + for (const std::string &AttributeMacro : Style.AttributeMacros) + Macros.insert({&IdentTable.get(AttributeMacro), TT_AttributeMacro}); for (const std::string &StatementMacro : Style.StatementMacros) Macros.insert({&IdentTable.get(StatementMacro), TT_StatementMacro}); for (const std::string &TypenameMacro : Style.TypenameMacros) @@ -50,6 +52,10 @@ FormatTokenLexer::FormatTokenLexer( Macros.insert( {&IdentTable.get(WhitespaceSensitiveMacro), TT_UntouchableMacroFunc}); } + for (const std::string &StatementAttributeLikeMacro : + Style.StatementAttributeLikeMacros) + Macros.insert({&IdentTable.get(StatementAttributeLikeMacro), + TT_StatementAttributeLikeMacro}); } ArrayRef<FormatToken *> FormatTokenLexer::lex() { @@ -119,6 +125,10 @@ void FormatTokenLexer::tryMergePreviousTokens() { tok::period}; static const tok::TokenKind JSNullishOperator[] = {tok::question, tok::question}; + static const tok::TokenKind JSNullishEqual[] = {tok::question, + tok::question, tok::equal}; + static const tok::TokenKind JSPipePipeEqual[] = {tok::pipepipe, tok::equal}; + static const tok::TokenKind JSAndAndEqual[] = {tok::ampamp, tok::equal}; // FIXME: Investigate what token type gives the correct operator priority. if (tryMergeTokens(JSIdentity, TT_BinaryOperator)) @@ -146,6 +156,13 @@ void FormatTokenLexer::tryMergePreviousTokens() { Tokens.back()->Tok.setKind(tok::period); return; } + if (tryMergeTokens(JSAndAndEqual, TT_JsAndAndEqual) || + tryMergeTokens(JSPipePipeEqual, TT_JsPipePipeEqual) || + tryMergeTokens(JSNullishEqual, TT_JsNullishCoalescingEqual)) { + // Treat like the "=" assignment operator. + Tokens.back()->Tok.setKind(tok::equal); + return; + } if (tryMergeJSPrivateIdentifier()) return; } @@ -399,7 +416,7 @@ bool FormatTokenLexer::tryTransformTryUsageForC() { if (!Try->is(tok::kw_try)) return false; auto &Next = *(Tokens.end() - 1); - if (Next->isOneOf(tok::l_brace, tok::colon)) + if (Next->isOneOf(tok::l_brace, tok::colon, tok::hash, tok::comment)) return false; if (Tokens.size() > 2) { @@ -761,7 +778,7 @@ bool FormatTokenLexer::tryMergeConflictMarkers() { unsigned FirstInLineOffset; std::tie(ID, FirstInLineOffset) = SourceMgr.getDecomposedLoc( Tokens[FirstInLineIndex]->getStartOfNonWhitespace()); - StringRef Buffer = SourceMgr.getBuffer(ID)->getBuffer(); + StringRef Buffer = SourceMgr.getBufferOrFake(ID).getBuffer(); // Calculate the offset of the start of the current line. auto LineOffset = Buffer.rfind('\n', FirstInLineOffset); if (LineOffset == StringRef::npos) { diff --git a/contrib/llvm-project/clang/lib/Format/MacroExpander.cpp b/contrib/llvm-project/clang/lib/Format/MacroExpander.cpp new file mode 100644 index 000000000000..e50c80446963 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Format/MacroExpander.cpp @@ -0,0 +1,224 @@ +//===--- MacroExpander.cpp - Format C++ code --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the implementation of MacroExpander, which handles macro +/// configuration and expansion while formatting. +/// +//===----------------------------------------------------------------------===// + +#include "Macros.h" + +#include "Encoding.h" +#include "FormatToken.h" +#include "FormatTokenLexer.h" +#include "clang/Basic/TokenKinds.h" +#include "clang/Format/Format.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang { +namespace format { + +struct MacroExpander::Definition { + StringRef Name; + SmallVector<FormatToken *, 8> Params; + SmallVector<FormatToken *, 8> Body; + + // Map from each argument's name to its position in the argument list. + // With "M(x, y) x + y": + // x -> 0 + // y -> 1 + llvm::StringMap<size_t> ArgMap; + + bool ObjectLike = true; +}; + +class MacroExpander::DefinitionParser { +public: + DefinitionParser(ArrayRef<FormatToken *> Tokens) : Tokens(Tokens) { + assert(!Tokens.empty()); + Current = Tokens[0]; + } + + // Parse the token stream and return the corresonding Definition object. + // Returns an empty definition object with a null-Name on error. + MacroExpander::Definition parse() { + if (!Current->is(tok::identifier)) + return {}; + Def.Name = Current->TokenText; + nextToken(); + if (Current->is(tok::l_paren)) { + Def.ObjectLike = false; + if (!parseParams()) + return {}; + } + if (!parseExpansion()) + return {}; + + return Def; + } + +private: + bool parseParams() { + assert(Current->is(tok::l_paren)); + nextToken(); + while (Current->is(tok::identifier)) { + Def.Params.push_back(Current); + Def.ArgMap[Def.Params.back()->TokenText] = Def.Params.size() - 1; + nextToken(); + if (Current->isNot(tok::comma)) + break; + nextToken(); + } + if (Current->isNot(tok::r_paren)) + return false; + nextToken(); + return true; + } + + bool parseExpansion() { + if (!Current->isOneOf(tok::equal, tok::eof)) + return false; + if (Current->is(tok::equal)) + nextToken(); + parseTail(); + return true; + } + + void parseTail() { + while (Current->isNot(tok::eof)) { + Def.Body.push_back(Current); + nextToken(); + } + Def.Body.push_back(Current); + } + + void nextToken() { + if (Pos + 1 < Tokens.size()) + ++Pos; + Current = Tokens[Pos]; + Current->Finalized = true; + } + + size_t Pos = 0; + FormatToken *Current = nullptr; + Definition Def; + ArrayRef<FormatToken *> Tokens; +}; + +MacroExpander::MacroExpander( + const std::vector<std::string> &Macros, clang::SourceManager &SourceMgr, + const FormatStyle &Style, + llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator, + IdentifierTable &IdentTable) + : SourceMgr(SourceMgr), Style(Style), Allocator(Allocator), + IdentTable(IdentTable) { + for (const std::string &Macro : Macros) { + parseDefinition(Macro); + } +} + +MacroExpander::~MacroExpander() = default; + +void MacroExpander::parseDefinition(const std::string &Macro) { + Buffers.push_back( + llvm::MemoryBuffer::getMemBufferCopy(Macro, "<scratch space>")); + clang::FileID FID = SourceMgr.createFileID(Buffers.back()->getMemBufferRef()); + FormatTokenLexer Lex(SourceMgr, FID, 0, Style, encoding::Encoding_UTF8, + Allocator, IdentTable); + const auto Tokens = Lex.lex(); + if (!Tokens.empty()) { + DefinitionParser Parser(Tokens); + auto Definition = Parser.parse(); + Definitions[Definition.Name] = std::move(Definition); + } +} + +bool MacroExpander::defined(llvm::StringRef Name) const { + return Definitions.find(Name) != Definitions.end(); +} + +bool MacroExpander::objectLike(llvm::StringRef Name) const { + return Definitions.find(Name)->second.ObjectLike; +} + +llvm::SmallVector<FormatToken *, 8> MacroExpander::expand(FormatToken *ID, + ArgsList Args) const { + assert(defined(ID->TokenText)); + SmallVector<FormatToken *, 8> Result; + const Definition &Def = Definitions.find(ID->TokenText)->second; + + // Expand each argument at most once. + llvm::StringSet<> ExpandedArgs; + + // Adds the given token to Result. + auto pushToken = [&](FormatToken *Tok) { + Tok->MacroCtx->ExpandedFrom.push_back(ID); + Result.push_back(Tok); + }; + + // If Tok references a parameter, adds the corresponding argument to Result. + // Returns false if Tok does not reference a parameter. + auto expandArgument = [&](FormatToken *Tok) -> bool { + // If the current token references a parameter, expand the corresponding + // argument. + if (!Tok->is(tok::identifier) || ExpandedArgs.contains(Tok->TokenText)) + return false; + ExpandedArgs.insert(Tok->TokenText); + auto I = Def.ArgMap.find(Tok->TokenText); + if (I == Def.ArgMap.end()) + return false; + // If there are fewer arguments than referenced parameters, treat the + // parameter as empty. + // FIXME: Potentially fully abort the expansion instead. + if (I->getValue() >= Args.size()) + return true; + for (FormatToken *Arg : Args[I->getValue()]) { + // A token can be part of a macro argument at multiple levels. + // For example, with "ID(x) x": + // in ID(ID(x)), 'x' is expanded first as argument to the inner + // ID, then again as argument to the outer ID. We keep the macro + // role the token had from the inner expansion. + if (!Arg->MacroCtx) + Arg->MacroCtx = MacroExpansion(MR_ExpandedArg); + pushToken(Arg); + } + return true; + }; + + // Expand the definition into Result. + for (FormatToken *Tok : Def.Body) { + if (expandArgument(Tok)) + continue; + // Create a copy of the tokens from the macro body, i.e. were not provided + // by user code. + FormatToken *New = new (Allocator.Allocate()) FormatToken; + New->copyFrom(*Tok); + assert(!New->MacroCtx); + // Tokens that are not part of the user code are not formatted. + New->MacroCtx = MacroExpansion(MR_Hidden); + pushToken(New); + } + assert(Result.size() >= 1 && Result.back()->is(tok::eof)); + if (Result.size() > 1) { + ++Result[0]->MacroCtx->StartOfExpansion; + ++Result[Result.size() - 2]->MacroCtx->EndOfExpansion; + } + return Result; +} + +} // namespace format +} // namespace clang diff --git a/contrib/llvm-project/clang/lib/Format/Macros.h b/contrib/llvm-project/clang/lib/Format/Macros.h new file mode 100644 index 000000000000..591ef8b5be3c --- /dev/null +++ b/contrib/llvm-project/clang/lib/Format/Macros.h @@ -0,0 +1,141 @@ +//===--- MacroExpander.h - Format C++ code ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the main building blocks of macro support in +/// clang-format. +/// +/// In order to not violate the requirement that clang-format can format files +/// in isolation, clang-format's macro support uses expansions users provide +/// as part of clang-format's style configuration. +/// +/// Macro definitions are of the form "MACRO(p1, p2)=p1 + p2", but only support +/// one level of expansion (\see MacroExpander for a full description of what +/// is supported). +/// +/// As part of parsing, clang-format uses the MacroExpander to expand the +/// spelled token streams into expanded token streams when it encounters a +/// macro call. The UnwrappedLineParser continues to parse UnwrappedLines +/// from the expanded token stream. +/// After the expanded unwrapped lines are parsed, the MacroUnexpander matches +/// the spelled token stream into unwrapped lines that best resemble the +/// structure of the expanded unwrapped lines. +/// +/// When formatting, clang-format formats the expanded unwrapped lines first, +/// determining the token types. Next, it formats the spelled unwrapped lines, +/// keeping the token types fixed, while allowing other formatting decisions +/// to change. +/// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_LIB_FORMAT_MACROS_H +#define CLANG_LIB_FORMAT_MACROS_H + +#include <string> +#include <unordered_map> +#include <vector> + +#include "Encoding.h" +#include "FormatToken.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +namespace llvm { +class MemoryBuffer; +} // namespace llvm + +namespace clang { +class IdentifierTable; +class SourceManager; + +namespace format { +struct FormatStyle; + +/// Takes a set of macro definitions as strings and allows expanding calls to +/// those macros. +/// +/// For example: +/// Definition: A(x, y)=x + y +/// Call : A(int a = 1, 2) +/// Expansion : int a = 1 + 2 +/// +/// Expansion does not check arity of the definition. +/// If fewer arguments than expected are provided, the remaining parameters +/// are considered empty: +/// Call : A(a) +/// Expansion: a + +/// If more arguments than expected are provided, they will be discarded. +/// +/// The expander does not support: +/// - recursive expansion +/// - stringification +/// - concatenation +/// - variadic macros +/// +/// Furthermore, only a single expansion of each macro argument is supported, +/// so that we cannot get conflicting formatting decisions from different +/// expansions. +/// Definition: A(x)=x+x +/// Call : A(id) +/// Expansion : id+x +/// +class MacroExpander { +public: + using ArgsList = llvm::ArrayRef<llvm::SmallVector<FormatToken *, 8>>; + + /// Construct a macro expander from a set of macro definitions. + /// Macro definitions must be encoded as UTF-8. + /// + /// Each entry in \p Macros must conform to the following simple + /// macro-definition language: + /// <definition> ::= <id> <expansion> | <id> "(" <params> ")" <expansion> + /// <params> ::= <id-list> | "" + /// <id-list> ::= <id> | <id> "," <params> + /// <expansion> ::= "=" <tail> | <eof> + /// <tail> ::= <tok> <tail> | <eof> + /// + /// Macros that cannot be parsed will be silently discarded. + /// + MacroExpander(const std::vector<std::string> &Macros, + clang::SourceManager &SourceMgr, const FormatStyle &Style, + llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator, + IdentifierTable &IdentTable); + ~MacroExpander(); + + /// Returns whether a macro \p Name is defined. + bool defined(llvm::StringRef Name) const; + + /// Returns whether the macro has no arguments and should not consume + /// subsequent parentheses. + bool objectLike(llvm::StringRef Name) const; + + /// Returns the expanded stream of format tokens for \p ID, where + /// each element in \p Args is a positional argument to the macro call. + llvm::SmallVector<FormatToken *, 8> expand(FormatToken *ID, + ArgsList Args) const; + +private: + struct Definition; + class DefinitionParser; + + void parseDefinition(const std::string &Macro); + + clang::SourceManager &SourceMgr; + const FormatStyle &Style; + llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator; + IdentifierTable &IdentTable; + std::vector<std::unique_ptr<llvm::MemoryBuffer>> Buffers; + llvm::StringMap<Definition> Definitions; +}; + +} // namespace format +} // namespace clang + +#endif diff --git a/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp b/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp index 914c05f72aec..82d6cfed308d 100644..100755 --- a/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp +++ b/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp @@ -27,7 +27,7 @@ namespace format { namespace { /// Returns \c true if the token can be used as an identifier in -/// an Objective-C \c @selector, \c false otherwise. +/// an Objective-C \c \@selector, \c false otherwise. /// /// Because getFormattingLangOpts() always lexes source code as /// Objective-C++, C++ keywords like \c new and \c delete are @@ -198,6 +198,8 @@ private: if (!CurrentToken) return false; FormatToken *Left = CurrentToken->Previous; + assert(Left && "Unknown previous token"); + FormatToken *PrevNonComment = Left->getPreviousNonComment(); Left->ParentBracket = Contexts.back().ContextKind; ScopedContextCreator ContextCreator(*this, tok::l_paren, 1); @@ -229,9 +231,8 @@ private: // export type X = (...); Contexts.back().IsExpression = false; } else if (Left->Previous && - (Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_decltype, - tok::kw_while, tok::l_paren, - tok::comma) || + (Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_while, + tok::l_paren, tok::comma) || Left->Previous->isIf() || Left->Previous->is(TT_BinaryOperator))) { // static_assert, if and while usually contain expressions. @@ -255,8 +256,6 @@ private: } else if (Contexts[Contexts.size() - 2].CaretFound) { // This is the parameter list of an ObjC block. Contexts.back().IsExpression = false; - } else if (Left->Previous && Left->Previous->is(tok::kw___attribute)) { - Left->setType(TT_AttributeParen); } else if (Left->Previous && Left->Previous->is(TT_ForEachMacro)) { // The first argument to a foreach macro is a declaration. Contexts.back().IsForEachMacro = true; @@ -270,6 +269,21 @@ private: Contexts.back().IsExpression = !IsForOrCatch; } + // Infer the role of the l_paren based on the previous token if we haven't + // detected one one yet. + if (PrevNonComment && Left->is(TT_Unknown)) { + if (PrevNonComment->is(tok::kw___attribute)) { + Left->setType(TT_AttributeParen); + } else if (PrevNonComment->isOneOf(TT_TypenameMacro, tok::kw_decltype, + tok::kw_typeof, tok::kw__Atomic, + tok::kw___underlying_type)) { + Left->setType(TT_TypeDeclarationParen); + // decltype() and typeof() usually contain expressions. + if (PrevNonComment->isOneOf(tok::kw_decltype, tok::kw_typeof)) + Contexts.back().IsExpression = true; + } + } + if (StartsObjCMethodExpr) { Contexts.back().ColonIsObjCMethodExpr = true; Left->setType(TT_ObjCMethodExpr); @@ -348,6 +362,8 @@ private: if (Left->is(TT_AttributeParen)) CurrentToken->setType(TT_AttributeParen); + if (Left->is(TT_TypeDeclarationParen)) + CurrentToken->setType(TT_TypeDeclarationParen); if (Left->Previous && Left->Previous->is(TT_JavaAnnotation)) CurrentToken->setType(TT_JavaAnnotation); if (Left->Previous && Left->Previous->is(TT_LeadingJavaAnnotation)) @@ -356,11 +372,11 @@ private: CurrentToken->setType(TT_AttributeSquare); if (!HasMultipleLines) - Left->PackingKind = PPK_Inconclusive; + Left->setPackingKind(PPK_Inconclusive); else if (HasMultipleParametersOnALine) - Left->PackingKind = PPK_BinPacked; + Left->setPackingKind(PPK_BinPacked); else - Left->PackingKind = PPK_OnePerLine; + Left->setPackingKind(PPK_OnePerLine); next(); return true; @@ -717,7 +733,7 @@ private: ScopedContextCreator ContextCreator(*this, tok::l_brace, 1); Contexts.back().ColonIsDictLiteral = true; - if (Left->BlockKind == BK_BracedInit) + if (Left->is(BK_BracedInit)) Contexts.back().IsExpression = true; if (Style.Language == FormatStyle::LK_JavaScript && Left->Previous && Left->Previous->is(TT_JsTypeColon)) @@ -764,7 +780,7 @@ private: // For ObjC methods, the number of parameters is calculated differently as // method declarations have a different structure (the parameters are not // inside a bracket scope). - if (Current->is(tok::l_brace) && Current->BlockKind == BK_Block) + if (Current->is(tok::l_brace) && Current->is(BK_Block)) ++Left->BlockParameterCount; if (Current->is(tok::comma)) { ++Left->ParameterCount; @@ -880,7 +896,8 @@ private: } else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) { Tok->setType(TT_BitFieldColon); } else if (Contexts.size() == 1 && - !Line.First->isOneOf(tok::kw_enum, tok::kw_case)) { + !Line.First->isOneOf(tok::kw_enum, tok::kw_case, + tok::kw_default)) { FormatToken *Prev = Tok->getPreviousNonComment(); if (Prev->isOneOf(tok::r_paren, tok::kw_noexcept)) Tok->setType(TT_CtorInitializerColon); @@ -953,9 +970,9 @@ private: return false; if (Line.MustBeDeclaration && Contexts.size() == 1 && !Contexts.back().IsExpression && !Line.startsWith(TT_ObjCProperty) && - (!Tok->Previous || - !Tok->Previous->isOneOf(tok::kw_decltype, tok::kw___attribute, - TT_LeadingJavaAnnotation))) + !Tok->is(TT_TypeDeclarationParen) && + (!Tok->Previous || !Tok->Previous->isOneOf(tok::kw___attribute, + TT_LeadingJavaAnnotation))) Line.MightBeFunctionDecl = true; break; case tok::l_square: @@ -1346,11 +1363,13 @@ private: // Reset token type in case we have already looked at it and then // recovered from an error (e.g. failure to find the matching >). if (!CurrentToken->isOneOf( - TT_LambdaLSquare, TT_LambdaLBrace, TT_ForEachMacro, - TT_TypenameMacro, TT_FunctionLBrace, TT_ImplicitStringLiteral, - TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow, TT_NamespaceMacro, - TT_OverloadedOperator, TT_RegexLiteral, TT_TemplateString, - TT_ObjCStringLiteral, TT_UntouchableMacroFunc)) + TT_LambdaLSquare, TT_LambdaLBrace, TT_AttributeMacro, + TT_ForEachMacro, TT_TypenameMacro, TT_FunctionLBrace, + TT_ImplicitStringLiteral, TT_InlineASMBrace, TT_JsFatArrow, + TT_LambdaArrow, TT_NamespaceMacro, TT_OverloadedOperator, + TT_RegexLiteral, TT_TemplateString, TT_ObjCStringLiteral, + TT_UntouchableMacroFunc, TT_ConstraintJunctions, + TT_StatementAttributeLikeMacro)) CurrentToken->setType(TT_Unknown); CurrentToken->Role.reset(); CurrentToken->MatchingParen = nullptr; @@ -1604,7 +1623,11 @@ private: !Current.Previous->is(tok::kw_operator)) { // not auto operator->() -> xxx; Current.setType(TT_TrailingReturnArrow); - + } else if (Current.is(tok::arrow) && Current.Previous && + Current.Previous->is(tok::r_brace)) { + // Concept implicit conversion contraint needs to be treated like + // a trailing return type ... } -> <type>. + Current.setType(TT_TrailingReturnArrow); } else if (isDeductionGuide(Current)) { // Deduction guides trailing arrow " A(...) -> A<T>;". Current.setType(TT_TrailingReturnArrow); @@ -1705,8 +1728,8 @@ private: // colon after this, this is the only place which annotates the identifier // as a selector.) Current.setType(TT_SelectorName); - } else if (Current.isOneOf(tok::identifier, tok::kw_const, - tok::kw_noexcept) && + } else if (Current.isOneOf(tok::identifier, tok::kw_const, tok::kw_noexcept, + tok::kw_requires) && Current.Previous && !Current.Previous->isOneOf(tok::equal, tok::at) && Line.MightBeFunctionDecl && Contexts.size() == 1) { @@ -1766,9 +1789,8 @@ private: PreviousNotConst->MatchingParen->Previous->isNot(tok::period) && PreviousNotConst->MatchingParen->Previous->isNot(tok::kw_template); - if (PreviousNotConst->is(tok::r_paren) && PreviousNotConst->MatchingParen && - PreviousNotConst->MatchingParen->Previous && - PreviousNotConst->MatchingParen->Previous->is(tok::kw_decltype)) + if (PreviousNotConst->is(tok::r_paren) && + PreviousNotConst->is(TT_TypeDeclarationParen)) return true; return (!IsPPKeyword && @@ -1823,8 +1845,8 @@ private: // Functions which end with decorations like volatile, noexcept are unlikely // to be casts. if (Tok.Next->isOneOf(tok::kw_noexcept, tok::kw_volatile, tok::kw_const, - tok::kw_throw, tok::arrow, Keywords.kw_override, - Keywords.kw_final) || + tok::kw_requires, tok::kw_throw, tok::arrow, + Keywords.kw_override, Keywords.kw_final) || isCpp11AttributeSpecifier(*Tok.Next)) return false; @@ -1840,10 +1862,38 @@ private: return true; // Heuristically try to determine whether the parentheses contain a type. + auto IsQualifiedPointerOrReference = [](FormatToken *T) { + // This is used to handle cases such as x = (foo *const)&y; + assert(!T->isSimpleTypeSpecifier() && "Should have already been checked"); + // Strip trailing qualifiers such as const or volatile when checking + // whether the parens could be a cast to a pointer/reference type. + while (T) { + if (T->is(TT_AttributeParen)) { + // Handle `x = (foo *__attribute__((foo)))&v;`: + if (T->MatchingParen && T->MatchingParen->Previous && + T->MatchingParen->Previous->is(tok::kw___attribute)) { + T = T->MatchingParen->Previous->Previous; + continue; + } + } else if (T->is(TT_AttributeSquare)) { + // Handle `x = (foo *[[clang::foo]])&v;`: + if (T->MatchingParen && T->MatchingParen->Previous) { + T = T->MatchingParen->Previous; + continue; + } + } else if (T->canBePointerOrReferenceQualifier()) { + T = T->Previous; + continue; + } + break; + } + return T && T->is(TT_PointerOrReference); + }; bool ParensAreType = !Tok.Previous || - Tok.Previous->isOneOf(TT_PointerOrReference, TT_TemplateCloser) || - Tok.Previous->isSimpleTypeSpecifier(); + Tok.Previous->isOneOf(TT_TemplateCloser, TT_TypeDeclarationParen) || + Tok.Previous->isSimpleTypeSpecifier() || + IsQualifiedPointerOrReference(Tok.Previous); bool ParensCouldEndDecl = Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace, tok::greater); if (ParensAreType && !ParensCouldEndDecl) @@ -1867,6 +1917,13 @@ private: if (Tok.Next->isOneOf(tok::identifier, tok::kw_this)) return true; + // Look for a cast `( x ) (`. + if (Tok.Next->is(tok::l_paren) && Tok.Previous && Tok.Previous->Previous) { + if (Tok.Previous->is(tok::identifier) && + Tok.Previous->Previous->is(tok::l_paren)) + return true; + } + if (!Tok.Next->Next) return false; @@ -1903,18 +1960,22 @@ private: const FormatToken *NextToken = Tok.getNextNonComment(); if (!NextToken || - NextToken->isOneOf(tok::arrow, tok::equal, tok::kw_const, - tok::kw_noexcept) || + NextToken->isOneOf(tok::arrow, tok::equal, tok::kw_noexcept) || + NextToken->canBePointerOrReferenceQualifier() || (NextToken->is(tok::l_brace) && !NextToken->getNextNonComment())) return TT_PointerOrReference; if (PrevToken->is(tok::coloncolon)) return TT_PointerOrReference; + if (PrevToken->is(tok::r_paren) && PrevToken->is(TT_TypeDeclarationParen)) + return TT_PointerOrReference; + if (PrevToken->isOneOf(tok::l_paren, tok::l_square, tok::l_brace, tok::comma, tok::semi, tok::kw_return, tok::colon, - tok::equal, tok::kw_delete, tok::kw_sizeof, - tok::kw_throw) || + tok::kw_co_return, tok::kw_co_await, + tok::kw_co_yield, tok::equal, tok::kw_delete, + tok::kw_sizeof, tok::kw_throw) || PrevToken->isOneOf(TT_BinaryOperator, TT_ConditionalExpr, TT_UnaryOperator, TT_CastRParen)) return TT_UnaryOperator; @@ -1926,15 +1987,6 @@ private: if (NextToken->isOneOf(tok::comma, tok::semi)) return TT_PointerOrReference; - if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen) { - FormatToken *TokenBeforeMatchingParen = - PrevToken->MatchingParen->getPreviousNonComment(); - if (TokenBeforeMatchingParen && - TokenBeforeMatchingParen->isOneOf(tok::kw_typeof, tok::kw_decltype, - TT_TypenameMacro)) - return TT_PointerOrReference; - } - if (PrevToken->Tok.isLiteral() || PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::kw_true, tok::kw_false, tok::r_brace) || @@ -2380,6 +2432,8 @@ static bool isFunctionDeclarationName(const FormatToken &Current, return true; for (const FormatToken *Tok = Next->Next; Tok && Tok != Next->MatchingParen; Tok = Tok->Next) { + if (Tok->is(TT_TypeDeclarationParen)) + return true; if (Tok->isOneOf(tok::l_paren, TT_TemplateOpener) && Tok->MatchingParen) { Tok = Tok->MatchingParen; continue; @@ -2433,7 +2487,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { if (isFunctionDeclarationName(*Current, Line)) Current->setType(TT_FunctionDeclarationName); if (Current->is(TT_LineComment)) { - if (Current->Previous->BlockKind == BK_BracedInit && + if (Current->Previous->is(BK_BracedInit) && Current->Previous->opensScope()) Current->SpacesRequiredBefore = (Style.Cpp11BracedListStyle && !Style.SpacesInParentheses) ? 0 : 1; @@ -2694,7 +2748,11 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if (Left.is(TT_TemplateOpener)) return 100; if (Left.opensScope()) { - if (Style.AlignAfterOpenBracket == FormatStyle::BAS_DontAlign) + // If we aren't aligning after opening parens/braces we can always break + // here unless the style does not want us to place all arguments on the + // next line. + if (Style.AlignAfterOpenBracket == FormatStyle::BAS_DontAlign && + (Left.ParameterCount <= 1 || Style.AllowAllArgumentsOnNextLine)) return 0; if (Left.is(tok::l_brace) && !Style.Cpp11BracedListStyle) return 19; @@ -2761,8 +2819,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Left.isOneOf(tok::hashhash, tok::hash)) return Right.is(tok::hash); if ((Left.is(tok::l_paren) && Right.is(tok::r_paren)) || - (Left.is(tok::l_brace) && Left.BlockKind != BK_Block && - Right.is(tok::r_brace) && Right.BlockKind != BK_Block)) + (Left.is(tok::l_brace) && Left.isNot(BK_Block) && + Right.is(tok::r_brace) && Right.isNot(BK_Block))) return Style.SpaceInEmptyParentheses; if (Style.SpacesInConditionalStatement) { if (Left.is(tok::l_paren) && Left.Previous && @@ -2773,6 +2831,14 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, isKeywordWithCondition(*Right.MatchingParen->Previous)) return true; } + + // requires ( or requires( + if (Right.is(tok::l_paren) && Left.is(tok::kw_requires)) + return spaceRequiredBeforeParens(Right); + // requires clause Concept1<T> && Concept2<T> + if (Left.is(TT_ConstraintJunctions) && Right.is(tok::identifier)) + return true; + if (Left.is(tok::l_paren) || Right.is(tok::r_paren)) return (Right.is(TT_CastRParen) || (Left.MatchingParen && Left.MatchingParen->is(TT_CastRParen))) @@ -2821,11 +2887,16 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return true; FormatToken *TokenBeforeMatchingParen = Left.MatchingParen->getPreviousNonComment(); - if (!TokenBeforeMatchingParen || - !TokenBeforeMatchingParen->isOneOf(tok::kw_typeof, tok::kw_decltype, - TT_TypenameMacro)) + if (!TokenBeforeMatchingParen || !Left.is(TT_TypeDeclarationParen)) return true; } + // Add a space if the previous token is a pointer qualifer or the closing + // parenthesis of __attribute__(()) expression and the style requires spaces + // after pointer qualifiers. + if ((Style.SpaceAroundPointerQualifiers == FormatStyle::SAPQ_After || + Style.SpaceAroundPointerQualifiers == FormatStyle::SAPQ_Both) && + (Left.is(TT_AttributeParen) || Left.canBePointerOrReferenceQualifier())) + return true; return (Left.Tok.isLiteral() || (!Left.isOneOf(TT_PointerOrReference, tok::l_paren) && (Style.PointerAlignment != FormatStyle::PAS_Left || @@ -2838,11 +2909,17 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, (Style.PointerAlignment != FormatStyle::PAS_Right && !Line.IsMultiVariableDeclStmt))) return true; - if (Left.is(TT_PointerOrReference)) + if (Left.is(TT_PointerOrReference)) { + // Add a space if the next token is a pointer qualifer and the style + // requires spaces before pointer qualifiers. + if ((Style.SpaceAroundPointerQualifiers == FormatStyle::SAPQ_Before || + Style.SpaceAroundPointerQualifiers == FormatStyle::SAPQ_Both) && + Right.canBePointerOrReferenceQualifier()) + return true; return Right.Tok.isLiteral() || Right.is(TT_BlockComment) || (Right.isOneOf(Keywords.kw_override, Keywords.kw_final) && !Right.is(TT_StartOfName)) || - (Right.is(tok::l_brace) && Right.BlockKind == BK_Block) || + (Right.is(tok::l_brace) && Right.is(BK_Block)) || (!Right.isOneOf(TT_PointerOrReference, TT_ArraySubscriptLSquare, tok::l_paren) && (Style.PointerAlignment != FormatStyle::PAS_Right && @@ -2850,6 +2927,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, Left.Previous && !Left.Previous->isOneOf(tok::l_paren, tok::coloncolon, tok::l_square)); + } // Ensure right pointer alignement with ellipsis e.g. int *...P if (Left.is(tok::ellipsis) && Left.Previous && Left.Previous->isOneOf(tok::star, tok::amp, tok::ampamp)) @@ -2927,9 +3005,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return false; if (Left.is(tok::l_brace) && Right.is(tok::r_brace)) return !Left.Children.empty(); // No spaces in "{}". - if ((Left.is(tok::l_brace) && Left.BlockKind != BK_Block) || + if ((Left.is(tok::l_brace) && Left.isNot(BK_Block)) || (Right.is(tok::r_brace) && Right.MatchingParen && - Right.MatchingParen->BlockKind != BK_Block)) + Right.MatchingParen->isNot(BK_Block))) return Style.Cpp11BracedListStyle ? Style.SpacesInParentheses : true; if (Left.is(TT_BlockComment)) // No whitespace in x(/*foo=*/1), except for JavaScript. @@ -2973,7 +3051,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, tok::r_paren) || Left.isSimpleTypeSpecifier()) && Right.is(tok::l_brace) && Right.getNextNonComment() && - Right.BlockKind != BK_Block) + Right.isNot(BK_Block)) return false; if (Left.is(tok::period) || Right.is(tok::period)) return false; @@ -3015,7 +3093,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Style.isCpp()) { if (Left.is(tok::kw_operator)) return Right.is(tok::coloncolon); - if (Right.is(tok::l_brace) && Right.BlockKind == BK_BracedInit && + if (Right.is(tok::l_brace) && Right.is(BK_BracedInit) && !Left.opensScope() && Style.SpaceBeforeCpp11BracedList) return true; } else if (Style.Language == FormatStyle::LK_Proto || @@ -3121,6 +3199,16 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, Keywords.kw_lock)) return Style.SpaceBeforeParens == FormatStyle::SBPO_ControlStatements || spaceRequiredBeforeParens(Right); + + // space between method modifier and opening parenthesis of a tuple return + // type + if (Left.isOneOf(tok::kw_public, tok::kw_private, tok::kw_protected, + tok::kw_virtual, tok::kw_extern, tok::kw_static, + Keywords.kw_internal, Keywords.kw_abstract, + Keywords.kw_sealed, Keywords.kw_override, + Keywords.kw_async, Keywords.kw_unsafe) && + Right.is(tok::l_paren)) + return true; } else if (Style.Language == FormatStyle::LK_JavaScript) { if (Left.is(TT_JsFatArrow)) return true; @@ -3257,9 +3345,13 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Right.is(TT_RangeBasedForLoopColon) && !Style.SpaceBeforeRangeBasedForLoopColon) return false; + if (Left.is(TT_BitFieldColon)) + return Style.BitFieldColonSpacing == FormatStyle::BFCS_Both || + Style.BitFieldColonSpacing == FormatStyle::BFCS_After; if (Right.is(tok::colon)) { - if (Line.First->isOneOf(tok::kw_case, tok::kw_default) || - !Right.getNextNonComment() || Right.getNextNonComment()->is(tok::semi)) + if (Line.First->isOneOf(tok::kw_default, tok::kw_case)) + return Style.SpaceBeforeCaseColon; + if (!Right.getNextNonComment() || Right.getNextNonComment()->is(tok::semi)) return false; if (Right.is(TT_ObjCMethodExpr)) return false; @@ -3273,6 +3365,9 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return false; if (Right.is(TT_CSharpNamedArgumentColon)) return false; + if (Right.is(TT_BitFieldColon)) + return Style.BitFieldColonSpacing == FormatStyle::BFCS_Both || + Style.BitFieldColonSpacing == FormatStyle::BFCS_Before; return true; } if (Left.is(TT_UnaryOperator)) { @@ -3362,7 +3457,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, // Returns 'true' if 'Tok' is a brace we'd want to break before in Allman style. static bool isAllmanBrace(const FormatToken &Tok) { - return Tok.is(tok::l_brace) && Tok.BlockKind == BK_Block && + return Tok.is(tok::l_brace) && Tok.is(BK_Block) && !Tok.isOneOf(TT_ObjCBlockLBrace, TT_LambdaLBrace, TT_DictLiteral); } @@ -3398,7 +3493,7 @@ static bool isOneChildWithoutMustBreakBefore(const FormatToken &Tok) { return true; } static bool isAllmanLambdaBrace(const FormatToken &Tok) { - return (Tok.is(tok::l_brace) && Tok.BlockKind == BK_Block && + return (Tok.is(tok::l_brace) && Tok.is(BK_Block) && !Tok.isOneOf(TT_ObjCBlockLBrace, TT_DictLiteral)); } @@ -3498,7 +3593,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, if ((Left.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || (Style.Language == FormatStyle::LK_JavaScript && Left.is(tok::l_paren))) && - Left.BlockKind != BK_Block && Left.MatchingParen) + Left.isNot(BK_Block) && Left.MatchingParen) BeforeClosingBrace = Left.MatchingParen->Previous; else if (Right.MatchingParen && (Right.MatchingParen->isOneOf(tok::l_brace, @@ -3512,8 +3607,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, } if (Right.is(tok::comment)) - return Left.BlockKind != BK_BracedInit && - Left.isNot(TT_CtorInitializerColon) && + return Left.isNot(BK_BracedInit) && Left.isNot(TT_CtorInitializerColon) && (Right.NewlinesBefore > 0 && Right.HasUnescapedNewline); if (Left.isTrailingComment()) return true; @@ -3523,11 +3617,17 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, Right.Previous->is(tok::string_literal) && Right.Next->is(tok::string_literal)) return true; + // Can break after template<> declaration if (Right.Previous->ClosesTemplateDeclaration && Right.Previous->MatchingParen && - Right.Previous->MatchingParen->NestingLevel == 0 && - Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes) - return true; + Right.Previous->MatchingParen->NestingLevel == 0) { + // Put concepts on the next line e.g. + // template<typename T> + // concept ... + if (Right.is(tok::kw_concept)) + return Style.BreakBeforeConceptDeclarations; + return (Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes); + } if (Right.is(TT_CtorInitializerComma) && Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma && !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) @@ -3822,7 +3922,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, // The first comment in a braced lists is always interpreted as belonging to // the first list element. Otherwise, it should be placed outside of the // list. - return Left.BlockKind == BK_BracedInit || + return Left.is(BK_BracedInit) || (Left.is(TT_CtorInitializerColon) && Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon); if (Left.is(tok::question) && Right.is(tok::colon)) @@ -3906,7 +4006,8 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, if (Left.is(tok::equal) && Right.is(tok::l_brace) && !Style.Cpp11BracedListStyle) return false; - if (Left.is(tok::l_paren) && Left.is(TT_AttributeParen)) + if (Left.is(tok::l_paren) && + Left.isOneOf(TT_AttributeParen, TT_TypeDeclarationParen)) return false; if (Left.is(tok::l_paren) && Left.Previous && (Left.Previous->isOneOf(TT_BinaryOperator, TT_CastRParen))) @@ -3923,7 +4024,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, // We only break before r_brace if there was a corresponding break before // the l_brace, which is tracked by BreakBeforeClosingBrace. if (Right.is(tok::r_brace)) - return Right.MatchingParen && Right.MatchingParen->BlockKind == BK_Block; + return Right.MatchingParen && Right.MatchingParen->is(BK_Block); // Allow breaking after a trailing annotation, e.g. after a method // declaration. @@ -4008,9 +4109,9 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) { << " T=" << getTokenTypeName(Tok->getType()) << " S=" << Tok->SpacesRequiredBefore << " F=" << Tok->Finalized << " B=" << Tok->BlockParameterCount - << " BK=" << Tok->BlockKind << " P=" << Tok->SplitPenalty + << " BK=" << Tok->getBlockKind() << " P=" << Tok->SplitPenalty << " Name=" << Tok->Tok.getName() << " L=" << Tok->TotalLength - << " PPK=" << Tok->PackingKind << " FakeLParens="; + << " PPK=" << Tok->getPackingKind() << " FakeLParens="; for (unsigned i = 0, e = Tok->FakeLParens.size(); i != e; ++i) llvm::errs() << Tok->FakeLParens[i] << "/"; llvm::errs() << " FakeRParens=" << Tok->FakeRParens; diff --git a/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.cpp b/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.cpp index 22f27a668dcc..7d197310e65b 100644 --- a/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -248,6 +248,11 @@ private: return !Style.BraceWrapping.SplitEmptyRecord && EmptyBlock ? tryMergeSimpleBlock(I, E, Limit) : 0; + + if (Tok && Tok->is(tok::kw_template) && + Style.BraceWrapping.SplitEmptyRecord && EmptyBlock) { + return 0; + } } // FIXME: TheLine->Level != 0 might or might not be the right check to do. @@ -309,7 +314,8 @@ private: // Try to merge a control statement block with left brace wrapped if (I[1]->First->is(tok::l_brace) && (TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for, - tok::kw_switch, tok::kw_try, tok::kw_do) || + tok::kw_switch, tok::kw_try, tok::kw_do, + TT_ForEachMacro) || (TheLine->First->is(tok::r_brace) && TheLine->First->Next && TheLine->First->Next->isOneOf(tok::kw_else, tok::kw_catch))) && Style.BraceWrapping.AfterControlStatement == @@ -354,6 +360,30 @@ private: if (TheLine->First->is(tok::l_brace) && I != AnnotatedLines.begin() && I[-1]->First->isOneOf(tok::kw_case, tok::kw_default)) return 0; + + // Don't merge an empty template class or struct if SplitEmptyRecords + // is defined. + if (Style.BraceWrapping.SplitEmptyRecord && + TheLine->Last->is(tok::l_brace) && I != AnnotatedLines.begin() && + I[-1]->Last) { + const FormatToken *Previous = I[-1]->Last; + if (Previous) { + if (Previous->is(tok::comment)) + Previous = Previous->getPreviousNonComment(); + if (Previous) { + if (Previous->is(tok::greater) && !I[-1]->InPPDirective) + return 0; + if (Previous->is(tok::identifier)) { + const FormatToken *PreviousPrevious = + Previous->getPreviousNonComment(); + if (PreviousPrevious && + PreviousPrevious->isOneOf(tok::kw_class, tok::kw_struct)) + return 0; + } + } + } + } + // Try to merge a block with left brace wrapped that wasn't yet covered if (TheLine->Last->is(tok::l_brace)) { return !Style.BraceWrapping.AfterFunction || @@ -606,7 +636,7 @@ private: if (I[1]->Last->is(TT_LineComment)) return 0; do { - if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit) + if (Tok->is(tok::l_brace) && Tok->isNot(BK_BracedInit)) return 0; Tok = Tok->Next; } while (Tok); @@ -767,8 +797,8 @@ protected: unsigned &Penalty) { const FormatToken *LBrace = State.NextToken->getPreviousNonComment(); FormatToken &Previous = *State.NextToken->Previous; - if (!LBrace || LBrace->isNot(tok::l_brace) || - LBrace->BlockKind != BK_Block || Previous.Children.size() == 0) + if (!LBrace || LBrace->isNot(tok::l_brace) || LBrace->isNot(BK_Block) || + Previous.Children.size() == 0) // The previous token does not open a block. Nothing to do. We don't // assert so that we can simply call this function for all tokens. return true; @@ -979,7 +1009,7 @@ private: // State already examined with lower penalty. continue; - FormatDecision LastFormat = Node->State.NextToken->Decision; + FormatDecision LastFormat = Node->State.NextToken->getDecision(); if (LastFormat == FD_Unformatted || LastFormat == FD_Continue) addNextStateToQueue(Penalty, Node, /*NewLine=*/false, &Count, &Queue); if (LastFormat == FD_Unformatted || LastFormat == FD_Break) @@ -1215,10 +1245,33 @@ void UnwrappedLineFormatter::formatFirstToken( !startsExternCBlock(*PreviousLine)) Newlines = 1; - // Insert extra new line before access specifiers. - if (PreviousLine && PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) && - RootToken.isAccessSpecifier() && RootToken.NewlinesBefore == 1) - ++Newlines; + // Insert or remove empty line before access specifiers. + if (PreviousLine && RootToken.isAccessSpecifier()) { + switch (Style.EmptyLineBeforeAccessModifier) { + case FormatStyle::ELBAMS_Never: + if (RootToken.NewlinesBefore > 1) + Newlines = 1; + break; + case FormatStyle::ELBAMS_Leave: + Newlines = std::max(RootToken.NewlinesBefore, 1u); + break; + case FormatStyle::ELBAMS_LogicalBlock: + if (PreviousLine->Last->isOneOf(tok::semi, tok::r_brace) && + RootToken.NewlinesBefore <= 1) + Newlines = 2; + break; + case FormatStyle::ELBAMS_Always: { + const FormatToken *previousToken; + if (PreviousLine->Last->is(tok::comment)) + previousToken = PreviousLine->Last->getPreviousNonComment(); + else + previousToken = PreviousLine->Last; + if ((!previousToken || !previousToken->is(tok::l_brace)) && + RootToken.NewlinesBefore <= 1) + Newlines = 2; + } break; + } + } // Remove empty lines after access specifiers. if (PreviousLine && PreviousLine->First->isAccessSpecifier() && @@ -1228,13 +1281,6 @@ void UnwrappedLineFormatter::formatFirstToken( if (Newlines) Indent = NewlineIndent; - // If in Whitemsmiths mode, indent start and end of blocks - if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) { - if (RootToken.isOneOf(tok::l_brace, tok::r_brace, tok::kw_case, - tok::kw_default)) - Indent += Style.IndentWidth; - } - // Preprocessor directives get indented before the hash only if specified if (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash && (Line.Type == LT_PreprocessorDirective || diff --git a/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp b/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp index ea8a41cfba82..bec18bd5d8df 100644 --- a/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp +++ b/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp @@ -472,19 +472,19 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { // individual members in a type member list, which would normally // trigger BK_Block. In both cases, this must be parsed as an inline // braced init. - Tok->BlockKind = BK_BracedInit; + Tok->setBlockKind(BK_BracedInit); else if (PrevTok->is(tok::r_paren)) // `) { }` can only occur in function or method declarations in JS. - Tok->BlockKind = BK_Block; + Tok->setBlockKind(BK_Block); } else { - Tok->BlockKind = BK_Unknown; + Tok->setBlockKind(BK_Unknown); } LBraceStack.push_back(Tok); break; case tok::r_brace: if (LBraceStack.empty()) break; - if (LBraceStack.back()->BlockKind == BK_Unknown) { + if (LBraceStack.back()->is(BK_Unknown)) { bool ProbablyBracedList = false; if (Style.Language == FormatStyle::LK_Proto) { ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square); @@ -524,11 +524,11 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { } } if (ProbablyBracedList) { - Tok->BlockKind = BK_BracedInit; - LBraceStack.back()->BlockKind = BK_BracedInit; + Tok->setBlockKind(BK_BracedInit); + LBraceStack.back()->setBlockKind(BK_BracedInit); } else { - Tok->BlockKind = BK_Block; - LBraceStack.back()->BlockKind = BK_Block; + Tok->setBlockKind(BK_Block); + LBraceStack.back()->setBlockKind(BK_Block); } } LBraceStack.pop_back(); @@ -545,8 +545,8 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { case tok::kw_switch: case tok::kw_try: case tok::kw___try: - if (!LBraceStack.empty() && LBraceStack.back()->BlockKind == BK_Unknown) - LBraceStack.back()->BlockKind = BK_Block; + if (!LBraceStack.empty() && LBraceStack.back()->is(BK_Unknown)) + LBraceStack.back()->setBlockKind(BK_Block); break; default: break; @@ -557,8 +557,8 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { // Assume other blocks for all unclosed opening braces. for (unsigned i = 0, e = LBraceStack.size(); i != e; ++i) { - if (LBraceStack[i]->BlockKind == BK_Unknown) - LBraceStack[i]->BlockKind = BK_Block; + if (LBraceStack[i]->is(BK_Unknown)) + LBraceStack[i]->setBlockKind(BK_Block); } FormatTok = Tokens->setPosition(StoredPosition); @@ -579,17 +579,23 @@ size_t UnwrappedLineParser::computePPHash() const { return h; } -void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel, - bool MunchSemi) { +void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels, + bool MunchSemi, + bool UnindentWhitesmithsBraces) { assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) && "'{' or macro block token expected"); const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin); - FormatTok->BlockKind = BK_Block; + FormatTok->setBlockKind(BK_Block); + + // For Whitesmiths mode, jump to the next level prior to skipping over the + // braces. + if (AddLevels > 0 && Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) + ++Line->Level; size_t PPStartHash = computePPHash(); unsigned InitialLevel = Line->Level; - nextToken(/*LevelDifference=*/AddLevel ? 1 : 0); + nextToken(/*LevelDifference=*/AddLevels); if (MacroBlock && FormatTok->is(tok::l_paren)) parseParens(); @@ -602,10 +608,16 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel, ? (UnwrappedLine::kInvalidIndex) : (CurrentLines->size() - 1 - NbPreprocessorDirectives); + // Whitesmiths is weird here. The brace needs to be indented for the namespace + // block, but the block itself may not be indented depending on the style + // settings. This allows the format to back up one level in those cases. + if (UnindentWhitesmithsBraces) + --Line->Level; + ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, MustBeDeclaration); - if (AddLevel) - ++Line->Level; + if (AddLevels > 0u && Style.BreakBeforeBraces != FormatStyle::BS_Whitesmiths) + Line->Level += AddLevels; parseLevel(/*HasOpeningBrace=*/true); if (eof()) @@ -614,21 +626,30 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel, if (MacroBlock ? !FormatTok->is(TT_MacroBlockEnd) : !FormatTok->is(tok::r_brace)) { Line->Level = InitialLevel; - FormatTok->BlockKind = BK_Block; + FormatTok->setBlockKind(BK_Block); return; } size_t PPEndHash = computePPHash(); // Munch the closing brace. - nextToken(/*LevelDifference=*/AddLevel ? -1 : 0); + nextToken(/*LevelDifference=*/-AddLevels); if (MacroBlock && FormatTok->is(tok::l_paren)) parseParens(); + if (FormatTok->is(tok::arrow)) { + // Following the } we can find a trailing return type arrow + // as part of an implicit conversion constraint. + nextToken(); + parseStructuralElement(); + } + if (MunchSemi && FormatTok->Tok.is(tok::semi)) nextToken(); + Line->Level = InitialLevel; + FormatTok->setBlockKind(BK_Block); if (PPStartHash == PPEndHash) { Line->MatchingOpeningBlockLineIndex = OpeningLineIndex; @@ -690,7 +711,7 @@ static bool ShouldBreakBeforeBrace(const FormatStyle &Style, } void UnwrappedLineParser::parseChildBlock() { - FormatTok->BlockKind = BK_Block; + FormatTok->setBlockKind(BK_Block); nextToken(); { bool SkipIndent = (Style.Language == FormatStyle::LK_JavaScript && @@ -1262,6 +1283,12 @@ void UnwrappedLineParser::parseStructuralElement() { break; } break; + case tok::kw_concept: + parseConcept(); + break; + case tok::kw_requires: + parseRequires(); + break; case tok::kw_enum: // Ignore if this is part of "template <enum ...". if (Previous && Previous->is(tok::less)) { @@ -1476,7 +1503,7 @@ void UnwrappedLineParser::parseStructuralElement() { // C# needs this change to ensure that array initialisers and object // initialisers are indented the same way. if (Style.isCSharp()) - FormatTok->BlockKind = BK_BracedInit; + FormatTok->setBlockKind(BK_BracedInit); nextToken(); parseBracedList(); } else if (Style.Language == FormatStyle::LK_Proto && @@ -1747,10 +1774,10 @@ void UnwrappedLineParser::tryToParseJSFunction() { } bool UnwrappedLineParser::tryToParseBracedList() { - if (FormatTok->BlockKind == BK_Unknown) + if (FormatTok->is(BK_Unknown)) calculateBraceTypes(); - assert(FormatTok->BlockKind != BK_Unknown); - if (FormatTok->BlockKind == BK_Block) + assert(FormatTok->isNot(BK_Unknown)); + if (FormatTok->is(BK_Block)) return false; nextToken(); parseBracedList(); @@ -1830,7 +1857,7 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons, case tok::l_brace: // Assume there are no blocks inside a braced init list apart // from the ones we explicitly parse out (like lambdas). - FormatTok->BlockKind = BK_BracedInit; + FormatTok->setBlockKind(BK_BracedInit); nextToken(); parseBracedList(); break; @@ -2025,6 +2052,13 @@ void UnwrappedLineParser::parseTryCatch() { nextToken(); if (FormatTok->is(tok::l_paren)) parseParens(); + if (FormatTok->Previous && FormatTok->Previous->is(tok::identifier) && + FormatTok->is(tok::l_brace)) { + do { + nextToken(); + } while (!FormatTok->is(tok::r_brace)); + nextToken(); + } // In case identifiers were removed by clang-tidy, what might follow is // multiple commas in sequence - after the first identifier. @@ -2107,15 +2141,34 @@ void UnwrappedLineParser::parseNamespace() { if (ShouldBreakBeforeBrace(Style, InitialToken)) addUnwrappedLine(); - bool AddLevel = Style.NamespaceIndentation == FormatStyle::NI_All || - (Style.NamespaceIndentation == FormatStyle::NI_Inner && - DeclarationScopeStack.size() > 1); - parseBlock(/*MustBeDeclaration=*/true, AddLevel); + unsigned AddLevels = + Style.NamespaceIndentation == FormatStyle::NI_All || + (Style.NamespaceIndentation == FormatStyle::NI_Inner && + DeclarationScopeStack.size() > 1) + ? 1u + : 0u; + bool ManageWhitesmithsBraces = + AddLevels == 0u && + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths; + + // If we're in Whitesmiths mode, indent the brace if we're not indenting + // the whole block. + if (ManageWhitesmithsBraces) + ++Line->Level; + + parseBlock(/*MustBeDeclaration=*/true, AddLevels, + /*MunchSemi=*/true, + /*UnindentWhitesmithsBraces=*/ManageWhitesmithsBraces); + // Munch the semicolon after a namespace. This is more common than one would // think. Putting the semicolon into its own line is very ugly. if (FormatTok->Tok.is(tok::semi)) nextToken(); - addUnwrappedLine(); + + addUnwrappedLine(AddLevels > 0 ? LineLevel::Remove : LineLevel::Keep); + + if (ManageWhitesmithsBraces) + --Line->Level; } // FIXME: Add error handling. } @@ -2201,6 +2254,11 @@ void UnwrappedLineParser::parseDoWhile() { return; } + // If in Whitesmiths mode, the line with the while() needs to be indented + // to the same level as the block. + if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) + ++Line->Level; + nextToken(); parseStructuralElement(); } @@ -2212,8 +2270,10 @@ void UnwrappedLineParser::parseLabel(bool LeftAlignLabel) { --Line->Level; if (LeftAlignLabel) Line->Level = 0; + if (!Style.IndentCaseBlocks && CommentsBeforeNextToken.empty() && FormatTok->Tok.is(tok::l_brace)) { + CompoundStatementIndenter Indenter(this, Line->Level, Style.BraceWrapping.AfterCaseLabel, Style.BraceWrapping.IndentBraces); @@ -2244,6 +2304,7 @@ void UnwrappedLineParser::parseLabel(bool LeftAlignLabel) { void UnwrappedLineParser::parseCaseLabel() { assert(FormatTok->Tok.is(tok::kw_case) && "'case' expected"); + // FIXME: fix handling of complex expressions here. do { nextToken(); @@ -2279,6 +2340,117 @@ void UnwrappedLineParser::parseAccessSpecifier() { addUnwrappedLine(); } +void UnwrappedLineParser::parseConcept() { + assert(FormatTok->Tok.is(tok::kw_concept) && "'concept' expected"); + nextToken(); + if (!FormatTok->Tok.is(tok::identifier)) + return; + nextToken(); + if (!FormatTok->Tok.is(tok::equal)) + return; + nextToken(); + if (FormatTok->Tok.is(tok::kw_requires)) { + nextToken(); + parseRequiresExpression(Line->Level); + } else { + parseConstraintExpression(Line->Level); + } +} + +void UnwrappedLineParser::parseRequiresExpression(unsigned int OriginalLevel) { + // requires (R range) + if (FormatTok->Tok.is(tok::l_paren)) { + parseParens(); + if (Style.IndentRequires && OriginalLevel != Line->Level) { + addUnwrappedLine(); + --Line->Level; + } + } + + if (FormatTok->Tok.is(tok::l_brace)) { + if (Style.BraceWrapping.AfterFunction) + addUnwrappedLine(); + FormatTok->setType(TT_FunctionLBrace); + parseBlock(/*MustBeDeclaration=*/false); + addUnwrappedLine(); + } else { + parseConstraintExpression(OriginalLevel); + } +} + +void UnwrappedLineParser::parseConstraintExpression( + unsigned int OriginalLevel) { + // requires Id<T> && Id<T> || Id<T> + while ( + FormatTok->isOneOf(tok::identifier, tok::kw_requires, tok::coloncolon)) { + nextToken(); + while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::less, + tok::greater, tok::comma, tok::ellipsis)) { + if (FormatTok->Tok.is(tok::less)) { + parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false, + /*ClosingBraceKind=*/tok::greater); + continue; + } + nextToken(); + } + if (FormatTok->Tok.is(tok::kw_requires)) { + parseRequiresExpression(OriginalLevel); + } + if (FormatTok->Tok.is(tok::less)) { + parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false, + /*ClosingBraceKind=*/tok::greater); + } + + if (FormatTok->Tok.is(tok::l_paren)) { + parseParens(); + } + if (FormatTok->Tok.is(tok::l_brace)) { + if (Style.BraceWrapping.AfterFunction) + addUnwrappedLine(); + FormatTok->setType(TT_FunctionLBrace); + parseBlock(/*MustBeDeclaration=*/false); + } + if (FormatTok->Tok.is(tok::semi)) { + // Eat any trailing semi. + nextToken(); + addUnwrappedLine(); + } + if (FormatTok->Tok.is(tok::colon)) { + return; + } + if (!FormatTok->Tok.isOneOf(tok::ampamp, tok::pipepipe)) { + if (FormatTok->Previous && + !FormatTok->Previous->isOneOf(tok::identifier, tok::kw_requires, + tok::coloncolon)) { + addUnwrappedLine(); + } + if (Style.IndentRequires && OriginalLevel != Line->Level) { + --Line->Level; + } + break; + } else { + FormatTok->setType(TT_ConstraintJunctions); + } + + nextToken(); + } +} + +void UnwrappedLineParser::parseRequires() { + assert(FormatTok->Tok.is(tok::kw_requires) && "'requires' expected"); + + unsigned OriginalLevel = Line->Level; + if (FormatTok->Previous && FormatTok->Previous->is(tok::greater)) { + addUnwrappedLine(); + if (Style.IndentRequires) { + Line->Level++; + } + } + nextToken(); + + parseRequiresExpression(OriginalLevel); +} + bool UnwrappedLineParser::parseEnum() { // Won't be 'enum' for NS_ENUMs. if (FormatTok->Tok.is(tok::kw_enum)) @@ -2318,7 +2490,7 @@ bool UnwrappedLineParser::parseEnum() { // Just a declaration or something is wrong. if (FormatTok->isNot(tok::l_brace)) return true; - FormatTok->BlockKind = BK_Block; + FormatTok->setBlockKind(BK_Block); if (Style.Language == FormatStyle::LK_Java) { // Java enums are different. @@ -2612,32 +2784,15 @@ void UnwrappedLineParser::parseObjCInterfaceOrImplementation() { // @interface can be followed by a lightweight generic // specialization list, then either a base class or a category. if (FormatTok->Tok.is(tok::less)) { - // Unlike protocol lists, generic parameterizations support - // nested angles: - // - // @interface Foo<ValueType : id <NSCopying, NSSecureCoding>> : - // NSObject <NSCopying, NSSecureCoding> - // - // so we need to count how many open angles we have left. - unsigned NumOpenAngles = 1; - do { - nextToken(); - // Early exit in case someone forgot a close angle. - if (FormatTok->isOneOf(tok::semi, tok::l_brace) || - FormatTok->Tok.isObjCAtKeyword(tok::objc_end)) - break; - if (FormatTok->Tok.is(tok::less)) - ++NumOpenAngles; - else if (FormatTok->Tok.is(tok::greater)) { - assert(NumOpenAngles > 0 && "'>' makes NumOpenAngles negative"); - --NumOpenAngles; - } - } while (!eof() && NumOpenAngles != 0); - nextToken(); // Skip '>'. + parseObjCLightweightGenerics(); } if (FormatTok->Tok.is(tok::colon)) { nextToken(); nextToken(); // base class name + // The base class can also have lightweight generics applied to it. + if (FormatTok->Tok.is(tok::less)) { + parseObjCLightweightGenerics(); + } } else if (FormatTok->Tok.is(tok::l_paren)) // Skip category, if present. parseParens(); @@ -2658,6 +2813,32 @@ void UnwrappedLineParser::parseObjCInterfaceOrImplementation() { parseObjCUntilAtEnd(); } +void UnwrappedLineParser::parseObjCLightweightGenerics() { + assert(FormatTok->Tok.is(tok::less)); + // Unlike protocol lists, generic parameterizations support + // nested angles: + // + // @interface Foo<ValueType : id <NSCopying, NSSecureCoding>> : + // NSObject <NSCopying, NSSecureCoding> + // + // so we need to count how many open angles we have left. + unsigned NumOpenAngles = 1; + do { + nextToken(); + // Early exit in case someone forgot a close angle. + if (FormatTok->isOneOf(tok::semi, tok::l_brace) || + FormatTok->Tok.isObjCAtKeyword(tok::objc_end)) + break; + if (FormatTok->Tok.is(tok::less)) + ++NumOpenAngles; + else if (FormatTok->Tok.is(tok::greater)) { + assert(NumOpenAngles > 0 && "'>' makes NumOpenAngles negative"); + --NumOpenAngles; + } + } while (!eof() && NumOpenAngles != 0); + nextToken(); // Skip '>'. +} + // Returns true for the declaration/definition form of @protocol, // false for the expression form. bool UnwrappedLineParser::parseObjCProtocol() { @@ -2726,7 +2907,7 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() { return; } if (FormatTok->is(tok::l_brace)) { - FormatTok->BlockKind = BK_Block; + FormatTok->setBlockKind(BK_Block); nextToken(); parseBracedList(); } else { @@ -2753,7 +2934,7 @@ LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line, E = Line.Tokens.end(); I != E; ++I) { llvm::dbgs() << I->Tok->Tok.getName() << "[" - << "T=" << I->Tok->getType() + << "T=" << (unsigned)I->Tok->getType() << ", OC=" << I->Tok->OriginalColumn << "] "; } for (std::list<UnwrappedLineNode>::const_iterator I = Line.Tokens.begin(), @@ -2770,17 +2951,29 @@ LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line, llvm::dbgs() << "\n"; } -void UnwrappedLineParser::addUnwrappedLine() { +void UnwrappedLineParser::addUnwrappedLine(LineLevel AdjustLevel) { if (Line->Tokens.empty()) return; LLVM_DEBUG({ if (CurrentLines == &Lines) printDebugInfo(*Line); }); + + // If this line closes a block when in Whitesmiths mode, remember that + // information so that the level can be decreased after the line is added. + // This has to happen after the addition of the line since the line itself + // needs to be indented. + bool ClosesWhitesmithsBlock = + Line->MatchingOpeningBlockLineIndex != UnwrappedLine::kInvalidIndex && + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths; + CurrentLines->push_back(std::move(*Line)); Line->Tokens.clear(); Line->MatchingOpeningBlockLineIndex = UnwrappedLine::kInvalidIndex; Line->FirstStartColumn = 0; + + if (ClosesWhitesmithsBlock && AdjustLevel == LineLevel::Remove) + --Line->Level; if (CurrentLines == &Lines && !PreprocessorDirectives.empty()) { CurrentLines->append( std::make_move_iterator(PreprocessorDirectives.begin()), diff --git a/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.h b/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.h index 8b3aa4c84edb..ce135fac5e57 100644 --- a/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.h +++ b/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.h @@ -85,8 +85,9 @@ private: void reset(); void parseFile(); void parseLevel(bool HasOpeningBrace); - void parseBlock(bool MustBeDeclaration, bool AddLevel = true, - bool MunchSemi = true); + void parseBlock(bool MustBeDeclaration, unsigned AddLevels = 1u, + bool MunchSemi = true, + bool UnindentWhitesmithsBraces = false); void parseChildBlock(); void parsePPDirective(); void parsePPDefine(); @@ -113,11 +114,16 @@ private: void parseNew(); void parseAccessSpecifier(); bool parseEnum(); + void parseConcept(); + void parseRequires(); + void parseRequiresExpression(unsigned int OriginalLevel); + void parseConstraintExpression(unsigned int OriginalLevel); void parseJavaEnumBody(); // Parses a record (aka class) as a top level element. If ParseAsExpr is true, // parses the record as a child block, i.e. if the class declaration is an // expression. void parseRecord(bool ParseAsExpr = false); + void parseObjCLightweightGenerics(); void parseObjCMethod(); void parseObjCProtocolList(); void parseObjCUntilAtEnd(); @@ -135,7 +141,12 @@ private: bool tryToParsePropertyAccessor(); void tryToParseJSFunction(); bool tryToParseSimpleAttribute(); - void addUnwrappedLine(); + + // Used by addUnwrappedLine to denote whether to keep or remove a level + // when resetting the line state. + enum class LineLevel { Remove, Keep }; + + void addUnwrappedLine(LineLevel AdjustLevel = LineLevel::Remove); bool eof() const; // LevelDifference is the difference of levels after and before the current // token. For example: diff --git a/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp b/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp index 3a265bd09168..7d6964b7c72f 100644 --- a/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp +++ b/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp @@ -49,7 +49,7 @@ void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines, bool IsAligned, bool InPPDirective) { if (Tok.Finalized) return; - Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue; + Tok.setDecision((Newlines > 0) ? FD_Break : FD_Continue); Changes.push_back(Change(Tok, /*CreateReplacement=*/true, Tok.WhitespaceRange, Spaces, StartOfTokenColumn, Newlines, "", "", IsAligned, InPPDirective && !Tok.IsFirst, @@ -361,9 +361,10 @@ AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches, // that are split across multiple lines. See the test case in FormatTest.cpp // that mentions "split function parameter alignment" for an example of this. template <typename F> -static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, - SmallVector<WhitespaceManager::Change, 16> &Changes, - unsigned StartAt) { +static unsigned AlignTokens( + const FormatStyle &Style, F &&Matches, + SmallVector<WhitespaceManager::Change, 16> &Changes, unsigned StartAt, + const FormatStyle::AlignConsecutiveStyle &ACS = FormatStyle::ACS_None) { unsigned MinColumn = 0; unsigned MaxColumn = UINT_MAX; @@ -386,6 +387,9 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, // Whether a matching token has been found on the current line. bool FoundMatchOnLine = false; + // Whether the current line consists purely of comments. + bool LineIsComment = true; + // Aligns a sequence of matching tokens, on the MinColumn column. // // Sequences start from the first matching token to align, and end at the @@ -411,19 +415,38 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, if (Changes[i].NewlinesBefore != 0) { CommasBeforeMatch = 0; EndOfSequence = i; - // If there is a blank line, or if the last line didn't contain any - // matching token, the sequence ends here. - if (Changes[i].NewlinesBefore > 1 || !FoundMatchOnLine) + + // Whether to break the alignment sequence because of an empty line. + bool EmptyLineBreak = + (Changes[i].NewlinesBefore > 1) && + (ACS != FormatStyle::ACS_AcrossEmptyLines) && + (ACS != FormatStyle::ACS_AcrossEmptyLinesAndComments); + + // Whether to break the alignment sequence because of a line without a + // match. + bool NoMatchBreak = + !FoundMatchOnLine && + !(LineIsComment && + ((ACS == FormatStyle::ACS_AcrossComments) || + (ACS == FormatStyle::ACS_AcrossEmptyLinesAndComments))); + + if (EmptyLineBreak || NoMatchBreak) AlignCurrentSequence(); + // A new line starts, re-initialize line status tracking bools. FoundMatchOnLine = false; + LineIsComment = true; + } + + if (!Changes[i].Tok->is(tok::comment)) { + LineIsComment = false; } if (Changes[i].Tok->is(tok::comma)) { ++CommasBeforeMatch; } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { // Call AlignTokens recursively, skipping over this scope block. - unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i); + unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS); i = StoppedAt - 1; continue; } @@ -518,7 +541,7 @@ static void AlignMacroSequence( } void WhitespaceManager::alignConsecutiveMacros() { - if (!Style.AlignConsecutiveMacros) + if (Style.AlignConsecutiveMacros == FormatStyle::ACS_None) return; auto AlignMacrosMatches = [](const Change &C) { @@ -560,17 +583,41 @@ void WhitespaceManager::alignConsecutiveMacros() { // Whether a matching token has been found on the current line. bool FoundMatchOnLine = false; + // Whether the current line consists only of comments + bool LineIsComment = true; + unsigned I = 0; for (unsigned E = Changes.size(); I != E; ++I) { if (Changes[I].NewlinesBefore != 0) { EndOfSequence = I; - // If there is a blank line, or if the last line didn't contain any - // matching token, the sequence ends here. - if (Changes[I].NewlinesBefore > 1 || !FoundMatchOnLine) + + // Whether to break the alignment sequence because of an empty line. + bool EmptyLineBreak = + (Changes[I].NewlinesBefore > 1) && + (Style.AlignConsecutiveMacros != FormatStyle::ACS_AcrossEmptyLines) && + (Style.AlignConsecutiveMacros != + FormatStyle::ACS_AcrossEmptyLinesAndComments); + + // Whether to break the alignment sequence because of a line without a + // match. + bool NoMatchBreak = + !FoundMatchOnLine && + !(LineIsComment && ((Style.AlignConsecutiveMacros == + FormatStyle::ACS_AcrossComments) || + (Style.AlignConsecutiveMacros == + FormatStyle::ACS_AcrossEmptyLinesAndComments))); + + if (EmptyLineBreak || NoMatchBreak) AlignMacroSequence(StartOfSequence, EndOfSequence, MinColumn, MaxColumn, FoundMatchOnLine, AlignMacrosMatches, Changes); + // A new line starts, re-initialize line status tracking bools. FoundMatchOnLine = false; + LineIsComment = true; + } + + if (!Changes[I].Tok->is(tok::comment)) { + LineIsComment = false; } if (!AlignMacrosMatches(Changes[I])) @@ -597,7 +644,7 @@ void WhitespaceManager::alignConsecutiveMacros() { } void WhitespaceManager::alignConsecutiveAssignments() { - if (!Style.AlignConsecutiveAssignments) + if (Style.AlignConsecutiveAssignments == FormatStyle::ACS_None) return; AlignTokens( @@ -613,11 +660,11 @@ void WhitespaceManager::alignConsecutiveAssignments() { return C.Tok->is(tok::equal); }, - Changes, /*StartAt=*/0); + Changes, /*StartAt=*/0, Style.AlignConsecutiveAssignments); } void WhitespaceManager::alignConsecutiveBitFields() { - if (!Style.AlignConsecutiveBitFields) + if (Style.AlignConsecutiveBitFields == FormatStyle::ACS_None) return; AlignTokens( @@ -633,11 +680,11 @@ void WhitespaceManager::alignConsecutiveBitFields() { return C.Tok->is(TT_BitFieldColon); }, - Changes, /*StartAt=*/0); + Changes, /*StartAt=*/0, Style.AlignConsecutiveBitFields); } void WhitespaceManager::alignConsecutiveDeclarations() { - if (!Style.AlignConsecutiveDeclarations) + if (Style.AlignConsecutiveDeclarations == FormatStyle::ACS_None) return; // FIXME: Currently we don't handle properly the PointerAlignment: Right @@ -655,6 +702,9 @@ void WhitespaceManager::alignConsecutiveDeclarations() { return true; if (C.Tok->isNot(TT_StartOfName)) return false; + if (C.Tok->Previous && + C.Tok->Previous->is(TT_StatementAttributeLikeMacro)) + return false; // Check if there is a subsequent name that starts the same declaration. for (FormatToken *Next = C.Tok->Next; Next; Next = Next->Next) { if (Next->is(tok::comment)) @@ -667,7 +717,7 @@ void WhitespaceManager::alignConsecutiveDeclarations() { } return true; }, - Changes, /*StartAt=*/0); + Changes, /*StartAt=*/0, Style.AlignConsecutiveDeclarations); } void WhitespaceManager::alignChainedConditionals() { |