@@ 4837-4993 (lines=157) @@ | ||
4834 | r'(?:.*stream\s*&\s*' + _RE_PATTERN_IDENT + r')') |
|
4835 | ||
4836 | ||
4837 | def CheckLanguage(filename, clean_lines, linenum, file_extension, |
|
4838 | include_state, nesting_state, error): |
|
4839 | """Checks rules from the 'C++ language rules' section of cppguide.html. |
|
4840 | ||
4841 | Some of these rules are hard to test (function overloading, using |
|
4842 | uint32 inappropriately), but we do the best we can. |
|
4843 | ||
4844 | Args: |
|
4845 | filename: The name of the current file. |
|
4846 | clean_lines: A CleansedLines instance containing the file. |
|
4847 | linenum: The number of the line to check. |
|
4848 | file_extension: The extension (without the dot) of the filename. |
|
4849 | include_state: An _IncludeState instance in which the headers are inserted. |
|
4850 | nesting_state: A NestingState instance which maintains information about |
|
4851 | the current stack of nested blocks being parsed. |
|
4852 | error: The function to call with any errors found. |
|
4853 | """ |
|
4854 | # If the line is empty or consists of entirely a comment, no need to |
|
4855 | # check it. |
|
4856 | line = clean_lines.elided[linenum] |
|
4857 | if not line: |
|
4858 | return |
|
4859 | ||
4860 | match = _RE_PATTERN_INCLUDE.search(line) |
|
4861 | if match: |
|
4862 | CheckIncludeLine(filename, clean_lines, linenum, include_state, error) |
|
4863 | return |
|
4864 | ||
4865 | # Reset include state across preprocessor directives. This is meant |
|
4866 | # to silence warnings for conditional includes. |
|
4867 | match = Match(r'^\s*#\s*(if|ifdef|ifndef|elif|else|endif)\b', line) |
|
4868 | if match: |
|
4869 | include_state.ResetSection(match.group(1)) |
|
4870 | ||
4871 | ||
4872 | # Perform other checks now that we are sure that this is not an include line |
|
4873 | CheckCasts(filename, clean_lines, linenum, error) |
|
4874 | CheckGlobalStatic(filename, clean_lines, linenum, error) |
|
4875 | CheckPrintf(filename, clean_lines, linenum, error) |
|
4876 | ||
4877 | if file_extension in GetHeaderExtensions(): |
|
4878 | # TODO(unknown): check that 1-arg constructors are explicit. |
|
4879 | # How to tell it's a constructor? |
|
4880 | # (handled in CheckForNonStandardConstructs for now) |
|
4881 | # TODO(unknown): check that classes declare or disable copy/assign |
|
4882 | # (level 1 error) |
|
4883 | pass |
|
4884 | ||
4885 | # Check if people are using the verboten C basic types. The only exception |
|
4886 | # we regularly allow is "unsigned short port" for port. |
|
4887 | if Search(r'\bshort port\b', line): |
|
4888 | if not Search(r'\bunsigned short port\b', line): |
|
4889 | error(filename, linenum, 'runtime/int', 4, |
|
4890 | 'Use "unsigned short" for ports, not "short"') |
|
4891 | else: |
|
4892 | match = Search(r'\b(short|long(?! +double)|long long)\b', line) |
|
4893 | if match: |
|
4894 | error(filename, linenum, 'runtime/int', 4, |
|
4895 | 'Use int16/int64/etc, rather than the C type %s' % match.group(1)) |
|
4896 | ||
4897 | # Check if some verboten operator overloading is going on |
|
4898 | # TODO(unknown): catch out-of-line unary operator&: |
|
4899 | # class X {}; |
|
4900 | # int operator&(const X& x) { return 42; } // unary operator& |
|
4901 | # The trick is it's hard to tell apart from binary operator&: |
|
4902 | # class Y { int operator&(const Y& x) { return 23; } }; // binary operator& |
|
4903 | if Search(r'\boperator\s*&\s*\(\s*\)', line): |
|
4904 | error(filename, linenum, 'runtime/operator', 4, |
|
4905 | 'Unary operator& is dangerous. Do not use it.') |
|
4906 | ||
4907 | # Check for suspicious usage of "if" like |
|
4908 | # } if (a == b) { |
|
4909 | if Search(r'\}\s*if\s*\(', line): |
|
4910 | error(filename, linenum, 'readability/braces', 4, |
|
4911 | 'Did you mean "else if"? If not, start a new line for "if".') |
|
4912 | ||
4913 | # Check for potential format string bugs like printf(foo). |
|
4914 | # We constrain the pattern not to pick things like DocidForPrintf(foo). |
|
4915 | # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str()) |
|
4916 | # TODO(unknown): Catch the following case. Need to change the calling |
|
4917 | # convention of the whole function to process multiple line to handle it. |
|
4918 | # printf( |
|
4919 | # boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line); |
|
4920 | printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(') |
|
4921 | if printf_args: |
|
4922 | match = Match(r'([\w.\->()]+)$', printf_args) |
|
4923 | if match and match.group(1) != '__VA_ARGS__': |
|
4924 | function_name = re.search(r'\b((?:string)?printf)\s*\(', |
|
4925 | line, re.I).group(1) |
|
4926 | error(filename, linenum, 'runtime/printf', 4, |
|
4927 | 'Potential format string bug. Do %s("%%s", %s) instead.' |
|
4928 | % (function_name, match.group(1))) |
|
4929 | ||
4930 | # Check for potential memset bugs like memset(buf, sizeof(buf), 0). |
|
4931 | match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line) |
|
4932 | if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)): |
|
4933 | error(filename, linenum, 'runtime/memset', 4, |
|
4934 | 'Did you mean "memset(%s, 0, %s)"?' |
|
4935 | % (match.group(1), match.group(2))) |
|
4936 | ||
4937 | if Search(r'\busing namespace\b', line): |
|
4938 | if Search(r'\bliterals\b', line): |
|
4939 | error(filename, linenum, 'build/namespaces_literals', 5, |
|
4940 | 'Do not use namespace using-directives. ' |
|
4941 | 'Use using-declarations instead.') |
|
4942 | else: |
|
4943 | error(filename, linenum, 'build/namespaces', 5, |
|
4944 | 'Do not use namespace using-directives. ' |
|
4945 | 'Use using-declarations instead.') |
|
4946 | ||
4947 | # Detect variable-length arrays. |
|
4948 | match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line) |
|
4949 | if (match and match.group(2) != 'return' and match.group(2) != 'delete' and |
|
4950 | match.group(3).find(']') == -1): |
|
4951 | # Split the size using space and arithmetic operators as delimiters. |
|
4952 | # If any of the resulting tokens are not compile time constants then |
|
4953 | # report the error. |
|
4954 | tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3)) |
|
4955 | is_const = True |
|
4956 | skip_next = False |
|
4957 | for tok in tokens: |
|
4958 | if skip_next: |
|
4959 | skip_next = False |
|
4960 | continue |
|
4961 | ||
4962 | if Search(r'sizeof\(.+\)', tok): continue |
|
4963 | if Search(r'arraysize\(\w+\)', tok): continue |
|
4964 | ||
4965 | tok = tok.lstrip('(') |
|
4966 | tok = tok.rstrip(')') |
|
4967 | if not tok: continue |
|
4968 | if Match(r'\d+', tok): continue |
|
4969 | if Match(r'0[xX][0-9a-fA-F]+', tok): continue |
|
4970 | if Match(r'k[A-Z0-9]\w*', tok): continue |
|
4971 | if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue |
|
4972 | if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue |
|
4973 | # A catch all for tricky sizeof cases, including 'sizeof expression', |
|
4974 | # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)' |
|
4975 | # requires skipping the next token because we split on ' ' and '*'. |
|
4976 | if tok.startswith('sizeof'): |
|
4977 | skip_next = True |
|
4978 | continue |
|
4979 | is_const = False |
|
4980 | break |
|
4981 | if not is_const: |
|
4982 | error(filename, linenum, 'runtime/arrays', 1, |
|
4983 | 'Do not use variable-length arrays. Use an appropriately named ' |
|
4984 | "('k' followed by CamelCase) compile-time constant for the size.") |
|
4985 | ||
4986 | # Check for use of unnamed namespaces in header files. Registration |
|
4987 | # macros are typically OK, so we allow use of "namespace {" on lines |
|
4988 | # that end with backslashes. |
|
4989 | if (file_extension in GetHeaderExtensions() |
|
4990 | and Search(r'\bnamespace\s*{', line) |
|
4991 | and line[-1] != '\\'): |
|
4992 | error(filename, linenum, 'build/namespaces', 4, |
|
4993 | 'Do not use unnamed namespaces in header files. See ' |
|
4994 | 'https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces' |
|
4995 | ' for more information.') |
|
4996 |
@@ 4837-4993 (lines=157) @@ | ||
4834 | r'(?:.*stream\s*&\s*' + _RE_PATTERN_IDENT + r')') |
|
4835 | ||
4836 | ||
4837 | def CheckLanguage(filename, clean_lines, linenum, file_extension, |
|
4838 | include_state, nesting_state, error): |
|
4839 | """Checks rules from the 'C++ language rules' section of cppguide.html. |
|
4840 | ||
4841 | Some of these rules are hard to test (function overloading, using |
|
4842 | uint32 inappropriately), but we do the best we can. |
|
4843 | ||
4844 | Args: |
|
4845 | filename: The name of the current file. |
|
4846 | clean_lines: A CleansedLines instance containing the file. |
|
4847 | linenum: The number of the line to check. |
|
4848 | file_extension: The extension (without the dot) of the filename. |
|
4849 | include_state: An _IncludeState instance in which the headers are inserted. |
|
4850 | nesting_state: A NestingState instance which maintains information about |
|
4851 | the current stack of nested blocks being parsed. |
|
4852 | error: The function to call with any errors found. |
|
4853 | """ |
|
4854 | # If the line is empty or consists of entirely a comment, no need to |
|
4855 | # check it. |
|
4856 | line = clean_lines.elided[linenum] |
|
4857 | if not line: |
|
4858 | return |
|
4859 | ||
4860 | match = _RE_PATTERN_INCLUDE.search(line) |
|
4861 | if match: |
|
4862 | CheckIncludeLine(filename, clean_lines, linenum, include_state, error) |
|
4863 | return |
|
4864 | ||
4865 | # Reset include state across preprocessor directives. This is meant |
|
4866 | # to silence warnings for conditional includes. |
|
4867 | match = Match(r'^\s*#\s*(if|ifdef|ifndef|elif|else|endif)\b', line) |
|
4868 | if match: |
|
4869 | include_state.ResetSection(match.group(1)) |
|
4870 | ||
4871 | ||
4872 | # Perform other checks now that we are sure that this is not an include line |
|
4873 | CheckCasts(filename, clean_lines, linenum, error) |
|
4874 | CheckGlobalStatic(filename, clean_lines, linenum, error) |
|
4875 | CheckPrintf(filename, clean_lines, linenum, error) |
|
4876 | ||
4877 | if file_extension in GetHeaderExtensions(): |
|
4878 | # TODO(unknown): check that 1-arg constructors are explicit. |
|
4879 | # How to tell it's a constructor? |
|
4880 | # (handled in CheckForNonStandardConstructs for now) |
|
4881 | # TODO(unknown): check that classes declare or disable copy/assign |
|
4882 | # (level 1 error) |
|
4883 | pass |
|
4884 | ||
4885 | # Check if people are using the verboten C basic types. The only exception |
|
4886 | # we regularly allow is "unsigned short port" for port. |
|
4887 | if Search(r'\bshort port\b', line): |
|
4888 | if not Search(r'\bunsigned short port\b', line): |
|
4889 | error(filename, linenum, 'runtime/int', 4, |
|
4890 | 'Use "unsigned short" for ports, not "short"') |
|
4891 | else: |
|
4892 | match = Search(r'\b(short|long(?! +double)|long long)\b', line) |
|
4893 | if match: |
|
4894 | error(filename, linenum, 'runtime/int', 4, |
|
4895 | 'Use int16/int64/etc, rather than the C type %s' % match.group(1)) |
|
4896 | ||
4897 | # Check if some verboten operator overloading is going on |
|
4898 | # TODO(unknown): catch out-of-line unary operator&: |
|
4899 | # class X {}; |
|
4900 | # int operator&(const X& x) { return 42; } // unary operator& |
|
4901 | # The trick is it's hard to tell apart from binary operator&: |
|
4902 | # class Y { int operator&(const Y& x) { return 23; } }; // binary operator& |
|
4903 | if Search(r'\boperator\s*&\s*\(\s*\)', line): |
|
4904 | error(filename, linenum, 'runtime/operator', 4, |
|
4905 | 'Unary operator& is dangerous. Do not use it.') |
|
4906 | ||
4907 | # Check for suspicious usage of "if" like |
|
4908 | # } if (a == b) { |
|
4909 | if Search(r'\}\s*if\s*\(', line): |
|
4910 | error(filename, linenum, 'readability/braces', 4, |
|
4911 | 'Did you mean "else if"? If not, start a new line for "if".') |
|
4912 | ||
4913 | # Check for potential format string bugs like printf(foo). |
|
4914 | # We constrain the pattern not to pick things like DocidForPrintf(foo). |
|
4915 | # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str()) |
|
4916 | # TODO(unknown): Catch the following case. Need to change the calling |
|
4917 | # convention of the whole function to process multiple line to handle it. |
|
4918 | # printf( |
|
4919 | # boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line); |
|
4920 | printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(') |
|
4921 | if printf_args: |
|
4922 | match = Match(r'([\w.\->()]+)$', printf_args) |
|
4923 | if match and match.group(1) != '__VA_ARGS__': |
|
4924 | function_name = re.search(r'\b((?:string)?printf)\s*\(', |
|
4925 | line, re.I).group(1) |
|
4926 | error(filename, linenum, 'runtime/printf', 4, |
|
4927 | 'Potential format string bug. Do %s("%%s", %s) instead.' |
|
4928 | % (function_name, match.group(1))) |
|
4929 | ||
4930 | # Check for potential memset bugs like memset(buf, sizeof(buf), 0). |
|
4931 | match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line) |
|
4932 | if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)): |
|
4933 | error(filename, linenum, 'runtime/memset', 4, |
|
4934 | 'Did you mean "memset(%s, 0, %s)"?' |
|
4935 | % (match.group(1), match.group(2))) |
|
4936 | ||
4937 | if Search(r'\busing namespace\b', line): |
|
4938 | if Search(r'\bliterals\b', line): |
|
4939 | error(filename, linenum, 'build/namespaces_literals', 5, |
|
4940 | 'Do not use namespace using-directives. ' |
|
4941 | 'Use using-declarations instead.') |
|
4942 | else: |
|
4943 | error(filename, linenum, 'build/namespaces', 5, |
|
4944 | 'Do not use namespace using-directives. ' |
|
4945 | 'Use using-declarations instead.') |
|
4946 | ||
4947 | # Detect variable-length arrays. |
|
4948 | match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line) |
|
4949 | if (match and match.group(2) != 'return' and match.group(2) != 'delete' and |
|
4950 | match.group(3).find(']') == -1): |
|
4951 | # Split the size using space and arithmetic operators as delimiters. |
|
4952 | # If any of the resulting tokens are not compile time constants then |
|
4953 | # report the error. |
|
4954 | tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3)) |
|
4955 | is_const = True |
|
4956 | skip_next = False |
|
4957 | for tok in tokens: |
|
4958 | if skip_next: |
|
4959 | skip_next = False |
|
4960 | continue |
|
4961 | ||
4962 | if Search(r'sizeof\(.+\)', tok): continue |
|
4963 | if Search(r'arraysize\(\w+\)', tok): continue |
|
4964 | ||
4965 | tok = tok.lstrip('(') |
|
4966 | tok = tok.rstrip(')') |
|
4967 | if not tok: continue |
|
4968 | if Match(r'\d+', tok): continue |
|
4969 | if Match(r'0[xX][0-9a-fA-F]+', tok): continue |
|
4970 | if Match(r'k[A-Z0-9]\w*', tok): continue |
|
4971 | if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue |
|
4972 | if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue |
|
4973 | # A catch all for tricky sizeof cases, including 'sizeof expression', |
|
4974 | # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)' |
|
4975 | # requires skipping the next token because we split on ' ' and '*'. |
|
4976 | if tok.startswith('sizeof'): |
|
4977 | skip_next = True |
|
4978 | continue |
|
4979 | is_const = False |
|
4980 | break |
|
4981 | if not is_const: |
|
4982 | error(filename, linenum, 'runtime/arrays', 1, |
|
4983 | 'Do not use variable-length arrays. Use an appropriately named ' |
|
4984 | "('k' followed by CamelCase) compile-time constant for the size.") |
|
4985 | ||
4986 | # Check for use of unnamed namespaces in header files. Registration |
|
4987 | # macros are typically OK, so we allow use of "namespace {" on lines |
|
4988 | # that end with backslashes. |
|
4989 | if (file_extension in GetHeaderExtensions() |
|
4990 | and Search(r'\bnamespace\s*{', line) |
|
4991 | and line[-1] != '\\'): |
|
4992 | error(filename, linenum, 'build/namespaces', 4, |
|
4993 | 'Do not use unnamed namespaces in header files. See ' |
|
4994 | 'https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces' |
|
4995 | ' for more information.') |
|
4996 |