Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ 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 ``*``, 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)
* We now error on relative include paths (``./``, ``../``). (#432)
* This makes ``#include "./foo.h"`` produce two separate errors: that foo.cpp should include foo.h and that relative paths are not allowed.

Expand Down
10 changes: 9 additions & 1 deletion cpplint.py
Original file line number Diff line number Diff line change
Expand Up @@ -6651,7 +6651,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
Expand All @@ -6662,6 +6663,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*[^() ]*\)\s*\(", matched_funcptr)
or matched_funcptr.startswith("(*)")
)
)
Expand Down Expand Up @@ -6803,6 +6805,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,
Expand Down
15 changes: 15 additions & 0 deletions cpplint_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1116,6 +1116,21 @@ def testDeprecatedCast(self):
self.TestLint("typedef set<int64_t, bool(*)(int64_t, int64_t)> 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);", "")
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.
def testMockMethod(self):
Expand Down