Reformat source code using new defaults

This commit is contained in:
Nick Cameron 2017-06-12 15:58:58 +12:00
parent 32e882789b
commit 1f512948a0
27 changed files with 3224 additions and 2447 deletions

2
Cargo.lock generated
View file

@ -1,6 +1,6 @@
[root] [root]
name = "rustfmt" name = "rustfmt"
version = "0.8.5" version = "0.9.0"
dependencies = [ dependencies = [
"diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -1,7 +1,7 @@
[package] [package]
name = "rustfmt" name = "rustfmt"
version = "0.9" version = "0.9.0"
authors = ["Nicholas Cameron <ncameron@mozilla.com>", "The Rustfmt developers"] authors = ["Nicholas Cameron <ncameron@mozilla.com>", "The Rustfmt developers"]
description = "Tool to find and fix Rust formatting issues" description = "Tool to find and fix Rust formatting issues"
repository = "https://github.com/rust-lang-nursery/rustfmt" repository = "https://github.com/rust-lang-nursery/rustfmt"

View file

@ -42,10 +42,12 @@ fn execute() -> i32 {
opts.optflag("h", "help", "show this message"); opts.optflag("h", "help", "show this message");
opts.optflag("q", "quiet", "no output printed to stdout"); opts.optflag("q", "quiet", "no output printed to stdout");
opts.optflag("v", "verbose", "use verbose output"); opts.optflag("v", "verbose", "use verbose output");
opts.optmulti("p", opts.optmulti(
"package", "p",
"specify package to format (only usable in workspaces)", "package",
"<package>"); "specify package to format (only usable in workspaces)",
"<package>",
);
opts.optflag("", "all", "format all packages (only usable in workspaces)"); opts.optflag("", "all", "format all packages (only usable in workspaces)");
let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) { let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
@ -90,9 +92,11 @@ fn execute() -> i32 {
fn print_usage(opts: &Options, reason: &str) { fn print_usage(opts: &Options, reason: &str) {
let msg = format!("{}\nusage: cargo fmt [options]", reason); let msg = format!("{}\nusage: cargo fmt [options]", reason);
println!("{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \ println!(
"{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
Arguments after `--` are passed to rustfmt.", Arguments after `--` are passed to rustfmt.",
opts.usage(&msg)); opts.usage(&msg)
);
} }
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
@ -102,9 +106,10 @@ pub enum Verbosity {
Quiet, Quiet,
} }
fn format_crate(verbosity: Verbosity, fn format_crate(
workspace_hitlist: WorkspaceHitlist) verbosity: Verbosity,
-> Result<ExitStatus, std::io::Error> { workspace_hitlist: WorkspaceHitlist,
) -> Result<ExitStatus, std::io::Error> {
let targets = get_targets(workspace_hitlist)?; let targets = get_targets(workspace_hitlist)?;
// Currently only bin and lib files get formatted // Currently only bin and lib files get formatted
@ -112,8 +117,8 @@ fn format_crate(verbosity: Verbosity,
.into_iter() .into_iter()
.filter(|t| t.kind.should_format()) .filter(|t| t.kind.should_format())
.inspect(|t| if verbosity == Verbosity::Verbose { .inspect(|t| if verbosity == Verbosity::Verbose {
println!("[{:?}] {:?}", t.kind, t.path) println!("[{:?}] {:?}", t.kind, t.path)
}) })
.map(|t| t.path) .map(|t| t.path)
.collect(); .collect();
@ -194,8 +199,10 @@ fn get_targets(workspace_hitlist: WorkspaceHitlist) -> Result<Vec<Target>, std::
return Ok(targets); return Ok(targets);
} }
return Err(std::io::Error::new(std::io::ErrorKind::NotFound, return Err(std::io::Error::new(
str::from_utf8(&output.stderr).unwrap())); std::io::ErrorKind::NotFound,
str::from_utf8(&output.stderr).unwrap(),
));
} }
// This happens when cargo-fmt is not used inside a crate or // This happens when cargo-fmt is not used inside a crate or
// is used inside a workspace. // is used inside a workspace.
@ -221,18 +228,22 @@ fn get_targets(workspace_hitlist: WorkspaceHitlist) -> Result<Vec<Target>, std::
.unwrap() .unwrap()
.into_iter() .into_iter()
.filter(|member| if workspace_hitlist == WorkspaceHitlist::All { .filter(|member| if workspace_hitlist == WorkspaceHitlist::All {
true true
} else { } else {
let member_obj = member.as_object().unwrap(); let member_obj = member.as_object().unwrap();
let member_name = member_obj.get("name").unwrap().as_str().unwrap(); let member_name = member_obj.get("name").unwrap().as_str().unwrap();
hitlist.take(&member_name.to_string()).is_some() hitlist.take(&member_name.to_string()).is_some()
}) })
.collect(); .collect();
if hitlist.len() != 0 { if hitlist.len() != 0 {
// Mimick cargo of only outputting one <package> spec. // Mimick cargo of only outputting one <package> spec.
return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, return Err(std::io::Error::new(
format!("package `{}` is not a member of the workspace", std::io::ErrorKind::InvalidInput,
hitlist.iter().next().unwrap()))); format!(
"package `{}` is not a member of the workspace",
hitlist.iter().next().unwrap()
),
));
} }
for member in members { for member in members {
let member_obj = member.as_object().unwrap(); let member_obj = member.as_object().unwrap();
@ -243,8 +254,10 @@ fn get_targets(workspace_hitlist: WorkspaceHitlist) -> Result<Vec<Target>, std::
} }
return Ok(targets); return Ok(targets);
} }
Err(std::io::Error::new(std::io::ErrorKind::NotFound, Err(std::io::Error::new(
str::from_utf8(&output.stderr).unwrap())) std::io::ErrorKind::NotFound,
str::from_utf8(&output.stderr).unwrap(),
))
} }
@ -268,10 +281,11 @@ fn target_from_json(jtarget: &Value) -> Target {
} }
} }
fn format_files(files: &[PathBuf], fn format_files(
fmt_args: &[String], files: &[PathBuf],
verbosity: Verbosity) fmt_args: &[String],
-> Result<ExitStatus, std::io::Error> { verbosity: Verbosity,
) -> Result<ExitStatus, std::io::Error> {
let stdout = if verbosity == Verbosity::Quiet { let stdout = if verbosity == Verbosity::Quiet {
std::process::Stdio::null() std::process::Stdio::null()
} else { } else {
@ -294,8 +308,10 @@ fn format_files(files: &[PathBuf],
.spawn() .spawn()
.map_err(|e| match e.kind() { .map_err(|e| match e.kind() {
std::io::ErrorKind::NotFound => { std::io::ErrorKind::NotFound => {
std::io::Error::new(std::io::ErrorKind::Other, std::io::Error::new(
"Could not run rustfmt, please make sure it is in your PATH.") std::io::ErrorKind::Other,
"Could not run rustfmt, please make sure it is in your PATH.",
)
} }
_ => e, _ => e,
})?; })?;

View file

@ -74,7 +74,9 @@ impl CliOptions {
if let Ok(write_mode) = WriteMode::from_str(write_mode) { if let Ok(write_mode) = WriteMode::from_str(write_mode) {
options.write_mode = Some(write_mode); options.write_mode = Some(write_mode);
} else { } else {
return Err(FmtError::from(format!("Invalid write-mode: {}", write_mode))); return Err(FmtError::from(
format!("Invalid write-mode: {}", write_mode),
));
} }
} }
@ -96,9 +98,10 @@ impl CliOptions {
} }
/// read the given config file path recursively if present else read the project file path /// read the given config file path recursively if present else read the project file path
fn match_cli_path_or_file(config_path: Option<PathBuf>, fn match_cli_path_or_file(
input_file: &Path) config_path: Option<PathBuf>,
-> FmtResult<(Config, Option<PathBuf>)> { input_file: &Path,
) -> FmtResult<(Config, Option<PathBuf>)> {
if let Some(config_file) = config_path { if let Some(config_file) = config_path {
let toml = Config::from_toml_path(config_file.as_ref())?; let toml = Config::from_toml_path(config_file.as_ref())?;
@ -112,32 +115,44 @@ fn make_opts() -> Options {
opts.optflag("h", "help", "show this message"); opts.optflag("h", "help", "show this message");
opts.optflag("V", "version", "show version information"); opts.optflag("V", "version", "show version information");
opts.optflag("v", "verbose", "print verbose output"); opts.optflag("v", "verbose", "print verbose output");
opts.optopt("", opts.optopt(
"write-mode", "",
"mode to write in (not usable when piping from stdin)", "write-mode",
"[replace|overwrite|display|diff|coverage|checkstyle]"); "mode to write in (not usable when piping from stdin)",
"[replace|overwrite|display|diff|coverage|checkstyle]",
);
opts.optflag("", "skip-children", "don't reformat child modules"); opts.optflag("", "skip-children", "don't reformat child modules");
opts.optflag("", opts.optflag(
"config-help", "",
"show details of rustfmt configuration options"); "config-help",
opts.optopt("", "show details of rustfmt configuration options",
"dump-default-config", );
"Dumps the default configuration to a file and exits.", opts.optopt(
"PATH"); "",
opts.optopt("", "dump-default-config",
"dump-minimal-config", "Dumps the default configuration to a file and exits.",
"Dumps configuration options that were checked during formatting to a file.", "PATH",
"PATH"); );
opts.optopt("", opts.optopt(
"config-path", "",
"Recursively searches the given path for the rustfmt.toml config file. If not \ "dump-minimal-config",
"Dumps configuration options that were checked during formatting to a file.",
"PATH",
);
opts.optopt(
"",
"config-path",
"Recursively searches the given path for the rustfmt.toml config file. If not \
found reverts to the input file path", found reverts to the input file path",
"[Path for the configuration file]"); "[Path for the configuration file]",
opts.optopt("", );
"file-lines", opts.optopt(
"Format specified line ranges. See README for more detail on the JSON format.", "",
"JSON"); "file-lines",
"Format specified line ranges. See README for more detail on the JSON format.",
"JSON",
);
opts opts
} }
@ -167,8 +182,8 @@ fn execute(opts: &Options) -> FmtResult<Summary> {
} }
Operation::Stdin { input, config_path } => { Operation::Stdin { input, config_path } => {
// try to read config from local directory // try to read config from local directory
let (mut config, _) = match_cli_path_or_file(config_path, let (mut config, _) =
&env::current_dir().unwrap())?; match_cli_path_or_file(config_path, &env::current_dir().unwrap())?;
// write_mode is always Plain for Stdin. // write_mode is always Plain for Stdin.
config.set().write_mode(WriteMode::Plain); config.set().write_mode(WriteMode::Plain);
@ -225,9 +240,11 @@ fn execute(opts: &Options) -> FmtResult<Summary> {
Config::from_resolved_toml_path(file.parent().unwrap())?; Config::from_resolved_toml_path(file.parent().unwrap())?;
if options.verbose { if options.verbose {
if let Some(path) = path_tmp.as_ref() { if let Some(path) = path_tmp.as_ref() {
println!("Using rustfmt config file {} for {}", println!(
path.display(), "Using rustfmt config file {} for {}",
file.display()); path.display(),
file.display()
);
} }
} }
config = config_tmp; config = config_tmp;
@ -288,16 +305,20 @@ fn main() {
} }
fn print_usage(opts: &Options, reason: &str) { fn print_usage(opts: &Options, reason: &str) {
let reason = format!("{}\n\nusage: {} [options] <file>...", let reason = format!(
reason, "{}\n\nusage: {} [options] <file>...",
env::args_os().next().unwrap().to_string_lossy()); reason,
env::args_os().next().unwrap().to_string_lossy()
);
println!("{}", opts.usage(&reason)); println!("{}", opts.usage(&reason));
} }
fn print_version() { fn print_version() {
println!("{}-nightly{}", println!(
env!("CARGO_PKG_VERSION"), "{}-nightly{}",
include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))) env!("CARGO_PKG_VERSION"),
include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))
)
} }
fn determine_operation(matches: &Matches) -> FmtResult<Operation> { fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
@ -318,8 +339,10 @@ fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
} }
let config_path_not_found = |path: &str| -> FmtResult<Operation> { let config_path_not_found = |path: &str| -> FmtResult<Operation> {
Err(FmtError::from(format!("Error: unable to find a config file for the given path: `{}`", Err(FmtError::from(format!(
path))) "Error: unable to find a config file for the given path: `{}`",
path
)))
}; };
// Read the config_path and convert to parent dir if a file is provided. // Read the config_path and convert to parent dir if a file is provided.
@ -346,25 +369,25 @@ fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
io::stdin().read_to_string(&mut buffer)?; io::stdin().read_to_string(&mut buffer)?;
return Ok(Operation::Stdin { return Ok(Operation::Stdin {
input: buffer, input: buffer,
config_path: config_path, config_path: config_path,
}); });
} }
let files: Vec<_> = matches let files: Vec<_> = matches
.free .free
.iter() .iter()
.map(|s| { .map(|s| {
let p = PathBuf::from(s); let p = PathBuf::from(s);
// we will do comparison later, so here tries to canonicalize first // we will do comparison later, so here tries to canonicalize first
// to get the expected behavior. // to get the expected behavior.
p.canonicalize().unwrap_or(p) p.canonicalize().unwrap_or(p)
}) })
.collect(); .collect();
Ok(Operation::Format { Ok(Operation::Format {
files: files, files: files,
config_path: config_path, config_path: config_path,
minimal_config_path: minimal_config_path, minimal_config_path: minimal_config_path,
}) })
} }

View file

@ -101,9 +101,9 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
let trailing_try_num = subexpr_list let trailing_try_num = subexpr_list
.iter() .iter()
.take_while(|e| match e.node { .take_while(|e| match e.node {
ast::ExprKind::Try(..) => true, ast::ExprKind::Try(..) => true,
_ => false, _ => false,
}) })
.count(); .count();
// Parent is the first item in the chain, e.g., `foo` in `foo.bar.baz()`. // Parent is the first item in the chain, e.g., `foo` in `foo.bar.baz()`.
@ -128,7 +128,10 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
} else { } else {
chain_indent(context, shape.add_offset(parent_rewrite.len())) chain_indent(context, shape.add_offset(parent_rewrite.len()))
}; };
(nested_shape, context.config.chain_indent() == IndentStyle::Visual || is_small_parent) (
nested_shape,
context.config.chain_indent() == IndentStyle::Visual || is_small_parent,
)
} else if is_block_expr(context, &parent, &parent_rewrite) { } else if is_block_expr(context, &parent, &parent_rewrite) {
match context.config.chain_indent() { match context.config.chain_indent() {
// Try to put the first child on the same line with parent's last line // Try to put the first child on the same line with parent's last line
@ -155,26 +158,33 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
} else { } else {
other_child_shape other_child_shape
}; };
debug!("child_shapes {:?} {:?}", debug!(
first_child_shape, "child_shapes {:?} {:?}",
other_child_shape); first_child_shape,
other_child_shape
);
let child_shape_iter = let child_shape_iter = Some(first_child_shape).into_iter().chain(
Some(first_child_shape) ::std::iter::repeat(
.into_iter() other_child_shape,
.chain(::std::iter::repeat(other_child_shape).take(subexpr_list.len() - 1)); ).take(
subexpr_list.len() - 1,
),
);
let iter = subexpr_list.iter().rev().zip(child_shape_iter); let iter = subexpr_list.iter().rev().zip(child_shape_iter);
let mut rewrites = try_opt!(iter.map(|(e, shape)| { let mut rewrites = try_opt!(
rewrite_chain_subexpr(e, total_span, context, shape) iter.map(|(e, shape)| {
}).collect::<Option<Vec<_>>>()); rewrite_chain_subexpr(e, total_span, context, shape)
}).collect::<Option<Vec<_>>>()
);
// Total of all items excluding the last. // Total of all items excluding the last.
let last_non_try_index = rewrites.len() - (1 + trailing_try_num); let last_non_try_index = rewrites.len() - (1 + trailing_try_num);
let almost_total = rewrites[..last_non_try_index] let almost_total = rewrites[..last_non_try_index].iter().fold(0, |a, b| {
.iter() a + first_line_width(b)
.fold(0, |a, b| a + first_line_width(b)) + parent_rewrite.len(); }) + parent_rewrite.len();
let one_line_len = rewrites.iter().fold(0, |a, r| a + first_line_width(r)) + let one_line_len = rewrites.iter().fold(0, |a, r| a + first_line_width(r)) +
parent_rewrite.len(); parent_rewrite.len();
let one_line_budget = min(shape.width, context.config.chain_one_line_max()); let one_line_budget = min(shape.width, context.config.chain_one_line_max());
let veto_single_line = if one_line_len > one_line_budget { let veto_single_line = if one_line_len > one_line_budget {
@ -206,12 +216,15 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
if fits_single_line { if fits_single_line {
fits_single_line = match expr.node { fits_single_line = match expr.node {
ref e @ ast::ExprKind::MethodCall(..) => { ref e @ ast::ExprKind::MethodCall(..) => {
if rewrite_method_call_with_overflow(e, if rewrite_method_call_with_overflow(
&mut last[0], e,
almost_total, &mut last[0],
total_span, almost_total,
context, total_span,
shape) { context,
shape,
)
{
// If the first line of the last method does not fit into a single line // If the first line of the last method does not fit into a single line
// after the others, allow new lines. // after the others, allow new lines.
almost_total + first_line_width(&last[0]) < context.config.max_width() almost_total + first_line_width(&last[0]) < context.config.max_width()
@ -233,13 +246,15 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
width: one_line_budget, width: one_line_budget,
..parent_shape ..parent_shape
}; };
fits_single_line = rewrite_last_child_with_overflow(context, fits_single_line = rewrite_last_child_with_overflow(
&subexpr_list[trailing_try_num], context,
overflow_shape, &subexpr_list[trailing_try_num],
total_span, overflow_shape,
almost_total, total_span,
one_line_budget, almost_total,
&mut last[0]); one_line_budget,
&mut last[0],
);
} }
} }
@ -254,68 +269,83 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
format!("\n{}", nested_shape.indent.to_string(context.config)) format!("\n{}", nested_shape.indent.to_string(context.config))
}; };
let first_connector = choose_first_connector(context, let first_connector = choose_first_connector(
&parent_rewrite, context,
&rewrites[0], &parent_rewrite,
&connector, &rewrites[0],
&subexpr_list, &connector,
extend); &subexpr_list,
extend,
);
if is_small_parent && rewrites.len() > 1 { if is_small_parent && rewrites.len() > 1 {
let second_connector = choose_first_connector(context, let second_connector = choose_first_connector(
&rewrites[0], context,
&rewrites[1], &rewrites[0],
&connector, &rewrites[1],
&subexpr_list[0..subexpr_list.len() - 1], &connector,
false); &subexpr_list[0..subexpr_list.len() - 1],
wrap_str(format!("{}{}{}{}{}", false,
parent_rewrite, );
first_connector, wrap_str(
rewrites[0], format!(
second_connector, "{}{}{}{}{}",
join_rewrites(&rewrites[1..], parent_rewrite,
&subexpr_list[0..subexpr_list.len() - 1], first_connector,
&connector)), rewrites[0],
context.config.max_width(), second_connector,
shape) join_rewrites(
&rewrites[1..],
&subexpr_list[0..subexpr_list.len() - 1],
&connector,
)
),
context.config.max_width(),
shape,
)
} else { } else {
wrap_str(format!("{}{}{}", wrap_str(
parent_rewrite, format!(
first_connector, "{}{}{}",
join_rewrites(&rewrites, &subexpr_list, &connector)), parent_rewrite,
context.config.max_width(), first_connector,
shape) join_rewrites(&rewrites, &subexpr_list, &connector)
),
context.config.max_width(),
shape,
)
} }
} }
fn is_extendable_parent(context: &RewriteContext, parent_str: &str) -> bool { fn is_extendable_parent(context: &RewriteContext, parent_str: &str) -> bool {
context.config.chain_indent() == IndentStyle::Block && context.config.chain_indent() == IndentStyle::Block &&
parent_str.lines().last().map_or(false, |s| { parent_str.lines().last().map_or(false, |s| {
s.trim() s.trim().chars().all(|c| {
.chars() c == ')' || c == ']' || c == '}' || c == '?'
.all(|c| c == ')' || c == ']' || c == '}' || c == '?') })
}) })
} }
// True if the chain is only `?`s. // True if the chain is only `?`s.
fn chain_only_try(exprs: &[ast::Expr]) -> bool { fn chain_only_try(exprs: &[ast::Expr]) -> bool {
exprs.iter().all(|e| if let ast::ExprKind::Try(_) = e.node { exprs.iter().all(|e| if let ast::ExprKind::Try(_) = e.node {
true true
} else { } else {
false false
}) })
} }
// Try to rewrite and replace the last non-try child. Return `true` if // Try to rewrite and replace the last non-try child. Return `true` if
// replacing succeeds. // replacing succeeds.
fn rewrite_last_child_with_overflow(context: &RewriteContext, fn rewrite_last_child_with_overflow(
expr: &ast::Expr, context: &RewriteContext,
shape: Shape, expr: &ast::Expr,
span: Span, shape: Shape,
almost_total: usize, span: Span,
one_line_budget: usize, almost_total: usize,
last_child: &mut String) one_line_budget: usize,
-> bool { last_child: &mut String,
) -> bool {
if let Some(shape) = shape.shrink_left(almost_total) { if let Some(shape) = shape.shrink_left(almost_total) {
if let Some(ref mut rw) = rewrite_chain_subexpr(expr, span, context, shape) { if let Some(ref mut rw) = rewrite_chain_subexpr(expr, span, context, shape) {
if almost_total + first_line_width(rw) <= one_line_budget { if almost_total + first_line_width(rw) <= one_line_budget {
@ -327,15 +357,18 @@ fn rewrite_last_child_with_overflow(context: &RewriteContext,
false false
} }
pub fn rewrite_try(expr: &ast::Expr, pub fn rewrite_try(
try_count: usize, expr: &ast::Expr,
context: &RewriteContext, try_count: usize,
shape: Shape) context: &RewriteContext,
-> Option<String> { shape: Shape,
) -> Option<String> {
let sub_expr = try_opt!(expr.rewrite(context, try_opt!(shape.sub_width(try_count)))); let sub_expr = try_opt!(expr.rewrite(context, try_opt!(shape.sub_width(try_count))));
Some(format!("{}{}", Some(format!(
sub_expr, "{}{}",
iter::repeat("?").take(try_count).collect::<String>())) sub_expr,
iter::repeat("?").take(try_count).collect::<String>()
))
} }
fn join_rewrites(rewrites: &[String], subexps: &[ast::Expr], connector: &str) -> String { fn join_rewrites(rewrites: &[String], subexps: &[ast::Expr], connector: &str) -> String {
@ -398,24 +431,27 @@ fn chain_indent(context: &RewriteContext, shape: Shape) -> Shape {
} }
} }
fn rewrite_method_call_with_overflow(expr_kind: &ast::ExprKind, fn rewrite_method_call_with_overflow(
last: &mut String, expr_kind: &ast::ExprKind,
almost_total: usize, last: &mut String,
total_span: Span, almost_total: usize,
context: &RewriteContext, total_span: Span,
shape: Shape) context: &RewriteContext,
-> bool { shape: Shape,
) -> bool {
if let &ast::ExprKind::MethodCall(ref method_name, ref types, ref expressions) = expr_kind { if let &ast::ExprKind::MethodCall(ref method_name, ref types, ref expressions) = expr_kind {
let shape = match shape.shrink_left(almost_total) { let shape = match shape.shrink_left(almost_total) {
Some(b) => b, Some(b) => b,
None => return false, None => return false,
}; };
let mut last_rewrite = rewrite_method_call(method_name.node, let mut last_rewrite = rewrite_method_call(
types, method_name.node,
expressions, types,
total_span, expressions,
context, total_span,
shape); context,
shape,
);
if let Some(ref mut s) = last_rewrite { if let Some(ref mut s) = last_rewrite {
::std::mem::swap(s, last); ::std::mem::swap(s, last);
@ -457,11 +493,12 @@ fn convert_try(expr: &ast::Expr, context: &RewriteContext) -> ast::Expr {
// Rewrite the last element in the chain `expr`. E.g., given `a.b.c` we rewrite // Rewrite the last element in the chain `expr`. E.g., given `a.b.c` we rewrite
// `.c`. // `.c`.
fn rewrite_chain_subexpr(expr: &ast::Expr, fn rewrite_chain_subexpr(
span: Span, expr: &ast::Expr,
context: &RewriteContext, span: Span,
shape: Shape) context: &RewriteContext,
-> Option<String> { shape: Shape,
) -> Option<String> {
let rewrite_element = |expr_str: String| if expr_str.len() <= shape.width { let rewrite_element = |expr_str: String| if expr_str.len() <= shape.width {
Some(expr_str) Some(expr_str)
} else { } else {
@ -500,20 +537,23 @@ fn is_try(expr: &ast::Expr) -> bool {
} }
} }
fn choose_first_connector<'a>(context: &RewriteContext, fn choose_first_connector<'a>(
parent_str: &str, context: &RewriteContext,
first_child_str: &str, parent_str: &str,
connector: &'a str, first_child_str: &str,
subexpr_list: &[ast::Expr], connector: &'a str,
extend: bool) subexpr_list: &[ast::Expr],
-> &'a str { extend: bool,
) -> &'a str {
if subexpr_list.is_empty() { if subexpr_list.is_empty() {
"" ""
} else if extend || subexpr_list.last().map_or(false, is_try) || } else if extend || subexpr_list.last().map_or(false, is_try) ||
is_extendable_parent(context, parent_str) { is_extendable_parent(context, parent_str)
{
// 1 = ";", being conservative here. // 1 = ";", being conservative here.
if last_line_width(parent_str) + first_line_width(first_child_str) + 1 <= if last_line_width(parent_str) + first_line_width(first_child_str) + 1 <=
context.config.max_width() { context.config.max_width()
{
"" ""
} else { } else {
connector connector
@ -523,18 +563,18 @@ fn choose_first_connector<'a>(context: &RewriteContext,
} }
} }
fn rewrite_method_call(method_name: ast::Ident, fn rewrite_method_call(
types: &[ptr::P<ast::Ty>], method_name: ast::Ident,
args: &[ptr::P<ast::Expr>], types: &[ptr::P<ast::Ty>],
span: Span, args: &[ptr::P<ast::Expr>],
context: &RewriteContext, span: Span,
shape: Shape) context: &RewriteContext,
-> Option<String> { shape: Shape,
) -> Option<String> {
let (lo, type_str) = if types.is_empty() { let (lo, type_str) = if types.is_empty() {
(args[0].span.hi, String::new()) (args[0].span.hi, String::new())
} else { } else {
let type_list: Vec<_> = let type_list: Vec<_> = try_opt!(types.iter().map(|ty| ty.rewrite(context, shape)).collect());
try_opt!(types.iter().map(|ty| ty.rewrite(context, shape)).collect());
let type_str = if context.config.spaces_within_angle_brackets() && type_list.len() > 0 { let type_str = if context.config.spaces_within_angle_brackets() && type_list.len() > 0 {
format!("::< {} >", type_list.join(", ")) format!("::< {} >", type_list.join(", "))

View file

@ -13,7 +13,8 @@ use config::WriteMode;
pub fn output_header<T>(out: &mut T, mode: WriteMode) -> Result<(), io::Error> pub fn output_header<T>(out: &mut T, mode: WriteMode) -> Result<(), io::Error>
where T: Write where
T: Write,
{ {
if mode == WriteMode::Checkstyle { if mode == WriteMode::Checkstyle {
let mut xml_heading = String::new(); let mut xml_heading = String::new();
@ -26,7 +27,8 @@ pub fn output_header<T>(out: &mut T, mode: WriteMode) -> Result<(), io::Error>
} }
pub fn output_footer<T>(out: &mut T, mode: WriteMode) -> Result<(), io::Error> pub fn output_footer<T>(out: &mut T, mode: WriteMode) -> Result<(), io::Error>
where T: Write where
T: Write,
{ {
if mode == WriteMode::Checkstyle { if mode == WriteMode::Checkstyle {
let mut xml_tail = String::new(); let mut xml_tail = String::new();
@ -36,11 +38,13 @@ pub fn output_footer<T>(out: &mut T, mode: WriteMode) -> Result<(), io::Error>
Ok(()) Ok(())
} }
pub fn output_checkstyle_file<T>(mut writer: T, pub fn output_checkstyle_file<T>(
filename: &str, mut writer: T,
diff: Vec<Mismatch>) filename: &str,
-> Result<(), io::Error> diff: Vec<Mismatch>,
where T: Write ) -> Result<(), io::Error>
where
T: Write,
{ {
write!(writer, "<file name=\"{}\">", filename)?; write!(writer, "<file name=\"{}\">", filename)?;
for mismatch in diff { for mismatch in diff {
@ -48,11 +52,13 @@ pub fn output_checkstyle_file<T>(mut writer: T,
// Do nothing with `DiffLine::Context` and `DiffLine::Resulting`. // Do nothing with `DiffLine::Context` and `DiffLine::Resulting`.
if let DiffLine::Expected(ref str) = line { if let DiffLine::Expected(ref str) = line {
let message = xml_escape_str(str); let message = xml_escape_str(str);
write!(writer, write!(
"<error line=\"{}\" severity=\"warning\" message=\"Should be `{}`\" \ writer,
"<error line=\"{}\" severity=\"warning\" message=\"Should be `{}`\" \
/>", />",
mismatch.line_number, mismatch.line_number,
message)?; message
)?;
} }
} }
} }

View file

@ -77,10 +77,12 @@ impl LineRangeUtils for CodeMap {
let lo = self.lookup_char_pos(span.lo); let lo = self.lookup_char_pos(span.lo);
let hi = self.lookup_char_pos(span.hi); let hi = self.lookup_char_pos(span.hi);
assert!(lo.file.name == hi.file.name, assert!(
"span crossed file boundary: lo: {:?}, hi: {:?}", lo.file.name == hi.file.name,
lo, "span crossed file boundary: lo: {:?}, hi: {:?}",
hi); lo,
hi
);
LineRange { LineRange {
file: lo.file.clone(), file: lo.file.clone(),

View file

@ -45,9 +45,9 @@ pub enum CommentStyle<'a> {
fn custom_opener(s: &str) -> &str { fn custom_opener(s: &str) -> &str {
s.lines().next().map_or("", |first_line| { s.lines().next().map_or("", |first_line| {
first_line first_line.find(' ').map_or(first_line, |space_index| {
.find(' ') &first_line[0..space_index + 1]
.map_or(first_line, |space_index| &first_line[0..space_index + 1]) })
}) })
} }
@ -98,14 +98,14 @@ impl<'a> CommentStyle<'a> {
CommentStyle::TripleSlash | CommentStyle::TripleSlash |
CommentStyle::Doc => { CommentStyle::Doc => {
line.trim_left().starts_with(self.line_start().trim_left()) || line.trim_left().starts_with(self.line_start().trim_left()) ||
comment_style(line, normalize_comments) == *self comment_style(line, normalize_comments) == *self
} }
CommentStyle::DoubleBullet | CommentStyle::DoubleBullet |
CommentStyle::SingleBullet | CommentStyle::SingleBullet |
CommentStyle::Exclamation => { CommentStyle::Exclamation => {
line.trim_left().starts_with(self.closer().trim_left()) || line.trim_left().starts_with(self.closer().trim_left()) ||
line.trim_left().starts_with(self.line_start().trim_left()) || line.trim_left().starts_with(self.line_start().trim_left()) ||
comment_style(line, normalize_comments) == *self comment_style(line, normalize_comments) == *self
} }
CommentStyle::Custom(opener) => line.trim_left().starts_with(opener.trim_right()), CommentStyle::Custom(opener) => line.trim_left().starts_with(opener.trim_right()),
} }
@ -130,7 +130,8 @@ fn comment_style(orig: &str, normalize_comments: bool) -> CommentStyle {
CommentStyle::DoubleSlash CommentStyle::DoubleSlash
} }
} else if (orig.starts_with("///") && orig.chars().nth(3).map_or(true, |c| c != '/')) || } else if (orig.starts_with("///") && orig.chars().nth(3).map_or(true, |c| c != '/')) ||
(orig.starts_with("/**") && !orig.starts_with("/**/")) { (orig.starts_with("/**") && !orig.starts_with("/**/"))
{
CommentStyle::TripleSlash CommentStyle::TripleSlash
} else if orig.starts_with("//!") || orig.starts_with("/*!") { } else if orig.starts_with("//!") || orig.starts_with("/*!") {
CommentStyle::Doc CommentStyle::Doc
@ -141,17 +142,20 @@ fn comment_style(orig: &str, normalize_comments: bool) -> CommentStyle {
} }
} }
pub fn rewrite_comment(orig: &str, pub fn rewrite_comment(
block_style: bool, orig: &str,
shape: Shape, block_style: bool,
config: &Config) shape: Shape,
-> Option<String> { config: &Config,
) -> Option<String> {
// If there are lines without a starting sigil, we won't format them correctly // If there are lines without a starting sigil, we won't format them correctly
// so in that case we won't even re-align (if !config.normalize_comments()) and // so in that case we won't even re-align (if !config.normalize_comments()) and
// we should stop now. // we should stop now.
let num_bare_lines = orig.lines() let num_bare_lines = orig.lines()
.map(|line| line.trim()) .map(|line| line.trim())
.filter(|l| !(l.starts_with('*') || l.starts_with("//") || l.starts_with("/*"))) .filter(|l| {
!(l.starts_with('*') || l.starts_with("//") || l.starts_with("/*"))
})
.count(); .count();
if num_bare_lines > 0 && !config.normalize_comments() { if num_bare_lines > 0 && !config.normalize_comments() {
return Some(orig.to_owned()); return Some(orig.to_owned());
@ -163,11 +167,12 @@ pub fn rewrite_comment(orig: &str,
identify_comment(orig, block_style, shape, config) identify_comment(orig, block_style, shape, config)
} }
fn identify_comment(orig: &str, fn identify_comment(
block_style: bool, orig: &str,
shape: Shape, block_style: bool,
config: &Config) shape: Shape,
-> Option<String> { config: &Config,
) -> Option<String> {
let style = comment_style(orig, false); let style = comment_style(orig, false);
let first_group = orig.lines() let first_group = orig.lines()
.take_while(|l| style.line_with_same_comment_style(l, false)) .take_while(|l| style.line_with_same_comment_style(l, false))
@ -178,28 +183,34 @@ fn identify_comment(orig: &str,
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n"); .join("\n");
let first_group_str = let first_group_str = try_opt!(rewrite_comment_inner(
try_opt!(rewrite_comment_inner(&first_group, block_style, style, shape, config)); &first_group,
block_style,
style,
shape,
config,
));
if rest.is_empty() { if rest.is_empty() {
Some(first_group_str) Some(first_group_str)
} else { } else {
identify_comment(&rest, block_style, shape, config).map(|rest_str| { identify_comment(&rest, block_style, shape, config).map(|rest_str| {
format!("{}\n{}{}", format!(
first_group_str, "{}\n{}{}",
shape first_group_str,
.indent shape.indent.to_string(config),
.to_string(config), rest_str
rest_str) )
}) })
} }
} }
fn rewrite_comment_inner(orig: &str, fn rewrite_comment_inner(
block_style: bool, orig: &str,
style: CommentStyle, block_style: bool,
shape: Shape, style: CommentStyle,
config: &Config) shape: Shape,
-> Option<String> { config: &Config,
) -> Option<String> {
let (opener, closer, line_start) = if block_style { let (opener, closer, line_start) = if block_style {
CommentStyle::SingleBullet.to_str_tuplet() CommentStyle::SingleBullet.to_str_tuplet()
} else { } else {
@ -235,10 +246,10 @@ fn rewrite_comment_inner(orig: &str,
}) })
.map(|s| left_trim_comment_line(s, &style)) .map(|s| left_trim_comment_line(s, &style))
.map(|line| if orig.starts_with("/*") && line_breaks == 0 { .map(|line| if orig.starts_with("/*") && line_breaks == 0 {
line.trim_left() line.trim_left()
} else { } else {
line line
}); });
let mut result = opener.to_owned(); let mut result = opener.to_owned();
for line in lines { for line in lines {
@ -299,7 +310,8 @@ fn light_rewrite_comment(orig: &str, offset: Indent, config: &Config) -> Option<
/// Does not trim all whitespace. /// Does not trim all whitespace.
fn left_trim_comment_line<'a>(line: &'a str, style: &CommentStyle) -> &'a str { fn left_trim_comment_line<'a>(line: &'a str, style: &CommentStyle) -> &'a str {
if line.starts_with("//! ") || line.starts_with("/// ") || line.starts_with("/*! ") || if line.starts_with("//! ") || line.starts_with("/// ") || line.starts_with("/*! ") ||
line.starts_with("/** ") { line.starts_with("/** ")
{
&line[4..] &line[4..]
} else if let &CommentStyle::Custom(opener) = style { } else if let &CommentStyle::Custom(opener) = style {
if line.starts_with(opener) { if line.starts_with(opener) {
@ -307,13 +319,15 @@ fn left_trim_comment_line<'a>(line: &'a str, style: &CommentStyle) -> &'a str {
} else { } else {
&line[opener.trim_right().len()..] &line[opener.trim_right().len()..]
} }
} else if line.starts_with("/* ") || line.starts_with("// ") || line.starts_with("//!") || } else if line.starts_with("/* ") || line.starts_with("// ") ||
line.starts_with("///") || line.starts_with("//!") || line.starts_with("///") ||
line.starts_with("** ") || line.starts_with("/*!") || line.starts_with("** ") || line.starts_with("/*!") ||
(line.starts_with("/**") && !line.starts_with("/**/")) { (line.starts_with("/**") && !line.starts_with("/**/"))
{
&line[3..] &line[3..]
} else if line.starts_with("/*") || line.starts_with("* ") || line.starts_with("//") || } else if line.starts_with("/*") || line.starts_with("* ") || line.starts_with("//") ||
line.starts_with("**") { line.starts_with("**")
{
&line[2..] &line[2..]
} else if line.starts_with('*') { } else if line.starts_with('*') {
&line[1..] &line[1..]
@ -379,8 +393,9 @@ pub fn contains_comment(text: &str) -> bool {
} }
struct CharClasses<T> struct CharClasses<T>
where T: Iterator, where
T::Item: RichChar T: Iterator,
T::Item: RichChar,
{ {
base: iter::Peekable<T>, base: iter::Peekable<T>,
status: CharClassesStatus, status: CharClassesStatus,
@ -462,8 +477,9 @@ impl FullCodeCharKind {
} }
impl<T> CharClasses<T> impl<T> CharClasses<T>
where T: Iterator, where
T::Item: RichChar T: Iterator,
T::Item: RichChar,
{ {
fn new(base: T) -> CharClasses<T> { fn new(base: T) -> CharClasses<T> {
CharClasses { CharClasses {
@ -474,8 +490,9 @@ impl<T> CharClasses<T>
} }
impl<T> Iterator for CharClasses<T> impl<T> Iterator for CharClasses<T>
where T: Iterator, where
T::Item: RichChar T: Iterator,
T::Item: RichChar,
{ {
type Item = (FullCodeCharKind, T::Item); type Item = (FullCodeCharKind, T::Item);
@ -603,13 +620,15 @@ impl<'a> Iterator for UngroupedCommentCodeSlices<'a> {
Some(&(_, (end_idx, _))) => &self.slice[start_idx..end_idx], Some(&(_, (end_idx, _))) => &self.slice[start_idx..end_idx],
None => &self.slice[start_idx..], None => &self.slice[start_idx..],
}; };
Some((if kind.is_comment() { Some((
CodeCharKind::Comment if kind.is_comment() {
} else { CodeCharKind::Comment
CodeCharKind::Normal } else {
}, CodeCharKind::Normal
start_idx, },
slice)) start_idx,
slice,
))
} }
} }
@ -650,8 +669,8 @@ impl<'a> Iterator for CommentCodeSlices<'a> {
for (kind, (i, c)) in &mut iter { for (kind, (i, c)) in &mut iter {
let is_comment_connector = self.last_slice_kind == CodeCharKind::Normal && let is_comment_connector = self.last_slice_kind == CodeCharKind::Normal &&
&subslice[..2] == "//" && &subslice[..2] == "//" &&
[' ', '\t'].contains(&c); [' ', '\t'].contains(&c);
if is_comment_connector && first_whitespace.is_none() { if is_comment_connector && first_whitespace.is_none() {
first_whitespace = Some(i); first_whitespace = Some(i);
@ -683,7 +702,11 @@ impl<'a> Iterator for CommentCodeSlices<'a> {
CodeCharKind::Comment => CodeCharKind::Normal, CodeCharKind::Comment => CodeCharKind::Normal,
CodeCharKind::Normal => CodeCharKind::Comment, CodeCharKind::Normal => CodeCharKind::Comment,
}; };
let res = (kind, self.last_slice_end, &self.slice[self.last_slice_end..sub_slice_end]); let res = (
kind,
self.last_slice_end,
&self.slice[self.last_slice_end..sub_slice_end],
);
self.last_slice_end = sub_slice_end; self.last_slice_end = sub_slice_end;
self.last_slice_kind = kind; self.last_slice_kind = kind;
@ -693,11 +716,12 @@ impl<'a> Iterator for CommentCodeSlices<'a> {
/// Checks is `new` didn't miss any comment from `span`, if it removed any, return previous text /// Checks is `new` didn't miss any comment from `span`, if it removed any, return previous text
/// (if it fits in the width/offset, else return None), else return `new` /// (if it fits in the width/offset, else return None), else return `new`
pub fn recover_comment_removed(new: String, pub fn recover_comment_removed(
span: Span, new: String,
context: &RewriteContext, span: Span,
shape: Shape) context: &RewriteContext,
-> Option<String> { shape: Shape,
) -> Option<String> {
let snippet = context.snippet(span); let snippet = context.snippet(span);
if changed_comment_content(&snippet, &new) { if changed_comment_content(&snippet, &new) {
// We missed some comments // We missed some comments
@ -723,12 +747,14 @@ fn changed_comment_content(orig: &str, new: &str) -> bool {
.flat_map(|(_, _, s)| CommentReducer::new(s)) .flat_map(|(_, _, s)| CommentReducer::new(s))
}; };
let res = code_comment_content(orig).ne(code_comment_content(new)); let res = code_comment_content(orig).ne(code_comment_content(new));
debug!("comment::changed_comment_content: {}\norig: '{}'\nnew: '{}'\nraw_old: {}\nraw_new: {}", debug!(
res, "comment::changed_comment_content: {}\norig: '{}'\nnew: '{}'\nraw_old: {}\nraw_new: {}",
orig, res,
new, orig,
code_comment_content(orig).collect::<String>(), new,
code_comment_content(new).collect::<String>()); code_comment_content(orig).collect::<String>(),
code_comment_content(new).collect::<String>()
);
res res
} }
@ -787,11 +813,14 @@ fn remove_comment_header(comment: &str) -> &str {
} else if comment.starts_with("//") { } else if comment.starts_with("//") {
&comment[2..] &comment[2..]
} else if (comment.starts_with("/**") && !comment.starts_with("/**/")) || } else if (comment.starts_with("/**") && !comment.starts_with("/**/")) ||
comment.starts_with("/*!") { comment.starts_with("/*!")
{
&comment[3..comment.len() - 2] &comment[3..comment.len() - 2]
} else { } else {
assert!(comment.starts_with("/*"), assert!(
format!("string '{}' is not a comment", comment)); comment.starts_with("/*"),
format!("string '{}' is not a comment", comment)
);
&comment[2..comment.len() - 2] &comment[2..comment.len() - 2]
} }
} }
@ -819,8 +848,10 @@ mod test {
let mut iter = CommentCodeSlices::new(input); let mut iter = CommentCodeSlices::new(input);
assert_eq!((CodeCharKind::Normal, 0, "code(); "), iter.next().unwrap()); assert_eq!((CodeCharKind::Normal, 0, "code(); "), iter.next().unwrap());
assert_eq!((CodeCharKind::Comment, 8, "/* test */"), assert_eq!(
iter.next().unwrap()); (CodeCharKind::Comment, 8, "/* test */"),
iter.next().unwrap()
);
assert_eq!((CodeCharKind::Normal, 18, " 1 + 1"), iter.next().unwrap()); assert_eq!((CodeCharKind::Normal, 18, " 1 + 1"), iter.next().unwrap());
assert_eq!(None, iter.next()); assert_eq!(None, iter.next());
} }
@ -831,10 +862,14 @@ mod test {
let mut iter = CommentCodeSlices::new(input); let mut iter = CommentCodeSlices::new(input);
assert_eq!((CodeCharKind::Normal, 0, ""), iter.next().unwrap()); assert_eq!((CodeCharKind::Normal, 0, ""), iter.next().unwrap());
assert_eq!((CodeCharKind::Comment, 0, "// comment\n"), assert_eq!(
iter.next().unwrap()); (CodeCharKind::Comment, 0, "// comment\n"),
assert_eq!((CodeCharKind::Normal, 11, " test();"), iter.next().unwrap()
iter.next().unwrap()); );
assert_eq!(
(CodeCharKind::Normal, 11, " test();"),
iter.next().unwrap()
);
assert_eq!(None, iter.next()); assert_eq!(None, iter.next());
} }
@ -844,8 +879,10 @@ mod test {
let mut iter = CommentCodeSlices::new(input); let mut iter = CommentCodeSlices::new(input);
assert_eq!((CodeCharKind::Normal, 0, "1 "), iter.next().unwrap()); assert_eq!((CodeCharKind::Normal, 0, "1 "), iter.next().unwrap());
assert_eq!((CodeCharKind::Comment, 2, "// comment\n // comment2\n"), assert_eq!(
iter.next().unwrap()); (CodeCharKind::Comment, 2, "// comment\n // comment2\n"),
iter.next().unwrap()
);
assert_eq!((CodeCharKind::Normal, 29, "\n"), iter.next().unwrap()); assert_eq!((CodeCharKind::Normal, 29, "\n"), iter.next().unwrap());
assert_eq!(None, iter.next()); assert_eq!(None, iter.next());
} }
@ -896,17 +933,19 @@ mod test {
fn uncommented(text: &str) -> String { fn uncommented(text: &str) -> String {
CharClasses::new(text.chars()) CharClasses::new(text.chars())
.filter_map(|(s, c)| match s { .filter_map(|(s, c)| match s {
FullCodeCharKind::Normal => Some(c), FullCodeCharKind::Normal => Some(c),
_ => None, _ => None,
}) })
.collect() .collect()
} }
#[test] #[test]
fn test_uncommented() { fn test_uncommented() {
assert_eq!(&uncommented("abc/*...*/"), "abc"); assert_eq!(&uncommented("abc/*...*/"), "abc");
assert_eq!(&uncommented("// .... /* \n../* /* *** / */ */a/* // */c\n"), assert_eq!(
"..ac\n"); &uncommented("// .... /* \n../* /* *** / */ */a/* // */c\n"),
"..ac\n"
);
assert_eq!(&uncommented("abc \" /* */\" qsdf"), "abc \" /* */\" qsdf"); assert_eq!(&uncommented("abc \" /* */\" qsdf"), "abc \" /* */\" qsdf");
} }
@ -927,9 +966,11 @@ mod test {
check("/*/ */test", "test", Some(6)); check("/*/ */test", "test", Some(6));
check("//test\ntest", "test", Some(7)); check("//test\ntest", "test", Some(7));
check("/* comment only */", "whatever", None); check("/* comment only */", "whatever", None);
check("/* comment */ some text /* more commentary */ result", check(
"result", "/* comment */ some text /* more commentary */ result",
Some(46)); "result",
Some(46),
);
check("sup // sup", "p", Some(2)); check("sup // sup", "p", Some(2));
check("sup", "x", None); check("sup", "x", None);
check(r#"π? /**/ π is nice!"#, r#"π is nice"#, Some(9)); check(r#"π? /**/ π is nice!"#, r#"π is nice"#, Some(9));

View file

@ -605,7 +605,9 @@ mod test {
let used_options = config.used_options(); let used_options = config.used_options();
let toml = used_options.to_toml().unwrap(); let toml = used_options.to_toml().unwrap();
assert_eq!(toml, assert_eq!(
format!("verbose = {}\nskip_children = {}\n", verbose, skip_children)); toml,
format!("verbose = {}\nskip_children = {}\n", verbose, skip_children)
);
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -52,7 +52,7 @@ impl Range {
false false
} else { } else {
(self.lo <= other.hi && other.hi <= self.hi) || (self.lo <= other.hi && other.hi <= self.hi) ||
(other.lo <= self.hi && self.hi <= other.hi) (other.lo <= self.hi && self.hi <= other.hi)
} }
} }
@ -68,7 +68,10 @@ impl Range {
/// intersect; returns `None` otherwise. /// intersect; returns `None` otherwise.
fn merge(self, other: Range) -> Option<Range> { fn merge(self, other: Range) -> Option<Range> {
if self.adjacent_to(other) || self.intersects(other) { if self.adjacent_to(other) || self.intersects(other) {
Some(Range::new(cmp::min(self.lo, other.lo), cmp::max(self.hi, other.hi))) Some(Range::new(
cmp::min(self.lo, other.lo),
cmp::max(self.hi, other.hi),
))
} else { } else {
None None
} }
@ -127,7 +130,8 @@ impl FileLines {
/// Returns true if `self` includes all lines in all files. Otherwise runs `f` on all ranges in /// Returns true if `self` includes all lines in all files. Otherwise runs `f` on all ranges in
/// the designated file (if any) and returns true if `f` ever does. /// the designated file (if any) and returns true if `f` ever does.
fn file_range_matches<F>(&self, file_name: &str, f: F) -> bool fn file_range_matches<F>(&self, file_name: &str, f: F) -> bool
where F: FnMut(&Range) -> bool where
F: FnMut(&Range) -> bool,
{ {
let map = match self.0 { let map = match self.0 {
// `None` means "all lines in all files". // `None` means "all lines in all files".
@ -209,8 +213,9 @@ struct JsonSpan {
impl JsonSpan { impl JsonSpan {
fn into_tuple(self) -> Result<(String, Range), String> { fn into_tuple(self) -> Result<(String, Range), String> {
let (lo, hi) = self.range; let (lo, hi) = self.range;
let canonical = canonicalize_path_string(&self.file) let canonical = canonicalize_path_string(&self.file).ok_or_else(|| {
.ok_or_else(|| format!("Can't canonicalize {}", &self.file))?; format!("Can't canonicalize {}", &self.file)
})?;
Ok((canonical, Range::new(lo, hi))) Ok((canonical, Range::new(lo, hi)))
} }
} }
@ -219,10 +224,13 @@ impl JsonSpan {
// for `FileLines`, so it will just panic instead. // for `FileLines`, so it will just panic instead.
impl<'de> ::serde::de::Deserialize<'de> for FileLines { impl<'de> ::serde::de::Deserialize<'de> for FileLines {
fn deserialize<D>(_: D) -> Result<Self, D::Error> fn deserialize<D>(_: D) -> Result<Self, D::Error>
where D: ::serde::de::Deserializer<'de> where
D: ::serde::de::Deserializer<'de>,
{ {
panic!("FileLines cannot be deserialized from a project rustfmt.toml file: please \ panic!(
specify it via the `--file-lines` option instead"); "FileLines cannot be deserialized from a project rustfmt.toml file: please \
specify it via the `--file-lines` option instead"
);
} }
} }
@ -230,7 +238,8 @@ impl<'de> ::serde::de::Deserialize<'de> for FileLines {
// `Config` struct should ensure this impl is never reached. // `Config` struct should ensure this impl is never reached.
impl ::serde::ser::Serialize for FileLines { impl ::serde::ser::Serialize for FileLines {
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
where S: ::serde::ser::Serializer where
S: ::serde::ser::Serializer,
{ {
unreachable!("FileLines cannot be serialized. This is a rustfmt bug."); unreachable!("FileLines cannot be serialized. This is a rustfmt bug.");
} }
@ -270,13 +279,21 @@ mod test {
fn test_range_merge() { fn test_range_merge() {
assert_eq!(None, Range::new(1, 3).merge(Range::new(5, 5))); assert_eq!(None, Range::new(1, 3).merge(Range::new(5, 5)));
assert_eq!(None, Range::new(4, 7).merge(Range::new(0, 1))); assert_eq!(None, Range::new(4, 7).merge(Range::new(0, 1)));
assert_eq!(Some(Range::new(3, 7)), assert_eq!(
Range::new(3, 5).merge(Range::new(4, 7))); Some(Range::new(3, 7)),
assert_eq!(Some(Range::new(3, 7)), Range::new(3, 5).merge(Range::new(4, 7))
Range::new(3, 5).merge(Range::new(5, 7))); );
assert_eq!(Some(Range::new(3, 7)), assert_eq!(
Range::new(3, 5).merge(Range::new(6, 7))); Some(Range::new(3, 7)),
assert_eq!(Some(Range::new(3, 7)), Range::new(3, 5).merge(Range::new(5, 7))
Range::new(3, 7).merge(Range::new(4, 5))); );
assert_eq!(
Some(Range::new(3, 7)),
Range::new(3, 5).merge(Range::new(6, 7))
);
assert_eq!(
Some(Range::new(3, 7)),
Range::new(3, 7).merge(Range::new(4, 5))
);
} }
} }

View file

@ -31,7 +31,8 @@ pub fn append_newline(s: &mut StringBuffer) {
} }
pub fn write_all_files<T>(file_map: &FileMap, out: &mut T, config: &Config) -> Result<(), io::Error> pub fn write_all_files<T>(file_map: &FileMap, out: &mut T, config: &Config) -> Result<(), io::Error>
where T: Write where
T: Write,
{ {
output_header(out, config.write_mode()).ok(); output_header(out, config.write_mode()).ok();
for &(ref filename, ref text) in file_map { for &(ref filename, ref text) in file_map {
@ -43,11 +44,13 @@ pub fn write_all_files<T>(file_map: &FileMap, out: &mut T, config: &Config) -> R
} }
// Prints all newlines either as `\n` or as `\r\n`. // Prints all newlines either as `\n` or as `\r\n`.
pub fn write_system_newlines<T>(writer: T, pub fn write_system_newlines<T>(
text: &StringBuffer, writer: T,
config: &Config) text: &StringBuffer,
-> Result<(), io::Error> config: &Config,
where T: Write ) -> Result<(), io::Error>
where
T: Write,
{ {
// Buffer output, since we're writing a since char at a time. // Buffer output, since we're writing a since char at a time.
let mut writer = BufWriter::new(writer); let mut writer = BufWriter::new(writer);
@ -78,18 +81,21 @@ pub fn write_system_newlines<T>(writer: T,
} }
} }
pub fn write_file<T>(text: &StringBuffer, pub fn write_file<T>(
filename: &str, text: &StringBuffer,
out: &mut T, filename: &str,
config: &Config) out: &mut T,
-> Result<bool, io::Error> config: &Config,
where T: Write ) -> Result<bool, io::Error>
where
T: Write,
{ {
fn source_and_formatted_text(text: &StringBuffer, fn source_and_formatted_text(
filename: &str, text: &StringBuffer,
config: &Config) filename: &str,
-> Result<(String, String), io::Error> { config: &Config,
) -> Result<(String, String), io::Error> {
let mut f = File::open(filename)?; let mut f = File::open(filename)?;
let mut ori_text = String::new(); let mut ori_text = String::new();
f.read_to_string(&mut ori_text)?; f.read_to_string(&mut ori_text)?;
@ -99,10 +105,11 @@ pub fn write_file<T>(text: &StringBuffer,
Ok((ori_text, fmt_text)) Ok((ori_text, fmt_text))
} }
fn create_diff(filename: &str, fn create_diff(
text: &StringBuffer, filename: &str,
config: &Config) text: &StringBuffer,
-> Result<Vec<Mismatch>, io::Error> { config: &Config,
) -> Result<Vec<Mismatch>, io::Error> {
let (ori, fmt) = source_and_formatted_text(text, filename, config)?; let (ori, fmt) = source_and_formatted_text(text, filename, config)?;
Ok(make_diff(&ori, &fmt, 3)) Ok(make_diff(&ori, &fmt, 3))
} }

View file

@ -73,9 +73,10 @@ fn compare_path_list_items(a: &ast::PathListItem, b: &ast::PathListItem) -> Orde
} }
} }
fn compare_path_list_item_lists(a_items: &Vec<ast::PathListItem>, fn compare_path_list_item_lists(
b_items: &Vec<ast::PathListItem>) a_items: &Vec<ast::PathListItem>,
-> Ordering { b_items: &Vec<ast::PathListItem>,
) -> Ordering {
let mut a = a_items.clone(); let mut a = a_items.clone();
let mut b = b_items.clone(); let mut b = b_items.clone();
a.sort_by(|a, b| compare_path_list_items(a, b)); a.sort_by(|a, b| compare_path_list_items(a, b));
@ -123,19 +124,33 @@ fn compare_use_items(a: &ast::Item, b: &ast::Item) -> Option<Ordering> {
// TODO (some day) remove unused imports, expand globs, compress many single // TODO (some day) remove unused imports, expand globs, compress many single
// imports into a list import. // imports into a list import.
fn rewrite_view_path_prefix(path: &ast::Path, fn rewrite_view_path_prefix(
context: &RewriteContext, path: &ast::Path,
shape: Shape) context: &RewriteContext,
-> Option<String> { shape: Shape,
) -> Option<String> {
let path_str = if path.segments.last().unwrap().identifier.to_string() == "self" && let path_str = if path.segments.last().unwrap().identifier.to_string() == "self" &&
path.segments.len() > 1 { path.segments.len() > 1
{
let path = &ast::Path { let path = &ast::Path {
span: path.span.clone(), span: path.span.clone(),
segments: path.segments[..path.segments.len() - 1].to_owned(), segments: path.segments[..path.segments.len() - 1].to_owned(),
}; };
try_opt!(rewrite_path(context, PathContext::Import, None, path, shape)) try_opt!(rewrite_path(
context,
PathContext::Import,
None,
path,
shape,
))
} else { } else {
try_opt!(rewrite_path(context, PathContext::Import, None, path, shape)) try_opt!(rewrite_path(
context,
PathContext::Import,
None,
path,
shape,
))
}; };
Some(path_str) Some(path_str)
} }
@ -162,11 +177,13 @@ impl Rewrite for ast::ViewPath {
let prefix_shape = try_opt!(shape.sub_width(ident_str.len() + 4)); let prefix_shape = try_opt!(shape.sub_width(ident_str.len() + 4));
let path_str = try_opt!(rewrite_view_path_prefix(path, context, prefix_shape)); let path_str = try_opt!(rewrite_view_path_prefix(path, context, prefix_shape));
Some(if path.segments.last().unwrap().identifier == ident { Some(
path_str if path.segments.last().unwrap().identifier == ident {
} else { path_str
format!("{} as {}", path_str, ident_str) } else {
}) format!("{} as {}", path_str, ident_str)
},
)
} }
} }
} }
@ -179,13 +196,13 @@ impl<'a> FmtVisitor<'a> {
let pos_before_first_use_item = use_items let pos_before_first_use_item = use_items
.first() .first()
.map(|p_i| { .map(|p_i| {
cmp::max(self.last_pos, cmp::max(
p_i.attrs self.last_pos,
.iter() p_i.attrs.iter().map(|attr| attr.span.lo).min().unwrap_or(
.map(|attr| attr.span.lo) p_i.span.lo,
.min() ),
.unwrap_or(p_i.span.lo)) )
}) })
.unwrap_or(self.last_pos); .unwrap_or(self.last_pos);
// Construct a list of pairs, each containing a `use` item and the start of span before // Construct a list of pairs, each containing a `use` item and the start of span before
// that `use` item. // that `use` item.
@ -193,10 +210,10 @@ impl<'a> FmtVisitor<'a> {
let mut ordered_use_items = use_items let mut ordered_use_items = use_items
.iter() .iter()
.map(|p_i| { .map(|p_i| {
let new_item = (&*p_i, last_pos_of_prev_use_item); let new_item = (&*p_i, last_pos_of_prev_use_item);
last_pos_of_prev_use_item = p_i.span.hi; last_pos_of_prev_use_item = p_i.span.hi;
new_item new_item
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let pos_after_last_use_item = last_pos_of_prev_use_item; let pos_after_last_use_item = last_pos_of_prev_use_item;
// Order the imports by view-path & other import path properties // Order the imports by view-path & other import path properties
@ -237,8 +254,10 @@ impl<'a> FmtVisitor<'a> {
let mut offset = self.block_indent; let mut offset = self.block_indent;
offset.alignment += vis.len() + "use ".len(); offset.alignment += vis.len() + "use ".len();
// 1 = ";" // 1 = ";"
match vp.rewrite(&self.get_context(), match vp.rewrite(
Shape::legacy(self.config.max_width() - offset.width() - 1, offset)) { &self.get_context(),
Shape::legacy(self.config.max_width() - offset.width() - 1, offset),
) {
Some(ref s) if s.is_empty() => { Some(ref s) if s.is_empty() => {
// Format up to last newline // Format up to last newline
let prev_span = utils::mk_sp(self.last_pos, source!(self, span).lo); let prev_span = utils::mk_sp(self.last_pos, source!(self, span).lo);
@ -295,14 +314,21 @@ fn append_alias(path_item_str: String, vpi: &ast::PathListItem) -> String {
// Pretty prints a multi-item import. // Pretty prints a multi-item import.
// Assumes that path_list.len() > 0. // Assumes that path_list.len() > 0.
pub fn rewrite_use_list(shape: Shape, pub fn rewrite_use_list(
path: &ast::Path, shape: Shape,
path_list: &[ast::PathListItem], path: &ast::Path,
span: Span, path_list: &[ast::PathListItem],
context: &RewriteContext) span: Span,
-> Option<String> { context: &RewriteContext,
) -> Option<String> {
// Returns a different option to distinguish `::foo` and `foo` // Returns a different option to distinguish `::foo` and `foo`
let path_str = try_opt!(rewrite_path(context, PathContext::Import, None, path, shape)); let path_str = try_opt!(rewrite_path(
context,
PathContext::Import,
None,
path,
shape,
));
match path_list.len() { match path_list.len() {
0 => unreachable!(), 0 => unreachable!(),
@ -321,14 +347,16 @@ pub fn rewrite_use_list(shape: Shape,
let mut items = { let mut items = {
// Dummy value, see explanation below. // Dummy value, see explanation below.
let mut items = vec![ListItem::from_str("")]; let mut items = vec![ListItem::from_str("")];
let iter = itemize_list(context.codemap, let iter = itemize_list(
path_list.iter(), context.codemap,
"}", path_list.iter(),
|vpi| vpi.span.lo, "}",
|vpi| vpi.span.hi, |vpi| vpi.span.lo,
rewrite_path_item, |vpi| vpi.span.hi,
context.codemap.span_after(span, "{"), rewrite_path_item,
span.hi); context.codemap.span_after(span, "{"),
span.hi,
);
items.extend(iter); items.extend(iter);
items items
}; };
@ -344,34 +372,40 @@ pub fn rewrite_use_list(shape: Shape,
} }
let tactic = definitive_tactic(&items[first_index..], let tactic = definitive_tactic(
::lists::ListTactic::Mixed, &items[first_index..],
remaining_width); ::lists::ListTactic::Mixed,
remaining_width,
);
let fmt = ListFormatting { let fmt = ListFormatting {
tactic: tactic, tactic: tactic,
separator: ",", separator: ",",
trailing_separator: SeparatorTactic::Never, trailing_separator: SeparatorTactic::Never,
// Add one to the indent to account for "{" // Add one to the indent to account for "{"
shape: Shape::legacy(remaining_width, shape: Shape::legacy(
shape.indent + path_str.len() + colons_offset + 1), remaining_width,
shape.indent + path_str.len() + colons_offset + 1,
),
ends_with_newline: false, ends_with_newline: false,
config: context.config, config: context.config,
}; };
let list_str = try_opt!(write_list(&items[first_index..], &fmt)); let list_str = try_opt!(write_list(&items[first_index..], &fmt));
Some(if path_str.is_empty() { Some(
format!("{{{}}}", list_str) if path_str.is_empty() {
} else { format!("{{{}}}", list_str)
format!("{}::{{{}}}", path_str, list_str) } else {
}) format!("{}::{{{}}}", path_str, list_str)
},
)
} }
// Returns true when self item was found. // Returns true when self item was found.
fn move_self_to_front(items: &mut Vec<ListItem>) -> bool { fn move_self_to_front(items: &mut Vec<ListItem>) -> bool {
match items match items.iter().position(|item| {
.iter() item.item.as_ref().map(|x| &x[..]) == Some("self")
.position(|item| item.item.as_ref().map(|x| &x[..]) == Some("self")) { }) {
Some(pos) => { Some(pos) => {
items[0] = items.remove(pos); items[0] = items.remove(pos);
true true

View file

@ -172,11 +172,12 @@ impl BadIssueSeeker {
} }
} }
fn inspect_number(&mut self, fn inspect_number(
c: char, &mut self,
issue: Issue, c: char,
mut part: NumberPart) issue: Issue,
-> IssueClassification { mut part: NumberPart,
) -> IssueClassification {
if !issue.missing_number || c == '\n' { if !issue.missing_number || c == '\n' {
return IssueClassification::Bad(issue); return IssueClassification::Bad(issue);
} else if c == ')' { } else if c == ')' {
@ -223,8 +224,10 @@ impl BadIssueSeeker {
fn find_unnumbered_issue() { fn find_unnumbered_issue() {
fn check_fail(text: &str, failing_pos: usize) { fn check_fail(text: &str, failing_pos: usize) {
let mut seeker = BadIssueSeeker::new(ReportTactic::Unnumbered, ReportTactic::Unnumbered); let mut seeker = BadIssueSeeker::new(ReportTactic::Unnumbered, ReportTactic::Unnumbered);
assert_eq!(Some(failing_pos), assert_eq!(
text.chars().position(|c| seeker.inspect(c).is_some())); Some(failing_pos),
text.chars().position(|c| seeker.inspect(c).is_some())
);
} }
fn check_pass(text: &str) { fn check_pass(text: &str) {
@ -252,46 +255,60 @@ fn find_issue() {
text.chars().any(|c| seeker.inspect(c).is_some()) text.chars().any(|c| seeker.inspect(c).is_some())
} }
assert!(is_bad_issue("TODO(@maintainer, #1222, hello)\n", assert!(is_bad_issue(
ReportTactic::Always, "TODO(@maintainer, #1222, hello)\n",
ReportTactic::Never)); ReportTactic::Always,
ReportTactic::Never,
));
assert!(!is_bad_issue("TODO: no number\n", assert!(!is_bad_issue(
ReportTactic::Never, "TODO: no number\n",
ReportTactic::Always)); ReportTactic::Never,
ReportTactic::Always,
));
assert!(is_bad_issue("This is a FIXME(#1)\n", assert!(is_bad_issue(
ReportTactic::Never, "This is a FIXME(#1)\n",
ReportTactic::Always)); ReportTactic::Never,
ReportTactic::Always,
));
assert!(!is_bad_issue("bad FIXME\n", ReportTactic::Always, ReportTactic::Never)); assert!(!is_bad_issue(
"bad FIXME\n",
ReportTactic::Always,
ReportTactic::Never,
));
} }
#[test] #[test]
fn issue_type() { fn issue_type() {
let mut seeker = BadIssueSeeker::new(ReportTactic::Always, ReportTactic::Never); let mut seeker = BadIssueSeeker::new(ReportTactic::Always, ReportTactic::Never);
let expected = Some(Issue { let expected = Some(Issue {
issue_type: IssueType::Todo, issue_type: IssueType::Todo,
missing_number: false, missing_number: false,
}); });
assert_eq!(expected, assert_eq!(
"TODO(#100): more awesomeness" expected,
.chars() "TODO(#100): more awesomeness"
.map(|c| seeker.inspect(c)) .chars()
.find(Option::is_some) .map(|c| seeker.inspect(c))
.unwrap()); .find(Option::is_some)
.unwrap()
);
let mut seeker = BadIssueSeeker::new(ReportTactic::Never, ReportTactic::Unnumbered); let mut seeker = BadIssueSeeker::new(ReportTactic::Never, ReportTactic::Unnumbered);
let expected = Some(Issue { let expected = Some(Issue {
issue_type: IssueType::Fixme, issue_type: IssueType::Fixme,
missing_number: true, missing_number: true,
}); });
assert_eq!(expected, assert_eq!(
"Test. FIXME: bad, bad, not good" expected,
.chars() "Test. FIXME: bad, bad, not good"
.map(|c| seeker.inspect(c)) .chars()
.find(Option::is_some) .map(|c| seeker.inspect(c))
.unwrap()); .find(Option::is_some)
.unwrap()
);
} }

File diff suppressed because it is too large Load diff

View file

@ -189,8 +189,10 @@ impl Sub for Indent {
type Output = Indent; type Output = Indent;
fn sub(self, rhs: Indent) -> Indent { fn sub(self, rhs: Indent) -> Indent {
Indent::new(self.block_indent - rhs.block_indent, Indent::new(
self.alignment - rhs.alignment) self.block_indent - rhs.block_indent,
self.alignment - rhs.alignment,
)
} }
} }
@ -315,17 +317,17 @@ impl Shape {
pub fn sub_width(&self, width: usize) -> Option<Shape> { pub fn sub_width(&self, width: usize) -> Option<Shape> {
Some(Shape { Some(Shape {
width: try_opt!(self.width.checked_sub(width)), width: try_opt!(self.width.checked_sub(width)),
..*self ..*self
}) })
} }
pub fn shrink_left(&self, width: usize) -> Option<Shape> { pub fn shrink_left(&self, width: usize) -> Option<Shape> {
Some(Shape { Some(Shape {
width: try_opt!(self.width.checked_sub(width)), width: try_opt!(self.width.checked_sub(width)),
indent: self.indent + width, indent: self.indent + width,
offset: self.offset + width, offset: self.offset + width,
}) })
} }
pub fn offset_left(&self, width: usize) -> Option<Shape> { pub fn offset_left(&self, width: usize) -> Option<Shape> {
@ -350,10 +352,12 @@ impl fmt::Display for ErrorKind {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self { match *self {
ErrorKind::LineOverflow(found, maximum) => { ErrorKind::LineOverflow(found, maximum) => {
write!(fmt, write!(
"line exceeded maximum length (maximum: {}, found: {})", fmt,
maximum, "line exceeded maximum length (maximum: {}, found: {})",
found) maximum,
found
)
} }
ErrorKind::TrailingWhitespace => write!(fmt, "left behind trailing whitespace"), ErrorKind::TrailingWhitespace => write!(fmt, "left behind trailing whitespace"),
ErrorKind::BadIssue(issue) => write!(fmt, "found {}", issue), ErrorKind::BadIssue(issue) => write!(fmt, "found {}", issue),
@ -412,13 +416,15 @@ impl fmt::Display for FormatReport {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
for (file, errors) in &self.file_error_map { for (file, errors) in &self.file_error_map {
for error in errors { for error in errors {
write!(fmt, write!(
"{} {}:{}: {} {}\n", fmt,
error.msg_prefix(), "{} {}:{}: {} {}\n",
file, error.msg_prefix(),
error.line, file,
error.kind, error.line,
error.msg_suffix())?; error.kind,
error.msg_suffix()
)?;
} }
} }
Ok(()) Ok(())
@ -426,14 +432,16 @@ impl fmt::Display for FormatReport {
} }
// Formatting which depends on the AST. // Formatting which depends on the AST.
fn format_ast<F>(krate: &ast::Crate, fn format_ast<F>(
mut parse_session: &mut ParseSess, krate: &ast::Crate,
main_file: &Path, mut parse_session: &mut ParseSess,
config: &Config, main_file: &Path,
codemap: &Rc<CodeMap>, config: &Config,
mut after_file: F) codemap: &Rc<CodeMap>,
-> Result<(FileMap, bool), io::Error> mut after_file: F,
where F: FnMut(&str, &mut StringBuffer) -> Result<bool, io::Error> ) -> Result<(FileMap, bool), io::Error>
where
F: FnMut(&str, &mut StringBuffer) -> Result<bool, io::Error>,
{ {
let mut result = FileMap::new(); let mut result = FileMap::new();
// diff mode: check if any files are differing // diff mode: check if any files are differing
@ -493,9 +501,9 @@ fn format_lines(text: &mut StringBuffer, name: &str, config: &Config, report: &m
// Add warnings for bad todos/ fixmes // Add warnings for bad todos/ fixmes
if let Some(issue) = issue_seeker.inspect(c) { if let Some(issue) = issue_seeker.inspect(c) {
errors.push(FormattingError { errors.push(FormattingError {
line: cur_line, line: cur_line,
kind: ErrorKind::BadIssue(issue), kind: ErrorKind::BadIssue(issue),
}); });
} }
} }
@ -510,9 +518,9 @@ fn format_lines(text: &mut StringBuffer, name: &str, config: &Config, report: &m
// Check for any line width errors we couldn't correct. // Check for any line width errors we couldn't correct.
if config.error_on_line_overflow() && line_len > config.max_width() { if config.error_on_line_overflow() && line_len > config.max_width() {
errors.push(FormattingError { errors.push(FormattingError {
line: cur_line, line: cur_line,
kind: ErrorKind::LineOverflow(line_len, config.max_width()), kind: ErrorKind::LineOverflow(line_len, config.max_width()),
}); });
} }
} }
@ -541,17 +549,18 @@ fn format_lines(text: &mut StringBuffer, name: &str, config: &Config, report: &m
for &(l, _, _) in &trims { for &(l, _, _) in &trims {
errors.push(FormattingError { errors.push(FormattingError {
line: l, line: l,
kind: ErrorKind::TrailingWhitespace, kind: ErrorKind::TrailingWhitespace,
}); });
} }
report.file_error_map.insert(name.to_owned(), errors); report.file_error_map.insert(name.to_owned(), errors);
} }
fn parse_input(input: Input, fn parse_input(
parse_session: &ParseSess) input: Input,
-> Result<ast::Crate, Option<DiagnosticBuilder>> { parse_session: &ParseSess,
) -> Result<ast::Crate, Option<DiagnosticBuilder>> {
let result = match input { let result = match input {
Input::File(file) => { Input::File(file) => {
let mut parser = parse::new_parser_from_file(parse_session, &file); let mut parser = parse::new_parser_from_file(parse_session, &file);
@ -579,10 +588,11 @@ fn parse_input(input: Input,
} }
} }
pub fn format_input<T: Write>(input: Input, pub fn format_input<T: Write>(
config: &Config, input: Input,
mut out: Option<&mut T>) config: &Config,
-> Result<(Summary, FileMap, FormatReport), (io::Error, Summary)> { mut out: Option<&mut T>,
) -> Result<(Summary, FileMap, FormatReport), (io::Error, Summary)> {
let mut summary = Summary::new(); let mut summary = Summary::new();
if config.disable_all_formatting() { if config.disable_all_formatting() {
return Ok((summary, FileMap::new(), FormatReport::new())); return Ok((summary, FileMap::new(), FormatReport::new()));
@ -614,7 +624,10 @@ pub fn format_input<T: Write>(input: Input,
} }
// Suppress error output after parsing. // Suppress error output after parsing.
let silent_emitter = Box::new(EmitterWriter::new(Box::new(Vec::new()), Some(codemap.clone()))); let silent_emitter = Box::new(EmitterWriter::new(
Box::new(Vec::new()),
Some(codemap.clone()),
));
parse_session.span_diagnostic = Handler::with_emitter(true, false, silent_emitter); parse_session.span_diagnostic = Handler::with_emitter(true, false, silent_emitter);
let mut report = FormatReport::new(); let mut report = FormatReport::new();

View file

@ -69,22 +69,27 @@ pub struct ListFormatting<'a> {
} }
pub fn format_fn_args<I>(items: I, shape: Shape, config: &Config) -> Option<String> pub fn format_fn_args<I>(items: I, shape: Shape, config: &Config) -> Option<String>
where I: Iterator<Item = ListItem> where
I: Iterator<Item = ListItem>,
{ {
list_helper(items, list_helper(
shape, items,
config, shape,
ListTactic::LimitedHorizontalVertical(config.fn_call_width())) config,
ListTactic::LimitedHorizontalVertical(config.fn_call_width()),
)
} }
pub fn format_item_list<I>(items: I, shape: Shape, config: &Config) -> Option<String> pub fn format_item_list<I>(items: I, shape: Shape, config: &Config) -> Option<String>
where I: Iterator<Item = ListItem> where
I: Iterator<Item = ListItem>,
{ {
list_helper(items, shape, config, ListTactic::HorizontalVertical) list_helper(items, shape, config, ListTactic::HorizontalVertical)
} }
pub fn list_helper<I>(items: I, shape: Shape, config: &Config, tactic: ListTactic) -> Option<String> pub fn list_helper<I>(items: I, shape: Shape, config: &Config, tactic: ListTactic) -> Option<String>
where I: Iterator<Item = ListItem> where
I: Iterator<Item = ListItem>,
{ {
let item_vec: Vec<_> = items.collect(); let item_vec: Vec<_> = items.collect();
let tactic = definitive_tactic(&item_vec, tactic, shape.width); let tactic = definitive_tactic(&item_vec, tactic, shape.width);
@ -120,15 +125,16 @@ pub struct ListItem {
impl ListItem { impl ListItem {
pub fn is_multiline(&self) -> bool { pub fn is_multiline(&self) -> bool {
self.item.as_ref().map_or(false, |s| s.contains('\n')) || self.pre_comment.is_some() || self.item.as_ref().map_or(false, |s| s.contains('\n')) || self.pre_comment.is_some() ||
self.post_comment self.post_comment.as_ref().map_or(
.as_ref() false,
.map_or(false, |s| s.contains('\n')) |s| s.contains('\n'),
)
} }
pub fn has_line_pre_comment(&self) -> bool { pub fn has_line_pre_comment(&self) -> bool {
self.pre_comment self.pre_comment.as_ref().map_or(false, |comment| {
.as_ref() comment.starts_with("//")
.map_or(false, |comment| comment.starts_with("//")) })
} }
pub fn from_str<S: Into<String>>(s: S) -> ListItem { pub fn from_str<S: Into<String>>(s: S) -> ListItem {
@ -150,13 +156,13 @@ pub enum DefinitiveListTactic {
} }
pub fn definitive_tactic<I, T>(items: I, tactic: ListTactic, width: usize) -> DefinitiveListTactic pub fn definitive_tactic<I, T>(items: I, tactic: ListTactic, width: usize) -> DefinitiveListTactic
where I: IntoIterator<Item = T> + Clone, where
T: AsRef<ListItem> I: IntoIterator<Item = T> + Clone,
T: AsRef<ListItem>,
{ {
let pre_line_comments = items let pre_line_comments = items.clone().into_iter().any(|item| {
.clone() item.as_ref().has_line_pre_comment()
.into_iter() });
.any(|item| item.as_ref().has_line_pre_comment());
let limit = match tactic { let limit = match tactic {
_ if pre_line_comments => return DefinitiveListTactic::Vertical, _ if pre_line_comments => return DefinitiveListTactic::Vertical,
@ -173,7 +179,8 @@ pub fn definitive_tactic<I, T>(items: I, tactic: ListTactic, width: usize) -> De
let real_total = total_width + total_sep_len; let real_total = total_width + total_sep_len;
if real_total <= limit && !pre_line_comments && if real_total <= limit && !pre_line_comments &&
!items.into_iter().any(|item| item.as_ref().is_multiline()) { !items.into_iter().any(|item| item.as_ref().is_multiline())
{
DefinitiveListTactic::Horizontal DefinitiveListTactic::Horizontal
} else { } else {
DefinitiveListTactic::Vertical DefinitiveListTactic::Vertical
@ -183,8 +190,9 @@ pub fn definitive_tactic<I, T>(items: I, tactic: ListTactic, width: usize) -> De
// Format a list of commented items into a string. // Format a list of commented items into a string.
// TODO: add unit tests // TODO: add unit tests
pub fn write_list<I, T>(items: I, formatting: &ListFormatting) -> Option<String> pub fn write_list<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
where I: IntoIterator<Item = T>, where
T: AsRef<ListItem> I: IntoIterator<Item = T>,
T: AsRef<ListItem>,
{ {
let tactic = formatting.tactic; let tactic = formatting.tactic;
let sep_len = formatting.separator.len(); let sep_len = formatting.separator.len();
@ -250,8 +258,12 @@ pub fn write_list<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
// Block style in non-vertical mode. // Block style in non-vertical mode.
let block_mode = tactic != DefinitiveListTactic::Vertical; let block_mode = tactic != DefinitiveListTactic::Vertical;
// Width restriction is only relevant in vertical mode. // Width restriction is only relevant in vertical mode.
let comment = let comment = try_opt!(rewrite_comment(
try_opt!(rewrite_comment(comment, block_mode, formatting.shape, formatting.config)); comment,
block_mode,
formatting.shape,
formatting.config,
));
result.push_str(&comment); result.push_str(&comment);
if tactic == DefinitiveListTactic::Vertical { if tactic == DefinitiveListTactic::Vertical {
@ -267,11 +279,12 @@ pub fn write_list<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
// Post-comments // Post-comments
if tactic != DefinitiveListTactic::Vertical && item.post_comment.is_some() { if tactic != DefinitiveListTactic::Vertical && item.post_comment.is_some() {
let comment = item.post_comment.as_ref().unwrap(); let comment = item.post_comment.as_ref().unwrap();
let formatted_comment = let formatted_comment = try_opt!(rewrite_comment(
try_opt!(rewrite_comment(comment, comment,
true, true,
Shape::legacy(formatting.shape.width, Indent::empty()), Shape::legacy(formatting.shape.width, Indent::empty()),
formatting.config)); formatting.config,
));
result.push(' '); result.push(' ');
result.push_str(&formatted_comment); result.push_str(&formatted_comment);
@ -295,13 +308,15 @@ pub fn write_list<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
debug!("Width = {}, offset = {:?}", width, offset); debug!("Width = {}, offset = {:?}", width, offset);
// Use block-style only for the last item or multiline comments. // Use block-style only for the last item or multiline comments.
let block_style = !formatting.ends_with_newline && last || let block_style = !formatting.ends_with_newline && last ||
comment.trim().contains('\n') || comment.trim().contains('\n') ||
comment.trim().len() > width; comment.trim().len() > width;
let formatted_comment = try_opt!(rewrite_comment(comment, let formatted_comment = try_opt!(rewrite_comment(
block_style, comment,
Shape::legacy(width, offset), block_style,
formatting.config)); Shape::legacy(width, offset),
formatting.config,
));
if !formatted_comment.starts_with('\n') { if !formatted_comment.starts_with('\n') {
result.push(' '); result.push(' ');
@ -318,7 +333,8 @@ pub fn write_list<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
} }
pub struct ListItems<'a, I, F1, F2, F3> pub struct ListItems<'a, I, F1, F2, F3>
where I: Iterator where
I: Iterator,
{ {
codemap: &'a CodeMap, codemap: &'a CodeMap,
inner: Peekable<I>, inner: Peekable<I>,
@ -331,10 +347,11 @@ pub struct ListItems<'a, I, F1, F2, F3>
} }
impl<'a, T, I, F1, F2, F3> Iterator for ListItems<'a, I, F1, F2, F3> impl<'a, T, I, F1, F2, F3> Iterator for ListItems<'a, I, F1, F2, F3>
where I: Iterator<Item = T>, where
F1: Fn(&T) -> BytePos, I: Iterator<Item = T>,
F2: Fn(&T) -> BytePos, F1: Fn(&T) -> BytePos,
F3: Fn(&T) -> Option<String> F2: Fn(&T) -> BytePos,
F3: Fn(&T) -> Option<String>,
{ {
type Item = ListItem; type Item = ListItem;
@ -349,7 +366,7 @@ impl<'a, T, I, F1, F2, F3> Iterator for ListItems<'a, I, F1, F2, F3>
.unwrap(); .unwrap();
let trimmed_pre_snippet = pre_snippet.trim(); let trimmed_pre_snippet = pre_snippet.trim();
let has_pre_comment = trimmed_pre_snippet.contains("//") || let has_pre_comment = trimmed_pre_snippet.contains("//") ||
trimmed_pre_snippet.contains("/*"); trimmed_pre_snippet.contains("/*");
let pre_comment = if has_pre_comment { let pre_comment = if has_pre_comment {
Some(trimmed_pre_snippet.to_owned()) Some(trimmed_pre_snippet.to_owned())
} else { } else {
@ -383,13 +400,17 @@ impl<'a, T, I, F1, F2, F3> Iterator for ListItems<'a, I, F1, F2, F3>
(Some(i), None) if i > separator_index => separator_index + 1, (Some(i), None) if i > separator_index => separator_index + 1,
// Block-style post-comment before the separator. // Block-style post-comment before the separator.
(Some(i), None) => { (Some(i), None) => {
cmp::max(find_comment_end(&post_snippet[i..]).unwrap() + i, cmp::max(
separator_index + 1) find_comment_end(&post_snippet[i..]).unwrap() + i,
separator_index + 1,
)
} }
// Block-style post-comment. Either before or after the separator. // Block-style post-comment. Either before or after the separator.
(Some(i), Some(j)) if i < j => { (Some(i), Some(j)) if i < j => {
cmp::max(find_comment_end(&post_snippet[i..]).unwrap() + i, cmp::max(
separator_index + 1) find_comment_end(&post_snippet[i..]).unwrap() + i,
separator_index + 1,
)
} }
// Potential *single* line comment. // Potential *single* line comment.
(_, Some(j)) if j > separator_index => j + 1, (_, Some(j)) if j > separator_index => j + 1,
@ -397,9 +418,10 @@ impl<'a, T, I, F1, F2, F3> Iterator for ListItems<'a, I, F1, F2, F3>
} }
} }
None => { None => {
post_snippet post_snippet.find_uncommented(self.terminator).unwrap_or(
.find_uncommented(self.terminator) post_snippet
.unwrap_or(post_snippet.len()) .len(),
)
} }
}; };
@ -412,9 +434,10 @@ impl<'a, T, I, F1, F2, F3> Iterator for ListItems<'a, I, F1, F2, F3>
let first_newline = test_snippet.find('\n').unwrap_or(test_snippet.len()); let first_newline = test_snippet.find('\n').unwrap_or(test_snippet.len());
// From the end of the first line of comments. // From the end of the first line of comments.
let test_snippet = &test_snippet[first_newline..]; let test_snippet = &test_snippet[first_newline..];
let first = test_snippet let first = test_snippet.find(|c: char| !c.is_whitespace()).unwrap_or(
.find(|c: char| !c.is_whitespace()) test_snippet
.unwrap_or(test_snippet.len()); .len(),
);
// From the end of the first line of comments to the next non-whitespace char. // From the end of the first line of comments to the next non-whitespace char.
let test_snippet = &test_snippet[..first]; let test_snippet = &test_snippet[..first];
@ -453,19 +476,21 @@ impl<'a, T, I, F1, F2, F3> Iterator for ListItems<'a, I, F1, F2, F3>
} }
// Creates an iterator over a list's items with associated comments. // Creates an iterator over a list's items with associated comments.
pub fn itemize_list<'a, T, I, F1, F2, F3>(codemap: &'a CodeMap, pub fn itemize_list<'a, T, I, F1, F2, F3>(
inner: I, codemap: &'a CodeMap,
terminator: &'a str, inner: I,
get_lo: F1, terminator: &'a str,
get_hi: F2, get_lo: F1,
get_item_string: F3, get_hi: F2,
prev_span_end: BytePos, get_item_string: F3,
next_span_start: BytePos) prev_span_end: BytePos,
-> ListItems<'a, I, F1, F2, F3> next_span_start: BytePos,
where I: Iterator<Item = T>, ) -> ListItems<'a, I, F1, F2, F3>
F1: Fn(&T) -> BytePos, where
F2: Fn(&T) -> BytePos, I: Iterator<Item = T>,
F3: Fn(&T) -> Option<String> F1: Fn(&T) -> BytePos,
F2: Fn(&T) -> BytePos,
F3: Fn(&T) -> Option<String>,
{ {
ListItems { ListItems {
codemap: codemap, codemap: codemap,
@ -479,9 +504,10 @@ pub fn itemize_list<'a, T, I, F1, F2, F3>(codemap: &'a CodeMap,
} }
} }
fn needs_trailing_separator(separator_tactic: SeparatorTactic, fn needs_trailing_separator(
list_tactic: DefinitiveListTactic) separator_tactic: SeparatorTactic,
-> bool { list_tactic: DefinitiveListTactic,
) -> bool {
match separator_tactic { match separator_tactic {
SeparatorTactic::Always => true, SeparatorTactic::Always => true,
SeparatorTactic::Vertical => list_tactic == DefinitiveListTactic::Vertical, SeparatorTactic::Vertical => list_tactic == DefinitiveListTactic::Vertical,
@ -491,8 +517,9 @@ fn needs_trailing_separator(separator_tactic: SeparatorTactic,
/// Returns the count and total width of the list items. /// Returns the count and total width of the list items.
fn calculate_width<I, T>(items: I) -> (usize, usize) fn calculate_width<I, T>(items: I) -> (usize, usize)
where I: IntoIterator<Item = T>, where
T: AsRef<ListItem> I: IntoIterator<Item = T>,
T: AsRef<ListItem>,
{ {
items items
.into_iter() .into_iter()
@ -502,8 +529,8 @@ fn calculate_width<I, T>(items: I) -> (usize, usize)
fn total_item_width(item: &ListItem) -> usize { fn total_item_width(item: &ListItem) -> usize {
comment_len(item.pre_comment.as_ref().map(|x| &(*x)[..])) + comment_len(item.pre_comment.as_ref().map(|x| &(*x)[..])) +
comment_len(item.post_comment.as_ref().map(|x| &(*x)[..])) + comment_len(item.post_comment.as_ref().map(|x| &(*x)[..])) +
item.item.as_ref().map_or(0, |str| str.len()) item.item.as_ref().map_or(0, |str| str.len())
} }
fn comment_len(comment: Option<&str>) -> usize { fn comment_len(comment: Option<&str>) -> usize {
@ -522,33 +549,36 @@ fn comment_len(comment: Option<&str>) -> usize {
} }
// Compute horizontal and vertical shapes for a struct-lit-like thing. // Compute horizontal and vertical shapes for a struct-lit-like thing.
pub fn struct_lit_shape(shape: Shape, pub fn struct_lit_shape(
context: &RewriteContext, shape: Shape,
prefix_width: usize, context: &RewriteContext,
suffix_width: usize) prefix_width: usize,
-> Option<(Option<Shape>, Shape)> { suffix_width: usize,
let v_shape = match context.config.struct_lit_style() { ) -> Option<(Option<Shape>, Shape)> {
IndentStyle::Visual => { let v_shape =
try_opt!(try_opt!(shape.visual_indent(0).shrink_left(prefix_width)) match context.config.struct_lit_style() {
IndentStyle::Visual => {
try_opt!(try_opt!(shape.visual_indent(0).shrink_left(prefix_width))
.sub_width(suffix_width)) .sub_width(suffix_width))
}
IndentStyle::Block => {
let shape = shape.block_indent(context.config.tab_spaces());
Shape {
width: try_opt!(context.config.max_width().checked_sub(shape.indent.width())),
..shape
} }
} IndentStyle::Block => {
}; let shape = shape.block_indent(context.config.tab_spaces());
Shape {
width: try_opt!(context.config.max_width().checked_sub(shape.indent.width())),
..shape
}
}
};
let h_shape = shape.sub_width(prefix_width + suffix_width); let h_shape = shape.sub_width(prefix_width + suffix_width);
Some((h_shape, v_shape)) Some((h_shape, v_shape))
} }
// Compute the tactic for the internals of a struct-lit-like thing. // Compute the tactic for the internals of a struct-lit-like thing.
pub fn struct_lit_tactic(h_shape: Option<Shape>, pub fn struct_lit_tactic(
context: &RewriteContext, h_shape: Option<Shape>,
items: &[ListItem]) context: &RewriteContext,
-> DefinitiveListTactic { items: &[ListItem],
) -> DefinitiveListTactic {
if let Some(h_shape) = h_shape { if let Some(h_shape) = h_shape {
let mut prelim_tactic = match (context.config.struct_lit_style(), items.len()) { let mut prelim_tactic = match (context.config.struct_lit_style(), items.len()) {
(IndentStyle::Visual, 1) => ListTactic::HorizontalVertical, (IndentStyle::Visual, 1) => ListTactic::HorizontalVertical,
@ -568,10 +598,11 @@ pub fn struct_lit_tactic(h_shape: Option<Shape>,
// Given a tactic and possible shapes for horizontal and vertical layout, // Given a tactic and possible shapes for horizontal and vertical layout,
// come up with the actual shape to use. // come up with the actual shape to use.
pub fn shape_for_tactic(tactic: DefinitiveListTactic, pub fn shape_for_tactic(
h_shape: Option<Shape>, tactic: DefinitiveListTactic,
v_shape: Shape) h_shape: Option<Shape>,
-> Shape { v_shape: Shape,
) -> Shape {
match tactic { match tactic {
DefinitiveListTactic::Horizontal => h_shape.unwrap(), DefinitiveListTactic::Horizontal => h_shape.unwrap(),
_ => v_shape, _ => v_shape,
@ -580,13 +611,14 @@ pub fn shape_for_tactic(tactic: DefinitiveListTactic,
// Create a ListFormatting object for formatting the internals of a // Create a ListFormatting object for formatting the internals of a
// struct-lit-like thing, that is a series of fields. // struct-lit-like thing, that is a series of fields.
pub fn struct_lit_formatting<'a>(shape: Shape, pub fn struct_lit_formatting<'a>(
tactic: DefinitiveListTactic, shape: Shape,
context: &'a RewriteContext, tactic: DefinitiveListTactic,
force_no_trailing_comma: bool) context: &'a RewriteContext,
-> ListFormatting<'a> { force_no_trailing_comma: bool,
) -> ListFormatting<'a> {
let ends_with_newline = context.config.struct_lit_style() != IndentStyle::Visual && let ends_with_newline = context.config.struct_lit_style() != IndentStyle::Visual &&
tactic == DefinitiveListTactic::Vertical; tactic == DefinitiveListTactic::Vertical;
ListFormatting { ListFormatting {
tactic: tactic, tactic: tactic,
separator: ",", separator: ",",

View file

@ -61,12 +61,13 @@ impl MacroStyle {
} }
} }
pub fn rewrite_macro(mac: &ast::Mac, pub fn rewrite_macro(
extra_ident: Option<ast::Ident>, mac: &ast::Mac,
context: &RewriteContext, extra_ident: Option<ast::Ident>,
shape: Shape, context: &RewriteContext,
position: MacroPosition) shape: Shape,
-> Option<String> { position: MacroPosition,
) -> Option<String> {
let mut context = &mut context.clone(); let mut context = &mut context.clone();
context.inside_macro = true; context.inside_macro = true;
if context.config.use_try_shorthand() { if context.config.use_try_shorthand() {
@ -191,24 +192,29 @@ pub fn rewrite_macro(mac: &ast::Mac,
} else { } else {
("[", "]") ("[", "]")
}; };
rewrite_pair(&*expr_vec[0], rewrite_pair(
&*expr_vec[1], &*expr_vec[0],
lbr, &*expr_vec[1],
"; ", lbr,
rbr, "; ",
context, rbr,
mac_shape) context,
.map(|s| format!("{}{}", macro_name, s)) mac_shape,
).map(|s| format!("{}{}", macro_name, s))
} else { } else {
// Format macro invocation as array literal. // Format macro invocation as array literal.
let rewrite = let rewrite = try_opt!(rewrite_array(
try_opt!(rewrite_array(expr_vec.iter().map(|x| &**x), expr_vec.iter().map(|x| &**x),
mk_sp(context mk_sp(
.codemap context.codemap.span_after(
.span_after(mac.span, original_style.opener()), mac.span,
mac.span.hi - BytePos(1)), original_style.opener(),
context, ),
mac_shape)); mac.span.hi - BytePos(1),
),
context,
mac_shape,
));
Some(format!("{}{}", macro_name, rewrite)) Some(format!("{}{}", macro_name, rewrite))
} }
@ -229,11 +235,11 @@ pub fn convert_try_mac(mac: &ast::Mac, context: &RewriteContext) -> Option<ast::
let mut parser = new_parser_from_tts(context.parse_session, ts.trees().collect()); let mut parser = new_parser_from_tts(context.parse_session, ts.trees().collect());
Some(ast::Expr { Some(ast::Expr {
id: ast::NodeId::new(0), // dummy value id: ast::NodeId::new(0), // dummy value
node: ast::ExprKind::Try(try_opt!(parser.parse_expr().ok())), node: ast::ExprKind::Try(try_opt!(parser.parse_expr().ok())),
span: mac.span, // incorrect span, but shouldn't matter too much span: mac.span, // incorrect span, but shouldn't matter too much
attrs: ThinVec::new(), attrs: ThinVec::new(),
}) })
} else { } else {
None None
} }

View file

@ -47,9 +47,11 @@ impl<'a> FmtVisitor<'a> {
}) })
} }
fn format_missing_inner<F: Fn(&mut FmtVisitor, &str, &str)>(&mut self, fn format_missing_inner<F: Fn(&mut FmtVisitor, &str, &str)>(
end: BytePos, &mut self,
process_last_snippet: F) { end: BytePos,
process_last_snippet: F,
) {
let start = self.last_pos; let start = self.last_pos;
if start == end { if start == end {
@ -60,10 +62,12 @@ impl<'a> FmtVisitor<'a> {
return; return;
} }
assert!(start < end, assert!(
"Request to format inverted span: {:?} to {:?}", start < end,
self.codemap.lookup_char_pos(start), "Request to format inverted span: {:?} to {:?}",
self.codemap.lookup_char_pos(end)); self.codemap.lookup_char_pos(start),
self.codemap.lookup_char_pos(end)
);
self.last_pos = end; self.last_pos = end;
let span = mk_sp(start, end); let span = mk_sp(start, end);
@ -72,7 +76,8 @@ impl<'a> FmtVisitor<'a> {
} }
fn write_snippet<F>(&mut self, span: Span, process_last_snippet: F) fn write_snippet<F>(&mut self, span: Span, process_last_snippet: F)
where F: Fn(&mut FmtVisitor, &str, &str) where
F: Fn(&mut FmtVisitor, &str, &str),
{ {
// Get a snippet from the file start to the span's hi without allocating. // Get a snippet from the file start to the span's hi without allocating.
// We need it to determine what precedes the current comment. If the comment // We need it to determine what precedes the current comment. If the comment
@ -92,13 +97,15 @@ impl<'a> FmtVisitor<'a> {
self.write_snippet_inner(big_snippet, big_diff, &snippet, span, process_last_snippet); self.write_snippet_inner(big_snippet, big_diff, &snippet, span, process_last_snippet);
} }
fn write_snippet_inner<F>(&mut self, fn write_snippet_inner<F>(
big_snippet: &str, &mut self,
big_diff: usize, big_snippet: &str,
old_snippet: &str, big_diff: usize,
span: Span, old_snippet: &str,
process_last_snippet: F) span: Span,
where F: Fn(&mut FmtVisitor, &str, &str) process_last_snippet: F,
) where
F: Fn(&mut FmtVisitor, &str, &str),
{ {
// Trim whitespace from the right hand side of each line. // Trim whitespace from the right hand side of each line.
// Annoyingly, the library functions for splitting by lines etc. are not // Annoyingly, the library functions for splitting by lines etc. are not
@ -139,9 +146,12 @@ impl<'a> FmtVisitor<'a> {
let subslice_num_lines = subslice.chars().filter(|c| *c == '\n').count(); let subslice_num_lines = subslice.chars().filter(|c| *c == '\n').count();
if rewrite_next_comment && if rewrite_next_comment &&
!self.config !self.config.file_lines().intersects_range(
.file_lines() file_name,
.intersects_range(file_name, cur_line, cur_line + subslice_num_lines) { cur_line,
cur_line + subslice_num_lines,
)
{
rewrite_next_comment = false; rewrite_next_comment = false;
} }
@ -150,32 +160,34 @@ impl<'a> FmtVisitor<'a> {
if let Some('{') = last_char { if let Some('{') = last_char {
self.buffer.push_str("\n"); self.buffer.push_str("\n");
} }
self.buffer self.buffer.push_str(
.push_str(&self.block_indent.to_string(self.config)); &self.block_indent.to_string(self.config),
);
} else { } else {
self.buffer.push_str(" "); self.buffer.push_str(" ");
} }
let comment_width = ::std::cmp::min(self.config.comment_width(), let comment_width = ::std::cmp::min(
self.config.max_width() - self.config.comment_width(),
self.block_indent.width()); self.config.max_width() - self.block_indent.width(),
);
self.buffer.push_str(&rewrite_comment(subslice, self.buffer.push_str(&rewrite_comment(
false, subslice,
Shape::legacy(comment_width, false,
self.block_indent), Shape::legacy(comment_width, self.block_indent),
self.config) self.config,
.unwrap()); ).unwrap());
last_wspace = None; last_wspace = None;
line_start = offset + subslice.len(); line_start = offset + subslice.len();
if let Some('/') = subslice.chars().skip(1).next() { if let Some('/') = subslice.chars().skip(1).next() {
// check that there are no contained block comments // check that there are no contained block comments
if !subslice if !subslice.split('\n').map(|s| s.trim_left()).any(|s| {
.split('\n') s.len() >= 2 && &s[0..2] == "/*"
.map(|s| s.trim_left()) })
.any(|s| s.len() >= 2 && &s[0..2] == "/*") { {
// Add a newline after line comments // Add a newline after line comments
self.buffer.push_str("\n"); self.buffer.push_str("\n");
} }

View file

@ -20,30 +20,35 @@ use syntax::parse::parser;
/// List all the files containing modules of a crate. /// List all the files containing modules of a crate.
/// If a file is used twice in a crate, it appears only once. /// If a file is used twice in a crate, it appears only once.
pub fn list_files<'a>(krate: &'a ast::Crate, pub fn list_files<'a>(
codemap: &codemap::CodeMap) krate: &'a ast::Crate,
-> BTreeMap<PathBuf, &'a ast::Mod> { codemap: &codemap::CodeMap,
) -> BTreeMap<PathBuf, &'a ast::Mod> {
let mut result = BTreeMap::new(); // Enforce file order determinism let mut result = BTreeMap::new(); // Enforce file order determinism
let root_filename: PathBuf = codemap.span_to_filename(krate.span).into(); let root_filename: PathBuf = codemap.span_to_filename(krate.span).into();
list_submodules(&krate.module, list_submodules(
root_filename.parent().unwrap(), &krate.module,
codemap, root_filename.parent().unwrap(),
&mut result); codemap,
&mut result,
);
result.insert(root_filename, &krate.module); result.insert(root_filename, &krate.module);
result result
} }
/// Recursively list all external modules included in a module. /// Recursively list all external modules included in a module.
fn list_submodules<'a>(module: &'a ast::Mod, fn list_submodules<'a>(
search_dir: &Path, module: &'a ast::Mod,
codemap: &codemap::CodeMap, search_dir: &Path,
result: &mut BTreeMap<PathBuf, &'a ast::Mod>) { codemap: &codemap::CodeMap,
result: &mut BTreeMap<PathBuf, &'a ast::Mod>,
) {
debug!("list_submodules: search_dir: {:?}", search_dir); debug!("list_submodules: search_dir: {:?}", search_dir);
for item in &module.items { for item in &module.items {
if let ast::ItemKind::Mod(ref sub_mod) = item.node { if let ast::ItemKind::Mod(ref sub_mod) = item.node {
if !utils::contains_skip(&item.attrs) { if !utils::contains_skip(&item.attrs) {
let is_internal = codemap.span_to_filename(item.span) == let is_internal = codemap.span_to_filename(item.span) ==
codemap.span_to_filename(sub_mod.inner); codemap.span_to_filename(sub_mod.inner);
let dir_path = if is_internal { let dir_path = if is_internal {
search_dir.join(&item.ident.to_string()) search_dir.join(&item.ident.to_string())
} else { } else {
@ -59,11 +64,12 @@ fn list_submodules<'a>(module: &'a ast::Mod,
} }
/// Find the file corresponding to an external mod /// Find the file corresponding to an external mod
fn module_file(id: ast::Ident, fn module_file(
attrs: &[ast::Attribute], id: ast::Ident,
dir_path: &Path, attrs: &[ast::Attribute],
codemap: &codemap::CodeMap) dir_path: &Path,
-> PathBuf { codemap: &codemap::CodeMap,
) -> PathBuf {
if let Some(path) = parser::Parser::submod_path_from_attr(attrs, dir_path) { if let Some(path) = parser::Parser::submod_path_from_attr(attrs, dir_path) {
return path; return path;
} }

View file

@ -39,12 +39,13 @@ impl Rewrite for Pat {
let sub_pat = match *sub_pat { let sub_pat = match *sub_pat {
Some(ref p) => { Some(ref p) => {
// 3 - ` @ `. // 3 - ` @ `.
let width = let width = try_opt!(shape.width.checked_sub(
try_opt!(shape.width.checked_sub(prefix.len() + mut_infix.len() + prefix.len() + mut_infix.len() + id_str.len() + 3,
id_str.len() + ));
3)); format!(
format!(" @ {}", " @ {}",
try_opt!(p.rewrite(context, Shape::legacy(width, shape.indent)))) try_opt!(p.rewrite(context, Shape::legacy(width, shape.indent)))
)
} }
None => "".to_owned(), None => "".to_owned(),
}; };
@ -80,23 +81,23 @@ impl Rewrite for Pat {
rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape) rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape)
} }
PatKind::TupleStruct(ref path, ref pat_vec, dotdot_pos) => { PatKind::TupleStruct(ref path, ref pat_vec, dotdot_pos) => {
let path_str = let path_str = try_opt!(rewrite_path(context, PathContext::Expr, None, path, shape));
try_opt!(rewrite_path(context, PathContext::Expr, None, path, shape)); rewrite_tuple_pat(
rewrite_tuple_pat(pat_vec, pat_vec,
dotdot_pos, dotdot_pos,
Some(path_str), Some(path_str),
self.span, self.span,
context, context,
shape) shape,
)
} }
PatKind::Lit(ref expr) => expr.rewrite(context, shape), PatKind::Lit(ref expr) => expr.rewrite(context, shape),
PatKind::Slice(ref prefix, ref slice_pat, ref suffix) => { PatKind::Slice(ref prefix, ref slice_pat, ref suffix) => {
// Rewrite all the sub-patterns. // Rewrite all the sub-patterns.
let prefix = prefix.iter().map(|p| p.rewrite(context, shape)); let prefix = prefix.iter().map(|p| p.rewrite(context, shape));
let slice_pat = let slice_pat = slice_pat.as_ref().map(|p| {
slice_pat Some(format!("{}..", try_opt!(p.rewrite(context, shape))))
.as_ref() });
.map(|p| Some(format!("{}..", try_opt!(p.rewrite(context, shape)))));
let suffix = suffix.iter().map(|p| p.rewrite(context, shape)); let suffix = suffix.iter().map(|p| p.rewrite(context, shape));
// Munge them together. // Munge them together.
@ -119,24 +120,33 @@ impl Rewrite for Pat {
} }
// FIXME(#819) format pattern macros. // FIXME(#819) format pattern macros.
PatKind::Mac(..) => { PatKind::Mac(..) => {
wrap_str(context.snippet(self.span), wrap_str(
context.config.max_width(), context.snippet(self.span),
shape) context.config.max_width(),
shape,
)
} }
} }
} }
} }
fn rewrite_struct_pat(path: &ast::Path, fn rewrite_struct_pat(
fields: &[codemap::Spanned<ast::FieldPat>], path: &ast::Path,
elipses: bool, fields: &[codemap::Spanned<ast::FieldPat>],
span: Span, elipses: bool,
context: &RewriteContext, span: Span,
shape: Shape) context: &RewriteContext,
-> Option<String> { shape: Shape,
) -> Option<String> {
// 2 = ` {` // 2 = ` {`
let path_shape = try_opt!(shape.sub_width(2)); let path_shape = try_opt!(shape.sub_width(2));
let path_str = try_opt!(rewrite_path(context, PathContext::Expr, None, path, path_shape)); let path_str = try_opt!(rewrite_path(
context,
PathContext::Expr,
None,
path,
path_shape,
));
if fields.len() == 0 && !elipses { if fields.len() == 0 && !elipses {
return Some(format!("{} {{}}", path_str)); return Some(format!("{} {{}}", path_str));
@ -145,17 +155,23 @@ fn rewrite_struct_pat(path: &ast::Path,
let (elipses_str, terminator) = if elipses { (", ..", "..") } else { ("", "}") }; let (elipses_str, terminator) = if elipses { (", ..", "..") } else { ("", "}") };
// 3 = ` { `, 2 = ` }`. // 3 = ` { `, 2 = ` }`.
let (h_shape, v_shape) = let (h_shape, v_shape) = try_opt!(struct_lit_shape(
try_opt!(struct_lit_shape(shape, context, path_str.len() + 3, elipses_str.len() + 2)); shape,
context,
path_str.len() + 3,
elipses_str.len() + 2,
));
let items = itemize_list(context.codemap, let items = itemize_list(
fields.iter(), context.codemap,
terminator, fields.iter(),
|f| f.span.lo, terminator,
|f| f.span.hi, |f| f.span.lo,
|f| f.node.rewrite(context, v_shape), |f| f.span.hi,
context.codemap.span_after(span, "{"), |f| f.node.rewrite(context, v_shape),
span.hi); context.codemap.span_after(span, "{"),
span.hi,
);
let item_vec = items.collect::<Vec<_>>(); let item_vec = items.collect::<Vec<_>>();
let tactic = struct_lit_tactic(h_shape, context, &item_vec); let tactic = struct_lit_tactic(h_shape, context, &item_vec);
@ -189,14 +205,16 @@ fn rewrite_struct_pat(path: &ast::Path,
let fields_str = if context.config.struct_lit_style() == IndentStyle::Block && let fields_str = if context.config.struct_lit_style() == IndentStyle::Block &&
(fields_str.contains('\n') || (fields_str.contains('\n') ||
context.config.struct_lit_multiline_style() == context.config.struct_lit_multiline_style() == MultilineStyle::ForceMulti ||
MultilineStyle::ForceMulti || fields_str.len() > h_shape.map(|s| s.width).unwrap_or(0))
fields_str.len() > h_shape.map(|s| s.width).unwrap_or(0)) { {
format!("\n{}{}\n{}", format!(
v_shape.indent.to_string(context.config), "\n{}{}\n{}",
fields_str, v_shape.indent.to_string(context.config),
shape.indent.to_string(context.config)) fields_str,
shape.indent.to_string(context.config)
)
} else { } else {
// One liner or visual indent. // One liner or visual indent.
format!(" {} ", fields_str) format!(" {} ", fields_str)
@ -211,9 +229,11 @@ impl Rewrite for FieldPat {
if self.is_shorthand { if self.is_shorthand {
pat pat
} else { } else {
wrap_str(format!("{}: {}", self.ident.to_string(), try_opt!(pat)), wrap_str(
context.config.max_width(), format!("{}: {}", self.ident.to_string(), try_opt!(pat)),
shape) context.config.max_width(),
shape,
)
} }
} }
} }
@ -241,13 +261,14 @@ impl<'a> Spanned for TuplePatField<'a> {
} }
} }
fn rewrite_tuple_pat(pats: &[ptr::P<ast::Pat>], fn rewrite_tuple_pat(
dotdot_pos: Option<usize>, pats: &[ptr::P<ast::Pat>],
path_str: Option<String>, dotdot_pos: Option<usize>,
span: Span, path_str: Option<String>,
context: &RewriteContext, span: Span,
shape: Shape) context: &RewriteContext,
-> Option<String> { shape: Shape,
) -> Option<String> {
let mut pat_vec: Vec<_> = pats.into_iter().map(|x| TuplePatField::Pat(x)).collect(); let mut pat_vec: Vec<_> = pats.into_iter().map(|x| TuplePatField::Pat(x)).collect();
if let Some(pos) = dotdot_pos { if let Some(pos) = dotdot_pos {
@ -285,15 +306,16 @@ fn rewrite_tuple_pat(pats: &[ptr::P<ast::Pat>],
let nested_shape = try_opt!(shape.sub_width(path_len + if add_comma { 3 } else { 2 })); let nested_shape = try_opt!(shape.sub_width(path_len + if add_comma { 3 } else { 2 }));
// 1 = "(".len() // 1 = "(".len()
let nested_shape = nested_shape.visual_indent(path_len + 1); let nested_shape = nested_shape.visual_indent(path_len + 1);
let mut items: Vec<_> = itemize_list(context.codemap, let mut items: Vec<_> = itemize_list(
pat_vec.iter(), context.codemap,
if add_comma { ",)" } else { ")" }, pat_vec.iter(),
|item| item.span().lo, if add_comma { ",)" } else { ")" },
|item| item.span().hi, |item| item.span().lo,
|item| item.rewrite(context, nested_shape), |item| item.span().hi,
context.codemap.span_after(span, "("), |item| item.rewrite(context, nested_shape),
span.hi - BytePos(1)) context.codemap.span_after(span, "("),
.collect(); span.hi - BytePos(1),
).collect();
// Condense wildcard string suffix into a single .. // Condense wildcard string suffix into a single ..
let wildcard_suffix_len = count_wildcard_suffix_len(&items); let wildcard_suffix_len = count_wildcard_suffix_len(&items);
@ -305,24 +327,32 @@ fn rewrite_tuple_pat(pats: &[ptr::P<ast::Pat>],
let da_iter = items.into_iter().take(new_item_count); let da_iter = items.into_iter().take(new_item_count);
try_opt!(format_item_list(da_iter, nested_shape, context.config)) try_opt!(format_item_list(da_iter, nested_shape, context.config))
} else { } else {
try_opt!(format_item_list(items.into_iter(), nested_shape, context.config)) try_opt!(format_item_list(
items.into_iter(),
nested_shape,
context.config,
))
}; };
match path_str { match path_str {
Some(path_str) => { Some(path_str) => {
Some(if context.config.spaces_within_parens() { Some(
format!("{}( {} )", path_str, list) if context.config.spaces_within_parens() {
} else { format!("{}( {} )", path_str, list)
format!("{}({})", path_str, list) } else {
}) format!("{}({})", path_str, list)
},
)
} }
None => { None => {
let comma = if add_comma { "," } else { "" }; let comma = if add_comma { "," } else { "" };
Some(if context.config.spaces_within_parens() { Some(
format!("( {}{} )", list, comma) if context.config.spaces_within_parens() {
} else { format!("( {}{} )", list, comma)
format!("({}{})", list, comma) } else {
}) format!("({}{})", list, comma)
},
)
} }
} }
} }
@ -331,10 +361,10 @@ fn count_wildcard_suffix_len(items: &[ListItem]) -> usize {
let mut suffix_len = 0; let mut suffix_len = 0;
for item in items.iter().rev().take_while(|i| match i.item { for item in items.iter().rev().take_while(|i| match i.item {
Some(ref internal_string) if internal_string == Some(ref internal_string) if internal_string == "_" => true,
"_" => true, _ => false,
_ => false, })
}) { {
suffix_len += 1; suffix_len += 1;
if item.pre_comment.is_some() || item.post_comment.is_some() { if item.pre_comment.is_some() || item.post_comment.is_some() {

View file

@ -86,7 +86,8 @@ pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Misma
} }
pub fn print_diff<F>(diff: Vec<Mismatch>, get_section_title: F) pub fn print_diff<F>(diff: Vec<Mismatch>, get_section_title: F)
where F: Fn(u32) -> String where
F: Fn(u32) -> String,
{ {
match term::stdout() { match term::stdout() {
Some(ref t) if isatty() && t.supports_color() => { Some(ref t) if isatty() && t.supports_color() => {
@ -115,10 +116,12 @@ pub fn print_diff<F>(diff: Vec<Mismatch>, get_section_title: F)
} }
} }
fn print_diff_fancy<F>(diff: Vec<Mismatch>, fn print_diff_fancy<F>(
get_section_title: F, diff: Vec<Mismatch>,
mut t: Box<term::Terminal<Output = io::Stdout>>) get_section_title: F,
where F: Fn(u32) -> String mut t: Box<term::Terminal<Output = io::Stdout>>,
) where
F: Fn(u32) -> String,
{ {
for mismatch in diff { for mismatch in diff {
let title = get_section_title(mismatch.line_number); let title = get_section_title(mismatch.line_number);
@ -145,7 +148,8 @@ fn print_diff_fancy<F>(diff: Vec<Mismatch>,
} }
pub fn print_diff_basic<F>(diff: Vec<Mismatch>, get_section_title: F) pub fn print_diff_basic<F>(diff: Vec<Mismatch>, get_section_title: F)
where F: Fn(u32) -> String where
F: Fn(u32) -> String,
{ {
for mismatch in diff { for mismatch in diff {
let title = get_section_title(mismatch.line_number); let title = get_section_title(mismatch.line_number);

View file

@ -42,10 +42,12 @@ pub fn rewrite_string<'a>(orig: &str, fmt: &StringFormat<'a>) -> Option<String>
// `cur_start` is the position in `orig` of the start of the current line. // `cur_start` is the position in `orig` of the start of the current line.
let mut cur_start = 0; let mut cur_start = 0;
let mut result = String::with_capacity(stripped_str let mut result = String::with_capacity(
.len() stripped_str
.checked_next_power_of_two() .len()
.unwrap_or(usize::max_value())); .checked_next_power_of_two()
.unwrap_or(usize::max_value()),
);
result.push_str(fmt.opener); result.push_str(fmt.opener);
let ender_length = fmt.line_end.len(); let ender_length = fmt.line_end.len();
@ -81,7 +83,8 @@ pub fn rewrite_string<'a>(orig: &str, fmt: &StringFormat<'a>) -> Option<String>
if cur_end < cur_start + MIN_STRING { if cur_end < cur_start + MIN_STRING {
cur_end = cur_start + max_chars; cur_end = cur_start + max_chars;
while !(punctuation.contains(graphemes[cur_end - 1]) || while !(punctuation.contains(graphemes[cur_end - 1]) ||
graphemes[cur_end - 1].trim().is_empty()) { graphemes[cur_end - 1].trim().is_empty())
{
if cur_end >= graphemes.len() { if cur_end >= graphemes.len() {
let line = &graphemes[cur_start..].join(""); let line = &graphemes[cur_start..].join("");
result.push_str(line); result.push_str(line);

View file

@ -54,7 +54,7 @@ impl Summary {
pub fn has_no_errors(&self) -> bool { pub fn has_no_errors(&self) -> bool {
!(self.has_operational_errors || self.has_parsing_errors || self.has_formatting_errors || !(self.has_operational_errors || self.has_parsing_errors || self.has_formatting_errors ||
self.has_diff) self.has_diff)
} }
pub fn add(&mut self, other: Summary) { pub fn add(&mut self, other: Summary) {

View file

@ -34,20 +34,21 @@ pub enum PathContext {
} }
// Does not wrap on simple segments. // Does not wrap on simple segments.
pub fn rewrite_path(context: &RewriteContext, pub fn rewrite_path(
path_context: PathContext, context: &RewriteContext,
qself: Option<&ast::QSelf>, path_context: PathContext,
path: &ast::Path, qself: Option<&ast::QSelf>,
shape: Shape) path: &ast::Path,
-> Option<String> { shape: Shape,
) -> Option<String> {
let skip_count = qself.map_or(0, |x| x.position); let skip_count = qself.map_or(0, |x| x.position);
let mut result = if path.is_global() && qself.is_none() && let mut result =
path_context != PathContext::Import { if path.is_global() && qself.is_none() && path_context != PathContext::Import {
"::".to_owned() "::".to_owned()
} else { } else {
String::new() String::new()
}; };
let mut span_lo = path.span.lo; let mut span_lo = path.span.lo;
@ -70,13 +71,15 @@ pub fn rewrite_path(context: &RewriteContext,
// 3 = ">::".len() // 3 = ">::".len()
let shape = try_opt!(try_opt!(shape.shrink_left(extra_offset)).sub_width(3)); let shape = try_opt!(try_opt!(shape.shrink_left(extra_offset)).sub_width(3));
result = try_opt!(rewrite_path_segments(PathContext::Type, result = try_opt!(rewrite_path_segments(
result, PathContext::Type,
path.segments.iter().take(skip_count), result,
span_lo, path.segments.iter().take(skip_count),
path.span.hi, span_lo,
context, path.span.hi,
shape)); context,
shape,
));
} }
if context.config.spaces_within_angle_brackets() { if context.config.spaces_within_angle_brackets() {
@ -87,24 +90,28 @@ pub fn rewrite_path(context: &RewriteContext,
span_lo = qself.ty.span.hi + BytePos(1); span_lo = qself.ty.span.hi + BytePos(1);
} }
rewrite_path_segments(path_context, rewrite_path_segments(
result, path_context,
path.segments.iter().skip(skip_count), result,
span_lo, path.segments.iter().skip(skip_count),
path.span.hi, span_lo,
context, path.span.hi,
shape) context,
shape,
)
} }
fn rewrite_path_segments<'a, I>(path_context: PathContext, fn rewrite_path_segments<'a, I>(
mut buffer: String, path_context: PathContext,
iter: I, mut buffer: String,
mut span_lo: BytePos, iter: I,
span_hi: BytePos, mut span_lo: BytePos,
context: &RewriteContext, span_hi: BytePos,
shape: Shape) context: &RewriteContext,
-> Option<String> shape: Shape,
where I: Iterator<Item = &'a ast::PathSegment> ) -> Option<String>
where
I: Iterator<Item = &'a ast::PathSegment>,
{ {
let mut first = true; let mut first = true;
let shape = shape.visual_indent(0); let shape = shape.visual_indent(0);
@ -122,12 +129,14 @@ fn rewrite_path_segments<'a, I>(path_context: PathContext,
let extra_offset = extra_offset(&buffer, shape); let extra_offset = extra_offset(&buffer, shape);
let new_shape = try_opt!(shape.shrink_left(extra_offset)); let new_shape = try_opt!(shape.shrink_left(extra_offset));
let segment_string = try_opt!(rewrite_segment(path_context, let segment_string = try_opt!(rewrite_segment(
segment, path_context,
&mut span_lo, segment,
span_hi, &mut span_lo,
context, span_hi,
new_shape)); context,
new_shape,
));
buffer.push_str(&segment_string); buffer.push_str(&segment_string);
} }
@ -163,10 +172,10 @@ impl<'a> Rewrite for SegmentParam<'a> {
TypeDensity::Compressed => format!("{}=", binding.ident), TypeDensity::Compressed => format!("{}=", binding.ident),
}; };
let budget = try_opt!(shape.width.checked_sub(result.len())); let budget = try_opt!(shape.width.checked_sub(result.len()));
let rewrite = try_opt!(binding.ty.rewrite(context, let rewrite = try_opt!(binding.ty.rewrite(
Shape::legacy(budget, context,
shape.indent + Shape::legacy(budget, shape.indent + result.len()),
result.len()))); ));
result.push_str(&rewrite); result.push_str(&rewrite);
Some(result) Some(result)
} }
@ -184,21 +193,22 @@ impl<'a> Rewrite for SegmentParam<'a> {
// //
// When the segment contains a positive number of parameters, we update span_lo // When the segment contains a positive number of parameters, we update span_lo
// so that invariants described above will hold for the next segment. // so that invariants described above will hold for the next segment.
fn rewrite_segment(path_context: PathContext, fn rewrite_segment(
segment: &ast::PathSegment, path_context: PathContext,
span_lo: &mut BytePos, segment: &ast::PathSegment,
span_hi: BytePos, span_lo: &mut BytePos,
context: &RewriteContext, span_hi: BytePos,
shape: Shape) context: &RewriteContext,
-> Option<String> { shape: Shape,
) -> Option<String> {
let ident_len = segment.identifier.to_string().len(); let ident_len = segment.identifier.to_string().len();
let shape = try_opt!(shape.shrink_left(ident_len)); let shape = try_opt!(shape.shrink_left(ident_len));
let params = if let Some(ref params) = segment.parameters { let params = if let Some(ref params) = segment.parameters {
match **params { match **params {
ast::PathParameters::AngleBracketed(ref data) if !data.lifetimes.is_empty() || ast::PathParameters::AngleBracketed(ref data) if !data.lifetimes.is_empty() ||
!data.types.is_empty() || !data.types.is_empty() ||
!data.bindings.is_empty() => { !data.bindings.is_empty() => {
let param_list = data.lifetimes let param_list = data.lifetimes
.iter() .iter()
.map(SegmentParam::LifeTime) .map(SegmentParam::LifeTime)
@ -239,12 +249,14 @@ fn rewrite_segment(path_context: PathContext,
Some(ref ty) => FunctionRetTy::Ty(ty.clone()), Some(ref ty) => FunctionRetTy::Ty(ty.clone()),
None => FunctionRetTy::Default(codemap::DUMMY_SP), None => FunctionRetTy::Default(codemap::DUMMY_SP),
}; };
try_opt!(format_function_type(data.inputs.iter().map(|x| &**x), try_opt!(format_function_type(
&output, data.inputs.iter().map(|x| &**x),
false, &output,
data.span, false,
context, data.span,
shape)) context,
shape,
))
} }
_ => String::new(), _ => String::new(),
} }
@ -255,22 +267,25 @@ fn rewrite_segment(path_context: PathContext,
Some(format!("{}{}", segment.identifier, params)) Some(format!("{}{}", segment.identifier, params))
} }
fn format_function_type<'a, I>(inputs: I, fn format_function_type<'a, I>(
output: &FunctionRetTy, inputs: I,
variadic: bool, output: &FunctionRetTy,
span: Span, variadic: bool,
context: &RewriteContext, span: Span,
shape: Shape) context: &RewriteContext,
-> Option<String> shape: Shape,
where I: ExactSizeIterator, ) -> Option<String>
<I as Iterator>::Item: Deref, where
<I::Item as Deref>::Target: Rewrite + Spanned + 'a I: ExactSizeIterator,
<I as Iterator>::Item: Deref,
<I::Item as Deref>::Target: Rewrite + Spanned + 'a,
{ {
// Code for handling variadics is somewhat duplicated for items, but they // Code for handling variadics is somewhat duplicated for items, but they
// are different enough to need some serious refactoring to share code. // are different enough to need some serious refactoring to share code.
enum ArgumentKind<T> enum ArgumentKind<T>
where T: Deref, where
<T as Deref>::Target: Rewrite + Spanned T: Deref,
<T as Deref>::Target: Rewrite + Spanned,
{ {
Regular(Box<T>), Regular(Box<T>),
Variadic(BytePos), Variadic(BytePos),
@ -288,31 +303,35 @@ fn format_function_type<'a, I>(inputs: I,
// 1 for ( // 1 for (
let offset = shape.indent + 1; let offset = shape.indent + 1;
let list_lo = context.codemap.span_after(span, "("); let list_lo = context.codemap.span_after(span, "(");
let items = itemize_list(context.codemap, let items = itemize_list(
// FIXME Would be nice to avoid this allocation, context.codemap,
// but I couldn't get the types to work out. // FIXME Would be nice to avoid this allocation,
inputs // but I couldn't get the types to work out.
.map(|i| ArgumentKind::Regular(Box::new(i))) inputs
.chain(variadic_arg), .map(|i| ArgumentKind::Regular(Box::new(i)))
")", .chain(variadic_arg),
|arg| match *arg { ")",
ArgumentKind::Regular(ref ty) => ty.span().lo, |arg| match *arg {
ArgumentKind::Variadic(start) => start, ArgumentKind::Regular(ref ty) => ty.span().lo,
}, ArgumentKind::Variadic(start) => start,
|arg| match *arg { },
ArgumentKind::Regular(ref ty) => ty.span().hi, |arg| match *arg {
ArgumentKind::Variadic(start) => start + BytePos(3), ArgumentKind::Regular(ref ty) => ty.span().hi,
}, ArgumentKind::Variadic(start) => start + BytePos(3),
|arg| match *arg { },
ArgumentKind::Regular(ref ty) => { |arg| match *arg {
ty.rewrite(context, Shape::legacy(budget, offset)) ArgumentKind::Regular(ref ty) => ty.rewrite(context, Shape::legacy(budget, offset)),
} ArgumentKind::Variadic(_) => Some("...".to_owned()),
ArgumentKind::Variadic(_) => Some("...".to_owned()), },
}, list_lo,
list_lo, span.hi,
span.hi); );
let list_str = try_opt!(format_fn_args(items, Shape::legacy(budget, offset), context.config)); let list_str = try_opt!(format_fn_args(
items,
Shape::legacy(budget, offset),
context.config,
));
let output = match *output { let output = match *output {
FunctionRetTy::Ty(ref ty) => { FunctionRetTy::Ty(ref ty) => {
@ -329,16 +348,20 @@ fn format_function_type<'a, I>(inputs: I,
String::new() String::new()
}; };
Some(if context.config.spaces_within_parens() { Some(
format!("( {} ){}{}", list_str, infix, output) if context.config.spaces_within_parens() {
} else { format!("( {} ){}{}", list_str, infix, output)
format!("({}){}{}", list_str, infix, output) } else {
}) format!("({}){}{}", list_str, infix, output)
},
)
} }
fn type_bound_colon(context: &RewriteContext) -> &'static str { fn type_bound_colon(context: &RewriteContext) -> &'static str {
colon_spaces(context.config.space_before_bound(), colon_spaces(
context.config.space_after_bound_colon()) context.config.space_before_bound(),
context.config.space_after_bound_colon(),
)
} }
impl Rewrite for ast::WherePredicate { impl Rewrite for ast::WherePredicate {
@ -356,11 +379,12 @@ impl Rewrite for ast::WherePredicate {
let colon = type_bound_colon(context); let colon = type_bound_colon(context);
if !bound_lifetimes.is_empty() { if !bound_lifetimes.is_empty() {
let lifetime_str: String = try_opt!(bound_lifetimes let lifetime_str: String = try_opt!(
.iter() bound_lifetimes
.map(|lt| lt.rewrite(context, shape)) .iter()
.collect::<Option<Vec<_>>>()) .map(|lt| lt.rewrite(context, shape))
.join(", "); .collect::<Option<Vec<_>>>()
).join(", ");
// 6 = "for<> ".len() // 6 = "for<> ".len()
let used_width = lifetime_str.len() + type_str.len() + colon.len() + 6; let used_width = lifetime_str.len() + type_str.len() + colon.len() + 6;
@ -373,11 +397,13 @@ impl Rewrite for ast::WherePredicate {
let bounds_str = join_bounds(context, ty_shape, &bounds); let bounds_str = join_bounds(context, ty_shape, &bounds);
if context.config.spaces_within_angle_brackets() && lifetime_str.len() > 0 { if context.config.spaces_within_angle_brackets() && lifetime_str.len() > 0 {
format!("for< {} > {}{}{}", format!(
lifetime_str, "for< {} > {}{}{}",
type_str, lifetime_str,
colon, type_str,
bounds_str) colon,
bounds_str
)
} else { } else {
format!("for<{}> {}{}{}", lifetime_str, type_str, colon, bounds_str) format!("for<{}> {}{}{}", lifetime_str, type_str, colon, bounds_str)
} }
@ -402,7 +428,12 @@ impl Rewrite for ast::WherePredicate {
ref bounds, ref bounds,
.. ..
}) => { }) => {
try_opt!(rewrite_bounded_lifetime(lifetime, bounds.iter(), context, shape)) try_opt!(rewrite_bounded_lifetime(
lifetime,
bounds.iter(),
context,
shape,
))
} }
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
ref lhs_ty, ref lhs_ty,
@ -413,9 +444,10 @@ impl Rewrite for ast::WherePredicate {
// 3 = " = ".len() // 3 = " = ".len()
let used_width = 3 + lhs_ty_str.len(); let used_width = 3 + lhs_ty_str.len();
let budget = try_opt!(shape.width.checked_sub(used_width)); let budget = try_opt!(shape.width.checked_sub(used_width));
let rhs_ty_str = try_opt!(rhs_ty.rewrite(context, let rhs_ty_str = try_opt!(rhs_ty.rewrite(
Shape::legacy(budget, context,
shape.indent + used_width))); Shape::legacy(budget, shape.indent + used_width),
));
format!("{} = {}", lhs_ty_str, rhs_ty_str) format!("{} = {}", lhs_ty_str, rhs_ty_str)
} }
}; };
@ -430,22 +462,26 @@ impl Rewrite for ast::LifetimeDef {
} }
} }
fn rewrite_bounded_lifetime<'b, I>(lt: &ast::Lifetime, fn rewrite_bounded_lifetime<'b, I>(
bounds: I, lt: &ast::Lifetime,
context: &RewriteContext, bounds: I,
shape: Shape) context: &RewriteContext,
-> Option<String> shape: Shape,
where I: ExactSizeIterator<Item = &'b ast::Lifetime> ) -> Option<String>
where
I: ExactSizeIterator<Item = &'b ast::Lifetime>,
{ {
let result = try_opt!(lt.rewrite(context, shape)); let result = try_opt!(lt.rewrite(context, shape));
if bounds.len() == 0 { if bounds.len() == 0 {
Some(result) Some(result)
} else { } else {
let appendix: Vec<_> = try_opt!(bounds let appendix: Vec<_> = try_opt!(
.into_iter() bounds
.map(|b| b.rewrite(context, shape)) .into_iter()
.collect()); .map(|b| b.rewrite(context, shape))
.collect()
);
let colon = type_bound_colon(context); let colon = type_bound_colon(context);
let overhead = last_line_width(&result) + colon.len(); let overhead = last_line_width(&result) + colon.len();
let result = format!("{}{}{}", let result = format!("{}{}{}",
@ -464,9 +500,13 @@ impl Rewrite for ast::TyParamBound {
} }
ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::Maybe) => { ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::Maybe) => {
let budget = try_opt!(shape.width.checked_sub(1)); let budget = try_opt!(shape.width.checked_sub(1));
Some(format!("?{}", Some(format!(
try_opt!(tref.rewrite(context, "?{}",
Shape::legacy(budget, shape.indent + 1))))) try_opt!(tref.rewrite(
context,
Shape::legacy(budget, shape.indent + 1),
))
))
} }
ast::TyParamBound::RegionTyParamBound(ref l) => l.rewrite(context, shape), ast::TyParamBound::RegionTyParamBound(ref l) => l.rewrite(context, shape),
} }
@ -475,9 +515,11 @@ impl Rewrite for ast::TyParamBound {
impl Rewrite for ast::Lifetime { impl Rewrite for ast::Lifetime {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> { fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
wrap_str(pprust::lifetime_to_string(self), wrap_str(
context.config.max_width(), pprust::lifetime_to_string(self),
shape) context.config.max_width(),
shape,
)
} }
} }
@ -514,8 +556,10 @@ impl Rewrite for ast::TyParam {
}; };
result.push_str(eq_str); result.push_str(eq_str);
let budget = try_opt!(shape.width.checked_sub(result.len())); let budget = try_opt!(shape.width.checked_sub(result.len()));
let rewrite = try_opt!(def.rewrite(context, let rewrite = try_opt!(def.rewrite(
Shape::legacy(budget, shape.indent + result.len()))); context,
Shape::legacy(budget, shape.indent + result.len()),
));
result.push_str(&rewrite); result.push_str(&rewrite);
} }
@ -526,25 +570,31 @@ impl Rewrite for ast::TyParam {
impl Rewrite for ast::PolyTraitRef { impl Rewrite for ast::PolyTraitRef {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> { fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
if !self.bound_lifetimes.is_empty() { if !self.bound_lifetimes.is_empty() {
let lifetime_str: String = try_opt!(self.bound_lifetimes let lifetime_str: String = try_opt!(
.iter() self.bound_lifetimes
.map(|lt| lt.rewrite(context, shape)) .iter()
.collect::<Option<Vec<_>>>()) .map(|lt| lt.rewrite(context, shape))
.join(", "); .collect::<Option<Vec<_>>>()
).join(", ");
// 6 is "for<> ".len() // 6 is "for<> ".len()
let extra_offset = lifetime_str.len() + 6; let extra_offset = lifetime_str.len() + 6;
let max_path_width = try_opt!(shape.width.checked_sub(extra_offset)); let max_path_width = try_opt!(shape.width.checked_sub(extra_offset));
let path_str = try_opt!(self.trait_ref.rewrite(context, let path_str = try_opt!(self.trait_ref.rewrite(
Shape::legacy(max_path_width, context,
shape.indent + Shape::legacy(
extra_offset))); max_path_width,
shape.indent + extra_offset,
),
));
Some(if context.config.spaces_within_angle_brackets() && lifetime_str.len() > 0 { Some(
format!("for< {} > {}", lifetime_str, path_str) if context.config.spaces_within_angle_brackets() && lifetime_str.len() > 0 {
} else { format!("for< {} > {}", lifetime_str, path_str)
format!("for<{}> {}", lifetime_str, path_str) } else {
}) format!("for<{}> {}", lifetime_str, path_str)
},
)
} else { } else {
self.trait_ref.rewrite(context, shape) self.trait_ref.rewrite(context, shape)
} }
@ -573,33 +623,39 @@ impl Rewrite for ast::Ty {
let mut_str = format_mutability(mt.mutbl); let mut_str = format_mutability(mt.mutbl);
let mut_len = mut_str.len(); let mut_len = mut_str.len();
Some(match *lifetime { Some(match *lifetime {
Some(ref lifetime) => { Some(ref lifetime) => {
let lt_budget = try_opt!(shape.width.checked_sub(2 + mut_len)); let lt_budget = try_opt!(shape.width.checked_sub(2 + mut_len));
let lt_str = try_opt!(lifetime.rewrite(context, let lt_str = try_opt!(lifetime.rewrite(
Shape::legacy(lt_budget, context,
shape.indent + 2 + Shape::legacy(lt_budget, shape.indent + 2 + mut_len),
mut_len))); ));
let lt_len = lt_str.len(); let lt_len = lt_str.len();
let budget = try_opt!(shape.width.checked_sub(2 + mut_len + lt_len)); let budget = try_opt!(shape.width.checked_sub(2 + mut_len + lt_len));
format!("&{} {}{}", format!(
lt_str, "&{} {}{}",
mut_str, lt_str,
try_opt!(mt.ty.rewrite(context, mut_str,
Shape::legacy(budget, try_opt!(mt.ty.rewrite(
shape.indent + 2 + context,
mut_len + Shape::legacy(
lt_len)))) budget,
} shape.indent + 2 + mut_len + lt_len,
None => { ),
let budget = try_opt!(shape.width.checked_sub(1 + mut_len)); ))
format!("&{}{}", )
mut_str, }
try_opt!(mt.ty.rewrite(context, None => {
Shape::legacy(budget, let budget = try_opt!(shape.width.checked_sub(1 + mut_len));
shape.indent + 1 + format!(
mut_len)))) "&{}{}",
} mut_str,
}) try_opt!(mt.ty.rewrite(
context,
Shape::legacy(budget, shape.indent + 1 + mut_len),
))
)
}
})
} }
// FIXME: we drop any comments here, even though it's a silly place to put // FIXME: we drop any comments here, even though it's a silly place to put
// comments. // comments.
@ -607,10 +663,10 @@ impl Rewrite for ast::Ty {
let budget = try_opt!(shape.width.checked_sub(2)); let budget = try_opt!(shape.width.checked_sub(2));
ty.rewrite(context, Shape::legacy(budget, shape.indent + 1)) ty.rewrite(context, Shape::legacy(budget, shape.indent + 1))
.map(|ty_str| if context.config.spaces_within_parens() { .map(|ty_str| if context.config.spaces_within_parens() {
format!("( {} )", ty_str) format!("( {} )", ty_str)
} else { } else {
format!("({})", ty_str) format!("({})", ty_str)
}) })
} }
ast::TyKind::Slice(ref ty) => { ast::TyKind::Slice(ref ty) => {
let budget = if context.config.spaces_within_square_brackets() { let budget = if context.config.spaces_within_square_brackets() {
@ -620,10 +676,10 @@ impl Rewrite for ast::Ty {
}; };
ty.rewrite(context, Shape::legacy(budget, shape.indent + 1)) ty.rewrite(context, Shape::legacy(budget, shape.indent + 1))
.map(|ty_str| if context.config.spaces_within_square_brackets() { .map(|ty_str| if context.config.spaces_within_square_brackets() {
format!("[ {} ]", ty_str) format!("[ {} ]", ty_str)
} else { } else {
format!("[{}]", ty_str) format!("[{}]", ty_str)
}) })
} }
ast::TyKind::Tup(ref items) => { ast::TyKind::Tup(ref items) => {
rewrite_tuple_type(context, items.iter().map(|x| &**x), self.span, shape) rewrite_tuple_type(context, items.iter().map(|x| &**x), self.span, shape)
@ -649,8 +705,9 @@ impl Rewrite for ast::Ty {
ast::TyKind::Mac(..) => None, ast::TyKind::Mac(..) => None,
ast::TyKind::ImplicitSelf => Some(String::from("")), ast::TyKind::ImplicitSelf => Some(String::from("")),
ast::TyKind::ImplTrait(ref it) => { ast::TyKind::ImplTrait(ref it) => {
it.rewrite(context, shape) it.rewrite(context, shape).map(|it_str| {
.map(|it_str| format!("impl {}", it_str)) format!("impl {}", it_str)
})
} }
ast::TyKind::Err | ast::TyKind::Err |
ast::TyKind::Typeof(..) => unreachable!(), ast::TyKind::Typeof(..) => unreachable!(),
@ -658,11 +715,12 @@ impl Rewrite for ast::Ty {
} }
} }
fn rewrite_bare_fn(bare_fn: &ast::BareFnTy, fn rewrite_bare_fn(
span: Span, bare_fn: &ast::BareFnTy,
context: &RewriteContext, span: Span,
shape: Shape) context: &RewriteContext,
-> Option<String> { shape: Shape,
) -> Option<String> {
let mut result = String::with_capacity(128); let mut result = String::with_capacity(128);
if !bare_fn.lifetimes.is_empty() { if !bare_fn.lifetimes.is_empty() {
@ -675,8 +733,10 @@ fn rewrite_bare_fn(bare_fn: &ast::BareFnTy,
.lifetimes .lifetimes
.iter() .iter()
.map(|l| { .map(|l| {
l.rewrite(context, l.rewrite(
Shape::legacy(try_opt!(shape.width.checked_sub(6)), shape.indent + 4)) context,
Shape::legacy(try_opt!(shape.width.checked_sub(6)), shape.indent + 4),
)
}) })
.collect::<Option<Vec<_>>>() .collect::<Option<Vec<_>>>()
).join(", ")); ).join(", "));
@ -686,7 +746,10 @@ fn rewrite_bare_fn(bare_fn: &ast::BareFnTy,
result.push_str(::utils::format_unsafety(bare_fn.unsafety)); result.push_str(::utils::format_unsafety(bare_fn.unsafety));
if bare_fn.abi != abi::Abi::Rust { if bare_fn.abi != abi::Abi::Rust {
result.push_str(&::utils::format_abi(bare_fn.abi, context.config.force_explicit_abi())); result.push_str(&::utils::format_abi(
bare_fn.abi,
context.config.force_explicit_abi(),
));
} }
result.push_str("fn"); result.push_str("fn");
@ -694,12 +757,14 @@ fn rewrite_bare_fn(bare_fn: &ast::BareFnTy,
let budget = try_opt!(shape.width.checked_sub(result.len())); let budget = try_opt!(shape.width.checked_sub(result.len()));
let indent = shape.indent + result.len(); let indent = shape.indent + result.len();
let rewrite = try_opt!(format_function_type(bare_fn.decl.inputs.iter(), let rewrite = try_opt!(format_function_type(
&bare_fn.decl.output, bare_fn.decl.inputs.iter(),
bare_fn.decl.variadic, &bare_fn.decl.output,
span, bare_fn.decl.variadic,
context, span,
Shape::legacy(budget, indent))); context,
Shape::legacy(budget, indent),
));
result.push_str(&rewrite); result.push_str(&rewrite);

View file

@ -44,9 +44,9 @@ pub fn format_visibility(vis: &Visibility) -> Cow<'static, str> {
let Path { ref segments, .. } = **path; let Path { ref segments, .. } = **path;
let mut segments_iter = segments.iter().map(|seg| seg.identifier.name.to_string()); let mut segments_iter = segments.iter().map(|seg| seg.identifier.name.to_string());
if path.is_global() { if path.is_global() {
segments_iter segments_iter.next().expect(
.next() "Non-global path in pub(restricted)?",
.expect("Non-global path in pub(restricted)?"); );
} }
let is_keyword = |s: &str| s == "self" || s == "super"; let is_keyword = |s: &str| s == "self" || s == "super";
let path = segments_iter.collect::<Vec<_>>().join("::"); let path = segments_iter.collect::<Vec<_>>().join("::");
@ -128,9 +128,9 @@ fn is_skip_nested(meta_item: &NestedMetaItem) -> bool {
#[inline] #[inline]
pub fn contains_skip(attrs: &[Attribute]) -> bool { pub fn contains_skip(attrs: &[Attribute]) -> bool {
attrs attrs.iter().any(
.iter() |a| a.meta().map_or(false, |a| is_skip(&a)),
.any(|a| a.meta().map_or(false, |a| is_skip(&a))) )
} }
// Find the end of a TyParam // Find the end of a TyParam
@ -333,7 +333,8 @@ pub fn wrap_str<S: AsRef<str>>(s: S, max_width: usize, shape: Shape) -> Option<S
// A special check for the last line, since the caller may // A special check for the last line, since the caller may
// place trailing characters on this line. // place trailing characters on this line.
if snippet.lines().rev().next().unwrap().len() > if snippet.lines().rev().next().unwrap().len() >
shape.indent.width() + shape.width { shape.indent.width() + shape.width
{
return None; return None;
} }
} }
@ -355,7 +356,8 @@ impl Rewrite for String {
// whether the `guess' was too high (Ordering::Less), or too low. // whether the `guess' was too high (Ordering::Less), or too low.
// This function is guaranteed to try to the hi value first. // This function is guaranteed to try to the hi value first.
pub fn binary_search<C, T>(mut lo: usize, mut hi: usize, callback: C) -> Option<T> pub fn binary_search<C, T>(mut lo: usize, mut hi: usize, callback: C) -> Option<T>
where C: Fn(usize) -> Result<T, Ordering> where
C: Fn(usize) -> Result<T, Ordering>,
{ {
let mut middle = hi; let mut middle = hi;

View file

@ -36,16 +36,16 @@ fn is_use_item(item: &ast::Item) -> bool {
} }
fn item_bound(item: &ast::Item) -> Span { fn item_bound(item: &ast::Item) -> Span {
item.attrs item.attrs.iter().map(|attr| attr.span).fold(
.iter() item.span,
.map(|attr| attr.span) |bound, span| {
.fold(item.span, |bound, span| {
Span { Span {
lo: cmp::min(bound.lo, span.lo), lo: cmp::min(bound.lo, span.lo),
hi: cmp::max(bound.hi, span.hi), hi: cmp::max(bound.hi, span.hi),
ctxt: span.ctxt, ctxt: span.ctxt,
} }
}) },
)
} }
pub struct FmtVisitor<'a> { pub struct FmtVisitor<'a> {
@ -62,14 +62,19 @@ pub struct FmtVisitor<'a> {
impl<'a> FmtVisitor<'a> { impl<'a> FmtVisitor<'a> {
fn visit_stmt(&mut self, stmt: &ast::Stmt) { fn visit_stmt(&mut self, stmt: &ast::Stmt) {
debug!("visit_stmt: {:?} {:?}", debug!(
self.codemap.lookup_char_pos(stmt.span.lo), "visit_stmt: {:?} {:?}",
self.codemap.lookup_char_pos(stmt.span.hi)); self.codemap.lookup_char_pos(stmt.span.lo),
self.codemap.lookup_char_pos(stmt.span.hi)
);
// FIXME(#434): Move this check to somewhere more central, eg Rewrite. // FIXME(#434): Move this check to somewhere more central, eg Rewrite.
if !self.config if !self.config.file_lines().intersects(
.file_lines() &self.codemap.lookup_line_range(
.intersects(&self.codemap.lookup_line_range(stmt.span)) { stmt.span,
),
)
{
return; return;
} }
@ -80,9 +85,10 @@ impl<'a> FmtVisitor<'a> {
ast::StmtKind::Local(..) | ast::StmtKind::Local(..) |
ast::StmtKind::Expr(..) | ast::StmtKind::Expr(..) |
ast::StmtKind::Semi(..) => { ast::StmtKind::Semi(..) => {
let rewrite = let rewrite = stmt.rewrite(
stmt.rewrite(&self.get_context(), &self.get_context(),
Shape::indented(self.block_indent, self.config)); Shape::indented(self.block_indent, self.config),
);
self.push_rewrite(stmt.span, rewrite); self.push_rewrite(stmt.span, rewrite);
} }
ast::StmtKind::Mac(ref mac) => { ast::StmtKind::Mac(ref mac) => {
@ -94,9 +100,11 @@ impl<'a> FmtVisitor<'a> {
} }
pub fn visit_block(&mut self, b: &ast::Block) { pub fn visit_block(&mut self, b: &ast::Block) {
debug!("visit_block: {:?} {:?}", debug!(
self.codemap.lookup_char_pos(b.span.lo), "visit_block: {:?} {:?}",
self.codemap.lookup_char_pos(b.span.hi)); self.codemap.lookup_char_pos(b.span.lo),
self.codemap.lookup_char_pos(b.span.hi)
);
// Check if this block has braces. // Check if this block has braces.
let snippet = self.snippet(b.span); let snippet = self.snippet(b.span);
@ -157,42 +165,48 @@ impl<'a> FmtVisitor<'a> {
// Note that this only gets called for function definitions. Required methods // Note that this only gets called for function definitions. Required methods
// on traits do not get handled here. // on traits do not get handled here.
fn visit_fn(&mut self, fn visit_fn(
fk: visit::FnKind, &mut self,
fd: &ast::FnDecl, fk: visit::FnKind,
s: Span, fd: &ast::FnDecl,
_: ast::NodeId, s: Span,
defaultness: ast::Defaultness) { _: ast::NodeId,
defaultness: ast::Defaultness,
) {
let indent = self.block_indent; let indent = self.block_indent;
let block; let block;
let rewrite = match fk { let rewrite = match fk {
visit::FnKind::ItemFn(ident, generics, unsafety, constness, abi, vis, b) => { visit::FnKind::ItemFn(ident, generics, unsafety, constness, abi, vis, b) => {
block = b; block = b;
self.rewrite_fn(indent, self.rewrite_fn(
ident, indent,
fd, ident,
generics, fd,
unsafety, generics,
constness.node, unsafety,
defaultness, constness.node,
abi, defaultness,
vis, abi,
mk_sp(s.lo, b.span.lo), vis,
&b) mk_sp(s.lo, b.span.lo),
&b,
)
} }
visit::FnKind::Method(ident, sig, vis, b) => { visit::FnKind::Method(ident, sig, vis, b) => {
block = b; block = b;
self.rewrite_fn(indent, self.rewrite_fn(
ident, indent,
fd, ident,
&sig.generics, fd,
sig.unsafety, &sig.generics,
sig.constness.node, sig.unsafety,
defaultness, sig.constness.node,
sig.abi, defaultness,
vis.unwrap_or(&ast::Visibility::Inherited), sig.abi,
mk_sp(s.lo, b.span.lo), vis.unwrap_or(&ast::Visibility::Inherited),
&b) mk_sp(s.lo, b.span.lo),
&b,
)
} }
visit::FnKind::Closure(_) => unreachable!(), visit::FnKind::Closure(_) => unreachable!(),
}; };
@ -267,23 +281,28 @@ impl<'a> FmtVisitor<'a> {
ast::ItemKind::Impl(..) => { ast::ItemKind::Impl(..) => {
self.format_missing_with_indent(source!(self, item.span).lo); self.format_missing_with_indent(source!(self, item.span).lo);
let snippet = self.get_context().snippet(item.span); let snippet = self.get_context().snippet(item.span);
let where_span_end = let where_span_end = snippet.find_uncommented("{").map(|x| {
snippet (BytePos(x as u32)) + source!(self, item.span).lo
.find_uncommented("{") });
.map(|x| (BytePos(x as u32)) + source!(self, item.span).lo); if let Some(impl_str) = format_impl(
if let Some(impl_str) = format_impl(&self.get_context(), &self.get_context(),
item, item,
self.block_indent, self.block_indent,
where_span_end) { where_span_end,
)
{
self.buffer.push_str(&impl_str); self.buffer.push_str(&impl_str);
self.last_pos = source!(self, item.span).hi; self.last_pos = source!(self, item.span).hi;
} }
} }
ast::ItemKind::Trait(..) => { ast::ItemKind::Trait(..) => {
self.format_missing_with_indent(item.span.lo); self.format_missing_with_indent(item.span.lo);
if let Some(trait_str) = format_trait(&self.get_context(), if let Some(trait_str) = format_trait(
item, &self.get_context(),
self.block_indent) { item,
self.block_indent,
)
{
self.buffer.push_str(&trait_str); self.buffer.push_str(&trait_str);
self.last_pos = source!(self, item.span).hi; self.last_pos = source!(self, item.span).hi;
} }
@ -298,19 +317,20 @@ impl<'a> FmtVisitor<'a> {
let rewrite = { let rewrite = {
let indent = self.block_indent; let indent = self.block_indent;
let context = self.get_context(); let context = self.get_context();
::items::format_struct(&context, ::items::format_struct(
"struct ", &context,
item.ident, "struct ",
&item.vis, item.ident,
def, &item.vis,
Some(generics), def,
item.span, Some(generics),
indent, item.span,
None) indent,
.map(|s| match *def { None,
ast::VariantData::Tuple(..) => s + ";", ).map(|s| match *def {
_ => s, ast::VariantData::Tuple(..) => s + ";",
}) _ => s,
})
}; };
self.push_rewrite(item.span, rewrite); self.push_rewrite(item.span, rewrite);
} }
@ -331,53 +351,63 @@ impl<'a> FmtVisitor<'a> {
self.format_foreign_mod(foreign_mod, item.span); self.format_foreign_mod(foreign_mod, item.span);
} }
ast::ItemKind::Static(ref ty, mutability, ref expr) => { ast::ItemKind::Static(ref ty, mutability, ref expr) => {
let rewrite = rewrite_static("static", let rewrite = rewrite_static(
&item.vis, "static",
item.ident, &item.vis,
ty, item.ident,
mutability, ty,
Some(expr), mutability,
self.block_indent, Some(expr),
item.span, self.block_indent,
&self.get_context()); item.span,
&self.get_context(),
);
self.push_rewrite(item.span, rewrite); self.push_rewrite(item.span, rewrite);
} }
ast::ItemKind::Const(ref ty, ref expr) => { ast::ItemKind::Const(ref ty, ref expr) => {
let rewrite = rewrite_static("const", let rewrite = rewrite_static(
&item.vis, "const",
item.ident, &item.vis,
ty, item.ident,
ast::Mutability::Immutable, ty,
Some(expr), ast::Mutability::Immutable,
self.block_indent, Some(expr),
item.span, self.block_indent,
&self.get_context()); item.span,
&self.get_context(),
);
self.push_rewrite(item.span, rewrite); self.push_rewrite(item.span, rewrite);
} }
ast::ItemKind::DefaultImpl(..) => { ast::ItemKind::DefaultImpl(..) => {
// FIXME(#78): format impl definitions. // FIXME(#78): format impl definitions.
} }
ast::ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { ast::ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
self.visit_fn(visit::FnKind::ItemFn(item.ident, self.visit_fn(
generics, visit::FnKind::ItemFn(
unsafety, item.ident,
constness, generics,
abi, unsafety,
&item.vis, constness,
body), abi,
decl, &item.vis,
item.span, body,
item.id, ),
ast::Defaultness::Final) decl,
item.span,
item.id,
ast::Defaultness::Final,
)
} }
ast::ItemKind::Ty(ref ty, ref generics) => { ast::ItemKind::Ty(ref ty, ref generics) => {
let rewrite = rewrite_type_alias(&self.get_context(), let rewrite = rewrite_type_alias(
self.block_indent, &self.get_context(),
item.ident, self.block_indent,
ty, item.ident,
generics, ty,
&item.vis, generics,
item.span); &item.vis,
item.span,
);
self.push_rewrite(item.span, rewrite); self.push_rewrite(item.span, rewrite);
} }
ast::ItemKind::Union(..) => { ast::ItemKind::Union(..) => {
@ -403,15 +433,17 @@ impl<'a> FmtVisitor<'a> {
match ti.node { match ti.node {
ast::TraitItemKind::Const(ref ty, ref expr_opt) => { ast::TraitItemKind::Const(ref ty, ref expr_opt) => {
let rewrite = rewrite_static("const", let rewrite = rewrite_static(
&ast::Visibility::Inherited, "const",
ti.ident, &ast::Visibility::Inherited,
ty, ti.ident,
ast::Mutability::Immutable, ty,
expr_opt.as_ref(), ast::Mutability::Immutable,
self.block_indent, expr_opt.as_ref(),
ti.span, self.block_indent,
&self.get_context()); ti.span,
&self.get_context(),
);
self.push_rewrite(ti.span, rewrite); self.push_rewrite(ti.span, rewrite);
} }
ast::TraitItemKind::Method(ref sig, None) => { ast::TraitItemKind::Method(ref sig, None) => {
@ -420,18 +452,22 @@ impl<'a> FmtVisitor<'a> {
self.push_rewrite(ti.span, rewrite); self.push_rewrite(ti.span, rewrite);
} }
ast::TraitItemKind::Method(ref sig, Some(ref body)) => { ast::TraitItemKind::Method(ref sig, Some(ref body)) => {
self.visit_fn(visit::FnKind::Method(ti.ident, sig, None, body), self.visit_fn(
&sig.decl, visit::FnKind::Method(ti.ident, sig, None, body),
ti.span, &sig.decl,
ti.id, ti.span,
ast::Defaultness::Final); ti.id,
ast::Defaultness::Final,
);
} }
ast::TraitItemKind::Type(ref type_param_bounds, ref type_default) => { ast::TraitItemKind::Type(ref type_param_bounds, ref type_default) => {
let rewrite = rewrite_associated_type(ti.ident, let rewrite = rewrite_associated_type(
type_default.as_ref(), ti.ident,
Some(type_param_bounds), type_default.as_ref(),
&self.get_context(), Some(type_param_bounds),
self.block_indent); &self.get_context(),
self.block_indent,
);
self.push_rewrite(ti.span, rewrite); self.push_rewrite(ti.span, rewrite);
} }
ast::TraitItemKind::Macro(ref mac) => { ast::TraitItemKind::Macro(ref mac) => {
@ -448,31 +484,37 @@ impl<'a> FmtVisitor<'a> {
match ii.node { match ii.node {
ast::ImplItemKind::Method(ref sig, ref body) => { ast::ImplItemKind::Method(ref sig, ref body) => {
self.visit_fn(visit::FnKind::Method(ii.ident, sig, Some(&ii.vis), body), self.visit_fn(
&sig.decl, visit::FnKind::Method(ii.ident, sig, Some(&ii.vis), body),
ii.span, &sig.decl,
ii.id, ii.span,
ii.defaultness); ii.id,
ii.defaultness,
);
} }
ast::ImplItemKind::Const(ref ty, ref expr) => { ast::ImplItemKind::Const(ref ty, ref expr) => {
let rewrite = rewrite_static("const", let rewrite = rewrite_static(
&ii.vis, "const",
ii.ident, &ii.vis,
ty, ii.ident,
ast::Mutability::Immutable, ty,
Some(expr), ast::Mutability::Immutable,
self.block_indent, Some(expr),
ii.span, self.block_indent,
&self.get_context()); ii.span,
&self.get_context(),
);
self.push_rewrite(ii.span, rewrite); self.push_rewrite(ii.span, rewrite);
} }
ast::ImplItemKind::Type(ref ty) => { ast::ImplItemKind::Type(ref ty) => {
let rewrite = rewrite_associated_impl_type(ii.ident, let rewrite = rewrite_associated_impl_type(
ii.defaultness, ii.ident,
Some(ty), ii.defaultness,
None, Some(ty),
&self.get_context(), None,
self.block_indent); &self.get_context(),
self.block_indent,
);
self.push_rewrite(ii.span, rewrite); self.push_rewrite(ii.span, rewrite);
} }
ast::ImplItemKind::Macro(ref mac) => { ast::ImplItemKind::Macro(ref mac) => {
@ -493,9 +535,10 @@ impl<'a> FmtVisitor<'a> {
fn push_rewrite(&mut self, span: Span, rewrite: Option<String>) { fn push_rewrite(&mut self, span: Span, rewrite: Option<String>) {
self.format_missing_with_indent(source!(self, span).lo); self.format_missing_with_indent(source!(self, span).lo);
self.failed = match rewrite { self.failed = match rewrite {
Some(ref s) if s.rewrite(&self.get_context(), Some(ref s) if s.rewrite(
Shape::indented(self.block_indent, self.config)) &self.get_context(),
.is_none() => true, Shape::indented(self.block_indent, self.config),
).is_none() => true,
None => true, None => true,
_ => self.failed, _ => self.failed,
}; };
@ -521,9 +564,11 @@ impl<'a> FmtVisitor<'a> {
match self.codemap.span_to_snippet(span) { match self.codemap.span_to_snippet(span) {
Ok(s) => s, Ok(s) => s,
Err(_) => { Err(_) => {
println!("Couldn't make snippet for span {:?}->{:?}", println!(
self.codemap.lookup_char_pos(span.lo), "Couldn't make snippet for span {:?}->{:?}",
self.codemap.lookup_char_pos(span.hi)); self.codemap.lookup_char_pos(span.lo),
self.codemap.lookup_char_pos(span.hi)
);
"".to_owned() "".to_owned()
} }
} }
@ -548,8 +593,10 @@ impl<'a> FmtVisitor<'a> {
self.format_missing_with_indent(source!(self, first.span).lo); self.format_missing_with_indent(source!(self, first.span).lo);
let rewrite = outers let rewrite = outers
.rewrite(&self.get_context(), .rewrite(
Shape::indented(self.block_indent, self.config)) &self.get_context(),
Shape::indented(self.block_indent, self.config),
)
.unwrap(); .unwrap();
self.buffer.push_str(&rewrite); self.buffer.push_str(&rewrite);
let last = outers.last().unwrap(); let last = outers.last().unwrap();
@ -570,13 +617,13 @@ impl<'a> FmtVisitor<'a> {
.iter() .iter()
.take_while(|ppi| { .take_while(|ppi| {
is_use_item(&***ppi) && is_use_item(&***ppi) &&
(!reorder_imports_in_group || (!reorder_imports_in_group ||
{ {
let current = self.codemap.lookup_line_range(item_bound(&ppi)); let current = self.codemap.lookup_line_range(item_bound(&ppi));
let in_same_group = current.lo < last.hi + 2; let in_same_group = current.lo < last.hi + 2;
last = current; last = current;
in_same_group in_same_group
}) })
}) })
.count(); .count();
let (use_items, rest) = items_left.split_at(use_item_length); let (use_items, rest) = items_left.split_at(use_item_length);
@ -597,7 +644,7 @@ impl<'a> FmtVisitor<'a> {
let local_file_name = self.codemap.span_to_filename(s); let local_file_name = self.codemap.span_to_filename(s);
let inner_span = source!(self, m.inner); let inner_span = source!(self, m.inner);
let is_internal = !(inner_span.lo.0 == 0 && inner_span.hi.0 == 0) && let is_internal = !(inner_span.lo.0 == 0 && inner_span.hi.0 == 0) &&
local_file_name == self.codemap.span_to_filename(inner_span); local_file_name == self.codemap.span_to_filename(inner_span);
self.buffer.push_str(&*utils::format_visibility(vis)); self.buffer.push_str(&*utils::format_visibility(vis));
self.buffer.push_str("mod "); self.buffer.push_str("mod ");
@ -658,66 +705,65 @@ impl Rewrite for ast::NestedMetaItem {
impl Rewrite for ast::MetaItem { impl Rewrite for ast::MetaItem {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> { fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
Some(match self.node { Some(match self.node {
ast::MetaItemKind::Word => String::from(&*self.name.as_str()), ast::MetaItemKind::Word => String::from(&*self.name.as_str()),
ast::MetaItemKind::List(ref list) => { ast::MetaItemKind::List(ref list) => {
let name = self.name.as_str(); let name = self.name.as_str();
// 3 = `#[` and `(`, 2 = `]` and `)` // 3 = `#[` and `(`, 2 = `]` and `)`
let item_shape = try_opt!(shape let item_shape = try_opt!(shape.shrink_left(name.len() + 3).and_then(
.shrink_left(name.len() + 3) |s| s.sub_width(2),
.and_then(|s| s.sub_width(2))); ));
let items = itemize_list(context.codemap, let items = itemize_list(
list.iter(), context.codemap,
")", list.iter(),
|nested_meta_item| nested_meta_item.span.lo, ")",
|nested_meta_item| nested_meta_item.span.hi, |nested_meta_item| nested_meta_item.span.lo,
|nested_meta_item| { |nested_meta_item| nested_meta_item.span.hi,
nested_meta_item.rewrite(context, item_shape) |nested_meta_item| nested_meta_item.rewrite(context, item_shape),
}, self.span.lo,
self.span.lo, self.span.hi,
self.span.hi); );
let item_vec = items.collect::<Vec<_>>(); let item_vec = items.collect::<Vec<_>>();
let fmt = ListFormatting { let fmt = ListFormatting {
tactic: DefinitiveListTactic::Mixed, tactic: DefinitiveListTactic::Mixed,
separator: ",", separator: ",",
trailing_separator: SeparatorTactic::Never, trailing_separator: SeparatorTactic::Never,
shape: item_shape, shape: item_shape,
ends_with_newline: false, ends_with_newline: false,
config: context.config, config: context.config,
}; };
format!("{}({})", name, try_opt!(write_list(&item_vec, &fmt))) format!("{}({})", name, try_opt!(write_list(&item_vec, &fmt)))
} }
ast::MetaItemKind::NameValue(ref literal) => { ast::MetaItemKind::NameValue(ref literal) => {
let name = self.name.as_str(); let name = self.name.as_str();
let value = context.snippet(literal.span); let value = context.snippet(literal.span);
if &*name == "doc" && value.starts_with("///") { if &*name == "doc" && value.starts_with("///") {
let doc_shape = Shape { let doc_shape = Shape {
width: cmp::min(shape.width, context.config.comment_width()) width: cmp::min(shape.width, context.config.comment_width())
.checked_sub(shape.indent.width()) .checked_sub(shape.indent.width())
.unwrap_or(0), .unwrap_or(0),
..shape ..shape
}; };
format!("{}", format!(
try_opt!(rewrite_comment(&value, "{}",
false, try_opt!(rewrite_comment(&value, false, doc_shape, context.config))
doc_shape, )
context.config))) } else {
} else { format!("{} = {}", name, value)
format!("{} = {}", name, value) }
} }
} })
})
} }
} }
impl Rewrite for ast::Attribute { impl Rewrite for ast::Attribute {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> { fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
try_opt!(self.meta()) try_opt!(self.meta()).rewrite(context, shape).map(|rw| {
.rewrite(context, shape) if rw.starts_with("///") {
.map(|rw| if rw.starts_with("///") { rw
rw } else {
} else { format!("#[{}]", rw)
format!("#[{}]", rw) }
}) })
} }
} }
@ -741,13 +787,15 @@ impl<'a> Rewrite for [ast::Attribute] {
let multi_line = a_str.starts_with("//") && comment.matches('\n').count() > 1; let multi_line = a_str.starts_with("//") && comment.matches('\n').count() > 1;
let comment = comment.trim(); let comment = comment.trim();
if !comment.is_empty() { if !comment.is_empty() {
let comment = let comment = try_opt!(rewrite_comment(
try_opt!(rewrite_comment(comment, comment,
false, false,
Shape::legacy(context.config.comment_width() - Shape::legacy(
shape.indent.width(), context.config.comment_width() - shape.indent.width(),
shape.indent), shape.indent,
context.config)); ),
context.config,
));
result.push_str(&indent); result.push_str(&indent);
result.push_str(&comment); result.push_str(&comment);
result.push('\n'); result.push('\n');