diff --git a/src/items.rs b/src/items.rs index a2c0e8e0f50..4978a62ca01 100644 --- a/src/items.rs +++ b/src/items.rs @@ -2465,10 +2465,31 @@ fn rewrite_fn_base( let where_clause = &fn_sig.generics.where_clause; let mut result = String::with_capacity(1024); - result.push_str(&fn_sig.to_str(context)); - // fn foo - result.push_str("fn "); + // Everything before `fn` + let before_ident_span = mk_sp(span.lo(), ident.span.lo()); + let fn_lo = context + .snippet_provider + .span_before_last(before_ident_span, "fn"); + let span_before_fn = mk_sp(span.lo(), fn_lo); + + if file_lines_contains!(context, span_before_fn) { + result.push_str(&fn_sig.to_str(context)); + } else { + result.push_str(context.snippet(mk_sp(span_before_fn.lo(), fn_lo))); + } + + result.push_str("fn"); + + // If both `fn` and the ident are selected, put them both on the same line. + // Otherwise, preserve the snippet between `fn` and the ident. + let fn_ident_span = mk_sp(fn_lo, ident.span.hi()); + if file_lines_contains!(context, fn_ident_span) { + result.push(' '); + } else { + let fn_hi = fn_lo + BytePos(2); + result.push_str(context.snippet(mk_sp(fn_hi, ident.span.lo()))); + } // Generics. let overhead = if let FnBraceStyle::SameLine = fn_brace_style { diff --git a/src/source_map.rs b/src/source_map.rs index 76e0d24cf1e..fc8bd9476a5 100644 --- a/src/source_map.rs +++ b/src/source_map.rs @@ -65,7 +65,7 @@ impl SpanUtils for SnippetProvider { offset += additional_offset + needle.len(); } - original.lo() + BytePos(offset as u32 - 1) + original.lo() + BytePos(offset as u32 - needle.len() as u32) } fn opt_span_after(&self, original: Span, needle: &str) -> Option { diff --git a/src/utils.rs b/src/utils.rs index b676803379f..fed60101171 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -381,6 +381,16 @@ macro_rules! out_of_file_lines_range { }; } +/// Returns `true` if the given span is fully contained by the selected file lines. +macro_rules! file_lines_contains { + ($self:ident, $span:expr) => { + $self + .config + .file_lines() + .contains(&$self.psess.lookup_line_range($span)) + }; +} + macro_rules! skip_out_of_file_lines_range_err { ($self:ident, $span:expr) => { if out_of_file_lines_range!($self, $span) { diff --git a/tests/source/issue-6868-before-fn/fn_and_ident.rs b/tests/source/issue-6868-before-fn/fn_and_ident.rs new file mode 100644 index 00000000000..aad742288ef --- /dev/null +++ b/tests/source/issue-6868-before-fn/fn_and_ident.rs @@ -0,0 +1,16 @@ +// rustfmt-file_lines: [{"file":"tests/source/issue-6868-before-fn/fn_and_ident.rs","range":[11,12]}] + +pub +( +crate +) +const +unsafe +extern +"C" +fn +foo +( +) +{ +} diff --git a/tests/source/issue-6868-before-fn/fully_selected.rs b/tests/source/issue-6868-before-fn/fully_selected.rs new file mode 100644 index 00000000000..4a3195dfa4d --- /dev/null +++ b/tests/source/issue-6868-before-fn/fully_selected.rs @@ -0,0 +1,16 @@ +// rustfmt-file_lines: [{"file":"tests/source/issue-6868-before-fn/fully_selected.rs","range":[3,11]}] + +pub +( +crate +) +const +unsafe +extern +"C" +fn +foo +( +) +{ +} diff --git a/tests/source/issue-6868-before-fn/partial.rs b/tests/source/issue-6868-before-fn/partial.rs new file mode 100644 index 00000000000..2166f691b60 --- /dev/null +++ b/tests/source/issue-6868-before-fn/partial.rs @@ -0,0 +1,16 @@ +// rustfmt-file_lines: [{"file":"tests/source/issue-6868-before-fn/partial.rs","range":[7,8]}] + +pub +( +crate +) +const +unsafe +extern +"C" +fn +foo +( +) +{ +} diff --git a/tests/source/issue-6868-before-fn/unselected.rs b/tests/source/issue-6868-before-fn/unselected.rs new file mode 100644 index 00000000000..510334a2b79 --- /dev/null +++ b/tests/source/issue-6868-before-fn/unselected.rs @@ -0,0 +1,16 @@ +// rustfmt-file_lines: [{"file":"tests/source/issue-6868-before-fn/unselected.rs","range":[11,14]}] + +pub +( +crate +) +const +unsafe +extern +"C" +fn +foo +( +) +{ +} diff --git a/tests/target/issue-6868-before-fn/fn_and_ident.rs b/tests/target/issue-6868-before-fn/fn_and_ident.rs new file mode 100644 index 00000000000..5e2d24580a8 --- /dev/null +++ b/tests/target/issue-6868-before-fn/fn_and_ident.rs @@ -0,0 +1,12 @@ +// rustfmt-file_lines: [{"file":"tests/source/issue-6868-before-fn/fn_and_ident.rs","range":[11,12]}] + +pub +( +crate +) +const +unsafe +extern +"C" +fn foo() { +} diff --git a/tests/target/issue-6868-before-fn/fully_selected.rs b/tests/target/issue-6868-before-fn/fully_selected.rs new file mode 100644 index 00000000000..2f78aa6ae0a --- /dev/null +++ b/tests/target/issue-6868-before-fn/fully_selected.rs @@ -0,0 +1,5 @@ +// rustfmt-file_lines: [{"file":"tests/source/issue-6868-before-fn/fully_selected.rs","range":[3,11]}] + +pub(crate) const unsafe extern "C" fn +foo() { +} diff --git a/tests/target/issue-6868-before-fn/partial.rs b/tests/target/issue-6868-before-fn/partial.rs new file mode 100644 index 00000000000..50bc2f433a3 --- /dev/null +++ b/tests/target/issue-6868-before-fn/partial.rs @@ -0,0 +1,13 @@ +// rustfmt-file_lines: [{"file":"tests/source/issue-6868-before-fn/partial.rs","range":[7,8]}] + +pub +( +crate +) +const +unsafe +extern +"C" +fn +foo() { +} diff --git a/tests/target/issue-6868-before-fn/unselected.rs b/tests/target/issue-6868-before-fn/unselected.rs new file mode 100644 index 00000000000..c9d9ef162c7 --- /dev/null +++ b/tests/target/issue-6868-before-fn/unselected.rs @@ -0,0 +1,12 @@ +// rustfmt-file_lines: [{"file":"tests/source/issue-6868-before-fn/unselected.rs","range":[11,14]}] + +pub +( +crate +) +const +unsafe +extern +"C" +fn foo() { +}