Merge pull request #628 from kyeah/single-line-fn

Single-line Functions
This commit is contained in:
Nick Cameron 2015-11-20 18:13:03 +13:00
commit a15dc3d373
18 changed files with 312 additions and 107 deletions

View File

@ -269,6 +269,8 @@ create_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_empty_single_line: bool, true, "Put empty-body functions on a single line";
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";

View File

@ -17,7 +17,8 @@ use rewrite::{Rewrite, RewriteContext};
use lists::{write_list, itemize_list, ListFormatting, SeparatorTactic, ListTactic,
DefinitiveListTactic, definitive_tactic, ListItem, format_fn_args};
use string::{StringFormat, rewrite_string};
use utils::{span_after, extra_offset, last_line_width, wrap_str, binary_search, first_line_width};
use utils::{span_after, extra_offset, last_line_width, wrap_str, binary_search, first_line_width,
semicolon_for_stmt};
use visitor::FmtVisitor;
use config::{StructLitStyle, MultilineStyle};
use comment::{FindUncommented, rewrite_comment, contains_comment};
@ -475,6 +476,33 @@ impl Rewrite for ast::Block {
}
}
impl Rewrite for ast::Stmt {
fn rewrite(&self, context: &RewriteContext, _width: usize, offset: Indent) -> Option<String> {
match self.node {
ast::Stmt_::StmtDecl(ref decl, _) => {
if let ast::Decl_::DeclLocal(ref local) = decl.node {
local.rewrite(context, context.config.max_width, offset)
} else {
None
}
}
ast::Stmt_::StmtExpr(ref ex, _) | ast::Stmt_::StmtSemi(ref ex, _) => {
let suffix = if semicolon_for_stmt(self) {
";"
} else {
""
};
ex.rewrite(context,
context.config.max_width - offset.width() - suffix.len(),
offset)
.map(|s| s + suffix)
}
ast::Stmt_::StmtMac(..) => None,
}
}
}
// Abstraction over for, while and loop expressions
struct Loop<'a> {
cond: Option<&'a ast::Expr>,
@ -677,15 +705,25 @@ fn single_line_if_else(context: &RewriteContext,
None
}
// Checks that a block contains no statements, an expression and no comments.
fn is_simple_block(block: &ast::Block, codemap: &CodeMap) -> bool {
if !block.stmts.is_empty() || block.expr.is_none() {
return false;
}
fn block_contains_comment(block: &ast::Block, codemap: &CodeMap) -> bool {
let snippet = codemap.span_to_snippet(block.span).unwrap();
contains_comment(&snippet)
}
!contains_comment(&snippet)
// Checks that a block contains no statements, an expression and no comments.
pub fn is_simple_block(block: &ast::Block, codemap: &CodeMap) -> bool {
block.stmts.is_empty() && block.expr.is_some() && !block_contains_comment(block, codemap)
}
/// Checks whether a block contains at most one statement or expression, and no comments.
pub fn is_simple_block_stmt(block: &ast::Block, codemap: &CodeMap) -> bool {
(block.stmts.is_empty() || (block.stmts.len() == 1 && block.expr.is_none())) &&
!block_contains_comment(block, codemap)
}
/// Checks whether a block contains no statements, expressions, or comments.
pub fn is_empty_block(block: &ast::Block, codemap: &CodeMap) -> bool {
block.stmts.is_empty() && block.expr.is_none() && !block_contains_comment(block, codemap)
}
// inter-match-arm-comment-rules:

View File

@ -12,10 +12,10 @@
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};
use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic,
DefinitiveListTactic, definitive_tactic, format_item_list};
use expr::rewrite_assign_rhs;
use expr::{is_empty_block, is_simple_block_stmt, rewrite_assign_rhs};
use comment::FindUncommented;
use visitor::FmtVisitor;
use rewrite::{Rewrite, RewriteContext};
@ -177,7 +177,8 @@ impl<'a> FmtVisitor<'a> {
constness: ast::Constness,
abi: abi::Abi,
vis: ast::Visibility,
span: Span)
span: Span,
block: &ast::Block)
-> Option<String> {
let mut newline_brace = self.newline_for_brace(&generics.where_clause);
@ -212,7 +213,7 @@ impl<'a> FmtVisitor<'a> {
result.push(' ');
}
Some(result)
self.single_line_fn(&result, block).or_else(|| Some(result))
}
pub fn rewrite_required_fn(&mut self,
@ -447,6 +448,53 @@ impl<'a> FmtVisitor<'a> {
Some((result, force_new_line_for_brace))
}
fn single_line_fn(&self, fn_str: &str, block: &ast::Block) -> Option<String> {
if fn_str.contains('\n') {
return None;
}
let codemap = self.get_context().codemap;
if self.config.fn_empty_single_line && is_empty_block(block, codemap) &&
self.block_indent.width() + fn_str.len() + 2 <= 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() {
stmt.rewrite(&self.get_context(),
self.config.max_width - self.block_indent.width(),
self.block_indent)
} else {
None
}
};
if let Some(res) = rewrite {
let width = self.block_indent.width() + fn_str.len() + res.len() + 4;
if !res.contains('\n') && width <= self.config.max_width {
return Some(format!("{}{{ {} }}", fn_str, res));
}
}
}
None
}
fn rewrite_args(&self,
args: &[ast::Arg],
explicit_self: Option<&ast::ExplicitSelf>,

View File

@ -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

View File

@ -38,28 +38,21 @@ 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 = stmt.rewrite(&self.get_context(),
self.config.max_width - self.block_indent.width(),
self.block_indent);
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 = stmt.rewrite(&self.get_context(),
self.config.max_width - self.block_indent.width(),
self.block_indent);
self.push_rewrite(stmt.span, rewrite);
}
ast::Stmt_::StmtMac(ref mac, _macro_style) => {
@ -101,7 +94,7 @@ impl<'a> FmtVisitor<'a> {
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(";");
}
}
@ -144,7 +137,8 @@ impl<'a> FmtVisitor<'a> {
constness,
abi,
vis,
codemap::mk_sp(s.lo, b.span.lo))
codemap::mk_sp(s.lo, b.span.lo),
&b)
}
visit::FnKind::Method(ident, ref sig, vis) => {
self.rewrite_fn(indent,
@ -156,7 +150,8 @@ impl<'a> FmtVisitor<'a> {
sig.constness,
sig.abi,
vis.unwrap_or(ast::Visibility::Inherited),
codemap::mk_sp(s.lo, b.span.lo))
codemap::mk_sp(s.lo, b.span.lo),
&b)
}
visit::FnKind::Closure => None,
};
@ -164,6 +159,12 @@ impl<'a> FmtVisitor<'a> {
if let Some(fn_str) = rewrite {
self.format_missing_with_indent(s.lo);
self.buffer.push_str(&fn_str);
if let Some(c) = fn_str.chars().last() {
if c == '}' {
self.last_pos = b.span.hi;
return;
}
}
} else {
self.format_missing(b.span.lo);
}
@ -501,31 +502,6 @@ impl<'a> FmtVisitor<'a> {
}
}
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();

View File

@ -0,0 +1,76 @@
// 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
}
fn mac() -> Vec<i32> { vec![] }
trait CoolTypes {
fn dummy(&self) {
}
}
trait CoolerTypes { fn dummy(&self) {
}
}

View File

@ -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 @@ impl Bar {
}
#[another_attribute]
fn f3(self) -> Dog {
}
fn f3(self) -> Dog {}
/// Blah blah bing.
#[attrib1]
@ -38,6 +36,5 @@ impl Bar {
// Another comment that needs rewrite because it's tooooooooooooooooooooooooooooooo
// loooooooooooong.
/// Blah blah bing.
fn f4(self) -> Cat {
}
fn f4(self) -> Cat {}
}

View File

@ -32,8 +32,7 @@ fn test() {
}
/// test123
fn doc_comment() {
}
fn doc_comment() {}
fn chains() {
foo.bar(|| {

View File

@ -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 */ {}

View File

@ -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>>,

View File

@ -0,0 +1,63 @@
// 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 }
fn mac() -> Vec<i32> { vec![] }
trait CoolTypes {
fn dummy(&self) {}
}
trait CoolerTypes {
fn dummy(&self) {}
}

View File

@ -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 @@ impl Foo {
{
}
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 @@ impl 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);

View File

@ -26,9 +26,7 @@ mod other;
// 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 @@ impl Bar {
}
#[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 {

View File

@ -1,4 +1,3 @@
// A standard mod
fn a() {
}
fn a() {}

View File

@ -1,3 +1,2 @@
// Another mod
fn a() {
}
fn a() {}

View File

@ -3,5 +3,4 @@
use c::a;
fn foo() {
}
fn foo() {}

View File

@ -1,2 +1 @@
fn main() {
}
fn main() {}

View File

@ -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 {}