| @@ 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 | ||