| @@ 2888-3048 (lines=161) @@ | ||
| 2885 | obj.name) |
|
| 2886 | ||
| 2887 | ||
| 2888 | def CheckForNonStandardConstructs(filename, clean_lines, linenum, |
|
| 2889 | nesting_state, error): |
|
| 2890 | r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2. |
|
| 2891 | ||
| 2892 | Complain about several constructs which gcc-2 accepts, but which are |
|
| 2893 | not standard C++. Warning about these in lint is one way to ease the |
|
| 2894 | transition to new compilers. |
|
| 2895 | - put storage class first (e.g. "static const" instead of "const static"). |
|
| 2896 | - "%lld" instead of %qd" in printf-type functions. |
|
| 2897 | - "%1$d" is non-standard in printf-type functions. |
|
| 2898 | - "\%" is an undefined character escape sequence. |
|
| 2899 | - text after #endif is not allowed. |
|
| 2900 | - invalid inner-style forward declaration. |
|
| 2901 | - >? and <? operators, and their >?= and <?= cousins. |
|
| 2902 | ||
| 2903 | Additionally, check for constructor/destructor style violations and reference |
|
| 2904 | members, as it is very convenient to do so while checking for |
|
| 2905 | gcc-2 compliance. |
|
| 2906 | ||
| 2907 | Args: |
|
| 2908 | filename: The name of the current file. |
|
| 2909 | clean_lines: A CleansedLines instance containing the file. |
|
| 2910 | linenum: The number of the line to check. |
|
| 2911 | nesting_state: A NestingState instance which maintains information about |
|
| 2912 | the current stack of nested blocks being parsed. |
|
| 2913 | error: A callable to which errors are reported, which takes 4 arguments: |
|
| 2914 | filename, line number, error level, and message |
|
| 2915 | """ |
|
| 2916 | ||
| 2917 | # Remove comments from the line, but leave in strings for now. |
|
| 2918 | line = clean_lines.lines[linenum] |
|
| 2919 | ||
| 2920 | if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line): |
|
| 2921 | error(filename, linenum, 'runtime/printf_format', 3, |
|
| 2922 | '%q in format strings is deprecated. Use %ll instead.') |
|
| 2923 | ||
| 2924 | if Search(r'printf\s*\(.*".*%\d+\$', line): |
|
| 2925 | error(filename, linenum, 'runtime/printf_format', 2, |
|
| 2926 | '%N$ formats are unconventional. Try rewriting to avoid them.') |
|
| 2927 | ||
| 2928 | # Remove escaped backslashes before looking for undefined escapes. |
|
| 2929 | line = line.replace('\\\\', '') |
|
| 2930 | ||
| 2931 | if Search(r'("|\').*\\(%|\[|\(|{)', line): |
|
| 2932 | error(filename, linenum, 'build/printf_format', 3, |
|
| 2933 | '%, [, (, and { are undefined character escapes. Unescape them.') |
|
| 2934 | ||
| 2935 | # For the rest, work with both comments and strings removed. |
|
| 2936 | line = clean_lines.elided[linenum] |
|
| 2937 | ||
| 2938 | if Search(r'\b(const|volatile|void|char|short|int|long' |
|
| 2939 | r'|float|double|signed|unsigned' |
|
| 2940 | r'|schar|u?int8|u?int16|u?int32|u?int64)' |
|
| 2941 | r'\s+(register|static|extern|typedef)\b', |
|
| 2942 | line): |
|
| 2943 | error(filename, linenum, 'build/storage_class', 5, |
|
| 2944 | 'Storage-class specifier (static, extern, typedef, etc) should be ' |
|
| 2945 | 'at the beginning of the declaration.') |
|
| 2946 | ||
| 2947 | if Match(r'\s*#\s*endif\s*[^/\s]+', line): |
|
| 2948 | error(filename, linenum, 'build/endif_comment', 5, |
|
| 2949 | 'Uncommented text after #endif is non-standard. Use a comment.') |
|
| 2950 | ||
| 2951 | if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line): |
|
| 2952 | error(filename, linenum, 'build/forward_decl', 5, |
|
| 2953 | 'Inner-style forward declarations are invalid. Remove this line.') |
|
| 2954 | ||
| 2955 | if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', |
|
| 2956 | line): |
|
| 2957 | error(filename, linenum, 'build/deprecated', 3, |
|
| 2958 | '>? and <? (max and min) operators are non-standard and deprecated.') |
|
| 2959 | ||
| 2960 | if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line): |
|
| 2961 | # TODO(unknown): Could it be expanded safely to arbitrary references, |
|
| 2962 | # without triggering too many false positives? The first |
|
| 2963 | # attempt triggered 5 warnings for mostly benign code in the regtest, hence |
|
| 2964 | # the restriction. |
|
| 2965 | # Here's the original regexp, for the reference: |
|
| 2966 | # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?' |
|
| 2967 | # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;' |
|
| 2968 | error(filename, linenum, 'runtime/member_string_references', 2, |
|
| 2969 | 'const string& members are dangerous. It is much better to use ' |
|
| 2970 | 'alternatives, such as pointers or simple constants.') |
|
| 2971 | ||
| 2972 | # Everything else in this function operates on class declarations. |
|
| 2973 | # Return early if the top of the nesting stack is not a class, or if |
|
| 2974 | # the class head is not completed yet. |
|
| 2975 | classinfo = nesting_state.InnermostClass() |
|
| 2976 | if not classinfo or not classinfo.seen_open_brace: |
|
| 2977 | return |
|
| 2978 | ||
| 2979 | # The class may have been declared with namespace or classname qualifiers. |
|
| 2980 | # The constructor and destructor will not have those qualifiers. |
|
| 2981 | base_classname = classinfo.name.split('::')[-1] |
|
| 2982 | ||
| 2983 | # Look for single-argument constructors that aren't marked explicit. |
|
| 2984 | # Technically a valid construct, but against style. |
|
| 2985 | explicit_constructor_match = Match( |
|
| 2986 | r'\s+(?:inline\s+)?(explicit\s+)?(?:inline\s+)?%s\s*' |
|
| 2987 | r'\(((?:[^()]|\([^()]*\))*)\)' |
|
| 2988 | % re.escape(base_classname), |
|
| 2989 | line) |
|
| 2990 | ||
| 2991 | if explicit_constructor_match: |
|
| 2992 | is_marked_explicit = explicit_constructor_match.group(1) |
|
| 2993 | ||
| 2994 | if not explicit_constructor_match.group(2): |
|
| 2995 | constructor_args = [] |
|
| 2996 | else: |
|
| 2997 | constructor_args = explicit_constructor_match.group(2).split(',') |
|
| 2998 | ||
| 2999 | # collapse arguments so that commas in template parameter lists and function |
|
| 3000 | # argument parameter lists don't split arguments in two |
|
| 3001 | i = 0 |
|
| 3002 | while i < len(constructor_args): |
|
| 3003 | constructor_arg = constructor_args[i] |
|
| 3004 | while (constructor_arg.count('<') > constructor_arg.count('>') or |
|
| 3005 | constructor_arg.count('(') > constructor_arg.count(')')): |
|
| 3006 | constructor_arg += ',' + constructor_args[i + 1] |
|
| 3007 | del constructor_args[i + 1] |
|
| 3008 | constructor_args[i] = constructor_arg |
|
| 3009 | i += 1 |
|
| 3010 | ||
| 3011 | variadic_args = [arg for arg in constructor_args if '&&...' in arg] |
|
| 3012 | defaulted_args = [arg for arg in constructor_args if '=' in arg] |
|
| 3013 | noarg_constructor = (not constructor_args or # empty arg list |
|
| 3014 | # 'void' arg specifier |
|
| 3015 | (len(constructor_args) == 1 and |
|
| 3016 | constructor_args[0].strip() == 'void')) |
|
| 3017 | onearg_constructor = ((len(constructor_args) == 1 and # exactly one arg |
|
| 3018 | not noarg_constructor) or |
|
| 3019 | # all but at most one arg defaulted |
|
| 3020 | (len(constructor_args) >= 1 and |
|
| 3021 | not noarg_constructor and |
|
| 3022 | len(defaulted_args) >= len(constructor_args) - 1) or |
|
| 3023 | # variadic arguments with zero or one argument |
|
| 3024 | (len(constructor_args) <= 2 and |
|
| 3025 | len(variadic_args) >= 1)) |
|
| 3026 | initializer_list_constructor = bool( |
|
| 3027 | onearg_constructor and |
|
| 3028 | Search(r'\bstd\s*::\s*initializer_list\b', constructor_args[0])) |
|
| 3029 | copy_constructor = bool( |
|
| 3030 | onearg_constructor and |
|
| 3031 | Match(r'(const\s+)?%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&' |
|
| 3032 | % re.escape(base_classname), constructor_args[0].strip())) |
|
| 3033 | ||
| 3034 | if (not is_marked_explicit and |
|
| 3035 | onearg_constructor and |
|
| 3036 | not initializer_list_constructor and |
|
| 3037 | not copy_constructor): |
|
| 3038 | if defaulted_args or variadic_args: |
|
| 3039 | error(filename, linenum, 'runtime/explicit', 5, |
|
| 3040 | 'Constructors callable with one argument ' |
|
| 3041 | 'should be marked explicit.') |
|
| 3042 | else: |
|
| 3043 | error(filename, linenum, 'runtime/explicit', 5, |
|
| 3044 | 'Single-parameter constructors should be marked explicit.') |
|
| 3045 | elif is_marked_explicit and not onearg_constructor: |
|
| 3046 | if noarg_constructor: |
|
| 3047 | error(filename, linenum, 'runtime/explicit', 5, |
|
| 3048 | 'Zero-parameter constructors should not be marked explicit.') |
|
| 3049 | ||
| 3050 | ||
| 3051 | def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error): |
|
| @@ 2888-3048 (lines=161) @@ | ||
| 2885 | obj.name) |
|
| 2886 | ||
| 2887 | ||
| 2888 | def CheckForNonStandardConstructs(filename, clean_lines, linenum, |
|
| 2889 | nesting_state, error): |
|
| 2890 | r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2. |
|
| 2891 | ||
| 2892 | Complain about several constructs which gcc-2 accepts, but which are |
|
| 2893 | not standard C++. Warning about these in lint is one way to ease the |
|
| 2894 | transition to new compilers. |
|
| 2895 | - put storage class first (e.g. "static const" instead of "const static"). |
|
| 2896 | - "%lld" instead of %qd" in printf-type functions. |
|
| 2897 | - "%1$d" is non-standard in printf-type functions. |
|
| 2898 | - "\%" is an undefined character escape sequence. |
|
| 2899 | - text after #endif is not allowed. |
|
| 2900 | - invalid inner-style forward declaration. |
|
| 2901 | - >? and <? operators, and their >?= and <?= cousins. |
|
| 2902 | ||
| 2903 | Additionally, check for constructor/destructor style violations and reference |
|
| 2904 | members, as it is very convenient to do so while checking for |
|
| 2905 | gcc-2 compliance. |
|
| 2906 | ||
| 2907 | Args: |
|
| 2908 | filename: The name of the current file. |
|
| 2909 | clean_lines: A CleansedLines instance containing the file. |
|
| 2910 | linenum: The number of the line to check. |
|
| 2911 | nesting_state: A NestingState instance which maintains information about |
|
| 2912 | the current stack of nested blocks being parsed. |
|
| 2913 | error: A callable to which errors are reported, which takes 4 arguments: |
|
| 2914 | filename, line number, error level, and message |
|
| 2915 | """ |
|
| 2916 | ||
| 2917 | # Remove comments from the line, but leave in strings for now. |
|
| 2918 | line = clean_lines.lines[linenum] |
|
| 2919 | ||
| 2920 | if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line): |
|
| 2921 | error(filename, linenum, 'runtime/printf_format', 3, |
|
| 2922 | '%q in format strings is deprecated. Use %ll instead.') |
|
| 2923 | ||
| 2924 | if Search(r'printf\s*\(.*".*%\d+\$', line): |
|
| 2925 | error(filename, linenum, 'runtime/printf_format', 2, |
|
| 2926 | '%N$ formats are unconventional. Try rewriting to avoid them.') |
|
| 2927 | ||
| 2928 | # Remove escaped backslashes before looking for undefined escapes. |
|
| 2929 | line = line.replace('\\\\', '') |
|
| 2930 | ||
| 2931 | if Search(r'("|\').*\\(%|\[|\(|{)', line): |
|
| 2932 | error(filename, linenum, 'build/printf_format', 3, |
|
| 2933 | '%, [, (, and { are undefined character escapes. Unescape them.') |
|
| 2934 | ||
| 2935 | # For the rest, work with both comments and strings removed. |
|
| 2936 | line = clean_lines.elided[linenum] |
|
| 2937 | ||
| 2938 | if Search(r'\b(const|volatile|void|char|short|int|long' |
|
| 2939 | r'|float|double|signed|unsigned' |
|
| 2940 | r'|schar|u?int8|u?int16|u?int32|u?int64)' |
|
| 2941 | r'\s+(register|static|extern|typedef)\b', |
|
| 2942 | line): |
|
| 2943 | error(filename, linenum, 'build/storage_class', 5, |
|
| 2944 | 'Storage-class specifier (static, extern, typedef, etc) should be ' |
|
| 2945 | 'at the beginning of the declaration.') |
|
| 2946 | ||
| 2947 | if Match(r'\s*#\s*endif\s*[^/\s]+', line): |
|
| 2948 | error(filename, linenum, 'build/endif_comment', 5, |
|
| 2949 | 'Uncommented text after #endif is non-standard. Use a comment.') |
|
| 2950 | ||
| 2951 | if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line): |
|
| 2952 | error(filename, linenum, 'build/forward_decl', 5, |
|
| 2953 | 'Inner-style forward declarations are invalid. Remove this line.') |
|
| 2954 | ||
| 2955 | if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', |
|
| 2956 | line): |
|
| 2957 | error(filename, linenum, 'build/deprecated', 3, |
|
| 2958 | '>? and <? (max and min) operators are non-standard and deprecated.') |
|
| 2959 | ||
| 2960 | if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line): |
|
| 2961 | # TODO(unknown): Could it be expanded safely to arbitrary references, |
|
| 2962 | # without triggering too many false positives? The first |
|
| 2963 | # attempt triggered 5 warnings for mostly benign code in the regtest, hence |
|
| 2964 | # the restriction. |
|
| 2965 | # Here's the original regexp, for the reference: |
|
| 2966 | # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?' |
|
| 2967 | # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;' |
|
| 2968 | error(filename, linenum, 'runtime/member_string_references', 2, |
|
| 2969 | 'const string& members are dangerous. It is much better to use ' |
|
| 2970 | 'alternatives, such as pointers or simple constants.') |
|
| 2971 | ||
| 2972 | # Everything else in this function operates on class declarations. |
|
| 2973 | # Return early if the top of the nesting stack is not a class, or if |
|
| 2974 | # the class head is not completed yet. |
|
| 2975 | classinfo = nesting_state.InnermostClass() |
|
| 2976 | if not classinfo or not classinfo.seen_open_brace: |
|
| 2977 | return |
|
| 2978 | ||
| 2979 | # The class may have been declared with namespace or classname qualifiers. |
|
| 2980 | # The constructor and destructor will not have those qualifiers. |
|
| 2981 | base_classname = classinfo.name.split('::')[-1] |
|
| 2982 | ||
| 2983 | # Look for single-argument constructors that aren't marked explicit. |
|
| 2984 | # Technically a valid construct, but against style. |
|
| 2985 | explicit_constructor_match = Match( |
|
| 2986 | r'\s+(?:inline\s+)?(explicit\s+)?(?:inline\s+)?%s\s*' |
|
| 2987 | r'\(((?:[^()]|\([^()]*\))*)\)' |
|
| 2988 | % re.escape(base_classname), |
|
| 2989 | line) |
|
| 2990 | ||
| 2991 | if explicit_constructor_match: |
|
| 2992 | is_marked_explicit = explicit_constructor_match.group(1) |
|
| 2993 | ||
| 2994 | if not explicit_constructor_match.group(2): |
|
| 2995 | constructor_args = [] |
|
| 2996 | else: |
|
| 2997 | constructor_args = explicit_constructor_match.group(2).split(',') |
|
| 2998 | ||
| 2999 | # collapse arguments so that commas in template parameter lists and function |
|
| 3000 | # argument parameter lists don't split arguments in two |
|
| 3001 | i = 0 |
|
| 3002 | while i < len(constructor_args): |
|
| 3003 | constructor_arg = constructor_args[i] |
|
| 3004 | while (constructor_arg.count('<') > constructor_arg.count('>') or |
|
| 3005 | constructor_arg.count('(') > constructor_arg.count(')')): |
|
| 3006 | constructor_arg += ',' + constructor_args[i + 1] |
|
| 3007 | del constructor_args[i + 1] |
|
| 3008 | constructor_args[i] = constructor_arg |
|
| 3009 | i += 1 |
|
| 3010 | ||
| 3011 | variadic_args = [arg for arg in constructor_args if '&&...' in arg] |
|
| 3012 | defaulted_args = [arg for arg in constructor_args if '=' in arg] |
|
| 3013 | noarg_constructor = (not constructor_args or # empty arg list |
|
| 3014 | # 'void' arg specifier |
|
| 3015 | (len(constructor_args) == 1 and |
|
| 3016 | constructor_args[0].strip() == 'void')) |
|
| 3017 | onearg_constructor = ((len(constructor_args) == 1 and # exactly one arg |
|
| 3018 | not noarg_constructor) or |
|
| 3019 | # all but at most one arg defaulted |
|
| 3020 | (len(constructor_args) >= 1 and |
|
| 3021 | not noarg_constructor and |
|
| 3022 | len(defaulted_args) >= len(constructor_args) - 1) or |
|
| 3023 | # variadic arguments with zero or one argument |
|
| 3024 | (len(constructor_args) <= 2 and |
|
| 3025 | len(variadic_args) >= 1)) |
|
| 3026 | initializer_list_constructor = bool( |
|
| 3027 | onearg_constructor and |
|
| 3028 | Search(r'\bstd\s*::\s*initializer_list\b', constructor_args[0])) |
|
| 3029 | copy_constructor = bool( |
|
| 3030 | onearg_constructor and |
|
| 3031 | Match(r'(const\s+)?%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&' |
|
| 3032 | % re.escape(base_classname), constructor_args[0].strip())) |
|
| 3033 | ||
| 3034 | if (not is_marked_explicit and |
|
| 3035 | onearg_constructor and |
|
| 3036 | not initializer_list_constructor and |
|
| 3037 | not copy_constructor): |
|
| 3038 | if defaulted_args or variadic_args: |
|
| 3039 | error(filename, linenum, 'runtime/explicit', 5, |
|
| 3040 | 'Constructors callable with one argument ' |
|
| 3041 | 'should be marked explicit.') |
|
| 3042 | else: |
|
| 3043 | error(filename, linenum, 'runtime/explicit', 5, |
|
| 3044 | 'Single-parameter constructors should be marked explicit.') |
|
| 3045 | elif is_marked_explicit and not onearg_constructor: |
|
| 3046 | if noarg_constructor: |
|
| 3047 | error(filename, linenum, 'runtime/explicit', 5, |
|
| 3048 | 'Zero-parameter constructors should not be marked explicit.') |
|
| 3049 | ||
| 3050 | ||
| 3051 | def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error): |
|