-
Notifications
You must be signed in to change notification settings - Fork 312
fix: handle multiline function templates in namespaces #447
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4161,6 +4161,9 @@ def CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line, err | |||||||||||||||||||||||||||||||||||||
| or (isinstance(nesting_state.previous_stack_top, _NamespaceInfo)) | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if IsMultilineFunctionTemplateDeclaration(clean_lines, line): | ||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if ShouldCheckNamespaceIndentation( | ||||||||||||||||||||||||||||||||||||||
| nesting_state, is_namespace_indent_item, clean_lines.elided, line | ||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -7384,6 +7387,36 @@ def IsBlockInNameSpace(nesting_state: NestingState, is_forward_declaration: bool | |||||||||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| def IsMultilineFunctionTemplateDeclaration(clean_lines, linenum): | ||||||||||||||||||||||||||||||||||||||
| """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): | ||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not
Suggested change
|
||||||||||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if template := re.search(r"\btemplate\s*<", line): | ||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||||||||||||||||||||||||||||||||||||||
| _, end_line, end_pos = CloseExpression(clean_lines, start_line, template.end() - 1) | ||||||||||||||||||||||||||||||||||||||
| if not start_line < linenum <= end_line or end_pos < 0: | ||||||||||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| declaration = clean_lines.elided[end_line][end_pos:] | ||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably strip here instead of at 7408. |
||||||||||||||||||||||||||||||||||||||
| for next_line in range(end_line + 1, clean_lines.NumLines()): | ||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. consider iterating over a slice |
||||||||||||||||||||||||||||||||||||||
| declaration += " " + clean_lines.elided[next_line].strip() | ||||||||||||||||||||||||||||||||||||||
| if re.search(r"[;{}]", declaration): | ||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||||||||||||
| break | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| declaration = declaration.strip() | ||||||||||||||||||||||||||||||||||||||
| if not declaration or "{" in declaration.split(";", 1)[0]: | ||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? |
||||||||||||||||||||||||||||||||||||||
| 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()] | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+7408
to
+7415
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 To support both declarations and definitions, we can split on both 🐛 Proposed fix 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()]📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| return False | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| def ShouldCheckNamespaceIndentation( | ||||||||||||||||||||||||||||||||||||||
| nesting_state: NestingState, is_namespace_indent_item, raw_lines_no_comments, linenum | ||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -323,6 +323,38 @@ def testNamespaceIndentationIndentedParameter(self): | |
| results = self.GetNamespaceResults(lines) | ||
| assert results == "" | ||
|
|
||
| def testNamespaceIndentationMultilineFunctionTemplateDeclaration(self): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably have a test for definition too. |
||
| lines = [ | ||
| "namespace Test {", | ||
| "template <typename Type1,", | ||
| " typename Type2>", | ||
| "void TestFunc(const Type1 &var1, Type2 &var2);", | ||
| "} // namespace Test", | ||
| ] | ||
| assert self.GetNamespaceResults(lines) == "" | ||
|
|
||
| lines = [ | ||
| "namespace Test {", | ||
| "template <typename T,", | ||
| " typename Callback = void (*)(T)>", | ||
| "void Register(Callback callback);", | ||
| "} // namespace Test", | ||
| ] | ||
| assert self.GetNamespaceResults(lines) == "" | ||
|
|
||
| def testNamespaceIndentationIndentedMultilineFunctionTemplateDeclaration(self): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method split seems unnecessary. |
||
| 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]", | ||
| ] | ||
|
Comment on lines
+346
to
+356
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
|
|
||
| def testNamespaceIndentationMemberInitializerList(self): | ||
| lines = [ | ||
| "namespace Opossum {", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,7 @@ include/boost/math/* | |
| 1 | ||
| 3 | ||
| Done processing include/boost/math/octonion.hpp | ||
| Total errors found: 2900 | ||
| Total errors found: 2898 | ||
|
|
||
| include/boost/math/octonion.hpp:11: #ifndef header guard has wrong style, please use: SAMPLES_BOOST_SAMPLE_INCLUDE_BOOST_MATH_OCTONION_HPP_ [build/header_guard] [5] | ||
| include/boost/math/octonion.hpp:4250: #endif line should be "#endif // SAMPLES_BOOST_SAMPLE_INCLUDE_BOOST_MATH_OCTONION_HPP_" [build/header_guard] [5] | ||
|
|
@@ -290,8 +290,6 @@ include/boost/math/octonion.hpp:672: { should almost always be at the end of th | |
| include/boost/math/octonion.hpp:673: Do not indent within a namespace. [whitespace/indent_namespace] [4] | ||
| 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] | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. False negative. |
||
| include/boost/math/octonion.hpp:677: Do not indent within a namespace. [whitespace/indent_namespace] [4] | ||
| include/boost/math/octonion.hpp:678: Do not indent within a namespace. [whitespace/indent_namespace] [4] | ||
| include/boost/math/octonion.hpp:679: Do not indent within a namespace. [whitespace/indent_namespace] [4] | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be part of ShouldCheckNamespaceIndentation()