<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/55027>55027</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            clang-format incorrectly updates cursor positions when collapsing include blocks
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          bbarenblat
      </td>
    </tr>
</table>

<pre>
    If clang-format removes vertical whitespace from an `#include` block and `--cursor` points past the include block, clang-format will incorrectly compute the new cursor location. Here’s an example:

```sh-session
$ printf '#include "a"\n\n#include "b"\n' | clang-format --cursor=25
{ "Cursor": 24, "IncompleteFormat": false }
#include "a"
#include "b"
$ printf '#include "a"\n\n#include "b"\n' | clang-format --cursor=26
{ "Cursor": 26, "IncompleteFormat": false }
#include "a"
#include "b"
```

In this example, I pass clang-format the 27-byte string ```#include "a"\n\n#include "b"\n```. If I tell clang-format that the cursor is sitting on the close quote of `#include "b"` (byte 25), it correctly moves the cursor to byte 24. But if I tell clang-format the cursor is sitting on the newline immediately after `#include "b"` (byte 26), it keeps the cursor at byte 26. In an editor, this makes the cursor appear to move one byte forward.

This isn’t related to byte 26 being the last byte in the input. For example,

```sh-session
$ printf '#include "a"\n\n#include "b"\nf();\n' | clang-format --cursor=28
{ "Cursor": 28, "IncompleteFormat": false }
#include "a"
#include "b"
f();
```

adds a function call after the includes. Before the format, the cursor is sitting on byte 28, the open parenthesis of the call. Afterwards, it’s still sitting on byte 28, but this is now the closing parenthesis of the call.

This bug only occurs if changes get made to includes. For example,

```sh-session
$ printf 'int f() {\n\n  int value = 0;\n  return value;\n}\n' | clang-format --cursor=30
{ "Cursor": 29, "IncompleteFormat": false }
int f() {
  int value = 0;
  return value;
}
```

starts with the cursor on byte 30, the “r” of `return`. clang-format deletes the spurious blank line at the start of the function body and correctly moves the cursor to byte 29, keeping it on the “r”.

I tested this at commit a571f82a50416b767fd3cce0fb5027bb5dfec58c, but it also occurs in released versions of LLVM (LLVM 11.0.1, for instance).
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy9Vstu6zYQ_Rp5Q1iQKcuyF14kdoMGuN0V3ZPSyGZDkSpJxc3fd4aS_MgLubhIATkKNSTnzMyZQ0pbv2wfG1ZpYQ7zxrpWBOagtc_g2TO4oCqh2emoAvhOVMAaZ1smDEtWWcJzZSrd14ADJrWtntBSk2k-r3rnrSNDZ5UJnnXCBxaOwMY1w4KE7259n5TWNMU6B1XQL6yybdcHiEsNnNiwMcPFIihrUvY7OEh-48k6SzYbT9jgX9F2GpL8Lsn2STb9RcTx8ce5B-9x8WjgS9Y5BNmwhJeXqHDEBf6SYmfi78YiJwsvWVK-iuIcf77nxeilvKdlu-E7rs3vGF9S_Dh4NBSmhgAPcYPR3gjt0Vm5n4C-gfbOd3n1_VsDW30S2Op7A5tKeV3fR4McUf5cfQTwSKzztxEQj3g5ly_IKR8wOwd22e5nUzQtTBn20CMLgOR95W10OdIW8XkVAnm1ZjBoi6n4p7eIxzbsDYroC9so4euIGfnENxScCuzSJUPDXjkKlg3Tlym77wNTH-H7BBq2m1YGO7ZtoVYCV78w0QRwX0C5uqB8AuhusKHfcRLmzcSOrVUg8uyGErbi6TYa0XUgYlAUKOKDYQeM4iRcnV7z4E_aQXlz1gQSNI3o60tSVkwCBUouNAlT_KzMKFAoOClDwl5x6X9QkgaTR1nL77_UfutP2m_9re13BfTjdhR1jWLMmt5UpNMMzxE9sufqFPDITsDgBn1vRpC7j3k51G89zbEdGGxyBwZHHqdiC8W16C1ld-SOCOIHKl4dEz7QQfP-xrIPAw_xMfZ0blOa-ZGvNwyUPW2LHWMrCoQasDpiKZHYBwhIccwq8vGSh1_mG77ZWBqs7f1ENsbI8Cx0j2XM9ywbCcawLULvzGCaWIec-AL58uwT8m1-inyvUceP72IeLa9Rj0D2n3DRB-HwCnJS4XjNrKnqGM1Ip4kgOzf9tx9FefAapf4mKTVQgINY-a53yvZYe5zxxKJ2jhobEUyEOfeExNtXvDJ9RchjWklLiYYoq6NIvwP5hoyk-j6KH7FS0KHRtrhcFOWiWXNRZMvFSparsqnzqoKskUXGSymLuoGqWFdTQ9AS7e2ZzoZUFYTHnfGeSJyMDfHjx19_0CkQ34tFmqUL2qGhRjaYBVMhuzfprN7m9SbfiFlQQcP2JqfX17--qwXld8xGh10Yoq_TETu_slqLLjbmzbXSz3qnt8cQOk-3QP6AzwGr38sUw8eB1s_Ta945-zc6w6HyvgfUioeCcjA7bterooFFVctmudpIzkGu1gXURcGzrNys85kWErTfJsU9spuup3GLKOj7mdryjPNsyRec83xRpvma51ldbrKsqRdLKZNlBq1QOiUcqXWHmdtGSCgeHo1a-eAvRrzLqIMBiO5wf9GHo3VbKUmTkHNhFr1vI_r_AIqvqS8">