parameters: (file_extension, clean_lines, line_number, error)
docstring: Checks for the correctness of various spacing issues in the code.
  
      Things we check for: spaces around operators, spaces after
      if/for/while/switch, no spaces around parens in function calls, two
      spaces between code and comment, don't start a block with a blank
      line, don't end a function with a blank line, don't have too many
      blank lines in a row.
  
      Args:
        file_extension: The current file extension, without the leading dot.
        clean_lines: A CleansedLines instance containing the file.
        line_number: The number of the line to check.
        error: The function to call with any errors found.
docstring_summary: Checks for the correctness of various spacing issues in the code.
docstring_tokens: Checks for the correctness of various spacing issues in the code .
function: def check_spacing(file_extension, clean_lines, line_number, error):
      """Checks for the correctness of various spacing issues in the code.
  
      Things we check for: spaces around operators, spaces after
      if/for/while/switch, no spaces around parens in function calls, two
      spaces between code and comment, don't start a block with a blank
      line, don't end a function with a blank line, don't have too many
      blank lines in a row.
  
      Args:
        file_extension: The current file extension, without the leading dot.
        clean_lines: A CleansedLines instance containing the file.
        line_number: The number of the line to check.
        error: The function to call with any errors found.
      """
  
      raw = clean_lines.raw_lines
      line = raw[line_number]
  
      # Before nixing comments, check if the line is blank for no good
      # reason.  This includes the first line after a block is opened, and
      # blank lines at the end of a function (ie, right before a line like '}').
      if is_blank_line(line):
          elided = clean_lines.elided
          previous_line = elided[line_number - 1]
          previous_brace = previous_line.rfind('{')
          # FIXME: Don't complain if line before blank line, and line after,
          #        both start with alnums and are indented the same amount.
          #        This ignores whitespace at the start of a namespace block
          #        because those are not usually indented.
          if (previous_brace != -1 and previous_line[previous_brace:].find('}') == -1
              and previous_line[:previous_brace].find('namespace') == -1):
              # OK, we have a blank line at the start of a code block.  Before we
              # complain, we check if it is an exception to the rule: The previous
              # non-empty line has the parameters of a function header that are indented
              # 4 spaces (because they did not fit in a 80 column line when placed on
              # the same line as the function name).  We also check for the case where
              # the previous line is indented 6 spaces, which may happen when the
              # initializers of a constructor do not fit into a 80 column line.
              exception = False
              if match(r' {6}\w', previous_line):  # Initializer list?
                  # We are looking for the opening column of initializer list, which
                  # should be indented 4 spaces to cause 6 space indentation afterwards.
                  search_position = line_number - 2
                  while (search_position >= 0
                         and match(r' {6}\w', elided[search_position])):
                      search_position -= 1
                  exception = (search_position >= 0
                               and elided[search_position][:5] == '    :')
              else:
                  # Search for the function arguments or an initializer list.  We use a
                  # simple heuristic here: If the line is indented 4 spaces; and we have a
                  # closing paren, without the opening paren, followed by an opening brace
                  # or colon (for initializer lists) we assume that it is the last line of
                  # a function header.  If we have a colon indented 4 spaces, it is an
                  # initializer list.
                  exception = (match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
                                     previous_line)
                               or match(r' {4}:', previous_line))
  
              if not exception:
                  error(line_number, 'whitespace/blank_line', 2,
                        'Blank line at the start of a code block.  Is this needed?')
          # This doesn't ignore whitespace at the end of a namespace block
          # because that is too hard without pairing open/close braces;
          # however, a special exception is made for namespace closing
          # brackets which have a comment containing "namespace".
          #
          # Also, ignore blank lines at the end of a block in a long if-else
          # chain, like this:
          #   if (condition1) {
          #     // Something followed by a blank line
          #
          #   } else if (condition2) {
          #     // Something else
          #   }
          if line_number + 1 < clean_lines.num_lines():
              next_line = raw[line_number + 1]
              if (next_line
                  and match(r'\s*}', next_line)
                  and next_line.find('namespace') == -1
                  and next_line.find('} else ') == -1):
                  error(line_number, 'whitespace/blank_line', 3,
                        'Blank line at the end of a code block.  Is this needed?')
  
      # Next, we check for proper spacing with respect to comments.
      comment_position = line.find('//')
      if comment_position != -1:
          # Check if the // may be in quotes.  If so, ignore it
          # Comparisons made explicit for clarity
          if (line.count('"', 0, comment_position) - line.count('\\"', 0, comment_position)) % 2 == 0:   # not in quotes
              # Allow one space before end of line comment.
              if (not match(r'^\s*$', line[:comment_position])
                  and (comment_position >= 1
                  and ((line[comment_position - 1] not in string.whitespace)
                       or (comment_position >= 2
                           and line[comment_position - 2] in string.whitespace)))):
                  error(line_number, 'whitespace/comments', 5,
                        'One space before end of line comments')
              # There should always be a space between the // and the comment
              commentend = comment_position + 2
              if commentend < len(line) and not line[commentend] == ' ':
                  # but some lines are exceptions -- e.g. if they're big
                  # comment delimiters like:
                  # //----------------------------------------------------------
                  # or they begin with multiple slashes followed by a space:
                  # //////// Header comment
                  matched = (search(r'[=/-]{4,}\s*$', line[commentend:])
                             or search(r'^/+ ', line[commentend:]))
                  if not matched:
                      error(line_number, 'whitespace/comments', 4,
                            'Should have a space between // and comment')
  
              # There should only be one space after punctuation in a comment.
              if search(r'[.!?,;:]\s\s+\w', line[comment_position:]):
                  error(line_number, 'whitespace/comments', 5,
                        'Should have only a single space after a punctuation in a comment.')
  
      line = clean_lines.elided[line_number]  # get rid of comments and strings
  
      # Objective-C @property lines.
      is_objective_c_property = search(r'^@property', line)
      if is_objective_c_property:
          # "@property (attr)" not "@property(attr)"
          if search(r'^@property\(', line):
              error(line_number, 'whitespace/property', 4,
                    'Should have space between @property and attributes.')
          # "(getter=foo)" not "(getter = foo)"
          if search(r'(\s+=|=\s+)', line):
              error(line_number, 'whitespace/property', 4,
                    'Should not have spaces around = in property attributes.')
  
      # Objective-C @synthesize lines.
      is_objective_c_synthesize = search(r'^@synthesize', line)
      if is_objective_c_synthesize:
          # "prop=_varName" not "prop = _varName"
          if search(r'(\s+=|=\s+)', line):
              error(line_number, 'whitespace/property', 4,
                    'Should not have spaces around = in property synthesis.')
  
      # Don't try to do spacing checks for operator methods
      line = sub(r'operator(==|!=|<|<<|<=|>=|>>|>|\+=|-=|\*=|/=|%=|&=|\|=|^=|<<=|>>=|/)\(', 'operator\(', line)
      # Don't try to do spacing checks for #include, #import, or #if statements at
      # minimum because it messes up checks for spacing around /
      if match(r'\s*#\s*(?:include|import|if)', line):
          return
      if not is_objective_c_property and not is_objective_c_synthesize and search(r'[\w.]=[\w.]', line):
          error(line_number, 'whitespace/operators', 4,
                'Missing spaces around =')
  
      # FIXME: It's not ok to have spaces around binary operators like .
  
      # You should always have whitespace around binary operators.
      # Alas, we can't test <, >, <<, >>, or && because they're legitimately used sans spaces
      # (a->b, vector<int> a, Foo&& a).  The only time we can tell is a < with no >, and
      # only if it's not template params list spilling into the next line.
      matched = search(r'[^<>=!\s](==|!=|\+=|-=|\*=|/=|/|\|=|&=|<<=|>>=|<=|>=|\|\||\|)[^<>=!\s]', line)
      if not matched:
          # Note that while it seems that the '<[^<]*' term in the following
          # regexp could be simplified to '<.*', which would indeed match
          # the same class of strings, the [^<] means that searching for the
          # regexp takes linear rather than quadratic time.
          if not search(r'<[^<]*,\s*$', line):  # template params spill
              matched = search(r'[^<>=!\s](<)[^<>=!\s]([^>]|->)*$', line)
      # It is necessary to check this, because rvaule references can be in
      # parameter packs (c++11 feature)
      if matched and not search(r'&&\.\.\.', line):
          error(line_number, 'whitespace/operators', 3,
                'Missing spaces around %s' % matched.group(1))
  
      # There shouldn't be space around unary operators
      matched = search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line)
      if matched:
          error(line_number, 'whitespace/operators', 4,
                'Extra space for operator %s' % matched.group(1))
  
      # A pet peeve of mine: no spaces after an if, while, switch, or for
      matched = search(r' (if\(|for\(|while\(|switch\()', line)
      if matched:
          error(line_number, 'whitespace/parens', 5,
                'Missing space before ( in %s' % matched.group(1))
  
      # For if/for/while/switch, the left and right parens should be
      # consistent about how many spaces are inside the parens, and
      # there should either be zero or one spaces inside the parens.
      # We don't want: "if ( foo)" or "if ( foo   )".
      # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed.
      matched = search(r'\b(?P<statement>if|for|while|switch)\s*\((?P<remainder>.*)$', line)
      if matched:
          statement = matched.group('statement')
          condition, rest = up_to_unmatched_closing_paren(matched.group('remainder'))
          if condition is not None:
              if statement == 'for' and search(r'(?:[^ :]:[^:]|[^:]:[^ :])', condition):
                  error(line_number, 'whitespace/colon', 4, 'Missing space around : in range-based for statement')
              condition_match = search(r'(?P<leading>[ ]*)(?P<separator>.).*[^ ]+(?P<trailing>[ ]*)', condition)
              if condition_match:
                  n_leading = len(condition_match.group('leading'))
                  n_trailing = len(condition_match.group('trailing'))
                  if n_leading != 0:
                      for_exception = statement == 'for' and condition.startswith(' ;')
                      if not for_exception:
                          error(line_number, 'whitespace/parens', 5,
                                'Extra space after ( in %s' % statement)
                  if n_trailing != 0:
                      for_exception = statement == 'for' and condition.endswith('; ')
                      if not for_exception:
                          error(line_number, 'whitespace/parens', 5,
                                'Extra space before ) in %s' % statement)
  
              # Do not check for more than one command in macros
              in_preprocessor_directive = match(r'\s*#', line)
              if not in_preprocessor_directive and not match(r'((\s*{\s*}?)|(\s*;?))\s*\\?$', rest):
                  error(line_number, 'whitespace/parens', 4,
                        'More than one command on the same line in %s' % statement)
  
      # You should always have a space after a comma (either as fn arg or operator)
      if search(r',[^\s]', line):
          error(line_number, 'whitespace/comma', 3,
                'Missing space after ,')
  
      matched = search(r'^\s*(?P<token1>[a-zA-Z0-9_\*&]+)\s\s+(?P<token2>[a-zA-Z0-9_\*&]+)', line)
      if matched:
          error(line_number, 'whitespace/declaration', 3,
                'Extra space between %s and %s' % (matched.group('token1'), matched.group('token2')))
  
      if file_extension == 'cpp':
          # C++ should have the & or * beside the type not the variable name.
          matched = match(r'\s*(?P<pre_part>\w[\w\s]+)\s+(?P<pointer_operator>\*|\&)\s*\w+', line)
          if matched and not matched.group('pre_part').startswith('return') and not matched.group('pre_part').startswith('delete'):
              error(line_number, 'whitespace/declaration', 3,
                    'Declaration has space between type name and %s in %s' % (matched.group('pointer_operator'), matched.group(0).strip()))
  
      elif file_extension == 'c':
          # C Pointer declaration should have the * beside the variable not the type name.
          matched = search(r'^\s*\w+\*\s+\w+', line)
          if matched:
              error(line_number, 'whitespace/declaration', 3,
                    'Declaration has space between * and variable name in %s' % matched.group(0).strip())
  
      # Next we will look for issues with function calls.
      check_spacing_for_function_call(line, line_number, error)
  
      # Except after an opening paren, ^ for blocks, or @ for Objective-C
      # literal NSDictionary, you should have spaces before your braces.
      # Since you should never have braces at the beginning of a line, this
      # is an easy test.
      if search(r'[^ ({\^@]{', line):
          error(line_number, 'whitespace/braces', 5,
                'Missing space before {')
  
      # Make sure '} else {' has spaces.
      if search(r'}else', line):
          error(line_number, 'whitespace/braces', 5,
                'Missing space before else')
  
      # You shouldn't have spaces before your brackets, except maybe after
      # 'delete []' or 'new char * []'. Objective-C can't follow this rule
      # because of method calls.
      if file_extension != 'mm' and file_extension != 'm':
          if search(r'\w\s+\[', line) and not search(r'(delete|return)\s+\[', line):
              error(line_number, 'whitespace/brackets', 5,
                    'Extra space before [.')
  
      # There should always be a single space in between braces on the same line.
      if search(r'\{\}', line):
          error(line_number, 'whitespace/braces', 5, 'Missing space inside { }.')
      if search(r'\{\s\s+\}', line):
          error(line_number, 'whitespace/braces', 5, 'Too many spaces inside { }.')
  
      # You shouldn't have a space before a semicolon at the end of the line.
      # There's a special case for "for" since the style guide allows space before
      # the semicolon there.
      if search(r':\s*;\s*$', line):
          error(line_number, 'whitespace/semicolon', 5,
                'Semicolon defining empty statement. Use { } instead.')
      elif search(r'^\s*;\s*$', line):
          error(line_number, 'whitespace/semicolon', 5,
                'Line contains only semicolon. If this should be an empty statement, '
                'use { } instead.')
      elif (search(r'\s+;\s*$', line) and not search(r'\bfor\b', line)):
          error(line_number, 'whitespace/semicolon', 5,
                'Extra space before last semicolon. If this should be an empty '
                'statement, use { } instead.')
      elif (search(r'\b(for|while)\s*\(.*\)\s*;\s*$', line)
            and line.count('(') == line.count(')')
            # Allow do {} while();
            and not search(r'}\s*while', line)):
          error(line_number, 'whitespace/semicolon', 5,
                'Semicolon defining empty statement for this loop. Use { } instead.')
