parameters: (filename, clean_lines, linenum, error)
docstring: Looks for misplaced braces (e.g. at the end of line).
  
    Args:
      filename: The name of the current file.
      clean_lines: A CleansedLines instance containing the file.
      linenum: The number of the line to check.
      error: The function to call with any errors found.
docstring_summary: Looks for misplaced braces (e.g. at the end of line).
docstring_tokens: Looks for misplaced braces ( e . g . at the end of line ) .
function: def CheckBraces(filename, clean_lines, linenum, error):
    """Looks for misplaced braces (e.g. at the end of line).
  
    Args:
      filename: The name of the current file.
      clean_lines: A CleansedLines instance containing the file.
      linenum: The number of the line to check.
      error: The function to call with any errors found.
    """
  
    line = clean_lines.elided[linenum]        # get rid of comments and strings
  
    if Match(r'\s*{\s*$', line):
      # We allow an open brace to start a line in the case where someone is using
      # braces in a block to explicitly create a new scope, which is commonly used
      # to control the lifetime of stack-allocated variables.  Braces are also
      # used for brace initializers inside function calls.  We don't detect this
      # perfectly: we just don't complain if the last non-whitespace character on
      # the previous non-blank line is ',', ';', ':', '(', '{', or '}', or if the
      # previous line starts a preprocessor block.
      prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
      if (not Search(r'[,;:}{(]\s*$', prevline) and
          not Match(r'\s*#', prevline)):
        error(filename, linenum, 'whitespace/braces', 4,
              '{ should almost always be at the end of the previous line')
  
    # An else clause should be on the same line as the preceding closing brace.
    if Match(r'\s*else\s*', line):
      prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
      if Match(r'\s*}\s*$', prevline):
        error(filename, linenum, 'whitespace/newline', 4,
              'An else should appear on the same line as the preceding }')
  
    # If braces come on one side of an else, they should be on both.
    # However, we have to worry about "else if" that spans multiple lines!
    if Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line):
      if Search(r'}\s*else if([^{]*)$', line):       # could be multi-line if
        # find the ( after the if
        pos = line.find('else if')
        pos = line.find('(', pos)
        if pos > 0:
          (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos)
          if endline[endpos:].find('{') == -1:    # must be brace after if
            error(filename, linenum, 'readability/braces', 5,
                  'If an else has a brace on one side, it should have it on both')
      else:            # common case: else not followed by a multi-line if
        error(filename, linenum, 'readability/braces', 5,
              'If an else has a brace on one side, it should have it on both')
  
    # Likewise, an else should never have the else clause on the same line
    if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line):
      error(filename, linenum, 'whitespace/newline', 4,
            'Else clause should never be on same line as else (use 2 lines)')
  
    # In the same way, a do/while should never be on one line
    if Match(r'\s*do [^\s{]', line):
      error(filename, linenum, 'whitespace/newline', 4,
            'do/while clauses should not be on a single line')
  
    # Block bodies should not be followed by a semicolon.  Due to C++11
    # brace initialization, there are more places where semicolons are
    # required than not, so we use a whitelist approach to check these
    # rather than a blacklist.  These are the places where "};" should
    # be replaced by just "}":
    # 1. Some flavor of block following closing parenthesis:
    #    for (;;) {};
    #    while (...) {};
    #    switch (...) {};
    #    Function(...) {};
    #    if (...) {};
    #    if (...) else if (...) {};
    #
    # 2. else block:
    #    if (...) else {};
    #
    # 3. const member function:
    #    Function(...) const {};
    #
    # 4. Block following some statement:
    #    x = 42;
    #    {};
    #
    # 5. Block at the beginning of a function:
    #    Function(...) {
    #      {};
    #    }
    #
    #    Note that naively checking for the preceding "{" will also match
    #    braces inside multi-dimensional arrays, but this is fine since
    #    that expression will not contain semicolons.
    #
    # 6. Block following another block:
    #    while (true) {}
    #    {};
    #
    # 7. End of namespaces:
    #    namespace {};
    #
    #    These semicolons seems far more common than other kinds of
    #    redundant semicolons, possibly due to people converting classes
    #    to namespaces.  For now we do not warn for this case.
    #
    # Try matching case 1 first.
    match = Match(r'^(.*\)\s*)\{', line)
    if match:
      # Matched closing parenthesis (case 1).  Check the token before the
      # matching opening parenthesis, and don't warn if it looks like a
      # macro.  This avoids these false positives:
      #  - macro that defines a base class
      #  - multi-line macro that defines a base class
      #  - macro that defines the whole class-head
      #
      # But we still issue warnings for macros that we know are safe to
      # warn, specifically:
      #  - TEST, TEST_F, TEST_P, MATCHER, MATCHER_P
      #  - TYPED_TEST
      #  - INTERFACE_DEF
      #  - EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED, LOCKS_EXCLUDED:
      #
      # We implement a whitelist of safe macros instead of a blacklist of
      # unsafe macros, even though the latter appears less frequently in
      # google code and would have been easier to implement.  This is because
      # the downside for getting the whitelist wrong means some extra
      # semicolons, while the downside for getting the blacklist wrong
      # would result in compile errors.
      #
      # In addition to macros, we also don't want to warn on compound
      # literals.
      closing_brace_pos = match.group(1).rfind(')')
      opening_parenthesis = ReverseCloseExpression(
          clean_lines, linenum, closing_brace_pos)
      if opening_parenthesis[2] > -1:
        line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]]
        macro = Search(r'\b([A-Z_]+)\s*$', line_prefix)
        if ((macro and
             macro.group(1) not in (
                 'TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST',
                 'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED',
                 'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or
            Search(r'\s+=\s*$', line_prefix)):
          match = None
  
    else:
      # Try matching cases 2-3.
      match = Match(r'^(.*(?:else|\)\s*const)\s*)\{', line)
      if not match:
        # Try matching cases 4-6.  These are always matched on separate lines.
        #
        # Note that we can't simply concatenate the previous line to the
        # current line and do a single match, otherwise we may output
        # duplicate warnings for the blank line case:
        #   if (cond) {
        #     // blank line
        #   }
        prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
        if prevline and Search(r'[;{}]\s*$', prevline):
          match = Match(r'^(\s*)\{', line)
  
    # Check matching closing brace
    if match:
      (endline, endlinenum, endpos) = CloseExpression(
          clean_lines, linenum, len(match.group(1)))
      if endpos > -1 and Match(r'^\s*;', endline[endpos:]):
        # Current {} pair is eligible for semicolon check, and we have found
        # the redundant semicolon, output warning here.
        #
        # Note: because we are scanning forward for opening braces, and
        # outputting warnings for the matching closing brace, if there are
        # nested blocks with trailing semicolons, we will get the error
        # messages in reversed order.
        error(filename, endlinenum, 'readability/braces', 4,
              "You don't need a ; after a }")
function_tokens: def CheckBraces ( filename , clean_lines , linenum , error ) : line = clean_lines . elided [ linenum ] # get rid of comments and strings if Match ( r'\s*{\s*$' , line ) : # We allow an open brace to start a line in the case where someone is using # braces in a block to explicitly create a new scope, which is commonly used # to control the lifetime of stack-allocated variables.  Braces are also # used for brace initializers inside function calls.  We don't detect this # perfectly: we just don't complain if the last non-whitespace character on # the previous non-blank line is ',', ';', ':', '(', '{', or '}', or if the # previous line starts a preprocessor block. prevline = GetPreviousNonBlankLine ( clean_lines , linenum ) [ 0 ] if ( not Search ( r'[,;:}{(]\s*$' , prevline ) and not Match ( r'\s*#' , prevline ) ) : error ( filename , linenum , 'whitespace/braces' , 4 , '{ should almost always be at the end of the previous line' ) # An else clause should be on the same line as the preceding closing brace. if Match ( r'\s*else\s*' , line ) : prevline = GetPreviousNonBlankLine ( clean_lines , linenum ) [ 0 ] if Match ( r'\s*}\s*$' , prevline ) : error ( filename , linenum , 'whitespace/newline' , 4 , 'An else should appear on the same line as the preceding }' ) # If braces come on one side of an else, they should be on both. # However, we have to worry about "else if" that spans multiple lines! if Search ( r'}\s*else[^{]*$' , line ) or Match ( r'[^}]*else\s*{' , line ) : if Search ( r'}\s*else if([^{]*)$' , line ) : # could be multi-line if # find the ( after the if pos = line . find ( 'else if' ) pos = line . find ( '(' , pos ) if pos > 0 : ( endline , _ , endpos ) = CloseExpression ( clean_lines , linenum , pos ) if endline [ endpos : ] . find ( '{' ) == - 1 : # must be brace after if error ( filename , linenum , 'readability/braces' , 5 , 'If an else has a brace on one side, it should have it on both' ) else : # common case: else not followed by a multi-line if error ( filename , linenum , 'readability/braces' , 5 , 'If an else has a brace on one side, it should have it on both' ) # Likewise, an else should never have the else clause on the same line if Search ( r'\belse [^\s{]' , line ) and not Search ( r'\belse if\b' , line ) : error ( filename , linenum , 'whitespace/newline' , 4 , 'Else clause should never be on same line as else (use 2 lines)' ) # In the same way, a do/while should never be on one line if Match ( r'\s*do [^\s{]' , line ) : error ( filename , linenum , 'whitespace/newline' , 4 , 'do/while clauses should not be on a single line' ) # Block bodies should not be followed by a semicolon.  Due to C++11 # brace initialization, there are more places where semicolons are # required than not, so we use a whitelist approach to check these # rather than a blacklist.  These are the places where "};" should # be replaced by just "}": # 1. Some flavor of block following closing parenthesis: #    for (;;) {}; #    while (...) {}; #    switch (...) {}; #    Function(...) {}; #    if (...) {}; #    if (...) else if (...) {}; # # 2. else block: #    if (...) else {}; # # 3. const member function: #    Function(...) const {}; # # 4. Block following some statement: #    x = 42; #    {}; # # 5. Block at the beginning of a function: #    Function(...) { #      {}; #    } # #    Note that naively checking for the preceding "{" will also match #    braces inside multi-dimensional arrays, but this is fine since #    that expression will not contain semicolons. # # 6. Block following another block: #    while (true) {} #    {}; # # 7. End of namespaces: #    namespace {}; # #    These semicolons seems far more common than other kinds of #    redundant semicolons, possibly due to people converting classes #    to namespaces.  For now we do not warn for this case. # # Try matching case 1 first. match = Match ( r'^(.*\)\s*)\{' , line ) if match : # Matched closing parenthesis (case 1).  Check the token before the # matching opening parenthesis, and don't warn if it looks like a # macro.  This avoids these false positives: #  - macro that defines a base class #  - multi-line macro that defines a base class #  - macro that defines the whole class-head # # But we still issue warnings for macros that we know are safe to # warn, specifically: #  - TEST, TEST_F, TEST_P, MATCHER, MATCHER_P #  - TYPED_TEST #  - INTERFACE_DEF #  - EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED, LOCKS_EXCLUDED: # # We implement a whitelist of safe macros instead of a blacklist of # unsafe macros, even though the latter appears less frequently in # google code and would have been easier to implement.  This is because # the downside for getting the whitelist wrong means some extra # semicolons, while the downside for getting the blacklist wrong # would result in compile errors. # # In addition to macros, we also don't want to warn on compound # literals. closing_brace_pos = match . group ( 1 ) . rfind ( ')' ) opening_parenthesis = ReverseCloseExpression ( clean_lines , linenum , closing_brace_pos ) if opening_parenthesis [ 2 ] > - 1 : line_prefix = opening_parenthesis [ 0 ] [ 0 : opening_parenthesis [ 2 ] ] macro = Search ( r'\b([A-Z_]+)\s*$' , line_prefix ) if ( ( macro and macro . group ( 1 ) not in ( 'TEST' , 'TEST_F' , 'MATCHER' , 'MATCHER_P' , 'TYPED_TEST' , 'EXCLUSIVE_LOCKS_REQUIRED' , 'SHARED_LOCKS_REQUIRED' , 'LOCKS_EXCLUDED' , 'INTERFACE_DEF' ) ) or Search ( r'\s+=\s*$' , line_prefix ) ) : match = None else : # Try matching cases 2-3. match = Match ( r'^(.*(?:else|\)\s*const)\s*)\{' , line ) if not match : # Try matching cases 4-6.  These are always matched on separate lines. # # Note that we can't simply concatenate the previous line to the # current line and do a single match, otherwise we may output # duplicate warnings for the blank line case: #   if (cond) { #     // blank line #   } prevline = GetPreviousNonBlankLine ( clean_lines , linenum ) [ 0 ] if prevline and Search ( r'[;{}]\s*$' , prevline ) : match = Match ( r'^(\s*)\{' , line ) # Check matching closing brace if match : ( endline , endlinenum , endpos ) = CloseExpression ( clean_lines , linenum , len ( match . group ( 1 ) ) ) if endpos > - 1 and Match ( r'^\s*;' , endline [ endpos : ] ) : # Current {} pair is eligible for semicolon check, and we have found # the redundant semicolon, output warning here. # # Note: because we are scanning forward for opening braces, and # outputting warnings for the matching closing brace, if there are # nested blocks with trailing semicolons, we will get the error # messages in reversed order. error ( filename , endlinenum , 'readability/braces' , 4 , "You don't need a ; after a }" )