diff options
Diffstat (limited to 'clang/lib/Format')
24 files changed, 2242 insertions, 941 deletions
diff --git a/clang/lib/Format/BreakableToken.cpp b/clang/lib/Format/BreakableToken.cpp index db82018a4c83..b3ef2a895d7f 100644 --- a/clang/lib/Format/BreakableToken.cpp +++ b/clang/lib/Format/BreakableToken.cpp @@ -49,10 +49,10 @@ static StringRef getLineCommentIndentPrefix(StringRef Comment, if (Style.Language == FormatStyle::LK_TextProto) KnownPrefixes = KnownTextProtoPrefixes; - assert(std::is_sorted(KnownPrefixes.begin(), KnownPrefixes.end(), - [](StringRef Lhs, StringRef Rhs) noexcept { - return Lhs.size() > Rhs.size(); - })); + assert( + llvm::is_sorted(KnownPrefixes, [](StringRef Lhs, StringRef Rhs) noexcept { + return Lhs.size() > Rhs.size(); + })); for (StringRef KnownPrefix : KnownPrefixes) { if (Comment.startswith(KnownPrefix)) { diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 651ec80d6196..412c57b850b5 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -21,6 +21,7 @@ #include "clang/Format/Format.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Debug.h" +#include <optional> #define DEBUG_TYPE "format-indenter" @@ -146,13 +147,13 @@ static bool opensProtoMessageField(const FormatToken &LessTok, (LessTok.Previous && LessTok.Previous->is(tok::equal)))); } -// Returns the delimiter of a raw string literal, or None if TokenText is not -// the text of a raw string literal. The delimiter could be the empty string. -// For example, the delimiter of R"deli(cont)deli" is deli. -static llvm::Optional<StringRef> getRawStringDelimiter(StringRef TokenText) { +// Returns the delimiter of a raw string literal, or std::nullopt if TokenText +// is not the text of a raw string literal. The delimiter could be the empty +// string. For example, the delimiter of R"deli(cont)deli" is deli. +static std::optional<StringRef> getRawStringDelimiter(StringRef TokenText) { if (TokenText.size() < 5 // The smallest raw string possible is 'R"()"'. || !TokenText.startswith("R\"") || !TokenText.endswith("\"")) { - return None; + return std::nullopt; } // A raw string starts with 'R"<delimiter>(' and delimiter is ascii and has @@ -160,15 +161,15 @@ static llvm::Optional<StringRef> getRawStringDelimiter(StringRef TokenText) { // 19 bytes. size_t LParenPos = TokenText.substr(0, 19).find_first_of('('); if (LParenPos == StringRef::npos) - return None; + return std::nullopt; StringRef Delimiter = TokenText.substr(2, LParenPos - 2); // Check that the string ends in ')Delimiter"'. size_t RParenPos = TokenText.size() - Delimiter.size() - 2; if (TokenText[RParenPos] != ')') - return None; + return std::nullopt; if (!TokenText.substr(RParenPos + 1).startswith(Delimiter)) - return None; + return std::nullopt; return Delimiter; } @@ -186,7 +187,7 @@ getCanonicalRawStringDelimiter(const FormatStyle &Style, RawStringFormatStyleManager::RawStringFormatStyleManager( const FormatStyle &CodeStyle) { for (const auto &RawStringFormat : CodeStyle.RawStringFormats) { - llvm::Optional<FormatStyle> LanguageStyle = + std::optional<FormatStyle> LanguageStyle = CodeStyle.GetLanguageStyle(RawStringFormat.Language); if (!LanguageStyle) { FormatStyle PredefinedStyle; @@ -205,20 +206,20 @@ RawStringFormatStyleManager::RawStringFormatStyleManager( } } -llvm::Optional<FormatStyle> +std::optional<FormatStyle> RawStringFormatStyleManager::getDelimiterStyle(StringRef Delimiter) const { auto It = DelimiterStyle.find(Delimiter); if (It == DelimiterStyle.end()) - return None; + return std::nullopt; return It->second; } -llvm::Optional<FormatStyle> +std::optional<FormatStyle> RawStringFormatStyleManager::getEnclosingFunctionStyle( StringRef EnclosingFunction) const { auto It = EnclosingFunctionStyle.find(EnclosingFunction); if (It == EnclosingFunctionStyle.end()) - return None; + return std::nullopt; return It->second; } @@ -331,6 +332,15 @@ bool ContinuationIndenter::canBreak(const LineState &State) { if (Previous.is(tok::l_square) && Previous.is(TT_ObjCMethodExpr)) return false; + if (Current.is(TT_ConditionalExpr) && Previous.is(tok::r_paren) && + Previous.MatchingParen && Previous.MatchingParen->Previous && + Previous.MatchingParen->Previous->MatchingParen && + Previous.MatchingParen->Previous->MatchingParen->is(TT_LambdaLBrace)) { + // We have a lambda within a conditional expression, allow breaking here. + assert(Previous.MatchingParen->Previous->is(tok::r_brace)); + return true; + } + return !CurrentState.NoLineBreak; } @@ -343,8 +353,12 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { auto LambdaBodyLength = getLengthToMatchingParen(Current, State.Stack); return LambdaBodyLength > getColumnLimit(State); } - if (Current.MustBreakBefore || Current.is(TT_InlineASMColon)) + if (Current.MustBreakBefore || + (Current.is(TT_InlineASMColon) && + (Style.BreakBeforeInlineASMColon == FormatStyle::BBIAS_Always || + Style.BreakBeforeInlineASMColon == FormatStyle::BBIAS_OnlyMultiline))) { return true; + } if (CurrentState.BreakBeforeClosingBrace && Current.closesBlockOrBlockTypeList(Style)) { return true; @@ -444,7 +458,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { } // If the template declaration spans multiple lines, force wrap before the - // function/class declaration + // function/class declaration. if (Previous.ClosesTemplateDeclaration && CurrentState.BreakBeforeParameter && Current.CanBreakBefore) { return true; @@ -552,7 +566,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { // If the return type spans multiple lines, wrap before the function name. if (((Current.is(TT_FunctionDeclarationName) && - // Don't break before a C# function when no break after return type + !State.Line->ReturnTypeWrapped && + // Don't break before a C# function when no break after return type. (!Style.isCSharp() || Style.AlwaysBreakAfterReturnType != FormatStyle::RTBS_None) && // Don't always break between a JavaScript `function` and the function @@ -707,8 +722,9 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, (Previous.is(tok::l_brace) && Previous.isNot(BK_Block) && Style.Cpp11BracedListStyle)) && State.Column > getNewLineColumn(State) && - (!Previous.Previous || !Previous.Previous->isOneOf( - tok::kw_for, tok::kw_while, tok::kw_switch)) && + (!Previous.Previous || + !Previous.Previous->isOneOf(TT_CastRParen, tok::kw_for, tok::kw_while, + tok::kw_switch)) && // Don't do this for simple (no expressions) one-argument function calls // as that feels like needlessly wasting whitespace, e.g.: // @@ -1090,8 +1106,12 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { CurrentState.Indent + Style.ContinuationIndentWidth); } - if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths && - State.Line->First->is(tok::kw_enum)) { + // After a goto label. Usually labels are on separate lines. However + // for Verilog the labels may be only recognized by the annotator and + // thus are on the same line as the current token. + if ((Style.isVerilog() && Keywords.isVerilogEndOfLabel(Previous)) || + (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths && + State.Line->First->is(tok::kw_enum))) { return (Style.IndentWidth * State.Line->First->IndentLevel) + Style.IndentWidth; } @@ -1244,6 +1264,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { return ContinuationIndent; } + if (State.Line->InPragmaDirective) + return CurrentState.Indent + Style.ContinuationIndentWidth; + // This ensure that we correctly format ObjC methods calls without inputs, // i.e. where the last element isn't selector like: [callee method]; if (NextNonComment->is(tok::identifier) && NextNonComment->FakeRParens == 0 && @@ -1301,7 +1324,7 @@ static bool hasNestedBlockInlined(const FormatToken *Previous, if (Previous->ParameterCount > 1) return true; - // Also a nested block if contains a lambda inside function with 1 parameter + // Also a nested block if contains a lambda inside function with 1 parameter. return Style.BraceWrapping.BeforeLambdaBody && Current.is(TT_LambdaLSquare); } @@ -1399,8 +1422,10 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, CurrentState.NestedBlockIndent = State.Column + Current.ColumnWidth + 1; if (Current.isOneOf(TT_LambdaLSquare, TT_LambdaArrow)) CurrentState.LastSpace = State.Column; - if (Current.is(TT_RequiresExpression)) + if (Current.is(TT_RequiresExpression) && + Style.RequiresExpressionIndentation == FormatStyle::REI_Keyword) { CurrentState.NestedBlockIndent = State.Column; + } // Insert scopes created by fake parenthesis. const FormatToken *Previous = Current.getPreviousNonComment(); @@ -1514,6 +1539,12 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State, std::max(State.Column, NewParenState.Indent), CurrentState.LastSpace); } + // 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->getPrecedence() == prec::Assignment || Previous->isOneOf(tok::kw_return, TT_RequiresClause) || @@ -1521,7 +1552,7 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State, Previous->is(TT_ConditionalExpr))) && !Newline) { // If BreakBeforeBinaryOperators is set, un-indent a bit to account for - // the operator and keep the operands aligned + // the operator and keep the operands aligned. if (Style.AlignOperands == FormatStyle::OAS_AlignAfterOperator) NewParenState.UnindentOperator = true; // Mark indentation as alignment if the expression is aligned. @@ -1660,8 +1691,12 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, (State.Line->Type != LT_ObjCDecl && Style.BinPackParameters) || (State.Line->Type == LT_ObjCDecl && ObjCBinPackProtocolList); + bool GenericSelection = + Current.getPreviousNonComment() && + Current.getPreviousNonComment()->is(tok::kw__Generic); + AvoidBinPacking = - (CurrentState.IsCSharpGenericTypeConstraint) || + (CurrentState.IsCSharpGenericTypeConstraint) || GenericSelection || (Style.isJavaScript() && EndsInComma) || (State.Line->MustBeDeclaration && !BinPackDeclaration) || (!State.Line->MustBeDeclaration && !Style.BinPackArguments) || @@ -1713,7 +1748,7 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, if (Style.BraceWrapping.BeforeLambdaBody && Current.Next != nullptr && Current.is(tok::l_paren)) { - // Search for any parameter that is a lambda + // Search for any parameter that is a lambda. FormatToken const *next = Current.Next; while (next != nullptr) { if (next->is(TT_LambdaLSquare)) { @@ -2045,21 +2080,21 @@ static StringRef getEnclosingFunctionName(const FormatToken &Current) { return Tok->TokenText; } -llvm::Optional<FormatStyle> +std::optional<FormatStyle> ContinuationIndenter::getRawStringStyle(const FormatToken &Current, const LineState &State) { if (!Current.isStringLiteral()) - return None; + return std::nullopt; auto Delimiter = getRawStringDelimiter(Current.TokenText); if (!Delimiter) - return None; + return std::nullopt; auto RawStringStyle = RawStringFormats.getDelimiterStyle(*Delimiter); if (!RawStringStyle && Delimiter->empty()) { RawStringStyle = RawStringFormats.getEnclosingFunctionStyle( getEnclosingFunctionName(Current)); } if (!RawStringStyle) - return None; + return std::nullopt; RawStringStyle->ColumnLimit = getColumnLimit(State); return RawStringStyle; } @@ -2533,7 +2568,7 @@ ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, } unsigned ContinuationIndenter::getColumnLimit(const LineState &State) const { - // In preprocessor directives reserve two chars for trailing " \" + // In preprocessor directives reserve two chars for trailing " \". return Style.ColumnLimit - (State.Line->InPPDirective ? 2 : 0); } diff --git a/clang/lib/Format/ContinuationIndenter.h b/clang/lib/Format/ContinuationIndenter.h index 620060e68861..2a1b96834a79 100644 --- a/clang/lib/Format/ContinuationIndenter.h +++ b/clang/lib/Format/ContinuationIndenter.h @@ -20,6 +20,7 @@ #include "clang/Format/Format.h" #include "llvm/Support/Regex.h" #include <map> +#include <optional> #include <tuple> namespace clang { @@ -41,9 +42,9 @@ struct RawStringFormatStyleManager { RawStringFormatStyleManager(const FormatStyle &CodeStyle); - llvm::Optional<FormatStyle> getDelimiterStyle(StringRef Delimiter) const; + std::optional<FormatStyle> getDelimiterStyle(StringRef Delimiter) const; - llvm::Optional<FormatStyle> + std::optional<FormatStyle> getEnclosingFunctionStyle(StringRef EnclosingFunction) const; }; @@ -120,8 +121,8 @@ private: /// If \p Current is a raw string that is configured to be reformatted, /// return the style to be used. - llvm::Optional<FormatStyle> getRawStringStyle(const FormatToken &Current, - const LineState &State); + std::optional<FormatStyle> getRawStringStyle(const FormatToken &Current, + const LineState &State); /// If the current token sticks out over the end of the line, break /// it if possible. diff --git a/clang/lib/Format/DefinitionBlockSeparator.cpp b/clang/lib/Format/DefinitionBlockSeparator.cpp index f6edcd13ecd6..5c006e2d037b 100644 --- a/clang/lib/Format/DefinitionBlockSeparator.cpp +++ b/clang/lib/Format/DefinitionBlockSeparator.cpp @@ -69,11 +69,11 @@ void DefinitionBlockSeparator::separateBlocks( (Style.SeparateDefinitionBlocks == FormatStyle::SDS_Always ? 1 : 0) + 1; WhitespaceManager Whitespaces( Env.getSourceManager(), Style, - Style.DeriveLineEnding + Style.LineEnding > FormatStyle::LE_CRLF ? WhitespaceManager::inputUsesCRLF( Env.getSourceManager().getBufferData(Env.getFileID()), - Style.UseCRLF) - : Style.UseCRLF); + Style.LineEnding == FormatStyle::LE_DeriveCRLF) + : Style.LineEnding == FormatStyle::LE_CRLF); for (unsigned I = 0; I < Lines.size(); ++I) { const auto &CurrentLine = Lines[I]; if (CurrentLine->InPPDirective) diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 2659fa2af1a7..f37c3f983635 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -20,6 +20,7 @@ #include "FormatInternal.h" #include "FormatToken.h" #include "FormatTokenLexer.h" +#include "IntegerLiteralSeparatorFixer.h" #include "NamespaceEndCommentsFixer.h" #include "QualifierAlignmentFixer.h" #include "SortJavaScriptImports.h" @@ -46,6 +47,7 @@ #include <algorithm> #include <memory> #include <mutex> +#include <optional> #include <string> #include <unordered_map> @@ -57,101 +59,6 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::RawStringFormat) namespace llvm { namespace yaml { -template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> { - static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) { - IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp); - IO.enumCase(Value, "Java", FormatStyle::LK_Java); - IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript); - IO.enumCase(Value, "ObjC", FormatStyle::LK_ObjC); - IO.enumCase(Value, "Proto", FormatStyle::LK_Proto); - IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen); - IO.enumCase(Value, "TextProto", FormatStyle::LK_TextProto); - IO.enumCase(Value, "CSharp", FormatStyle::LK_CSharp); - IO.enumCase(Value, "Json", FormatStyle::LK_Json); - } -}; - -template <> struct ScalarEnumerationTraits<FormatStyle::LanguageStandard> { - static void enumeration(IO &IO, FormatStyle::LanguageStandard &Value) { - IO.enumCase(Value, "c++03", FormatStyle::LS_Cpp03); - IO.enumCase(Value, "C++03", FormatStyle::LS_Cpp03); // Legacy alias - IO.enumCase(Value, "Cpp03", FormatStyle::LS_Cpp03); // Legacy alias - - IO.enumCase(Value, "c++11", FormatStyle::LS_Cpp11); - IO.enumCase(Value, "C++11", FormatStyle::LS_Cpp11); // Legacy alias - - IO.enumCase(Value, "c++14", FormatStyle::LS_Cpp14); - IO.enumCase(Value, "c++17", FormatStyle::LS_Cpp17); - IO.enumCase(Value, "c++20", FormatStyle::LS_Cpp20); - - IO.enumCase(Value, "Latest", FormatStyle::LS_Latest); - IO.enumCase(Value, "Cpp11", FormatStyle::LS_Latest); // Legacy alias - IO.enumCase(Value, "Auto", FormatStyle::LS_Auto); - } -}; - -template <> -struct ScalarEnumerationTraits<FormatStyle::LambdaBodyIndentationKind> { - static void enumeration(IO &IO, - FormatStyle::LambdaBodyIndentationKind &Value) { - IO.enumCase(Value, "Signature", FormatStyle::LBI_Signature); - IO.enumCase(Value, "OuterScope", FormatStyle::LBI_OuterScope); - } -}; - -template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> { - static void enumeration(IO &IO, FormatStyle::UseTabStyle &Value) { - IO.enumCase(Value, "Never", FormatStyle::UT_Never); - IO.enumCase(Value, "false", FormatStyle::UT_Never); - IO.enumCase(Value, "Always", FormatStyle::UT_Always); - IO.enumCase(Value, "true", FormatStyle::UT_Always); - IO.enumCase(Value, "ForIndentation", FormatStyle::UT_ForIndentation); - IO.enumCase(Value, "ForContinuationAndIndentation", - FormatStyle::UT_ForContinuationAndIndentation); - IO.enumCase(Value, "AlignWithSpaces", FormatStyle::UT_AlignWithSpaces); - } -}; - -template <> struct ScalarEnumerationTraits<FormatStyle::JavaScriptQuoteStyle> { - static void enumeration(IO &IO, FormatStyle::JavaScriptQuoteStyle &Value) { - IO.enumCase(Value, "Leave", FormatStyle::JSQS_Leave); - IO.enumCase(Value, "Single", FormatStyle::JSQS_Single); - IO.enumCase(Value, "Double", FormatStyle::JSQS_Double); - } -}; - -template <> struct ScalarEnumerationTraits<FormatStyle::ShortBlockStyle> { - static void enumeration(IO &IO, FormatStyle::ShortBlockStyle &Value) { - IO.enumCase(Value, "Never", FormatStyle::SBS_Never); - IO.enumCase(Value, "false", FormatStyle::SBS_Never); - IO.enumCase(Value, "Always", FormatStyle::SBS_Always); - IO.enumCase(Value, "true", FormatStyle::SBS_Always); - IO.enumCase(Value, "Empty", FormatStyle::SBS_Empty); - } -}; - -template <> -struct ScalarEnumerationTraits<FormatStyle::QualifierAlignmentStyle> { - static void enumeration(IO &IO, FormatStyle::QualifierAlignmentStyle &Value) { - IO.enumCase(Value, "Leave", FormatStyle::QAS_Leave); - IO.enumCase(Value, "Left", FormatStyle::QAS_Left); - IO.enumCase(Value, "Right", FormatStyle::QAS_Right); - IO.enumCase(Value, "Custom", FormatStyle::QAS_Custom); - } -}; - -template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> { - static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) { - IO.enumCase(Value, "None", FormatStyle::SFS_None); - IO.enumCase(Value, "false", FormatStyle::SFS_None); - IO.enumCase(Value, "All", FormatStyle::SFS_All); - IO.enumCase(Value, "true", FormatStyle::SFS_All); - IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline); - IO.enumCase(Value, "InlineOnly", FormatStyle::SFS_InlineOnly); - IO.enumCase(Value, "Empty", FormatStyle::SFS_Empty); - } -}; - template <> struct MappingTraits<FormatStyle::AlignConsecutiveStyle> { static void enumInput(IO &IO, FormatStyle::AlignConsecutiveStyle &Value) { IO.enumCase(Value, "None", @@ -205,6 +112,15 @@ template <> struct MappingTraits<FormatStyle::AlignConsecutiveStyle> { }; template <> +struct ScalarEnumerationTraits<FormatStyle::AttributeBreakingStyle> { + static void enumeration(IO &IO, FormatStyle::AttributeBreakingStyle &Value) { + IO.enumCase(Value, "Always", FormatStyle::ABS_Always); + IO.enumCase(Value, "Leave", FormatStyle::ABS_Leave); + IO.enumCase(Value, "Never", FormatStyle::ABS_Never); + } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::ArrayInitializerAlignmentStyle> { static void enumeration(IO &IO, FormatStyle::ArrayInitializerAlignmentStyle &Value) { @@ -214,28 +130,13 @@ struct ScalarEnumerationTraits<FormatStyle::ArrayInitializerAlignmentStyle> { } }; -template <> struct ScalarEnumerationTraits<FormatStyle::ShortIfStyle> { - static void enumeration(IO &IO, FormatStyle::ShortIfStyle &Value) { - IO.enumCase(Value, "Never", FormatStyle::SIS_Never); - IO.enumCase(Value, "WithoutElse", FormatStyle::SIS_WithoutElse); - IO.enumCase(Value, "OnlyFirstIf", FormatStyle::SIS_OnlyFirstIf); - IO.enumCase(Value, "AllIfsAndElse", FormatStyle::SIS_AllIfsAndElse); - - // For backward compatibility. - IO.enumCase(Value, "Always", FormatStyle::SIS_OnlyFirstIf); - IO.enumCase(Value, "false", FormatStyle::SIS_Never); - IO.enumCase(Value, "true", FormatStyle::SIS_WithoutElse); - } -}; - -template <> struct ScalarEnumerationTraits<FormatStyle::ShortLambdaStyle> { - static void enumeration(IO &IO, FormatStyle::ShortLambdaStyle &Value) { - IO.enumCase(Value, "None", FormatStyle::SLS_None); - IO.enumCase(Value, "false", FormatStyle::SLS_None); - IO.enumCase(Value, "Empty", FormatStyle::SLS_Empty); - IO.enumCase(Value, "Inline", FormatStyle::SLS_Inline); - IO.enumCase(Value, "All", FormatStyle::SLS_All); - IO.enumCase(Value, "true", FormatStyle::SLS_All); +template <> struct ScalarEnumerationTraits<FormatStyle::BinaryOperatorStyle> { + static void enumeration(IO &IO, FormatStyle::BinaryOperatorStyle &Value) { + IO.enumCase(Value, "All", FormatStyle::BOS_All); + IO.enumCase(Value, "true", FormatStyle::BOS_All); + IO.enumCase(Value, "None", FormatStyle::BOS_None); + IO.enumCase(Value, "false", FormatStyle::BOS_None); + IO.enumCase(Value, "NonAssignment", FormatStyle::BOS_NonAssignment); } }; @@ -247,20 +148,14 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BinPackStyle> { } }; -template <> struct ScalarEnumerationTraits<FormatStyle::TrailingCommaStyle> { - static void enumeration(IO &IO, FormatStyle::TrailingCommaStyle &Value) { - IO.enumCase(Value, "None", FormatStyle::TCS_None); - IO.enumCase(Value, "Wrapped", FormatStyle::TCS_Wrapped); - } -}; - -template <> struct ScalarEnumerationTraits<FormatStyle::BinaryOperatorStyle> { - static void enumeration(IO &IO, FormatStyle::BinaryOperatorStyle &Value) { - IO.enumCase(Value, "All", FormatStyle::BOS_All); - IO.enumCase(Value, "true", FormatStyle::BOS_All); - IO.enumCase(Value, "None", FormatStyle::BOS_None); - IO.enumCase(Value, "false", FormatStyle::BOS_None); - IO.enumCase(Value, "NonAssignment", FormatStyle::BOS_NonAssignment); +template <> +struct ScalarEnumerationTraits<FormatStyle::BitFieldColonSpacingStyle> { + static void enumeration(IO &IO, + FormatStyle::BitFieldColonSpacingStyle &Value) { + IO.enumCase(Value, "Both", FormatStyle::BFCS_Both); + IO.enumCase(Value, "None", FormatStyle::BFCS_None); + IO.enumCase(Value, "Before", FormatStyle::BFCS_Before); + IO.enumCase(Value, "After", FormatStyle::BFCS_After); } }; @@ -278,6 +173,42 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> { } }; +template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> { + static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) { + IO.mapOptional("AfterCaseLabel", Wrapping.AfterCaseLabel); + IO.mapOptional("AfterClass", Wrapping.AfterClass); + IO.mapOptional("AfterControlStatement", Wrapping.AfterControlStatement); + IO.mapOptional("AfterEnum", Wrapping.AfterEnum); + IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock); + IO.mapOptional("AfterFunction", Wrapping.AfterFunction); + IO.mapOptional("AfterNamespace", Wrapping.AfterNamespace); + IO.mapOptional("AfterObjCDeclaration", Wrapping.AfterObjCDeclaration); + IO.mapOptional("AfterStruct", Wrapping.AfterStruct); + IO.mapOptional("AfterUnion", Wrapping.AfterUnion); + IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch); + IO.mapOptional("BeforeElse", Wrapping.BeforeElse); + IO.mapOptional("BeforeLambdaBody", Wrapping.BeforeLambdaBody); + IO.mapOptional("BeforeWhile", Wrapping.BeforeWhile); + IO.mapOptional("IndentBraces", Wrapping.IndentBraces); + IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction); + IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord); + IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace); + } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> { + static void enumeration(IO &IO, FormatStyle::BracketAlignmentStyle &Value) { + IO.enumCase(Value, "Align", FormatStyle::BAS_Align); + IO.enumCase(Value, "DontAlign", FormatStyle::BAS_DontAlign); + IO.enumCase(Value, "AlwaysBreak", FormatStyle::BAS_AlwaysBreak); + IO.enumCase(Value, "BlockIndent", FormatStyle::BAS_BlockIndent); + + // For backward compatibility. + IO.enumCase(Value, "true", FormatStyle::BAS_Align); + IO.enumCase(Value, "false", FormatStyle::BAS_DontAlign); + } +}; + template <> struct ScalarEnumerationTraits< FormatStyle::BraceWrappingAfterControlStatementStyle> { @@ -310,6 +241,15 @@ struct ScalarEnumerationTraits< }; template <> +struct ScalarEnumerationTraits<FormatStyle::BreakBeforeInlineASMColonStyle> { + static void enumeration(IO &IO, + FormatStyle::BreakBeforeInlineASMColonStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::BBIAS_Never); + IO.enumCase(Value, "OnlyMultiline", FormatStyle::BBIAS_OnlyMultiline); + IO.enumCase(Value, "Always", FormatStyle::BBIAS_Always); + } +}; +template <> struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> { static void enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) { @@ -331,13 +271,44 @@ struct ScalarEnumerationTraits<FormatStyle::BreakInheritanceListStyle> { }; template <> -struct ScalarEnumerationTraits<FormatStyle::PackConstructorInitializersStyle> { +struct ScalarEnumerationTraits<FormatStyle::BreakTemplateDeclarationsStyle> { + static void enumeration(IO &IO, + FormatStyle::BreakTemplateDeclarationsStyle &Value) { + IO.enumCase(Value, "No", FormatStyle::BTDS_No); + IO.enumCase(Value, "MultiLine", FormatStyle::BTDS_MultiLine); + IO.enumCase(Value, "Yes", FormatStyle::BTDS_Yes); + + // For backward compatibility. + IO.enumCase(Value, "false", FormatStyle::BTDS_MultiLine); + IO.enumCase(Value, "true", FormatStyle::BTDS_Yes); + } +}; + +template <> +struct ScalarEnumerationTraits<FormatStyle::DefinitionReturnTypeBreakingStyle> { static void - enumeration(IO &IO, FormatStyle::PackConstructorInitializersStyle &Value) { - IO.enumCase(Value, "Never", FormatStyle::PCIS_Never); - IO.enumCase(Value, "BinPack", FormatStyle::PCIS_BinPack); - IO.enumCase(Value, "CurrentLine", FormatStyle::PCIS_CurrentLine); - IO.enumCase(Value, "NextLine", FormatStyle::PCIS_NextLine); + enumeration(IO &IO, FormatStyle::DefinitionReturnTypeBreakingStyle &Value) { + IO.enumCase(Value, "None", FormatStyle::DRTBS_None); + IO.enumCase(Value, "All", FormatStyle::DRTBS_All); + IO.enumCase(Value, "TopLevel", FormatStyle::DRTBS_TopLevel); + + // For backward compatibility. + IO.enumCase(Value, "false", FormatStyle::DRTBS_None); + IO.enumCase(Value, "true", FormatStyle::DRTBS_All); + } +}; + +template <> +struct ScalarEnumerationTraits<FormatStyle::EscapedNewlineAlignmentStyle> { + static void enumeration(IO &IO, + FormatStyle::EscapedNewlineAlignmentStyle &Value) { + IO.enumCase(Value, "DontAlign", FormatStyle::ENAS_DontAlign); + IO.enumCase(Value, "Left", FormatStyle::ENAS_Left); + IO.enumCase(Value, "Right", FormatStyle::ENAS_Right); + + // For backward compatibility. + IO.enumCase(Value, "true", FormatStyle::ENAS_Left); + IO.enumCase(Value, "false", FormatStyle::ENAS_Right); } }; @@ -364,15 +335,6 @@ struct ScalarEnumerationTraits< }; template <> -struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> { - static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) { - IO.enumCase(Value, "None", FormatStyle::PPDIS_None); - IO.enumCase(Value, "AfterHash", FormatStyle::PPDIS_AfterHash); - IO.enumCase(Value, "BeforeHash", FormatStyle::PPDIS_BeforeHash); - } -}; - -template <> struct ScalarEnumerationTraits<FormatStyle::IndentExternBlockStyle> { static void enumeration(IO &IO, FormatStyle::IndentExternBlockStyle &Value) { IO.enumCase(Value, "AfterExternBlock", FormatStyle::IEBS_AfterExternBlock); @@ -383,80 +345,80 @@ struct ScalarEnumerationTraits<FormatStyle::IndentExternBlockStyle> { } }; -template <> -struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> { - static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) { - IO.enumCase(Value, "None", FormatStyle::RTBS_None); - IO.enumCase(Value, "All", FormatStyle::RTBS_All); - IO.enumCase(Value, "TopLevel", FormatStyle::RTBS_TopLevel); - IO.enumCase(Value, "TopLevelDefinitions", - FormatStyle::RTBS_TopLevelDefinitions); - IO.enumCase(Value, "AllDefinitions", FormatStyle::RTBS_AllDefinitions); +template <> struct MappingTraits<FormatStyle::IntegerLiteralSeparatorStyle> { + static void mapping(IO &IO, FormatStyle::IntegerLiteralSeparatorStyle &Base) { + IO.mapOptional("Binary", Base.Binary); + IO.mapOptional("Decimal", Base.Decimal); + IO.mapOptional("Hex", Base.Hex); } }; -template <> -struct ScalarEnumerationTraits<FormatStyle::BreakTemplateDeclarationsStyle> { - static void enumeration(IO &IO, - FormatStyle::BreakTemplateDeclarationsStyle &Value) { - IO.enumCase(Value, "No", FormatStyle::BTDS_No); - IO.enumCase(Value, "MultiLine", FormatStyle::BTDS_MultiLine); - IO.enumCase(Value, "Yes", FormatStyle::BTDS_Yes); +template <> struct ScalarEnumerationTraits<FormatStyle::JavaScriptQuoteStyle> { + static void enumeration(IO &IO, FormatStyle::JavaScriptQuoteStyle &Value) { + IO.enumCase(Value, "Leave", FormatStyle::JSQS_Leave); + IO.enumCase(Value, "Single", FormatStyle::JSQS_Single); + IO.enumCase(Value, "Double", FormatStyle::JSQS_Double); + } +}; - // For backward compatibility. - IO.enumCase(Value, "false", FormatStyle::BTDS_MultiLine); - IO.enumCase(Value, "true", FormatStyle::BTDS_Yes); +template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> { + static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) { + IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp); + IO.enumCase(Value, "Java", FormatStyle::LK_Java); + IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript); + IO.enumCase(Value, "ObjC", FormatStyle::LK_ObjC); + IO.enumCase(Value, "Proto", FormatStyle::LK_Proto); + IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen); + IO.enumCase(Value, "TextProto", FormatStyle::LK_TextProto); + IO.enumCase(Value, "CSharp", FormatStyle::LK_CSharp); + IO.enumCase(Value, "Json", FormatStyle::LK_Json); } }; -template <> -struct ScalarEnumerationTraits<FormatStyle::DefinitionReturnTypeBreakingStyle> { - static void - enumeration(IO &IO, FormatStyle::DefinitionReturnTypeBreakingStyle &Value) { - IO.enumCase(Value, "None", FormatStyle::DRTBS_None); - IO.enumCase(Value, "All", FormatStyle::DRTBS_All); - IO.enumCase(Value, "TopLevel", FormatStyle::DRTBS_TopLevel); +template <> struct ScalarEnumerationTraits<FormatStyle::LanguageStandard> { + static void enumeration(IO &IO, FormatStyle::LanguageStandard &Value) { + IO.enumCase(Value, "c++03", FormatStyle::LS_Cpp03); + IO.enumCase(Value, "C++03", FormatStyle::LS_Cpp03); // Legacy alias + IO.enumCase(Value, "Cpp03", FormatStyle::LS_Cpp03); // Legacy alias - // For backward compatibility. - IO.enumCase(Value, "false", FormatStyle::DRTBS_None); - IO.enumCase(Value, "true", FormatStyle::DRTBS_All); + IO.enumCase(Value, "c++11", FormatStyle::LS_Cpp11); + IO.enumCase(Value, "C++11", FormatStyle::LS_Cpp11); // Legacy alias + + IO.enumCase(Value, "c++14", FormatStyle::LS_Cpp14); + IO.enumCase(Value, "c++17", FormatStyle::LS_Cpp17); + IO.enumCase(Value, "c++20", FormatStyle::LS_Cpp20); + + IO.enumCase(Value, "Latest", FormatStyle::LS_Latest); + IO.enumCase(Value, "Cpp11", FormatStyle::LS_Latest); // Legacy alias + IO.enumCase(Value, "Auto", FormatStyle::LS_Auto); } }; template <> -struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> { +struct ScalarEnumerationTraits<FormatStyle::LambdaBodyIndentationKind> { static void enumeration(IO &IO, - FormatStyle::NamespaceIndentationKind &Value) { - IO.enumCase(Value, "None", FormatStyle::NI_None); - IO.enumCase(Value, "Inner", FormatStyle::NI_Inner); - IO.enumCase(Value, "All", FormatStyle::NI_All); + FormatStyle::LambdaBodyIndentationKind &Value) { + IO.enumCase(Value, "Signature", FormatStyle::LBI_Signature); + IO.enumCase(Value, "OuterScope", FormatStyle::LBI_OuterScope); } }; -template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> { - static void enumeration(IO &IO, FormatStyle::BracketAlignmentStyle &Value) { - IO.enumCase(Value, "Align", FormatStyle::BAS_Align); - IO.enumCase(Value, "DontAlign", FormatStyle::BAS_DontAlign); - IO.enumCase(Value, "AlwaysBreak", FormatStyle::BAS_AlwaysBreak); - IO.enumCase(Value, "BlockIndent", FormatStyle::BAS_BlockIndent); - - // For backward compatibility. - IO.enumCase(Value, "true", FormatStyle::BAS_Align); - IO.enumCase(Value, "false", FormatStyle::BAS_DontAlign); +template <> struct ScalarEnumerationTraits<FormatStyle::LineEndingStyle> { + static void enumeration(IO &IO, FormatStyle::LineEndingStyle &Value) { + IO.enumCase(Value, "LF", FormatStyle::LE_LF); + IO.enumCase(Value, "CRLF", FormatStyle::LE_CRLF); + IO.enumCase(Value, "DeriveLF", FormatStyle::LE_DeriveLF); + IO.enumCase(Value, "DeriveCRLF", FormatStyle::LE_DeriveCRLF); } }; template <> -struct ScalarEnumerationTraits<FormatStyle::EscapedNewlineAlignmentStyle> { +struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> { static void enumeration(IO &IO, - FormatStyle::EscapedNewlineAlignmentStyle &Value) { - IO.enumCase(Value, "DontAlign", FormatStyle::ENAS_DontAlign); - IO.enumCase(Value, "Left", FormatStyle::ENAS_Left); - IO.enumCase(Value, "Right", FormatStyle::ENAS_Right); - - // For backward compatibility. - IO.enumCase(Value, "true", FormatStyle::ENAS_Left); - IO.enumCase(Value, "false", FormatStyle::ENAS_Right); + FormatStyle::NamespaceIndentationKind &Value) { + IO.enumCase(Value, "None", FormatStyle::NI_None); + IO.enumCase(Value, "Inner", FormatStyle::NI_Inner); + IO.enumCase(Value, "All", FormatStyle::NI_All); } }; @@ -473,6 +435,17 @@ template <> struct ScalarEnumerationTraits<FormatStyle::OperandAlignmentStyle> { } }; +template <> +struct ScalarEnumerationTraits<FormatStyle::PackConstructorInitializersStyle> { + static void + enumeration(IO &IO, FormatStyle::PackConstructorInitializersStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::PCIS_Never); + IO.enumCase(Value, "BinPack", FormatStyle::PCIS_BinPack); + IO.enumCase(Value, "CurrentLine", FormatStyle::PCIS_CurrentLine); + IO.enumCase(Value, "NextLine", FormatStyle::PCIS_NextLine); + } +}; + template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> { static void enumeration(IO &IO, FormatStyle::PointerAlignmentStyle &Value) { IO.enumCase(Value, "Middle", FormatStyle::PAS_Middle); @@ -486,22 +459,31 @@ template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> { }; template <> -struct ScalarEnumerationTraits<FormatStyle::SeparateDefinitionStyle> { - static void enumeration(IO &IO, FormatStyle::SeparateDefinitionStyle &Value) { - IO.enumCase(Value, "Leave", FormatStyle::SDS_Leave); - IO.enumCase(Value, "Always", FormatStyle::SDS_Always); - IO.enumCase(Value, "Never", FormatStyle::SDS_Never); +struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> { + static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) { + IO.enumCase(Value, "None", FormatStyle::PPDIS_None); + IO.enumCase(Value, "AfterHash", FormatStyle::PPDIS_AfterHash); + IO.enumCase(Value, "BeforeHash", FormatStyle::PPDIS_BeforeHash); } }; template <> -struct ScalarEnumerationTraits<FormatStyle::SpaceAroundPointerQualifiersStyle> { - static void - enumeration(IO &IO, FormatStyle::SpaceAroundPointerQualifiersStyle &Value) { - IO.enumCase(Value, "Default", FormatStyle::SAPQ_Default); - IO.enumCase(Value, "Before", FormatStyle::SAPQ_Before); - IO.enumCase(Value, "After", FormatStyle::SAPQ_After); - IO.enumCase(Value, "Both", FormatStyle::SAPQ_Both); +struct ScalarEnumerationTraits<FormatStyle::QualifierAlignmentStyle> { + static void enumeration(IO &IO, FormatStyle::QualifierAlignmentStyle &Value) { + IO.enumCase(Value, "Leave", FormatStyle::QAS_Leave); + IO.enumCase(Value, "Left", FormatStyle::QAS_Left); + IO.enumCase(Value, "Right", FormatStyle::QAS_Right); + IO.enumCase(Value, "Custom", FormatStyle::QAS_Custom); + } +}; + +template <> struct MappingTraits<FormatStyle::RawStringFormat> { + static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) { + IO.mapOptional("Language", Format.Language); + IO.mapOptional("Delimiters", Format.Delimiters); + IO.mapOptional("EnclosingFunctions", Format.EnclosingFunctions); + IO.mapOptional("CanonicalDelimiter", Format.CanonicalDelimiter); + IO.mapOptional("BasedOnStyle", Format.BasedOnStyle); } }; @@ -527,34 +509,79 @@ struct ScalarEnumerationTraits<FormatStyle::RequiresClausePositionStyle> { }; template <> -struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensStyle> { - static void enumeration(IO &IO, FormatStyle::SpaceBeforeParensStyle &Value) { - IO.enumCase(Value, "Never", FormatStyle::SBPO_Never); - IO.enumCase(Value, "ControlStatements", - FormatStyle::SBPO_ControlStatements); - IO.enumCase(Value, "ControlStatementsExceptControlMacros", - FormatStyle::SBPO_ControlStatementsExceptControlMacros); - IO.enumCase(Value, "NonEmptyParentheses", - FormatStyle::SBPO_NonEmptyParentheses); - IO.enumCase(Value, "Always", FormatStyle::SBPO_Always); - IO.enumCase(Value, "Custom", FormatStyle::SBPO_Custom); +struct ScalarEnumerationTraits<FormatStyle::RequiresExpressionIndentationKind> { + static void + enumeration(IO &IO, FormatStyle::RequiresExpressionIndentationKind &Value) { + IO.enumCase(Value, "Keyword", FormatStyle::REI_Keyword); + IO.enumCase(Value, "OuterScope", FormatStyle::REI_OuterScope); + } +}; - // For backward compatibility. - IO.enumCase(Value, "false", FormatStyle::SBPO_Never); - IO.enumCase(Value, "true", FormatStyle::SBPO_ControlStatements); - IO.enumCase(Value, "ControlStatementsExceptForEachMacros", - FormatStyle::SBPO_ControlStatementsExceptControlMacros); +template <> +struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> { + static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) { + IO.enumCase(Value, "None", FormatStyle::RTBS_None); + IO.enumCase(Value, "All", FormatStyle::RTBS_All); + IO.enumCase(Value, "TopLevel", FormatStyle::RTBS_TopLevel); + IO.enumCase(Value, "TopLevelDefinitions", + FormatStyle::RTBS_TopLevelDefinitions); + IO.enumCase(Value, "AllDefinitions", FormatStyle::RTBS_AllDefinitions); } }; template <> -struct ScalarEnumerationTraits<FormatStyle::BitFieldColonSpacingStyle> { - static void enumeration(IO &IO, - FormatStyle::BitFieldColonSpacingStyle &Value) { - IO.enumCase(Value, "Both", FormatStyle::BFCS_Both); - IO.enumCase(Value, "None", FormatStyle::BFCS_None); - IO.enumCase(Value, "Before", FormatStyle::BFCS_Before); - IO.enumCase(Value, "After", FormatStyle::BFCS_After); +struct ScalarEnumerationTraits<FormatStyle::SeparateDefinitionStyle> { + static void enumeration(IO &IO, FormatStyle::SeparateDefinitionStyle &Value) { + IO.enumCase(Value, "Leave", FormatStyle::SDS_Leave); + IO.enumCase(Value, "Always", FormatStyle::SDS_Always); + IO.enumCase(Value, "Never", FormatStyle::SDS_Never); + } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::ShortBlockStyle> { + static void enumeration(IO &IO, FormatStyle::ShortBlockStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::SBS_Never); + IO.enumCase(Value, "false", FormatStyle::SBS_Never); + IO.enumCase(Value, "Always", FormatStyle::SBS_Always); + IO.enumCase(Value, "true", FormatStyle::SBS_Always); + IO.enumCase(Value, "Empty", FormatStyle::SBS_Empty); + } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> { + static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) { + IO.enumCase(Value, "None", FormatStyle::SFS_None); + IO.enumCase(Value, "false", FormatStyle::SFS_None); + IO.enumCase(Value, "All", FormatStyle::SFS_All); + IO.enumCase(Value, "true", FormatStyle::SFS_All); + IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline); + IO.enumCase(Value, "InlineOnly", FormatStyle::SFS_InlineOnly); + IO.enumCase(Value, "Empty", FormatStyle::SFS_Empty); + } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::ShortIfStyle> { + static void enumeration(IO &IO, FormatStyle::ShortIfStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::SIS_Never); + IO.enumCase(Value, "WithoutElse", FormatStyle::SIS_WithoutElse); + IO.enumCase(Value, "OnlyFirstIf", FormatStyle::SIS_OnlyFirstIf); + IO.enumCase(Value, "AllIfsAndElse", FormatStyle::SIS_AllIfsAndElse); + + // For backward compatibility. + IO.enumCase(Value, "Always", FormatStyle::SIS_OnlyFirstIf); + IO.enumCase(Value, "false", FormatStyle::SIS_Never); + IO.enumCase(Value, "true", FormatStyle::SIS_WithoutElse); + } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::ShortLambdaStyle> { + static void enumeration(IO &IO, FormatStyle::ShortLambdaStyle &Value) { + IO.enumCase(Value, "None", FormatStyle::SLS_None); + IO.enumCase(Value, "false", FormatStyle::SLS_None); + IO.enumCase(Value, "Empty", FormatStyle::SLS_Empty); + IO.enumCase(Value, "Inline", FormatStyle::SLS_Inline); + IO.enumCase(Value, "All", FormatStyle::SLS_All); + IO.enumCase(Value, "true", FormatStyle::SLS_All); } }; @@ -579,6 +606,71 @@ struct ScalarEnumerationTraits<FormatStyle::SortJavaStaticImportOptions> { } }; +template <> +struct ScalarEnumerationTraits<FormatStyle::SortUsingDeclarationsOptions> { + static void enumeration(IO &IO, + FormatStyle::SortUsingDeclarationsOptions &Value) { + IO.enumCase(Value, "Never", FormatStyle::SUD_Never); + IO.enumCase(Value, "Lexicographic", FormatStyle::SUD_Lexicographic); + IO.enumCase(Value, "LexicographicNumeric", + FormatStyle::SUD_LexicographicNumeric); + + // For backward compatibility. + IO.enumCase(Value, "false", FormatStyle::SUD_Never); + IO.enumCase(Value, "true", FormatStyle::SUD_LexicographicNumeric); + } +}; + +template <> +struct ScalarEnumerationTraits<FormatStyle::SpaceAroundPointerQualifiersStyle> { + static void + enumeration(IO &IO, FormatStyle::SpaceAroundPointerQualifiersStyle &Value) { + IO.enumCase(Value, "Default", FormatStyle::SAPQ_Default); + IO.enumCase(Value, "Before", FormatStyle::SAPQ_Before); + IO.enumCase(Value, "After", FormatStyle::SAPQ_After); + IO.enumCase(Value, "Both", FormatStyle::SAPQ_Both); + } +}; + +template <> struct MappingTraits<FormatStyle::SpaceBeforeParensCustom> { + static void mapping(IO &IO, FormatStyle::SpaceBeforeParensCustom &Spacing) { + IO.mapOptional("AfterControlStatements", Spacing.AfterControlStatements); + IO.mapOptional("AfterForeachMacros", Spacing.AfterForeachMacros); + IO.mapOptional("AfterFunctionDefinitionName", + Spacing.AfterFunctionDefinitionName); + IO.mapOptional("AfterFunctionDeclarationName", + Spacing.AfterFunctionDeclarationName); + IO.mapOptional("AfterIfMacros", Spacing.AfterIfMacros); + IO.mapOptional("AfterOverloadedOperator", Spacing.AfterOverloadedOperator); + IO.mapOptional("AfterRequiresInClause", Spacing.AfterRequiresInClause); + IO.mapOptional("AfterRequiresInExpression", + Spacing.AfterRequiresInExpression); + IO.mapOptional("BeforeNonEmptyParentheses", + Spacing.BeforeNonEmptyParentheses); + } +}; + +template <> +struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensStyle> { + static void enumeration(IO &IO, FormatStyle::SpaceBeforeParensStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::SBPO_Never); + IO.enumCase(Value, "ControlStatements", + FormatStyle::SBPO_ControlStatements); + IO.enumCase(Value, "ControlStatementsExceptControlMacros", + FormatStyle::SBPO_ControlStatementsExceptControlMacros); + IO.enumCase(Value, "NonEmptyParentheses", + FormatStyle::SBPO_NonEmptyParentheses); + IO.enumCase(Value, "Always", FormatStyle::SBPO_Always); + IO.enumCase(Value, "Custom", FormatStyle::SBPO_Custom); + + // For backward compatibility. + IO.enumCase(Value, "false", FormatStyle::SBPO_Never); + IO.enumCase(Value, "true", FormatStyle::SBPO_ControlStatements); + IO.enumCase(Value, "ControlStatementsExceptForEachMacros", + FormatStyle::SBPO_ControlStatementsExceptControlMacros); + } +}; + template <> struct ScalarEnumerationTraits<FormatStyle::SpacesInAnglesStyle> { static void enumeration(IO &IO, FormatStyle::SpacesInAnglesStyle &Value) { IO.enumCase(Value, "Never", FormatStyle::SIAS_Never); @@ -591,11 +683,86 @@ template <> struct ScalarEnumerationTraits<FormatStyle::SpacesInAnglesStyle> { } }; +template <> struct MappingTraits<FormatStyle::SpacesInLineComment> { + static void mapping(IO &IO, FormatStyle::SpacesInLineComment &Space) { + // Transform the maximum to signed, to parse "-1" correctly + int signedMaximum = static_cast<int>(Space.Maximum); + IO.mapOptional("Minimum", Space.Minimum); + IO.mapOptional("Maximum", signedMaximum); + Space.Maximum = static_cast<unsigned>(signedMaximum); + + if (Space.Maximum != -1u) + Space.Minimum = std::min(Space.Minimum, Space.Maximum); + } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::TrailingCommaStyle> { + static void enumeration(IO &IO, FormatStyle::TrailingCommaStyle &Value) { + IO.enumCase(Value, "None", FormatStyle::TCS_None); + IO.enumCase(Value, "Wrapped", FormatStyle::TCS_Wrapped); + } +}; + +template <> +struct ScalarEnumerationTraits<FormatStyle::TrailingCommentsAlignmentKinds> { + static void enumeration(IO &IO, + FormatStyle::TrailingCommentsAlignmentKinds &Value) { + IO.enumCase(Value, "Leave", FormatStyle::TCAS_Leave); + IO.enumCase(Value, "Always", FormatStyle::TCAS_Always); + IO.enumCase(Value, "Never", FormatStyle::TCAS_Never); + } +}; + +template <> struct MappingTraits<FormatStyle::TrailingCommentsAlignmentStyle> { + static void enumInput(IO &IO, + FormatStyle::TrailingCommentsAlignmentStyle &Value) { + IO.enumCase(Value, "Leave", + FormatStyle::TrailingCommentsAlignmentStyle( + {FormatStyle::TCAS_Leave, 1})); + + IO.enumCase(Value, "Always", + FormatStyle::TrailingCommentsAlignmentStyle( + {FormatStyle::TCAS_Always, 1})); + + IO.enumCase(Value, "Never", + FormatStyle::TrailingCommentsAlignmentStyle( + {FormatStyle::TCAS_Never, 1})); + + // For backwards compatibility + IO.enumCase(Value, "true", + FormatStyle::TrailingCommentsAlignmentStyle( + {FormatStyle::TCAS_Always, 1})); + IO.enumCase(Value, "false", + FormatStyle::TrailingCommentsAlignmentStyle( + {FormatStyle::TCAS_Never, 1})); + } + + static void mapping(IO &IO, + FormatStyle::TrailingCommentsAlignmentStyle &Value) { + IO.mapOptional("Kind", Value.Kind); + IO.mapOptional("OverEmptyLines", Value.OverEmptyLines); + } +}; + +template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> { + static void enumeration(IO &IO, FormatStyle::UseTabStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::UT_Never); + IO.enumCase(Value, "false", FormatStyle::UT_Never); + IO.enumCase(Value, "Always", FormatStyle::UT_Always); + IO.enumCase(Value, "true", FormatStyle::UT_Always); + IO.enumCase(Value, "ForIndentation", FormatStyle::UT_ForIndentation); + IO.enumCase(Value, "ForContinuationAndIndentation", + FormatStyle::UT_ForContinuationAndIndentation); + IO.enumCase(Value, "AlignWithSpaces", FormatStyle::UT_AlignWithSpaces); + } +}; + template <> struct MappingTraits<FormatStyle> { static void mapping(IO &IO, FormatStyle &Style) { // When reading, read the language first, we need it for getPredefinedStyle. IO.mapOptional("Language", Style.Language); + StringRef BasedOnStyle; if (IO.outputting()) { StringRef Styles[] = {"LLVM", "Google", "Chromium", "Mozilla", "WebKit", "GNU", "Microsoft"}; @@ -604,11 +771,11 @@ template <> struct MappingTraits<FormatStyle> { if (getPredefinedStyle(StyleName, Style.Language, &PredefinedStyle) && Style == PredefinedStyle) { IO.mapOptional("# BasedOnStyle", StyleName); + BasedOnStyle = StyleName; break; } } } else { - StringRef BasedOnStyle; IO.mapOptional("BasedOnStyle", BasedOnStyle); if (!BasedOnStyle.empty()) { FormatStyle::LanguageKind OldLanguage = Style.Language; @@ -622,9 +789,39 @@ template <> struct MappingTraits<FormatStyle> { } } + // Initialize some variables used in the parsing. The using logic is at the + // end. + + // For backward compatibility: + // The default value of ConstructorInitializerAllOnOneLineOrOnePerLine was + // false unless BasedOnStyle was Google or Chromium whereas that of + // AllowAllConstructorInitializersOnNextLine was always true, so the + // equivalent default value of PackConstructorInitializers is PCIS_NextLine + // for Google/Chromium or PCIS_BinPack otherwise. If the deprecated options + // had a non-default value while PackConstructorInitializers has a default + // value, set the latter to an equivalent non-default value if needed. + const bool IsGoogleOrChromium = BasedOnStyle.equals_insensitive("google") || + BasedOnStyle.equals_insensitive("chromium"); + bool OnCurrentLine = IsGoogleOrChromium; + bool OnNextLine = true; + + bool BreakBeforeInheritanceComma = false; + bool BreakConstructorInitializersBeforeComma = false; + + bool DeriveLineEnding = true; + bool UseCRLF = false; + // For backward compatibility. if (!IO.outputting()) { IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlines); + IO.mapOptional("AllowAllConstructorInitializersOnNextLine", OnNextLine); + IO.mapOptional("BreakBeforeInheritanceComma", + BreakBeforeInheritanceComma); + IO.mapOptional("BreakConstructorInitializersBeforeComma", + BreakConstructorInitializersBeforeComma); + IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine", + OnCurrentLine); + IO.mapOptional("DeriveLineEnding", DeriveLineEnding); IO.mapOptional("DerivePointerBinding", Style.DerivePointerAlignment); IO.mapOptional("IndentFunctionDeclarationAfterType", Style.IndentWrappedFunctionNames); @@ -632,6 +829,7 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("PointerBindsToType", Style.PointerAlignment); IO.mapOptional("SpaceAfterControlStatementKeyword", Style.SpaceBeforeParens); + IO.mapOptional("UseCRLF", UseCRLF); } IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset); @@ -651,40 +849,24 @@ template <> struct MappingTraits<FormatStyle> { Style.AllowAllArgumentsOnNextLine); IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine", Style.AllowAllParametersOfDeclarationOnNextLine); - IO.mapOptional("AllowShortEnumsOnASingleLine", - Style.AllowShortEnumsOnASingleLine); IO.mapOptional("AllowShortBlocksOnASingleLine", Style.AllowShortBlocksOnASingleLine); IO.mapOptional("AllowShortCaseLabelsOnASingleLine", Style.AllowShortCaseLabelsOnASingleLine); + IO.mapOptional("AllowShortEnumsOnASingleLine", + Style.AllowShortEnumsOnASingleLine); IO.mapOptional("AllowShortFunctionsOnASingleLine", Style.AllowShortFunctionsOnASingleLine); - IO.mapOptional("AllowShortLambdasOnASingleLine", - Style.AllowShortLambdasOnASingleLine); IO.mapOptional("AllowShortIfStatementsOnASingleLine", Style.AllowShortIfStatementsOnASingleLine); + IO.mapOptional("AllowShortLambdasOnASingleLine", + Style.AllowShortLambdasOnASingleLine); IO.mapOptional("AllowShortLoopsOnASingleLine", Style.AllowShortLoopsOnASingleLine); IO.mapOptional("AlwaysBreakAfterDefinitionReturnType", Style.AlwaysBreakAfterDefinitionReturnType); IO.mapOptional("AlwaysBreakAfterReturnType", Style.AlwaysBreakAfterReturnType); - - // If AlwaysBreakAfterDefinitionReturnType was specified but - // AlwaysBreakAfterReturnType was not, initialize the latter from the - // former for backwards compatibility. - if (Style.AlwaysBreakAfterDefinitionReturnType != FormatStyle::DRTBS_None && - Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) { - if (Style.AlwaysBreakAfterDefinitionReturnType == - FormatStyle::DRTBS_All) { - Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions; - } else if (Style.AlwaysBreakAfterDefinitionReturnType == - FormatStyle::DRTBS_TopLevel) { - Style.AlwaysBreakAfterReturnType = - FormatStyle::RTBS_TopLevelDefinitions; - } - } - IO.mapOptional("AlwaysBreakBeforeMultilineStrings", Style.AlwaysBreakBeforeMultilineStrings); IO.mapOptional("AlwaysBreakTemplateDeclarations", @@ -692,61 +874,32 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("AttributeMacros", Style.AttributeMacros); IO.mapOptional("BinPackArguments", Style.BinPackArguments); IO.mapOptional("BinPackParameters", Style.BinPackParameters); + IO.mapOptional("BitFieldColonSpacing", Style.BitFieldColonSpacing); IO.mapOptional("BraceWrapping", Style.BraceWrapping); + IO.mapOptional("BreakAfterAttributes", Style.BreakAfterAttributes); + IO.mapOptional("BreakAfterJavaFieldAnnotations", + Style.BreakAfterJavaFieldAnnotations); + IO.mapOptional("BreakArrays", Style.BreakArrays); IO.mapOptional("BreakBeforeBinaryOperators", Style.BreakBeforeBinaryOperators); IO.mapOptional("BreakBeforeConceptDeclarations", Style.BreakBeforeConceptDeclarations); IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces); - - bool BreakBeforeInheritanceComma = false; - IO.mapOptional("BreakBeforeInheritanceComma", BreakBeforeInheritanceComma); - IO.mapOptional("BreakInheritanceList", Style.BreakInheritanceList); - // If BreakBeforeInheritanceComma was specified but - // BreakInheritance was not, initialize the latter from the - // former for backwards compatibility. - if (BreakBeforeInheritanceComma && - Style.BreakInheritanceList == FormatStyle::BILS_BeforeColon) { - Style.BreakInheritanceList = FormatStyle::BILS_BeforeComma; - } - + IO.mapOptional("BreakBeforeInlineASMColon", + Style.BreakBeforeInlineASMColon); IO.mapOptional("BreakBeforeTernaryOperators", Style.BreakBeforeTernaryOperators); - - bool BreakConstructorInitializersBeforeComma = false; - IO.mapOptional("BreakConstructorInitializersBeforeComma", - BreakConstructorInitializersBeforeComma); IO.mapOptional("BreakConstructorInitializers", Style.BreakConstructorInitializers); - // If BreakConstructorInitializersBeforeComma was specified but - // BreakConstructorInitializers was not, initialize the latter from the - // former for backwards compatibility. - if (BreakConstructorInitializersBeforeComma && - Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColon) { - Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma; - } - - IO.mapOptional("BreakAfterJavaFieldAnnotations", - Style.BreakAfterJavaFieldAnnotations); + IO.mapOptional("BreakInheritanceList", Style.BreakInheritanceList); IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals); IO.mapOptional("ColumnLimit", Style.ColumnLimit); IO.mapOptional("CommentPragmas", Style.CommentPragmas); - IO.mapOptional("QualifierAlignment", Style.QualifierAlignment); - - // Default Order for Left/Right based Qualifier alignment. - if (Style.QualifierAlignment == FormatStyle::QAS_Right) - Style.QualifierOrder = {"type", "const", "volatile"}; - else if (Style.QualifierAlignment == FormatStyle::QAS_Left) - Style.QualifierOrder = {"const", "volatile", "type"}; - else if (Style.QualifierAlignment == FormatStyle::QAS_Custom) - IO.mapOptional("QualifierOrder", Style.QualifierOrder); - IO.mapOptional("CompactNamespaces", Style.CompactNamespaces); IO.mapOptional("ConstructorInitializerIndentWidth", Style.ConstructorInitializerIndentWidth); IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth); IO.mapOptional("Cpp11BracedListStyle", Style.Cpp11BracedListStyle); - IO.mapOptional("DeriveLineEnding", Style.DeriveLineEnding); IO.mapOptional("DerivePointerAlignment", Style.DerivePointerAlignment); IO.mapOptional("DisableFormat", Style.DisableFormat); IO.mapOptional("EmptyLineAfterAccessModifier", @@ -755,68 +908,35 @@ template <> struct MappingTraits<FormatStyle> { Style.EmptyLineBeforeAccessModifier); IO.mapOptional("ExperimentalAutoDetectBinPacking", Style.ExperimentalAutoDetectBinPacking); - - IO.mapOptional("PackConstructorInitializers", - Style.PackConstructorInitializers); - // For backward compatibility: - // The default value of ConstructorInitializerAllOnOneLineOrOnePerLine was - // false unless BasedOnStyle was Google or Chromium whereas that of - // AllowAllConstructorInitializersOnNextLine was always true, so the - // equivalent default value of PackConstructorInitializers is PCIS_NextLine - // for Google/Chromium or PCIS_BinPack otherwise. If the deprecated options - // had a non-default value while PackConstructorInitializers has a default - // value, set the latter to an equivalent non-default value if needed. - StringRef BasedOn; - IO.mapOptional("BasedOnStyle", BasedOn); - const bool IsGoogleOrChromium = BasedOn.equals_insensitive("google") || - BasedOn.equals_insensitive("chromium"); - bool OnCurrentLine = IsGoogleOrChromium; - bool OnNextLine = true; - IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine", - OnCurrentLine); - IO.mapOptional("AllowAllConstructorInitializersOnNextLine", OnNextLine); - if (!IsGoogleOrChromium) { - if (Style.PackConstructorInitializers == FormatStyle::PCIS_BinPack && - OnCurrentLine) { - Style.PackConstructorInitializers = OnNextLine - ? FormatStyle::PCIS_NextLine - : FormatStyle::PCIS_CurrentLine; - } - } else if (Style.PackConstructorInitializers == - FormatStyle::PCIS_NextLine) { - if (!OnCurrentLine) - Style.PackConstructorInitializers = FormatStyle::PCIS_BinPack; - else if (!OnNextLine) - Style.PackConstructorInitializers = FormatStyle::PCIS_CurrentLine; - } - IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments); IO.mapOptional("ForEachMacros", Style.ForEachMacros); IO.mapOptional("IfMacros", Style.IfMacros); - IO.mapOptional("IncludeBlocks", Style.IncludeStyle.IncludeBlocks); IO.mapOptional("IncludeCategories", Style.IncludeStyle.IncludeCategories); IO.mapOptional("IncludeIsMainRegex", Style.IncludeStyle.IncludeIsMainRegex); IO.mapOptional("IncludeIsMainSourceRegex", Style.IncludeStyle.IncludeIsMainSourceRegex); IO.mapOptional("IndentAccessModifiers", Style.IndentAccessModifiers); - IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); IO.mapOptional("IndentCaseBlocks", Style.IndentCaseBlocks); + IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); + IO.mapOptional("IndentExternBlock", Style.IndentExternBlock); IO.mapOptional("IndentGotoLabels", Style.IndentGotoLabels); IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives); - IO.mapOptional("IndentExternBlock", Style.IndentExternBlock); IO.mapOptional("IndentRequiresClause", Style.IndentRequiresClause); IO.mapOptional("IndentWidth", Style.IndentWidth); IO.mapOptional("IndentWrappedFunctionNames", Style.IndentWrappedFunctionNames); IO.mapOptional("InsertBraces", Style.InsertBraces); + IO.mapOptional("InsertNewlineAtEOF", Style.InsertNewlineAtEOF); IO.mapOptional("InsertTrailingCommas", Style.InsertTrailingCommas); + IO.mapOptional("IntegerLiteralSeparator", Style.IntegerLiteralSeparator); IO.mapOptional("JavaImportGroups", Style.JavaImportGroups); IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes); IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports); IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks", Style.KeepEmptyLinesAtTheStartOfBlocks); IO.mapOptional("LambdaBodyIndentation", Style.LambdaBodyIndentation); + IO.mapOptional("LineEnding", Style.LineEnding); IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin); IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd); IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep); @@ -829,6 +949,8 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty); IO.mapOptional("ObjCSpaceBeforeProtocolList", Style.ObjCSpaceBeforeProtocolList); + IO.mapOptional("PackConstructorInitializers", + Style.PackConstructorInitializers); IO.mapOptional("PenaltyBreakAssignment", Style.PenaltyBreakAssignment); IO.mapOptional("PenaltyBreakBeforeFirstCallParameter", Style.PenaltyBreakBeforeFirstCallParameter); @@ -841,17 +963,28 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("PenaltyBreakTemplateDeclaration", Style.PenaltyBreakTemplateDeclaration); IO.mapOptional("PenaltyExcessCharacter", Style.PenaltyExcessCharacter); - IO.mapOptional("PenaltyReturnTypeOnItsOwnLine", - Style.PenaltyReturnTypeOnItsOwnLine); IO.mapOptional("PenaltyIndentedWhitespace", Style.PenaltyIndentedWhitespace); + IO.mapOptional("PenaltyReturnTypeOnItsOwnLine", + Style.PenaltyReturnTypeOnItsOwnLine); IO.mapOptional("PointerAlignment", Style.PointerAlignment); IO.mapOptional("PPIndentWidth", Style.PPIndentWidth); + IO.mapOptional("QualifierAlignment", Style.QualifierAlignment); + // Default Order for Left/Right based Qualifier alignment. + if (Style.QualifierAlignment == FormatStyle::QAS_Right) + Style.QualifierOrder = {"type", "const", "volatile"}; + else if (Style.QualifierAlignment == FormatStyle::QAS_Left) + Style.QualifierOrder = {"const", "volatile", "type"}; + else if (Style.QualifierAlignment == FormatStyle::QAS_Custom) + IO.mapOptional("QualifierOrder", Style.QualifierOrder); IO.mapOptional("RawStringFormats", Style.RawStringFormats); IO.mapOptional("ReferenceAlignment", Style.ReferenceAlignment); IO.mapOptional("ReflowComments", Style.ReflowComments); IO.mapOptional("RemoveBracesLLVM", Style.RemoveBracesLLVM); + IO.mapOptional("RemoveSemicolon", Style.RemoveSemicolon); IO.mapOptional("RequiresClausePosition", Style.RequiresClausePosition); + IO.mapOptional("RequiresExpressionIndentation", + Style.RequiresExpressionIndentation); IO.mapOptional("SeparateDefinitionBlocks", Style.SeparateDefinitionBlocks); IO.mapOptional("ShortNamespaceLines", Style.ShortNamespaceLines); IO.mapOptional("SortIncludes", Style.SortIncludes); @@ -861,6 +994,8 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("SpaceAfterLogicalNot", Style.SpaceAfterLogicalNot); IO.mapOptional("SpaceAfterTemplateKeyword", Style.SpaceAfterTemplateKeyword); + IO.mapOptional("SpaceAroundPointerQualifiers", + Style.SpaceAroundPointerQualifiers); IO.mapOptional("SpaceBeforeAssignmentOperators", Style.SpaceBeforeAssignmentOperators); IO.mapOptional("SpaceBeforeCaseColon", Style.SpaceBeforeCaseColon); @@ -872,10 +1007,10 @@ template <> struct MappingTraits<FormatStyle> { Style.SpaceBeforeInheritanceColon); IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens); IO.mapOptional("SpaceBeforeParensOptions", Style.SpaceBeforeParensOptions); - IO.mapOptional("SpaceAroundPointerQualifiers", - Style.SpaceAroundPointerQualifiers); IO.mapOptional("SpaceBeforeRangeBasedForLoopColon", Style.SpaceBeforeRangeBasedForLoopColon); + IO.mapOptional("SpaceBeforeSquareBrackets", + Style.SpaceBeforeSquareBrackets); IO.mapOptional("SpaceInEmptyBlock", Style.SpaceInEmptyBlock); IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses); IO.mapOptional("SpacesBeforeTrailingComments", @@ -891,83 +1026,67 @@ template <> struct MappingTraits<FormatStyle> { Style.SpacesInLineCommentPrefix); IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses); IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets); - IO.mapOptional("SpaceBeforeSquareBrackets", - Style.SpaceBeforeSquareBrackets); - IO.mapOptional("BitFieldColonSpacing", Style.BitFieldColonSpacing); IO.mapOptional("Standard", Style.Standard); IO.mapOptional("StatementAttributeLikeMacros", Style.StatementAttributeLikeMacros); IO.mapOptional("StatementMacros", Style.StatementMacros); IO.mapOptional("TabWidth", Style.TabWidth); IO.mapOptional("TypenameMacros", Style.TypenameMacros); - IO.mapOptional("UseCRLF", Style.UseCRLF); IO.mapOptional("UseTab", Style.UseTab); IO.mapOptional("WhitespaceSensitiveMacros", Style.WhitespaceSensitiveMacros); - } -}; -template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> { - static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) { - IO.mapOptional("AfterCaseLabel", Wrapping.AfterCaseLabel); - IO.mapOptional("AfterClass", Wrapping.AfterClass); - IO.mapOptional("AfterControlStatement", Wrapping.AfterControlStatement); - IO.mapOptional("AfterEnum", Wrapping.AfterEnum); - IO.mapOptional("AfterFunction", Wrapping.AfterFunction); - IO.mapOptional("AfterNamespace", Wrapping.AfterNamespace); - IO.mapOptional("AfterObjCDeclaration", Wrapping.AfterObjCDeclaration); - IO.mapOptional("AfterStruct", Wrapping.AfterStruct); - IO.mapOptional("AfterUnion", Wrapping.AfterUnion); - IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock); - IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch); - IO.mapOptional("BeforeElse", Wrapping.BeforeElse); - IO.mapOptional("BeforeLambdaBody", Wrapping.BeforeLambdaBody); - IO.mapOptional("BeforeWhile", Wrapping.BeforeWhile); - IO.mapOptional("IndentBraces", Wrapping.IndentBraces); - IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction); - IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord); - IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace); - } -}; + // If AlwaysBreakAfterDefinitionReturnType was specified but + // AlwaysBreakAfterReturnType was not, initialize the latter from the + // former for backwards compatibility. + if (Style.AlwaysBreakAfterDefinitionReturnType != FormatStyle::DRTBS_None && + Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) { + if (Style.AlwaysBreakAfterDefinitionReturnType == + FormatStyle::DRTBS_All) { + Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions; + } else if (Style.AlwaysBreakAfterDefinitionReturnType == + FormatStyle::DRTBS_TopLevel) { + Style.AlwaysBreakAfterReturnType = + FormatStyle::RTBS_TopLevelDefinitions; + } + } -template <> struct MappingTraits<FormatStyle::SpaceBeforeParensCustom> { - static void mapping(IO &IO, FormatStyle::SpaceBeforeParensCustom &Spacing) { - IO.mapOptional("AfterControlStatements", Spacing.AfterControlStatements); - IO.mapOptional("AfterForeachMacros", Spacing.AfterForeachMacros); - IO.mapOptional("AfterFunctionDefinitionName", - Spacing.AfterFunctionDefinitionName); - IO.mapOptional("AfterFunctionDeclarationName", - Spacing.AfterFunctionDeclarationName); - IO.mapOptional("AfterIfMacros", Spacing.AfterIfMacros); - IO.mapOptional("AfterOverloadedOperator", Spacing.AfterOverloadedOperator); - IO.mapOptional("AfterRequiresInClause", Spacing.AfterRequiresInClause); - IO.mapOptional("AfterRequiresInExpression", - Spacing.AfterRequiresInExpression); - IO.mapOptional("BeforeNonEmptyParentheses", - Spacing.BeforeNonEmptyParentheses); - } -}; + // If BreakBeforeInheritanceComma was specified but BreakInheritance was + // not, initialize the latter from the former for backwards compatibility. + if (BreakBeforeInheritanceComma && + Style.BreakInheritanceList == FormatStyle::BILS_BeforeColon) { + Style.BreakInheritanceList = FormatStyle::BILS_BeforeComma; + } -template <> struct MappingTraits<FormatStyle::RawStringFormat> { - static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) { - IO.mapOptional("Language", Format.Language); - IO.mapOptional("Delimiters", Format.Delimiters); - IO.mapOptional("EnclosingFunctions", Format.EnclosingFunctions); - IO.mapOptional("CanonicalDelimiter", Format.CanonicalDelimiter); - IO.mapOptional("BasedOnStyle", Format.BasedOnStyle); - } -}; + // If BreakConstructorInitializersBeforeComma was specified but + // BreakConstructorInitializers was not, initialize the latter from the + // former for backwards compatibility. + if (BreakConstructorInitializersBeforeComma && + Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColon) { + Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma; + } -template <> struct MappingTraits<FormatStyle::SpacesInLineComment> { - static void mapping(IO &IO, FormatStyle::SpacesInLineComment &Space) { - // Transform the maximum to signed, to parse "-1" correctly - int signedMaximum = static_cast<int>(Space.Maximum); - IO.mapOptional("Minimum", Space.Minimum); - IO.mapOptional("Maximum", signedMaximum); - Space.Maximum = static_cast<unsigned>(signedMaximum); + if (!IsGoogleOrChromium) { + if (Style.PackConstructorInitializers == FormatStyle::PCIS_BinPack && + OnCurrentLine) { + Style.PackConstructorInitializers = OnNextLine + ? FormatStyle::PCIS_NextLine + : FormatStyle::PCIS_CurrentLine; + } + } else if (Style.PackConstructorInitializers == + FormatStyle::PCIS_NextLine) { + if (!OnCurrentLine) + Style.PackConstructorInitializers = FormatStyle::PCIS_BinPack; + else if (!OnNextLine) + Style.PackConstructorInitializers = FormatStyle::PCIS_CurrentLine; + } - if (Space.Maximum != -1u) - Space.Minimum = std::min(Space.Minimum, Space.Maximum); + if (Style.LineEnding == FormatStyle::LE_DeriveLF) { + if (!DeriveLineEnding) + Style.LineEnding = UseCRLF ? FormatStyle::LE_CRLF : FormatStyle::LE_LF; + else if (UseCRLF) + Style.LineEnding = FormatStyle::LE_DeriveCRLF; + } } }; @@ -1181,7 +1300,6 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align; LLVMStyle.AlignArrayOfStructures = FormatStyle::AIAS_None; LLVMStyle.AlignOperands = FormatStyle::OAS_Align; - LLVMStyle.AlignTrailingComments = true; LLVMStyle.AlignConsecutiveAssignments = {}; LLVMStyle.AlignConsecutiveAssignments.Enabled = false; LLVMStyle.AlignConsecutiveAssignments.AcrossEmptyLines = false; @@ -1191,12 +1309,15 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.AlignConsecutiveBitFields = {}; LLVMStyle.AlignConsecutiveDeclarations = {}; LLVMStyle.AlignConsecutiveMacros = {}; + LLVMStyle.AlignTrailingComments = {}; + LLVMStyle.AlignTrailingComments.Kind = FormatStyle::TCAS_Always; + LLVMStyle.AlignTrailingComments.OverEmptyLines = 0; LLVMStyle.AllowAllArgumentsOnNextLine = true; LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true; - LLVMStyle.AllowShortEnumsOnASingleLine = true; - LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All; LLVMStyle.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never; LLVMStyle.AllowShortCaseLabelsOnASingleLine = false; + LLVMStyle.AllowShortEnumsOnASingleLine = true; + LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All; LLVMStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; LLVMStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_All; LLVMStyle.AllowShortLoopsOnASingleLine = false; @@ -1205,12 +1326,9 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { 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.BreakBeforeBinaryOperators = FormatStyle::BOS_None; - LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always; - LLVMStyle.BreakBeforeTernaryOperators = true; - LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; LLVMStyle.BraceWrapping = {/*AfterCaseLabel=*/false, /*AfterClass=*/false, /*AfterControlStatement=*/FormatStyle::BWACS_Never, @@ -1229,8 +1347,14 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { /*SplitEmptyFunction=*/true, /*SplitEmptyRecord=*/true, /*SplitEmptyNamespace=*/true}; - LLVMStyle.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; + LLVMStyle.BreakAfterAttributes = FormatStyle::ABS_Never; LLVMStyle.BreakAfterJavaFieldAnnotations = false; + LLVMStyle.BreakArrays = true; + LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None; + LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; + LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always; + LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline; + LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon; LLVMStyle.BreakStringLiterals = true; @@ -1240,16 +1364,11 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.ConstructorInitializerIndentWidth = 4; LLVMStyle.ContinuationIndentWidth = 4; LLVMStyle.Cpp11BracedListStyle = true; - - // Off by default Qualifier ordering - LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave; - - LLVMStyle.DeriveLineEnding = true; LLVMStyle.DerivePointerAlignment = false; + LLVMStyle.DisableFormat = false; LLVMStyle.EmptyLineAfterAccessModifier = FormatStyle::ELAAMS_Never; LLVMStyle.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_LogicalBlock; LLVMStyle.ExperimentalAutoDetectBinPacking = false; - LLVMStyle.PackConstructorInitializers = FormatStyle::PCIS_BinPack; LLVMStyle.FixNamespaceComments = true; LLVMStyle.ForEachMacros.push_back("foreach"); LLVMStyle.ForEachMacros.push_back("Q_FOREACH"); @@ -1264,44 +1383,43 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.IndentAccessModifiers = false; LLVMStyle.IndentCaseLabels = false; LLVMStyle.IndentCaseBlocks = false; + LLVMStyle.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; LLVMStyle.IndentGotoLabels = true; LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None; LLVMStyle.IndentRequiresClause = true; - LLVMStyle.IndentWrappedFunctionNames = false; LLVMStyle.IndentWidth = 2; - LLVMStyle.PPIndentWidth = -1; + LLVMStyle.IndentWrappedFunctionNames = false; LLVMStyle.InsertBraces = false; + LLVMStyle.InsertNewlineAtEOF = false; LLVMStyle.InsertTrailingCommas = FormatStyle::TCS_None; + LLVMStyle.IntegerLiteralSeparator = {/*Binary=*/0, /*Decimal=*/0, /*Hex=*/0}; LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave; LLVMStyle.JavaScriptWrapImports = true; - LLVMStyle.TabWidth = 8; + LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true; LLVMStyle.LambdaBodyIndentation = FormatStyle::LBI_Signature; + LLVMStyle.LineEnding = FormatStyle::LE_DeriveLF; LLVMStyle.MaxEmptyLinesToKeep = 1; - LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true; LLVMStyle.NamespaceIndentation = FormatStyle::NI_None; LLVMStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Auto; LLVMStyle.ObjCBlockIndentWidth = 2; LLVMStyle.ObjCBreakBeforeNestedBlockParam = true; LLVMStyle.ObjCSpaceAfterProperty = false; LLVMStyle.ObjCSpaceBeforeProtocolList = true; + LLVMStyle.PackConstructorInitializers = FormatStyle::PCIS_BinPack; LLVMStyle.PointerAlignment = FormatStyle::PAS_Right; + LLVMStyle.PPIndentWidth = -1; + LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave; LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer; + LLVMStyle.ReflowComments = true; + LLVMStyle.RemoveBracesLLVM = false; + LLVMStyle.RemoveSemicolon = false; LLVMStyle.RequiresClausePosition = FormatStyle::RCPS_OwnLine; + LLVMStyle.RequiresExpressionIndentation = FormatStyle::REI_OuterScope; LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave; LLVMStyle.ShortNamespaceLines = 1; - LLVMStyle.SpacesBeforeTrailingComments = 1; - LLVMStyle.Standard = FormatStyle::LS_Latest; - LLVMStyle.UseCRLF = false; - LLVMStyle.UseTab = FormatStyle::UT_Never; - LLVMStyle.ReflowComments = true; - LLVMStyle.RemoveBracesLLVM = false; - LLVMStyle.SpacesInParentheses = false; - LLVMStyle.SpacesInSquareBrackets = false; - LLVMStyle.SpaceInEmptyBlock = false; - LLVMStyle.SpaceInEmptyParentheses = false; - LLVMStyle.SpacesInContainerLiterals = true; - LLVMStyle.SpacesInCStyleCastParentheses = false; - LLVMStyle.SpacesInLineCommentPrefix = {/*Minimum=*/1, /*Maximum=*/-1u}; + LLVMStyle.SortIncludes = FormatStyle::SI_CaseSensitive; + LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before; + LLVMStyle.SortUsingDeclarations = FormatStyle::SUD_LexicographicNumeric; LLVMStyle.SpaceAfterCStyleCast = false; LLVMStyle.SpaceAfterLogicalNot = false; LLVMStyle.SpaceAfterTemplateKeyword = true; @@ -1318,9 +1436,27 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SpaceBeforeAssignmentOperators = true; LLVMStyle.SpaceBeforeCpp11BracedList = false; LLVMStyle.SpaceBeforeSquareBrackets = false; - LLVMStyle.BitFieldColonSpacing = FormatStyle::BFCS_Both; + LLVMStyle.SpaceInEmptyBlock = false; + LLVMStyle.SpaceInEmptyParentheses = false; + LLVMStyle.SpacesBeforeTrailingComments = 1; LLVMStyle.SpacesInAngles = FormatStyle::SIAS_Never; + LLVMStyle.SpacesInContainerLiterals = true; + LLVMStyle.SpacesInCStyleCastParentheses = false; + LLVMStyle.SpacesInLineCommentPrefix = {/*Minimum=*/1, /*Maximum=*/-1u}; + LLVMStyle.SpacesInParentheses = false; + LLVMStyle.SpacesInSquareBrackets = false; LLVMStyle.SpacesInConditionalStatement = false; + LLVMStyle.Standard = FormatStyle::LS_Latest; + LLVMStyle.StatementAttributeLikeMacros.push_back("Q_EMIT"); + LLVMStyle.StatementMacros.push_back("Q_UNUSED"); + LLVMStyle.StatementMacros.push_back("QT_REQUIRE_VERSION"); + LLVMStyle.TabWidth = 8; + LLVMStyle.UseTab = FormatStyle::UT_Never; + LLVMStyle.WhitespaceSensitiveMacros.push_back("BOOST_PP_STRINGIZE"); + LLVMStyle.WhitespaceSensitiveMacros.push_back("CF_SWIFT_NAME"); + LLVMStyle.WhitespaceSensitiveMacros.push_back("NS_SWIFT_NAME"); + LLVMStyle.WhitespaceSensitiveMacros.push_back("PP_STRINGIZE"); + LLVMStyle.WhitespaceSensitiveMacros.push_back("STRINGIZE"); LLVMStyle.PenaltyBreakAssignment = prec::Assignment; LLVMStyle.PenaltyBreakComment = 300; @@ -1333,24 +1469,20 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.PenaltyBreakTemplateDeclaration = prec::Relational; LLVMStyle.PenaltyIndentedWhitespace = 0; - LLVMStyle.DisableFormat = false; - LLVMStyle.SortIncludes = FormatStyle::SI_CaseSensitive; - LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before; - LLVMStyle.SortUsingDeclarations = true; - LLVMStyle.StatementAttributeLikeMacros.push_back("Q_EMIT"); - LLVMStyle.StatementMacros.push_back("Q_UNUSED"); - LLVMStyle.StatementMacros.push_back("QT_REQUIRE_VERSION"); - LLVMStyle.WhitespaceSensitiveMacros.push_back("STRINGIZE"); - LLVMStyle.WhitespaceSensitiveMacros.push_back("PP_STRINGIZE"); - LLVMStyle.WhitespaceSensitiveMacros.push_back("BOOST_PP_STRINGIZE"); - LLVMStyle.WhitespaceSensitiveMacros.push_back("NS_SWIFT_NAME"); - LLVMStyle.WhitespaceSensitiveMacros.push_back("CF_SWIFT_NAME"); - // Defaults that differ when not C++. - if (Language == FormatStyle::LK_TableGen) + switch (Language) { + case FormatStyle::LK_TableGen: LLVMStyle.SpacesInContainerLiterals = false; - if (LLVMStyle.isJson()) + break; + case FormatStyle::LK_Json: LLVMStyle.ColumnLimit = 0; + break; + case FormatStyle::LK_Verilog: + LLVMStyle.IndentCaseLabels = true; + break; + default: + break; + } return LLVMStyle; } @@ -1438,7 +1570,8 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { if (Language == FormatStyle::LK_Java) { GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign; GoogleStyle.AlignOperands = FormatStyle::OAS_DontAlign; - GoogleStyle.AlignTrailingComments = false; + GoogleStyle.AlignTrailingComments = {}; + GoogleStyle.AlignTrailingComments.Kind = FormatStyle::TCAS_Never; GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; GoogleStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; GoogleStyle.AlwaysBreakBeforeMultilineStrings = false; @@ -1586,7 +1719,8 @@ FormatStyle getWebKitStyle() { Style.AccessModifierOffset = -4; Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign; Style.AlignOperands = FormatStyle::OAS_DontAlign; - Style.AlignTrailingComments = false; + Style.AlignTrailingComments = {}; + Style.AlignTrailingComments.Kind = FormatStyle::TCAS_Never; Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty; Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; Style.BreakBeforeBraces = FormatStyle::BS_WebKit; @@ -1653,7 +1787,7 @@ FormatStyle getNoStyle() { FormatStyle NoStyle = getLLVMStyle(); NoStyle.DisableFormat = true; NoStyle.SortIncludes = FormatStyle::SI_Never; - NoStyle.SortUsingDeclarations = false; + NoStyle.SortUsingDeclarations = FormatStyle::SUD_Never; return NoStyle; } @@ -1710,9 +1844,7 @@ ParseError validateQualifierOrder(FormatStyle *Style) { } // Ensure the list has 'type' in it. - auto type = std::find(Style->QualifierOrder.begin(), - Style->QualifierOrder.end(), "type"); - if (type == Style->QualifierOrder.end()) + if (!llvm::is_contained(Style->QualifierOrder, "type")) return ParseError::MissingQualifierType; return ParseError::Success; @@ -1798,13 +1930,13 @@ std::string configurationAsText(const FormatStyle &Style) { return Stream.str(); } -llvm::Optional<FormatStyle> +std::optional<FormatStyle> FormatStyle::FormatStyleSet::Get(FormatStyle::LanguageKind Language) const { if (!Styles) - return None; + return std::nullopt; auto It = Styles->find(Language); if (It == Styles->end()) - return None; + return std::nullopt; FormatStyle Style = It->second; Style.StyleSet = *this; return Style; @@ -1823,7 +1955,7 @@ void FormatStyle::FormatStyleSet::Add(FormatStyle Style) { void FormatStyle::FormatStyleSet::Clear() { Styles.reset(); } -llvm::Optional<FormatStyle> +std::optional<FormatStyle> FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const { return StyleSet.Get(Language); } @@ -1833,9 +1965,7 @@ namespace { class BracesInserter : public TokenAnalyzer { public: BracesInserter(const Environment &Env, const FormatStyle &Style) - : TokenAnalyzer(Env, Style) { - this->Style.RemoveBracesLLVM = false; - } + : TokenAnalyzer(Env, Style) {} std::pair<tooling::Replacements, unsigned> analyze(TokenAnnotator &Annotator, @@ -1851,35 +1981,44 @@ private: void insertBraces(SmallVectorImpl<AnnotatedLine *> &Lines, tooling::Replacements &Result) { const auto &SourceMgr = Env.getSourceManager(); + int OpeningBraceSurplus = 0; for (AnnotatedLine *Line : Lines) { insertBraces(Line->Children, Result); - if (!Line->Affected) + if (!Line->Affected && OpeningBraceSurplus == 0) continue; for (FormatToken *Token = Line->First; Token && !Token->Finalized; Token = Token->Next) { - if (Token->BraceCount == 0) + int BraceCount = Token->BraceCount; + if (BraceCount == 0) continue; std::string Brace; - if (Token->BraceCount < 0) { - assert(Token->BraceCount == -1); - Brace = '{'; + if (BraceCount < 0) { + assert(BraceCount == -1); + if (!Line->Affected) + break; + Brace = Token->is(tok::comment) ? "\n{" : "{"; + ++OpeningBraceSurplus; } else { - Brace = '\n' + std::string(Token->BraceCount, '}'); + if (OpeningBraceSurplus == 0) + break; + if (OpeningBraceSurplus < BraceCount) + BraceCount = OpeningBraceSurplus; + Brace = '\n' + std::string(BraceCount, '}'); + OpeningBraceSurplus -= BraceCount; } Token->BraceCount = 0; const auto Start = Token->Tok.getEndLoc(); cantFail(Result.add(tooling::Replacement(SourceMgr, Start, 0, Brace))); } } + assert(OpeningBraceSurplus == 0); } }; class BracesRemover : public TokenAnalyzer { public: BracesRemover(const Environment &Env, const FormatStyle &Style) - : TokenAnalyzer(Env, Style) { - this->Style.InsertBraces = false; - } + : TokenAnalyzer(Env, Style) {} std::pair<tooling::Replacements, unsigned> analyze(TokenAnnotator &Annotator, @@ -1895,31 +2034,85 @@ private: void removeBraces(SmallVectorImpl<AnnotatedLine *> &Lines, tooling::Replacements &Result) { const auto &SourceMgr = Env.getSourceManager(); - bool EndsWithComment = false; - for (AnnotatedLine *Line : Lines) { + const auto End = Lines.end(); + for (auto I = Lines.begin(); I != End; ++I) { + const auto Line = *I; removeBraces(Line->Children, Result); - if (Line->Affected) { - for (FormatToken *Token = Line->First; Token && !Token->Finalized; - Token = Token->Next) { - if (!Token->Optional) - continue; - assert(Token->isOneOf(tok::l_brace, tok::r_brace)); - assert(Token->Previous || Token == Line->First); - const FormatToken *Next = Token->Next; - assert(Next || Token == Line->Last); - const auto Start = - (!Token->Previous && EndsWithComment) || - (Next && !(Next->isOneOf(tok::kw_else, tok::comment) && - Next->NewlinesBefore > 0)) - ? Token->Tok.getLocation() - : Token->WhitespaceRange.getBegin(); - const auto Range = - CharSourceRange::getCharRange(Start, Token->Tok.getEndLoc()); - cantFail(Result.add(tooling::Replacement(SourceMgr, Range, ""))); + if (!Line->Affected) + continue; + 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->isOneOf(tok::l_brace, tok::r_brace)) + continue; + auto Next = Token->Next; + assert(Next || Token == Line->Last); + if (!Next && NextLine) + Next = NextLine->First; + SourceLocation Start; + if (Next && Next->NewlinesBefore == 0 && Next->isNot(tok::eof)) { + Start = Token->Tok.getLocation(); + Next->WhitespaceRange = Token->WhitespaceRange; + } else { + Start = Token->WhitespaceRange.getBegin(); } + const auto Range = + CharSourceRange::getCharRange(Start, Token->Tok.getEndLoc()); + cantFail(Result.add(tooling::Replacement(SourceMgr, Range, ""))); + } + } + } +}; + +class SemiRemover : public TokenAnalyzer { +public: + SemiRemover(const Environment &Env, const FormatStyle &Style) + : TokenAnalyzer(Env, Style) {} + + std::pair<tooling::Replacements, unsigned> + analyze(TokenAnnotator &Annotator, + SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, + FormatTokenLexer &Tokens) override { + AffectedRangeMgr.computeAffectedLines(AnnotatedLines); + tooling::Replacements Result; + removeSemi(AnnotatedLines, Result); + return {Result, 0}; + } + +private: + void removeSemi(SmallVectorImpl<AnnotatedLine *> &Lines, + tooling::Replacements &Result) { + 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); + if (!Line->Affected) + continue; + 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)) + continue; + auto Next = Token->Next; + assert(Next || Token == Line->Last); + if (!Next && NextLine) + Next = NextLine->First; + SourceLocation Start; + if (Next && Next->NewlinesBefore == 0 && Next->isNot(tok::eof)) { + Start = Token->Tok.getLocation(); + Next->WhitespaceRange = Token->WhitespaceRange; + } else { + Start = Token->WhitespaceRange.getBegin(); + } + const auto Range = + CharSourceRange::getCharRange(Start, Token->Tok.getEndLoc()); + cantFail(Result.add(tooling::Replacement(SourceMgr, Range, ""))); } - assert(Line->Last); - EndsWithComment = Line->Last->is(tok::comment); } } }; @@ -2031,11 +2224,11 @@ public: WhitespaceManager Whitespaces( Env.getSourceManager(), Style, - Style.DeriveLineEnding + Style.LineEnding > FormatStyle::LE_CRLF ? WhitespaceManager::inputUsesCRLF( Env.getSourceManager().getBufferData(Env.getFileID()), - Style.UseCRLF) - : Style.UseCRLF); + Style.LineEnding == FormatStyle::LE_DeriveCRLF) + : Style.LineEnding == FormatStyle::LE_CRLF); ContinuationIndenter Indenter(Style, Tokens.getKeywords(), Env.getSourceManager(), Whitespaces, Encoding, BinPackInconclusiveFunctions); @@ -2123,9 +2316,11 @@ private: } } if (Style.DerivePointerAlignment) { - Style.PointerAlignment = countVariableAlignments(AnnotatedLines) <= 0 - ? FormatStyle::PAS_Left - : FormatStyle::PAS_Right; + const auto NetRightCount = countVariableAlignments(AnnotatedLines); + if (NetRightCount > 0) + Style.PointerAlignment = FormatStyle::PAS_Right; + else if (NetRightCount < 0) + Style.PointerAlignment = FormatStyle::PAS_Left; Style.ReferenceAlignment = FormatStyle::RAS_Pointer; } if (Style.Standard == FormatStyle::LS_Auto) { @@ -2533,7 +2728,7 @@ private: "UIView", }; - for (auto Line : AnnotatedLines) { + for (auto *Line : AnnotatedLines) { if (Line->First && (Line->First->TokenText.startswith("#") || Line->First->TokenText == "__pragma" || Line->First->TokenText == "_Pragma")) { @@ -2758,13 +2953,6 @@ static void sortCppIncludes(const FormatStyle &Style, } } -namespace { - -const char CppIncludeRegexPattern[] = - R"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))"; - -} // anonymous namespace - tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code, ArrayRef<tooling::Range> Ranges, StringRef FileName, @@ -2774,7 +2962,6 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code, .StartsWith("\xEF\xBB\xBF", 3) // UTF-8 BOM .Default(0); unsigned SearchFrom = 0; - llvm::Regex IncludeRegex(CppIncludeRegexPattern); SmallVector<StringRef, 4> Matches; SmallVector<IncludeDirective, 16> IncludesInBlock; @@ -2831,7 +3018,7 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code, bool MergeWithNextLine = Trimmed.endswith("\\"); if (!FormattingOff && !MergeWithNextLine) { - if (IncludeRegex.match(Line, &Matches)) { + if (tooling::HeaderIncludes::IncludeRegex.match(Line, &Matches)) { StringRef IncludeName = Matches[2]; if (Line.contains("/*") && !Line.contains("*/")) { // #include with a start of a block comment, but without the end. @@ -3109,8 +3296,8 @@ namespace { inline bool isHeaderInsertion(const tooling::Replacement &Replace) { return Replace.getOffset() == UINT_MAX && Replace.getLength() == 0 && - llvm::Regex(CppIncludeRegexPattern) - .match(Replace.getReplacementText()); + tooling::HeaderIncludes::IncludeRegex.match( + Replace.getReplacementText()); } inline bool isHeaderDeletion(const tooling::Replacement &Replace) { @@ -3162,17 +3349,18 @@ fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces, } } - llvm::Regex IncludeRegex = llvm::Regex(CppIncludeRegexPattern); llvm::SmallVector<StringRef, 4> Matches; for (const auto &R : HeaderInsertions) { auto IncludeDirective = R.getReplacementText(); - bool Matched = IncludeRegex.match(IncludeDirective, &Matches); + bool Matched = + tooling::HeaderIncludes::IncludeRegex.match(IncludeDirective, &Matches); assert(Matched && "Header insertion replacement must have replacement text " "'#include ...'"); (void)Matched; auto IncludeName = Matches[2]; auto Replace = - Includes.insert(IncludeName.trim("\"<>"), IncludeName.startswith("<")); + Includes.insert(IncludeName.trim("\"<>"), IncludeName.startswith("<"), + tooling::IncludeDirective::Include); if (Replace) { auto Err = Result.add(*Replace); if (Err) { @@ -3203,7 +3391,7 @@ cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces, // Make header insertion replacements insert new headers into correct blocks. tooling::Replacements NewReplaces = fixCppIncludeInsertions(Code, Replaces, Style); - return processReplacements(Cleanup, Code, NewReplaces, Style); + return cantFail(processReplacements(Cleanup, Code, NewReplaces, Style)); } namespace internal { @@ -3215,6 +3403,9 @@ reformat(const FormatStyle &Style, StringRef Code, FormatStyle Expanded = Style; expandPresetsBraceWrapping(Expanded); expandPresetsSpaceBeforeParens(Expanded); + Expanded.InsertBraces = false; + Expanded.RemoveBracesLLVM = false; + Expanded.RemoveSemicolon = false; switch (Expanded.RequiresClausePosition) { case FormatStyle::RCPS_SingleLine: case FormatStyle::RCPS_WithPreceding: @@ -3250,11 +3441,20 @@ reformat(const FormatStyle &Style, StringRef Code, return {tooling::Replacements(), 0}; } + auto Env = Environment::make(Code, FileName, Ranges, FirstStartColumn, + NextStartColumn, LastStartColumn); + if (!Env) + return {}; + typedef std::function<std::pair<tooling::Replacements, unsigned>( const Environment &)> AnalyzerPass; SmallVector<AnalyzerPass, 8> Passes; + Passes.emplace_back([&](const Environment &Env) { + return IntegerLiteralSeparatorFixer().process(Env, Expanded); + }); + if (Style.isCpp()) { if (Style.QualifierAlignment != FormatStyle::QAS_Leave) { Passes.emplace_back([&](const Environment &Env) { @@ -3266,14 +3466,26 @@ reformat(const FormatStyle &Style, StringRef Code, } if (Style.InsertBraces) { - Passes.emplace_back([&](const Environment &Env) { - return BracesInserter(Env, Expanded).process(); + FormatStyle S = Expanded; + S.InsertBraces = true; + Passes.emplace_back([&, S](const Environment &Env) { + return BracesInserter(Env, S).process(/*SkipAnnotation=*/true); }); } if (Style.RemoveBracesLLVM) { - Passes.emplace_back([&](const Environment &Env) { - return BracesRemover(Env, Expanded).process(); + FormatStyle S = Expanded; + S.RemoveBracesLLVM = true; + Passes.emplace_back([&, S](const Environment &Env) { + return BracesRemover(Env, S).process(/*SkipAnnotation=*/true); + }); + } + + if (Style.RemoveSemicolon) { + FormatStyle S = Expanded; + S.RemoveSemicolon = true; + Passes.emplace_back([&, S](const Environment &Env) { + return SemiRemover(Env, S).process(/*SkipAnnotation=*/true); }); } @@ -3283,7 +3495,7 @@ reformat(const FormatStyle &Style, StringRef Code, }); } - if (Style.SortUsingDeclarations) { + if (Style.SortUsingDeclarations != FormatStyle::SUD_Never) { Passes.emplace_back([&](const Environment &Env) { return UsingDeclarationsSorter(Env, Expanded).process(); }); @@ -3299,7 +3511,7 @@ reformat(const FormatStyle &Style, StringRef Code, if (Style.isJavaScript() && Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) { Passes.emplace_back([&](const Environment &Env) { - return JavaScriptRequoter(Env, Expanded).process(); + return JavaScriptRequoter(Env, Expanded).process(/*SkipAnnotation=*/true); }); } @@ -3314,11 +3526,7 @@ reformat(const FormatStyle &Style, StringRef Code, }); } - auto Env = Environment::make(Code, FileName, Ranges, FirstStartColumn, - NextStartColumn, LastStartColumn); - if (!Env) - return {}; - llvm::Optional<std::string> CurrentCode = None; + std::optional<std::string> CurrentCode; tooling::Replacements Fixes; unsigned Penalty = 0; for (size_t I = 0, E = Passes.size(); I < E; ++I) { diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp index 832af463206c..f9f0d712bc16 100644 --- a/clang/lib/Format/FormatToken.cpp +++ b/clang/lib/Format/FormatToken.cpp @@ -56,7 +56,8 @@ bool FormatToken::isSimpleTypeSpecifier() const { case tok::kw___ibm128: case tok::kw_wchar_t: case tok::kw_bool: - case tok::kw___underlying_type: +#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: diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 73e32979853f..9d055efd8007 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -20,6 +20,7 @@ #include "clang/Format/Format.h" #include "clang/Lex/Lexer.h" #include <memory> +#include <optional> #include <unordered_set> namespace clang { @@ -39,7 +40,10 @@ namespace format { TYPE(CastRParen) \ TYPE(ClassLBrace) \ TYPE(CompoundRequirementLBrace) \ + /* ternary ?: expression */ \ TYPE(ConditionalExpr) \ + /* the condition in an if statement */ \ + TYPE(ConditionLParen) \ TYPE(ConflictAlternative) \ TYPE(ConflictEnd) \ TYPE(ConflictStart) \ @@ -67,6 +71,11 @@ namespace format { TYPE(FunctionLBrace) \ TYPE(FunctionLikeOrFreestandingMacro) \ TYPE(FunctionTypeLParen) \ + /* The colons as part of a C11 _Generic selection */ \ + TYPE(GenericSelectionColon) \ + /* The colon at the end of a goto label or a case label. Currently only used \ + * for Verilog. */ \ + TYPE(GotoLabelColon) \ TYPE(IfMacro) \ TYPE(ImplicitStringLiteral) \ TYPE(InheritanceColon) \ @@ -135,6 +144,16 @@ namespace format { TYPE(UnaryOperator) \ TYPE(UnionLBrace) \ TYPE(UntouchableMacroFunc) \ + /* like in begin : block */ \ + TYPE(VerilogBlockLabelColon) \ + /* The square bracket for the dimension part of the type name. \ + * In 'logic [1:0] x[1:0]', only the first '['. This way we can have space \ + * before the first bracket but not the second. */ \ + TYPE(VerilogDimensionedTypeName) \ + /* for the base in a number literal, not including the quote */ \ + TYPE(VerilogNumberBase) \ + /* Things inside the table in user-defined primitives. */ \ + TYPE(VerilogTableItem) \ TYPE(Unknown) /// Determines the semantic type of a syntactic token, e.g. whether "<" is a @@ -231,7 +250,8 @@ struct FormatToken { CanBreakBefore(false), ClosesTemplateDeclaration(false), StartsBinaryExpression(false), EndsBinaryExpression(false), PartOfMultiVariableDeclStmt(false), ContinuesLineCommentSection(false), - Finalized(false), ClosesRequiresClause(false), BlockKind(BK_Unknown), + Finalized(false), ClosesRequiresClause(false), + EndsCppAttributeGroup(false), BlockKind(BK_Unknown), Decision(FD_Unformatted), PackingKind(PPK_Inconclusive), TypeIsFinalized(false), Type(TT_Unknown) {} @@ -302,6 +322,9 @@ struct FormatToken { /// \c true if this is the last token within requires clause. unsigned ClosesRequiresClause : 1; + /// \c true if this token ends a group of C++ attributes. + unsigned EndsCppAttributeGroup : 1; + private: /// Contains the kind of block if this token is a brace. unsigned BlockKind : 2; @@ -368,6 +391,9 @@ public: } bool isTypeFinalized() const { return TypeIsFinalized; } + /// Used to set an operator precedence explicitly. + prec::Level ForcedPrecedence = prec::Unknown; + /// The number of newlines immediately before the \c Token. /// /// This can be used to determine what the user wrote in the original code @@ -495,7 +521,7 @@ public: // Contains all attributes related to how this token takes part // in a configured macro expansion. - llvm::Optional<MacroExpansion> MacroCtx; + std::optional<MacroExpansion> MacroCtx; /// When macro expansion introduces nodes with children, those are marked as /// \c MacroParent. @@ -565,8 +591,12 @@ public: } bool isAccessSpecifier(bool ColonRequired = true) const { - return isOneOf(tok::kw_public, tok::kw_protected, tok::kw_private) && - (!ColonRequired || (Next && Next->is(tok::colon))); + if (!isOneOf(tok::kw_public, tok::kw_protected, tok::kw_private)) + return false; + if (!ColonRequired) + return true; + const auto NextNonComment = getNextNonComment(); + return NextNonComment && NextNonComment->is(tok::colon); } bool canBePointerOrReferenceQualifier() const { @@ -577,9 +607,9 @@ public: } /// Determine whether the token is a simple-type-specifier. - LLVM_NODISCARD bool isSimpleTypeSpecifier() const; + [[nodiscard]] bool isSimpleTypeSpecifier() const; - LLVM_NODISCARD bool isTypeOrIdentifier() const; + [[nodiscard]] bool isTypeOrIdentifier() const; bool isObjCAccessSpecifier() const { return is(tok::at) && Next && @@ -658,7 +688,8 @@ public: case tok::kw_static_assert: case tok::kw__Atomic: case tok::kw___attribute: - case tok::kw___underlying_type: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: +#include "clang/Basic/TransformTypeTraits.def" case tok::kw_requires: return true; default: @@ -697,12 +728,14 @@ public: } prec::Level getPrecedence() const { + if (ForcedPrecedence != prec::Unknown) + return ForcedPrecedence; return getBinOpPrecedence(Tok.getKind(), /*GreaterThanIsOperator=*/true, /*CPlusPlus11=*/true); } /// Returns the previous token ignoring comments. - LLVM_NODISCARD FormatToken *getPreviousNonComment() const { + [[nodiscard]] FormatToken *getPreviousNonComment() const { FormatToken *Tok = Previous; while (Tok && Tok->is(tok::comment)) Tok = Tok->Previous; @@ -710,7 +743,7 @@ public: } /// Returns the next token ignoring comments. - LLVM_NODISCARD const FormatToken *getNextNonComment() const { + [[nodiscard]] const FormatToken *getNextNonComment() const { const FormatToken *Tok = Next; while (Tok && Tok->is(tok::comment)) Tok = Tok->Next; @@ -719,7 +752,7 @@ public: /// Returns \c true if this tokens starts a block-type list, i.e. a /// list that should be indented with a block indent. - LLVM_NODISCARD bool opensBlockOrBlockTypeList(const FormatStyle &Style) const; + [[nodiscard]] bool opensBlockOrBlockTypeList(const FormatStyle &Style) const; /// Returns whether the token is the left square bracket of a C++ /// structured binding declaration. @@ -988,6 +1021,7 @@ struct AdditionalKeywords { kw_when = &IdentTable.get("when"); kw_where = &IdentTable.get("where"); + // Verilog keywords kw_always = &IdentTable.get("always"); kw_always_comb = &IdentTable.get("always_comb"); kw_always_ff = &IdentTable.get("always_ff"); @@ -1119,6 +1153,7 @@ struct AdditionalKeywords { // Symbols that are treated as keywords. kw_verilogHash = &IdentTable.get("#"); kw_verilogHashHash = &IdentTable.get("##"); + kw_apostrophe = &IdentTable.get("\'"); // Keep this at the end of the constructor to make sure everything here // is @@ -1511,11 +1546,14 @@ struct AdditionalKeywords { IdentifierInfo *kw_verilogHash; IdentifierInfo *kw_verilogHashHash; + // Symbols in Verilog that don't exist in C++. + IdentifierInfo *kw_apostrophe; + /// Returns \c true if \p Tok is a keyword or an identifier. bool isWordLike(const FormatToken &Tok) const { // getIdentifierinfo returns non-null for keywords as well as identifiers. return Tok.Tok.getIdentifierInfo() != nullptr && - !Tok.isOneOf(kw_verilogHash, kw_verilogHashHash); + !Tok.isOneOf(kw_verilogHash, kw_verilogHashHash, kw_apostrophe); } /// Returns \c true if \p Tok is a true JavaScript identifier, returns @@ -1644,6 +1682,11 @@ struct AdditionalKeywords { } } + bool isVerilogWordOperator(const FormatToken &Tok) const { + return Tok.isOneOf(kw_before, kw_intersect, kw_dist, kw_iff, kw_inside, + kw_with); + } + bool isVerilogIdentifier(const FormatToken &Tok) const { switch (Tok.Tok.getKind()) { case tok::kw_case: @@ -1724,10 +1767,29 @@ struct AdditionalKeywords { kw_join_any, kw_join_none); } - /// Whether the token begins a block. - bool isBlockBegin(const FormatToken &Tok, const FormatStyle &Style) const { - return Tok.is(TT_MacroBlockBegin) || - (Style.isVerilog() ? isVerilogBegin(Tok) : Tok.is(tok::l_brace)); + /// Returns whether \p Tok is a Verilog keyword that opens a module, etc. + bool isVerilogHierarchy(const FormatToken &Tok) const { + if (Tok.endsSequence(kw_function, kw_with)) + return false; + if (Tok.is(kw_property)) { + const FormatToken *Prev = Tok.getPreviousNonComment(); + return !(Prev && + Prev->isOneOf(tok::kw_restrict, kw_assert, kw_assume, kw_cover)); + } + return Tok.isOneOf(tok::kw_case, tok::kw_class, kw_function, kw_module, + kw_interface, kw_package, kw_casex, kw_casez, kw_checker, + kw_clocking, kw_covergroup, kw_macromodule, kw_primitive, + kw_program, kw_property, kw_randcase, kw_randsequence, + kw_task); + } + + bool isVerilogEndOfLabel(const FormatToken &Tok) const { + const FormatToken *Next = Tok.getNextNonComment(); + // In Verilog the colon in a default label is optional. + return Tok.is(TT_GotoLabelColon) || + (Tok.is(tok::kw_default) && + !(Next && Next->isOneOf(tok::colon, tok::semi, kw_clocking, kw_iff, + kw_input, kw_output, kw_sequence))); } private: diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index 3f9b68ccbb39..f8f5f7112188 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -193,6 +193,78 @@ void FormatTokenLexer::tryMergePreviousTokens() { if (tryMergeTokens(JavaRightLogicalShiftAssign, TT_BinaryOperator)) return; } + + if (Style.isVerilog()) { + // Merge the number following a base like `'h?a0`. + if (Tokens.size() >= 3 && Tokens.end()[-3]->is(TT_VerilogNumberBase) && + Tokens.end()[-2]->is(tok::numeric_constant) && + Tokens.back()->isOneOf(tok::numeric_constant, tok::identifier, + tok::question) && + tryMergeTokens(2, TT_Unknown)) { + return; + } + // Part select. + if (tryMergeTokensAny({{tok::minus, tok::colon}, {tok::plus, tok::colon}}, + TT_BitFieldColon)) { + return; + } + // Xnor. The combined token is treated as a caret which can also be either a + // unary or binary operator. The actual type is determined in + // TokenAnnotator. We also check the token length so we know it is not + // already a merged token. + if (Tokens.back()->TokenText.size() == 1 && + tryMergeTokensAny({{tok::caret, tok::tilde}, {tok::tilde, tok::caret}}, + TT_BinaryOperator)) { + Tokens.back()->Tok.setKind(tok::caret); + return; + } + // Signed shift and distribution weight. + if (tryMergeTokens({tok::less, tok::less}, TT_BinaryOperator)) { + Tokens.back()->Tok.setKind(tok::lessless); + return; + } + if (tryMergeTokens({tok::greater, tok::greater}, TT_BinaryOperator)) { + Tokens.back()->Tok.setKind(tok::greatergreater); + return; + } + if (tryMergeTokensAny({{tok::lessless, tok::equal}, + {tok::lessless, tok::lessequal}, + {tok::greatergreater, tok::equal}, + {tok::greatergreater, tok::greaterequal}, + {tok::colon, tok::equal}, + {tok::colon, tok::slash}}, + TT_BinaryOperator)) { + Tokens.back()->ForcedPrecedence = prec::Assignment; + return; + } + // Exponentiation, signed shift, case equality, and wildcard equality. + if (tryMergeTokensAny({{tok::star, tok::star}, + {tok::lessless, tok::less}, + {tok::greatergreater, tok::greater}, + {tok::exclaimequal, tok::equal}, + {tok::exclaimequal, tok::question}, + {tok::equalequal, tok::equal}, + {tok::equalequal, tok::question}}, + TT_BinaryOperator)) { + return; + } + // Module paths in specify blocks and implications in properties. + if (tryMergeTokensAny({{tok::plusequal, tok::greater}, + {tok::plus, tok::star, tok::greater}, + {tok::minusequal, tok::greater}, + {tok::minus, tok::star, tok::greater}, + {tok::less, tok::arrow}, + {tok::equal, tok::greater}, + {tok::star, tok::greater}, + {tok::pipeequal, tok::greater}, + {tok::pipe, tok::arrow}, + {tok::hash, tok::minus, tok::hash}, + {tok::hash, tok::equal, tok::hash}}, + TT_BinaryOperator)) { + Tokens.back()->ForcedPrecedence = prec::Comma; + return; + } + } } bool FormatTokenLexer::tryMergeNSStringLiteral() { @@ -240,36 +312,32 @@ bool FormatTokenLexer::tryMergeCSharpStringLiteral() { return false; // Look for @"aaaaaa" or $"aaaaaa". - auto &String = *(Tokens.end() - 1); - if (!String->is(tok::string_literal)) + const auto String = *(Tokens.end() - 1); + if (String->isNot(tok::string_literal)) return false; - auto &At = *(Tokens.end() - 2); - if (!(At->is(tok::at) || At->TokenText == "$")) + auto Prefix = *(Tokens.end() - 2); + if (Prefix->isNot(tok::at) && Prefix->TokenText != "$") return false; - if (Tokens.size() > 2 && At->is(tok::at)) { - auto &Dollar = *(Tokens.end() - 3); - if (Dollar->TokenText == "$") { - // This looks like $@"aaaaa" so we need to combine all 3 tokens. - Dollar->Tok.setKind(tok::string_literal); - Dollar->TokenText = - StringRef(Dollar->TokenText.begin(), - String->TokenText.end() - Dollar->TokenText.begin()); - Dollar->ColumnWidth += (At->ColumnWidth + String->ColumnWidth); - Dollar->setType(TT_CSharpStringLiteral); + if (Tokens.size() > 2) { + const auto Tok = *(Tokens.end() - 3); + if ((Tok->TokenText == "$" && Prefix->is(tok::at)) || + (Tok->is(tok::at) && Prefix->TokenText == "$")) { + // This looks like $@"aaa" or @$"aaa" so we need to combine all 3 tokens. + Tok->ColumnWidth += Prefix->ColumnWidth; Tokens.erase(Tokens.end() - 2); - Tokens.erase(Tokens.end() - 1); - return true; + Prefix = Tok; } } // Convert back into just a string_literal. - At->Tok.setKind(tok::string_literal); - At->TokenText = StringRef(At->TokenText.begin(), - String->TokenText.end() - At->TokenText.begin()); - At->ColumnWidth += String->ColumnWidth; - At->setType(TT_CSharpStringLiteral); + Prefix->Tok.setKind(tok::string_literal); + Prefix->TokenText = + StringRef(Prefix->TokenText.begin(), + String->TokenText.end() - Prefix->TokenText.begin()); + Prefix->ColumnWidth += String->ColumnWidth; + Prefix->setType(TT_CSharpStringLiteral); Tokens.erase(Tokens.end() - 1); return true; } @@ -303,9 +371,11 @@ bool FormatTokenLexer::tryMergeNullishCoalescingEqual() { bool FormatTokenLexer::tryMergeCSharpKeywordVariables() { if (Tokens.size() < 2) return false; - auto &At = *(Tokens.end() - 2); - auto &Keyword = *(Tokens.end() - 1); - if (!At->is(tok::at)) + const auto At = *(Tokens.end() - 2); + if (At->isNot(tok::at)) + return false; + const auto Keyword = *(Tokens.end() - 1); + if (Keyword->TokenText == "$") return false; if (!Keywords.isCSharpKeyword(*Keyword)) return false; @@ -412,15 +482,28 @@ bool FormatTokenLexer::tryMergeTokens(ArrayRef<tok::TokenKind> Kinds, SmallVectorImpl<FormatToken *>::const_iterator First = Tokens.end() - Kinds.size(); - if (!First[0]->is(Kinds[0])) + for (unsigned i = 0; i < Kinds.size(); ++i) + if (!First[i]->is(Kinds[i])) + return false; + + return tryMergeTokens(Kinds.size(), NewType); +} + +bool FormatTokenLexer::tryMergeTokens(size_t Count, TokenType NewType) { + if (Tokens.size() < Count) return false; + + SmallVectorImpl<FormatToken *>::const_iterator First = Tokens.end() - Count; unsigned AddLength = 0; - for (unsigned i = 1; i < Kinds.size(); ++i) { - if (!First[i]->is(Kinds[i]) || First[i]->hasWhitespaceBefore()) + for (size_t i = 1; i < Count; ++i) { + // If there is whitespace separating the token and the previous one, + // they should not be merged. + if (First[i]->hasWhitespaceBefore()) return false; AddLength += First[i]->TokenText.size(); } - Tokens.resize(Tokens.size() - Kinds.size() + 1); + + Tokens.resize(Tokens.size() - Count + 1); First[0]->TokenText = StringRef(First[0]->TokenText.data(), First[0]->TokenText.size() + AddLength); First[0]->ColumnWidth += AddLength; @@ -428,6 +511,13 @@ bool FormatTokenLexer::tryMergeTokens(ArrayRef<tok::TokenKind> Kinds, return true; } +bool FormatTokenLexer::tryMergeTokensAny( + ArrayRef<ArrayRef<tok::TokenKind>> Kinds, TokenType NewType) { + return llvm::any_of(Kinds, [this, NewType](ArrayRef<tok::TokenKind> Kinds) { + return tryMergeTokens(Kinds, NewType); + }); +} + // Returns \c true if \p Tok can only be followed by an operand in JavaScript. bool FormatTokenLexer::precedesOperand(FormatToken *Tok) { // NB: This is not entirely correct, as an r_paren can introduce an operand @@ -591,7 +681,7 @@ void FormatTokenLexer::handleCSharpVerbatimAndInterpolatedStrings() { bool Verbatim = false; bool Interpolated = false; - if (TokenText.startswith(R"($@")")) { + if (TokenText.startswith(R"($@")") || TokenText.startswith(R"(@$")")) { Verbatim = true; Interpolated = true; } else if (TokenText.startswith(R"(@")")) { @@ -670,6 +760,7 @@ void FormatTokenLexer::handleTemplateStrings() { for (; Offset != Lex->getBuffer().end(); ++Offset) { if (Offset[0] == '`') { StateStack.pop(); + ++Offset; break; } if (Offset[0] == '\\') { @@ -678,12 +769,12 @@ void FormatTokenLexer::handleTemplateStrings() { Offset[1] == '{') { // '${' introduces an expression interpolation in the template string. StateStack.push(LexerState::NORMAL); - ++Offset; + Offset += 2; break; } } - StringRef LiteralText(TmplBegin, Offset - TmplBegin + 1); + StringRef LiteralText(TmplBegin, Offset - TmplBegin); BacktickToken->setType(TT_TemplateString); BacktickToken->Tok.setKind(tok::string_literal); BacktickToken->TokenText = LiteralText; @@ -704,9 +795,7 @@ void FormatTokenLexer::handleTemplateStrings() { StartColumn, Style.TabWidth, Encoding); } - SourceLocation loc = Offset < Lex->getBuffer().end() - ? Lex->getSourceLocation(Offset + 1) - : SourceMgr.getLocForEndOfFile(ID); + SourceLocation loc = Lex->getSourceLocation(Offset); resetLexer(SourceMgr.getFileOffset(loc)); } @@ -935,7 +1024,7 @@ FormatToken *FormatTokenLexer::getNextToken() { // the same as a single LF. if (i + 1 < e && Text[i + 1] == '\n') break; - LLVM_FALLTHROUGH; + [[fallthrough]]; case '\n': ++FormatTok->NewlinesBefore; if (!InEscape) @@ -1004,12 +1093,19 @@ FormatToken *FormatTokenLexer::getNextToken() { } if (Style.isVerilog()) { + static const llvm::Regex NumberBase("^s?[bdho]", llvm::Regex::IgnoreCase); + SmallVector<StringRef, 1> Matches; // Verilog uses the backtick instead of the hash for preprocessor stuff. // And it uses the hash for delays and parameter lists. In order to continue // using `tok::hash` in other places, the backtick gets marked as the hash // here. And in order to tell the backtick and hash apart for // Verilog-specific stuff, the hash becomes an identifier. - if (FormatTok->isOneOf(tok::hash, tok::hashhash)) { + if (FormatTok->is(tok::numeric_constant)) { + // In Verilog the quote is not part of a number. + auto Quote = FormatTok->TokenText.find('\''); + if (Quote != StringRef::npos) + truncateToken(Quote); + } else if (FormatTok->isOneOf(tok::hash, tok::hashhash)) { FormatTok->Tok.setKind(tok::raw_identifier); } else if (FormatTok->is(tok::raw_identifier)) { if (FormatTok->TokenText == "`") { @@ -1018,6 +1114,15 @@ FormatToken *FormatTokenLexer::getNextToken() { } else if (FormatTok->TokenText == "``") { FormatTok->Tok.setIdentifierInfo(nullptr); FormatTok->Tok.setKind(tok::hashhash); + } else if (Tokens.size() > 0 && + Tokens.back()->is(Keywords.kw_apostrophe) && + NumberBase.match(FormatTok->TokenText, &Matches)) { + // In Verilog in a based number literal like `'b10`, there may be + // whitespace between `'b` and `10`. Therefore we handle the base and + // the rest of the number literal as two tokens. But if there is no + // space in the input code, we need to manually separate the two parts. + truncateToken(Matches[0].size()); + FormatTok->setFinalizedType(TT_VerilogNumberBase); } } } @@ -1060,6 +1165,13 @@ FormatToken *FormatTokenLexer::getNextToken() { StateStack.push(LexerState::TOKEN_STASHED); } + if (Style.isVerilog() && Tokens.size() > 0 && + Tokens.back()->is(TT_VerilogNumberBase) && + FormatTok->Tok.isOneOf(tok::identifier, tok::question)) { + // Mark the number following a base like `'h?a0` as a number. + FormatTok->Tok.setKind(tok::numeric_constant); + } + // Now FormatTok is the next non-whitespace token. StringRef Text = FormatTok->TokenText; diff --git a/clang/lib/Format/FormatTokenLexer.h b/clang/lib/Format/FormatTokenLexer.h index bff2c181d81e..950305a37d68 100644 --- a/clang/lib/Format/FormatTokenLexer.h +++ b/clang/lib/Format/FormatTokenLexer.h @@ -60,7 +60,14 @@ private: bool tryMergeForEach(); bool tryTransformTryUsageForC(); + // Merge the most recently lexed tokens into a single token if their kinds are + // correct. bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds, TokenType NewType); + // Merge without checking their kinds. + bool tryMergeTokens(size_t Count, TokenType NewType); + // Merge if their kinds match any one of Kinds. + bool tryMergeTokensAny(ArrayRef<ArrayRef<tok::TokenKind>> Kinds, + TokenType NewType); // Returns \c true if \p Tok can only be followed by an operand in JavaScript. bool precedesOperand(FormatToken *Tok); diff --git a/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp b/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp new file mode 100644 index 000000000000..ef07ab06760b --- /dev/null +++ b/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp @@ -0,0 +1,199 @@ +//===--- IntegerLiteralSeparatorFixer.cpp -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements IntegerLiteralSeparatorFixer that fixes C++ integer +/// literal separators. +/// +//===----------------------------------------------------------------------===// + +#include "IntegerLiteralSeparatorFixer.h" + +namespace clang { +namespace format { + +enum class Base { Binary, Decimal, Hex, Other }; + +static Base getBase(const StringRef IntegerLiteral) { + assert(IntegerLiteral.size() > 1); + + if (IntegerLiteral[0] > '0') { + assert(IntegerLiteral[0] <= '9'); + return Base::Decimal; + } + + assert(IntegerLiteral[0] == '0'); + + switch (IntegerLiteral[1]) { + case 'b': + case 'B': + return Base::Binary; + case 'x': + case 'X': + return Base::Hex; + default: + return Base::Other; + } +} + +std::pair<tooling::Replacements, unsigned> +IntegerLiteralSeparatorFixer::process(const Environment &Env, + const FormatStyle &Style) { + switch (Style.Language) { + case FormatStyle::LK_Cpp: + case FormatStyle::LK_ObjC: + Separator = '\''; + break; + case FormatStyle::LK_CSharp: + case FormatStyle::LK_Java: + case FormatStyle::LK_JavaScript: + Separator = '_'; + break; + default: + return {}; + } + + const auto &Option = Style.IntegerLiteralSeparator; + const auto Binary = Option.Binary; + const auto Decimal = Option.Decimal; + const auto Hex = Option.Hex; + const bool SkipBinary = Binary == 0; + const bool SkipDecimal = Decimal == 0; + const bool SkipHex = Hex == 0; + + if (SkipBinary && SkipDecimal && SkipHex) + return {}; + + const auto &SourceMgr = Env.getSourceManager(); + AffectedRangeManager AffectedRangeMgr(SourceMgr, Env.getCharRanges()); + + const auto ID = Env.getFileID(); + const auto LangOpts = getFormattingLangOpts(Style); + Lexer Lex(ID, SourceMgr.getBufferOrFake(ID), SourceMgr, LangOpts); + Lex.SetCommentRetentionState(true); + + Token Tok; + tooling::Replacements Result; + + for (bool Skip = false; !Lex.LexFromRawLexer(Tok);) { + auto Length = Tok.getLength(); + if (Length < 2) + continue; + auto Location = Tok.getLocation(); + auto Text = StringRef(SourceMgr.getCharacterData(Location), Length); + if (Tok.is(tok::comment)) { + if (Text == "// clang-format off" || Text == "/* clang-format off */") + Skip = true; + else if (Text == "// clang-format on" || Text == "/* clang-format on */") + Skip = false; + continue; + } + if (Skip || Tok.isNot(tok::numeric_constant) || Text[0] == '.' || + !AffectedRangeMgr.affectsCharSourceRange( + CharSourceRange::getCharRange(Location, Tok.getEndLoc()))) { + continue; + } + const auto B = getBase(Text); + const bool IsBase2 = B == Base::Binary; + const bool IsBase10 = B == Base::Decimal; + const bool IsBase16 = B == Base::Hex; + if ((IsBase2 && SkipBinary) || (IsBase10 && SkipDecimal) || + (IsBase16 && SkipHex) || B == Base::Other) { + continue; + } + if ((IsBase10 && Text.find_last_of(".eEfFdDmM") != StringRef::npos) || + (IsBase16 && Text.find_last_of(".pP") != StringRef::npos)) { + continue; + } + if (((IsBase2 && Binary < 0) || (IsBase10 && Decimal < 0) || + (IsBase16 && Hex < 0)) && + Text.find(Separator) == StringRef::npos) { + continue; + } + const auto Start = Text[0] == '0' ? 2 : 0; + auto End = Text.find_first_of("uUlLzZn"); + if (End == StringRef::npos) + End = Length; + if (Start > 0 || End < Length) { + Length = End - Start; + Text = Text.substr(Start, Length); + } + auto DigitsPerGroup = Decimal; + if (IsBase2) + DigitsPerGroup = Binary; + else if (IsBase16) + DigitsPerGroup = Hex; + if (DigitsPerGroup > 0 && checkSeparator(Text, DigitsPerGroup)) + continue; + if (Start > 0) + Location = Location.getLocWithOffset(Start); + cantFail(Result.add(tooling::Replacement(SourceMgr, Location, Length, + format(Text, DigitsPerGroup)))); + } + + return {Result, 0}; +} + +bool IntegerLiteralSeparatorFixer::checkSeparator( + const StringRef IntegerLiteral, int DigitsPerGroup) const { + assert(DigitsPerGroup > 0); + + int I = 0; + for (auto C : llvm::reverse(IntegerLiteral)) { + if (C == Separator) { + if (I < DigitsPerGroup) + return false; + I = 0; + } else { + ++I; + if (I == DigitsPerGroup) + return false; + } + } + + return true; +} + +std::string IntegerLiteralSeparatorFixer::format(const StringRef IntegerLiteral, + int DigitsPerGroup) const { + assert(DigitsPerGroup != 0); + + std::string Formatted; + + if (DigitsPerGroup < 0) { + for (auto C : IntegerLiteral) + if (C != Separator) + Formatted.push_back(C); + return Formatted; + } + + int DigitCount = 0; + for (auto C : IntegerLiteral) + if (C != Separator) + ++DigitCount; + + int Remainder = DigitCount % DigitsPerGroup; + + int I = 0; + for (auto C : IntegerLiteral) { + if (C == Separator) + continue; + if (I == (Remainder > 0 ? Remainder : DigitsPerGroup)) { + Formatted.push_back(Separator); + I = 0; + Remainder = 0; + } + Formatted.push_back(C); + ++I; + } + + return Formatted; +} + +} // namespace format +} // namespace clang diff --git a/clang/lib/Format/IntegerLiteralSeparatorFixer.h b/clang/lib/Format/IntegerLiteralSeparatorFixer.h new file mode 100644 index 000000000000..156bf5c14fca --- /dev/null +++ b/clang/lib/Format/IntegerLiteralSeparatorFixer.h @@ -0,0 +1,38 @@ +//===--- IntegerLiteralSeparatorFixer.h -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file declares IntegerLiteralSeparatorFixer that fixes C++ integer +/// literal separators. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_FORMAT_INTEGERLITERALSEPARATORFIXER_H +#define LLVM_CLANG_LIB_FORMAT_INTEGERLITERALSEPARATORFIXER_H + +#include "TokenAnalyzer.h" + +namespace clang { +namespace format { + +class IntegerLiteralSeparatorFixer { +public: + std::pair<tooling::Replacements, unsigned> process(const Environment &Env, + const FormatStyle &Style); + +private: + bool checkSeparator(const StringRef IntegerLiteral, int DigitsPerGroup) const; + std::string format(const StringRef IntegerLiteral, int DigitsPerGroup) const; + + char Separator; +}; + +} // end namespace format +} // end namespace clang + +#endif diff --git a/clang/lib/Format/MacroCallReconstructor.cpp b/clang/lib/Format/MacroCallReconstructor.cpp index ccff183cf0da..1c295477a922 100644 --- a/clang/lib/Format/MacroCallReconstructor.cpp +++ b/clang/lib/Format/MacroCallReconstructor.cpp @@ -35,9 +35,8 @@ void forEachToken(const UnwrappedLine &Line, const T &Call, for (const auto &N : Line.Tokens) { Call(N.Tok, Parent, First); First = false; - for (const auto &Child : N.Children) { + for (const auto &Child : N.Children) forEachToken(Child, Call, N.Tok); - } } } @@ -61,7 +60,8 @@ void MacroCallReconstructor::addLine(const UnwrappedLine &Line) { UnwrappedLine MacroCallReconstructor::takeResult() && { finalize(); - assert(Result.Tokens.size() == 1 && Result.Tokens.front()->Children.size() == 1); + assert(Result.Tokens.size() == 1 && + Result.Tokens.front()->Children.size() == 1); UnwrappedLine Final = createUnwrappedLine(*Result.Tokens.front()->Children.front(), Level); assert(!Final.Tokens.empty()); @@ -194,9 +194,8 @@ FormatToken *MacroCallReconstructor::getParentInResult(FormatToken *Parent) { FormatToken *Mapped = SpelledParentToReconstructedParent.lookup(Parent); if (!Mapped) return Parent; - for (; Mapped; Mapped = SpelledParentToReconstructedParent.lookup(Parent)) { + for (; Mapped; Mapped = SpelledParentToReconstructedParent.lookup(Parent)) Parent = Mapped; - } // If we use a different token than the parent in the expanded token stream // as parent, mark it as a special parent, so the formatting code knows it // needs to have its children formatted. @@ -216,9 +215,8 @@ void MacroCallReconstructor::reconstruct(FormatToken *Token) { // If the order of tokens in the expanded token stream is not the // same as the order of tokens in the reconstructed stream, we need // to reconstruct tokens that arrive later in the stream. - if (Token->MacroCtx->Role != MR_Hidden) { + if (Token->MacroCtx->Role != MR_Hidden) reconstructActiveCallUntil(Token); - } } assert(!ActiveExpansions.empty()); if (ActiveExpansions.back().SpelledI != ActiveExpansions.back().SpelledE) { @@ -275,7 +273,7 @@ void MacroCallReconstructor::startReconstruction(FormatToken *Token) { // Note that the token's expanded from stack is inside-to-outside, and the // expansions for which this token is not the first are the outermost ones. ArrayRef<FormatToken *> StartedMacros = - makeArrayRef(Token->MacroCtx->ExpandedFrom) + ArrayRef(Token->MacroCtx->ExpandedFrom) .drop_back(ActiveExpansions.size()); assert(StartedMacros.size() == Token->MacroCtx->StartOfExpansion); // We reconstruct macro calls outside-to-inside. @@ -334,9 +332,8 @@ void MacroCallReconstructor::endReconstruction(FormatToken *Token) { bool PreviousLevel = Token->MacroCtx && (ActiveExpansions.size() < Token->MacroCtx->ExpandedFrom.size()); - if (!ClosingParen && !TrailingComment && !PreviousLevel) { + if (!ClosingParen && !TrailingComment && !PreviousLevel) llvm::dbgs() << "At token: " << Token->TokenText << "\n"; - } // In addition to the following cases, we can also run into this // when a macro call had more arguments than expected; in that case, // the comma and the remaining tokens in the macro call will potentially @@ -392,9 +389,8 @@ bool MacroCallReconstructor::processNextReconstructed() { ++ActiveExpansions.back().SpelledI; if (Token->MacroCtx) { // Skip tokens that are not part of the macro call. - if (Token->MacroCtx->Role == MR_Hidden) { + if (Token->MacroCtx->Role == MR_Hidden) return false; - } // Skip tokens we already expanded during an inner reconstruction. // For example, given: #define ID(x) {x} // And the call: ID(ID(f)) @@ -403,9 +399,8 @@ bool MacroCallReconstructor::processNextReconstructed() { // ID({f}) -> {{f}} // We reconstruct f during the first reconstruction, and skip it during the // second reconstruction. - if (ActiveExpansions.size() < Token->MacroCtx->ExpandedFrom.size()) { + if (ActiveExpansions.size() < Token->MacroCtx->ExpandedFrom.size()) return false; - } } // Tokens that do not have a macro context are tokens in that are part of the // macro call that have not taken part in expansion. diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp index 61f17cae383e..cef8b36ff758 100644 --- a/clang/lib/Format/QualifierAlignmentFixer.cpp +++ b/clang/lib/Format/QualifierAlignmentFixer.cpp @@ -18,6 +18,7 @@ #include "llvm/Support/Regex.h" #include <algorithm> +#include <optional> #define DEBUG_TYPE "format-qualifier-alignment-fixer" @@ -66,7 +67,7 @@ std::pair<tooling::Replacements, unsigned> QualifierAlignmentFixer::analyze( NextStartColumn, LastStartColumn); if (!Env) return {}; - llvm::Optional<std::string> CurrentCode = None; + std::optional<std::string> CurrentCode; tooling::Replacements Fixes; for (size_t I = 0, E = Passes.size(); I < E; ++I) { std::pair<tooling::Replacements, unsigned> PassFixes = Passes[I](*Env); @@ -413,6 +414,7 @@ tok::TokenKind LeftRightQualifierAlignmentFixer::getTokenFromQualifier( .Case("inline", tok::kw_inline) .Case("constexpr", tok::kw_constexpr) .Case("restrict", tok::kw_restrict) + .Case("friend", tok::kw_friend) .Default(tok::identifier); } diff --git a/clang/lib/Format/TokenAnalyzer.cpp b/clang/lib/Format/TokenAnalyzer.cpp index 0a775c0a87ed..77e403581a0d 100644 --- a/clang/lib/Format/TokenAnalyzer.cpp +++ b/clang/lib/Format/TokenAnalyzer.cpp @@ -97,7 +97,8 @@ TokenAnalyzer::TokenAnalyzer(const Environment &Env, const FormatStyle &Style) << "\n"); } -std::pair<tooling::Replacements, unsigned> TokenAnalyzer::process() { +std::pair<tooling::Replacements, unsigned> +TokenAnalyzer::process(bool SkipAnnotation) { tooling::Replacements Result; llvm::SpecificBumpPtrAllocator<FormatToken> Allocator; IdentifierTable IdentTable(getFormattingLangOpts(Style)); @@ -121,7 +122,8 @@ std::pair<tooling::Replacements, unsigned> TokenAnalyzer::process() { TokenAnnotator Annotator(Style, Lex.getKeywords()); for (const UnwrappedLine &Line : Lines) { AnnotatedLines.push_back(new AnnotatedLine(Line)); - Annotator.annotate(*AnnotatedLines.back()); + if (!SkipAnnotation) + Annotator.annotate(*AnnotatedLines.back()); } std::pair<tooling::Replacements, unsigned> RunResult = diff --git a/clang/lib/Format/TokenAnalyzer.h b/clang/lib/Format/TokenAnalyzer.h index aaca518df41f..e5cc1287c616 100644 --- a/clang/lib/Format/TokenAnalyzer.h +++ b/clang/lib/Format/TokenAnalyzer.h @@ -89,7 +89,8 @@ class TokenAnalyzer : public UnwrappedLineConsumer { public: TokenAnalyzer(const Environment &Env, const FormatStyle &Style); - std::pair<tooling::Replacements, unsigned> process(); + std::pair<tooling::Replacements, unsigned> + process(bool SkipAnnotation = false); protected: virtual std::pair<tooling::Replacements, unsigned> diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 5991cf23d5dc..49c30ca78deb 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -71,6 +71,38 @@ static bool isKeywordWithCondition(const FormatToken &Tok) { tok::kw_constexpr, tok::kw_catch); } +/// Returns \c true if the token starts a C++ attribute, \c false otherwise. +static bool isCppAttribute(bool IsCpp, const FormatToken &Tok) { + if (!IsCpp || !Tok.startsSequence(tok::l_square, tok::l_square)) + return false; + // The first square bracket is part of an ObjC array literal + if (Tok.Previous && Tok.Previous->is(tok::at)) + return false; + const FormatToken *AttrTok = Tok.Next->Next; + if (!AttrTok) + return false; + // C++17 '[[using ns: foo, bar(baz, blech)]]' + // We assume nobody will name an ObjC variable 'using'. + if (AttrTok->startsSequence(tok::kw_using, tok::identifier, tok::colon)) + return true; + if (AttrTok->isNot(tok::identifier)) + return false; + while (AttrTok && !AttrTok->startsSequence(tok::r_square, tok::r_square)) { + // ObjC message send. We assume nobody will use : in a C++11 attribute + // specifier parameter, although this is technically valid: + // [[foo(:)]]. + if (AttrTok->is(tok::colon) || + AttrTok->startsSequence(tok::identifier, tok::identifier) || + AttrTok->startsSequence(tok::r_paren, tok::identifier)) { + return false; + } + if (AttrTok->is(tok::ellipsis)) + return true; + AttrTok = AttrTok->Next; + } + return AttrTok && AttrTok->startsSequence(tok::r_square, tok::r_square); +} + /// A parser that gathers additional information about tokens. /// /// The \c TokenAnnotator tries to match parenthesis and square brakets and @@ -134,10 +166,9 @@ private: // parameter cases, but should not alter program semantics. if (CurrentToken->Next && CurrentToken->Next->is(tok::greater) && Left->ParentBracket != tok::less && - (isKeywordWithCondition(*Line.First) || - CurrentToken->getStartOfNonWhitespace() == - CurrentToken->Next->getStartOfNonWhitespace().getLocWithOffset( - -1))) { + CurrentToken->getStartOfNonWhitespace() == + CurrentToken->Next->getStartOfNonWhitespace().getLocWithOffset( + -1)) { return false; } Left->MatchingParen = CurrentToken; @@ -238,11 +269,13 @@ private: } bool StartsObjCMethodExpr = false; - if (FormatToken *MaybeSel = OpeningParen.Previous) { - // @selector( starts a selector. - if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous && - MaybeSel->Previous->is(tok::at)) { - StartsObjCMethodExpr = true; + if (!Style.isVerilog()) { + if (FormatToken *MaybeSel = OpeningParen.Previous) { + // @selector( starts a selector. + if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && + MaybeSel->Previous && MaybeSel->Previous->is(tok::at)) { + StartsObjCMethodExpr = true; + } } } @@ -287,6 +320,12 @@ private: } else if (isLambdaParameterList(&OpeningParen)) { // This is a parameter list of a lambda expression. Contexts.back().IsExpression = false; + } else if (OpeningParen.is(TT_RequiresExpressionLParen)) { + Contexts.back().IsExpression = false; + } else if (OpeningParen.Previous && + OpeningParen.Previous->is(tok::kw__Generic)) { + Contexts.back().ContextType = Context::C11GenericSelection; + Contexts.back().IsExpression = true; } else if (Line.InPPDirective && (!OpeningParen.Previous || !OpeningParen.Previous->is(tok::identifier))) { @@ -300,7 +339,8 @@ private: Contexts.back().ContextType = Context::ForEachMacro; Contexts.back().IsExpression = false; } else if (OpeningParen.Previous && OpeningParen.Previous->MatchingParen && - OpeningParen.Previous->MatchingParen->is(TT_ObjCBlockLParen)) { + OpeningParen.Previous->MatchingParen->isOneOf( + TT_ObjCBlockLParen, TT_FunctionTypeLParen)) { Contexts.back().IsExpression = false; } else if (!Line.MustBeDeclaration && !Line.InPPDirective) { bool IsForOrCatch = @@ -310,13 +350,15 @@ private: } // Infer the role of the l_paren based on the previous token if we haven't - // detected one one yet. + // detected one yet. if (PrevNonComment && OpeningParen.is(TT_Unknown)) { if (PrevNonComment->is(tok::kw___attribute)) { OpeningParen.setType(TT_AttributeParen); } else if (PrevNonComment->isOneOf(TT_TypenameMacro, tok::kw_decltype, - tok::kw_typeof, tok::kw__Atomic, - tok::kw___underlying_type)) { + tok::kw_typeof, +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) tok::kw___##Trait, +#include "clang/Basic/TransformTypeTraits.def" + tok::kw__Atomic)) { OpeningParen.setType(TT_TypeDeclarationParen); // decltype() and typeof() usually contain expressions. if (PrevNonComment->isOneOf(tok::kw_decltype, tok::kw_typeof)) @@ -357,7 +399,8 @@ private: FormatToken *Next = CurrentToken->Next; if (PrevPrev && PrevPrev->is(tok::identifier) && Prev->isOneOf(tok::star, tok::amp, tok::ampamp) && - CurrentToken->is(tok::identifier) && Next->isNot(tok::equal)) { + CurrentToken->is(tok::identifier) && + !Next->isOneOf(tok::equal, tok::l_brace)) { Prev->setType(TT_BinaryOperator); LookForDecls = false; } @@ -532,34 +575,7 @@ private: } bool isCpp11AttributeSpecifier(const FormatToken &Tok) { - if (!Style.isCpp() || !Tok.startsSequence(tok::l_square, tok::l_square)) - return false; - // The first square bracket is part of an ObjC array literal - if (Tok.Previous && Tok.Previous->is(tok::at)) - return false; - const FormatToken *AttrTok = Tok.Next->Next; - if (!AttrTok) - return false; - // C++17 '[[using ns: foo, bar(baz, blech)]]' - // We assume nobody will name an ObjC variable 'using'. - if (AttrTok->startsSequence(tok::kw_using, tok::identifier, tok::colon)) - return true; - if (AttrTok->isNot(tok::identifier)) - return false; - while (AttrTok && !AttrTok->startsSequence(tok::r_square, tok::r_square)) { - // ObjC message send. We assume nobody will use : in a C++11 attribute - // specifier parameter, although this is technically valid: - // [[foo(:)]]. - if (AttrTok->is(tok::colon) || - AttrTok->startsSequence(tok::identifier, tok::identifier) || - AttrTok->startsSequence(tok::r_paren, tok::identifier)) { - return false; - } - if (AttrTok->is(tok::ellipsis)) - return true; - AttrTok = AttrTok->Next; - } - return AttrTok && AttrTok->startsSequence(tok::r_square, tok::r_square); + return isCppAttribute(Style.isCpp(), Tok); } bool parseSquare() { @@ -582,8 +598,9 @@ private: (Contexts.back().CanBeExpression || Contexts.back().IsExpression || Contexts.back().ContextType == Context::TemplateArgument); - bool IsCpp11AttributeSpecifier = isCpp11AttributeSpecifier(*Left) || - Contexts.back().InCpp11AttributeSpecifier; + const bool IsInnerSquare = Contexts.back().InCpp11AttributeSpecifier; + const bool IsCpp11AttributeSpecifier = + isCpp11AttributeSpecifier(*Left) || IsInnerSquare; // Treat C# Attributes [STAThread] much like C++ attributes [[...]]. bool IsCSharpAttributeSpecifier = @@ -618,6 +635,8 @@ private: Left->setType(TT_InlineASMSymbolicNameLSquare); } else if (IsCpp11AttributeSpecifier) { Left->setType(TT_AttributeSquare); + if (!IsInnerSquare && Left->Previous) + Left->Previous->EndsCppAttributeGroup = false; } else if (Style.isJavaScript() && Parent && Contexts.back().ContextKind == tok::l_brace && Parent->isOneOf(tok::l_brace, tok::comma)) { @@ -691,8 +710,11 @@ private: while (CurrentToken) { if (CurrentToken->is(tok::r_square)) { - if (IsCpp11AttributeSpecifier) + if (IsCpp11AttributeSpecifier) { CurrentToken->setType(TT_AttributeSquare); + if (!IsInnerSquare) + CurrentToken->EndsCppAttributeGroup = true; + } if (IsCSharpAttributeSpecifier) { CurrentToken->setType(TT_AttributeSquare); } else if (((CurrentToken->Next && @@ -761,7 +783,8 @@ private: // Remember that this is a [[using ns: foo]] C++ attribute, so we // don't add a space before the colon (unlike other colons). CurrentToken->setType(TT_AttributeColon); - } else if (Left->isOneOf(TT_ArraySubscriptLSquare, + } else if (!Style.isVerilog() && !Line.InPragmaDirective && + Left->isOneOf(TT_ArraySubscriptLSquare, TT_DesignatedInitializerLSquare)) { Left->setType(TT_ObjCMethodExpr); StartsObjCMethodExpr = true; @@ -914,6 +937,10 @@ private: bool consumeToken() { FormatToken *Tok = CurrentToken; next(); + // In Verilog primitives' state tables, `:`, `?`, and `-` aren't normal + // operators. + if (Tok->is(TT_VerilogTableItem)) + return true; switch (Tok->Tok.getKind()) { case tok::plus: case tok::minus: @@ -947,6 +974,25 @@ private: Tok->setType(TT_CSharpNamedArgumentColon); break; } + } else if (Style.isVerilog() && Tok->isNot(TT_BinaryOperator)) { + // The distribution weight operators are labeled + // TT_BinaryOperator by the lexer. + if (Keywords.isVerilogEnd(*Tok->Previous) || + Keywords.isVerilogBegin(*Tok->Previous)) { + Tok->setType(TT_VerilogBlockLabelColon); + } else if (Contexts.back().ContextKind == tok::l_square) { + Tok->setType(TT_BitFieldColon); + } else if (Contexts.back().ColonIsDictLiteral) { + Tok->setType(TT_DictLiteral); + } else if (Contexts.size() == 1) { + // In Verilog a case label doesn't have the case keyword. We + // assume a colon following an expression is a case label. + // Colons from ?: are annotated in parseConditional(). + Tok->setType(TT_GotoLabelColon); + if (Line.Level > 1 || (!Line.InPPDirective && Line.Level > 0)) + --Line.Level; + } + break; } if (Line.First->isOneOf(Keywords.kw_module, Keywords.kw_import) || Line.First->startsSequence(tok::kw_export, Keywords.kw_module) || @@ -991,6 +1037,8 @@ private: } } else if (Contexts.back().ColonIsForRangeExpr) { Tok->setType(TT_RangeBasedForLoopColon); + } else if (Contexts.back().ContextType == Context::C11GenericSelection) { + Tok->setType(TT_GenericSelectionColon); } else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) { Tok->setType(TT_BitFieldColon); } else if (Contexts.size() == 1 && @@ -1019,7 +1067,8 @@ 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) { + } else if (Contexts.back().ContextKind == tok::l_paren && + !Line.InPragmaDirective) { Tok->setType(TT_InlineASMColon); } break; @@ -1035,7 +1084,7 @@ private: CurrentToken->isOneOf(tok::kw_constexpr, tok::identifier)) { next(); } - LLVM_FALLTHROUGH; + [[fallthrough]]; case tok::kw_while: if (CurrentToken && CurrentToken->is(tok::l_paren)) { next(); @@ -1082,7 +1131,7 @@ private: !Contexts.back().IsExpression && !Line.startsWith(TT_ObjCProperty) && !Tok->isOneOf(TT_TypeDeclarationParen, TT_RequiresExpressionLParen) && (!Tok->Previous || - !Tok->Previous->isOneOf(tok::kw___attribute, + !Tok->Previous->isOneOf(tok::kw___attribute, TT_RequiresClause, TT_LeadingJavaAnnotation))) { Line.MightBeFunctionDecl = true; } @@ -1147,13 +1196,17 @@ private: if (CurrentToken->isOneOf(tok::star, tok::amp)) CurrentToken->setType(TT_PointerOrReference); consumeToken(); - if (CurrentToken && CurrentToken->is(tok::comma) && + if (!CurrentToken) + continue; + if (CurrentToken->is(tok::comma) && CurrentToken->Previous->isNot(tok::kw_operator)) { break; } - if (CurrentToken && CurrentToken->Previous->isOneOf( - TT_BinaryOperator, TT_UnaryOperator, tok::comma, - tok::star, tok::arrow, tok::amp, tok::ampamp)) { + if (CurrentToken->Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator, + tok::comma, tok::star, tok::arrow, + tok::amp, tok::ampamp) || + // User defined literal. + CurrentToken->Previous->TokenText.startswith("\"\"")) { CurrentToken->Previous->setType(TT_OverloadedOperator); } } @@ -1215,6 +1268,13 @@ private: if (Contexts.back().ContextType == Context::ForEachMacro) Contexts.back().IsExpression = true; break; + case tok::kw_default: + // Unindent case labels. + if (Style.isVerilog() && Keywords.isVerilogEndOfLabel(*Tok) && + (Line.Level > 1 || (!Line.InPPDirective && Line.Level > 0))) { + --Line.Level; + } + break; case tok::identifier: if (Tok->isOneOf(Keywords.kw___has_include, Keywords.kw___has_include_next)) { @@ -1224,6 +1284,8 @@ private: Tok->Next->isNot(tok::l_paren)) { Tok->setType(TT_CSharpGenericTypeConstraint); parseCSharpGenericTypeConstraint(); + if (Tok->getPreviousNonComment() == nullptr) + Line.IsContinuation = true; } break; case tok::arrow: @@ -1232,6 +1294,10 @@ private: Tok->setType(TT_TrailingReturnArrow); } break; + case tok::eof: + if (Style.InsertNewlineAtEOF && Tok->NewlinesBefore == 0) + Tok->NewlinesBefore = 1; + break; default: break; } @@ -1298,11 +1364,12 @@ private: if (CurrentToken && CurrentToken->isOneOf(Keywords.kw_mark, Keywords.kw_option, Keywords.kw_region)) { - bool IsMark = CurrentToken->is(Keywords.kw_mark); + bool IsMarkOrRegion = + CurrentToken->isOneOf(Keywords.kw_mark, Keywords.kw_region); next(); next(); // Consume first token (so we fix leading whitespace). while (CurrentToken) { - if (IsMark || CurrentToken->Previous->is(TT_BinaryOperator)) + if (IsMarkOrRegion || CurrentToken->Previous->is(TT_BinaryOperator)) CurrentToken->setType(TT_ImplicitStringLiteral); next(); } @@ -1390,7 +1457,7 @@ public: if (!CurrentToken) return LT_Invalid; NonTemplateLess.clear(); - if (CurrentToken->is(tok::hash)) { + if (!Line.InMacroBody && CurrentToken->is(tok::hash)) { // We were not yet allowed to use C++17 optional when this was being // written. So we used LT_Invalid to mark that the line is not a // preprocessor directive. @@ -1405,8 +1472,8 @@ public: IdentifierInfo *Info = CurrentToken->Tok.getIdentifierInfo(); if ((Style.Language == FormatStyle::LK_Java && CurrentToken->is(Keywords.kw_package)) || - (Info && Info->getPPKeywordID() == tok::pp_import && - CurrentToken->Next && + (!Style.isVerilog() && Info && + Info->getPPKeywordID() == tok::pp_import && CurrentToken->Next && CurrentToken->Next->isOneOf(tok::string_literal, tok::identifier, tok::kw_static))) { next(); @@ -1571,6 +1638,8 @@ private: StructArrayInitializer, // Like in `static_cast<int>`. TemplateArgument, + // C11 _Generic selection. + C11GenericSelection, } ContextType = Unknown; }; @@ -1628,8 +1697,8 @@ private: if (!Tok) return false; - if (Tok->isOneOf(tok::kw_class, tok::kw_enum, tok::kw_concept, - tok::kw_struct, tok::kw_using)) { + if (Tok->isOneOf(tok::kw_class, tok::kw_enum, tok::kw_struct, + tok::kw_using)) { return false; } @@ -1754,21 +1823,8 @@ private: FormatToken *LeadingIdentifier = Current.Previous->MatchingParen->Previous; - // Differentiate a deduction guide by seeing the - // > of the template prior to the leading identifier. - if (LeadingIdentifier) { - FormatToken *PriorLeadingIdentifier = LeadingIdentifier->Previous; - // Skip back past explicit decoration - if (PriorLeadingIdentifier && - PriorLeadingIdentifier->is(tok::kw_explicit)) { - PriorLeadingIdentifier = PriorLeadingIdentifier->Previous; - } - - return PriorLeadingIdentifier && - (PriorLeadingIdentifier->is(TT_TemplateCloser) || - PriorLeadingIdentifier->ClosesRequiresClause) && - LeadingIdentifier->TokenText == Current.Next->TokenText; - } + return LeadingIdentifier && + LeadingIdentifier->TokenText == Current.Next->TokenText; } } return false; @@ -1842,7 +1898,8 @@ private: Current, Contexts.back().CanBeExpression && Contexts.back().IsExpression, Contexts.back().ContextType == Context::TemplateArgument)); - } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) { + } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret) || + (Style.isVerilog() && Current.is(tok::pipe))) { Current.setType(determinePlusMinusCaretUsage(Current)); if (Current.is(TT_UnaryOperator) && Current.is(tok::caret)) Contexts.back().CaretFound = true; @@ -1886,7 +1943,7 @@ private: !Current.Next->isBinaryOperator() && !Current.Next->isOneOf(tok::semi, tok::colon, tok::l_brace, tok::comma, tok::period, tok::arrow, - tok::coloncolon)) { + tok::coloncolon, tok::kw_noexcept)) { if (FormatToken *AfterParen = Current.MatchingParen->Next) { // Make sure this isn't the return type of an Obj-C block declaration if (AfterParen->isNot(tok::caret)) { @@ -1943,7 +2000,9 @@ private: } else if (Current.isOneOf(tok::identifier, tok::kw_const, tok::kw_noexcept, tok::kw_requires) && Current.Previous && - !Current.Previous->isOneOf(tok::equal, tok::at) && + !Current.Previous->isOneOf(tok::equal, tok::at, + TT_CtorInitializerComma, + TT_CtorInitializerColon) && Line.MightBeFunctionDecl && Contexts.size() == 1) { // Line.MightBeFunctionDecl can only be true after the parentheses of a // function declaration have been found. @@ -2029,6 +2088,12 @@ private: if (PreviousNotConst->isSimpleTypeSpecifier()) return true; + // type[] a in Java + if (Style.Language == FormatStyle::LK_Java && + PreviousNotConst->is(tok::r_square)) { + return true; + } + // const a = in JavaScript. return Style.isJavaScript() && PreviousNotConst->is(tok::kw_const); } @@ -2066,6 +2131,9 @@ private: if (Tok.Previous == Tok.MatchingParen || !Tok.Next || !Tok.MatchingParen) return false; + if (Tok.MatchingParen->is(TT_OverloadedOperatorLParen)) + return false; + FormatToken *LeftOfParens = Tok.MatchingParen->getPreviousNonComment(); if (LeftOfParens) { // If there is a closing parenthesis left of the current @@ -2110,7 +2178,7 @@ private: // before the parentheses, this is unlikely to be a cast. if (LeftOfParens->Tok.getIdentifierInfo() && !LeftOfParens->isOneOf(Keywords.kw_in, tok::kw_return, tok::kw_case, - tok::kw_delete)) { + tok::kw_delete, tok::kw_throw)) { return false; } @@ -2293,7 +2361,8 @@ private: return TT_BinaryOperator; if (!NextToken || - NextToken->isOneOf(tok::arrow, tok::equal, tok::kw_noexcept) || + NextToken->isOneOf(tok::arrow, tok::equal, tok::kw_noexcept, tok::comma, + tok::r_paren) || NextToken->canBePointerOrReferenceQualifier() || (NextToken->is(tok::l_brace) && !NextToken->getNextNonComment())) { return TT_PointerOrReference; @@ -2326,28 +2395,19 @@ private: // case, the matching `{` is on the same unwrapped line, so check for the // presence of the matching brace to distinguish between those. if (PrevToken->is(tok::r_brace) && Tok.is(tok::star) && - !PrevToken->MatchingParen) + !PrevToken->MatchingParen) { return TT_PointerOrReference; + } - // For "} &&" - if (PrevToken->is(tok::r_brace) && Tok.is(tok::ampamp)) { - const FormatToken *MatchingLBrace = PrevToken->MatchingParen; - - // We check whether there is a TemplateCloser(">") to indicate it's a - // template or not. If it's not a template, "&&" is likely a reference - // operator. - // struct {} &&ref = {}; - if (!MatchingLBrace) - return TT_PointerOrReference; - FormatToken *BeforeLBrace = MatchingLBrace->getPreviousNonComment(); - if (!BeforeLBrace || BeforeLBrace->isNot(TT_TemplateCloser)) - return TT_PointerOrReference; - - // If it is a template, "&&" is a binary operator. - // enable_if<>{} && ... - return TT_BinaryOperator; + // if (Class* obj { function() }) + if (PrevToken->Tok.isAnyIdentifier() && NextToken->Tok.isAnyIdentifier() && + NextToken->Next && NextToken->Next->is(tok::l_brace)) { + return TT_PointerOrReference; } + if (PrevToken->endsSequence(tok::r_square, tok::l_square, tok::kw_delete)) + return TT_UnaryOperator; + if (PrevToken->Tok.isLiteral() || PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::kw_true, tok::kw_false, tok::r_brace)) { @@ -2529,7 +2589,7 @@ public: (Start->Previous && Start->Previous->isOneOf(TT_RequiresClause, TT_RequiresClauseInARequiresExpression)) - ? [this](){ + ? [this]() { auto Ret = Current ? Current : Line.Last; while (!Ret->ClosesRequiresClause && Ret->Previous) Ret = Ret->Previous; @@ -2584,13 +2644,19 @@ private: } if (Current->is(TT_BinaryOperator) || Current->is(tok::comma)) return Current->getPrecedence(); - if (Current->isOneOf(tok::period, tok::arrow)) + if (Current->isOneOf(tok::period, tok::arrow) && + Current->isNot(TT_TrailingReturnArrow)) { return PrecedenceArrowAndPeriod; + } if ((Style.Language == FormatStyle::LK_Java || Style.isJavaScript()) && Current->isOneOf(Keywords.kw_extends, Keywords.kw_implements, Keywords.kw_throws)) { return 0; } + // In Verilog case labels are not on separate lines straight out of + // UnwrappedLineParser. The colon is not part of an expression. + if (Style.isVerilog() && Current->is(tok::colon)) + return 0; } return -1; } @@ -2670,15 +2736,18 @@ void TokenAnnotator::setCommentLineLevels( NextNonCommentLine->First->NewlinesBefore <= 1 && NextNonCommentLine->First->OriginalColumn == Line->First->OriginalColumn) { + const bool PPDirectiveOrImportStmt = + NextNonCommentLine->Type == LT_PreprocessorDirective || + NextNonCommentLine->Type == LT_ImportStatement; + if (PPDirectiveOrImportStmt) + Line->Type = LT_CommentAbovePPDirective; // Align comments for preprocessor lines with the # in column 0 if // preprocessor lines are not indented. Otherwise, align with the next // line. - Line->Level = - (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash && - (NextNonCommentLine->Type == LT_PreprocessorDirective || - NextNonCommentLine->Type == LT_ImportStatement)) - ? 0 - : NextNonCommentLine->Level; + Line->Level = Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash && + PPDirectiveOrImportStmt + ? 0 + : NextNonCommentLine->Level; } else { NextNonCommentLine = Line->First->isNot(tok::r_brace) ? Line : nullptr; } @@ -2774,7 +2843,7 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current, if (!Current.is(TT_StartOfName) || Current.NestingLevel != 0) return false; for (; Next; Next = Next->Next) { - if (Next->is(TT_TemplateOpener)) { + if (Next->is(TT_TemplateOpener) && Next->MatchingParen) { Next = Next->MatchingParen; } else if (Next->is(tok::coloncolon)) { Next = Next->Next; @@ -2786,6 +2855,10 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current, } if (!Next->is(tok::identifier)) return false; + } else if (isCppAttribute(IsCpp, *Next)) { + Next = Next->MatchingParen; + if (!Next) + return false; } else if (Next->is(tok::l_paren)) { break; } else { @@ -2867,6 +2940,18 @@ bool TokenAnnotator::mustBreakForReturnType(const AnnotatedLine &Line) const { return false; } +static bool mustBreakAfterAttributes(const FormatToken &Tok, + const FormatStyle &Style) { + switch (Style.BreakAfterAttributes) { + case FormatStyle::ABS_Always: + return true; + case FormatStyle::ABS_Leave: + return Tok.NewlinesBefore > 0; + default: + return false; + } +} + void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const { for (AnnotatedLine *ChildLine : Line.Children) calculateFormattingInformation(*ChildLine); @@ -2882,9 +2967,22 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const { if (AlignArrayOfStructures) calculateArrayInitializerColumnList(Line); + for (FormatToken *Tok = Current, *AfterLastAttribute = nullptr; Tok; + Tok = Tok->Next) { + if (isFunctionDeclarationName(Style.isCpp(), *Tok, Line)) { + Tok->setType(TT_FunctionDeclarationName); + if (AfterLastAttribute && + mustBreakAfterAttributes(*AfterLastAttribute, Style)) { + AfterLastAttribute->MustBreakBefore = true; + Line.ReturnTypeWrapped = true; + } + break; + } + if (Tok->Previous->EndsCppAttributeGroup) + AfterLastAttribute = Tok; + } + while (Current) { - if (isFunctionDeclarationName(Style.isCpp(), *Current, Line)) - Current->setType(TT_FunctionDeclarationName); const FormatToken *Prev = Current->Previous; if (Current->is(TT_LineComment)) { if (Prev->is(BK_BracedInit) && Prev->opensScope()) { @@ -3057,6 +3155,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if (Left.is(tok::semi)) return 0; + // Language specific handling. if (Style.Language == FormatStyle::LK_Java) { if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_throws)) return 1; @@ -3076,13 +3175,16 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, // Prefer breaking call chains (".foo") over empty "{}", "[]" or "()". if (Left.opensScope() && Right.closesScope()) return 200; + } else if (Style.isProto()) { + if (Right.is(tok::l_square)) + return 1; + if (Right.is(tok::period)) + return 500; } if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral)) return 1; if (Right.is(tok::l_square)) { - if (Style.Language == FormatStyle::LK_Proto) - return 1; if (Left.is(tok::r_square)) return 200; // Slightly prefer formatting local lambda definitions like functions. @@ -3095,10 +3197,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, } } - if (Left.is(tok::coloncolon) || - (Right.is(tok::period) && Style.Language == FormatStyle::LK_Proto)) { + if (Left.is(tok::coloncolon)) return 500; - } if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) || Right.is(tok::kw_operator)) { if (Line.startsWith(tok::kw_for) && Right.PartOfMultiVariableDeclStmt) @@ -3117,7 +3217,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, return 160; if (Left.is(TT_CastRParen)) return 100; - if (Left.isOneOf(tok::kw_class, tok::kw_struct)) + if (Left.isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union)) return 5000; if (Left.is(tok::comment)) return 1000; @@ -3193,7 +3293,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, return 100; } if (Left.is(tok::l_paren) && Left.Previous && - (Left.Previous->is(tok::kw_for) || Left.Previous->isIf())) { + (Left.Previous->isOneOf(tok::kw_for, tok::kw__Generic) || + Left.Previous->isIf())) { return 1000; } if (Left.is(tok::equal) && InFunctionDecl) @@ -3281,6 +3382,10 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, !Right.isOneOf(tok::semi, tok::r_paren, tok::hashhash)) { return true; } + if (Left.is(tok::kw_throw) && Right.is(tok::l_paren) && Right.MatchingParen && + Right.MatchingParen->is(TT_CastRParen)) { + return true; + } if (Style.isJson() && Left.is(tok::string_literal) && Right.is(tok::colon)) return false; if (Left.is(Keywords.kw_assert) && Style.Language == FormatStyle::LK_Java) @@ -3310,6 +3415,13 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, } } + // trailing return type 'auto': []() -> auto {}, auto foo() -> auto {} + if (Left.is(tok::kw_auto) && Right.isOneOf(TT_LambdaLBrace, TT_FunctionLBrace, + // function return type 'auto' + TT_FunctionTypeLParen)) { + return true; + } + // auto{x} auto(x) if (Left.is(tok::kw_auto) && Right.isOneOf(tok::l_paren, tok::l_brace)) return false; @@ -3362,7 +3474,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return false; return !Style.Cpp11BracedListStyle; } - return false; + // Don't attempt to format operator<(), as it is handled later. + if (Right.isNot(TT_OverloadedOperatorLParen)) + return false; } if (Right.is(tok::ellipsis)) { return Left.Tok.isLiteral() || (Left.is(tok::identifier) && Left.Previous && @@ -3424,7 +3538,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Right.is(TT_BlockComment)) return true; // foo() -> const Bar * override/final - if (Right.isOneOf(Keywords.kw_override, Keywords.kw_final) && + if (Right.isOneOf(Keywords.kw_override, Keywords.kw_final, + tok::kw_noexcept) && !Right.is(TT_StartOfName)) { return true; } @@ -3591,7 +3706,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return true; if (Left.isOneOf(tok::pp_elif, tok::kw_for, tok::kw_while, tok::kw_switch, tok::kw_case, TT_ForEachMacro, TT_ObjCForIn) || - Left.isIf(Line.Type != LT_PreprocessorDirective)) { + Left.isIf(Line.Type != LT_PreprocessorDirective) || + Right.is(TT_ConditionLParen)) { return Style.SpaceBeforeParensOptions.AfterControlStatements || spaceRequiredBeforeParens(Right); } @@ -3977,8 +4093,16 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return true; } } else if (Style.isVerilog()) { + // Add space between things in a primitive's state table unless in a + // transition like `(0?)`. + if ((Left.is(TT_VerilogTableItem) && + !Right.isOneOf(tok::r_paren, tok::semi)) || + (Right.is(TT_VerilogTableItem) && Left.isNot(tok::l_paren))) { + const FormatToken *Next = Right.getNextNonComment(); + return !(Next && Next->is(tok::r_paren)); + } // Don't add space within a delay like `#0`. - if (!Left.is(TT_BinaryOperator) && + if (Left.isNot(TT_BinaryOperator) && Left.isOneOf(Keywords.kw_verilogHash, Keywords.kw_verilogHashHash)) { return false; } @@ -3991,6 +4115,31 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, Left.MatchingParen->endsSequence(tok::l_paren, tok::at)))) { return true; } + // Don't add embedded spaces in a number literal like `16'h1?ax` or an array + // literal like `'{}`. + if (Left.is(Keywords.kw_apostrophe) || + (Left.is(TT_VerilogNumberBase) && Right.is(tok::numeric_constant))) { + return false; + } + // Add space between the type name and dimension like `logic [1:0]`. + if (Right.is(tok::l_square) && + Left.isOneOf(TT_VerilogDimensionedTypeName, Keywords.kw_function)) { + return true; + } + // Don't add spaces between a casting type and the quote or repetition count + // and the brace. + if ((Right.is(Keywords.kw_apostrophe) || + (Right.is(BK_BracedInit) && Right.is(tok::l_brace))) && + !(Left.isOneOf(Keywords.kw_assign, Keywords.kw_unique) || + Keywords.isVerilogWordOperator(Left)) && + (Left.isOneOf(tok::r_square, tok::r_paren, tok::r_brace, + tok::numeric_constant) || + Keywords.isWordLike(Left))) { + return false; + } + // Add space in attribute like `(* ASYNC_REG = "TRUE" *)`. + if (Left.endsSequence(tok::star, tok::l_paren) && Right.is(tok::identifier)) + return true; } if (Left.is(TT_ImplicitStringLiteral)) return Right.hasWhitespaceBefore(); @@ -4032,6 +4181,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, Style.BitFieldColonSpacing == FormatStyle::BFCS_After; } if (Right.is(tok::colon)) { + if (Right.is(TT_GotoLabelColon) || + (!Style.isVerilog() && + Line.First->isOneOf(tok::kw_default, tok::kw_case))) { + return Style.SpaceBeforeCaseColon; + } if (Line.First->isOneOf(tok::kw_default, tok::kw_case)) return Style.SpaceBeforeCaseColon; const FormatToken *Next = Right.getNextNonComment(); @@ -4049,6 +4203,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return false; if (Right.is(TT_CSharpNamedArgumentColon)) return false; + if (Right.is(TT_GenericSelectionColon)) + return false; if (Right.is(TT_BitFieldColon)) { return Style.BitFieldColonSpacing == FormatStyle::BFCS_Both || Style.BitFieldColonSpacing == FormatStyle::BFCS_Before; @@ -4157,7 +4313,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return false; } if (Right.is(tok::less) && Left.isNot(tok::l_paren) && - Line.startsWith(tok::hash)) { + Line.Type == LT_ImportStatement) { return true; } if (Right.is(TT_TrailingUnaryOperator)) @@ -4294,6 +4450,11 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, Right.Next->is(tok::string_literal)) { return true; } + } else if (Style.isVerilog()) { + // Break after labels. In Verilog labels don't have the 'case' keyword, so + // it is hard to identify them in UnwrappedLineParser. + if (!Keywords.isVerilogBegin(Right) && Keywords.isVerilogEndOfLabel(Left)) + return true; } else if (Style.Language == FormatStyle::LK_Cpp || Style.Language == FormatStyle::LK_ObjC || Style.Language == FormatStyle::LK_Proto || @@ -4310,18 +4471,27 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, // } if (Left.is(TT_DictLiteral) && Left.is(tok::l_brace)) return true; - // Always break after a JSON array opener. - // [ - // ] - if (Left.is(TT_ArrayInitializerLSquare) && Left.is(tok::l_square) && - !Right.is(tok::r_square)) { - return true; + // Always break after a JSON array opener based on BreakArrays. + if ((Left.is(TT_ArrayInitializerLSquare) && Left.is(tok::l_square) && + Right.isNot(tok::r_square)) || + Left.is(tok::comma)) { + if (Right.is(tok::l_brace)) + return true; + // scan to the right if an we see an object or an array inside + // then break. + for (const auto *Tok = &Right; Tok; Tok = Tok->Next) { + if (Tok->isOneOf(tok::l_brace, tok::l_square)) + return true; + if (Tok->isOneOf(tok::r_brace, tok::r_square)) + break; + } + return Style.BreakArrays; } - // Always break after successive entries. - // 1, - // 2 - if (Left.is(tok::comma)) - return true; + } + + if (Line.startsWith(tok::kw_asm) && Right.is(TT_InlineASMColon) && + Style.BreakBeforeInlineASMColon == FormatStyle::BBIAS_Always) { + return true; } // If the last token before a '}', ']', or ')' is a comma or a trailing @@ -4784,7 +4954,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, // // instead, even if it is longer by one line. // - // Note that this allows allows the "{" to go over the column limit + // Note that this allows the "{" to go over the column limit // when the column limit is just between ":" and "{", but that does // not happen too often and alternative formattings in this case are // not much better. @@ -4881,6 +5051,11 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, !Right.MatchingParen) { return false; } + auto Next = Right.Next; + if (Next && Next->is(tok::r_paren)) + Next = Next->Next; + if (Next && Next->is(tok::l_paren)) + return false; const FormatToken *Previous = Right.MatchingParen->Previous; return !(Previous && (Previous->is(tok::kw_for) || Previous->isIf())); } @@ -4961,7 +5136,9 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, } void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) const { - llvm::errs() << "AnnotatedTokens(L=" << Line.Level << "):\n"; + llvm::errs() << "AnnotatedTokens(L=" << Line.Level << ", P=" << Line.PPLevel + << ", T=" << Line.Type << ", C=" << Line.IsContinuation + << "):\n"; const FormatToken *Tok = Line.First; while (Tok) { llvm::errs() << " M=" << Tok->MustBreakBefore diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h index 1be64ed6d3b5..354511b6323a 100644 --- a/clang/lib/Format/TokenAnnotator.h +++ b/clang/lib/Format/TokenAnnotator.h @@ -31,18 +31,23 @@ enum LineType { LT_PreprocessorDirective, LT_VirtualFunctionDecl, LT_ArrayOfStructInitializer, + LT_CommentAbovePPDirective, }; class AnnotatedLine { public: AnnotatedLine(const UnwrappedLine &Line) : First(Line.Tokens.front().Tok), Level(Line.Level), + PPLevel(Line.PPLevel), MatchingOpeningBlockLineIndex(Line.MatchingOpeningBlockLineIndex), MatchingClosingBlockLineIndex(Line.MatchingClosingBlockLineIndex), InPPDirective(Line.InPPDirective), + InPragmaDirective(Line.InPragmaDirective), + InMacroBody(Line.InMacroBody), MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false), IsMultiVariableDeclStmt(false), Affected(false), LeadingEmptyLinesAffected(false), ChildrenAffected(false), + ReturnTypeWrapped(false), IsContinuation(Line.IsContinuation), FirstStartColumn(Line.FirstStartColumn) { assert(!Line.Tokens.empty()); @@ -125,9 +130,12 @@ public: LineType Type; unsigned Level; + unsigned PPLevel; size_t MatchingOpeningBlockLineIndex; size_t MatchingClosingBlockLineIndex; bool InPPDirective; + bool InPragmaDirective; + bool InMacroBody; bool MustBeDeclaration; bool MightBeFunctionDecl; bool IsMultiVariableDeclStmt; @@ -143,6 +151,13 @@ public: /// \c True if one of this line's children intersects with an input range. bool ChildrenAffected; + /// \c True if breaking after last attribute group in function return type. + bool ReturnTypeWrapped; + + /// \c True if this line should be indented by ContinuationIndent in addition + /// to the normal indention level. + bool IsContinuation; + unsigned FirstStartColumn; private: diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index abeb93d23776..8e1d907208c0 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -60,16 +60,23 @@ public: // Update the indent level cache size so that we can rely on it // having the right size in adjustToUnmodifiedline. skipLine(Line, /*UnknownIndent=*/true); - if (Line.InPPDirective) { - unsigned IndentWidth = + if (Style.IndentPPDirectives != FormatStyle::PPDIS_None && + (Line.InPPDirective || + (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash && + Line.Type == LT_CommentAbovePPDirective))) { + unsigned PPIndentWidth = (Style.PPIndentWidth >= 0) ? Style.PPIndentWidth : Style.IndentWidth; - Indent = Line.Level * IndentWidth + AdditionalIndent; + Indent = Line.InMacroBody + ? Line.PPLevel * PPIndentWidth + + (Line.Level - Line.PPLevel) * Style.IndentWidth + : Line.Level * PPIndentWidth; + Indent += AdditionalIndent; } else { Indent = getIndent(Line.Level); } if (static_cast<int>(Indent) + Offset >= 0) Indent += Offset; - if (Line.First->is(TT_CSharpGenericTypeConstraint)) + if (Line.IsContinuation) Indent = Line.Level * Style.IndentWidth + Style.ContinuationIndentWidth; } @@ -641,6 +648,7 @@ private: unsigned Length = 0; bool EndsWithComment = false; bool InPPDirective = I[0]->InPPDirective; + bool InMacroBody = I[0]->InMacroBody; const unsigned Level = I[0]->Level; for (; NumStmts < 3; ++NumStmts) { if (I + 1 + NumStmts == E) @@ -648,6 +656,8 @@ private: const AnnotatedLine *Line = I[1 + NumStmts]; if (Line->InPPDirective != InPPDirective) break; + if (Line->InMacroBody != InMacroBody) + break; if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace)) break; if (Line->First->isOneOf(tok::kw_if, tok::kw_for, tok::kw_switch, @@ -709,16 +719,23 @@ private: if (Tok && Tok->is(tok::colon)) return 0; } - if (Line.First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while, tok::kw_do, - tok::kw_try, tok::kw___try, tok::kw_catch, - tok::kw___finally, tok::kw_for, TT_ForEachMacro, - tok::r_brace, Keywords.kw___except)) { - if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never) - return 0; - if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Empty && - !I[1]->First->is(tok::r_brace)) { + + auto IsCtrlStmt = [](const auto &Line) { + return Line.First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while, + tok::kw_do, tok::kw_for, TT_ForEachMacro); + }; + + const bool IsSplitBlock = + Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never || + (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Empty && + I[1]->First->isNot(tok::r_brace)); + + if (IsCtrlStmt(Line) || + Line.First->isOneOf(tok::kw_try, tok::kw___try, tok::kw_catch, + tok::kw___finally, tok::r_brace, + Keywords.kw___except)) { + if (IsSplitBlock) return 0; - } // Don't merge when we can't except the case when // the control statement block is empty if (!Style.AllowShortIfStatementsOnASingleLine && @@ -761,6 +778,11 @@ private: } if (Line.Last->is(tok::l_brace)) { + if (IsSplitBlock && Line.First == Line.Last && + I > AnnotatedLines.begin() && + (I[-1]->endsWith(tok::kw_else) || IsCtrlStmt(*I[-1]))) { + return 0; + } FormatToken *Tok = I[1]->First; auto ShouldMerge = [Tok]() { if (Tok->isNot(tok::r_brace) || Tok->MustBreakBefore) @@ -1297,7 +1319,7 @@ unsigned UnwrappedLineFormatter::format( // We continue formatting unchanged lines to adjust their indent, e.g. if a // scope was added. However, we need to carefully stop doing this when we - // exit the scope of affected lines to prevent indenting a the entire + // exit the scope of affected lines to prevent indenting the entire // remaining file if it currently missing a closing brace. bool PreviousRBrace = PreviousLine && PreviousLine->startsWith(tok::r_brace); diff --git a/clang/lib/Format/UnwrappedLineFormatter.h b/clang/lib/Format/UnwrappedLineFormatter.h index 3e33de07fa12..ee6d31de8c42 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.h +++ b/clang/lib/Format/UnwrappedLineFormatter.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// Implements a combinartorial exploration of all the different +/// Implements a combinatorial exploration of all the different /// linebreaks unwrapped lines can be formatted in. /// //===----------------------------------------------------------------------===// diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 83b4f1e7991f..3e58b6f90559 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -41,13 +41,7 @@ public: // Returns the token that would be returned by the next call to // getNextToken(). - virtual FormatToken *peekNextToken() = 0; - - // Returns the token that would be returned after the next N calls to - // getNextToken(). N needs to be greater than zero, and small enough that - // there are still tokens. Check for tok::eof with N-1 before calling it with - // N. - virtual FormatToken *peekNextToken(int N) = 0; + virtual FormatToken *peekNextToken(bool SkipComment = false) = 0; // Returns whether we are at the end of the file. // This can be different from whether getNextToken() returned an eof token @@ -64,6 +58,39 @@ public: namespace { +void printLine(llvm::raw_ostream &OS, const UnwrappedLine &Line, + StringRef Prefix = "", bool PrintText = false) { + OS << Prefix << "Line(" << Line.Level << ", FSC=" << Line.FirstStartColumn + << ")" << (Line.InPPDirective ? " MACRO" : "") << ": "; + bool NewLine = false; + for (std::list<UnwrappedLineNode>::const_iterator I = Line.Tokens.begin(), + E = Line.Tokens.end(); + I != E; ++I) { + if (NewLine) { + OS << Prefix; + NewLine = false; + } + OS << I->Tok->Tok.getName() << "[" + << "T=" << (unsigned)I->Tok->getType() + << ", OC=" << I->Tok->OriginalColumn << ", \"" << I->Tok->TokenText + << "\"] "; + for (SmallVectorImpl<UnwrappedLine>::const_iterator + CI = I->Children.begin(), + CE = I->Children.end(); + CI != CE; ++CI) { + OS << "\n"; + printLine(OS, *CI, (Prefix + " ").str()); + NewLine = true; + } + } + if (!NewLine) + OS << "\n"; +} + +LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line) { + printLine(llvm::dbgs(), Line); +} + class ScopedDeclarationState { public: ScopedDeclarationState(UnwrappedLine &Line, llvm::BitVector &Stack, @@ -116,12 +143,14 @@ public: TokenSource = this; Line.Level = 0; Line.InPPDirective = true; + // InMacroBody gets set after the `#define x` part. } ~ScopedMacroState() override { TokenSource = PreviousTokenSource; ResetToken = Token; Line.InPPDirective = false; + Line.InMacroBody = false; Line.Level = PreviousLineLevel; } @@ -140,17 +169,10 @@ public: return PreviousTokenSource->getPreviousToken(); } - FormatToken *peekNextToken() override { + FormatToken *peekNextToken(bool SkipComment) override { if (eof()) return &FakeEOF; - return PreviousTokenSource->peekNextToken(); - } - - FormatToken *peekNextToken(int N) override { - assert(N > 0); - if (eof()) - return &FakeEOF; - return PreviousTokenSource->peekNextToken(N); + return PreviousTokenSource->peekNextToken(SkipComment); } bool isEOF() override { return PreviousTokenSource->isEOF(); } @@ -195,7 +217,9 @@ public: PreBlockLine = std::move(Parser.Line); Parser.Line = std::make_unique<UnwrappedLine>(); Parser.Line->Level = PreBlockLine->Level; + Parser.Line->PPLevel = PreBlockLine->PPLevel; Parser.Line->InPPDirective = PreBlockLine->InPPDirective; + Parser.Line->InMacroBody = PreBlockLine->InMacroBody; } ~ScopedLineState() { @@ -245,7 +269,7 @@ public: : Tokens(Tokens), Position(-1) {} FormatToken *getNextToken() override { - if (Position >= 0 && Tokens[Position]->is(tok::eof)) { + if (Position >= 0 && isEOF()) { LLVM_DEBUG({ llvm::dbgs() << "Next "; dbgToken(Position); @@ -264,8 +288,11 @@ public: return Position > 0 ? Tokens[Position - 1] : nullptr; } - FormatToken *peekNextToken() override { + FormatToken *peekNextToken(bool SkipComment) override { int Next = Position + 1; + if (SkipComment) + while (Tokens[Next]->is(tok::comment)) + ++Next; LLVM_DEBUG({ llvm::dbgs() << "Peeking "; dbgToken(Next); @@ -273,16 +300,6 @@ public: return Tokens[Next]; } - FormatToken *peekNextToken(int N) override { - assert(N > 0); - int Next = Position + N; - LLVM_DEBUG({ - llvm::dbgs() << "Peeking (+" << (N - 1) << ") "; - dbgToken(Next); - }); - return Tokens[Next]; - } - bool isEOF() override { return Tokens[Position]->is(tok::eof); } unsigned getPosition() override { @@ -573,12 +590,16 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, break; } // Else, if it is 'default:', fall through to the case handling. - LLVM_FALLTHROUGH; + [[fallthrough]]; } case tok::kw_case: - if (Style.isJavaScript() && Line->MustBeDeclaration) { - // A 'case: string' style field declaration. - parseStructuralElement(); + if (Style.isProto() || Style.isVerilog() || + (Style.isJavaScript() && Line->MustBeDeclaration)) { + // Proto: there are no switch/case statements + // Verilog: Case labels don't have this word. We handle case + // labels including default in TokenAnnotator. + // JavaScript: A 'case: string' style field declaration. + ParseDefault(); break; } if (!SwitchLabelEncountered && @@ -597,7 +618,7 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, } if (handleCppAttributes()) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; default: ParseDefault(); break; @@ -733,7 +754,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { case tok::identifier: if (!Tok->is(TT_StatementMacro)) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; case tok::at: case tok::semi: case tok::kw_if: @@ -812,9 +833,18 @@ bool UnwrappedLineParser::mightFitOnOneLine( auto Length = LastToken->TotalLength; if (OpeningBrace) { assert(OpeningBrace != Tokens.front().Tok); + if (auto Prev = OpeningBrace->Previous; + Prev && Prev->TotalLength + ColumnLimit == OpeningBrace->TotalLength) { + Length -= ColumnLimit; + } Length -= OpeningBrace->TokenText.size() + 1; } + if (const auto *FirstToken = Line.First; FirstToken->is(tok::r_brace)) { + assert(!OpeningBrace || OpeningBrace->is(TT_ControlStatementLBrace)); + Length -= FirstToken->TokenText.size() + 1; + } + Index = 0; for (auto &Token : Tokens) { const auto &SavedToken = SavedTokens[Index++]; @@ -823,6 +853,9 @@ bool UnwrappedLineParser::mightFitOnOneLine( delete SavedToken.Tok; } + // If these change PPLevel needs to be used for get correct indentation. + assert(!Line.InMacroBody); + assert(!Line.InPPDirective); return Line.Level * Style.IndentWidth + Length <= ColumnLimit; } @@ -839,8 +872,13 @@ FormatToken *UnwrappedLineParser::parseBlock( } }; + // Whether this is a Verilog-specific block that has a special header like a + // module. + const bool VerilogHierarchy = + Style.isVerilog() && Keywords.isVerilogHierarchy(*FormatTok); assert((FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) || - (Style.isVerilog() && Keywords.isVerilogBegin(*FormatTok))) && + (Style.isVerilog() && + (Keywords.isVerilogBegin(*FormatTok) || VerilogHierarchy))) && "'{' or macro block token expected"); FormatToken *Tok = FormatTok; const bool FollowedByComment = Tokens->peekNextToken()->is(tok::comment); @@ -850,14 +888,20 @@ FormatToken *UnwrappedLineParser::parseBlock( // For Whitesmiths mode, jump to the next level prior to skipping over the // braces. - if (AddLevels > 0 && Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) + if (!VerilogHierarchy && AddLevels > 0 && + Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) { ++Line->Level; + } size_t PPStartHash = computePPHash(); const unsigned InitialLevel = Line->Level; - nextToken(/*LevelDifference=*/AddLevels); - HandleVerilogBlockLabel(); + if (VerilogHierarchy) { + AddLevels += parseVerilogHierarchyHeader(); + } else { + nextToken(/*LevelDifference=*/AddLevels); + HandleVerilogBlockLabel(); + } // Bail out if there are too many levels. Otherwise, the stack might overflow. if (Line->Level > 300) @@ -899,6 +943,9 @@ FormatToken *UnwrappedLineParser::parseBlock( return IfLBrace; } + const bool IsFunctionRBrace = + FormatTok->is(tok::r_brace) && Tok->is(TT_FunctionLBrace); + auto RemoveBraces = [=]() mutable { if (!SimpleBlock) return false; @@ -938,11 +985,24 @@ FormatToken *UnwrappedLineParser::parseBlock( // Munch the closing brace. nextToken(/*LevelDifference=*/-AddLevels); + + // When this is a function block and there is an unnecessary semicolon + // afterwards then mark it as optional (so the RemoveSemi pass can get rid of + // it later). + if (Style.RemoveSemicolon && IsFunctionRBrace) { + while (FormatTok->is(tok::semi)) { + FormatTok->Optional = true; + nextToken(); + } + } + HandleVerilogBlockLabel(); if (MacroBlock && FormatTok->is(tok::l_paren)) parseParens(); + Line->Level = InitialLevel; + if (FormatTok->is(tok::kw_noexcept)) { // A noexcept in a requires expression. nextToken(); @@ -958,8 +1018,6 @@ FormatToken *UnwrappedLineParser::parseBlock( if (MunchSemi && FormatTok->is(tok::semi)) nextToken(); - Line->Level = InitialLevel; - if (PPStartHash == PPEndHash) { Line->MatchingOpeningBlockLineIndex = OpeningLineIndex; if (OpeningLineIndex != UnwrappedLine::kInvalidIndex) { @@ -1073,16 +1131,17 @@ void UnwrappedLineParser::parsePPDirective() { parsePPIf(/*IfDef=*/true); break; case tok::pp_else: - parsePPElse(); - break; case tok::pp_elifdef: case tok::pp_elifndef: case tok::pp_elif: - parsePPElIf(); + parsePPElse(); break; case tok::pp_endif: parsePPEndIf(); break; + case tok::pp_pragma: + parsePPPragma(); + break; default: parsePPUnknown(); break; @@ -1109,7 +1168,7 @@ void UnwrappedLineParser::conditionalCompilationStart(bool Unreachable) { PPLevelBranchIndex.push_back(0); PPLevelBranchCount.push_back(0); } - PPChainBranchIndex.push(0); + PPChainBranchIndex.push(Unreachable ? -1 : 0); bool Skip = PPLevelBranchIndex[PPBranchLevel] > 0; conditionalCompilationCondition(Unreachable || Skip); } @@ -1175,15 +1234,16 @@ void UnwrappedLineParser::parsePPElse() { // If a potential include guard has an #else, it's not an include guard. if (IncludeGuard == IG_Defined && PPBranchLevel == 0) IncludeGuard = IG_Rejected; + // Don't crash when there is an #else without an #if. + assert(PPBranchLevel >= -1); + if (PPBranchLevel == -1) + conditionalCompilationStart(/*Unreachable=*/true); conditionalCompilationAlternative(); - if (PPBranchLevel > -1) - --PPBranchLevel; + --PPBranchLevel; parsePPUnknown(); ++PPBranchLevel; } -void UnwrappedLineParser::parsePPElIf() { parsePPElse(); } - void UnwrappedLineParser::parsePPEndIf() { conditionalCompilationEnd(); parsePPUnknown(); @@ -1234,6 +1294,10 @@ void UnwrappedLineParser::parsePPDefine() { addUnwrappedLine(); ++Line->Level; + Line->PPLevel = PPBranchLevel + (IncludeGuard == IG_Defined ? 0 : 1); + assert((int)Line->PPLevel >= 0); + Line->InMacroBody = true; + // 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 @@ -1242,6 +1306,11 @@ void UnwrappedLineParser::parsePPDefine() { parseFile(); } +void UnwrappedLineParser::parsePPPragma() { + Line->InPragmaDirective = true; + parsePPUnknown(); +} + void UnwrappedLineParser::parsePPUnknown() { do { nextToken(); @@ -1369,7 +1438,15 @@ static bool isC78ParameterDecl(const FormatToken *Tok, const FormatToken *Next, return Tok->Previous && Tok->Previous->isOneOf(tok::l_paren, tok::comma); } -void UnwrappedLineParser::parseModuleImport() { +bool UnwrappedLineParser::parseModuleImport() { + assert(FormatTok->is(Keywords.kw_import) && "'import' expected"); + + if (auto Token = Tokens->peekNextToken(/*SkipComment=*/true); + !Token->Tok.getIdentifierInfo() && + !Token->isOneOf(tok::colon, tok::less, tok::string_literal)) { + return false; + } + nextToken(); while (!eof()) { if (FormatTok->is(tok::colon)) { @@ -1396,6 +1473,7 @@ void UnwrappedLineParser::parseModuleImport() { } addUnwrappedLine(); + return true; } // readTokenWithJavaScriptASI reads the next token and terminates the current @@ -1457,13 +1535,30 @@ void UnwrappedLineParser::parseStructuralElement( addUnwrappedLine(); return; } + + if (Style.isVerilog()) { + // Skip things that can exist before keywords like 'if' and 'case'. + while (true) { + if (FormatTok->isOneOf(Keywords.kw_priority, Keywords.kw_unique, + Keywords.kw_unique0)) { + nextToken(); + } else if (FormatTok->is(tok::l_paren) && + Tokens->peekNextToken()->is(tok::star)) { + parseParens(); + } else { + break; + } + } + } + + // Tokens that only make sense at the beginning of a line. switch (FormatTok->Tok.getKind()) { case tok::kw_asm: nextToken(); if (FormatTok->is(tok::l_brace)) { FormatTok->setFinalizedType(TT_InlineASMBrace); nextToken(); - while (FormatTok && FormatTok->isNot(tok::eof)) { + while (FormatTok && !eof()) { if (FormatTok->is(tok::r_brace)) { FormatTok->setFinalizedType(TT_InlineASMBrace); nextToken(); @@ -1523,6 +1618,9 @@ void UnwrappedLineParser::parseStructuralElement( parseSwitch(); return; case tok::kw_default: + // In Verilog default along with other labels are handled in the next loop. + if (Style.isVerilog()) + break; if (Style.isJavaScript() && Line->MustBeDeclaration) { // 'default: string' field declaration. break; @@ -1535,6 +1633,16 @@ void UnwrappedLineParser::parseStructuralElement( // e.g. "default void f() {}" in a Java interface. break; case tok::kw_case: + // Proto: there are no switch/case statements. + if (Style.isProto()) { + nextToken(); + return; + } + if (Style.isVerilog()) { + parseBlock(); + addUnwrappedLine(); + return; + } if (Style.isJavaScript() && Line->MustBeDeclaration) { // 'case: string' field declaration. nextToken(); @@ -1552,7 +1660,14 @@ void UnwrappedLineParser::parseStructuralElement( return; case tok::kw_extern: nextToken(); - if (FormatTok->is(tok::string_literal)) { + if (Style.isVerilog()) { + // In Verilog and extern module declaration looks like a start of module. + // But there is no body and endmodule. So we handle it separately. + if (Keywords.isVerilogHierarchy(*FormatTok)) { + parseVerilogHierarchyHeader(); + return; + } + } else if (FormatTok->is(tok::string_literal)) { nextToken(); if (FormatTok->is(tok::l_brace)) { if (Style.BraceWrapping.AfterExternBlock) @@ -1577,10 +1692,16 @@ void UnwrappedLineParser::parseStructuralElement( parseJavaScriptEs6ImportExport(); return; } - if (!Style.isCpp()) - break; - // Handle C++ "(inline|export) namespace". - LLVM_FALLTHROUGH; + if (Style.isCpp()) { + nextToken(); + if (FormatTok->is(tok::kw_namespace)) { + parseNamespace(); + return; + } + if (FormatTok->is(Keywords.kw_import) && parseModuleImport()) + return; + } + break; case tok::kw_inline: nextToken(); if (FormatTok->is(tok::kw_namespace)) { @@ -1615,10 +1736,8 @@ void UnwrappedLineParser::parseStructuralElement( addUnwrappedLine(); return; } - if (Style.isCpp()) { - parseModuleImport(); + if (Style.isCpp() && parseModuleImport()) return; - } } if (Style.isCpp() && FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals, @@ -1712,9 +1831,6 @@ void UnwrappedLineParser::parseStructuralElement( break; } break; - case tok::kw_concept: - parseConcept(); - return; case tok::kw_requires: { if (Style.isCpp()) { bool ParsedClause = parseRequires(); @@ -1751,9 +1867,15 @@ void UnwrappedLineParser::parseStructuralElement( parseEnum(); } break; + case tok::kw_class: + if (Style.isVerilog()) { + parseBlock(); + addUnwrappedLine(); + return; + } + [[fallthrough]]; case tok::kw_struct: case tok::kw_union: - case tok::kw_class: if (parseStructLike()) return; break; @@ -1782,9 +1904,11 @@ void UnwrappedLineParser::parseStructuralElement( parseParens(); // Break the unwrapped line if a K&R C function definition has a parameter // declaration. - if (!IsTopLevel || !Style.isCpp() || !Previous || FormatTok->is(tok::eof)) + if (!IsTopLevel || !Style.isCpp() || !Previous || eof()) break; - if (isC78ParameterDecl(FormatTok, Tokens->peekNextToken(), Previous)) { + if (isC78ParameterDecl(FormatTok, + Tokens->peekNextToken(/*SkipComment=*/true), + Previous)) { addUnwrappedLine(); return; } @@ -1825,8 +1949,7 @@ void UnwrappedLineParser::parseStructuralElement( } else if (Style.BraceWrapping.AfterFunction) { addUnwrappedLine(); } - if (!Line->InPPDirective) - FormatTok->setFinalizedType(TT_FunctionLBrace); + FormatTok->setFinalizedType(TT_FunctionLBrace); parseBlock(); addUnwrappedLine(); return; @@ -1888,6 +2011,19 @@ void UnwrappedLineParser::parseStructuralElement( return; } + if (Style.isVerilog()) { + if (FormatTok->is(Keywords.kw_table)) { + parseVerilogTable(); + return; + } + if (Keywords.isVerilogBegin(*FormatTok) || + Keywords.isVerilogHierarchy(*FormatTok)) { + parseBlock(); + addUnwrappedLine(); + return; + } + } + if (FormatTok->is(Keywords.kw_interface)) { if (parseStructLike()) return; @@ -1919,7 +2055,9 @@ void UnwrappedLineParser::parseStructuralElement( return I != E && (++I == E); }; if (OneTokenSoFar()) { - if (FormatTok->is(tok::colon) && !Line->MustBeDeclaration) { + // In Verilog labels can be any expression, so we don't do them here. + if (!Style.isVerilog() && FormatTok->is(tok::colon) && + !Line->MustBeDeclaration) { Line->Tokens.begin()->Tok->MustBreakBefore = true; parseLabel(!Style.IndentGotoLabels); if (HasLabel) @@ -1939,7 +2077,8 @@ void UnwrappedLineParser::parseStructuralElement( if (FollowedByNewline && (Text.size() >= 5 || FunctionLike) && tokenCanStartNewLine(*FormatTok) && Text == Text.upper()) { - PreviousToken->setFinalizedType(TT_FunctionLikeOrFreestandingMacro); + if (PreviousToken->isNot(TT_UntouchableMacroFunc)) + PreviousToken->setFinalizedType(TT_FunctionLikeOrFreestandingMacro); addUnwrappedLine(); return; } @@ -1976,6 +2115,17 @@ void UnwrappedLineParser::parseStructuralElement( parseNew(); break; case tok::kw_case: + // Proto: there are no switch/case statements. + if (Style.isProto()) { + nextToken(); + return; + } + // In Verilog switch is called case. + if (Style.isVerilog()) { + parseBlock(); + addUnwrappedLine(); + return; + } if (Style.isJavaScript() && Line->MustBeDeclaration) { // 'case: string' field declaration. nextToken(); @@ -1983,6 +2133,30 @@ void UnwrappedLineParser::parseStructuralElement( } parseCaseLabel(); break; + case tok::kw_default: + nextToken(); + if (Style.isVerilog()) { + if (FormatTok->is(tok::colon)) { + // The label will be handled in the next iteration. + break; + } + if (FormatTok->is(Keywords.kw_clocking)) { + // A default clocking block. + parseBlock(); + addUnwrappedLine(); + return; + } + parseVerilogCaseLabel(); + return; + } + break; + case tok::colon: + nextToken(); + if (Style.isVerilog()) { + parseVerilogCaseLabel(); + return; + } + break; default: nextToken(); break; @@ -2108,26 +2282,29 @@ bool UnwrappedLineParser::tryToParseLambda() { case tok::l_square: parseSquare(); break; - case tok::kw_class: - case tok::kw_template: - case tok::kw_typename: + case tok::less: assert(FormatTok->Previous); - if (FormatTok->Previous->is(tok::less)) + if (FormatTok->Previous->is(tok::r_square)) InTemplateParameterList = true; nextToken(); break; + case tok::kw_auto: + case tok::kw_class: + case tok::kw_template: + case tok::kw_typename: case tok::amp: case tok::star: case tok::kw_const: case tok::kw_constexpr: + case tok::kw_consteval: case tok::comma: - case tok::less: case tok::greater: case tok::identifier: case tok::numeric_constant: case tok::coloncolon: case tok::kw_mutable: case tok::kw_noexcept: + case tok::kw_static: nextToken(); break; // Specialization of a template with an integer parameter can contain @@ -2201,7 +2378,7 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() { if (FormatTok->is(tok::l_square)) return false; if (FormatTok->is(tok::r_square)) { - const FormatToken *Next = Tokens->peekNextToken(); + const FormatToken *Next = Tokens->peekNextToken(/*SkipComment=*/true); if (Next->is(tok::greater)) return false; } @@ -2432,7 +2609,7 @@ void UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) { case tok::ampamp: if (AmpAmpTokenType != TT_Unknown) FormatTok->setFinalizedType(AmpAmpTokenType); - LLVM_FALLTHROUGH; + [[fallthrough]]; default: nextToken(); break; @@ -2502,8 +2679,10 @@ void UnwrappedLineParser::parseUnbracedBody(bool CheckEOF) { FormatToken *Tok = nullptr; if (Style.InsertBraces && !Line->InPPDirective && !Line->Tokens.empty() && - PreprocessorDirectives.empty()) { - Tok = getLastNonComment(*Line); + PreprocessorDirectives.empty() && FormatTok->isNot(tok::semi)) { + Tok = Style.BraceWrapping.AfterControlStatement == FormatStyle::BWACS_Never + ? getLastNonComment(*Line) + : Line->Tokens.back().Tok; assert(Tok); if (Tok->BraceCount < 0) { assert(Tok->BraceCount == -1); @@ -2530,7 +2709,7 @@ void UnwrappedLineParser::parseUnbracedBody(bool CheckEOF) { ++Tok->BraceCount; } - if (CheckEOF && FormatTok->is(tok::eof)) + if (CheckEOF && eof()) addUnwrappedLine(); --Line->Level; @@ -2572,6 +2751,14 @@ bool UnwrappedLineParser::handleCppAttributes() { return false; } +/// Returns whether \c Tok begins a block. +bool UnwrappedLineParser::isBlockBegin(const FormatToken &Tok) const { + // FIXME: rename the function or make + // Tok.isOneOf(tok::l_brace, TT_MacroBlockBegin) work. + return Style.isVerilog() ? Keywords.isVerilogBegin(Tok) + : Tok.is(tok::l_brace); +} + FormatToken *UnwrappedLineParser::parseIfThenElse(IfStmtKind *IfKind, bool KeepBraces) { assert(FormatTok->is(tok::kw_if) && "'if' expected"); @@ -2597,7 +2784,7 @@ FormatToken *UnwrappedLineParser::parseIfThenElse(IfStmtKind *IfKind, FormatToken *IfLeftBrace = nullptr; IfStmtKind IfBlockKind = IfStmtKind::NotIf; - if (Keywords.isBlockBegin(*FormatTok, Style)) { + if (isBlockBegin(*FormatTok)) { FormatTok->setFinalizedType(TT_ControlStatementLBrace); IfLeftBrace = FormatTok; CompoundStatementIndenter Indenter(this, Style, Line->Level); @@ -2630,7 +2817,7 @@ FormatToken *UnwrappedLineParser::parseIfThenElse(IfStmtKind *IfKind, } nextToken(); handleAttributes(); - if (Keywords.isBlockBegin(*FormatTok, Style)) { + if (isBlockBegin(*FormatTok)) { const bool FollowedByIf = Tokens->peekNextToken()->is(tok::kw_if); FormatTok->setFinalizedType(TT_ElseLBrace); ElseLeftBrace = FormatTok; @@ -2862,6 +3049,11 @@ void UnwrappedLineParser::parseNew() { if (Style.isCSharp()) { do { + // Handle constructor invocation, e.g. `new(field: value)`. + if (FormatTok->is(tok::l_paren)) + parseParens(); + + // Handle array initialization syntax, e.g. `new[] {10, 20, 30}`. if (FormatTok->is(tok::l_brace)) parseBracedList(); @@ -2897,7 +3089,7 @@ void UnwrappedLineParser::parseNew() { void UnwrappedLineParser::parseLoopBody(bool KeepBraces, bool WrapRightBrace) { keepAncestorBraces(); - if (Keywords.isBlockBegin(*FormatTok, Style)) { + if (isBlockBegin(*FormatTok)) { if (!KeepBraces) FormatTok->setFinalizedType(TT_ControlStatementLBrace); FormatToken *LeftBrace = FormatTok; @@ -3102,26 +3294,6 @@ void UnwrappedLineParser::parseAccessSpecifier() { } } -/// \brief Parses a concept definition. -/// \pre The current token has to be the concept keyword. -/// -/// Returns if either the concept has been completely parsed, or if it detects -/// that the concept definition is incorrect. -void UnwrappedLineParser::parseConcept() { - assert(FormatTok->is(tok::kw_concept) && "'concept' expected"); - nextToken(); - if (!FormatTok->is(tok::identifier)) - return; - nextToken(); - if (!FormatTok->is(tok::equal)) - return; - nextToken(); - parseConstraintExpression(); - if (FormatTok->is(tok::semi)) - nextToken(); - addUnwrappedLine(); -} - /// \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. @@ -3204,37 +3376,41 @@ bool clang::format::UnwrappedLineParser::parseRequires() { // So we want basically to check for TYPE NAME, but TYPE can contain all kinds // of stuff: typename, const, *, &, &&, ::, identifiers. - int NextTokenOffset = 1; - auto NextToken = Tokens->peekNextToken(NextTokenOffset); - auto PeekNext = [&NextTokenOffset, &NextToken, this] { - ++NextTokenOffset; - NextToken = Tokens->peekNextToken(NextTokenOffset); + unsigned StoredPosition = Tokens->getPosition(); + FormatToken *NextToken = Tokens->getNextToken(); + int Lookahead = 0; + auto PeekNext = [&Lookahead, &NextToken, this] { + ++Lookahead; + NextToken = Tokens->getNextToken(); }; bool FoundType = false; bool LastWasColonColon = false; int OpenAngles = 0; - for (; NextTokenOffset < 50; PeekNext()) { + for (; Lookahead < 50; PeekNext()) { switch (NextToken->Tok.getKind()) { case tok::kw_volatile: case tok::kw_const: case tok::comma: + FormatTok = Tokens->setPosition(StoredPosition); parseRequiresExpression(RequiresToken); return false; case tok::r_paren: case tok::pipepipe: + FormatTok = Tokens->setPosition(StoredPosition); parseRequiresClause(RequiresToken); return true; case tok::eof: // Break out of the loop. - NextTokenOffset = 50; + Lookahead = 50; break; case tok::coloncolon: LastWasColonColon = true; break; case tok::identifier: if (FoundType && !LastWasColonColon && OpenAngles == 0) { + FormatTok = Tokens->setPosition(StoredPosition); parseRequiresExpression(RequiresToken); return false; } @@ -3249,14 +3425,15 @@ bool clang::format::UnwrappedLineParser::parseRequires() { break; default: if (NextToken->isSimpleTypeSpecifier()) { + FormatTok = Tokens->setPosition(StoredPosition); parseRequiresExpression(RequiresToken); return false; } break; } } - // This seems to be a complicated expression, just assume it's a clause. + FormatTok = Tokens->setPosition(StoredPosition); parseRequiresClause(RequiresToken); return true; } @@ -3283,6 +3460,8 @@ void UnwrappedLineParser::parseRequiresClause(FormatToken *RequiresToken) { ? TT_RequiresClauseInARequiresExpression : TT_RequiresClause); + // NOTE: parseConstraintExpression is only ever called from this function. + // It could be inlined into here. parseConstraintExpression(); if (!InRequiresExpression) @@ -3316,9 +3495,8 @@ void UnwrappedLineParser::parseRequiresExpression(FormatToken *RequiresToken) { /// \brief Parses a constraint expression. /// -/// This is either the definition of a concept, or the body of a requires -/// clause. It returns, when the parsing is complete, or the expression is -/// incorrect. +/// This is the body of a requires clause. It returns, when the parsing is +/// complete, or the expression is incorrect. void UnwrappedLineParser::parseConstraintExpression() { // The special handling for lambdas is needed since tryToParseLambda() eats a // token and if a requires expression is the last part of a requires clause @@ -3385,7 +3563,6 @@ void UnwrappedLineParser::parseConstraintExpression() { case tok::minus: case tok::star: case tok::slash: - case tok::kw_decltype: LambdaNextTimeAllowed = true; // Just eat them. nextToken(); @@ -3417,9 +3594,9 @@ void UnwrappedLineParser::parseConstraintExpression() { // concept C = bool(...); // and bool is the only type, all other types as cast must be inside a // cast to bool an thus are handled by the other cases. - nextToken(); - if (FormatTok->isNot(tok::l_paren)) + if (Tokens->peekNextToken()->isNot(tok::l_paren)) return; + nextToken(); parseParens(); break; @@ -3438,7 +3615,8 @@ void UnwrappedLineParser::parseConstraintExpression() { switch (FormatTok->Previous->Tok.getKind()) { case tok::coloncolon: // Nested identifier. case tok::ampamp: // Start of a function or variable for the - case tok::pipepipe: // constraint expression. + case tok::pipepipe: // constraint expression. (binary) + case tok::exclaim: // The same as above, but unary. case tok::kw_requires: // Initial identifier of a requires clause. case tok::equal: // Initial identifier of a concept declaration. break; @@ -3639,7 +3817,7 @@ void UnwrappedLineParser::parseJavaEnumBody() { ++Line->Level; // Parse the enum constants. - while (FormatTok->isNot(tok::eof)) { + while (!eof()) { if (FormatTok->is(tok::l_brace)) { // Parse the constant's class body. parseBlock(/*MustBeDeclaration=*/true, /*AddLevels=*/1u, @@ -3989,21 +4167,176 @@ void UnwrappedLineParser::parseStatementMacro() { addUnwrappedLine(); } -LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line, - StringRef Prefix = "") { - llvm::dbgs() << Prefix << "Line(" << Line.Level - << ", FSC=" << Line.FirstStartColumn << ")" - << (Line.InPPDirective ? " MACRO" : "") << ": "; - for (const auto &Node : Line.Tokens) { - llvm::dbgs() << Node.Tok->Tok.getName() << "[" - << "T=" << static_cast<unsigned>(Node.Tok->getType()) - << ", OC=" << Node.Tok->OriginalColumn << "] "; - } - for (const auto &Node : Line.Tokens) - for (const auto &ChildNode : Node.Children) - printDebugInfo(ChildNode, "\nChild: "); - - llvm::dbgs() << "\n"; +void UnwrappedLineParser::parseVerilogHierarchyIdentifier() { + // consume things like a::`b.c[d:e] or a::* + while (true) { + if (FormatTok->isOneOf(tok::star, tok::period, tok::periodstar, + tok::coloncolon, tok::hash) || + Keywords.isVerilogIdentifier(*FormatTok)) { + nextToken(); + } else if (FormatTok->is(tok::l_square)) { + parseSquare(); + } else { + break; + } + } +} + +void UnwrappedLineParser::parseVerilogSensitivityList() { + if (!FormatTok->is(tok::at)) + return; + nextToken(); + // A block event expression has 2 at signs. + if (FormatTok->is(tok::at)) + nextToken(); + switch (FormatTok->Tok.getKind()) { + case tok::star: + nextToken(); + break; + case tok::l_paren: + parseParens(); + break; + default: + parseVerilogHierarchyIdentifier(); + break; + } +} + +unsigned UnwrappedLineParser::parseVerilogHierarchyHeader() { + unsigned AddLevels = 0; + + if (FormatTok->is(Keywords.kw_clocking)) { + nextToken(); + if (Keywords.isVerilogIdentifier(*FormatTok)) + nextToken(); + parseVerilogSensitivityList(); + if (FormatTok->is(tok::semi)) + nextToken(); + } else if (FormatTok->isOneOf(tok::kw_case, Keywords.kw_casex, + Keywords.kw_casez, Keywords.kw_randcase, + Keywords.kw_randsequence)) { + if (Style.IndentCaseLabels) + AddLevels++; + nextToken(); + if (FormatTok->is(tok::l_paren)) { + FormatTok->setFinalizedType(TT_ConditionLParen); + parseParens(); + } + if (FormatTok->isOneOf(Keywords.kw_inside, Keywords.kw_matches)) + nextToken(); + // The case header has no semicolon. + } else { + // "module" etc. + nextToken(); + // all the words like the name of the module and specifiers like + // "automatic" and the width of function return type + while (true) { + if (FormatTok->is(tok::l_square)) { + auto Prev = FormatTok->getPreviousNonComment(); + if (Prev && Keywords.isVerilogIdentifier(*Prev)) + Prev->setFinalizedType(TT_VerilogDimensionedTypeName); + parseSquare(); + } else if (Keywords.isVerilogIdentifier(*FormatTok) || + FormatTok->isOneOf(Keywords.kw_automatic, tok::kw_static)) { + nextToken(); + } else { + break; + } + } + + auto NewLine = [this]() { + addUnwrappedLine(); + Line->IsContinuation = true; + }; + + // package imports + while (FormatTok->is(Keywords.kw_import)) { + NewLine(); + nextToken(); + parseVerilogHierarchyIdentifier(); + if (FormatTok->is(tok::semi)) + nextToken(); + } + + // parameters and ports + if (FormatTok->is(Keywords.kw_verilogHash)) { + NewLine(); + nextToken(); + if (FormatTok->is(tok::l_paren)) + parseParens(); + } + if (FormatTok->is(tok::l_paren)) { + NewLine(); + parseParens(); + } + + // extends and implements + if (FormatTok->is(Keywords.kw_extends)) { + NewLine(); + nextToken(); + parseVerilogHierarchyIdentifier(); + if (FormatTok->is(tok::l_paren)) + parseParens(); + } + if (FormatTok->is(Keywords.kw_implements)) { + NewLine(); + do { + nextToken(); + parseVerilogHierarchyIdentifier(); + } while (FormatTok->is(tok::comma)); + } + + // Coverage event for cover groups. + if (FormatTok->is(tok::at)) { + NewLine(); + parseVerilogSensitivityList(); + } + + if (FormatTok->is(tok::semi)) + nextToken(/*LevelDifference=*/1); + addUnwrappedLine(); + } + + return AddLevels; +} + +void UnwrappedLineParser::parseVerilogTable() { + assert(FormatTok->is(Keywords.kw_table)); + nextToken(/*LevelDifference=*/1); + addUnwrappedLine(); + + auto InitialLevel = Line->Level++; + while (!eof() && !Keywords.isVerilogEnd(*FormatTok)) { + FormatToken *Tok = FormatTok; + nextToken(); + if (Tok->is(tok::semi)) + addUnwrappedLine(); + else if (Tok->isOneOf(tok::star, tok::colon, tok::question, tok::minus)) + Tok->setFinalizedType(TT_VerilogTableItem); + } + Line->Level = InitialLevel; + nextToken(/*LevelDifference=*/-1); + addUnwrappedLine(); +} + +void UnwrappedLineParser::parseVerilogCaseLabel() { + // The label will get unindented in AnnotatingParser. If there are no leading + // spaces, indent the rest here so that things inside the block will be + // indented relative to things outside. We don't use parseLabel because we + // don't know whether this colon is a label or a ternary expression at this + // point. + auto OrigLevel = Line->Level; + auto FirstLine = CurrentLines->size(); + if (Line->Level == 0 || (Line->InPPDirective && Line->Level <= 1)) + ++Line->Level; + else if (!Style.IndentCaseBlocks && Keywords.isVerilogBegin(*FormatTok)) + --Line->Level; + parseStructuralElement(); + // Restore the indentation in both the new line and the line that has the + // label. + if (CurrentLines->size() > FirstLine) + (*CurrentLines)[FirstLine].Level = OrigLevel; + Line->Level = OrigLevel; } void UnwrappedLineParser::addUnwrappedLine(LineLevel AdjustLevel) { @@ -4026,6 +4359,7 @@ void UnwrappedLineParser::addUnwrappedLine(LineLevel AdjustLevel) { Line->Tokens.clear(); Line->MatchingOpeningBlockLineIndex = UnwrappedLine::kInvalidIndex; Line->FirstStartColumn = 0; + Line->IsContinuation = false; if (ClosesWhitesmithsBlock && AdjustLevel == LineLevel::Remove) --Line->Level; diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index 3394bfab8b8e..f043e567eb73 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -44,11 +44,23 @@ struct UnwrappedLine { /// The indent level of the \c UnwrappedLine. unsigned Level; + /// The \c PPBranchLevel (adjusted for header guards) if this line is a + /// \c InMacroBody line, and 0 otherwise. + unsigned PPLevel; + /// Whether this \c UnwrappedLine is part of a preprocessor directive. bool InPPDirective; + /// Whether this \c UnwrappedLine is part of a pramga directive. + bool InPragmaDirective; + /// Whether it is part of a macro body. + bool InMacroBody; bool MustBeDeclaration; + /// \c True if this line should be indented by ContinuationIndent in + /// addition to the normal indention level. + bool IsContinuation = false; + /// If this \c UnwrappedLine closes a block in a sequence of lines, /// \c MatchingOpeningBlockLineIndex stores the index of the corresponding /// opening line. Otherwise, \c MatchingOpeningBlockLineIndex must be @@ -111,9 +123,9 @@ private: void parsePPDirective(); void parsePPDefine(); void parsePPIf(bool IfDef); - void parsePPElIf(); void parsePPElse(); void parsePPEndIf(); + void parsePPPragma(); void parsePPUnknown(); void readTokenWithJavaScriptASI(); void parseStructuralElement(bool IsTopLevel = false, @@ -131,6 +143,7 @@ private: void parseUnbracedBody(bool CheckEOF = false); void handleAttributes(); bool handleCppAttributes(); + bool isBlockBegin(const FormatToken &Tok) const; FormatToken *parseIfThenElse(IfStmtKind *IfKind, bool KeepBraces = false); void parseTryCatch(); void parseLoopBody(bool KeepBraces, bool WrapRightBrace); @@ -140,12 +153,11 @@ private: void parseCaseLabel(); void parseSwitch(); void parseNamespace(); - void parseModuleImport(); + bool parseModuleImport(); void parseNew(); void parseAccessSpecifier(); bool parseEnum(); bool parseStructLike(); - void parseConcept(); bool parseRequires(); void parseRequiresClause(FormatToken *RequiresToken); void parseRequiresExpression(FormatToken *RequiresToken); @@ -174,6 +186,13 @@ private: bool tryToParsePropertyAccessor(); void tryToParseJSFunction(); bool tryToParseSimpleAttribute(); + void parseVerilogHierarchyIdentifier(); + void parseVerilogSensitivityList(); + // Returns the number of levels of indentation in addition to the normal 1 + // level for a block, used for indenting case labels. + unsigned parseVerilogHierarchyHeader(); + void parseVerilogTable(); + void parseVerilogCaseLabel(); // Used by addUnwrappedLine to denote whether to keep or remove a level // when resetting the line state. @@ -197,7 +216,7 @@ private: // // NextTok specifies the next token. A null pointer NextTok is supported, and // signifies either the absence of a next token, or that the next token - // shouldn't be taken into accunt for the analysis. + // shouldn't be taken into account for the analysis. void distributeComments(const SmallVectorImpl<FormatToken *> &Comments, const FormatToken *NextTok); @@ -342,7 +361,8 @@ struct UnwrappedLineNode { }; inline UnwrappedLine::UnwrappedLine() - : Level(0), InPPDirective(false), MustBeDeclaration(false), + : Level(0), PPLevel(0), InPPDirective(false), InPragmaDirective(false), + InMacroBody(false), MustBeDeclaration(false), MatchingOpeningBlockLineIndex(kInvalidIndex) {} } // end namespace format diff --git a/clang/lib/Format/UsingDeclarationsSorter.cpp b/clang/lib/Format/UsingDeclarationsSorter.cpp index bf5307260c0b..2f4b1e0e4627 100644 --- a/clang/lib/Format/UsingDeclarationsSorter.cpp +++ b/clang/lib/Format/UsingDeclarationsSorter.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "UsingDeclarationsSorter.h" +#include "clang/Format/Format.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Regex.h" @@ -32,7 +33,7 @@ namespace { // individual names is that all non-namespace names come before all namespace // names, and within those groups, names are in case-insensitive lexicographic // order. -int compareLabels(StringRef A, StringRef B) { +int compareLabelsLexicographicNumeric(StringRef A, StringRef B) { SmallVector<StringRef, 2> NamesA; A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false); SmallVector<StringRef, 2> NamesB; @@ -64,16 +65,38 @@ int compareLabels(StringRef A, StringRef B) { return 0; } +int compareLabelsLexicographic(StringRef A, StringRef B) { + SmallVector<StringRef, 2> NamesA; + A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false); + SmallVector<StringRef, 2> NamesB; + B.split(NamesB, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false); + size_t SizeA = NamesA.size(); + size_t SizeB = NamesB.size(); + for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) { + // Two namespaces names within a group compare case-insensitively. + int C = NamesA[I].compare_insensitive(NamesB[I]); + if (C != 0) + return C; + } + if (SizeA < SizeB) + return -1; + return SizeA == SizeB ? 0 : 1; +} + +int compareLabels( + StringRef A, StringRef B, + FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations) { + if (SortUsingDeclarations == FormatStyle::SUD_LexicographicNumeric) + return compareLabelsLexicographicNumeric(A, B); + return compareLabelsLexicographic(A, B); +} + struct UsingDeclaration { const AnnotatedLine *Line; std::string Label; UsingDeclaration(const AnnotatedLine *Line, const std::string &Label) : Line(Line), Label(Label) {} - - bool operator<(const UsingDeclaration &Other) const { - return compareLabels(Label, Other.Label) < 0; - } }; /// Computes the label of a using declaration starting at tthe using token @@ -113,7 +136,8 @@ std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) { void endUsingDeclarationBlock( SmallVectorImpl<UsingDeclaration> *UsingDeclarations, - const SourceManager &SourceMgr, tooling::Replacements *Fixes) { + const SourceManager &SourceMgr, tooling::Replacements *Fixes, + FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations) { bool BlockAffected = false; for (const UsingDeclaration &Declaration : *UsingDeclarations) { if (Declaration.Line->Affected) { @@ -127,7 +151,11 @@ void endUsingDeclarationBlock( } SmallVector<UsingDeclaration, 4> SortedUsingDeclarations( UsingDeclarations->begin(), UsingDeclarations->end()); - llvm::stable_sort(SortedUsingDeclarations); + auto Comp = [SortUsingDeclarations](const UsingDeclaration &Lhs, + const UsingDeclaration &Rhs) -> bool { + return compareLabels(Lhs.Label, Rhs.Label, SortUsingDeclarations) < 0; + }; + llvm::stable_sort(SortedUsingDeclarations, Comp); SortedUsingDeclarations.erase( std::unique(SortedUsingDeclarations.begin(), SortedUsingDeclarations.end(), @@ -192,21 +220,26 @@ std::pair<tooling::Replacements, unsigned> UsingDeclarationsSorter::analyze( const auto *FirstTok = Line->First; if (Line->InPPDirective || !Line->startsWith(tok::kw_using) || FirstTok->Finalized) { - endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); + endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes, + Style.SortUsingDeclarations); continue; } - if (FirstTok->NewlinesBefore > 1) - endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); + if (FirstTok->NewlinesBefore > 1) { + endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes, + Style.SortUsingDeclarations); + } const auto *UsingTok = FirstTok->is(tok::comment) ? FirstTok->getNextNonComment() : FirstTok; std::string Label = computeUsingDeclarationLabel(UsingTok); if (Label.empty()) { - endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); + endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes, + Style.SortUsingDeclarations); continue; } UsingDeclarations.push_back(UsingDeclaration(Line, Label)); } - endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); + endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes, + Style.SortUsingDeclarations); return {Fixes, 0}; } diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index 6ec788ad23c6..9951906b6af0 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -522,6 +522,13 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, ? Changes[StartAt].indentAndNestingLevel() : std::tuple<unsigned, unsigned, unsigned>(); + // Keep track if the first token has a non-zero indent and nesting level. + // This can happen when aligning the contents of "#else" preprocessor blocks, + // which is done separately. + bool HasInitialIndentAndNesting = + StartAt == 0 && + IndentAndNestingLevel > std::tuple<unsigned, unsigned, unsigned>(); + // Keep track of the number of commas before the matching tokens, we will only // align a sequence of matching tokens if they are preceded by the same number // of commas. @@ -556,8 +563,19 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, unsigned i = StartAt; for (unsigned e = Changes.size(); i != e; ++i) { - if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) - break; + if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) { + if (!HasInitialIndentAndNesting) + break; + // The contents of preprocessor blocks are aligned separately. + // If the initial preprocessor block is indented or nested (e.g. it's in + // a function), do not align and exit after finishing this scope block. + // Instead, align, and then lower the baseline indent and nesting level + // in order to continue aligning subsequent blocks. + EndOfSequence = i; + AlignCurrentSequence(); + IndentAndNestingLevel = + Changes[i].indentAndNestingLevel(); // new baseline + } if (Changes[i].NewlinesBefore != 0) { CommasBeforeMatch = 0; @@ -591,7 +609,8 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, ++CommasBeforeMatch; } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { // Call AlignTokens recursively, skipping over this scope block. - unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS); + unsigned StoppedAt = + AlignTokens(Style, Matches, Changes, i, ACS, RightJustify); i = StoppedAt - 1; continue; } @@ -852,9 +871,7 @@ void WhitespaceManager::alignConsecutiveDeclarations() { AlignTokens( Style, [](Change const &C) { - // tok::kw_operator is necessary for aligning operator overload - // definitions. - if (C.Tok->isOneOf(TT_FunctionDeclarationName, tok::kw_operator)) + if (C.Tok->is(TT_FunctionDeclarationName)) return true; if (C.Tok->isNot(TT_StartOfName)) return false; @@ -927,6 +944,10 @@ void WhitespaceManager::alignTrailingComments() { unsigned StartOfSequence = 0; bool BreakBeforeNext = false; unsigned Newlines = 0; + unsigned int NewLineThreshold = 1; + if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Always) + NewLineThreshold = Style.AlignTrailingComments.OverEmptyLines + 1; + for (unsigned i = 0, e = Changes.size(); i != e; ++i) { if (Changes[i].StartOfBlockComment) continue; @@ -934,6 +955,21 @@ void WhitespaceManager::alignTrailingComments() { if (!Changes[i].IsTrailingComment) continue; + if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Leave) { + auto OriginalSpaces = + Changes[i].OriginalWhitespaceRange.getEnd().getRawEncoding() - + Changes[i].OriginalWhitespaceRange.getBegin().getRawEncoding() - + Changes[i].Tok->NewlinesBefore; + unsigned RestoredLineLength = Changes[i].StartOfTokenColumn + + Changes[i].TokenLength + OriginalSpaces; + // If leaving comments makes the line exceed the column limit, give up to + // leave the comments. + if (RestoredLineLength >= Style.ColumnLimit && Style.ColumnLimit != 0) + break; + Changes[i].Spaces = OriginalSpaces; + continue; + } + unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn; unsigned ChangeMaxColumn; @@ -957,7 +993,7 @@ void WhitespaceManager::alignTrailingComments() { Changes[i - 1].Tok->is(tok::r_brace) && Changes[i - 1].StartOfTokenColumn == 0; bool WasAlignedWithStartOfNextLine = false; - if (Changes[i].NewlinesBefore == 1) { // A comment on its own line. + if (Changes[i].NewlinesBefore >= 1) { // A comment on its own line. unsigned CommentColumn = SourceMgr.getSpellingColumnNumber( Changes[i].OriginalWhitespaceRange.getEnd()); for (unsigned j = i + 1; j != e; ++j) { @@ -974,12 +1010,13 @@ void WhitespaceManager::alignTrailingComments() { break; } } - if (!Style.AlignTrailingComments || FollowsRBraceInColumn0) { + if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Never || + FollowsRBraceInColumn0) { alignTrailingComments(StartOfSequence, i, MinColumn); MinColumn = ChangeMinColumn; MaxColumn = ChangeMinColumn; StartOfSequence = i; - } else if (BreakBeforeNext || Newlines > 1 || + } else if (BreakBeforeNext || Newlines > NewLineThreshold || (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) || // Break the comment sequence if the previous line did not end // in a trailing comment. @@ -1014,7 +1051,7 @@ void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End, Changes[i].StartOfBlockComment->StartOfTokenColumn - Changes[i].StartOfTokenColumn; } - if (Shift < 0) + if (Shift <= 0) continue; Changes[i].Spaces += Shift; if (i + 1 != Changes.size()) diff --git a/clang/lib/Format/WhitespaceManager.h b/clang/lib/Format/WhitespaceManager.h index 2be62338bc9a..2ccf8c08302a 100644 --- a/clang/lib/Format/WhitespaceManager.h +++ b/clang/lib/Format/WhitespaceManager.h @@ -199,7 +199,7 @@ private: SmallVector<unsigned> CellCounts; unsigned InitialSpaces = 0; - // Determine if every row in the the array + // Determine if every row in the array // has the same number of columns. bool isRectangular() const { if (CellCounts.empty()) |