diff --git a/cpplint.py b/cpplint.py index 209c3ac38c..0e7f4a8ef0 100755 --- a/cpplint.py +++ b/cpplint.py @@ -418,6 +418,231 @@ _CPP_HEADERS = frozenset([ 'cwctype', ]) +# List of functions from . See [meta.type.synop] +_TYPE_TRAITS = [ + # 23.15.3, helper class + 'integral_constant', + # 23.15.4.1, primary type categories + 'is_void', + 'is_null_pointer', + 'is_integral', + 'is_floating_point', + 'is_array', + 'is_pointer', + 'is_lvalue_reference', + 'is_rvalue_reference', + 'is_member_object_pointer', + 'is_member_function_pointer', + 'is_enum', + 'is_union', + 'is_class', + 'is_function', + # 23.15.4.2, composite type categories + 'is_reference', + 'is_arithmetic', + 'is_fundamental', + 'is_object', + 'is_scalar', + 'is_compound', + 'is_member_pointer', + # 23.15.4.3, type properties + 'is_const', + 'is_volatile', + 'is_trivial', + 'is_trivially_copyable', + 'is_standard_layout', + 'is_pod', + 'is_empty', + 'is_polymorphic', + 'is_abstract', + 'is_final', + 'is_aggregate', + 'is_signed', + 'is_unsigned', + 'is_constructible', + 'is_default_constructible', + 'is_copy_constructible', + 'is_move_constructible', + 'is_assignable', + 'is_copy_assignable', + 'is_move_assignable', + 'is_swappable_with', + 'is_swappable', + 'is_destructible', + 'is_trivially_constructible', + 'is_trivially_default_constructible', + 'is_trivially_copy_constructible', + 'is_trivially_move_constructible', + 'is_trivially_assignable', + 'is_trivially_copy_assignable', + 'is_trivially_move_assignable', + 'is_trivially_destructible', + 'is_nothrow_constructible', + 'is_nothrow_default_constructible', + 'is_nothrow_copy_constructible', + 'is_nothrow_move_constructible', + 'is_nothrow_assignable', + 'is_nothrow_copy_assignable', + 'is_nothrow_move_assignable', + 'is_nothrow_swappable_with', + 'is_nothrow_swappable', + 'is_nothrow_destructible', + 'has_virtual_destructor', + 'has_unique_object_representations', + # 23.15.5, type property queries + 'alignment_of', + 'rank', + 'extent', + # 23.15.6, type relations + 'is_same', + 'is_base_of', + 'is_convertible', + 'is_invocable', + 'is_invocable_r', + 'is_nothrow_invocable', + 'is_nothrow_invocable_r', + # 23.15.7.1, const-volatile modifications + 'remove_const', + 'remove_volatile', + 'remove_cv', + 'add_const', + 'add_volatile', + 'add_cv', + 'remove_const_t', + 'remove_volatile_t', + 'remove_cv_t', + 'add_const_t', + 'add_volatile_t', + 'add_cv_t', + # 23.15.7.2, reference modifications + 'remove_reference', + 'add_lvalue_reference', + 'add_rvalue_reference', + 'remove_reference_t', + 'add_lvalue_reference_t', + 'add_rvalue_reference_t', + # 23.15.7.3, sign modifications + 'make_signed', + 'make_unsigned', + 'make_signed_t', + 'make_unsigned_t', + # 23.15.7.4, array modifications + 'remove_extent', + 'remove_all_extents', + 'remove_extent_t', + 'remove_all_extents_t', + # 23.15.7.5, pointer modifications + 'remove_pointer', + 'add_pointer', + 'remove_pointer_t', + 'add_pointer_t', + # 23.15.7.6, other transformations + 'aligned_storage', + 'aligned_union', + 'decay', + 'enable_if', + 'conditional', + 'common_type', + 'underlying_type', + 'invoke_result', + 'aligned_storage_t', + 'aligned_union_t', + 'decay_t', + 'enable_if_t', + 'conditional_t', + 'common_type_t', + 'underlying_type_t', + 'invoke_result_t', + 'void_t', + # 23.15.8, logical operator traits + 'conjunction', + 'disjunction', + 'negation', + # 23.15.4.1, primary type categories + 'is_void_v', + 'is_null_pointer_v', + 'is_integral_v', + 'is_floating_point_v', + 'is_array_v', + 'is_pointer_v', + 'is_lvalue_reference_v', + 'is_rvalue_reference_v', + 'is_member_object_pointer_v', + 'is_member_function_pointer_v', + 'is_enum_v', + 'is_union_v', + 'is_class_v', + 'is_function_v', + # 23.15.4.2, composite type categories + 'is_reference_v', + 'is_arithmetic_v', + 'is_fundamental_v', + 'is_object_v', + 'is_scalar_v', + 'is_compound_v', + 'is_member_pointer_v', + # 23.15.4.3, type properties + 'is_const_v', + 'is_volatile_v', + 'is_trivial_v', + 'is_trivially_copyable_v', + 'is_standard_layout_v', + 'is_pod_v', + 'is_empty_v', + 'is_polymorphic_v', + 'is_abstract_v', + 'is_final_v', + 'is_aggregate_v', + 'is_signed_v', + 'is_unsigned_v', + 'is_constructible_v', + 'is_default_constructible_v', + 'is_copy_constructible_v', + 'is_move_constructible_v', + 'is_assignable_v', + 'is_copy_assignable_v', + 'is_move_assignable_v', + 'is_swappable_with_v', + 'is_swappable_v', + 'is_destructible_v', + 'is_trivially_constructible_v', + 'is_trivially_default_constructible_v', + 'is_trivially_copy_constructible_v', + 'is_trivially_move_constructible_v', + 'is_trivially_assignable_v', + 'is_trivially_copy_assignable_v', + 'is_trivially_move_assignable_v', + 'is_trivially_destructible_v', + 'is_nothrow_constructible_v', + 'is_nothrow_default_constructible_v', + 'is_nothrow_copy_constructible_v', + 'is_nothrow_move_constructible_v', + 'is_nothrow_assignable_v', + 'is_nothrow_copy_assignable_v', + 'is_nothrow_move_assignable_v', + 'is_nothrow_swappable_with_v', + 'is_nothrow_swappable_v', + 'is_nothrow_destructible_v', + 'has_virtual_destructor_v', + 'has_unique_object_representations_v', + # 23.15.5, type property queries + 'alignment_of_v', + 'rank_v', + 'extent_v', + 'is_same_v', + 'is_base_of_v', + 'is_convertible_v', + 'is_invocable_v', + 'is_invocable_r_v', + 'is_nothrow_invocable_v', + 'is_nothrow_invocable_r_v', + # 23.15.8, logical operator traits + 'conjunction_v', + 'disjunction_v', + 'negation_v', +] +_TYPE_TRAITS_RE = re.compile(r'\b::(?:' + ('|'.join(_TYPE_TRAITS)) + ')<') + # Type names _TYPES = re.compile( r'^(?:' @@ -3832,10 +4057,10 @@ def CheckTrailingSemicolon(filename, clean_lines, linenum, error): line = clean_lines.elided[linenum] # Block bodies should not be followed by a semicolon. Due to C++11 - # brace initialization, there are more places where semicolons are - # required than not, so we use an allowlist approach to check these - # rather than a blocklist. These are the places where "};" should - # be replaced by just "}": + # brace initialization and C++20 concepts, there are more places + # where semicolons are required than not. Places that are + # recognized as true positives are listed below. + # # 1. Some flavor of block following closing parenthesis: # for (;;) {}; # while (...) {}; @@ -3903,6 +4128,10 @@ def CheckTrailingSemicolon(filename, clean_lines, linenum, error): # - Lambdas # - alignas specifier with anonymous structs # - decltype + # - Type casts with parentheses, e.g.: var = (Type){value}; + # - Return type casts with parentheses, e.g.: return (Type){value}; + # - Function pointers with initializer list, e.g.: int (*f)(){}; + # - Requires expression, e.g. C = requires(){}; closing_brace_pos = match.group(1).rfind(')') opening_parenthesis = ReverseCloseExpression( clean_lines, linenum, closing_brace_pos) @@ -3910,15 +4139,17 @@ def CheckTrailingSemicolon(filename, clean_lines, linenum, error): line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]] macro = Search(r'\b([A-Z_][A-Z0-9_]*)\s*$', line_prefix) func = Match(r'^(.*\])\s*$', line_prefix) - if ((macro and - macro.group(1) not in ( - 'TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST', - 'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED', - 'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or - (func and not Search(r'\boperator\s*\[\s*\]', func.group(1))) or - Search(r'\b(?:struct|union)\s+alignas\s*$', line_prefix) or - Search(r'\bdecltype$', line_prefix) or - Search(r'\s+=\s*$', line_prefix)): + if ((macro and macro.group(1) not in + ('TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST', + 'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED', + 'LOCKS_EXCLUDED', 'INTERFACE_DEF')) + or (func and not Search(r'\boperator\s*\[\s*\]', func.group(1))) + or Search(r'\b(?:struct|union)\s+alignas\s*$', line_prefix) + or Search(r'\b(decltype|requires)$', line_prefix) + or Search(r'(?:\s+=|\breturn)\s*$', line_prefix) + or (Match(r'^\s*$', line_prefix) and Search( + r'(?:\s+=|\breturn)\s*$', clean_lines.elided[linenum - 1])) + or Search(r'\(\*\w+\)$', line_prefix)): match = None if (match and opening_parenthesis[1] > 1 and @@ -5285,14 +5516,15 @@ def ExpectingFunctionArgs(clean_lines, linenum): of function types. """ line = clean_lines.elided[linenum] - return (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or - (linenum >= 2 and - (Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\((?:\S+,)?\s*$', - clean_lines.elided[linenum - 1]) or - Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\(\s*$', - clean_lines.elided[linenum - 2]) or - Search(r'\bstd::m?function\s*\<\s*$', - clean_lines.elided[linenum - 1])))) + return (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) + or _TYPE_TRAITS_RE.search(line) + or (linenum >= 2 and + (Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\((?:\S+,)?\s*$', + clean_lines.elided[linenum - 1]) + or Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\(\s*$', + clean_lines.elided[linenum - 2]) + or Search(r'\b(::function|base::FunctionRef)\s*\<\s*$', + clean_lines.elided[linenum - 1])))) _HEADERS_CONTAINING_TEMPLATES = ( diff --git a/cpplint_chromium.py b/cpplint_chromium.py index 4fcd99b6b8..9318a8657c 100755 --- a/cpplint_chromium.py +++ b/cpplint_chromium.py @@ -31,7 +31,9 @@ import re # Matches Foo *foo declarations. _RE_PATTERN_POINTER_DECLARATION_WHITESPACE = re.compile( - r'\s*\w+(?\*|\&)\w+') + r'\s*\w+((?\*|\&)\w+') + def CheckPointerDeclarationWhitespace(filename, clean_lines, linenum, error): """Checks for Foo *foo declarations.