@@ -361,9 +361,18 @@ class LineJoiner {
361361 const auto *FirstNonComment = TheLine->getFirstNonComment ();
362362 if (!FirstNonComment)
363363 return 0 ;
364+
364365 // FIXME: There are probably cases where we should use FirstNonComment
365366 // instead of TheLine->First.
366367
368+ if (Style.AllowShortNamespacesOnASingleLine &&
369+ TheLine->First ->is (tok::kw_namespace) &&
370+ TheLine->Last ->is (tok::l_brace)) {
371+ const auto result = tryMergeNamespace (I, E, Limit);
372+ if (result > 0 )
373+ return result;
374+ }
375+
367376 if (Style.CompactNamespaces ) {
368377 if (const auto *NSToken = TheLine->First ->getNamespaceToken ()) {
369378 int J = 1 ;
@@ -373,7 +382,7 @@ class LineJoiner {
373382 ClosingLineIndex == I[J]->MatchingClosingBlockLineIndex &&
374383 I[J]->Last ->TotalLength < Limit;
375384 ++J, --ClosingLineIndex) {
376- Limit -= I[J]->Last ->TotalLength ;
385+ Limit -= I[J]->Last ->TotalLength + 1 ;
377386
378387 // Reduce indent level for bodies of namespaces which were compacted,
379388 // but only if their content was indented in the first place.
@@ -420,6 +429,7 @@ class LineJoiner {
420429 TheLine->First != LastNonComment) {
421430 return MergeShortFunctions ? tryMergeSimpleBlock (I, E, Limit) : 0 ;
422431 }
432+
423433 // Try to merge a control statement block with left brace unwrapped.
424434 if (TheLine->Last ->is (tok::l_brace) && FirstNonComment != TheLine->Last &&
425435 FirstNonComment->isOneOf (tok::kw_if, tok::kw_while, tok::kw_for,
@@ -616,6 +626,72 @@ class LineJoiner {
616626 return 1 ;
617627 }
618628
629+ unsigned tryMergeNamespace (SmallVectorImpl<AnnotatedLine *>::const_iterator I,
630+ SmallVectorImpl<AnnotatedLine *>::const_iterator E,
631+ unsigned Limit) {
632+ if (Limit == 0 )
633+ return 0 ;
634+
635+ assert (I[1 ]);
636+ const auto &L1 = *I[1 ];
637+ if (L1.InPPDirective != (*I)->InPPDirective ||
638+ (L1.InPPDirective && L1.First ->HasUnescapedNewline )) {
639+ return 0 ;
640+ }
641+
642+ if (std::distance (I, E) <= 2 )
643+ return 0 ;
644+
645+ assert (I[2 ]);
646+ const auto &L2 = *I[2 ];
647+ if (L2.Type == LT_Invalid)
648+ return 0 ;
649+
650+ Limit = limitConsideringMacros (I + 1 , E, Limit);
651+
652+ if (!nextTwoLinesFitInto (I, Limit))
653+ return 0 ;
654+
655+ // Check if it's a namespace inside a namespace, and call recursively if so.
656+ // '3' is the sizes of the whitespace and closing brace for " _inner_ }".
657+ if (L1.First ->is (tok::kw_namespace)) {
658+ if (L1.Last ->is (tok::comment) || !Style.CompactNamespaces )
659+ return 0 ;
660+
661+ assert (Limit >= L1.Last ->TotalLength + 3 );
662+ const auto InnerLimit = Limit - L1.Last ->TotalLength - 3 ;
663+ const auto MergedLines = tryMergeNamespace (I + 1 , E, InnerLimit);
664+ if (MergedLines == 0 )
665+ return 0 ;
666+ const auto N = MergedLines + 2 ;
667+ // Check if there is even a line after the inner result.
668+ if (std::distance (I, E) <= N)
669+ return 0 ;
670+ // Check that the line after the inner result starts with a closing brace
671+ // which we are permitted to merge into one line.
672+ if (I[N]->First ->is (tok::r_brace) && !I[N]->First ->MustBreakBefore &&
673+ I[MergedLines + 1 ]->Last ->isNot (tok::comment) &&
674+ nextNLinesFitInto (I, I + N + 1 , Limit)) {
675+ return N;
676+ }
677+ return 0 ;
678+ }
679+
680+ // There's no inner namespace, so we are considering to merge at most one
681+ // line.
682+
683+ // The line which is in the namespace should end with semicolon.
684+ if (L1.Last ->isNot (tok::semi))
685+ return 0 ;
686+
687+ // Last, check that the third line starts with a closing brace.
688+ if (L2.First ->isNot (tok::r_brace) || L2.First ->MustBreakBefore )
689+ return 0 ;
690+
691+ // If so, merge all three lines.
692+ return 2 ;
693+ }
694+
619695 unsigned tryMergeSimpleControlStatement (
620696 SmallVectorImpl<AnnotatedLine *>::const_iterator I,
621697 SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
@@ -916,6 +992,21 @@ class LineJoiner {
916992 return 1 + I[1 ]->Last ->TotalLength + 1 + I[2 ]->Last ->TotalLength <= Limit;
917993 }
918994
995+ bool nextNLinesFitInto (SmallVectorImpl<AnnotatedLine *>::const_iterator I,
996+ SmallVectorImpl<AnnotatedLine *>::const_iterator E,
997+ unsigned Limit) {
998+ unsigned JoinedLength = 0 ;
999+ for (const auto *J = I + 1 ; J != E; ++J) {
1000+ if ((*J)->First ->MustBreakBefore )
1001+ return false ;
1002+
1003+ JoinedLength += 1 + (*J)->Last ->TotalLength ;
1004+ if (JoinedLength > Limit)
1005+ return false ;
1006+ }
1007+ return true ;
1008+ }
1009+
9191010 bool containsMustBreak (const AnnotatedLine *Line) {
9201011 assert (Line->First );
9211012 // Ignore the first token, because in this situation, it applies more to the
0 commit comments