Search code examples
clang-format

clang-format: Setting to control C++ attributes


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);

Solution

  • 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();