From 659350a0b63347bebdfd79abc5d0cf125c0e5aef Mon Sep 17 00:00:00 2001 From: androvonx95 Date: Sun, 19 Jul 2026 23:28:24 +0530 Subject: [PATCH 1/2] fix(readability/casting): ignore calling-convention function pointers Treat typedef/using forms like (CALLCONV* name)(args) as function pointer types instead of deprecated or C-style casts (#409). Co-authored-by: Cursor --- CHANGELOG.rst | 4 ++++ cpplint.py | 10 +++++++++- cpplint_unittest.py | 13 +++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7aa9397..8bcefab 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,10 @@ Changelog TBA === +* Fixed false positives in readability/casting for function-pointer typedefs and alias + declarations that use a calling-convention macro before ``*`` + (e.g. ``typedef int32_t(CALLCONV* Func)(void);``). (https://github.com/cpplint/cpplint/issues/409) + 2.0.2 (2025-04-08) =========== diff --git a/cpplint.py b/cpplint.py index 128bb3c..40b3ccf 100755 --- a/cpplint.py +++ b/cpplint.py @@ -6674,7 +6674,8 @@ def CheckCasts(filename, clean_lines, linenum, error): return # Other things to ignore: - # - Function pointers + # - Function pointers (including calling-convention forms like + # (CALLCONV* name)(args) and (CALLCONV *)(args)) # - Casts to pointer types # - Placement new # - Alias declarations @@ -6685,6 +6686,7 @@ def CheckCasts(filename, clean_lines, linenum, error): matched_funcptr and ( re.match(r"\((?:[^() ]+::\s*\*\s*)?[^() ]+\)\s*\(", matched_funcptr) + or re.match(r"\((?:\w+\s*)?\*\s*\w*\)\s*\(", matched_funcptr) or matched_funcptr.startswith("(*)") ) ) @@ -6826,6 +6828,12 @@ def CheckCStyleCast(filename, clean_lines, linenum, cast_type, pattern, error): if re.match(r"^\s*(?:;|const\b|throw\b|final\b|override\b|[=>{),]|->)", remainder): return False + # Function-pointer types in typedef/alias declarations can look like + # pointer casts followed by a parameter list, e.g. + # using Func = int32_t(CALLCONV *)(void); + if re.search(r"\b(?:typedef|using)\b", line) and re.match(r"^\s*\(", remainder): + return False + # At this point, all that should be left is actual casts. error( filename, diff --git a/cpplint_unittest.py b/cpplint_unittest.py index 7b39074..cd17fd0 100755 --- a/cpplint_unittest.py +++ b/cpplint_unittest.py @@ -1108,6 +1108,19 @@ def testDeprecatedCast(self): self.TestLint("typedef set SortedIdSet", "") self.TestLint("bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *t)) {}", "") + # Function pointers with a calling-convention macro before '*' should + # not be flagged as deprecated/C-style casts. (https://github.com/cpplint/cpplint/issues/409) + self.TestLint( + "typedef int32_t(NAPI_CDECL* node_api_addon_get_api_version_func)(void);", + "", + ) + self.TestLint( + "using node_api_addon_get_api_version_func = int32_t(NAPI_CDECL *)(void);", + "", + ) + self.TestLint("typedef int32_t(CALLCONV* Func)(int);", "") + self.TestLint("using Func = int32_t(CALLCONV *)(int, int);", "") + # The second parameter to a gMock method definition is a function signature # that often looks like a bad cast but should not picked up by lint. def testMockMethod(self): From b2b1cc8b446e47f1eb996b825a7501717f9e1237 Mon Sep 17 00:00:00 2001 From: androvonx95 Date: Sat, 25 Jul 2026 22:12:21 +0530 Subject: [PATCH 2/2] fix(readability/casting): allow arrays of function pointers in typedef/using Broaden the declarator part of the function-pointer pattern so that array declarators such as `typedef int32_t(CALLCONV* FuncArray[3])(void);` are recognized instead of being reported as a deprecated cast. --- CHANGELOG.rst | 5 +++-- cpplint.py | 2 +- cpplint_unittest.py | 2 ++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fb745d7..09af0f3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,8 +7,9 @@ TBA * Fixed a whitespace/newline false positive for control conditions containing lambdas. (#410) * Fixed false positives in readability/casting for function-pointer typedefs and alias - declarations that use a calling-convention macro before ``*`` - (e.g. ``typedef int32_t(CALLCONV* Func)(void);``). (https://github.com/cpplint/cpplint/issues/409) + declarations that use a calling-convention macro before ``*``, including array declarators + (e.g. ``typedef int32_t(CALLCONV* Func)(void);`` and + ``typedef int32_t(CALLCONV* FuncArray[3])(void);``). (https://github.com/cpplint/cpplint/issues/409) 2.0.2 (2025-04-08) =========== diff --git a/cpplint.py b/cpplint.py index edd7d3a..8f9aa75 100755 --- a/cpplint.py +++ b/cpplint.py @@ -6655,7 +6655,7 @@ def CheckCasts(filename, clean_lines, linenum, error): matched_funcptr and ( re.match(r"\((?:[^() ]+::\s*\*\s*)?[^() ]+\)\s*\(", matched_funcptr) - or re.match(r"\((?:\w+\s*)?\*\s*\w*\)\s*\(", matched_funcptr) + or re.match(r"\((?:\w+\s*)?\*\s*[^() ]*\)\s*\(", matched_funcptr) or matched_funcptr.startswith("(*)") ) ) diff --git a/cpplint_unittest.py b/cpplint_unittest.py index 07a54d1..7d72363 100755 --- a/cpplint_unittest.py +++ b/cpplint_unittest.py @@ -1128,6 +1128,8 @@ def testDeprecatedCast(self): ) self.TestLint("typedef int32_t(CALLCONV* Func)(int);", "") self.TestLint("using Func = int32_t(CALLCONV *)(int, int);", "") + self.TestLint("typedef int32_t(CALLCONV* FuncArray[3])(void);", "") + self.TestLint("typedef int32_t(*FuncArray[3])(void);", "") # The second parameter to a gMock method definition is a function signature # that often looks like a bad cast but should not picked up by lint.