clang-format: break after 'inline' in function definition

I am trying to add a style option to clang-format, in order to get one
step closer to mapping our coding style to a .clang-format file.
Our guidelines mandate that for function definitions and non-member
function declarations, the following elements (if they exist) need to
be on a separate line each:
- template specification
- inline keyword [only legal in function definitions]
- function return type
- function name (and arguments, potentially on separate lines)

This is to increase discoverability of the return type as well as the
function name. Consider a complex function definition such as:
template <typename BidirIt, typename IndexType>
inline
std::iterator_traits<BidirIt>::value_type
Foo<ScalarType>::bar(BidirIt begin, BidirIt end, IndexType index)
{ ...

With the currently available clang-format options
  AlwaysBreakAfterDefinitionReturnType: true
  AlwaysBreakTemplateDeclarations: true
one can get as far as:

template <typename BidirIt, typename IndexType>
inline std::iterator_traits<BidirIt>::value_type
Foo<ScalarType>::bar(BidirIt begin, BidirIt end, IndexType index)
{ ...

but there is no good reason why the inline keyword should reside on
the same line as the return type (they are not logically linked in any
way). Hence our guideline to have it on a separate line, which makes
spotting the return type easier, too.

I have tried to add a new boolean option
'AlwaysBreakAfterDefinitionInline', somewhat mimicking the
implementation of 'AlwaysBreakAfterDefinitionReturnType'. The
intention is to break after the 'inline' keyword in a definition, but
not in a declaration (where the keyword is not supposed to be anyway).
See the patch below, which appears to do the right thing using our
coding conventions.

However, the new unit test, which I added as a copy-&-paste from the
AlwaysBreakAfterDefinitionReturnType test, is broken. clang-format (in
combination with LLVM style) seems to indent the lines right after the
inline keyword, which gives the following error:

Value of: format(test::messUp(Code), Style)
  Actual: "inline\n const char *\n f(void) {\n return
\"\";\n}\ninline const char *bar(void);\n"
Expected: Code.str()
Which is: "inline\nconst char *f(void) {\n return \"\";\n}\ninline
const char *bar(void);\n"
...

Since this is my first excursion into the clang-format codebase, it is
not clear to me how this line breaking is linked to indentation.
Can someone help me out there? Or ideally implement the option correctly? :slight_smile:

Thanks,
Michael

By default, a line break somewhere within a statement or a declaration is a continuation and is indented by whatever is configured in ContinuationIndentWidth. Not indenting when wrapping after the template declaration or return type is special cased. Take look at the function getNewLineColumn in ContinuationIndenter.cpp, the special case here is the if at line 546.

As for the patch itself, how important is it not to break after inline in declarations? It seems to add unnecessary complexity and is wrong as implemented (won’t break in “inline void f() { // comment”).

Cheers,
Daniel

OK, I now understood the continuation bit. As far as I can see, adding
the respective condition in the
ContinuationIndenter::getNewLineColumn() function should take care of
the indentation level, right? (See diff below.)

However, I still can't get "break after inline" to work properly, even
if I change the condition inside
TokenAnnotator::calculateFormattingInformation() to the one below
(removing the check for tok::comment).
In particular, I experience failure cases with the following code

inline void f(){ // hello
    x;
}
template <class T> inline T *f(T &c) { return NULL; }
template <class T> inline T *f(T &c);

where the break after inline won't happen for the first two cases,
where it should. Adding the -debug flag tells me "Could not find a
solution." in UnwrappedLineFormatter::analyzeSolutionSpace(). I'm not
quite sure what's going on there without diving much deeper into the
code base.

It's not terribly important to me personally to prevent breaking after
inline in function *declarations* (again, the keyword should not be
used there according to our coding convention), but it seems more
consistent to so do, since there already is a
'AlwaysBreakAfterDefinitionReturnType' option that breaks the return
type in definitions but not declarations.
It would of course be ideal if the conditions [[~] break after]
[template decl. | inline | return type ] [in declarations |
definitions] would be fully composable, but that appears to be quite
tricky to implement.

Cheers,
Michael