[PATCH] D144296: [clang-format] Rewrite how indent is reduced for compacted namespaces

2023-02-25 Thread Emilia Dreamer via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG7ba91016c6ad: [clang-format] Rewrite how indent is reduced 
for compacted namespaces (authored by rymiel).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144296/new/

https://reviews.llvm.org/D144296

Files:
  clang/lib/Format/UnwrappedLineFormatter.cpp
  clang/unittests/Format/FormatTest.cpp

Index: clang/unittests/Format/FormatTest.cpp
===
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -4431,6 +4431,46 @@
"int k; }} // namespace out::mid",
Style));
 
+  verifyFormat("namespace A { namespace B { namespace C {\n"
+   "  int i;\n"
+   "}}} // namespace A::B::C\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   "namespace A { namespace B {\n"
+   "namespace C {\n"
+   "  int i;\n"
+   "}} // namespace B::C\n"
+   "} // namespace A\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   Style);
+
+  verifyFormat("namespace A { namespace B { namespace C {\n"
+   "#ifdef FOO\n"
+   "  int i;\n"
+   "#endif\n"
+   "}}} // namespace A::B::C\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   "namespace A { namespace B {\n"
+   "namespace C {\n"
+   "#ifdef FOO\n"
+   "  int i;\n"
+   "#endif\n"
+   "}} // namespace B::C\n"
+   "} // namespace A\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   Style);
+
   Style.NamespaceIndentation = FormatStyle::NI_Inner;
   EXPECT_EQ("namespace out { namespace in {\n"
 "  int i;\n"
Index: clang/lib/Format/UnwrappedLineFormatter.cpp
===
--- clang/lib/Format/UnwrappedLineFormatter.cpp
+++ clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -60,7 +60,8 @@
 Offset = getIndentOffset(*Line.First);
 // Update the indent level cache size so that we can rely on it
 // having the right size in adjustToUnmodifiedline.
-skipLine(Line, /*UnknownIndent=*/true);
+if (Line.Level >= IndentForLevel.size())
+  IndentForLevel.resize(Line.Level + 1, -1);
 if (Style.IndentPPDirectives != FormatStyle::PPDIS_None &&
 (Line.InPPDirective ||
  (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash &&
@@ -81,13 +82,6 @@
   Indent = Line.Level * Style.IndentWidth + Style.ContinuationIndentWidth;
   }
 
-  /// Update the indent state given that \p Line indent should be
-  /// skipped.
-  void skipLine(const AnnotatedLine , bool UnknownIndent = false) {
-if (Line.Level >= IndentForLevel.size())
-  IndentForLevel.resize(Line.Level + 1, UnknownIndent ? -1 : Indent);
-  }
-
   /// Update the level indent to adapt to the given \p Line.
   ///
   /// When a line is not formatted, we move the subsequent lines on the same
@@ -367,20 +361,27 @@
 // instead of TheLine->First.
 
 if (Style.CompactNamespaces) {
-  if (auto nsToken = TheLine->First->getNamespaceToken()) {
-int i = 0;
-unsigned closingLine = TheLine->MatchingClosingBlockLineIndex - 1;
-for (; I + 1 + i != E &&
-   nsToken->TokenText == getNamespaceTokenText(I[i + 1]) &&
-   closingLine == I[i + 1]->MatchingClosingBlockLineIndex &&
-   I[i + 1]->Last->TotalLength < Limit;
- i++, --closingLine) {
-  // No extra indent for compacted namespaces.
-  IndentTracker.skipLine(*I[i + 1]);
-
-  Limit -= I[i + 1]->Last->TotalLength;
+  if (const auto *NSToken = TheLine->First->getNamespaceToken()) {
+int J = 1;
+assert(TheLine->MatchingClosingBlockLineIndex > 0);
+for (auto ClosingLineIndex = TheLine->MatchingClosingBlockLineIndex - 1;
+ I + J != E && NSToken->TokenText == getNamespaceTokenText(I[J]) &&
+ ClosingLineIndex == I[J]->MatchingClosingBlockLineIndex &&
+ I[J]->Last->TotalLength < Limit;
+ ++J, --ClosingLineIndex) {
+  Limit -= I[J]->Last->TotalLength;
+
+  // Reduce indent level for bodies of namespaces which were compacted,
+  // but only if their content was indented in the first place.
+  auto *ClosingLine = AnnotatedLines.begin() + ClosingLineIndex + 1;
+  auto OutdentBy = I[J]->Level - TheLine->Level;
+  for (auto *CompactedLine 

[PATCH] D144296: [clang-format] Rewrite how indent is reduced for compacted namespaces

2023-02-21 Thread Emilia Dreamer via Phabricator via cfe-commits
rymiel updated this revision to Diff 499330.
rymiel added a comment.

Inline and remove LevelIndentTracker::skipLine


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144296/new/

https://reviews.llvm.org/D144296

Files:
  clang/lib/Format/UnwrappedLineFormatter.cpp
  clang/unittests/Format/FormatTest.cpp

Index: clang/unittests/Format/FormatTest.cpp
===
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -4431,6 +4431,46 @@
"int k; }} // namespace out::mid",
Style));
 
+  verifyFormat("namespace A { namespace B { namespace C {\n"
+   "  int i;\n"
+   "}}} // namespace A::B::C\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   "namespace A { namespace B {\n"
+   "namespace C {\n"
+   "  int i;\n"
+   "}} // namespace B::C\n"
+   "} // namespace A\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   Style);
+
+  verifyFormat("namespace A { namespace B { namespace C {\n"
+   "#ifdef FOO\n"
+   "  int i;\n"
+   "#endif\n"
+   "}}} // namespace A::B::C\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   "namespace A { namespace B {\n"
+   "namespace C {\n"
+   "#ifdef FOO\n"
+   "  int i;\n"
+   "#endif\n"
+   "}} // namespace B::C\n"
+   "} // namespace A\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   Style);
+
   Style.NamespaceIndentation = FormatStyle::NI_Inner;
   EXPECT_EQ("namespace out { namespace in {\n"
 "  int i;\n"
Index: clang/lib/Format/UnwrappedLineFormatter.cpp
===
--- clang/lib/Format/UnwrappedLineFormatter.cpp
+++ clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -59,7 +59,8 @@
 Offset = getIndentOffset(*Line.First);
 // Update the indent level cache size so that we can rely on it
 // having the right size in adjustToUnmodifiedline.
-skipLine(Line, /*UnknownIndent=*/true);
+if (Line.Level >= IndentForLevel.size())
+  IndentForLevel.resize(Line.Level + 1, -1);
 if (Style.IndentPPDirectives != FormatStyle::PPDIS_None &&
 (Line.InPPDirective ||
  (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash &&
@@ -80,13 +81,6 @@
   Indent = Line.Level * Style.IndentWidth + Style.ContinuationIndentWidth;
   }
 
-  /// Update the indent state given that \p Line indent should be
-  /// skipped.
-  void skipLine(const AnnotatedLine , bool UnknownIndent = false) {
-if (Line.Level >= IndentForLevel.size())
-  IndentForLevel.resize(Line.Level + 1, UnknownIndent ? -1 : Indent);
-  }
-
   /// Update the level indent to adapt to the given \p Line.
   ///
   /// When a line is not formatted, we move the subsequent lines on the same
@@ -366,20 +360,27 @@
 // instead of TheLine->First.
 
 if (Style.CompactNamespaces) {
-  if (auto nsToken = TheLine->First->getNamespaceToken()) {
-int i = 0;
-unsigned closingLine = TheLine->MatchingClosingBlockLineIndex - 1;
-for (; I + 1 + i != E &&
-   nsToken->TokenText == getNamespaceTokenText(I[i + 1]) &&
-   closingLine == I[i + 1]->MatchingClosingBlockLineIndex &&
-   I[i + 1]->Last->TotalLength < Limit;
- i++, --closingLine) {
-  // No extra indent for compacted namespaces.
-  IndentTracker.skipLine(*I[i + 1]);
+  if (const auto *NSToken = TheLine->First->getNamespaceToken()) {
+int J = 1;
+assert(TheLine->MatchingClosingBlockLineIndex > 0);
+for (auto ClosingLineIndex = TheLine->MatchingClosingBlockLineIndex - 1;
+ I + J != E && NSToken->TokenText == getNamespaceTokenText(I[J]) &&
+ ClosingLineIndex == I[J]->MatchingClosingBlockLineIndex &&
+ I[J]->Last->TotalLength < Limit;
+ ++J, --ClosingLineIndex) {
+  Limit -= I[J]->Last->TotalLength;
 
-  Limit -= I[i + 1]->Last->TotalLength;
+  // Reduce indent level for bodies of namespaces which were compacted,
+  // but only if their content was indented in the first place.
+  auto *ClosingLine = AnnotatedLines.begin() + ClosingLineIndex + 1;
+  auto OutdentBy = I[J]->Level - TheLine->Level;
+  for (auto *CompactedLine = I + J; CompactedLine <= ClosingLine;
+   ++CompactedLine) {
+if (!(*CompactedLine)->InPPDirective)
+  

[PATCH] D144296: [clang-format] Rewrite how indent is reduced for compacted namespaces

2023-02-21 Thread Emilia Dreamer via Phabricator via cfe-commits
rymiel added inline comments.



Comment at: clang/lib/Format/UnwrappedLineFormatter.cpp:387
+if (!(*compactedLine)->InPPDirective)
+  (*compactedLine)->Level-= dedentBy;
+  }

owenpan wrote:
> Did git-clang-format miss this?
Nope, I forgot to amend the change!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144296/new/

https://reviews.llvm.org/D144296

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144296: [clang-format] Rewrite how indent is reduced for compacted namespaces

2023-02-21 Thread Emilia Dreamer via Phabricator via cfe-commits
rymiel updated this revision to Diff 499328.
rymiel marked 7 inline comments as done.
rymiel added a comment.

Apply suggestions and add extra test


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144296/new/

https://reviews.llvm.org/D144296

Files:
  clang/lib/Format/UnwrappedLineFormatter.cpp
  clang/unittests/Format/FormatTest.cpp


Index: clang/unittests/Format/FormatTest.cpp
===
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -4431,6 +4431,46 @@
"int k; }} // namespace out::mid",
Style));
 
+  verifyFormat("namespace A { namespace B { namespace C {\n"
+   "  int i;\n"
+   "}}} // namespace A::B::C\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   "namespace A { namespace B {\n"
+   "namespace C {\n"
+   "  int i;\n"
+   "}} // namespace B::C\n"
+   "} // namespace A\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   Style);
+
+  verifyFormat("namespace A { namespace B { namespace C {\n"
+   "#ifdef FOO\n"
+   "  int i;\n"
+   "#endif\n"
+   "}}} // namespace A::B::C\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   "namespace A { namespace B {\n"
+   "namespace C {\n"
+   "#ifdef FOO\n"
+   "  int i;\n"
+   "#endif\n"
+   "}} // namespace B::C\n"
+   "} // namespace A\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   Style);
+
   Style.NamespaceIndentation = FormatStyle::NI_Inner;
   EXPECT_EQ("namespace out { namespace in {\n"
 "  int i;\n"
Index: clang/lib/Format/UnwrappedLineFormatter.cpp
===
--- clang/lib/Format/UnwrappedLineFormatter.cpp
+++ clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -366,20 +366,27 @@
 // instead of TheLine->First.
 
 if (Style.CompactNamespaces) {
-  if (auto nsToken = TheLine->First->getNamespaceToken()) {
-int i = 0;
-unsigned closingLine = TheLine->MatchingClosingBlockLineIndex - 1;
-for (; I + 1 + i != E &&
-   nsToken->TokenText == getNamespaceTokenText(I[i + 1]) &&
-   closingLine == I[i + 1]->MatchingClosingBlockLineIndex &&
-   I[i + 1]->Last->TotalLength < Limit;
- i++, --closingLine) {
-  // No extra indent for compacted namespaces.
-  IndentTracker.skipLine(*I[i + 1]);
+  if (const auto *NSToken = TheLine->First->getNamespaceToken()) {
+int J = 1;
+assert(TheLine->MatchingClosingBlockLineIndex > 0);
+for (auto ClosingLineIndex = TheLine->MatchingClosingBlockLineIndex - 
1;
+ I + J != E && NSToken->TokenText == getNamespaceTokenText(I[J]) &&
+ ClosingLineIndex == I[J]->MatchingClosingBlockLineIndex &&
+ I[J]->Last->TotalLength < Limit;
+ ++J, --ClosingLineIndex) {
+  Limit -= I[J]->Last->TotalLength;
 
-  Limit -= I[i + 1]->Last->TotalLength;
+  // Reduce indent level for bodies of namespaces which were compacted,
+  // but only if their content was indented in the first place.
+  auto *ClosingLine = AnnotatedLines.begin() + ClosingLineIndex + 1;
+  auto OutdentBy = I[J]->Level - TheLine->Level;
+  for (auto *CompactedLine = I + J; CompactedLine <= ClosingLine;
+   ++CompactedLine) {
+if (!(*CompactedLine)->InPPDirective)
+  (*CompactedLine)->Level -= OutdentBy;
+  }
 }
-return i;
+return J - 1;
   }
 
   if (auto nsToken = getMatchingNamespaceToken(TheLine, AnnotatedLines)) {


Index: clang/unittests/Format/FormatTest.cpp
===
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -4431,6 +4431,46 @@
"int k; }} // namespace out::mid",
Style));
 
+  verifyFormat("namespace A { namespace B { namespace C {\n"
+   "  int i;\n"
+   "}}} // namespace A::B::C\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   "namespace A { namespace B {\n"
+   "namespace C {\n"
+   "  int i;\n"
+   "}} // namespace B::C\n"
+   "} // namespace A\n"
+   "int main() {\n"
+   

[PATCH] D144296: [clang-format] Rewrite how indent is reduced for compacted namespaces

2023-02-19 Thread Owen Pan via Phabricator via cfe-commits
owenpan added a comment.

In D144296#4137508 , 
@HazardyKnusperkeks wrote:

> And I see the style was bogus before, but shouldn't all variables start with 
> a capital letter? Please fix that in the code you touch.

+1.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144296/new/

https://reviews.llvm.org/D144296

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144296: [clang-format] Rewrite how indent is reduced for compacted namespaces

2023-02-19 Thread Owen Pan via Phabricator via cfe-commits
owenpan added a comment.

In D144296#4136133 , @rymiel wrote:

> Note: this patch also makes `LevelIndentTracker::skipLine` obsolete. I 
> suppose I could clean that up in a following patch

I'd delete it in this patch.




Comment at: clang/lib/Format/UnwrappedLineFormatter.cpp:369
 if (Style.CompactNamespaces) {
-  if (auto nsToken = TheLine->First->getNamespaceToken()) {
-int i = 0;
-unsigned closingLine = TheLine->MatchingClosingBlockLineIndex - 1;
-for (; I + 1 + i != E &&
-   nsToken->TokenText == getNamespaceTokenText(I[i + 1]) &&
-   closingLine == I[i + 1]->MatchingClosingBlockLineIndex &&
-   I[i + 1]->Last->TotalLength < Limit;
- i++, --closingLine) {
-  // No extra indent for compacted namespaces.
-  IndentTracker.skipLine(*I[i + 1]);
+  if (auto *nsToken = TheLine->First->getNamespaceToken()) {
+int j = 1;





Comment at: clang/lib/Format/UnwrappedLineFormatter.cpp:371-373
+unsigned closingLineIndex = TheLine->MatchingClosingBlockLineIndex - 1;
 
+for (; I + j != E &&





Comment at: clang/lib/Format/UnwrappedLineFormatter.cpp:377
+   I[j]->Last->TotalLength < Limit;
+ j++, --closingLineIndex) {
+  Limit -= I[j]->Last->TotalLength;





Comment at: clang/lib/Format/UnwrappedLineFormatter.cpp:381
+  // Reduce indent level for bodies of namespaces which were compacted,
+  // but only if their content was indented in the first place
+  auto *closingLine = AnnotatedLines.begin() + closingLineIndex + 1;





Comment at: clang/lib/Format/UnwrappedLineFormatter.cpp:383
+  auto *closingLine = AnnotatedLines.begin() + closingLineIndex + 1;
+  auto dedentBy = I[j]->Level - TheLine->Level;
+  for (auto *compactedLine = I + j; compactedLine <= closingLine;

`outdentBy`?



Comment at: clang/lib/Format/UnwrappedLineFormatter.cpp:385
+  for (auto *compactedLine = I + j; compactedLine <= closingLine;
+   compactedLine++) {
+if (!(*compactedLine)->InPPDirective)





Comment at: clang/lib/Format/UnwrappedLineFormatter.cpp:387
+if (!(*compactedLine)->InPPDirective)
+  (*compactedLine)->Level-= dedentBy;
+  }

Did git-clang-format miss this?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144296/new/

https://reviews.llvm.org/D144296

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144296: [clang-format] Rewrite how indent is reduced for compacted namespaces

2023-02-19 Thread Björn Schäpers via Phabricator via cfe-commits
HazardyKnusperkeks added a comment.

There is no PP stuff in the new tests.

And I see the style was bogus before, but shouldn't all variables start with a 
capital letter? Please fix that in the code you touch.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144296/new/

https://reviews.llvm.org/D144296

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144296: [clang-format] Rewrite how indent is reduced for compacted namespaces

2023-02-17 Thread Emilia Dreamer via Phabricator via cfe-commits
rymiel added a comment.

Note: this patch also makes `LevelIndentTracker::skipLine` obsolete. I suppose 
I could clean that up in a following patch


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D144296/new/

https://reviews.llvm.org/D144296

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D144296: [clang-format] Rewrite how indent is reduced for compacted namespaces

2023-02-17 Thread Emilia Dreamer via Phabricator via cfe-commits
rymiel created this revision.
rymiel added a project: clang-format.
rymiel added reviewers: owenpan, MyDeveloperDay, HazardyKnusperkeks.
Herald added a project: All.
rymiel requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

The previous version set the indentation directly using IndentForLevel,
however, this has a few caveats, namely:

- IndentForLevel applies to all scopes of the entire program being

formatted, but this indentation should only be adjusted for scopes of
namespaces.

- The method it used only set the correct indent amount if one wasn't

already set for a given level, meaning it didn't work correctly if
anything with indentation preceded a namespace keyword. This includes
preprocessing directives if using IndentPPDirectives.

This patch instead reduces the Level of all lines within namespaces
which are compacted by CompactNamespaces. This means they will get
correct indentation using the normal process.

Fixes https://github.com/llvm/llvm-project/issues/60843


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D144296

Files:
  clang/lib/Format/UnwrappedLineFormatter.cpp
  clang/unittests/Format/FormatTest.cpp


Index: clang/unittests/Format/FormatTest.cpp
===
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -4431,6 +4431,24 @@
"int k; }} // namespace out::mid",
Style));
 
+  verifyFormat("namespace A { namespace B { namespace C {\n"
+   "  int i;\n"
+   "}}} // namespace A::B::C\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   "namespace A { namespace B {\n"
+   "namespace C {\n"
+   "  int i;\n"
+   "}} // namespace B::C\n"
+   "} // namespace A\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   Style);
+
   Style.NamespaceIndentation = FormatStyle::NI_Inner;
   EXPECT_EQ("namespace out { namespace in {\n"
 "  int i;\n"
Index: clang/lib/Format/UnwrappedLineFormatter.cpp
===
--- clang/lib/Format/UnwrappedLineFormatter.cpp
+++ clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -366,20 +366,28 @@
 // instead of TheLine->First.
 
 if (Style.CompactNamespaces) {
-  if (auto nsToken = TheLine->First->getNamespaceToken()) {
-int i = 0;
-unsigned closingLine = TheLine->MatchingClosingBlockLineIndex - 1;
-for (; I + 1 + i != E &&
-   nsToken->TokenText == getNamespaceTokenText(I[i + 1]) &&
-   closingLine == I[i + 1]->MatchingClosingBlockLineIndex &&
-   I[i + 1]->Last->TotalLength < Limit;
- i++, --closingLine) {
-  // No extra indent for compacted namespaces.
-  IndentTracker.skipLine(*I[i + 1]);
+  if (auto *nsToken = TheLine->First->getNamespaceToken()) {
+int j = 1;
+unsigned closingLineIndex = TheLine->MatchingClosingBlockLineIndex - 1;
 
-  Limit -= I[i + 1]->Last->TotalLength;
+for (; I + j != E &&
+   nsToken->TokenText == getNamespaceTokenText(I[j]) &&
+   closingLineIndex == I[j]->MatchingClosingBlockLineIndex &&
+   I[j]->Last->TotalLength < Limit;
+ j++, --closingLineIndex) {
+  Limit -= I[j]->Last->TotalLength;
+
+  // Reduce indent level for bodies of namespaces which were compacted,
+  // but only if their content was indented in the first place
+  auto *closingLine = AnnotatedLines.begin() + closingLineIndex + 1;
+  auto dedentBy = I[j]->Level - TheLine->Level;
+  for (auto *compactedLine = I + j; compactedLine <= closingLine;
+   compactedLine++) {
+if (!(*compactedLine)->InPPDirective)
+  (*compactedLine)->Level-= dedentBy;
+  }
 }
-return i;
+return j - 1;
   }
 
   if (auto nsToken = getMatchingNamespaceToken(TheLine, AnnotatedLines)) {


Index: clang/unittests/Format/FormatTest.cpp
===
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -4431,6 +4431,24 @@
"int k; }} // namespace out::mid",
Style));
 
+  verifyFormat("namespace A { namespace B { namespace C {\n"
+   "  int i;\n"
+   "}}} // namespace A::B::C\n"
+   "int main() {\n"
+   "  if (true)\n"
+   "return 0;\n"
+   "}",
+   "namespace A { namespace B {\n"
+   "namespace C {\n"
+   "  int i;\n"
+   "}} // namespace B::C\n"
+