GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — fix: handle multiline function templates in namespaces by janmarsino98 · Pull Request #447 · cpplint/cpplint Conversation
|
📝 WalkthroughWalkthrough
ChangesNamespace indentation handling
Estimated code review effort: 3 (Moderate) | ~20 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
cpplint.py (1)
4164-4170: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winDelay the multiline template check for better performance.
Currently,
IsMultilineFunctionTemplateDeclarationruns for every line in the file. This results in unnecessary backward string scanning and regex evaluations for the vast majority of lines (e.g., inside function bodies or outside namespaces).Moving this check inside the
ShouldCheckNamespaceIndentationblock ensures we only incur this cost for lines that are actually candidates for the namespace indentation warning.⚡ Proposed refactor
- if IsMultilineFunctionTemplateDeclaration(clean_lines, line): - return - if ShouldCheckNamespaceIndentation( nesting_state, is_namespace_indent_item, clean_lines.elided, line ): + if IsMultilineFunctionTemplateDeclaration(clean_lines, line): + return CheckItemIndentationInNamespace(filename, clean_lines.elided, line, error)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cpplint.py` around lines 4164 - 4170, Move the IsMultilineFunctionTemplateDeclaration check inside the ShouldCheckNamespaceIndentation conditional, after confirming the line is a namespace-indentation candidate and before calling CheckItemIndentationInNamespace; remove the unconditional early return so the expensive scan is skipped for unrelated lines.cpplint_unittest.py (1)
326-357: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a test case for function template definitions.
The tests added here only cover function template declarations. To ensure that function template definitions (which include a
{block) are also correctly exempted from false positive warnings and don't regress in the future, consider adding a test case for them. This will also verify the bug fix proposed incpplint.py.🧪 Proposed test addition
] assert self.GetNamespaceResults(lines) == "" + lines = [ + "namespace Test {", + "template <typename Type1,", + " typename Type2>", + "void TestFunc(const Type1 &var1, Type2 &var2) {", + "}", + "} // namespace Test", + ] + assert self.GetNamespaceResults(lines) == "" + def testNamespaceIndentationIndentedMultilineFunctionTemplateDeclaration(self):🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cpplint_unittest.py` around lines 326 - 357, Add coverage in the namespace indentation tests for multiline function template definitions, including a body block with `{`, and verify correctly aligned definitions produce no warnings while indented definitions report the expected namespace-indentation violations. Extend the existing test methods near testNamespaceIndentationMultilineFunctionTemplateDeclaration, reusing GetNamespaceResults and the established declaration expectations.
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@cpplint.py`:
- Around line 7408-7415: Update the declaration handling around the existing
function-template detection to isolate the signature by splitting on either “;”
or “{” before checking for braces and matching the function name. Preserve the
existing exemptions for empty declarations, class/enum/struct/using
declarations, and assignment operators while allowing function template
definitions to return the same result as declarations.
---
Nitpick comments:
In `@cpplint_unittest.py`:
- Around line 326-357: Add coverage in the namespace indentation tests for
multiline function template definitions, including a body block with `{`, and
verify correctly aligned definitions produce no warnings while indented
definitions report the expected namespace-indentation violations. Extend the
existing test methods near
testNamespaceIndentationMultilineFunctionTemplateDeclaration, reusing
GetNamespaceResults and the established declaration expectations.
In `@cpplint.py`:
- Around line 4164-4170: Move the IsMultilineFunctionTemplateDeclaration check
inside the ShouldCheckNamespaceIndentation conditional, after confirming the
line is a namespace-indentation candidate and before calling
CheckItemIndentationInNamespace; remove the unconditional early return so the
expensive scan is skipped for unrelated lines.
Fix all unresolved CodeRabbit comments on this PR:
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 484524ee-ff9f-4aef-8dc6-575e23645c1c
CHANGELOG.rstcpplint.pycpplint_unittest.pysamples/boost-sample/simple.def
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| declaration = declaration.strip() | ||
| if not declaration or "{" in declaration.split(";", 1)[0]: | ||
| return False | ||
| if re.match(r"(?:class|enum|struct|using)\b", declaration): | ||
| return False | ||
|
|
||
| function = re.search(r"\b(?:operator\s*\S+|~?[A-Za-z_]\w*)\s*\(", declaration) | ||
| return function is not None and "=" not in declaration[: function.start()] |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Fix false positives for function template definitions.
The current logic correctly exempts function template declarations but fails for function template definitions (which have a { before any ;). Because "{" in declaration.split(";", 1)[0] evaluates to True for definitions, the function returns False, causing the continuation lines of a function template definition's parameters to still trigger false positive indentation warnings.
To support both declarations and definitions, we can split on both ; and { to isolate the signature, and then run the existing checks on it.
declaration = declaration.strip() - if not declaration or "{" in declaration.split(";", 1)[0]: + if not declaration: return False - if re.match(r"(?:class|enum|struct|using)\b", declaration): + + decl_head = re.split(r"[;{]", declaration, 1)[0].strip() + if re.match(r"(?:class|enum|struct|using)\b", decl_head): return False - function = re.search(r"\b(?:operator\s*\S+|~?[A-Za-z_]\w*)\s*\(", declaration) - return function is not None and "=" not in declaration[: function.start()] + function = re.search(r"\b(?:operator\s*\S+|~?[A-Za-z_]\w*)\s*\(", decl_head) + return function is not None and "=" not in decl_head[: function.start()]
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| declaration = declaration.strip() | |
| if not declaration or "{" in declaration.split(";", 1)[0]: | |
| return False | |
| if re.match(r"(?:class|enum|struct|using)\b", declaration): | |
| return False | |
| function = re.search(r"\b(?:operator\s*\S+|~?[A-Za-z_]\w*)\s*\(", declaration) | |
| return function is not None and "=" not in declaration[: function.start()] | |
| declaration = declaration.strip() | |
| if not declaration: | |
| return False | |
| decl_head = re.split(r"[;{]", declaration, 1)[0].strip() | |
| if re.match(r"(?:class|enum|struct|using)\b", decl_head): | |
| return False | |
| function = re.search(r"\b(?:operator\s*\S+|~?[A-Za-z_]\w*)\s*\(", decl_head) | |
| return function is not None and "=" not in decl_head[: function.start()] |
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@cpplint.py` around lines 7408 - 7415, Update the declaration handling around
the existing function-template detection to isolate the signature by splitting
on either “;” or “{” before checking for braces and matching the function name.
Preserve the existing exemptions for empty declarations, class/enum/struct/using
declarations, and assignment operators while allowing function template
definitions to return the same result as declarations.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I reproduced this on the PR head:
Please treat the signature as the text before either |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I have reviewed it locally: "pytest cpplint_unittest.py -k NamespaceIndentation" passes
(6 passed), and a manual repro confirms the behaviour, a
"template <...>\nvoid F(...)" continuation at column 0 no longer triggers
"whitespace/indent_namespace", while the same template indented is still
flagged twice (matches the negative test). The boost-sample delta
(2900->2898, octonion.hpp:675-676) lines up with the intended removal.
The fix is well-targeted: IsMultilineFunctionTemplateDeclaration only
suppresses lines that fall within a multiline "template<...>" span whose
post-">" declaration resolves to a function, and it correctly bails for
class/struct/enum/using so template type declarations stay checked.
One non-blocking suggestion: the class/struct/enum/using exclusion branch
isn't directly covered — adding a case (e.g. a multiline
"template<...>\n class Foo;" indented) asserting it's still flagged would
lock that distinction in against future regressions.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
In general, I'm not sure why we should bail if it's not a function. Was the F+ triggerable with template usage in non-functions too?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| results = self.GetNamespaceResults(lines) | ||
| assert results == "" | ||
|
|
||
| def testNamespaceIndentationMultilineFunctionTemplateDeclaration(self): |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
We should probably have a test for definition too.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| ] | ||
| assert self.GetNamespaceResults(lines) == "" | ||
|
|
||
| def testNamespaceIndentationIndentedMultilineFunctionTemplateDeclaration(self): |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
This method split seems unnecessary.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| include/boost/math/octonion.hpp:673: Line ends in whitespace. Consider deleting these extra spaces. [whitespace/end_of_line] [4] | ||
| include/boost/math/octonion.hpp:674: Do not indent within a namespace. [whitespace/indent_namespace] [4] | ||
| include/boost/math/octonion.hpp:675: Do not indent within a namespace. [whitespace/indent_namespace] [4] | ||
| include/boost/math/octonion.hpp:676: Do not indent within a namespace. [whitespace/indent_namespace] [4] |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
False negative.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| """Checks whether a line continues a function template declaration.""" | ||
| for start_line in range(linenum - 1, -1, -1): | ||
| line = clean_lines.elided[start_line] | ||
| if re.search(r"[;{}]", line): |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
why not
| if re.search(r"[;{}]", line): | |
| if any((c in set(";{}")) for c in line): |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| or (isinstance(nesting_state.previous_stack_top, _NamespaceInfo)) | ||
| ) | ||
|
|
||
| if IsMultilineFunctionTemplateDeclaration(clean_lines, line): |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Should be part of ShouldCheckNamespaceIndentation()
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| declaration = clean_lines.elided[end_line][end_pos:] | ||
| for next_line in range(end_line + 1, clean_lines.NumLines()): | ||
| declaration += " " + clean_lines.elided[next_line].strip() | ||
| if re.search(r"[;{}]", declaration): |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| if re.search(r"[;{}]", line): | ||
| return False | ||
|
|
||
| if template := re.search(r"\btemplate\s*<", line): |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
seems more pythonic to have an early exit instead of an implicit else to me
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| if not start_line < linenum <= end_line or end_pos < 0: | ||
| return False | ||
|
|
||
| declaration = clean_lines.elided[end_line][end_pos:] |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
We should probably strip here instead of at 7408.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| break | ||
|
|
||
| declaration = declaration.strip() | ||
| if not declaration or "{" in declaration.split(";", 1)[0]: |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
What kind of false positive are we avoiding here? Wouldn't this stop functions with both template and definition from being exempted?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| lines = [ | ||
| "namespace Test {", | ||
| " template <typename Type1,", | ||
| " typename Type2>", | ||
| " void TestFunc(const Type1 &var1, Type2 &var2);", | ||
| "} // namespace Test", | ||
| ] | ||
| assert self.GetNamespaceResults(lines) == [ | ||
| "Do not indent within a namespace. [whitespace/indent_namespace] [4]", | ||
| "Do not indent within a namespace. [whitespace/indent_namespace] [4]", | ||
| ] |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I don't think this does what you think it does. If it was erroring for truly indented, we would see three errors instead of two. It is a compelling design decision (performance for a pretty niche case, and we'd have errored on the starting line already) whether we even want to check for this kind of false negative (see also the Boost sample's F- above), but this makes codereaders thought it still emits on the F- when it does not.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@aaronliu0130, tested it, and you're right: the F+ fires for non-function Only the function-declaration case is cleaned up, so the function-only |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Even within the function-declaration scope of this change, the template-span scan still misses valid continuation lines when an earlier template parameter contains braces or a semicolon. For example:
namespace Test { template <typename T, bool Valid = requires { typename T::value_type; }, typename U = void> void Func(); } // namespace Test
On cd67aa7, the typename U = void line still emits whitespace/indent_namespace. IsMultilineFunctionTemplateDeclaration() walks backward and returns at [;{}] before finding the enclosing template <, even though those tokens belong to the requires-expression inside the template parameter list.
Please identify the enclosing template-parameter span before treating statement delimiters as boundaries, and add a regression with a later continuation line after a requires-expression or braced default argument. The full suite passes (227 passed), so this boundary currently has no focused coverage.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Rechecked current head cd67aa7.
The existing requires-expression boundary blocker is still present: the backward scan treats ;, {, or } inside a template parameter's requires-expression as statement boundaries before it reaches the enclosing template <...>, so later continuation lines remain false positives.
Please identify the enclosing template-parameter span before applying declaration delimiters and add the requires-expression regression already described in review.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I re-investigated the remaining review blockers and prepared a rebased version of this PR on current Ready branch: Commit: The updated implementation addresses the outstanding cases:
It is rebased onto Local validation on the committed state:
I cannot update this PR directly because its head branch is in The ready branch above can be fetched and used to update |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Revalidated at exact head cd67aa7.
I independently reproduced the already-reported blockers on this head.
For example:
namespace Test { template <typename T, bool Valid = requires { typename T::value_type; }, typename U = void> void Func(); } // namespace Test The later template continuation still emits whitespace/indent_namespace. The current implementation also still misses: multiline function-template definitions, because the { in the definition causes IsMultilineFunctionTemplateDeclaration() to reject the declaration continuation lines after an inner template-template parameter, because the scan stops at the first non-enclosing template <...> span instead of continuing to the outer span So the implementation remains incomplete for the reported scope. I re-ran the relevant validation on this exact head: namespace-focused tests: 6 passed full cpplint_unittest.py: 207 passed Pylint: passed Mypy: passed pre-commit: passed git diff --check: passed Please resolve the enclosing-span-before-delimiter handling, function-definition signature boundary, and outermost-template-span selection, with regressions for requires-expression continuations, definitions, and nested template-template parameters.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Requested changes must be addressed to merge this pull request.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
Several false positives for whitespace/indent_namespace
There was an error while loading. Please reload this page.