[C++] What's new in clang-format 5

Clang 5 was released last week.
It's a good opportunity to talk about a not-enough-known tool: Clang-format.

Clang-format is part of the Clang project but can be used without the Clang compiler. It's an independent executable.

Clang-format is a code linter for C++. It takes a non-formatted code as input and produces a well-formatted code as output. The result is instantaneous.

Clang-format comes with predefined settings form well-known coding styles, like Google, LLVM and Mozilla. But you can also define your own style by writing a .clang-format file.

The .clang-format file describes the coding style to be used. It supports tens of settings and we'll see in this article what new settings have been added.

Don't miss the conclusion were I share four pro-tips to integrate Clang-format in your workflow.

New options

AlignEscapedNewlines

This option affects the position of the backslashes in a macro definition.

AlignEscapedNewlines has three possible values: DontAlign, Left and Right.

If set to DontAlign, backslashes are not aligned:

#define A \
  int aaaa; \
  int b; \
  int dddddddddd;

If set to Left, backslashes are aligned and pushed to the left:

#define A   \
  int aaaa; \
  int b;    \
  int dddddddddd;

If set to Right, backslashes are aligned and pushed to the right:

#define A                         \
  int aaaa;                       \
  int b;                          \
  int dddddddddd;

In this case the position depends on the number of columns configured in ColumnLimit.

AlignEscapedNewlines replaces the boolean AlignEscapedNewlinesLeft which produced the same result as the new Left value.

BreakBeforeInheritanceComma

This option specifies the way inheritances are written. It's only use when there is multiple inheritance.

BreakBeforeInheritanceComma can be set to either true or false.

If set to true, it puts each inheritance on a new line:

class MyClass
     : public X
     , public Y {
};

If set to false, it puts everything on a single line:

class MyClass : public X, public Y {
};

BreakConstructorInitializers

This option specifies the way initializers are written in a constructor.

BreakConstructorInitializers has three possible values: BeforeColon, BeforeComma and AfterColon.

If set to BeforeColon, the colon is on the left and all commas are on the right:

Constructor()
     : initializer1(),
       initializer2()

If set to BeforeComma, the colon and all commas are on the left:

Constructor()
     : initializer1()
     , initializer2()

If set to AfterColon, the colon and all commas are on the right:

Constructor() :
     initializer1(),
     initializer2()

BreakConstructorInitializers replaces the boolean BreakConstructorInitializersBeforeComma which produced the same result as BeforeComma.

CompactNamespaces

This setting changes the way consecutive namespace declaration are written.

CompactNamespaces can be set to either true or false.

If set to true, consecutive namespaces are written on the same line:

namespace Foo { namespace Bar {
}}

If set to false, consecutive namespaces are written on different lines:

namespace Foo {
namespace Bar {
}
}

FixNamespaceComments

When enabled, this adds a comment at the end of each namespace.

FixNamespaceComments can be set to either true or false.

If set to true, Clang-format adds a comment with the name of the namespace.

namespace a {
foo();
} // namespace a

This is very useful as a namespace rarely fits in a single screen.

If you rename the namespace, the Clang-format will adjust the comment accordingly; the two will always be in-sync.

You can combine this option with the previous one and get the following result:

namespace Foo { namespace Bar {
}} // namespace Foo::Bar

ShortFunctionStyle: InlineOnly

This is a new value for an existing option. It adds finer control on which short functions are allowed to be on a single line.

If ShortFunctionStyle is set to InlineOnly, only short functions that are defined inside a class are written on a single line:

class Foo {
  void f() { foo(); }
};
void f() {
  foo();
}
void f() {
}

This is a complement to the Inline value which also put empty top-level functions in a single line:

class Foo {
  void f() { foo(); }
};
void f() {
  foo();
}
void f() {}

SplitEmptyFunction

This setting affects the way empty function are written.
It's only used when the opening brace is on a new line, i.e. only when BraceWrapping/AfterFunction is true.

SplitEmptyFunction can be set to either true or false.

