diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -2638,10 +2638,10 @@ StringRef Code, tooling::Replacements &Replaces, unsigned *Cursor) { tooling::IncludeCategoryManager Categories(Style.IncludeStyle, FileName); - unsigned IncludesBeginOffset = Includes.front().Offset; - unsigned IncludesEndOffset = + const unsigned IncludesBeginOffset = Includes.front().Offset; + const unsigned IncludesEndOffset = Includes.back().Offset + Includes.back().Text.size(); - unsigned IncludesBlockSize = IncludesEndOffset - IncludesBeginOffset; + const unsigned IncludesBlockSize = IncludesEndOffset - IncludesBeginOffset; if (!affectsRange(Ranges, IncludesBeginOffset, IncludesEndOffset)) return; SmallVector Indices = @@ -2685,7 +2685,7 @@ // the entire block. Otherwise, no replacement is generated. // In case Style.IncldueStyle.IncludeBlocks != IBS_Preserve, this check is not // enough as additional newlines might be added or removed across #include - // blocks. This we handle below by generating the updated #imclude blocks and + // blocks. This we handle below by generating the updated #include blocks and // comparing it to the original. if (Indices.size() == Includes.size() && llvm::is_sorted(Indices) && Style.IncludeStyle.IncludeBlocks == tooling::IncludeStyle::IBS_Preserve) @@ -2706,6 +2706,9 @@ 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( diff --git a/clang/unittests/Format/SortIncludesTest.cpp b/clang/unittests/Format/SortIncludesTest.cpp --- a/clang/unittests/Format/SortIncludesTest.cpp +++ b/clang/unittests/Format/SortIncludesTest.cpp @@ -890,6 +890,21 @@ EXPECT_EQ(10u, newCursor(Code, 43)); } +TEST_F(SortIncludesTest, CalculatesCorrectCursorPositionWithRegrouping) { + Style.IncludeBlocks = Style.IBS_Regroup; + std::string Code = "#include \"b\"\n" // Start of line: 0 + "\n" // Start of line: 13 + "#include \"aa\"\n" // Start of line: 14 + "int i;"; // Start of line: 28 + std::string Expected = "#include \"aa\"\n" // Start of line: 0 + "#include \"b\"\n" // Start of line: 14 + "int i;"; // Start of line: 27 + EXPECT_EQ(Expected, sort(Code)); + EXPECT_EQ(12u, newCursor(Code, 26)); // Closing quote of "aa" + EXPECT_EQ(26u, newCursor(Code, 27)); // Newline after "aa" + EXPECT_EQ(27u, newCursor(Code, 28)); // Start of last line +} + TEST_F(SortIncludesTest, DeduplicateIncludes) { EXPECT_EQ("#include \n" "#include \n"