Skip to content

Commit cc9c8d7

Browse files
author
Ivan Rymarchyk
committed
[clang-format]: Add StaticInlineOnly and StaticInline options to ShortFunctionStyle
Currently, the `ShortFunctionStyle` option in clang-format lacks the granularity to specifically control the single-line formatting of `static inline` C functions independently from other function types like regular empty functions. **Problem:** Users may want to enforce a style where: 1. **Only `static inline` functions** are allowed on a single line (if they fit), forcing all other functions (including empty ones) onto multiple lines. This is useful for keeping utility/helper functions concise while maintaining a consistent multi-line format for primary function definitions. 2. **`static inline` functions *or* empty functions** are allowed on a single line (if they fit), while other non-empty, non-`static inline` functions are forced onto multiple lines. This is a slightly less strict variation. The existing `ShortFunctionStyle` options do not cover these specific C use cases adequately: * `None`: Forces all functions multi-line. * `Empty`: Allows *any* empty function on one line, not just `static inline` ones. * `All`: Allows any short function on one line. * `Inline`/`InlineOnly`: Primarily target C++ member functions or C++ free inline functions, not specifically the C `static inline` pattern. **Proposed Solution:** Introduce two new values for the `ShortFunctionStyle` enum (currently named `ShortFunctionStyle` internally, likely `SFS_...` values): 1. **`StaticInlineOnly`** * **Configuration Name:** `StaticInlineOnly` * **Internal Enum Value (Suggestion):** `SFS_StaticInlineOnly` * **Behavior:** Allows *only* functions declared with both `static` and `inline` specifiers to be formatted on a single line, provided they fit within the `ColumnLimit`. All other functions (regular, static non-inline, inline non-static, empty or not) must be formatted across multiple lines. 2. **`StaticInline`** * **Configuration Name:** `StaticInline` * **Internal Enum Value (Suggestion):** `SFS_StaticInline` * **Behavior:** Allows functions declared with both `static` and `inline` specifiers *or* functions with an empty body (`{}`) to be formatted on a single line, provided they fit within the `ColumnLimit`. Non-empty functions that are *not* `static inline` must be formatted across multiple lines. This effectively combines the `SFS_Empty` behavior with allowing non-empty `static inline` functions. **Expected Formatting:** * **With `ShortFunctionStyle: StaticInlineOnly`** ```c void f1(void) // Multi-line (not static inline) { } int f2(int a, int b) // Multi-line (not static inline) { return a + b; } static void f3(void) // Multi-line (not static inline) { } static int f4(int a, int b) // Multi-line (not static inline) { return a + b; } static inline void f5(void) {} // Single-line allowed static inline int f6(int a, int b) { return a + b; } // Single-line allowed (if fits) inline void f7(void) // Multi-line (not static inline) { } ``` * **With `ShortFunctionStyle: StaticInline`** (Implies Empty) ```c void f1(void) {} // Single-line allowed (empty) int f2(int a, int b) // Multi-line (non-empty, not static inline) { return a + b; } static void f3(void) {} // Single-line allowed (empty) static int f4(int a, int b) // Multi-line (non-empty, not static inline) { return a + b; } static inline void f5(void) {} // Single-line allowed (static inline and empty) static inline int f6(int a, int b) { return a + b; } // Single-line allowed (static inline, if fits) inline void f7(void) {} // Single-line allowed (empty) ```
1 parent 8ea3f81 commit cc9c8d7

File tree

7 files changed

+150
-4
lines changed

7 files changed

+150
-4
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,6 +1926,15 @@ the configuration (without a prefix: ``Auto``).
19261926
void f() {
19271927
}
19281928

1929+
* ``SFS_StaticInlineOnly`` (in configuration: ``StaticInlineOnly``)
1930+
Only merge functions defined as static inline.
1931+
1932+
.. code-block:: c++
1933+
1934+
void f5(void) {
1935+
}
1936+
static inline int f6(int a, int b) { return a + b; }
1937+
19291938
* ``SFS_Empty`` (in configuration: ``Empty``)
19301939
Only merge empty functions.
19311940

@@ -1949,6 +1958,14 @@ the configuration (without a prefix: ``Auto``).
19491958
}
19501959
void f() {}
19511960

1961+
* ``SFS_StaticInline`` (in configuration: ``StaticInline``)
1962+
Only merge functions defined as static inline. Implies ``empty``.
1963+
1964+
.. code-block:: c++
1965+
1966+
void f5(void) {}
1967+
static inline int f6(int a, int b) { return a + b; }
1968+
19521969
* ``SFS_All`` (in configuration: ``All``)
19531970
Merge all functions fitting on a single line.
19541971

