parameters: (filename, clean_lines, linenum,
                                nesting_state, error)
docstring: Check for non-const references.
  
    Separate from CheckLanguage since it scans backwards from current
    line, instead of scanning forward.
  
    Args:
      filename: The name of the current file.
      clean_lines: A CleansedLines instance containing the file.
      linenum: The number of the line to check.
      nesting_state: A _NestingState instance which maintains information about
                     the current stack of nested blocks being parsed.
      error: The function to call with any errors found.
docstring_summary: Check for non-const references.
docstring_tokens: Check for non - const references .
function: def CheckForNonConstReference(filename, clean_lines, linenum,
                                nesting_state, error):
    """Check for non-const references.
  
    Separate from CheckLanguage since it scans backwards from current
    line, instead of scanning forward.
  
    Args:
      filename: The name of the current file.
      clean_lines: A CleansedLines instance containing the file.
      linenum: The number of the line to check.
      nesting_state: A _NestingState instance which maintains information about
                     the current stack of nested blocks being parsed.
      error: The function to call with any errors found.
    """
    # Do nothing if there is no '&' on current line.
    line = clean_lines.elided[linenum]
    if '&' not in line:
      return
  
    # Long type names may be broken across multiple lines, usually in one
    # of these forms:
    #   LongType
    #       ::LongTypeContinued &identifier
    #   LongType::
    #       LongTypeContinued &identifier
    #   LongType<
    #       ...>::LongTypeContinued &identifier
    #
    # If we detected a type split across two lines, join the previous
    # line to current line so that we can match const references
    # accordingly.
    #
    # Note that this only scans back one line, since scanning back
    # arbitrary number of lines would be expensive.  If you have a type
    # that spans more than 2 lines, please use a typedef.
    if linenum > 1:
      previous = None
      if Match(r'\s*::(?:[\w<>]|::)+\s*&\s*\S', line):
        # previous_line\n + ::current_line
        previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+[\w<>])\s*$',
                          clean_lines.elided[linenum - 1])
      elif Match(r'\s*[a-zA-Z_]([\w<>]|::)+\s*&\s*\S', line):
        # previous_line::\n + current_line
        previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+::)\s*$',
                          clean_lines.elided[linenum - 1])
      if previous:
        line = previous.group(1) + line.lstrip()
      else:
        # Check for templated parameter that is split across multiple lines
        endpos = line.rfind('>')
        if endpos > -1:
          (_, startline, startpos) = ReverseCloseExpression(
              clean_lines, linenum, endpos)
          if startpos > -1 and startline < linenum:
            # Found the matching < on an earlier line, collect all
            # pieces up to current line.
            line = ''
            for i in xrange(startline, linenum + 1):
              line += clean_lines.elided[i].strip()
  
    # Check for non-const references in function parameters.  A single '&' may
    # found in the following places:
    #   inside expression: binary & for bitwise AND
    #   inside expression: unary & for taking the address of something
    #   inside declarators: reference parameter
    # We will exclude the first two cases by checking that we are not inside a
    # function body, including one that was just introduced by a trailing '{'.
    # TODO(unknwon): Doesn't account for preprocessor directives.
    # TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare].
    check_params = False
    if not nesting_state.stack:
      check_params = True  # top level
    elif (isinstance(nesting_state.stack[-1], _ClassInfo) or
          isinstance(nesting_state.stack[-1], _NamespaceInfo)):
      check_params = True  # within class or namespace
    elif Match(r'.*{\s*$', line):
      if (len(nesting_state.stack) == 1 or
          isinstance(nesting_state.stack[-2], _ClassInfo) or
          isinstance(nesting_state.stack[-2], _NamespaceInfo)):
        check_params = True  # just opened global/class/namespace block
    # We allow non-const references in a few standard places, like functions
    # called "swap()" or iostream operators like "<<" or ">>".  Do not check
    # those function parameters.
    #
    # We also accept & in static_assert, which looks like a function but
    # it's actually a declaration expression.
    whitelisted_functions = (r'(?:[sS]wap(?:<\w:+>)?|'
                             r'operator\s*[<>][<>]|'
                             r'static_assert|COMPILE_ASSERT'
                             r')\s*\(')
    if Search(whitelisted_functions, line):
      check_params = False
    elif not Search(r'\S+\([^)]*$', line):
      # Don't see a whitelisted function on this line.  Actually we
      # didn't see any function name on this line, so this is likely a
      # multi-line parameter list.  Try a bit harder to catch this case.
      for i in xrange(2):
        if (linenum > i and
            Search(whitelisted_functions, clean_lines.elided[linenum - i - 1])):
          check_params = False
          break
  
    if check_params:
      decls = ReplaceAll(r'{[^}]*}', ' ', line)  # exclude function body
      for parameter in re.findall(_RE_PATTERN_REF_PARAM, decls):
        if not Match(_RE_PATTERN_CONST_REF_PARAM, parameter):
          error(filename, linenum, 'runtime/references', 2,
                'Is this a non-const reference? '
                'If so, make const or use a pointer: ' +
                ReplaceAll(' *<', '<', parameter))
