Commit 26748a32 authored by Mitchell Balan's avatar Mitchell Balan
Browse files

[clang-format] Add new option to add spaces around conditions

Summary:
This diff adds a new option SpacesAroundConditions that inserts spaces inside the braces for conditional statements.

Reviewers: klimek, owenpan, mitchell-stellar, MyDeveloperDay

Patch by: timwoj

Subscribers: rsmmr, cfe-commits

Tags: clang, clang-format

Differential Revision: https://reviews.llvm.org/D68346
parent 9a20c79d
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -2328,6 +2328,9 @@ the configuration (without a prefix: ``Auto``).
     true:                                  false:
     x = ( int32 )y                 vs.     x = (int32)y

**SpacesInConditionalStatement** (``bool``)
  If ``true``, spaces will be inserted around if/for/while (and similar) conditions.

**SpacesInContainerLiterals** (``bool``)
  If ``true``, spaces are inserted inside container literals (e.g.
  ObjC and Javascript array and dict literals).
+10 −0
Original line number Diff line number Diff line
@@ -1953,6 +1953,15 @@ struct FormatStyle {
  /// \endcode
  bool SpacesInAngles;

  /// If ``true``, spaces will be inserted around if/for/switch/while
  /// conditions.
  /// \code
  ///    true:                                  false:
  ///    if ( a )  { ... }              vs.     if (a) { ... }
  ///    while ( i < 5 )  { ... }               while (i < 5) { ... }
  /// \endcode
  bool SpacesInConditionalStatement;

  /// If ``true``, spaces are inserted inside container literals (e.g.
  /// ObjC and Javascript array and dict literals).
  /// \code{.js}
@@ -2155,6 +2164,7 @@ struct FormatStyle {
           SpaceInEmptyParentheses == R.SpaceInEmptyParentheses &&
           SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments &&
           SpacesInAngles == R.SpacesInAngles &&
           SpacesInConditionalStatement == R.SpacesInConditionalStatement &&
           SpacesInContainerLiterals == R.SpacesInContainerLiterals &&
           SpacesInCStyleCastParentheses == R.SpacesInCStyleCastParentheses &&
           SpacesInParentheses == R.SpacesInParentheses &&
+3 −0
Original line number Diff line number Diff line
@@ -537,6 +537,8 @@ template <> struct MappingTraits<FormatStyle> {
    IO.mapOptional("SpacesBeforeTrailingComments",
                   Style.SpacesBeforeTrailingComments);
    IO.mapOptional("SpacesInAngles", Style.SpacesInAngles);
    IO.mapOptional("SpacesInConditionalStatement",
                   Style.SpacesInConditionalStatement);
    IO.mapOptional("SpacesInContainerLiterals",
                   Style.SpacesInContainerLiterals);
    IO.mapOptional("SpacesInCStyleCastParentheses",
@@ -817,6 +819,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
  LLVMStyle.SpaceBeforeCpp11BracedList = false;
  LLVMStyle.SpaceBeforeSquareBrackets = false;
  LLVMStyle.SpacesInAngles = false;
  LLVMStyle.SpacesInConditionalStatement = false;

  LLVMStyle.PenaltyBreakAssignment = prec::Assignment;
  LLVMStyle.PenaltyBreakComment = 300;
+18 −1
Original line number Diff line number Diff line
@@ -2592,6 +2592,13 @@ bool TokenAnnotator::spaceRequiredBeforeParens(const FormatToken &Right) const {
          Right.ParameterCount > 0);
}

/// Returns \c true if the token is followed by a boolean condition, \c false
/// otherwise.
static bool isKeywordWithCondition(const FormatToken &Tok) {
  return Tok.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch,
                     tok::kw_constexpr);
};

bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
                                          const FormatToken &Left,
                                          const FormatToken &Right) {
@@ -2610,6 +2617,15 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
      (Left.is(tok::l_brace) && Left.BlockKind != BK_Block &&
       Right.is(tok::r_brace) && Right.BlockKind != BK_Block))
    return Style.SpaceInEmptyParentheses;
  if (Style.SpacesInConditionalStatement) {
    if (Left.is(tok::l_paren) && Left.Previous &&
        isKeywordWithCondition(*Left.Previous))
      return true;
    if (Right.is(tok::r_paren) && Right.MatchingParen &&
        Right.MatchingParen->Previous &&
        isKeywordWithCondition(*Right.MatchingParen->Previous))
      return true;
  }
  if (Left.is(tok::l_paren) || Right.is(tok::r_paren))
    return (Right.is(TT_CastRParen) ||
            (Left.MatchingParen && Left.MatchingParen->is(TT_CastRParen)))
@@ -3044,7 +3060,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
    // The identifier might actually be a macro name such as ALWAYS_INLINE. If
    // this turns out to be too lenient, add analysis of the identifier itself.
    return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd();
  if (Right.is(tok::coloncolon) && !Left.isOneOf(tok::l_brace, tok::comment))
  if (Right.is(tok::coloncolon) &&
      !Left.isOneOf(tok::l_brace, tok::comment, tok::l_paren))
    return (Left.is(TT_TemplateOpener) &&
            Style.Standard < FormatStyle::LS_Cpp11) ||
           !(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square,
+17 −0
Original line number Diff line number Diff line
@@ -12555,6 +12555,7 @@ TEST_F(FormatTest, ParsesConfigurationBools) {
  CHECK_PARSE_BOOL(SpacesInParentheses);
  CHECK_PARSE_BOOL(SpacesInSquareBrackets);
  CHECK_PARSE_BOOL(SpacesInAngles);
  CHECK_PARSE_BOOL(SpacesInConditionalStatement);
  CHECK_PARSE_BOOL(SpaceInEmptyBlock);
  CHECK_PARSE_BOOL(SpaceInEmptyParentheses);
  CHECK_PARSE_BOOL(SpacesInContainerLiterals);
@@ -14880,6 +14881,22 @@ TEST_F(FormatTest, AmbersandInLamda) {
  verifyFormat("auto lambda = [&a = a]() { a = 2; };", AlignStyle);
}
 TEST_F(FormatTest, SpacesInConditionalStatement) {
  FormatStyle Spaces = getLLVMStyle();
  Spaces.SpacesInConditionalStatement = true;
  verifyFormat("for ( int i = 0; i; i++ )\n  continue;", Spaces);
  verifyFormat("if ( !a )\n  return;", Spaces);
  verifyFormat("if ( a )\n  return;", Spaces);
  verifyFormat("if constexpr ( a )\n  return;", Spaces);
  verifyFormat("switch ( a )\ncase 1:\n  return;", Spaces);
  verifyFormat("while ( a )\n  return;", Spaces);
  verifyFormat("while ( (a && b) )\n  return;", Spaces);
  verifyFormat("do {\n} while ( 1 != 0 );", Spaces);
  // Check that space on the left of "::" is inserted as expected at beginning
  // of condition.
  verifyFormat("while ( ::func() )\n  return;", Spaces);
}
TEST_F(FormatTest, AlternativeOperators) {
  // Test case for ensuring alternate operators are not
  // combined with their right most neighbour.