Skip to content
Merged
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
14 changes: 14 additions & 0 deletions inst/tinytest/test_rformat.R
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@ expect_true(
info = "Inline function body should be preserved"
)

# Multi-line function header + bare if body + expand_if (regression)
# The signature collapse used to leave blank lines between function(...)
# and the body, making it look like two separate statements.
code <- "`%||%` <- function(\n x,\n y\n) if (is.null(x)) y else x"
result <- rformat(code, control_braces = "multi", expand_if = TRUE)
expect_true(
!is.null(tryCatch(parse(text = result), error = function(e) NULL)),
info = "Collapsed signature with bare if body should still parse"
)
expect_false(
grepl("function\\(x, y\\)\\s*\\n\\s*\\n", result),
info = "No blank line should separate collapsed signature from its bare body"
)

# Nested parentheses collapse (regression test)
# Short nested calls should collapse to a single line
code <- "tryCatch(
Expand Down
29 changes: 29 additions & 0 deletions src/funcdef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,42 @@ void reformat_function_defs(std::vector<Token>& tokens,
need_change = true;
if (!need_change) continue;

// Record the last line the signature currently occupies so we
// can close any gap between the collapsed signature and a
// bare (braceless) body.
int old_sig_end_line = tokens[fi].out_line;
for (int k = fi; k <= close_idx; k++) {
if (tokens[k].out_line > old_sig_end_line)
old_sig_end_line = tokens[k].out_line;
}
for (int c : comma_indices) {
if (tokens[c].out_line > old_sig_end_line)
old_sig_end_line = tokens[c].out_line;
}

for (int k = fi; k <= close_idx; k++)
tokens[k].out_line = func_line;
for (int c : comma_indices)
tokens[c].out_line = func_line;
if (has_brace)
tokens[brace_idx].out_line = func_line;

// Close the gap for a bare-body function: shift any tokens
// that lived on the old signature's trailing lines up so the
// body stays adjacent to the collapsed signature.
if (!has_brace && old_sig_end_line > func_line) {
int shift = old_sig_end_line - func_line;
for (int k = 0; k < n; k++) {
if (tokens[k].out_line >= old_sig_end_line + 1) {
tokens[k].out_line -= shift;
} else if (tokens[k].out_line == old_sig_end_line) {
// Body tokens that shared the old close-paren
// line now belong on func_line.
tokens[k].out_line = func_line;
}
}
}

reorder_tokens(tokens);
changed = true;
break;
Expand Down