function_tokens: def CheckForNonConstReference ( filename , clean_lines , linenum , nesting_state , error ) : # Do nothing if there is no '&' on current line. line = clean_lines . elided [ linenum ] if '&' not in line : return # Long type names may be broken across multiple lines, usually in one # of these forms: #   LongType #       ::LongTypeContinued &identifier #   LongType:: #       LongTypeContinued &identifier #   LongType< #       ...>::LongTypeContinued &identifier # # If we detected a type split across two lines, join the previous # line to current line so that we can match const references # accordingly. # # Note that this only scans back one line, since scanning back # arbitrary number of lines would be expensive.  If you have a type # that spans more than 2 lines, please use a typedef. if linenum > 1 : previous = None if Match ( r'\s*::(?:[\w<>]|::)+\s*&\s*\S' , line ) : # previous_line\n + ::current_line previous = Search ( r'\b((?:const\s*)?(?:[\w<>]|::)+[\w<>])\s*$' , clean_lines . elided [ linenum - 1 ] ) elif Match ( r'\s*[a-zA-Z_]([\w<>]|::)+\s*&\s*\S' , line ) : # previous_line::\n + current_line previous = Search ( r'\b((?:const\s*)?(?:[\w<>]|::)+::)\s*$' , clean_lines . elided [ linenum - 1 ] ) if previous : line = previous . group ( 1 ) + line . lstrip ( ) else : # Check for templated parameter that is split across multiple lines endpos = line . rfind ( '>' ) if endpos > - 1 : ( _ , startline , startpos ) = ReverseCloseExpression ( clean_lines , linenum , endpos ) if startpos > - 1 and startline < linenum : # Found the matching < on an earlier line, collect all # pieces up to current line. line = '' for i in xrange ( startline , linenum + 1 ) : line += clean_lines . elided [ i ] . strip ( ) # Check for non-const references in function parameters.  A single '&' may # found in the following places: #   inside expression: binary & for bitwise AND #   inside expression: unary & for taking the address of something #   inside declarators: reference parameter # We will exclude the first two cases by checking that we are not inside a # function body, including one that was just introduced by a trailing '{'. # TODO(unknwon): Doesn't account for preprocessor directives. # TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare]. check_params = False if not nesting_state . stack : check_params = True # top level elif ( isinstance ( nesting_state . stack [ - 1 ] , _ClassInfo ) or isinstance ( nesting_state . stack [ - 1 ] , _NamespaceInfo ) ) : check_params = True # within class or namespace elif Match ( r'.*{\s*$' , line ) : if ( len ( nesting_state . stack ) == 1 or isinstance ( nesting_state . stack [ - 2 ] , _ClassInfo ) or isinstance ( nesting_state . stack [ - 2 ] , _NamespaceInfo ) ) : check_params = True # just opened global/class/namespace block # We allow non-const references in a few standard places, like functions # called "swap()" or iostream operators like "<<" or ">>".  Do not check # those function parameters. # # We also accept & in static_assert, which looks like a function but # it's actually a declaration expression. whitelisted_functions = ( r'(?:[sS]wap(?:<\w:+>)?|' r'operator\s*[<>][<>]|' r'static_assert|COMPILE_ASSERT' r')\s*\(' ) if Search ( whitelisted_functions , line ) : check_params = False elif not Search ( r'\S+\([^)]*$' , line ) : # Don't see a whitelisted function on this line.  Actually we # didn't see any function name on this line, so this is likely a # multi-line parameter list.  Try a bit harder to catch this case. for i in xrange ( 2 ) : if ( linenum > i and Search ( whitelisted_functions , clean_lines . elided [ linenum - i - 1 ] ) ) : check_params = False break if check_params : decls = ReplaceAll ( r'{[^}]*}' , ' ' , line ) # exclude function body for parameter in re . findall ( _RE_PATTERN_REF_PARAM , decls ) : if not Match ( _RE_PATTERN_CONST_REF_PARAM , parameter ) : error ( filename , linenum , 'runtime/references' , 2 , 'Is this a non-const reference? ' 'If so, make const or use a pointer: ' + ReplaceAll ( ' *<' , '<' , parameter ) )