clang/include/clang/Format/Format.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,13 @@ struct FormatStyle {
844844
/// }
845845
/// \endcode
846846
SFS_InlineOnly,
847+
/// Only merge functions defined as static inline.
848+
/// \code
849+
/// void f5(void) {
850+
/// }
851+
/// static inline int f6(int a, int b) { return a + b; }
852+
/// \endcode
853+
SFS_StaticInlineOnly,
847854
/// Only merge empty functions.
848855
/// \code
849856
/// void f() {}
@@ -863,6 +870,12 @@ struct FormatStyle {
863870
/// void f() {}
864871
/// \endcode
865872
SFS_Inline,
873+
/// Only merge functions defined as static inline. Implies ``empty``.
874+
/// \code
875+
/// void f5(void) {}
876+
/// static inline int f6(int a, int b) { return a + b; }
877+
/// \endcode
878+
SFS_StaticInline,
866879
/// Merge all functions fitting on a single line.
867880
/// \code
868881
/// class Foo {

clang/lib/Format/Format.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,8 @@ template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
622622
IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline);
623623
IO.enumCase(Value, "InlineOnly", FormatStyle::SFS_InlineOnly);
624624
IO.enumCase(Value, "Empty", FormatStyle::SFS_Empty);
625+
IO.enumCase(Value, "StaticInlineOnly", FormatStyle::SFS_StaticInlineOnly);
626+
IO.enumCase(Value, "StaticInline", FormatStyle::SFS_StaticInline);
625627
}
626628
};
627629

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5690,8 +5690,10 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
56905690
return Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_None ||
56915691
Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Empty ||
56925692
(Left.NestingLevel == 0 && Line.Level == 0 &&
5693-
Style.AllowShortFunctionsOnASingleLine &
5694-
FormatStyle::SFS_InlineOnly);
5693+
(Style.AllowShortFunctionsOnASingleLine ==
5694+
FormatStyle::SFS_InlineOnly ||
5695+
Style.AllowShortFunctionsOnASingleLine ==
5696+
FormatStyle::SFS_Inline));
56955697
}
56965698
} else if (Style.Language == FormatStyle::LK_Java) {
56975699
if (Right.is(tok::plus) && Left.is(tok::string_literal) && AfterRight &&

clang/lib/Format/UnwrappedLineFormatter.cpp

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,9 @@ class LineJoiner {
300300
return true;
301301
}
302302

303-
if (Style.AllowShortFunctionsOnASingleLine &
304-
FormatStyle::SFS_InlineOnly) {
303+
if (Style.AllowShortFunctionsOnASingleLine ==
304+
FormatStyle::SFS_InlineOnly ||
305+
Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline) {
305306
// Just checking TheLine->Level != 0 is not enough, because it
306307
// provokes treating functions inside indented namespaces as short.
307308
if (Style.isJavaScript() && TheLine->Last->is(TT_FunctionLBrace))
@@ -335,6 +336,32 @@ class LineJoiner {
335336
}
336337
}
337338

339+
if (Style.AllowShortFunctionsOnASingleLine ==
340+
FormatStyle::SFS_StaticInlineOnly ||
341+
Style.AllowShortFunctionsOnASingleLine ==
342+
FormatStyle::SFS_StaticInline) {
343+
// Check if the current line belongs to a static inline function
344+
const auto *FirstNonCommentToken =
345+
TheLine ? TheLine->getFirstNonComment() : nullptr;
346+
347+
// Look for 'static' and 'inline' keywords in any order
348+
bool HasStatic = false;
349+
bool HasInline = false;
350+
const FormatToken *Tok = FirstNonCommentToken;
351+
352+
while (Tok && !Tok->is(TT_FunctionLBrace)) {
353+
if (Tok->is(tok::kw_static))
354+
HasStatic = true;
355+
if (Tok->is(tok::kw_inline))
356+
HasInline = true;
357+
Tok = Tok->Next;
358+
}
359+
360+
// If we found both static and inline, allow merging
361+
if (HasStatic && HasInline)
362+
return true;
363+
}
364+
338365
return false;
339366
};
340367

clang/unittests/Format/ConfigParseTest.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,12 @@ TEST(ConfigParseTest, ParsesConfiguration) {
620620
AllowShortFunctionsOnASingleLine, FormatStyle::SFS_Empty);
621621
CHECK_PARSE("AllowShortFunctionsOnASingleLine: All",
622622
AllowShortFunctionsOnASingleLine, FormatStyle::SFS_All);
623+
CHECK_PARSE("AllowShortFunctionsOnASingleLine: StaticInlineOnly",
624+
AllowShortFunctionsOnASingleLine,
625+
FormatStyle::SFS_StaticInlineOnly);
626+
CHECK_PARSE("AllowShortFunctionsOnASingleLine: StaticInline",
627+
AllowShortFunctionsOnASingleLine, FormatStyle::SFS_StaticInline);
628+
623629
// For backward compatibility:
624630
CHECK_PARSE("AllowShortFunctionsOnASingleLine: false",
625631
AllowShortFunctionsOnASingleLine, FormatStyle::SFS_None);

clang/unittests/Format/FormatTest.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15120,6 +15120,85 @@ TEST_F(FormatTest, PullInlineFunctionDefinitionsIntoSingleLine) {
1512015120
MergeInlineOnly);
1512115121
}
1512215122

15123+
TEST_F(FormatTest, PullStaticInlineFunctionDefinitionsIntoSingleLine) {
15124+
FormatStyle MergeStaticInlineOnly = getLLVMStyle();
15125+
MergeStaticInlineOnly.AllowShortFunctionsOnASingleLine =
15126+
FormatStyle::SFS_StaticInlineOnly;
15127+
verifyFormat("static inline int f() { return 42; }",
15128+
"static inline int f() {\n"
15129+
" return 42; \n"
15130+
"}",
15131+
MergeStaticInlineOnly);
15132+
verifyFormat("inline static int f() { return 42; }",
15133+
"inline static int f() \n"
15134+
"{\n"
15135+
" return 42; \n"
15136+
"}",
15137+
MergeStaticInlineOnly);
15138+
verifyNoChange("int f() {\n"
15139+
" return 42;\n"
15140+
"}",
15141+
MergeStaticInlineOnly);
15142+
15143+
verifyFormat("void f1(void) {\n"
15144+
"}",
15145+
"void f1(void)\n"
15146+
"{\n"
15147+
"}",
15148+
MergeStaticInlineOnly);
15149+
15150+
verifyNoChange("int f2(int a, int b) {\n"
15151+
" return a + b;\n"
15152+
"}",
15153+
MergeStaticInlineOnly);
15154+
15155+
verifyNoChange("static void f3(void) {\n"
15156+
"}\n",
15157+
MergeStaticInlineOnly);
15158+
15159+
verifyFormat("static int f4(int a, int b) {\n"
15160+
" return a + b;\n"
15161+
"}\n",
15162+
MergeStaticInlineOnly);
15163+
15164+
verifyNoChange("static inline void f5(void) {}", MergeStaticInlineOnly);
15165+
15166+
verifyFormat("static inline int f6(int a, int b) { return a + b; }",
15167+
"static inline int f6(int a, int b) \n"
15168+
"{ return a + b; }",
15169+
MergeStaticInlineOnly);
15170+
15171+
verifyFormat("int f(int a, int b) {\n"
15172+
" return a + b;\n"
15173+
"}",
15174+
"int f(int a, int b) { return a + b; }", MergeStaticInlineOnly);
15175+
15176+
FormatStyle MergeStaticInline = getLLVMStyle();
15177+
MergeStaticInline.AllowShortFunctionsOnASingleLine =
15178+
FormatStyle::SFS_StaticInline;
15179+
verifyFormat("static inline int f() { return 42; }",
15180+
"static inline int f() {\n"
15181+
" return 42; \n"
15182+
"}",
15183+
MergeStaticInline);
15184+
verifyFormat("inline static int f() { return 42; }",
15185+
"inline static int f() \n"
15186+
"{\n"
15187+
" return 42; \n"
15188+
"}",
15189+
MergeStaticInline);
15190+
verifyNoChange("int f() {\n"
15191+
" return 42;\n"
15192+
"}",
15193+
MergeStaticInline);
15194+
15195+
verifyFormat("void f1(void) {}",
15196+
"void f1(void)\n"
15197+
"{\n"
15198+
"}",
15199+
MergeStaticInline);
15200+
}
15201+
1512315202
TEST_F(FormatTest, PullInlineOnlyFunctionDefinitionsIntoSingleLine) {
1512415203
FormatStyle MergeInlineOnly = getLLVMStyle();
1512515204
MergeInlineOnly.AllowShortFunctionsOnASingleLine =

0 commit comments

Comments
 (0)