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"
+               "} // 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)) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to