clang-format and driver code

. . . I am now free to return to banging my fucking head against the wall trying to make clang-format (as packaged in VS 2019) actually do what I want it to do. Because, you know, that’s something easy to accomplish.

My head still has bruises from my fights with clang-format. I can’t say I’m 100% happy with the current cease-fire, but I have been able to coax clang into doing something … passable … with NDIS code.

The hard part was SAL annotations. I eventually solved that using a feature that was just introduced in the very recent clang 9.0 release: StatementMacros. This 9.0 release isn’t currently bundled with Visual Studio, so you have to download it separately and configure VS to use your custom clang-format.exe. Tools > Options > Text Editor > C/C++ > Formatting > General > Use custom clang-format.exe file.

Then in your .clang-format, put something like this:

StatementMacros: [
    'EXTERN_C',
    '_At_',
    '_When_',
    '_Success_',
    '_Check_return_',
    '_Must_inspect_result_',
    '_IRQL_requires_',
    '_IRQL_requires_max_',
    '_IRQL_requires_min_',
    '_IRQL_saves_',
    '_IRQL_restores_',
    '_IRQL_saves_global_',
    '_IRQL_restores_global_',
    '_IRQL_raises_',
    '_IRQL_lowers_',
    '_Acquires_lock_',
    '_Releases_lock_',
    '_Acquires_exclusive_lock_',
    '_Releases_exclusive_lock_',
    '_Acquires_shared_lock_',
    '_Releases_shared_lock_',
    '_Requires_lock_held_',
    '_Use_decl_annotations_',
    '_Guarded_by_',
    ]

That’ll ensure that each function-level annotation winds up on its own line, like this:

_IRQL_requires_(PASSIVE_LEVEL)
NTSTATUS Foo()
{
    return STATUS_NOT_IMPLEMENTED;
}

Another tip for drivers. If you use WPP tracing, you’ll probably want this .clang-format directive:

CommentPragmas: '^begin_wpp|^end_wpp'

Otherwise, clang-format will permit itself to mangle the special //begin_wpp comment blocks.

That all being said, there’s still brokenness here. For example, clang-format recognizes __declspec as a built-in token, so it won’t let you hack it using StatementMacros. So NDIS code currently has this unfortunate spot of indentation:

__declspec(noinline)
    VOID ndisNblTrackerDebugBreak(. . . something . . .)
{
    . . .;
}

I also have some issues with clang-format’s “binpacking” of arguments, but that’s a general style issue and not specific to drivers, so I’ll not discuss it here.

Have you got a complete .clang-format file that works well for you generally? I wouldn’t mind just adopting whatever code style you use wholesale.

I won’t say I’m completely happy about clang-format’s output. Let’s just say this format file is the best I could do, before my patience expired. But it is what we’re using now for NDIS code.

Some small parts of it are specific to NDIS code, like the PAGED and INITCODE tokens. You almost certainly don’t need those.

https://gist.github.com/jtippet/443c3769d5ff81691ebe6cdd9b9edd42

Thanks! It’s not so bad, and generally some enforced style even if not ideal is better than nothing.

If I could only get the damn thing to wrap function arguments, one argument per line and aligned with the left brace. Always. I’d be a happy man.

        status = WdfDeviceCreate(&FxDeviceInit, 
                                 &deviceAttributes,
                                 &fxDevice);

(let’s hope everyone can read that. The point is the ampersands are all directly under each other)

There is no setting – none at all – that I could use to get clang-format to produce anything even remotely like this. I don’t even care if the first argument is on the same line as the function. I just want them all lined-up under each other, and with the left bracket, as Gxd himself so very obviously intended.

I know, it defies common sense. I wasn’t the only one who spent a whole day trying to get this to work, even :frowning:

+1 I really don’t like clang-format’s love of what it calls “bin-packing”. It’s nice that the feature exists for whoever wants it, but I just want to turn it off everywhere. I got so frustrated that I tried to go fix their code, but then I discovered that it’s this generic soup of crap that is designed to be equally bad at whitespacing both javascript, C++, Objective C, and google protobuf files. Because those are all clearly the same thing and need the same whitespacing rules.

I got so frustrated that I tried to go fix their code, but then I discovered …

:smiley: LOL LOL LOL

That’s exactly what we did: “It’s open source. Pull the fucking repo and change the code to make it work. I mean, how hard can it be?”

Most of my worst experiences have been prefaced with the phrase: how hard can it be?

Yeah. Well. The answer is “Not hard. Rather, it’s effectively impossible unless you want to make clang-format your life’s work. And, while my life may be pitifully silly in some respects, it’s not nearly pitiful enough to want to spend more than an hour of it on making clang-format do what it already should.

“Oh well, whatever never mind”

Peter