parameters: (filename, clean_lines, linenum, nesting_state, error)
docstring: r"""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.
  
      Additionally, check for constructor/destructor style violations and reference
      members, as it is very convenient to do so while checking for
      gcc-2 compliance.
  
      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: A callable to which errors are reported, which takes 4 arguments:
               filename, line number, error level, and message
docstring_summary: r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
docstring_tokens: r Logs an error if we see certain non - ANSI constructs ignored by gcc - 2 .
function: def CheckForNonStandardConstructs(filename, clean_lines, linenum, nesting_state, error):
      r"""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.
  
      Additionally, check for constructor/destructor style violations and reference
      members, as it is very convenient to do so while checking for
      gcc-2 compliance.
  
      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: A callable to which errors are reported, which takes 4 arguments:
               filename, line number, error level, and message
      """
  
      # Remove comments from the line, but leave in strings for now.
      line = clean_lines.lines[linenum]
  
      if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line):
          error(
              filename,
              linenum,
              "runtime/printf_format",
              3,
              "%q in format strings is deprecated.  Use %ll instead.",
          )
  
      if Search(r'printf\s*\(.*".*%\d+\$', line):
          error(
              filename,
              linenum,
              "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(
              filename,
              linenum,
              "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[linenum]
  
      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+(register|static|extern|typedef)\b",
          line,
      ):
          error(
              filename,
              linenum,
              "build/storage_class",
              5,
              "Storage class (static, extern, typedef, etc) should be first.",
          )
  
      if Match(r"\s*#\s*endif\s*[^/\s]+", line):
          error(
              filename,
              linenum,
              "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(
              filename,
              linenum,
              "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(
              filename,
              linenum,
              "build/deprecated",
              3,
              ">? and <? (max and min) operators are non-standard and deprecated.",
          )
  
      if Search(r"^\s*const\s*string\s*&\s*\w+\s*;", line):
          # TODO(unknown): Could it be expanded safely to arbitrary references,
          # without triggering too many false positives? The first
          # attempt triggered 5 warnings for mostly benign code in the regtest, hence
          # the restriction.
          # Here's the original regexp, for the reference:
          # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?'
          # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;'
          error(
              filename,
              linenum,
              "runtime/member_string_references",
              2,
              "const string& members are dangerous. It is much better to use "
              "alternatives, such as pointers or simple constants.",
          )
  
      # Everything else in this function operates on class declarations.
      # Return early if the top of the nesting stack is not a class, or if
      # the class head is not completed yet.
      classinfo = nesting_state.InnermostClass()
      if not classinfo or not classinfo.seen_open_brace:
          return
  
      # 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. Also look for
      # non-single-argument constructors which are also technically valid, but
      # strongly suggest something is wrong.
      explicit_constructor_match = Match(
          r"\s+(?:inline\s+)?(explicit\s+)?(?:inline\s+)?%s\s*"
          r"\(((?:[^()]|\([^()]*\))*)\)" % re.escape(base_classname),
          line,
      )
  
      if explicit_constructor_match:
          is_marked_explicit = explicit_constructor_match.group(1)
  
          if not explicit_constructor_match.group(2):
              constructor_args = []
          else:
              constructor_args = explicit_constructor_match.group(2).split(",")
  
          # collapse arguments so that commas in template parameter lists and function
          # argument parameter lists don't split arguments in two
          i = 0
          while i < len(constructor_args):
              constructor_arg = constructor_args[i]
              while constructor_arg.count("<") > constructor_arg.count(
                  ">"
              ) or constructor_arg.count("(") > constructor_arg.count(")"):
                  constructor_arg += "," + constructor_args[i + 1]
                  del constructor_args[i + 1]
              constructor_args[i] = constructor_arg
              i += 1
  
          defaulted_args = [arg for arg in constructor_args if "=" in arg]
          noarg_constructor = (
              not constructor_args
              or  # empty arg list
              # 'void' arg specifier
              (len(constructor_args) == 1 and constructor_args[0].strip() == "void")
          )
          onearg_constructor = (
              (len(constructor_args) == 1 and not noarg_constructor)  # exactly one arg
              or
              # all but at most one arg defaulted
              (
                  len(constructor_args) >= 1
                  and not noarg_constructor
                  and len(defaulted_args) >= len(constructor_args) - 1
              )
          )
          initializer_list_constructor = bool(
              onearg_constructor
              and Search(r"\bstd\s*::\s*initializer_list\b", constructor_args[0])
          )
          copy_constructor = bool(
              onearg_constructor
              and Match(
                  r"(const\s+)?%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&"
                  % re.escape(base_classname),
                  constructor_args[0].strip(),
              )
          )
  
          if (
              not is_marked_explicit
              and onearg_constructor
              and not initializer_list_constructor
              and not copy_constructor
          ):
              if defaulted_args:
                  error(
                      filename,
                      linenum,
                      "runtime/explicit",
                      5,
                      "Constructors callable with one argument "
                      "should be marked explicit.",
                  )
              else:
                  error(
                      filename,
                      linenum,
                      "runtime/explicit",
                      5,
                      "Single-parameter constructors should be marked explicit.",
                  )
          elif is_marked_explicit and not onearg_constructor:
              if noarg_constructor:
                  error(
                      filename,
                      linenum,
                      "runtime/explicit",
                      5,
                      "Zero-parameter constructors should not be marked explicit.",
                  )
              else:
                  error(
                      filename,
                      linenum,
                      "runtime/explicit",
                      0,
                      "Constructors that require multiple arguments "
                      "should not be marked explicit.",
                  )
function_tokens: def CheckForNonStandardConstructs ( filename , clean_lines , linenum , nesting_state , error ) : # Remove comments from the line, but leave in strings for now. line = clean_lines . lines [ linenum ] if Search ( r'printf\s*\(.*".*%[-+ ]?\d*q' , line ) : error ( filename , linenum , "runtime/printf_format" , 3 , "%q in format strings is deprecated.  Use %ll instead." , ) if Search ( r'printf\s*\(.*".*%\d+\$' , line ) : error ( filename , linenum , "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 ( filename , linenum , "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 [ linenum ] 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+(register|static|extern|typedef)\b" , line , ) : error ( filename , linenum , "build/storage_class" , 5 , "Storage class (static, extern, typedef, etc) should be first." , ) if Match ( r"\s*#\s*endif\s*[^/\s]+" , line ) : error ( filename , linenum , "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 ( filename , linenum , "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 ( filename , linenum , "build/deprecated" , 3 , ">? and <? (max and min) operators are non-standard and deprecated." , ) if Search ( r"^\s*const\s*string\s*&\s*\w+\s*;" , line ) : # TODO(unknown): Could it be expanded safely to arbitrary references, # without triggering too many false positives? The first # attempt triggered 5 warnings for mostly benign code in the regtest, hence # the restriction. # Here's the original regexp, for the reference: # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?' # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;' error ( filename , linenum , "runtime/member_string_references" , 2 , "const string& members are dangerous. It is much better to use " "alternatives, such as pointers or simple constants." , ) # Everything else in this function operates on class declarations. # Return early if the top of the nesting stack is not a class, or if # the class head is not completed yet. classinfo = nesting_state . InnermostClass ( ) if not classinfo or not classinfo . seen_open_brace : return # 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. Also look for # non-single-argument constructors which are also technically valid, but # strongly suggest something is wrong. explicit_constructor_match = Match ( r"\s+(?:inline\s+)?(explicit\s+)?(?:inline\s+)?%s\s*" r"\(((?:[^()]|\([^()]*\))*)\)" % re . escape ( base_classname ) , line , ) if explicit_constructor_match : is_marked_explicit = explicit_constructor_match . group ( 1 ) if not explicit_constructor_match . group ( 2 ) : constructor_args = [ ] else : constructor_args = explicit_constructor_match . group ( 2 ) . split ( "," ) # collapse arguments so that commas in template parameter lists and function # argument parameter lists don't split arguments in two i = 0 while i < len ( constructor_args ) : constructor_arg = constructor_args [ i ] while constructor_arg . count ( "<" ) > constructor_arg . count ( ">" ) or constructor_arg . count ( "(" ) > constructor_arg . count ( ")" ) : constructor_arg += "," + constructor_args [ i + 1 ] del constructor_args [ i + 1 ] constructor_args [ i ] = constructor_arg i += 1 defaulted_args = [ arg for arg in constructor_args if "=" in arg ] noarg_constructor = ( not constructor_args or # empty arg list # 'void' arg specifier ( len ( constructor_args ) == 1 and constructor_args [ 0 ] . strip ( ) == "void" ) ) onearg_constructor = ( ( len ( constructor_args ) == 1 and not noarg_constructor ) # exactly one arg or # all but at most one arg defaulted ( len ( constructor_args ) >= 1 and not noarg_constructor and len ( defaulted_args ) >= len ( constructor_args ) - 1 ) ) initializer_list_constructor = bool ( onearg_constructor and Search ( r"\bstd\s*::\s*initializer_list\b" , constructor_args [ 0 ] ) ) copy_constructor = bool ( onearg_constructor and Match ( r"(const\s+)?%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&" % re . escape ( base_classname ) , constructor_args [ 0 ] . strip ( ) , ) ) if ( not is_marked_explicit and onearg_constructor and not initializer_list_constructor and not copy_constructor ) : if defaulted_args : error ( filename , linenum , "runtime/explicit" , 5 , "Constructors callable with one argument " "should be marked explicit." , ) else : error ( filename , linenum , "runtime/explicit" , 5 , "Single-parameter constructors should be marked explicit." , ) elif is_marked_explicit and not onearg_constructor : if noarg_constructor : error ( filename , linenum , "runtime/explicit" , 5 , "Zero-parameter constructors should not be marked explicit." , ) else : error ( filename , linenum , "runtime/explicit" , 0 , "Constructors that require multiple arguments " "should not be marked explicit." , )