Merge pull request #869 from ConnorGBrewster/add-trait-formatting
Add trait formatting
This commit is contained in:
commit
73f5f4a213
204
src/items.rs
204
src/items.rs
@ -22,7 +22,7 @@ use rewrite::{Rewrite, RewriteContext};
|
||||
use config::{Config, BlockIndentStyle, Density, ReturnIndent, BraceStyle, StructLitStyle};
|
||||
use syntax::codemap;
|
||||
|
||||
use syntax::{ast, abi};
|
||||
use syntax::{ast, abi, ptr};
|
||||
use syntax::codemap::{Span, BytePos, mk_sp};
|
||||
use syntax::parse::token;
|
||||
use syntax::ast::ImplItem;
|
||||
@ -607,6 +607,133 @@ pub fn format_struct(context: &RewriteContext,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent) -> Option<String> {
|
||||
if let ast::ItemKind::Trait(unsafety, ref generics, ref type_param_bounds, ref trait_items) =
|
||||
item.node {
|
||||
let mut result = String::new();
|
||||
let header = format!("{}{}trait {}",
|
||||
format_visibility(item.vis),
|
||||
format_unsafety(unsafety),
|
||||
item.ident);
|
||||
|
||||
result.push_str(&header);
|
||||
|
||||
let body_lo = context.codemap.span_after(item.span, "{");
|
||||
|
||||
let generics_str = try_opt!(rewrite_generics(context,
|
||||
generics,
|
||||
offset,
|
||||
context.config.max_width,
|
||||
offset + result.len(),
|
||||
mk_sp(item.span.lo, body_lo)));
|
||||
result.push_str(&generics_str);
|
||||
|
||||
let trait_bound_str = try_opt!(rewrite_trait_bounds(context,
|
||||
type_param_bounds,
|
||||
offset,
|
||||
context.config.max_width));
|
||||
// If the trait, generics, and trait bound cannot fit on the same line,
|
||||
// put the trait bounds on an indented new line
|
||||
if offset.width() + last_line_width(&result) + trait_bound_str.len() >
|
||||
context.config.ideal_width {
|
||||
result.push('\n');
|
||||
let width = context.block_indent.width() + context.config.tab_spaces;
|
||||
let trait_indent = Indent::new(0, width);
|
||||
result.push_str(&trait_indent.to_string(context.config));
|
||||
}
|
||||
result.push_str(&trait_bound_str);
|
||||
|
||||
let has_body = !trait_items.is_empty();
|
||||
|
||||
let where_density = if (context.config.where_density == Density::Compressed &&
|
||||
(!result.contains('\n') ||
|
||||
context.config.fn_args_layout == StructLitStyle::Block)) ||
|
||||
(context.config.fn_args_layout == StructLitStyle::Block &&
|
||||
result.is_empty()) ||
|
||||
(context.config.where_density == Density::CompressedIfEmpty &&
|
||||
!has_body &&
|
||||
!result.contains('\n')) {
|
||||
Density::Compressed
|
||||
} else {
|
||||
Density::Tall
|
||||
};
|
||||
|
||||
let where_budget = try_opt!(context.config
|
||||
.max_width
|
||||
.checked_sub(last_line_width(&result)));
|
||||
let where_clause_str = try_opt!(rewrite_where_clause(context,
|
||||
&generics.where_clause,
|
||||
context.config,
|
||||
context.config.item_brace_style,
|
||||
context.block_indent,
|
||||
where_budget,
|
||||
where_density,
|
||||
"{",
|
||||
has_body,
|
||||
None));
|
||||
// If the where clause cannot fit on the same line,
|
||||
// put the where clause on a new line
|
||||
if !where_clause_str.contains('\n') &&
|
||||
last_line_width(&result) + where_clause_str.len() + offset.width() >
|
||||
context.config.ideal_width {
|
||||
result.push('\n');
|
||||
let width = context.block_indent.width() + context.config.tab_spaces - 1;
|
||||
let where_indent = Indent::new(0, width);
|
||||
result.push_str(&where_indent.to_string(context.config));
|
||||
}
|
||||
result.push_str(&where_clause_str);
|
||||
|
||||
match context.config.item_brace_style {
|
||||
BraceStyle::AlwaysNextLine => {
|
||||
result.push('\n');
|
||||
result.push_str(&offset.to_string(context.config));
|
||||
}
|
||||
BraceStyle::PreferSameLine => result.push(' '),
|
||||
BraceStyle::SameLineWhere => {
|
||||
if !where_clause_str.is_empty() &&
|
||||
(trait_items.len() > 0 || result.contains('\n')) {
|
||||
result.push('\n');
|
||||
result.push_str(&offset.to_string(context.config));
|
||||
} else {
|
||||
result.push(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
result.push('{');
|
||||
|
||||
let snippet = context.snippet(item.span);
|
||||
let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
|
||||
|
||||
if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
|
||||
let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
|
||||
visitor.block_indent = context.block_indent.block_indent(context.config);
|
||||
visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
|
||||
|
||||
for item in trait_items {
|
||||
visitor.visit_trait_item(&item);
|
||||
}
|
||||
|
||||
visitor.format_missing(item.span.hi - BytePos(1));
|
||||
|
||||
let inner_indent_str = visitor.block_indent.to_string(context.config);
|
||||
let outer_indent_str = context.block_indent.to_string(context.config);
|
||||
|
||||
result.push('\n');
|
||||
result.push_str(&inner_indent_str);
|
||||
result.push_str(&trim_newlines(&visitor.buffer.to_string().trim()));
|
||||
result.push('\n');
|
||||
result.push_str(&outer_indent_str);
|
||||
} else if result.contains('\n') {
|
||||
result.push('\n');
|
||||
}
|
||||
|
||||
result.push('}');
|
||||
Some(result)
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
fn format_unit_struct(item_name: &str, ident: ast::Ident, vis: ast::Visibility) -> Option<String> {
|
||||
let mut result = String::with_capacity(1024);
|
||||
|
||||
@ -894,7 +1021,7 @@ pub fn rewrite_static(prefix: &str,
|
||||
ident: ast::Ident,
|
||||
ty: &ast::Ty,
|
||||
mutability: ast::Mutability,
|
||||
expr: &ast::Expr,
|
||||
expr_opt: Option<&ptr::P<ast::Expr>>,
|
||||
context: &RewriteContext)
|
||||
-> Option<String> {
|
||||
let prefix = format!("{}{} {}{}: ",
|
||||
@ -907,11 +1034,54 @@ pub fn rewrite_static(prefix: &str,
|
||||
context.config.max_width - context.block_indent.width() -
|
||||
prefix.len() - 2,
|
||||
context.block_indent));
|
||||
let lhs = format!("{}{} =", prefix, ty_str);
|
||||
|
||||
// 1 = ;
|
||||
let remaining_width = context.config.max_width - context.block_indent.width() - 1;
|
||||
rewrite_assign_rhs(context, lhs, expr, remaining_width, context.block_indent).map(|s| s + ";")
|
||||
if let Some(ref expr) = expr_opt {
|
||||
let lhs = format!("{}{} =", prefix, ty_str);
|
||||
// 1 = ;
|
||||
let remaining_width = context.config.max_width - context.block_indent.width() - 1;
|
||||
rewrite_assign_rhs(context, lhs, expr, remaining_width, context.block_indent)
|
||||
.map(|s| s + ";")
|
||||
} else {
|
||||
let lhs = format!("{}{};", prefix, ty_str);
|
||||
Some(lhs)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rewrite_associated_type(ident: ast::Ident,
|
||||
ty_opt: Option<&ptr::P<ast::Ty>>,
|
||||
ty_param_bounds_opt: Option<&ast::TyParamBounds>,
|
||||
context: &RewriteContext,
|
||||
indent: Indent)
|
||||
-> Option<String> {
|
||||
let prefix = format!("type {}", ident);
|
||||
|
||||
let type_bounds_str = if let Some(ty_param_bounds) = ty_param_bounds_opt {
|
||||
let bounds: &[_] = &ty_param_bounds.as_slice();
|
||||
let bound_str = bounds.iter()
|
||||
.filter_map(|ty_bound| {
|
||||
ty_bound.rewrite(context, context.config.max_width, indent)
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join(" + ");
|
||||
if bounds.len() > 0 {
|
||||
format!(": {}", bound_str)
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
if let Some(ty) = ty_opt {
|
||||
let ty_str = try_opt!(ty.rewrite(context,
|
||||
context.config.max_width - context.block_indent.width() -
|
||||
prefix.len() -
|
||||
2,
|
||||
context.block_indent));
|
||||
Some(format!("{} = {};", prefix, ty_str))
|
||||
} else {
|
||||
Some(format!("{}{};", prefix, type_bounds_str))
|
||||
}
|
||||
}
|
||||
|
||||
impl Rewrite for ast::FunctionRetTy {
|
||||
@ -1482,6 +1652,28 @@ fn rewrite_generics(context: &RewriteContext,
|
||||
Some(format!("<{}>", list_str))
|
||||
}
|
||||
|
||||
fn rewrite_trait_bounds(context: &RewriteContext,
|
||||
type_param_bounds: &ast::TyParamBounds,
|
||||
indent: Indent,
|
||||
width: usize)
|
||||
-> Option<String> {
|
||||
let bounds: &[_] = &type_param_bounds.as_slice();
|
||||
|
||||
if bounds.is_empty() {
|
||||
return Some(String::new());
|
||||
}
|
||||
|
||||
let bound_str = bounds.iter()
|
||||
.filter_map(|ty_bound| ty_bound.rewrite(&context, width, indent))
|
||||
.collect::<Vec<String>>()
|
||||
.join(" + ");
|
||||
|
||||
let mut result = String::new();
|
||||
result.push_str(": ");
|
||||
result.push_str(&bound_str);
|
||||
Some(result)
|
||||
}
|
||||
|
||||
fn rewrite_where_clause(context: &RewriteContext,
|
||||
where_clause: &ast::WhereClause,
|
||||
config: &Config,
|
||||
|
@ -21,7 +21,7 @@ use config::Config;
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
use comment::rewrite_comment;
|
||||
use macros::rewrite_macro;
|
||||
use items::{rewrite_static, rewrite_type_alias, format_impl};
|
||||
use items::{rewrite_static, rewrite_associated_type, rewrite_type_alias, format_impl, format_trait};
|
||||
|
||||
pub struct FmtVisitor<'a> {
|
||||
pub parse_session: &'a ParseSess,
|
||||
@ -207,14 +207,14 @@ impl<'a> FmtVisitor<'a> {
|
||||
self.last_pos = item.span.hi;
|
||||
}
|
||||
}
|
||||
// FIXME(#78): format traits.
|
||||
ast::ItemKind::Trait(_, _, _, ref trait_items) => {
|
||||
ast::ItemKind::Trait(..) => {
|
||||
self.format_missing_with_indent(item.span.lo);
|
||||
self.block_indent = self.block_indent.block_indent(self.config);
|
||||
for item in trait_items {
|
||||
self.visit_trait_item(&item);
|
||||
if let Some(trait_str) = format_trait(&self.get_context(),
|
||||
item,
|
||||
self.block_indent) {
|
||||
self.buffer.push_str(&trait_str);
|
||||
self.last_pos = item.span.hi;
|
||||
}
|
||||
self.block_indent = self.block_indent.block_unindent(self.config);
|
||||
}
|
||||
ast::ItemKind::ExternCrate(_) => {
|
||||
self.format_missing_with_indent(item.span.lo);
|
||||
@ -266,7 +266,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
item.ident,
|
||||
ty,
|
||||
mutability,
|
||||
expr,
|
||||
Some(expr),
|
||||
&self.get_context());
|
||||
self.push_rewrite(item.span, rewrite);
|
||||
}
|
||||
@ -276,7 +276,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
item.ident,
|
||||
ty,
|
||||
ast::Mutability::Immutable,
|
||||
expr,
|
||||
Some(expr),
|
||||
&self.get_context());
|
||||
self.push_rewrite(item.span, rewrite);
|
||||
}
|
||||
@ -308,14 +308,21 @@ impl<'a> FmtVisitor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
|
||||
pub fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
|
||||
if self.visit_attrs(&ti.attrs) {
|
||||
return;
|
||||
}
|
||||
|
||||
match ti.node {
|
||||
ast::TraitItemKind::Const(..) => {
|
||||
// FIXME: Implement
|
||||
ast::TraitItemKind::Const(ref ty, ref expr_opt) => {
|
||||
let rewrite = rewrite_static("const",
|
||||
ast::Visibility::Inherited,
|
||||
ti.ident,
|
||||
ty,
|
||||
ast::Mutability::Immutable,
|
||||
expr_opt.as_ref(),
|
||||
&self.get_context());
|
||||
self.push_rewrite(ti.span, rewrite);
|
||||
}
|
||||
ast::TraitItemKind::Method(ref sig, None) => {
|
||||
let indent = self.block_indent;
|
||||
@ -329,8 +336,13 @@ impl<'a> FmtVisitor<'a> {
|
||||
ti.span,
|
||||
ti.id);
|
||||
}
|
||||
ast::TraitItemKind::Type(..) => {
|
||||
// FIXME: Implement
|
||||
ast::TraitItemKind::Type(ref type_param_bounds, _) => {
|
||||
let rewrite = rewrite_associated_type(ti.ident,
|
||||
None,
|
||||
Some(type_param_bounds),
|
||||
&self.get_context(),
|
||||
self.block_indent);
|
||||
self.push_rewrite(ti.span, rewrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -348,11 +360,23 @@ impl<'a> FmtVisitor<'a> {
|
||||
ii.span,
|
||||
ii.id);
|
||||
}
|
||||
ast::ImplItemKind::Const(..) => {
|
||||
// FIXME: Implement
|
||||
ast::ImplItemKind::Const(ref ty, ref expr) => {
|
||||
let rewrite = rewrite_static("const",
|
||||
ast::Visibility::Inherited,
|
||||
ii.ident,
|
||||
ty,
|
||||
ast::Mutability::Immutable,
|
||||
Some(expr),
|
||||
&self.get_context());
|
||||
self.push_rewrite(ii.span, rewrite);
|
||||
}
|
||||
ast::ImplItemKind::Type(_) => {
|
||||
// FIXME: Implement
|
||||
ast::ImplItemKind::Type(ref ty) => {
|
||||
let rewrite = rewrite_associated_type(ii.ident,
|
||||
Some(ty),
|
||||
None,
|
||||
&self.get_context(),
|
||||
self.block_indent);
|
||||
self.push_rewrite(ii.span, rewrite);
|
||||
}
|
||||
ast::ImplItemKind::Macro(ref mac) => {
|
||||
self.format_missing_with_indent(ii.span.lo);
|
||||
|
@ -1,6 +1,10 @@
|
||||
impl Foo for Bar { fn foo() { "hi" } }
|
||||
|
||||
pub impl Foo for Bar {
|
||||
// Associated Constants
|
||||
const Baz: i32 = 16;
|
||||
// Associated Types
|
||||
type FooBar = usize;
|
||||
// Comment 1
|
||||
fn foo() { "hi" }
|
||||
// Comment 2
|
||||
|
@ -35,3 +35,21 @@ trait TraitWithExpr {
|
||||
trait Test {
|
||||
fn read_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
|
||||
}
|
||||
|
||||
trait T<> {}
|
||||
|
||||
trait Foo { type Bar: Baz;}
|
||||
|
||||
trait ConstCheck<T>:Foo where T: Baz {
|
||||
const J: i32;
|
||||
}
|
||||
|
||||
trait Tttttttttttttttttttttttttttttttttttttttttttttttttttttttttt<T>
|
||||
where T: Foo {}
|
||||
|
||||
trait Ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt<T> where T: Foo {}
|
||||
|
||||
trait FooBar<T> : Tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt where J: Bar { fn test(); }
|
||||
|
||||
trait WhereList<T, J> where T: Foo, J: Bar {}
|
||||
|
||||
|
@ -20,7 +20,7 @@ struct Pair<S, T> where T: P, S: P + Q {
|
||||
|
||||
struct TupPair<S, T> (S, T) where T: P, S: P + Q;
|
||||
|
||||
enum E<S, T> where S: P, T: P {
|
||||
enum E<S, T> where S: P, T: P {
|
||||
A {a: T},
|
||||
}
|
||||
|
||||
@ -30,7 +30,6 @@ extern "C" {
|
||||
fn f<S, T>(x: T, y: S) -> T where T: P, S: Q;
|
||||
}
|
||||
|
||||
// Note: trait declarations are not fully formatted (issue #78)
|
||||
trait Q<S, T> where T: P, S: R
|
||||
{
|
||||
fn f<U, V>(self, x: T, y: S, z: U) -> Self where U: P, V: P;
|
||||
|
@ -5,6 +5,10 @@ impl Foo for Bar {
|
||||
}
|
||||
|
||||
pub impl Foo for Bar {
|
||||
// Associated Constants
|
||||
const Baz: i32 = 16;
|
||||
// Associated Types
|
||||
type FooBar = usize;
|
||||
// Comment 1
|
||||
fn foo() {
|
||||
"hi"
|
||||
|
@ -34,3 +34,35 @@ trait Test {
|
||||
fn read_struct<T, F>(&mut self, s_name: &str, len: usize, f: F) -> Result<T, Self::Error>
|
||||
where F: FnOnce(&mut Self) -> Result<T, Self::Error>;
|
||||
}
|
||||
|
||||
trait T {}
|
||||
|
||||
trait Foo {
|
||||
type Bar: Baz;
|
||||
}
|
||||
|
||||
trait ConstCheck<T>: Foo
|
||||
where T: Baz
|
||||
{
|
||||
const J: i32;
|
||||
}
|
||||
|
||||
trait Tttttttttttttttttttttttttttttttttttttttttttttttttttttttttt<T> where T: Foo {}
|
||||
|
||||
trait Ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt<T>
|
||||
where T: Foo
|
||||
{
|
||||
}
|
||||
|
||||
trait FooBar<T>
|
||||
: Tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
|
||||
where J: Bar
|
||||
{
|
||||
fn test();
|
||||
}
|
||||
|
||||
trait WhereList<T, J>
|
||||
where T: Foo,
|
||||
J: Bar
|
||||
{
|
||||
}
|
||||
|
@ -48,8 +48,9 @@ extern "C" {
|
||||
S: Q;
|
||||
}
|
||||
|
||||
// Note: trait declarations are not fully formatted (issue #78)
|
||||
trait Q<S, T> where T: P, S: R
|
||||
trait Q<S, T>
|
||||
where T: P,
|
||||
S: R,
|
||||
{
|
||||
fn f<U, V>(self, x: T, y: S, z: U) -> Self
|
||||
where U: P,
|
||||
|
Loading…
x
Reference in New Issue
Block a user