parameters: (clean_lines, line_number,
                                        class_state, error)
docstring: Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
  
      Complain about several constructs which gcc-2 accepts, but which are
      not standard C++.  Warning about these in lint is one way to ease the
      transition to new compilers.
      - put storage class first (e.g. "static const" instead of "const static").
      - "%lld" instead of %qd" in printf-type functions.
      - "%1$d" is non-standard in printf-type functions.
      - "\%" is an undefined character escape sequence.
      - text after #endif is not allowed.
      - invalid inner-style forward declaration.
      - >? and <? operators, and their >?= and <?= cousins.
      - classes with virtual methods need virtual destructors (compiler warning
          available, but not turned on yet.)
  
      Additionally, check for constructor/destructor style violations as it
      is very convenient to do so while checking for gcc-2 compliance.
  
      Args:
        clean_lines: A CleansedLines instance containing the file.
        line_number: The number of the line to check.
        class_state: A _ClassState instance which maintains information about
                     the current stack of nested class declarations being parsed.
        error: A callable to which errors are reported, which takes parameters:
               line number, error level, and message
docstring_summary: Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
docstring_tokens: Logs an error if we see certain non - ANSI constructs ignored by gcc - 2 .
function: def check_for_non_standard_constructs(clean_lines, line_number,
                                        class_state, error):
      """Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
  
      Complain about several constructs which gcc-2 accepts, but which are
      not standard C++.  Warning about these in lint is one way to ease the
      transition to new compilers.
      - put storage class first (e.g. "static const" instead of "const static").
      - "%lld" instead of %qd" in printf-type functions.
      - "%1$d" is non-standard in printf-type functions.
      - "\%" is an undefined character escape sequence.
      - text after #endif is not allowed.
      - invalid inner-style forward declaration.
      - >? and <? operators, and their >?= and <?= cousins.
      - classes with virtual methods need virtual destructors (compiler warning
          available, but not turned on yet.)
  
      Additionally, check for constructor/destructor style violations as it
      is very convenient to do so while checking for gcc-2 compliance.
  
      Args:
        clean_lines: A CleansedLines instance containing the file.
        line_number: The number of the line to check.
        class_state: A _ClassState instance which maintains information about
                     the current stack of nested class declarations being parsed.
        error: A callable to which errors are reported, which takes parameters:
               line number, error level, and message
      """
  
      # Remove comments from the line, but leave in strings for now.
      line = clean_lines.lines[line_number]
  
      if search(r'printf\s*\(.*".*%[-+ ]?\d*q', line):
          error(line_number, 'runtime/printf_format', 3,
                '%q in format strings is deprecated.  Use %ll instead.')
  
      if search(r'printf\s*\(.*".*%\d+\$', line):
          error(line_number, 'runtime/printf_format', 2,
                '%N$ formats are unconventional.  Try rewriting to avoid them.')
  
      # Remove escaped backslashes before looking for undefined escapes.
      line = line.replace('\\\\', '')
  
      if search(r'("|\').*\\(%|\[|\(|{)', line):
          error(line_number, 'build/printf_format', 3,
                '%, [, (, and { are undefined character escapes.  Unescape them.')
  
      # For the rest, work with both comments and strings removed.
      line = clean_lines.elided[line_number]
  
      if search(r'\b(const|volatile|void|char|short|int|long'
                r'|float|double|signed|unsigned'
                r'|schar|u?int8|u?int16|u?int32|u?int64)'
                r'\s+(auto|register|static|extern|typedef)\b',
                line):
          error(line_number, 'build/storage_class', 5,
                'Storage class (static, extern, typedef, etc) should be first.')
  
      if match(r'\s*#\s*endif\s*[^/\s]+', line):
          error(line_number, 'build/endif_comment', 5,
                'Uncommented text after #endif is non-standard.  Use a comment.')
  
      if match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line):
          error(line_number, 'build/forward_decl', 5,
                'Inner-style forward declarations are invalid.  Remove this line.')
  
      if search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', line):
          error(line_number, 'build/deprecated', 3,
                '>? and <? (max and min) operators are non-standard and deprecated.')
  
      # Track class entry and exit, and attempt to find cases within the
      # class declaration that don't meet the C++ style
      # guidelines. Tracking is very dependent on the code matching Google
      # style guidelines, but it seems to perform well enough in testing
      # to be a worthwhile addition to the checks.
      classinfo_stack = class_state.classinfo_stack
      # Look for a class declaration
      class_decl_match = match(
          r'\s*(template\s*<[\w\s<>,:]*>\s*)?(class|struct)\s+(\w+(::\w+)*)', line)
      if class_decl_match:
          classinfo_stack.append(_ClassInfo(class_decl_match.group(3), line_number))
  
      # Everything else in this function uses the top of the stack if it's
      # not empty.
      if not classinfo_stack:
          return
  
      classinfo = classinfo_stack[-1]
  
      # If the opening brace hasn't been seen look for it and also
      # parent class declarations.
      if not classinfo.seen_open_brace:
          # If the line has a ';' in it, assume it's a forward declaration or
          # a single-line class declaration, which we won't process.
          if line.find(';') != -1:
              classinfo_stack.pop()
              return
          classinfo.seen_open_brace = (line.find('{') != -1)
          # Look for a bare ':'
          if search('(^|[^:]):($|[^:])', line):
              classinfo.is_derived = True
          if not classinfo.seen_open_brace:
              return  # Everything else in this function is for after open brace
  
      # The class may have been declared with namespace or classname qualifiers.
      # The constructor and destructor will not have those qualifiers.
      base_classname = classinfo.name.split('::')[-1]
  
      # Look for single-argument constructors that aren't marked explicit.
      # Technically a valid construct, but against style.
      args = match(r'(?<!explicit)\s+%s\s*\(([^,()]+)\)'
                   % re.escape(base_classname),
                   line)
      if (args
          and args.group(1) != 'void'
          and not match(r'(const\s+)?%s\s*&' % re.escape(base_classname),
                        args.group(1).strip())):
          error(line_number, 'runtime/explicit', 5,
                'Single-argument constructors should be marked explicit.')
  
      # Look for methods declared virtual.
      if search(r'\bvirtual\b', line):
          classinfo.virtual_method_line_number = line_number
          # Only look for a destructor declaration on the same line. It would
          # be extremely unlikely for the destructor declaration to occupy
          # more than one line.
          if search(r'~%s\s*\(' % base_classname, line):
              classinfo.has_virtual_destructor = True
  
      # Look for class end.
      brace_depth = classinfo.brace_depth
      brace_depth = brace_depth + line.count('{') - line.count('}')
      if brace_depth <= 0:
          classinfo = classinfo_stack.pop()
          # Try to detect missing virtual destructor declarations.
          # For now, only warn if a non-derived class with virtual methods lacks
          # a virtual destructor. This is to make it less likely that people will
          # declare derived virtual destructors without declaring the base
          # destructor virtual.
          if ((classinfo.virtual_method_line_number is not None)
              and (not classinfo.has_virtual_destructor)
              and (not classinfo.is_derived)):  # Only warn for base classes
              error(classinfo.line_number, 'runtime/virtual', 4,
                    'The class %s probably needs a virtual destructor due to '
                    'having virtual method(s), one declared at line %d.'
                    % (classinfo.name, classinfo.virtual_method_line_number))
      else:
          classinfo.brace_depth = brace_depth
function_tokens: def check_for_non_standard_constructs ( clean_lines , line_number , class_state , error ) : # Remove comments from the line, but leave in strings for now. line = clean_lines . lines [ line_number ] if search ( r'printf\s*\(.*".*%[-+ ]?\d*q' , line ) : error ( line_number , 'runtime/printf_format' , 3 , '%q in format strings is deprecated.  Use %ll instead.' ) if search ( r'printf\s*\(.*".*%\d+\$' , line ) : error ( line_number , 'runtime/printf_format' , 2 , '%N$ formats are unconventional.  Try rewriting to avoid them.' ) # Remove escaped backslashes before looking for undefined escapes. line = line . replace ( '\\\\' , '' ) if search ( r'("|\').*\\(%|\[|\(|{)' , line ) : error ( line_number , 'build/printf_format' , 3 , '%, [, (, and { are undefined character escapes.  Unescape them.' ) # For the rest, work with both comments and strings removed. line = clean_lines . elided [ line_number ] if search ( r'\b(const|volatile|void|char|short|int|long' r'|float|double|signed|unsigned' r'|schar|u?int8|u?int16|u?int32|u?int64)' r'\s+(auto|register|static|extern|typedef)\b' , line ) : error ( line_number , 'build/storage_class' , 5 , 'Storage class (static, extern, typedef, etc) should be first.' ) if match ( r'\s*#\s*endif\s*[^/\s]+' , line ) : error ( line_number , 'build/endif_comment' , 5 , 'Uncommented text after #endif is non-standard.  Use a comment.' ) if match ( r'\s*class\s+(\w+\s*::\s*)+\w+\s*;' , line ) : error ( line_number , 'build/forward_decl' , 5 , 'Inner-style forward declarations are invalid.  Remove this line.' ) if search ( r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?' , line ) : error ( line_number , 'build/deprecated' , 3 , '>? and <? (max and min) operators are non-standard and deprecated.' ) # Track class entry and exit, and attempt to find cases within the # class declaration that don't meet the C++ style # guidelines. Tracking is very dependent on the code matching Google # style guidelines, but it seems to perform well enough in testing # to be a worthwhile addition to the checks. classinfo_stack = class_state . classinfo_stack # Look for a class declaration class_decl_match = match ( r'\s*(template\s*<[\w\s<>,:]*>\s*)?(class|struct)\s+(\w+(::\w+)*)' , line ) if class_decl_match : classinfo_stack . append ( _ClassInfo ( class_decl_match . group ( 3 ) , line_number ) ) # Everything else in this function uses the top of the stack if it's # not empty. if not classinfo_stack : return classinfo = classinfo_stack [ - 1 ] # If the opening brace hasn't been seen look for it and also # parent class declarations. if not classinfo . seen_open_brace : # If the line has a ';' in it, assume it's a forward declaration or # a single-line class declaration, which we won't process. if line . find ( ';' ) != - 1 : classinfo_stack . pop ( ) return classinfo . seen_open_brace = ( line . find ( '{' ) != - 1 ) # Look for a bare ':' if search ( '(^|[^:]):($|[^:])' , line ) : classinfo . is_derived = True if not classinfo . seen_open_brace : return # Everything else in this function is for after open brace # The class may have been declared with namespace or classname qualifiers. # The constructor and destructor will not have those qualifiers. base_classname = classinfo . name . split ( '::' ) [ - 1 ] # Look for single-argument constructors that aren't marked explicit. # Technically a valid construct, but against style. args = match ( r'(?<!explicit)\s+%s\s*\(([^,()]+)\)' % re . escape ( base_classname ) , line ) if ( args and args . group ( 1 ) != 'void' and not match ( r'(const\s+)?%s\s*&' % re . escape ( base_classname ) , args . group ( 1 ) . strip ( ) ) ) : error ( line_number , 'runtime/explicit' , 5 , 'Single-argument constructors should be marked explicit.' ) # Look for methods declared virtual. if search ( r'\bvirtual\b' , line ) : classinfo . virtual_method_line_number = line_number # Only look for a destructor declaration on the same line. It would # be extremely unlikely for the destructor declaration to occupy # more than one line. if search ( r'~%s\s*\(' % base_classname , line ) : classinfo . has_virtual_destructor = True # Look for class end. brace_depth = classinfo . brace_depth brace_depth = brace_depth + line . count ( '{' ) - line . count ( '}' ) if brace_depth <= 0 : classinfo = classinfo_stack . pop ( ) # Try to detect missing virtual destructor declarations. # For now, only warn if a non-derived class with virtual methods lacks # a virtual destructor. This is to make it less likely that people will # declare derived virtual destructors without declaring the base # destructor virtual. if ( ( classinfo . virtual_method_line_number is not None ) and ( not classinfo . has_virtual_destructor ) and ( not classinfo . is_derived ) ) : # Only warn for base classes error ( classinfo . line_number , 'runtime/virtual' , 4 , 'The class %s probably needs a virtual destructor due to ' 'having virtual method(s), one declared at line %d.' % ( classinfo . name , classinfo . virtual_method_line_number ) ) else : classinfo . brace_depth = brace_depth