Typz updated this revision to Diff 99421.
Typz added a comment.
clang-format: Add CompactNamespaces option
- Change option name to CompactNamespaces
- Clarify & test behavior when wrapping is needed
- Separate from the 'remove semicolon' patch
https://reviews.llvm.org/D32480
Files:
include/clang/Format/Format.h
lib/Format/Format.cpp
lib/Format/NamespaceEndCommentsFixer.cpp
lib/Format/UnwrappedLineFormatter.cpp
unittests/Format/FormatTest.cpp
Index: unittests/Format/FormatTest.cpp
===================================================================
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -1306,6 +1306,61 @@
"} // namespace in\n"
"} // namespace out",
Style));
+
+ FormatStyle LLVMWithCompactNamespaces = getLLVMStyle();
+ LLVMWithCompactNamespaces.CompactNamespaces = true;
+
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "}} // namespace out::in",
+ format("namespace out {\n"
+ "namespace in {\n"
+ "} // namespace in\n"
+ "} // namespace out",
+ LLVMWithCompactNamespaces));
+
+ EXPECT_EQ("namespace out { namespace in1 {\n"
+ "} // namespace in1\n"
+ "namespace in2 {\n"
+ "}} // namespace out::in2",
+ format("namespace out {\n"
+ "namespace in1 {\n"
+ "} // namespace in1\n"
+ "namespace in2 {\n"
+ "} // namespace in2\n"
+ "} // namespace out",
+ LLVMWithCompactNamespaces));
+
+ EXPECT_EQ("namespace out {\n"
+ "int i;\n"
+ "namespace in {\n"
+ "int j;\n"
+ "} // namespace in\n"
+ "int k;\n"
+ "} // namespace out",
+ format("namespace out { int i;\n"
+ "namespace in { int j; } // namespace in\n"
+ "int k; } // namespace out",
+ LLVMWithCompactNamespaces));
+
+ EXPECT_EQ("namespace aaaaaaaaaaaaaaaaaaaaaaaaaaaa {\n"
+ "namespace bbbbbbbbbbbbbbbbbbbbbbbbbbbb {\n"
+ "}} // namespace aaaaaaaaaaaaaaaaaaaaaaaaaaaa::bbbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ format("namespace aaaaaaaaaaaaaaaaaaaaaaaaaaaa {\n"
+ "namespace bbbbbbbbbbbbbbbbbbbbbbbbbbbb {\n"
+ "} // namespace bbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+ "} // namespace aaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ LLVMWithCompactNamespaces));
+
+ EXPECT_EQ("namespace aaaaaaaaaaaaaaaaa { namespace bbbbbbbbbbbbbbbbb {\n"
+ "namespace ccccccccccccccccc {\n"
+ "}}} // namespace aaaaaaaaaaaaaaaaa::bbbbbbbbbbbbbbbbb::ccccccccccccccccc",
+ format("namespace aaaaaaaaaaaaaaaaa {\n"
+ "namespace bbbbbbbbbbbbbbbbb {\n"
+ "namespace ccccccccccccccccc {\n"
+ "} // namespace ccccccccccccccccc\n"
+ "} // namespace bbbbbbbbbbbbbbbbb\n"
+ "} // namespace aaaaaaaaaaaaaaaaa",
+ LLVMWithCompactNamespaces));
}
TEST_F(FormatTest, FormatsExternC) { verifyFormat("extern \"C\" {\nint a;"); }
@@ -8683,6 +8738,7 @@
CHECK_PARSE_BOOL(BreakConstructorInitializersBeforeComma);
CHECK_PARSE_BOOL(BreakStringLiterals);
CHECK_PARSE_BOOL(BreakBeforeInheritanceComma)
+ CHECK_PARSE_BOOL(CompactNamespaces);
CHECK_PARSE_BOOL(ConstructorInitializerAllOnOneLineOrOnePerLine);
CHECK_PARSE_BOOL(DerivePointerAlignment);
CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding");
Index: lib/Format/UnwrappedLineFormatter.cpp
===================================================================
--- lib/Format/UnwrappedLineFormatter.cpp
+++ lib/Format/UnwrappedLineFormatter.cpp
@@ -127,12 +127,33 @@
unsigned Indent = 0;
};
+bool isNamespaceToken(const FormatToken *NamespaceTok) {
+ // Detect "(inline)? namespace" in the beginning of a line.
+ if (NamespaceTok->is(tok::kw_inline))
+ NamespaceTok = NamespaceTok->getNextNonComment();
+ if (!NamespaceTok || NamespaceTok->isNot(tok::kw_namespace))
+ return false;
+ return true;
+}
+
+bool isEndOfNamespace(const AnnotatedLine *line,
+ const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
+ if (!line->startsWith(tok::r_brace))
+ return false;
+ size_t StartLineIndex = line->MatchingOpeningBlockLineIndex;
+ if (StartLineIndex == UnwrappedLine::kInvalidIndex)
+ return false;
+ assert(StartLineIndex < AnnotatedLines.size());
+ const FormatToken *NamespaceTok = AnnotatedLines[StartLineIndex]->First;
+ return isNamespaceToken(NamespaceTok);
+}
+
class LineJoiner {
public:
LineJoiner(const FormatStyle &Style, const AdditionalKeywords &Keywords,
const SmallVectorImpl<AnnotatedLine *> &Lines)
: Style(Style), Keywords(Keywords), End(Lines.end()),
- Next(Lines.begin()) {}
+ Next(Lines.begin()), AnnotatedLines(Lines) {}
/// \brief Returns the next line, merging multiple lines into one if possible.
const AnnotatedLine *getNextMergedLine(bool DryRun,
@@ -195,6 +216,28 @@
(Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline &&
TheLine->Level != 0);
+ if (Style.CompactNamespaces) {
+ if (isNamespaceToken(TheLine->First)) {
+ int i = 0;
+ while (I + 1 + i != E && isNamespaceToken(I[i + 1]->First) &&
+ I[i + 1]->Last->TotalLength < Limit) {
+ Limit -= I[i + 1]->Last->TotalLength;
+ i++;
+ }
+ return i;
+ }
+
+ if (isEndOfNamespace(TheLine, AnnotatedLines)) {
+ int i = 0;
+ while (I + 1 + i != E && isEndOfNamespace(I[i + 1], AnnotatedLines)) {
+ // No space between consecutive braces
+ I[i + 1]->First->SpacesRequiredBefore = !I[i]->Last->is(tok::r_brace);
+ i++;
+ }
+ return i;
+ }
+ }
+
if (TheLine->Last->is(TT_FunctionLBrace) &&
TheLine->First != TheLine->Last) {
return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
@@ -449,6 +492,7 @@
const SmallVectorImpl<AnnotatedLine *>::const_iterator End;
SmallVectorImpl<AnnotatedLine *>::const_iterator Next;
+ const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines;
};
static void markFinalized(FormatToken *Tok) {
Index: lib/Format/NamespaceEndCommentsFixer.cpp
===================================================================
--- lib/Format/NamespaceEndCommentsFixer.cpp
+++ lib/Format/NamespaceEndCommentsFixer.cpp
@@ -120,6 +120,23 @@
<< llvm::toString(std::move(Err)) << "\n";
}
}
+
+const FormatToken * getNamespaceToken(const AnnotatedLine *line,
+ const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
+ if (!line->Affected || line->InPPDirective || !line->startsWith(tok::r_brace))
+ return NULL;
+ size_t StartLineIndex = line->MatchingOpeningBlockLineIndex;
+ if (StartLineIndex == UnwrappedLine::kInvalidIndex)
+ return NULL;
+ assert(StartLineIndex < AnnotatedLines.size());
+ const FormatToken *NamespaceTok = AnnotatedLines[StartLineIndex]->First;
+ // Detect "(inline)? namespace" in the beginning of a line.
+ if (NamespaceTok->is(tok::kw_inline))
+ NamespaceTok = NamespaceTok->getNextNonComment();
+ if (!NamespaceTok || NamespaceTok->isNot(tok::kw_namespace))
+ return NULL;
+ return NamespaceTok;
+}
} // namespace
NamespaceEndCommentsFixer::NamespaceEndCommentsFixer(const Environment &Env,
@@ -133,20 +150,12 @@
AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(),
AnnotatedLines.end());
tooling::Replacements Fixes;
+ std::string AllNamespaceNames = "";
+ size_t StartLineIndex = SIZE_MAX;
for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
- if (!AnnotatedLines[I]->Affected || AnnotatedLines[I]->InPPDirective ||
- !AnnotatedLines[I]->startsWith(tok::r_brace))
- continue;
const AnnotatedLine *EndLine = AnnotatedLines[I];
- size_t StartLineIndex = EndLine->MatchingOpeningBlockLineIndex;
- if (StartLineIndex == UnwrappedLine::kInvalidIndex)
- continue;
- assert(StartLineIndex < E);
- const FormatToken *NamespaceTok = AnnotatedLines[StartLineIndex]->First;
- // Detect "(inline)? namespace" in the beginning of a line.
- if (NamespaceTok->is(tok::kw_inline))
- NamespaceTok = NamespaceTok->getNextNonComment();
- if (!NamespaceTok || NamespaceTok->isNot(tok::kw_namespace))
+ const FormatToken *NamespaceTok = getNamespaceToken(EndLine, AnnotatedLines);
+ if (!NamespaceTok)
continue;
FormatToken *RBraceTok = EndLine->First;
if (RBraceTok->Finalized)
@@ -160,6 +169,22 @@
if (!Style.AllowSemicolonAfterNamespace)
removeTrailingSemicolon(RBraceTok->Next, SourceMgr, &Fixes);
}
+ if (StartLineIndex == SIZE_MAX)
+ StartLineIndex = EndLine->MatchingOpeningBlockLineIndex;
+ std::string NamespaceName = computeName(NamespaceTok);
+ bool CombineWithNext = I + 1 < E &&
+ Style.CompactNamespaces &&
+ getNamespaceToken(AnnotatedLines[I + 1], AnnotatedLines) &&
+ !AnnotatedLines[I + 1]->First->Finalized;
+ if (CombineWithNext) {
+ if (hasEndComment(EndCommentPrevTok) && validEndComment(EndCommentPrevTok, NamespaceName))
+ // remove end comment, it will be merged in next one
+ updateEndComment(EndCommentPrevTok, std::string(), SourceMgr, &Fixes);
+ AllNamespaceNames = "::" + NamespaceName + AllNamespaceNames;
+ continue;
+ }
+ NamespaceName += std::move(AllNamespaceNames);
+ AllNamespaceNames = std::string();
// The next token in the token stream after the place where the end comment
// token must be. This is either the next token on the current line or the
// first token on the next line.
@@ -171,17 +196,16 @@
bool AddNewline = EndCommentNextTok &&
EndCommentNextTok->NewlinesBefore == 0 &&
EndCommentNextTok->isNot(tok::eof);
- const std::string NamespaceName = computeName(NamespaceTok);
const std::string EndCommentText =
computeEndCommentText(NamespaceName, AddNewline);
if (!hasEndComment(EndCommentPrevTok)) {
bool isShort = I - StartLineIndex <= kShortNamespaceMaxLines + 1;
if (!isShort)
addEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes);
- continue;
- }
- if (!validEndComment(EndCommentPrevTok, NamespaceName))
+ } else if (!validEndComment(EndCommentPrevTok, NamespaceName)) {
updateEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes);
+ }
+ StartLineIndex = SIZE_MAX;
}
return Fixes;
}
Index: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp
+++ lib/Format/Format.cpp
@@ -287,20 +287,21 @@
IO.mapOptional("BinPackArguments", Style.BinPackArguments);
IO.mapOptional("BinPackParameters", Style.BinPackParameters);
IO.mapOptional("BraceWrapping", Style.BraceWrapping);
+ IO.mapOptional("BreakAfterJavaFieldAnnotations",
+ Style.BreakAfterJavaFieldAnnotations);
IO.mapOptional("BreakBeforeBinaryOperators",
Style.BreakBeforeBinaryOperators);
IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
+ IO.mapOptional("BreakBeforeInheritanceComma",
+ Style.BreakBeforeInheritanceComma);
IO.mapOptional("BreakBeforeTernaryOperators",
Style.BreakBeforeTernaryOperators);
IO.mapOptional("BreakConstructorInitializersBeforeComma",
Style.BreakConstructorInitializersBeforeComma);
- IO.mapOptional("BreakAfterJavaFieldAnnotations",
- Style.BreakAfterJavaFieldAnnotations);
IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals);
IO.mapOptional("ColumnLimit", Style.ColumnLimit);
IO.mapOptional("CommentPragmas", Style.CommentPragmas);
- IO.mapOptional("BreakBeforeInheritanceComma",
- Style.BreakBeforeInheritanceComma);
+ IO.mapOptional("CompactNamespaces", Style.CompactNamespaces);
IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
Style.ConstructorInitializerAllOnOneLineOrOnePerLine);
IO.mapOptional("ConstructorInitializerIndentWidth",
@@ -516,8 +517,8 @@
LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
LLVMStyle.AlwaysBreakTemplateDeclarations = false;
- LLVMStyle.BinPackParameters = true;
LLVMStyle.BinPackArguments = true;
+ LLVMStyle.BinPackParameters = true;
LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
LLVMStyle.BreakBeforeTernaryOperators = true;
LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
@@ -529,6 +530,7 @@
LLVMStyle.BreakStringLiterals = true;
LLVMStyle.ColumnLimit = 80;
LLVMStyle.CommentPragmas = "^ IWYU pragma:";
+ LLVMStyle.CompactNamespaces = false;
LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
LLVMStyle.ConstructorInitializerIndentWidth = 4;
LLVMStyle.ContinuationIndentWidth = 4;
Index: include/clang/Format/Format.h
===================================================================
--- include/clang/Format/Format.h
+++ include/clang/Format/Format.h
@@ -751,6 +751,28 @@
/// \endcode
bool BreakBeforeInheritanceComma;
+ /// \brief If ``true``, consecutive namespace declarations will be on the same
+ /// line. If ``false``, each namespace is declared on a new line.
+ /// \code
+ /// true:
+ /// namespace Foo { namespace Bar {
+ /// }}
+ ///
+ /// false:
+ /// namespace Foo {
+ /// namespace Bar {
+ /// }
+ /// }
+ /// \endcode
+ ///
+ /// If it does not fit on a single line, the overflowing namespaces get wrapped:
+ /// /// \code
+ /// namespace Foo { namespace Bar {
+ /// namespace Extra {
+ /// }}}
+ /// \endcode
+ bool CompactNamespaces;
+
/// \brief If the constructor initializers don't fit on a line, put each
/// initializer on its own line.
/// \code
@@ -1379,6 +1401,7 @@
BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators &&
BreakBeforeBraces == R.BreakBeforeBraces &&
BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators &&
+ CompactNamespaces == R.CompactNamespaces &&
BreakConstructorInitializersBeforeComma ==
R.BreakConstructorInitializersBeforeComma &&
BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations &&
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits