Index: clang/docs/ClangFormatStyleOptions.rst =================================================================== --- clang/docs/ClangFormatStyleOptions.rst +++ clang/docs/ClangFormatStyleOptions.rst @@ -3618,7 +3618,7 @@ true: false: class Foo : Bar {} vs. class Foo: Bar {} -**SpaceBeforeParens** (``SpaceBeforeParensOptions``) :versionbadge:`clang-format 3.5` +**SpaceBeforeParens** (``SpaceBeforeParensStyle``) :versionbadge:`clang-format 3.5` Defines in which cases to put a space before opening parentheses. Possible values: @@ -3688,6 +3688,78 @@ } } + * ``SBPO_Custom`` (in configuration: ``Custom``) + Configure each individual space before parentheses in + `SpaceBeforeParensOptions`. + + + +**SpaceBeforeParensOptions** (``SpaceBeforeParensCustom``) :versionbadge:`clang-format 14` + Control of individual space before parentheses. + + If ``SpaceBeforeParens`` is set to ``Custom``, use this to specify + how each individual space before parentheses case should be handled. + Otherwise, this is ignored. + + .. code-block:: yaml + + # Example of usage: + SpaceBeforeParens: Custom + SpaceBeforeParensOptions: + AfterControlStatements: true + AfterFunctionDefinitionName: true + + Nested configuration flags: + + + * ``bool AfterControlStatements`` If ``true``, put space betwee control statement keywords + (for/if/while...) and opening parentheses. + + .. code-block:: c++ + + true: false: + if (...) {} vs. if(...) {} + + * ``bool AfterFunctionDeclarationName`` If ``true``, put a space between function declaration name and opening + parentheses. + + .. code-block:: c++ + + true: false: + void f (); vs. void f(); + + * ``bool AfterFunctionDefinitionName`` If ``true``, put a space between function definition name and opening + parentheses. + + .. code-block:: c++ + + true: false: + void f () {} vs. void f() {} + + * ``bool AfterIfMacros`` If ``true``, put space between if macros and opening parentheses. + + .. code-block:: c++ + + true: false: + IF (...) vs. IF(...) + + + * ``bool AfterForeachMacros`` If ``true``, put space between foreach macros and opening parentheses. + + .. code-block:: c++ + + true: false: + FOREACH (...) vs. FOREACH(...) + + + * ``bool BeforeNonEmptyParentheses`` If ``true``, put a space before opening parentheses only if the + parentheses are not empty. + + .. code-block:: c++ + + true: false: + void f (int a); vs. void f(); + f (a); f(); **SpaceBeforeRangeBasedForLoopColon** (``Boolean``) :versionbadge:`clang-format 7` Index: clang/include/clang/Format/Format.h =================================================================== --- clang/include/clang/Format/Format.h +++ clang/include/clang/Format/Format.h @@ -3258,7 +3258,7 @@ bool SpaceBeforeInheritanceColon; /// Different ways to put a space before opening parentheses. - enum SpaceBeforeParensOptions : unsigned char { + enum SpaceBeforeParensStyle : unsigned char { /// Never put a space before opening parentheses. /// \code /// void f() { @@ -3313,12 +3313,99 @@ /// } /// } /// \endcode - SBPO_Always + SBPO_Always, + /// Configure each individual space before parentheses in + /// `SpaceBeforeParensOptions`. + SBPO_Custom }; /// Defines in which cases to put a space before opening parentheses. /// \version 3.5 - SpaceBeforeParensOptions SpaceBeforeParens; + SpaceBeforeParensStyle SpaceBeforeParens; + + /// Precise control over the spacing before parentheses. + /// \code + /// # Should be declared this way: + /// SpaceBeforeParens: Custom + /// SpaceBeforeParensOptions: + /// AfterControlStatements: true + /// AfterFunctionDefinitionName: true + /// \endcode + struct SpaceBeforeParensCustom { + /// If ``true``, put space betwee control statement keywords + /// (for/if/while...) and opening parentheses. + /// \code + /// true: false: + /// if (...) {} vs. if(...) {} + /// \endcode + bool AfterControlStatements; + /// If ``true``, put a space between function declaration name and opening + /// parentheses. + /// \code + /// true: false: + /// void f (); vs. void f(); + /// \endcode + bool AfterFunctionDeclarationName; + /// If ``true``, put a space between function definition name and opening + /// parentheses. + /// \code + /// true: false: + /// void f () {} vs. void f() {} + /// \endcode + bool AfterFunctionDefinitionName; + /// If ``true``, put space between if macros and opening parentheses. + /// \code + /// true: false: + /// IF (...) vs. IF(...) + /// + /// \endcode + bool AfterIfMacros; + /// If ``true``, put space between foreach macros and opening parentheses. + /// \code + /// true: false: + /// FOREACH (...) vs. FOREACH(...) + /// + /// \endcode + bool AfterForeachMacros; + /// If ``true``, put a space before opening parentheses only if the + /// parentheses are not empty. + /// \code + /// true: false: + /// void f (int a); vs. void f(); + /// f (a); f(); + /// \endcode + bool BeforeNonEmptyParentheses; + + SpaceBeforeParensCustom() + : AfterControlStatements(false), AfterFunctionDeclarationName(false), + AfterFunctionDefinitionName(false), AfterIfMacros(false), + AfterForeachMacros(false), BeforeNonEmptyParentheses(false) {} + + bool operator==(const SpaceBeforeParensCustom &Other) const { + return AfterControlStatements == Other.AfterControlStatements && + AfterFunctionDeclarationName == + Other.AfterFunctionDeclarationName && + AfterFunctionDefinitionName == Other.AfterFunctionDefinitionName && + AfterIfMacros == Other.AfterIfMacros && + AfterForeachMacros == Other.AfterForeachMacros && + BeforeNonEmptyParentheses == Other.BeforeNonEmptyParentheses; + } + }; + + /// Control of individual space before parentheses. + /// + /// If ``SpaceBeforeParens`` is set to ``Custom``, use this to specify + /// how each individual space before parentheses case should be handled. + /// Otherwise, this is ignored. + /// \code{.yaml} + /// # Example of usage: + /// SpaceBeforeParens: Custom + /// SpaceBeforeParensOptions: + /// AfterControlStatements: true + /// AfterFunctionDefinitionName: true + /// \endcode + /// \version 14 + SpaceBeforeParensCustom SpaceBeforeParensOptions; /// If ``false``, spaces will be removed before range-based for loop /// colon. @@ -3713,6 +3800,7 @@ R.SpaceBeforeCtorInitializerColon && SpaceBeforeInheritanceColon == R.SpaceBeforeInheritanceColon && SpaceBeforeParens == R.SpaceBeforeParens && + SpaceBeforeParensOptions == R.SpaceBeforeParensOptions && SpaceAroundPointerQualifiers == R.SpaceAroundPointerQualifiers && SpaceBeforeRangeBasedForLoopColon == R.SpaceBeforeRangeBasedForLoopColon && Index: clang/lib/Format/Format.cpp =================================================================== --- clang/lib/Format/Format.cpp +++ clang/lib/Format/Format.cpp @@ -451,9 +451,8 @@ }; template <> -struct ScalarEnumerationTraits { - static void enumeration(IO &IO, - FormatStyle::SpaceBeforeParensOptions &Value) { +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, FormatStyle::SpaceBeforeParensStyle &Value) { IO.enumCase(Value, "Never", FormatStyle::SBPO_Never); IO.enumCase(Value, "ControlStatements", FormatStyle::SBPO_ControlStatements); @@ -462,6 +461,7 @@ 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); @@ -787,6 +787,7 @@ IO.mapOptional("SpaceBeforeInheritanceColon", Style.SpaceBeforeInheritanceColon); IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens); + IO.mapOptional("SpaceBeforeParensOptions", Style.SpaceBeforeParensOptions); IO.mapOptional("SpaceAroundPointerQualifiers", Style.SpaceAroundPointerQualifiers); IO.mapOptional("SpaceBeforeRangeBasedForLoopColon", @@ -845,6 +846,20 @@ } }; +template <> struct MappingTraits { + static void mapping(IO &IO, FormatStyle::SpaceBeforeParensCustom &Spacing) { + IO.mapOptional("AfterFunctionDefinitionName", + Spacing.AfterFunctionDefinitionName); + IO.mapOptional("AfterFunctionDeclarationName", + Spacing.AfterFunctionDeclarationName); + IO.mapOptional("AfterControlStatements", Spacing.AfterControlStatements); + IO.mapOptional("AfterIfMacros", Spacing.AfterIfMacros); + IO.mapOptional("AfterForeachMacros", Spacing.AfterForeachMacros); + IO.mapOptional("BeforeNonEmptyParentheses", + Spacing.BeforeNonEmptyParentheses); + } +}; + template <> struct MappingTraits { static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) { IO.mapOptional("Language", Format.Language); @@ -939,10 +954,9 @@ llvm_unreachable("unexpected parse error"); } -static FormatStyle expandPresets(const FormatStyle &Style) { - if (Style.BreakBeforeBraces == FormatStyle::BS_Custom) - return Style; - FormatStyle Expanded = Style; +static void expandPresetsBraceWrapping(FormatStyle &Expanded) { + if (Expanded.BreakBeforeBraces == FormatStyle::BS_Custom) + return; Expanded.BraceWrapping = {/*AfterCaseLabel=*/false, /*AfterClass=*/false, /*AfterControlStatement=*/FormatStyle::BWACS_Never, @@ -961,7 +975,7 @@ /*SplitEmptyFunction=*/true, /*SplitEmptyRecord=*/true, /*SplitEmptyNamespace=*/true}; - switch (Style.BreakBeforeBraces) { + switch (Expanded.BreakBeforeBraces) { case FormatStyle::BS_Linux: Expanded.BraceWrapping.AfterClass = true; Expanded.BraceWrapping.AfterFunction = true; @@ -1042,7 +1056,33 @@ default: break; } - return Expanded; +} + +static void expandPresetsSpaceBeforeParens(FormatStyle &Expanded) { + if (Expanded.SpaceBeforeParens == FormatStyle::SBPO_Custom) + return; + // Reset all flags + Expanded.SpaceBeforeParensOptions = {}; + + switch (Expanded.SpaceBeforeParens) { + case FormatStyle::SBPO_Never: + break; + case FormatStyle::SBPO_ControlStatements: + Expanded.SpaceBeforeParensOptions.AfterControlStatements = true; + Expanded.SpaceBeforeParensOptions.AfterIfMacros = true; + Expanded.SpaceBeforeParensOptions.AfterForeachMacros = true; + break; + case FormatStyle::SBPO_ControlStatementsExceptControlMacros: + Expanded.SpaceBeforeParensOptions.AfterControlStatements = true; + break; + case FormatStyle::SBPO_NonEmptyParentheses: + Expanded.SpaceBeforeParensOptions.BeforeNonEmptyParentheses = true; + break; + case FormatStyle::SBPO_Always: + break; + default: + break; + } } FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { @@ -1174,6 +1214,9 @@ LLVMStyle.SpaceBeforeCtorInitializerColon = true; LLVMStyle.SpaceBeforeInheritanceColon = true; LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements; + LLVMStyle.SpaceBeforeParensOptions.AfterControlStatements = true; + LLVMStyle.SpaceBeforeParensOptions.AfterIfMacros = true; + LLVMStyle.SpaceBeforeParensOptions.AfterForeachMacros = true; LLVMStyle.SpaceBeforeRangeBasedForLoopColon = true; LLVMStyle.SpaceBeforeAssignmentOperators = true; LLVMStyle.SpaceBeforeCpp11BracedList = false; @@ -1649,8 +1692,11 @@ llvm::yaml::Output Output(Stream); // We use the same mapping method for input and output, so we need a non-const // reference here. - FormatStyle NonConstStyle = expandPresets(Style); + FormatStyle NonConstStyle = Style; + expandPresetsBraceWrapping(NonConstStyle); + expandPresetsSpaceBeforeParens(NonConstStyle); Output << NonConstStyle; + return Stream.str(); } @@ -2929,7 +2975,9 @@ ArrayRef Ranges, unsigned FirstStartColumn, unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName, FormattingAttemptStatus *Status) { - FormatStyle Expanded = expandPresets(Style); + FormatStyle Expanded = Style; + expandPresetsBraceWrapping(Expanded); + expandPresetsSpaceBeforeParens(Expanded); if (Expanded.DisableFormat) return {tooling::Replacements(), 0}; if (isLikelyXml(Code)) Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -2906,7 +2906,7 @@ bool TokenAnnotator::spaceRequiredBeforeParens(const FormatToken &Right) const { return Style.SpaceBeforeParens == FormatStyle::SBPO_Always || - (Style.SpaceBeforeParens == FormatStyle::SBPO_NonEmptyParentheses && + (Style.SpaceBeforeParensOptions.BeforeNonEmptyParentheses && Right.ParameterCount > 0); } @@ -2940,9 +2940,6 @@ return true; } - // requires ( or requires( - if (Right.is(tok::l_paren) && Left.is(tok::kw_requires)) - return spaceRequiredBeforeParens(Right); // requires clause Concept1 && Concept2 if (Left.is(TT_ConstraintJunctions) && Right.is(tok::identifier)) return true; @@ -3134,33 +3131,60 @@ // e.g. template [[nodiscard]] ... if (Left.is(TT_TemplateCloser) && Right.is(TT_AttributeSquare)) return true; + // Space before parentheses common for all languages if (Right.is(tok::l_paren)) { + if (Left.is(TT_TemplateCloser) && Right.isNot(TT_FunctionTypeLParen)) + return spaceRequiredBeforeParens(Right); + if (Left.is(tok::kw_requires)) + return spaceRequiredBeforeParens(Right); if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) || (Left.is(tok::r_square) && Left.is(TT_AttributeSquare))) return true; - if (Style.SpaceBeforeParens == - FormatStyle::SBPO_ControlStatementsExceptControlMacros && - Left.is(TT_ForEachMacro)) - return false; - if (Style.SpaceBeforeParens == - FormatStyle::SBPO_ControlStatementsExceptControlMacros && - Left.is(TT_IfMacro)) - return false; - return Line.Type == LT_ObjCDecl || Left.is(tok::semi) || - (Style.SpaceBeforeParens != FormatStyle::SBPO_Never && - (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.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch, - tok::kw_new, tok::kw_delete) && - (!Left.Previous || Left.Previous->isNot(tok::period))))) || - (spaceRequiredBeforeParens(Right) && - (Left.is(tok::identifier) || Left.isFunctionLikeKeyword() || - Left.is(tok::r_paren) || Left.isSimpleTypeSpecifier() || - (Left.is(tok::r_square) && Left.MatchingParen && - Left.MatchingParen->is(TT_LambdaLSquare))) && - Line.Type != LT_PreprocessorDirective); + if (Left.is(TT_ForEachMacro)) + return (Style.SpaceBeforeParensOptions.AfterForeachMacros || + spaceRequiredBeforeParens(Right)); + if (Left.is(TT_IfMacro)) + return (Style.SpaceBeforeParensOptions.AfterIfMacros || + spaceRequiredBeforeParens(Right)); + if (Line.Type == LT_ObjCDecl) + return true; + if (Left.is(tok::semi)) + return true; + if (Left.isOneOf(tok::pp_elif, tok::kw_for, tok::kw_while, tok::kw_switch, + tok::kw_case, TT_ForEachMacro, TT_ObjCForIn)) + return Style.SpaceBeforeParensOptions.AfterControlStatements || + spaceRequiredBeforeParens(Right); + if (Left.isIf(Line.Type != LT_PreprocessorDirective)) + return Style.SpaceBeforeParensOptions.AfterControlStatements || + spaceRequiredBeforeParens(Right); + // Function declaration or definition + if (Line.MightBeFunctionDecl && (Left.is(TT_FunctionDeclarationName) || + Right.is(TT_OverloadedOperatorLParen))) { + if (Line.mightBeFunctionDefinition()) + return Style.SpaceBeforeParensOptions.AfterFunctionDefinitionName || + spaceRequiredBeforeParens(Right); + else + return Style.SpaceBeforeParensOptions.AfterFunctionDeclarationName || + spaceRequiredBeforeParens(Right); + } + // Lambda + if (Line.Type != LT_PreprocessorDirective && Left.is(tok::r_square) && + Left.MatchingParen && Left.MatchingParen->is(TT_LambdaLSquare)) + return Style.SpaceBeforeParensOptions.AfterFunctionDefinitionName || + spaceRequiredBeforeParens(Right); + if (!Left.Previous || Left.Previous->isNot(tok::period)) { + if (Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch)) + return Style.SpaceBeforeParensOptions.AfterControlStatements || + spaceRequiredBeforeParens(Right); + if (Left.isOneOf(tok::kw_new, tok::kw_delete)) + return Style.SpaceBeforeParens != FormatStyle::SBPO_Never || + spaceRequiredBeforeParens(Right); + } + if (Line.Type != LT_PreprocessorDirective && + (Left.is(tok::identifier) || Left.isFunctionLikeKeyword() || + Left.is(tok::r_paren) || Left.isSimpleTypeSpecifier())) + return spaceRequiredBeforeParens(Right); + return false; } if (Left.is(tok::at) && Right.Tok.getObjCKeywordID() != tok::objc_not_keyword) return false; @@ -3202,6 +3226,7 @@ // qualifiers such as // void Fn() const &; return getTokenReferenceAlignment(Right) != FormatStyle::PAS_Left; + return true; } @@ -3307,7 +3332,7 @@ if (Right.is(tok::l_paren)) if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when, Keywords.kw_lock)) - return Style.SpaceBeforeParens == FormatStyle::SBPO_ControlStatements || + return Style.SpaceBeforeParensOptions.AfterControlStatements || spaceRequiredBeforeParens(Right); // space between method modifier and opening parenthesis of a tuple return @@ -3414,7 +3439,8 @@ if (Left.is(tok::r_square) && Right.is(tok::l_brace)) return true; if (Left.is(Keywords.kw_synchronized) && Right.is(tok::l_paren)) - return Style.SpaceBeforeParens != FormatStyle::SBPO_Never; + return Style.SpaceBeforeParensOptions.AfterControlStatements || + spaceRequiredBeforeParens(Right); if ((Left.isOneOf(tok::kw_static, tok::kw_public, tok::kw_private, tok::kw_protected) || Left.isOneOf(Keywords.kw_final, Keywords.kw_abstract, @@ -3440,9 +3466,7 @@ if (Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow) || Left.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow)) return true; - if (Right.is(TT_OverloadedOperatorLParen)) - return spaceRequiredBeforeParens(Right); - if (Left.is(tok::comma)) + if (Left.is(tok::comma) && !Right.is(TT_OverloadedOperatorLParen)) return true; if (Right.is(tok::comma)) return false; @@ -3565,9 +3589,6 @@ (Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) && !Right.is(tok::r_paren))) return true; - if (Left.is(TT_TemplateCloser) && Right.is(tok::l_paren) && - Right.isNot(TT_FunctionTypeLParen)) - return spaceRequiredBeforeParens(Right); if (Right.is(TT_TemplateOpener) && Left.is(tok::r_paren) && Left.MatchingParen && Left.MatchingParen->is(TT_OverloadedOperatorLParen)) return false; Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -14133,6 +14133,173 @@ verifyFormat("X A::operator++ (T);", SomeSpace); verifyFormat("int x = int (y);", SomeSpace); verifyFormat("auto lambda = []() { return 0; };", SomeSpace); + + FormatStyle SpaceControlStatements = getLLVMStyle(); + SpaceControlStatements.SpaceBeforeParens = FormatStyle::SBPO_Custom; + SpaceControlStatements.SpaceBeforeParensOptions.AfterControlStatements = true; + + verifyFormat("while (true)\n" + " continue;", + SpaceControlStatements); + verifyFormat("if (true)\n" + " f();\n" + "else if (true)\n" + " f();", + SpaceControlStatements); + verifyFormat("for (;;) {\n" + " do_something();\n" + "}", + SpaceControlStatements); + verifyFormat("do {\n" + " do_something();\n" + "} while (something());", + SpaceControlStatements); + verifyFormat("switch (x) {\n" + "default:\n" + " break;\n" + "}", + SpaceControlStatements); + + FormatStyle SpaceFuncDecl = getLLVMStyle(); + SpaceFuncDecl.SpaceBeforeParens = FormatStyle::SBPO_Custom; + SpaceFuncDecl.SpaceBeforeParensOptions.AfterFunctionDeclarationName = true; + + verifyFormat("int f ();", SpaceFuncDecl); + verifyFormat("void f(int a, T b) {}", SpaceFuncDecl); + verifyFormat("A::A() : a(1) {}", SpaceFuncDecl); + verifyFormat("void f () __attribute__((asdf));", SpaceFuncDecl); + verifyFormat("#define A(x) x", SpaceFuncDecl); + verifyFormat("#define A (x) x", SpaceFuncDecl); + verifyFormat("#if defined(x)\n" + "#endif", + SpaceFuncDecl); + verifyFormat("auto i = std::make_unique(5);", SpaceFuncDecl); + verifyFormat("size_t x = sizeof(x);", SpaceFuncDecl); + verifyFormat("auto f (int x) -> decltype(x);", SpaceFuncDecl); + verifyFormat("auto f (int x) -> typeof(x);", SpaceFuncDecl); + verifyFormat("auto f (int x) -> _Atomic(x);", SpaceFuncDecl); + verifyFormat("auto f (int x) -> __underlying_type(x);", SpaceFuncDecl); + verifyFormat("int f (T x) noexcept(x.create());", SpaceFuncDecl); + verifyFormat("alignas(128) char a[128];", SpaceFuncDecl); + verifyFormat("size_t x = alignof(MyType);", SpaceFuncDecl); + verifyFormat("static_assert(sizeof(char) == 1, \"Impossible!\");", + SpaceFuncDecl); + verifyFormat("int f () throw(Deprecated);", SpaceFuncDecl); + verifyFormat("typedef void (*cb)(int);", SpaceFuncDecl); + verifyFormat("T A::operator() ();", SpaceFuncDecl); + verifyFormat("X A::operator++ (T);", SpaceFuncDecl); + verifyFormat("T A::operator()() {}", SpaceFuncDecl); + verifyFormat("auto lambda = []() { return 0; };", SpaceFuncDecl); + verifyFormat("int x = int(y);", SpaceFuncDecl); + verifyFormat("M(std::size_t R, std::size_t C) : C(C), data(R) {}", + SpaceFuncDecl); + + FormatStyle SpaceFuncDef = getLLVMStyle(); + SpaceFuncDef.SpaceBeforeParens = FormatStyle::SBPO_Custom; + SpaceFuncDef.SpaceBeforeParensOptions.AfterFunctionDefinitionName = true; + + verifyFormat("int f();", SpaceFuncDef); + verifyFormat("void f (int a, T b) {}", SpaceFuncDef); + verifyFormat("A::A() : a(1) {}", SpaceFuncDef); + verifyFormat("void f() __attribute__((asdf));", SpaceFuncDef); + verifyFormat("#define A(x) x", SpaceFuncDef); + verifyFormat("#define A (x) x", SpaceFuncDef); + verifyFormat("#if defined(x)\n" + "#endif", + SpaceFuncDef); + verifyFormat("auto i = std::make_unique(5);", SpaceFuncDef); + verifyFormat("size_t x = sizeof(x);", SpaceFuncDef); + verifyFormat("auto f(int x) -> decltype(x);", SpaceFuncDef); + verifyFormat("auto f(int x) -> typeof(x);", SpaceFuncDef); + verifyFormat("auto f(int x) -> _Atomic(x);", SpaceFuncDef); + verifyFormat("auto f(int x) -> __underlying_type(x);", SpaceFuncDef); + verifyFormat("int f(T x) noexcept(x.create());", SpaceFuncDef); + verifyFormat("alignas(128) char a[128];", SpaceFuncDef); + verifyFormat("size_t x = alignof(MyType);", SpaceFuncDef); + verifyFormat("static_assert(sizeof(char) == 1, \"Impossible!\");", + SpaceFuncDef); + verifyFormat("int f() throw(Deprecated);", SpaceFuncDef); + verifyFormat("typedef void (*cb)(int);", SpaceFuncDef); + verifyFormat("T A::operator()();", SpaceFuncDef); + verifyFormat("X A::operator++(T);", SpaceFuncDef); + verifyFormat("T A::operator() () {}", SpaceFuncDef); + verifyFormat("auto lambda = [] () { return 0; };", SpaceFuncDef); + verifyFormat("int x = int(y);", SpaceFuncDef); + verifyFormat("M(std::size_t R, std::size_t C) : C(C), data(R) {}", + SpaceFuncDef); + + FormatStyle SpaceIfMacros = getLLVMStyle(); + SpaceIfMacros.IfMacros.clear(); + SpaceIfMacros.IfMacros.push_back("MYIF"); + SpaceIfMacros.SpaceBeforeParens = FormatStyle::SBPO_Custom; + SpaceIfMacros.SpaceBeforeParensOptions.AfterIfMacros = true; + verifyFormat("MYIF (a)\n return;", SpaceIfMacros); + verifyFormat("MYIF (a)\n return;\nelse MYIF (b)\n return;", SpaceIfMacros); + verifyFormat("MYIF (a)\n return;\nelse\n return;", SpaceIfMacros); + + FormatStyle SpaceForeachMacros = getLLVMStyle(); + SpaceForeachMacros.SpaceBeforeParens = FormatStyle::SBPO_Custom; + SpaceForeachMacros.SpaceBeforeParensOptions.AfterForeachMacros = true; + verifyFormat("foreach (Item *item, itemlist) {}", SpaceForeachMacros); + verifyFormat("Q_FOREACH (Item *item, itemlist) {}", SpaceForeachMacros); + verifyFormat("BOOST_FOREACH (Item *item, itemlist) {}", SpaceForeachMacros); + verifyFormat("UNKNOWN_FOREACH(Item *item, itemlist) {}", SpaceForeachMacros); + + FormatStyle SomeSpace2 = getLLVMStyle(); + SomeSpace2.SpaceBeforeParens = FormatStyle::SBPO_Custom; + SomeSpace2.SpaceBeforeParensOptions.BeforeNonEmptyParentheses = true; + verifyFormat("[]() -> float {}", SomeSpace2); + verifyFormat("[] (auto foo) {}", SomeSpace2); + verifyFormat("[foo]() -> int {}", SomeSpace2); + verifyFormat("int f();", SomeSpace2); + verifyFormat("void f (int a, T b) {\n" + " while (true)\n" + " continue;\n" + "}", + SomeSpace2); + verifyFormat("if (true)\n" + " f();\n" + "else if (true)\n" + " f();", + SomeSpace2); + verifyFormat("do {\n" + " do_something();\n" + "} while (something());", + SomeSpace2); + verifyFormat("switch (x) {\n" + "default:\n" + " break;\n" + "}", + SomeSpace2); + verifyFormat("A::A() : a (1) {}", SomeSpace2); + verifyFormat("void f() __attribute__ ((asdf));", SomeSpace2); + verifyFormat("*(&a + 1);\n" + "&((&a)[1]);\n" + "a[(b + c) * d];\n" + "(((a + 1) * 2) + 3) * 4;", + SomeSpace2); + verifyFormat("#define A(x) x", SomeSpace2); + verifyFormat("#define A (x) x", SomeSpace2); + verifyFormat("#if defined(x)\n" + "#endif", + SomeSpace2); + verifyFormat("auto i = std::make_unique (5);", SomeSpace2); + verifyFormat("size_t x = sizeof (x);", SomeSpace2); + verifyFormat("auto f (int x) -> decltype (x);", SomeSpace2); + verifyFormat("auto f (int x) -> typeof (x);", SomeSpace2); + verifyFormat("auto f (int x) -> _Atomic (x);", SomeSpace2); + verifyFormat("auto f (int x) -> __underlying_type (x);", SomeSpace2); + verifyFormat("int f (T x) noexcept (x.create());", SomeSpace2); + verifyFormat("alignas (128) char a[128];", SomeSpace2); + verifyFormat("size_t x = alignof (MyType);", SomeSpace2); + verifyFormat("static_assert (sizeof (char) == 1, \"Impossible!\");", + SomeSpace2); + verifyFormat("int f() throw (Deprecated);", SomeSpace2); + verifyFormat("typedef void (*cb) (int);", SomeSpace2); + verifyFormat("T A::operator()();", SomeSpace2); + verifyFormat("X A::operator++ (T);", SomeSpace2); + verifyFormat("int x = int (y);", SomeSpace2); + verifyFormat("auto lambda = []() { return 0; };", SomeSpace2); } TEST_F(FormatTest, SpaceAfterLogicalNot) { @@ -18631,6 +18798,8 @@ FormatStyle::SBPO_ControlStatementsExceptControlMacros); CHECK_PARSE("SpaceBeforeParens: NonEmptyParentheses", SpaceBeforeParens, FormatStyle::SBPO_NonEmptyParentheses); + CHECK_PARSE("SpaceBeforeParens: Custom", SpaceBeforeParens, + FormatStyle::SBPO_Custom); // For backward compatibility: CHECK_PARSE("SpaceAfterControlStatementKeyword: false", SpaceBeforeParens, FormatStyle::SBPO_Never);