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
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ TBA
* Fixed a whitespace/newline false positive for control conditions containing lambdas. (#410)
* 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.
* Update and add checks for whitespace before left square brackets. In particular:
* A single whitespace character is allowed before the left square bracket in structured binding.
* No more than one whitespace character is allowed before the left square bracket, regardless of what character comes before the space (apart from whitespace due to indentation). Previously, whitespace characters were only complained about if they were preceded by a word character.

2.0.2 (2025-04-08)
===========
Expand Down
34 changes: 31 additions & 3 deletions cpplint.py
Original file line number Diff line number Diff line change
Expand Up @@ -4401,11 +4401,39 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
# get rid of comments and strings
line = clean_lines.elided[linenum]

# You shouldn't have spaces before your brackets, except for C++11 attributes
# or maybe after 'delete []', 'return []() {};', or 'auto [abc, ...] = ...;'.
if re.search(r"\w\s+\[(?!\[)", line) and not re.search(r"(?:auto&?|delete|return)\s+\[", line):
# Other than due to indentation, you shouldn't have more than one space before
# a left square bracket.
if re.search(r"\S\s{2,}\[", line):
error(filename, linenum, "whitespace/braces", 5, "Extra space before [")

# After a word character, you shouldn't have any spaces before a left square bracket, except
# for:
# * before C++11 attributes, in which case the first left square bracket will be immediately
# followed by another;
# * after "delete" or "return"; or
# * inside of a structured binding, such as `auto const& [abc, ...] = ...;`.
#
# In these cases, the left square bracket should be preceded by exactly one space. For the
# specificatio of structured bindings, see
# https://en.cppreference.com/cpp/language/structured_binding.
matches = re.finditer(r"[^\[]*\w\s\[(?!\[)", line)
for match in matches:
if not (
re.search(r"(?:delete|return)\s\[", match.group())
or re.search(
r"""
(?:((constexpr\s+)|(constinit\s+)|(static\s+)|(thread_local\s+)|(const\s+)|(volatile\s+))*)
auto
(?:((\s+constexpr)|(\s+constinit)|(\s+static)|(\s+thread_local)|(\s+const)|(\s+volatile))*)
(?:(\&|\&\&)?)
\s\[
""",
match.group(),
re.VERBOSE,
) # Structured binding
):
error(filename, linenum, "whitespace/braces", 5, "Extra space before [")

# In range-based for, we wanted spaces before and after the colon, but
# not around "::" tokens that might appear.
if re.search(r"for *\(.*[^:]:[^: ]", line) or re.search(r"for *\(.*[^: ]:[^:]", line):
Expand Down
78 changes: 76 additions & 2 deletions cpplint_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3157,10 +3157,84 @@ def testSpacingBeforeBrackets(self):
self.TestLint(
"int numbers [] = { 1, 2, 3 };", "Extra space before [ [whitespace/braces] [5]"
)
# space allowed in some cases
self.TestLint("auto [abc, def] = func();", "")

# space due to indentation is allowed
self.TestLint(" [[nodiscard]] bool func();", "")

# single space allowed in some cases
self.TestLint("#define NODISCARD [[nodiscard]]", "")
self.TestLint("void foo(int param [[maybe_unused]]);", "")
self.TestLint("return [a, b]", "")
self.TestLint("delete [c]", "")
self.TestLint("auto [abc, def] = func();", "")
self.TestLint("static auto [abc, def] = func();", "")
self.TestLint("auto const [abc, def] = func();", "")
self.TestLint("static auto const [abc, def] = func();", "")
self.TestLint("auto& [abc, def] = func();", "")
self.TestLint("static auto& [abc, def] = func();", "")
self.TestLint("auto const& [abc, def] = func();", "")
self.TestLint("static auto const& [abc, def] = func();", "")
self.TestLint("auto&& [abc, def] = func();", "")
self.TestLint("static auto&& [abc, def] = func();", "")
self.TestLint("auto const&& [abc, def] = func();", "")
self.TestLint("static auto const&& [abc, def] = func();", "")
self.TestLint("auto constinit [x, y] = value;", "")

# multiple spaces not allowed before before braces
self.TestLint(
"#define NODISCARD [[nodiscard]]", "Extra space before [ [whitespace/braces] [5]"
)
self.TestLint(
"void foo(int param [[maybe_unused]]);",
"Extra space before [ [whitespace/braces] [5]",
)
self.TestLint("return [a, b]", "Extra space before [ [whitespace/braces] [5]")
self.TestLint("delete [c]", "Extra space before [ [whitespace/braces] [5]")
self.TestLint("auto [abc, def] = func();", "Extra space before [ [whitespace/braces] [5]")
self.TestLint(
"static auto [abc, def] = func();", "Extra space before [ [whitespace/braces] [5]"
)
self.TestLint(
"auto const [abc, def] = func();", "Extra space before [ [whitespace/braces] [5]"
)
self.TestLint(
"static auto const [abc, def] = func();",
"Extra space before [ [whitespace/braces] [5]",
)
self.TestLint(
"auto& [abc, def] = func();", "Extra space before [ [whitespace/braces] [5]"
)
self.TestLint(
"static auto& [abc, def] = func();", "Extra space before [ [whitespace/braces] [5]"
)
self.TestLint(
"auto const& [abc, def] = func();", "Extra space before [ [whitespace/braces] [5]"
)
self.TestLint(
"static auto const& [abc, def] = func();",
"Extra space before [ [whitespace/braces] [5]",
)
self.TestLint(
"auto&& [abc, def] = func();", "Extra space before [ [whitespace/braces] [5]"
)
self.TestLint(
"static auto&& [abc, def] = func();", "Extra space before [ [whitespace/braces] [5]"
)
self.TestLint(
"auto const&& [abc, def] = func();", "Extra space before [ [whitespace/braces] [5]"
)
self.TestLint(
"static auto const&& [abc, def] = func();",
"Extra space before [ [whitespace/braces] [5]",
)
self.TestLint(
"auto [key, value] = values [index];",
"Extra space before [ [whitespace/braces] [5]",
)
self.TestLint(
"auto constinit [x, y] = value;",
"Extra space before [ [whitespace/braces] [5]",
)

def testLambda(self):
self.TestLint("auto x = []() {};", "")
Expand Down