Search code examples
cllvmcode-formattingclang-formatidempotent

clang-format makes changes to an already formatted file


When formatting the same file with the clang-format command line tool twice, changes are made both times.

My understanding is that once formatted, attempting to re-format the same file should not yield any changes.

Here's the test I ran:

Input file

$ cat test.c 
//********************************************** AAAAAAA BBBB***************************************************//
  1. First format - Changes made as expected
$ clang-format -i test.c 
$ cat test.c 
//********************************************** AAAAAAA
//BBBB***************************************************//
  1. Second format - Unexpected change in line two (extra space was added before BBBB)**
$ clang-format -i test.c 
$ cat test.c 
//********************************************** AAAAAAA
// BBBB***************************************************//
  1. Third format - finally yields the same results.

The version I'm using is: 10.0.0-++20200323042644+d32170dbd5b-1~exp1~20200323154014.129 on Ubuntu 18.04.2 (note that I managed to reproduce this behavior in clang-format-9 as well)

Is this a bug I ran into, or is my initial assumption incorrect?

Edit: Reproducible in 10.0.1-++20200507062652+bab8d1790a3-1~exp1~20200507163249.158 as well


Solution

  • I can reproduce this lack of idempotency. There are three things you can do here: Use a different style, use fewer rules, or file it as a bug.

    1. Use a different style

    The styles that come with clang-format 10.0.0 are listed in --help:

     --style=<string>           - Coding style, currently supports:
                                     LLVM, Google, Chromium, Mozilla, WebKit.
    

    Where LLVM is the default. To specify a style, use clang-format --style=<style> .... Every style but Webkit reproduces this error (but webkit style makes no changes to the initial file):

    $ clang-format --style=webkit test.c > test2.c
    $ clang-format --style=webkit test2.c > test3.c
    $ diff test2.c test3.c
    $ 
    

    Your mileage may vary as you've said that this is one of many idempotency issues you've encountered.

    2. Use a rule subset

    Each style consists of rules that you can modify to suit your needs. You can dump the current config (default llvm) with clang-format --dump-config.

    $ clang-format --dump-config | tee .clang-format
    ---
    Language:        Cpp
    # BasedOnStyle:  LLVM
    AccessModifierOffset: -2
    AlignAfterOpenBracket: Align
    AlignConsecutiveMacros: false
    AlignConsecutiveAssignments: false
    
    <output truncated> 
    

    You can manually choose a smaller subset of these rules to use, or eliminate rules until you achieve idempotency.

    If you put this .clang-format file in the root directory of your project with your modifications, you can then tell clang-format to look for it with --style=file. Note that you can put a .clang-format file in a subdirectory if you want different formatting rules applied in that directory.

    3. File a Bug

    One of the key components of your question is whether clang-format treats a lack of idempotency as a bug. This is the case, based on reviews where this issue has been treated as a bug 0, 1.

    I can replicate this on 10.0.0 on Macos. You have all of the information you need to file it as a bug per the intro in the bug report docs. Obviously, this option requires you to wait until a fix is available.