Updated to latest rustfmt
This commit is contained in:
commit
3163071c75
3
.gitignore
vendored
3
.gitignore
vendored
@ -1 +1,2 @@
|
||||
/target/
|
||||
**/*.rs.bk
|
||||
/target/
|
||||
|
66
Cargo.lock
generated
66
Cargo.lock
generated
@ -1,26 +1,26 @@
|
||||
[root]
|
||||
name = "rustfmt"
|
||||
version = "0.2.1"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"diff 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"diff 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strings 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntex_syntax 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syntex_syntax 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-segmentation 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.4.0"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -30,7 +30,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.8"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@ -38,8 +38,8 @@ name = "env_logger"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -58,43 +58,44 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.2"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.4"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "0.1.7"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.1.43"
|
||||
version = "0.1.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.2.2"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-serialize"
|
||||
version = "0.3.16"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@ -102,18 +103,18 @@ name = "strings"
|
||||
version = "0.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syntex_syntax"
|
||||
version = "0.23.0"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@ -129,10 +130,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.1.24"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -145,6 +146,11 @@ name = "unicode-xid"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.5"
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
|
||||
name = "rustfmt"
|
||||
version = "0.2.1"
|
||||
version = "0.3.0"
|
||||
authors = ["Nicholas Cameron <ncameron@mozilla.com>", "Marcus Klaas <mail@marcusklaas.nl>", "The Rustfmt contributors"]
|
||||
description = "Tool to find and fix Rust formatting issues"
|
||||
repository = "https://github.com/rust-lang-nursery/rustfmt"
|
||||
@ -21,7 +21,7 @@ regex = "0.1.41"
|
||||
term = "0.2.11"
|
||||
strings = "0.0.1"
|
||||
diff = "0.1.8"
|
||||
syntex_syntax = "0.23.0"
|
||||
syntex_syntax = "0.29.1"
|
||||
log = "0.3.2"
|
||||
env_logger = "0.3.1"
|
||||
getopts = "0.2"
|
||||
|
37
Design.md
37
Design.md
@ -134,25 +134,34 @@ not worthwhile due to uniformity being desirable, but it is a useful goal).
|
||||
|
||||
### Architecture details
|
||||
|
||||
We use the AST from libsyntax. We use libsyntax's visit module to walk the AST
|
||||
to find starting points for reformatting. Eventually, we should reformat everything
|
||||
and we shouldn't need the visit module. We keep track of the last formatted
|
||||
position in the code, and when we reformat the next piece of code we make sure
|
||||
to output the span for all the code in between (handled by missed_spans.rs).
|
||||
We use the AST from [syntex_syntax], an export of rustc's libsyntax. We use
|
||||
syntex_syntax's visit module to walk the AST to find starting points for
|
||||
reformatting. Eventually, we should reformat everything and we shouldn't need
|
||||
the visit module. We keep track of the last formatted position in the code, and
|
||||
when we reformat the next piece of code we make sure to output the span for all
|
||||
the code in between (handled by missed_spans.rs).
|
||||
|
||||
[syntex_syntax]: https://crates.io/crates/syntex_syntax
|
||||
|
||||
We read in formatting configuration from a `rustfmt.toml` file if there is one.
|
||||
The options and their defaults are defined in `config.rs`. A `Config` object is
|
||||
passed throughout the formatting code, and each formatting routine looks there
|
||||
for its configuration.
|
||||
|
||||
Our visitor keeps track of the desired current indent due to blocks (
|
||||
`block_indent`). Each `visit_*` method reformats code according to this indent
|
||||
and `IDEAL_WIDTH` and `MAX_WIDTH` (which should one day be supplied from a
|
||||
config file). Most reformatting done in the `visit_*` methods is a bit hackey
|
||||
and is meant to be temporary until it can be done properly.
|
||||
`block_indent`). Each `visit_*` method reformats code according to this indent,
|
||||
`config.ideal_width` and `config.max_width`. Most reformatting done in the
|
||||
`visit_*` methods is a bit hackey and is meant to be temporary until it can be
|
||||
done properly.
|
||||
|
||||
There are a bunch of methods called `rewrite_*`. There do the bulk of the
|
||||
reformatting. These take the AST node to be reformatted (this may not literally
|
||||
be an AST node from libsyntax, there might be multiple parameters describing a
|
||||
logical node), the current indent, and the current width budget. They return a
|
||||
`String` (or sometimes an `Option<String>`) which formats the code in the box
|
||||
given by the indent and width budget. If the method fails, it returns `None` and
|
||||
the calling method then has to fallback in some way to give the callee more space.
|
||||
be an AST node from syntex_syntax: there might be multiple parameters
|
||||
describing a logical node), the current indent, and the current width budget.
|
||||
They return a `String` (or sometimes an `Option<String>`) which formats the
|
||||
code in the box given by the indent and width budget. If the method fails, it
|
||||
returns `None` and the calling method then has to fallback in some way to give
|
||||
the callee more space.
|
||||
|
||||
So, in summary to format a node, we calculate the width budget and then walk down
|
||||
the tree from the node. At a leaf, we generate an actual string and then unwind,
|
||||
|
25
README.md
25
README.md
@ -51,14 +51,17 @@ read data from stdin. Alternatively, you can use `cargo fmt` to format all
|
||||
binary and library targets of your crate.
|
||||
|
||||
You'll probably want to specify the write mode. Currently, there are modes for
|
||||
replace, overwrite, display, and coverage. The replace mode is the default
|
||||
and overwrites the original files after renaming them. In overwrite mode,
|
||||
rustfmt does not backup the source files. To print the output to stdout, use the
|
||||
display mode. The write mode can be set by passing the `--write-mode` flag on
|
||||
the command line.
|
||||
diff, replace, overwrite, display, coverage, and checkstyle.
|
||||
|
||||
`rustfmt filename --write-mode=display` prints the output of rustfmt to the
|
||||
screen, for example.
|
||||
* `replace` Is the default and overwrites the original files after creating backups of the files.
|
||||
* `overwrite` Overwrites the original files _without_ creating backups.
|
||||
* `display` Will print the formatted files to stdout.
|
||||
* `diff` Will print a diff between the original files and formatted files to stdout.
|
||||
* `checkstyle` Will output the lines that need to be corrected as a checkstyle XML file,
|
||||
that can be used by tools like Jenkins.
|
||||
|
||||
The write mode can be set by passing the `--write-mode` flag on
|
||||
the command line. For example `rustfmt --write-mode=display src/filename.rs`
|
||||
|
||||
You can run `rustfmt --help` for more information.
|
||||
|
||||
@ -75,8 +78,6 @@ You can run `rustfmt --help` for more information.
|
||||
|
||||
## How to build and test
|
||||
|
||||
First make sure you've got Rust **1.4.0** or greater available, then:
|
||||
|
||||
`cargo build` to build.
|
||||
|
||||
`cargo test` to run all tests.
|
||||
@ -85,12 +86,12 @@ To run rustfmt after this, use `cargo run --bin rustfmt -- filename`. See the
|
||||
notes above on running rustfmt.
|
||||
|
||||
|
||||
## What style does Rustfmt use?
|
||||
## Configuring Rustfmt
|
||||
|
||||
Rustfmt is designed to be very configurable. You can create a TOML file called
|
||||
rustfmt.toml, place it in the project directory and it will apply the options
|
||||
in that file. See `cargo run -- --config-help` for the options which are available,
|
||||
or if you prefer to see source code, [src/config.rs].
|
||||
in that file. See `rustfmt --config-help` for the options which are available,
|
||||
or if you prefer to see source code, [src/config.rs](src/config.rs).
|
||||
|
||||
By default, Rustfmt uses a style which (mostly) conforms to the
|
||||
[Rust style guidelines](https://github.com/rust-lang/rust/tree/master/src/doc/style).
|
||||
|
@ -17,69 +17,120 @@ extern crate toml;
|
||||
extern crate env_logger;
|
||||
extern crate getopts;
|
||||
|
||||
use rustfmt::{WriteMode, run, run_from_stdin};
|
||||
use rustfmt::config::Config;
|
||||
use rustfmt::{run, run_from_stdin};
|
||||
use rustfmt::config::{Config, WriteMode};
|
||||
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, Read, Write};
|
||||
use std::io::{self, ErrorKind, Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
|
||||
use getopts::{Matches, Options};
|
||||
|
||||
/// Rustfmt operations.
|
||||
enum Operation {
|
||||
/// Format files and their child modules.
|
||||
Format(Vec<PathBuf>, WriteMode),
|
||||
Format {
|
||||
files: Vec<PathBuf>,
|
||||
config_path: Option<PathBuf>,
|
||||
},
|
||||
/// Print the help message.
|
||||
Help,
|
||||
// Print version information
|
||||
Version,
|
||||
/// Print detailed configuration help.
|
||||
ConfigHelp,
|
||||
/// Invalid program input, including reason.
|
||||
InvalidInput(String),
|
||||
/// Invalid program input.
|
||||
InvalidInput {
|
||||
reason: String,
|
||||
},
|
||||
/// No file specified, read from stdin
|
||||
Stdin(String, WriteMode),
|
||||
Stdin {
|
||||
input: String,
|
||||
config_path: Option<PathBuf>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Try to find a project file in the input file directory and its parents.
|
||||
fn lookup_project_file(input_file: &Path) -> io::Result<PathBuf> {
|
||||
let mut current = if input_file.is_relative() {
|
||||
try!(env::current_dir()).join(input_file)
|
||||
/// Try to find a project file in the given directory and its parents. Returns the path of a the
|
||||
/// nearest project file if one exists, or `None` if no project file was found.
|
||||
fn lookup_project_file(dir: &Path) -> io::Result<Option<PathBuf>> {
|
||||
let mut current = if dir.is_relative() {
|
||||
try!(env::current_dir()).join(dir)
|
||||
} else {
|
||||
input_file.to_path_buf()
|
||||
dir.to_path_buf()
|
||||
};
|
||||
|
||||
// FIXME: We should canonize path to properly handle its parents,
|
||||
// but `canonicalize` function is unstable now (recently added API)
|
||||
// current = try!(fs::canonicalize(current));
|
||||
current = try!(fs::canonicalize(current));
|
||||
|
||||
loop {
|
||||
let config_file = current.join("rustfmt.toml");
|
||||
if fs::metadata(&config_file).is_ok() {
|
||||
return Ok(config_file);
|
||||
match fs::metadata(&config_file) {
|
||||
Ok(md) => {
|
||||
// Properly handle unlikely situation of a directory named `rustfmt.toml`.
|
||||
if md.is_file() {
|
||||
return Ok(Some(config_file));
|
||||
}
|
||||
}
|
||||
// If it's not found, we continue searching; otherwise something went wrong and we
|
||||
// return the error.
|
||||
Err(e) => {
|
||||
if e.kind() != ErrorKind::NotFound {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the current directory has no parent, we're done searching.
|
||||
if !current.pop() {
|
||||
return Err(io::Error::new(io::ErrorKind::NotFound, "Config not found"));
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to find a project file. If it's found, read it.
|
||||
fn lookup_and_read_project_file(input_file: &Path) -> io::Result<(PathBuf, String)> {
|
||||
let path = try!(lookup_project_file(input_file));
|
||||
/// Resolve the config for input in `dir`.
|
||||
///
|
||||
/// Returns the `Config` to use, and the path of the project file if there was
|
||||
/// one.
|
||||
fn resolve_config(dir: &Path) -> io::Result<(Config, Option<PathBuf>)> {
|
||||
let path = try!(lookup_project_file(dir));
|
||||
if path.is_none() {
|
||||
return Ok((Config::default(), None));
|
||||
}
|
||||
let path = path.unwrap();
|
||||
let mut file = try!(File::open(&path));
|
||||
let mut toml = String::new();
|
||||
try!(file.read_to_string(&mut toml));
|
||||
Ok((path, toml))
|
||||
Ok((Config::from_toml(&toml), Some(path)))
|
||||
}
|
||||
|
||||
fn update_config(config: &mut Config, matches: &Matches) {
|
||||
/// 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>,
|
||||
input_file: &Path)
|
||||
-> io::Result<(Config, Option<PathBuf>)> {
|
||||
|
||||
if let Some(config_file) = config_path {
|
||||
let (toml, path) = try!(resolve_config(config_file.as_ref()));
|
||||
if path.is_some() {
|
||||
return Ok((toml, path));
|
||||
}
|
||||
}
|
||||
resolve_config(input_file)
|
||||
}
|
||||
|
||||
fn update_config(config: &mut Config, matches: &Matches) -> Result<(), String> {
|
||||
config.verbose = matches.opt_present("verbose");
|
||||
config.skip_children = matches.opt_present("skip-children");
|
||||
|
||||
let write_mode = matches.opt_str("write-mode");
|
||||
match matches.opt_str("write-mode").map(|wm| WriteMode::from_str(&wm)) {
|
||||
None => Ok(()),
|
||||
Some(Ok(write_mode)) => {
|
||||
config.write_mode = write_mode;
|
||||
Ok(())
|
||||
}
|
||||
Some(Err(_)) => Err(format!("Invalid write-mode: {}", write_mode.expect("cannot happen"))),
|
||||
}
|
||||
}
|
||||
|
||||
fn execute() -> i32 {
|
||||
@ -90,12 +141,17 @@ fn execute() -> i32 {
|
||||
opts.optopt("",
|
||||
"write-mode",
|
||||
"mode to write in (not usable when piping from stdin)",
|
||||
"[replace|overwrite|display|diff|coverage]");
|
||||
"[replace|overwrite|display|diff|coverage|checkstyle]");
|
||||
opts.optflag("", "skip-children", "don't reformat child modules");
|
||||
|
||||
opts.optflag("",
|
||||
"config-help",
|
||||
"show details of rustfmt configuration options");
|
||||
opts.optopt("",
|
||||
"config-path",
|
||||
"Recursively searches the given path for the rustfmt.toml config file. If not \
|
||||
found reverts to the input file path",
|
||||
"[Path for the configuration file]");
|
||||
|
||||
let matches = match opts.parse(env::args().skip(1)) {
|
||||
Ok(m) => m,
|
||||
@ -108,7 +164,7 @@ fn execute() -> i32 {
|
||||
let operation = determine_operation(&matches);
|
||||
|
||||
match operation {
|
||||
Operation::InvalidInput(reason) => {
|
||||
Operation::InvalidInput { reason } => {
|
||||
print_usage(&opts, &reason);
|
||||
1
|
||||
}
|
||||
@ -124,30 +180,51 @@ fn execute() -> i32 {
|
||||
Config::print_docs();
|
||||
0
|
||||
}
|
||||
Operation::Stdin(input, write_mode) => {
|
||||
Operation::Stdin { input, config_path } => {
|
||||
// try to read config from local directory
|
||||
let config = match lookup_and_read_project_file(&Path::new(".")) {
|
||||
Ok((_, toml)) => Config::from_toml(&toml),
|
||||
Err(_) => Default::default(),
|
||||
};
|
||||
let (mut config, _) = match_cli_path_or_file(config_path, &env::current_dir().unwrap())
|
||||
.expect("Error resolving config");
|
||||
|
||||
run_from_stdin(input, write_mode, &config);
|
||||
// write_mode is always Plain for Stdin.
|
||||
config.write_mode = WriteMode::Plain;
|
||||
|
||||
run_from_stdin(input, &config);
|
||||
0
|
||||
}
|
||||
Operation::Format(files, write_mode) => {
|
||||
Operation::Format { files, config_path } => {
|
||||
let mut config = Config::default();
|
||||
let mut path = None;
|
||||
// Load the config path file if provided
|
||||
if let Some(config_file) = config_path {
|
||||
let (cfg_tmp, path_tmp) = resolve_config(config_file.as_ref())
|
||||
.expect(&format!("Error resolving config for {:?}",
|
||||
config_file));
|
||||
config = cfg_tmp;
|
||||
path = path_tmp;
|
||||
};
|
||||
if let Some(path) = path.as_ref() {
|
||||
println!("Using rustfmt config file {}", path.display());
|
||||
}
|
||||
for file in files {
|
||||
let mut config = match lookup_and_read_project_file(&file) {
|
||||
Ok((path, toml)) => {
|
||||
// Check the file directory if the config-path could not be read or not provided
|
||||
if path.is_none() {
|
||||
let (config_tmp, path_tmp) = resolve_config(file.parent().unwrap())
|
||||
.expect(&format!("Error resolving config \
|
||||
for {}",
|
||||
file.display()));
|
||||
if let Some(path) = path_tmp.as_ref() {
|
||||
println!("Using rustfmt config file {} for {}",
|
||||
path.display(),
|
||||
file.display());
|
||||
Config::from_toml(&toml)
|
||||
}
|
||||
Err(_) => Default::default(),
|
||||
};
|
||||
config = config_tmp;
|
||||
}
|
||||
|
||||
update_config(&mut config, &matches);
|
||||
run(&file, write_mode, &config);
|
||||
if let Err(e) = update_config(&mut config, &matches) {
|
||||
print_usage(&opts, &e);
|
||||
return 1;
|
||||
}
|
||||
run(&file, &config);
|
||||
}
|
||||
0
|
||||
}
|
||||
@ -196,30 +273,35 @@ fn determine_operation(matches: &Matches) -> Operation {
|
||||
return Operation::Version;
|
||||
}
|
||||
|
||||
// Read the config_path and convert to parent dir if a file is provided.
|
||||
let config_path: Option<PathBuf> = matches.opt_str("config-path")
|
||||
.map(PathBuf::from)
|
||||
.and_then(|dir| {
|
||||
if dir.is_file() {
|
||||
return dir.parent().map(|v| v.into());
|
||||
}
|
||||
Some(dir)
|
||||
});
|
||||
|
||||
// if no file argument is supplied, read from stdin
|
||||
if matches.free.is_empty() {
|
||||
|
||||
let mut buffer = String::new();
|
||||
match io::stdin().read_to_string(&mut buffer) {
|
||||
Ok(..) => (),
|
||||
Err(e) => return Operation::InvalidInput(e.to_string()),
|
||||
Err(e) => return Operation::InvalidInput { reason: e.to_string() },
|
||||
}
|
||||
|
||||
// WriteMode is always plain for Stdin
|
||||
return Operation::Stdin(buffer, WriteMode::Plain);
|
||||
return Operation::Stdin {
|
||||
input: buffer,
|
||||
config_path: config_path,
|
||||
};
|
||||
}
|
||||
|
||||
let write_mode = match matches.opt_str("write-mode") {
|
||||
Some(mode) => {
|
||||
match mode.parse() {
|
||||
Ok(mode) => mode,
|
||||
Err(..) => return Operation::InvalidInput("Unrecognized write mode".into()),
|
||||
}
|
||||
}
|
||||
None => WriteMode::Replace,
|
||||
};
|
||||
|
||||
let files: Vec<_> = matches.free.iter().map(PathBuf::from).collect();
|
||||
|
||||
Operation::Format(files, write_mode)
|
||||
Operation::Format {
|
||||
files: files,
|
||||
config_path: config_path,
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ pub fn rewrite_chain(mut expr: &ast::Expr,
|
||||
|
||||
let fits_single_line = !veto_single_line &&
|
||||
match subexpr_list[0].node {
|
||||
ast::Expr_::ExprMethodCall(ref method_name, ref types, ref expressions)
|
||||
ast::ExprKind::MethodCall(ref method_name, ref types, ref expressions)
|
||||
if context.config.chains_overflow_last => {
|
||||
let len = rewrites.len();
|
||||
let (init, last) = rewrites.split_at_mut(len - 1);
|
||||
@ -150,28 +150,28 @@ pub fn rewrite_chain(mut expr: &ast::Expr,
|
||||
// parens, braces and brackets in its idiomatic formatting.
|
||||
fn is_block_expr(expr: &ast::Expr, repr: &str) -> bool {
|
||||
match expr.node {
|
||||
ast::Expr_::ExprStruct(..) |
|
||||
ast::Expr_::ExprWhile(..) |
|
||||
ast::Expr_::ExprWhileLet(..) |
|
||||
ast::Expr_::ExprIf(..) |
|
||||
ast::Expr_::ExprIfLet(..) |
|
||||
ast::Expr_::ExprBlock(..) |
|
||||
ast::Expr_::ExprLoop(..) |
|
||||
ast::Expr_::ExprForLoop(..) |
|
||||
ast::Expr_::ExprMatch(..) => repr.contains('\n'),
|
||||
ast::Expr_::ExprParen(ref expr) |
|
||||
ast::Expr_::ExprBinary(_, _, ref expr) |
|
||||
ast::Expr_::ExprIndex(_, ref expr) |
|
||||
ast::Expr_::ExprUnary(_, ref expr) => is_block_expr(expr, repr),
|
||||
ast::ExprKind::Struct(..) |
|
||||
ast::ExprKind::While(..) |
|
||||
ast::ExprKind::WhileLet(..) |
|
||||
ast::ExprKind::If(..) |
|
||||
ast::ExprKind::IfLet(..) |
|
||||
ast::ExprKind::Block(..) |
|
||||
ast::ExprKind::Loop(..) |
|
||||
ast::ExprKind::ForLoop(..) |
|
||||
ast::ExprKind::Match(..) => repr.contains('\n'),
|
||||
ast::ExprKind::Paren(ref expr) |
|
||||
ast::ExprKind::Binary(_, _, ref expr) |
|
||||
ast::ExprKind::Index(_, ref expr) |
|
||||
ast::ExprKind::Unary(_, ref expr) => is_block_expr(expr, repr),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn pop_expr_chain(expr: &ast::Expr) -> Option<&ast::Expr> {
|
||||
match expr.node {
|
||||
ast::Expr_::ExprMethodCall(_, _, ref expressions) => Some(&expressions[0]),
|
||||
ast::Expr_::ExprTupField(ref subexpr, _) |
|
||||
ast::Expr_::ExprField(ref subexpr, _) => Some(subexpr),
|
||||
ast::ExprKind::MethodCall(_, _, ref expressions) => Some(&expressions[0]),
|
||||
ast::ExprKind::TupField(ref subexpr, _) |
|
||||
ast::ExprKind::Field(ref subexpr, _) => Some(subexpr),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -183,7 +183,7 @@ fn rewrite_chain_expr(expr: &ast::Expr,
|
||||
offset: Indent)
|
||||
-> Option<String> {
|
||||
match expr.node {
|
||||
ast::Expr_::ExprMethodCall(ref method_name, ref types, ref expressions) => {
|
||||
ast::ExprKind::MethodCall(ref method_name, ref types, ref expressions) => {
|
||||
let inner = &RewriteContext { block_indent: offset, ..*context };
|
||||
rewrite_method_call(method_name.node,
|
||||
types,
|
||||
@ -193,7 +193,7 @@ fn rewrite_chain_expr(expr: &ast::Expr,
|
||||
width,
|
||||
offset)
|
||||
}
|
||||
ast::Expr_::ExprField(_, ref field) => {
|
||||
ast::ExprKind::Field(_, ref field) => {
|
||||
let s = format!(".{}", field.node);
|
||||
if s.len() <= width {
|
||||
Some(s)
|
||||
@ -201,7 +201,7 @@ fn rewrite_chain_expr(expr: &ast::Expr,
|
||||
None
|
||||
}
|
||||
}
|
||||
ast::Expr_::ExprTupField(_, ref field) => {
|
||||
ast::ExprKind::TupField(_, ref field) => {
|
||||
let s = format!(".{}", field.node);
|
||||
if s.len() <= width {
|
||||
Some(s)
|
||||
@ -216,7 +216,7 @@ fn rewrite_chain_expr(expr: &ast::Expr,
|
||||
// Determines we can continue formatting a given expression on the same line.
|
||||
fn is_continuable(expr: &ast::Expr) -> bool {
|
||||
match expr.node {
|
||||
ast::Expr_::ExprPath(..) => true,
|
||||
ast::ExprKind::Path(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
82
src/checkstyle.rs
Normal file
82
src/checkstyle.rs
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
use rustfmt_diff::{Mismatch, DiffLine};
|
||||
use std::io::{self, Write, Read};
|
||||
use config::WriteMode;
|
||||
|
||||
|
||||
pub fn output_header<T>(out: &mut T, mode: WriteMode) -> Result<(), io::Error>
|
||||
where T: Write
|
||||
{
|
||||
if mode == WriteMode::Checkstyle {
|
||||
let mut xml_heading = String::new();
|
||||
xml_heading.push_str("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
|
||||
xml_heading.push_str("\n");
|
||||
xml_heading.push_str("<checkstyle version=\"4.3\">");
|
||||
try!(write!(out, "{}", xml_heading));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn output_footer<T>(out: &mut T, mode: WriteMode) -> Result<(), io::Error>
|
||||
where T: Write
|
||||
{
|
||||
if mode == WriteMode::Checkstyle {
|
||||
let mut xml_tail = String::new();
|
||||
xml_tail.push_str("</checkstyle>");
|
||||
try!(write!(out, "{}", xml_tail));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn output_checkstyle_file<T>(mut writer: T,
|
||||
filename: &str,
|
||||
diff: Vec<Mismatch>)
|
||||
-> Result<(), io::Error>
|
||||
where T: Write
|
||||
{
|
||||
try!(write!(writer, "<file name=\"{}\">", filename));
|
||||
for mismatch in diff {
|
||||
for line in mismatch.lines {
|
||||
match line {
|
||||
DiffLine::Expected(ref str) => {
|
||||
let message = xml_escape_str(&str);
|
||||
try!(write!(writer,
|
||||
"<error line=\"{}\" severity=\"warning\" message=\"Should be \
|
||||
`{}`\" />",
|
||||
mismatch.line_number,
|
||||
message));
|
||||
}
|
||||
_ => {
|
||||
// Do nothing with context and expected.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
try!(write!(writer, "</file>"));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Convert special characters into XML entities.
|
||||
// This is needed for checkstyle output.
|
||||
fn xml_escape_str(string: &str) -> String {
|
||||
let mut out = String::new();
|
||||
for c in string.chars() {
|
||||
match c {
|
||||
'<' => out.push_str("<"),
|
||||
'>' => out.push_str(">"),
|
||||
'"' => out.push_str("""),
|
||||
'\'' => out.push_str("'"),
|
||||
'&' => out.push_str("&"),
|
||||
_ => out.push(c),
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
@ -73,6 +73,13 @@ configuration_option_enum! { Density:
|
||||
CompressedIfEmpty,
|
||||
}
|
||||
|
||||
configuration_option_enum! { TypeDensity:
|
||||
// No spaces around "=" and "+"
|
||||
Compressed,
|
||||
// Spaces around " = " and " + "
|
||||
Wide,
|
||||
}
|
||||
|
||||
impl Density {
|
||||
pub fn to_list_tactic(self) -> ListTactic {
|
||||
match self {
|
||||
@ -113,6 +120,23 @@ configuration_option_enum! { ReportTactic:
|
||||
Never,
|
||||
}
|
||||
|
||||
configuration_option_enum! { WriteMode:
|
||||
// Backsup the original file and overwrites the orignal.
|
||||
Replace,
|
||||
// Overwrites original file without backup.
|
||||
Overwrite,
|
||||
// Write the output to stdout.
|
||||
Display,
|
||||
// Write the diff to stdout.
|
||||
Diff,
|
||||
// Display how much of the input file was processed
|
||||
Coverage,
|
||||
// Unfancy stdout
|
||||
Plain,
|
||||
// Output a checkstyle XML file.
|
||||
Checkstyle,
|
||||
}
|
||||
|
||||
// This trait and the following impl blocks are there so that we an use
|
||||
// UCFS inside the get_docs() function on types for configs.
|
||||
pub trait ConfigType {
|
||||
@ -191,12 +215,12 @@ macro_rules! create_config {
|
||||
}
|
||||
|
||||
pub fn from_toml(toml: &str) -> Config {
|
||||
let parsed = toml.parse().unwrap();
|
||||
let parsed = toml.parse().expect("Could not parse TOML");
|
||||
let parsed_config:ParsedConfig = match toml::decode(parsed) {
|
||||
Some(decoded) => decoded,
|
||||
None => {
|
||||
println!("Decoding config file failed. Config:\n{}", toml);
|
||||
let parsed: toml::Value = toml.parse().unwrap();
|
||||
let parsed: toml::Value = toml.parse().expect("Could not parse TOML");
|
||||
println!("\n\nParsed:\n{:?}", parsed);
|
||||
panic!();
|
||||
}
|
||||
@ -208,10 +232,14 @@ macro_rules! create_config {
|
||||
match key {
|
||||
$(
|
||||
stringify!($i) => {
|
||||
self.$i = val.parse::<$ty>().unwrap();
|
||||
self.$i = val.parse::<$ty>()
|
||||
.expect(&format!("Failed to parse override for {} (\"{}\") as a {}",
|
||||
stringify!($i),
|
||||
val,
|
||||
stringify!($ty)));
|
||||
}
|
||||
)+
|
||||
_ => panic!("Bad config key!")
|
||||
_ => panic!("Unknown config key in override: {}", key)
|
||||
}
|
||||
}
|
||||
|
||||
@ -270,6 +298,7 @@ create_config! {
|
||||
newline_style: NewlineStyle, NewlineStyle::Unix, "Unix or Windows line endings";
|
||||
fn_brace_style: BraceStyle, BraceStyle::SameLineWhere, "Brace style for functions";
|
||||
item_brace_style: BraceStyle, BraceStyle::SameLineWhere, "Brace style for structs and enums";
|
||||
impl_empty_single_line: bool, true, "Put empty-body implementations on a single line";
|
||||
fn_empty_single_line: bool, true, "Put empty-body functions on a single line";
|
||||
fn_single_line: bool, false, "Put single-expression functions on a single line";
|
||||
fn_return_indent: ReturnIndent, ReturnIndent::WithArgs,
|
||||
@ -278,6 +307,8 @@ create_config! {
|
||||
fn_args_density: Density, Density::Tall, "Argument density in functions";
|
||||
fn_args_layout: StructLitStyle, StructLitStyle::Visual, "Layout of function arguments";
|
||||
fn_arg_indent: BlockIndentStyle, BlockIndentStyle::Visual, "Indent on function arguments";
|
||||
type_punctuation_density: TypeDensity, TypeDensity::Wide,
|
||||
"Determines if '+' or '=' are wrapped in spaces in the punctuation of types";
|
||||
// Should we at least try to put the where clause on the same line as the rest of the
|
||||
// function decl?
|
||||
where_density: Density, Density::CompressedIfEmpty, "Density of a where clause";
|
||||
@ -286,6 +317,7 @@ create_config! {
|
||||
where_layout: ListTactic, ListTactic::Vertical, "Element layout inside a where clause";
|
||||
where_pred_indent: BlockIndentStyle, BlockIndentStyle::Visual,
|
||||
"Indentation style of a where predicate";
|
||||
where_trailing_comma: bool, false, "Put a trailing comma on where clauses";
|
||||
generics_indent: BlockIndentStyle, BlockIndentStyle::Visual, "Indentation of generics";
|
||||
struct_trailing_comma: SeparatorTactic, SeparatorTactic::Vertical,
|
||||
"If there is a trailing comma on structs";
|
||||
@ -295,7 +327,7 @@ create_config! {
|
||||
struct_lit_multiline_style: MultilineStyle, MultilineStyle::PreferSingle,
|
||||
"Multiline style on literal structs";
|
||||
enum_trailing_comma: bool, true, "Put a trailing comma on enum declarations";
|
||||
report_todo: ReportTactic, ReportTactic::Always,
|
||||
report_todo: ReportTactic, ReportTactic::Never,
|
||||
"Report all, none or unnumbered occurrences of TODO in source file comments";
|
||||
report_fixme: ReportTactic, ReportTactic::Never,
|
||||
"Report all, none or unnumbered occurrences of FIXME in source file comments";
|
||||
@ -303,7 +335,8 @@ create_config! {
|
||||
chain_indent: BlockIndentStyle, BlockIndentStyle::Visual, "Indentation of chain";
|
||||
reorder_imports: bool, false, "Reorder import statements alphabetically";
|
||||
single_line_if_else: bool, false, "Put else on same line as closing brace for if statements";
|
||||
format_strings: bool, true, "Format string literals, or leave as is";
|
||||
format_strings: bool, true, "Format string literals where necessary";
|
||||
force_format_strings: bool, false, "Always format string literals";
|
||||
chains_overflow_last: bool, true, "Allow last call in method chain to break the line";
|
||||
take_source_hints: bool, true, "Retain some formatting characteristics from the source code";
|
||||
hard_tabs: bool, false, "Use tab characters for indentation, spaces for alignment";
|
||||
@ -313,4 +346,6 @@ create_config! {
|
||||
match_block_trailing_comma: bool, false,
|
||||
"Put a trailing comma after a block based match arm (non-block arms are not affected)";
|
||||
match_wildcard_trailing_comma: bool, true, "Put a trailing comma after a wildcard arm";
|
||||
write_mode: WriteMode, WriteMode::Replace,
|
||||
"What Write Mode to use when none is supplied: Replace, Overwrite, Display, Diff, Coverage";
|
||||
}
|
||||
|
284
src/expr.rs
284
src/expr.rs
@ -13,14 +13,15 @@ use std::borrow::Borrow;
|
||||
use std::mem::swap;
|
||||
use std::ops::Deref;
|
||||
use std::iter::ExactSizeIterator;
|
||||
use std::fmt::Write;
|
||||
|
||||
use {Indent, Spanned};
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
use lists::{write_list, itemize_list, ListFormatting, SeparatorTactic, ListTactic,
|
||||
DefinitiveListTactic, definitive_tactic, ListItem, format_fn_args};
|
||||
use string::{StringFormat, rewrite_string};
|
||||
use utils::{span_after, extra_offset, last_line_width, wrap_str, binary_search, first_line_width,
|
||||
semicolon_for_stmt};
|
||||
use utils::{span_after, span_before, extra_offset, last_line_width, wrap_str, binary_search,
|
||||
first_line_width, semicolon_for_stmt};
|
||||
use visitor::FmtVisitor;
|
||||
use config::{Config, StructLitStyle, MultilineStyle};
|
||||
use comment::{FindUncommented, rewrite_comment, contains_comment, recover_comment_removed};
|
||||
@ -36,16 +37,16 @@ use syntax::visit::Visitor;
|
||||
impl Rewrite for ast::Expr {
|
||||
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
|
||||
let result = match self.node {
|
||||
ast::Expr_::ExprVec(ref expr_vec) => {
|
||||
ast::ExprKind::Vec(ref expr_vec) => {
|
||||
rewrite_array(expr_vec.iter().map(|e| &**e),
|
||||
mk_sp(span_after(self.span, "[", context.codemap), self.span.hi),
|
||||
context,
|
||||
width,
|
||||
offset)
|
||||
}
|
||||
ast::Expr_::ExprLit(ref l) => {
|
||||
ast::ExprKind::Lit(ref l) => {
|
||||
match l.node {
|
||||
ast::Lit_::LitStr(_, ast::StrStyle::CookedStr) => {
|
||||
ast::LitKind::Str(_, ast::StrStyle::Cooked) => {
|
||||
rewrite_string_lit(context, l.span, width, offset)
|
||||
}
|
||||
_ => {
|
||||
@ -56,18 +57,18 @@ impl Rewrite for ast::Expr {
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::Expr_::ExprCall(ref callee, ref args) => {
|
||||
ast::ExprKind::Call(ref callee, ref args) => {
|
||||
let inner_span = mk_sp(callee.span.hi, self.span.hi);
|
||||
rewrite_call(context, &**callee, args, inner_span, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprParen(ref subexpr) => rewrite_paren(context, subexpr, width, offset),
|
||||
ast::Expr_::ExprBinary(ref op, ref lhs, ref rhs) => {
|
||||
ast::ExprKind::Paren(ref subexpr) => rewrite_paren(context, subexpr, width, offset),
|
||||
ast::ExprKind::Binary(ref op, ref lhs, ref rhs) => {
|
||||
rewrite_binary_op(context, op, lhs, rhs, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprUnary(ref op, ref subexpr) => {
|
||||
ast::ExprKind::Unary(ref op, ref subexpr) => {
|
||||
rewrite_unary_op(context, op, subexpr, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprStruct(ref path, ref fields, ref base) => {
|
||||
ast::ExprKind::Struct(ref path, ref fields, ref base) => {
|
||||
rewrite_struct_lit(context,
|
||||
path,
|
||||
fields,
|
||||
@ -76,79 +77,81 @@ impl Rewrite for ast::Expr {
|
||||
width,
|
||||
offset)
|
||||
}
|
||||
ast::Expr_::ExprTup(ref items) => {
|
||||
ast::ExprKind::Tup(ref items) => {
|
||||
rewrite_tuple(context,
|
||||
items.iter().map(|x| &**x),
|
||||
self.span,
|
||||
width,
|
||||
offset)
|
||||
}
|
||||
ast::Expr_::ExprWhile(ref cond, ref block, label) => {
|
||||
ast::ExprKind::While(ref cond, ref block, label) => {
|
||||
Loop::new_while(None, cond, block, label).rewrite(context, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprWhileLet(ref pat, ref cond, ref block, label) => {
|
||||
ast::ExprKind::WhileLet(ref pat, ref cond, ref block, label) => {
|
||||
Loop::new_while(Some(pat), cond, block, label).rewrite(context, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprForLoop(ref pat, ref cond, ref block, label) => {
|
||||
ast::ExprKind::ForLoop(ref pat, ref cond, ref block, label) => {
|
||||
Loop::new_for(pat, cond, block, label).rewrite(context, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprLoop(ref block, label) => {
|
||||
ast::ExprKind::Loop(ref block, label) => {
|
||||
Loop::new_loop(block, label).rewrite(context, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprBlock(ref block) => block.rewrite(context, width, offset),
|
||||
ast::Expr_::ExprIf(ref cond, ref if_block, ref else_block) => {
|
||||
ast::ExprKind::Block(ref block) => block.rewrite(context, width, offset),
|
||||
ast::ExprKind::If(ref cond, ref if_block, ref else_block) => {
|
||||
rewrite_if_else(context,
|
||||
cond,
|
||||
if_block,
|
||||
else_block.as_ref().map(|e| &**e),
|
||||
self.span,
|
||||
None,
|
||||
width,
|
||||
offset,
|
||||
true)
|
||||
}
|
||||
ast::Expr_::ExprIfLet(ref pat, ref cond, ref if_block, ref else_block) => {
|
||||
ast::ExprKind::IfLet(ref pat, ref cond, ref if_block, ref else_block) => {
|
||||
rewrite_if_else(context,
|
||||
cond,
|
||||
if_block,
|
||||
else_block.as_ref().map(|e| &**e),
|
||||
self.span,
|
||||
Some(pat),
|
||||
width,
|
||||
offset,
|
||||
true)
|
||||
}
|
||||
ast::Expr_::ExprMatch(ref cond, ref arms) => {
|
||||
ast::ExprKind::Match(ref cond, ref arms) => {
|
||||
rewrite_match(context, cond, arms, width, offset, self.span)
|
||||
}
|
||||
ast::Expr_::ExprPath(ref qself, ref path) => {
|
||||
ast::ExprKind::Path(ref qself, ref path) => {
|
||||
rewrite_path(context, true, qself.as_ref(), path, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprAssign(ref lhs, ref rhs) => {
|
||||
ast::ExprKind::Assign(ref lhs, ref rhs) => {
|
||||
rewrite_assignment(context, lhs, rhs, None, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprAssignOp(ref op, ref lhs, ref rhs) => {
|
||||
ast::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => {
|
||||
rewrite_assignment(context, lhs, rhs, Some(op), width, offset)
|
||||
}
|
||||
ast::Expr_::ExprAgain(ref opt_ident) => {
|
||||
ast::ExprKind::Again(ref opt_ident) => {
|
||||
let id_str = match *opt_ident {
|
||||
Some(ident) => format!(" {}", ident.node),
|
||||
None => String::new(),
|
||||
};
|
||||
Some(format!("continue{}", id_str))
|
||||
}
|
||||
ast::Expr_::ExprBreak(ref opt_ident) => {
|
||||
ast::ExprKind::Break(ref opt_ident) => {
|
||||
let id_str = match *opt_ident {
|
||||
Some(ident) => format!(" {}", ident.node),
|
||||
None => String::new(),
|
||||
};
|
||||
Some(format!("break{}", id_str))
|
||||
}
|
||||
ast::Expr_::ExprClosure(capture, ref fn_decl, ref body) => {
|
||||
ast::ExprKind::Closure(capture, ref fn_decl, ref body) => {
|
||||
rewrite_closure(capture, fn_decl, body, self.span, context, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprField(..) |
|
||||
ast::Expr_::ExprTupField(..) |
|
||||
ast::Expr_::ExprMethodCall(..) => rewrite_chain(self, context, width, offset),
|
||||
ast::Expr_::ExprMac(ref mac) => {
|
||||
ast::ExprKind::Field(..) |
|
||||
ast::ExprKind::TupField(..) |
|
||||
ast::ExprKind::MethodCall(..) => rewrite_chain(self, context, width, offset),
|
||||
ast::ExprKind::Mac(ref mac) => {
|
||||
// Failure to rewrite a marco should not imply failure to
|
||||
// rewrite the expression.
|
||||
rewrite_macro(mac, context, width, offset).or_else(|| {
|
||||
@ -158,40 +161,43 @@ impl Rewrite for ast::Expr {
|
||||
offset)
|
||||
})
|
||||
}
|
||||
ast::Expr_::ExprRet(None) => {
|
||||
ast::ExprKind::Ret(None) => {
|
||||
wrap_str("return".to_owned(), context.config.max_width, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprRet(Some(ref expr)) => {
|
||||
ast::ExprKind::Ret(Some(ref expr)) => {
|
||||
rewrite_unary_prefix(context, "return ", &**expr, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprBox(ref expr) => {
|
||||
ast::ExprKind::Box(ref expr) => {
|
||||
rewrite_unary_prefix(context, "box ", &**expr, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprAddrOf(mutability, ref expr) => {
|
||||
ast::ExprKind::AddrOf(mutability, ref expr) => {
|
||||
rewrite_expr_addrof(context, mutability, expr, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprCast(ref expr, ref ty) => {
|
||||
ast::ExprKind::Cast(ref expr, ref ty) => {
|
||||
rewrite_pair(&**expr, &**ty, "", " as ", "", context, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprIndex(ref expr, ref index) => {
|
||||
// TODO(#848): Handle type ascription; rust tracking issue
|
||||
// https://github.com/rust-lang/rust/issues/23416
|
||||
ast::ExprKind::Type(_, _) => unimplemented!(),
|
||||
ast::ExprKind::Index(ref expr, ref index) => {
|
||||
rewrite_pair(&**expr, &**index, "", "[", "]", context, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprRepeat(ref expr, ref repeats) => {
|
||||
ast::ExprKind::Repeat(ref expr, ref repeats) => {
|
||||
rewrite_pair(&**expr, &**repeats, "[", "; ", "]", context, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprRange(Some(ref lhs), Some(ref rhs)) => {
|
||||
ast::ExprKind::Range(Some(ref lhs), Some(ref rhs)) => {
|
||||
rewrite_pair(&**lhs, &**rhs, "", "..", "", context, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprRange(None, Some(ref rhs)) => {
|
||||
ast::ExprKind::Range(None, Some(ref rhs)) => {
|
||||
rewrite_unary_prefix(context, "..", &**rhs, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprRange(Some(ref lhs), None) => {
|
||||
ast::ExprKind::Range(Some(ref lhs), None) => {
|
||||
Some(format!("{}..",
|
||||
try_opt!(lhs.rewrite(context,
|
||||
try_opt!(width.checked_sub(2)),
|
||||
offset))))
|
||||
}
|
||||
ast::Expr_::ExprRange(None, None) => {
|
||||
ast::ExprKind::Range(None, None) => {
|
||||
if width >= 2 {
|
||||
Some("..".into())
|
||||
} else {
|
||||
@ -200,8 +206,8 @@ impl Rewrite for ast::Expr {
|
||||
}
|
||||
// We do not format these expressions yet, but they should still
|
||||
// satisfy our width restrictions.
|
||||
ast::Expr_::ExprInPlace(..) |
|
||||
ast::Expr_::ExprInlineAsm(..) => {
|
||||
ast::ExprKind::InPlace(..) |
|
||||
ast::ExprKind::InlineAsm(..) => {
|
||||
wrap_str(context.snippet(self.span),
|
||||
context.config.max_width,
|
||||
width,
|
||||
@ -299,7 +305,7 @@ pub fn rewrite_array<'a, I>(expr_iter: I,
|
||||
|
||||
// This functions is pretty messy because of the wrapping and unwrapping of
|
||||
// expressions into and from blocks. See rust issue #27872.
|
||||
fn rewrite_closure(capture: ast::CaptureClause,
|
||||
fn rewrite_closure(capture: ast::CaptureBy,
|
||||
fn_decl: &ast::FnDecl,
|
||||
body: &ast::Block,
|
||||
span: Span,
|
||||
@ -307,7 +313,7 @@ fn rewrite_closure(capture: ast::CaptureClause,
|
||||
width: usize,
|
||||
offset: Indent)
|
||||
-> Option<String> {
|
||||
let mover = if capture == ast::CaptureClause::CaptureByValue {
|
||||
let mover = if capture == ast::CaptureBy::Value {
|
||||
"move "
|
||||
} else {
|
||||
""
|
||||
@ -371,9 +377,8 @@ fn rewrite_closure(capture: ast::CaptureClause,
|
||||
// All closure bodies are blocks in the eyes of the AST, but we may not
|
||||
// want to unwrap them when they only contain a single expression.
|
||||
let inner_expr = match expr.node {
|
||||
ast::Expr_::ExprBlock(ref inner) if inner.stmts.is_empty() && inner.expr.is_some() &&
|
||||
inner.rules ==
|
||||
ast::BlockCheckMode::DefaultBlock => {
|
||||
ast::ExprKind::Block(ref inner) if inner.stmts.is_empty() && inner.expr.is_some() &&
|
||||
inner.rules == ast::BlockCheckMode::Default => {
|
||||
inner.expr.as_ref().unwrap()
|
||||
}
|
||||
_ => expr,
|
||||
@ -395,7 +400,7 @@ fn rewrite_closure(capture: ast::CaptureClause,
|
||||
let body_rewrite = body.expr
|
||||
.as_ref()
|
||||
.and_then(|body_expr| {
|
||||
if let ast::Expr_::ExprBlock(ref inner) = body_expr.node {
|
||||
if let ast::ExprKind::Block(ref inner) = body_expr.node {
|
||||
Some(inner.rewrite(&context, 2, Indent::empty()))
|
||||
} else {
|
||||
None
|
||||
@ -424,11 +429,11 @@ impl Rewrite for ast::Block {
|
||||
return Some(user_str);
|
||||
}
|
||||
|
||||
let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config, None);
|
||||
let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
|
||||
visitor.block_indent = context.block_indent;
|
||||
|
||||
let prefix = match self.rules {
|
||||
ast::BlockCheckMode::UnsafeBlock(..) => {
|
||||
ast::BlockCheckMode::Unsafe(..) => {
|
||||
let snippet = context.snippet(self.span);
|
||||
let open_pos = try_opt!(snippet.find_uncommented("{"));
|
||||
visitor.last_pos = self.span.lo + BytePos(open_pos as u32);
|
||||
@ -464,7 +469,7 @@ impl Rewrite for ast::Block {
|
||||
|
||||
prefix
|
||||
}
|
||||
ast::BlockCheckMode::DefaultBlock => {
|
||||
ast::BlockCheckMode::Default => {
|
||||
visitor.last_pos = self.span.lo;
|
||||
|
||||
String::new()
|
||||
@ -480,14 +485,14 @@ impl Rewrite for ast::Block {
|
||||
impl Rewrite for ast::Stmt {
|
||||
fn rewrite(&self, context: &RewriteContext, _width: usize, offset: Indent) -> Option<String> {
|
||||
let result = match self.node {
|
||||
ast::Stmt_::StmtDecl(ref decl, _) => {
|
||||
if let ast::Decl_::DeclLocal(ref local) = decl.node {
|
||||
ast::StmtKind::Decl(ref decl, _) => {
|
||||
if let ast::DeclKind::Local(ref local) = decl.node {
|
||||
local.rewrite(context, context.config.max_width, offset)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
ast::Stmt_::StmtExpr(ref ex, _) | ast::Stmt_::StmtSemi(ref ex, _) => {
|
||||
ast::StmtKind::Expr(ref ex, _) | ast::StmtKind::Semi(ref ex, _) => {
|
||||
let suffix = if semicolon_for_stmt(self) {
|
||||
";"
|
||||
} else {
|
||||
@ -499,7 +504,7 @@ impl Rewrite for ast::Stmt {
|
||||
offset)
|
||||
.map(|s| s + suffix)
|
||||
}
|
||||
ast::Stmt_::StmtMac(..) => None,
|
||||
ast::StmtKind::Mac(..) => None,
|
||||
};
|
||||
result.and_then(|res| recover_comment_removed(res, self.span, context, _width, offset))
|
||||
}
|
||||
@ -605,12 +610,33 @@ fn rewrite_label(label: Option<ast::Ident>) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_comment(span: Span,
|
||||
context: &RewriteContext,
|
||||
offset: Indent,
|
||||
width: usize)
|
||||
-> Option<String> {
|
||||
let comment_str = context.snippet(span);
|
||||
if contains_comment(&comment_str) {
|
||||
let comment = try_opt!(rewrite_comment(comment_str.trim(),
|
||||
false,
|
||||
width,
|
||||
offset,
|
||||
context.config));
|
||||
Some(format!("\n{indent}{}\n{indent}",
|
||||
comment,
|
||||
indent = offset.to_string(context.config)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// Rewrites if-else blocks. If let Some(_) = pat, the expression is
|
||||
// treated as an if-let-else expression.
|
||||
fn rewrite_if_else(context: &RewriteContext,
|
||||
cond: &ast::Expr,
|
||||
if_block: &ast::Block,
|
||||
else_block_opt: Option<&ast::Expr>,
|
||||
span: Span,
|
||||
pat: Option<&ast::Pat>,
|
||||
width: usize,
|
||||
offset: Indent,
|
||||
@ -635,27 +661,45 @@ fn rewrite_if_else(context: &RewriteContext,
|
||||
}
|
||||
|
||||
let if_block_string = try_opt!(if_block.rewrite(context, width, offset));
|
||||
let mut result = format!("if {} {}", pat_expr_string, if_block_string);
|
||||
|
||||
let between_if_cond = mk_sp(span_after(span, "if", context.codemap),
|
||||
pat.map_or(cond.span.lo,
|
||||
|_| span_before(span, "let", context.codemap)));
|
||||
|
||||
let between_if_cond_comment = extract_comment(between_if_cond, &context, offset, width);
|
||||
|
||||
let after_cond_comment = extract_comment(mk_sp(cond.span.hi, if_block.span.lo),
|
||||
context,
|
||||
offset,
|
||||
width);
|
||||
|
||||
let mut result = format!("if{}{}{}{}",
|
||||
between_if_cond_comment.as_ref().map_or(" ", |str| &**str),
|
||||
pat_expr_string,
|
||||
after_cond_comment.as_ref().map_or(" ", |str| &**str),
|
||||
if_block_string);
|
||||
|
||||
if let Some(else_block) = else_block_opt {
|
||||
let rewrite = match else_block.node {
|
||||
// If the else expression is another if-else expression, prevent it
|
||||
// from being formatted on a single line.
|
||||
ast::Expr_::ExprIfLet(ref pat, ref cond, ref if_block, ref else_block) => {
|
||||
ast::ExprKind::IfLet(ref pat, ref cond, ref if_block, ref next_else_block) => {
|
||||
rewrite_if_else(context,
|
||||
cond,
|
||||
if_block,
|
||||
else_block.as_ref().map(|e| &**e),
|
||||
next_else_block.as_ref().map(|e| &**e),
|
||||
mk_sp(else_block.span.lo, span.hi),
|
||||
Some(pat),
|
||||
width,
|
||||
offset,
|
||||
false)
|
||||
}
|
||||
ast::Expr_::ExprIf(ref cond, ref if_block, ref else_block) => {
|
||||
ast::ExprKind::If(ref cond, ref if_block, ref next_else_block) => {
|
||||
rewrite_if_else(context,
|
||||
cond,
|
||||
if_block,
|
||||
else_block.as_ref().map(|e| &**e),
|
||||
next_else_block.as_ref().map(|e| &**e),
|
||||
mk_sp(else_block.span.lo, span.hi),
|
||||
None,
|
||||
width,
|
||||
offset,
|
||||
@ -664,7 +708,26 @@ fn rewrite_if_else(context: &RewriteContext,
|
||||
_ => else_block.rewrite(context, width, offset),
|
||||
};
|
||||
|
||||
result.push_str(" else ");
|
||||
let between_if_else_block = mk_sp(if_block.span.hi,
|
||||
span_before(mk_sp(if_block.span.hi, else_block.span.lo),
|
||||
"else",
|
||||
context.codemap));
|
||||
let between_if_else_block_comment = extract_comment(between_if_else_block,
|
||||
&context,
|
||||
offset,
|
||||
width);
|
||||
|
||||
let after_else = mk_sp(span_after(mk_sp(if_block.span.hi, else_block.span.lo),
|
||||
"else",
|
||||
context.codemap),
|
||||
else_block.span.lo);
|
||||
let after_else_comment = extract_comment(after_else, &context, offset, width);
|
||||
|
||||
try_opt!(write!(&mut result,
|
||||
"{}else{}",
|
||||
between_if_else_block_comment.as_ref().map_or(" ", |str| &**str),
|
||||
after_else_comment.as_ref().map_or(" ", |str| &**str))
|
||||
.ok());
|
||||
result.push_str(&&try_opt!(rewrite));
|
||||
}
|
||||
|
||||
@ -680,7 +743,7 @@ fn single_line_if_else(context: &RewriteContext,
|
||||
let else_block = try_opt!(else_block_opt);
|
||||
let fixed_cost = "if { } else { }".len();
|
||||
|
||||
if let ast::ExprBlock(ref else_node) = else_block.node {
|
||||
if let ast::ExprKind::Block(ref else_node) = else_block.node {
|
||||
if !is_simple_block(if_node, context.codemap) ||
|
||||
!is_simple_block(else_node, context.codemap) || pat_expr_str.contains('\n') {
|
||||
return None;
|
||||
@ -733,7 +796,7 @@ pub fn is_empty_block(block: &ast::Block, codemap: &CodeMap) -> bool {
|
||||
}
|
||||
|
||||
fn is_unsafe_block(block: &ast::Block) -> bool {
|
||||
if let ast::BlockCheckMode::UnsafeBlock(..) = block.rules {
|
||||
if let ast::BlockCheckMode::Unsafe(..) = block.rules {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@ -864,15 +927,15 @@ fn arm_end_pos(arm: &ast::Arm) -> BytePos {
|
||||
|
||||
fn arm_comma(config: &Config, arm: &ast::Arm, body: &ast::Expr) -> &'static str {
|
||||
if !config.match_wildcard_trailing_comma {
|
||||
if arm.pats.len() == 1 && arm.pats[0].node == ast::PatWild && arm.guard.is_none() {
|
||||
if arm.pats.len() == 1 && arm.pats[0].node == ast::PatKind::Wild && arm.guard.is_none() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
if config.match_block_trailing_comma {
|
||||
","
|
||||
} else if let ast::ExprBlock(ref block) = body.node {
|
||||
if let ast::DefaultBlock = block.rules {
|
||||
} else if let ast::ExprKind::Block(ref block) = body.node {
|
||||
if let ast::BlockCheckMode::Default = block.rules {
|
||||
""
|
||||
} else {
|
||||
","
|
||||
@ -893,9 +956,7 @@ impl Rewrite for ast::Arm {
|
||||
let attr_str = if !attrs.is_empty() {
|
||||
// We only use this visitor for the attributes, should we use it for
|
||||
// more?
|
||||
let mut attr_visitor = FmtVisitor::from_codemap(context.parse_session,
|
||||
context.config,
|
||||
None);
|
||||
let mut attr_visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
|
||||
attr_visitor.block_indent = context.block_indent;
|
||||
attr_visitor.last_pos = attrs[0].span.lo;
|
||||
if attr_visitor.visit_attrs(attrs) {
|
||||
@ -956,12 +1017,9 @@ impl Rewrite for ast::Arm {
|
||||
}
|
||||
|
||||
let body = match **body {
|
||||
ast::Expr { node: ast::ExprBlock(ref block), .. } if !is_unsafe_block(block) &&
|
||||
is_simple_block(block,
|
||||
context.codemap) &&
|
||||
context.config.wrap_match_arms => {
|
||||
block.expr.as_ref().map(|e| &**e).unwrap()
|
||||
}
|
||||
ast::Expr { node: ast::ExprKind::Block(ref block), .. }
|
||||
if !is_unsafe_block(block) && is_simple_block(block, context.codemap) &&
|
||||
context.config.wrap_match_arms => block.expr.as_ref().map(|e| &**e).unwrap(),
|
||||
ref x => x,
|
||||
};
|
||||
|
||||
@ -973,7 +1031,7 @@ impl Rewrite for ast::Arm {
|
||||
let budget = context.config.max_width - line_start - comma.len() - 4;
|
||||
let offset = Indent::new(offset.block_indent, line_start + 4 - offset.block_indent);
|
||||
let rewrite = nop_block_collapse(body.rewrite(context, budget, offset), budget);
|
||||
let is_block = if let ast::ExprBlock(..) = body.node {
|
||||
let is_block = if let ast::ExprKind::Block(..) = body.node {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@ -1121,8 +1179,15 @@ fn rewrite_string_lit(context: &RewriteContext,
|
||||
width: usize,
|
||||
offset: Indent)
|
||||
-> Option<String> {
|
||||
if !context.config.format_strings {
|
||||
return Some(context.snippet(span));
|
||||
let string_lit = context.snippet(span);
|
||||
|
||||
if !context.config.format_strings && !context.config.force_format_strings {
|
||||
return Some(string_lit);
|
||||
}
|
||||
|
||||
if !context.config.force_format_strings &&
|
||||
!string_requires_rewrite(context, span, &string_lit, width, offset) {
|
||||
return Some(string_lit);
|
||||
}
|
||||
|
||||
let fmt = StringFormat {
|
||||
@ -1136,12 +1201,37 @@ fn rewrite_string_lit(context: &RewriteContext,
|
||||
config: context.config,
|
||||
};
|
||||
|
||||
let string_lit = context.snippet(span);
|
||||
let str_lit = &string_lit[1..string_lit.len() - 1]; // Remove the quote characters.
|
||||
// Remove the quote characters.
|
||||
let str_lit = &string_lit[1..string_lit.len() - 1];
|
||||
|
||||
rewrite_string(str_lit, &fmt)
|
||||
}
|
||||
|
||||
fn string_requires_rewrite(context: &RewriteContext,
|
||||
span: Span,
|
||||
string: &str,
|
||||
width: usize,
|
||||
offset: Indent)
|
||||
-> bool {
|
||||
if context.codemap.lookup_char_pos(span.lo).col.0 != offset.width() {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (i, line) in string.lines().enumerate() {
|
||||
if i == 0 {
|
||||
if line.len() > width {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if line.len() > width + offset.width() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn rewrite_call<R>(context: &RewriteContext,
|
||||
callee: &R,
|
||||
args: &[ptr::P<ast::Expr>],
|
||||
@ -1216,8 +1306,8 @@ fn rewrite_call_inner<R>(context: &RewriteContext,
|
||||
// indentation. If its first line fits on one line with the other arguments,
|
||||
// we format the function arguments horizontally.
|
||||
let overflow_last = match args.last().map(|x| &x.node) {
|
||||
Some(&ast::Expr_::ExprClosure(..)) |
|
||||
Some(&ast::Expr_::ExprBlock(..)) if arg_count > 1 => true,
|
||||
Some(&ast::ExprKind::Closure(..)) |
|
||||
Some(&ast::ExprKind::Block(..)) if arg_count > 1 => true,
|
||||
_ => false,
|
||||
} && context.config.chains_overflow_last;
|
||||
|
||||
@ -1311,6 +1401,7 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
|
||||
|
||||
// Foo { a: Foo } - indent is +3, width is -5.
|
||||
let h_budget = width.checked_sub(path_str.len() + 5).unwrap_or(0);
|
||||
// The 1 taken from the v_budget is for the comma.
|
||||
let (indent, v_budget) = match context.config.struct_lit_style {
|
||||
StructLitStyle::Visual => (offset + path_str.len() + 3, h_budget),
|
||||
StructLitStyle::Block => {
|
||||
@ -1355,7 +1446,10 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
|
||||
|item| {
|
||||
match *item {
|
||||
StructLitField::Regular(ref field) => {
|
||||
rewrite_field(inner_context, &field, v_budget, indent)
|
||||
rewrite_field(inner_context,
|
||||
&field,
|
||||
v_budget.checked_sub(1).unwrap_or(0),
|
||||
indent)
|
||||
}
|
||||
StructLitField::Base(ref expr) => {
|
||||
// 2 = ..
|
||||
@ -1441,7 +1535,19 @@ fn rewrite_field(context: &RewriteContext,
|
||||
let expr = field.expr.rewrite(context,
|
||||
try_opt!(width.checked_sub(overhead)),
|
||||
offset + overhead);
|
||||
expr.map(|s| format!("{}: {}", name, s))
|
||||
|
||||
match expr {
|
||||
Some(e) => Some(format!("{}: {}", name, e)),
|
||||
None => {
|
||||
let expr_offset = offset.block_indent(&context.config);
|
||||
let expr = field.expr.rewrite(context,
|
||||
try_opt!(context.config
|
||||
.max_width
|
||||
.checked_sub(expr_offset.width())),
|
||||
expr_offset);
|
||||
expr.map(|s| format!("{}:\n{}{}", name, expr_offset.to_string(&context.config), s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rewrite_tuple<'a, I>(context: &RewriteContext,
|
||||
@ -1559,9 +1665,9 @@ fn rewrite_unary_op(context: &RewriteContext,
|
||||
-> Option<String> {
|
||||
// For some reason, an UnOp is not spanned like BinOp!
|
||||
let operator_str = match *op {
|
||||
ast::UnOp::UnDeref => "*",
|
||||
ast::UnOp::UnNot => "!",
|
||||
ast::UnOp::UnNeg => "-",
|
||||
ast::UnOp::Deref => "*",
|
||||
ast::UnOp::Not => "!",
|
||||
ast::UnOp::Neg => "-",
|
||||
};
|
||||
rewrite_unary_prefix(context, operator_str, expr, width, offset)
|
||||
}
|
||||
@ -1637,8 +1743,8 @@ fn rewrite_expr_addrof(context: &RewriteContext,
|
||||
offset: Indent)
|
||||
-> Option<String> {
|
||||
let operator_str = match mutability {
|
||||
ast::Mutability::MutImmutable => "&",
|
||||
ast::Mutability::MutMutable => "&mut ",
|
||||
ast::Mutability::Immutable => "&",
|
||||
ast::Mutability::Mutable => "&mut ",
|
||||
};
|
||||
rewrite_unary_prefix(context, operator_str, expr, width, offset)
|
||||
}
|
||||
|
118
src/filemap.rs
118
src/filemap.rs
@ -15,11 +15,11 @@ use strings::string_buffer::StringBuffer;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{self, Write, Read, stdout};
|
||||
use std::io::{self, Write, Read, stdout, BufWriter};
|
||||
|
||||
use WriteMode;
|
||||
use config::{NewlineStyle, Config};
|
||||
use rustfmt_diff::{make_diff, print_diff};
|
||||
use config::{NewlineStyle, Config, WriteMode};
|
||||
use rustfmt_diff::{make_diff, print_diff, Mismatch};
|
||||
use checkstyle::{output_header, output_footer, output_checkstyle_file};
|
||||
|
||||
// A map of the files of a crate, with their new content
|
||||
pub type FileMap = HashMap<String, StringBuffer>;
|
||||
@ -31,59 +31,62 @@ pub fn append_newlines(file_map: &mut FileMap) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_all_files(file_map: &FileMap,
|
||||
mode: WriteMode,
|
||||
config: &Config)
|
||||
-> Result<(HashMap<String, String>), io::Error> {
|
||||
let mut result = HashMap::new();
|
||||
pub fn write_all_files<T>(file_map: &FileMap, mut out: T, config: &Config) -> Result<(), io::Error>
|
||||
where T: Write
|
||||
{
|
||||
output_header(&mut out, config.write_mode).ok();
|
||||
for filename in file_map.keys() {
|
||||
let one_result = try!(write_file(&file_map[filename], filename, mode, config));
|
||||
if let Some(r) = one_result {
|
||||
result.insert(filename.clone(), r);
|
||||
}
|
||||
try!(write_file(&file_map[filename], filename, &mut out, config));
|
||||
}
|
||||
output_footer(&mut out, config.write_mode).ok();
|
||||
|
||||
Ok(result)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_file(text: &StringBuffer,
|
||||
filename: &str,
|
||||
mode: WriteMode,
|
||||
config: &Config)
|
||||
-> Result<Option<String>, io::Error> {
|
||||
|
||||
// prints all newlines either as `\n` or as `\r\n`
|
||||
fn write_system_newlines<T>(mut writer: T,
|
||||
// Prints all newlines either as `\n` or as `\r\n`.
|
||||
pub fn write_system_newlines<T>(writer: T,
|
||||
text: &StringBuffer,
|
||||
config: &Config)
|
||||
-> Result<(), io::Error>
|
||||
where T: Write
|
||||
{
|
||||
let style = if config.newline_style == NewlineStyle::Native {
|
||||
if cfg!(windows) {
|
||||
NewlineStyle::Windows
|
||||
} else {
|
||||
NewlineStyle::Unix
|
||||
}
|
||||
} else {
|
||||
config.newline_style
|
||||
};
|
||||
where T: Write
|
||||
{
|
||||
// Buffer output, since we're writing a since char at a time.
|
||||
let mut writer = BufWriter::new(writer);
|
||||
|
||||
match style {
|
||||
NewlineStyle::Unix => write!(writer, "{}", text),
|
||||
NewlineStyle::Windows => {
|
||||
for (c, _) in text.chars() {
|
||||
match c {
|
||||
'\n' => try!(write!(writer, "\r\n")),
|
||||
'\r' => continue,
|
||||
c => try!(write!(writer, "{}", c)),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
NewlineStyle::Native => unreachable!(),
|
||||
let style = if config.newline_style == NewlineStyle::Native {
|
||||
if cfg!(windows) {
|
||||
NewlineStyle::Windows
|
||||
} else {
|
||||
NewlineStyle::Unix
|
||||
}
|
||||
} else {
|
||||
config.newline_style
|
||||
};
|
||||
|
||||
match style {
|
||||
NewlineStyle::Unix => write!(writer, "{}", text),
|
||||
NewlineStyle::Windows => {
|
||||
for (c, _) in text.chars() {
|
||||
match c {
|
||||
'\n' => try!(write!(writer, "\r\n")),
|
||||
'\r' => continue,
|
||||
c => try!(write!(writer, "{}", c)),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
NewlineStyle::Native => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_file<T>(text: &StringBuffer,
|
||||
filename: &str,
|
||||
out: &mut T,
|
||||
config: &Config)
|
||||
-> Result<Option<String>, io::Error>
|
||||
where T: Write
|
||||
{
|
||||
|
||||
fn source_and_formatted_text(text: &StringBuffer,
|
||||
filename: &str,
|
||||
@ -98,7 +101,15 @@ pub fn write_file(text: &StringBuffer,
|
||||
Ok((ori_text, fmt_text))
|
||||
}
|
||||
|
||||
match mode {
|
||||
fn create_diff(filename: &str,
|
||||
text: &StringBuffer,
|
||||
config: &Config)
|
||||
-> Result<Vec<Mismatch>, io::Error> {
|
||||
let (ori, fmt) = try!(source_and_formatted_text(text, filename, config));
|
||||
Ok(make_diff(&ori, &fmt, 3))
|
||||
}
|
||||
|
||||
match config.write_mode {
|
||||
WriteMode::Replace => {
|
||||
if let Ok((ori, fmt)) = source_and_formatted_text(text, filename, config) {
|
||||
if fmt != ori {
|
||||
@ -123,11 +134,6 @@ pub fn write_file(text: &StringBuffer,
|
||||
let file = try!(File::create(filename));
|
||||
try!(write_system_newlines(file, text, config));
|
||||
}
|
||||
WriteMode::NewFile(extn) => {
|
||||
let filename = filename.to_owned() + "." + extn;
|
||||
let file = try!(File::create(&filename));
|
||||
try!(write_system_newlines(file, text, config));
|
||||
}
|
||||
WriteMode::Plain => {
|
||||
let stdout = stdout();
|
||||
let stdout = stdout.lock();
|
||||
@ -146,13 +152,9 @@ pub fn write_file(text: &StringBuffer,
|
||||
|line_num| format!("\nDiff at line {}:", line_num));
|
||||
}
|
||||
}
|
||||
WriteMode::Return => {
|
||||
// io::Write is not implemented for String, working around with
|
||||
// Vec<u8>
|
||||
let mut v = Vec::new();
|
||||
try!(write_system_newlines(&mut v, text, config));
|
||||
// won't panic, we are writing correct utf8
|
||||
return Ok(Some(String::from_utf8(v).unwrap()));
|
||||
WriteMode::Checkstyle => {
|
||||
let diff = try!(create_diff(filename, text, config));
|
||||
try!(output_checkstyle_file(out, filename, diff));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ impl Rewrite for ast::ViewPath {
|
||||
}
|
||||
|
||||
fn rewrite_single_use_list(path_str: String, vpi: &ast::PathListItem) -> String {
|
||||
let path_item_str = if let ast::PathListItem_::PathListIdent{ name, .. } = vpi.node {
|
||||
let path_item_str = if let ast::PathListItemKind::Ident { name, .. } = vpi.node {
|
||||
// A name.
|
||||
if path_str.is_empty() {
|
||||
name.to_string()
|
||||
@ -74,8 +74,8 @@ fn rewrite_single_use_list(path_str: String, vpi: &ast::PathListItem) -> String
|
||||
|
||||
fn rewrite_path_item(vpi: &&ast::PathListItem) -> Option<String> {
|
||||
let path_item_str = match vpi.node {
|
||||
ast::PathListItem_::PathListIdent{ name, .. } => name.to_string(),
|
||||
ast::PathListItem_::PathListMod{ .. } => "self".to_owned(),
|
||||
ast::PathListItemKind::Ident { name, .. } => name.to_string(),
|
||||
ast::PathListItemKind::Mod { .. } => "self".to_owned(),
|
||||
};
|
||||
|
||||
Some(append_alias(path_item_str, vpi))
|
||||
@ -83,8 +83,8 @@ fn rewrite_path_item(vpi: &&ast::PathListItem) -> Option<String> {
|
||||
|
||||
fn append_alias(path_item_str: String, vpi: &ast::PathListItem) -> String {
|
||||
match vpi.node {
|
||||
ast::PathListItem_::PathListIdent{ rename: Some(rename), .. } |
|
||||
ast::PathListItem_::PathListMod{ rename: Some(rename), .. } => {
|
||||
ast::PathListItemKind::Ident { rename: Some(rename), .. } |
|
||||
ast::PathListItemKind::Mod { rename: Some(rename), .. } => {
|
||||
format!("{} as {}", path_item_str, rename)
|
||||
}
|
||||
_ => path_item_str,
|
||||
|
@ -15,8 +15,8 @@
|
||||
use std::fmt;
|
||||
pub use config::ReportTactic;
|
||||
|
||||
static TO_DO_CHARS: &'static [char] = &['T', 'O', 'D', 'O'];
|
||||
static FIX_ME_CHARS: &'static [char] = &['F', 'I', 'X', 'M', 'E'];
|
||||
const TO_DO_CHARS: &'static [char] = &['T', 'O', 'D', 'O'];
|
||||
const FIX_ME_CHARS: &'static [char] = &['F', 'I', 'X', 'M', 'E'];
|
||||
|
||||
// Enabled implementation detail is here because it is
|
||||
// irrelevant outside the issues module
|
||||
|
116
src/items.rs
116
src/items.rs
@ -21,10 +21,12 @@ use comment::{FindUncommented, contains_comment};
|
||||
use visitor::FmtVisitor;
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
use config::{Config, BlockIndentStyle, Density, ReturnIndent, BraceStyle, StructLitStyle};
|
||||
use syntax::codemap;
|
||||
|
||||
use syntax::{ast, abi};
|
||||
use syntax::codemap::{Span, BytePos, mk_sp};
|
||||
use syntax::parse::token;
|
||||
use syntax::ast::ImplItem;
|
||||
|
||||
// Statements of the form
|
||||
// let pat: ty = init;
|
||||
@ -107,7 +109,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
let span = mk_sp(item.span.lo, item.span.hi - BytePos(1));
|
||||
|
||||
match item.node {
|
||||
ast::ForeignItem_::ForeignItemFn(ref fn_decl, ref generics) => {
|
||||
ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => {
|
||||
let indent = self.block_indent;
|
||||
let rewrite = rewrite_fn_base(&self.get_context(),
|
||||
indent,
|
||||
@ -133,7 +135,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
None => self.format_missing(item.span.hi),
|
||||
}
|
||||
}
|
||||
ast::ForeignItem_::ForeignItemStatic(ref ty, is_mutable) => {
|
||||
ast::ForeignItemKind::Static(ref ty, is_mutable) => {
|
||||
// FIXME(#21): we're dropping potential comments in between the
|
||||
// function keywords here.
|
||||
let mut_str = if is_mutable {
|
||||
@ -180,6 +182,10 @@ impl<'a> FmtVisitor<'a> {
|
||||
let mut newline_brace = newline_for_brace(self.config, &generics.where_clause);
|
||||
let context = self.get_context();
|
||||
|
||||
let block_snippet = self.snippet(codemap::mk_sp(block.span.lo, block.span.hi));
|
||||
let has_body = !block_snippet[1..block_snippet.len() - 1].trim().is_empty() ||
|
||||
!context.config.fn_empty_single_line;
|
||||
|
||||
let (mut result, force_newline_brace) = try_opt!(rewrite_fn_base(&context,
|
||||
indent,
|
||||
ident,
|
||||
@ -192,7 +198,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
vis,
|
||||
span,
|
||||
newline_brace,
|
||||
true));
|
||||
has_body));
|
||||
|
||||
if self.config.fn_brace_style != BraceStyle::AlwaysNextLine && !result.contains('\n') {
|
||||
newline_brace = false;
|
||||
@ -434,12 +440,12 @@ impl<'a> FmtVisitor<'a> {
|
||||
}
|
||||
|
||||
pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) -> Option<String> {
|
||||
if let ast::Item_::ItemImpl(unsafety,
|
||||
polarity,
|
||||
ref generics,
|
||||
ref trait_ref,
|
||||
ref self_ty,
|
||||
ref items) = item.node {
|
||||
if let ast::ItemKind::Impl(unsafety,
|
||||
polarity,
|
||||
ref generics,
|
||||
ref trait_ref,
|
||||
ref self_ty,
|
||||
ref items) = item.node {
|
||||
let mut result = String::new();
|
||||
result.push_str(format_visibility(item.vis));
|
||||
result.push_str(format_unsafety(unsafety));
|
||||
@ -484,9 +490,20 @@ pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) -
|
||||
where_budget,
|
||||
context.config.where_density,
|
||||
"{",
|
||||
true,
|
||||
None));
|
||||
if !where_clause_str.contains('\n') &&
|
||||
result.len() + where_clause_str.len() + offset.width() > context.config.max_width {
|
||||
|
||||
if try_opt!(is_impl_single_line(context, &items, &result, &where_clause_str, &item)) {
|
||||
result.push_str(&where_clause_str);
|
||||
if where_clause_str.contains('\n') {
|
||||
result.push_str("\n{\n}");
|
||||
} else {
|
||||
result.push_str(" {}");
|
||||
}
|
||||
return Some(result);
|
||||
}
|
||||
|
||||
if !where_clause_str.is_empty() && !where_clause_str.contains('\n') {
|
||||
result.push('\n');
|
||||
let width = context.block_indent.width() + context.config.tab_spaces - 1;
|
||||
let where_indent = Indent::new(0, width);
|
||||
@ -505,13 +522,14 @@ pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) -
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.push('{');
|
||||
|
||||
let snippet = context.snippet(item.span);
|
||||
let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
|
||||
|
||||
if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
|
||||
let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config, None);
|
||||
let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
|
||||
visitor.block_indent = context.block_indent.block_indent(context.config);
|
||||
visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
|
||||
|
||||
@ -531,13 +549,31 @@ pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) -
|
||||
result.push_str(&outer_indent_str);
|
||||
}
|
||||
|
||||
if result.chars().last().unwrap() == '{' {
|
||||
result.push('\n');
|
||||
}
|
||||
result.push('}');
|
||||
|
||||
Some(result)
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
fn is_impl_single_line(context: &RewriteContext,
|
||||
items: &Vec<ImplItem>,
|
||||
result: &str,
|
||||
where_clause_str: &str,
|
||||
item: &ast::Item)
|
||||
-> Option<bool> {
|
||||
let snippet = context.snippet(item.span);
|
||||
let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
|
||||
|
||||
Some(context.config.impl_empty_single_line && items.is_empty() &&
|
||||
result.len() + where_clause_str.len() <= context.config.max_width &&
|
||||
!contains_comment(&snippet[open_pos..]))
|
||||
}
|
||||
|
||||
pub fn format_struct(context: &RewriteContext,
|
||||
item_name: &str,
|
||||
ident: ast::Ident,
|
||||
@ -573,7 +609,7 @@ pub fn format_struct(context: &RewriteContext,
|
||||
}
|
||||
|
||||
pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent) -> Option<String> {
|
||||
if let ast::Item_::ItemTrait(unsafety, ref generics, ref type_param_bounds, ref trait_items) =
|
||||
if let ast::ItemKind::Trait(unsafety, ref generics, ref type_param_bounds, ref trait_items) =
|
||||
item.node {
|
||||
let mut result = String::new();
|
||||
let header = format!("{}{}trait {}",
|
||||
@ -619,6 +655,7 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
|
||||
where_budget,
|
||||
context.config.where_density,
|
||||
"{",
|
||||
context.config.where_trailing_comma,
|
||||
None));
|
||||
if !where_clause_str.contains('\n') &&
|
||||
result.len() + where_clause_str.len() + offset.width() > context.config.max_width {
|
||||
@ -650,7 +687,7 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
|
||||
let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
|
||||
|
||||
if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
|
||||
let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config, None);
|
||||
let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
|
||||
visitor.block_indent = context.block_indent.block_indent(context.config);
|
||||
visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
|
||||
|
||||
@ -732,7 +769,7 @@ fn format_struct_struct(context: &RewriteContext,
|
||||
}
|
||||
|
||||
let item_indent = offset.block_indent(context.config);
|
||||
// 2 = ","
|
||||
// 1 = ","
|
||||
let item_budget = try_opt!(context.config.max_width.checked_sub(item_indent.width() + 1));
|
||||
|
||||
let items = itemize_list(context.codemap,
|
||||
@ -806,6 +843,7 @@ fn format_tuple_struct(context: &RewriteContext,
|
||||
where_budget,
|
||||
Density::Compressed,
|
||||
";",
|
||||
false,
|
||||
None))
|
||||
}
|
||||
None => "".to_owned(),
|
||||
@ -887,6 +925,7 @@ pub fn rewrite_type_alias(context: &RewriteContext,
|
||||
where_budget,
|
||||
context.config.where_density,
|
||||
"=",
|
||||
false,
|
||||
Some(span.hi)));
|
||||
result.push_str(&where_clause_str);
|
||||
result.push_str(" = ");
|
||||
@ -985,15 +1024,15 @@ pub fn rewrite_static(prefix: &str,
|
||||
impl Rewrite for ast::FunctionRetTy {
|
||||
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
|
||||
match *self {
|
||||
ast::FunctionRetTy::DefaultReturn(_) => Some(String::new()),
|
||||
ast::FunctionRetTy::NoReturn(_) => {
|
||||
ast::FunctionRetTy::Default(_) => Some(String::new()),
|
||||
ast::FunctionRetTy::None(_) => {
|
||||
if width >= 4 {
|
||||
Some("-> !".to_owned())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
ast::FunctionRetTy::Return(ref ty) => {
|
||||
ast::FunctionRetTy::Ty(ref ty) => {
|
||||
let inner_width = try_opt!(width.checked_sub(3));
|
||||
ty.rewrite(context, inner_width, offset + 3).map(|r| format!("-> {}", r))
|
||||
}
|
||||
@ -1006,7 +1045,7 @@ impl Rewrite for ast::Arg {
|
||||
if is_named_arg(self) {
|
||||
let mut result = try_opt!(self.pat.rewrite(context, width, offset));
|
||||
|
||||
if self.ty.node != ast::Ty_::TyInfer {
|
||||
if self.ty.node != ast::TyKind::Infer {
|
||||
result.push_str(": ");
|
||||
let max_width = try_opt!(width.checked_sub(result.len()));
|
||||
let ty_str = try_opt!(self.ty.rewrite(context, max_width, offset + result.len()));
|
||||
@ -1025,7 +1064,7 @@ fn rewrite_explicit_self(explicit_self: &ast::ExplicitSelf,
|
||||
context: &RewriteContext)
|
||||
-> Option<String> {
|
||||
match explicit_self.node {
|
||||
ast::ExplicitSelf_::SelfRegion(lt, m, _) => {
|
||||
ast::SelfKind::Region(lt, m, _) => {
|
||||
let mut_str = format_mutability(m);
|
||||
match lt {
|
||||
Some(ref l) => {
|
||||
@ -1037,7 +1076,7 @@ fn rewrite_explicit_self(explicit_self: &ast::ExplicitSelf,
|
||||
None => Some(format!("&{}self", mut_str)),
|
||||
}
|
||||
}
|
||||
ast::ExplicitSelf_::SelfExplicit(ref ty, _) => {
|
||||
ast::SelfKind::Explicit(ref ty, _) => {
|
||||
assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty.");
|
||||
|
||||
let mutability = explicit_self_mutability(&args[0]);
|
||||
@ -1045,7 +1084,7 @@ fn rewrite_explicit_self(explicit_self: &ast::ExplicitSelf,
|
||||
|
||||
Some(format!("{}self: {}", format_mutability(mutability), type_str))
|
||||
}
|
||||
ast::ExplicitSelf_::SelfValue(_) => {
|
||||
ast::SelfKind::Value(_) => {
|
||||
assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty.");
|
||||
|
||||
let mutability = explicit_self_mutability(&args[0]);
|
||||
@ -1059,7 +1098,7 @@ fn rewrite_explicit_self(explicit_self: &ast::ExplicitSelf,
|
||||
// Hacky solution caused by absence of `Mutability` in `SelfValue` and
|
||||
// `SelfExplicit` variants of `ast::ExplicitSelf_`.
|
||||
fn explicit_self_mutability(arg: &ast::Arg) -> ast::Mutability {
|
||||
if let ast::Pat_::PatIdent(ast::BindingMode::BindByValue(mutability), _, _) = arg.pat.node {
|
||||
if let ast::PatKind::Ident(ast::BindingMode::ByValue(mutability), _, _) = arg.pat.node {
|
||||
mutability
|
||||
} else {
|
||||
unreachable!()
|
||||
@ -1076,13 +1115,13 @@ pub fn span_lo_for_arg(arg: &ast::Arg) -> BytePos {
|
||||
|
||||
pub fn span_hi_for_arg(arg: &ast::Arg) -> BytePos {
|
||||
match arg.ty.node {
|
||||
ast::Ty_::TyInfer if is_named_arg(arg) => arg.pat.span.hi,
|
||||
ast::TyKind::Infer if is_named_arg(arg) => arg.pat.span.hi,
|
||||
_ => arg.ty.span.hi,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_named_arg(arg: &ast::Arg) -> bool {
|
||||
if let ast::Pat_::PatIdent(_, ident, _) = arg.pat.node {
|
||||
if let ast::PatKind::Ident(_, ident, _) = arg.pat.node {
|
||||
ident.node != token::special_idents::invalid
|
||||
} else {
|
||||
true
|
||||
@ -1091,9 +1130,9 @@ pub fn is_named_arg(arg: &ast::Arg) -> bool {
|
||||
|
||||
fn span_for_return(ret: &ast::FunctionRetTy) -> Span {
|
||||
match *ret {
|
||||
ast::FunctionRetTy::NoReturn(ref span) |
|
||||
ast::FunctionRetTy::DefaultReturn(ref span) => span.clone(),
|
||||
ast::FunctionRetTy::Return(ref ty) => ty.span,
|
||||
ast::FunctionRetTy::None(ref span) |
|
||||
ast::FunctionRetTy::Default(ref span) => span.clone(),
|
||||
ast::FunctionRetTy::Ty(ref ty) => ty.span,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1145,13 +1184,14 @@ fn rewrite_fn_base(context: &RewriteContext,
|
||||
let mut result = String::with_capacity(1024);
|
||||
// Vis unsafety abi.
|
||||
result.push_str(format_visibility(vis));
|
||||
result.push_str(::utils::format_unsafety(unsafety));
|
||||
|
||||
if let ast::Constness::Const = constness {
|
||||
result.push_str("const ");
|
||||
}
|
||||
|
||||
if abi != abi::Rust {
|
||||
result.push_str(::utils::format_unsafety(unsafety));
|
||||
|
||||
if abi != abi::Abi::Rust {
|
||||
result.push_str(&::utils::format_abi(abi));
|
||||
}
|
||||
|
||||
@ -1301,7 +1341,7 @@ fn rewrite_fn_base(context: &RewriteContext,
|
||||
(context.config.fn_args_layout == StructLitStyle::Block &&
|
||||
ret_str.is_empty()) ||
|
||||
(context.config.where_density == Density::CompressedIfEmpty &&
|
||||
!has_body) {
|
||||
!has_body && !result.contains('\n')) {
|
||||
Density::Compressed
|
||||
} else {
|
||||
Density::Tall
|
||||
@ -1317,7 +1357,14 @@ fn rewrite_fn_base(context: &RewriteContext,
|
||||
where_budget,
|
||||
where_density,
|
||||
"{",
|
||||
has_body,
|
||||
Some(span.hi)));
|
||||
|
||||
if last_line_width(&result) + where_clause_str.len() > context.config.max_width &&
|
||||
!where_clause_str.contains('\n') {
|
||||
result.push('\n');
|
||||
}
|
||||
|
||||
result.push_str(&where_clause_str);
|
||||
|
||||
Some((result, force_new_line_for_brace))
|
||||
@ -1559,7 +1606,7 @@ fn rewrite_trait_bounds(context: &RewriteContext,
|
||||
.join(" + ");
|
||||
|
||||
let mut result = String::new();
|
||||
result.push_str(" : ");
|
||||
result.push_str(": ");
|
||||
result.push_str(&bound_str);
|
||||
Some(result)
|
||||
}
|
||||
@ -1572,6 +1619,7 @@ fn rewrite_where_clause(context: &RewriteContext,
|
||||
width: usize,
|
||||
density: Density,
|
||||
terminator: &str,
|
||||
allow_trailing_comma: bool,
|
||||
span_end: Option<BytePos>)
|
||||
-> Option<String> {
|
||||
if where_clause.predicates.is_empty() {
|
||||
@ -1611,11 +1659,12 @@ fn rewrite_where_clause(context: &RewriteContext,
|
||||
// FIXME: we don't need to collect here if the where_layout isn't
|
||||
// HorizontalVertical.
|
||||
let tactic = definitive_tactic(&item_vec, context.config.where_layout, budget);
|
||||
let use_trailing_comma = allow_trailing_comma && context.config.where_trailing_comma;
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: tactic,
|
||||
separator: ",",
|
||||
trailing_separator: SeparatorTactic::Never,
|
||||
trailing_separator: SeparatorTactic::from_bool(use_trailing_comma),
|
||||
indent: offset,
|
||||
width: budget,
|
||||
ends_with_newline: true,
|
||||
@ -1677,6 +1726,7 @@ fn format_generics(context: &RewriteContext,
|
||||
budget,
|
||||
Density::Tall,
|
||||
terminator,
|
||||
true,
|
||||
Some(span.hi)));
|
||||
result.push_str(&where_clause_str);
|
||||
if !force_same_line_brace &&
|
||||
|
105
src/lib.rs
105
src/lib.rs
@ -26,15 +26,17 @@ extern crate diff;
|
||||
extern crate term;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{mk_sp, Span};
|
||||
use syntax::diagnostic::{EmitterWriter, Handler};
|
||||
use syntax::codemap::{mk_sp, CodeMap, Span};
|
||||
use syntax::errors::Handler;
|
||||
use syntax::errors::emitter::{ColorConfig, EmitterWriter};
|
||||
use syntax::parse::{self, ParseSess};
|
||||
|
||||
use std::io::stdout;
|
||||
use std::ops::{Add, Sub};
|
||||
use std::path::Path;
|
||||
use std::rc::Rc;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use issues::{BadIssueSeeker, Issue};
|
||||
use filemap::FileMap;
|
||||
@ -46,6 +48,7 @@ mod utils;
|
||||
pub mod config;
|
||||
pub mod filemap;
|
||||
mod visitor;
|
||||
mod checkstyle;
|
||||
mod items;
|
||||
mod missed_spans;
|
||||
mod lists;
|
||||
@ -187,42 +190,6 @@ impl Sub<usize> for Indent {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum WriteMode {
|
||||
// Backsup the original file and overwrites the orignal.
|
||||
Replace,
|
||||
// Overwrites original file without backup.
|
||||
Overwrite,
|
||||
// str is the extension of the new file.
|
||||
NewFile(&'static str),
|
||||
// Write the output to stdout.
|
||||
Display,
|
||||
// Write the diff to stdout.
|
||||
Diff,
|
||||
// Return the result as a mapping from filenames to Strings.
|
||||
Return,
|
||||
// Display how much of the input file was processed
|
||||
Coverage,
|
||||
// Unfancy stdout
|
||||
Plain,
|
||||
}
|
||||
|
||||
impl FromStr for WriteMode {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"replace" => Ok(WriteMode::Replace),
|
||||
"display" => Ok(WriteMode::Display),
|
||||
"overwrite" => Ok(WriteMode::Overwrite),
|
||||
"diff" => Ok(WriteMode::Diff),
|
||||
"coverage" => Ok(WriteMode::Coverage),
|
||||
"plain" => Ok(WriteMode::Plain),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ErrorKind {
|
||||
// Line has exceeded character limit
|
||||
LineOverflow,
|
||||
@ -299,8 +266,7 @@ impl fmt::Display for FormatReport {
|
||||
fn fmt_ast(krate: &ast::Crate,
|
||||
parse_session: &ParseSess,
|
||||
main_file: &Path,
|
||||
config: &Config,
|
||||
mode: WriteMode)
|
||||
config: &Config)
|
||||
-> FileMap {
|
||||
let mut file_map = FileMap::new();
|
||||
for (path, module) in modules::list_files(krate, parse_session.codemap()) {
|
||||
@ -311,7 +277,7 @@ fn fmt_ast(krate: &ast::Crate,
|
||||
if config.verbose {
|
||||
println!("Formatting {}", path);
|
||||
}
|
||||
let mut visitor = FmtVisitor::from_codemap(parse_session, config, Some(mode));
|
||||
let mut visitor = FmtVisitor::from_codemap(parse_session, config);
|
||||
visitor.format_separate_mod(module);
|
||||
file_map.insert(path.to_owned(), visitor.buffer);
|
||||
}
|
||||
@ -401,24 +367,32 @@ pub fn fmt_lines(file_map: &mut FileMap, config: &Config) -> FormatReport {
|
||||
report
|
||||
}
|
||||
|
||||
pub fn format_string(input: String, config: &Config, mode: WriteMode) -> FileMap {
|
||||
pub fn format_string(input: String, config: &Config) -> FileMap {
|
||||
let path = "stdin";
|
||||
let mut parse_session = ParseSess::new();
|
||||
let codemap = Rc::new(CodeMap::new());
|
||||
|
||||
let tty_handler = Handler::with_tty_emitter(ColorConfig::Auto,
|
||||
None,
|
||||
true,
|
||||
false,
|
||||
codemap.clone());
|
||||
let mut parse_session = ParseSess::with_span_handler(tty_handler, codemap.clone());
|
||||
|
||||
let krate = parse::parse_crate_from_source_str(path.to_owned(),
|
||||
input,
|
||||
Vec::new(),
|
||||
&parse_session);
|
||||
|
||||
// Suppress error output after parsing.
|
||||
let emitter = Box::new(EmitterWriter::new(Box::new(Vec::new()), None));
|
||||
parse_session.span_diagnostic.handler = Handler::with_emitter(false, emitter);
|
||||
let silent_emitter = Box::new(EmitterWriter::new(Box::new(Vec::new()), None, codemap.clone()));
|
||||
parse_session.span_diagnostic = Handler::with_emitter(true, false, silent_emitter);
|
||||
|
||||
// FIXME: we still use a FileMap even though we only have
|
||||
// one file, because fmt_lines requires a FileMap
|
||||
let mut file_map = FileMap::new();
|
||||
|
||||
// do the actual formatting
|
||||
let mut visitor = FmtVisitor::from_codemap(&parse_session, config, Some(mode));
|
||||
let mut visitor = FmtVisitor::from_codemap(&parse_session, config);
|
||||
visitor.format_separate_mod(&krate.module);
|
||||
|
||||
// append final newline
|
||||
@ -428,15 +402,23 @@ pub fn format_string(input: String, config: &Config, mode: WriteMode) -> FileMap
|
||||
file_map
|
||||
}
|
||||
|
||||
pub fn format(file: &Path, config: &Config, mode: WriteMode) -> FileMap {
|
||||
let mut parse_session = ParseSess::new();
|
||||
pub fn format(file: &Path, config: &Config) -> FileMap {
|
||||
let codemap = Rc::new(CodeMap::new());
|
||||
|
||||
let tty_handler = Handler::with_tty_emitter(ColorConfig::Auto,
|
||||
None,
|
||||
true,
|
||||
false,
|
||||
codemap.clone());
|
||||
let mut parse_session = ParseSess::with_span_handler(tty_handler, codemap.clone());
|
||||
|
||||
let krate = parse::parse_crate_from_file(file, Vec::new(), &parse_session);
|
||||
|
||||
// Suppress error output after parsing.
|
||||
let emitter = Box::new(EmitterWriter::new(Box::new(Vec::new()), None));
|
||||
parse_session.span_diagnostic.handler = Handler::with_emitter(false, emitter);
|
||||
let silent_emitter = Box::new(EmitterWriter::new(Box::new(Vec::new()), None, codemap.clone()));
|
||||
parse_session.span_diagnostic = Handler::with_emitter(true, false, silent_emitter);
|
||||
|
||||
let mut file_map = fmt_ast(&krate, &parse_session, file, config, mode);
|
||||
let mut file_map = fmt_ast(&krate, &parse_session, file, config);
|
||||
|
||||
// For some reason, the codemap does not include terminating
|
||||
// newlines so we must add one on for each file. This is sad.
|
||||
@ -445,16 +427,12 @@ pub fn format(file: &Path, config: &Config, mode: WriteMode) -> FileMap {
|
||||
file_map
|
||||
}
|
||||
|
||||
// args are the arguments passed on the command line, generally passed through
|
||||
// to the compiler.
|
||||
// write_mode determines what happens to the result of running rustfmt, see
|
||||
// WriteMode.
|
||||
pub fn run(file: &Path, write_mode: WriteMode, config: &Config) {
|
||||
let mut result = format(file, config, write_mode);
|
||||
pub fn run(file: &Path, config: &Config) {
|
||||
let mut result = format(file, config);
|
||||
|
||||
print!("{}", fmt_lines(&mut result, config));
|
||||
|
||||
let write_result = filemap::write_all_files(&result, write_mode, config);
|
||||
let out = stdout();
|
||||
let write_result = filemap::write_all_files(&result, out, config);
|
||||
|
||||
if let Err(msg) = write_result {
|
||||
println!("Error writing files: {}", msg);
|
||||
@ -462,11 +440,12 @@ pub fn run(file: &Path, write_mode: WriteMode, config: &Config) {
|
||||
}
|
||||
|
||||
// Similar to run, but takes an input String instead of a file to format
|
||||
pub fn run_from_stdin(input: String, mode: WriteMode, config: &Config) {
|
||||
let mut result = format_string(input, config, mode);
|
||||
pub fn run_from_stdin(input: String, config: &Config) {
|
||||
let mut result = format_string(input, config);
|
||||
fmt_lines(&mut result, config);
|
||||
|
||||
let write_result = filemap::write_file(&result["stdin"], "stdin", mode, config);
|
||||
let mut out = stdout();
|
||||
let write_result = filemap::write_file(&result["stdin"], "stdin", &mut out, config);
|
||||
|
||||
if let Err(msg) = write_result {
|
||||
panic!("Error writing to stdout: {}", msg);
|
||||
|
@ -30,10 +30,10 @@ use expr::{rewrite_call, rewrite_array};
|
||||
use comment::FindUncommented;
|
||||
use utils::{wrap_str, span_after};
|
||||
|
||||
static FORCED_BRACKET_MACROS: &'static [&'static str] = &["vec!"];
|
||||
const FORCED_BRACKET_MACROS: &'static [&'static str] = &["vec!"];
|
||||
|
||||
// FIXME: use the enum from libsyntax?
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum MacroStyle {
|
||||
Parens,
|
||||
Brackets,
|
||||
@ -63,9 +63,7 @@ pub fn rewrite_macro(mac: &ast::Mac,
|
||||
original_style
|
||||
};
|
||||
|
||||
if let MacroStyle::Braces = style {
|
||||
return None;
|
||||
} else if mac.node.tts.is_empty() {
|
||||
if mac.node.tts.is_empty() {
|
||||
return if let MacroStyle::Parens = style {
|
||||
Some(format!("{}()", macro_name))
|
||||
} else {
|
||||
@ -76,22 +74,24 @@ pub fn rewrite_macro(mac: &ast::Mac,
|
||||
let mut parser = tts_to_parser(context.parse_session, mac.node.tts.clone(), Vec::new());
|
||||
let mut expr_vec = Vec::new();
|
||||
|
||||
loop {
|
||||
expr_vec.push(match parser.parse_expr() {
|
||||
Ok(expr) => expr,
|
||||
Err(..) => return None,
|
||||
});
|
||||
if MacroStyle::Braces != style {
|
||||
loop {
|
||||
expr_vec.push(match parser.parse_expr() {
|
||||
Ok(expr) => expr,
|
||||
Err(..) => return None,
|
||||
});
|
||||
|
||||
match parser.token {
|
||||
Token::Eof => break,
|
||||
Token::Comma => (),
|
||||
_ => return None,
|
||||
}
|
||||
match parser.token {
|
||||
Token::Eof => break,
|
||||
Token::Comma => (),
|
||||
_ => return None,
|
||||
}
|
||||
|
||||
let _ = parser.bump();
|
||||
let _ = parser.bump();
|
||||
|
||||
if parser.token == Token::Eof {
|
||||
return None;
|
||||
if parser.token == Token::Eof {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use WriteMode;
|
||||
use config::WriteMode;
|
||||
use visitor::FmtVisitor;
|
||||
use syntax::codemap::{self, BytePos, Span, Pos};
|
||||
use comment::{CodeCharKind, CommentCodeSlices, rewrite_comment};
|
||||
@ -103,14 +103,9 @@ impl<'a> FmtVisitor<'a> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
let replaced = match self.write_mode {
|
||||
Some(mode) => {
|
||||
match mode {
|
||||
WriteMode::Coverage => replace_chars(old_snippet),
|
||||
_ => old_snippet.to_owned(),
|
||||
}
|
||||
}
|
||||
None => old_snippet.to_owned(),
|
||||
let replaced = match self.config.write_mode {
|
||||
WriteMode::Coverage => replace_chars(old_snippet),
|
||||
_ => old_snippet.to_owned(),
|
||||
};
|
||||
let snippet = &*replaced;
|
||||
|
||||
@ -147,11 +142,11 @@ impl<'a> FmtVisitor<'a> {
|
||||
if let Some('/') = subslice.chars().skip(1).next() {
|
||||
// Add a newline after line comments
|
||||
self.buffer.push_str("\n");
|
||||
} else if line_start < snippet.len() {
|
||||
} else if line_start <= snippet.len() {
|
||||
// For other comments add a newline if there isn't one at the end already
|
||||
let c = snippet[line_start..].chars().next().unwrap();
|
||||
if c != '\n' && c != '\r' {
|
||||
self.buffer.push_str("\n");
|
||||
match snippet[line_start..].chars().next() {
|
||||
Some('\n') | Some('\r') => (),
|
||||
_ => self.buffer.push_str("\n"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ fn list_submodules<'a>(module: &'a ast::Mod,
|
||||
result: &mut HashMap<PathBuf, &'a ast::Mod>) {
|
||||
debug!("list_submodules: search_dir: {:?}", search_dir);
|
||||
for item in &module.items {
|
||||
if let ast::ItemMod(ref sub_mod) = item.node {
|
||||
if let ast::ItemKind::Mod(ref sub_mod) = item.node {
|
||||
if !utils::contains_skip(&item.attrs) {
|
||||
let is_internal = codemap.span_to_filename(item.span) ==
|
||||
codemap.span_to_filename(sub_mod.inner);
|
||||
|
180
src/patterns.rs
180
src/patterns.rs
@ -15,80 +15,160 @@ use lists::{format_item_list, itemize_list};
|
||||
use expr::{rewrite_unary_prefix, rewrite_pair, rewrite_tuple};
|
||||
use types::rewrite_path;
|
||||
|
||||
use syntax::ast::{BindingMode, Pat, Pat_};
|
||||
use syntax::ast::{BindingMode, Pat, PatKind, FieldPat};
|
||||
|
||||
// FIXME(#18): implement pattern formatting.
|
||||
impl Rewrite for Pat {
|
||||
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
|
||||
match self.node {
|
||||
Pat_::PatBox(ref pat) => rewrite_unary_prefix(context, "box ", &**pat, width, offset),
|
||||
Pat_::PatIdent(binding_mode, ident, None) => {
|
||||
PatKind::Box(ref pat) => rewrite_unary_prefix(context, "box ", &**pat, width, offset),
|
||||
PatKind::Ident(binding_mode, ident, ref sub_pat) => {
|
||||
let (prefix, mutability) = match binding_mode {
|
||||
BindingMode::BindByRef(mutability) => ("ref ", mutability),
|
||||
BindingMode::BindByValue(mutability) => ("", mutability),
|
||||
BindingMode::ByRef(mutability) => ("ref ", mutability),
|
||||
BindingMode::ByValue(mutability) => ("", mutability),
|
||||
};
|
||||
let mut_infix = format_mutability(mutability);
|
||||
let result = format!("{}{}{}", prefix, mut_infix, ident.node);
|
||||
let id_str = ident.node.to_string();
|
||||
|
||||
let sub_pat = match *sub_pat {
|
||||
Some(ref p) => {
|
||||
// 3 - ` @ `.
|
||||
let width = try_opt!(width.checked_sub(prefix.len() + mut_infix.len() +
|
||||
id_str.len() +
|
||||
3));
|
||||
format!(" @ {}", try_opt!(p.rewrite(context, width, offset)))
|
||||
}
|
||||
None => "".to_owned(),
|
||||
};
|
||||
|
||||
let result = format!("{}{}{}{}", prefix, mut_infix, id_str, sub_pat);
|
||||
wrap_str(result, context.config.max_width, width, offset)
|
||||
}
|
||||
Pat_::PatWild => {
|
||||
PatKind::Wild => {
|
||||
if 1 <= width {
|
||||
Some("_".to_owned())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Pat_::PatQPath(ref q_self, ref path) => {
|
||||
PatKind::QPath(ref q_self, ref path) => {
|
||||
rewrite_path(context, true, Some(q_self), path, width, offset)
|
||||
}
|
||||
Pat_::PatRange(ref lhs, ref rhs) => {
|
||||
PatKind::Range(ref lhs, ref rhs) => {
|
||||
rewrite_pair(&**lhs, &**rhs, "", "...", "", context, width, offset)
|
||||
}
|
||||
Pat_::PatRegion(ref pat, mutability) => {
|
||||
PatKind::Ref(ref pat, mutability) => {
|
||||
let prefix = format!("&{}", format_mutability(mutability));
|
||||
rewrite_unary_prefix(context, &prefix, &**pat, width, offset)
|
||||
}
|
||||
Pat_::PatTup(ref items) => {
|
||||
PatKind::Tup(ref items) => {
|
||||
rewrite_tuple(context,
|
||||
items.iter().map(|x| &**x),
|
||||
self.span,
|
||||
width,
|
||||
offset)
|
||||
}
|
||||
Pat_::PatEnum(ref path, Some(ref pat_vec)) => {
|
||||
let path_str = try_opt!(::types::rewrite_path(context,
|
||||
true,
|
||||
None,
|
||||
path,
|
||||
width,
|
||||
offset));
|
||||
PatKind::Path(ref path) => rewrite_path(context, true, None, path, width, offset),
|
||||
PatKind::TupleStruct(ref path, ref pat_vec) => {
|
||||
let path_str = try_opt!(rewrite_path(context, true, None, path, width, offset));
|
||||
|
||||
if pat_vec.is_empty() {
|
||||
Some(path_str)
|
||||
} else {
|
||||
// 1 = (
|
||||
let width = try_opt!(width.checked_sub(path_str.len() + 1));
|
||||
let offset = offset + path_str.len() + 1;
|
||||
let items = itemize_list(context.codemap,
|
||||
pat_vec.iter(),
|
||||
")",
|
||||
|item| item.span.lo,
|
||||
|item| item.span.hi,
|
||||
|item| item.rewrite(context, width, offset),
|
||||
span_after(self.span, "(", context.codemap),
|
||||
self.span.hi);
|
||||
Some(format!("{}({})",
|
||||
path_str,
|
||||
try_opt!(format_item_list(items, width, offset, context.config))))
|
||||
match *pat_vec {
|
||||
Some(ref pat_vec) => {
|
||||
if pat_vec.is_empty() {
|
||||
Some(path_str)
|
||||
} else {
|
||||
// 1 = (
|
||||
let width = try_opt!(width.checked_sub(path_str.len() + 1));
|
||||
let offset = offset + path_str.len() + 1;
|
||||
let items = itemize_list(context.codemap,
|
||||
pat_vec.iter(),
|
||||
")",
|
||||
|item| item.span.lo,
|
||||
|item| item.span.hi,
|
||||
|item| item.rewrite(context, width, offset),
|
||||
span_after(self.span, "(", context.codemap),
|
||||
self.span.hi);
|
||||
Some(format!("{}({})",
|
||||
path_str,
|
||||
try_opt!(format_item_list(items,
|
||||
width,
|
||||
offset,
|
||||
context.config))))
|
||||
}
|
||||
}
|
||||
None => Some(format!("{}(..)", path_str)),
|
||||
}
|
||||
}
|
||||
Pat_::PatLit(ref expr) => expr.rewrite(context, width, offset),
|
||||
// FIXME(#8): format remaining pattern variants.
|
||||
Pat_::PatIdent(_, _, Some(..)) |
|
||||
Pat_::PatEnum(_, None) |
|
||||
Pat_::PatStruct(..) |
|
||||
Pat_::PatVec(..) |
|
||||
Pat_::PatMac(..) => {
|
||||
PatKind::Lit(ref expr) => expr.rewrite(context, width, offset),
|
||||
PatKind::Vec(ref prefix, ref slice_pat, ref suffix) => {
|
||||
// Rewrite all the sub-patterns.
|
||||
let prefix = prefix.iter().map(|p| p.rewrite(context, width, offset));
|
||||
let slice_pat = slice_pat.as_ref().map(|p| {
|
||||
Some(format!("{}..", try_opt!(p.rewrite(context, width, offset))))
|
||||
});
|
||||
let suffix = suffix.iter().map(|p| p.rewrite(context, width, offset));
|
||||
|
||||
// Munge them together.
|
||||
let pats: Option<Vec<String>> = prefix.chain(slice_pat.into_iter())
|
||||
.chain(suffix)
|
||||
.collect();
|
||||
|
||||
// Check that all the rewrites succeeded, and if not return None.
|
||||
let pats = try_opt!(pats);
|
||||
|
||||
// Unwrap all the sub-strings and join them with commas.
|
||||
let result = format!("[{}]", pats.join(", "));
|
||||
wrap_str(result, context.config.max_width, width, offset)
|
||||
}
|
||||
PatKind::Struct(ref path, ref fields, elipses) => {
|
||||
let path = try_opt!(rewrite_path(context, true, None, path, width, offset));
|
||||
|
||||
let (elipses_str, terminator) = if elipses {
|
||||
(", ..", "..")
|
||||
} else {
|
||||
("", "}")
|
||||
};
|
||||
|
||||
// 5 = `{` plus space before and after plus `}` plus space before.
|
||||
let budget = try_opt!(width.checked_sub(path.len() + 5 + elipses_str.len()));
|
||||
// FIXME Using visual indenting, should use block or visual to match
|
||||
// struct lit preference (however, in practice I think it is rare
|
||||
// for struct patterns to be multi-line).
|
||||
// 3 = `{` plus space before and after.
|
||||
let offset = offset + path.len() + 3;
|
||||
|
||||
let items = itemize_list(context.codemap,
|
||||
fields.iter(),
|
||||
terminator,
|
||||
|f| f.span.lo,
|
||||
|f| f.span.hi,
|
||||
|f| f.node.rewrite(context, budget, offset),
|
||||
span_after(self.span, "{", context.codemap),
|
||||
self.span.hi);
|
||||
let mut field_string = try_opt!(format_item_list(items,
|
||||
budget,
|
||||
offset,
|
||||
context.config));
|
||||
if elipses {
|
||||
if field_string.contains('\n') {
|
||||
field_string.push_str(",\n");
|
||||
field_string.push_str(&offset.to_string(context.config));
|
||||
field_string.push_str("..");
|
||||
} else {
|
||||
if field_string.len() > 0 {
|
||||
field_string.push_str(", ");
|
||||
}
|
||||
field_string.push_str("..");
|
||||
}
|
||||
}
|
||||
|
||||
if field_string.is_empty() {
|
||||
Some(format!("{} {{}}", path))
|
||||
} else {
|
||||
Some(format!("{} {{ {} }}", path, field_string))
|
||||
}
|
||||
}
|
||||
// FIXME(#819) format pattern macros.
|
||||
PatKind::Mac(..) => {
|
||||
wrap_str(context.snippet(self.span),
|
||||
context.config.max_width,
|
||||
width,
|
||||
@ -97,3 +177,17 @@ impl Rewrite for Pat {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rewrite for FieldPat {
|
||||
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
|
||||
let pat = self.pat.rewrite(context, width, offset);
|
||||
if self.is_shorthand {
|
||||
pat
|
||||
} else {
|
||||
wrap_str(format!("{}: {}", self.ident.to_string(), try_opt!(pat)),
|
||||
context.config.max_width,
|
||||
width,
|
||||
offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
65
src/types.rs
65
src/types.rs
@ -21,6 +21,7 @@ use lists::{format_item_list, itemize_list, format_fn_args};
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
use utils::{extra_offset, span_after, format_mutability, wrap_str};
|
||||
use expr::{rewrite_unary_prefix, rewrite_pair, rewrite_tuple};
|
||||
use config::TypeDensity;
|
||||
|
||||
// Does not wrap on simple segments.
|
||||
pub fn rewrite_path(context: &RewriteContext,
|
||||
@ -52,7 +53,7 @@ pub fn rewrite_path(context: &RewriteContext,
|
||||
// 3 = ">::".len()
|
||||
let budget = try_opt!(width.checked_sub(extra_offset + 3));
|
||||
|
||||
result = try_opt!(rewrite_path_segments(expr_context,
|
||||
result = try_opt!(rewrite_path_segments(false,
|
||||
result,
|
||||
path.segments.iter().take(skip_count),
|
||||
span_lo,
|
||||
@ -171,9 +172,9 @@ fn rewrite_segment(expr_context: bool,
|
||||
let offset = offset + ident_len;
|
||||
|
||||
let params = match segment.parameters {
|
||||
ast::PathParameters::AngleBracketedParameters(ref data) if !data.lifetimes.is_empty() ||
|
||||
!data.types.is_empty() ||
|
||||
!data.bindings.is_empty() => {
|
||||
ast::PathParameters::AngleBracketed(ref data) if !data.lifetimes.is_empty() ||
|
||||
!data.types.is_empty() ||
|
||||
!data.bindings.is_empty() => {
|
||||
let param_list = data.lifetimes
|
||||
.iter()
|
||||
.map(SegmentParam::LifeTime)
|
||||
@ -212,10 +213,10 @@ fn rewrite_segment(expr_context: bool,
|
||||
|
||||
format!("{}<{}>", separator, list_str)
|
||||
}
|
||||
ast::PathParameters::ParenthesizedParameters(ref data) => {
|
||||
ast::PathParameters::Parenthesized(ref data) => {
|
||||
let output = match data.output {
|
||||
Some(ref ty) => FunctionRetTy::Return(ty.clone()),
|
||||
None => FunctionRetTy::DefaultReturn(codemap::DUMMY_SP),
|
||||
Some(ref ty) => FunctionRetTy::Ty(ty.clone()),
|
||||
None => FunctionRetTy::Default(codemap::DUMMY_SP),
|
||||
};
|
||||
try_opt!(format_function_type(data.inputs.iter().map(|x| &**x),
|
||||
&output,
|
||||
@ -258,13 +259,13 @@ fn format_function_type<'a, I>(inputs: I,
|
||||
let list_str = try_opt!(format_fn_args(items, budget, offset, context.config));
|
||||
|
||||
let output = match *output {
|
||||
FunctionRetTy::Return(ref ty) => {
|
||||
FunctionRetTy::Ty(ref ty) => {
|
||||
let budget = try_opt!(width.checked_sub(4));
|
||||
let type_str = try_opt!(ty.rewrite(context, budget, offset + 4));
|
||||
format!(" -> {}", type_str)
|
||||
}
|
||||
FunctionRetTy::NoReturn(..) => " -> !".to_owned(),
|
||||
FunctionRetTy::DefaultReturn(..) => String::new(),
|
||||
FunctionRetTy::None(..) => " -> !".to_owned(),
|
||||
FunctionRetTy::Default(..) => String::new(),
|
||||
};
|
||||
|
||||
let infix = if output.len() + list_str.len() > width {
|
||||
@ -424,7 +425,12 @@ impl Rewrite for ast::TyParam {
|
||||
result.push_str(&bounds);
|
||||
}
|
||||
if let Some(ref def) = self.default {
|
||||
result.push_str(" = ");
|
||||
|
||||
let eq_str = match context.config.type_punctuation_density {
|
||||
TypeDensity::Compressed => "=",
|
||||
TypeDensity::Wide => " = ",
|
||||
};
|
||||
result.push_str(eq_str);
|
||||
let budget = try_opt!(width.checked_sub(result.len()));
|
||||
let rewrite = try_opt!(def.rewrite(context, budget, offset + result.len()));
|
||||
result.push_str(&rewrite);
|
||||
@ -464,24 +470,29 @@ impl Rewrite for ast::TraitRef {
|
||||
impl Rewrite for ast::Ty {
|
||||
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
|
||||
match self.node {
|
||||
ast::TyObjectSum(ref ty, ref bounds) => {
|
||||
ast::TyKind::ObjectSum(ref ty, ref bounds) => {
|
||||
let ty_str = try_opt!(ty.rewrite(context, width, offset));
|
||||
let overhead = ty_str.len() + 3;
|
||||
Some(format!("{} + {}",
|
||||
let plus_str = match context.config.type_punctuation_density {
|
||||
TypeDensity::Compressed => "+",
|
||||
TypeDensity::Wide => " + ",
|
||||
};
|
||||
Some(format!("{}{}{}",
|
||||
ty_str,
|
||||
plus_str,
|
||||
try_opt!(bounds.rewrite(context,
|
||||
try_opt!(width.checked_sub(overhead)),
|
||||
offset + overhead))))
|
||||
}
|
||||
ast::TyPtr(ref mt) => {
|
||||
ast::TyKind::Ptr(ref mt) => {
|
||||
let prefix = match mt.mutbl {
|
||||
Mutability::MutMutable => "*mut ",
|
||||
Mutability::MutImmutable => "*const ",
|
||||
Mutability::Mutable => "*mut ",
|
||||
Mutability::Immutable => "*const ",
|
||||
};
|
||||
|
||||
rewrite_unary_prefix(context, prefix, &*mt.ty, width, offset)
|
||||
}
|
||||
ast::TyRptr(ref lifetime, ref mt) => {
|
||||
ast::TyKind::Rptr(ref lifetime, ref mt) => {
|
||||
let mut_str = format_mutability(mt.mutbl);
|
||||
let mut_len = mut_str.len();
|
||||
Some(match *lifetime {
|
||||
@ -509,39 +520,39 @@ impl Rewrite for ast::Ty {
|
||||
}
|
||||
// FIXME: we drop any comments here, even though it's a silly place to put
|
||||
// comments.
|
||||
ast::TyParen(ref ty) => {
|
||||
ast::TyKind::Paren(ref ty) => {
|
||||
let budget = try_opt!(width.checked_sub(2));
|
||||
ty.rewrite(context, budget, offset + 1).map(|ty_str| format!("({})", ty_str))
|
||||
}
|
||||
ast::TyVec(ref ty) => {
|
||||
ast::TyKind::Vec(ref ty) => {
|
||||
let budget = try_opt!(width.checked_sub(2));
|
||||
ty.rewrite(context, budget, offset + 1).map(|ty_str| format!("[{}]", ty_str))
|
||||
}
|
||||
ast::TyTup(ref items) => {
|
||||
ast::TyKind::Tup(ref items) => {
|
||||
rewrite_tuple(context,
|
||||
items.iter().map(|x| &**x),
|
||||
self.span,
|
||||
width,
|
||||
offset)
|
||||
}
|
||||
ast::TyPolyTraitRef(ref trait_ref) => trait_ref.rewrite(context, width, offset),
|
||||
ast::TyPath(ref q_self, ref path) => {
|
||||
ast::TyKind::PolyTraitRef(ref trait_ref) => trait_ref.rewrite(context, width, offset),
|
||||
ast::TyKind::Path(ref q_self, ref path) => {
|
||||
rewrite_path(context, false, q_self.as_ref(), path, width, offset)
|
||||
}
|
||||
ast::TyFixedLengthVec(ref ty, ref repeats) => {
|
||||
ast::TyKind::FixedLengthVec(ref ty, ref repeats) => {
|
||||
rewrite_pair(&**ty, &**repeats, "[", "; ", "]", context, width, offset)
|
||||
}
|
||||
ast::TyInfer => {
|
||||
ast::TyKind::Infer => {
|
||||
if width >= 1 {
|
||||
Some("_".to_owned())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
ast::TyBareFn(ref bare_fn) => {
|
||||
ast::TyKind::BareFn(ref bare_fn) => {
|
||||
rewrite_bare_fn(bare_fn, self.span, context, width, offset)
|
||||
}
|
||||
ast::TyMac(..) | ast::TyTypeof(..) => unreachable!(),
|
||||
ast::TyKind::Mac(..) | ast::TyKind::Typeof(..) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -556,7 +567,7 @@ fn rewrite_bare_fn(bare_fn: &ast::BareFnTy,
|
||||
|
||||
result.push_str(&::utils::format_unsafety(bare_fn.unsafety));
|
||||
|
||||
if bare_fn.abi != abi::Rust {
|
||||
if bare_fn.abi != abi::Abi::Rust {
|
||||
result.push_str(&::utils::format_abi(bare_fn.abi));
|
||||
}
|
||||
|
||||
|
36
src/utils.rs
36
src/utils.rs
@ -10,7 +10,7 @@
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use syntax::ast::{self, Visibility, Attribute, MetaItem, MetaItem_};
|
||||
use syntax::ast::{self, Visibility, Attribute, MetaItem, MetaItemKind};
|
||||
use syntax::codemap::{CodeMap, Span, BytePos};
|
||||
use syntax::abi;
|
||||
|
||||
@ -38,6 +38,14 @@ pub fn span_after(original: Span, needle: &str, codemap: &CodeMap) -> BytePos {
|
||||
original.lo + BytePos(offset as u32)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn span_before(original: Span, needle: &str, codemap: &CodeMap) -> BytePos {
|
||||
let snippet = codemap.span_to_snippet(original).unwrap();
|
||||
let offset = snippet.find_uncommented(needle).unwrap();
|
||||
|
||||
original.lo + BytePos(offset as u32)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn span_after_last(original: Span, needle: &str, codemap: &CodeMap) -> BytePos {
|
||||
let snippet = codemap.span_to_snippet(original).unwrap();
|
||||
@ -69,8 +77,8 @@ pub fn format_unsafety(unsafety: ast::Unsafety) -> &'static str {
|
||||
#[inline]
|
||||
pub fn format_mutability(mutability: ast::Mutability) -> &'static str {
|
||||
match mutability {
|
||||
ast::Mutability::MutMutable => "mut ",
|
||||
ast::Mutability::MutImmutable => "",
|
||||
ast::Mutability::Mutable => "mut ",
|
||||
ast::Mutability::Immutable => "",
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,8 +109,8 @@ pub fn last_line_width(s: &str) -> usize {
|
||||
#[inline]
|
||||
fn is_skip(meta_item: &MetaItem) -> bool {
|
||||
match meta_item.node {
|
||||
MetaItem_::MetaWord(ref s) => *s == SKIP_ANNOTATION,
|
||||
MetaItem_::MetaList(ref s, ref l) => *s == "cfg_attr" && l.len() == 2 && is_skip(&l[1]),
|
||||
MetaItemKind::Word(ref s) => *s == SKIP_ANNOTATION,
|
||||
MetaItemKind::List(ref s, ref l) => *s == "cfg_attr" && l.len() == 2 && is_skip(&l[1]),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -129,9 +137,9 @@ pub fn end_typaram(typaram: &ast::TyParam) -> BytePos {
|
||||
#[inline]
|
||||
pub fn semicolon_for_expr(expr: &ast::Expr) -> bool {
|
||||
match expr.node {
|
||||
ast::Expr_::ExprRet(..) |
|
||||
ast::Expr_::ExprAgain(..) |
|
||||
ast::Expr_::ExprBreak(..) => true,
|
||||
ast::ExprKind::Ret(..) |
|
||||
ast::ExprKind::Again(..) |
|
||||
ast::ExprKind::Break(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -139,16 +147,16 @@ pub fn semicolon_for_expr(expr: &ast::Expr) -> bool {
|
||||
#[inline]
|
||||
pub fn semicolon_for_stmt(stmt: &ast::Stmt) -> bool {
|
||||
match stmt.node {
|
||||
ast::Stmt_::StmtSemi(ref expr, _) => {
|
||||
ast::StmtKind::Semi(ref expr, _) => {
|
||||
match expr.node {
|
||||
ast::Expr_::ExprWhile(..) |
|
||||
ast::Expr_::ExprWhileLet(..) |
|
||||
ast::Expr_::ExprLoop(..) |
|
||||
ast::Expr_::ExprForLoop(..) => false,
|
||||
ast::ExprKind::While(..) |
|
||||
ast::ExprKind::WhileLet(..) |
|
||||
ast::ExprKind::Loop(..) |
|
||||
ast::ExprKind::ForLoop(..) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
ast::Stmt_::StmtExpr(..) => false,
|
||||
ast::StmtKind::Expr(..) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use syntax::visit;
|
||||
|
||||
use strings::string_buffer::StringBuffer;
|
||||
|
||||
use {Indent, WriteMode};
|
||||
use Indent;
|
||||
use utils;
|
||||
use config::Config;
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
@ -31,14 +31,13 @@ pub struct FmtVisitor<'a> {
|
||||
// FIXME: use an RAII util or closure for indenting
|
||||
pub block_indent: Indent,
|
||||
pub config: &'a Config,
|
||||
pub write_mode: Option<WriteMode>,
|
||||
}
|
||||
|
||||
impl<'a> FmtVisitor<'a> {
|
||||
fn visit_stmt(&mut self, stmt: &ast::Stmt) {
|
||||
match stmt.node {
|
||||
ast::Stmt_::StmtDecl(ref decl, _) => {
|
||||
if let ast::Decl_::DeclItem(ref item) = decl.node {
|
||||
ast::StmtKind::Decl(ref decl, _) => {
|
||||
if let ast::DeclKind::Item(ref item) = decl.node {
|
||||
self.visit_item(item);
|
||||
} else {
|
||||
let rewrite = stmt.rewrite(&self.get_context(),
|
||||
@ -48,14 +47,14 @@ impl<'a> FmtVisitor<'a> {
|
||||
self.push_rewrite(stmt.span, rewrite);
|
||||
}
|
||||
}
|
||||
ast::Stmt_::StmtExpr(..) | ast::Stmt_::StmtSemi(..) => {
|
||||
ast::StmtKind::Expr(..) | ast::StmtKind::Semi(..) => {
|
||||
let rewrite = stmt.rewrite(&self.get_context(),
|
||||
self.config.max_width - self.block_indent.width(),
|
||||
self.block_indent);
|
||||
|
||||
self.push_rewrite(stmt.span, rewrite);
|
||||
}
|
||||
ast::Stmt_::StmtMac(ref mac, _macro_style, _) => {
|
||||
ast::StmtKind::Mac(ref mac, _macro_style, _) => {
|
||||
self.format_missing_with_indent(stmt.span.lo);
|
||||
self.visit_mac(mac);
|
||||
}
|
||||
@ -184,7 +183,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
// FIXME This is overly conservative and means we miss attributes on
|
||||
// inline modules.
|
||||
match item.node {
|
||||
ast::Item_::ItemMod(_) => {
|
||||
ast::ItemKind::Mod(_) => {
|
||||
if utils::contains_skip(&item.attrs) {
|
||||
return;
|
||||
}
|
||||
@ -198,10 +197,10 @@ impl<'a> FmtVisitor<'a> {
|
||||
}
|
||||
|
||||
match item.node {
|
||||
ast::Item_::ItemUse(ref vp) => {
|
||||
ast::ItemKind::Use(ref vp) => {
|
||||
self.format_import(item.vis, vp, item.span);
|
||||
}
|
||||
ast::Item_::ItemImpl(..) => {
|
||||
ast::ItemKind::Impl(..) => {
|
||||
self.format_missing_with_indent(item.span.lo);
|
||||
if let Some(impl_str) = format_impl(&self.get_context(), item, self.block_indent) {
|
||||
self.buffer.push_str(&impl_str);
|
||||
@ -209,7 +208,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
}
|
||||
}
|
||||
// FIXME(#78): format traits.
|
||||
ast::Item_::ItemTrait(..) => {
|
||||
ast::ItemKind::Trait(..) => {
|
||||
self.format_missing_with_indent(item.span.lo);
|
||||
if let Some(trait_str) = format_trait(&self.get_context(),
|
||||
item,
|
||||
@ -223,13 +222,13 @@ impl<'a> FmtVisitor<'a> {
|
||||
// }
|
||||
// self.block_indent = self.block_indent.block_unindent(self.config);
|
||||
}
|
||||
ast::Item_::ItemExternCrate(_) => {
|
||||
ast::ItemKind::ExternCrate(_) => {
|
||||
self.format_missing_with_indent(item.span.lo);
|
||||
let new_str = self.snippet(item.span);
|
||||
self.buffer.push_str(&new_str);
|
||||
self.last_pos = item.span.hi;
|
||||
}
|
||||
ast::Item_::ItemStruct(ref def, ref generics) => {
|
||||
ast::ItemKind::Struct(ref def, ref generics) => {
|
||||
let rewrite = {
|
||||
let indent = self.block_indent;
|
||||
let context = self.get_context();
|
||||
@ -250,28 +249,24 @@ impl<'a> FmtVisitor<'a> {
|
||||
};
|
||||
self.push_rewrite(item.span, rewrite);
|
||||
}
|
||||
ast::Item_::ItemEnum(ref def, ref generics) => {
|
||||
ast::ItemKind::Enum(ref def, ref generics) => {
|
||||
self.format_missing_with_indent(item.span.lo);
|
||||
self.visit_enum(item.ident, item.vis, def, generics, item.span);
|
||||
self.last_pos = item.span.hi;
|
||||
}
|
||||
ast::Item_::ItemMod(ref module) => {
|
||||
ast::ItemKind::Mod(ref module) => {
|
||||
self.format_missing_with_indent(item.span.lo);
|
||||
self.format_mod(module, item.vis, item.span, item.ident);
|
||||
}
|
||||
ast::Item_::ItemMac(..) => {
|
||||
ast::ItemKind::Mac(ref mac) => {
|
||||
self.format_missing_with_indent(item.span.lo);
|
||||
let snippet = self.snippet(item.span);
|
||||
self.buffer.push_str(&snippet);
|
||||
self.last_pos = item.span.hi;
|
||||
// FIXME: we cannot format these yet, because of a bad span.
|
||||
// See rust lang issue #28424.
|
||||
self.visit_mac(mac);
|
||||
}
|
||||
ast::Item_::ItemForeignMod(ref foreign_mod) => {
|
||||
ast::ItemKind::ForeignMod(ref foreign_mod) => {
|
||||
self.format_missing_with_indent(item.span.lo);
|
||||
self.format_foreign_mod(foreign_mod, item.span);
|
||||
}
|
||||
ast::Item_::ItemStatic(ref ty, mutability, ref expr) => {
|
||||
ast::ItemKind::Static(ref ty, mutability, ref expr) => {
|
||||
let rewrite = rewrite_static("static",
|
||||
item.vis,
|
||||
item.ident,
|
||||
@ -281,32 +276,32 @@ impl<'a> FmtVisitor<'a> {
|
||||
&self.get_context());
|
||||
self.push_rewrite(item.span, rewrite);
|
||||
}
|
||||
ast::Item_::ItemConst(ref ty, ref expr) => {
|
||||
ast::ItemKind::Const(ref ty, ref expr) => {
|
||||
let rewrite = rewrite_static("const",
|
||||
item.vis,
|
||||
item.ident,
|
||||
ty,
|
||||
ast::Mutability::MutImmutable,
|
||||
ast::Mutability::Immutable,
|
||||
expr,
|
||||
&self.get_context());
|
||||
self.push_rewrite(item.span, rewrite);
|
||||
}
|
||||
ast::Item_::ItemDefaultImpl(..) => {
|
||||
ast::ItemKind::DefaultImpl(..) => {
|
||||
// FIXME(#78): format impl definitions.
|
||||
}
|
||||
ast::ItemFn(ref declaration, 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,
|
||||
generics,
|
||||
unsafety,
|
||||
constness,
|
||||
abi,
|
||||
item.vis),
|
||||
declaration,
|
||||
decl,
|
||||
body,
|
||||
item.span,
|
||||
item.id)
|
||||
}
|
||||
ast::Item_::ItemTy(ref ty, ref generics) => {
|
||||
ast::ItemKind::Ty(ref ty, ref generics) => {
|
||||
let rewrite = rewrite_type_alias(&self.get_context(),
|
||||
self.block_indent,
|
||||
item.ident,
|
||||
@ -325,22 +320,22 @@ impl<'a> FmtVisitor<'a> {
|
||||
}
|
||||
|
||||
match ti.node {
|
||||
ast::ConstTraitItem(..) => {
|
||||
ast::TraitItemKind::Const(..) => {
|
||||
// FIXME: Implement
|
||||
}
|
||||
ast::MethodTraitItem(ref sig, None) => {
|
||||
ast::TraitItemKind::Method(ref sig, None) => {
|
||||
let indent = self.block_indent;
|
||||
let rewrite = self.rewrite_required_fn(indent, ti.ident, sig, ti.span);
|
||||
self.push_rewrite(ti.span, rewrite);
|
||||
}
|
||||
ast::MethodTraitItem(ref sig, Some(ref body)) => {
|
||||
ast::TraitItemKind::Method(ref sig, Some(ref body)) => {
|
||||
self.visit_fn(visit::FnKind::Method(ti.ident, sig, None),
|
||||
&sig.decl,
|
||||
&body,
|
||||
ti.span,
|
||||
ti.id);
|
||||
}
|
||||
ast::TypeTraitItem(ref type_param_bounds, _) => {
|
||||
ast::TraitItemKind::Type(ref type_param_bounds, _) => {
|
||||
let indent = self.block_indent;
|
||||
let mut result = String::new();
|
||||
result.push_str(&format!("type {}", ti.ident));
|
||||
@ -408,10 +403,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
self.last_pos = span.hi;
|
||||
}
|
||||
|
||||
pub fn from_codemap(parse_session: &'a ParseSess,
|
||||
config: &'a Config,
|
||||
mode: Option<WriteMode>)
|
||||
-> FmtVisitor<'a> {
|
||||
pub fn from_codemap(parse_session: &'a ParseSess, config: &'a Config) -> FmtVisitor<'a> {
|
||||
FmtVisitor {
|
||||
parse_session: parse_session,
|
||||
codemap: parse_session.codemap(),
|
||||
@ -422,7 +414,6 @@ impl<'a> FmtVisitor<'a> {
|
||||
alignment: 0,
|
||||
},
|
||||
config: config,
|
||||
write_mode: mode,
|
||||
}
|
||||
}
|
||||
|
||||
@ -482,11 +473,19 @@ impl<'a> FmtVisitor<'a> {
|
||||
|
||||
if is_internal {
|
||||
self.buffer.push_str(" {");
|
||||
self.last_pos = ::utils::span_after(s, "{", self.codemap);
|
||||
self.block_indent = self.block_indent.block_indent(self.config);
|
||||
self.walk_mod_items(m);
|
||||
self.format_missing_with_indent(m.inner.hi - BytePos(1));
|
||||
self.close_block();
|
||||
// Hackery to account for the closing }.
|
||||
let mod_lo = ::utils::span_after(s, "{", self.codemap);
|
||||
let body_snippet = self.snippet(codemap::mk_sp(mod_lo, m.inner.hi - BytePos(1)));
|
||||
let body_snippet = body_snippet.trim();
|
||||
if body_snippet.is_empty() {
|
||||
self.buffer.push_str("}");
|
||||
} else {
|
||||
self.last_pos = mod_lo;
|
||||
self.block_indent = self.block_indent.block_indent(self.config);
|
||||
self.walk_mod_items(m);
|
||||
self.format_missing_with_indent(m.inner.hi - BytePos(1));
|
||||
self.close_block();
|
||||
}
|
||||
self.last_pos = m.inner.hi;
|
||||
} else {
|
||||
self.buffer.push_str(";");
|
||||
|
@ -12,6 +12,7 @@ where_density = "Tall"
|
||||
where_indent = "Tabbed"
|
||||
where_layout = "Vertical"
|
||||
where_pred_indent = "Visual"
|
||||
where_trailing_comma = false
|
||||
generics_indent = "Visual"
|
||||
struct_trailing_comma = "Vertical"
|
||||
struct_lit_trailing_comma = "Vertical"
|
||||
|
@ -45,3 +45,5 @@ fn chains() {
|
||||
|
||||
/*
|
||||
* random comment */
|
||||
|
||||
fn main() {/* Test */}
|
||||
|
@ -233,3 +233,14 @@ fn blocks() {
|
||||
println!("yay arithmetix!");
|
||||
};
|
||||
}
|
||||
|
||||
fn issue767() {
|
||||
if false {
|
||||
if false {
|
||||
} else {
|
||||
// A let binding here seems necessary to trigger it.
|
||||
let _ = ();
|
||||
}
|
||||
} else if let false = false {
|
||||
}
|
||||
}
|
||||
|
@ -74,3 +74,6 @@ trait CoolTypes {
|
||||
trait CoolerTypes { fn dummy(&self) {
|
||||
}
|
||||
}
|
||||
|
||||
fn Foo<T>() where T: Bar {
|
||||
}
|
||||
|
@ -22,6 +22,12 @@ impl<'a, 'b, X, Y: Foo<Bar>> Foo<'a, X> for Bar<'b, Y> where X: Fooooooooooooooo
|
||||
fn foo() { "hi" }
|
||||
}
|
||||
|
||||
impl<T> Foo for Bar<T> where T: Baz
|
||||
{
|
||||
}
|
||||
|
||||
impl<T> Foo for Bar<T> where T: Baz { /* Comment */ }
|
||||
|
||||
impl Foo {
|
||||
fn foo() {}
|
||||
}
|
||||
@ -64,3 +70,10 @@ impl X { fn do_parse( mut self : X ) {} }
|
||||
impl Y5000 {
|
||||
fn bar(self: X< 'a , 'b >, y: Y) {}
|
||||
}
|
||||
|
||||
pub impl<T> Foo for Bar<T> where T: Foo
|
||||
{
|
||||
fn foo() { "hi" }
|
||||
}
|
||||
|
||||
pub impl<T, Z> Foo for Bar<T, Z> where T: Foo, Z: Baz {}
|
||||
|
37
tests/source/issue-447.rs
Normal file
37
tests/source/issue-447.rs
Normal file
@ -0,0 +1,37 @@
|
||||
fn main() {
|
||||
if /* shouldn't be dropped
|
||||
shouldn't be dropped */
|
||||
|
||||
cond /* shouldn't be dropped
|
||||
shouldn't be dropped */
|
||||
|
||||
{
|
||||
} /* shouldn't be dropped
|
||||
shouldn't be dropped */
|
||||
|
||||
else /* shouldn't be dropped
|
||||
shouldn't be dropped */
|
||||
|
||||
if /* shouldn't be dropped
|
||||
shouldn't be dropped */
|
||||
|
||||
cond /* shouldn't be dropped
|
||||
shouldn't be dropped */
|
||||
|
||||
{
|
||||
} /* shouldn't be dropped
|
||||
shouldn't be dropped */
|
||||
|
||||
else /* shouldn't be dropped
|
||||
shouldn't be dropped */
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
if /* shouldn't be dropped
|
||||
shouldn't be dropped */
|
||||
let Some(x) = y/* shouldn't be dropped
|
||||
shouldn't be dropped */
|
||||
{
|
||||
}
|
||||
}
|
19
tests/source/issue-811.rs
Normal file
19
tests/source/issue-811.rs
Normal file
@ -0,0 +1,19 @@
|
||||
trait FooTrait<T>: Sized {
|
||||
type Bar: BarTrait<T>;
|
||||
}
|
||||
|
||||
trait BarTrait<T>: Sized {
|
||||
type Baz;
|
||||
fn foo();
|
||||
}
|
||||
|
||||
type Foo<T: FooTrait> = <<T as FooTrait<U>>::Bar as BarTrait<U>>::Baz;
|
||||
type Bar<T: BarTrait> = <T as BarTrait<U>>::Baz;
|
||||
|
||||
fn some_func<T: FooTrait<U>, U>() {
|
||||
<<T as FooTrait<U>>::Bar as BarTrait<U>>::foo();
|
||||
}
|
||||
|
||||
fn some_func<T: BarTrait<U>>() {
|
||||
<T as BarTrait<U>>::foo();
|
||||
}
|
1
tests/source/issue-850.rs
Normal file
1
tests/source/issue-850.rs
Normal file
@ -0,0 +1 @@
|
||||
const unsafe fn x() {}
|
@ -1,4 +1,8 @@
|
||||
itemmacro!(this, is.not() .formatted(yet));
|
||||
itemmacro!(this, is.now() .formatted(yay));
|
||||
|
||||
itemmacro!(really, long.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbb() .is.formatted());
|
||||
|
||||
itemmacro!{this, is.bracket().formatted()}
|
||||
|
||||
fn main() {
|
||||
foo! ( );
|
||||
|
@ -11,6 +11,20 @@ fn main() {
|
||||
let Some ( ref xyz /* comment! */) = opt;
|
||||
|
||||
if let None = opt2 { panic!("oh noes"); }
|
||||
|
||||
let foo@bar (f) = 42;
|
||||
let a::foo ( ..) = 42;
|
||||
let [ ] = 42;
|
||||
let [a.., b,c ] = 42;
|
||||
let [ a,b,c.. ] = 42;
|
||||
let [a, b, c, d..,e,f, g] = 42;
|
||||
let foo { } = 42;
|
||||
let foo {..} = 42;
|
||||
let foo { x, y: ref foo, .. } = 42;
|
||||
let foo { x, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy: ref foo, .. } = 42;
|
||||
let foo { x, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy: ref foo, } = 42;
|
||||
let foo { x, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy: ref foo, .. };
|
||||
let foo { x, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy: ref foo, };
|
||||
}
|
||||
|
||||
impl<'a,'b> ResolveGeneratedContentFragmentMutator<'a,'b> {
|
||||
|
14
tests/source/string-lit-2.rs
Normal file
14
tests/source/string-lit-2.rs
Normal file
@ -0,0 +1,14 @@
|
||||
fn main() -> &'static str {
|
||||
let too_many_lines = "H\
|
||||
e\
|
||||
l\
|
||||
l\
|
||||
o";
|
||||
let leave_me = "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss\
|
||||
s
|
||||
jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj";
|
||||
// Crappy formatting :-(
|
||||
let change_me = "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss\
|
||||
s
|
||||
jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj";
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
// rustfmt-force_format_strings: true
|
||||
// Long string literals
|
||||
|
||||
fn main() -> &'static str {
|
||||
|
@ -114,3 +114,12 @@ fn issue491() {
|
||||
Foo { a: aaaaaaaaaa, b: bbbbbbbb, c: cccccccccc, d: dddddddddd, /* a comment */
|
||||
e: eeeeeeeee };
|
||||
}
|
||||
|
||||
fn issue698() {
|
||||
Record {
|
||||
ffffffffffffffffffffffffffields: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
|
||||
};
|
||||
Record {
|
||||
ffffffffffffffffffffffffffields: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
|
||||
}
|
||||
}
|
||||
|
5
tests/source/type-punctuation.rs
Normal file
5
tests/source/type-punctuation.rs
Normal file
@ -0,0 +1,5 @@
|
||||
// rustfmt-type_punctuation_density: Compressed
|
||||
|
||||
fn Foo<T = Foo, Output = Expr<'tcx> + Foo>() {
|
||||
let i = 6;
|
||||
}
|
37
tests/source/where-trailing-comma.rs
Normal file
37
tests/source/where-trailing-comma.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// rustfmt-where_trailing_comma: true
|
||||
|
||||
fn f<S, T>(x: T, y: S) -> T where T: P, S: Q
|
||||
{
|
||||
x
|
||||
}
|
||||
|
||||
impl Trait for T where T: P
|
||||
{
|
||||
fn f(x: T) -> T where T: Q + R
|
||||
{
|
||||
x
|
||||
}
|
||||
}
|
||||
|
||||
struct Pair<S, T> where T: P, S: P + Q {
|
||||
a: T,
|
||||
b: S
|
||||
}
|
||||
|
||||
struct TupPair<S, T> (S, T) where T: P, S: P + Q;
|
||||
|
||||
enum E<S, T> where S: P, T: P {
|
||||
A {a: T},
|
||||
}
|
||||
|
||||
type Double<T> where T: P, T: Q = Pair<T, T>;
|
||||
|
||||
extern "C" {
|
||||
fn f<S, T>(x: T, y: S) -> T where T: P, S: Q;
|
||||
}
|
||||
|
||||
// Note: trait declarations are not fully formatted (issue #78)
|
||||
trait Q<S, T> where T: P, S: R
|
||||
{
|
||||
fn f<U, V>(self, x: T, y: S, z: U) -> Self where U: P, V: P;
|
||||
}
|
135
tests/system.rs
135
tests/system.rs
@ -19,15 +19,16 @@ use std::io::{self, Read, BufRead, BufReader};
|
||||
use std::path::Path;
|
||||
|
||||
use rustfmt::*;
|
||||
use rustfmt::config::{Config, ReportTactic};
|
||||
use rustfmt::filemap::{write_system_newlines, FileMap};
|
||||
use rustfmt::config::{Config, ReportTactic, WriteMode};
|
||||
use rustfmt::rustfmt_diff::*;
|
||||
|
||||
static DIFF_CONTEXT_SIZE: usize = 3;
|
||||
const DIFF_CONTEXT_SIZE: usize = 3;
|
||||
|
||||
fn get_path_string(dir_entry: io::Result<fs::DirEntry>) -> String {
|
||||
let path = dir_entry.ok().expect("Couldn't get DirEntry.").path();
|
||||
let path = dir_entry.expect("Couldn't get DirEntry").path();
|
||||
|
||||
path.to_str().expect("Couldn't stringify path.").to_owned()
|
||||
path.to_str().expect("Couldn't stringify path").to_owned()
|
||||
}
|
||||
|
||||
// Integration tests. The files in the tests/source are formatted and compared
|
||||
@ -39,11 +40,11 @@ fn get_path_string(dir_entry: io::Result<fs::DirEntry>) -> String {
|
||||
#[test]
|
||||
fn system_tests() {
|
||||
// Get all files in the tests/source directory.
|
||||
let files = fs::read_dir("tests/source").ok().expect("Couldn't read source dir.");
|
||||
let files = fs::read_dir("tests/source").expect("Couldn't read source dir");
|
||||
// Turn a DirEntry into a String that represents the relative path to the
|
||||
// file.
|
||||
let files = files.map(get_path_string);
|
||||
let (_reports, count, fails) = check_files(files, WriteMode::Return);
|
||||
let (_reports, count, fails) = check_files(files, None);
|
||||
|
||||
// Display results.
|
||||
println!("Ran {} system tests.", count);
|
||||
@ -54,24 +55,60 @@ fn system_tests() {
|
||||
// the only difference is the coverage mode
|
||||
#[test]
|
||||
fn coverage_tests() {
|
||||
let files = fs::read_dir("tests/coverage-source").ok().expect("Couldn't read source dir.");
|
||||
let files = fs::read_dir("tests/coverage-source").expect("Couldn't read source dir");
|
||||
let files = files.map(get_path_string);
|
||||
let (_reports, count, fails) = check_files(files, WriteMode::Coverage);
|
||||
let (_reports, count, fails) = check_files(files, Some(WriteMode::Coverage));
|
||||
|
||||
println!("Ran {} tests in coverage mode.", count);
|
||||
assert!(fails == 0, "{} tests failed", fails);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checkstyle_test() {
|
||||
let filename = "tests/source/fn-single-line.rs";
|
||||
let expected_filename = "tests/writemode/checkstyle.xml";
|
||||
assert_output(filename, expected_filename, Some(WriteMode::Checkstyle));
|
||||
}
|
||||
|
||||
|
||||
// Helper function for comparing the results of rustfmt
|
||||
// to a known output file generated by one of the write modes.
|
||||
fn assert_output(source: &str, expected_filename: &str, write_mode: Option<WriteMode>) {
|
||||
let file_map = run_rustfmt(source.to_string(), write_mode);
|
||||
|
||||
let mut config = read_config(&source);
|
||||
if let Some(write_mode) = write_mode {
|
||||
config.write_mode = write_mode;
|
||||
}
|
||||
|
||||
// Populate output by writing to a vec.
|
||||
let mut out = vec![];
|
||||
let _ = filemap::write_all_files(&file_map, &mut out, &config);
|
||||
let output = String::from_utf8(out).unwrap();
|
||||
|
||||
let mut expected_file = fs::File::open(&expected_filename).expect("Couldn't open target");
|
||||
let mut expected_text = String::new();
|
||||
expected_file.read_to_string(&mut expected_text)
|
||||
.expect("Failed reading target");
|
||||
|
||||
let compare = make_diff(&expected_text, &output, DIFF_CONTEXT_SIZE);
|
||||
if compare.len() > 0 {
|
||||
let mut failures = HashMap::new();
|
||||
failures.insert(source.to_string(), compare);
|
||||
print_mismatches(failures);
|
||||
assert!(false, "Text does not match expected output");
|
||||
}
|
||||
}
|
||||
|
||||
// Idempotence tests. Files in tests/target are checked to be unaltered by
|
||||
// rustfmt.
|
||||
#[test]
|
||||
fn idempotence_tests() {
|
||||
// Get all files in the tests/target directory.
|
||||
let files = fs::read_dir("tests/target")
|
||||
.ok()
|
||||
.expect("Couldn't read target dir.")
|
||||
.expect("Couldn't read target dir")
|
||||
.map(get_path_string);
|
||||
let (_reports, count, fails) = check_files(files, WriteMode::Return);
|
||||
let (_reports, count, fails) = check_files(files, None);
|
||||
|
||||
// Display results.
|
||||
println!("Ran {} idempotent tests.", count);
|
||||
@ -83,14 +120,13 @@ fn idempotence_tests() {
|
||||
#[test]
|
||||
fn self_tests() {
|
||||
let files = fs::read_dir("src/bin")
|
||||
.ok()
|
||||
.expect("Couldn't read src dir.")
|
||||
.chain(fs::read_dir("tests").ok().expect("Couldn't read tests dir."))
|
||||
.expect("Couldn't read src dir")
|
||||
.chain(fs::read_dir("tests").expect("Couldn't read tests dir"))
|
||||
.map(get_path_string);
|
||||
// Hack because there's no `IntoIterator` impl for `[T; N]`.
|
||||
let files = files.chain(Some("src/lib.rs".to_owned()).into_iter());
|
||||
|
||||
let (reports, count, fails) = check_files(files, WriteMode::Return);
|
||||
let (reports, count, fails) = check_files(files, None);
|
||||
let mut warnings = 0;
|
||||
|
||||
// Display results.
|
||||
@ -109,7 +145,7 @@ fn self_tests() {
|
||||
|
||||
// For each file, run rustfmt and collect the output.
|
||||
// Returns the number of files checked and the number of failures.
|
||||
fn check_files<I>(files: I, write_mode: WriteMode) -> (Vec<FormatReport>, u32, u32)
|
||||
fn check_files<I>(files: I, write_mode: Option<WriteMode>) -> (Vec<FormatReport>, u32, u32)
|
||||
where I: Iterator<Item = String>
|
||||
{
|
||||
let mut count = 0;
|
||||
@ -144,9 +180,7 @@ fn print_mismatches(result: HashMap<String, Vec<Mismatch>>) {
|
||||
assert!(t.reset().unwrap());
|
||||
}
|
||||
|
||||
pub fn idempotent_check(filename: String,
|
||||
write_mode: WriteMode)
|
||||
-> Result<FormatReport, HashMap<String, Vec<Mismatch>>> {
|
||||
fn read_config(filename: &str) -> Config {
|
||||
let sig_comments = read_significant_comments(&filename);
|
||||
let mut config = get_config(sig_comments.get("config").map(|x| &(*x)[..]));
|
||||
|
||||
@ -158,12 +192,36 @@ pub fn idempotent_check(filename: String,
|
||||
|
||||
// Don't generate warnings for to-do items.
|
||||
config.report_todo = ReportTactic::Never;
|
||||
config
|
||||
}
|
||||
|
||||
let mut file_map = format(Path::new(&filename), &config, write_mode);
|
||||
// Simulate run()
|
||||
fn run_rustfmt(filename: String, write_mode: Option<WriteMode>) -> FileMap {
|
||||
let mut config = read_config(&filename);
|
||||
if let Some(write_mode) = write_mode {
|
||||
config.write_mode = write_mode;
|
||||
}
|
||||
format(Path::new(&filename), &config)
|
||||
}
|
||||
|
||||
pub fn idempotent_check(filename: String,
|
||||
write_mode: Option<WriteMode>)
|
||||
-> Result<FormatReport, HashMap<String, Vec<Mismatch>>> {
|
||||
let sig_comments = read_significant_comments(&filename);
|
||||
let config = read_config(&filename);
|
||||
let mut file_map = run_rustfmt(filename, write_mode);
|
||||
let format_report = fmt_lines(&mut file_map, &config);
|
||||
|
||||
// Won't panic, as we're not doing any IO.
|
||||
let write_result = filemap::write_all_files(&file_map, WriteMode::Return, &config).unwrap();
|
||||
let mut write_result = HashMap::new();
|
||||
for (filename, text) in file_map.iter() {
|
||||
let mut v = Vec::new();
|
||||
// Won't panic, as we're not doing any IO.
|
||||
write_system_newlines(&mut v, text, &config).unwrap();
|
||||
// Won't panic, we are writing correct utf8.
|
||||
let one_result = String::from_utf8(v).unwrap();
|
||||
write_result.insert(filename.clone(), one_result);
|
||||
}
|
||||
|
||||
let target = sig_comments.get("target").map(|x| &(*x)[..]);
|
||||
|
||||
handle_result(write_result, target, write_mode).map(|_| format_report)
|
||||
@ -180,11 +238,9 @@ fn get_config(config_file: Option<&str>) -> Config {
|
||||
}
|
||||
};
|
||||
|
||||
let mut def_config_file = fs::File::open(config_file_name)
|
||||
.ok()
|
||||
.expect("Couldn't open config.");
|
||||
let mut def_config_file = fs::File::open(config_file_name).expect("Couldn't open config");
|
||||
let mut def_config = String::new();
|
||||
def_config_file.read_to_string(&mut def_config).ok().expect("Couldn't read config.");
|
||||
def_config_file.read_to_string(&mut def_config).expect("Couldn't read config");
|
||||
|
||||
Config::from_toml(&def_config)
|
||||
}
|
||||
@ -192,25 +248,22 @@ fn get_config(config_file: Option<&str>) -> Config {
|
||||
// Reads significant comments of the form: // rustfmt-key: value
|
||||
// into a hash map.
|
||||
fn read_significant_comments(file_name: &str) -> HashMap<String, String> {
|
||||
let file = fs::File::open(file_name)
|
||||
.ok()
|
||||
.expect(&format!("Couldn't read file {}.", file_name));
|
||||
let file = fs::File::open(file_name).expect(&format!("Couldn't read file {}", file_name));
|
||||
let reader = BufReader::new(file);
|
||||
let pattern = r"^\s*//\s*rustfmt-([^:]+):\s*(\S+)";
|
||||
let regex = regex::Regex::new(&pattern).ok().expect("Failed creating pattern 1.");
|
||||
let regex = regex::Regex::new(&pattern).expect("Failed creating pattern 1");
|
||||
|
||||
// Matches lines containing significant comments or whitespace.
|
||||
let line_regex = regex::Regex::new(r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)")
|
||||
.ok()
|
||||
.expect("Failed creating pattern 2.");
|
||||
.expect("Failed creating pattern 2");
|
||||
|
||||
reader.lines()
|
||||
.map(|line| line.ok().expect("Failed getting line."))
|
||||
.map(|line| line.expect("Failed getting line"))
|
||||
.take_while(|line| line_regex.is_match(&line))
|
||||
.filter_map(|line| {
|
||||
regex.captures_iter(&line).next().map(|capture| {
|
||||
(capture.at(1).expect("Couldn't unwrap capture.").to_owned(),
|
||||
capture.at(2).expect("Couldn't unwrap capture.").to_owned())
|
||||
(capture.at(1).expect("Couldn't unwrap capture").to_owned(),
|
||||
capture.at(2).expect("Couldn't unwrap capture").to_owned())
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
@ -220,20 +273,22 @@ fn read_significant_comments(file_name: &str) -> HashMap<String, String> {
|
||||
// TODO: needs a better name, more explanation.
|
||||
fn handle_result(result: HashMap<String, String>,
|
||||
target: Option<&str>,
|
||||
write_mode: WriteMode)
|
||||
write_mode: Option<WriteMode>)
|
||||
-> Result<(), HashMap<String, Vec<Mismatch>>> {
|
||||
let mut failures = HashMap::new();
|
||||
|
||||
for (file_name, fmt_text) in result {
|
||||
// If file is in tests/source, compare to file with same name in tests/target.
|
||||
let target = get_target(&file_name, target, write_mode);
|
||||
let mut f = fs::File::open(&target).ok().expect("Couldn't open target.");
|
||||
let mut f = fs::File::open(&target).expect("Couldn't open target");
|
||||
|
||||
let mut text = String::new();
|
||||
f.read_to_string(&mut text).ok().expect("Failed reading target.");
|
||||
f.read_to_string(&mut text).expect("Failed reading target");
|
||||
|
||||
if fmt_text != text {
|
||||
let diff = make_diff(&text, &fmt_text, DIFF_CONTEXT_SIZE);
|
||||
assert!(!diff.is_empty(),
|
||||
"Empty diff? Maybe due to a missing a newline at the end of a file?");
|
||||
failures.insert(file_name, diff);
|
||||
}
|
||||
}
|
||||
@ -246,10 +301,10 @@ fn handle_result(result: HashMap<String, String>,
|
||||
}
|
||||
|
||||
// Map source file paths to their target paths.
|
||||
fn get_target(file_name: &str, target: Option<&str>, write_mode: WriteMode) -> String {
|
||||
fn get_target(file_name: &str, target: Option<&str>, write_mode: Option<WriteMode>) -> String {
|
||||
let file_path = Path::new(file_name);
|
||||
let (source_path_prefix, target_path_prefix) = match write_mode {
|
||||
WriteMode::Coverage => {
|
||||
Some(WriteMode::Coverage) => {
|
||||
(Path::new("tests/coverage-source/"),
|
||||
"tests/coverage-target/")
|
||||
}
|
||||
|
@ -2,14 +2,14 @@
|
||||
|
||||
fn main() {
|
||||
reader.lines()
|
||||
.map(|line| line.ok().expect("Failed getting line."))
|
||||
.map(|line| line.expect("Failed getting line"))
|
||||
.take_while(|line| line_regex.is_match(&line))
|
||||
.filter_map(|line| {
|
||||
regex.captures_iter(&line)
|
||||
.next()
|
||||
.map(|capture| {
|
||||
(capture.at(1).expect("Couldn\'t unwrap capture.").to_owned(),
|
||||
capture.at(2).expect("Couldn\'t unwrap capture.").to_owned())
|
||||
(capture.at(1).expect("Couldn\'t unwrap capture").to_owned(),
|
||||
capture.at(2).expect("Couldn\'t unwrap capture").to_owned())
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
@ -28,12 +28,6 @@ fn foo() -> Vec<i32> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn d() {
|
||||
if true /* and ... */ {
|
||||
a();
|
||||
}
|
||||
}
|
||||
|
||||
fn calc_page_len(prefix_len: usize, sofar: usize) -> usize {
|
||||
2 // page type and flags
|
||||
+ 1 // stored depth
|
||||
|
@ -46,3 +46,7 @@ fn chains() {
|
||||
}
|
||||
|
||||
// random comment
|
||||
|
||||
fn main() {
|
||||
// Test
|
||||
}
|
||||
|
@ -2,5 +2,4 @@
|
||||
|
||||
/// This is a long line that angers rustfmt. Rustfmt shall deal with it swiftly
|
||||
/// and justly.
|
||||
pub mod foo {
|
||||
}
|
||||
pub mod foo {}
|
||||
|
@ -3,5 +3,4 @@
|
||||
//! This is a long line that angers rustfmt. Rustfmt shall deal with it swiftly
|
||||
//! and justly.
|
||||
|
||||
pub mod foo {
|
||||
}
|
||||
pub mod foo {}
|
||||
|
@ -256,3 +256,14 @@ fn blocks() {
|
||||
println!("yay arithmetix!");
|
||||
};
|
||||
}
|
||||
|
||||
fn issue767() {
|
||||
if false {
|
||||
if false {
|
||||
} else {
|
||||
// A let binding here seems necessary to trigger it.
|
||||
let _ = ();
|
||||
}
|
||||
} else if let false = false {
|
||||
}
|
||||
}
|
||||
|
@ -61,3 +61,5 @@ trait CoolTypes {
|
||||
trait CoolerTypes {
|
||||
fn dummy(&self) {}
|
||||
}
|
||||
|
||||
fn Foo<T>() where T: Bar {}
|
||||
|
@ -2,17 +2,9 @@
|
||||
|
||||
fn foo(a: AAAA, b: BBB, c: CCC) -> RetType {}
|
||||
|
||||
fn foo(a: AAAA, b: BBB /* some, weird, inline comment */, c: CCC) -> RetType
|
||||
where T: Blah
|
||||
{
|
||||
fn foo(a: AAAA, b: BBB /* some, weird, inline comment */, c: CCC) -> RetType where T: Blah {}
|
||||
|
||||
}
|
||||
|
||||
fn foo(a: AAA /* (comment) */)
|
||||
where T: Blah
|
||||
{
|
||||
|
||||
}
|
||||
fn foo(a: AAA /* (comment) */) where T: Blah {}
|
||||
|
||||
fn foo(a: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,
|
||||
b: BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB)
|
||||
@ -35,10 +27,7 @@ fn foo<U, T>(a: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,
|
||||
fn foo<U: Fn(A) -> B /* paren inside generics */>() {}
|
||||
|
||||
impl Foo {
|
||||
fn with_no_errors<T, F>(&mut self, f: F) -> T
|
||||
where F: FnOnce(&mut Resolver) -> T
|
||||
{
|
||||
}
|
||||
fn with_no_errors<T, F>(&mut self, f: F) -> T where F: FnOnce(&mut Resolver) -> T {}
|
||||
|
||||
fn foo(mut self, mut bar: u32) {}
|
||||
|
||||
|
@ -16,7 +16,8 @@ pub impl Foo for Bar {
|
||||
// Comment 3
|
||||
}
|
||||
|
||||
pub unsafe impl<'a, 'b, X, Y: Foo<Bar>> !Foo<'a, X> for Bar<'b, Y> where X: Foo<'a, Z>
|
||||
pub unsafe impl<'a, 'b, X, Y: Foo<Bar>> !Foo<'a, X> for Bar<'b, Y>
|
||||
where X: Foo<'a, Z>
|
||||
{
|
||||
fn foo() {
|
||||
"hi"
|
||||
@ -31,13 +32,22 @@ impl<'a, 'b, X, Y: Foo<Bar>> Foo<'a, X> for Bar<'b, Y>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, X, Y: Foo<Bar>> Foo<'a, X> for Bar<'b, Y> where X: Foooooooooooooooooooooooooooo<'a, Z>
|
||||
impl<'a, 'b, X, Y: Foo<Bar>> Foo<'a, X> for Bar<'b, Y>
|
||||
where X: Foooooooooooooooooooooooooooo<'a, Z>
|
||||
{
|
||||
fn foo() {
|
||||
"hi"
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Foo for Bar<T> where T: Baz {}
|
||||
|
||||
impl<T> Foo for Bar<T>
|
||||
where T: Baz
|
||||
{
|
||||
// Comment
|
||||
}
|
||||
|
||||
impl Foo {
|
||||
fn foo() {}
|
||||
}
|
||||
@ -80,3 +90,17 @@ impl X {
|
||||
impl Y5000 {
|
||||
fn bar(self: X<'a, 'b>, y: Y) {}
|
||||
}
|
||||
|
||||
pub impl<T> Foo for Bar<T>
|
||||
where T: Foo
|
||||
{
|
||||
fn foo() {
|
||||
"hi"
|
||||
}
|
||||
}
|
||||
|
||||
pub impl<T, Z> Foo for Bar<T, Z>
|
||||
where T: Foo,
|
||||
Z: Baz
|
||||
{
|
||||
}
|
||||
|
39
tests/target/issue-447.rs
Normal file
39
tests/target/issue-447.rs
Normal file
@ -0,0 +1,39 @@
|
||||
fn main() {
|
||||
if
|
||||
// shouldn't be dropped
|
||||
// shouldn't be dropped
|
||||
cond
|
||||
// shouldn't be dropped
|
||||
// shouldn't be dropped
|
||||
{
|
||||
}
|
||||
// shouldn't be dropped
|
||||
// shouldn't be dropped
|
||||
else
|
||||
// shouldn't be dropped
|
||||
// shouldn't be dropped
|
||||
if
|
||||
// shouldn't be dropped
|
||||
// shouldn't be dropped
|
||||
cond
|
||||
// shouldn't be dropped
|
||||
// shouldn't be dropped
|
||||
{
|
||||
}
|
||||
// shouldn't be dropped
|
||||
// shouldn't be dropped
|
||||
else
|
||||
// shouldn't be dropped
|
||||
// shouldn't be dropped
|
||||
{
|
||||
}
|
||||
|
||||
if
|
||||
// shouldn't be dropped
|
||||
// shouldn't be dropped
|
||||
let Some(x) = y
|
||||
// shouldn't be dropped
|
||||
// shouldn't be dropped
|
||||
{
|
||||
}
|
||||
}
|
20
tests/target/issue-811.rs
Normal file
20
tests/target/issue-811.rs
Normal file
@ -0,0 +1,20 @@
|
||||
trait FooTrait<T>: Sized {
|
||||
type Bar: BarTrait<T>;
|
||||
}
|
||||
|
||||
trait BarTrait<T>: Sized {
|
||||
type Baz;
|
||||
fn foo();
|
||||
}
|
||||
|
||||
type Foo<T: FooTrait> =
|
||||
<<T as FooTrait<U>>::Bar as BarTrait<U>>::Baz;
|
||||
type Bar<T: BarTrait> = <T as BarTrait<U>>::Baz;
|
||||
|
||||
fn some_func<T: FooTrait<U>, U>() {
|
||||
<<T as FooTrait<U>>::Bar as BarTrait<U>>::foo();
|
||||
}
|
||||
|
||||
fn some_func<T: BarTrait<U>>() {
|
||||
<T as BarTrait<U>>::foo();
|
||||
}
|
1
tests/target/issue-850.rs
Normal file
1
tests/target/issue-850.rs
Normal file
@ -0,0 +1 @@
|
||||
const unsafe fn x() {}
|
@ -1,4 +1,11 @@
|
||||
itemmacro!(this, is.not() .formatted(yet));
|
||||
itemmacro!(this, is.now().formatted(yay));
|
||||
|
||||
itemmacro!(really,
|
||||
long.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbb()
|
||||
.is
|
||||
.formatted());
|
||||
|
||||
itemmacro!{this, is.bracket().formatted()}
|
||||
|
||||
fn main() {
|
||||
foo!();
|
||||
|
@ -251,7 +251,7 @@ fn issue280() {
|
||||
|
||||
fn issue383() {
|
||||
match resolution.last_private {
|
||||
LastImport{..} => false,
|
||||
LastImport { .. } => false,
|
||||
_ => true,
|
||||
};
|
||||
}
|
||||
|
@ -2,8 +2,7 @@
|
||||
|
||||
mod foo {
|
||||
mod bar {
|
||||
mod baz {
|
||||
}
|
||||
mod baz {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,9 +15,7 @@ mod foo {
|
||||
}
|
||||
}
|
||||
|
||||
mod qux {
|
||||
|
||||
}
|
||||
mod qux {}
|
||||
}
|
||||
|
||||
mod boxed {
|
||||
|
@ -13,6 +13,23 @@ fn main() {
|
||||
if let None = opt2 {
|
||||
panic!("oh noes");
|
||||
}
|
||||
|
||||
let foo @ bar(f) = 42;
|
||||
let a::foo(..) = 42;
|
||||
let [] = 42;
|
||||
let [a.., b, c] = 42;
|
||||
let [a, b, c..] = 42;
|
||||
let [a, b, c, d.., e, f, g] = 42;
|
||||
let foo {} = 42;
|
||||
let foo { .. } = 42;
|
||||
let foo { x, y: ref foo, .. } = 42;
|
||||
let foo { x, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy: ref foo, .. } = 42;
|
||||
let foo { x, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy: ref foo } = 42;
|
||||
let foo { x,
|
||||
yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy: ref foo,
|
||||
.. };
|
||||
let foo { x,
|
||||
yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy: ref foo };
|
||||
}
|
||||
|
||||
impl<'a, 'b> ResolveGeneratedContentFragmentMutator<'a, 'b> {
|
||||
|
15
tests/target/string-lit-2.rs
Normal file
15
tests/target/string-lit-2.rs
Normal file
@ -0,0 +1,15 @@
|
||||
fn main() -> &'static str {
|
||||
let too_many_lines = "H\
|
||||
e\
|
||||
l\
|
||||
l\
|
||||
o";
|
||||
let leave_me = "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss\
|
||||
s
|
||||
jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj";
|
||||
// Crappy formatting :-(
|
||||
let change_me = "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
|
||||
\
|
||||
jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj\
|
||||
j";
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
// rustfmt-force_format_strings: true
|
||||
// Long string literals
|
||||
|
||||
fn main() -> &'static str {
|
||||
|
@ -149,3 +149,13 @@ fn issue491() {
|
||||
e: eeeeeeeee,
|
||||
};
|
||||
}
|
||||
|
||||
fn issue698() {
|
||||
Record {
|
||||
ffffffffffffffffffffffffffields: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
|
||||
};
|
||||
Record {
|
||||
ffffffffffffffffffffffffffields:
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
|
||||
}
|
||||
}
|
||||
|
5
tests/target/type-punctuation.rs
Normal file
5
tests/target/type-punctuation.rs
Normal file
@ -0,0 +1,5 @@
|
||||
// rustfmt-type_punctuation_density: Compressed
|
||||
|
||||
fn Foo<T=Foo, Output=Expr<'tcx>+Foo>() {
|
||||
let i = 6;
|
||||
}
|
57
tests/target/where-trailing-comma.rs
Normal file
57
tests/target/where-trailing-comma.rs
Normal file
@ -0,0 +1,57 @@
|
||||
// rustfmt-where_trailing_comma: true
|
||||
|
||||
fn f<S, T>(x: T, y: S) -> T
|
||||
where T: P,
|
||||
S: Q,
|
||||
{
|
||||
x
|
||||
}
|
||||
|
||||
impl Trait for T
|
||||
where T: P,
|
||||
{
|
||||
fn f(x: T) -> T
|
||||
where T: Q + R,
|
||||
{
|
||||
x
|
||||
}
|
||||
}
|
||||
|
||||
struct Pair<S, T>
|
||||
where T: P,
|
||||
S: P + Q,
|
||||
{
|
||||
a: T,
|
||||
b: S,
|
||||
}
|
||||
|
||||
struct TupPair<S, T>(S, T)
|
||||
where T: P,
|
||||
S: P + Q;
|
||||
|
||||
enum E<S, T>
|
||||
where S: P,
|
||||
T: P,
|
||||
{
|
||||
A {
|
||||
a: T,
|
||||
},
|
||||
}
|
||||
|
||||
type Double<T>
|
||||
where T: P,
|
||||
T: Q = Pair<T, T>;
|
||||
|
||||
extern "C" {
|
||||
fn f<S, T>(x: T, y: S) -> T
|
||||
where T: P,
|
||||
S: Q;
|
||||
}
|
||||
|
||||
// Note: trait declarations are not fully formatted (issue #78)
|
||||
trait Q<S, T> where T: P, S: R
|
||||
{
|
||||
fn f<U, V>(self, x: T, y: S, z: U) -> Self
|
||||
where U: P,
|
||||
V: P;
|
||||
}
|
2
tests/writemode/checkstyle.xml
Normal file
2
tests/writemode/checkstyle.xml
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<checkstyle version="4.3"><file name="tests/source/fn-single-line.rs"><error line="1" severity="warning" message="Should be `fn foo_expr() { 1 }`" /><error line="1" severity="warning" message="Should be `fn foo_stmt() { foo(); }`" /><error line="1" severity="warning" message="Should be `fn foo_decl_local() { let z = 5; }`" /><error line="1" severity="warning" message="Should be `fn foo_decl_item(x: &mut i32) { x = 3; }`" /><error line="1" severity="warning" message="Should be `fn empty() {}`" /><error line="1" severity="warning" message="Should be `fn foo_return() -> String { "yay" }`" /><error line="1" severity="warning" message="Should be `fn foo_where() -> T`" /><error line="1" severity="warning" message="Should be ` where T: Sync`" /><error line="1" severity="warning" message="Should be `{`" /><error line="50" severity="warning" message="Should be `fn lots_of_space() { 1 }`" /><error line="57" severity="warning" message="Should be ` fn dummy(&self) {}`" /><error line="57" severity="warning" message="Should be `trait CoolerTypes {`" /><error line="57" severity="warning" message="Should be ` fn dummy(&self) {}`" /><error line="57" severity="warning" message="Should be `fn Foo<T>() where T: Bar {}`" /><error line="57" severity="warning" message="Should be ``" /></file></checkstyle>
|
Loading…
x
Reference in New Issue
Block a user