function_tokens: def check_spacing ( file_extension , clean_lines , line_number , error ) : raw = clean_lines . raw_lines line = raw [ line_number ] # Before nixing comments, check if the line is blank for no good # reason.  This includes the first line after a block is opened, and # blank lines at the end of a function (ie, right before a line like '}'). if is_blank_line ( line ) : elided = clean_lines . elided previous_line = elided [ line_number - 1 ] previous_brace = previous_line . rfind ( '{' ) # FIXME: Don't complain if line before blank line, and line after, #        both start with alnums and are indented the same amount. #        This ignores whitespace at the start of a namespace block #        because those are not usually indented. if ( previous_brace != - 1 and previous_line [ previous_brace : ] . find ( '}' ) == - 1 and previous_line [ : previous_brace ] . find ( 'namespace' ) == - 1 ) : # OK, we have a blank line at the start of a code block.  Before we # complain, we check if it is an exception to the rule: The previous # non-empty line has the parameters of a function header that are indented # 4 spaces (because they did not fit in a 80 column line when placed on # the same line as the function name).  We also check for the case where # the previous line is indented 6 spaces, which may happen when the # initializers of a constructor do not fit into a 80 column line. exception = False if match ( r' {6}\w' , previous_line ) : # Initializer list? # We are looking for the opening column of initializer list, which # should be indented 4 spaces to cause 6 space indentation afterwards. search_position = line_number - 2 while ( search_position >= 0 and match ( r' {6}\w' , elided [ search_position ] ) ) : search_position -= 1 exception = ( search_position >= 0 and elided [ search_position ] [ : 5 ] == '    :' ) else : # Search for the function arguments or an initializer list.  We use a # simple heuristic here: If the line is indented 4 spaces; and we have a # closing paren, without the opening paren, followed by an opening brace # or colon (for initializer lists) we assume that it is the last line of # a function header.  If we have a colon indented 4 spaces, it is an # initializer list. exception = ( match ( r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)' , previous_line ) or match ( r' {4}:' , previous_line ) ) if not exception : error ( line_number , 'whitespace/blank_line' , 2 , 'Blank line at the start of a code block.  Is this needed?' ) # This doesn't ignore whitespace at the end of a namespace block # because that is too hard without pairing open/close braces; # however, a special exception is made for namespace closing # brackets which have a comment containing "namespace". # # Also, ignore blank lines at the end of a block in a long if-else # chain, like this: #   if (condition1) { #     // Something followed by a blank line # #   } else if (condition2) { #     // Something else #   } if line_number + 1 < clean_lines . num_lines ( ) : next_line = raw [ line_number + 1 ] if ( next_line and match ( r'\s*}' , next_line ) and next_line . find ( 'namespace' ) == - 1 and next_line . find ( '} else ' ) == - 1 ) : error ( line_number , 'whitespace/blank_line' , 3 , 'Blank line at the end of a code block.  Is this needed?' ) # Next, we check for proper spacing with respect to comments. comment_position = line . find ( '//' ) if comment_position != - 1 : # Check if the // may be in quotes.  If so, ignore it # Comparisons made explicit for clarity if ( line . count ( '"' , 0 , comment_position ) - line . count ( '\\"' , 0 , comment_position ) ) % 2 == 0 : # not in quotes # Allow one space before end of line comment. if ( not match ( r'^\s*$' , line [ : comment_position ] ) and ( comment_position >= 1 and ( ( line [ comment_position - 1 ] not in string . whitespace ) or ( comment_position >= 2 and line [ comment_position - 2 ] in string . whitespace ) ) ) ) : error ( line_number , 'whitespace/comments' , 5 , 'One space before end of line comments' ) # There should always be a space between the // and the comment commentend = comment_position + 2 if commentend < len ( line ) and not line [ commentend ] == ' ' : # but some lines are exceptions -- e.g. if they're big # comment delimiters like: # //---------------------------------------------------------- # or they begin with multiple slashes followed by a space: # //////// Header comment matched = ( search ( r'[=/-]{4,}\s*$' , line [ commentend : ] ) or search ( r'^/+ ' , line [ commentend : ] ) ) if not matched : error ( line_number , 'whitespace/comments' , 4 , 'Should have a space between // and comment' ) # There should only be one space after punctuation in a comment. if search ( r'[.!?,;:]\s\s+\w' , line [ comment_position : ] ) : error ( line_number , 'whitespace/comments' , 5 , 'Should have only a single space after a punctuation in a comment.' ) line = clean_lines . elided [ line_number ] # get rid of comments and strings # Objective-C @property lines. is_objective_c_property = search ( r'^@property' , line ) if is_objective_c_property : # "@property (attr)" not "@property(attr)" if search ( r'^@property\(' , line ) : error ( line_number , 'whitespace/property' , 4 , 'Should have space between @property and attributes.' ) # "(getter=foo)" not "(getter = foo)" if search ( r'(\s+=|=\s+)' , line ) : error ( line_number , 'whitespace/property' , 4 , 'Should not have spaces around = in property attributes.' ) # Objective-C @synthesize lines. is_objective_c_synthesize = search ( r'^@synthesize' , line ) if is_objective_c_synthesize : # "prop=_varName" not "prop = _varName" if search ( r'(\s+=|=\s+)' , line ) : error ( line_number , 'whitespace/property' , 4 , 'Should not have spaces around = in property synthesis.' ) # Don't try to do spacing checks for operator methods line = sub ( r'operator(==|!=|<|<<|<=|>=|>>|>|\+=|-=|\*=|/=|%=|&=|\|=|^=|<<=|>>=|/)\(' , 'operator\(' , line ) # Don't try to do spacing checks for #include, #import, or #if statements at # minimum because it messes up checks for spacing around / if match ( r'\s*#\s*(?:include|import|if)' , line ) : return if not is_objective_c_property and not is_objective_c_synthesize and search ( r'[\w.]=[\w.]' , line ) : error ( line_number , 'whitespace/operators' , 4 , 'Missing spaces around =' ) # FIXME: It's not ok to have spaces around binary operators like . # You should always have whitespace around binary operators. # Alas, we can't test <, >, <<, >>, or && because they're legitimately used sans spaces # (a->b, vector<int> a, Foo&& a).  The only time we can tell is a < with no >, and # only if it's not template params list spilling into the next line. matched = search ( r'[^<>=!\s](==|!=|\+=|-=|\*=|/=|/|\|=|&=|<<=|>>=|<=|>=|\|\||\|)[^<>=!\s]' , line ) if not matched : # Note that while it seems that the '<[^<]*' term in the following # regexp could be simplified to '<.*', which would indeed match # the same class of strings, the [^<] means that searching for the # regexp takes linear rather than quadratic time. if not search ( r'<[^<]*,\s*$' , line ) : # template params spill matched = search ( r'[^<>=!\s](<)[^<>=!\s]([^>]|->)*$' , line ) # It is necessary to check this, because rvaule references can be in # parameter packs (c++11 feature) if matched and not search ( r'&&\.\.\.' , line ) : error ( line_number , 'whitespace/operators' , 3 , 'Missing spaces around %s' % matched . group ( 1 ) ) # There shouldn't be space around unary operators matched = search ( r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])' , line ) if matched : error ( line_number , 'whitespace/operators' , 4 , 'Extra space for operator %s' % matched . group ( 1 ) ) # A pet peeve of mine: no spaces after an if, while, switch, or for matched = search ( r' (if\(|for\(|while\(|switch\()' , line ) if matched : error ( line_number , 'whitespace/parens' , 5 , 'Missing space before ( in %s' % matched . group ( 1 ) ) # For if/for/while/switch, the left and right parens should be # consistent about how many spaces are inside the parens, and # there should either be zero or one spaces inside the parens. # We don't want: "if ( foo)" or "if ( foo   )". # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed. matched = search ( r'\b(?P<statement>if|for|while|switch)\s*\((?P<remainder>.*)$' , line ) if matched : statement = matched . group ( 'statement' ) condition , rest = up_to_unmatched_closing_paren ( matched . group ( 'remainder' ) ) if condition is not None : if statement == 'for' and search ( r'(?:[^ :]:[^:]|[^:]:[^ :])' , condition ) : error ( line_number , 'whitespace/colon' , 4 , 'Missing space around : in range-based for statement' ) condition_match = search ( r'(?P<leading>[ ]*)(?P<separator>.).*[^ ]+(?P<trailing>[ ]*)' , condition ) if condition_match : n_leading = len ( condition_match . group ( 'leading' ) ) n_trailing = len ( condition_match . group ( 'trailing' ) ) if n_leading != 0 : for_exception = statement == 'for' and condition . startswith ( ' ;' ) if not for_exception : error ( line_number , 'whitespace/parens' , 5 , 'Extra space after ( in %s' % statement ) if n_trailing != 0 : for_exception = statement == 'for' and condition . endswith ( '; ' ) if not for_exception : error ( line_number , 'whitespace/parens' , 5 , 'Extra space before ) in %s' % statement ) # Do not check for more than one command in macros in_preprocessor_directive = match ( r'\s*#' , line ) if not in_preprocessor_directive and not match ( r'((\s*{\s*}?)|(\s*;?))\s*\\?$' , rest ) : error ( line_number , 'whitespace/parens' , 4 , 'More than one command on the same line in %s' % statement ) # You should always have a space after a comma (either as fn arg or operator) if search ( r',[^\s]' , line ) : error ( line_number , 'whitespace/comma' , 3 , 'Missing space after ,' ) matched = search ( r'^\s*(?P<token1>[a-zA-Z0-9_\*&]+)\s\s+(?P<token2>[a-zA-Z0-9_\*&]+)' , line ) if matched : error ( line_number , 'whitespace/declaration' , 3 , 'Extra space between %s and %s' % ( matched . group ( 'token1' ) , matched . group ( 'token2' ) ) ) if file_extension == 'cpp' : # C++ should have the & or * beside the type not the variable name. matched = match ( r'\s*(?P<pre_part>\w[\w\s]+)\s+(?P<pointer_operator>\*|\&)\s*\w+' , line ) if matched and not matched . group ( 'pre_part' ) . startswith ( 'return' ) and not matched . group ( 'pre_part' ) . startswith ( 'delete' ) : error ( line_number , 'whitespace/declaration' , 3 , 'Declaration has space between type name and %s in %s' % ( matched . group ( 'pointer_operator' ) , matched . group ( 0 ) . strip ( ) ) ) elif file_extension == 'c' : # C Pointer declaration should have the * beside the variable not the type name. matched = search ( r'^\s*\w+\*\s+\w+' , line ) if matched : error ( line_number , 'whitespace/declaration' , 3 , 'Declaration has space between * and variable name in %s' % matched . group ( 0 ) . strip ( ) ) # Next we will look for issues with function calls. check_spacing_for_function_call ( line , line_number , error ) # Except after an opening paren, ^ for blocks, or @ for Objective-C # literal NSDictionary, you should have spaces before your braces. # Since you should never have braces at the beginning of a line, this # is an easy test. if search ( r'[^ ({\^@]{' , line ) : error ( line_number , 'whitespace/braces' , 5 , 'Missing space before {' ) # Make sure '} else {' has spaces. if search ( r'}else' , line ) : error ( line_number , 'whitespace/braces' , 5 , 'Missing space before else' ) # You shouldn't have spaces before your brackets, except maybe after # 'delete []' or 'new char * []'. Objective-C can't follow this rule # because of method calls. if file_extension != 'mm' and file_extension != 'm' : if search ( r'\w\s+\[' , line ) and not search ( r'(delete|return)\s+\[' , line ) : error ( line_number , 'whitespace/brackets' , 5 , 'Extra space before [.' ) # There should always be a single space in between braces on the same line. if search ( r'\{\}' , line ) : error ( line_number , 'whitespace/braces' , 5 , 'Missing space inside { }.' ) if search ( r'\{\s\s+\}' , line ) : error ( line_number , 'whitespace/braces' , 5 , 'Too many spaces inside { }.' ) # You shouldn't have a space before a semicolon at the end of the line. # There's a special case for "for" since the style guide allows space before # the semicolon there. if search ( r':\s*;\s*$' , line ) : error ( line_number , 'whitespace/semicolon' , 5 , 'Semicolon defining empty statement. Use { } instead.' ) elif search ( r'^\s*;\s*$' , line ) : error ( line_number , 'whitespace/semicolon' , 5 , 'Line contains only semicolon. If this should be an empty statement, ' 'use { } instead.' ) elif ( search ( r'\s+;\s*$' , line ) and not search ( r'\bfor\b' , line ) ) : error ( line_number , 'whitespace/semicolon' , 5 , 'Extra space before last semicolon. If this should be an empty ' 'statement, use { } instead.' ) elif ( search ( r'\b(for|while)\s*\(.*\)\s*;\s*$' , line ) and line . count ( '(' ) == line . count ( ')' ) # Allow do {} while(); and not search ( r'}\s*while' , line ) ) : error ( line_number , 'whitespace/semicolon' , 5 , 'Semicolon defining empty statement for this loop. Use { } instead.' )