Hi klimek, djasper,
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.
http://llvm-reviews.chandlerc.com/D1770
Files:
include/clang/Format/Format.h
lib/Format/BreakableToken.cpp
lib/Format/ContinuationIndenter.cpp
lib/Format/Format.cpp
lib/Format/WhitespaceManager.cpp
lib/Format/WhitespaceManager.h
unittests/Format/FormatTest.cpp
Index: include/clang/Format/Format.h
===================================================================
--- include/clang/Format/Format.h
+++ include/clang/Format/Format.h
@@ -166,9 +166,19 @@
/// \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;
Index: lib/Format/BreakableToken.cpp
===================================================================
--- lib/Format/BreakableToken.cpp
+++ lib/Format/BreakableToken.cpp
@@ -173,9 +173,10 @@
void BreakableStringLiteral::insertBreak(unsigned LineIndex,
unsigned TailOffset, Split Split,
WhitespaceManager &Whitespaces) {
+ // FIXME: Insert correct IndentLevel.
Whitespaces.replaceWhitespaceInToken(
Tok, Prefix.size() + TailOffset + Split.first, Split.second, Postfix,
- Prefix, InPPDirective, 1, StartColumn);
+ Prefix, InPPDirective, 1, /*IndentLevel=*/0, StartColumn);
}
static StringRef getLineCommentPrefix(StringRef Comment) {
@@ -214,17 +215,18 @@
void BreakableLineComment::insertBreak(unsigned LineIndex, unsigned TailOffset,
Split Split,
WhitespaceManager &Whitespaces) {
+ // FIXME: Insert correct IndentLevel.
Whitespaces.replaceWhitespaceInToken(
Tok, OriginalPrefix.size() + TailOffset + Split.first, Split.second,
- Postfix, Prefix, InPPDirective, 1, StartColumn);
+ Postfix, Prefix, InPPDirective, 1, /*IndentLevel=*/0, StartColumn);
}
void
BreakableLineComment::replaceWhitespaceBefore(unsigned LineIndex,
WhitespaceManager &Whitespaces) {
if (OriginalPrefix != Prefix) {
Whitespaces.replaceWhitespaceInToken(Tok, OriginalPrefix.size(), 0, "", "",
- false, 0, 1);
+ false, 0, /*IndentLevel=*/0, 1);
}
}
@@ -376,8 +378,10 @@
Text.data() - Tok.TokenText.data() + Split.first;
unsigned CharsToRemove = Split.second;
assert(IndentAtLineBreak >= Decoration.size());
+ // FIXME: Insert correct IndentLevel.
Whitespaces.replaceWhitespaceInToken(Tok, BreakOffsetInToken, CharsToRemove,
"", Prefix, InPPDirective, 1,
+ /*IndentLevel=*/0,
IndentAtLineBreak - Decoration.size());
}
@@ -410,9 +414,11 @@
Tok.TokenText.data() -
LeadingWhitespace[LineIndex];
assert(StartOfLineColumn[LineIndex] >= Prefix.size());
+ // FIXME: Insert correct IndentLevel.
Whitespaces.replaceWhitespaceInToken(
Tok, WhitespaceOffsetInToken, LeadingWhitespace[LineIndex], "", Prefix,
- InPPDirective, 1, StartOfLineColumn[LineIndex] - Prefix.size());
+ InPPDirective, 1, /*IndentLevel=*/0,
+ StartOfLineColumn[LineIndex] - Prefix.size());
}
unsigned
Index: lib/Format/ContinuationIndenter.cpp
===================================================================
--- lib/Format/ContinuationIndenter.cpp
+++ lib/Format/ContinuationIndenter.cpp
@@ -303,12 +303,13 @@
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 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) {
Index: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp
+++ lib/Format/Format.cpp
@@ -45,6 +45,19 @@
};
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 @@
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 @@
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;
@@ -532,14 +545,14 @@
I = LBrace.Children.begin(),
E = LBrace.Children.end();
I != E; ++I) {
- unsigned Indent =
- ParentIndent + ((*I)->Level - Line.Level - 1) * Style.IndentWidth;
+ unsigned IndentLevel = (*I)->Level - Line.Level - 1;
+ unsigned Indent = ParentIndent + IndentLevel * Style.IndentWidth;
if (!DryRun) {
unsigned Newlines = std::min((*I)->First->NewlinesBefore,
Style.MaxEmptyLinesToKeep + 1);
Newlines = std::max(1u, Newlines);
Whitespaces->replaceWhitespace(
- *(*I)->First, Newlines, /*Spaces=*/Indent,
+ *(*I)->First, Newlines, IndentLevel, /*Spaces=*/Indent,
/*StartOfTokenColumn=*/Indent, Line.InPPDirective);
}
UnwrappedLineFormatter Formatter(Indenter, Whitespaces, Style, **I);
@@ -556,10 +569,10 @@
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 @@
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 @@
++Newlines;
Whitespaces.replaceWhitespace(
- RootToken, Newlines, Indent, Indent,
+ RootToken, Newlines, Indent / Style.IndentWidth, Indent, Indent,
InPPDirective && !RootToken.HasUnescapedNewline);
}
Index: lib/Format/WhitespaceManager.cpp
===================================================================
--- lib/Format/WhitespaceManager.cpp
+++ lib/Format/WhitespaceManager.cpp
@@ -28,41 +28,44 @@
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 @@
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::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 @@
}
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;
}
}
Index: lib/Format/WhitespaceManager.h
===================================================================
--- lib/Format/WhitespaceManager.h
+++ lib/Format/WhitespaceManager.h
@@ -44,7 +44,8 @@
/// \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 @@
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 @@
/// \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 @@
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 @@
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;
Index: unittests/Format/FormatTest.cpp
===================================================================
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -5758,7 +5758,7 @@
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,25 @@
" \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);
+
+
+ Tab.UseTab = FormatStyle::UT_Never;
EXPECT_EQ("/*\n"
" a\t\tcomment\n"
" in multiple lines\n"
@@ -6265,7 +6283,6 @@
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 +6309,13 @@
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);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits