Reputation: 27633
Searching through the Clang-Format Style Options, I can't seem to find a way to control the behavior on the placement of C++ attributes.
As an example, take these two declarations, the first of which does not overflow the column limit and the second of which does:
template <typename TChar>
[[gnu::always_inline]]
static ptr<TChar> within_limit(ptr<TChar> first, ptr<TChar> last);
template <typename TChar, typename FApply, typename... FApplyRest>
[[gnu::always_inline]]
static ptr<TChar> overflow(ptr<TChar> first, ptr<TChar> last, const FApply& apply, const FApplyRest&... apply_rest);
No matter how I tweak my .clang-format
, the output is some variant of this:
[[gnu::always_inline]] static ptr<TChar> within_limit(ptr<TChar> first, ptr<TChar> last);
[[gnu::always_inline]] static ptr<TChar>
overflow(ptr<TChar> first, ptr<TChar> last, const FApply& apply, const FApplyRest&... apply_rest);
Having the attributes on the same line as the type is rather unreadable (to me), so I would prefer clang-format
not do this. Using __attribute__((always_inline))
exhibits the same behavior. Specifying multiple attributes in a single list ([[noreturn, gnu::cold]]
) causes reformatting (to [[ noreturn, gnu::cold ]]
for reasons unclear to me). The formatter has at least some basic understanding of attributes.
SO: Is there a way to get clang-format
to put attributes on their own line (the C++ equivalent to BreakAfterJavaFieldAnnotations
)?
Attempted Workarounds
Use of // clang-format off
/// clang-format on
is an okay stopgap, but it is definitely too ham-handed for a permanent solution. I still want the declaration formatted properly. Aside from that, the project requires the use of a lot of attributes, so having clang-format
comments everywhere is arguably less readable.
Use of CommentPragmas
theoretically would allow me to be more localized in disabling, but the output is still quite odd:
template <typename TChar>
[[gnu::always_inline]] // NO-FORMAT: Attribute
static ptr<TChar>
within_limit(ptr<TChar> first, ptr<TChar> last);
Upvotes: 78
Views: 3426
Reputation: 76
The feature you're asking for has been added in clang-format 16. The attribute is called BreakAfterAttributes
(documentation), and for the behavior you asked for (newlines after the attribute group) is Always
.
Section for this attribute from the docs:
BreakAfterAttributes
Break after a group of C++11 attributes before a function declaration/definition name.
Possible values:
ABS_Always
(in configuration:Always
) Always break after attributes.[[nodiscard]] inline int f(); [[gnu::const]] [[nodiscard]] int g();
ABS_Leave
(in configuration:Leave
) Leave the line breaking after attributes as is.[[nodiscard]] inline int f(); [[gnu::const]] [[nodiscard]] int g();
ABS_Never
(in configuration:Never
) Never break after attributes.[[nodiscard]] inline int f(); [[gnu::const]] [[nodiscard]] int g();
There does not seem to be a setting for breaking after each attribute in the group, as of clang-format 17. If anyone coming here is interested in that. e.g.:
// Even `Leave` will format this into one line
[[gnu::const]]
[[nodiscard]]
int g();
The line comment trick suggested by Possseidon in another answer will work for this.
// Will remain like this when using `Leave` or `Always`
[[gnu::const]] // <-- Empty line comment after each attribute you want a break after
[[nodiscard]]
int g();
Upvotes: 6
Reputation: 582
This is not a "solution", but a general workaround for preventing clang-format (and other formatters) from removing line breaks.
Just add an empty line comment at the end of a line like so:
template <typename TChar>
[[gnu::always_inline]] //
static ptr<TChar>
within_limit(ptr<TChar> first, ptr<TChar> last);
template <typename TChar, typename FApply, typename... FApplyRest>
[[gnu::always_inline]] //
static ptr<TChar>
overflow(ptr<TChar> first, ptr<TChar> last, const FApply& apply, const FApplyRest&... apply_rest);
It can't merge the lines now, as this would comment out the entire rest of the line.
For this specific example, it's unfortunately not perfect, as it also seems to introduce a second line break after the return type (which looks arguably worse than having everything on a single line). Nontheless I thought this might come in handy in some scenarios (although I haven't personally used it all that much either).
It's at least a lot less verbose than turning off clang-format completely for just a single line.
Upvotes: 3