diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2024-07-27 23:34:35 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2024-10-23 18:26:01 +0000 |
commit | 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583 (patch) | |
tree | 6cf5ab1f05330c6773b1f3f64799d56a9c7a1faa /contrib/llvm-project/clang/lib/Format | |
parent | 6b9f7133aba44189d9625c352bc2c2a59baf18ef (diff) | |
parent | ac9a064cb179f3425b310fa2847f8764ac970a4d (diff) |
Diffstat (limited to 'contrib/llvm-project/clang/lib/Format')
29 files changed, 1606 insertions, 781 deletions
diff --git a/contrib/llvm-project/clang/lib/Format/BreakableToken.cpp b/contrib/llvm-project/clang/lib/Format/BreakableToken.cpp index 473908e8fee3..75304908dc65 100644 --- a/contrib/llvm-project/clang/lib/Format/BreakableToken.cpp +++ b/contrib/llvm-project/clang/lib/Format/BreakableToken.cpp @@ -449,11 +449,11 @@ const FormatToken &BreakableComment::tokenAt(unsigned LineIndex) const { static bool mayReflowContent(StringRef Content) { Content = Content.trim(Blanks); - // Lines starting with '@' commonly have special meaning. + // Lines starting with '@' or '\' commonly have special meaning. // Lines starting with '-', '-#', '+' or '*' are bulleted/numbered lists. bool hasSpecialMeaningPrefix = false; for (StringRef Prefix : - {"@", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* "}) { + {"@", "\\", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* "}) { if (Content.starts_with(Prefix)) { hasSpecialMeaningPrefix = true; break; diff --git a/contrib/llvm-project/clang/lib/Format/BreakableToken.h b/contrib/llvm-project/clang/lib/Format/BreakableToken.h index e7c0680641e2..8b9360a3335e 100644 --- a/contrib/llvm-project/clang/lib/Format/BreakableToken.h +++ b/contrib/llvm-project/clang/lib/Format/BreakableToken.h @@ -18,11 +18,8 @@ #define LLVM_CLANG_LIB_FORMAT_BREAKABLETOKEN_H #include "Encoding.h" -#include "TokenAnnotator.h" #include "WhitespaceManager.h" #include "llvm/ADT/StringSet.h" -#include "llvm/Support/Regex.h" -#include <utility> namespace clang { namespace format { diff --git a/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.cpp b/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.cpp index 53cd169b0590..b07360425ca6 100644 --- a/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.cpp +++ b/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.cpp @@ -328,9 +328,17 @@ bool ContinuationIndenter::canBreak(const LineState &State) { // Don't break after very short return types (e.g. "void") as that is often // unexpected. - if (Current.is(TT_FunctionDeclarationName) && State.Column < 6) { - if (Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) + if (Current.is(TT_FunctionDeclarationName)) { + if (Style.BreakAfterReturnType == FormatStyle::RTBS_None && + State.Column < 6) { return false; + } + + if (Style.BreakAfterReturnType == FormatStyle::RTBS_ExceptShortType) { + assert(State.Column >= State.FirstIndent); + if (State.Column - State.FirstIndent < 6) + return false; + } } // If binary operators are moved to the next line (including commas for some @@ -561,7 +569,9 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { return true; } } - return Style.AlwaysBreakTemplateDeclarations != FormatStyle::BTDS_No; + return Style.BreakTemplateDeclarations != FormatStyle::BTDS_No && + (Style.BreakTemplateDeclarations != FormatStyle::BTDS_Leave || + Current.NewlinesBefore > 0); } if (Previous.is(TT_FunctionAnnotationRParen) && State.Line->Type != LT_PreprocessorDirective) { @@ -587,7 +597,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { !State.Line->ReturnTypeWrapped && // Don't break before a C# function when no break after return type. (!Style.isCSharp() || - Style.AlwaysBreakAfterReturnType != FormatStyle::RTBS_None) && + Style.BreakAfterReturnType > FormatStyle::RTBS_ExceptShortType) && // Don't always break between a JavaScript `function` and the function // name. !Style.isJavaScript() && Previous.isNot(tok::kw_template) && @@ -817,6 +827,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, if (Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign && !CurrentState.IsCSharpGenericTypeConstraint && Previous.opensScope() && Previous.isNot(TT_ObjCMethodExpr) && Previous.isNot(TT_RequiresClause) && + Previous.isNot(TT_TableGenDAGArgOpener) && + Previous.isNot(TT_TableGenDAGArgOpenerToBreak) && !(Current.MacroParent && Previous.MacroParent) && (Current.isNot(TT_LineComment) || Previous.isOneOf(BK_BracedInit, TT_VerilogMultiLineListLParen))) { @@ -1245,8 +1257,13 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { } return CurrentState.Indent; } + if (Current.is(TT_TrailingReturnArrow) && + Previous.isOneOf(tok::kw_noexcept, tok::kw_mutable, tok::kw_constexpr, + tok::kw_consteval, tok::kw_static, TT_AttributeSquare)) { + return ContinuationIndent; + } if ((Current.isOneOf(tok::r_brace, tok::r_square) || - (Current.is(tok::greater) && Style.isProto())) && + (Current.is(tok::greater) && (Style.isProto() || Style.isTableGen()))) && State.Stack.size() > 1) { if (Current.closesBlockOrBlockTypeList(Style)) return State.Stack[State.Stack.size() - 2].NestedBlockIndent; @@ -1274,6 +1291,12 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { Current.Next->isOneOf(tok::semi, tok::kw_const, tok::l_brace))) { return State.Stack[State.Stack.size() - 2].LastSpace; } + // When DAGArg closer exists top of line, it should be aligned in the similar + // way as function call above. + if (Style.isTableGen() && Current.is(TT_TableGenDAGArgCloser) && + State.Stack.size() > 1) { + return State.Stack[State.Stack.size() - 2].LastSpace; + } if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent && (Current.is(tok::r_paren) || (Current.is(tok::r_brace) && Current.MatchingParen && @@ -1404,7 +1427,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { // the next line. if (State.Line->InPragmaDirective) { FormatToken *PragmaType = State.Line->First->Next->Next; - if (PragmaType && PragmaType->TokenText.equals("omp")) + if (PragmaType && PragmaType->TokenText == "omp") return CurrentState.Indent + Style.ContinuationIndentWidth; } @@ -1433,7 +1456,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { Style.BreakInheritanceList == FormatStyle::BILS_AfterColon) { return CurrentState.Indent; } - if (Previous.is(tok::r_paren) && !Current.isBinaryOperator() && + if (Previous.is(tok::r_paren) && + Previous.isNot(TT_TableGenDAGArgOperatorToBreak) && + !Current.isBinaryOperator() && !Current.isOneOf(tok::colon, tok::comment)) { return ContinuationIndent; } @@ -1692,7 +1717,10 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State, (!Previous || Previous->isNot(tok::kw_return) || (Style.Language != FormatStyle::LK_Java && PrecedenceLevel > 0)) && (Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign || - PrecedenceLevel != prec::Comma || Current.NestingLevel == 0)) { + PrecedenceLevel > prec::Comma || Current.NestingLevel == 0) && + (!Style.isTableGen() || + (Previous && Previous->isOneOf(TT_TableGenDAGArgListComma, + TT_TableGenDAGArgListCommaToBreak)))) { NewParenState.Indent = std::max( std::max(State.Column, NewParenState.Indent), CurrentState.LastSpace); } @@ -1700,8 +1728,11 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State, // Special case for generic selection expressions, its comma-separated // expressions are not aligned to the opening paren like regular calls, but // rather continuation-indented relative to the _Generic keyword. - if (Previous && Previous->endsSequence(tok::l_paren, tok::kw__Generic)) - NewParenState.Indent = CurrentState.LastSpace; + if (Previous && Previous->endsSequence(tok::l_paren, tok::kw__Generic) && + State.Stack.size() > 1) { + NewParenState.Indent = State.Stack[State.Stack.size() - 2].Indent + + Style.ContinuationIndentWidth; + } if ((shouldUnindentNextOperator(Current) || (Previous && @@ -1787,7 +1818,7 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, } if (Current.MatchingParen && Current.is(BK_Block)) { - moveStateToNewBlock(State); + moveStateToNewBlock(State, Newline); return; } @@ -1826,6 +1857,17 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, Style.ContinuationIndentWidth + std::max(CurrentState.LastSpace, CurrentState.StartOfFunctionCall); + if (Style.isTableGen() && Current.is(TT_TableGenDAGArgOpenerToBreak) && + Style.TableGenBreakInsideDAGArg == FormatStyle::DAS_BreakElements) { + // For the case the next token is a TableGen DAGArg operator identifier + // that is not marked to have a line break after it. + // In this case the option DAS_BreakElements requires to align the + // DAGArg elements to the operator. + const FormatToken *Next = Current.Next; + if (Next && Next->is(TT_TableGenDAGArgOperatorID)) + NewIndent = State.Column + Next->TokenText.size() + 2; + } + // Ensure that different different brackets force relative alignment, e.g.: // void SomeFunction(vector< // break // int> v); @@ -1935,6 +1977,7 @@ void ContinuationIndenter::moveStatePastScopeCloser(LineState &State) { (Current.isOneOf(tok::r_paren, tok::r_square, TT_TemplateString) || (Current.is(tok::r_brace) && State.NextToken != State.Line->First) || State.NextToken->is(TT_TemplateCloser) || + State.NextToken->is(TT_TableGenListCloser) || (Current.is(tok::greater) && Current.is(TT_DictLiteral)))) { State.Stack.pop_back(); } @@ -1974,7 +2017,7 @@ void ContinuationIndenter::moveStatePastScopeCloser(LineState &State) { } } -void ContinuationIndenter::moveStateToNewBlock(LineState &State) { +void ContinuationIndenter::moveStateToNewBlock(LineState &State, bool NewLine) { if (Style.LambdaBodyIndentation == FormatStyle::LBI_OuterScope && State.NextToken->is(TT_LambdaLBrace) && !State.Line->MightBeFunctionDecl) { @@ -1986,10 +2029,18 @@ void ContinuationIndenter::moveStateToNewBlock(LineState &State) { NestedBlockIndent + (State.NextToken->is(TT_ObjCBlockLBrace) ? Style.ObjCBlockIndentWidth : Style.IndentWidth); + + // Even when wrapping before lambda body, the left brace can still be added to + // the same line. This occurs when checking whether the whole lambda body can + // go on a single line. In this case we have to make sure there are no line + // breaks in the body, otherwise we could just end up with a regular lambda + // body without the brace wrapped. + bool NoLineBreak = Style.BraceWrapping.BeforeLambdaBody && !NewLine && + State.NextToken->is(TT_LambdaLBrace); + State.Stack.push_back(ParenState(State.NextToken, NewIndent, State.Stack.back().LastSpace, - /*AvoidBinPacking=*/true, - /*NoLineBreak=*/false)); + /*AvoidBinPacking=*/true, NoLineBreak)); State.Stack.back().NestedBlockIndent = NestedBlockIndent; State.Stack.back().BreakBeforeParameter = true; } diff --git a/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.h b/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.h index 057b85bd32d5..18441e10a124 100644 --- a/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.h +++ b/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.h @@ -17,11 +17,6 @@ #include "Encoding.h" #include "FormatToken.h" -#include "clang/Format/Format.h" -#include "llvm/Support/Regex.h" -#include <map> -#include <optional> -#include <tuple> namespace clang { class SourceManager; @@ -104,7 +99,7 @@ private: /// Update 'State' according to the next token being one of ")>}]". void moveStatePastScopeCloser(LineState &State); /// Update 'State' with the next token opening a nested block. - void moveStateToNewBlock(LineState &State); + void moveStateToNewBlock(LineState &State, bool NewLine); /// Reformats a raw string literal. /// diff --git a/contrib/llvm-project/clang/lib/Format/Encoding.h b/contrib/llvm-project/clang/lib/Format/Encoding.h index a0d664121b2b..12f9043bb95a 100644 --- a/contrib/llvm-project/clang/lib/Format/Encoding.h +++ b/contrib/llvm-project/clang/lib/Format/Encoding.h @@ -16,7 +16,6 @@ #define LLVM_CLANG_LIB_FORMAT_ENCODING_H #include "clang/Basic/LLVM.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Unicode.h" diff --git a/contrib/llvm-project/clang/lib/Format/Format.cpp b/contrib/llvm-project/clang/lib/Format/Format.cpp index 10fe35c79a4f..7fd42e46e0cc 100644 --- a/contrib/llvm-project/clang/lib/Format/Format.cpp +++ b/contrib/llvm-project/clang/lib/Format/Format.cpp @@ -13,50 +13,22 @@ //===----------------------------------------------------------------------===// #include "clang/Format/Format.h" -#include "AffectedRangeManager.h" -#include "BreakableToken.h" -#include "ContinuationIndenter.h" #include "DefinitionBlockSeparator.h" -#include "FormatInternal.h" -#include "FormatToken.h" -#include "FormatTokenLexer.h" #include "IntegerLiteralSeparatorFixer.h" #include "NamespaceEndCommentsFixer.h" #include "ObjCPropertyAttributeOrderFixer.h" #include "QualifierAlignmentFixer.h" #include "SortJavaScriptImports.h" -#include "TokenAnalyzer.h" -#include "TokenAnnotator.h" #include "UnwrappedLineFormatter.h" -#include "UnwrappedLineParser.h" #include "UsingDeclarationsSorter.h" -#include "WhitespaceManager.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/DiagnosticOptions.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Lex/Lexer.h" #include "clang/Tooling/Inclusions/HeaderIncludes.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Sequence.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Regex.h" -#include "llvm/Support/VirtualFileSystem.h" -#include "llvm/Support/YAMLTraits.h" -#include <algorithm> -#include <memory> -#include <mutex> -#include <optional> -#include <string> -#include <unordered_map> #define DEBUG_TYPE "format-formatter" using clang::format::FormatStyle; -LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::RawStringFormat) +LLVM_YAML_IS_SEQUENCE_VECTOR(FormatStyle::RawStringFormat) namespace llvm { namespace yaml { @@ -128,6 +100,7 @@ struct MappingTraits<FormatStyle::ShortCaseStatementsAlignmentStyle> { IO.mapOptional("Enabled", Value.Enabled); IO.mapOptional("AcrossEmptyLines", Value.AcrossEmptyLines); IO.mapOptional("AcrossComments", Value.AcrossComments); + IO.mapOptional("AlignCaseArrows", Value.AlignCaseArrows); IO.mapOptional("AlignCaseColons", Value.AlignCaseColons); } }; @@ -296,6 +269,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BreakTemplateDeclarationsStyle> { static void enumeration(IO &IO, FormatStyle::BreakTemplateDeclarationsStyle &Value) { + IO.enumCase(Value, "Leave", FormatStyle::BTDS_Leave); IO.enumCase(Value, "No", FormatStyle::BTDS_No); IO.enumCase(Value, "MultiLine", FormatStyle::BTDS_MultiLine); IO.enumCase(Value, "Yes", FormatStyle::BTDS_Yes); @@ -306,6 +280,14 @@ struct ScalarEnumerationTraits<FormatStyle::BreakTemplateDeclarationsStyle> { } }; +template <> struct ScalarEnumerationTraits<FormatStyle::DAGArgStyle> { + static void enumeration(IO &IO, FormatStyle::DAGArgStyle &Value) { + IO.enumCase(Value, "DontBreak", FormatStyle::DAS_DontBreak); + IO.enumCase(Value, "BreakElements", FormatStyle::DAS_BreakElements); + IO.enumCase(Value, "BreakAll", FormatStyle::DAS_BreakAll); + } +}; + template <> struct ScalarEnumerationTraits<FormatStyle::DefinitionReturnTypeBreakingStyle> { static void @@ -326,6 +308,7 @@ struct ScalarEnumerationTraits<FormatStyle::EscapedNewlineAlignmentStyle> { FormatStyle::EscapedNewlineAlignmentStyle &Value) { IO.enumCase(Value, "DontAlign", FormatStyle::ENAS_DontAlign); IO.enumCase(Value, "Left", FormatStyle::ENAS_Left); + IO.enumCase(Value, "LeftWithLastLine", FormatStyle::ENAS_LeftWithLastLine); IO.enumCase(Value, "Right", FormatStyle::ENAS_Right); // For backward compatibility. @@ -386,6 +369,14 @@ template <> struct ScalarEnumerationTraits<FormatStyle::JavaScriptQuoteStyle> { } }; +template <> struct MappingTraits<FormatStyle::KeepEmptyLinesStyle> { + static void mapping(IO &IO, FormatStyle::KeepEmptyLinesStyle &Value) { + IO.mapOptional("AtEndOfFile", Value.AtEndOfFile); + IO.mapOptional("AtStartOfBlock", Value.AtStartOfBlock); + IO.mapOptional("AtStartOfFile", Value.AtStartOfFile); + } +}; + template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> { static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) { IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp); @@ -558,6 +549,8 @@ template <> struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> { static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) { IO.enumCase(Value, "None", FormatStyle::RTBS_None); + IO.enumCase(Value, "Automatic", FormatStyle::RTBS_Automatic); + IO.enumCase(Value, "ExceptShortType", FormatStyle::RTBS_ExceptShortType); IO.enumCase(Value, "All", FormatStyle::RTBS_All); IO.enumCase(Value, "TopLevel", FormatStyle::RTBS_TopLevel); IO.enumCase(Value, "TopLevelDefinitions", @@ -736,6 +729,7 @@ template <> struct MappingTraits<FormatStyle::SpacesInLineComment> { template <> struct MappingTraits<FormatStyle::SpacesInParensCustom> { static void mapping(IO &IO, FormatStyle::SpacesInParensCustom &Spaces) { + IO.mapOptional("ExceptDoubleParentheses", Spaces.ExceptDoubleParentheses); IO.mapOptional("InCStyleCasts", Spaces.InCStyleCasts); IO.mapOptional("InConditionalStatements", Spaces.InConditionalStatements); IO.mapOptional("InEmptyParentheses", Spaces.InEmptyParentheses); @@ -824,7 +818,6 @@ template <> struct MappingTraits<FormatStyle> { FormatStyle PredefinedStyle; if (getPredefinedStyle(StyleName, Style.Language, &PredefinedStyle) && Style == PredefinedStyle) { - IO.mapOptional("# BasedOnStyle", StyleName); BasedOnStyle = StyleName; break; } @@ -874,6 +867,9 @@ template <> struct MappingTraits<FormatStyle> { if (!IO.outputting()) { IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlines); IO.mapOptional("AllowAllConstructorInitializersOnNextLine", OnNextLine); + IO.mapOptional("AlwaysBreakAfterReturnType", Style.BreakAfterReturnType); + IO.mapOptional("AlwaysBreakTemplateDeclarations", + Style.BreakTemplateDeclarations); IO.mapOptional("BreakBeforeInheritanceComma", BreakBeforeInheritanceComma); IO.mapOptional("BreakConstructorInitializersBeforeComma", @@ -882,6 +878,9 @@ template <> struct MappingTraits<FormatStyle> { OnCurrentLine); IO.mapOptional("DeriveLineEnding", DeriveLineEnding); IO.mapOptional("DerivePointerBinding", Style.DerivePointerAlignment); + IO.mapOptional("KeepEmptyLinesAtEOF", Style.KeepEmptyLines.AtEndOfFile); + IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks", + Style.KeepEmptyLines.AtStartOfBlock); IO.mapOptional("IndentFunctionDeclarationAfterType", Style.IndentWrappedFunctionNames); IO.mapOptional("IndentRequires", Style.IndentRequiresClause); @@ -909,6 +908,12 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("AlignConsecutiveMacros", Style.AlignConsecutiveMacros); IO.mapOptional("AlignConsecutiveShortCaseStatements", Style.AlignConsecutiveShortCaseStatements); + IO.mapOptional("AlignConsecutiveTableGenBreakingDAGArgColons", + Style.AlignConsecutiveTableGenBreakingDAGArgColons); + IO.mapOptional("AlignConsecutiveTableGenCondOperatorColons", + Style.AlignConsecutiveTableGenCondOperatorColons); + IO.mapOptional("AlignConsecutiveTableGenDefinitionColons", + Style.AlignConsecutiveTableGenDefinitionColons); IO.mapOptional("AlignEscapedNewlines", Style.AlignEscapedNewlines); IO.mapOptional("AlignOperands", Style.AlignOperands); IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments); @@ -920,6 +925,8 @@ template <> struct MappingTraits<FormatStyle> { Style.AllowBreakBeforeNoexceptSpecifier); IO.mapOptional("AllowShortBlocksOnASingleLine", Style.AllowShortBlocksOnASingleLine); + IO.mapOptional("AllowShortCaseExpressionOnASingleLine", + Style.AllowShortCaseExpressionOnASingleLine); IO.mapOptional("AllowShortCaseLabelsOnASingleLine", Style.AllowShortCaseLabelsOnASingleLine); IO.mapOptional("AllowShortCompoundRequirementOnASingleLine", @@ -936,12 +943,8 @@ template <> struct MappingTraits<FormatStyle> { Style.AllowShortLoopsOnASingleLine); IO.mapOptional("AlwaysBreakAfterDefinitionReturnType", Style.AlwaysBreakAfterDefinitionReturnType); - IO.mapOptional("AlwaysBreakAfterReturnType", - Style.AlwaysBreakAfterReturnType); IO.mapOptional("AlwaysBreakBeforeMultilineStrings", Style.AlwaysBreakBeforeMultilineStrings); - IO.mapOptional("AlwaysBreakTemplateDeclarations", - Style.AlwaysBreakTemplateDeclarations); IO.mapOptional("AttributeMacros", Style.AttributeMacros); IO.mapOptional("BinPackArguments", Style.BinPackArguments); IO.mapOptional("BinPackParameters", Style.BinPackParameters); @@ -954,6 +957,7 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("BreakAfterAttributes", Style.BreakAfterAttributes); IO.mapOptional("BreakAfterJavaFieldAnnotations", Style.BreakAfterJavaFieldAnnotations); + IO.mapOptional("BreakAfterReturnType", Style.BreakAfterReturnType); IO.mapOptional("BreakArrays", Style.BreakArrays); IO.mapOptional("BreakBeforeBinaryOperators", Style.BreakBeforeBinaryOperators); @@ -966,8 +970,12 @@ template <> struct MappingTraits<FormatStyle> { Style.BreakBeforeTernaryOperators); IO.mapOptional("BreakConstructorInitializers", Style.BreakConstructorInitializers); + IO.mapOptional("BreakFunctionDefinitionParameters", + Style.BreakFunctionDefinitionParameters); IO.mapOptional("BreakInheritanceList", Style.BreakInheritanceList); IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals); + IO.mapOptional("BreakTemplateDeclarations", + Style.BreakTemplateDeclarations); IO.mapOptional("ColumnLimit", Style.ColumnLimit); IO.mapOptional("CommentPragmas", Style.CommentPragmas); IO.mapOptional("CompactNamespaces", Style.CompactNamespaces); @@ -1008,14 +1016,13 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("JavaImportGroups", Style.JavaImportGroups); IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes); IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports); - IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks", - Style.KeepEmptyLinesAtTheStartOfBlocks); - IO.mapOptional("KeepEmptyLinesAtEOF", Style.KeepEmptyLinesAtEOF); + IO.mapOptional("KeepEmptyLines", Style.KeepEmptyLines); IO.mapOptional("LambdaBodyIndentation", Style.LambdaBodyIndentation); IO.mapOptional("LineEnding", Style.LineEnding); IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin); IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd); IO.mapOptional("Macros", Style.Macros); + IO.mapOptional("MainIncludeChar", Style.IncludeStyle.MainIncludeChar); IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep); IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation); IO.mapOptional("NamespaceMacros", Style.NamespaceMacros); @@ -1110,6 +1117,10 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("StatementAttributeLikeMacros", Style.StatementAttributeLikeMacros); IO.mapOptional("StatementMacros", Style.StatementMacros); + IO.mapOptional("TableGenBreakingDAGArgOperators", + Style.TableGenBreakingDAGArgOperators); + IO.mapOptional("TableGenBreakInsideDAGArg", + Style.TableGenBreakInsideDAGArg); IO.mapOptional("TabWidth", Style.TabWidth); IO.mapOptional("TypeNames", Style.TypeNames); IO.mapOptional("TypenameMacros", Style.TypenameMacros); @@ -1120,17 +1131,16 @@ template <> struct MappingTraits<FormatStyle> { Style.WhitespaceSensitiveMacros); // If AlwaysBreakAfterDefinitionReturnType was specified but - // AlwaysBreakAfterReturnType was not, initialize the latter from the - // former for backwards compatibility. + // BreakAfterReturnType was not, initialize the latter from the former for + // backwards compatibility. if (Style.AlwaysBreakAfterDefinitionReturnType != FormatStyle::DRTBS_None && - Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) { + Style.BreakAfterReturnType == FormatStyle::RTBS_None) { if (Style.AlwaysBreakAfterDefinitionReturnType == FormatStyle::DRTBS_All) { - Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions; + Style.BreakAfterReturnType = FormatStyle::RTBS_AllDefinitions; } else if (Style.AlwaysBreakAfterDefinitionReturnType == FormatStyle::DRTBS_TopLevel) { - Style.AlwaysBreakAfterReturnType = - FormatStyle::RTBS_TopLevelDefinitions; + Style.BreakAfterReturnType = FormatStyle::RTBS_TopLevelDefinitions; } } @@ -1175,8 +1185,8 @@ template <> struct MappingTraits<FormatStyle> { (SpacesInParentheses || SpaceInEmptyParentheses || SpacesInConditionalStatement || SpacesInCStyleCastParentheses)) { if (SpacesInParentheses) { - // set all options except InCStyleCasts and InEmptyParentheses - // to true for backward compatibility. + // For backward compatibility. + Style.SpacesInParensOptions.ExceptDoubleParentheses = false; Style.SpacesInParensOptions.InConditionalStatements = true; Style.SpacesInParensOptions.InCStyleCasts = SpacesInCStyleCastParentheses; @@ -1236,7 +1246,7 @@ std::error_code make_error_code(ParseError e) { return std::error_code(static_cast<int>(e), getParseCategory()); } -inline llvm::Error make_string_error(const llvm::Twine &Message) { +inline llvm::Error make_string_error(const Twine &Message) { return llvm::make_error<llvm::StringError>(Message, llvm::inconvertibleErrorCode()); } @@ -1401,30 +1411,33 @@ static void expandPresetsSpacesInParens(FormatStyle &Expanded) { FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { FormatStyle LLVMStyle; - LLVMStyle.InheritsParentConfig = false; - LLVMStyle.Language = Language; LLVMStyle.AccessModifierOffset = -2; - LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right; LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align; LLVMStyle.AlignArrayOfStructures = FormatStyle::AIAS_None; - LLVMStyle.AlignOperands = FormatStyle::OAS_Align; LLVMStyle.AlignConsecutiveAssignments = {}; - LLVMStyle.AlignConsecutiveAssignments.Enabled = false; - LLVMStyle.AlignConsecutiveAssignments.AcrossEmptyLines = false; LLVMStyle.AlignConsecutiveAssignments.AcrossComments = false; + LLVMStyle.AlignConsecutiveAssignments.AcrossEmptyLines = false; LLVMStyle.AlignConsecutiveAssignments.AlignCompound = false; LLVMStyle.AlignConsecutiveAssignments.AlignFunctionPointers = false; + LLVMStyle.AlignConsecutiveAssignments.Enabled = false; LLVMStyle.AlignConsecutiveAssignments.PadOperators = true; LLVMStyle.AlignConsecutiveBitFields = {}; LLVMStyle.AlignConsecutiveDeclarations = {}; LLVMStyle.AlignConsecutiveMacros = {}; LLVMStyle.AlignConsecutiveShortCaseStatements = {}; + LLVMStyle.AlignConsecutiveTableGenBreakingDAGArgColons = {}; + LLVMStyle.AlignConsecutiveTableGenCondOperatorColons = {}; + LLVMStyle.AlignConsecutiveTableGenDefinitionColons = {}; + LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right; + LLVMStyle.AlignOperands = FormatStyle::OAS_Align; LLVMStyle.AlignTrailingComments = {}; LLVMStyle.AlignTrailingComments.Kind = FormatStyle::TCAS_Always; LLVMStyle.AlignTrailingComments.OverEmptyLines = 0; LLVMStyle.AllowAllArgumentsOnNextLine = true; LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true; + LLVMStyle.AllowBreakBeforeNoexceptSpecifier = FormatStyle::BBNSS_Never; LLVMStyle.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never; + LLVMStyle.AllowShortCaseExpressionOnASingleLine = true; LLVMStyle.AllowShortCaseLabelsOnASingleLine = false; LLVMStyle.AllowShortCompoundRequirementOnASingleLine = true; LLVMStyle.AllowShortEnumsOnASingleLine = true; @@ -1432,14 +1445,12 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; LLVMStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_All; LLVMStyle.AllowShortLoopsOnASingleLine = false; - LLVMStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None; LLVMStyle.AlwaysBreakBeforeMultilineStrings = false; - LLVMStyle.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_MultiLine; LLVMStyle.AttributeMacros.push_back("__capability"); - LLVMStyle.BitFieldColonSpacing = FormatStyle::BFCS_Both; LLVMStyle.BinPackArguments = true; LLVMStyle.BinPackParameters = true; + LLVMStyle.BitFieldColonSpacing = FormatStyle::BFCS_Both; LLVMStyle.BracedInitializerIndentWidth = std::nullopt; LLVMStyle.BraceWrapping = {/*AfterCaseLabel=*/false, /*AfterClass=*/false, @@ -1462,16 +1473,18 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.BreakAdjacentStringLiterals = true; LLVMStyle.BreakAfterAttributes = FormatStyle::ABS_Leave; LLVMStyle.BreakAfterJavaFieldAnnotations = false; + LLVMStyle.BreakAfterReturnType = FormatStyle::RTBS_None; LLVMStyle.BreakArrays = true; LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None; LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always; LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline; - LLVMStyle.AllowBreakBeforeNoexceptSpecifier = FormatStyle::BBNSS_Never; LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; + LLVMStyle.BreakFunctionDefinitionParameters = false; LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon; LLVMStyle.BreakStringLiterals = true; + LLVMStyle.BreakTemplateDeclarations = FormatStyle::BTDS_MultiLine; LLVMStyle.ColumnLimit = 80; LLVMStyle.CommentPragmas = "^ IWYU pragma:"; LLVMStyle.CompactNamespaces = false; @@ -1488,21 +1501,23 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.ForEachMacros.push_back("Q_FOREACH"); LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH"); LLVMStyle.IfMacros.push_back("KJ_IF_MAYBE"); + LLVMStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Preserve; LLVMStyle.IncludeStyle.IncludeCategories = { {"^\"(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.IncludeStyle.MainIncludeChar = tooling::IncludeStyle::MICD_Quote; LLVMStyle.IndentAccessModifiers = false; - LLVMStyle.IndentCaseLabels = false; LLVMStyle.IndentCaseBlocks = false; + LLVMStyle.IndentCaseLabels = false; LLVMStyle.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; LLVMStyle.IndentGotoLabels = true; LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None; LLVMStyle.IndentRequiresClause = true; LLVMStyle.IndentWidth = 2; LLVMStyle.IndentWrappedFunctionNames = false; + LLVMStyle.InheritsParentConfig = false; LLVMStyle.InsertBraces = false; LLVMStyle.InsertNewlineAtEOF = false; LLVMStyle.InsertTrailingCommas = FormatStyle::TCS_None; @@ -1512,9 +1527,13 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { /*Hex=*/0, /*HexMinDigits=*/0}; LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave; LLVMStyle.JavaScriptWrapImports = true; - LLVMStyle.KeepEmptyLinesAtEOF = false; - LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true; + LLVMStyle.KeepEmptyLines = { + /*AtEndOfFile=*/false, + /*AtStartOfBlock=*/true, + /*AtStartOfFile=*/true, + }; LLVMStyle.LambdaBodyIndentation = FormatStyle::LBI_Signature; + LLVMStyle.Language = Language; LLVMStyle.LineEnding = FormatStyle::LE_DeriveLF; LLVMStyle.MaxEmptyLinesToKeep = 1; LLVMStyle.NamespaceIndentation = FormatStyle::NI_None; @@ -1544,7 +1563,9 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SpaceAfterLogicalNot = false; LLVMStyle.SpaceAfterTemplateKeyword = true; LLVMStyle.SpaceAroundPointerQualifiers = FormatStyle::SAPQ_Default; + LLVMStyle.SpaceBeforeAssignmentOperators = true; LLVMStyle.SpaceBeforeCaseColon = false; + LLVMStyle.SpaceBeforeCpp11BracedList = false; LLVMStyle.SpaceBeforeCtorInitializerColon = true; LLVMStyle.SpaceBeforeInheritanceColon = true; LLVMStyle.SpaceBeforeJsonColon = false; @@ -1554,8 +1575,6 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SpaceBeforeParensOptions.AfterForeachMacros = true; LLVMStyle.SpaceBeforeParensOptions.AfterIfMacros = true; LLVMStyle.SpaceBeforeRangeBasedForLoopColon = true; - LLVMStyle.SpaceBeforeAssignmentOperators = true; - LLVMStyle.SpaceBeforeCpp11BracedList = false; LLVMStyle.SpaceBeforeSquareBrackets = false; LLVMStyle.SpaceInEmptyBlock = false; LLVMStyle.SpacesBeforeTrailingComments = 1; @@ -1568,6 +1587,8 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.StatementAttributeLikeMacros.push_back("Q_EMIT"); LLVMStyle.StatementMacros.push_back("Q_UNUSED"); LLVMStyle.StatementMacros.push_back("QT_REQUIRE_VERSION"); + LLVMStyle.TableGenBreakingDAGArgOperators = {}; + LLVMStyle.TableGenBreakInsideDAGArg = FormatStyle::DAS_DontBreak; LLVMStyle.TabWidth = 8; LLVMStyle.UseTab = FormatStyle::UT_Never; LLVMStyle.VerilogBreakBetweenInstancePorts = true; @@ -1578,16 +1599,16 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.WhitespaceSensitiveMacros.push_back("STRINGIZE"); LLVMStyle.PenaltyBreakAssignment = prec::Assignment; + LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19; LLVMStyle.PenaltyBreakComment = 300; LLVMStyle.PenaltyBreakFirstLessLess = 120; - LLVMStyle.PenaltyBreakString = 1000; - LLVMStyle.PenaltyExcessCharacter = 1000000; - LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60; - LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19; LLVMStyle.PenaltyBreakOpenParenthesis = 0; LLVMStyle.PenaltyBreakScopeResolution = 500; + LLVMStyle.PenaltyBreakString = 1000; LLVMStyle.PenaltyBreakTemplateDeclaration = prec::Relational; + LLVMStyle.PenaltyExcessCharacter = 1'000'000; LLVMStyle.PenaltyIndentedWhitespace = 0; + LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60; // Defaults that differ when not C++. switch (Language) { @@ -1624,16 +1645,16 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { FormatStyle::SIS_WithoutElse; GoogleStyle.AllowShortLoopsOnASingleLine = true; GoogleStyle.AlwaysBreakBeforeMultilineStrings = true; - GoogleStyle.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes; + GoogleStyle.BreakTemplateDeclarations = FormatStyle::BTDS_Yes; GoogleStyle.DerivePointerAlignment = true; + GoogleStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup; 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; - GoogleStyle.KeepEmptyLinesAtTheStartOfBlocks = false; + GoogleStyle.KeepEmptyLines.AtStartOfBlock = false; GoogleStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Never; GoogleStyle.ObjCSpaceAfterProperty = false; GoogleStyle.ObjCSpaceBeforeProtocolList = true; @@ -1686,8 +1707,8 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { GoogleStyle.SpacesBeforeTrailingComments = 2; GoogleStyle.Standard = FormatStyle::LS_Auto; - GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200; GoogleStyle.PenaltyBreakBeforeFirstCallParameter = 1; + GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 200; if (Language == FormatStyle::LK_Java) { GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign; @@ -1715,22 +1736,22 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { // TODO: enable once decided, in particular re disabling bin packing. // https://google.github.io/styleguide/jsguide.html#features-arrays-trailing-comma // GoogleStyle.InsertTrailingCommas = FormatStyle::TCS_Wrapped; + GoogleStyle.JavaScriptQuotes = FormatStyle::JSQS_Single; + GoogleStyle.JavaScriptWrapImports = false; GoogleStyle.MaxEmptyLinesToKeep = 3; GoogleStyle.NamespaceIndentation = FormatStyle::NI_All; GoogleStyle.SpacesInContainerLiterals = false; - GoogleStyle.JavaScriptQuotes = FormatStyle::JSQS_Single; - GoogleStyle.JavaScriptWrapImports = false; } else if (Language == FormatStyle::LK_Proto) { GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; GoogleStyle.AlwaysBreakBeforeMultilineStrings = false; - GoogleStyle.SpacesInContainerLiterals = false; - GoogleStyle.Cpp11BracedListStyle = false; // This affects protocol buffer options specifications and text protos. // Text protos are currently mostly formatted inside C++ raw string literals // and often the current breaking behavior of string literals is not // beneficial there. Investigate turning this on once proper string reflow // has been implemented. GoogleStyle.BreakStringLiterals = false; + GoogleStyle.Cpp11BracedListStyle = false; + GoogleStyle.SpacesInContainerLiterals = false; } else if (Language == FormatStyle::LK_ObjC) { GoogleStyle.AlwaysBreakBeforeMultilineStrings = false; GoogleStyle.ColumnLimit = 100; @@ -1814,15 +1835,15 @@ FormatStyle getMozillaStyle() { FormatStyle MozillaStyle = getLLVMStyle(); MozillaStyle.AllowAllParametersOfDeclarationOnNextLine = false; MozillaStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; - MozillaStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_TopLevel; MozillaStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_TopLevel; - MozillaStyle.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes; - MozillaStyle.BinPackParameters = false; MozillaStyle.BinPackArguments = false; + MozillaStyle.BinPackParameters = false; + MozillaStyle.BreakAfterReturnType = FormatStyle::RTBS_TopLevel; MozillaStyle.BreakBeforeBraces = FormatStyle::BS_Mozilla; MozillaStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma; MozillaStyle.BreakInheritanceList = FormatStyle::BILS_BeforeComma; + MozillaStyle.BreakTemplateDeclarations = FormatStyle::BTDS_Yes; MozillaStyle.ConstructorInitializerIndentWidth = 2; MozillaStyle.ContinuationIndentWidth = 2; MozillaStyle.Cpp11BracedListStyle = false; @@ -1847,8 +1868,8 @@ FormatStyle getWebKitStyle() { Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; Style.BreakBeforeBraces = FormatStyle::BS_WebKit; Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma; - Style.Cpp11BracedListStyle = false; Style.ColumnLimit = 0; + Style.Cpp11BracedListStyle = false; Style.FixNamespaceComments = false; Style.IndentWidth = 4; Style.NamespaceIndentation = FormatStyle::NI_Inner; @@ -1863,12 +1884,12 @@ FormatStyle getWebKitStyle() { FormatStyle getGNUStyle() { FormatStyle Style = getLLVMStyle(); Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_All; - Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions; + Style.BreakAfterReturnType = FormatStyle::RTBS_AllDefinitions; Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; Style.BreakBeforeBraces = FormatStyle::BS_GNU; Style.BreakBeforeTernaryOperators = true; - Style.Cpp11BracedListStyle = false; Style.ColumnLimit = 79; + Style.Cpp11BracedListStyle = false; Style.FixNamespaceComments = false; Style.SpaceBeforeParens = FormatStyle::SBPO_Always; Style.Standard = FormatStyle::LS_Cpp03; @@ -1900,7 +1921,7 @@ FormatStyle getMicrosoftStyle(FormatStyle::LanguageKind Language) { Style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; Style.AllowShortLoopsOnASingleLine = false; Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None; - Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; + Style.BreakAfterReturnType = FormatStyle::RTBS_None; return Style; } @@ -1908,9 +1929,12 @@ FormatStyle getClangFormatStyle() { FormatStyle Style = getLLVMStyle(); Style.InsertBraces = true; Style.InsertNewlineAtEOF = true; + Style.IntegerLiteralSeparator.Decimal = 3; + Style.IntegerLiteralSeparator.DecimalMinDigits = 5; Style.LineEnding = FormatStyle::LE_LF; Style.RemoveBracesLLVM = true; Style.RemoveParentheses = FormatStyle::RPS_ReturnStatement; + Style.RemoveSemicolon = true; return Style; } @@ -2255,27 +2279,36 @@ public: FormatTokenLexer &Tokens) override { AffectedRangeMgr.computeAffectedLines(AnnotatedLines); tooling::Replacements Result; - removeSemi(AnnotatedLines, Result); + removeSemi(Annotator, AnnotatedLines, Result); return {Result, 0}; } private: - void removeSemi(SmallVectorImpl<AnnotatedLine *> &Lines, + void removeSemi(TokenAnnotator &Annotator, + SmallVectorImpl<AnnotatedLine *> &Lines, tooling::Replacements &Result) { + auto PrecededByFunctionRBrace = [](const FormatToken &Tok) { + const auto *Prev = Tok.Previous; + if (!Prev || Prev->isNot(tok::r_brace)) + return false; + const auto *LBrace = Prev->MatchingParen; + return LBrace && LBrace->is(TT_FunctionLBrace); + }; const auto &SourceMgr = Env.getSourceManager(); const auto End = Lines.end(); for (auto I = Lines.begin(); I != End; ++I) { const auto Line = *I; - removeSemi(Line->Children, Result); + removeSemi(Annotator, Line->Children, Result); if (!Line->Affected) continue; + Annotator.calculateFormattingInformation(*Line); const auto NextLine = I + 1 == End ? nullptr : I[1]; for (auto Token = Line->First; Token && !Token->Finalized; Token = Token->Next) { - if (!Token->Optional) - continue; - if (Token->isNot(tok::semi)) + if (Token->isNot(tok::semi) || + (!Token->Optional && !PrecededByFunctionRBrace(*Token))) { continue; + } auto Next = Token->Next; assert(Next || Token == Line->Last); if (!Next && NextLine) @@ -2342,7 +2375,7 @@ private: // FIXME: handle error. For now, print error message and skip the // replacement for release version. if (Err) { - llvm::errs() << llvm::toString(std::move(Err)) << "\n"; + llvm::errs() << toString(std::move(Err)) << "\n"; assert(false); } }; @@ -2783,7 +2816,7 @@ private: // FIXME: better error handling. for now just print error message and skip // for the release version. if (Err) { - llvm::errs() << llvm::toString(std::move(Err)) << "\n"; + llvm::errs() << toString(std::move(Err)) << "\n"; assert(false && "Fixes must not conflict!"); } Idx = End + 1; @@ -2942,9 +2975,9 @@ private: << getTokenTypeName(FormatTok->getType()) << "\n"); return true; } - if (guessIsObjC(SourceManager, Line->Children, Keywords)) - return true; } + if (guessIsObjC(SourceManager, Line->Children, Keywords)) + return true; } return false; } @@ -3055,7 +3088,7 @@ static void sortCppIncludes(const FormatStyle &Style, llvm::to_vector<16>(llvm::seq<unsigned>(0, Includes.size())); if (Style.SortIncludes == FormatStyle::SI_CaseInsensitive) { - llvm::stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { + stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { const auto LHSFilenameLower = Includes[LHSI].Filename.lower(); const auto RHSFilenameLower = Includes[RHSI].Filename.lower(); return std::tie(Includes[LHSI].Priority, LHSFilenameLower, @@ -3064,7 +3097,7 @@ static void sortCppIncludes(const FormatStyle &Style, Includes[RHSI].Filename); }); } else { - llvm::stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { + stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { return std::tie(Includes[LHSI].Priority, Includes[LHSI].Filename) < std::tie(Includes[RHSI].Priority, Includes[RHSI].Filename); }); @@ -3096,11 +3129,12 @@ static void sortCppIncludes(const FormatStyle &Style, // enough as additional newlines might be added or removed across #include // blocks. This we handle below by generating the updated #include blocks and // comparing it to the original. - if (Indices.size() == Includes.size() && llvm::is_sorted(Indices) && + if (Indices.size() == Includes.size() && is_sorted(Indices) && Style.IncludeStyle.IncludeBlocks == tooling::IncludeStyle::IBS_Preserve) { return; } + const auto OldCursor = Cursor ? *Cursor : 0; std::string result; for (unsigned Index : Indices) { if (!result.empty()) { @@ -3124,6 +3158,8 @@ static void sortCppIncludes(const FormatStyle &Style, // the entire range of blocks. Otherwise, no replacement is generated. if (replaceCRLF(result) == replaceCRLF(std::string(Code.substr( IncludesBeginOffset, IncludesBlockSize)))) { + if (Cursor) + *Cursor = OldCursor; return; } @@ -3132,7 +3168,7 @@ static void sortCppIncludes(const FormatStyle &Style, // FIXME: better error handling. For now, just skip the replacement for the // release version. if (Err) { - llvm::errs() << llvm::toString(std::move(Err)) << "\n"; + llvm::errs() << toString(std::move(Err)) << "\n"; assert(false); } } @@ -3186,10 +3222,16 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code, if (Trimmed.contains(RawStringTermination)) FormattingOff = false; - if (isClangFormatOff(Trimmed)) + bool IsBlockComment = false; + + if (isClangFormatOff(Trimmed)) { FormattingOff = true; - else if (isClangFormatOn(Trimmed)) + } else if (isClangFormatOn(Trimmed)) { FormattingOff = false; + } else if (Trimmed.starts_with("/*")) { + IsBlockComment = true; + Pos = Code.find("*/", SearchFrom + 2); + } const bool EmptyLineSkipped = Trimmed.empty() && @@ -3199,9 +3241,10 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code, bool MergeWithNextLine = Trimmed.ends_with("\\"); if (!FormattingOff && !MergeWithNextLine) { - if (tooling::HeaderIncludes::IncludeRegex.match(Line, &Matches)) { + if (!IsBlockComment && + tooling::HeaderIncludes::IncludeRegex.match(Trimmed, &Matches)) { StringRef IncludeName = Matches[2]; - if (Line.contains("/*") && !Line.contains("*/")) { + if (Trimmed.contains("/*") && !Trimmed.contains("*/")) { // #include with a start of a block comment, but without the end. // Need to keep all the lines until the end of the comment together. // FIXME: This is somehow simplified check that probably does not work @@ -3285,7 +3328,7 @@ static void sortJavaImports(const FormatStyle &Style, bool StaticImportAfterNormalImport = Style.SortJavaStaticImport == FormatStyle::SJSIO_After; - llvm::sort(Indices, [&](unsigned LHSI, unsigned RHSI) { + sort(Indices, [&](unsigned LHSI, unsigned RHSI) { // Negating IsStatic to push static imports above non-static imports. return std::make_tuple(!Imports[LHSI].IsStatic ^ StaticImportAfterNormalImport, @@ -3335,7 +3378,7 @@ static void sortJavaImports(const FormatStyle &Style, // FIXME: better error handling. For now, just skip the replacement for the // release version. if (Err) { - llvm::errs() << llvm::toString(std::move(Err)) << "\n"; + llvm::errs() << toString(std::move(Err)) << "\n"; assert(false); } } @@ -3429,7 +3472,7 @@ tooling::Replacements sortIncludes(const FormatStyle &Style, StringRef Code, } template <typename T> -static llvm::Expected<tooling::Replacements> +static Expected<tooling::Replacements> processReplacements(T ProcessFunc, StringRef Code, const tooling::Replacements &Replaces, const FormatStyle &Style) { @@ -3448,7 +3491,7 @@ processReplacements(T ProcessFunc, StringRef Code, return Replaces.merge(FormatReplaces); } -llvm::Expected<tooling::Replacements> +Expected<tooling::Replacements> formatReplacements(StringRef Code, const tooling::Replacements &Replaces, const FormatStyle &Style) { // We need to use lambda function here since there are two versions of @@ -3493,13 +3536,13 @@ fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces, return Replaces; tooling::Replacements HeaderInsertions; - std::set<llvm::StringRef> HeadersToDelete; + std::set<StringRef> HeadersToDelete; tooling::Replacements Result; for (const auto &R : Replaces) { if (isHeaderInsertion(R)) { // Replacements from \p Replaces must be conflict-free already, so we can // simply consume the error. - llvm::consumeError(HeaderInsertions.add(R)); + consumeError(HeaderInsertions.add(R)); } else if (isHeaderDeletion(R)) { HeadersToDelete.insert(R.getReplacementText()); } else if (R.getOffset() == UINT_MAX) { @@ -3507,7 +3550,7 @@ fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces, "not supported! " << R.getReplacementText() << "\n"; } else { - llvm::consumeError(Result.add(R)); + consumeError(Result.add(R)); } } if (HeaderInsertions.empty() && HeadersToDelete.empty()) @@ -3524,13 +3567,12 @@ fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces, if (Err) { // Ignore the deletion on conflict. llvm::errs() << "Failed to add header deletion replacement for " - << Header << ": " << llvm::toString(std::move(Err)) - << "\n"; + << Header << ": " << toString(std::move(Err)) << "\n"; } } } - llvm::SmallVector<StringRef, 4> Matches; + SmallVector<StringRef, 4> Matches; for (const auto &R : HeaderInsertions) { auto IncludeDirective = R.getReplacementText(); bool Matched = @@ -3545,7 +3587,7 @@ fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces, if (Replace) { auto Err = Result.add(*Replace); if (Err) { - llvm::consumeError(std::move(Err)); + consumeError(std::move(Err)); unsigned NewOffset = Result.getShiftedCodePosition(Replace->getOffset()); auto Shifted = tooling::Replacement(FileName, NewOffset, 0, @@ -3559,13 +3601,13 @@ fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces, } // anonymous namespace -llvm::Expected<tooling::Replacements> +Expected<tooling::Replacements> cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces, const FormatStyle &Style) { // We need to use lambda function here since there are two versions of // `cleanup`. auto Cleanup = [](const FormatStyle &Style, StringRef Code, - std::vector<tooling::Range> Ranges, + ArrayRef<tooling::Range> Ranges, StringRef FileName) -> tooling::Replacements { return cleanup(Style, Code, Ranges, FileName); }; @@ -3671,7 +3713,7 @@ reformat(const FormatStyle &Style, StringRef Code, FormatStyle S = Expanded; S.RemoveSemicolon = true; Passes.emplace_back([&, S = std::move(S)](const Environment &Env) { - return SemiRemover(Env, S).process(/*SkipAnnotation=*/true); + return SemiRemover(Env, S).process(); }); } @@ -3748,11 +3790,11 @@ reformat(const FormatStyle &Style, StringRef Code, tooling::Replacements NonNoOpFixes; for (const tooling::Replacement &Fix : Fixes) { StringRef OriginalCode = Code.substr(Fix.getOffset(), Fix.getLength()); - if (!OriginalCode.equals(Fix.getReplacementText())) { + if (OriginalCode != Fix.getReplacementText()) { auto Err = NonNoOpFixes.add(Fix); if (Err) { llvm::errs() << "Error adding replacements : " - << llvm::toString(std::move(Err)) << "\n"; + << toString(std::move(Err)) << "\n"; } } } @@ -3836,8 +3878,7 @@ LangOptions getFormattingLangOpts(const FormatStyle &Style) { LangOpts.Digraphs = LexingStd >= FormatStyle::LS_Cpp11; LangOpts.LineComment = 1; - bool AlternativeOperators = Style.isCpp(); - LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0; + LangOpts.CXXOperatorNames = Style.isCpp(); LangOpts.Bool = 1; LangOpts.ObjC = 1; LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally. @@ -3875,7 +3916,11 @@ static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) { FileName.ends_with_insensitive(".protodevel")) { return FormatStyle::LK_Proto; } - if (FileName.ends_with_insensitive(".textpb") || + // txtpb is the canonical extension, and textproto is the legacy canonical + // extension + // https://protobuf.dev/reference/protobuf/textformat-spec/#text-format-files + if (FileName.ends_with_insensitive(".txtpb") || + FileName.ends_with_insensitive(".textpb") || FileName.ends_with_insensitive(".pb.txt") || FileName.ends_with_insensitive(".textproto") || FileName.ends_with_insensitive(".asciipb")) { @@ -3902,7 +3947,7 @@ FormatStyle::LanguageKind guessLanguage(StringRef FileName, StringRef Code) { auto Extension = llvm::sys::path::extension(FileName); // If there's no file extension (or it's .h), we need to check the contents // of the code to see if it contains Objective-C. - if (Extension.empty() || Extension == ".h") { + if (!Code.empty() && (Extension.empty() || Extension == ".h")) { auto NonEmptyFileName = FileName.empty() ? "guess.h" : FileName; Environment Env(Code, NonEmptyFileName, /*Ranges=*/{}); ObjCHeaderStyleGuesser Guesser(Env, getLLVMStyle()); @@ -3921,34 +3966,37 @@ const char *DefaultFallbackStyle = "LLVM"; llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> loadAndParseConfigFile(StringRef ConfigFile, llvm::vfs::FileSystem *FS, - FormatStyle *Style, bool AllowUnknownOptions) { + FormatStyle *Style, bool AllowUnknownOptions, + llvm::SourceMgr::DiagHandlerTy DiagHandler) { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = FS->getBufferForFile(ConfigFile.str()); if (auto EC = Text.getError()) return EC; - if (auto EC = parseConfiguration(*Text.get(), Style, AllowUnknownOptions)) + if (auto EC = parseConfiguration(*Text.get(), Style, AllowUnknownOptions, + DiagHandler)) { return EC; + } return Text; } -llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, - StringRef FallbackStyleName, - StringRef Code, llvm::vfs::FileSystem *FS, - bool AllowUnknownOptions) { +Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, + StringRef FallbackStyleName, StringRef Code, + llvm::vfs::FileSystem *FS, + bool AllowUnknownOptions, + llvm::SourceMgr::DiagHandlerTy DiagHandler) { FormatStyle Style = getLLVMStyle(guessLanguage(FileName, Code)); FormatStyle FallbackStyle = getNoStyle(); if (!getPredefinedStyle(FallbackStyleName, Style.Language, &FallbackStyle)) return make_string_error("Invalid fallback style: " + FallbackStyleName); - llvm::SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 1> - ChildFormatTextToApply; + SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 1> ChildFormatTextToApply; if (StyleName.starts_with("{")) { // Parse YAML/JSON style from the command line. StringRef Source = "<command-line>"; if (std::error_code ec = parseConfiguration(llvm::MemoryBufferRef(StyleName, Source), &Style, - AllowUnknownOptions)) { + AllowUnknownOptions, DiagHandler)) { return make_string_error("Error parsing -style: " + ec.message()); } @@ -3968,7 +4016,8 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, StyleName.starts_with_insensitive("file:")) { auto ConfigFile = StyleName.substr(5); llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = - loadAndParseConfigFile(ConfigFile, FS, &Style, AllowUnknownOptions); + loadAndParseConfigFile(ConfigFile, FS, &Style, AllowUnknownOptions, + DiagHandler); if (auto EC = Text.getError()) { return make_string_error("Error reading " + ConfigFile + ": " + EC.message()); @@ -4007,8 +4056,9 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, auto applyChildFormatTexts = [&](FormatStyle *Style) { for (const auto &MemBuf : llvm::reverse(ChildFormatTextToApply)) { - auto EC = parseConfiguration(*MemBuf, Style, AllowUnknownOptions, - dropDiagnosticHandler); + auto EC = + parseConfiguration(*MemBuf, Style, AllowUnknownOptions, + DiagHandler ? DiagHandler : dropDiagnosticHandler); // It was already correctly parsed. assert(!EC); static_cast<void>(EC); @@ -4016,7 +4066,7 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, }; // Look for .clang-format/_clang-format file in the file's parent directories. - llvm::SmallVector<std::string, 2> FilesToLookFor; + SmallVector<std::string, 2> FilesToLookFor; FilesToLookFor.push_back(".clang-format"); FilesToLookFor.push_back("_clang-format"); @@ -4042,7 +4092,8 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, } llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = - loadAndParseConfigFile(ConfigFile, FS, &Style, AllowUnknownOptions); + loadAndParseConfigFile(ConfigFile, FS, &Style, AllowUnknownOptions, + DiagHandler); if (auto EC = Text.getError()) { if (EC != ParseError::Unsuitable) { return make_string_error("Error reading " + ConfigFile + ": " + diff --git a/contrib/llvm-project/clang/lib/Format/FormatInternal.h b/contrib/llvm-project/clang/lib/Format/FormatInternal.h index 9043ce32e9e3..60c5bf6b786b 100644 --- a/contrib/llvm-project/clang/lib/Format/FormatInternal.h +++ b/contrib/llvm-project/clang/lib/Format/FormatInternal.h @@ -15,7 +15,9 @@ #ifndef LLVM_CLANG_LIB_FORMAT_FORMATINTERNAL_H #define LLVM_CLANG_LIB_FORMAT_FORMATINTERNAL_H -#include "BreakableToken.h" +#include "clang/Basic/LLVM.h" +#include "clang/Format/Format.h" +#include "clang/Tooling/Core/Replacement.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 b791c5a26bbe..85bec71ffbbc 100644 --- a/contrib/llvm-project/clang/lib/Format/FormatToken.cpp +++ b/contrib/llvm-project/clang/lib/Format/FormatToken.cpp @@ -34,45 +34,23 @@ const char *getTokenTypeName(TokenType Type) { return nullptr; } -// FIXME: This is copy&pasted from Sema. Put it in a common place and remove -// duplication. -bool FormatToken::isSimpleTypeSpecifier() const { - switch (Tok.getKind()) { - case tok::kw_short: - case tok::kw_long: - case tok::kw___int64: - case tok::kw___int128: - case tok::kw_signed: - case tok::kw_unsigned: - case tok::kw_void: - case tok::kw_char: - case tok::kw_int: - case tok::kw_half: - case tok::kw_float: - case tok::kw_double: - case tok::kw___bf16: - case tok::kw__Float16: - case tok::kw___float128: - case tok::kw___ibm128: - case tok::kw_wchar_t: - case tok::kw_bool: -#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: -#include "clang/Basic/TransformTypeTraits.def" - case tok::annot_typename: - case tok::kw_char8_t: - case tok::kw_char16_t: - case tok::kw_char32_t: - case tok::kw_typeof: - case tok::kw_decltype: - case tok::kw__Atomic: - return true; - default: - return false; - } +// Sorted common C++ non-keyword types. +static SmallVector<StringRef> CppNonKeywordTypes = { + "clock_t", "int16_t", "int32_t", "int64_t", "int8_t", + "intptr_t", "ptrdiff_t", "size_t", "time_t", "uint16_t", + "uint32_t", "uint64_t", "uint8_t", "uintptr_t", +}; + +bool FormatToken::isTypeName(const LangOptions &LangOpts) const { + const bool IsCpp = LangOpts.CXXOperatorNames; + return is(TT_TypeName) || Tok.isSimpleTypeSpecifier(LangOpts) || + (IsCpp && is(tok::identifier) && + std::binary_search(CppNonKeywordTypes.begin(), + CppNonKeywordTypes.end(), TokenText)); } -bool FormatToken::isTypeOrIdentifier() const { - return isSimpleTypeSpecifier() || Tok.isOneOf(tok::kw_auto, tok::identifier); +bool FormatToken::isTypeOrIdentifier(const LangOptions &LangOpts) const { + return isTypeName(LangOpts) || isOneOf(tok::kw_auto, tok::identifier); } bool FormatToken::isBlockIndentedInitRBrace(const FormatStyle &Style) const { @@ -137,7 +115,7 @@ unsigned CommaSeparatedList::formatAfterToken(LineState &State, // bin-packed. Add a severe penalty to this so that column layouts are // preferred if possible. if (!Format) - return 10000; + return 10'000; // Format the entire list. unsigned Penalty = 0; diff --git a/contrib/llvm-project/clang/lib/Format/FormatToken.h b/contrib/llvm-project/clang/lib/Format/FormatToken.h index dede89f26001..cc45d5a8c5c1 100644 --- a/contrib/llvm-project/clang/lib/Format/FormatToken.h +++ b/contrib/llvm-project/clang/lib/Format/FormatToken.h @@ -19,8 +19,6 @@ #include "clang/Basic/OperatorPrecedence.h" #include "clang/Format/Format.h" #include "clang/Lex/Lexer.h" -#include <memory> -#include <optional> #include <unordered_set> namespace clang { @@ -37,7 +35,10 @@ namespace format { TYPE(BinaryOperator) \ TYPE(BitFieldColon) \ TYPE(BlockComment) \ + /* l_brace of a block that is not the body of a (e.g. loop) statement. */ \ + TYPE(BlockLBrace) \ TYPE(BracedListLBrace) \ + TYPE(CaseLabelArrow) \ /* The colon at the end of a case label. */ \ TYPE(CaseLabelColon) \ TYPE(CastRParen) \ @@ -76,6 +77,7 @@ namespace format { TYPE(ForEachMacro) \ TYPE(FunctionAnnotationRParen) \ TYPE(FunctionDeclarationName) \ + TYPE(FunctionDeclarationLParen) \ TYPE(FunctionLBrace) \ TYPE(FunctionLikeOrFreestandingMacro) \ TYPE(FunctionTypeLParen) \ @@ -148,7 +150,26 @@ namespace format { TYPE(StructLBrace) \ TYPE(StructRBrace) \ TYPE(StructuredBindingLSquare) \ + TYPE(SwitchExpressionLabel) \ + TYPE(SwitchExpressionLBrace) \ + TYPE(TableGenBangOperator) \ + TYPE(TableGenCondOperator) \ + TYPE(TableGenCondOperatorColon) \ + TYPE(TableGenCondOperatorComma) \ + TYPE(TableGenDAGArgCloser) \ + TYPE(TableGenDAGArgListColon) \ + TYPE(TableGenDAGArgListColonToAlign) \ + TYPE(TableGenDAGArgListComma) \ + TYPE(TableGenDAGArgListCommaToBreak) \ + TYPE(TableGenDAGArgOpener) \ + TYPE(TableGenDAGArgOpenerToBreak) \ + TYPE(TableGenDAGArgOperatorID) \ + TYPE(TableGenDAGArgOperatorToBreak) \ + TYPE(TableGenListCloser) \ + TYPE(TableGenListOpener) \ TYPE(TableGenMultiLineString) \ + TYPE(TableGenTrailingPasteOperator) \ + TYPE(TableGenValueSuffix) \ TYPE(TemplateCloser) \ TYPE(TemplateOpener) \ TYPE(TemplateString) \ @@ -559,6 +580,9 @@ public: /// Is optional and can be removed. bool Optional = false; + /// Might be function declaration open/closing paren. + bool MightBeFunctionDeclParen = false; + /// Number of optional braces to be inserted after this token: /// -1: a single left brace /// 0: no braces @@ -644,12 +668,16 @@ public: return Tok.isObjCAtKeyword(Kind); } + bool isAccessSpecifierKeyword() const { + return isOneOf(tok::kw_public, tok::kw_protected, tok::kw_private); + } + bool isAccessSpecifier(bool ColonRequired = true) const { - if (!isOneOf(tok::kw_public, tok::kw_protected, tok::kw_private)) + if (!isAccessSpecifierKeyword()) return false; if (!ColonRequired) return true; - const auto NextNonComment = getNextNonComment(); + const auto *NextNonComment = getNextNonComment(); return NextNonComment && NextNonComment->is(tok::colon); } @@ -661,10 +689,8 @@ public: isAttribute(); } - /// Determine whether the token is a simple-type-specifier. - [[nodiscard]] bool isSimpleTypeSpecifier() const; - - [[nodiscard]] bool isTypeOrIdentifier() const; + [[nodiscard]] bool isTypeName(const LangOptions &LangOpts) const; + [[nodiscard]] bool isTypeOrIdentifier(const LangOptions &LangOpts) const; bool isObjCAccessSpecifier() const { return is(tok::at) && Next && @@ -706,6 +732,29 @@ public: return isOneOf(tok::star, tok::amp, tok::ampamp); } + bool isCppAlternativeOperatorKeyword() const { + assert(!TokenText.empty()); + if (!isalpha(TokenText[0])) + return false; + + switch (Tok.getKind()) { + case tok::ampamp: + case tok::ampequal: + case tok::amp: + case tok::pipe: + case tok::tilde: + case tok::exclaim: + case tok::exclaimequal: + case tok::pipepipe: + case tok::pipeequal: + case tok::caret: + case tok::caretequal: + return true; + default: + return false; + } + } + bool isUnaryOperator() const { switch (Tok.getKind()) { case tok::plus: @@ -809,8 +858,8 @@ public: /// Returns whether the token is the left square bracket of a C++ /// structured binding declaration. - bool isCppStructuredBinding(const FormatStyle &Style) const { - if (!Style.isCpp() || isNot(tok::l_square)) + bool isCppStructuredBinding(bool IsCpp) const { + if (!IsCpp || isNot(tok::l_square)) return false; const FormatToken *T = this; do { @@ -1601,10 +1650,10 @@ struct AdditionalKeywords { IdentifierInfo *kw_then; /// Returns \c true if \p Tok is a keyword or an identifier. - bool isWordLike(const FormatToken &Tok) const { + bool isWordLike(const FormatToken &Tok, bool IsVerilog = true) const { // getIdentifierinfo returns non-null for keywords as well as identifiers. return Tok.Tok.getIdentifierInfo() && - !Tok.isOneOf(kw_verilogHash, kw_verilogHashHash, kw_apostrophe); + (!IsVerilog || !isVerilogKeywordSymbol(Tok)); } /// Returns \c true if \p Tok is a true JavaScript identifier, returns @@ -1612,10 +1661,12 @@ struct AdditionalKeywords { /// If \c AcceptIdentifierName is true, returns true not only for keywords, // but also for IdentifierName tokens (aka pseudo-keywords), such as // ``yield``. - bool IsJavaScriptIdentifier(const FormatToken &Tok, + bool isJavaScriptIdentifier(const FormatToken &Tok, bool AcceptIdentifierName = true) const { // Based on the list of JavaScript & TypeScript keywords here: // https://github.com/microsoft/TypeScript/blob/main/src/compiler/scanner.ts#L74 + if (Tok.isAccessSpecifierKeyword()) + return false; switch (Tok.Tok.getKind()) { case tok::kw_break: case tok::kw_case: @@ -1635,9 +1686,6 @@ struct AdditionalKeywords { case tok::kw_import: case tok::kw_module: case tok::kw_new: - case tok::kw_private: - case tok::kw_protected: - case tok::kw_public: case tok::kw_return: case tok::kw_static: case tok::kw_switch: @@ -1680,6 +1728,8 @@ struct AdditionalKeywords { /// Returns \c true if \p Tok is a C# keyword, returns /// \c false if it is a anything else. bool isCSharpKeyword(const FormatToken &Tok) const { + if (Tok.isAccessSpecifierKeyword()) + return true; switch (Tok.Tok.getKind()) { case tok::kw_bool: case tok::kw_break: @@ -1706,9 +1756,6 @@ struct AdditionalKeywords { case tok::kw_namespace: case tok::kw_new: case tok::kw_operator: - case tok::kw_private: - case tok::kw_protected: - case tok::kw_public: case tok::kw_return: case tok::kw_short: case tok::kw_sizeof: @@ -1733,6 +1780,10 @@ struct AdditionalKeywords { } } + bool isVerilogKeywordSymbol(const FormatToken &Tok) const { + return Tok.isOneOf(kw_verilogHash, kw_verilogHashHash, kw_apostrophe); + } + bool isVerilogWordOperator(const FormatToken &Tok) const { return Tok.isOneOf(kw_before, kw_intersect, kw_dist, kw_iff, kw_inside, kw_with); diff --git a/contrib/llvm-project/clang/lib/Format/FormatTokenLexer.cpp b/contrib/llvm-project/clang/lib/Format/FormatTokenLexer.cpp index 52a55ea23b5f..e21b5a882b77 100644 --- a/contrib/llvm-project/clang/lib/Format/FormatTokenLexer.cpp +++ b/contrib/llvm-project/clang/lib/Format/FormatTokenLexer.cpp @@ -276,13 +276,44 @@ void FormatTokenLexer::tryMergePreviousTokens() { return; } } - // TableGen's Multi line string starts with [{ - if (Style.isTableGen() && tryMergeTokens({tok::l_square, tok::l_brace}, - TT_TableGenMultiLineString)) { - // Set again with finalizing. This must never be annotated as other types. - Tokens.back()->setFinalizedType(TT_TableGenMultiLineString); - Tokens.back()->Tok.setKind(tok::string_literal); - return; + if (Style.isTableGen()) { + // TableGen's Multi line string starts with [{ + if (tryMergeTokens({tok::l_square, tok::l_brace}, + TT_TableGenMultiLineString)) { + // Set again with finalizing. This must never be annotated as other types. + Tokens.back()->setFinalizedType(TT_TableGenMultiLineString); + Tokens.back()->Tok.setKind(tok::string_literal); + return; + } + // TableGen's bang operator is the form !<name>. + // !cond is a special case with specific syntax. + if (tryMergeTokens({tok::exclaim, tok::identifier}, + TT_TableGenBangOperator)) { + Tokens.back()->Tok.setKind(tok::identifier); + Tokens.back()->Tok.setIdentifierInfo(nullptr); + if (Tokens.back()->TokenText == "!cond") + Tokens.back()->setFinalizedType(TT_TableGenCondOperator); + else + Tokens.back()->setFinalizedType(TT_TableGenBangOperator); + return; + } + if (tryMergeTokens({tok::exclaim, tok::kw_if}, TT_TableGenBangOperator)) { + // Here, "! if" becomes "!if". That is, ! captures if even when the space + // exists. That is only one possibility in TableGen's syntax. + Tokens.back()->Tok.setKind(tok::identifier); + Tokens.back()->Tok.setIdentifierInfo(nullptr); + Tokens.back()->setFinalizedType(TT_TableGenBangOperator); + return; + } + // +, - with numbers are literals. Not unary operators. + if (tryMergeTokens({tok::plus, tok::numeric_constant}, TT_Unknown)) { + Tokens.back()->Tok.setKind(tok::numeric_constant); + return; + } + if (tryMergeTokens({tok::minus, tok::numeric_constant}, TT_Unknown)) { + Tokens.back()->Tok.setKind(tok::numeric_constant); + return; + } } } @@ -373,7 +404,7 @@ bool FormatTokenLexer::tryMergeNullishCoalescingEqual() { return false; auto &NullishCoalescing = *(Tokens.end() - 2); auto &Equal = *(Tokens.end() - 1); - if (NullishCoalescing->getType() != TT_NullCoalescingOperator || + if (NullishCoalescing->isNot(TT_NullCoalescingOperator) || Equal->isNot(tok::equal)) { return false; } @@ -785,7 +816,7 @@ void FormatTokenLexer::handleTableGenMultilineString() { auto CloseOffset = Lex->getBuffer().find("}]", OpenOffset); if (CloseOffset == StringRef::npos) return; - auto Text = Lex->getBuffer().substr(OpenOffset, CloseOffset + 2); + auto Text = Lex->getBuffer().substr(OpenOffset, CloseOffset - OpenOffset + 2); MultiLineString->TokenText = Text; resetLexer(SourceMgr.getFileOffset( Lex->getSourceLocation(Lex->getBufferLocation() - 2 + Text.size()))); @@ -1389,7 +1420,7 @@ void FormatTokenLexer::readRawToken(FormatToken &Tok) { // For formatting, treat unterminated string literals like normal string // literals. if (Tok.is(tok::unknown)) { - if (!Tok.TokenText.empty() && Tok.TokenText[0] == '"') { + if (Tok.TokenText.starts_with("\"")) { Tok.Tok.setKind(tok::string_literal); Tok.IsUnterminatedLiteral = true; } else if (Style.isJavaScript() && Tok.TokenText == "''") { @@ -1411,7 +1442,6 @@ void FormatTokenLexer::readRawToken(FormatToken &Tok) { void FormatTokenLexer::resetLexer(unsigned Offset) { StringRef Buffer = SourceMgr.getBufferData(ID); - LangOpts = getFormattingLangOpts(Style); Lex.reset(new Lexer(SourceMgr.getLocForStartOfFile(ID), LangOpts, Buffer.begin(), Buffer.begin() + Offset, Buffer.end())); Lex->SetKeepWhitespaceMode(true); diff --git a/contrib/llvm-project/clang/lib/Format/FormatTokenLexer.h b/contrib/llvm-project/clang/lib/Format/FormatTokenLexer.h index 65dd733bd533..277cc0a2dfde 100644 --- a/contrib/llvm-project/clang/lib/Format/FormatTokenLexer.h +++ b/contrib/llvm-project/clang/lib/Format/FormatTokenLexer.h @@ -17,14 +17,9 @@ #include "Encoding.h" #include "FormatToken.h" -#include "clang/Basic/LangOptions.h" -#include "clang/Basic/SourceLocation.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Format/Format.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringSet.h" -#include "llvm/Support/Regex.h" #include <stack> diff --git a/contrib/llvm-project/clang/lib/Format/FormatTokenSource.h b/contrib/llvm-project/clang/lib/Format/FormatTokenSource.h index 7819244eb7d1..8f00e5f4582c 100644 --- a/contrib/llvm-project/clang/lib/Format/FormatTokenSource.h +++ b/contrib/llvm-project/clang/lib/Format/FormatTokenSource.h @@ -15,10 +15,7 @@ #ifndef LLVM_CLANG_LIB_FORMAT_FORMATTOKENSOURCE_H #define LLVM_CLANG_LIB_FORMAT_FORMATTOKENSOURCE_H -#include "FormatToken.h" #include "UnwrappedLineParser.h" -#include "llvm/ADT/DenseMap.h" -#include <cstddef> #define DEBUG_TYPE "format-token-source" @@ -75,6 +72,15 @@ public: // getNextToken() -> a1 // getNextToken() -> a2 virtual FormatToken *insertTokens(ArrayRef<FormatToken *> Tokens) = 0; + + [[nodiscard]] FormatToken *getNextNonComment() { + FormatToken *Tok; + do { + Tok = getNextToken(); + assert(Tok); + } while (Tok->is(tok::comment)); + return Tok; + } }; class IndexedTokenSource : public FormatTokenSource { @@ -167,7 +173,7 @@ private: return Next; } - void dbgToken(int Position, llvm::StringRef Indent = "") { + void dbgToken(int Position, StringRef Indent = "") { FormatToken *Tok = Tokens[Position]; llvm::dbgs() << Indent << "[" << Position << "] Token: " << Tok->Tok.getName() << " / " << Tok->TokenText diff --git a/contrib/llvm-project/clang/lib/Format/MacroCallReconstructor.cpp b/contrib/llvm-project/clang/lib/Format/MacroCallReconstructor.cpp index cbdd1683c54d..101acefdfe7a 100644 --- a/contrib/llvm-project/clang/lib/Format/MacroCallReconstructor.cpp +++ b/contrib/llvm-project/clang/lib/Format/MacroCallReconstructor.cpp @@ -33,7 +33,7 @@ void forEachToken(const UnwrappedLine &Line, const T &Call, FormatToken *Parent = nullptr) { bool First = true; for (const auto &N : Line.Tokens) { - Call(N.Tok, Parent, First); + Call(N.Tok, Parent, First, Line.Level); First = false; for (const auto &Child : N.Children) forEachToken(Child, Call, N.Tok); @@ -44,7 +44,7 @@ MacroCallReconstructor::MacroCallReconstructor( unsigned Level, const llvm::DenseMap<FormatToken *, std::unique_ptr<UnwrappedLine>> &ActiveExpansions) - : Level(Level), IdToReconstructed(ActiveExpansions) { + : Result(Level), IdToReconstructed(ActiveExpansions) { Result.Tokens.push_back(std::make_unique<LineNode>()); ActiveReconstructedLines.push_back(&Result); } @@ -52,9 +52,8 @@ MacroCallReconstructor::MacroCallReconstructor( void MacroCallReconstructor::addLine(const UnwrappedLine &Line) { assert(State != Finalized); LLVM_DEBUG(llvm::dbgs() << "MCR: new line...\n"); - forEachToken(Line, [&](FormatToken *Token, FormatToken *Parent, bool First) { - add(Token, Parent, First); - }); + forEachToken(Line, [&](FormatToken *Token, FormatToken *Parent, bool First, + unsigned Level) { add(Token, Parent, First, Level); }); assert(InProgress || finished()); } @@ -62,8 +61,8 @@ UnwrappedLine MacroCallReconstructor::takeResult() && { finalize(); assert(Result.Tokens.size() == 1 && Result.Tokens.front()->Children.size() == 1); - UnwrappedLine Final = - createUnwrappedLine(*Result.Tokens.front()->Children.front(), Level); + UnwrappedLine Final = createUnwrappedLine( + *Result.Tokens.front()->Children.front(), Result.Level); assert(!Final.Tokens.empty()); return Final; } @@ -72,7 +71,8 @@ UnwrappedLine MacroCallReconstructor::takeResult() && { // ExpandedParent in the incoming unwrapped line. \p First specifies whether it // is the first token in a given unwrapped line. void MacroCallReconstructor::add(FormatToken *Token, - FormatToken *ExpandedParent, bool First) { + FormatToken *ExpandedParent, bool First, + unsigned Level) { LLVM_DEBUG( llvm::dbgs() << "MCR: Token: " << Token->TokenText << ", Parent: " << (ExpandedParent ? ExpandedParent->TokenText : "<null>") @@ -102,7 +102,7 @@ void MacroCallReconstructor::add(FormatToken *Token, First = true; } - prepareParent(ExpandedParent, First); + prepareParent(ExpandedParent, First, Level); if (Token->MacroCtx) { // If this token was generated by a macro call, add the reconstructed @@ -129,7 +129,7 @@ void MacroCallReconstructor::add(FormatToken *Token, // is the parent of ActiveReconstructedLines.back() in the reconstructed // unwrapped line. void MacroCallReconstructor::prepareParent(FormatToken *ExpandedParent, - bool NewLine) { + bool NewLine, unsigned Level) { LLVM_DEBUG({ llvm::dbgs() << "ParentMap:\n"; debugParentMap(); @@ -172,7 +172,7 @@ void MacroCallReconstructor::prepareParent(FormatToken *ExpandedParent, } assert(!ActiveReconstructedLines.empty()); ActiveReconstructedLines.back()->Tokens.back()->Children.push_back( - std::make_unique<ReconstructedLine>()); + std::make_unique<ReconstructedLine>(Level)); ActiveReconstructedLines.push_back( &*ActiveReconstructedLines.back()->Tokens.back()->Children.back()); } else if (parentLine().Tokens.back()->Tok != Parent) { @@ -424,7 +424,8 @@ bool MacroCallReconstructor::processNextReconstructed() { SpelledParentToReconstructedParent[MacroCallStructure.back() .ParentLastToken] = Token; appendToken(Token); - prepareParent(Token, /*NewLine=*/true); + prepareParent(Token, /*NewLine=*/true, + MacroCallStructure.back().Line->Level); Token->MacroParent = true; return false; } @@ -435,7 +436,8 @@ bool MacroCallReconstructor::processNextReconstructed() { [MacroCallStructure.back().Line->Tokens.back()->Tok] = Token; Token->MacroParent = true; appendToken(Token, MacroCallStructure.back().Line); - prepareParent(Token, /*NewLine=*/true); + prepareParent(Token, /*NewLine=*/true, + MacroCallStructure.back().Line->Level); return true; } if (Token->is(tok::r_paren)) { @@ -509,16 +511,36 @@ MacroCallReconstructor::createUnwrappedLine(const ReconstructedLine &Line, for (const auto &N : Line.Tokens) { Result.Tokens.push_back(N->Tok); UnwrappedLineNode &Current = Result.Tokens.back(); - for (const auto &Child : N->Children) { - if (Child->Tokens.empty()) - continue; - Current.Children.push_back(createUnwrappedLine(*Child, Level + 1)); - } - if (Current.Children.size() == 1 && - Current.Tok->isOneOf(tok::l_paren, tok::comma)) { - Result.Tokens.splice(Result.Tokens.end(), - Current.Children.front().Tokens); - Current.Children.clear(); + auto NumChildren = + std::count_if(N->Children.begin(), N->Children.end(), + [](const auto &Child) { return !Child->Tokens.empty(); }); + if (NumChildren == 1 && Current.Tok->isOneOf(tok::l_paren, tok::comma)) { + // If we only have one child, and the child is due to a macro expansion + // (either attached to a left parenthesis or comma), merge the child into + // the current line to prevent forced breaks for macro arguments. + auto *Child = std::find_if( + N->Children.begin(), N->Children.end(), + [](const auto &Child) { return !Child->Tokens.empty(); }); + auto Line = createUnwrappedLine(**Child, Level); + Result.Tokens.splice(Result.Tokens.end(), Line.Tokens); + } else if (NumChildren > 0) { + // When there are multiple children with different indent, make sure that + // we indent them: + // 1. One level below the current line's level. + // 2. At the correct level relative to each other. + unsigned MinChildLevel = + std::min_element(N->Children.begin(), N->Children.end(), + [](const auto &E1, const auto &E2) { + return E1->Level < E2->Level; + }) + ->get() + ->Level; + for (const auto &Child : N->Children) { + if (Child->Tokens.empty()) + continue; + Current.Children.push_back(createUnwrappedLine( + *Child, Level + 1 + (Child->Level - MinChildLevel))); + } } } return Result; diff --git a/contrib/llvm-project/clang/lib/Format/MacroExpander.cpp b/contrib/llvm-project/clang/lib/Format/MacroExpander.cpp index 5a1cdd884c5e..5768ff37fefc 100644 --- a/contrib/llvm-project/clang/lib/Format/MacroExpander.cpp +++ b/contrib/llvm-project/clang/lib/Format/MacroExpander.cpp @@ -119,7 +119,7 @@ private: }; MacroExpander::MacroExpander( - const std::vector<std::string> &Macros, clang::SourceManager &SourceMgr, + const std::vector<std::string> &Macros, SourceManager &SourceMgr, const FormatStyle &Style, llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator, IdentifierTable &IdentTable) @@ -134,7 +134,7 @@ 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()); + FileID FID = SourceMgr.createFileID(Buffers.back()->getMemBufferRef()); FormatTokenLexer Lex(SourceMgr, FID, 0, Style, encoding::Encoding_UTF8, Allocator, IdentTable); const auto Tokens = Lex.lex(); @@ -150,20 +150,20 @@ void MacroExpander::parseDefinition(const std::string &Macro) { } } -bool MacroExpander::defined(llvm::StringRef Name) const { +bool MacroExpander::defined(StringRef Name) const { return FunctionLike.contains(Name) || ObjectLike.contains(Name); } -bool MacroExpander::objectLike(llvm::StringRef Name) const { +bool MacroExpander::objectLike(StringRef Name) const { return ObjectLike.contains(Name); } -bool MacroExpander::hasArity(llvm::StringRef Name, unsigned Arity) const { +bool MacroExpander::hasArity(StringRef Name, unsigned Arity) const { auto it = FunctionLike.find(Name); return it != FunctionLike.end() && it->second.contains(Arity); } -llvm::SmallVector<FormatToken *, 8> +SmallVector<FormatToken *, 8> MacroExpander::expand(FormatToken *ID, std::optional<ArgsList> OptionalArgs) const { if (OptionalArgs) diff --git a/contrib/llvm-project/clang/lib/Format/Macros.h b/contrib/llvm-project/clang/lib/Format/Macros.h index 1964624e828c..e05f734b0db8 100644 --- a/contrib/llvm-project/clang/lib/Format/Macros.h +++ b/contrib/llvm-project/clang/lib/Format/Macros.h @@ -39,15 +39,9 @@ #define CLANG_LIB_FORMAT_MACROS_H #include <list> -#include <map> -#include <string> -#include <vector> #include "FormatToken.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" namespace clang { namespace format { @@ -85,7 +79,7 @@ struct UnwrappedLineNode; /// class MacroExpander { public: - using ArgsList = llvm::ArrayRef<llvm::SmallVector<FormatToken *, 8>>; + using ArgsList = ArrayRef<SmallVector<FormatToken *, 8>>; /// Construct a macro expander from a set of macro definitions. /// Macro definitions must be encoded as UTF-8. @@ -101,27 +95,27 @@ public: /// Macros that cannot be parsed will be silently discarded. /// MacroExpander(const std::vector<std::string> &Macros, - clang::SourceManager &SourceMgr, const FormatStyle &Style, + SourceManager &SourceMgr, const FormatStyle &Style, llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator, IdentifierTable &IdentTable); ~MacroExpander(); /// Returns whether any macro \p Name is defined, regardless of overloads. - bool defined(llvm::StringRef Name) const; + bool defined(StringRef Name) const; /// Returns whetherh there is an object-like overload, i.e. where the macro /// has no arguments and should not consume subsequent parentheses. - bool objectLike(llvm::StringRef Name) const; + bool objectLike(StringRef Name) const; /// Returns whether macro \p Name provides an overload with the given arity. - bool hasArity(llvm::StringRef Name, unsigned Arity) const; + bool hasArity(StringRef Name, unsigned Arity) 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. /// If \p Args is not set, the object-like overload is used. /// If \p Args is set, the overload with the arity equal to \c Args.size() is /// used. - llvm::SmallVector<FormatToken *, 8> + SmallVector<FormatToken *, 8> expand(FormatToken *ID, std::optional<ArgsList> OptionalArgs) const; private: @@ -130,7 +124,7 @@ private: void parseDefinition(const std::string &Macro); - clang::SourceManager &SourceMgr; + SourceManager &SourceMgr; const FormatStyle &Style; llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator; IdentifierTable &IdentTable; @@ -231,8 +225,9 @@ public: UnwrappedLine takeResult() &&; private: - void add(FormatToken *Token, FormatToken *ExpandedParent, bool First); - void prepareParent(FormatToken *ExpandedParent, bool First); + void add(FormatToken *Token, FormatToken *ExpandedParent, bool First, + unsigned Level); + void prepareParent(FormatToken *ExpandedParent, bool First, unsigned Level); FormatToken *getParentInResult(FormatToken *Parent); void reconstruct(FormatToken *Token); void startReconstruction(FormatToken *Token); @@ -265,14 +260,16 @@ private: LineNode() = default; LineNode(FormatToken *Tok) : Tok(Tok) {} FormatToken *Tok = nullptr; - llvm::SmallVector<std::unique_ptr<ReconstructedLine>> Children; + SmallVector<std::unique_ptr<ReconstructedLine>> Children; }; // Line in which we build up the resulting unwrapped line. // FIXME: Investigate changing UnwrappedLine to a pointer type and using it // instead of rolling our own type. struct ReconstructedLine { - llvm::SmallVector<std::unique_ptr<LineNode>> Tokens; + explicit ReconstructedLine(unsigned Level) : Level(Level) {} + unsigned Level; + SmallVector<std::unique_ptr<LineNode>> Tokens; }; // The line in which we collect the resulting reconstructed output. @@ -288,7 +285,7 @@ private: // Stack of currently "open" lines, where each line's predecessor's last // token is the parent token for that line. - llvm::SmallVector<ReconstructedLine *> ActiveReconstructedLines; + SmallVector<ReconstructedLine *> ActiveReconstructedLines; // Maps from the expanded token to the token that takes its place in the // reconstructed token stream in terms of parent-child relationships. @@ -328,7 +325,7 @@ private: }; // Stack of macro calls for which we're in the middle of an expansion. - llvm::SmallVector<Expansion> ActiveExpansions; + SmallVector<Expansion> ActiveExpansions; struct MacroCallState { MacroCallState(ReconstructedLine *Line, FormatToken *ParentLastToken, @@ -371,10 +368,7 @@ private: // |- , // | \- <argument> // \- ) - llvm::SmallVector<MacroCallState> MacroCallStructure; - - // Level the generated UnwrappedLine will be at. - const unsigned Level; + SmallVector<MacroCallState> MacroCallStructure; // Maps from identifier of the macro call to an unwrapped line containing // all tokens of the macro call. diff --git a/contrib/llvm-project/clang/lib/Format/QualifierAlignmentFixer.cpp b/contrib/llvm-project/clang/lib/Format/QualifierAlignmentFixer.cpp index 84941746f0df..593f8efff25a 100644 --- a/contrib/llvm-project/clang/lib/Format/QualifierAlignmentFixer.cpp +++ b/contrib/llvm-project/clang/lib/Format/QualifierAlignmentFixer.cpp @@ -272,7 +272,7 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( // The case `long const long int volatile` -> `long long int const volatile` // The case `long long volatile int const` -> `long long int const volatile` // The case `const long long volatile int` -> `long long int const volatile` - if (TypeToken->isSimpleTypeSpecifier()) { + if (TypeToken->isTypeName(LangOpts)) { // The case `const decltype(foo)` -> `const decltype(foo)` // The case `const typeof(foo)` -> `const typeof(foo)` // The case `const _Atomic(foo)` -> `const _Atomic(foo)` @@ -280,8 +280,10 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( return Tok; const FormatToken *LastSimpleTypeSpecifier = TypeToken; - while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment())) + while (isQualifierOrType(LastSimpleTypeSpecifier->getNextNonComment(), + LangOpts)) { LastSimpleTypeSpecifier = LastSimpleTypeSpecifier->getNextNonComment(); + } rotateTokens(SourceMgr, Fixes, Tok, LastSimpleTypeSpecifier, /*Left=*/false); @@ -291,7 +293,7 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( // The case `unsigned short const` -> `unsigned short const` // The case: // `unsigned short volatile const` -> `unsigned short const volatile` - if (PreviousCheck && PreviousCheck->isSimpleTypeSpecifier()) { + if (PreviousCheck && PreviousCheck->isTypeName(LangOpts)) { if (LastQual != Tok) rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false); return Tok; @@ -408,11 +410,11 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( // The case `volatile long long const int` -> `const volatile long long int` // The case `const long long volatile int` -> `const volatile long long int` // The case `long volatile long int const` -> `const volatile long long int` - if (TypeToken->isSimpleTypeSpecifier()) { + if (TypeToken->isTypeName(LangOpts)) { const FormatToken *LastSimpleTypeSpecifier = TypeToken; while (isConfiguredQualifierOrType( LastSimpleTypeSpecifier->getPreviousNonComment(), - ConfiguredQualifierTokens)) { + ConfiguredQualifierTokens, LangOpts)) { LastSimpleTypeSpecifier = LastSimpleTypeSpecifier->getPreviousNonComment(); } @@ -561,6 +563,8 @@ void LeftRightQualifierAlignmentFixer::fixQualifierAlignment( for (const auto *Tok = First; Tok && Tok != Last && Tok->Next; Tok = Tok->Next) { + if (Tok->MustBreakBefore) + break; if (Tok->is(tok::comment)) continue; if (RightAlign) { @@ -608,22 +612,21 @@ void prepareLeftRightOrderingForQualifierAlignmentFixer( } } -bool LeftRightQualifierAlignmentFixer::isQualifierOrType( - const FormatToken *const Tok) { - return Tok && (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_auto) || +bool isQualifierOrType(const FormatToken *Tok, const LangOptions &LangOpts) { + return Tok && (Tok->isTypeName(LangOpts) || Tok->is(tok::kw_auto) || isQualifier(Tok)); } -bool LeftRightQualifierAlignmentFixer::isConfiguredQualifierOrType( - const FormatToken *const Tok, - const std::vector<tok::TokenKind> &Qualifiers) { - return Tok && (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_auto) || +bool isConfiguredQualifierOrType(const FormatToken *Tok, + const std::vector<tok::TokenKind> &Qualifiers, + const LangOptions &LangOpts) { + return Tok && (Tok->isTypeName(LangOpts) || Tok->is(tok::kw_auto) || isConfiguredQualifier(Tok, Qualifiers)); } // If a token is an identifier and it's upper case, it could // be a macro and hence we need to be able to ignore it. -bool LeftRightQualifierAlignmentFixer::isPossibleMacro(const FormatToken *Tok) { +bool isPossibleMacro(const FormatToken *Tok) { if (!Tok) return false; if (Tok->isNot(tok::identifier)) diff --git a/contrib/llvm-project/clang/lib/Format/QualifierAlignmentFixer.h b/contrib/llvm-project/clang/lib/Format/QualifierAlignmentFixer.h index e922d8005595..a0a0d597ebf3 100644 --- a/contrib/llvm-project/clang/lib/Format/QualifierAlignmentFixer.h +++ b/contrib/llvm-project/clang/lib/Format/QualifierAlignmentFixer.h @@ -32,6 +32,15 @@ void prepareLeftRightOrderingForQualifierAlignmentFixer( std::vector<std::string> &RightOrder, std::vector<tok::TokenKind> &Qualifiers); +// Is the Token a simple or qualifier type +bool isQualifierOrType(const FormatToken *Tok, const LangOptions &LangOpts); +bool isConfiguredQualifierOrType(const FormatToken *Tok, + const std::vector<tok::TokenKind> &Qualifiers, + const LangOptions &LangOpts); + +// Is the Token likely a Macro +bool isPossibleMacro(const FormatToken *Tok); + class LeftRightQualifierAlignmentFixer : public TokenAnalyzer { std::string Qualifier; bool RightAlign; @@ -69,15 +78,6 @@ public: const FormatToken *Tok, const std::string &Qualifier, tok::TokenKind QualifierType); - - // Is the Token a simple or qualifier type - static bool isQualifierOrType(const FormatToken *Tok); - static bool - isConfiguredQualifierOrType(const FormatToken *Tok, - const std::vector<tok::TokenKind> &Qualifiers); - - // Is the Token likely a Macro - static bool isPossibleMacro(const FormatToken *Tok); }; } // end namespace format diff --git a/contrib/llvm-project/clang/lib/Format/SortJavaScriptImports.cpp b/contrib/llvm-project/clang/lib/Format/SortJavaScriptImports.cpp index 1a6a1b19e702..1acce26ff279 100644 --- a/contrib/llvm-project/clang/lib/Format/SortJavaScriptImports.cpp +++ b/contrib/llvm-project/clang/lib/Format/SortJavaScriptImports.cpp @@ -34,8 +34,6 @@ namespace format { class FormatTokenLexer; -using clang::format::FormatStyle; - // An imported symbol in a JavaScript ES6 import/export, possibly aliased. struct JsImportedSymbol { StringRef Symbol; @@ -178,7 +176,7 @@ public: } } } - llvm::StringRef PreviousText = getSourceText(InsertionPoint); + StringRef PreviousText = getSourceText(InsertionPoint); if (ReferencesText == PreviousText) return {Result, 0}; @@ -209,7 +207,7 @@ public: // FIXME: better error handling. For now, just print error message and skip // the replacement for the release version. if (Err) { - llvm::errs() << llvm::toString(std::move(Err)) << "\n"; + llvm::errs() << toString(std::move(Err)) << "\n"; assert(false); } @@ -276,7 +274,7 @@ private: SortChunk.push_back(*Start); ++Start; } - llvm::stable_sort(SortChunk); + stable_sort(SortChunk); mergeModuleReferences(SortChunk); ReferencesSorted.insert(ReferencesSorted.end(), SortChunk.begin(), SortChunk.end()); @@ -334,10 +332,10 @@ private: // Sort the individual symbols within the import. // E.g. `import {b, a} from 'x';` -> `import {a, b} from 'x';` SmallVector<JsImportedSymbol, 1> Symbols = Reference.Symbols; - llvm::stable_sort( - Symbols, [&](const JsImportedSymbol &LHS, const JsImportedSymbol &RHS) { - return LHS.Symbol.compare_insensitive(RHS.Symbol) < 0; - }); + stable_sort(Symbols, + [&](const JsImportedSymbol &LHS, const JsImportedSymbol &RHS) { + return LHS.Symbol.compare_insensitive(RHS.Symbol) < 0; + }); if (!Reference.SymbolsMerged && Symbols == Reference.Symbols) { // Symbols didn't change, just emit the entire module reference. StringRef ReferenceStmt = getSourceText(Reference.Range); @@ -349,7 +347,7 @@ private: // ... then the references in order ... if (!Symbols.empty()) { Buffer += getSourceText(Symbols.front().Range); - for (const JsImportedSymbol &Symbol : llvm::drop_begin(Symbols)) { + for (const JsImportedSymbol &Symbol : drop_begin(Symbols)) { Buffer += ","; Buffer += getSourceText(Symbol.Range); } diff --git a/contrib/llvm-project/clang/lib/Format/SortJavaScriptImports.h b/contrib/llvm-project/clang/lib/Format/SortJavaScriptImports.h index 7336db9537b0..b55b149aab4c 100644 --- a/contrib/llvm-project/clang/lib/Format/SortJavaScriptImports.h +++ b/contrib/llvm-project/clang/lib/Format/SortJavaScriptImports.h @@ -14,10 +14,7 @@ #ifndef LLVM_CLANG_LIB_FORMAT_SORTJAVASCRIPTIMPORTS_H #define LLVM_CLANG_LIB_FORMAT_SORTJAVASCRIPTIMPORTS_H -#include "clang/Basic/LLVM.h" #include "clang/Format/Format.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" namespace clang { namespace format { diff --git a/contrib/llvm-project/clang/lib/Format/TokenAnalyzer.cpp b/contrib/llvm-project/clang/lib/Format/TokenAnalyzer.cpp index bd648c430f9b..804a2b0f5e8c 100644 --- a/contrib/llvm-project/clang/lib/Format/TokenAnalyzer.cpp +++ b/contrib/llvm-project/clang/lib/Format/TokenAnalyzer.cpp @@ -84,7 +84,7 @@ Environment::Environment(StringRef Code, StringRef FileName, NextStartColumn(NextStartColumn), LastStartColumn(LastStartColumn) {} TokenAnalyzer::TokenAnalyzer(const Environment &Env, const FormatStyle &Style) - : Style(Style), Env(Env), + : Style(Style), LangOpts(getFormattingLangOpts(Style)), Env(Env), AffectedRangeMgr(Env.getSourceManager(), Env.getCharRanges()), UnwrappedLines(1), Encoding(encoding::detectEncoding( @@ -101,7 +101,7 @@ std::pair<tooling::Replacements, unsigned> TokenAnalyzer::process(bool SkipAnnotation) { tooling::Replacements Result; llvm::SpecificBumpPtrAllocator<FormatToken> Allocator; - IdentifierTable IdentTable(getFormattingLangOpts(Style)); + IdentifierTable IdentTable(LangOpts); FormatTokenLexer Lex(Env.getSourceManager(), Env.getFileID(), Env.getFirstStartColumn(), Style, Encoding, Allocator, IdentTable); diff --git a/contrib/llvm-project/clang/lib/Format/TokenAnalyzer.h b/contrib/llvm-project/clang/lib/Format/TokenAnalyzer.h index 4086dab1c94c..ef559099d325 100644 --- a/contrib/llvm-project/clang/lib/Format/TokenAnalyzer.h +++ b/contrib/llvm-project/clang/lib/Format/TokenAnalyzer.h @@ -17,19 +17,8 @@ #define LLVM_CLANG_LIB_FORMAT_TOKENANALYZER_H #include "AffectedRangeManager.h" -#include "Encoding.h" -#include "FormatToken.h" #include "FormatTokenLexer.h" #include "TokenAnnotator.h" -#include "UnwrappedLineParser.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/DiagnosticOptions.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Format/Format.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/Debug.h" -#include <memory> namespace clang { namespace format { @@ -103,6 +92,7 @@ protected: void finishRun() override; FormatStyle Style; + LangOptions LangOpts; // Stores Style, FileID and SourceManager etc. const Environment &Env; // AffectedRangeMgr stores ranges to be fixed. diff --git a/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp b/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp index c1f166248192..21924a8fe17d 100644 --- a/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp +++ b/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp @@ -126,7 +126,9 @@ public: const AdditionalKeywords &Keywords, SmallVector<ScopeType> &Scopes) : Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false), - Keywords(Keywords), Scopes(Scopes) { + IsCpp(Style.isCpp()), LangOpts(getFormattingLangOpts(Style)), + Keywords(Keywords), Scopes(Scopes), TemplateDeclarationDepth(0) { + assert(IsCpp == LangOpts.CXXOperatorNames); Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false)); resetTokenMetadata(); } @@ -174,10 +176,6 @@ private: Left->ParentBracket = Contexts.back().ContextKind; ScopedContextCreator ContextCreator(*this, tok::less, 12); - // If this angle is in the context of an expression, we need to be more - // hesitant to detect it as opening template parameters. - bool InExprContext = Contexts.back().IsExpression; - Contexts.back().IsExpression = false; // If there's a template keyword before the opening angle bracket, this is a // template parameter, not an argument. @@ -229,11 +227,8 @@ private: next(); continue; } - if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) || - (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext && - !Style.isCSharp() && !Style.isProto())) { + if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace)) return false; - } // If a && or || is found and interpreted as a binary operator, this set // of angles is likely part of something like "a < b && c > d". If the // angles are inside an expression, the ||/&& might also be a binary @@ -256,6 +251,18 @@ private: } } } + if (Style.isTableGen()) { + if (CurrentToken->isOneOf(tok::comma, tok::equal)) { + // They appear as separators. Unless they are not in class definition. + next(); + continue; + } + // In angle, there must be Value like tokens. Types are also able to be + // parsed in the same way with Values. + if (!parseTableGenValue()) + return false; + continue; + } if (!consumeToken()) return false; } @@ -365,10 +372,6 @@ private: OpeningParen.Previous->is(tok::kw__Generic)) { Contexts.back().ContextType = Context::C11GenericSelection; Contexts.back().IsExpression = true; - } else if (Line.InPPDirective && - (!OpeningParen.Previous || - OpeningParen.Previous->isNot(tok::identifier))) { - Contexts.back().IsExpression = true; } else if (Contexts[Contexts.size() - 2].CaretFound) { // This is the parameter list of an ObjC block. Contexts.back().IsExpression = false; @@ -381,13 +384,48 @@ private: OpeningParen.Previous->MatchingParen->isOneOf( TT_ObjCBlockLParen, TT_FunctionTypeLParen)) { Contexts.back().IsExpression = false; - } else if (!Line.MustBeDeclaration && !Line.InPPDirective) { + } else if (Line.InPPDirective) { + auto IsExpr = [&OpeningParen] { + const auto *Tok = OpeningParen.Previous; + if (!Tok || Tok->isNot(tok::identifier)) + return true; + Tok = Tok->Previous; + while (Tok && Tok->endsSequence(tok::coloncolon, tok::identifier)) { + assert(Tok->Previous); + Tok = Tok->Previous->Previous; + } + return !Tok || !Tok->Tok.getIdentifierInfo(); + }; + Contexts.back().IsExpression = IsExpr(); + } else if (!Line.MustBeDeclaration) { bool IsForOrCatch = OpeningParen.Previous && OpeningParen.Previous->isOneOf(tok::kw_for, tok::kw_catch); Contexts.back().IsExpression = !IsForOrCatch; } + if (Style.isTableGen()) { + if (FormatToken *Prev = OpeningParen.Previous) { + if (Prev->is(TT_TableGenCondOperator)) { + Contexts.back().IsTableGenCondOpe = true; + Contexts.back().IsExpression = true; + } else if (Contexts.size() > 1 && + Contexts[Contexts.size() - 2].IsTableGenBangOpe) { + // Hack to handle bang operators. The parent context's flag + // was set by parseTableGenSimpleValue(). + // We have to specify the context outside because the prev of "(" may + // be ">", not the bang operator in this case. + Contexts.back().IsTableGenBangOpe = true; + Contexts.back().IsExpression = true; + } else { + // Otherwise, this paren seems DAGArg. + if (!parseTableGenDAGArg()) + return false; + return parseTableGenDAGArgAndList(&OpeningParen); + } + } + } + // Infer the role of the l_paren based on the previous token if we haven't // detected one yet. if (PrevNonComment && OpeningParen.is(TT_Unknown)) { @@ -528,7 +566,7 @@ private: (CurrentToken->is(tok::l_paren) && CurrentToken->Next && CurrentToken->Next->isOneOf(tok::star, tok::amp, tok::caret)); if ((CurrentToken->Previous->isOneOf(tok::kw_const, tok::kw_auto) || - CurrentToken->Previous->isSimpleTypeSpecifier()) && + CurrentToken->Previous->isTypeName(LangOpts)) && !(CurrentToken->is(tok::l_brace) || (CurrentToken->is(tok::l_paren) && !ProbablyFunctionTypeLParen))) { Contexts.back().IsExpression = false; @@ -549,6 +587,22 @@ private: if (CurrentToken->is(tok::comma)) Contexts.back().CanBeExpression = true; + if (Style.isTableGen()) { + if (CurrentToken->is(tok::comma)) { + if (Contexts.back().IsTableGenCondOpe) + CurrentToken->setType(TT_TableGenCondOperatorComma); + next(); + } else if (CurrentToken->is(tok::colon)) { + if (Contexts.back().IsTableGenCondOpe) + CurrentToken->setType(TT_TableGenCondOperatorColon); + next(); + } + // In TableGen there must be Values in parens. + if (!parseTableGenValue()) + return false; + continue; + } + FormatToken *Tok = CurrentToken; if (!consumeToken()) return false; @@ -595,8 +649,8 @@ private: return true; // Limit this to being an access modifier that follows. - if (AttrTok->isOneOf(tok::kw_public, tok::kw_private, tok::kw_protected, - tok::comment, tok::kw_class, tok::kw_static, + if (AttrTok->isAccessSpecifierKeyword() || + AttrTok->isOneOf(tok::comment, tok::kw_class, tok::kw_static, tok::l_square, Keywords.kw_internal)) { return true; } @@ -626,13 +680,13 @@ private: // In C++, this can happen either in array of templates (foo<int>[10]) // or when array is a nested template type (unique_ptr<type1<type2>[]>). bool CppArrayTemplates = - Style.isCpp() && Parent && Parent->is(TT_TemplateCloser) && + IsCpp && Parent && Parent->is(TT_TemplateCloser) && (Contexts.back().CanBeExpression || Contexts.back().IsExpression || Contexts.back().ContextType == Context::TemplateArgument); const bool IsInnerSquare = Contexts.back().InCpp11AttributeSpecifier; const bool IsCpp11AttributeSpecifier = - isCppAttribute(Style.isCpp(), *Left) || IsInnerSquare; + isCppAttribute(IsCpp, *Left) || IsInnerSquare; // Treat C# Attributes [STAThread] much like C++ attributes [[...]]. bool IsCSharpAttributeSpecifier = @@ -640,12 +694,11 @@ private: Contexts.back().InCSharpAttributeSpecifier; bool InsideInlineASM = Line.startsWith(tok::kw_asm); - bool IsCppStructuredBinding = Left->isCppStructuredBinding(Style); + bool IsCppStructuredBinding = Left->isCppStructuredBinding(IsCpp); bool StartsObjCMethodExpr = !IsCppStructuredBinding && !InsideInlineASM && !CppArrayTemplates && - Style.isCpp() && !IsCpp11AttributeSpecifier && - !IsCSharpAttributeSpecifier && Contexts.back().CanBeExpression && - Left->isNot(TT_LambdaLSquare) && + IsCpp && !IsCpp11AttributeSpecifier && !IsCSharpAttributeSpecifier && + Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) && !CurrentToken->isOneOf(tok::l_brace, tok::r_square) && (!Parent || Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren, @@ -673,7 +726,7 @@ private: Contexts.back().ContextKind == tok::l_brace && Parent->isOneOf(tok::l_brace, tok::comma)) { Left->setType(TT_JsComputedPropertyName); - } else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace && + } else if (IsCpp && Contexts.back().ContextKind == tok::l_brace && Parent && Parent->isOneOf(tok::l_brace, tok::comma)) { Left->setType(TT_DesignatedInitializerLSquare); } else if (IsCSharpAttributeSpecifier) { @@ -776,8 +829,7 @@ private: Parent->overwriteFixedType(TT_BinaryOperator); } // An arrow after an ObjC method expression is not a lambda arrow. - if (CurrentToken->getType() == TT_ObjCMethodExpr && - CurrentToken->Next && + if (CurrentToken->is(TT_ObjCMethodExpr) && CurrentToken->Next && CurrentToken->Next->is(TT_TrailingReturnArrow)) { CurrentToken->Next->overwriteFixedType(TT_Unknown); } @@ -803,6 +855,8 @@ private: if (Left->BlockParameterCount > 1) Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = 0; } + if (Style.isTableGen() && Left->is(TT_TableGenListOpener)) + CurrentToken->setType(TT_TableGenListCloser); next(); return true; } @@ -833,6 +887,19 @@ private: Left->setType(TT_ArrayInitializerLSquare); } FormatToken *Tok = CurrentToken; + if (Style.isTableGen()) { + if (CurrentToken->isOneOf(tok::comma, tok::minus, tok::ellipsis)) { + // '-' and '...' appears as a separator in slice. + next(); + } else { + // In TableGen there must be a list of Values in square brackets. + // It must be ValueList or SliceElements. + if (!parseTableGenValue()) + return false; + } + updateParameterCount(Left, Tok); + continue; + } if (!consumeToken()) return false; updateParameterCount(Left, Tok); @@ -840,6 +907,242 @@ private: return false; } + void skipToNextNonComment() { + next(); + while (CurrentToken && CurrentToken->is(tok::comment)) + next(); + } + + // Simplified parser for TableGen Value. Returns true on success. + // It consists of SimpleValues, SimpleValues with Suffixes, and Value followed + // by '#', paste operator. + // There also exists the case the Value is parsed as NameValue. + // In this case, the Value ends if '{' is found. + bool parseTableGenValue(bool ParseNameMode = false) { + if (!CurrentToken) + return false; + while (CurrentToken->is(tok::comment)) + next(); + if (!parseTableGenSimpleValue()) + return false; + if (!CurrentToken) + return true; + // Value "#" [Value] + if (CurrentToken->is(tok::hash)) { + if (CurrentToken->Next && + CurrentToken->Next->isOneOf(tok::colon, tok::semi, tok::l_brace)) { + // Trailing paste operator. + // These are only the allowed cases in TGParser::ParseValue(). + CurrentToken->setType(TT_TableGenTrailingPasteOperator); + next(); + return true; + } + FormatToken *HashTok = CurrentToken; + skipToNextNonComment(); + HashTok->setType(TT_Unknown); + if (!parseTableGenValue(ParseNameMode)) + return false; + } + // In name mode, '{' is regarded as the end of the value. + // See TGParser::ParseValue in TGParser.cpp + if (ParseNameMode && CurrentToken->is(tok::l_brace)) + return true; + // These tokens indicates this is a value with suffixes. + if (CurrentToken->isOneOf(tok::l_brace, tok::l_square, tok::period)) { + CurrentToken->setType(TT_TableGenValueSuffix); + FormatToken *Suffix = CurrentToken; + skipToNextNonComment(); + if (Suffix->is(tok::l_square)) + return parseSquare(); + if (Suffix->is(tok::l_brace)) { + Scopes.push_back(getScopeType(*Suffix)); + return parseBrace(); + } + } + return true; + } + + // TokVarName ::= "$" ualpha (ualpha | "0"..."9")* + // Appears as a part of DagArg. + // This does not change the current token on fail. + bool tryToParseTableGenTokVar() { + if (!CurrentToken) + return false; + if (CurrentToken->is(tok::identifier) && + CurrentToken->TokenText.front() == '$') { + skipToNextNonComment(); + return true; + } + return false; + } + + // DagArg ::= Value [":" TokVarName] | TokVarName + // Appears as a part of SimpleValue6. + bool parseTableGenDAGArg(bool AlignColon = false) { + if (tryToParseTableGenTokVar()) + return true; + if (parseTableGenValue()) { + if (CurrentToken && CurrentToken->is(tok::colon)) { + if (AlignColon) + CurrentToken->setType(TT_TableGenDAGArgListColonToAlign); + else + CurrentToken->setType(TT_TableGenDAGArgListColon); + skipToNextNonComment(); + return tryToParseTableGenTokVar(); + } + return true; + } + return false; + } + + // Judge if the token is a operator ID to insert line break in DAGArg. + // That is, TableGenBreakingDAGArgOperators is empty (by the definition of the + // option) or the token is in the list. + bool isTableGenDAGArgBreakingOperator(const FormatToken &Tok) { + auto &Opes = Style.TableGenBreakingDAGArgOperators; + // If the list is empty, all operators are breaking operators. + if (Opes.empty()) + return true; + // Otherwise, the operator is limited to normal identifiers. + if (Tok.isNot(tok::identifier) || + Tok.isOneOf(TT_TableGenBangOperator, TT_TableGenCondOperator)) { + return false; + } + // The case next is colon, it is not a operator of identifier. + if (!Tok.Next || Tok.Next->is(tok::colon)) + return false; + return std::find(Opes.begin(), Opes.end(), Tok.TokenText.str()) != + Opes.end(); + } + + // SimpleValue6 ::= "(" DagArg [DagArgList] ")" + // This parses SimpleValue 6's inside part of "(" ")" + bool parseTableGenDAGArgAndList(FormatToken *Opener) { + FormatToken *FirstTok = CurrentToken; + if (!parseTableGenDAGArg()) + return false; + bool BreakInside = false; + if (Style.TableGenBreakInsideDAGArg != FormatStyle::DAS_DontBreak) { + // Specialized detection for DAGArgOperator, that determines the way of + // line break for this DAGArg elements. + if (isTableGenDAGArgBreakingOperator(*FirstTok)) { + // Special case for identifier DAGArg operator. + BreakInside = true; + Opener->setType(TT_TableGenDAGArgOpenerToBreak); + if (FirstTok->isOneOf(TT_TableGenBangOperator, + TT_TableGenCondOperator)) { + // Special case for bang/cond operators. Set the whole operator as + // the DAGArg operator. Always break after it. + CurrentToken->Previous->setType(TT_TableGenDAGArgOperatorToBreak); + } else if (FirstTok->is(tok::identifier)) { + if (Style.TableGenBreakInsideDAGArg == FormatStyle::DAS_BreakAll) + FirstTok->setType(TT_TableGenDAGArgOperatorToBreak); + else + FirstTok->setType(TT_TableGenDAGArgOperatorID); + } + } + } + // Parse the [DagArgList] part + bool FirstDAGArgListElm = true; + while (CurrentToken) { + if (!FirstDAGArgListElm && CurrentToken->is(tok::comma)) { + CurrentToken->setType(BreakInside ? TT_TableGenDAGArgListCommaToBreak + : TT_TableGenDAGArgListComma); + skipToNextNonComment(); + } + if (CurrentToken && CurrentToken->is(tok::r_paren)) { + CurrentToken->setType(TT_TableGenDAGArgCloser); + Opener->MatchingParen = CurrentToken; + CurrentToken->MatchingParen = Opener; + skipToNextNonComment(); + return true; + } + if (!parseTableGenDAGArg( + BreakInside && + Style.AlignConsecutiveTableGenBreakingDAGArgColons.Enabled)) { + return false; + } + FirstDAGArgListElm = false; + } + return false; + } + + bool parseTableGenSimpleValue() { + assert(Style.isTableGen()); + if (!CurrentToken) + return false; + FormatToken *Tok = CurrentToken; + skipToNextNonComment(); + // SimpleValue 1, 2, 3: Literals + if (Tok->isOneOf(tok::numeric_constant, tok::string_literal, + TT_TableGenMultiLineString, tok::kw_true, tok::kw_false, + tok::question, tok::kw_int)) { + return true; + } + // SimpleValue 4: ValueList, Type + if (Tok->is(tok::l_brace)) { + Scopes.push_back(getScopeType(*Tok)); + return parseBrace(); + } + // SimpleValue 5: List initializer + if (Tok->is(tok::l_square)) { + Tok->setType(TT_TableGenListOpener); + if (!parseSquare()) + return false; + if (Tok->is(tok::less)) { + CurrentToken->setType(TT_TemplateOpener); + return parseAngle(); + } + return true; + } + // SimpleValue 6: DAGArg [DAGArgList] + // SimpleValue6 ::= "(" DagArg [DagArgList] ")" + if (Tok->is(tok::l_paren)) { + Tok->setType(TT_TableGenDAGArgOpener); + return parseTableGenDAGArgAndList(Tok); + } + // SimpleValue 9: Bang operator + if (Tok->is(TT_TableGenBangOperator)) { + if (CurrentToken && CurrentToken->is(tok::less)) { + CurrentToken->setType(TT_TemplateOpener); + skipToNextNonComment(); + if (!parseAngle()) + return false; + } + if (!CurrentToken || CurrentToken->isNot(tok::l_paren)) + return false; + skipToNextNonComment(); + // FIXME: Hack using inheritance to child context + Contexts.back().IsTableGenBangOpe = true; + bool Result = parseParens(); + Contexts.back().IsTableGenBangOpe = false; + return Result; + } + // SimpleValue 9: Cond operator + if (Tok->is(TT_TableGenCondOperator)) { + Tok = CurrentToken; + skipToNextNonComment(); + if (!Tok || Tok->isNot(tok::l_paren)) + return false; + bool Result = parseParens(); + return Result; + } + // We have to check identifier at the last because the kind of bang/cond + // operators are also identifier. + // SimpleValue 7: Identifiers + if (Tok->is(tok::identifier)) { + // SimpleValue 8: Anonymous record + if (CurrentToken && CurrentToken->is(tok::less)) { + CurrentToken->setType(TT_TemplateOpener); + skipToNextNonComment(); + return parseAngle(); + } + return true; + } + + return false; + } + bool couldBeInStructArrayInitializer() const { if (Contexts.size() < 2) return false; @@ -880,6 +1183,8 @@ private: OpeningBrace.getPreviousNonComment()->isNot(Keywords.kw_apostrophe))) { Contexts.back().VerilogMayBeConcatenation = true; } + if (Style.isTableGen()) + Contexts.back().ColonIsDictLiteral = false; unsigned CommaCount = 0; while (CurrentToken) { @@ -906,8 +1211,8 @@ private: FormatToken *Previous = CurrentToken->getPreviousNonComment(); if (Previous->is(TT_JsTypeOptionalQuestion)) Previous = Previous->getPreviousNonComment(); - if ((CurrentToken->is(tok::colon) && - (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) || + if ((CurrentToken->is(tok::colon) && !Style.isTableGen() && + (!Contexts.back().ColonIsDictLiteral || !IsCpp)) || Style.isProto()) { OpeningBrace.setType(TT_DictLiteral); if (Previous->Tok.getIdentifierInfo() || @@ -915,10 +1220,12 @@ private: Previous->setType(TT_SelectorName); } } - if (CurrentToken->is(tok::colon) && OpeningBrace.is(TT_Unknown)) + if (CurrentToken->is(tok::colon) && OpeningBrace.is(TT_Unknown) && + !Style.isTableGen()) { OpeningBrace.setType(TT_DictLiteral); - else if (Style.isJavaScript()) + } else if (Style.isJavaScript()) { OpeningBrace.overwriteFixedType(TT_DictLiteral); + } } if (CurrentToken->is(tok::comma)) { if (Style.isJavaScript()) @@ -961,20 +1268,26 @@ private: } bool parseTemplateDeclaration() { - if (CurrentToken && CurrentToken->is(tok::less)) { - CurrentToken->setType(TT_TemplateOpener); - next(); - if (!parseAngle()) - return false; - if (CurrentToken) - CurrentToken->Previous->ClosesTemplateDeclaration = true; - return true; - } - return false; + if (!CurrentToken || CurrentToken->isNot(tok::less)) + return false; + + CurrentToken->setType(TT_TemplateOpener); + next(); + + TemplateDeclarationDepth++; + const bool WellFormed = parseAngle(); + TemplateDeclarationDepth--; + if (!WellFormed) + return false; + + if (CurrentToken && TemplateDeclarationDepth == 0) + CurrentToken->Previous->ClosesTemplateDeclaration = true; + + return true; } bool consumeToken() { - if (Style.isCpp()) { + if (IsCpp) { const auto *Prev = CurrentToken->getPreviousNonComment(); if (Prev && Prev->is(tok::r_square) && Prev->is(TT_AttributeSquare) && CurrentToken->isOneOf(tok::kw_if, tok::kw_switch, tok::kw_case, @@ -989,6 +1302,9 @@ private: // operators. if (Tok->is(TT_VerilogTableItem)) return true; + // Multi-line string itself is a single annotated token. + if (Tok->is(TT_TableGenMultiLineString)) + return true; switch (Tok->Tok.getKind()) { case tok::plus: case tok::minus: @@ -1050,6 +1366,8 @@ private: Line.First->startsSequence(tok::kw_export, Keywords.kw_module) || Line.First->startsSequence(tok::kw_export, Keywords.kw_import)) { Tok->setType(TT_ModulePartitionColon); + } else if (Line.First->is(tok::kw_asm)) { + Tok->setType(TT_InlineASMColon); } else if (Contexts.back().ColonIsDictLiteral || Style.isProto()) { Tok->setType(TT_DictLiteral); if (Style.Language == FormatStyle::LK_TextProto) { @@ -1109,6 +1427,8 @@ private: Tok->setType(TT_CtorInitializerColon); } else { Tok->setType(TT_InheritanceColon); + if (Prev->isAccessSpecifierKeyword()) + Line.Type = LT_AccessModifier; } } else if (canBeObjCSelectorComponent(*Tok->Previous) && Tok->Next && (Tok->Next->isOneOf(tok::r_paren, tok::comma) || @@ -1117,9 +1437,6 @@ private: // This handles a special macro in ObjC code where selectors including // the colon are passed as macro arguments. Tok->setType(TT_ObjCMethodExpr); - } else if (Contexts.back().ContextKind == tok::l_paren && - !Line.InPragmaDirective) { - Tok->setType(TT_InlineASMColon); } break; case tok::pipe: @@ -1130,6 +1447,14 @@ private: Tok->setType(TT_JsTypeOperator); break; case tok::kw_if: + if (Style.isTableGen()) { + // In TableGen it has the form 'if' <value> 'then'. + if (!parseTableGenValue()) + return false; + if (CurrentToken && CurrentToken->is(Keywords.kw_then)) + next(); // skip then + break; + } if (CurrentToken && CurrentToken->isOneOf(tok::kw_constexpr, tok::identifier)) { next(); @@ -1153,7 +1478,7 @@ private: if (CurrentToken && CurrentToken->is(Keywords.kw_await)) next(); } - if (Style.isCpp() && CurrentToken && CurrentToken->is(tok::kw_co_await)) + if (IsCpp && CurrentToken && CurrentToken->is(tok::kw_co_await)) next(); Contexts.back().ColonIsForRangeExpr = true; if (!CurrentToken || CurrentToken->isNot(tok::l_paren)) @@ -1225,23 +1550,27 @@ private: return false; if (Line.MustBeDeclaration && Contexts.size() == 1 && !Contexts.back().IsExpression && !Line.startsWith(TT_ObjCProperty) && + !Line.startsWith(tok::l_paren) && !Tok->isOneOf(TT_TypeDeclarationParen, TT_RequiresExpressionLParen)) { if (const auto *Previous = Tok->Previous; !Previous || (!Previous->isAttribute() && !Previous->isOneOf(TT_RequiresClause, TT_LeadingJavaAnnotation))) { Line.MightBeFunctionDecl = true; + Tok->MightBeFunctionDeclParen = true; } } break; case tok::l_square: + if (Style.isTableGen()) + Tok->setType(TT_TableGenListOpener); if (!parseSquare()) return false; break; case tok::l_brace: if (Style.Language == FormatStyle::LK_TextProto) { FormatToken *Previous = Tok->getPreviousNonComment(); - if (Previous && Previous->getType() != TT_DictLiteral) + if (Previous && Previous->isNot(TT_DictLiteral)) Previous->setType(TT_SelectorName); } Scopes.push_back(getScopeType(*Tok)); @@ -1261,9 +1590,11 @@ private: Tok->Previous->isOneOf(TT_SelectorName, TT_DictLiteral))) { Tok->setType(TT_DictLiteral); FormatToken *Previous = Tok->getPreviousNonComment(); - if (Previous && Previous->getType() != TT_DictLiteral) + if (Previous && Previous->isNot(TT_DictLiteral)) Previous->setType(TT_SelectorName); } + if (Style.isTableGen()) + Tok->setType(TT_TemplateOpener); } else { Tok->setType(TT_BinaryOperator); NonTemplateLess.insert(Tok); @@ -1423,11 +1754,28 @@ private: if (!Tok->getPreviousNonComment()) Line.IsContinuation = true; } + if (Style.isTableGen()) { + if (Tok->is(Keywords.kw_assert)) { + if (!parseTableGenValue()) + return false; + } else if (Tok->isOneOf(Keywords.kw_def, Keywords.kw_defm) && + (!Tok->Next || + !Tok->Next->isOneOf(tok::colon, tok::l_brace))) { + // The case NameValue appears. + if (!parseTableGenValue(true)) + return false; + } + } break; case tok::arrow: if (Tok->Previous && Tok->Previous->is(tok::kw_noexcept)) Tok->setType(TT_TrailingReturnArrow); break; + case tok::equal: + // In TableGen, there must be a value after "="; + if (Style.isTableGen() && !parseTableGenValue()) + return false; + break; default: break; } @@ -1564,6 +1912,8 @@ private: case tok::pp_elif: Contexts.back().IsExpression = true; next(); + if (CurrentToken) + CurrentToken->SpacesRequiredBefore = true; parseLine(); break; default: @@ -1658,6 +2008,8 @@ public: if (!consumeToken()) return LT_Invalid; } + if (Line.Type == LT_AccessModifier) + return LT_AccessModifier; if (KeywordVirtualFound) return LT_VirtualFunctionDecl; if (ImportStatement) @@ -1757,6 +2109,9 @@ private: // Whether the braces may mean concatenation instead of structure or array // literal. bool VerilogMayBeConcatenation = false; + bool IsTableGenDAGArg = false; + bool IsTableGenBangOpe = false; + bool IsTableGenCondOpe = false; enum { Unknown, // Like the part after `:` in a constructor. @@ -1986,7 +2341,7 @@ private: if (Current.Previous) { bool IsIdentifier = Style.isJavaScript() - ? Keywords.IsJavaScriptIdentifier( + ? Keywords.isJavaScriptIdentifier( *Current.Previous, /* AcceptIdentifierName= */ true) : Current.Previous->is(tok::identifier); if (IsIdentifier || @@ -2009,7 +2364,8 @@ private: // Line.MightBeFunctionDecl can only be true after the parentheses of a // function declaration have been found. In this case, 'Current' is a // trailing token of this declaration and thus cannot be a name. - if (Current.is(Keywords.kw_instanceof)) { + if ((Style.isJavaScript() || Style.Language == FormatStyle::LK_Java) && + Current.is(Keywords.kw_instanceof)) { Current.setType(TT_BinaryOperator); } else if (isStartOfName(Current) && (!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) { @@ -2061,6 +2417,9 @@ private: // In JavaScript, `interface X { foo?(): bar; }` is an optional method // on the interface, not a ternary expression. Current.setType(TT_JsTypeOptionalQuestion); + } else if (Style.isTableGen()) { + // In TableGen, '?' is just an identifier like token. + Current.setType(TT_Unknown); } else { Current.setType(TT_ConditionalExpr); } @@ -2108,9 +2467,9 @@ private: Current.setType(TT_CastRParen); if (Current.MatchingParen && Current.Next && !Current.Next->isBinaryOperator() && - !Current.Next->isOneOf(tok::semi, tok::colon, tok::l_brace, - tok::comma, tok::period, tok::arrow, - tok::coloncolon, tok::kw_noexcept)) { + !Current.Next->isOneOf( + tok::semi, tok::colon, tok::l_brace, tok::l_paren, tok::comma, + tok::period, tok::arrow, tok::coloncolon, tok::kw_noexcept)) { if (FormatToken *AfterParen = Current.MatchingParen->Next; AfterParen && AfterParen->isNot(tok::caret)) { // Make sure this isn't the return type of an Obj-C block declaration. @@ -2239,6 +2598,9 @@ private: // keywords such as let and def* defines names. if (Keywords.isTableGenDefinition(*PreviousNotConst)) return true; + // Otherwise C++ style declarations is available only inside the brace. + if (Contexts.back().ContextKind != tok::l_brace) + return false; } bool IsPPKeyword = PreviousNotConst->is(tok::identifier) && @@ -2263,15 +2625,17 @@ private: return false; // int a or auto a. - if (PreviousNotConst->isOneOf(tok::identifier, tok::kw_auto)) + if (PreviousNotConst->isOneOf(tok::identifier, tok::kw_auto) && + PreviousNotConst->isNot(TT_StatementAttributeLikeMacro)) { return true; + } // *a or &a or &&a. if (PreviousNotConst->is(TT_PointerOrReference)) return true; // MyClass a; - if (PreviousNotConst->isSimpleTypeSpecifier()) + if (PreviousNotConst->isTypeName(LangOpts)) return true; // type[] a in Java @@ -2287,7 +2651,7 @@ private: /// Determine whether '(' is starting a C++ cast. bool lParenStartsCppCast(const FormatToken &Tok) { // C-style casts are only used in C++. - if (!Style.isCpp()) + if (!IsCpp) return false; FormatToken *LeftOfParens = Tok.getPreviousNonComment(); @@ -2307,20 +2671,27 @@ private: /// Determine whether ')' is ending a cast. bool rParenEndsCast(const FormatToken &Tok) { + assert(Tok.is(tok::r_paren)); + + if (!Tok.MatchingParen || !Tok.Previous) + return false; + // C-style casts are only used in C++, C# and Java. - if (!Style.isCSharp() && !Style.isCpp() && - Style.Language != FormatStyle::LK_Java) { + if (!IsCpp && !Style.isCSharp() && Style.Language != FormatStyle::LK_Java) return false; - } + + const auto *LParen = Tok.MatchingParen; + const auto *BeforeRParen = Tok.Previous; + const auto *AfterRParen = Tok.Next; // Empty parens aren't casts and there are no casts at the end of the line. - if (Tok.Previous == Tok.MatchingParen || !Tok.Next || !Tok.MatchingParen) + if (BeforeRParen == LParen || !AfterRParen) return false; - if (Tok.MatchingParen->is(TT_OverloadedOperatorLParen)) + if (LParen->is(TT_OverloadedOperatorLParen)) return false; - FormatToken *LeftOfParens = Tok.MatchingParen->getPreviousNonComment(); + auto *LeftOfParens = LParen->getPreviousNonComment(); if (LeftOfParens) { // If there is a closing parenthesis left of the current // parentheses, look past it as these might be chained casts. @@ -2376,37 +2747,41 @@ private: } } - if (Tok.Next->isOneOf(tok::question, tok::ampamp)) + if (AfterRParen->is(tok::question) || + (AfterRParen->is(tok::ampamp) && !BeforeRParen->isTypeName(LangOpts))) { return false; + } // `foreach((A a, B b) in someList)` should not be seen as a cast. - if (Tok.Next->is(Keywords.kw_in) && Style.isCSharp()) + if (AfterRParen->is(Keywords.kw_in) && Style.isCSharp()) return false; // 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_requires, tok::kw_throw, tok::arrow, - Keywords.kw_override, Keywords.kw_final) || - isCppAttribute(Style.isCpp(), *Tok.Next)) { + if (AfterRParen->isOneOf(tok::kw_noexcept, tok::kw_volatile, tok::kw_const, + tok::kw_requires, tok::kw_throw, tok::arrow, + Keywords.kw_override, Keywords.kw_final) || + isCppAttribute(IsCpp, *AfterRParen)) { return false; } // As Java has no function types, a "(" after the ")" likely means that this // is a cast. - if (Style.Language == FormatStyle::LK_Java && Tok.Next->is(tok::l_paren)) + if (Style.Language == FormatStyle::LK_Java && AfterRParen->is(tok::l_paren)) return true; // If a (non-string) literal follows, this is likely a cast. - if (Tok.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof) || - (Tok.Next->Tok.isLiteral() && Tok.Next->isNot(tok::string_literal))) { + if (AfterRParen->isOneOf(tok::kw_sizeof, tok::kw_alignof) || + (AfterRParen->Tok.isLiteral() && + AfterRParen->isNot(tok::string_literal))) { return true; } // Heuristically try to determine whether the parentheses contain a type. - auto IsQualifiedPointerOrReference = [](FormatToken *T) { + auto IsQualifiedPointerOrReference = [](const FormatToken *T, + const LangOptions &LangOpts) { // This is used to handle cases such as x = (foo *const)&y; - assert(!T->isSimpleTypeSpecifier() && "Should have already been checked"); + assert(!T->isTypeName(LangOpts) && "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) { @@ -2436,12 +2811,11 @@ private: return T && T->is(TT_PointerOrReference); }; bool ParensAreType = - !Tok.Previous || - Tok.Previous->isOneOf(TT_TemplateCloser, TT_TypeDeclarationParen) || - Tok.Previous->isSimpleTypeSpecifier() || - IsQualifiedPointerOrReference(Tok.Previous); + BeforeRParen->isOneOf(TT_TemplateCloser, TT_TypeDeclarationParen) || + BeforeRParen->isTypeName(LangOpts) || + IsQualifiedPointerOrReference(BeforeRParen, LangOpts); bool ParensCouldEndDecl = - Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace, tok::greater); + AfterRParen->isOneOf(tok::equal, tok::semi, tok::l_brace, tok::greater); if (ParensAreType && !ParensCouldEndDecl) return true; @@ -2453,49 +2827,54 @@ private: // Certain token types inside the parentheses mean that this can't be a // cast. - for (const FormatToken *Token = Tok.MatchingParen->Next; Token != &Tok; - Token = Token->Next) { + for (const auto *Token = LParen->Next; Token != &Tok; Token = Token->Next) if (Token->is(TT_BinaryOperator)) return false; - } // If the following token is an identifier or 'this', this is a cast. All // cases where this can be something else are handled above. - if (Tok.Next->isOneOf(tok::identifier, tok::kw_this)) + if (AfterRParen->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)) { + if (AfterRParen->is(tok::l_paren) && BeforeRParen->Previous) { + if (BeforeRParen->is(tok::identifier) && + BeforeRParen->Previous->is(tok::l_paren)) { return true; } } - if (!Tok.Next->Next) + if (!AfterRParen->Next) return false; + if (AfterRParen->is(tok::l_brace) && + AfterRParen->getBlockKind() == BK_BracedInit) { + return true; + } + // If the next token after the parenthesis is a unary operator, assume // that this is cast, unless there are unexpected tokens inside the // parenthesis. - const bool NextIsAmpOrStar = Tok.Next->isOneOf(tok::amp, tok::star); - if (!(Tok.Next->isUnaryOperator() || NextIsAmpOrStar) || - Tok.Next->is(tok::plus) || - !Tok.Next->Next->isOneOf(tok::identifier, tok::numeric_constant)) { + const bool NextIsAmpOrStar = AfterRParen->isOneOf(tok::amp, tok::star); + if (!(AfterRParen->isUnaryOperator() || NextIsAmpOrStar) || + AfterRParen->is(tok::plus) || + !AfterRParen->Next->isOneOf(tok::identifier, tok::numeric_constant)) { return false; } + if (NextIsAmpOrStar && - (Tok.Next->Next->is(tok::numeric_constant) || Line.InPPDirective)) { + (AfterRParen->Next->is(tok::numeric_constant) || Line.InPPDirective)) { return false; } - if (Line.InPPDirective && Tok.Next->is(tok::minus)) + + if (Line.InPPDirective && AfterRParen->is(tok::minus)) return false; + // Search for unexpected tokens. - for (FormatToken *Prev = Tok.Previous; Prev != Tok.MatchingParen; - Prev = Prev->Previous) { + for (auto *Prev = BeforeRParen; Prev != LParen; Prev = Prev->Previous) if (!Prev->isOneOf(tok::kw_const, tok::identifier, tok::coloncolon)) return false; - } + return true; } @@ -2562,6 +2941,8 @@ private: return TT_UnaryOperator; if (PrevToken->is(TT_TypeName)) return TT_PointerOrReference; + if (PrevToken->isOneOf(tok::kw_new, tok::kw_delete) && Tok.is(tok::ampamp)) + return TT_BinaryOperator; const FormatToken *NextToken = Tok.getNextNonComment(); @@ -2709,6 +3090,8 @@ private: AnnotatedLine &Line; FormatToken *CurrentToken; bool AutoFound; + bool IsCpp; + LangOptions LangOpts; const AdditionalKeywords &Keywords; SmallVector<ScopeType> &Scopes; @@ -2718,6 +3101,8 @@ private: // same decision irrespective of the decisions for tokens leading up to it. // Store this information to prevent this from causing exponential runtime. llvm::SmallPtrSet<FormatToken *, 16> NonTemplateLess; + + int TemplateDeclarationDepth; }; static const int PrecedenceUnaryOperator = prec::PointerToMember + 1; @@ -3055,7 +3440,8 @@ private: } else { break; } - } else if (Tok->is(tok::hash)) { + } else if (Tok->is(Keywords.kw_verilogHash)) { + // Delay control. if (Next->is(tok::l_paren)) Next = Next->MatchingParen; if (Next) @@ -3164,7 +3550,8 @@ static unsigned maxNestingDepth(const AnnotatedLine &Line) { // Returns the name of a function with no return type, e.g. a constructor or // destructor. -static FormatToken *getFunctionName(const AnnotatedLine &Line) { +static FormatToken *getFunctionName(const AnnotatedLine &Line, + FormatToken *&OpeningParen) { for (FormatToken *Tok = Line.getFirstNonComment(), *Name = nullptr; Tok; Tok = Tok->getNextNonComment()) { // Skip C++11 attributes both before and after the function name. @@ -3177,10 +3564,12 @@ static FormatToken *getFunctionName(const AnnotatedLine &Line) { // Make sure the name is followed by a pair of parentheses. if (Name) { - return Tok->is(tok::l_paren) && Tok->isNot(TT_FunctionTypeLParen) && - Tok->MatchingParen - ? Name - : nullptr; + if (Tok->is(tok::l_paren) && Tok->isNot(TT_FunctionTypeLParen) && + Tok->MatchingParen) { + OpeningParen = Tok; + return Name; + } + return nullptr; } // Skip keywords that may precede the constructor/destructor name. @@ -3256,11 +3645,14 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) { ExpressionParser ExprParser(Style, Keywords, Line); ExprParser.parse(); - if (Style.isCpp()) { - auto *Tok = getFunctionName(Line); + if (IsCpp) { + FormatToken *OpeningParen = nullptr; + auto *Tok = getFunctionName(Line, OpeningParen); if (Tok && ((!Scopes.empty() && Scopes.back() == ST_Class) || Line.endsWith(TT_FunctionLBrace) || isCtorOrDtorName(Tok))) { Tok->setFinalizedType(TT_CtorDtorDeclName); + assert(OpeningParen); + OpeningParen->setFinalizedType(TT_FunctionDeclarationLParen); } } @@ -3283,7 +3675,8 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) { // This function heuristically determines whether 'Current' starts the name of a // function declaration. -static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current, +static bool isFunctionDeclarationName(const LangOptions &LangOpts, + const FormatToken &Current, const AnnotatedLine &Line, FormatToken *&ClosingParen) { assert(Current.Previous); @@ -3294,7 +3687,15 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current, if (!Current.Tok.getIdentifierInfo()) return false; - auto skipOperatorName = [](const FormatToken *Next) -> const FormatToken * { + const auto &Previous = *Current.Previous; + + if (const auto *PrevPrev = Previous.Previous; + PrevPrev && PrevPrev->is(TT_ObjCDecl)) { + return false; + } + + auto skipOperatorName = + [&LangOpts](const FormatToken *Next) -> const FormatToken * { for (; Next; Next = Next->Next) { if (Next->is(TT_OverloadedOperatorLParen)) return Next; @@ -3313,7 +3714,7 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current, Next = Next->Next; continue; } - if ((Next->isSimpleTypeSpecifier() || Next->is(tok::identifier)) && + if ((Next->isTypeName(LangOpts) || Next->is(tok::identifier)) && Next->Next && Next->Next->isPointerOrReference()) { // For operator void*(), operator char*(), operator Foo*(). Next = Next->Next; @@ -3329,21 +3730,22 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current, return nullptr; }; + const auto *Next = Current.Next; + const bool IsCpp = LangOpts.CXXOperatorNames; + // Find parentheses of parameter list. - const FormatToken *Next = Current.Next; if (Current.is(tok::kw_operator)) { - const auto *Previous = Current.Previous; - if (Previous->Tok.getIdentifierInfo() && - !Previous->isOneOf(tok::kw_return, tok::kw_co_return)) { + if (Previous.Tok.getIdentifierInfo() && + !Previous.isOneOf(tok::kw_return, tok::kw_co_return)) { return true; } - if (Previous->is(tok::r_paren) && Previous->is(TT_TypeDeclarationParen)) { - assert(Previous->MatchingParen); - assert(Previous->MatchingParen->is(tok::l_paren)); - assert(Previous->MatchingParen->is(TT_TypeDeclarationParen)); + if (Previous.is(tok::r_paren) && Previous.is(TT_TypeDeclarationParen)) { + assert(Previous.MatchingParen); + assert(Previous.MatchingParen->is(tok::l_paren)); + assert(Previous.MatchingParen->is(TT_TypeDeclarationParen)); return true; } - if (!Previous->isPointerOrReference() && Previous->isNot(TT_TemplateCloser)) + if (!Previous.isPointerOrReference() && Previous.isNot(TT_TemplateCloser)) return false; Next = skipOperatorName(Next); } else { @@ -3411,9 +3813,8 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current, Tok = Tok->MatchingParen; continue; } - if (Tok->is(tok::kw_const) || Tok->isSimpleTypeSpecifier() || - Tok->isOneOf(TT_PointerOrReference, TT_StartOfName, tok::ellipsis, - TT_TypeName)) { + if (Tok->is(tok::kw_const) || Tok->isTypeName(LangOpts) || + Tok->isOneOf(TT_PointerOrReference, TT_StartOfName, tok::ellipsis)) { return true; } if (Tok->isOneOf(tok::l_brace, TT_ObjCMethodExpr) || Tok->Tok.isLiteral()) @@ -3425,15 +3826,16 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current, bool TokenAnnotator::mustBreakForReturnType(const AnnotatedLine &Line) const { assert(Line.MightBeFunctionDecl); - if ((Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_TopLevel || - Style.AlwaysBreakAfterReturnType == - FormatStyle::RTBS_TopLevelDefinitions) && + if ((Style.BreakAfterReturnType == FormatStyle::RTBS_TopLevel || + Style.BreakAfterReturnType == FormatStyle::RTBS_TopLevelDefinitions) && Line.Level > 0) { return false; } - switch (Style.AlwaysBreakAfterReturnType) { + switch (Style.BreakAfterReturnType) { case FormatStyle::RTBS_None: + case FormatStyle::RTBS_Automatic: + case FormatStyle::RTBS_ExceptShortType: return false; case FormatStyle::RTBS_All: case FormatStyle::RTBS_TopLevel: @@ -3462,7 +3864,6 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const { if (AlignArrayOfStructures) calculateArrayInitializerColumnList(Line); - const bool IsCpp = Style.isCpp(); bool SeenName = false; bool LineIsFunctionDeclaration = false; FormatToken *ClosingParen = nullptr; @@ -3475,11 +3876,17 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const { AfterLastAttribute = Tok; if (const bool IsCtorOrDtor = Tok->is(TT_CtorDtorDeclName); IsCtorOrDtor || - isFunctionDeclarationName(Style.isCpp(), *Tok, Line, ClosingParen)) { + isFunctionDeclarationName(LangOpts, *Tok, Line, ClosingParen)) { if (!IsCtorOrDtor) Tok->setFinalizedType(TT_FunctionDeclarationName); LineIsFunctionDeclaration = true; SeenName = true; + if (ClosingParen) { + auto *OpeningParen = ClosingParen->MatchingParen; + assert(OpeningParen); + if (OpeningParen->is(TT_Unknown)) + OpeningParen->setType(TT_FunctionDeclarationLParen); + } break; } } @@ -3513,7 +3920,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const { do { Tok = Tok->Next; } while (Tok && Tok->isNot(TT_OverloadedOperatorLParen)); - if (!Tok) + if (!Tok || !Tok->MatchingParen) break; const auto *LeftParen = Tok; for (Tok = Tok->Next; Tok && Tok != LeftParen->MatchingParen; @@ -3968,11 +4375,24 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return Left.is(tok::hash); if (Left.isOneOf(tok::hashhash, tok::hash)) return Right.is(tok::hash); + if (Left.is(BK_Block) && Right.is(tok::r_brace) && + Right.MatchingParen == &Left && Line.Children.empty()) { + return Style.SpaceInEmptyBlock; + } if ((Left.is(tok::l_paren) && Right.is(tok::r_paren)) || (Left.is(tok::l_brace) && Left.isNot(BK_Block) && Right.is(tok::r_brace) && Right.isNot(BK_Block))) { return Style.SpacesInParensOptions.InEmptyParentheses; } + if (Style.SpacesInParens == FormatStyle::SIPO_Custom && + Style.SpacesInParensOptions.ExceptDoubleParentheses && + Left.is(tok::r_paren) && Right.is(tok::r_paren)) { + auto *InnerLParen = Left.MatchingParen; + if (InnerLParen && InnerLParen->Previous == Right.MatchingParen) { + InnerLParen->SpacesRequiredBefore = 0; + return false; + } + } if (Style.SpacesInParensOptions.InConditionalStatements) { const FormatToken *LeftParen = nullptr; if (Left.is(tok::l_paren)) @@ -3998,9 +4418,11 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Left.is(tok::kw_auto) && Right.isOneOf(tok::l_paren, tok::l_brace)) return false; + const auto *BeforeLeft = Left.Previous; + // operator co_await(x) - if (Right.is(tok::l_paren) && Left.is(tok::kw_co_await) && Left.Previous && - Left.Previous->is(tok::kw_operator)) { + if (Right.is(tok::l_paren) && Left.is(tok::kw_co_await) && BeforeLeft && + BeforeLeft->is(tok::kw_operator)) { return false; } // co_await (x), co_yield (x), co_return (x) @@ -4035,8 +4457,10 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, } if (Left.is(tok::colon)) return Left.isNot(TT_ObjCMethodExpr); - if (Left.is(tok::coloncolon)) - return false; + if (Left.is(tok::coloncolon)) { + return Right.is(tok::star) && Right.is(TT_PointerOrReference) && + Style.PointerAlignment != FormatStyle::PAS_Left; + } if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less)) { if (Style.Language == FormatStyle::LK_TextProto || (Style.Language == FormatStyle::LK_Proto && @@ -4051,8 +4475,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return false; } if (Right.is(tok::ellipsis)) { - return Left.Tok.isLiteral() || (Left.is(tok::identifier) && Left.Previous && - Left.Previous->is(tok::kw_case)); + return Left.Tok.isLiteral() || (Left.is(tok::identifier) && BeforeLeft && + BeforeLeft->is(tok::kw_case)); } if (Left.is(tok::l_square) && Right.is(tok::amp)) return Style.SpacesInSquareBrackets; @@ -4077,7 +4501,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Left.Tok.isLiteral()) return true; // for (auto a = 0, b = 0; const auto & c : {1, 2, 3}) - if (Left.isTypeOrIdentifier() && Right.Next && Right.Next->Next && + if (Left.isTypeOrIdentifier(LangOpts) && Right.Next && Right.Next->Next && Right.Next->Next->is(TT_RangeBasedForLoopColon)) { return getTokenPointerOrReferenceAlignment(Right) != FormatStyle::PAS_Left; @@ -4120,7 +4544,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Right.is(tok::l_brace) && Right.is(BK_Block)) return true; // for (auto a = 0, b = 0; const auto& c : {1, 2, 3}) - if (Left.Previous && Left.Previous->isTypeOrIdentifier() && Right.Next && + if (BeforeLeft && BeforeLeft->isTypeOrIdentifier(LangOpts) && Right.Next && Right.Next->is(TT_RangeBasedForLoopColon)) { return getTokenPointerOrReferenceAlignment(Left) != FormatStyle::PAS_Right; @@ -4143,12 +4567,17 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, startsWithInitStatement(Line)))) { return false; } - return Left.Previous && !Left.Previous->isOneOf( - tok::l_paren, tok::coloncolon, tok::l_square); + if (!BeforeLeft) + return false; + if (BeforeLeft->is(tok::coloncolon)) { + return Left.is(tok::star) && + Style.PointerAlignment != FormatStyle::PAS_Right; + } + return !BeforeLeft->isOneOf(tok::l_paren, tok::l_square); } // Ensure right pointer alignment with ellipsis e.g. int *...P - if (Left.is(tok::ellipsis) && Left.Previous && - Left.Previous->isPointerOrReference()) { + if (Left.is(tok::ellipsis) && BeforeLeft && + BeforeLeft->isPointerOrReference()) { return Style.PointerAlignment != FormatStyle::PAS_Right; } @@ -4159,7 +4588,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Right.isPointerOrReference()) { const FormatToken *Previous = &Left; while (Previous && Previous->isNot(tok::kw_operator)) { - if (Previous->is(tok::identifier) || Previous->isSimpleTypeSpecifier()) { + if (Previous->is(tok::identifier) || Previous->isTypeName(LangOpts)) { Previous = Previous->getPreviousNonComment(); continue; } @@ -4295,14 +4724,13 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Right.is(TT_OverloadedOperatorLParen)) return spaceRequiredBeforeParens(Right); // Function declaration or definition - if (Line.MightBeFunctionDecl && (Left.is(TT_FunctionDeclarationName))) { - if (Line.mightBeFunctionDefinition()) { - return Style.SpaceBeforeParensOptions.AfterFunctionDefinitionName || - spaceRequiredBeforeParens(Right); - } else { - return Style.SpaceBeforeParensOptions.AfterFunctionDeclarationName || - spaceRequiredBeforeParens(Right); - } + if (Line.MightBeFunctionDecl && Right.is(TT_FunctionDeclarationLParen)) { + if (spaceRequiredBeforeParens(Right)) + return true; + const auto &Options = Style.SpaceBeforeParensOptions; + return Line.mightBeFunctionDefinition() + ? Options.AfterFunctionDefinitionName + : Options.AfterFunctionDeclarationName; } // Lambda if (Line.Type != LT_PreprocessorDirective && Left.is(tok::r_square) && @@ -4310,13 +4738,13 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return Style.SpaceBeforeParensOptions.AfterFunctionDefinitionName || spaceRequiredBeforeParens(Right); } - if (!Left.Previous || Left.Previous->isNot(tok::period)) { + if (!BeforeLeft || !BeforeLeft->isOneOf(tok::period, tok::arrow)) { if (Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch)) { return Style.SpaceBeforeParensOptions.AfterControlStatements || spaceRequiredBeforeParens(Right); } if (Left.isOneOf(tok::kw_new, tok::kw_delete)) { - return ((!Line.MightBeFunctionDecl || !Left.Previous) && + return ((!Line.MightBeFunctionDecl || !BeforeLeft) && Style.SpaceBeforeParens != FormatStyle::SBPO_Never) || spaceRequiredBeforeParens(Right); } @@ -4348,7 +4776,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (!Style.isVerilog() && (Left.isOneOf(tok::identifier, tok::greater, tok::r_square, tok::r_paren) || - Left.isSimpleTypeSpecifier()) && + Left.isTypeName(LangOpts)) && Right.is(tok::l_brace) && Right.getNextNonComment() && Right.isNot(BK_Block)) { return false; @@ -4384,8 +4812,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, // Objective-C dictionary literal -> no space before closing brace. return false; } - if (Right.getType() == TT_TrailingAnnotation && - Right.isOneOf(tok::amp, tok::ampamp) && + if (Right.is(TT_TrailingAnnotation) && Right.isOneOf(tok::amp, tok::ampamp) && Left.isOneOf(tok::kw_const, tok::kw_volatile) && (!Right.Next || Right.Next->is(tok::semi))) { // Match const and volatile ref-qualifiers without any additional @@ -4406,16 +4833,21 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Left.Finalized) return Right.hasWhitespaceBefore(); + const bool IsVerilog = Style.isVerilog(); + assert(!IsVerilog || !IsCpp); + // Never ever merge two words. - if (Keywords.isWordLike(Right) && Keywords.isWordLike(Left)) + if (Keywords.isWordLike(Right, IsVerilog) && + Keywords.isWordLike(Left, IsVerilog)) { return true; + } // Leave a space between * and /* to avoid C4138 `comment end` found outside // of comment. if (Left.is(tok::star) && Right.is(tok::comment)) return true; - if (Style.isCpp()) { + if (IsCpp) { if (Left.is(TT_OverloadedOperator) && Right.isOneOf(TT_TemplateOpener, TT_TemplateCloser)) { return true; @@ -4460,6 +4892,12 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, Right.is(TT_TemplateOpener)) { return true; } + // C++ Core Guidelines suppression tag, e.g. `[[suppress(type.5)]]`. + if (Left.is(tok::identifier) && Right.is(tok::numeric_constant)) + return Right.TokenText[0] != '.'; + // `Left` is a keyword (including C++ alternative operator) or identifier. + if (Left.Tok.getIdentifierInfo() && Right.Tok.isLiteral()) + return true; } else if (Style.isProto()) { if (Right.is(tok::period) && Left.isOneOf(Keywords.kw_optional, Keywords.kw_required, @@ -4557,11 +4995,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, // 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) && + if ((Left.isAccessSpecifierKeyword() || + Left.isOneOf(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; } @@ -4587,7 +5025,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, } // In tagged template literals ("html`bar baz`"), there is no space between // the tag identifier and the template string. - if (Keywords.IsJavaScriptIdentifier(Left, + if (Keywords.isJavaScriptIdentifier(Left, /* AcceptIdentifierName= */ false) && Right.is(TT_TemplateString)) { return false; @@ -4670,6 +5108,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return true; // "x! as string", "x! in y" } } else if (Style.Language == FormatStyle::LK_Java) { + if (Left.is(TT_CaseLabelArrow) || Right.is(TT_CaseLabelArrow)) + return true; if (Left.is(tok::r_square) && Right.is(tok::l_brace)) return true; // spaces inside square brackets. @@ -4680,19 +5120,16 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return Style.SpaceBeforeParensOptions.AfterControlStatements || spaceRequiredBeforeParens(Right); } - if ((Left.isOneOf(tok::kw_static, tok::kw_public, tok::kw_private, - tok::kw_protected) || - Left.isOneOf(Keywords.kw_final, Keywords.kw_abstract, + if ((Left.isAccessSpecifierKeyword() || + Left.isOneOf(tok::kw_static, Keywords.kw_final, Keywords.kw_abstract, Keywords.kw_native)) && Right.is(TT_TemplateOpener)) { return true; } - } else if (Style.isVerilog()) { + } else if (IsVerilog) { // An escaped identifier ends with whitespace. - if (Style.isVerilog() && Left.is(tok::identifier) && - Left.TokenText[0] == '\\') { + if (Left.is(tok::identifier) && Left.TokenText[0] == '\\') return true; - } // Add space between things in a primitive's state table unless in a // transition like `(0?)`. if ((Left.is(TT_VerilogTableItem) && @@ -4770,7 +5207,45 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, Left.endsSequence(tok::greatergreater, tok::l_brace))) { return false; } + } else if (Style.isTableGen()) { + // Avoid to connect [ and {. [{ is start token of multiline string. + if (Left.is(tok::l_square) && Right.is(tok::l_brace)) + return true; + if (Left.is(tok::r_brace) && Right.is(tok::r_square)) + return true; + // Do not insert around colon in DAGArg and cond operator. + if (Right.isOneOf(TT_TableGenDAGArgListColon, + TT_TableGenDAGArgListColonToAlign) || + Left.isOneOf(TT_TableGenDAGArgListColon, + TT_TableGenDAGArgListColonToAlign)) { + return false; + } + if (Right.is(TT_TableGenCondOperatorColon)) + return false; + if (Left.isOneOf(TT_TableGenDAGArgOperatorID, + TT_TableGenDAGArgOperatorToBreak) && + Right.isNot(TT_TableGenDAGArgCloser)) { + return true; + } + // Do not insert bang operators and consequent openers. + if (Right.isOneOf(tok::l_paren, tok::less) && + Left.isOneOf(TT_TableGenBangOperator, TT_TableGenCondOperator)) { + return false; + } + // Trailing paste requires space before '{' or ':', the case in name values. + // Not before ';', the case in normal values. + if (Left.is(TT_TableGenTrailingPasteOperator) && + Right.isOneOf(tok::l_brace, tok::colon)) { + return true; + } + // Otherwise paste operator does not prefer space around. + if (Left.is(tok::hash) || Right.is(tok::hash)) + return false; + // Sure not to connect after defining keywords. + if (Keywords.isTableGenDefinition(Left)) + return true; } + if (Left.is(TT_ImplicitStringLiteral)) return Right.hasWhitespaceBefore(); if (Line.Type == LT_ObjCMethodDecl) { @@ -4850,21 +5325,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return true; } if (Left.is(TT_UnaryOperator)) { - if (Right.isNot(tok::l_paren)) { - // The alternative operators for ~ and ! are "compl" and "not". - // If they are used instead, we do not want to combine them with - // the token to the right, unless that is a left paren. - if (Left.is(tok::exclaim) && Left.TokenText == "not") - return true; - if (Left.is(tok::tilde) && Left.TokenText == "compl") - return true; - // Lambda captures allow for a lone &, so "&]" needs to be properly - // handled. - if (Left.is(tok::amp) && Right.is(tok::r_square)) - return Style.SpacesInSquareBrackets; - } - return (Style.SpaceAfterLogicalNot && Left.is(tok::exclaim)) || - Right.is(TT_BinaryOperator); + // Lambda captures allow for a lone &, so "&]" needs to be properly + // handled. + if (Left.is(tok::amp) && Right.is(tok::r_square)) + return Style.SpacesInSquareBrackets; + return Style.SpaceAfterLogicalNot && Left.is(tok::exclaim); } // If the next token is a binary operator or a selector name, we have @@ -4983,6 +5448,15 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, if (Right.NewlinesBefore > 1 && Style.MaxEmptyLinesToKeep > 0) return true; + if (Style.BreakFunctionDefinitionParameters && Line.MightBeFunctionDecl && + Line.mightBeFunctionDefinition() && Left.MightBeFunctionDeclParen && + Left.ParameterCount > 0) { + return true; + } + + const auto *BeforeLeft = Left.Previous; + const auto *AfterRight = Right.Next; + if (Style.isCSharp()) { if (Left.is(TT_FatArrow) && Right.is(tok::l_brace) && Style.BraceWrapping.AfterFunction) { @@ -4994,7 +5468,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, } if (Right.is(TT_CSharpGenericTypeConstraint)) return true; - if (Right.Next && Right.Next->is(TT_FatArrow) && + if (AfterRight && AfterRight->is(TT_FatArrow) && (Right.is(tok::numeric_constant) || (Right.is(tok::identifier) && Right.TokenText == "_"))) { return true; @@ -5011,15 +5485,14 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, Left.is(tok::r_square) && Right.is(tok::l_square)) { return true; } - } else if (Style.isJavaScript()) { // FIXME: This might apply to other languages and token kinds. - if (Right.is(tok::string_literal) && Left.is(tok::plus) && Left.Previous && - Left.Previous->is(tok::string_literal)) { + if (Right.is(tok::string_literal) && Left.is(tok::plus) && BeforeLeft && + BeforeLeft->is(tok::string_literal)) { return true; } if (Left.is(TT_DictLiteral) && Left.is(tok::l_brace) && Line.Level == 0 && - Left.Previous && Left.Previous->is(tok::equal) && + BeforeLeft && BeforeLeft->is(tok::equal) && Line.First->isOneOf(tok::identifier, Keywords.kw_import, tok::kw_export, tok::kw_const) && // kw_var/kw_let are pseudo-tokens that are tok::identifier, so match @@ -5038,8 +5511,8 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, // instead of bin-packing. return true; } - if (Right.is(tok::r_brace) && Left.is(tok::l_brace) && Left.Previous && - Left.Previous->is(TT_FatArrow)) { + if (Right.is(tok::r_brace) && Left.is(tok::l_brace) && BeforeLeft && + BeforeLeft->is(TT_FatArrow)) { // JS arrow function (=> {...}). switch (Style.AllowShortLambdasOnASingleLine) { case FormatStyle::SLS_All: @@ -5067,8 +5540,8 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, FormatStyle::SFS_InlineOnly); } } else if (Style.Language == FormatStyle::LK_Java) { - if (Right.is(tok::plus) && Left.is(tok::string_literal) && Right.Next && - Right.Next->is(tok::string_literal)) { + if (Right.is(tok::plus) && Left.is(tok::string_literal) && AfterRight && + AfterRight->is(tok::string_literal)) { return true; } } else if (Style.isVerilog()) { @@ -5092,7 +5565,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, if (!Keywords.isVerilogBegin(Right) && Keywords.isVerilogEndOfLabel(Left)) return true; } else if (Style.BreakAdjacentStringLiterals && - (Style.isCpp() || Style.isProto() || + (IsCpp || Style.isProto() || Style.Language == FormatStyle::LK_TableGen)) { if (Left.isStringLiteral() && Right.isStringLiteral()) return true; @@ -5121,6 +5594,24 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, } return Style.BreakArrays; } + } else if (Style.isTableGen()) { + // Break the comma in side cond operators. + // !cond(case1:1, + // case2:0); + if (Left.is(TT_TableGenCondOperatorComma)) + return true; + if (Left.is(TT_TableGenDAGArgOperatorToBreak) && + Right.isNot(TT_TableGenDAGArgCloser)) { + return true; + } + if (Left.is(TT_TableGenDAGArgListCommaToBreak)) + return true; + if (Right.is(TT_TableGenDAGArgCloser) && Right.MatchingParen && + Right.MatchingParen->is(TT_TableGenDAGArgOpenerToBreak) && + &Left != Right.MatchingParen->Next) { + // Check to avoid empty DAGArg such as (ins). + return Style.TableGenBreakInsideDAGArg == FormatStyle::DAS_BreakAll; + } } if (Line.startsWith(tok::kw_asm) && Right.is(TT_InlineASMColon) && @@ -5159,10 +5650,13 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, return true; if (Left.IsUnterminatedLiteral) return true; - if (Right.is(tok::lessless) && Right.Next && Left.is(tok::string_literal) && - Right.Next->is(tok::string_literal)) { - return true; + + if (BeforeLeft && BeforeLeft->is(tok::lessless) && + Left.is(tok::string_literal) && Right.is(tok::lessless) && AfterRight && + AfterRight->is(tok::string_literal)) { + return Right.NewlinesBefore > 0; } + if (Right.is(TT_RequiresClause)) { switch (Style.RequiresClausePosition) { case FormatStyle::RCPS_OwnLine: @@ -5180,7 +5674,9 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, // concept ... if (Right.is(tok::kw_concept)) return Style.BreakBeforeConceptDeclarations == FormatStyle::BBCDS_Always; - return Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes; + return Style.BreakTemplateDeclarations == FormatStyle::BTDS_Yes || + (Style.BreakTemplateDeclarations == FormatStyle::BTDS_Leave && + Right.NewlinesBefore > 0); } if (Left.ClosesRequiresClause && Right.isNot(tok::semi)) { switch (Style.RequiresClausePosition) { @@ -5235,8 +5731,8 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, // string literal accordingly. Thus, we try keep existing line breaks. return Right.IsMultiline && Right.NewlinesBefore > 0; } - if ((Left.is(tok::l_brace) || (Left.is(tok::less) && Left.Previous && - Left.Previous->is(tok::equal))) && + if ((Left.is(tok::l_brace) || + (Left.is(tok::less) && BeforeLeft && BeforeLeft->is(tok::equal))) && Right.NestingLevel == 1 && Style.Language == FormatStyle::LK_Proto) { // Don't put enums or option definitions onto single lines in protocol // buffers. @@ -5248,9 +5744,8 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, if (isAllmanBrace(Left) || isAllmanBrace(Right)) { auto *FirstNonComment = Line.getFirstNonComment(); bool AccessSpecifier = - FirstNonComment && - FirstNonComment->isOneOf(Keywords.kw_internal, tok::kw_public, - tok::kw_private, tok::kw_protected); + FirstNonComment && (FirstNonComment->is(Keywords.kw_internal) || + FirstNonComment->isAccessSpecifierKeyword()); if (Style.BraceWrapping.AfterEnum) { if (Line.startsWith(tok::kw_enum) || @@ -5350,7 +5845,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, // // We ensure elsewhere that extensions are always on their own line. if (Style.isProto() && Right.is(TT_SelectorName) && - Right.isNot(tok::r_square) && Right.Next) { + Right.isNot(tok::r_square) && AfterRight) { // Keep `@submessage` together in: // @submessage { key: value } if (Left.is(tok::at)) @@ -5359,7 +5854,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, // selector { ... // selector: { ... // selector: @base { ... - FormatToken *LBrace = Right.Next; + const auto *LBrace = AfterRight; if (LBrace && LBrace->is(tok::colon)) { LBrace = LBrace->Next; if (LBrace && LBrace->is(tok::at)) { @@ -5436,13 +5931,13 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, } else if (Style.isJavaScript()) { const FormatToken *NonComment = Right.getPreviousNonComment(); if (NonComment && - NonComment->isOneOf( - tok::kw_return, Keywords.kw_yield, tok::kw_continue, tok::kw_break, - tok::kw_throw, Keywords.kw_interface, Keywords.kw_type, - tok::kw_static, tok::kw_public, tok::kw_private, tok::kw_protected, - Keywords.kw_readonly, Keywords.kw_override, Keywords.kw_abstract, - Keywords.kw_get, Keywords.kw_set, Keywords.kw_async, - Keywords.kw_await)) { + (NonComment->isAccessSpecifierKeyword() || + NonComment->isOneOf( + tok::kw_return, Keywords.kw_yield, tok::kw_continue, tok::kw_break, + tok::kw_throw, Keywords.kw_interface, Keywords.kw_type, + tok::kw_static, Keywords.kw_readonly, Keywords.kw_override, + Keywords.kw_abstract, Keywords.kw_get, Keywords.kw_set, + Keywords.kw_async, Keywords.kw_await))) { return false; // Otherwise automatic semicolon insertion would trigger. } if (Right.NestingLevel == 0 && @@ -5514,6 +6009,23 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, return false; if (Left.is(TT_TemplateString) && Left.opensScope()) return true; + } else if (Style.isTableGen()) { + // Avoid to break after "def", "class", "let" and so on. + if (Keywords.isTableGenDefinition(Left)) + return false; + // Avoid to break after '(' in the cases that is in bang operators. + if (Right.is(tok::l_paren)) { + return !Left.isOneOf(TT_TableGenBangOperator, TT_TableGenCondOperator, + TT_TemplateCloser); + } + // Avoid to break between the value and its suffix part. + if (Left.is(TT_TableGenValueSuffix)) + return false; + // Avoid to break around paste operator. + if (Left.is(tok::hash) || Right.is(tok::hash)) + return false; + if (Left.isOneOf(TT_TableGenBangOperator, TT_TableGenCondOperator)) + return false; } if (Left.is(tok::at)) @@ -5613,7 +6125,11 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, return Style.BreakBeforeConceptDeclarations != FormatStyle::BBCDS_Never; if (Right.is(TT_RequiresClause)) return true; - if (Left.ClosesTemplateDeclaration || Left.is(TT_FunctionAnnotationRParen)) + if (Left.ClosesTemplateDeclaration) { + return Style.BreakTemplateDeclarations != FormatStyle::BTDS_Leave || + Right.NewlinesBefore > 0; + } + if (Left.is(TT_FunctionAnnotationRParen)) return true; if (Left.ClosesRequiresClause) return true; diff --git a/contrib/llvm-project/clang/lib/Format/TokenAnnotator.h b/contrib/llvm-project/clang/lib/Format/TokenAnnotator.h index 05a6daa87d80..f4f2bba0eb21 100644 --- a/contrib/llvm-project/clang/lib/Format/TokenAnnotator.h +++ b/contrib/llvm-project/clang/lib/Format/TokenAnnotator.h @@ -16,13 +16,14 @@ #define LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H #include "UnwrappedLineParser.h" -#include "clang/Format/Format.h" namespace clang { namespace format { enum LineType { LT_Invalid, + // Contains public/private/protected followed by TT_InheritanceColon. + LT_AccessModifier, LT_ImportStatement, LT_ObjCDecl, // An @interface, @implementation, or @protocol line. LT_ObjCMethodDecl, @@ -46,7 +47,7 @@ enum ScopeType { class AnnotatedLine { public: AnnotatedLine(const UnwrappedLine &Line) - : First(Line.Tokens.front().Tok), Level(Line.Level), + : First(Line.Tokens.front().Tok), Type(LT_Other), Level(Line.Level), PPLevel(Line.PPLevel), MatchingOpeningBlockLineIndex(Line.MatchingOpeningBlockLineIndex), MatchingClosingBlockLineIndex(Line.MatchingClosingBlockLineIndex), @@ -212,7 +213,10 @@ private: class TokenAnnotator { public: TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords) - : Style(Style), Keywords(Keywords) {} + : Style(Style), IsCpp(Style.isCpp()), + LangOpts(getFormattingLangOpts(Style)), Keywords(Keywords) { + assert(IsCpp == LangOpts.CXXOperatorNames); + } /// Adapts the indent levels of comment lines to the indent of the /// subsequent line. @@ -260,6 +264,9 @@ private: const FormatStyle &Style; + bool IsCpp; + LangOptions LangOpts; + const AdditionalKeywords &Keywords; SmallVector<ScopeType> Scopes; diff --git a/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.cpp b/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.cpp index adeb07243487..1804c1437fd4 100644 --- a/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -57,7 +57,7 @@ public: /// Update the indent state given that \p Line is going to be formatted /// next. void nextLine(const AnnotatedLine &Line) { - Offset = getIndentOffset(*Line.First); + Offset = getIndentOffset(Line); // Update the indent level cache size so that we can rely on it // having the right size in adjustToUnmodifiedline. if (Line.Level >= IndentForLevel.size()) @@ -111,42 +111,41 @@ private: /// /// For example, 'public:' labels in classes are offset by 1 or 2 /// characters to the left from their level. - int getIndentOffset(const FormatToken &RootToken) { + int getIndentOffset(const AnnotatedLine &Line) { if (Style.Language == FormatStyle::LK_Java || Style.isJavaScript() || Style.isCSharp()) { return 0; } - auto IsAccessModifier = [this, &RootToken]() { - if (RootToken.isAccessSpecifier(Style.isCpp())) { + auto IsAccessModifier = [&](const FormatToken &RootToken) { + if (Line.Type == LT_AccessModifier || RootToken.isObjCAccessSpecifier()) return true; - } else if (RootToken.isObjCAccessSpecifier()) { - return true; - } + + const auto *Next = RootToken.Next; + // Handle Qt signals. - else if (RootToken.isOneOf(Keywords.kw_signals, Keywords.kw_qsignals) && - RootToken.Next && RootToken.Next->is(tok::colon)) { - return true; - } else if (RootToken.Next && - RootToken.Next->isOneOf(Keywords.kw_slots, - Keywords.kw_qslots) && - RootToken.Next->Next && RootToken.Next->Next->is(tok::colon)) { + if (RootToken.isOneOf(Keywords.kw_signals, Keywords.kw_qsignals) && + Next && Next->is(tok::colon)) { return true; } - // Handle malformed access specifier e.g. 'private' without trailing ':'. - else if (!RootToken.Next && RootToken.isAccessSpecifier(false)) { + + if (Next && Next->isOneOf(Keywords.kw_slots, Keywords.kw_qslots) && + Next->Next && Next->Next->is(tok::colon)) { return true; } - return false; + + // Handle malformed access specifier e.g. 'private' without trailing ':'. + return !Next && RootToken.isAccessSpecifier(false); }; - if (IsAccessModifier()) { + if (IsAccessModifier(*Line.First)) { // The AccessModifierOffset may be overridden by IndentAccessModifiers, // in which case we take a negative value of the IndentWidth to simulate // the upper indent level. return Style.IndentAccessModifiers ? -Style.IndentWidth : Style.AccessModifierOffset; } + return 0; } @@ -515,6 +514,12 @@ private: } } + if (TheLine->First->is(TT_SwitchExpressionLabel)) { + return Style.AllowShortCaseExpressionOnASingleLine + ? tryMergeShortCaseLabels(I, E, Limit) + : 0; + } + if (TheLine->Last->is(tok::l_brace)) { bool ShouldMerge = false; // Try to merge records. @@ -796,8 +801,12 @@ private: } } - if (const auto *LastNonComment = Line.getLastNonComment(); - LastNonComment && LastNonComment->is(tok::l_brace)) { + if (Line.endsWith(tok::l_brace)) { + if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never && + Line.First->is(TT_BlockLBrace)) { + return 0; + } + if (IsSplitBlock && Line.First == Line.Last && I > AnnotatedLines.begin() && (I[-1]->endsWith(tok::kw_else) || IsCtrlStmt(*I[-1]))) { @@ -1221,7 +1230,7 @@ private: // While not empty, take first element and follow edges. while (!Queue.empty()) { // Quit if we still haven't found a solution by now. - if (Count > 25000000) + if (Count > 25'000'000) return 0; Penalty = Queue.top().first.first; @@ -1235,7 +1244,7 @@ private: // Cut off the analysis of certain solutions if the analysis gets too // complex. See description of IgnoreStackForComparison. - if (Count > 50000) + if (Count > 50'000) Node->State.IgnoreStackForComparison = true; if (!Seen.insert(&Node->State).second) { @@ -1469,11 +1478,13 @@ static auto computeNewlines(const AnnotatedLine &Line, Newlines = std::min(Newlines, 1u); if (Newlines == 0 && !RootToken.IsFirst) Newlines = 1; - if (RootToken.IsFirst && !RootToken.HasUnescapedNewline) + if (RootToken.IsFirst && + (!Style.KeepEmptyLines.AtStartOfFile || !RootToken.HasUnescapedNewline)) { Newlines = 0; + } // Remove empty lines after "{". - if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine && + if (!Style.KeepEmptyLines.AtStartOfBlock && PreviousLine && PreviousLine->Last->is(tok::l_brace) && !PreviousLine->startsWithNamespace() && !(PrevPrevLine && PrevPrevLine->startsWithNamespace() && @@ -1545,9 +1556,9 @@ void UnwrappedLineFormatter::formatFirstToken( unsigned NewlineIndent) { FormatToken &RootToken = *Line.First; if (RootToken.is(tok::eof)) { - unsigned Newlines = - std::min(RootToken.NewlinesBefore, - Style.KeepEmptyLinesAtEOF ? Style.MaxEmptyLinesToKeep + 1 : 1); + unsigned Newlines = std::min( + RootToken.NewlinesBefore, + Style.KeepEmptyLines.AtEndOfFile ? Style.MaxEmptyLinesToKeep + 1 : 1); unsigned TokenIndent = Newlines ? NewlineIndent : 0; Whitespaces->replaceWhitespace(RootToken, Newlines, TokenIndent, TokenIndent); diff --git a/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.h b/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.h index ee6d31de8c42..9b8acf427a2a 100644 --- a/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.h +++ b/contrib/llvm-project/clang/lib/Format/UnwrappedLineFormatter.h @@ -16,8 +16,6 @@ #define LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H #include "ContinuationIndenter.h" -#include "clang/Format/Format.h" -#include <map> namespace clang { namespace format { diff --git a/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp b/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp index f70affb732a0..d406a531a5c0 100644 --- a/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp +++ b/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp @@ -47,7 +47,8 @@ void printLine(llvm::raw_ostream &OS, const UnwrappedLine &Line, OS << Prefix; NewLine = false; } - OS << I->Tok->Tok.getName() << "[" << "T=" << (unsigned)I->Tok->getType() + OS << I->Tok->Tok.getName() << "[" + << "T=" << (unsigned)I->Tok->getType() << ", OC=" << I->Tok->OriginalColumn << ", \"" << I->Tok->TokenText << "\"] "; for (SmallVectorImpl<UnwrappedLine>::const_iterator @@ -90,6 +91,12 @@ private: } // end anonymous namespace +std::ostream &operator<<(std::ostream &Stream, const UnwrappedLine &Line) { + llvm::raw_os_ostream OS(Stream); + printLine(OS, Line); + return Stream; +} + class ScopedLineState { public: ScopedLineState(UnwrappedLineParser &Parser, @@ -105,6 +112,7 @@ public: Parser.Line->PPLevel = PreBlockLine->PPLevel; Parser.Line->InPPDirective = PreBlockLine->InPPDirective; Parser.Line->InMacroBody = PreBlockLine->InMacroBody; + Parser.Line->UnbracedBodyLevel = PreBlockLine->UnbracedBodyLevel; } ~ScopedLineState() { @@ -153,14 +161,17 @@ UnwrappedLineParser::UnwrappedLineParser( llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator, IdentifierTable &IdentTable) : Line(new UnwrappedLine), MustBreakBeforeNextToken(false), - CurrentLines(&Lines), Style(Style), Keywords(Keywords), + CurrentLines(&Lines), Style(Style), IsCpp(Style.isCpp()), + LangOpts(getFormattingLangOpts(Style)), Keywords(Keywords), CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr), Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1), IncludeGuard(Style.IndentPPDirectives == FormatStyle::PPDIS_None ? IG_Rejected : IG_Inited), IncludeGuardToken(nullptr), FirstStartColumn(FirstStartColumn), - Macros(Style.Macros, SourceMgr, Style, Allocator, IdentTable) {} + Macros(Style.Macros, SourceMgr, Style, Allocator, IdentTable) { + assert(IsCpp == LangOpts.CXXOperatorNames); +} void UnwrappedLineParser::reset() { PPBranchLevel = -1; @@ -357,13 +368,15 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, do { if (FormatTok->isAttribute()) { nextToken(); + if (FormatTok->is(tok::l_paren)) + parseParens(); continue; } - tok::TokenKind kind = FormatTok->Tok.getKind(); - if (FormatTok->getType() == TT_MacroBlockBegin) - kind = tok::l_brace; - else if (FormatTok->getType() == TT_MacroBlockEnd) - kind = tok::r_brace; + tok::TokenKind Kind = FormatTok->Tok.getKind(); + if (FormatTok->is(TT_MacroBlockBegin)) + Kind = tok::l_brace; + else if (FormatTok->is(TT_MacroBlockEnd)) + Kind = tok::r_brace; auto ParseDefault = [this, OpeningBrace, IfKind, &IfLBrace, &HasDoWhile, &HasLabel, &StatementCount] { @@ -374,7 +387,7 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, assert(StatementCount > 0 && "StatementCount overflow!"); }; - switch (kind) { + switch (Kind) { case tok::comment: nextToken(); addUnwrappedLine(); @@ -389,9 +402,10 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, ParseDefault(); continue; } - if (!InRequiresExpression && FormatTok->isNot(TT_MacroBlockBegin) && - tryToParseBracedList()) { - continue; + if (!InRequiresExpression && FormatTok->isNot(TT_MacroBlockBegin)) { + if (tryToParseBracedList()) + continue; + FormatTok->setFinalizedType(TT_BlockLBrace); } parseBlock(); ++StatementCount; @@ -421,15 +435,11 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, break; case tok::kw_default: { unsigned StoredPosition = Tokens->getPosition(); - FormatToken *Next; - do { - Next = Tokens->getNextToken(); - assert(Next); - } while (Next->is(tok::comment)); + auto *Next = Tokens->getNextNonComment(); FormatTok = Tokens->setPosition(StoredPosition); - if (Next->isNot(tok::colon)) { - // default not followed by ':' is not a case label; treat it like - // an identifier. + if (!Next->isOneOf(tok::colon, tok::arrow)) { + // default not followed by `:` or `->` is not a case label; treat it + // like an identifier. parseStructuralElement(); break; } @@ -448,6 +458,7 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, } if (!SwitchLabelEncountered && (Style.IndentCaseLabels || + (OpeningBrace && OpeningBrace->is(TT_SwitchExpressionLBrace)) || (Line->InPPDirective && Line->Level == 1))) { ++Line->Level; } @@ -491,12 +502,9 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { assert(Tok->is(tok::l_brace)); do { - FormatToken *NextTok; - do { - NextTok = Tokens->getNextToken(); - } while (NextTok->is(tok::comment)); + auto *NextTok = Tokens->getNextNonComment(); - if (!Line->InMacroBody) { + if (!Line->InMacroBody && !Style.isTableGen()) { // Skip PPDirective lines and comments. while (NextTok->is(tok::hash)) { do { @@ -534,11 +542,11 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { case tok::r_brace: if (LBraceStack.empty()) break; - if (LBraceStack.back().Tok->is(BK_Unknown)) { + if (auto *LBrace = LBraceStack.back().Tok; LBrace->is(BK_Unknown)) { bool ProbablyBracedList = false; if (Style.Language == FormatStyle::LK_Proto) { ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square); - } else { + } else if (LBrace->isNot(TT_EnumLBrace)) { // Using OriginalColumn to distinguish between ObjC methods and // binary operators is a bit hacky. bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) && @@ -552,14 +560,14 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { // If we already marked the opening brace as braced list, the closing // must also be part of it. - ProbablyBracedList = LBraceStack.back().Tok->is(TT_BracedListLBrace); + ProbablyBracedList = LBrace->is(TT_BracedListLBrace); ProbablyBracedList = ProbablyBracedList || (Style.isJavaScript() && NextTok->isOneOf(Keywords.kw_of, Keywords.kw_in, Keywords.kw_as)); - ProbablyBracedList = ProbablyBracedList || - (Style.isCpp() && NextTok->is(tok::l_paren)); + ProbablyBracedList = + ProbablyBracedList || (IsCpp && NextTok->is(tok::l_paren)); // If there is a comma, semicolon or right paren after the closing // brace, we assume this is a braced initializer list. @@ -599,7 +607,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { } // Cpp macro definition body that is a nonempty braced list or block: - if (Style.isCpp() && Line->InMacroBody && PrevTok != FormatTok && + if (IsCpp && Line->InMacroBody && PrevTok != FormatTok && !FormatTok->Previous && NextTok->is(tok::eof) && // A statement can end with only `;` (simple statement), a block // closing brace (compound statement), or `:` (label statement). @@ -608,13 +616,9 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { ProbablyBracedList = true; } } - if (ProbablyBracedList) { - Tok->setBlockKind(BK_BracedInit); - LBraceStack.back().Tok->setBlockKind(BK_BracedInit); - } else { - Tok->setBlockKind(BK_Block); - LBraceStack.back().Tok->setBlockKind(BK_Block); - } + const auto BlockKind = ProbablyBracedList ? BK_BracedInit : BK_Block; + Tok->setBlockKind(BlockKind); + LBrace->setBlockKind(BlockKind); } LBraceStack.pop_back(); break; @@ -819,8 +823,11 @@ FormatToken *UnwrappedLineParser::parseBlock(bool MustBeDeclaration, return IfLBrace; } - if (FormatTok->is(tok::r_brace) && Tok->is(TT_NamespaceLBrace)) - FormatTok->setFinalizedType(TT_NamespaceRBrace); + if (FormatTok->is(tok::r_brace)) { + FormatTok->setBlockKind(BK_Block); + if (Tok->is(TT_NamespaceLBrace)) + FormatTok->setFinalizedType(TT_NamespaceRBrace); + } const bool IsFunctionRBrace = FormatTok->is(tok::r_brace) && Tok->is(TT_FunctionLBrace); @@ -1177,20 +1184,14 @@ void UnwrappedLineParser::parsePPDefine() { Line->InMacroBody = true; if (Style.SkipMacroDefinitionBody) { - do { + while (!eof()) { FormatTok->Finalized = true; - nextToken(); - } while (!eof()); + FormatTok = Tokens->getNextToken(); + } addUnwrappedLine(); return; } - if (FormatTok->is(tok::identifier) && - Tokens->peekNextToken()->is(tok::colon)) { - nextToken(); - nextToken(); - } - // Errors during a preprocessor directive can only affect the layout of the // preprocessor directive, and thus we ignore them. An alternative approach // would be to use the same approach we use on the file level (no @@ -1219,7 +1220,6 @@ void UnwrappedLineParser::parsePPUnknown() { static bool tokenCanStartNewLine(const FormatToken &Tok) { // Semicolon can be a null-statement, l_square can be a start of a macro or // a C++11 attribute, but this doesn't seem to be common. - assert(Tok.isNot(TT_AttributeSquare)); return !Tok.isOneOf(tok::semi, tok::l_brace, // Tokens that can only be used as binary operators and a // part of overloaded operator names. @@ -1425,7 +1425,7 @@ void UnwrappedLineParser::parseStructuralElement( return; } - if (Style.isCpp()) { + if (IsCpp) { while (FormatTok->is(tok::l_square) && handleCppAttributes()) { } } else if (Style.isVerilog()) { @@ -1458,6 +1458,15 @@ void UnwrappedLineParser::parseStructuralElement( } // Tokens that only make sense at the beginning of a line. + if (FormatTok->isAccessSpecifierKeyword()) { + if (Style.Language == FormatStyle::LK_Java || Style.isJavaScript() || + Style.isCSharp()) { + nextToken(); + } else { + parseAccessSpecifier(); + } + return; + } switch (FormatTok->Tok.getKind()) { case tok::kw_asm: nextToken(); @@ -1479,16 +1488,6 @@ void UnwrappedLineParser::parseStructuralElement( case tok::kw_namespace: parseNamespace(); return; - case tok::kw_public: - case tok::kw_protected: - case tok::kw_private: - if (Style.Language == FormatStyle::LK_Java || Style.isJavaScript() || - Style.isCSharp()) { - nextToken(); - } else { - parseAccessSpecifier(); - } - return; case tok::kw_if: { if (Style.isJavaScript() && Line->MustBeDeclaration) { // field/method declaration. @@ -1521,9 +1520,9 @@ void UnwrappedLineParser::parseStructuralElement( // 'switch: string' field declaration. break; } - parseSwitch(); + parseSwitch(/*IsExpr=*/false); return; - case tok::kw_default: + case tok::kw_default: { // In Verilog default along with other labels are handled in the next loop. if (Style.isVerilog()) break; @@ -1531,14 +1530,22 @@ void UnwrappedLineParser::parseStructuralElement( // 'default: string' field declaration. break; } + auto *Default = FormatTok; nextToken(); if (FormatTok->is(tok::colon)) { FormatTok->setFinalizedType(TT_CaseLabelColon); parseLabel(); return; } + if (FormatTok->is(tok::arrow)) { + FormatTok->setFinalizedType(TT_CaseLabelArrow); + Default->setFinalizedType(TT_SwitchExpressionLabel); + parseLabel(); + return; + } // e.g. "default void f() {}" in a Java interface. break; + } case tok::kw_case: // Proto: there are no switch/case statements. if (Style.Language == FormatStyle::LK_Proto) { @@ -1599,7 +1606,7 @@ void UnwrappedLineParser::parseStructuralElement( parseJavaScriptEs6ImportExport(); return; } - if (Style.isCpp()) { + if (IsCpp) { nextToken(); if (FormatTok->is(tok::kw_namespace)) { parseNamespace(); @@ -1643,12 +1650,11 @@ void UnwrappedLineParser::parseStructuralElement( addUnwrappedLine(); return; } - if (Style.isCpp() && parseModuleImport()) + if (IsCpp && parseModuleImport()) return; } - if (Style.isCpp() && - FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals, - Keywords.kw_slots, Keywords.kw_qslots)) { + if (IsCpp && FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals, + Keywords.kw_slots, Keywords.kw_qslots)) { nextToken(); if (FormatTok->is(tok::colon)) { nextToken(); @@ -1656,11 +1662,11 @@ void UnwrappedLineParser::parseStructuralElement( return; } } - if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) { + if (IsCpp && FormatTok->is(TT_StatementMacro)) { parseStatementMacro(); return; } - if (Style.isCpp() && FormatTok->is(TT_NamespaceMacro)) { + if (IsCpp && FormatTok->is(TT_NamespaceMacro)) { parseNamespace(); return; } @@ -1671,7 +1677,8 @@ void UnwrappedLineParser::parseStructuralElement( if (!Style.isJavaScript() && !Style.isVerilog() && !Style.isTableGen() && Tokens->peekNextToken()->is(tok::colon) && !Line->MustBeDeclaration) { nextToken(); - Line->Tokens.begin()->Tok->MustBreakBefore = true; + if (!Line->InMacroBody || CurrentLines->size() > 1) + Line->Tokens.begin()->Tok->MustBreakBefore = true; FormatTok->setFinalizedType(TT_GotoLabelColon); parseLabel(!Style.IndentGotoLabels); if (HasLabel) @@ -1684,9 +1691,15 @@ void UnwrappedLineParser::parseStructuralElement( break; } - const bool InRequiresExpression = - OpeningBrace && OpeningBrace->is(TT_RequiresExpressionLBrace); - do { + for (const bool InRequiresExpression = + OpeningBrace && OpeningBrace->is(TT_RequiresExpressionLBrace); + !eof();) { + if (IsCpp && FormatTok->isCppAlternativeOperatorKeyword()) { + if (auto *Next = Tokens->peekNextToken(/*SkipComment=*/true); + Next && Next->isBinaryOperator()) { + FormatTok->Tok.setKind(tok::identifier); + } + } const FormatToken *Previous = FormatTok->Previous; switch (FormatTok->Tok.getKind()) { case tok::at: @@ -1756,7 +1769,7 @@ void UnwrappedLineParser::parseStructuralElement( } break; case tok::kw_requires: { - if (Style.isCpp()) { + if (IsCpp) { bool ParsedClause = parseRequires(); if (ParsedClause) return; @@ -1766,8 +1779,9 @@ void UnwrappedLineParser::parseStructuralElement( break; } case tok::kw_enum: - // Ignore if this is part of "template <enum ...". - if (Previous && Previous->is(tok::less)) { + // Ignore if this is part of "template <enum ..." or "... -> enum" or + // "template <..., enum ...>". + if (Previous && Previous->isOneOf(tok::less, tok::arrow, tok::comma)) { nextToken(); break; } @@ -1777,7 +1791,7 @@ void UnwrappedLineParser::parseStructuralElement( if (!parseEnum()) break; // This only applies to C++ and Verilog. - if (!Style.isCpp() && !Style.isVerilog()) { + if (!IsCpp && !Style.isVerilog()) { addUnwrappedLine(); return; } @@ -1845,7 +1859,7 @@ void UnwrappedLineParser::parseStructuralElement( parseParens(); // Break the unwrapped line if a K&R C function definition has a parameter // declaration. - if (OpeningBrace || !Style.isCpp() || !Previous || eof()) + if (OpeningBrace || !IsCpp || !Previous || eof()) break; if (isC78ParameterDecl(FormatTok, Tokens->peekNextToken(/*SkipComment=*/true), @@ -1863,8 +1877,7 @@ void UnwrappedLineParser::parseStructuralElement( case tok::caret: nextToken(); // Block return type. - if (FormatTok->Tok.isAnyIdentifier() || - FormatTok->isSimpleTypeSpecifier()) { + if (FormatTok->Tok.isAnyIdentifier() || FormatTok->isTypeName(LangOpts)) { nextToken(); // Return types: pointers are ok too. while (FormatTok->is(tok::star)) @@ -1897,7 +1910,8 @@ void UnwrappedLineParser::parseStructuralElement( } else if (Style.BraceWrapping.AfterFunction) { addUnwrappedLine(); } - FormatTok->setFinalizedType(TT_FunctionLBrace); + if (!Previous || Previous->isNot(TT_TypeDeclarationParen)) + FormatTok->setFinalizedType(TT_FunctionLBrace); parseBlock(); IsDecltypeAutoFunction = false; addUnwrappedLine(); @@ -1974,13 +1988,13 @@ void UnwrappedLineParser::parseStructuralElement( } } - if (!Style.isCpp() && FormatTok->is(Keywords.kw_interface)) { + if (!IsCpp && FormatTok->is(Keywords.kw_interface)) { if (parseStructLike()) return; break; } - if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) { + if (IsCpp && FormatTok->is(TT_StatementMacro)) { parseStatementMacro(); return; } @@ -2065,6 +2079,11 @@ void UnwrappedLineParser::parseStructuralElement( case tok::kw_new: parseNew(); break; + case tok::kw_switch: + if (Style.Language == FormatStyle::LK_Java) + parseSwitch(/*IsExpr=*/true); + nextToken(); + break; case tok::kw_case: // Proto: there are no switch/case statements. if (Style.Language == FormatStyle::LK_Proto) { @@ -2112,7 +2131,7 @@ void UnwrappedLineParser::parseStructuralElement( nextToken(); break; } - } while (!eof()); + } } bool UnwrappedLineParser::tryToParsePropertyAccessor() { @@ -2137,8 +2156,8 @@ bool UnwrappedLineParser::tryToParsePropertyAccessor() { bool HasSpecialAccessor = false; bool IsTrivialPropertyAccessor = true; while (!eof()) { - if (Tok->isOneOf(tok::semi, tok::kw_public, tok::kw_private, - tok::kw_protected, Keywords.kw_internal, Keywords.kw_get, + if (Tok->isAccessSpecifierKeyword() || + Tok->isOneOf(tok::semi, Keywords.kw_internal, Keywords.kw_get, Keywords.kw_init, Keywords.kw_set)) { if (Tok->isOneOf(Keywords.kw_get, Keywords.kw_init, Keywords.kw_set)) HasSpecialAccessor = true; @@ -2208,7 +2227,7 @@ bool UnwrappedLineParser::tryToParsePropertyAccessor() { bool UnwrappedLineParser::tryToParseLambda() { assert(FormatTok->is(tok::l_square)); - if (!Style.isCpp()) { + if (!IsCpp) { nextToken(); return false; } @@ -2220,7 +2239,7 @@ bool UnwrappedLineParser::tryToParseLambda() { bool InTemplateParameterList = false; while (FormatTok->isNot(tok::l_brace)) { - if (FormatTok->isSimpleTypeSpecifier()) { + if (FormatTok->isTypeName(LangOpts) || FormatTok->isAttribute()) { nextToken(); continue; } @@ -2241,6 +2260,8 @@ bool UnwrappedLineParser::tryToParseLambda() { break; case tok::kw_auto: case tok::kw_class: + case tok::kw_struct: + case tok::kw_union: case tok::kw_template: case tok::kw_typename: case tok::amp: @@ -2337,7 +2358,7 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() { !Previous->isOneOf(tok::kw_return, tok::kw_co_await, tok::kw_co_yield, tok::kw_co_return)) || Previous->closesScope())) || - LeftSquare->isCppStructuredBinding(Style)) { + LeftSquare->isCppStructuredBinding(IsCpp)) { return false; } if (FormatTok->is(tok::l_square) || tok::isLiteral(FormatTok->Tok.getKind())) @@ -2418,6 +2439,7 @@ bool UnwrappedLineParser::tryToParseChildBlock() { } bool UnwrappedLineParser::parseBracedList(bool IsAngleBracket, bool IsEnum) { + assert(!IsAngleBracket || !IsEnum); bool HasError = false; // FIXME: Once we have an expression parser in the UnwrappedLineParser, @@ -2440,8 +2462,11 @@ bool UnwrappedLineParser::parseBracedList(bool IsAngleBracket, bool IsEnum) { } } if (FormatTok->is(IsAngleBracket ? tok::greater : tok::r_brace)) { - if (IsEnum && !Style.AllowShortEnumsOnASingleLine) - addUnwrappedLine(); + if (IsEnum) { + FormatTok->setBlockKind(BK_Block); + if (!Style.AllowShortEnumsOnASingleLine) + addUnwrappedLine(); + } nextToken(); return !HasError; } @@ -2521,10 +2546,10 @@ bool UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) { if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_brace)) parseChildBlock(); break; - case tok::r_paren: + case tok::r_paren: { + const auto *Prev = LeftParen->Previous; if (!MightBeStmtExpr && !MightBeFoldExpr && !Line->InMacroBody && Style.RemoveParentheses > FormatStyle::RPS_Leave) { - const auto *Prev = LeftParen->Previous; const auto *Next = Tokens->peekNextToken(); const bool DoubleParens = Prev && Prev->is(tok::l_paren) && Next && Next->is(tok::r_paren); @@ -2546,8 +2571,13 @@ bool UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) { FormatTok->Optional = true; } } + if (Prev && Prev->is(TT_TypenameMacro)) { + LeftParen->setFinalizedType(TT_TypeDeclarationParen); + FormatTok->setFinalizedType(TT_TypeDeclarationParen); + } nextToken(); return SeenEqual; + } case tok::r_brace: // A "}" inside parenthesis is an error if there wasn't a matching "{". return SeenEqual; @@ -2588,6 +2618,9 @@ bool UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) { else nextToken(); break; + case tok::kw_switch: + parseSwitch(/*IsExpr=*/true); + break; case tok::kw_requires: { auto RequiresToken = FormatTok; nextToken(); @@ -2683,7 +2716,9 @@ void UnwrappedLineParser::parseUnbracedBody(bool CheckEOF) { addUnwrappedLine(); ++Line->Level; + ++Line->UnbracedBodyLevel; parseStructuralElement(); + --Line->UnbracedBodyLevel; if (Tok) { assert(!Line->InPPDirective); @@ -2926,9 +2961,15 @@ void UnwrappedLineParser::parseTryCatch() { assert(FormatTok->isOneOf(tok::kw_try, tok::kw___try) && "'try' expected"); nextToken(); bool NeedsUnwrappedLine = false; + bool HasCtorInitializer = false; if (FormatTok->is(tok::colon)) { + auto *Colon = FormatTok; // We are in a function try block, what comes is an initializer list. nextToken(); + if (FormatTok->is(tok::identifier)) { + HasCtorInitializer = true; + Colon->setFinalizedType(TT_CtorInitializerColon); + } // In case identifiers were removed by clang-tidy, what might follow is // multiple commas in sequence - before the first identifier. @@ -2937,14 +2978,11 @@ void UnwrappedLineParser::parseTryCatch() { while (FormatTok->is(tok::identifier)) { nextToken(); - if (FormatTok->is(tok::l_paren)) + if (FormatTok->is(tok::l_paren)) { parseParens(); - if (FormatTok->Previous && FormatTok->Previous->is(tok::identifier) && - FormatTok->is(tok::l_brace)) { - do { - nextToken(); - } while (FormatTok->isNot(tok::r_brace)); + } else if (FormatTok->is(tok::l_brace)) { nextToken(); + parseBracedList(); } // In case identifiers were removed by clang-tidy, what might follow is @@ -2960,6 +2998,8 @@ void UnwrappedLineParser::parseTryCatch() { keepAncestorBraces(); if (FormatTok->is(tok::l_brace)) { + if (HasCtorInitializer) + FormatTok->setFinalizedType(TT_FunctionLBrace); CompoundStatementIndenter Indenter(this, Style, Line->Level); parseBlock(); if (Style.BraceWrapping.BeforeCatch) @@ -3155,7 +3195,7 @@ void UnwrappedLineParser::parseForOrWhileLoop(bool HasParens) { // JS' for await ( ... if (Style.isJavaScript() && FormatTok->is(Keywords.kw_await)) nextToken(); - if (Style.isCpp() && FormatTok->is(tok::kw_co_await)) + if (IsCpp && FormatTok->is(tok::kw_co_await)) nextToken(); if (HasParens && FormatTok->is(tok::l_paren)) { // The type is only set for Verilog basically because we were afraid to @@ -3206,10 +3246,11 @@ void UnwrappedLineParser::parseDoWhile() { void UnwrappedLineParser::parseLabel(bool LeftAlignLabel) { nextToken(); unsigned OldLineLevel = Line->Level; - if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0)) - --Line->Level; + if (LeftAlignLabel) Line->Level = 0; + else if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0)) + --Line->Level; if (!Style.IndentCaseBlocks && CommentsBeforeNextToken.empty() && FormatTok->is(tok::l_brace)) { @@ -3244,6 +3285,7 @@ void UnwrappedLineParser::parseLabel(bool LeftAlignLabel) { void UnwrappedLineParser::parseCaseLabel() { assert(FormatTok->is(tok::kw_case) && "'case' expected"); + auto *Case = FormatTok; // FIXME: fix handling of complex expressions here. do { @@ -3252,11 +3294,16 @@ void UnwrappedLineParser::parseCaseLabel() { FormatTok->setFinalizedType(TT_CaseLabelColon); break; } + if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::arrow)) { + FormatTok->setFinalizedType(TT_CaseLabelArrow); + Case->setFinalizedType(TT_SwitchExpressionLabel); + break; + } } while (!eof()); parseLabel(); } -void UnwrappedLineParser::parseSwitch() { +void UnwrappedLineParser::parseSwitch(bool IsExpr) { assert(FormatTok->is(tok::kw_switch) && "'switch' expected"); nextToken(); if (FormatTok->is(tok::l_paren)) @@ -3266,10 +3313,15 @@ void UnwrappedLineParser::parseSwitch() { if (FormatTok->is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - FormatTok->setFinalizedType(TT_ControlStatementLBrace); - parseBlock(); + FormatTok->setFinalizedType(IsExpr ? TT_SwitchExpressionLBrace + : TT_ControlStatementLBrace); + if (IsExpr) + parseChildBlock(); + else + parseBlock(); setPreviousRBraceType(TT_ControlStatementRBrace); - addUnwrappedLine(); + if (!IsExpr) + addUnwrappedLine(); } else { addUnwrappedLine(); ++Line->Level; @@ -3282,8 +3334,8 @@ void UnwrappedLineParser::parseSwitch() { } // Operators that can follow a C variable. -static bool isCOperatorFollowingVar(tok::TokenKind kind) { - switch (kind) { +static bool isCOperatorFollowingVar(tok::TokenKind Kind) { + switch (Kind) { case tok::ampamp: case tok::ampequal: case tok::arrow: @@ -3355,7 +3407,7 @@ void UnwrappedLineParser::parseAccessSpecifier() { /// \brief Parses a requires, decides if it is a clause or an expression. /// \pre The current token has to be the requires keyword. /// \returns true if it parsed a clause. -bool clang::format::UnwrappedLineParser::parseRequires() { +bool UnwrappedLineParser::parseRequires() { assert(FormatTok->is(tok::kw_requires) && "'requires' expected"); auto RequiresToken = FormatTok; @@ -3418,7 +3470,7 @@ bool clang::format::UnwrappedLineParser::parseRequires() { break; } default: - if (PreviousNonComment->isTypeOrIdentifier()) { + if (PreviousNonComment->isTypeOrIdentifier(LangOpts)) { // This is a requires clause. parseRequiresClause(RequiresToken); return true; @@ -3457,11 +3509,6 @@ bool clang::format::UnwrappedLineParser::parseRequires() { return false; } break; - case tok::r_paren: - case tok::pipepipe: - FormatTok = Tokens->setPosition(StoredPosition); - parseRequiresClause(RequiresToken); - return true; case tok::eof: // Break out of the loop. Lookahead = 50; @@ -3469,6 +3516,7 @@ bool clang::format::UnwrappedLineParser::parseRequires() { case tok::coloncolon: LastWasColonColon = true; break; + case tok::kw_decltype: case tok::identifier: if (FoundType && !LastWasColonColon && OpenAngles == 0) { FormatTok = Tokens->setPosition(StoredPosition); @@ -3485,7 +3533,7 @@ bool clang::format::UnwrappedLineParser::parseRequires() { --OpenAngles; break; default: - if (NextToken->isSimpleTypeSpecifier()) { + if (NextToken->isTypeName(LangOpts)) { FormatTok = Tokens->setPosition(StoredPosition); parseRequiresExpression(RequiresToken); return false; @@ -3718,14 +3766,19 @@ bool UnwrappedLineParser::parseEnum() { if (Style.Language == FormatStyle::LK_Proto && FormatTok->is(tok::equal)) return false; - // Eat up enum class ... - if (FormatTok->isOneOf(tok::kw_class, tok::kw_struct)) - nextToken(); + if (IsCpp) { + // Eat up enum class ... + if (FormatTok->isOneOf(tok::kw_class, tok::kw_struct)) + nextToken(); + while (FormatTok->is(tok::l_square)) + if (!handleCppAttributes()) + return false; + } while (FormatTok->Tok.getIdentifierInfo() || FormatTok->isOneOf(tok::colon, tok::coloncolon, tok::less, tok::greater, tok::comma, tok::question, - tok::l_square, tok::r_square)) { + tok::l_square)) { if (Style.isVerilog()) { FormatTok->setFinalizedType(TT_VerilogDimensionedTypeName); nextToken(); @@ -3738,12 +3791,11 @@ bool UnwrappedLineParser::parseEnum() { // We can have macros or attributes in between 'enum' and the enum name. if (FormatTok->is(tok::l_paren)) parseParens(); - assert(FormatTok->isNot(TT_AttributeSquare)); if (FormatTok->is(tok::identifier)) { nextToken(); // If there are two identifiers in a row, this is likely an elaborate // return type. In Java, this can be "implements", etc. - if (Style.isCpp() && FormatTok->is(tok::identifier)) + if (IsCpp && FormatTok->is(tok::identifier)) return false; } } @@ -3918,6 +3970,8 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { const FormatToken &InitialToken = *FormatTok; nextToken(); + const FormatToken *ClassName = nullptr; + bool IsDerived = false; auto IsNonMacroIdentifier = [](const FormatToken *Tok) { return Tok->is(tok::identifier) && Tok->TokenText != Tok->TokenText.upper(); }; @@ -3942,14 +3996,37 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { } if (FormatTok->is(tok::l_square) && handleCppAttributes()) continue; + const auto *Previous = FormatTok; nextToken(); - // We can have macros in between 'class' and the class name. - if (!IsNonMacroIdentifier(FormatTok->Previous) && - FormatTok->is(tok::l_paren)) { - parseParens(); + switch (FormatTok->Tok.getKind()) { + case tok::l_paren: + // We can have macros in between 'class' and the class name. + if (!IsNonMacroIdentifier(Previous) || + // e.g. `struct macro(a) S { int i; };` + Previous->Previous == &InitialToken) { + parseParens(); + } + break; + case tok::coloncolon: + break; + default: + if (!ClassName && Previous->is(tok::identifier) && + Previous->isNot(TT_AttributeMacro)) { + ClassName = Previous; + } } } + auto IsListInitialization = [&] { + if (!ClassName || IsDerived) + return false; + assert(FormatTok->is(tok::l_brace)); + const auto *Prev = FormatTok->getPreviousNonComment(); + assert(Prev); + return Prev != ClassName && Prev->is(tok::identifier) && + Prev->isNot(Keywords.kw_final) && tryToParseBracedList(); + }; + if (FormatTok->isOneOf(tok::colon, tok::less)) { int AngleNestingLevel = 0; do { @@ -3958,19 +4035,28 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { else if (FormatTok->is(tok::greater)) --AngleNestingLevel; - if (AngleNestingLevel == 0 && FormatTok->is(tok::l_paren) && - IsNonMacroIdentifier(FormatTok->Previous)) { - break; + if (AngleNestingLevel == 0) { + if (FormatTok->is(tok::colon)) { + IsDerived = true; + } else if (FormatTok->is(tok::identifier) && + FormatTok->Previous->is(tok::coloncolon)) { + ClassName = FormatTok; + } else if (FormatTok->is(tok::l_paren) && + IsNonMacroIdentifier(FormatTok->Previous)) { + break; + } } if (FormatTok->is(tok::l_brace)) { + if (AngleNestingLevel == 0 && IsListInitialization()) + return; calculateBraceTypes(/*ExpectClassBody=*/true); if (!tryToParseBracedList()) break; } if (FormatTok->is(tok::l_square)) { FormatToken *Previous = FormatTok->Previous; - if (!Previous || - !(Previous->is(tok::r_paren) || Previous->isTypeOrIdentifier())) { + if (!Previous || (Previous->isNot(tok::r_paren) && + !Previous->isTypeOrIdentifier(LangOpts))) { // Don't try parsing a lambda if we had a closing parenthesis before, // it was probably a pointer to an array: int (*)[]. if (!tryToParseLambda()) @@ -4007,6 +4093,8 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { } }; if (FormatTok->is(tok::l_brace)) { + if (IsListInitialization()) + return; auto [OpenBraceType, ClosingBraceType] = GetBraceTypes(InitialToken); FormatTok->setFinalizedType(OpenBraceType); if (ParseAsExpr) { @@ -4711,14 +4799,13 @@ void UnwrappedLineParser::readToken(int LevelDifference) { do { FormatTok = Tokens->getNextToken(); assert(FormatTok); - while (FormatTok->getType() == TT_ConflictStart || - FormatTok->getType() == TT_ConflictEnd || - FormatTok->getType() == TT_ConflictAlternative) { - if (FormatTok->getType() == TT_ConflictStart) + while (FormatTok->isOneOf(TT_ConflictStart, TT_ConflictEnd, + TT_ConflictAlternative)) { + if (FormatTok->is(TT_ConflictStart)) conditionalCompilationStart(/*Unreachable=*/false); - else if (FormatTok->getType() == TT_ConflictAlternative) + else if (FormatTok->is(TT_ConflictAlternative)) conditionalCompilationAlternative(); - else if (FormatTok->getType() == TT_ConflictEnd) + else if (FormatTok->is(TT_ConflictEnd)) conditionalCompilationEnd(); FormatTok = Tokens->getNextToken(); FormatTok->MustBreakBefore = true; @@ -4764,6 +4851,8 @@ void UnwrappedLineParser::readToken(int LevelDifference) { PPBranchLevel > 0) { Line->Level += PPBranchLevel; } + assert(Line->Level >= Line->UnbracedBodyLevel); + Line->Level -= Line->UnbracedBodyLevel; flushComments(isOnNewLine(*FormatTok)); parsePPDirective(); PreviousWasComment = FormatTok->is(tok::comment); diff --git a/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.h b/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.h index 739298690bbd..d5eeb3d57149 100644 --- a/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.h +++ b/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.h @@ -15,17 +15,8 @@ #ifndef LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEPARSER_H #define LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEPARSER_H -#include "Encoding.h" -#include "FormatToken.h" #include "Macros.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/Format/Format.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/Support/Regex.h" -#include <list> #include <stack> -#include <vector> namespace clang { namespace format { @@ -58,6 +49,9 @@ struct UnwrappedLine { /// Whether it is part of a macro body. bool InMacroBody = false; + /// Nesting level of unbraced body of a control statement. + unsigned UnbracedBodyLevel = 0; + bool MustBeDeclaration = false; /// Whether the parser has seen \c decltype(auto) in this line. @@ -166,7 +160,7 @@ private: void parseDoWhile(); void parseLabel(bool LeftAlignLabel = false); void parseCaseLabel(); - void parseSwitch(); + void parseSwitch(bool IsExpr); void parseNamespace(); bool parseModuleImport(); void parseNew(); @@ -324,6 +318,8 @@ private: llvm::BitVector DeclarationScopeStack; const FormatStyle &Style; + bool IsCpp; + LangOptions LangOpts; const AdditionalKeywords &Keywords; llvm::Regex CommentPragmasRegex; @@ -420,6 +416,8 @@ struct UnwrappedLineNode { SmallVector<UnwrappedLine, 0> Children; }; +std::ostream &operator<<(std::ostream &Stream, const UnwrappedLine &Line); + } // end namespace format } // end namespace clang diff --git a/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp b/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp index 7525e6ee650b..a31874a7c319 100644 --- a/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp +++ b/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp @@ -107,10 +107,16 @@ const tooling::Replacements &WhitespaceManager::generateReplacements() { llvm::sort(Changes, Change::IsBeforeInFile(SourceMgr)); calculateLineBreakInformation(); alignConsecutiveMacros(); - alignConsecutiveShortCaseStatements(); + alignConsecutiveShortCaseStatements(/*IsExpr=*/true); + alignConsecutiveShortCaseStatements(/*IsExpr=*/false); alignConsecutiveDeclarations(); alignConsecutiveBitFields(); alignConsecutiveAssignments(); + if (Style.isTableGen()) { + alignConsecutiveTableGenBreakingDAGArgColons(); + alignConsecutiveTableGenCondOperatorColons(); + alignConsecutiveTableGenDefinitions(); + } alignChainedConditionals(); alignTrailingComments(); alignEscapedNewlines(); @@ -123,11 +129,14 @@ const tooling::Replacements &WhitespaceManager::generateReplacements() { void WhitespaceManager::calculateLineBreakInformation() { Changes[0].PreviousEndOfTokenColumn = 0; Change *LastOutsideTokenChange = &Changes[0]; - for (unsigned i = 1, e = Changes.size(); i != e; ++i) { + for (unsigned I = 1, e = Changes.size(); I != e; ++I) { + auto &C = Changes[I]; + auto &P = Changes[I - 1]; + auto &PrevTokLength = P.TokenLength; SourceLocation OriginalWhitespaceStart = - Changes[i].OriginalWhitespaceRange.getBegin(); + C.OriginalWhitespaceRange.getBegin(); SourceLocation PreviousOriginalWhitespaceEnd = - Changes[i - 1].OriginalWhitespaceRange.getEnd(); + P.OriginalWhitespaceRange.getEnd(); unsigned OriginalWhitespaceStartOffset = SourceMgr.getFileOffset(OriginalWhitespaceStart); unsigned PreviousOriginalWhitespaceEndOffset = @@ -162,31 +171,28 @@ void WhitespaceManager::calculateLineBreakInformation() { // line of the token. auto NewlinePos = Text.find_first_of('\n'); if (NewlinePos == StringRef::npos) { - Changes[i - 1].TokenLength = OriginalWhitespaceStartOffset - - PreviousOriginalWhitespaceEndOffset + - Changes[i].PreviousLinePostfix.size() + - Changes[i - 1].CurrentLinePrefix.size(); + PrevTokLength = OriginalWhitespaceStartOffset - + PreviousOriginalWhitespaceEndOffset + + C.PreviousLinePostfix.size() + P.CurrentLinePrefix.size(); + if (!P.IsInsideToken) + PrevTokLength = std::min(PrevTokLength, P.Tok->ColumnWidth); } else { - Changes[i - 1].TokenLength = - NewlinePos + Changes[i - 1].CurrentLinePrefix.size(); + PrevTokLength = NewlinePos + P.CurrentLinePrefix.size(); } // If there are multiple changes in this token, sum up all the changes until // the end of the line. - if (Changes[i - 1].IsInsideToken && Changes[i - 1].NewlinesBefore == 0) { - LastOutsideTokenChange->TokenLength += - Changes[i - 1].TokenLength + Changes[i - 1].Spaces; - } else { - LastOutsideTokenChange = &Changes[i - 1]; - } + if (P.IsInsideToken && P.NewlinesBefore == 0) + LastOutsideTokenChange->TokenLength += PrevTokLength + P.Spaces; + else + LastOutsideTokenChange = &P; - Changes[i].PreviousEndOfTokenColumn = - Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength; + C.PreviousEndOfTokenColumn = P.StartOfTokenColumn + PrevTokLength; - Changes[i - 1].IsTrailingComment = - (Changes[i].NewlinesBefore > 0 || Changes[i].Tok->is(tok::eof) || - (Changes[i].IsInsideToken && Changes[i].Tok->is(tok::comment))) && - Changes[i - 1].Tok->is(tok::comment) && + P.IsTrailingComment = + (C.NewlinesBefore > 0 || C.Tok->is(tok::eof) || + (C.IsInsideToken && C.Tok->is(tok::comment))) && + P.Tok->is(tok::comment) && // FIXME: This is a dirty hack. The problem is that // BreakableLineCommentSection does comment reflow changes and here is // the aligning of trailing comments. Consider the case where we reflow @@ -459,16 +465,16 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, if (i + 1 != Changes.size()) Changes[i + 1].PreviousEndOfTokenColumn += Shift; - // If PointerAlignment is PAS_Right, keep *s or &s next to the token + // If PointerAlignment is PAS_Right, keep *s or &s next to the token, + // except if the token is equal, then a space is needed. if ((Style.PointerAlignment == FormatStyle::PAS_Right || Style.ReferenceAlignment == FormatStyle::RAS_Right) && - CurrentChange.Spaces != 0) { + CurrentChange.Spaces != 0 && CurrentChange.Tok->isNot(tok::equal)) { const bool ReferenceNotRightAligned = Style.ReferenceAlignment != FormatStyle::RAS_Right && Style.ReferenceAlignment != FormatStyle::RAS_Pointer; for (int Previous = i - 1; - Previous >= 0 && - Changes[Previous].Tok->getType() == TT_PointerOrReference; + Previous >= 0 && Changes[Previous].Tok->is(TT_PointerOrReference); --Previous) { assert(Changes[Previous].Tok->isPointerOrReference()); if (Changes[Previous].Tok->isNot(tok::star)) { @@ -849,7 +855,12 @@ void WhitespaceManager::alignConsecutiveAssignments() { } void WhitespaceManager::alignConsecutiveBitFields() { - if (!Style.AlignConsecutiveBitFields.Enabled) + alignConsecutiveColons(Style.AlignConsecutiveBitFields, TT_BitFieldColon); +} + +void WhitespaceManager::alignConsecutiveColons( + const FormatStyle::AlignConsecutiveStyle &AlignStyle, TokenType Type) { + if (!AlignStyle.Enabled) return; AlignTokens( @@ -863,27 +874,32 @@ void WhitespaceManager::alignConsecutiveBitFields() { if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0) return false; - return C.Tok->is(TT_BitFieldColon); + return C.Tok->is(Type); }, - Changes, /*StartAt=*/0, Style.AlignConsecutiveBitFields); + Changes, /*StartAt=*/0, AlignStyle); } -void WhitespaceManager::alignConsecutiveShortCaseStatements() { +void WhitespaceManager::alignConsecutiveShortCaseStatements(bool IsExpr) { if (!Style.AlignConsecutiveShortCaseStatements.Enabled || - !Style.AllowShortCaseLabelsOnASingleLine) { + !(IsExpr ? Style.AllowShortCaseExpressionOnASingleLine + : Style.AllowShortCaseLabelsOnASingleLine)) { return; } + const auto Type = IsExpr ? TT_CaseLabelArrow : TT_CaseLabelColon; + const auto &Option = Style.AlignConsecutiveShortCaseStatements; + const bool AlignArrowOrColon = + IsExpr ? Option.AlignCaseArrows : Option.AlignCaseColons; + auto Matches = [&](const Change &C) { - if (Style.AlignConsecutiveShortCaseStatements.AlignCaseColons) - return C.Tok->is(TT_CaseLabelColon); + if (AlignArrowOrColon) + return C.Tok->is(Type); // Ignore 'IsInsideToken' to allow matching trailing comments which // need to be reflowed as that causes the token to appear in two // different changes, which will cause incorrect alignment as we'll // reflow early due to detecting multiple aligning tokens per line. - return !C.IsInsideToken && C.Tok->Previous && - C.Tok->Previous->is(TT_CaseLabelColon); + return !C.IsInsideToken && C.Tok->Previous && C.Tok->Previous->is(Type); }; unsigned MinColumn = 0; @@ -934,7 +950,7 @@ void WhitespaceManager::alignConsecutiveShortCaseStatements() { if (Changes[I].Tok->isNot(tok::comment)) LineIsComment = false; - if (Changes[I].Tok->is(TT_CaseLabelColon)) { + if (Changes[I].Tok->is(Type)) { LineIsEmptyCase = !Changes[I].Tok->Next || Changes[I].Tok->Next->isTrailingComment(); @@ -972,6 +988,21 @@ void WhitespaceManager::alignConsecutiveShortCaseStatements() { Changes); } +void WhitespaceManager::alignConsecutiveTableGenBreakingDAGArgColons() { + alignConsecutiveColons(Style.AlignConsecutiveTableGenBreakingDAGArgColons, + TT_TableGenDAGArgListColonToAlign); +} + +void WhitespaceManager::alignConsecutiveTableGenCondOperatorColons() { + alignConsecutiveColons(Style.AlignConsecutiveTableGenCondOperatorColons, + TT_TableGenCondOperatorColon); +} + +void WhitespaceManager::alignConsecutiveTableGenDefinitions() { + alignConsecutiveColons(Style.AlignConsecutiveTableGenDefinitionColons, + TT_InheritanceColon); +} + void WhitespaceManager::alignConsecutiveDeclarations() { if (!Style.AlignConsecutiveDeclarations.Enabled) return; @@ -1085,7 +1116,7 @@ void WhitespaceManager::alignTrailingComments() { // leave the comments. if (RestoredLineLength >= Style.ColumnLimit && Style.ColumnLimit > 0) break; - C.Spaces = OriginalSpaces; + C.Spaces = C.NewlinesBefore > 0 ? C.Tok->OriginalColumn : OriginalSpaces; continue; } @@ -1214,22 +1245,29 @@ void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End, } void WhitespaceManager::alignEscapedNewlines() { - if (Style.AlignEscapedNewlines == FormatStyle::ENAS_DontAlign) + const auto Align = Style.AlignEscapedNewlines; + if (Align == FormatStyle::ENAS_DontAlign) return; - bool AlignLeft = Style.AlignEscapedNewlines == FormatStyle::ENAS_Left; - unsigned MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit; + const bool WithLastLine = Align == FormatStyle::ENAS_LeftWithLastLine; + const bool AlignLeft = Align == FormatStyle::ENAS_Left || WithLastLine; + const auto MaxColumn = Style.ColumnLimit; + unsigned MaxEndOfLine = AlignLeft ? 0 : MaxColumn; unsigned StartOfMacro = 0; for (unsigned i = 1, e = Changes.size(); i < e; ++i) { Change &C = Changes[i]; - if (C.NewlinesBefore > 0) { - if (C.ContinuesPPDirective) { - MaxEndOfLine = std::max(C.PreviousEndOfTokenColumn + 2, MaxEndOfLine); - } else { - alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine); - MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit; - StartOfMacro = i; - } + if (C.NewlinesBefore == 0 && (!WithLastLine || C.Tok->isNot(tok::eof))) + continue; + const bool InPPDirective = C.ContinuesPPDirective; + const auto BackslashColumn = C.PreviousEndOfTokenColumn + 2; + if (InPPDirective || + (WithLastLine && (MaxColumn == 0 || BackslashColumn <= MaxColumn))) { + MaxEndOfLine = std::max(BackslashColumn, MaxEndOfLine); + } + if (!InPPDirective) { + alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine); + MaxEndOfLine = AlignLeft ? 0 : MaxColumn; + StartOfMacro = i; } } alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine); @@ -1469,7 +1507,7 @@ WhitespaceManager::CellDescriptions WhitespaceManager::getCells(unsigned Start, while (NextNonComment && NextNonComment->is(tok::comma)) NextNonComment = NextNonComment->getNextNonComment(); auto j = i; - while (Changes[j].Tok != NextNonComment && j < End) + while (j < End && Changes[j].Tok != NextNonComment) ++j; if (j < End && Changes[j].NewlinesBefore == 0 && Changes[j].Tok->isNot(tok::r_brace)) { diff --git a/contrib/llvm-project/clang/lib/Format/WhitespaceManager.h b/contrib/llvm-project/clang/lib/Format/WhitespaceManager.h index 8ac73305871a..7b91d8bf4db7 100644 --- a/contrib/llvm-project/clang/lib/Format/WhitespaceManager.h +++ b/contrib/llvm-project/clang/lib/Format/WhitespaceManager.h @@ -17,11 +17,6 @@ #include "TokenAnnotator.h" #include "clang/Basic/SourceManager.h" -#include "clang/Format/Format.h" -#include "llvm/ADT/SmallVector.h" -#include <algorithm> -#include <string> -#include <tuple> namespace clang { namespace format { @@ -226,6 +221,11 @@ private: /// Align consecutive bitfields over all \c Changes. void alignConsecutiveBitFields(); + /// Align consecutive colon. For bitfields, TableGen DAGArgs and defintions. + void + alignConsecutiveColons(const FormatStyle::AlignConsecutiveStyle &AlignStyle, + TokenType Type); + /// Align consecutive declarations over all \c Changes. void alignConsecutiveDeclarations(); @@ -233,7 +233,16 @@ private: void alignChainedConditionals(); /// Align consecutive short case statements over all \c Changes. - void alignConsecutiveShortCaseStatements(); + void alignConsecutiveShortCaseStatements(bool IsExpr); + + /// Align consecutive TableGen DAGArg colon over all \c Changes. + void alignConsecutiveTableGenBreakingDAGArgColons(); + + /// Align consecutive TableGen cond operator colon over all \c Changes. + void alignConsecutiveTableGenCondOperatorColons(); + + /// Align consecutive TableGen definitions over all \c Changes. + void alignConsecutiveTableGenDefinitions(); /// Align trailing comments over all \c Changes. void alignTrailingComments(); |