]> granicus.if.org Git - clang/commitdiff
Takes the context into account when re-indenting regions.
authorManuel Klimek <klimek@google.com>
Fri, 8 Feb 2013 17:38:27 +0000 (17:38 +0000)
committerManuel Klimek <klimek@google.com>
Fri, 8 Feb 2013 17:38:27 +0000 (17:38 +0000)
Fixes llvm.org/PR14916.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174720 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Format/Format.cpp
unittests/Format/FormatTest.cpp

index bef5f9284397fc60ac82bd2fcb4f6dd3f9a1b456..0797fb8da4ad6a675ef4869cd723bb4df1d110dd 100644 (file)
@@ -921,34 +921,90 @@ public:
     for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
       Annotator.calculateFormattingInformation(AnnotatedLines[i]);
     }
+    std::vector<int> IndentForLevel;
     for (std::vector<AnnotatedLine>::iterator I = AnnotatedLines.begin(),
                                               E = AnnotatedLines.end();
          I != E; ++I) {
       const AnnotatedLine &TheLine = *I;
+      int Offset = GetIndentOffset(TheLine.First);
+      while (IndentForLevel.size() <= TheLine.Level)
+        IndentForLevel.push_back(-1);
+      IndentForLevel.resize(TheLine.Level + 1);
       if (touchesRanges(TheLine) && TheLine.Type != LT_Invalid) {
-        unsigned Indent =
-            formatFirstToken(TheLine.First, TheLine.Level,
-                             TheLine.InPPDirective, PreviousEndOfLineColumn);
+        unsigned LevelIndent = GetIndent(IndentForLevel, TheLine.Level);
+        unsigned Indent = LevelIndent;
+        if (static_cast<int>(Indent) + Offset >= 0)
+          Indent += Offset;
+        if (!TheLine.First.FormatTok.WhiteSpaceStart.isValid() ||
+            StructuralError) {
+          Indent = LevelIndent = SourceMgr.getSpellingColumnNumber(
+              TheLine.First.FormatTok.Tok.getLocation()) - 1;
+        } else {
+          formatFirstToken(TheLine.First, Indent, TheLine.InPPDirective,
+                           PreviousEndOfLineColumn);
+        }
         tryFitMultipleLinesInOne(Indent, I, E);
         UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine, Indent,
                                          TheLine.First, Whitespaces,
                                          StructuralError);
         PreviousEndOfLineColumn = Formatter.format();
+        IndentForLevel[TheLine.Level] = LevelIndent;
       } else {
         // If we did not reformat this unwrapped line, the column at the end of
         // the last token is unchanged - thus, we can calculate the end of the
-        // last token, and return the result.
+        // last token.
         PreviousEndOfLineColumn =
             SourceMgr.getSpellingColumnNumber(
                 TheLine.Last->FormatTok.Tok.getLocation()) +
             Lex.MeasureTokenLength(TheLine.Last->FormatTok.Tok.getLocation(),
                                    SourceMgr, Lex.getLangOpts()) - 1;
+        unsigned Indent = SourceMgr.getSpellingColumnNumber(
+            TheLine.First.FormatTok.Tok.getLocation()) - 1;
+        unsigned LevelIndent = Indent;
+        if (static_cast<int>(LevelIndent) - Offset >= 0)
+          LevelIndent -= Offset;
+        IndentForLevel[TheLine.Level] = LevelIndent;
       }
     }
     return Whitespaces.generateReplacements();
   }
 
 private:
+  /// \brief Get the indent of \p Level from \p IndentForLevel.
+  ///
+  /// \p IndentForLevel must contain the indent for the level \c l
+  /// at \p IndentForLevel[l], or a value < 0 if the indent for
+  /// that level is unknown.
+  unsigned GetIndent(const std::vector<int> IndentForLevel,
+                     unsigned Level) {
+    if (Level == 0)
+      return 0;
+    if (IndentForLevel[Level] != -1)
+      return IndentForLevel[Level];
+    return GetIndent(IndentForLevel, Level - 1) + 2;
+  }
+
+  /// \brief Get the offset of the line relatively to the level.
+  ///
+  /// For example, 'public:' labels in classes are offset by 1 or 2
+  /// characters to the left from their level.
+  int GetIndentOffset(const AnnotatedToken &RootToken) {
+    bool IsAccessModifier = false;
+    if (RootToken.is(tok::kw_public) || RootToken.is(tok::kw_protected) ||
+        RootToken.is(tok::kw_private))
+      IsAccessModifier = true;
+    else if (RootToken.is(tok::at) && !RootToken.Children.empty() &&
+             (RootToken.Children[0].isObjCAtKeyword(tok::objc_public) ||
+              RootToken.Children[0].isObjCAtKeyword(tok::objc_protected) ||
+              RootToken.Children[0].isObjCAtKeyword(tok::objc_package) ||
+              RootToken.Children[0].isObjCAtKeyword(tok::objc_private)))
+      IsAccessModifier = true;
+
+    if (IsAccessModifier)
+      return Style.AccessModifierOffset;
+    return 0;
+  }
+
   /// \brief Tries to merge lines into one.
   ///
   /// This will change \c Line and \c AnnotatedLine to contain the merged line,
@@ -1109,40 +1165,21 @@ private:
   /// \brief Add a new line and the required indent before the first Token
   /// of the \c UnwrappedLine if there was no structural parsing error.
   /// Returns the indent level of the \c UnwrappedLine.
-  unsigned formatFirstToken(const AnnotatedToken &RootToken, unsigned Level,
-                            bool InPPDirective,
-                            unsigned PreviousEndOfLineColumn) {
+  void formatFirstToken(const AnnotatedToken &RootToken, unsigned Indent,
+                        bool InPPDirective, unsigned PreviousEndOfLineColumn) {
     const FormatToken &Tok = RootToken.FormatTok;
-    if (!Tok.WhiteSpaceStart.isValid() || StructuralError)
-      return SourceMgr.getSpellingColumnNumber(Tok.Tok.getLocation()) - 1;
 
     unsigned Newlines =
         std::min(Tok.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
     if (Newlines == 0 && !Tok.IsFirst)
       Newlines = 1;
-    unsigned Indent = Level * 2;
-
-    bool IsAccessModifier = false;
-    if (RootToken.is(tok::kw_public) || RootToken.is(tok::kw_protected) ||
-        RootToken.is(tok::kw_private))
-      IsAccessModifier = true;
-    else if (RootToken.is(tok::at) && !RootToken.Children.empty() &&
-             (RootToken.Children[0].isObjCAtKeyword(tok::objc_public) ||
-              RootToken.Children[0].isObjCAtKeyword(tok::objc_protected) ||
-              RootToken.Children[0].isObjCAtKeyword(tok::objc_package) ||
-              RootToken.Children[0].isObjCAtKeyword(tok::objc_private)))
-      IsAccessModifier = true;
 
-    if (IsAccessModifier &&
-        static_cast<int>(Indent) + Style.AccessModifierOffset >= 0)
-      Indent += Style.AccessModifierOffset;
     if (!InPPDirective || Tok.HasUnescapedNewline) {
       Whitespaces.replaceWhitespace(RootToken, Newlines, Indent, 0, Style);
     } else {
       Whitespaces.replacePPWhitespace(RootToken, Newlines, Indent,
                                       PreviousEndOfLineColumn, Style);
     }
-    return Indent;
   }
 
   DiagnosticsEngine &Diag;
index 997a55353b1b4277c8e1a5c9e56fea6d0987a908..df0b2962f29c7d6bd9b0f16276abd4fa4615a09a 100644 (file)
@@ -2544,5 +2544,56 @@ TEST_F(FormatTest, ObjCLiterals) {
 
 }
 
+TEST_F(FormatTest, ReformatRegionAdjustsIndent) {
+  EXPECT_EQ("{\n"
+            "{\n"
+            "a;\n"
+            "b;\n"
+            "}\n"
+            "}", format("{\n"
+                        "{\n"
+                        "a;\n"
+                        "     b;\n"
+                        "}\n"
+                        "}", 13, 2, getLLVMStyle()));
+  EXPECT_EQ("{\n"
+            "{\n"
+            "  a;\n"
+            "b;\n"
+            "}\n"
+            "}", format("{\n"
+                        "{\n"
+                        "     a;\n"
+                        "b;\n"
+                        "}\n"
+                        "}", 9, 2, getLLVMStyle()));
+  EXPECT_EQ("{\n"
+            "{\n"
+            "public:\n"
+            "  b;\n"
+            "}\n"
+            "}", format("{\n"
+                        "{\n"
+                        "public:\n"
+                        "     b;\n"
+                        "}\n"
+                        "}", 17, 2, getLLVMStyle()));
+  EXPECT_EQ("{\n"
+            "{\n"
+            "a;\n"
+            "}\n"
+            "{\n"
+            "  b;\n"
+            "}\n"
+            "}", format("{\n"
+                        "{\n"
+                        "a;\n"
+                        "}\n"
+                        "{\n"
+                        "           b;\n"
+                        "}\n"
+                        "}", 22, 2, getLLVMStyle()));
+} 
+
 } // end namespace tooling
 } // end namespace clang