If set to true, an empty function will take three lines:

int f()
{
}

If set to false, an empty function will only take two lines:

int f()
{}

SplitEmptyRecord

This setting is similar to the previous one excepts that it affects struct, class and union.

If set to true, an empty class will take three lines:

class Foo
{
}

If set to false, an empty class will only take two lines:

class Foo
{}

SplitEmptyNamespace

This setting is similar to the previous one excepts that it affects namespaces.

If set to true, an empty namespace will take three lines:

namespace Foo
{
}

If set to false, an empty namespace will only take two lines:

namespace Foo
{}

SortUsingDeclaration

When enabled, this option sort using declaration in alphabetical order. Clang-format 4 was already able to sort #include, now it can do the same with using declarations.

SortUsingDeclaration can be either true or false.

If set to true, using declarations will be written in alphabetical order:

using std::cin;
using std::cout;

If set to false, they are left as is:

using std::cout;
using std::cin;

It's possible to add priority to certain #include directives using the option IncludeCategories, but there is no such feature for using declarations.

IndentPPDirectives (v6 only)

This setting is not available in Clang-format 5, but will be in version 6 and is already available in the trunk.

It enables indentation of preprocessor directives.

IndentPPDirectives can be set to either None or AfterHash.

If set to None, the preprocessor directives are not indented:

#if FOO
#if BAR
#include <foo>
#endif
#endif

If set to AfterHash, they are indented with spaces placed after the hash sign:

#if FOO
#  if BAR
#    include <foo>
#  endif
#endif

It's not yet possible to have the spaces before the hash, but one can assume that a BeforeHash will be added in a very near future.

Clang-format is clever enough to detect include-guards. If you have a header surrounded by a #ifndef/#define/#endif, this will be detected as an include-guard and will not be indented.

Conlusion

Clang-format is more flexible than ever and it still very fast.
I strongly recommend that you integrate it your daily practice.

As promised, here are my four advises.

Pro-tip 1: Throw away your "coding style" document

Yes! You know what I'm talking about. This document that many team have and pisses everybody off.

From what I've seen, many teams have a member that has a very strong opinion on how others should write code. This person writes a hundred page long "coding style" document that defines what is legal or not in the team.

Not only it's very time consuming to write such a document, it's also impossible to get it right. You cannot predict every situation before hand, there a too many ways to write good C++.

Think about the time spent by each member of the team reading the document! Not just once, but regularly, because the documents is often updated to fill the holes.

WELL, STOP DOING THAT!

Instead, write a .clang-format file and commit it alongside with the code.
This document is easy to write and unambiguous.

Best of all, nobody is forced to read it anymore.

RIP: codingstyle.txt

Pro-tip 2: Don't discard Clang-format because a detail is missing

There are things that are not possible in Clang-format.
For instance, if you want different indentation for anonymous namespace and for named namespaces, that's not supported.

From there, you have two options:

  1. you can either change your coding styles (amount of work == 0), or
  2. you can submit a Pull Request to LLVM, so a new option is added to Clang-format.

Several options we saw in this article come from new contributors, you can be the next one.

Pro-tip 3: Add Clang-format to your CI

Stop arguing about code formatting during code reviews, this is a complete waste of time!

People are wasting too much energy on the position of braces and number of spaces, but this adds absolutely no value.

Instead make Clang-format a part of your Continuous Integration.
Either let the CI report a warning when the code is not properly formatted (you're likely to prefer that to a co-worker pointing at your mistakes) or let the CI commit the change.

You'll save a tremendous amount of energy that you'll be able to focus on important stuff like design, algorithms and test coverage.

Pro-tip 4: Stop formatting code by hand

Have mercy for your space bar. Stop hitting it hundreds times a day!

Instead, configure your text editor or IDE to apply Clang-format each time the file is saved.

This has another benefit: if you mistyped a brace or a bracket, you'll instantly see that the indentation is wrong.
You'll be able to fix many typos without going through the compilation phase, and thus save a lot of time.