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
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Changelog
TBA
===

* Avoid casting warnings for unnamed parameters when a function body starts on the next line. (#131)
* Use path-aware prefix checks instead of deprecated os.path.commonprefix(). (#445)
* Fixed a whitespace/newline false positive for control conditions containing lambdas. (#410)
* We now error on relative include paths (``./``, ``../``). (#432)
Expand Down
21 changes: 21 additions & 0 deletions cpplint.py
Original file line number Diff line number Diff line change
Expand Up @@ -6802,6 +6802,27 @@ 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

# A function body can start on the next non-blank line. Require a return
# type and function name, or a lambda capture, so a compound literal's
# opening brace is not mistaken for a body.
signature_context = ReplaceAlternateTokens(line[: match.start(0)])
signature = re.search(r"(?:\b[\w:<>]+[\s*&]+(?:\w+::)*\w+|\])\s*$", signature_context)
if (
not remainder.strip()
and signature
and not re.search(
r"\b(?:return|throw|co_return|co_yield|co_await|delete|else|__extension__)\b",
signature.group(0),
)
and not re.search(r"\bdelete\s*\[\s*\]\s*$", signature_context)
):
for next_linenum in range(linenum + 1, clean_lines.NumLines()):
next_line = clean_lines.elided[next_linenum].strip()
if next_line:
if next_line.startswith("{"):
return False
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
break

# At this point, all that should be left is actual casts.
error(
filename,
Expand Down
59 changes: 59 additions & 0 deletions cpplint_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,65 @@ def testCheckForUnnamedParams(self):
self.TestLint("void f(int /*unused*/) override {", "")
self.TestLint("void f(int /*unused*/) final {", "")

@pytest.mark.parametrize(
"signature",
[
"void Func(int)",
"void Func(int*)",
"const Foo* Func(int)",
"void ns::Func(int)",
"auto func = [](int)",
"auto func = [value](int)",
"return [](int)",
],
)
@pytest.mark.parametrize("separator", ["\n", "\n\n", "\n// Unused argument.\n"])
def testUnnamedParamBeforeMultilineBody(self, signature, separator):
"""Keep unnamed parameters before multiline function bodies free of cast warnings."""
code = signature + separator + "{\n return;\n}"
clean_lines = cpplint.CleansedLines(code.split("\n"))
error_collector = ErrorCollector(self.assertTrue)
cpplint.CheckCasts("foo.cc", clean_lines, 0, error_collector)
assert error_collector.Results() == ""

@pytest.mark.parametrize(
("code", "cast_type", "type_name"),
[
("int value = (int)\n 1.5;", "static_cast", "int"),
("return (int)\n (value);", "static_cast", "int"),
("int* ptr = (int*)\n value;", "reinterpret_cast", "int*"),
("int value = (int)\n// Cast operand.\n 1.5;", "static_cast", "int"),
("int value = (int)\n", "static_cast", "int"),
("int value = (int)\n{1};", "static_cast", "int"),
("return (int)\n{1};", "static_cast", "int"),
("return(int)\n{1};", "static_cast", "int"),
("throw (int)\n{1};", "static_cast", "int"),
("else return (int)\n{1};", "static_cast", "int"),
("else throw (int)\n{1};", "static_cast", "int"),
("else delete (int*)\n{0};", "reinterpret_cast", "int*"),
("delete [] (int*)\n{0};", "reinterpret_cast", "int*"),
("return __extension__ (int)\n{1};", "static_cast", "int"),
("int* ptr = (int*)\n{0};", "reinterpret_cast", "int*"),
("int value = 1 bitand (int)\n{1};", "static_cast", "int"),
("int value = not (int)\n{1};", "static_cast", "int"),
(
"void Func(int)\n{\n int value = (int)\n {1};\n}",
"static_cast",
"int",
),
],
)
def testMultilineCStyleCast(self, code, cast_type, type_name):
"""Retain diagnostics for multiline casts, compound literals, and incomplete casts."""
clean_lines = cpplint.CleansedLines(code.split("\n"))
error_collector = ErrorCollector(self.assertTrue)
for linenum in range(clean_lines.NumLines()):
cpplint.CheckCasts("foo.cc", clean_lines, linenum, error_collector)
assert error_collector.Results() == (
f"Using C-style cast. Use {cast_type}<{type_name}>(...) instead"
" [readability/casting] [4]"
)

# Test deprecated casts such as int(d)
def testDeprecatedCast(self):
self.TestLint(
Expand Down
Loading