Thanks!
Here’s a (not minimal) reduction of the first issue; it looks like the other issues are basically the same thing:
$ cat fmt.c
void cdataSectionTok()
{
switch (1) {
#define LEAD_CASE(n)
case BT_LEAD ## n:
break
LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
#undef LEAD_CASE
default:
break;
}
}
$ out/gn/bin/clang-format fmt.c
void cdataSectionTok() {
switch (1) {
#define LEAD_CASE(n)
case BT_LEAD##n:
break
LEAD_CASE(2)
LEAD_CASE(3) LEAD_CASE(4)
#undef LEAD_CASE
default : break;
}
}
As you can see by the weird “default : break” at the end, clang-format gets confused about the whole switch statement. It looks like the macros confuse it. Just adding semicolons after it is sufficient to unconfuse it:
$ cat fmt.c
void cdataSectionTok()
{
switch (1) {
#define LEAD_CASE(n)
case BT_LEAD ## n:
break
LEAD_CASE(2); LEAD_CASE(3); LEAD_CASE(4);
#undef LEAD_CASE
default:
break;
}
}
$ out/gn/bin/clang-format fmt.c
void cdataSectionTok() {
switch (1) {
#define LEAD_CASE(n)
case BT_LEAD##n:
break
LEAD_CASE(2);
LEAD_CASE(3);
LEAD_CASE(4);
#undef LEAD_CASE
default:
break;
}
}
If you’re able to change expat’s source, this might be a good approach.
Else, you can explicitly tell clang-format the name of macros that should be handled as statements in your .clang-format file like so:
StatementMacros: [‘LEAD_CASE’]
That helps with LEAD_CASE. (clang-format should still converge within one round, but it’s going to converge to something bad without either of the two things I suggest, so it wouldn’t help you much).
Like Raphaël’s mail says, XCS is slightly different because it’s not a statement. clang-format has special logic for formatting sequences of string literals, and that doesn’t fire if each literal is surrounded by a macro.
You can fix this by doing XCS("foo" "bar")
(with a linebreak in between foo and bar) instead of XCS("foo") XCS("bar")
. Semantically they do the same thing as far as I can tell, but clang-format does much better with the first form. Having done this transformation locally, this is arguably easier to read for humans too.
There isn’t a .clang-format setting for this case as far as I know.
(Again, clang-format should reach a fixed point in one hop, but again the one hop gives you pretty bad formatting so fixing that bug wouldn’t help you all that much.)
With these two changes, clang-format does reach an end state in one step, and its output (for the two cases I looked at) looks good too.
Hope this helps!