<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/77450>77450</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[clang-format] Incorrect cursor position with IncludeBlocksStyle Regroup and LineEnding CRLF
</td>
</tr>
<tr>
<th>Labels</th>
<td>
clang-format
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
NorthBlue333
</td>
</tr>
</table>
<pre>
Hello,
We recently configured clang-format on our projects with Visual Studio.
We found what we consider to be a bug: the cursor has the wrong position when formatting a file with CRLF line endings and includes already formatted.
Here are the reproduction steps:
`.clang-format`
```yml
LineEnding: CRLF
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
SortPriority: 0
- Regex: '^<.*\.h>'
Priority: 1
SortPriority: 0
- Regex: '^<.*'
Priority: 2
SortPriority: 0
- Regex: '.*\.generated\.h.*' # always last
Priority: 2
SortPriority: 100
- Regex: '.*\/.*\.h'
Priority: 20
SortPriority: 40
- Regex: '.*\/.*'
Priority: 20
SortPriority: 40
- Regex: '.*\.h'
Priority: 30
SortPriority: 30
- Regex: '.*'
Priority: 30
SortPriority: 30
```
`Foo.cpp`
```cpp
#include "Foo.h"
#include "Bar.h"
#include "Sub/Bar.h"
#include "Sub/Foo.h"
class Foo {
}
```
When formatting `Foo.cpp`, it correctly formats the include block:
`Foo.cpp`
```cpp
#include "Foo.h"
#include "Bar.h"
#include "Sub/Bar.h"
#include "Sub/Foo.h"
class Foo {
}
```
But when reformatting again, if the cursor is at pos 62 (just before `#include "Sub/Foo.h"`, note that we use CRLF), it will not return any replacements BUT it will return the wrong position for the cursor: 60. The cursor goes one line up, on `#include "Sub/Bar.h"`. The same thing happens when placing the cursor before `class Foo {`.
This seems to be aggravated by Visual Studio, which always sends to clang-format the start of the line as the cursor position, no matter where the cursor is on the line.
After some research, we think we've found the issue.
`clang/lib/Format/Format.cpp:2694`
```
std::string result;
for (unsigned Index : Indices) {
if (!result.empty()) {
result += "\n";
if (Style.IncludeStyle.IncludeBlocks ==
tooling::IncludeStyle::IBS_Regroup &&
CurrentCategory != Includes[Index].Category)
result += "\n";
}
result += Includes[Index].Text;
if (Cursor && CursorIndex == Index)
*Cursor = IncludesBeginOffset + result.size() - CursorToEOLOffset;
CurrentCategory = Includes[Index].Category;
}
if (Cursor && *Cursor >= IncludesEndOffset)
*Cursor += result.size() - IncludesBlockSize;
// If the #includes are out of order, we generate a single replacement fixing
// the entire range of blocks. Otherwise, no replacement is generated.
if (replaceCRLF(result) == replaceCRLF(std::string(Code.substr(
IncludesBeginOffset, IncludesBlockSize))))
return;
```
In this code, both cursor updates seem wrong. They are based on `result.size()` which **does not include the second line ending character** `\r`. The cursor position is then offsetted by the number of lines between include blocks.
The solution might be to use the correct new line character here, or to check the line ending length (1 character for LF and CR, 2 characters for CRLF).
I will provide a PR.
Thanks for your time
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzEWF9v4joW_zTm5agoONCUBx6AFt1Ko52raXfv48okh8R3jI1spwz76VfHdiChTDuredgqghKfv79jn99JhHOy1ogLNlux2eNItL4xdvEPY32zUi3meT7amuq0-AOVMoyvWfbIsuVfCBZL1F6doDR6J-vWYgWlErq-2xm7Fx6MBtNaOFjzN5bewVH6Bv4lXSsUvPi2kmZ8NrYzra7g2AgPRySLTlZowRvYIgjYtjXLl-AbhLK1zlhohAs_j9boGg7GSS-NhmODGqJ_L3UNAnZSYXS9_vZlA0pqBNSV1LUDoSuQulRthQ6EsiiqU6eNVYoufv6BFkFYDE4tHqyp2jK4dB4PjuXLvjS7z8Z9LNh9dl6I12mv4p0vUuNTiIcypBjj_ecY10qZ8juZh29YW9MeBqtr4bE2VuIlAIA7EsUfpHP5Y7xgsyeWr_GHZ3wzZnzJZutxw_InWoqqf1pprPSnnirvrAK8GOuvJLIbPs-ebvsAuOVm8ptuPjH_v2cxQK7LpEaNVnisQlrJMTCeg1BHcXKghPO3A_k4gkn2qzEMavdh4bIPPU5_gumVm89w_S0n_Qxu288_tn9e_hC03_CRXx_bq0O-MWZcHg7vjzfdjHd4njoMMM5JvmGc31pbCfvTtZd2y_jmc4kr--GzVMI52BgDrFilheLxg7z-uuqhwzz5GqSH0liLJXX_KBibcRfPlprW-5b4m2h9jtn_G7lV6yMDWexzUC2kDrjt-gwmHQhPzAX3HBh_-Lt1HrakiBCA_iDIWAdtPPFR5MzWYWQPPk81OkqlSAYs-tZqEPpEzKVEiXvU3sHqn69nuSRzg1J3xvbCplNxn43h9ZJIbdCB0Ri5tT2Qe6N_lsO5FJ0VJ_aUBSHViMMBtYsYUqB0swfZBZ1hae6zAVe_NtKBQ9y7boCoayveqHHD9jQcQSjYYyPLpmvhDnUV9AazDAXhvLAeTCxiyDXNICm6DrFYGghDhKVc0tRwqbvRZxuDwJc70nBmTyOGQ2HLJsQX8fkOR2S8eOumpXDinGuHNiI4umZ8o2TcNGEC6f4JJzBf8vv59P1BTJ3Q-YpOb7503lIJLLpWeZavuk5Je4Lxh1aH4bGCZ13hD6C98awrWaJjfH45NNRZ5Y4UGJ9EW2PcH_wp3Jm_k4XkEBhfsfyR9g6brTV95QOxaPTFnxSO00Q0-BGHJ2D5I11R0Ruj4rDF8mVfKd1Zvfw7TVrA-D1dPYf0t26tRe3T6HUCxicUZDLl2GwV0GCzx3EnQ0kOrPxSfudecyV-y9MrjXX5O7zXccvFRCD-6mr1GG2RgWF4jC87vZ63FdZSf93tHIZAUkxjJ_-DsYxwlxy8mqevX6LkIKR3wH2G2ln50nWTsVvZ9cN-6tt-0lWKpp9nTzzCeiuhc_K0kV5opYupM8T4hvENPMeucGl4LjwsmDY0DGMrtOkkdzMkCHBS1wr7PRl28gdtzqFxsozaS4tgha6RTAaKdWP46hu0R-kwdZ2-MenO3rqHmQ66JBYJ4yGdbzqHcVsMl6_aASFvKhy7duu8Jayi6Rs7hYJ6j2E48uk61yMS0AXfW_z6TH1TOihNFfLdGt90bbU9VMJj7PuRwgK9nEIdtsJhlUjpXZ3ZfZYoIEyLy4r4jHiz467Q_LE0uuo_PkLZCCtKT5UltUB4s7VlV_R4JlIZ2EKDCdAkMiLbut1v0VJVybyDLfojoh6OU-6K4hCcUW0wvJd1Q6MDsRaNAYFs4oAGGo8x6HO0QIQUODo8X5cNlt8vlJZyU6hrT4A8THqa1Pa_bMJj8_obmeCXRRdW0wQyiPU5ThgHa95kRfv-z29XuQj9PaqfTGvByz2OqkVezfO5GOFiUmTTh4xns2LULGb5dJpNi-nsYTqbP-zKYp5PC3yYz2aTrKqyyUgueMan2SSbT3hW5MVY7Ios3xXT6YSLajov2DTDvZBqrNTbfmxsPQokuiiK6SwbKbFF5cLbEM4Hj_DUpB9HdkFqd9u2dmyaKem8uxjy0qvwJmWgOAutKNXjelOENxMDugpk1D3tB6wvrwgCvqPWqkXjfXzrEFpELX3Tbsel2RPtq7fu6y69fGF8E5J0jG9Cnv8NAAD__1tSWVI">