Support single-line functions
By default, places functions with empty bodies on one line. If the function has only one expression or statement that fits on one line, the 'fn_single_line' option can be used.
This commit is contained in:
parent
f09aa85798
commit
4d7de5a16e
@ -269,6 +269,7 @@ fn default() -> Config {
|
||||
newline_style: NewlineStyle, NewlineStyle::Unix, "Unix or Windows line endings";
|
||||
fn_brace_style: BraceStyle, BraceStyle::SameLineWhere, "Brace style for functions";
|
||||
item_brace_style: BraceStyle, BraceStyle::SameLineWhere, "Brace style for structs and enums";
|
||||
fn_single_line: bool, false, "Put single-expression functions on a single line";
|
||||
fn_return_indent: ReturnIndent, ReturnIndent::WithArgs,
|
||||
"Location of return type in function declaration";
|
||||
fn_args_paren_newline: bool, true, "If function argument parenthesis goes on a newline";
|
||||
|
101
src/items.rs
101
src/items.rs
@ -12,17 +12,17 @@
|
||||
|
||||
use Indent;
|
||||
use utils::{format_mutability, format_visibility, contains_skip, span_after, end_typaram,
|
||||
wrap_str, last_line_width};
|
||||
wrap_str, last_line_width, semicolon_for_expr, semicolon_for_stmt};
|
||||
use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic,
|
||||
DefinitiveListTactic, definitive_tactic, format_item_list};
|
||||
use expr::rewrite_assign_rhs;
|
||||
use comment::FindUncommented;
|
||||
use comment::{FindUncommented, contains_comment};
|
||||
use visitor::FmtVisitor;
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
use config::{Config, BlockIndentStyle, Density, ReturnIndent, BraceStyle, StructLitStyle};
|
||||
|
||||
use syntax::{ast, abi};
|
||||
use syntax::codemap::{Span, BytePos, mk_sp};
|
||||
use syntax::codemap::{Span, BytePos, CodeMap, mk_sp};
|
||||
use syntax::print::pprust;
|
||||
use syntax::parse::token;
|
||||
|
||||
@ -447,6 +447,81 @@ fn rewrite_fn_base(&mut self,
|
||||
Some((result, force_new_line_for_brace))
|
||||
}
|
||||
|
||||
pub fn rewrite_single_line_fn(&self,
|
||||
fn_rewrite: &Option<String>,
|
||||
block: &ast::Block)
|
||||
-> Option<String> {
|
||||
|
||||
let fn_str = match *fn_rewrite {
|
||||
Some(ref s) if !s.contains('\n') => s,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let codemap = self.get_context().codemap;
|
||||
|
||||
if is_empty_block(block, codemap) &&
|
||||
self.block_indent.width() + fn_str.len() + 3 <= self.config.max_width {
|
||||
return Some(format!("{}{{ }}", fn_str));
|
||||
}
|
||||
|
||||
if self.config.fn_single_line && is_simple_block_stmt(block, codemap) {
|
||||
let rewrite = {
|
||||
if let Some(ref e) = block.expr {
|
||||
let suffix = if semicolon_for_expr(e) {
|
||||
";"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
e.rewrite(&self.get_context(),
|
||||
self.config.max_width - self.block_indent.width(),
|
||||
self.block_indent)
|
||||
.map(|s| s + suffix)
|
||||
.or_else(|| Some(self.snippet(e.span)))
|
||||
} else if let Some(ref stmt) = block.stmts.first() {
|
||||
self.rewrite_stmt(stmt)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(res) = rewrite {
|
||||
let width = self.block_indent.width() + fn_str.len() + res.len() + 3;
|
||||
if !res.contains('\n') && width <= self.config.max_width {
|
||||
return Some(format!("{}{{ {} }}", fn_str, res));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn rewrite_stmt(&self, stmt: &ast::Stmt) -> Option<String> {
|
||||
match stmt.node {
|
||||
ast::Stmt_::StmtDecl(ref decl, _) => {
|
||||
if let ast::Decl_::DeclLocal(ref local) = decl.node {
|
||||
let context = self.get_context();
|
||||
local.rewrite(&context, self.config.max_width, self.block_indent)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
ast::Stmt_::StmtExpr(ref ex, _) | ast::Stmt_::StmtSemi(ref ex, _) => {
|
||||
let suffix = if semicolon_for_stmt(stmt) {
|
||||
";"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
ex.rewrite(&self.get_context(),
|
||||
self.config.max_width - self.block_indent.width() - suffix.len(),
|
||||
self.block_indent)
|
||||
.map(|s| s + suffix)
|
||||
}
|
||||
ast::Stmt_::StmtMac(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn rewrite_args(&self,
|
||||
args: &[ast::Arg],
|
||||
explicit_self: Option<&ast::ExplicitSelf>,
|
||||
@ -1317,3 +1392,23 @@ fn span_for_where_pred(pred: &ast::WherePredicate) -> Span {
|
||||
ast::WherePredicate::EqPredicate(ref p) => p.span,
|
||||
}
|
||||
}
|
||||
|
||||
// Checks whether a block contains at most one statement or expression, and no comments.
|
||||
fn is_simple_block_stmt(block: &ast::Block, codemap: &CodeMap) -> bool {
|
||||
if (!block.stmts.is_empty() && block.expr.is_some()) ||
|
||||
(block.stmts.len() != 1 && block.expr.is_none()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let snippet = codemap.span_to_snippet(block.span).unwrap();
|
||||
!contains_comment(&snippet)
|
||||
}
|
||||
|
||||
fn is_empty_block(block: &ast::Block, codemap: &CodeMap) -> bool {
|
||||
if !block.stmts.is_empty() || block.expr.is_some() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let snippet = codemap.span_to_snippet(block.span).unwrap();
|
||||
!contains_comment(&snippet)
|
||||
}
|
||||
|
27
src/utils.rs
27
src/utils.rs
@ -102,6 +102,33 @@ pub fn end_typaram(typaram: &ast::TyParam) -> BytePos {
|
||||
.hi
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn semicolon_for_expr(expr: &ast::Expr) -> bool {
|
||||
match expr.node {
|
||||
ast::Expr_::ExprRet(..) |
|
||||
ast::Expr_::ExprAgain(..) |
|
||||
ast::Expr_::ExprBreak(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn semicolon_for_stmt(stmt: &ast::Stmt) -> bool {
|
||||
match stmt.node {
|
||||
ast::Stmt_::StmtSemi(ref expr, _) => {
|
||||
match expr.node {
|
||||
ast::Expr_::ExprWhile(..) |
|
||||
ast::Expr_::ExprWhileLet(..) |
|
||||
ast::Expr_::ExprLoop(..) |
|
||||
ast::Expr_::ExprForLoop(..) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
ast::Stmt_::StmtExpr(..) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(target_pointer_width="64")]
|
||||
// Based on the trick layed out at
|
||||
|
@ -38,28 +38,15 @@ impl<'a> FmtVisitor<'a> {
|
||||
fn visit_stmt(&mut self, stmt: &ast::Stmt) {
|
||||
match stmt.node {
|
||||
ast::Stmt_::StmtDecl(ref decl, _) => {
|
||||
match decl.node {
|
||||
ast::Decl_::DeclLocal(ref local) => {
|
||||
let rewrite = {
|
||||
let context = self.get_context();
|
||||
local.rewrite(&context, self.config.max_width, self.block_indent)
|
||||
};
|
||||
self.push_rewrite(stmt.span, rewrite);
|
||||
}
|
||||
ast::Decl_::DeclItem(ref item) => self.visit_item(item),
|
||||
if let ast::Decl_::DeclItem(ref item) = decl.node {
|
||||
self.visit_item(item);
|
||||
} else {
|
||||
let rewrite = self.rewrite_stmt(stmt);
|
||||
self.push_rewrite(stmt.span, rewrite);
|
||||
}
|
||||
}
|
||||
ast::Stmt_::StmtExpr(ref ex, _) | ast::Stmt_::StmtSemi(ref ex, _) => {
|
||||
let suffix = if semicolon_for_stmt(stmt) {
|
||||
";"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let rewrite = ex.rewrite(&self.get_context(),
|
||||
self.config.max_width - self.block_indent.width() -
|
||||
suffix.len(),
|
||||
self.block_indent)
|
||||
.map(|s| s + suffix);
|
||||
ast::Stmt_::StmtExpr(..) | ast::Stmt_::StmtSemi(..) => {
|
||||
let rewrite = self.rewrite_stmt(stmt);
|
||||
self.push_rewrite(stmt.span, rewrite);
|
||||
}
|
||||
ast::Stmt_::StmtMac(ref mac, _macro_style) => {
|
||||
@ -101,7 +88,7 @@ pub fn visit_block(&mut self, b: &ast::Block) {
|
||||
self.buffer.push_str(&rewrite);
|
||||
self.last_pos = e.span.hi;
|
||||
|
||||
if semicolon_for_expr(e) {
|
||||
if utils::semicolon_for_expr(e) {
|
||||
self.buffer.push_str(";");
|
||||
}
|
||||
}
|
||||
@ -161,6 +148,13 @@ fn visit_fn(&mut self,
|
||||
visit::FnKind::Closure => None,
|
||||
};
|
||||
|
||||
if let Some(ref single_line_fn) = self.rewrite_single_line_fn(&rewrite, &b) {
|
||||
self.format_missing_with_indent(s.lo);
|
||||
self.buffer.push_str(single_line_fn);
|
||||
self.last_pos = b.span.hi;
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(fn_str) = rewrite {
|
||||
self.format_missing_with_indent(s.lo);
|
||||
self.buffer.push_str(&fn_str);
|
||||
@ -501,31 +495,6 @@ pub fn get_context(&self) -> RewriteContext {
|
||||
}
|
||||
}
|
||||
|
||||
fn semicolon_for_stmt(stmt: &ast::Stmt) -> bool {
|
||||
match stmt.node {
|
||||
ast::Stmt_::StmtSemi(ref expr, _) => {
|
||||
match expr.node {
|
||||
ast::Expr_::ExprWhile(..) |
|
||||
ast::Expr_::ExprWhileLet(..) |
|
||||
ast::Expr_::ExprLoop(..) |
|
||||
ast::Expr_::ExprForLoop(..) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
ast::Stmt_::StmtExpr(..) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn semicolon_for_expr(expr: &ast::Expr) -> bool {
|
||||
match expr.node {
|
||||
ast::Expr_::ExprRet(..) |
|
||||
ast::Expr_::ExprAgain(..) |
|
||||
ast::Expr_::ExprBreak(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Rewrite for [ast::Attribute] {
|
||||
fn rewrite(&self, context: &RewriteContext, _: usize, offset: Indent) -> Option<String> {
|
||||
let mut result = String::new();
|
||||
|
74
tests/source/fn-single-line.rs
Normal file
74
tests/source/fn-single-line.rs
Normal file
@ -0,0 +1,74 @@
|
||||
// rustfmt-fn_single_line: true
|
||||
// Test single-line functions.
|
||||
|
||||
fn foo_expr() {
|
||||
1
|
||||
}
|
||||
|
||||
fn foo_stmt() {
|
||||
foo();
|
||||
}
|
||||
|
||||
fn foo_decl_local() {
|
||||
let z = 5;
|
||||
}
|
||||
|
||||
fn foo_decl_item(x: &mut i32) {
|
||||
x = 3;
|
||||
}
|
||||
|
||||
fn empty() {
|
||||
|
||||
}
|
||||
|
||||
fn foo_return() -> String {
|
||||
"yay"
|
||||
}
|
||||
|
||||
fn foo_where() -> T where T: Sync {
|
||||
let x = 2;
|
||||
}
|
||||
|
||||
fn fooblock() {
|
||||
{
|
||||
"inner-block"
|
||||
}
|
||||
}
|
||||
|
||||
fn fooblock2(x: i32) {
|
||||
let z = match x {
|
||||
_ => 2,
|
||||
};
|
||||
}
|
||||
|
||||
fn comment() {
|
||||
// this is a test comment
|
||||
1
|
||||
}
|
||||
|
||||
fn comment2() {
|
||||
// multi-line comment
|
||||
let z = 2;
|
||||
1
|
||||
}
|
||||
|
||||
fn only_comment() {
|
||||
// Keep this here
|
||||
}
|
||||
|
||||
fn aaaaaaaaaaaaaaaaa_looooooooooooooooooooooong_name() {
|
||||
let z = "aaaaaaawwwwwwwwwwwwwwwwwwwwwwwwwwww";
|
||||
}
|
||||
|
||||
fn lots_of_space () {
|
||||
1
|
||||
}
|
||||
|
||||
trait CoolTypes {
|
||||
fn dummy(&self) {
|
||||
}
|
||||
}
|
||||
|
||||
trait CoolerTypes { fn dummy(&self) {
|
||||
}
|
||||
}
|
@ -13,8 +13,7 @@ impl Bar {
|
||||
/// Blah blah blooo.
|
||||
/// Blah blah blooo.
|
||||
#[an_attribute]
|
||||
fn foo(&mut self) -> isize {
|
||||
}
|
||||
fn foo(&mut self) -> isize { }
|
||||
|
||||
/// Blah blah bing.
|
||||
/// Blah blah bing.
|
||||
@ -28,8 +27,7 @@ pub fn f2(self) {
|
||||
}
|
||||
|
||||
#[another_attribute]
|
||||
fn f3(self) -> Dog {
|
||||
}
|
||||
fn f3(self) -> Dog { }
|
||||
|
||||
/// Blah blah bing.
|
||||
#[attrib1]
|
||||
@ -38,6 +36,5 @@ fn f3(self) -> Dog {
|
||||
// Another comment that needs rewrite because it's tooooooooooooooooooooooooooooooo
|
||||
// loooooooooooong.
|
||||
/// Blah blah bing.
|
||||
fn f4(self) -> Cat {
|
||||
}
|
||||
fn f4(self) -> Cat { }
|
||||
}
|
||||
|
@ -32,8 +32,7 @@ fn test() {
|
||||
}
|
||||
|
||||
/// test123
|
||||
fn doc_comment() {
|
||||
}
|
||||
fn doc_comment() { }
|
||||
|
||||
fn chains() {
|
||||
foo.bar(|| {
|
||||
|
@ -16,8 +16,6 @@ fn foo<F, G>(a: aaaaaaaaaaaaa, // A comment
|
||||
|
||||
}
|
||||
|
||||
fn bar<F /* comment on F */, G /* comment on G */>() {
|
||||
}
|
||||
fn bar<F /* comment on F */, G /* comment on G */>() { }
|
||||
|
||||
fn baz() -> Baz /* Comment after return type */ {
|
||||
}
|
||||
fn baz() -> Baz /* Comment after return type */ { }
|
||||
|
@ -28,15 +28,13 @@ fn generic<T>(arg: T) -> &SomeType
|
||||
arg(a, b, c, d, e)
|
||||
}
|
||||
|
||||
fn foo() -> ! {
|
||||
}
|
||||
fn foo() -> ! { }
|
||||
|
||||
pub fn http_fetch_async(listener: Box<AsyncCORSResponseListener + Send>,
|
||||
script_chan: Box<ScriptChan + Send>) {
|
||||
}
|
||||
|
||||
fn some_func<T: Box<Trait + Bound>>(val: T) {
|
||||
}
|
||||
fn some_func<T: Box<Trait + Bound>>(val: T) { }
|
||||
|
||||
fn zzzzzzzzzzzzzzzzzzzz<Type, NodeType>(selff: Type,
|
||||
mut handle: node::Handle<IdRef<'id, Node<K, V>>,
|
||||
|
61
tests/target/fn-single-line.rs
Normal file
61
tests/target/fn-single-line.rs
Normal file
@ -0,0 +1,61 @@
|
||||
// rustfmt-fn_single_line: true
|
||||
// Test single-line functions.
|
||||
|
||||
fn foo_expr() { 1 }
|
||||
|
||||
fn foo_stmt() { foo(); }
|
||||
|
||||
fn foo_decl_local() { let z = 5; }
|
||||
|
||||
fn foo_decl_item(x: &mut i32) { x = 3; }
|
||||
|
||||
fn empty() { }
|
||||
|
||||
fn foo_return() -> String { "yay" }
|
||||
|
||||
fn foo_where() -> T
|
||||
where T: Sync
|
||||
{
|
||||
let x = 2;
|
||||
}
|
||||
|
||||
fn fooblock() {
|
||||
{
|
||||
"inner-block"
|
||||
}
|
||||
}
|
||||
|
||||
fn fooblock2(x: i32) {
|
||||
let z = match x {
|
||||
_ => 2,
|
||||
};
|
||||
}
|
||||
|
||||
fn comment() {
|
||||
// this is a test comment
|
||||
1
|
||||
}
|
||||
|
||||
fn comment2() {
|
||||
// multi-line comment
|
||||
let z = 2;
|
||||
1
|
||||
}
|
||||
|
||||
fn only_comment() {
|
||||
// Keep this here
|
||||
}
|
||||
|
||||
fn aaaaaaaaaaaaaaaaa_looooooooooooooooooooooong_name() {
|
||||
let z = "aaaaaaawwwwwwwwwwwwwwwwwwwwwwwwwwww";
|
||||
}
|
||||
|
||||
fn lots_of_space() { 1 }
|
||||
|
||||
trait CoolTypes {
|
||||
fn dummy(&self) { }
|
||||
}
|
||||
|
||||
trait CoolerTypes {
|
||||
fn dummy(&self) { }
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
// Tests different fns
|
||||
|
||||
fn foo(a: AAAA, b: BBB, c: CCC) -> RetType {
|
||||
|
||||
}
|
||||
fn foo(a: AAAA, b: BBB, c: CCC) -> RetType { }
|
||||
|
||||
fn foo(a: AAAA, b: BBB /* some, weird, inline comment */, c: CCC) -> RetType
|
||||
where T: Blah
|
||||
@ -34,8 +32,7 @@ fn foo<U, T>(a: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,
|
||||
|
||||
}
|
||||
|
||||
fn foo<U: Fn(A) -> B /* paren inside generics */>() {
|
||||
}
|
||||
fn foo<U: Fn(A) -> B /* paren inside generics */>() { }
|
||||
|
||||
impl Foo {
|
||||
fn with_no_errors<T, F>(&mut self, f: F) -> T
|
||||
@ -43,11 +40,9 @@ fn with_no_errors<T, F>(&mut self, f: F) -> T
|
||||
{
|
||||
}
|
||||
|
||||
fn foo(mut self, mut bar: u32) {
|
||||
}
|
||||
fn foo(mut self, mut bar: u32) { }
|
||||
|
||||
fn bar(self, mut bazz: u32) {
|
||||
}
|
||||
fn bar(self, mut bazz: u32) { }
|
||||
}
|
||||
|
||||
pub fn render<'a,
|
||||
@ -75,12 +70,9 @@ const fn foo() {
|
||||
}
|
||||
}
|
||||
|
||||
fn homura<T: Deref<Target = i32>>(_: T) {
|
||||
fn homura<T: Deref<Target = i32>>(_: T) { }
|
||||
|
||||
}
|
||||
|
||||
fn issue377() -> (Box<CompositorProxy + Send>, Box<CompositorReceiver>) {
|
||||
}
|
||||
fn issue377() -> (Box<CompositorProxy + Send>, Box<CompositorReceiver>) { }
|
||||
|
||||
fn main() {
|
||||
let _ = function(move || 5);
|
||||
|
@ -26,9 +26,7 @@
|
||||
// sfdgfffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
// ffffffffffffffffffffffffffffffffffffffffff
|
||||
|
||||
fn foo(a: isize, b: u32 /* blah blah */, c: f64) {
|
||||
|
||||
}
|
||||
fn foo(a: isize, b: u32 /* blah blah */, c: f64) { }
|
||||
|
||||
fn foo() -> Box<Write + 'static>
|
||||
where 'a: 'b,
|
||||
@ -77,8 +75,7 @@ pub fn f2(self) {
|
||||
}
|
||||
|
||||
#[an_attribute]
|
||||
fn f3(self) -> Dog {
|
||||
}
|
||||
fn f3(self) -> Dog { }
|
||||
}
|
||||
|
||||
/// The `nodes` and `edges` method each return instantiations of
|
||||
@ -118,8 +115,7 @@ pub struct Foo<'a, Y: Baz>
|
||||
f: SomeType, // Comment beside a field
|
||||
}
|
||||
|
||||
fn foo(ann: &'a (PpAnn + 'a)) {
|
||||
}
|
||||
fn foo(ann: &'a (PpAnn + 'a)) { }
|
||||
|
||||
fn main() {
|
||||
for i in 0i32..4 {
|
||||
|
@ -1,4 +1,3 @@
|
||||
// A standard mod
|
||||
|
||||
fn a() {
|
||||
}
|
||||
fn a() { }
|
||||
|
@ -1,3 +1,2 @@
|
||||
// Another mod
|
||||
fn a() {
|
||||
}
|
||||
fn a() { }
|
||||
|
@ -3,5 +3,4 @@
|
||||
|
||||
use c::a;
|
||||
|
||||
fn foo() {
|
||||
}
|
||||
fn foo() { }
|
||||
|
@ -1,2 +1 @@
|
||||
fn main() {
|
||||
}
|
||||
fn main() { }
|
||||
|
@ -19,5 +19,4 @@ fn main() {
|
||||
let x: Foo<A>;
|
||||
}
|
||||
|
||||
fn op(foo: Bar, key: &[u8], upd: Fn(Option<&memcache::Item>, Baz) -> Result) -> MapResult {
|
||||
}
|
||||
fn op(foo: Bar, key: &[u8], upd: Fn(Option<&memcache::Item>, Baz) -> Result) -> MapResult { }
|
||||
|
Loading…
Reference in New Issue
Block a user