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
22 changes: 21 additions & 1 deletion desloppify/languages/csharp/_parse_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,47 @@ def find_matching_brace(content: str, open_pos: int) -> int | None:
depth = 0
in_string: str | None = None
escape = False
for i in range(open_pos, len(content)):
i = open_pos
length = len(content)
while i < length:
ch = content[i]
if in_string:
if escape:
escape = False
i += 1
continue
if ch == "\\":
escape = True
i += 1
continue
if ch == in_string:
in_string = None
i += 1
continue
if ch in ("'", '"'):
in_string = ch
i += 1
continue
if ch == "/" and i + 1 < length and content[i + 1] == "*":
i += 2
while i + 1 < length:
if content[i] == "*" and content[i + 1] == "/":
i += 2
break
i += 1
continue
if ch == "/" and i + 1 < length and content[i + 1] == "/":
i += 2
while i < length and content[i] != "\n":
i += 1
continue
if ch == "{":
depth += 1
elif ch == "}":
depth -= 1
if depth == 0:
return i
i += 1
return None


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ def test_empty_body(self):
content = "{}"
assert find_matching_brace(content, 0) == 1

def test_skips_block_comments_with_unbalanced_braces(self):
content = "{ /* } }} {{{ */ return 1; }"
assert find_matching_brace(content, 0) == len(content) - 1

def test_skips_line_comments_with_unbalanced_braces(self):
content = "{ // } }}\n return 1; }"
assert find_matching_brace(content, 0) == len(content) - 1


class TestFindExpressionEnd:
def test_simple(self):
Expand Down
22 changes: 21 additions & 1 deletion desloppify/languages/cxx/_parse_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,47 @@ def find_matching_brace(content: str, open_pos: int) -> int | None:
depth = 0
in_string: str | None = None
escape = False
for i in range(open_pos, len(content)):
i = open_pos
length = len(content)
while i < length:
ch = content[i]
if in_string:
if escape:
escape = False
i += 1
continue
if ch == "\\":
escape = True
i += 1
continue
if ch == in_string:
in_string = None
i += 1
continue
if ch in ("'", '"'):
in_string = ch
i += 1
continue
if ch == "/" and i + 1 < length and content[i + 1] == "*":
i += 2
while i + 1 < length:
if content[i] == "*" and content[i + 1] == "/":
i += 2
break
i += 1
continue
if ch == "/" and i + 1 < length and content[i + 1] == "/":
i += 2
while i < length and content[i] != "\n":
i += 1
continue
if ch == "{":
depth += 1
elif ch == "}":
depth -= 1
if depth == 0:
return i
i += 1
return None


Expand Down
28 changes: 27 additions & 1 deletion desloppify/languages/cxx/tests/test_extractors.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,30 @@ def test_find_cxx_files_includes_common_header_only_extensions(tmp_path):


def test_cxx_extractors_use_local_brace_helper():
assert cxx_extractors.find_matching_brace.__module__ == "desloppify.languages.cxx._parse_helpers"
assert cxx_extractors.find_matching_brace.__module__ == "desloppify.languages.cxx._parse_helpers"


def test_extract_function_with_unbalanced_brace_in_comment(tmp_path):
source = tmp_path / "test.cpp"
source.write_text(
"""void validateInput() {
/* Validate against old schema:
{ "type": "required" }
See ticket #1234 for context }
*/
if (input.isValid()) {
return;
}
throw std::runtime_error("Invalid");
}
""",
encoding="utf-8",
)

functions = extract_all_cxx_functions([str(source)])

assert len(functions) == 1
func = functions[0]
assert func.name == "validateInput"
assert func.end_line == 10
assert "input.isValid()" in func.body
32 changes: 32 additions & 0 deletions desloppify/languages/dart/tests/test_extractors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Tests for Dart regex-based function extraction."""

from __future__ import annotations

from desloppify.languages.dart.extractors import extract_dart_functions


def test_extract_dart_functions_ignores_unbalanced_braces_inside_comments(tmp_path):
source = tmp_path / "lib" / "app.dart"
source.parent.mkdir(parents=True, exist_ok=True)
source.write_text(
"""void validateInput() {
/* Validate against old schema:
{ "type": "required" }
See ticket #1234 for context }
*/
if (input.isValid()) {
return;
}
throw StateError("Invalid");
}
""",
encoding="utf-8",
)

functions = extract_dart_functions(str(source))

assert len(functions) == 1
func = functions[0]
assert func.name == "validateInput"
assert func.end_line == 10
assert "input.isValid()" in func.body
16 changes: 15 additions & 1 deletion desloppify/languages/rust/extractors.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ def _find_matching_brace(content: str, open_pos: int) -> int | None:
depth = 0
in_string: str | None = None
i = open_pos
while i < len(content):
length = len(content)
while i < length:
char = content[i]
if in_string:
if char == "\\":
Expand All @@ -95,6 +96,19 @@ def _find_matching_brace(content: str, open_pos: int) -> int | None:
in_string = char
i += 1
continue
if char == "/" and i + 1 < length and content[i + 1] == "*":
i += 2
while i + 1 < length:
if content[i] == "*" and content[i + 1] == "/":
i += 2
break
i += 1
continue
if char == "/" and i + 1 < length and content[i + 1] == "/":
i += 2
while i < length and content[i] != "\n":
i += 1
continue
if char == "{":
depth += 1
elif char == "}":
Expand Down
27 changes: 27 additions & 0 deletions desloppify/languages/rust/tests/test_extractors.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,30 @@ def test_normalize_rust_body_strips_comments_and_logging():
assert "// comment" not in normalized
assert "println!" not in normalized
assert "let value = 1;" in normalized


def test_extract_rust_functions_ignores_unbalanced_braces_inside_comments(tmp_path):
filepath = _write(
tmp_path,
"src/lib.rs",
"""
pub fn validate_input() {
/* Validate against old schema:
{ "type": "required" }
See ticket #1234 for context }
*/
if input_is_valid() {
return;
}
panic!("Invalid");
}
""",
)

functions = extract_rust_functions(filepath)

assert len(functions) == 1
func = functions[0]
assert func.name == "validate_input"
assert func.end_line == 11
assert "input_is_valid()" in func.body