Skip to content

[clang-format] AlignAfterOpenBracket tries to do too much and doesn't do what it says #80049

Open
@davidstone

Description

@davidstone

AlignAfterOpenBracket has four configuration values:

  • Align
  • DontAlign
  • AlwaysBreak
  • BlockIndent

This configuration option is trying to accomplish the following separate goals, assuming you need to insert a line break between arguments:

  1. Do you use one indentation level or do you align to the opening bracket? (Align vs DontAlign)
  2. Do you start the first argument on the same line as the open bracket or the next line? (AlwaysBreak vs others)
  3. Do you put the closing bracket on the same line as the last argument or a new line? (BlockIndent vs others)

My style (and one I've seen other people use) is to always put a new argument on each line, with one level of indentation, and have the closing bracket on its own line (I think I've seen this indented or not? I prefer not), by analogy to curly braces {}:

function(
    a,
    b,
    c
);

The behavior of BlockIndent also does not match the documentation. The documentation states:

BAS_BlockIndent (in configuration: BlockIndent) Always break after an open bracket, if the parameters don’t fit on a single line. Closing brackets will be placed on a new line.

However, given

	using type = std::remove_cv_t<
		add_common_cv_reference<
			std::common_type_t<std::decay_t<T0>, std::decay_t<T1>>,
			T0,
			T1
		>
	>;

and AlignAfterOpenBracket set to BlockIndent, clang-format turns that into

	using type = std::remove_cv_t<
		add_common_cv_reference<
			std::common_type_t<std::decay_t<T0>, std::decay_t<T1>>,
			T0,
			T1>>;

It's also unclear whether BlockIndent is supposed to do alignment or indentation, but in my code it looks like it inconsistently does both? AlwaysBreak is similarly ambiguous in its documentation.

To summarize, my preferred resolution of this issue is that we would have something like:

AlignWithOpenBracket

true is behavior of current Align, false is behavior of current DontAlign: this option controls only whether new arguments are aligned to be right after the open bracket if they don't fit on the first line.

// true
function(a,
         b,
         c);

vs

// false
function(a,
    b,
    c);

BreakAfterOpenBracket

true means that if arguments don't all fit on one line, the first argument starts on a new line, false means the first one goes on the same line as the open bracket.

// true
function(
         a,
         b,
         c);

vs

// false
function(a,
         b,
         c);

BreakBeforeCloseBracket

true means that if arguments don't all fit on one line, the closing bracket starts a new line, false means it goes on the same line as the final argument.

// true
function(a,
         b,
         c
);

vs

// false
function(a,
         b,
         c);

So for me to get my preferred formatting, I would have

AlignWithOpenBracket: false
BreakAfterOpenBracket: true
BreakBeforeCloseBracket: true

It is not clear to me what any of the four current options correspond to exactly in this system, based on documentation and current behavior.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions