r191527 - Implemented tab usage only for indentation (http://llvm.org/PR17363)

Alexander Kornienko alexfh at google.com
Fri Sep 27 09:14:23 PDT 2013


Author: alexfh
Date: Fri Sep 27 11:14:22 2013
New Revision: 191527

URL: http://llvm.org/viewvc/llvm-project?rev=191527&view=rev
Log:
Implemented tab usage only for indentation (http://llvm.org/PR17363)

Summary:
Changed UseTab to be a enum with three options: Never, Always,
ForIndentation (true/false are still supported when reading .clang-format).
IndentLevel should currently be propagated correctly for all tokens, except for
block comments. Please take a look at the general idea before I start dealing
with block comments.

Reviewers: klimek, djasper

Reviewed By: klimek

CC: cfe-commits

Differential Revision: http://llvm-reviews.chandlerc.com/D1770

Modified:
    cfe/trunk/include/clang/Format/Format.h
    cfe/trunk/lib/Format/BreakableToken.cpp
    cfe/trunk/lib/Format/BreakableToken.h
    cfe/trunk/lib/Format/ContinuationIndenter.cpp
    cfe/trunk/lib/Format/Format.cpp
    cfe/trunk/lib/Format/WhitespaceManager.cpp
    cfe/trunk/lib/Format/WhitespaceManager.h
    cfe/trunk/unittests/Format/FormatTest.cpp

Modified: cfe/trunk/include/clang/Format/Format.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Format/Format.h?rev=191527&r1=191526&r2=191527&view=diff
==============================================================================
--- cfe/trunk/include/clang/Format/Format.h (original)
+++ cfe/trunk/include/clang/Format/Format.h Fri Sep 27 11:14:22 2013
@@ -166,9 +166,19 @@ struct FormatStyle {
   /// \brief If \c true, always break before multiline string literals.
   bool AlwaysBreakBeforeMultilineStrings;
 
-  /// \brief If \c true, \c IndentWidth consecutive spaces will be replaced
-  /// with tab characters.
-  bool UseTab;
+  /// \brief Different ways to use tab in formatting.
+  enum UseTabStyle {
+    /// Never use tab.
+    UT_Never,
+    /// Use tabs only for indentation.
+    UT_ForIndentation,
+    /// Use tabs whenever we need to fill whitespace that spans at least from
+    /// one tab stop to the next one.
+    UT_Always
+  };
+
+  /// \brief The way to use tab characters in the resulting file.
+  UseTabStyle UseTab;
 
   /// \brief If \c true, binary operators will be placed after line breaks.
   bool BreakBeforeBinaryOperators;

Modified: cfe/trunk/lib/Format/BreakableToken.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/BreakableToken.cpp?rev=191527&r1=191526&r2=191527&view=diff
==============================================================================
--- cfe/trunk/lib/Format/BreakableToken.cpp (original)
+++ cfe/trunk/lib/Format/BreakableToken.cpp Fri Sep 27 11:14:22 2013
@@ -145,10 +145,10 @@ unsigned BreakableSingleLineToken::getLi
 }
 
 BreakableSingleLineToken::BreakableSingleLineToken(
-    const FormatToken &Tok, unsigned StartColumn, StringRef Prefix,
-    StringRef Postfix, bool InPPDirective, encoding::Encoding Encoding,
-    const FormatStyle &Style)
-    : BreakableToken(Tok, InPPDirective, Encoding, Style),
+    const FormatToken &Tok, unsigned IndentLevel, unsigned StartColumn,
+    StringRef Prefix, StringRef Postfix, bool InPPDirective,
+    encoding::Encoding Encoding, const FormatStyle &Style)
+    : BreakableToken(Tok, IndentLevel, InPPDirective, Encoding, Style),
       StartColumn(StartColumn), Prefix(Prefix), Postfix(Postfix) {
   assert(Tok.TokenText.startswith(Prefix) && Tok.TokenText.endswith(Postfix));
   Line = Tok.TokenText.substr(
@@ -156,11 +156,11 @@ BreakableSingleLineToken::BreakableSingl
 }
 
 BreakableStringLiteral::BreakableStringLiteral(
-    const FormatToken &Tok, unsigned StartColumn, StringRef Prefix,
-    StringRef Postfix, bool InPPDirective, encoding::Encoding Encoding,
-    const FormatStyle &Style)
-    : BreakableSingleLineToken(Tok, StartColumn, Prefix, Postfix, InPPDirective,
-                               Encoding, Style) {}
+    const FormatToken &Tok, unsigned IndentLevel, unsigned StartColumn,
+    StringRef Prefix, StringRef Postfix, bool InPPDirective,
+    encoding::Encoding Encoding, const FormatStyle &Style)
+    : BreakableSingleLineToken(Tok, IndentLevel, StartColumn, Prefix, Postfix,
+                               InPPDirective, Encoding, Style) {}
 
 BreakableToken::Split
 BreakableStringLiteral::getSplit(unsigned LineIndex, unsigned TailOffset,
@@ -175,7 +175,7 @@ void BreakableStringLiteral::insertBreak
                                          WhitespaceManager &Whitespaces) {
   Whitespaces.replaceWhitespaceInToken(
       Tok, Prefix.size() + TailOffset + Split.first, Split.second, Postfix,
-      Prefix, InPPDirective, 1, StartColumn);
+      Prefix, InPPDirective, 1, IndentLevel, StartColumn);
 }
 
 static StringRef getLineCommentPrefix(StringRef Comment) {
@@ -186,12 +186,10 @@ static StringRef getLineCommentPrefix(St
   return "";
 }
 
-BreakableLineComment::BreakableLineComment(const FormatToken &Token,
-                                           unsigned StartColumn,
-                                           bool InPPDirective,
-                                           encoding::Encoding Encoding,
-                                           const FormatStyle &Style)
-    : BreakableSingleLineToken(Token, StartColumn,
+BreakableLineComment::BreakableLineComment(
+    const FormatToken &Token, unsigned IndentLevel, unsigned StartColumn,
+    bool InPPDirective, encoding::Encoding Encoding, const FormatStyle &Style)
+    : BreakableSingleLineToken(Token, IndentLevel, StartColumn,
                                getLineCommentPrefix(Token.TokenText), "",
                                InPPDirective, Encoding, Style) {
   OriginalPrefix = Prefix;
@@ -216,7 +214,7 @@ void BreakableLineComment::insertBreak(u
                                        WhitespaceManager &Whitespaces) {
   Whitespaces.replaceWhitespaceInToken(
       Tok, OriginalPrefix.size() + TailOffset + Split.first, Split.second,
-      Postfix, Prefix, InPPDirective, 1, StartColumn);
+      Postfix, Prefix, InPPDirective, 1, IndentLevel, StartColumn);
 }
 
 void
@@ -224,15 +222,15 @@ BreakableLineComment::replaceWhitespaceB
                                               WhitespaceManager &Whitespaces) {
   if (OriginalPrefix != Prefix) {
     Whitespaces.replaceWhitespaceInToken(Tok, OriginalPrefix.size(), 0, "", "",
-                                         false, 0, 1);
+                                         false, 0, /*IndentLevel=*/0, 1);
   }
 }
 
 BreakableBlockComment::BreakableBlockComment(
-    const FormatToken &Token, unsigned StartColumn,
+    const FormatToken &Token, unsigned IndentLevel, unsigned StartColumn,
     unsigned OriginalStartColumn, bool FirstInLine, bool InPPDirective,
     encoding::Encoding Encoding, const FormatStyle &Style)
-    : BreakableToken(Token, InPPDirective, Encoding, Style) {
+    : BreakableToken(Token, IndentLevel, InPPDirective, Encoding, Style) {
   StringRef TokenText(Token.TokenText);
   assert(TokenText.startswith("/*") && TokenText.endswith("*/"));
   TokenText.substr(2, TokenText.size() - 4).split(Lines, "\n");
@@ -327,12 +325,6 @@ void BreakableBlockComment::adjustWhites
   LeadingWhitespace[LineIndex] =
       Lines[LineIndex].begin() - Lines[LineIndex - 1].end();
 
-  // FIXME: We currently count tabs as 1 character. To solve this, we need to
-  // get the correct indentation width of the start of the comment, which
-  // requires correct counting of the tab expansions before the comment, and
-  // a configurable tab width. Since the current implementation only breaks
-  // if leading tabs are intermixed with spaces, that is not a high priority.
-
   // Adjust the start column uniformly accross all lines.
   StartOfLineColumn[LineIndex] = std::max<int>(
       0,
@@ -376,9 +368,9 @@ void BreakableBlockComment::insertBreak(
       Text.data() - Tok.TokenText.data() + Split.first;
   unsigned CharsToRemove = Split.second;
   assert(IndentAtLineBreak >= Decoration.size());
-  Whitespaces.replaceWhitespaceInToken(Tok, BreakOffsetInToken, CharsToRemove,
-                                       "", Prefix, InPPDirective, 1,
-                                       IndentAtLineBreak - Decoration.size());
+  Whitespaces.replaceWhitespaceInToken(
+      Tok, BreakOffsetInToken, CharsToRemove, "", Prefix, InPPDirective, 1,
+      IndentLevel, IndentAtLineBreak - Decoration.size());
 }
 
 void
@@ -412,7 +404,8 @@ BreakableBlockComment::replaceWhitespace
   assert(StartOfLineColumn[LineIndex] >= Prefix.size());
   Whitespaces.replaceWhitespaceInToken(
       Tok, WhitespaceOffsetInToken, LeadingWhitespace[LineIndex], "", Prefix,
-      InPPDirective, 1, StartOfLineColumn[LineIndex] - Prefix.size());
+      InPPDirective, 1, IndentLevel,
+      StartOfLineColumn[LineIndex] - Prefix.size());
 }
 
 unsigned

Modified: cfe/trunk/lib/Format/BreakableToken.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/BreakableToken.h?rev=191527&r1=191526&r2=191527&view=diff
==============================================================================
--- cfe/trunk/lib/Format/BreakableToken.h (original)
+++ cfe/trunk/lib/Format/BreakableToken.h Fri Sep 27 11:14:22 2013
@@ -66,12 +66,14 @@ public:
                                        WhitespaceManager &Whitespaces) {}
 
 protected:
-  BreakableToken(const FormatToken &Tok, bool InPPDirective,
-                 encoding::Encoding Encoding, const FormatStyle &Style)
-      : Tok(Tok), InPPDirective(InPPDirective), Encoding(Encoding),
-        Style(Style) {}
+  BreakableToken(const FormatToken &Tok, unsigned IndentLevel,
+                 bool InPPDirective, encoding::Encoding Encoding,
+                 const FormatStyle &Style)
+      : Tok(Tok), IndentLevel(IndentLevel), InPPDirective(InPPDirective),
+        Encoding(Encoding), Style(Style) {}
 
   const FormatToken &Tok;
+  const unsigned IndentLevel;
   const bool InPPDirective;
   const encoding::Encoding Encoding;
   const FormatStyle &Style;
@@ -88,9 +90,10 @@ public:
                                            StringRef::size_type Length) const;
 
 protected:
-  BreakableSingleLineToken(const FormatToken &Tok, unsigned StartColumn,
-                           StringRef Prefix, StringRef Postfix,
-                           bool InPPDirective, encoding::Encoding Encoding,
+  BreakableSingleLineToken(const FormatToken &Tok, unsigned IndentLevel,
+                           unsigned StartColumn, StringRef Prefix,
+                           StringRef Postfix, bool InPPDirective,
+                           encoding::Encoding Encoding,
                            const FormatStyle &Style);
 
   // The column in which the token starts.
@@ -109,10 +112,10 @@ public:
   ///
   /// \p StartColumn specifies the column in which the token will start
   /// after formatting.
-  BreakableStringLiteral(const FormatToken &Tok, unsigned StartColumn,
-                         StringRef Prefix, StringRef Postfix,
-                         bool InPPDirective, encoding::Encoding Encoding,
-                         const FormatStyle &Style);
+  BreakableStringLiteral(const FormatToken &Tok, unsigned IndentLevel,
+                         unsigned StartColumn, StringRef Prefix,
+                         StringRef Postfix, bool InPPDirective,
+                         encoding::Encoding Encoding, const FormatStyle &Style);
 
   virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
                          unsigned ColumnLimit) const;
@@ -126,9 +129,9 @@ public:
   ///
   /// \p StartColumn specifies the column in which the comment will start
   /// after formatting.
-  BreakableLineComment(const FormatToken &Token, unsigned StartColumn,
-                       bool InPPDirective, encoding::Encoding Encoding,
-                       const FormatStyle &Style);
+  BreakableLineComment(const FormatToken &Token, unsigned IndentLevel,
+                       unsigned StartColumn, bool InPPDirective,
+                       encoding::Encoding Encoding, const FormatStyle &Style);
 
   virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
                          unsigned ColumnLimit) const;
@@ -150,10 +153,10 @@ public:
   /// after formatting, while \p OriginalStartColumn specifies in which
   /// column the comment started before formatting.
   /// If the comment starts a line after formatting, set \p FirstInLine to true.
-  BreakableBlockComment(const FormatToken &Token, unsigned StartColumn,
-                        unsigned OriginaStartColumn, bool FirstInLine,
-                        bool InPPDirective, encoding::Encoding Encoding,
-                        const FormatStyle &Style);
+  BreakableBlockComment(const FormatToken &Token, unsigned IndentLevel,
+                        unsigned StartColumn, unsigned OriginaStartColumn,
+                        bool FirstInLine, bool InPPDirective,
+                        encoding::Encoding Encoding, const FormatStyle &Style);
 
   virtual unsigned getLineCount() const;
   virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,

Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.cpp?rev=191527&r1=191526&r2=191527&view=diff
==============================================================================
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original)
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Fri Sep 27 11:14:22 2013
@@ -303,12 +303,13 @@ unsigned ContinuationIndenter::addTokenT
       State.Stack.back().BreakBeforeParameter = false;
 
     if (!DryRun) {
-      unsigned NewLines = 1;
+      unsigned Newlines = 1;
       if (Current.is(tok::comment))
-        NewLines = std::max(NewLines, std::min(Current.NewlinesBefore,
+        Newlines = std::max(Newlines, std::min(Current.NewlinesBefore,
                                                Style.MaxEmptyLinesToKeep + 1));
-      Whitespaces.replaceWhitespace(Current, NewLines, State.Column,
-                                    State.Column, State.Line->InPPDirective);
+      Whitespaces.replaceWhitespace(Current, Newlines, State.Line->Level,
+                                    State.Column, State.Column,
+                                    State.Line->InPPDirective);
     }
 
     if (!Current.isTrailingComment())
@@ -363,7 +364,8 @@ unsigned ContinuationIndenter::addTokenT
     unsigned Spaces = State.NextToken->SpacesRequiredBefore + ExtraSpaces;
 
     if (!DryRun)
-      Whitespaces.replaceWhitespace(Current, 0, Spaces, State.Column + Spaces);
+      Whitespaces.replaceWhitespace(Current, /*Newlines=*/0, /*IndentLevel=*/0,
+                                    Spaces, State.Column + Spaces);
 
     if (Current.Type == TT_ObjCSelectorName &&
         State.Stack.back().ColonPos == 0) {
@@ -693,21 +695,22 @@ unsigned ContinuationIndenter::breakProt
           Text.startswith(Prefix = "L\""))) ||
         (Text.startswith(Prefix = "_T(\"") && Text.endswith(Postfix = "\")")) ||
         getRawStringLiteralPrefixPostfix(Text, Prefix, Postfix)) {
-      Token.reset(new BreakableStringLiteral(Current, StartColumn, Prefix,
-                                             Postfix, State.Line->InPPDirective,
-                                             Encoding, Style));
+      Token.reset(new BreakableStringLiteral(
+          Current, State.Line->Level, StartColumn, Prefix, Postfix,
+          State.Line->InPPDirective, Encoding, Style));
     } else {
       return 0;
     }
   } else if (Current.Type == TT_BlockComment && Current.isTrailingComment()) {
     Token.reset(new BreakableBlockComment(
-        Current, StartColumn, Current.OriginalColumn, !Current.Previous,
-        State.Line->InPPDirective, Encoding, Style));
+        Current, State.Line->Level, StartColumn, Current.OriginalColumn,
+        !Current.Previous, State.Line->InPPDirective, Encoding, Style));
   } else if (Current.Type == TT_LineComment &&
              (Current.Previous == NULL ||
               Current.Previous->Type != TT_ImplicitStringLiteral)) {
-    Token.reset(new BreakableLineComment(
-        Current, StartColumn, State.Line->InPPDirective, Encoding, Style));
+    Token.reset(new BreakableLineComment(Current, State.Line->Level,
+                                         StartColumn, State.Line->InPPDirective,
+                                         Encoding, Style));
   } else {
     return 0;
   }

Modified: cfe/trunk/lib/Format/Format.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=191527&r1=191526&r2=191527&view=diff
==============================================================================
--- cfe/trunk/lib/Format/Format.cpp (original)
+++ cfe/trunk/lib/Format/Format.cpp Fri Sep 27 11:14:22 2013
@@ -45,6 +45,19 @@ struct ScalarEnumerationTraits<clang::fo
 };
 
 template <>
+struct ScalarEnumerationTraits<clang::format::FormatStyle::UseTabStyle> {
+  static void
+  enumeration(IO &IO, clang::format::FormatStyle::UseTabStyle &Value) {
+    IO.enumCase(Value, "Never", clang::format::FormatStyle::UT_Never);
+    IO.enumCase(Value, "false", clang::format::FormatStyle::UT_Never);
+    IO.enumCase(Value, "Always", clang::format::FormatStyle::UT_Always);
+    IO.enumCase(Value, "true", clang::format::FormatStyle::UT_Always);
+    IO.enumCase(Value, "ForIndentation",
+                clang::format::FormatStyle::UT_ForIndentation);
+  }
+};
+
+template <>
 struct ScalarEnumerationTraits<clang::format::FormatStyle::BraceBreakingStyle> {
   static void
   enumeration(IO &IO, clang::format::FormatStyle::BraceBreakingStyle &Value) {
@@ -194,7 +207,7 @@ FormatStyle getLLVMStyle() {
   LLVMStyle.PointerBindsToType = false;
   LLVMStyle.SpacesBeforeTrailingComments = 1;
   LLVMStyle.Standard = FormatStyle::LS_Cpp03;
-  LLVMStyle.UseTab = false;
+  LLVMStyle.UseTab = FormatStyle::UT_Never;
   LLVMStyle.SpacesInParentheses = false;
   LLVMStyle.SpaceInEmptyParentheses = false;
   LLVMStyle.SpacesInCStyleCastParentheses = false;
@@ -237,7 +250,7 @@ FormatStyle getGoogleStyle() {
   GoogleStyle.PointerBindsToType = true;
   GoogleStyle.SpacesBeforeTrailingComments = 2;
   GoogleStyle.Standard = FormatStyle::LS_Auto;
-  GoogleStyle.UseTab = false;
+  GoogleStyle.UseTab = FormatStyle::UT_Never;
   GoogleStyle.SpacesInParentheses = false;
   GoogleStyle.SpaceInEmptyParentheses = false;
   GoogleStyle.SpacesInCStyleCastParentheses = false;
@@ -539,7 +552,7 @@ private:
                                        Style.MaxEmptyLinesToKeep + 1);
           Newlines = std::max(1u, Newlines);
           Whitespaces->replaceWhitespace(
-              *(*I)->First, Newlines, /*Spaces=*/Indent,
+              *(*I)->First, Newlines, (*I)->Level, /*Spaces=*/Indent,
               /*StartOfTokenColumn=*/Indent, Line.InPPDirective);
         }
         UnwrappedLineFormatter Formatter(Indenter, Whitespaces, Style, **I);
@@ -556,10 +569,10 @@ private:
       return false;
 
     if (!DryRun) {
-      Whitespaces->replaceWhitespace(*LBrace.Children[0]->First,
-                                     /*Newlines=*/0, /*Spaces=*/1,
-                                     /*StartOfTokenColumn=*/State.Column,
-                                     State.Line->InPPDirective);
+      Whitespaces->replaceWhitespace(
+          *LBrace.Children[0]->First,
+          /*Newlines=*/0, /*IndentLevel=*/1, /*Spaces=*/1,
+          /*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);
       UnwrappedLineFormatter Formatter(Indenter, Whitespaces, Style,
                                        *LBrace.Children[0]);
       Penalty += Formatter.format(State.Column + 1, DryRun);
@@ -847,8 +860,9 @@ public:
       if (TheLine.First->is(tok::eof)) {
         if (PreviousLineWasTouched) {
           unsigned NewLines = std::min(FirstTok->NewlinesBefore, 1u);
-          Whitespaces.replaceWhitespace(*TheLine.First, NewLines, /*Indent*/ 0,
-                                        /*TargetColumn*/ 0);
+          Whitespaces.replaceWhitespace(*TheLine.First, NewLines,
+                                        /*IndentLevel=*/0, /*Spaces=*/0,
+                                        /*TargetColumn=*/0);
         }
       } else if (TheLine.Type != LT_Invalid &&
                  (WasMoved || FormatPPDirective || touchesLine(TheLine))) {
@@ -1225,7 +1239,7 @@ private:
       ++Newlines;
 
     Whitespaces.replaceWhitespace(
-        RootToken, Newlines, Indent, Indent,
+        RootToken, Newlines, Indent / Style.IndentWidth, Indent, Indent,
         InPPDirective && !RootToken.HasUnescapedNewline);
   }
 

Modified: cfe/trunk/lib/Format/WhitespaceManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/WhitespaceManager.cpp?rev=191527&r1=191526&r2=191527&view=diff
==============================================================================
--- cfe/trunk/lib/Format/WhitespaceManager.cpp (original)
+++ cfe/trunk/lib/Format/WhitespaceManager.cpp Fri Sep 27 11:14:22 2013
@@ -28,41 +28,44 @@ WhitespaceManager::Change::IsBeforeInFil
 
 WhitespaceManager::Change::Change(
     bool CreateReplacement, const SourceRange &OriginalWhitespaceRange,
-    unsigned Spaces, unsigned StartOfTokenColumn, unsigned NewlinesBefore,
-    StringRef PreviousLinePostfix, StringRef CurrentLinePrefix,
-    tok::TokenKind Kind, bool ContinuesPPDirective)
+    unsigned IndentLevel, unsigned Spaces, unsigned StartOfTokenColumn,
+    unsigned NewlinesBefore, StringRef PreviousLinePostfix,
+    StringRef CurrentLinePrefix, tok::TokenKind Kind, bool ContinuesPPDirective)
     : CreateReplacement(CreateReplacement),
       OriginalWhitespaceRange(OriginalWhitespaceRange),
       StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
       PreviousLinePostfix(PreviousLinePostfix),
       CurrentLinePrefix(CurrentLinePrefix), Kind(Kind),
-      ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces) {}
+      ContinuesPPDirective(ContinuesPPDirective), IndentLevel(IndentLevel),
+      Spaces(Spaces) {}
 
 void WhitespaceManager::replaceWhitespace(const FormatToken &Tok,
-                                          unsigned Newlines, unsigned Spaces,
+                                          unsigned Newlines,
+                                          unsigned IndentLevel, unsigned Spaces,
                                           unsigned StartOfTokenColumn,
                                           bool InPPDirective) {
-  Changes.push_back(Change(true, Tok.WhitespaceRange, Spaces,
+  Changes.push_back(Change(true, Tok.WhitespaceRange, IndentLevel, Spaces,
                            StartOfTokenColumn, Newlines, "", "",
                            Tok.Tok.getKind(), InPPDirective && !Tok.IsFirst));
 }
 
 void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
                                             bool InPPDirective) {
-  Changes.push_back(Change(false, Tok.WhitespaceRange, /*Spaces=*/0,
-                           Tok.OriginalColumn, Tok.NewlinesBefore, "", "",
-                           Tok.Tok.getKind(), InPPDirective && !Tok.IsFirst));
+  Changes.push_back(Change(false, Tok.WhitespaceRange, /*IndentLevel=*/0,
+                           /*Spaces=*/0, Tok.OriginalColumn, Tok.NewlinesBefore,
+                           "", "", Tok.Tok.getKind(),
+                           InPPDirective && !Tok.IsFirst));
 }
 
 void WhitespaceManager::replaceWhitespaceInToken(
     const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
     StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
-    unsigned Newlines, unsigned Spaces) {
+    unsigned Newlines, unsigned IndentLevel, unsigned Spaces) {
   Changes.push_back(Change(
       true, SourceRange(Tok.getStartOfNonWhitespace().getLocWithOffset(Offset),
                         Tok.getStartOfNonWhitespace().getLocWithOffset(
                             Offset + ReplaceChars)),
-      Spaces, Spaces, Newlines, PreviousPostfix, CurrentPrefix,
+      IndentLevel, Spaces, Spaces, Newlines, PreviousPostfix, CurrentPrefix,
       // If we don't add a newline this change doesn't start a comment. Thus,
       // when we align line comments, we don't need to treat this change as one.
       // FIXME: We still need to take this change in account to properly
@@ -225,7 +228,8 @@ void WhitespaceManager::generateChanges(
                           C.PreviousEndOfTokenColumn, C.EscapedNewlineColumn);
       else
         appendNewlineText(ReplacementText, C.NewlinesBefore);
-      appendIndentText(ReplacementText, C.Spaces, C.StartOfTokenColumn - C.Spaces);
+      appendIndentText(ReplacementText, C.IndentLevel, C.Spaces,
+                       C.StartOfTokenColumn - C.Spaces);
       ReplacementText.append(C.CurrentLinePrefix);
       storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
     }
@@ -264,11 +268,14 @@ void WhitespaceManager::appendNewlineTex
   }
 }
 
-void WhitespaceManager::appendIndentText(std::string &Text, unsigned Spaces,
+void WhitespaceManager::appendIndentText(std::string &Text,
+                                         unsigned IndentLevel, unsigned Spaces,
                                          unsigned WhitespaceStartColumn) {
-  if (!Style.UseTab) {
+  switch (Style.UseTab) {
+  case FormatStyle::UT_Never:
     Text.append(std::string(Spaces, ' '));
-  } else {
+    break;
+  case FormatStyle::UT_Always: {
     unsigned FirstTabWidth =
         Style.TabWidth - WhitespaceStartColumn % Style.TabWidth;
     // Indent with tabs only when there's at least one full tab.
@@ -278,6 +285,19 @@ void WhitespaceManager::appendIndentText
     }
     Text.append(std::string(Spaces / Style.TabWidth, '\t'));
     Text.append(std::string(Spaces % Style.TabWidth, ' '));
+    break;
+  }
+  case FormatStyle::UT_ForIndentation:
+    if (WhitespaceStartColumn == 0) {
+      unsigned Indentation = IndentLevel * Style.IndentWidth;
+      if (Indentation > Spaces)
+        Indentation = Spaces;
+      unsigned Tabs = Indentation / Style.TabWidth;
+      Text.append(std::string(Tabs, '\t'));
+      Spaces -= Tabs * Style.TabWidth;
+    }
+    Text.append(std::string(Spaces, ' '));
+    break;
   }
 }
 

Modified: cfe/trunk/lib/Format/WhitespaceManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/WhitespaceManager.h?rev=191527&r1=191526&r2=191527&view=diff
==============================================================================
--- cfe/trunk/lib/Format/WhitespaceManager.h (original)
+++ cfe/trunk/lib/Format/WhitespaceManager.h Fri Sep 27 11:14:22 2013
@@ -44,7 +44,8 @@ public:
   /// \brief Replaces the whitespace in front of \p Tok. Only call once for
   /// each \c AnnotatedToken.
   void replaceWhitespace(const FormatToken &Tok, unsigned Newlines,
-                         unsigned Spaces, unsigned StartOfTokenColumn,
+                         unsigned IndentLevel, unsigned Spaces,
+                         unsigned StartOfTokenColumn,
                          bool InPPDirective = false);
 
   /// \brief Adds information about an unchangable token's whitespace.
@@ -65,7 +66,8 @@ public:
                                 unsigned ReplaceChars,
                                 StringRef PreviousPostfix,
                                 StringRef CurrentPrefix, bool InPPDirective,
-                                unsigned Newlines, unsigned Spaces);
+                                unsigned Newlines, unsigned IndentLevel,
+                                unsigned Spaces);
 
   /// \brief Returns all the \c Replacements created during formatting.
   const tooling::Replacements &generateReplacements();
@@ -96,7 +98,7 @@ private:
     /// \p StartOfTokenColumn and \p InPPDirective will be used to lay out
     /// trailing comments and escaped newlines.
     Change(bool CreateReplacement, const SourceRange &OriginalWhitespaceRange,
-           unsigned Spaces, unsigned StartOfTokenColumn,
+           unsigned IndentLevel, unsigned Spaces, unsigned StartOfTokenColumn,
            unsigned NewlinesBefore, StringRef PreviousLinePostfix,
            StringRef CurrentLinePrefix, tok::TokenKind Kind,
            bool ContinuesPPDirective);
@@ -116,6 +118,11 @@ private:
     tok::TokenKind Kind;
     bool ContinuesPPDirective;
 
+    // The number of nested blocks the token is in. This is used to add tabs
+    // only for the indentation, and not for alignment, when
+    // UseTab = US_ForIndentation.
+    unsigned IndentLevel;
+
     // The number of spaces in front of the token or broken part of the token.
     // This will be adapted when aligning tokens.
     unsigned Spaces;
@@ -157,8 +164,8 @@ private:
   void appendNewlineText(std::string &Text, unsigned Newlines,
                          unsigned PreviousEndOfTokenColumn,
                          unsigned EscapedNewlineColumn);
-  void appendIndentText(std::string &Text, unsigned Spaces,
-                        unsigned WhitespaceStartColumn);
+  void appendIndentText(std::string &Text, unsigned IndentLevel,
+                        unsigned Spaces, unsigned WhitespaceStartColumn);
 
   SmallVector<Change, 16> Changes;
   SourceManager &SourceMgr;

Modified: cfe/trunk/unittests/Format/FormatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=191527&r1=191526&r2=191527&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTest.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTest.cpp Fri Sep 27 11:14:22 2013
@@ -5758,7 +5758,7 @@ TEST_F(FormatTest, ConfigurableFunctionD
 TEST_F(FormatTest, ConfigurableUseOfTab) {
   FormatStyle Tab = getLLVMStyleWithColumns(42);
   Tab.IndentWidth = 8;
-  Tab.UseTab = true;
+  Tab.UseTab = FormatStyle::UT_Always;
   Tab.AlignEscapedNewlinesLeft = true;
 
   EXPECT_EQ("if (aaaaaaaa && // q\n"
@@ -5858,7 +5858,83 @@ TEST_F(FormatTest, ConfigurableUseOfTab)
                    " \t  */",
                    Tab));
 
-  Tab.UseTab = false;
+  Tab.UseTab = FormatStyle::UT_ForIndentation;
+  EXPECT_EQ("if (aaaaaaaa && // q\n"
+            "    bb)         // w\n"
+            "\t;",
+            format("if (aaaaaaaa &&// q\n"
+                   "bb)// w\n"
+                   ";",
+                   Tab));
+  verifyFormat("class X {\n"
+               "\tvoid f() {\n"
+               "\t\tsomeFunction(parameter1,\n"
+               "\t\t             parameter2);\n"
+               "\t}\n"
+               "};",
+               Tab);
+  verifyFormat("{\n"
+               "\tQ({\n"
+               "\t\t  int a;\n"
+               "\t\t  someFunction(aaaaaaaaaa,\n"
+               "\t\t               bbbbbbbbb);\n"
+               "\t  },\n"
+               "\t  p);\n"
+               "}",
+               Tab);
+  EXPECT_EQ("{\n"
+            "\t/* aaaa\n"
+            "\t   bbbb */\n"
+            "}",
+            format("{\n"
+                   "/* aaaa\n"
+                   "   bbbb */\n"
+                   "}",
+                   Tab));
+  EXPECT_EQ("{\n"
+            "\t/*\n"
+            "\t  aaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+            "\t  bbbbbbbbbbbbb\n"
+            "\t*/\n"
+            "}",
+            format("{\n"
+                   "/*\n"
+                   "  aaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbb\n"
+                   "*/\n"
+                   "}",
+                   Tab));
+  EXPECT_EQ("{\n"
+            "\t// aaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+            "\t// bbbbbbbbbbbbb\n"
+            "}",
+            format("{\n"
+                   "\t// aaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbb\n"
+                   "}",
+                   Tab));
+  EXPECT_EQ("{\n"
+            "\t/*\n"
+            "\t  aaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+            "\t  bbbbbbbbbbbbb\n"
+            "\t*/\n"
+            "}",
+            format("{\n"
+                   "\t/*\n"
+                   "\t  aaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbb\n"
+                   "\t*/\n"
+                   "}",
+                   Tab));
+  EXPECT_EQ("{\n"
+            "\t/*\n"
+            "\n"
+            "\t*/\n"
+            "}",
+            format("{\n"
+                   "\t/*\n"
+                   "\n"
+                   "\t*/\n"
+                   "}", Tab));
+
+  Tab.UseTab = FormatStyle::UT_Never;
   EXPECT_EQ("/*\n"
             "              a\t\tcomment\n"
             "              in multiple lines\n"
@@ -6265,7 +6341,6 @@ TEST_F(FormatTest, ParsesConfiguration)
   CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList);
   CHECK_PARSE_BOOL(PointerBindsToType);
   CHECK_PARSE_BOOL(Cpp11BracedListStyle);
-  CHECK_PARSE_BOOL(UseTab);
   CHECK_PARSE_BOOL(IndentFunctionDeclarationAfterType);
   CHECK_PARSE_BOOL(SpacesInParentheses);
   CHECK_PARSE_BOOL(SpaceInEmptyParentheses);
@@ -6292,6 +6367,13 @@ TEST_F(FormatTest, ParsesConfiguration)
   CHECK_PARSE("Standard: C++11", Standard, FormatStyle::LS_Cpp11);
   CHECK_PARSE("Standard: Auto", Standard, FormatStyle::LS_Auto);
 
+  Style.UseTab = FormatStyle::UT_ForIndentation;
+  CHECK_PARSE("UseTab: false", UseTab, FormatStyle::UT_Never);
+  CHECK_PARSE("UseTab: true", UseTab, FormatStyle::UT_Always);
+  CHECK_PARSE("UseTab: Never", UseTab, FormatStyle::UT_Never);
+  CHECK_PARSE("UseTab: ForIndentation", UseTab, FormatStyle::UT_ForIndentation);
+  CHECK_PARSE("UseTab: Always", UseTab, FormatStyle::UT_Always);
+
   Style.ColumnLimit = 123;
   FormatStyle BaseStyle = getLLVMStyle();
   CHECK_PARSE("BasedOnStyle: LLVM", ColumnLimit, BaseStyle.ColumnLimit);





More information about the cfe-commits mailing list